[PowerPC][Future] More support for PCRel addressing for global values
authorStefan Pintilie <stefanp@ca.ibm.com>
Fri, 17 Apr 2020 16:05:02 +0000 (11:05 -0500)
committerKamau Bridgeman <kamau.bridgeman@ibm.com>
Fri, 17 Apr 2020 16:06:13 +0000 (11:06 -0500)
Add initial support for PC Relative addressing for global values that
require GOT indirect addressing. This patch adds PCRelative support for
global addresses that may not be known at link time and may require
access through the GOT.

Differential Revision: https://reviews.llvm.org/D76064

llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def
llvm/include/llvm/MC/MCExpr.h
llvm/lib/MC/MCExpr.cpp
llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
llvm/lib/Target/PowerPC/PPC.h
llvm/lib/Target/PowerPC/PPCISelLowering.cpp
llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
llvm/lib/Target/PowerPC/PPCMCInstLower.cpp
llvm/test/CodeGen/PowerPC/pcrel-call-linkage-with-calls.ll
llvm/test/CodeGen/PowerPC/pcrel-got-indirect.ll [new file with mode: 0644]

index eb88c53..e28c9ca 100644 (file)
@@ -98,6 +98,7 @@
 #undef R_PPC64_DTPREL16_HIGHA
 #undef R_PPC64_REL24_NOTOC
 #undef R_PPC64_PCREL34
+#undef R_PPC64_GOT_PCREL34
 #undef R_PPC64_IRELATIVE
 #undef R_PPC64_REL16
 #undef R_PPC64_REL16_LO
@@ -194,6 +195,7 @@ ELF_RELOC(R_PPC64_DTPREL16_HIGH,        114)
 ELF_RELOC(R_PPC64_DTPREL16_HIGHA,       115)
 ELF_RELOC(R_PPC64_REL24_NOTOC,          116)
 ELF_RELOC(R_PPC64_PCREL34,              132)
+ELF_RELOC(R_PPC64_GOT_PCREL34,          133)
 ELF_RELOC(R_PPC64_IRELATIVE,            248)
 ELF_RELOC(R_PPC64_REL16,                249)
 ELF_RELOC(R_PPC64_REL16_LO,             250)
index d1ffef7..776e116 100644 (file)
@@ -210,9 +210,9 @@ public:
     VK_TLSLDM,
     VK_TPOFF,
     VK_DTPOFF,
-    VK_TLSCALL,   // symbol(tlscall)
-    VK_TLSDESC,   // symbol(tlsdesc)
-    VK_TLVP,      // Mach-O thread local variable relocations
+    VK_TLSCALL, // symbol(tlscall)
+    VK_TLSDESC, // symbol(tlsdesc)
+    VK_TLVP,    // Mach-O thread local variable relocations
     VK_TLVPPAGE,
     VK_TLVPPAGEOFF,
     VK_PAGE,
@@ -220,8 +220,8 @@ public:
     VK_GOTPAGE,
     VK_GOTPAGEOFF,
     VK_SECREL,
-    VK_SIZE,      // symbol@SIZE
-    VK_WEAKREF,   // The link between the symbols in .weakref foo, bar
+    VK_SIZE,    // symbol@SIZE
+    VK_WEAKREF, // The link between the symbols in .weakref foo, bar
 
     VK_X86_ABS8,
 
@@ -230,8 +230,8 @@ public:
     VK_ARM_TARGET1,
     VK_ARM_TARGET2,
     VK_ARM_PREL31,
-    VK_ARM_SBREL,          // symbol(sbrel)
-    VK_ARM_TLSLDO,         // symbol(tlsldo)
+    VK_ARM_SBREL,  // symbol(sbrel)
+    VK_ARM_TLSLDO, // symbol(tlsldo)
     VK_ARM_TLSDESCSEQ,
 
     VK_AVR_NONE,
@@ -242,65 +242,66 @@ public:
     VK_AVR_DIFF16,
     VK_AVR_DIFF32,
 
