[PowerPC][Future] More support for PCRel addressing for global values

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
This commit is contained in:
Stefan Pintilie 2020-04-17 11:05:02 -05:00 committed by Kamau Bridgeman
parent a127d61835
commit b771c4a842
11 changed files with 373 additions and 104 deletions

View 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)

View 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)

View 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";

View 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:

View 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)));

View 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,

View 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());

View 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);
}

View 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();

View 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

View File

@ -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(...)