diff --git a/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp index d1664febd39..98bec19b53d 100644 --- a/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp +++ b/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp @@ -297,6 +297,7 @@ struct PPCOperand : public MCParsedAsmOperand { enum KindTy { Token, Immediate, + ContextImmediate, Expression, TLSRegister } Kind; @@ -341,6 +342,7 @@ public: Tok = o.Tok; break; case Immediate: + case ContextImmediate: Imm = o.Imm; break; case Expression: @@ -365,6 +367,16 @@ public: assert(Kind == Immediate && "Invalid access!"); return Imm.Val; } + int64_t getImmS16Context() const { + assert((Kind == Immediate || Kind == ContextImmediate) && "Invalid access!"); + if (Kind == Immediate) + return Imm.Val; + return static_cast(Imm.Val); + } + int64_t getImmU16Context() const { + assert((Kind == Immediate || Kind == ContextImmediate) && "Invalid access!"); + return Imm.Val; + } const MCExpr *getExpr() const { assert(Kind == Expression && "Invalid access!"); @@ -422,15 +434,42 @@ public: bool isU8ImmX8() const { return Kind == Immediate && isUInt<8>(getImm()) && (getImm() & 7) == 0; } - bool isU16Imm() const { return Kind == Expression || - (Kind == Immediate && isUInt<16>(getImm())); } - bool isS16Imm() const { return Kind == Expression || - (Kind == Immediate && isInt<16>(getImm())); } + bool isU16Imm() const { + switch (Kind) { + case Expression: + return true; + case Immediate: + case ContextImmediate: + return isUInt<16>(getImmU16Context()); + default: + return false; + } + } + bool isS16Imm() const { + switch (Kind) { + case Expression: + return true; + case Immediate: + case ContextImmediate: + return isInt<16>(getImmS16Context()); + default: + return false; + } + } bool isS16ImmX4() const { return Kind == Expression || (Kind == Immediate && isInt<16>(getImm()) && (getImm() & 3) == 0); } - bool isS17Imm() const { return Kind == Expression || - (Kind == Immediate && isInt<17>(getImm())); } + bool isS17Imm() const { + switch (Kind) { + case Expression: + return true; + case Immediate: + case ContextImmediate: + return isInt<17>(getImmS16Context()); + default: + return false; + } + } bool isTLSReg() const { return Kind == TLSRegister; } bool isDirectBr() const { if (Kind == Expression) @@ -553,6 +592,36 @@ public: Inst.addOperand(MCOperand::CreateExpr(getExpr())); } + void addS16ImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + switch (Kind) { + case Immediate: + Inst.addOperand(MCOperand::CreateImm(getImm())); + break; + case ContextImmediate: + Inst.addOperand(MCOperand::CreateImm(getImmS16Context())); + break; + default: + Inst.addOperand(MCOperand::CreateExpr(getExpr())); + break; + } + } + + void addU16ImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + switch (Kind) { + case Immediate: + Inst.addOperand(MCOperand::CreateImm(getImm())); + break; + case ContextImmediate: + Inst.addOperand(MCOperand::CreateImm(getImmU16Context())); + break; + default: + Inst.addOperand(MCOperand::CreateExpr(getExpr())); + break; + } + } + void addBranchTargetOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); if (Kind == Immediate) @@ -633,6 +702,16 @@ public: return Op; } + static std::unique_ptr + CreateContextImm(int64_t Val, SMLoc S, SMLoc E, bool IsPPC64) { + auto Op = make_unique(ContextImmediate); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + Op->IsPPC64 = IsPPC64; + return Op; + } + static std::unique_ptr CreateFromMCExpr(const MCExpr *Val, SMLoc S, SMLoc E, bool IsPPC64) { if (const MCConstantExpr *CE = dyn_cast(Val)) @@ -642,6 +721,12 @@ public: if (SRE->getKind() == MCSymbolRefExpr::VK_PPC_TLS) return CreateTLSReg(SRE, S, E, IsPPC64); + if (const PPCMCExpr *TE = dyn_cast(Val)) { + int64_t Res; + if (TE->EvaluateAsConstant(Res)) + return CreateContextImm(Res, S, E, IsPPC64); + } + return CreateExpr(Val, S, E, IsPPC64); } }; @@ -654,6 +739,7 @@ void PPCOperand::print(raw_ostream &OS) const { OS << "'" << getToken() << "'"; break; case Immediate: + case ContextImmediate: OS << getImm(); break; case Expression: diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp index e8512cd2332..7204befe15e 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp +++ b/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "PPCFixupKinds.h" #include "PPCMCExpr.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAssembler.h" @@ -51,6 +52,43 @@ void PPCMCExpr::PrintImpl(raw_ostream &OS) const { } } +bool +PPCMCExpr::EvaluateAsConstant(int64_t &Res) const { + MCValue Value; + + if (!getSubExpr()->EvaluateAsRelocatable(Value, nullptr, nullptr)) + return false; + + if (!Value.isAbsolute()) + return false; + + Res = EvaluateAsInt64(Value.getConstant()); + return true; +} + +int64_t +PPCMCExpr::EvaluateAsInt64(int64_t Value) const { + switch (Kind) { + case VK_PPC_LO: + return Value & 0xffff; + case VK_PPC_HI: + return (Value >> 16) & 0xffff; + case VK_PPC_HA: + return ((Value + 0x8000) >> 16) & 0xffff; + case VK_PPC_HIGHER: + return (Value >> 32) & 0xffff; + case VK_PPC_HIGHERA: + return ((Value + 0x8000) >> 32) & 0xffff; + case VK_PPC_HIGHEST: + return (Value >> 48) & 0xffff; + case VK_PPC_HIGHESTA: + return ((Value + 0x8000) >> 48) & 0xffff; + case VK_PPC_None: + break; + } + llvm_unreachable("Invalid kind!"); +} + bool PPCMCExpr::EvaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, @@ -61,32 +99,10 @@ PPCMCExpr::EvaluateAsRelocatableImpl(MCValue &Res, return false; if (Value.isAbsolute()) { - int64_t Result = Value.getConstant(); - switch (Kind) { - default: - llvm_unreachable("Invalid kind!"); - case VK_PPC_LO: - Result = Result & 0xffff; - break; - case VK_PPC_HI: - Result = (Result >> 16) & 0xffff; - break; - case VK_PPC_HA: - Result = ((Result + 0x8000) >> 16) & 0xffff; - break; - case VK_PPC_HIGHER: - Result = (Result >> 32) & 0xffff; - break; - case VK_PPC_HIGHERA: - Result = ((Result + 0x8000) >> 32) & 0xffff; - break; - case VK_PPC_HIGHEST: - Result = (Result >> 48) & 0xffff; - break; - case VK_PPC_HIGHESTA: - Result = ((Result + 0x8000) >> 48) & 0xffff; - break; - } + int64_t Result = EvaluateAsInt64(Value.getConstant()); + if ((Fixup == nullptr || (unsigned)Fixup->getKind() != PPC::fixup_ppc_half16) && + (Result >= 0x8000)) + return false; Res = MCValue::get(Result); } else { if (!Layout) diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.h b/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.h index f9baf5de5a0..32b6f9a6c08 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.h +++ b/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.h @@ -34,6 +34,8 @@ private: const MCExpr *Expr; bool IsDarwin; + int64_t EvaluateAsInt64(int64_t Value) const; + explicit PPCMCExpr(VariantKind _Kind, const MCExpr *_Expr, bool _IsDarwin) : Kind(_Kind), Expr(_Expr), IsDarwin(_IsDarwin) {} @@ -88,6 +90,8 @@ public: // There are no TLS PPCMCExprs at the moment. void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} + bool EvaluateAsConstant(int64_t &Res) const; + static bool classof(const MCExpr *E) { return E->getKind() == MCExpr::Target; } diff --git a/lib/Target/PowerPC/PPCInstrInfo.td b/lib/Target/PowerPC/PPCInstrInfo.td index e33ded03952..3b2c7cb3d81 100644 --- a/lib/Target/PowerPC/PPCInstrInfo.td +++ b/lib/Target/PowerPC/PPCInstrInfo.td @@ -458,7 +458,7 @@ def u6imm : Operand { } def PPCS16ImmAsmOperand : AsmOperandClass { let Name = "S16Imm"; let PredicateMethod = "isS16Imm"; - let RenderMethod = "addImmOperands"; + let RenderMethod = "addS16ImmOperands"; } def s16imm : Operand { let PrintMethod = "printS16ImmOperand"; @@ -468,7 +468,7 @@ def s16imm : Operand { } def PPCU16ImmAsmOperand : AsmOperandClass { let Name = "U16Imm"; let PredicateMethod = "isU16Imm"; - let RenderMethod = "addImmOperands"; + let RenderMethod = "addU16ImmOperands"; } def u16imm : Operand { let PrintMethod = "printU16ImmOperand"; @@ -478,7 +478,7 @@ def u16imm : Operand { } def PPCS17ImmAsmOperand : AsmOperandClass { let Name = "S17Imm"; let PredicateMethod = "isS17Imm"; - let RenderMethod = "addImmOperands"; + let RenderMethod = "addS16ImmOperands"; } def s17imm : Operand { // This operand type is used for addis/lis to allow the assembler parser @@ -554,7 +554,7 @@ def ptr_rc_idx : Operand, PointerLikeRegClass<0> { def PPCDispRIOperand : AsmOperandClass { let Name = "DispRI"; let PredicateMethod = "isS16Imm"; - let RenderMethod = "addImmOperands"; + let RenderMethod = "addS16ImmOperands"; } def dispRI : Operand { let ParserMatchClass = PPCDispRIOperand; diff --git a/test/MC/PowerPC/ppc64-fixup-apply.s b/test/MC/PowerPC/ppc64-fixup-apply.s index 24bd83ffd18..f98b46d6b18 100644 --- a/test/MC/PowerPC/ppc64-fixup-apply.s +++ b/test/MC/PowerPC/ppc64-fixup-apply.s @@ -27,6 +27,8 @@ subis 1, 1, target4-target3@ha addi 1, 1, target5+0x8000@l addis 1, 1, target5+0x8000@ha +ori 1, 1, target5+0x8000@l +oris 1, 1, target5+0x8000@ha .set target5, 0x10000001 @@ -68,7 +70,7 @@ addis 1, 1, target7@highesta # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 # CHECK-NEXT: Offset: -# CHECK-NEXT: Size: 64 +# CHECK-NEXT: Size: 72 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 4 @@ -78,10 +80,12 @@ addis 1, 1, target7@highesta # CHECK-LE-NEXT: 0000: 34122138 3412213C 78562138 3412213C # CHECK-BE-NEXT: 0010: 38214444 3C211111 38218001 3C211001 # CHECK-LE-NEXT: 0010: 44442138 1111213C 01802138 0110213C -# CHECK-BE-NEXT: 0020: 38210008 3C210000 38214321 3C214321 -# CHECK-LE-NEXT: 0020: 08002138 0000213C 21432138 2143213C -# CHECK-BE-NEXT: 0030: 3821FFFF 3C211234 38210000 3C211235 -# CHECK-LE-NEXT: 0030: FFFF2138 3412213C 00002138 3512213C +# CHECK-BE-NEXT: 0020: 60218001 64211001 38210008 3C210000 +# CHECK-LE-NEXT: 0020: 01802160 01102164 08002138 0000213C +# CHECK-BE-NEXT: 0030: 38214321 3C214321 3821FFFF 3C211234 +# CHECK-LE-NEXT: 0030: 21432138 2143213C FFFF2138 3412213C +# CHECK-BE-NEXT: 0040: 38210000 3C211235 +# CHECK-LE-NEXT: 0040: 00002138 3512213C # CHECK-NEXT: ) # CHECK-NEXT: } diff --git a/test/MC/PowerPC/ppc64-fixups.s b/test/MC/PowerPC/ppc64-fixups.s index d3769f52580..20a70c27054 100644 --- a/test/MC/PowerPC/ppc64-fixups.s +++ b/test/MC/PowerPC/ppc64-fixups.s @@ -687,6 +687,18 @@ base: # CHECK-BE: ori 1, 2, 2 # encoding: [0x60,0x41,0x00,0x02] # CHECK-LE: ori 1, 2, 2 # encoding: [0x02,0x00,0x41,0x60] ori 1, 2, 131071@ha +# CHECK-BE: addi 1, 2, -1 # encoding: [0x38,0x22,0xff,0xff] +# CHECK-LE: addi 1, 2, -1 # encoding: [0xff,0xff,0x22,0x38] + addi 1, 2, 131071@l +# CHECK-BE: addi 1, 2, 1 # encoding: [0x38,0x22,0x00,0x01] +# CHECK-LE: addi 1, 2, 1 # encoding: [0x01,0x00,0x22,0x38] + addi 1, 2, 131071@h +# CHECK-BE: addi 1, 2, 2 # encoding: [0x38,0x22,0x00,0x02] +# CHECK-LE: addi 1, 2, 2 # encoding: [0x02,0x00,0x22,0x38] + addi 1, 2, 131071@ha +# CHECK-BE: addis 1, 2, -4096 # encoding: [0x3c,0x22,0xf0,0x00] +# CHECK-LE: addis 1, 2, -4096 # encoding: [0x00,0xf0,0x22,0x3c] + addis 1, 2, 0xf0000000@h # Data relocs # llvm-mc does not show any "encoding" string for data, so we just check the relocs