-    VK_PPC_LO,             // symbol@l
-    VK_PPC_HI,             // symbol@h
-    VK_PPC_HA,             // symbol@ha
-    VK_PPC_HIGH,           // symbol@high
-    VK_PPC_HIGHA,          // symbol@higha
-    VK_PPC_HIGHER,         // symbol@higher
-    VK_PPC_HIGHERA,        // symbol@highera
-    VK_PPC_HIGHEST,        // symbol@highest
-    VK_PPC_HIGHESTA,       // symbol@highesta
-    VK_PPC_GOT_LO,         // symbol@got@l
-    VK_PPC_GOT_HI,         // symbol@got@h
-    VK_PPC_GOT_HA,         // symbol@got@ha
-    VK_PPC_TOCBASE,        // symbol@tocbase
-    VK_PPC_TOC,            // symbol@toc
-    VK_PPC_TOC_LO,         // symbol@toc@l
-    VK_PPC_TOC_HI,         // symbol@toc@h
-    VK_PPC_TOC_HA,         // symbol@toc@ha
-    VK_PPC_U,              // symbol@u
-    VK_PPC_L,              // symbol@l
-    VK_PPC_DTPMOD,         // symbol@dtpmod
-    VK_PPC_TPREL_LO,       // symbol@tprel@l
-    VK_PPC_TPREL_HI,       // symbol@tprel@h
-    VK_PPC_TPREL_HA,       // symbol@tprel@ha
-    VK_PPC_TPREL_HIGH,     // symbol@tprel@high
-    VK_PPC_TPREL_HIGHA,    // symbol@tprel@higha
-    VK_PPC_TPREL_HIGHER,   // symbol@tprel@higher
-    VK_PPC_TPREL_HIGHERA,  // symbol@tprel@highera
-    VK_PPC_TPREL_HIGHEST,  // symbol@tprel@highest
-    VK_PPC_TPREL_HIGHESTA, // symbol@tprel@highesta
-    VK_PPC_DTPREL_LO,      // symbol@dtprel@l
-    VK_PPC_DTPREL_HI,      // symbol@dtprel@h
-    VK_PPC_DTPREL_HA,      // symbol@dtprel@ha
-    VK_PPC_DTPREL_HIGH,    // symbol@dtprel@high
-    VK_PPC_DTPREL_HIGHA,   // symbol@dtprel@higha
-    VK_PPC_DTPREL_HIGHER,  // symbol@dtprel@higher
-    VK_PPC_DTPREL_HIGHERA, // symbol@dtprel@highera
-    VK_PPC_DTPREL_HIGHEST, // symbol@dtprel@highest
-    VK_PPC_DTPREL_HIGHESTA,// symbol@dtprel@highesta
-    VK_PPC_GOT_TPREL,      // symbol@got@tprel
-    VK_PPC_GOT_TPREL_LO,   // symbol@got@tprel@l
-    VK_PPC_GOT_TPREL_HI,   // symbol@got@tprel@h
-    VK_PPC_GOT_TPREL_HA,   // symbol@got@tprel@ha
-    VK_PPC_GOT_DTPREL,     // symbol@got@dtprel
-    VK_PPC_GOT_DTPREL_LO,  // symbol@got@dtprel@l
-    VK_PPC_GOT_DTPREL_HI,  // symbol@got@dtprel@h
-    VK_PPC_GOT_DTPREL_HA,  // symbol@got@dtprel@ha
-    VK_PPC_TLS,            // symbol@tls
-    VK_PPC_GOT_TLSGD,      // symbol@got@tlsgd
-    VK_PPC_GOT_TLSGD_LO,   // symbol@got@tlsgd@l
-    VK_PPC_GOT_TLSGD_HI,   // symbol@got@tlsgd@h
-    VK_PPC_GOT_TLSGD_HA,   // symbol@got@tlsgd@ha
-    VK_PPC_TLSGD,          // symbol@tlsgd
-    VK_PPC_GOT_TLSLD,      // symbol@got@tlsld
-    VK_PPC_GOT_TLSLD_LO,   // symbol@got@tlsld@l
-    VK_PPC_GOT_TLSLD_HI,   // symbol@got@tlsld@h
-    VK_PPC_GOT_TLSLD_HA,   // symbol@got@tlsld@ha
-    VK_PPC_TLSLD,          // symbol@tlsld
-    VK_PPC_LOCAL,          // symbol@local
-    VK_PPC_NOTOC,          // symbol@notoc
+    VK_PPC_LO,              // symbol@l
+    VK_PPC_HI,              // symbol@h
+    VK_PPC_HA,              // symbol@ha
+    VK_PPC_HIGH,            // symbol@high
+    VK_PPC_HIGHA,           // symbol@higha
+    VK_PPC_HIGHER,          // symbol@higher
+    VK_PPC_HIGHERA,         // symbol@highera
+    VK_PPC_HIGHEST,         // symbol@highest
+    VK_PPC_HIGHESTA,        // symbol@highesta
+    VK_PPC_GOT_LO,          // symbol@got@l
+    VK_PPC_GOT_HI,          // symbol@got@h
+    VK_PPC_GOT_HA,          // symbol@got@ha
+    VK_PPC_TOCBASE,         // symbol@tocbase
+    VK_PPC_TOC,             // symbol@toc
+    VK_PPC_TOC_LO,          // symbol@toc@l
+    VK_PPC_TOC_HI,          // symbol@toc@h
+    VK_PPC_TOC_HA,          // symbol@toc@ha
+    VK_PPC_U,               // symbol@u
+    VK_PPC_L,               // symbol@l
+    VK_PPC_DTPMOD,          // symbol@dtpmod
+    VK_PPC_TPREL_LO,        // symbol@tprel@l
+    VK_PPC_TPREL_HI,        // symbol@tprel@h
+    VK_PPC_TPREL_HA,        // symbol@tprel@ha
+    VK_PPC_TPREL_HIGH,      // symbol@tprel@high
+    VK_PPC_TPREL_HIGHA,     // symbol@tprel@higha
+    VK_PPC_TPREL_HIGHER,    // symbol@tprel@higher
+    VK_PPC_TPREL_HIGHERA,   // symbol@tprel@highera
+    VK_PPC_TPREL_HIGHEST,   // symbol@tprel@highest
+    VK_PPC_TPREL_HIGHESTA,  // symbol@tprel@highesta
+    VK_PPC_DTPREL_LO,       // symbol@dtprel@l
+    VK_PPC_DTPREL_HI,       // symbol@dtprel@h
+    VK_PPC_DTPREL_HA,       // symbol@dtprel@ha
+    VK_PPC_DTPREL_HIGH,     // symbol@dtprel@high
+    VK_PPC_DTPREL_HIGHA,    // symbol@dtprel@higha
+    VK_PPC_DTPREL_HIGHER,   // symbol@dtprel@higher
+    VK_PPC_DTPREL_HIGHERA,  // symbol@dtprel@highera
+    VK_PPC_DTPREL_HIGHEST,  // symbol@dtprel@highest
+    VK_PPC_DTPREL_HIGHESTA, // symbol@dtprel@highesta
+    VK_PPC_GOT_TPREL,       // symbol@got@tprel
+    VK_PPC_GOT_TPREL_LO,    // symbol@got@tprel@l
+    VK_PPC_GOT_TPREL_HI,    // symbol@got@tprel@h
+    VK_PPC_GOT_TPREL_HA,    // symbol@got@tprel@ha
+    VK_PPC_GOT_DTPREL,      // symbol@got@dtprel
+    VK_PPC_GOT_DTPREL_LO,   // symbol@got@dtprel@l
+    VK_PPC_GOT_DTPREL_HI,   // symbol@got@dtprel@h
+    VK_PPC_GOT_DTPREL_HA,   // symbol@got@dtprel@ha
+    VK_PPC_TLS,             // symbol@tls
+    VK_PPC_GOT_TLSGD,       // symbol@got@tlsgd
+    VK_PPC_GOT_TLSGD_LO,    // symbol@got@tlsgd@l
+    VK_PPC_GOT_TLSGD_HI,    // symbol@got@tlsgd@h
+    VK_PPC_GOT_TLSGD_HA,    // symbol@got@tlsgd@ha
+    VK_PPC_TLSGD,           // symbol@tlsgd
+    VK_PPC_GOT_TLSLD,       // symbol@got@tlsld
+    VK_PPC_GOT_TLSLD_LO,    // symbol@got@tlsld@l
+    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_TLSLD,           // symbol@tlsld
+    VK_PPC_LOCAL,           // symbol@local
+    VK_PPC_NOTOC,           // symbol@notoc
 
     VK_COFF_IMGREL32, // symbol@imgrel (image-relative)
 
