diff --git a/llvm/docs/GlobalISel/GenericOpcode.rst b/llvm/docs/GlobalISel/GenericOpcode.rst --- a/llvm/docs/GlobalISel/GenericOpcode.rst +++ b/llvm/docs/GlobalISel/GenericOpcode.rst @@ -69,6 +69,15 @@ %0:_(p0) = G_BLOCK_ADDR blockaddress(@test_blockaddress, %ir-block.block) +G_CONSTANT_POOL_INDEX +^^^^^^^^^^^^^^^^^^^^^ + +The address of an object in the constant pool. + +.. code-block:: none + + %0:_(p0) = G_CONSTANT_POOL_INDEX %const.0 + Integer Extension and Truncation -------------------------------- diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h --- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h @@ -359,6 +359,7 @@ LegalizeResult bitcastInsertVectorElt(MachineInstr &MI, unsigned TypeIdx, LLT CastTy); + LegalizeResult lowerFConstant(MachineInstr &MI); LegalizeResult lowerBitcast(MachineInstr &MI); LegalizeResult lowerLoad(GAnyLoad &MI); LegalizeResult lowerStore(GStore &MI); diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -456,6 +456,17 @@ /// \return a MachineInstrBuilder for the newly created instruction. MachineInstrBuilder buildGlobalValue(const DstOp &Res, const GlobalValue *GV); + /// Build and insert \p Res = G_CONSTANT_POOL_INDEX \p Idx + /// + /// G_CONSTANT_POOL_INDEX materializes the address of an object in the + /// constant pool. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Res must be a generic virtual register with pointer type. + /// + /// \return a MachineInstrBuilder for the newly created instruction. + MachineInstrBuilder buildConstantPoolIndex(const DstOp &Res, unsigned Idx); + /// Build and insert \p Res = G_PTR_ADD \p Op0, \p Op1 /// /// G_PTR_ADD adds \p Op1 addressible units to the pointer specified by \p Op0, diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def --- a/llvm/include/llvm/Support/TargetOpcodes.def +++ b/llvm/include/llvm/Support/TargetOpcodes.def @@ -286,6 +286,10 @@ /// Generic reference to global value. HANDLE_TARGET_OPCODE(G_GLOBAL_VALUE) +/// Generic instruction to materialize the address of an object in the constant +/// pool. +HANDLE_TARGET_OPCODE(G_CONSTANT_POOL_INDEX) + /// Generic instruction to extract blocks of bits from the register given /// (typically a sub-register COPY after instruction selection). HANDLE_TARGET_OPCODE(G_EXTRACT) diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -106,6 +106,12 @@ let hasSideEffects = false; } +def G_CONSTANT_POOL_INDEX : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins unknown:$src); + let hasSideEffects = false; +} + def G_INTTOPTR : GenericInstruction { let OutOperandList = (outs type0:$dst); let InOperandList = (ins type1:$src); diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -21,6 +21,7 @@ #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" #include "llvm/CodeGen/GlobalISel/Utils.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetFrameLowering.h" @@ -2628,6 +2629,31 @@ Pieces.push_back(Unmerge.getReg(I)); } +LegalizerHelper::LegalizeResult +LegalizerHelper::lowerFConstant(MachineInstr &MI) { + Register Dst = MI.getOperand(0).getReg(); + + MachineFunction &MF = MIRBuilder.getMF(); + const DataLayout &DL = MIRBuilder.getDataLayout(); + + unsigned AddrSpace = DL.getAllocaAddrSpace(); + LLT AddrPtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace)); + Align Alignment(DL.getPointerSizeInBits(AddrSpace) / 8); + + auto Addr = MIRBuilder.buildConstantPoolIndex( + AddrPtrTy, MF.getConstantPool()->getConstantPoolIndex( + MI.getOperand(1).getFPImm(), Alignment)); + + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo::getConstantPool(MF), MachineMemOperand::MOLoad, + MRI.getType(Dst), Alignment); + + MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, Dst, Addr, *MMO); + MI.eraseFromParent(); + + return Legalized; +} + LegalizerHelper::LegalizeResult LegalizerHelper::lowerBitcast(MachineInstr &MI) { Register Dst = MI.getOperand(0).getReg(); @@ -3248,6 +3274,8 @@ switch(MI.getOpcode()) { default: return UnableToLegalize; + case TargetOpcode::G_FCONSTANT: + return lowerFConstant(MI); case TargetOpcode::G_BITCAST: return lowerBitcast(MI); case TargetOpcode::G_SREM: diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp --- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -164,6 +164,15 @@ return MIB; } +MachineInstrBuilder MachineIRBuilder::buildConstantPoolIndex(const DstOp &Res, + unsigned Idx) { + assert(Res.getLLTTy(*getMRI()).isPointer() && "invalid operand type"); + auto MIB = buildInstr(TargetOpcode::G_CONSTANT_POOL_INDEX); + Res.addDefToMIB(*getMRI(), MIB); + MIB.addConstantPoolIndex(Idx); + return MIB; +} + MachineInstrBuilder MachineIRBuilder::buildJumpTable(const LLT PtrTy, unsigned JTI) { return buildInstr(TargetOpcode::G_JUMP_TABLE, {PtrTy}, {}) diff --git a/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp b/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp --- a/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp +++ b/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp @@ -12,6 +12,7 @@ #include "PPC.h" #include "PPCInstrInfo.h" +#include "PPCMachineFunctionInfo.h" #include "PPCRegisterBankInfo.h" #include "PPCSubtarget.h" #include "PPCTargetMachine.h" @@ -58,7 +59,10 @@ MachineRegisterInfo &MRI) const; bool selectZExt(MachineInstr &I, MachineBasicBlock &MBB, MachineRegisterInfo &MRI) const; + bool selectConstantPoolIndex(MachineInstr &I, MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const; + const PPCTargetMachine &TM; const PPCSubtarget &STI; const PPCInstrInfo &TII; const PPCRegisterInfo &TRI; @@ -82,7 +86,8 @@ PPCInstructionSelector::PPCInstructionSelector(const PPCTargetMachine &TM, const PPCSubtarget &STI, const PPCRegisterBankInfo &RBI) - : STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), RBI(RBI), + : TM(TM), STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), + RBI(RBI), #define GET_GLOBALISEL_PREDICATES_INIT #include "PPCGenGlobalISel.inc" #undef GET_GLOBALISEL_PREDICATES_INIT @@ -352,6 +357,66 @@ return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); } +bool PPCInstructionSelector::selectConstantPoolIndex( + MachineInstr &I, MachineBasicBlock &MBB, MachineRegisterInfo &MRI) const { + const DebugLoc &DbgLoc = I.getDebugLoc(); + MachineFunction *MF = MBB.getParent(); + + // TODO: handle 32-bit. + // TODO: Enabling floating point constant selection on AIX requires global + // isel on big endian target enabled first. + // See CallLowering::enableBigEndian(). + if (!STI.isPPC64() || !STI.isLittleEndian()) + return false; + + MF->getInfo()->setUsesTOCBasePtr(); + + const Register DstReg = I.getOperand(0).getReg(); + unsigned CPI = I.getOperand(1).getIndex(); + + // Address stored in the TOC entry. This is related to code model and the ABI + // we are currently using. For now we only handle 64-bit Linux LE. PowerPC + // only supports small, medium and large code model. + const CodeModel::Model CModel = TM.getCodeModel(); + assert(!(CModel == CodeModel::Tiny || CModel == CodeModel::Kernel) && + "PowerPC doesn't support tiny or kernel code models."); + + MachineMemOperand *MMO = MF->getMachineMemOperand( + MachinePointerInfo::getGOT(*MF), MachineMemOperand::MOLoad, + MRI.getType(DstReg), Align(MRI.getType(DstReg).getSizeInBits() / 8)); + + MachineInstr *MI = nullptr; + // For now we only handle 64-bit Linux. + if (CModel == CodeModel::Small) { + // For small code model, generate LDtocCPT(CPI, X2). + MI = BuildMI(MBB, I, DbgLoc, TII.get(PPC::LDtocCPT), DstReg) + .addConstantPoolIndex(CPI) + .addReg(PPC::X2) + .addMemOperand(MMO); + } else { + Register HaAddrReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + BuildMI(MBB, I, DbgLoc, TII.get(PPC::ADDIStocHA8), HaAddrReg) + .addReg(PPC::X2) + .addConstantPoolIndex(CPI); + + if (CModel == CodeModel::Large) { + // For large code model, generate LDtocL(CPI, ADDIStocHA8(X2, CPI)) + MI = BuildMI(MBB, I, DbgLoc, TII.get(PPC::LDtocL), DstReg) + .addConstantPoolIndex(CPI) + .addReg(HaAddrReg) + .addMemOperand(MMO); + } else { + // For medium code model, generate ADDItocL(CPI, ADDIStocHA8(X2, CPI)) + MI = BuildMI(MBB, I, DbgLoc, TII.get(PPC::ADDItocL), DstReg) + .addReg(HaAddrReg) + .addConstantPoolIndex(CPI); + } + } + + I.eraseFromParent(); + return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); +} + bool PPCInstructionSelector::select(MachineInstr &I) { auto &MBB = *I.getParent(); auto &MF = *MBB.getParent(); @@ -422,6 +487,8 @@ // G_SEXT will be selected in tb-gen pattern. case TargetOpcode::G_ZEXT: return selectZExt(I, MBB, MRI); + case TargetOpcode::G_CONSTANT_POOL_INDEX: + return selectConstantPoolIndex(I, MBB, MRI); } return false; } diff --git a/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp b/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp --- a/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp +++ b/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp @@ -54,5 +54,8 @@ getActionDefinitionsBuilder({G_LOAD, G_STORE}) .legalForTypesWithMemDesc({{S64, P0, S64, 8}, {S32, P0, S32, 4}}); + getActionDefinitionsBuilder(G_FCONSTANT).lowerFor({S32, S64}); + getActionDefinitionsBuilder(G_CONSTANT_POOL_INDEX).legalFor({P0}); + getLegacyLegalizerInfo().computeTables(); } diff --git a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp --- a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp +++ b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp @@ -113,6 +113,9 @@ case TargetOpcode::G_CONSTANT: OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr}); break; + case TargetOpcode::G_CONSTANT_POOL_INDEX: + OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr}); + break; case TargetOpcode::G_FPTOUI: case TargetOpcode::G_FPTOSI: { Register SrcReg = MI.getOperand(1).getReg(); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir @@ -86,6 +86,10 @@ # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected # +# DEBUG-NEXT: G_CONSTANT_POOL_INDEX (opcode {{[0-9]+}}): 1 type index, 0 imm indices +# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined +# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined +# # DEBUG-NEXT: G_EXTRACT (opcode {{[0-9]+}}): 2 type indices, 1 imm index # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected diff --git a/llvm/test/CodeGen/PowerPC/GlobalISel/fconstant-unsupported.ll b/llvm/test/CodeGen/PowerPC/GlobalISel/fconstant-unsupported.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/GlobalISel/fconstant-unsupported.ll @@ -0,0 +1,17 @@ +; REQUIRES: asserts + +; RUN: not --crash llc -mtriple=powerpc-unknown-linux-gnu -global-isel \ +; RUN: -o -verify-machineinstrs - < %s 2>&1 | FileCheck %s --check-prefix=BE +; RUN: not --crash llc -mtriple=powerpcle-unknown-linux-gnu -global-isel \ +; RUN: -o -verify-machineinstrs - < %s 2>&1 | FileCheck %s --check-prefix=BIT32 + +; BE: LLVM ERROR: unable to translate in big endian mode + +; for 32 bit target, the G_LOAD will have a 32-bit alignment which can not be +; handled by now. +; BIT32: LLVM ERROR: unable to legalize instruction: %0:_(s64) = G_LOAD{{.*}}align 4 + +define double @foo() { + entry: + ret double 1.000000e+00 +} diff --git a/llvm/test/CodeGen/PowerPC/GlobalISel/fconstant.ll b/llvm/test/CodeGen/PowerPC/GlobalISel/fconstant.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/GlobalISel/fconstant.ll @@ -0,0 +1,56 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py + +; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -global-isel -code-model=small \ +; RUN: -verify-machineinstrs -o - < %s | FileCheck %s --check-prefix=SMALL +; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -global-isel -code-model=medium \ +; RUN: -verify-machineinstrs -o - < %s | FileCheck %s --check-prefix=MEDIUM +; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -global-isel -code-model=large \ +; RUN: -verify-machineinstrs -o - < %s | FileCheck %s --check-prefix=LARGE + +define float @foo_float() { +; SMALL-LABEL: foo_float: +; SMALL: # %bb.0: # %entry +; SMALL-NEXT: ld 3, .LC0@toc(2) +; SMALL-NEXT: lfs 1, 0(3) +; SMALL-NEXT: blr +; +; MEDIUM-LABEL: foo_float: +; MEDIUM: # %bb.0: # %entry +; MEDIUM-NEXT: addis 3, 2, .LCPI0_0@toc@ha +; MEDIUM-NEXT: addi 3, 3, .LCPI0_0@toc@l +; MEDIUM-NEXT: lfs 1, 0(3) +; MEDIUM-NEXT: blr +; +; LARGE-LABEL: foo_float: +; LARGE: # %bb.0: # %entry +; LARGE-NEXT: addis 3, 2, .LC0@toc@ha +; LARGE-NEXT: ld 3, .LC0@toc@l(3) +; LARGE-NEXT: lfs 1, 0(3) +; LARGE-NEXT: blr +entry: + ret float 1.000000e+00 +} + +define double @foo_double() { +; SMALL-LABEL: foo_double: +; SMALL: # %bb.0: # %entry +; SMALL-NEXT: ld 3, .LC1@toc(2) +; SMALL-NEXT: lfd 1, 0(3) +; SMALL-NEXT: blr +; +; MEDIUM-LABEL: foo_double: +; MEDIUM: # %bb.0: # %entry +; MEDIUM-NEXT: addis 3, 2, .LCPI1_0@toc@ha +; MEDIUM-NEXT: addi 3, 3, .LCPI1_0@toc@l +; MEDIUM-NEXT: lfd 1, 0(3) +; MEDIUM-NEXT: blr +; +; LARGE-LABEL: foo_double: +; LARGE: # %bb.0: # %entry +; LARGE-NEXT: addis 3, 2, .LC1@toc@ha +; LARGE-NEXT: ld 3, .LC1@toc@l(3) +; LARGE-NEXT: lfd 1, 0(3) +; LARGE-NEXT: blr +entry: + ret double 1.000000e+00 +}