diff --git a/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp index e4fc3b9ded7..237ecdc60e4 100644 --- a/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp +++ b/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp @@ -237,7 +237,8 @@ struct PPCOperand : public MCParsedAsmOperand { enum KindTy { Token, Immediate, - Expression + Expression, + TLSRegister } Kind; SMLoc StartLoc, EndLoc; @@ -257,10 +258,15 @@ struct PPCOperand : public MCParsedAsmOperand { int64_t CRVal; // Cached result of EvaluateCRExpr(Val) }; + struct TLSRegOp { + const MCSymbolRefExpr *Sym; + }; + union { struct TokOp Tok; struct ImmOp Imm; struct ExprOp Expr; + struct TLSRegOp TLSReg; }; PPCOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} @@ -280,6 +286,9 @@ public: case Expression: Expr = o.Expr; break; + case TLSRegister: + TLSReg = o.TLSReg; + break; } } @@ -307,6 +316,11 @@ public: return Expr.CRVal; } + const MCExpr *getTLSReg() const { + assert(Kind == TLSRegister && "Invalid access!"); + return TLSReg.Sym; + } + unsigned getReg() const { assert(isRegNumber() && "Invalid access!"); return (unsigned) Imm.Val; @@ -341,6 +355,7 @@ public: (getImm() & 3) == 0); } bool isS17Imm() const { return Kind == Expression || (Kind == Immediate && isInt<17>(getImm())); } + bool isTLSReg() const { return Kind == TLSRegister; } bool isDirectBr() const { return Kind == Expression || (Kind == Immediate && isInt<26>(getImm()) && (getImm() & 3) == 0); } @@ -445,6 +460,11 @@ public: Inst.addOperand(MCOperand::CreateExpr(getExpr())); } + void addTLSRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateExpr(getTLSReg())); + } + StringRef getToken() const { assert(Kind == Token && "Invalid access!"); return StringRef(Tok.Data, Tok.Length); @@ -481,6 +501,28 @@ public: Op->IsPPC64 = IsPPC64; return Op; } + + static PPCOperand *CreateTLSReg(const MCSymbolRefExpr *Sym, + SMLoc S, SMLoc E, bool IsPPC64) { + PPCOperand *Op = new PPCOperand(TLSRegister); + Op->TLSReg.Sym = Sym; + Op->StartLoc = S; + Op->EndLoc = E; + Op->IsPPC64 = IsPPC64; + return Op; + } + + static PPCOperand *CreateFromMCExpr(const MCExpr *Val, + SMLoc S, SMLoc E, bool IsPPC64) { + if (const MCConstantExpr *CE = dyn_cast(Val)) + return CreateImm(CE->getValue(), S, E, IsPPC64); + + if (const MCSymbolRefExpr *SRE = dyn_cast(Val)) + if (SRE->getKind() == MCSymbolRefExpr::VK_PPC_TLS) + return CreateTLSReg(SRE, S, E, IsPPC64); + + return CreateExpr(Val, S, E, IsPPC64); + } }; } // end anonymous namespace. @@ -496,6 +538,9 @@ void PPCOperand::print(raw_ostream &OS) const { case Expression: getExpr()->print(OS); break; + case TLSRegister: + getTLSReg()->print(OS); + break; } } @@ -1011,12 +1056,8 @@ ParseOperand(SmallVectorImpl &Operands) { return Error(S, "unknown operand"); } - if (const MCConstantExpr *CE = dyn_cast(EVal)) - Op = PPCOperand::CreateImm(CE->getValue(), S, E, isPPC64()); - else - Op = PPCOperand::CreateExpr(EVal, S, E, isPPC64()); - // Push the parsed operand into the list of operands + Op = PPCOperand::CreateFromMCExpr(EVal, S, E, isPPC64()); Operands.push_back(Op); // Check whether this is a TLS call expression @@ -1036,7 +1077,7 @@ ParseOperand(SmallVectorImpl &Operands) { E = Parser.getTok().getLoc(); Parser.Lex(); // Eat the ')'. - Op = PPCOperand::CreateExpr(TLSSym, S, E, isPPC64()); + Op = PPCOperand::CreateFromMCExpr(TLSSym, S, E, isPPC64()); Operands.push_back(Op); } diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp index b37a17933c1..4f999a15346 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp +++ b/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp @@ -30,7 +30,6 @@ static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) { case FK_Data_2: case FK_Data_4: case FK_Data_8: - case PPC::fixup_ppc_tlsreg: case PPC::fixup_ppc_nofixup: return Value; case PPC::fixup_ppc_brcond14: @@ -64,7 +63,6 @@ static unsigned getFixupKindNumBytes(unsigned Kind) { return 4; case FK_Data_8: return 8; - case PPC::fixup_ppc_tlsreg: case PPC::fixup_ppc_nofixup: return 0; } @@ -101,7 +99,6 @@ public: { "fixup_ppc_brcond14abs", 16, 14, 0 }, { "fixup_ppc_half16", 0, 16, 0 }, { "fixup_ppc_half16ds", 0, 14, 0 }, - { "fixup_ppc_tlsreg", 0, 0, 0 }, { "fixup_ppc_nofixup", 0, 0, 0 } }; diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp index 76cf43f6e58..ffc5002a96b 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp +++ b/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp @@ -289,9 +289,6 @@ unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target, break; } break; - case PPC::fixup_ppc_tlsreg: - Type = ELF::R_PPC64_TLS; - break; case PPC::fixup_ppc_nofixup: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); @@ -301,6 +298,9 @@ unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target, case MCSymbolRefExpr::VK_TLSLD: Type = ELF::R_PPC64_TLSLD; break; + case MCSymbolRefExpr::VK_PPC_TLS: + Type = ELF::R_PPC64_TLS; + break; } break; case FK_Data_8: diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h b/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h index 0438c0e3abf..68de8c1f27a 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h +++ b/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h @@ -41,11 +41,9 @@ enum Fixups { /// implied 2 zero bits for instrs like 'std'. fixup_ppc_half16ds, - /// fixup_ppc_tlsreg - Insert thread-pointer register number. - fixup_ppc_tlsreg, - /// fixup_ppc_nofixup - Not a true fixup, but ties a symbol to a call - /// to __tls_get_addr for the TLS general and local dynamic models. + /// to __tls_get_addr for the TLS general and local dynamic models, + /// or inserts the thread-pointer register number. fixup_ppc_nofixup, // Marker diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp index 27ad980703a..59ba9c4af62 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp +++ b/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp @@ -209,7 +209,7 @@ unsigned PPCMCCodeEmitter::getTLSRegEncoding(const MCInst &MI, unsigned OpNo, // hint to the linker that this statement is part of a relocation sequence. // Return the thread-pointer register's encoding. Fixups.push_back(MCFixup::Create(0, MO.getExpr(), - (MCFixupKind)PPC::fixup_ppc_tlsreg)); + (MCFixupKind)PPC::fixup_ppc_nofixup)); return CTX.getRegisterInfo()->getEncodingValue(PPC::X13); } diff --git a/lib/Target/PowerPC/PPC.h b/lib/Target/PowerPC/PPC.h index d5a08eed6dc..96b882aef1f 100644 --- a/lib/Target/PowerPC/PPC.h +++ b/lib/Target/PowerPC/PPC.h @@ -85,7 +85,10 @@ namespace llvm { /// into memory operations. MO_DTPREL_LO = 5 << 4, MO_TLSLD_LO = 6 << 4, - MO_TOC_LO = 7 << 4 + MO_TOC_LO = 7 << 4, + + // Symbol for VK_PPC_TLS fixup attached to an ADD instruction + MO_TLS = 8 << 4 }; } // end namespace PPCII diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index c4f961cbd64..0f790313638 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -1359,12 +1359,14 @@ SDValue PPCTargetLowering::LowerGlobalTLSAddress(SDValue Op, if (Model == TLSModel::InitialExec) { SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, 0); + SDValue TGATLS = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, + PPCII::MO_TLS); SDValue GOTReg = DAG.getRegister(PPC::X2, MVT::i64); SDValue TPOffsetHi = DAG.getNode(PPCISD::ADDIS_GOT_TPREL_HA, dl, PtrVT, GOTReg, TGA); SDValue TPOffset = DAG.getNode(PPCISD::LD_GOT_TPREL_L, dl, PtrVT, TGA, TPOffsetHi); - return DAG.getNode(PPCISD::ADD_TLS, dl, PtrVT, TPOffset, TGA); + return DAG.getNode(PPCISD::ADD_TLS, dl, PtrVT, TPOffset, TGATLS); } if (Model == TLSModel::GeneralDynamic) { diff --git a/lib/Target/PowerPC/PPCInstr64Bit.td b/lib/Target/PowerPC/PPCInstr64Bit.td index d19a7d439fd..e7bb25941d8 100644 --- a/lib/Target/PowerPC/PPCInstr64Bit.td +++ b/lib/Target/PowerPC/PPCInstr64Bit.td @@ -36,8 +36,13 @@ def s17imm64 : Operand { def tocentry : Operand { let MIOperandInfo = (ops i64imm:$imm); } +def PPCTLSRegOperand : AsmOperandClass { + let Name = "TLSReg"; let PredicateMethod = "isTLSReg"; + let RenderMethod = "addTLSRegOperands"; +} def tlsreg : Operand { let EncoderMethod = "getTLSRegEncoding"; + let ParserMatchClass = PPCTLSRegOperand; } def tlsgd : Operand {} def tlscall : Operand { @@ -404,9 +409,8 @@ defm ADD8 : XOForm_1r<31, 266, 0, (outs g8rc:$rT), (ins g8rc:$rA, g8rc:$rB), [(set i64:$rT, (add i64:$rA, i64:$rB))]>; // ADD8 has a special form: reg = ADD8(reg, sym@tls) for use by the // initial-exec thread-local storage model. -let isCodeGenOnly = 1 in def ADD8TLS : XOForm_1<31, 266, 0, (outs g8rc:$rT), (ins g8rc:$rA, tlsreg:$rB), - "add $rT, $rA, $rB@tls", IntSimple, + "add $rT, $rA, $rB", IntSimple, [(set i64:$rT, (add i64:$rA, tglobaltlsaddr:$rB))]>; defm ADDC8 : XOForm_1rc<31, 10, 0, (outs g8rc:$rT), (ins g8rc:$rA, g8rc:$rB), diff --git a/lib/Target/PowerPC/PPCMCInstLower.cpp b/lib/Target/PowerPC/PPCMCInstLower.cpp index 1eefb7f08d2..b7e88d452c4 100644 --- a/lib/Target/PowerPC/PPCMCInstLower.cpp +++ b/lib/Target/PowerPC/PPCMCInstLower.cpp @@ -127,6 +127,9 @@ static MCOperand GetSymbolRef(const MachineOperand &MO, const MCSymbol *Symbol, case PPCII::MO_TOC_LO: RefKind = MCSymbolRefExpr::VK_PPC_TOC_LO; break; + case PPCII::MO_TLS: + RefKind = MCSymbolRefExpr::VK_PPC_TLS; + break; } const MCExpr *Expr = MCSymbolRefExpr::Create(Symbol, RefKind, Ctx); diff --git a/test/MC/PowerPC/ppc64-errors.s b/test/MC/PowerPC/ppc64-errors.s index 8b6dd5395ff..bc8c95c2237 100644 --- a/test/MC/PowerPC/ppc64-errors.s +++ b/test/MC/PowerPC/ppc64-errors.s @@ -12,6 +12,16 @@ # CHECK-NEXT: add %r32, %r32, %r32 add %r32, %r32, %r32 +# TLS register operands + +# CHECK: error: invalid operand for instruction +# CHECK-NEXT: add 3, symbol@tls, 4 + add 3, symbol@tls, 4 + +# CHECK: error: invalid operand for instruction +# CHECK-NEXT: subf 3, 4, symbol@tls + subf 3, 4, symbol@tls + # Signed 16-bit immediate operands # CHECK: error: invalid operand for instruction diff --git a/test/MC/PowerPC/ppc64-fixups.s b/test/MC/PowerPC/ppc64-fixups.s index 937e55758e8..9f23882e452 100644 --- a/test/MC/PowerPC/ppc64-fixups.s +++ b/test/MC/PowerPC/ppc64-fixups.s @@ -206,8 +206,6 @@ base: # CHECK-REL: 0x{{[0-9A-F]*[26AE]}} R_PPC64_GOT16_LO_DS target 0x0 ld 1, target@got@l(3) -# FIXME: @tls - # CHECK: addis 3, 2, target@tprel@ha # encoding: [0x3c,0x62,A,A] # CHECK-NEXT: # fixup A - offset: 2, value: target@tprel@ha, kind: fixup_ppc_half16 @@ -405,6 +403,11 @@ base: # CHECK-REL-NEXT: 0x{{[0-9A-F]*[048C]}} R_PPC64_REL24 __tls_get_addr 0x0 bl __tls_get_addr(target@tlsld) +# CHECK: add 3, 4, target@tls # encoding: [0x7c,0x64,0x6a,0x14] +# CHECK-NEXT: # fixup A - offset: 0, value: target@tls, kind: fixup_ppc_nofixup +# CHECK-REL: 0x{{[0-9A-F]*[048C]}} R_PPC64_TLS target 0x0 + add 3, 4, target@tls + # Data relocs # llvm-mc does not show any "encoding" string for data, so we just check the relocs