index 1448a54..ead2ef2 100644 (file)
@@ -317,6 +317,8 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
   case VK_PPC_GOT_TLSLD_LO: return "got@tlsld@l";
   case VK_PPC_GOT_TLSLD_HI: return "got@tlsld@h";
   case VK_PPC_GOT_TLSLD_HA: return "got@tlsld@ha";
+  case VK_PPC_GOT_PCREL:
+    return "got@pcrel";
   case VK_PPC_TLSLD: return "tlsld";
   case VK_PPC_LOCAL: return "local";
   case VK_PPC_NOTOC: return "notoc";
index 1687b29..d8b3301 100644 (file)
@@ -129,7 +129,16 @@ unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
       errs() << '\n';
       report_fatal_error("Invalid PC-relative half16ds relocation");
     case PPC::fixup_ppc_pcrel34:
-      Type = ELF::R_PPC64_PCREL34;
+      switch (Modifier) {
+      default:
+        llvm_unreachable("Unsupported Modifier for fixup_ppc_pcrel34");
+      case MCSymbolRefExpr::VK_PCREL:
+        Type = ELF::R_PPC64_PCREL34;
+        break;
+      case MCSymbolRefExpr::VK_PPC_GOT_PCREL:
+        Type = ELF::R_PPC64_GOT_PCREL34;
+        break;
+      }
       break;
     case FK_Data_4:
     case FK_PCRel_4:
