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 @@ -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_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) 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 @@ -210,9 +210,9 @@ 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 @@ 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 @@ 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 @@ 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) 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 @@ -317,6 +317,8 @@ 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"; 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 @@ -129,7 +129,16 @@ 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: 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 @@ -193,8 +193,9 @@ const MCExpr *Expr = MO.getExpr(); const MCSymbolRefExpr *SRE = cast(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(PPC::fixup_ppc_pcrel34))); 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 @@ -102,6 +102,11 @@ /// 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, 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 @@ -3051,11 +3051,21 @@ // 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()); 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 @@ -2048,7 +2048,8 @@ static const std::pair 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); } 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 @@ -82,6 +82,8 @@ 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(); diff --git a/llvm/test/CodeGen/PowerPC/pcrel-call-linkage-with-calls.ll b/llvm/test/CodeGen/PowerPC/pcrel-call-linkage-with-calls.ll --- a/llvm/test/CodeGen/PowerPC/pcrel-call-linkage-with-calls.ll +++ b/llvm/test/CodeGen/PowerPC/pcrel-call-linkage-with-calls.ll @@ -53,9 +53,7 @@ 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 @@ ; 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 @@ 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 @@ ; 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 @@ 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 @@ 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 @@ ; 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 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/pcrel-got-indirect.ll @@ -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(...) +