diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp --- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -5066,46 +5066,88 @@ return; } case PPCISD::TOC_ENTRY: { - assert ((PPCSubTarget->isPPC64() || PPCSubTarget->isSVR4ABI()) && - "Only supported for 64-bit ABI and 32-bit SVR4"); - if (PPCSubTarget->isSVR4ABI() && !PPCSubTarget->isPPC64()) { - SDValue GA = N->getOperand(0); + const bool isPPC64 = PPCSubTarget->isPPC64(); + const bool isSVR4ABI = PPCSubTarget->isSVR4ABI(); + const bool isAIXABI = PPCSubTarget->isAIXABI(); + const bool isDarwin = PPCSubTarget->isDarwin(); + + assert (!isDarwin && "TOC is an ELF/XCOFF construct"); + + // Transforms the ISD::TOC_ENTRY node to a PPCISD::LWZtoc. + auto replaceWithLWZtoc = [this, dl](SDNode *TocEntry) { + SDValue GA = TocEntry->getOperand(0); + SDValue TocBase = TocEntry->getOperand(1); SDNode *MN = CurDAG->getMachineNode(PPC::LWZtoc, dl, MVT::i32, GA, - N->getOperand(1)); - transferMemOperands(N, MN); - ReplaceNode(N, MN); - return; + TocBase); + transferMemOperands(TocEntry, MN); + ReplaceNode(TocEntry, MN); + }; + + // Transforms the ISD::TOC_ENTRY node for medium or large code model under + // either 32-bit or 64-bit mode. The first source operand is a symbol + // reference. + auto replaceForMediumOrLargeCM = [this, dl, isPPC64](SDNode *TocEntry) { + SDValue GA = TocEntry->getOperand(0); + SDValue TOCbase = TocEntry->getOperand(1); + + EVT VT = isPPC64 ? MVT::i64 : MVT::i32; + SDNode *Tmp = CurDAG->getMachineNode((isPPC64) ? PPC::ADDIStocHA : + PPC::ADDIStocHA32, dl, VT, TOCbase, + GA); + + if (PPCLowering->isAccessedAsGotIndirect(GA)) { + // If it is accessed as got-indirect, we need an extra LD to load + // the address. + SDNode *MN = CurDAG->getMachineNode((isPPC64) ? PPC::LDtocL : + PPC::LWZtocL, dl, VT, GA, + SDValue(Tmp, 0)); + transferMemOperands(TocEntry, MN); + ReplaceNode(TocEntry, MN); + return; + } + // Build the address relative to the TOC-pointer. + ReplaceNode(TocEntry, CurDAG->getMachineNode(PPC::ADDItocL, dl, MVT::i64, + SDValue(Tmp, 0), GA)); + }; + + if (!isPPC64 && isSVR4ABI) { + const Module *M = MF->getFunction().getParent(); + assert (TM.isPositionIndependent() && + "32-bit ELF can only have TOC entries in position independant" + " code."); + // 32-bit ELF always uses a small codemodel toc access. + replaceWithLWZtoc(N); + return; + } + + CodeModel::Model CModel = TM.getCodeModel(); + if (!isPPC64 && isAIXABI && CModel == CodeModel::Small) { + replaceWithLWZtoc(N); + return; + } + + if (!isPPC64 && isAIXABI && CModel == CodeModel::Large) { + // AIX is always toc-referenced. We generate: + // LWZtocL(@sym, ADDIStocHA32(%r2, @sym)) + replaceForMediumOrLargeCM(N); + return; } + + if (isAIXABI && CModel == CodeModel::Medium) + report_fatal_error("Medium code model is not supported on AIX."); - // For medium and large code model, we generate two instructions as - // described below. Otherwise we allow SelectCodeCommon to handle this, - // selecting one of LDtoc, LDtocJTI, LDtocCPT, and LDtocBA. - CodeModel::Model CModel = TM.getCodeModel(); + // PowerPC doesn't support tiny or kernel codemodels. For 64-bit medium + // and large code model, we generate two instructions as described below. + // Otherwise for 64-bit small code model, we allow SelectCodeCommon to + // handle this, selecting one of LDtoc, LDtocJTI, LDtocCPT, and LDtocBA. if (CModel != CodeModel::Medium && CModel != CodeModel::Large) break; - // The first source operand is a TargetGlobalAddress or a TargetJumpTable. // If it must be toc-referenced according to PPCSubTarget, we generate: // LDtocL(@sym, ADDIStocHA(%x2, @sym)) // Otherwise we generate: // ADDItocL(ADDIStocHA(%x2, @sym), @sym) - SDValue GA = N->getOperand(0); - SDValue TOCbase = N->getOperand(1); - SDNode *Tmp = CurDAG->getMachineNode(PPC::ADDIStocHA, dl, MVT::i64, - TOCbase, GA); - if (PPCLowering->isAccessedAsGotIndirect(GA)) { - // If it is access as got-indirect, we need an extra LD to load - // the address. - SDNode *MN = CurDAG->getMachineNode(PPC::LDtocL, dl, MVT::i64, GA, - SDValue(Tmp, 0)); - transferMemOperands(N, MN); - ReplaceNode(N, MN); - return; - } - - // Build the address relative to the TOC-pointer.. - ReplaceNode(N, CurDAG->getMachineNode(PPC::ADDItocL, dl, MVT::i64, - SDValue(Tmp, 0), GA)); + replaceForMediumOrLargeCM(N); return; } case PPCISD::PPC32_PICGOT: 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 @@ -1511,7 +1511,7 @@ bool PPC::isVPKUDUMShuffleMask(ShuffleVectorSDNode *N, unsigned ShuffleKind, SelectionDAG &DAG) { const PPCSubtarget& Subtarget = - static_cast(DAG.getSubtarget()); + static_cast(DAG.getSubtarget()); if (!Subtarget.hasP8Vector()) return false; @@ -2638,12 +2638,15 @@ setUsesTOCBasePtr(DAG.getMachineFunction()); } -static SDValue getTOCEntry(SelectionDAG &DAG, const SDLoc &dl, bool Is64Bit, - SDValue GA) { +static SDValue getTOCEntry(SelectionDAG &DAG, const SDLoc &dl, SDValue GA) { + const PPCSubtarget& Subtarget = + static_cast(DAG.getSubtarget()); + bool Is64Bit = Subtarget.isPPC64(); EVT VT = Is64Bit ? MVT::i64 : MVT::i32; - SDValue Reg = Is64Bit ? DAG.getRegister(PPC::X2, VT) : - DAG.getNode(PPCISD::GlobalBaseReg, dl, VT); - + SDValue Reg = Is64Bit ? DAG.getRegister(PPC::X2, VT) + : Subtarget.isAIXABI() + ? DAG.getRegister(PPC::R2, VT) + : DAG.getNode(PPCISD::GlobalBaseReg, dl, VT); SDValue Ops[] = { GA, Reg }; return DAG.getMemIntrinsicNode( PPCISD::TOC_ENTRY, dl, DAG.getVTList(VT, MVT::Other), Ops, VT, @@ -2662,7 +2665,7 @@ if (Subtarget.isSVR4ABI() && Subtarget.isPPC64()) { setUsesTOCBasePtr(DAG); SDValue GA = DAG.getTargetConstantPool(C, PtrVT, CP->getAlignment(), 0); - return getTOCEntry(DAG, SDLoc(CP), true, GA); + return getTOCEntry(DAG, SDLoc(CP), GA); } unsigned MOHiFlag, MOLoFlag; @@ -2672,7 +2675,7 @@ if (IsPIC && Subtarget.isSVR4ABI()) { SDValue GA = DAG.getTargetConstantPool(C, PtrVT, CP->getAlignment(), PPCII::MO_PIC_FLAG); - return getTOCEntry(DAG, SDLoc(CP), false, GA); + return getTOCEntry(DAG, SDLoc(CP), GA); } SDValue CPIHi = @@ -2738,7 +2741,7 @@ if (Subtarget.isSVR4ABI() && Subtarget.isPPC64()) { setUsesTOCBasePtr(DAG); SDValue GA = DAG.getTargetJumpTable(JT->getIndex(), PtrVT); - return getTOCEntry(DAG, SDLoc(JT), true, GA); + return getTOCEntry(DAG, SDLoc(JT), GA); } unsigned MOHiFlag, MOLoFlag; @@ -2748,7 +2751,7 @@ if (IsPIC && Subtarget.isSVR4ABI()) { SDValue GA = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, PPCII::MO_PIC_FLAG); - return getTOCEntry(DAG, SDLoc(GA), false, GA); + return getTOCEntry(DAG, SDLoc(GA), GA); } SDValue JTIHi = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, MOHiFlag); @@ -2769,7 +2772,7 @@ if (Subtarget.isPPC64()) setUsesTOCBasePtr(DAG); SDValue GA = DAG.getTargetBlockAddress(BA, PtrVT, BASDN->getOffset()); - return getTOCEntry(DAG, SDLoc(BASDN), Subtarget.isPPC64(), GA); + return getTOCEntry(DAG, SDLoc(BASDN), GA); } unsigned MOHiFlag, MOLoFlag; @@ -2884,12 +2887,12 @@ SDLoc DL(GSDN); const GlobalValue *GV = GSDN->getGlobal(); - // 64-bit SVR4 ABI code is always position-independent. + // 64-bit SVR4 ABI & AIX ABI code is always position-independent. // The actual address of the GlobalValue is stored in the TOC. - if (Subtarget.isSVR4ABI() && Subtarget.isPPC64()) { + if ((Subtarget.isSVR4ABI() && Subtarget.isPPC64()) || Subtarget.isAIXABI()) { setUsesTOCBasePtr(DAG); SDValue GA = DAG.getTargetGlobalAddress(GV, DL, PtrVT, GSDN->getOffset()); - return getTOCEntry(DAG, DL, true, GA); + return getTOCEntry(DAG, DL, GA); } unsigned MOHiFlag, MOLoFlag; @@ -2900,7 +2903,7 @@ SDValue GA = DAG.getTargetGlobalAddress(GV, DL, PtrVT, GSDN->getOffset(), PPCII::MO_PIC_FLAG); - return getTOCEntry(DAG, DL, false, GA); + return getTOCEntry(DAG, DL, GA); } SDValue GAHi = @@ -14302,11 +14305,17 @@ if (Subtarget.isSVR4ABI() && !Subtarget.isPPC64()) return true; + // AIX accesses everything indirectly through the TOC, which is similar to + // the GOT. + if (Subtarget.isAIXABI()) + return true; + CodeModel::Model CModel = getTargetMachine().getCodeModel(); // If it is small or large code model, module locals are accessed // indirectly by loading their address from .toc/.got. The difference - // is that for large code model we have ADDISTocHa + LDtocL and for - // small code model we simply have LDtoc. + // is that for large code model we have ADDISTocHa + LDtocL(64-bit)/ + // LWZtocL(32-bit) and for small code model we simply have LDtoc(64-bit)/ + // LWZtoc(32-bit). if (CModel == CodeModel::Small || CModel == CodeModel::Large) return true; 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 @@ -3166,6 +3166,15 @@ "#LWZtoc", [(set i32:$rD, (PPCtoc_entry tglobaladdr:$disp, i32:$reg))]>; +def LWZtocL : PPCEmitTimePseudo<(outs gprc:$rD), (ins tocentry32:$disp, gprc_nor0:$reg), + "#LWZtocL", + [(set i32:$rD, + (PPCtoc_entry tglobaladdr:$disp, i32:$reg))]>; +def ADDIStocHA32: PPCEmitTimePseudo<(outs gprc:$rD), (ins gprc:$reg, tocentry32:$disp), + "#ADDIStocHA32", + [(set i32:$rD, + (PPCtoc_entry i32:$reg, tglobaladdr:$disp))]>; + // Get Global (GOT) Base Register offset, from the word immediately preceding // the function label. def UpdateGBR : PPCEmitTimePseudo<(outs gprc:$rD, gprc:$rT), (ins gprc:$rI), "#UpdateGBR", []>; diff --git a/llvm/lib/Target/PowerPC/PPCTOCRegDeps.cpp b/llvm/lib/Target/PowerPC/PPCTOCRegDeps.cpp --- a/llvm/lib/Target/PowerPC/PPCTOCRegDeps.cpp +++ b/llvm/lib/Target/PowerPC/PPCTOCRegDeps.cpp @@ -95,7 +95,8 @@ protected: bool hasTOCLoReloc(const MachineInstr &MI) { if (MI.getOpcode() == PPC::LDtocL || - MI.getOpcode() == PPC::ADDItocL) + MI.getOpcode() == PPC::ADDItocL || + MI.getOpcode() == PPC::LWZtocL) return true; for (const MachineOperand &MO : MI.operands()) { @@ -109,11 +110,16 @@ bool processBlock(MachineBasicBlock &MBB) { bool Changed = false; + const PPCSubtarget &Subtarget = + MBB.getParent()->getSubtarget(); + const bool is32BitAIX = !Subtarget.isPPC64() && Subtarget.isAIXABI(); + const unsigned TOCReg = (!is32BitAIX) ? PPC::X2 : PPC::R2; + for (auto &MI : MBB) { if (!hasTOCLoReloc(MI)) continue; - MI.addOperand(MachineOperand::CreateReg(PPC::X2, + MI.addOperand(MachineOperand::CreateReg(TOCReg, false /*IsDef*/, true /*IsImp*/)); Changed = true; diff --git a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp --- a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp +++ b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp @@ -248,7 +248,7 @@ report_fatal_error("Target does not support the kernel CodeModel", false); return *CM; } - if (!TT.isOSDarwin() && !JIT && + if (!TT.isOSAIX() && !TT.isOSDarwin() && !JIT && (TT.getArch() == Triple::ppc64 || TT.getArch() == Triple::ppc64le)) return CodeModel::Medium; return CodeModel::Small; diff --git a/llvm/test/CodeGen/PowerPC/lower-globaladdr32-aix.ll b/llvm/test/CodeGen/PowerPC/lower-globaladdr32-aix.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/lower-globaladdr32-aix.ll @@ -0,0 +1,38 @@ +; RUN: llc -mtriple powerpc-ibm-aix-xcoff -code-model=small \ +; RUN: -stop-after=machine-cp -print-before=simple-register-coalescing 2>&1 < \ +; RUN: %s | FileCheck --check-prefix=SMALL %s + +; RUN: not llc -mtriple powerpc-ibm-aix-xcoff -code-model=medium \ +; RUN: -stop-after=machine-cp 2>&1 < %s | FileCheck --check-prefix=MEDIUM %s + +; RUN: llc -mtriple powerpc-ibm-aix-xcoff -code-model=large \ +; RUN: -stop-after=machine-cp -print-before=simple-register-coalescing 2>&1 < \ +; RUN: %s | FileCheck --check-prefix=LARGE %s + +; RUN: llc -mtriple powerpc-ibm-aix-xcoff -stop-after=machine-cp \ +; RUN: -print-before=simple-register-coalescing 2>&1 < %s | FileCheck \ +; RUN: --check-prefix=SMALL %s + +@msg = common global i8* null, align 4 +@ptr = common global i8* null, align 4 + +define void @foo() { +entry: +; SMALL: %0:gprc_and_gprc_nor0 = LWZtoc @msg, $r2 :: (load 4 from got) +; SMALL: %1:gprc = LWZ 0, %0:gprc_and_gprc_nor0 :: (dereferenceable load 4 from @msg) +; SMALL: %2:gprc_and_gprc_nor0 = LWZtoc @ptr, $r2 :: (load 4 from got) +; SMALL: STW %1:gprc, 0, %2:gprc_and_gprc_nor0 :: (store 4 into @ptr) + +; MEDIUM: Medium code model is not supported on AIX. + +; LARGE: %0:gprc_and_gprc_nor0 = ADDIStocHA32 $r2, @msg +; LARGE: %1:gprc_and_gprc_nor0 = LWZtocL @msg, %0:gprc_and_gprc_nor0, implicit $r2 :: (load 4 from got) +; LARGE: %2:gprc = LWZ 0, %1:gprc_and_gprc_nor0 :: (dereferenceable load 4 from @msg) +; LARGE: %3:gprc_and_gprc_nor0 = ADDIStocHA32 $r2, @ptr +; LARGE: %4:gprc_and_gprc_nor0 = LWZtocL @ptr, %3:gprc_and_gprc_nor0, implicit $r2 :: (load 4 from got) +; LARGE: STW %2:gprc, 0, %4:gprc_and_gprc_nor0 :: (store 4 into @ptr) + + %0 = load i8*, i8** @msg, align 4 + store i8* %0, i8** @ptr, align 4 + ret void +} diff --git a/llvm/test/CodeGen/PowerPC/lower-globaladdr64-aix.ll b/llvm/test/CodeGen/PowerPC/lower-globaladdr64-aix.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/lower-globaladdr64-aix.ll @@ -0,0 +1,38 @@ +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff -code-model=small \ +; RUN: -stop-after=machine-cp -print-before=simple-register-coalescing 2>&1 < \ +; RUN: %s | FileCheck --check-prefix=SMALL %s + +; RUN: not llc -mtriple powerpc64-ibm-aix-xcoff -code-model=medium \ +; RUN: -stop-after=machine-cp 2>&1 < %s | FileCheck --check-prefix=MEDIUM %s + +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff -code-model=large \ +; RUN: -stop-after=machine-cp -print-before=simple-register-coalescing 2>&1 < \ +; RUN: %s | FileCheck --check-prefix=LARGE %s + +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff -stop-after=machine-cp \ +; RUN: -print-before=simple-register-coalescing 2>&1 < %s | FileCheck \ +; RUN: --check-prefix=SMALL %s + +@msg = common global i8* null, align 8 +@ptr = common global i8* null, align 8 + +define void @foo() { +entry: +; SMALL: %0:g8rc_and_g8rc_nox0 = LDtoc @msg, $x2 :: (load 8 from got) +; SMALL: %1:g8rc = LD 0, %0:g8rc_and_g8rc_nox0 :: (dereferenceable load 8 from @msg) +; SMALL: %2:g8rc_and_g8rc_nox0 = LDtoc @ptr, $x2 :: (load 8 from got) +; SMALL: STD %1:g8rc, 0, %2:g8rc_and_g8rc_nox0 :: (store 8 into @ptr) + +; MEDIUM: Medium code model is not supported on AIX. + +; LARGE: %0:g8rc_and_g8rc_nox0 = ADDIStocHA $x2, @msg +; LARGE: %1:g8rc_and_g8rc_nox0 = LDtocL @msg, %0:g8rc_and_g8rc_nox0, implicit $x2 :: (load 8 from got) +; LARGE: %2:g8rc = LD 0, %1:g8rc_and_g8rc_nox0 :: (dereferenceable load 8 from @msg) +; LARGE: %3:g8rc_and_g8rc_nox0 = ADDIStocHA $x2, @ptr +; LARGE: %4:g8rc_and_g8rc_nox0 = LDtocL @ptr, %3:g8rc_and_g8rc_nox0, implicit $x2 :: (load 8 from got) +; LARGE: STD %2:g8rc, 0, %4:g8rc_and_g8rc_nox0 :: (store 8 into @ptr) + + %0 = load i8*, i8** @msg, align 8 + store i8* %0, i8** @ptr, align 8 + ret void +}