From 3cffac50618df11963f9a727a50d80423efb63f9 Mon Sep 17 00:00:00 2001 From: Weiming Zhao Date: Mon, 23 Jun 2014 20:44:16 +0000 Subject: Fix PR20056: Implement pseudo LDR , = for AArch64 This patch is based on the changes from ARM target [1,2] Based on ARM doc [3], if the literal value can be loaded with a valid MOV, it can emit that instruction. This is implemented in this patch. [1] Fix PR18345: ldr= pseudo instruction produces incorrect code when using in inline assembly Author: David Peixotto commit b92cca222898d87bbc764fa22e805adb04ef7f13 (r200777) [2] Implement the ldr-pseudo opcode for ARM assembly Author: David Peixotto commit 0fa193b08627927ccaa0804a34d80480894614b8 (r197708) [3] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0802a/CJAHAIBC.html Differential Revision: http://reviews.llvm.org/D4163 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@211533 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/MC/MCStreamer.h | 21 +++++++++ lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp | 55 ++++++++++++++++++++++- lib/Target/AArch64/MCTargetDesc/CMakeLists.txt | 1 + 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index bf224979de..cd1fa9b6a8 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -86,6 +86,27 @@ public: virtual void finish(); }; +class AArch64TargetStreamer : public MCTargetStreamer { +public: + AArch64TargetStreamer(MCStreamer &S); + ~AArch64TargetStreamer(); + + + void finish() override; + + /// Callback used to implement the ldr= pseudo. + /// Add a new entry to the constant pool for the current section and return an + /// MCExpr that can be used to refer to the constant pool location. + const MCExpr *addConstantPoolEntry(const MCExpr *); + + /// Callback used to implemnt the .ltorg directive. + /// Emit contents of constant pool for the current section. + void emitCurrentConstantPool(); + +private: + std::unique_ptr ConstantPools; +}; + // FIXME: declared here because it is used from // lib/CodeGen/AsmPrinter/ARMException.cpp. class ARMTargetStreamer : public MCTargetStreamer { diff --git a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 5d363a00dc..c4d840d90b 100644 --- a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -43,6 +43,11 @@ private: MCSubtargetInfo &STI; MCAsmParser &Parser; + AArch64TargetStreamer &getTargetStreamer() { + MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); + return static_cast(TS); + } + MCAsmParser &getParser() const { return Parser; } MCAsmLexer &getLexer() const { return Parser.getLexer(); } @@ -67,6 +72,7 @@ private: bool parseDirectiveTLSDescCall(SMLoc L); bool parseDirectiveLOH(StringRef LOH, SMLoc L); + bool parseDirectiveLtorg(SMLoc L); bool validateInstruction(MCInst &Inst, SmallVectorImpl &Loc); bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, @@ -105,6 +111,8 @@ public: const MCTargetOptions &Options) : MCTargetAsmParser(), STI(_STI), Parser(_Parser) { MCAsmParserExtension::Initialize(_Parser); + if (Parser.getStreamer().getTargetStreamer() == nullptr) + new AArch64TargetStreamer(Parser.getStreamer()); // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); @@ -3004,6 +3012,43 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode, Operands.push_back(AArch64Operand::CreateImm(ImmVal, S, E, getContext())); return false; } + case AsmToken::Equal: { + SMLoc Loc = Parser.getTok().getLoc(); + if (Mnemonic != "ldr") // only parse for ldr pseudo (e.g. ldr r0, =val) + return Error(Loc, "unexpected token in operand"); + Parser.Lex(); // Eat '=' + const MCExpr *SubExprVal; + if (getParser().parseExpression(SubExprVal)) + return true; + + MCContext& Ctx = getContext(); + E = SMLoc::getFromPointer(Loc.getPointer() - 1); + // If the op is an imm and can be fit into a mov, then replace ldr with mov. + if (isa(SubExprVal) && Operands.size() >= 2 && + static_cast(*Operands[1]).isReg()) { + bool IsXReg = AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains( + Operands[1]->getReg()); + uint64_t Imm = (cast(SubExprVal))->getValue(); + uint32_t ShiftAmt = 0, MaxShiftAmt = IsXReg ? 48 : 16; + while(Imm > 0xFFFF && countTrailingZeros(Imm) >= 16) { + ShiftAmt += 16; + Imm >>= 16; + } + if (ShiftAmt <= MaxShiftAmt && Imm <= 0xFFFF) { + Operands[0] = AArch64Operand::CreateToken("movz", false, Loc, Ctx); + Operands.push_back(AArch64Operand::CreateImm( + MCConstantExpr::Create(Imm, Ctx), S, E, Ctx)); + if (ShiftAmt) + Operands.push_back(AArch64Operand::CreateShiftExtend(AArch64_AM::LSL, + ShiftAmt, true, S, E, Ctx)); + return false; + } + } + // If it is a label or an imm that cannot fit in a movz, put it into CP. + const MCExpr *CPLoc = getTargetStreamer().addConstantPoolEntry(SubExprVal); + Operands.push_back(AArch64Operand::CreateImm(CPLoc, S, E, Ctx)); + return false; + } } } @@ -3810,7 +3855,8 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) { return parseDirectiveWord(8, Loc); if (IDVal == ".tlsdesccall") return parseDirectiveTLSDescCall(Loc); - + if (IDVal == ".ltorg" || IDVal == ".pool") + return parseDirectiveLtorg(Loc); return parseDirectiveLOH(IDVal, Loc); } @@ -3911,6 +3957,13 @@ bool AArch64AsmParser::parseDirectiveLOH(StringRef IDVal, SMLoc Loc) { return false; } +/// parseDirectiveLtorg +/// ::= .ltorg | .pool +bool AArch64AsmParser::parseDirectiveLtorg(SMLoc L) { + getTargetStreamer().emitCurrentConstantPool(); + return false; +} + bool AArch64AsmParser::classifySymbolRef(const MCExpr *Expr, AArch64MCExpr::VariantKind &ELFRefKind, diff --git a/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt b/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt index 7d5bced17a..6d8be5e63f 100644 --- a/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt +++ b/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt @@ -7,6 +7,7 @@ add_llvm_library(LLVMAArch64Desc AArch64MCExpr.cpp AArch64MCTargetDesc.cpp AArch64MachObjectWriter.cpp + AArch64TargetStreamer.cpp ) add_dependencies(LLVMAArch64Desc AArch64CommonTableGen) -- cgit v1.2.3