diff --git a/include/llvm/MC/MCExpr.h b/include/llvm/MC/MCExpr.h index 3ac5b399978..882cf7d181a 100644 --- a/include/llvm/MC/MCExpr.h +++ b/include/llvm/MC/MCExpr.h @@ -179,6 +179,8 @@ public: VK_PPC_GAS_LO16, // symbol@l VK_PPC_TPREL16_HA, // symbol@tprel@ha VK_PPC_TPREL16_LO, // symbol@tprel@l + VK_PPC_DTPREL16_HA, // symbol@dtprel@ha + VK_PPC_DTPREL16_LO, // symbol@dtprel@l VK_PPC_TOC16_HA, // symbol@toc@ha VK_PPC_TOC16_LO, // symbol@toc@l VK_PPC_GOT_TPREL16_DS, // symbol@got@tprel @@ -186,6 +188,9 @@ public: VK_PPC_GOT_TLSGD16_HA, // symbol@got@tlsgd@ha VK_PPC_GOT_TLSGD16_LO, // symbol@got@tlsgd@l VK_PPC_TLSGD, // symbol@tlsgd + VK_PPC_GOT_TLSLD16_HA, // symbol@got@tlsld@ha + VK_PPC_GOT_TLSLD16_LO, // symbol@got@tlsld@l + VK_PPC_TLSLD, // symbol@tlsld VK_Mips_GPREL, VK_Mips_GOT_CALL, diff --git a/include/llvm/Support/ELF.h b/include/llvm/Support/ELF.h index 44b3a8cec40..813d630b032 100644 --- a/include/llvm/Support/ELF.h +++ b/include/llvm/Support/ELF.h @@ -478,10 +478,15 @@ enum { R_PPC64_TOC16_DS = 63, R_PPC64_TOC16_LO_DS = 64, R_PPC64_TLS = 67, + R_PPC64_DTPREL16_LO = 75, + R_PPC64_DTPREL16_HA = 77, R_PPC64_GOT_TLSGD16_LO = 80, R_PPC64_GOT_TLSGD16_HA = 82, + R_PPC64_GOT_TLSLD16_LO = 84, + R_PPC64_GOT_TLSLD16_HA = 86, R_PPC64_GOT_TPREL16_DS = 87, - R_PPC64_TLSGD = 107 + R_PPC64_TLSGD = 107, + R_PPC64_TLSLD = 108 }; // ARM Specific e_flags diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index 7a0c317ac47..cbb8a8583dc 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -213,13 +213,18 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { case VK_PPC_GAS_LO16: return "l"; case VK_PPC_TPREL16_HA: return "tprel@ha"; case VK_PPC_TPREL16_LO: return "tprel@l"; + case VK_PPC_DTPREL16_HA: return "dtprel@ha"; + case VK_PPC_DTPREL16_LO: return "dtprel@l"; case VK_PPC_TOC16_HA: return "toc@ha"; case VK_PPC_TOC16_LO: return "toc@l"; case VK_PPC_GOT_TPREL16_DS: return "got@tprel"; case VK_PPC_TLS: return "tls"; case VK_PPC_GOT_TLSGD16_HA: return "got@tlsgd@ha"; case VK_PPC_GOT_TLSGD16_LO: return "got@tlsgd@l"; + case VK_PPC_GOT_TLSLD16_HA: return "got@tlsld@ha"; + case VK_PPC_GOT_TLSLD16_LO: return "got@tlsld@l"; case VK_PPC_TLSGD: return "tlsgd"; + case VK_PPC_TLSLD: return "tlsld"; case VK_Mips_GPREL: return "GPREL"; case VK_Mips_GOT_CALL: return "GOT_CALL"; case VK_Mips_GOT16: return "GOT16"; diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp index ed7b92c19fb..f9a1ebfd4ac 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp +++ b/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp @@ -32,7 +32,7 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { case FK_Data_8: case PPC::fixup_ppc_toc: case PPC::fixup_ppc_tlsreg: - case PPC::fixup_ppc_tlsgd: + case PPC::fixup_ppc_nofixup: return Value; case PPC::fixup_ppc_lo14: case PPC::fixup_ppc_toc16_ds: @@ -87,7 +87,7 @@ public: { "fixup_ppc_toc16", 16, 16, 0 }, { "fixup_ppc_toc16_ds", 16, 14, 0 }, { "fixup_ppc_tlsreg", 0, 0, 0 }, - { "fixup_ppc_tlsgd", 0, 0, 0 } + { "fixup_ppc_nofixup", 0, 0, 0 } }; if (Kind < FirstTargetFixupKind) diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp index 9e8d9c90bf8..b8945d64374 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp +++ b/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp @@ -79,6 +79,9 @@ unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target, case MCSymbolRefExpr::VK_PPC_TPREL16_HA: Type = ELF::R_PPC_TPREL16_HA; break; + case MCSymbolRefExpr::VK_PPC_DTPREL16_HA: + Type = ELF::R_PPC64_DTPREL16_HA; + break; case MCSymbolRefExpr::VK_None: Type = ELF::R_PPC_ADDR16_HA; break; @@ -88,6 +91,9 @@ unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target, case MCSymbolRefExpr::VK_PPC_GOT_TLSGD16_HA: Type = ELF::R_PPC64_GOT_TLSGD16_HA; break; + case MCSymbolRefExpr::VK_PPC_GOT_TLSLD16_HA: + Type = ELF::R_PPC64_GOT_TLSLD16_HA; + break; } break; case PPC::fixup_ppc_lo16: @@ -96,6 +102,9 @@ unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target, case MCSymbolRefExpr::VK_PPC_TPREL16_LO: Type = ELF::R_PPC_TPREL16_LO; break; + case MCSymbolRefExpr::VK_PPC_DTPREL16_LO: + Type = ELF::R_PPC64_DTPREL16_LO; + break; case MCSymbolRefExpr::VK_None: Type = ELF::R_PPC_ADDR16_LO; break; @@ -105,6 +114,9 @@ unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target, case MCSymbolRefExpr::VK_PPC_GOT_TLSGD16_LO: Type = ELF::R_PPC64_GOT_TLSGD16_LO; break; + case MCSymbolRefExpr::VK_PPC_GOT_TLSLD16_LO: + Type = ELF::R_PPC64_GOT_TLSLD16_LO; + break; } break; case PPC::fixup_ppc_lo14: @@ -133,8 +145,16 @@ unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target, case PPC::fixup_ppc_tlsreg: Type = ELF::R_PPC64_TLS; break; - case PPC::fixup_ppc_tlsgd: - Type = ELF::R_PPC64_TLSGD; + case PPC::fixup_ppc_nofixup: + switch (Modifier) { + default: llvm_unreachable("Unsupported Modifier"); + case MCSymbolRefExpr::VK_PPC_TLSGD: + Type = ELF::R_PPC64_TLSGD; + break; + case MCSymbolRefExpr::VK_PPC_TLSLD: + Type = ELF::R_PPC64_TLSLD; + break; + } break; case FK_Data_8: switch (Modifier) { diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h b/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h index ffa7aa7b57e..7917f7736ee 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h +++ b/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h @@ -48,9 +48,9 @@ enum Fixups { /// fixup_ppc_tlsreg - Insert thread-pointer register number. fixup_ppc_tlsreg, - /// fixup_ppc_tlsgd - Not a true fixup, but ties a symbol to a call - /// to __tls_get_addr for the TLS global dynamic model. - fixup_ppc_tlsgd, + /// 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. + fixup_ppc_nofixup, // Marker LastTargetFixupKind, diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp index 8be4de2c29a..71f317abc26 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp +++ b/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp @@ -83,11 +83,12 @@ public: SmallVectorImpl &Fixups) const { uint64_t Bits = getBinaryCodeForInstr(MI, Fixups); - // BL8_NOPELF and BLA8_NOP_ELF is both size of 8 bacause of the + // BL8_NOP_ELF, BLA8_NOP_ELF, etc., all have a size of 8 because of the // following 'nop'. unsigned Size = 4; // FIXME: Have Desc.getSize() return the correct value! unsigned Opcode = MI.getOpcode(); - if (Opcode == PPC::BL8_NOP_ELF || Opcode == PPC::BLA8_NOP_ELF) + if (Opcode == PPC::BL8_NOP_ELF || Opcode == PPC::BLA8_NOP_ELF || + Opcode == PPC::BL8_NOP_ELF_TLSGD || Opcode == PPC::BL8_NOP_ELF_TLSLD) Size = 8; // Output the constant in big endian byte order. @@ -122,13 +123,14 @@ getDirectBrEncoding(const MCInst &MI, unsigned OpNo, (MCFixupKind)PPC::fixup_ppc_br24)); // For special TLS calls, add another fixup for the symbol. Apparently - // BL8_NOP_ELF and BL8_NOP_ELF_TLSGD are sufficiently similar that TblGen - // will not generate a separate case for the latter, so this is the only - // way to get the extra fixup generated. - if (MI.getOpcode() == PPC::BL8_NOP_ELF_TLSGD) { + // BL8_NOP_ELF, BL8_NOP_ELF_TLSGD, and BL8_NOP_ELF_TLSLD are sufficiently + // similar that TblGen will not generate a separate case for the latter + // two, so this is the only way to get the extra fixup generated. + unsigned Opcode = MI.getOpcode(); + if (Opcode == PPC::BL8_NOP_ELF_TLSGD || Opcode == PPC::BL8_NOP_ELF_TLSLD) { const MCOperand &MO2 = MI.getOperand(OpNo+1); Fixups.push_back(MCFixup::Create(0, MO2.getExpr(), - (MCFixupKind)PPC::fixup_ppc_tlsgd)); + (MCFixupKind)PPC::fixup_ppc_nofixup)); } return 0; } diff --git a/lib/Target/PowerPC/PPCAsmPrinter.cpp b/lib/Target/PowerPC/PPCAsmPrinter.cpp index 25428a097f2..0ebf8912d05 100644 --- a/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -582,6 +582,90 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { .addExpr(SymVar)); return; } + case PPC::ADDIStlsldHA: { + // Transform: %Xd = ADDIStlsldHA %X2, + // Into: %Xd = ADDIS8 %X2, sym@got@tlsld@ha + assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); + const MachineOperand &MO = MI->getOperand(2); + const GlobalValue *GValue = MO.getGlobal(); + MCSymbol *MOSymbol = Mang->getSymbol(GValue); + const MCExpr *SymGotTlsLD = + MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TLSLD16_HA, + OutContext); + OutStreamer.EmitInstruction(MCInstBuilder(PPC::ADDIS8) + .addReg(MI->getOperand(0).getReg()) + .addReg(PPC::X2) + .addExpr(SymGotTlsLD)); + return; + } + case PPC::ADDItlsldL: { + // Transform: %Xd = ADDItlsldL %Xs, + // Into: %Xd = ADDI8L %Xs, sym@got@tlsld@l + assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); + const MachineOperand &MO = MI->getOperand(2); + const GlobalValue *GValue = MO.getGlobal(); + MCSymbol *MOSymbol = Mang->getSymbol(GValue); + const MCExpr *SymGotTlsLD = + MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TLSLD16_LO, + OutContext); + OutStreamer.EmitInstruction(MCInstBuilder(PPC::ADDI8L) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addExpr(SymGotTlsLD)); + return; + } + case PPC::GETtlsldADDR: { + // Transform: %X3 = GETtlsldADDR %X3, + // Into: BL8_NOP_ELF_TLSLD __tls_get_addr(sym@tlsld) + assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); + + StringRef Name = "__tls_get_addr"; + MCSymbol *TlsGetAddr = OutContext.GetOrCreateSymbol(Name); + const MCSymbolRefExpr *TlsRef = + MCSymbolRefExpr::Create(TlsGetAddr, MCSymbolRefExpr::VK_None, OutContext); + const MachineOperand &MO = MI->getOperand(2); + const GlobalValue *GValue = MO.getGlobal(); + MCSymbol *MOSymbol = Mang->getSymbol(GValue); + const MCExpr *SymVar = + MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_TLSLD, + OutContext); + OutStreamer.EmitInstruction(MCInstBuilder(PPC::BL8_NOP_ELF_TLSLD) + .addExpr(TlsRef) + .addExpr(SymVar)); + return; + } + case PPC::ADDISdtprelHA: { + // Transform: %Xd = ADDISdtprelHA %X3, + // Into: %Xd = ADDIS8 %X3, sym@dtprel@ha + assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); + const MachineOperand &MO = MI->getOperand(2); + const GlobalValue *GValue = MO.getGlobal(); + MCSymbol *MOSymbol = Mang->getSymbol(GValue); + const MCExpr *SymDtprel = + MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_DTPREL16_HA, + OutContext); + OutStreamer.EmitInstruction(MCInstBuilder(PPC::ADDIS8) + .addReg(MI->getOperand(0).getReg()) + .addReg(PPC::X3) + .addExpr(SymDtprel)); + return; + } + case PPC::ADDIdtprelL: { + // Transform: %Xd = ADDIdtprelL %Xs, + // Into: %Xd = ADDI8L %Xs, sym@dtprel@l + assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); + const MachineOperand &MO = MI->getOperand(2); + const GlobalValue *GValue = MO.getGlobal(); + MCSymbol *MOSymbol = Mang->getSymbol(GValue); + const MCExpr *SymDtprel = + MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_DTPREL16_LO, + OutContext); + OutStreamer.EmitInstruction(MCInstBuilder(PPC::ADDI8L) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addExpr(SymDtprel)); + return; + } case PPC::MFCRpseud: case PPC::MFCR8pseud: // Transform: %R3 = MFCRpseud %CR7 diff --git a/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/lib/Target/PowerPC/PPCISelDAGToDAG.cpp index 6a98c3fe8f2..806c4449270 100644 --- a/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -1332,6 +1332,32 @@ SDNode *PPCDAGToDAGISel::Select(SDNode *N) { return CurDAG->getMachineNode(PPC::GETtlsADDR, dl, MVT::i64, N->getOperand(0), N->getOperand(1)); } + case PPCISD::ADDIS_TLSLD_HA: { + assert (PPCSubTarget.isPPC64() && "Only supported for 64-bit ABI"); + return CurDAG->getMachineNode(PPC::ADDIStlsldHA, dl, MVT::i64, + N->getOperand(0), N->getOperand(1)); + } + case PPCISD::ADDI_TLSLD_L: { + assert (PPCSubTarget.isPPC64() && "Only supported for 64-bit ABI"); + return CurDAG->getMachineNode(PPC::ADDItlsldL, dl, MVT::i64, + N->getOperand(0), N->getOperand(1)); + } + case PPCISD::GET_TLSLD_ADDR: { + assert (PPCSubTarget.isPPC64() && "Only supported for 64-bit ABI"); + return CurDAG->getMachineNode(PPC::GETtlsldADDR, dl, MVT::i64, + N->getOperand(0), N->getOperand(1)); + } + case PPCISD::ADDIS_DTPREL_HA: { + assert (PPCSubTarget.isPPC64() && "Only supported for 64-bit ABI"); + return CurDAG->getMachineNode(PPC::ADDISdtprelHA, dl, MVT::i64, + N->getOperand(0), N->getOperand(1), + N->getOperand(2)); + } + case PPCISD::ADDI_DTPREL_L: { + assert (PPCSubTarget.isPPC64() && "Only supported for 64-bit ABI"); + return CurDAG->getMachineNode(PPC::ADDIdtprelL, dl, MVT::i64, + N->getOperand(0), N->getOperand(1)); + } } return SelectCode(N); diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index 1402718f71d..68f1bc6eaea 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -583,6 +583,11 @@ const char *PPCTargetLowering::getTargetNodeName(unsigned Opcode) const { case PPCISD::ADDIS_TLSGD_HA: return "PPCISD::ADDIS_TLSGD_HA"; case PPCISD::ADDI_TLSGD_L: return "PPCISD::ADDI_TLSGD_L"; case PPCISD::GET_TLS_ADDR: return "PPCISD::GET_TLS_ADDR"; + case PPCISD::ADDIS_TLSLD_HA: return "PPCISD::ADDIS_TLSLD_HA"; + case PPCISD::ADDI_TLSLD_L: return "PPCISD::ADDI_TLSLD_L"; + case PPCISD::GET_TLSLD_ADDR: return "PPCISD::GET_TLSLD_ADDR"; + case PPCISD::ADDIS_DTPREL_HA: return "PPCISD::ADDIS_DTPREL_HA"; + case PPCISD::ADDI_DTPREL_L: return "PPCISD::ADDI_DTPREL_L"; } } @@ -1373,14 +1378,39 @@ SDValue PPCTargetLowering::LowerGlobalTLSAddress(SDValue Op, SDValue ParmReg = DAG.getRegister(PPC::X3, MVT::i64); SDValue TLSAddr = DAG.getNode(PPCISD::GET_TLS_ADDR, dl, PtrVT, ParmReg, TGA); - // The call to GET_TLS_ADDR really is in X3 already, but - // some hacks are needed here to tie everything together. - // The extra copies dissolve during subsequent transforms. + // The return value from GET_TLS_ADDR really is in X3 already, but + // some hacks are needed here to tie everything together. The extra + // copies dissolve during subsequent transforms. Chain = DAG.getCopyToReg(Chain, dl, PPC::X3, TLSAddr); return DAG.getCopyFromReg(Chain, dl, PPC::X3, PtrVT); } - llvm_unreachable("local-dynamic TLS mode is not yet supported"); + if (Model == TLSModel::LocalDynamic) { + SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, 0); + SDValue GOTReg = DAG.getRegister(PPC::X2, MVT::i64); + SDValue GOTEntryHi = DAG.getNode(PPCISD::ADDIS_TLSLD_HA, dl, PtrVT, + GOTReg, TGA); + SDValue GOTEntry = DAG.getNode(PPCISD::ADDI_TLSLD_L, dl, PtrVT, + GOTEntryHi, TGA); + + // We need a chain node, and don't have one handy. The underlying + // call has no side effects, so using the function entry node + // suffices. + SDValue Chain = DAG.getEntryNode(); + Chain = DAG.getCopyToReg(Chain, dl, PPC::X3, GOTEntry); + SDValue ParmReg = DAG.getRegister(PPC::X3, MVT::i64); + SDValue TLSAddr = DAG.getNode(PPCISD::GET_TLSLD_ADDR, dl, + PtrVT, ParmReg, TGA); + // The return value from GET_TLSLD_ADDR really is in X3 already, but + // some hacks are needed here to tie everything together. The extra + // copies dissolve during subsequent transforms. + Chain = DAG.getCopyToReg(Chain, dl, PPC::X3, TLSAddr); + SDValue DtvOffsetHi = DAG.getNode(PPCISD::ADDIS_DTPREL_HA, dl, PtrVT, + ParmReg, TGA, Chain); + return DAG.getNode(PPCISD::ADDI_DTPREL_L, dl, PtrVT, DtvOffsetHi, TGA); + } + + llvm_unreachable("Unknown TLS model!"); } SDValue PPCTargetLowering::LowerGlobalAddress(SDValue Op, diff --git a/lib/Target/PowerPC/PPCISelLowering.h b/lib/Target/PowerPC/PPCISelLowering.h index 4b44dbcef80..f36fbfd6ef1 100644 --- a/lib/Target/PowerPC/PPCISelLowering.h +++ b/lib/Target/PowerPC/PPCISelLowering.h @@ -206,6 +206,32 @@ namespace llvm { /// model, produces a call to __tls_get_addr(sym@tlsgd). GET_TLS_ADDR, + /// G8RC = ADDIS_TLSLD_HA %X2, Symbol - For the local-dynamic TLS + /// model, produces an ADDIS8 instruction that adds the GOT base + /// register to sym@got@tlsld@ha. + ADDIS_TLSLD_HA, + + /// G8RC = ADDI_TLSLD_L G8RReg, Symbol - For the local-dynamic TLS + /// model, produces an ADDI8 instruction that adds G8RReg to + /// sym@got@tlsld@l. + ADDI_TLSLD_L, + + /// G8RC = GET_TLSLD_ADDR %X3, Symbol - For the local-dynamic TLS + /// model, produces a call to __tls_get_addr(sym@tlsld). + GET_TLSLD_ADDR, + + /// G8RC = ADDIS_DTPREL_HA %X3, Symbol, Chain - For the + /// local-dynamic TLS model, produces an ADDIS8 instruction + /// that adds X3 to sym@dtprel@ha. The Chain operand is needed + /// to tie this in place following a copy to %X3 from the result + /// of a GET_TLSLD_ADDR. + ADDIS_DTPREL_HA, + + /// G8RC = ADDI_DTPREL_L G8RReg, Symbol - For the local-dynamic TLS + /// model, produces an ADDI8 instruction that adds G8RReg to + /// sym@got@dtprel@l. + ADDI_DTPREL_L, + /// STD_32 - This is the STD instruction for use with "32-bit" registers. STD_32 = ISD::FIRST_TARGET_MEMORY_OPCODE, diff --git a/lib/Target/PowerPC/PPCInstr64Bit.td b/lib/Target/PowerPC/PPCInstr64Bit.td index 3b8e9539916..bc66d5c0a06 100644 --- a/lib/Target/PowerPC/PPCInstr64Bit.td +++ b/lib/Target/PowerPC/PPCInstr64Bit.td @@ -116,6 +116,11 @@ let isCall = 1, PPC970_Unit = 7, Defs = [LR8] in { (outs), (ins calltarget:$func, tlsgd:$sym), "bl $func($sym)\n\tnop", BrB, []>; + let isCodeGenOnly = 1 in + def BL8_NOP_ELF_TLSLD : IForm_and_DForm_4_zero<18, 0, 1, 24, + (outs), (ins calltarget:$func, tlsgd:$sym), + "bl $func($sym)\n\tnop", BrB, []>; + def BLA8_ELF : IForm<18, 1, 1, (outs), (ins aaddr:$func), "bla $func", BrB, [(PPCcall_SVR4 (i64 imm:$func))]>; @@ -737,6 +742,31 @@ def GETtlsADDR : Pseudo<(outs G8RC:$rD), (ins G8RC:$reg, tlsgd:$sym), [(set G8RC:$rD, (PPCgetTlsAddr G8RC:$reg, tglobaladdr:$sym))]>, isPPC64; +def ADDIStlsldHA: Pseudo<(outs G8RC:$rD), (ins G8RC:$reg, symbolHi64:$disp), + "#ADDIStlsldHA", + [(set G8RC:$rD, + (PPCaddisTlsldHA G8RC:$reg, tglobaladdr:$disp))]>, + isPPC64; +def ADDItlsldL : Pseudo<(outs G8RC:$rD), (ins G8RC:$reg, symbolLo64:$disp), + "#ADDItlsldL", + [(set G8RC:$rD, + (PPCaddiTlsldL G8RC:$reg, tglobaladdr:$disp))]>, + isPPC64; +def GETtlsldADDR : Pseudo<(outs G8RC:$rD), (ins G8RC:$reg, tlsgd:$sym), + "#GETtlsldADDR", + [(set G8RC:$rD, + (PPCgetTlsldAddr G8RC:$reg, tglobaladdr:$sym))]>, + isPPC64; +def ADDISdtprelHA: Pseudo<(outs G8RC:$rD), (ins G8RC:$reg, symbolHi64:$disp), + "#ADDISdtprelHA", + [(set G8RC:$rD, + (PPCaddisDtprelHA G8RC:$reg, tglobaladdr:$disp))]>, + isPPC64; +def ADDIdtprelL : Pseudo<(outs G8RC:$rD), (ins G8RC:$reg, symbolLo64:$disp), + "#ADDIdtprelL", + [(set G8RC:$rD, + (PPCaddiDtprelL G8RC:$reg, tglobaladdr:$disp))]>, + isPPC64; let PPC970_Unit = 2 in { // Truncating stores. diff --git a/lib/Target/PowerPC/PPCInstrInfo.td b/lib/Target/PowerPC/PPCInstrInfo.td index 61b7ef33498..13153e02428 100644 --- a/lib/Target/PowerPC/PPCInstrInfo.td +++ b/lib/Target/PowerPC/PPCInstrInfo.td @@ -96,6 +96,12 @@ def PPCaddTls : SDNode<"PPCISD::ADD_TLS", SDTIntBinOp, []>; def PPCaddisTlsgdHA : SDNode<"PPCISD::ADDIS_TLSGD_HA", SDTIntBinOp>; def PPCaddiTlsgdL : SDNode<"PPCISD::ADDI_TLSGD_L", SDTIntBinOp>; def PPCgetTlsAddr : SDNode<"PPCISD::GET_TLS_ADDR", SDTIntBinOp>; +def PPCaddisTlsldHA : SDNode<"PPCISD::ADDIS_TLSLD_HA", SDTIntBinOp>; +def PPCaddiTlsldL : SDNode<"PPCISD::ADDI_TLSLD_L", SDTIntBinOp>; +def PPCgetTlsldAddr : SDNode<"PPCISD::GET_TLSLD_ADDR", SDTIntBinOp>; +def PPCaddisDtprelHA : SDNode<"PPCISD::ADDIS_DTPREL_HA", SDTIntBinOp, + [SDNPHasChain]>; +def PPCaddiDtprelL : SDNode<"PPCISD::ADDI_DTPREL_L", SDTIntBinOp>; def PPCvperm : SDNode<"PPCISD::VPERM", SDT_PPCvperm, []>; diff --git a/test/CodeGen/PowerPC/tls-ld-obj.ll b/test/CodeGen/PowerPC/tls-ld-obj.ll new file mode 100644 index 00000000000..4b9f340fdda --- /dev/null +++ b/test/CodeGen/PowerPC/tls-ld-obj.ll @@ -0,0 +1,49 @@ +; RUN: llc -mcpu=pwr7 -O0 -filetype=obj -relocation-model=pic %s -o - | \ +; RUN: elf-dump --dump-section-data | FileCheck %s + +; Test correct relocation generation for thread-local storage using +; the local dynamic model. + +target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-v128:128:128-n32:64" +target triple = "powerpc64-unknown-linux-gnu" + +@a = hidden thread_local global i32 0, align 4 + +define signext i32 @main() nounwind { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval + %0 = load i32* @a, align 4 + ret i32 %0 +} + +; Verify generation of R_PPC64_GOT_TLSGD16_HA, R_PPC64_GOT_TLSGD16_LO, +; and R_PPC64_TLSGD for accessing external variable a, and R_PPC64_REL24 +; for the call to __tls_get_addr. +; +; CHECK: '.rela.text' +; CHECK: Relocation 0 +; CHECK-NEXT: 'r_offset' +; CHECK-NEXT: 'r_sym', 0x[[SYM1:[0-9a-f]+]] +; CHECK-NEXT: 'r_type', 0x00000056 +; CHECK: Relocation 1 +; CHECK-NEXT: 'r_offset' +; CHECK-NEXT: 'r_sym', 0x[[SYM1]] +; CHECK-NEXT: 'r_type', 0x00000054 +; CHECK: Relocation 2 +; CHECK-NEXT: 'r_offset' +; CHECK-NEXT: 'r_sym', 0x[[SYM1]] +; CHECK-NEXT: 'r_type', 0x0000006c +; CHECK: Relocation 3 +; CHECK-NEXT: 'r_offset' +; CHECK-NEXT: 'r_sym', 0x{{[0-9a-f]+}} +; CHECK-NEXT: 'r_type', 0x0000000a +; CHECK: Relocation 4 +; CHECK-NEXT: 'r_offset' +; CHECK-NEXT: 'r_sym', 0x[[SYM1]] +; CHECK-NEXT: 'r_type', 0x0000004d +; CHECK: Relocation 5 +; CHECK-NEXT: 'r_offset' +; CHECK-NEXT: 'r_sym', 0x[[SYM1]] +; CHECK-NEXT: 'r_type', 0x0000004b + diff --git a/test/CodeGen/PowerPC/tls-ld.ll b/test/CodeGen/PowerPC/tls-ld.ll new file mode 100644 index 00000000000..1ebc6129e2a --- /dev/null +++ b/test/CodeGen/PowerPC/tls-ld.ll @@ -0,0 +1,24 @@ +; RUN: llc -mcpu=pwr7 -O0 -relocation-model=pic < %s | FileCheck %s + +; Test correct assembly code generation for thread-local storage using +; the local dynamic model. + +target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-v128:128:128-n32:64" +target triple = "powerpc64-unknown-linux-gnu" + +@a = hidden thread_local global i32 0, align 4 + +define signext i32 @main() nounwind { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval + %0 = load i32* @a, align 4 + ret i32 %0 +} + +; CHECK: addis [[REG:[0-9]+]], 2, a@got@tlsld@ha +; CHECK-NEXT: addi 3, [[REG]], a@got@tlsld@l +; CHECK-NEXT: bl __tls_get_addr(a@tlsld) +; CHECK-NEXT: nop +; CHECK-NEXT: addis [[REG2:[0-9]+]], 3, a@dtprel@ha +; CHECK-NEXT: addi {{[0-9]+}}, [[REG2]], a@dtprel@l