index e782fc1..f1b5711 100644 (file)
@@ -193,8 +193,9 @@ PPCMCCodeEmitter::getMemRI34PCRelEncoding(const MCInst &MI, unsigned OpNo,
     const MCExpr *Expr = MO.getExpr();
     const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(Expr);
     (void)SRE;
-    assert(SRE->getKind() == MCSymbolRefExpr::VK_PCREL &&
-           "VariantKind must be VK_PCREL");
+    assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL ||
+            SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL) &&
+           "VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL");
     Fixups.push_back(
         MCFixup::create(IsLittleEndian ? 0 : 1, Expr,
                         static_cast<MCFixupKind>(PPC::fixup_ppc_pcrel34)));
index 8a78a8d..815c672 100644 (file)
@@ -102,6 +102,11 @@ namespace llvm {
     /// the current instruction address(pc), e.g., var@pcrel. Fixup is VK_PCREL.
     MO_PCREL_FLAG = 4,
 
+    /// MO_GOT_FLAG - If this bit is set the symbol reference is to be computed
+    /// via the GOT. For example when combined with the MO_PCREL_FLAG it should
+    /// produce the relocation @got@pcrel. Fixup is VK_PPC_GOT_PCREL.
+    MO_GOT_FLAG = 32,
+
     /// The next are not flags but distinct values.
     MO_ACCESS_MASK = 0xf00,
 
index 6cf4b85..c9bd6e8 100644 (file)
@@ -3051,11 +3051,21 @@ SDValue PPCTargetLowering::LowerGlobalAddress(SDValue Op,
   // 64-bit SVR4 ABI & AIX ABI code is always position-independent.
   // The actual address of the GlobalValue is stored in the TOC.
   if (Subtarget.is64BitELFABI() || Subtarget.isAIXABI()) {
-    if (!isAccessedAsGotIndirect(Op) && Subtarget.isUsingPCRelativeCalls()) {
+    if (Subtarget.isUsingPCRelativeCalls()) {
       EVT Ty = getPointerTy(DAG.getDataLayout());
-      SDValue GA = DAG.getTargetGlobalAddress(GV, DL, Ty, GSDN->getOffset(),
-                                              PPCII::MO_PCREL_FLAG);
-      return DAG.getNode(PPCISD::MAT_PCREL_ADDR, DL, Ty, GA);
+      if (isAccessedAsGotIndirect(Op)) {
+        SDValue GA = DAG.getTargetGlobalAddress(GV, DL, Ty, GSDN->getOffset(),
+                                                PPCII::MO_PCREL_FLAG |
+                                                    PPCII::MO_GOT_FLAG);
+        SDValue MatPCRel = DAG.getNode(PPCISD::MAT_PCREL_ADDR, DL, Ty, GA);
+        SDValue Load = DAG.getLoad(MVT::i64, DL, DAG.getEntryNode(), MatPCRel,
+                                   MachinePointerInfo());
+        return Load;
+      } else {
+        SDValue GA = DAG.getTargetGlobalAddress(GV, DL, Ty, GSDN->getOffset(),
+                                                PPCII::MO_PCREL_FLAG);
+        return DAG.getNode(PPCISD::MAT_PCREL_ADDR, DL, Ty, GA);
+      }
     }
     setUsesTOCBasePtr(DAG);
     SDValue GA = DAG.getTargetGlobalAddress(GV, DL, PtrVT, GSDN->getOffset());
index 2dfc5c5..709b213 100644 (file)
@@ -2048,7 +2048,8 @@ PPCInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
   static const std::pair<unsigned, const char *> TargetFlags[] = {
       {MO_PLT, "ppc-plt"},
       {MO_PIC_FLAG, "ppc-pic"},
-      {MO_PCREL_FLAG, "ppc-pcrel"}};
+      {MO_PCREL_FLAG, "ppc-pcrel"},
+      {MO_GOT_FLAG, "ppc-got"}};
   return makeArrayRef(TargetFlags);
 }
 
index 0a0e168..add4de2 100644 (file)
@@ -82,6 +82,8 @@ static MCOperand GetSymbolRef(const MachineOperand &MO, const MCSymbol *Symbol,
     RefKind = MCSymbolRefExpr::VK_PLT;
   else if (MO.getTargetFlags() == PPCII::MO_PCREL_FLAG)
     RefKind = MCSymbolRefExpr::VK_PCREL;
+  else if (MO.getTargetFlags() == (PPCII::MO_PCREL_FLAG | PPCII::MO_GOT_FLAG))
+    RefKind = MCSymbolRefExpr::VK_PPC_GOT_PCREL;
 
   const MachineInstr *MI = MO.getParent();
 
index 59001d4..ed96e73 100644 (file)
@@ -53,9 +53,7 @@ entry:
 
 define dso_local signext i32 @DirectCallLocal2(i32 signext %a, i32 signext %b) local_unnamed_addr {
 ; CHECK-ALL-LABEL: DirectCallLocal2:
-; CHECK-S:         addis r2, r12, .TOC.-.Lfunc_gep2@ha
-; CHECK-S-NEXT:    addi r2, r2, .TOC.-.Lfunc_gep2@l
-; CHECK-S:         .localentry     DirectCallLocal2, .Lfunc_lep2-.Lfunc_gep2
+; CHECK-S:         .localentry     DirectCallLocal2
 ; CHECK-S:       # %bb.0: # %entry
 ; CHECK-S-NEXT:    mflr r0
 ; CHECK-S-NEXT:    std r0, 16(r1)
@@ -64,10 +62,8 @@ define dso_local signext i32 @DirectCallLocal2(i32 signext %a, i32 signext %b) l
 ; CHECK-S-NEXT:    .cfi_offset lr, 16
 ; CHECK-S-NEXT:    add r3, r4, r3
 ; CHECK-S-NEXT:    extsw r3, r3
-; CHECK-S-NEXT:    bl localCall
-; CHECK-S-NEXT:    nop
-; CHECK-S-NEXT:    addis r4, r2, .LC0@toc@ha
-; CHECK-S-NEXT:    ld r4, .LC0@toc@l(r4)
+; CHECK-S-NEXT:    bl localCall@notoc
+; CHECK-S-NEXT:    pld r4, externGlobalVar@got@pcrel(0), 1
 ; CHECK-S-NEXT:    lwz r4, 0(r4)
 ; CHECK-S-NEXT:    mullw r3, r4, r3
 ; CHECK-S-NEXT:    extsw r3, r3
@@ -140,9 +136,7 @@ declare signext i32 @externCall(i32 signext) local_unnamed_addr
 
 define dso_local signext i32 @DirectCallExtern2(i32 signext %a, i32 signext %b) local_unnamed_addr {
 ; CHECK-ALL-LABEL: DirectCallExtern2:
-; CHECK-S:         addis r2, r12, .TOC.-.Lfunc_gep5@ha
-; CHECK-S-NEXT:    addi r2, r2, .TOC.-.Lfunc_gep5@l
-; CHECK-S:         .localentry     DirectCallExtern2, .Lfunc_lep5-.Lfunc_gep5
+; CHECK-S:         .localentry     DirectCallExtern2
 ; CHECK-S:       # %bb.0: # %entry
 ; CHECK-S-NEXT:    mflr r0
 ; CHECK-S-NEXT:    std r0, 16(r1)
@@ -151,10 +145,8 @@ define dso_local signext i32 @DirectCallExtern2(i32 signext %a, i32 signext %b)
 ; CHECK-S-NEXT:    .cfi_offset lr, 16
 ; CHECK-S-NEXT:    add r3, r4, r3
 ; CHECK-S-NEXT:    extsw r3, r3
-; CHECK-S-NEXT:    bl externCall
-; CHECK-S-NEXT:    nop
-; CHECK-S-NEXT:    addis r4, r2, .LC0@toc@ha
-; CHECK-S-NEXT:    ld r4, .LC0@toc@l(r4)
+; CHECK-S-NEXT:    bl externCall@notoc
+; CHECK-S-NEXT:    pld r4, externGlobalVar@got@pcrel(0), 1
 ; CHECK-S-NEXT:    lwz r4, 0(r4)
 ; CHECK-S-NEXT:    mullw r3, r4, r3
 ; CHECK-S-NEXT:    extsw r3, r3
@@ -223,22 +215,18 @@ entry:
 
 define dso_local signext i32 @TailCallLocal2(i32 signext %a) local_unnamed_addr {
 ; CHECK-ALL-LABEL: TailCallLocal2:
-; CHECK-S:         addis r2, r12, .TOC.-.Lfunc_gep8@ha
-; CHECK-S-NEXT:    addi r2, r2, .TOC.-.Lfunc_gep8@l
-; CHECK-S:         .localentry     TailCallLocal2, .Lfunc_lep8-.Lfunc_gep8
+; CHECK-S:         .localentry     TailCallLocal2
 ; CHECK-S:       # %bb.0: # %entry
 ; CHECK-S-NEXT:    mflr r0
 ; CHECK-S-NEXT:    std r0, 16(r1)
 ; CHECK-S-NEXT:    stdu r1, -32(r1)
 ; CHECK-S-NEXT:    .cfi_def_cfa_offset 32
 ; CHECK-S-NEXT:    .cfi_offset lr, 16
-; CHECK-S-NEXT:    addis r4, r2, .LC0@toc@ha
-; CHECK-S-NEXT:    ld r4, .LC0@toc@l(r4)
+; CHECK-S-NEXT:    pld r4, externGlobalVar@got@pcrel(0), 1
 ; CHECK-S-NEXT:    lwz r4, 0(r4)
 ; CHECK-S-NEXT:    add r3, r4, r3
 ; CHECK-S-NEXT:    extsw r3, r3
-; CHECK-S-NEXT:    bl localCall
-; CHECK-S-NEXT:    nop
+; CHECK-S-NEXT:    bl localCall@notoc
 ; CHECK-S-NEXT:    addi r1, r1, 32
 ; CHECK-S-NEXT:    ld r0, 16(r1)
 ; CHECK-S-NEXT:    mtlr r0
@@ -296,22 +284,18 @@ entry:
 
 define dso_local signext i32 @TailCallExtern2(i32 signext %a) local_unnamed_addr {
 ; CHECK-ALL-LABEL: TailCallExtern2:
-; CHECK-S:         addis r2, r12, .TOC.-.Lfunc_gep11@ha
-; CHECK-S-NEXT:    addi r2, r2, .TOC.-.Lfunc_gep11@l
-; CHECK-S:         .localentry     TailCallExtern2, .Lfunc_lep11-.Lfunc_gep11
+; CHECK-S:         .localentry     TailCallExtern2
 ; CHECK-S:       # %bb.0: # %entry
 ; CHECK-S-NEXT:    mflr r0
 ; CHECK-S-NEXT:    std r0, 16(r1)
 ; CHECK-S-NEXT:    stdu r1, -32(r1)
 ; CHECK-S-NEXT:    .cfi_def_cfa_offset 32
 ; CHECK-S-NEXT:    .cfi_offset lr, 16
-; CHECK-S-NEXT:    addis r4, r2, .LC0@toc@ha
-; CHECK-S-NEXT:    ld r4, .LC0@toc@l(r4)
+; CHECK-S-NEXT:    pld r4, externGlobalVar@got@pcrel(0), 1
 ; CHECK-S-NEXT:    lwz r4, 0(r4)
 ; CHECK-S-NEXT:    add r3, r4, r3
 ; CHECK-S-NEXT:    extsw r3, r3
-; CHECK-S-NEXT:    bl externCall
-; CHECK-S-NEXT:    nop
+; CHECK-S-NEXT:    bl externCall@notoc
 ; CHECK-S-NEXT:    addi r1, r1, 32
 ; CHECK-S-NEXT:    ld r0, 16(r1)
 ; CHECK-S-NEXT:    mtlr r0
@@ -394,8 +378,7 @@ define dso_local signext i32 @IndirectCall2(i32 signext %a, i32 signext %b) loca
 ; CHECK-S-NEXT:    mtctr r12
 ; CHECK-S-NEXT:    bctrl
 ; CHECK-S-NEXT:    ld 2, 24(r1)
-; CHECK-S-NEXT:    addis r4, r2, .LC0@toc@ha
-; CHECK-S-NEXT:    ld r4, .LC0@toc@l(r4)
+; CHECK-S-NEXT:    pld r4, externGlobalVar@got@pcrel(0), 1
 ; CHECK-S-NEXT:    lwz r4, 0(r4)
 ; CHECK-S-NEXT:    mullw r3, r4, r3
 ; CHECK-S-NEXT:    extsw r3, r3
diff --git a/llvm/test/CodeGen/PowerPC/pcrel-got-indirect.ll b/llvm/test/CodeGen/PowerPC/pcrel-got-indirect.ll
new file mode 100644 (file)
index 0000000..e9aeccd
--- /dev/null
@@ -0,0 +1,253 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \
+; RUN:   -mcpu=future -enable-ppc-quad-precision -ppc-asm-full-reg-names \
+; RUN:   -ppc-vsr-nums-as-vr < %s | FileCheck %s
+
+%struct.Struct = type { i8, i16, i32 }
+
+@valChar = external local_unnamed_addr global i8, align 1
+@valShort = external local_unnamed_addr global i16, align 2
+@valInt = external global i32, align 4
+@valUnsigned = external local_unnamed_addr global i32, align 4
+@valLong = external local_unnamed_addr global i64, align 8
+@ptr = external local_unnamed_addr global i32*, align 8
+@array = external local_unnamed_addr global [10 x i32], align 4
+@structure = external local_unnamed_addr global %struct.Struct, align 4
+@ptrfunc = external local_unnamed_addr global void (...)*, align 8
+
+define dso_local signext i32 @ReadGlobalVarChar() local_unnamed_addr  {
+; CHECK-LABEL: ReadGlobalVarChar:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, valChar@got@pcrel(0), 1
+; CHECK-NEXT:    lbz r3, 0(r3)
+; CHECK-NEXT:    blr
+entry:
+  %0 = load i8, i8* @valChar, align 1
+  %conv = zext i8 %0 to i32
+  ret i32 %conv
+}
+
+define dso_local void @WriteGlobalVarChar() local_unnamed_addr  {
+; CHECK-LABEL: WriteGlobalVarChar:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, valChar@got@pcrel(0), 1
+; CHECK-NEXT:    li r4, 3
+; CHECK-NEXT:    stb r4, 0(r3)
+; CHECK-NEXT:    blr
+entry:
+  store i8 3, i8* @valChar, align 1
+  ret void
+}
+
+define dso_local signext i32 @ReadGlobalVarShort() local_unnamed_addr  {
+; CHECK-LABEL: ReadGlobalVarShort:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, valShort@got@pcrel(0), 1
+; CHECK-NEXT:    lha r3, 0(r3)
+; CHECK-NEXT:    blr
+entry:
+  %0 = load i16, i16* @valShort, align 2
+  %conv = sext i16 %0 to i32
+  ret i32 %conv
+}
+
+define dso_local void @WriteGlobalVarShort() local_unnamed_addr  {
+; CHECK-LABEL: WriteGlobalVarShort:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, valShort@got@pcrel(0), 1
+; CHECK-NEXT:    li r4, 3
+; CHECK-NEXT:    sth r4, 0(r3)
+; CHECK-NEXT:    blr
+entry:
+  store i16 3, i16* @valShort, align 2
+  ret void
+}
+
+define dso_local signext i32 @ReadGlobalVarInt() local_unnamed_addr  {
+; CHECK-LABEL: ReadGlobalVarInt:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, valInt@got@pcrel(0), 1
+; CHECK-NEXT:    lwa r3, 0(r3)
+; CHECK-NEXT:    blr
+entry:
+  %0 = load i32, i32* @valInt, align 4
+  ret i32 %0
+}
+
+define dso_local void @WriteGlobalVarInt() local_unnamed_addr  {
+; CHECK-LABEL: WriteGlobalVarInt:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, valInt@got@pcrel(0), 1
+; CHECK-NEXT:    li r4, 33
+; CHECK-NEXT:    stw r4, 0(r3)
+; CHECK-NEXT:    blr
+entry:
+  store i32 33, i32* @valInt, align 4
+  ret void
+}
+
+define dso_local signext i32 @ReadGlobalVarUnsigned() local_unnamed_addr  {
+; CHECK-LABEL: ReadGlobalVarUnsigned:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, valUnsigned@got@pcrel(0), 1
+; CHECK-NEXT:    lwa r3, 0(r3)
+; CHECK-NEXT:    blr
+entry:
+  %0 = load i32, i32* @valUnsigned, align 4
+  ret i32 %0
+}
+
+define dso_local void @WriteGlobalVarUnsigned() local_unnamed_addr  {
+; CHECK-LABEL: WriteGlobalVarUnsigned:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, valUnsigned@got@pcrel(0), 1
+; CHECK-NEXT:    li r4, 33
+; CHECK-NEXT:    stw r4, 0(r3)
+; CHECK-NEXT:    blr
+entry:
+  store i32 33, i32* @valUnsigned, align 4
+  ret void
+}
+
+define dso_local signext i32 @ReadGlobalVarLong() local_unnamed_addr  {
+; CHECK-LABEL: ReadGlobalVarLong:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, valLong@got@pcrel(0), 1
+; CHECK-NEXT:    lwa r3, 0(r3)
+; CHECK-NEXT:    blr
+entry:
+  %0 = load i64, i64* @valLong, align 8
+  %conv = trunc i64 %0 to i32
+  ret i32 %conv
+}
+
+define dso_local void @WriteGlobalVarLong() local_unnamed_addr  {
+; CHECK-LABEL: WriteGlobalVarLong:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, valLong@got@pcrel(0), 1
+; CHECK-NEXT:    li r4, 3333
+; CHECK-NEXT:    std r4, 0(r3)
+; CHECK-NEXT:    blr
+entry:
+  store i64 3333, i64* @valLong, align 8
+  ret void
+}
+
+define dso_local i32* @ReadGlobalPtr() local_unnamed_addr  {
+; CHECK-LABEL: ReadGlobalPtr:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, ptr@got@pcrel(0), 1
+; CHECK-NEXT:    ld r3, 0(r3)
+; CHECK-NEXT:    blr
+entry:
+  %0 = load i32*, i32** @ptr, align 8
+  ret i32* %0
+}
+
+define dso_local void @WriteGlobalPtr() local_unnamed_addr  {
+; CHECK-LABEL: WriteGlobalPtr:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, ptr@got@pcrel(0), 1
+; CHECK-NEXT:    li r4, 3
+; CHECK-NEXT:    ld r3, 0(r3)
+; CHECK-NEXT:    stw r4, 0(r3)
+; CHECK-NEXT:    blr
+entry:
+  %0 = load i32*, i32** @ptr, align 8
+  store i32 3, i32* %0, align 4
+  ret void
+}
+
+define dso_local nonnull i32* @GlobalVarAddr() local_unnamed_addr  {
+; CHECK-LABEL: GlobalVarAddr:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, valInt@got@pcrel(0), 1
+; CHECK-NEXT:    blr
+entry:
+  ret i32* @valInt
+}
+
+define dso_local signext i32 @ReadGlobalArray() local_unnamed_addr  {
+; CHECK-LABEL: ReadGlobalArray:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, array@got@pcrel(0), 1
+; CHECK-NEXT:    lwa r3, 12(r3)
+; CHECK-NEXT:    blr
+entry:
+  %0 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @array, i64 0, i64 3), align 4
+  ret i32 %0
+}
+
+define dso_local void @WriteGlobalArray() local_unnamed_addr  {
+; CHECK-LABEL: WriteGlobalArray:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, array@got@pcrel(0), 1
+; CHECK-NEXT:    li r4, 5
+; CHECK-NEXT:    stw r4, 12(r3)
+; CHECK-NEXT:    blr
+entry:
+  store i32 5, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @array, i64 0, i64 3), align 4
+  ret void
+}
+
+define dso_local signext i32 @ReadGlobalStruct() local_unnamed_addr  {
+; CHECK-LABEL: ReadGlobalStruct:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, structure@got@pcrel(0), 1
+; CHECK-NEXT:    lwa r3, 4(r3)
+; CHECK-NEXT:    blr
+entry:
+  %0 = load i32, i32* getelementptr inbounds (%struct.Struct, %struct.Struct* @structure, i64 0, i32 2), align 4
+  ret i32 %0
+}
+
+define dso_local void @WriteGlobalStruct() local_unnamed_addr  {
+; CHECK-LABEL: WriteGlobalStruct:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, structure@got@pcrel(0), 1
+; CHECK-NEXT:    li r4, 3
+; CHECK-NEXT:    stw r4, 4(r3)
+; CHECK-NEXT:    blr
+entry:
+  store i32 3, i32* getelementptr inbounds (%struct.Struct, %struct.Struct* @structure, i64 0, i32 2), align 4
+  ret void
+}
+
+define dso_local void @ReadFuncPtr() local_unnamed_addr  {
+; CHECK-LABEL: ReadFuncPtr:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    mflr r0
+; CHECK-NEXT:    std r0, 16(r1)
+; CHECK-NEXT:    stdu r1, -32(r1)
+; CHECK-NEXT:    std r2, 24(r1)
+; CHECK-NEXT:    .cfi_def_cfa_offset 32
+; CHECK-NEXT:    .cfi_offset lr, 16
+; CHECK-NEXT:    pld r3, ptrfunc@got@pcrel(0), 1
+; CHECK-NEXT:    ld r12, 0(r3)
+; CHECK-NEXT:    mtctr r12
+; CHECK-NEXT:    bctrl
+; CHECK-NEXT:    ld 2, 24(r1)
+; CHECK-NEXT:    addi r1, r1, 32
+; CHECK-NEXT:    ld r0, 16(r1)
+; CHECK-NEXT:    mtlr r0
+; CHECK-NEXT:    blr
+entry:
+  %0 = load void ()*, void ()** bitcast (void (...)** @ptrfunc to void ()**), align 8
+  tail call void %0()
+  ret void
+}
+
+define dso_local void @WriteFuncPtr() local_unnamed_addr  {
+; CHECK-LABEL: WriteFuncPtr:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    pld r3, ptrfunc@got@pcrel(0), 1
+; CHECK-NEXT:    pld r4, function@got@pcrel(0), 1
+; CHECK-NEXT:    std r4, 0(r3)
+; CHECK-NEXT:    blr
+entry:
+  store void (...)* @function, void (...)** @ptrfunc, align 8
+  ret void
+}
+
+declare void @function(...)
+