diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def @@ -99,6 +99,7 @@ #undef R_PPC64_REL24_NOTOC #undef R_PPC64_PCREL34 #undef R_PPC64_GOT_PCREL34 +#undef R_PPC64_GOT_TLSGD_PCREL34 #undef R_PPC64_IRELATIVE #undef R_PPC64_REL16 #undef R_PPC64_REL16_LO @@ -196,6 +197,7 @@ ELF_RELOC(R_PPC64_REL24_NOTOC, 116) ELF_RELOC(R_PPC64_PCREL34, 132) ELF_RELOC(R_PPC64_GOT_PCREL34, 133) +ELF_RELOC(R_PPC64_GOT_TLSGD_PCREL34, 148) ELF_RELOC(R_PPC64_IRELATIVE, 248) ELF_RELOC(R_PPC64_REL16, 249) ELF_RELOC(R_PPC64_REL16_LO, 250) diff --git a/llvm/include/llvm/MC/MCExpr.h b/llvm/include/llvm/MC/MCExpr.h --- a/llvm/include/llvm/MC/MCExpr.h +++ b/llvm/include/llvm/MC/MCExpr.h @@ -299,6 +299,7 @@ VK_PPC_GOT_TLSLD_HI, // symbol@got@tlsld@h VK_PPC_GOT_TLSLD_HA, // symbol@got@tlsld@ha VK_PPC_GOT_PCREL, // symbol@got@pcrel + VK_PPC_GOT_TLSGD_PCREL, // symbol@got@tlsgd@pcrel VK_PPC_TLSLD, // symbol@tlsld VK_PPC_LOCAL, // symbol@local VK_PPC_NOTOC, // symbol@notoc diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -319,6 +319,8 @@ case VK_PPC_GOT_TLSLD_HA: return "got@tlsld@ha"; case VK_PPC_GOT_PCREL: return "got@pcrel"; + case VK_PPC_GOT_TLSGD_PCREL: + return "got@tlsgd@pcrel"; case VK_PPC_TLSLD: return "tlsld"; case VK_PPC_LOCAL: return "local"; case VK_PPC_NOTOC: return "notoc"; @@ -349,121 +351,122 @@ MCSymbolRefExpr::VariantKind MCSymbolRefExpr::getVariantKindForName(StringRef Name) { return StringSwitch(Name.lower()) - .Case("dtprel", VK_DTPREL) - .Case("dtpoff", VK_DTPOFF) - .Case("got", VK_GOT) - .Case("gotoff", VK_GOTOFF) - .Case("gotrel", VK_GOTREL) - .Case("pcrel", VK_PCREL) - .Case("gotpcrel", VK_GOTPCREL) - .Case("gottpoff", VK_GOTTPOFF) - .Case("indntpoff", VK_INDNTPOFF) - .Case("ntpoff", VK_NTPOFF) - .Case("gotntpoff", VK_GOTNTPOFF) - .Case("plt", VK_PLT) - .Case("tlscall", VK_TLSCALL) - .Case("tlsdesc", VK_TLSDESC) - .Case("tlsgd", VK_TLSGD) - .Case("tlsld", VK_TLSLD) - .Case("tlsldm", VK_TLSLDM) - .Case("tpoff", VK_TPOFF) - .Case("tprel", VK_TPREL) - .Case("tlvp", VK_TLVP) - .Case("tlvppage", VK_TLVPPAGE) - .Case("tlvppageoff", VK_TLVPPAGEOFF) - .Case("page", VK_PAGE) - .Case("pageoff", VK_PAGEOFF) - .Case("gotpage", VK_GOTPAGE) - .Case("gotpageoff", VK_GOTPAGEOFF) - .Case("imgrel", VK_COFF_IMGREL32) - .Case("secrel32", VK_SECREL) - .Case("size", VK_SIZE) - .Case("abs8", VK_X86_ABS8) - .Case("l", VK_PPC_LO) - .Case("h", VK_PPC_HI) - .Case("ha", VK_PPC_HA) - .Case("high", VK_PPC_HIGH) - .Case("higha", VK_PPC_HIGHA) - .Case("higher", VK_PPC_HIGHER) - .Case("highera", VK_PPC_HIGHERA) - .Case("highest", VK_PPC_HIGHEST) - .Case("highesta", VK_PPC_HIGHESTA) - .Case("got@l", VK_PPC_GOT_LO) - .Case("got@h", VK_PPC_GOT_HI) - .Case("got@ha", VK_PPC_GOT_HA) - .Case("local", VK_PPC_LOCAL) - .Case("tocbase", VK_PPC_TOCBASE) - .Case("toc", VK_PPC_TOC) - .Case("toc@l", VK_PPC_TOC_LO) - .Case("toc@h", VK_PPC_TOC_HI) - .Case("toc@ha", VK_PPC_TOC_HA) - .Case("u", VK_PPC_U) - .Case("l", VK_PPC_L) - .Case("tls", VK_PPC_TLS) - .Case("dtpmod", VK_PPC_DTPMOD) - .Case("tprel@l", VK_PPC_TPREL_LO) - .Case("tprel@h", VK_PPC_TPREL_HI) - .Case("tprel@ha", VK_PPC_TPREL_HA) - .Case("tprel@high", VK_PPC_TPREL_HIGH) - .Case("tprel@higha", VK_PPC_TPREL_HIGHA) - .Case("tprel@higher", VK_PPC_TPREL_HIGHER) - .Case("tprel@highera", VK_PPC_TPREL_HIGHERA) - .Case("tprel@highest", VK_PPC_TPREL_HIGHEST) - .Case("tprel@highesta", VK_PPC_TPREL_HIGHESTA) - .Case("dtprel@l", VK_PPC_DTPREL_LO) - .Case("dtprel@h", VK_PPC_DTPREL_HI) - .Case("dtprel@ha", VK_PPC_DTPREL_HA) - .Case("dtprel@high", VK_PPC_DTPREL_HIGH) - .Case("dtprel@higha", VK_PPC_DTPREL_HIGHA) - .Case("dtprel@higher", VK_PPC_DTPREL_HIGHER) - .Case("dtprel@highera", VK_PPC_DTPREL_HIGHERA) - .Case("dtprel@highest", VK_PPC_DTPREL_HIGHEST) - .Case("dtprel@highesta", VK_PPC_DTPREL_HIGHESTA) - .Case("got@tprel", VK_PPC_GOT_TPREL) - .Case("got@tprel@l", VK_PPC_GOT_TPREL_LO) - .Case("got@tprel@h", VK_PPC_GOT_TPREL_HI) - .Case("got@tprel@ha", VK_PPC_GOT_TPREL_HA) - .Case("got@dtprel", VK_PPC_GOT_DTPREL) - .Case("got@dtprel@l", VK_PPC_GOT_DTPREL_LO) - .Case("got@dtprel@h", VK_PPC_GOT_DTPREL_HI) - .Case("got@dtprel@ha", VK_PPC_GOT_DTPREL_HA) - .Case("got@tlsgd", VK_PPC_GOT_TLSGD) - .Case("got@tlsgd@l", VK_PPC_GOT_TLSGD_LO) - .Case("got@tlsgd@h", VK_PPC_GOT_TLSGD_HI) - .Case("got@tlsgd@ha", VK_PPC_GOT_TLSGD_HA) - .Case("got@tlsld", VK_PPC_GOT_TLSLD) - .Case("got@tlsld@l", VK_PPC_GOT_TLSLD_LO) - .Case("got@tlsld@h", VK_PPC_GOT_TLSLD_HI) - .Case("got@tlsld@ha", VK_PPC_GOT_TLSLD_HA) - .Case("got@pcrel", VK_PPC_GOT_PCREL) - .Case("notoc", VK_PPC_NOTOC) - .Case("gdgot", VK_Hexagon_GD_GOT) - .Case("gdplt", VK_Hexagon_GD_PLT) - .Case("iegot", VK_Hexagon_IE_GOT) - .Case("ie", VK_Hexagon_IE) - .Case("ldgot", VK_Hexagon_LD_GOT) - .Case("ldplt", VK_Hexagon_LD_PLT) - .Case("none", VK_ARM_NONE) - .Case("got_prel", VK_ARM_GOT_PREL) - .Case("target1", VK_ARM_TARGET1) - .Case("target2", VK_ARM_TARGET2) - .Case("prel31", VK_ARM_PREL31) - .Case("sbrel", VK_ARM_SBREL) - .Case("tlsldo", VK_ARM_TLSLDO) - .Case("lo8", VK_AVR_LO8) - .Case("hi8", VK_AVR_HI8) - .Case("hlo8", VK_AVR_HLO8) - .Case("typeindex", VK_WASM_TYPEINDEX) - .Case("tbrel", VK_WASM_TBREL) - .Case("mbrel", VK_WASM_MBREL) - .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) - .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI) - .Case("rel32@lo", VK_AMDGPU_REL32_LO) - .Case("rel32@hi", VK_AMDGPU_REL32_HI) - .Case("rel64", VK_AMDGPU_REL64) - .Case("abs32@lo", VK_AMDGPU_ABS32_LO) - .Case("abs32@hi", VK_AMDGPU_ABS32_HI) - .Default(VK_Invalid); + .Case("dtprel", VK_DTPREL) + .Case("dtpoff", VK_DTPOFF) + .Case("got", VK_GOT) + .Case("gotoff", VK_GOTOFF) + .Case("gotrel", VK_GOTREL) + .Case("pcrel", VK_PCREL) + .Case("gotpcrel", VK_GOTPCREL) + .Case("gottpoff", VK_GOTTPOFF) + .Case("indntpoff", VK_INDNTPOFF) + .Case("ntpoff", VK_NTPOFF) + .Case("gotntpoff", VK_GOTNTPOFF) + .Case("plt", VK_PLT) + .Case("tlscall", VK_TLSCALL) + .Case("tlsdesc", VK_TLSDESC) + .Case("tlsgd", VK_TLSGD) + .Case("tlsld", VK_TLSLD) + .Case("tlsldm", VK_TLSLDM) + .Case("tpoff", VK_TPOFF) + .Case("tprel", VK_TPREL) + .Case("tlvp", VK_TLVP) + .Case("tlvppage", VK_TLVPPAGE) + .Case("tlvppageoff", VK_TLVPPAGEOFF) + .Case("page", VK_PAGE) + .Case("pageoff", VK_PAGEOFF) + .Case("gotpage", VK_GOTPAGE) + .Case("gotpageoff", VK_GOTPAGEOFF) + .Case("imgrel", VK_COFF_IMGREL32) + .Case("secrel32", VK_SECREL) + .Case("size", VK_SIZE) + .Case("abs8", VK_X86_ABS8) + .Case("l", VK_PPC_LO) + .Case("h", VK_PPC_HI) + .Case("ha", VK_PPC_HA) + .Case("high", VK_PPC_HIGH) + .Case("higha", VK_PPC_HIGHA) + .Case("higher", VK_PPC_HIGHER) + .Case("highera", VK_PPC_HIGHERA) + .Case("highest", VK_PPC_HIGHEST) + .Case("highesta", VK_PPC_HIGHESTA) + .Case("got@l", VK_PPC_GOT_LO) + .Case("got@h", VK_PPC_GOT_HI) + .Case("got@ha", VK_PPC_GOT_HA) + .Case("local", VK_PPC_LOCAL) + .Case("tocbase", VK_PPC_TOCBASE) + .Case("toc", VK_PPC_TOC) + .Case("toc@l", VK_PPC_TOC_LO) + .Case("toc@h", VK_PPC_TOC_HI) + .Case("toc@ha", VK_PPC_TOC_HA) + .Case("u", VK_PPC_U) + .Case("l", VK_PPC_L) + .Case("tls", VK_PPC_TLS) + .Case("dtpmod", VK_PPC_DTPMOD) + .Case("tprel@l", VK_PPC_TPREL_LO) + .Case("tprel@h", VK_PPC_TPREL_HI) + .Case("tprel@ha", VK_PPC_TPREL_HA) + .Case("tprel@high", VK_PPC_TPREL_HIGH) + .Case("tprel@higha", VK_PPC_TPREL_HIGHA) + .Case("tprel@higher", VK_PPC_TPREL_HIGHER) + .Case("tprel@highera", VK_PPC_TPREL_HIGHERA) + .Case("tprel@highest", VK_PPC_TPREL_HIGHEST) + .Case("tprel@highesta", VK_PPC_TPREL_HIGHESTA) + .Case("dtprel@l", VK_PPC_DTPREL_LO) + .Case("dtprel@h", VK_PPC_DTPREL_HI) + .Case("dtprel@ha", VK_PPC_DTPREL_HA) + .Case("dtprel@high", VK_PPC_DTPREL_HIGH) + .Case("dtprel@higha", VK_PPC_DTPREL_HIGHA) + .Case("dtprel@higher", VK_PPC_DTPREL_HIGHER) + .Case("dtprel@highera", VK_PPC_DTPREL_HIGHERA) + .Case("dtprel@highest", VK_PPC_DTPREL_HIGHEST) + .Case("dtprel@highesta", VK_PPC_DTPREL_HIGHESTA) + .Case("got@tprel", VK_PPC_GOT_TPREL) + .Case("got@tprel@l", VK_PPC_GOT_TPREL_LO) + .Case("got@tprel@h", VK_PPC_GOT_TPREL_HI) + .Case("got@tprel@ha", VK_PPC_GOT_TPREL_HA) + .Case("got@dtprel", VK_PPC_GOT_DTPREL) + .Case("got@dtprel@l", VK_PPC_GOT_DTPREL_LO) + .Case("got@dtprel@h", VK_PPC_GOT_DTPREL_HI) + .Case("got@dtprel@ha", VK_PPC_GOT_DTPREL_HA) + .Case("got@tlsgd", VK_PPC_GOT_TLSGD) + .Case("got@tlsgd@l", VK_PPC_GOT_TLSGD_LO) + .Case("got@tlsgd@h", VK_PPC_GOT_TLSGD_HI) + .Case("got@tlsgd@ha", VK_PPC_GOT_TLSGD_HA) + .Case("got@tlsld", VK_PPC_GOT_TLSLD) + .Case("got@tlsld@l", VK_PPC_GOT_TLSLD_LO) + .Case("got@tlsld@h", VK_PPC_GOT_TLSLD_HI) + .Case("got@tlsld@ha", VK_PPC_GOT_TLSLD_HA) + .Case("got@pcrel", VK_PPC_GOT_PCREL) + .Case("got@tlsgd@pcrel", VK_PPC_GOT_TLSGD_PCREL) + .Case("notoc", VK_PPC_NOTOC) + .Case("gdgot", VK_Hexagon_GD_GOT) + .Case("gdplt", VK_Hexagon_GD_PLT) + .Case("iegot", VK_Hexagon_IE_GOT) + .Case("ie", VK_Hexagon_IE) + .Case("ldgot", VK_Hexagon_LD_GOT) + .Case("ldplt", VK_Hexagon_LD_PLT) + .Case("none", VK_ARM_NONE) + .Case("got_prel", VK_ARM_GOT_PREL) + .Case("target1", VK_ARM_TARGET1) + .Case("target2", VK_ARM_TARGET2) + .Case("prel31", VK_ARM_PREL31) + .Case("sbrel", VK_ARM_SBREL) + .Case("tlsldo", VK_ARM_TLSLDO) + .Case("lo8", VK_AVR_LO8) + .Case("hi8", VK_AVR_HI8) + .Case("hlo8", VK_AVR_HLO8) + .Case("typeindex", VK_WASM_TYPEINDEX) + .Case("tbrel", VK_WASM_TBREL) + .Case("mbrel", VK_WASM_MBREL) + .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) + .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI) + .Case("rel32@lo", VK_AMDGPU_REL32_LO) + .Case("rel32@hi", VK_AMDGPU_REL32_HI) + .Case("rel64", VK_AMDGPU_REL64) + .Case("abs32@lo", VK_AMDGPU_ABS32_LO) + .Case("abs32@hi", VK_AMDGPU_ABS32_HI) + .Default(VK_Invalid); } void MCSymbolRefExpr::printVariantKind(raw_ostream &OS) const { diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp @@ -138,6 +138,9 @@ case MCSymbolRefExpr::VK_PPC_GOT_PCREL: Type = ELF::R_PPC64_GOT_PCREL34; break; + case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_PCREL: + Type = ELF::R_PPC64_GOT_TLSGD_PCREL34; + break; } break; case FK_Data_4: diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp @@ -513,10 +513,17 @@ RefExp = cast(Op.getExpr()); O << RefExp->getSymbol().getName(); + // The variant kind VK_PPC_NOTOC needs to be handled as a special case + // because we do not want the assembly to print out the @notoc at the + // end like __tls_get_addr(x@tlsgd)@notoc. Instead we want it to look + // like __tls_get_addr@notoc(x@tlsgd). + if (RefExp->getKind() == MCSymbolRefExpr::VK_PPC_NOTOC) + O << '@' << MCSymbolRefExpr::getVariantKindName(RefExp->getKind()); O << '('; printOperand(MI, OpNo+1, O); O << ')'; - if (RefExp->getKind() != MCSymbolRefExpr::VK_None) + if (RefExp->getKind() != MCSymbolRefExpr::VK_None && + RefExp->getKind() != MCSymbolRefExpr::VK_PPC_NOTOC) O << '@' << MCSymbolRefExpr::getVariantKindName(RefExp->getKind()); if (ConstExp != nullptr) O << '+' << ConstExp->getValue(); diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp @@ -44,11 +44,13 @@ SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(OpNo); - if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups, STI); + if (MO.isReg() || MO.isImm()) + return getMachineOpValue(MI, MO, Fixups, STI); // Add a fixup for the branch target. Fixups.push_back(MCFixup::create(0, MO.getExpr(), - ((MI.getOpcode() == PPC::BL8_NOTOC) + ((MI.getOpcode() == PPC::BL8_NOTOC || + MI.getOpcode() == PPC::BL8_NOTOC_TLS) ? (MCFixupKind)PPC::fixup_ppc_br24_notoc : (MCFixupKind)PPC::fixup_ppc_br24))); return 0; @@ -213,8 +215,10 @@ (void)SRE; // Currently these are the only valid PCRelative Relocations. assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL || - SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL) && - "VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL"); + SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL || + SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_TLSGD_PCREL) && + "VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL or " + "VK_PPC_GOT_TLSGD_PCREL"); // Generate the fixup for the relocation. Fixups.push_back( MCFixup::create(0, Expr, diff --git a/llvm/lib/Target/PowerPC/PPC.h b/llvm/lib/Target/PowerPC/PPC.h --- a/llvm/lib/Target/PowerPC/PPC.h +++ b/llvm/lib/Target/PowerPC/PPC.h @@ -107,6 +107,15 @@ /// produce the relocation @got@pcrel. Fixup is VK_PPC_GOT_PCREL. MO_GOT_FLAG = 8, + /// MO_TLSGD_FLAG - If this bit is set the symbol reference is relative to + /// TLS General Dynamic model. + MO_TLSGD_FLAG = 16, + + /// MO_GOT_TLSGD_PCREL_FLAG - A combintaion of flags, if these bits are set + /// they should produce the relocation @got@tlsgd@pcrel. + /// Fix up is VK_PPC_GOT_TLSGD_PCREL + MO_GOT_TLSGD_PCREL_FLAG = MO_PCREL_FLAG | MO_GOT_FLAG | MO_TLSGD_FLAG, + /// The next are not flags but distinct values. MO_ACCESS_MASK = 0xf00, diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -463,6 +463,13 @@ StringRef Name = "__tls_get_addr"; MCSymbol *TlsGetAddr = OutContext.getOrCreateSymbol(Name); MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None; + unsigned Opcode = PPC::BL8_NOP_TLS; + + assert(MI->getNumOperands() >= 3 && "Expecting at least 3 operands from MI"); + if (MI->getOperand(2).getTargetFlags() == PPCII::MO_GOT_TLSGD_PCREL_FLAG) { + Kind = MCSymbolRefExpr::VK_PPC_NOTOC; + Opcode = PPC::BL8_NOTOC_TLS; + } const Module *M = MF->getFunction().getParent(); assert(MI->getOperand(0).isReg() && @@ -490,10 +497,9 @@ MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymVar = MCSymbolRefExpr::create(MOSymbol, VK, OutContext); EmitToStreamer(*OutStreamer, - MCInstBuilder(Subtarget->isPPC64() ? - PPC::BL8_NOP_TLS : PPC::BL_TLS) - .addExpr(TlsRef) - .addExpr(SymVar)); + MCInstBuilder(Subtarget->isPPC64() ? Opcode : PPC::BL_TLS) + .addExpr(TlsRef) + .addExpr(SymVar)); } /// Map a machine operand for a TOC pseudo-machine instruction to its diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h --- a/llvm/lib/Target/PowerPC/PPCISelLowering.h +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h @@ -444,6 +444,11 @@ /// PLD. MAT_PCREL_ADDR, + /// TLS_DYNAMIC_MAT_PCREL_ADDR = Materialize a PC Relative address for + /// TLS global address when using dynamic access models. This can be done + /// through an add like PADDI. + TLS_DYNAMIC_MAT_PCREL_ADDR, + /// CHAIN = STBRX CHAIN, GPRC, Ptr, Type - This is a /// byte-swapping store instruction. It byte-swaps the low "Type" bits of /// the GPRC input, then stores it through Ptr. Type can be either i16 or diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -1572,6 +1572,8 @@ case PPCISD::LD_VSX_LH: return "PPCISD::LD_VSX_LH"; case PPCISD::FP_EXTEND_HALF: return "PPCISD::FP_EXTEND_HALF"; case PPCISD::MAT_PCREL_ADDR: return "PPCISD::MAT_PCREL_ADDR"; + case PPCISD::TLS_DYNAMIC_MAT_PCREL_ADDR: + return "PPCISD::TLS_DYNAMIC_MAT_PCREL_ADDR"; case PPCISD::LD_SPLAT: return "PPCISD::LD_SPLAT"; case PPCISD::FNMSUB: return "PPCISD::FNMSUB"; } @@ -3098,6 +3100,12 @@ } if (Model == TLSModel::GeneralDynamic) { + if (Subtarget.isUsingPCRelativeCalls()) { + SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, + PPCII::MO_GOT_TLSGD_PCREL_FLAG); + return DAG.getNode(PPCISD::TLS_DYNAMIC_MAT_PCREL_ADDR, dl, PtrVT, TGA); + } + SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, 0); SDValue GOTPtr; if (is64bit) { diff --git a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td --- a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td +++ b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td @@ -148,6 +148,9 @@ def BL8_NOTOC : IForm<18, 0, 1, (outs), (ins calltarget:$func), "bl $func", IIC_BrB, []>; + def BL8_NOTOC_TLS : IForm<18, 0, 1, (outs), + (ins tlscall:$func), + "bl $func", IIC_BrB, []>; } } let Uses = [CTR8, RM] in { diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp @@ -2270,7 +2270,9 @@ {MO_PLT, "ppc-plt"}, {MO_PIC_FLAG, "ppc-pic"}, {MO_PCREL_FLAG, "ppc-pcrel"}, - {MO_GOT_FLAG, "ppc-got"}}; + {MO_GOT_FLAG, "ppc-got"}, + {MO_TLSGD_FLAG, "ppc-tlsgd"}, + {MO_GOT_TLSGD_PCREL_FLAG, "ppc-got-tlsgd-pcrel"}}; return makeArrayRef(TargetFlags); } diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -326,6 +326,8 @@ // PC Relative Specific Nodes def PPCmatpcreladdr : SDNode<"PPCISD::MAT_PCREL_ADDR", SDTIntUnaryOp, []>; +def PPCtlsdynamatpcreladdr : SDNode<"PPCISD::TLS_DYNAMIC_MAT_PCREL_ADDR", + SDTIntUnaryOp, []>; //===----------------------------------------------------------------------===// // PowerPC specific transformation functions and pattern fragments. diff --git a/llvm/lib/Target/PowerPC/PPCInstrPrefix.td b/llvm/lib/Target/PowerPC/PPCInstrPrefix.td --- a/llvm/lib/Target/PowerPC/PPCInstrPrefix.td +++ b/llvm/lib/Target/PowerPC/PPCInstrPrefix.td @@ -694,6 +694,9 @@ // If the PPCmatpcreladdr node is not caught by any other pattern it should be // caught here and turned into a paddi instruction to materialize the address. def : Pat<(PPCmatpcreladdr pcreladdr:$addr), (PADDI8pc 0, $addr)>; + // PPCtlsdynamatpcreladdr node is used for TLS dynamic models to materialize + // tls global address with paddi instruction. + def : Pat<(PPCtlsdynamatpcreladdr pcreladdr:$addr), (PADDI8pc 0, $addr)>; } let Predicates = [PrefixInstrs] in { diff --git a/llvm/lib/Target/PowerPC/PPCMCInstLower.cpp b/llvm/lib/Target/PowerPC/PPCMCInstLower.cpp --- a/llvm/lib/Target/PowerPC/PPCMCInstLower.cpp +++ b/llvm/lib/Target/PowerPC/PPCMCInstLower.cpp @@ -84,6 +84,8 @@ RefKind = MCSymbolRefExpr::VK_PCREL; else if (MO.getTargetFlags() == (PPCII::MO_PCREL_FLAG | PPCII::MO_GOT_FLAG)) RefKind = MCSymbolRefExpr::VK_PPC_GOT_PCREL; + else if (MO.getTargetFlags() == PPCII::MO_GOT_TLSGD_PCREL_FLAG) + RefKind = MCSymbolRefExpr::VK_PPC_GOT_TLSGD_PCREL; const MachineInstr *MI = MO.getParent(); const MachineFunction *MF = MI->getMF(); diff --git a/llvm/lib/Target/PowerPC/PPCTLSDynamicCall.cpp b/llvm/lib/Target/PowerPC/PPCTLSDynamicCall.cpp --- a/llvm/lib/Target/PowerPC/PPCTLSDynamicCall.cpp +++ b/llvm/lib/Target/PowerPC/PPCTLSDynamicCall.cpp @@ -50,16 +50,17 @@ bool Changed = false; bool NeedFence = true; bool Is64Bit = MBB.getParent()->getSubtarget().isPPC64(); + bool IsTLSGDPCREL = false; for (MachineBasicBlock::iterator I = MBB.begin(), IE = MBB.end(); I != IE;) { MachineInstr &MI = *I; + IsTLSGDPCREL = isTLSGDPCREL(MI); if (MI.getOpcode() != PPC::ADDItlsgdLADDR && MI.getOpcode() != PPC::ADDItlsldLADDR && MI.getOpcode() != PPC::ADDItlsgdLADDR32 && - MI.getOpcode() != PPC::ADDItlsldLADDR32) { - + MI.getOpcode() != PPC::ADDItlsldLADDR32 && !IsTLSGDPCREL) { // Although we create ADJCALLSTACKDOWN and ADJCALLSTACKUP // as scheduling fences, we skip creating fences if we already // have existing ADJCALLSTACKDOWN/UP to avoid nesting, @@ -76,12 +77,16 @@ LLVM_DEBUG(dbgs() << "TLS Dynamic Call Fixup:\n " << MI); Register OutReg = MI.getOperand(0).getReg(); - Register InReg = MI.getOperand(1).getReg(); - DebugLoc DL = MI.getDebugLoc(); + Register InReg = PPC::NoRegister; Register GPR3 = Is64Bit ? PPC::X3 : PPC::R3; - unsigned Opc1, Opc2; - const Register OrigRegs[] = {OutReg, InReg, GPR3}; + SmallVector OrigRegs = {OutReg, GPR3}; + if (!IsTLSGDPCREL) { + InReg = MI.getOperand(1).getReg(); + OrigRegs.push_back(InReg); + } + DebugLoc DL = MI.getDebugLoc(); + unsigned Opc1, Opc2; switch (MI.getOpcode()) { default: llvm_unreachable("Opcode inconsistency error"); @@ -101,6 +106,10 @@ Opc1 = PPC::ADDItlsldL32; Opc2 = PPC::GETtlsldADDR32; break; + case PPC::PADDI8pc: + assert(IsTLSGDPCREL && "Expecting General Dynamic PCRel"); + Opc1 = PPC::PADDI8pc; + Opc2 = PPC::GETtlsADDR; } // We create ADJCALLSTACKUP and ADJCALLSTACKDOWN around _tls_get_addr @@ -113,9 +122,15 @@ BuildMI(MBB, I, DL, TII->get(PPC::ADJCALLSTACKDOWN)).addImm(0) .addImm(0); - // Expand into two ops built prior to the existing instruction. - MachineInstr *Addi = BuildMI(MBB, I, DL, TII->get(Opc1), GPR3) - .addReg(InReg); + MachineInstr *Addi; + if (IsTLSGDPCREL) { + Addi = BuildMI(MBB, I, DL, TII->get(Opc1), GPR3).addImm(0); + } else { + // Expand into two ops built prior to the existing instruction. + assert(InReg != PPC::NoRegister && "Operand must be a register"); + Addi = BuildMI(MBB, I, DL, TII->get(Opc1), GPR3).addReg(InReg); + } + Addi->addOperand(MI.getOperand(2)); // The ADDItls* instruction is the first instruction in the @@ -125,7 +140,10 @@ MachineInstr *Call = (BuildMI(MBB, I, DL, TII->get(Opc2), GPR3) .addReg(GPR3)); - Call->addOperand(MI.getOperand(3)); + if (IsTLSGDPCREL) + Call->addOperand(MI.getOperand(2)); + else + Call->addOperand(MI.getOperand(3)); if (NeedFence) BuildMI(MBB, I, DL, TII->get(PPC::ADJCALLSTACKUP)).addImm(0).addImm(0); @@ -150,6 +168,11 @@ } public: + bool isTLSGDPCREL(const MachineInstr &MI) { + return (MI.getOpcode() == PPC::PADDI8pc) && + (MI.getOperand(2).getTargetFlags() == + PPCII::MO_GOT_TLSGD_PCREL_FLAG); + } bool runOnMachineFunction(MachineFunction &MF) override { TII = MF.getSubtarget().getInstrInfo(); LIS = &getAnalysis(); diff --git a/llvm/test/CodeGen/PowerPC/pcrel-tls-general-dynamic.ll b/llvm/test/CodeGen/PowerPC/pcrel-tls-general-dynamic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/pcrel-tls-general-dynamic.ll @@ -0,0 +1,51 @@ +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: --relocation-model=pic -mcpu=pwr10 -ppc-asm-full-reg-names < %s | \ +; RUN: FileCheck %s --check-prefix=CHECK-S +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: --relocation-model=pic -mcpu=pwr10 -ppc-asm-full-reg-names \ +; RUN: --filetype=obj < %s | \ +; RUN: llvm-objdump --mcpu=pwr10 -dr - | FileCheck %s --check-prefix=CHECK-O + +; These test cases are to ensure that when using pc relative memory operations +; ABI correct code and relocations are produced for General Dynamic TLS Model. + +@x = external thread_local global i32, align 4 + +define nonnull i32* @GeneralDynamicAddressLoad() { + ; CHECK-S-LABEL: GeneralDynamicAddressLoad: + ; CHECK-S: paddi r3, 0, x@got@tlsgd@pcrel, 1 + ; CHECK-S-NEXT: bl __tls_get_addr@notoc(x@tlsgd) + ; CHECK-S-NEXT: addi r1, r1, 32 + ; CHECK-S-NEXT: ld r0, 16(r1) + ; CHECK-S-NEXT: mtlr r0 + ; CHECK-S-NEXT: blr + ; CHECK-O-LABEL: : + ; CHECK-O: c: 00 00 10 06 00 00 60 38 paddi 3, 0, 0, 1 + ; CHECK-O-NEXT: 000000000000000c: R_PPC64_GOT_TLSGD_PCREL34 x + ; CHECK-O-NEXT: 14: 01 00 00 48 bl 0x14 + ; CHECK-O-NEXT: 0000000000000014: R_PPC64_TLSGD x + ; CHECK-O-NEXT: 0000000000000014: R_PPC64_REL24_NOTOC __tls_get_addr + entry: + ret i32* @x +} + +define i32 @GeneralDynamicValueLoad() { + ; CHECK-S-LABEL: GeneralDynamicValueLoad: + ; CHECK-S: paddi r3, 0, x@got@tlsgd@pcrel, 1 + ; CHECK-S-NEXT: bl __tls_get_addr@notoc(x@tlsgd) + ; CHECK-S-NEXT: lwz r3, 0(r3) + ; CHECK-S-NEXT: addi r1, r1, 32 + ; CHECK-S-NEXT: ld r0, 16(r1) + ; CHECK-S-NEXT: mtlr r0 + ; CHECK-S-NEXT: blr + ; CHECK-O-LABEL: : + ; CHECK-O: 4c: 00 00 10 06 00 00 60 38 paddi 3, 0, 0, 1 + ; CHECK-O-NEXT: 000000000000004c: R_PPC64_GOT_TLSGD_PCREL34 x + ; CHECK-O-NEXT: 54: 01 00 00 48 bl 0x54 + ; CHECK-O-NEXT: 0000000000000054: R_PPC64_TLSGD x + ; CHECK-O-NEXT: 0000000000000054: R_PPC64_REL24_NOTOC __tls_get_addr + ; CHECK-O-NEXT: 58: 00 00 63 80 lwz 3, 0(3) + entry: + %0 = load i32, i32* @x, align 4 + ret i32 %0 +} diff --git a/llvm/test/MC/PowerPC/pcrel-tls-general-dynamic-address-load-reloc.s b/llvm/test/MC/PowerPC/pcrel-tls-general-dynamic-address-load-reloc.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/PowerPC/pcrel-tls-general-dynamic-address-load-reloc.s @@ -0,0 +1,40 @@ +# RUN: llvm-mc -triple=powerpc64le-unknown-unknown -filetype=obj %s 2>&1 | \ +# RUN: FileCheck %s -check-prefix=MC +# RUN: llvm-mc -triple=powerpc64le-unknown-unknown -filetype=obj %s | \ +# RUN: llvm-readobj -r | FileCheck %s -check-prefix=READOBJ + +# This test checks that on Power PC we can correctly convert @got@tlsgd@pcrel +# x@tlsgd and __tls_get_addr@notoc into R_PPC64_GOT_TLSGD_PCREL34, R_PPC64_TLSGD +# and R_PPC64_REL24_NOTOC for general dynamic relocations with address loaded + +# MC-NOT: error: invalid variant + +# READOBJ: 0xC R_PPC64_GOT_TLSGD_PCREL34 x 0x0 +# READOBJ-NEXT: 0x14 R_PPC64_TLSGD x 0x0 +# READOBJ-NEXT: 0x14 R_PPC64_REL24_NOTOC __tls_get_addr 0x0 + + .text + .abiversion 2 + .file "tls_general_dynamic_address_load.cpp" + .globl GeneralDynamicAddrLoad # -- Begin function GeneralDynamicAddrLoad + .p2align 4 + .type GeneralDynamicAddrLoad,@function +GeneralDynamicAddrLoad: # @GeneralDynamicAddrLoad +.Lfunc_begin0: +# %bb.0: # %entry + mflr 0 + std 0, 16(1) + stdu 1, -32(1) + paddi 3, 0, x@got@tlsgd@pcrel, 1 + bl __tls_get_addr@notoc(x@tlsgd) + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size GeneralDynamicAddrLoad, .Lfunc_end0-.Lfunc_begin0 + # -- End function + .section ".note.GNU-stack","",@progbits + .addrsig diff --git a/llvm/test/MC/PowerPC/pcrel-tls-general-dynamic-value-load-reloc.s b/llvm/test/MC/PowerPC/pcrel-tls-general-dynamic-value-load-reloc.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/PowerPC/pcrel-tls-general-dynamic-value-load-reloc.s @@ -0,0 +1,41 @@ +# RUN: llvm-mc -triple=powerpc64le-unknown-unknown -filetype=obj %s 2>&1 | \ +# RUN: FileCheck %s -check-prefix=MC +# RUN: llvm-mc -triple=powerpc64le-unknown-unknown -filetype=obj %s | \ +# RUN: llvm-readobj -r | FileCheck %s -check-prefix=READOBJ + +# This test checks that on Power PC we can correctly convert @got@tlsgd@pcrel +# x@tlsgd and __tls_get_addr@notoc into R_PPC64_GOT_TLSGD_PCREL34, R_PPC64_TLSGD +# and R_PPC64_REL24_NOTOC for general dynamic relocations with value loaded + +# MC-NOT: error: invalid variant + +# READOBJ: 0xC R_PPC64_GOT_TLSGD_PCREL34 x 0x0 +# READOBJ-NEXT: 0x14 R_PPC64_TLSGD x 0x0 +# READOBJ-NEXT: 0x14 R_PPC64_REL24_NOTOC __tls_get_addr 0x0 + + .text + .abiversion 2 + .file "tls_general_dynamic_value_load.cpp" + .globl GeneralDynamicValueLoad # -- Begin function GeneralDynamicValueLoad + .p2align 4 + .type GeneralDynamicValueLoad,@function +GeneralDynamicValueLoad: # @GeneralDynamicValueLoad +.Lfunc_begin0: +# %bb.0: # %entry + mflr 0 + std 0, 16(1) + stdu 1, -32(1) + paddi 3, 0, x@got@tlsgd@pcrel, 1 + bl __tls_get_addr@notoc(x@tlsgd) + lwz 3, 0(3) + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size GeneralDynamicValueLoad, .Lfunc_end0-.Lfunc_begin0 + # -- End function + .section ".note.GNU-stack","",@progbits + .addrsig