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 @@ -10,12 +10,15 @@ /// PowerPC. //===----------------------------------------------------------------------===// +#include "PPC.h" #include "PPCInstrInfo.h" +#include "PPCMachineFunctionInfo.h" #include "PPCRegisterBankInfo.h" #include "PPCSubtarget.h" #include "PPCTargetMachine.h" #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" #include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/IR/IntrinsicsPowerPC.h" #include "llvm/Support/Debug.h" @@ -42,7 +45,11 @@ /// tblgen generated 'select' implementation that is used as the initial /// selector for the patterns that do not require complex C++. bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; + bool materializeFP(MachineInstr &I, MachineRegisterInfo &MRI, + MachineFunction &MF) const; + const PPCTargetMachine &TM; + const PPCSubtarget &STI; const PPCInstrInfo &TII; const PPCRegisterInfo &TRI; const PPCRegisterBankInfo &RBI; @@ -65,7 +72,8 @@ PPCInstructionSelector::PPCInstructionSelector(const PPCTargetMachine &TM, const PPCSubtarget &STI, const PPCRegisterBankInfo &RBI) - : 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 @@ -118,6 +126,95 @@ return true; } +bool PPCInstructionSelector::materializeFP(MachineInstr &I, + MachineRegisterInfo &MRI, + MachineFunction &MF) const { + const DebugLoc &DbgLoc = I.getDebugLoc(); + + // TODO: handle 32-bit. + assert(STI.isPPC64() && "Only 64-bit is supported!"); + + // TODO: Enabling floating point constant selection on AIX requires global + // isel on big endian target enabled first. + // See CallLowering::enableBigEndian(). + assert(STI.isLittleEndian() && "Only little-endian is supported!"); + + MF.getInfo()->setUsesTOCBasePtr(); + + const Register DstReg = I.getOperand(0).getReg(); + unsigned Size = MRI.getType(DstReg).getSizeInBits() / 8; + + assert((Size == 4 || Size == 8) && "Unsupported FP constant type"); + auto LoadOpcode = Size == 4 ? PPC::LFS : PPC::LFD; + + // Constant in the constant pool. + Align Alignment(Size); + const ConstantFP *CFP = I.getOperand(1).getFPImm(); + unsigned CPI = MF.getConstantPool()->getConstantPoolIndex(CFP, Alignment); + + // Address stored in the TOC entry. This is related to code model and ABI we + // are currently using. For now we only handle 64-bit Linux LE. + // PowerPC only support 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::getConstantPool(MF), MachineMemOperand::MOLoad, + LLT::pointer(0, MF.getDataLayout().getPointerSizeInBits()), Alignment); + MachineInstr *LoadInst = nullptr; + + // For now we only handle 64-bit Linux. + if (CModel == CodeModel::Small) { + // For small code model, generate a LF[SD](0, LDtocCPT(CPI, X2)). + Register AddrReg = + MRI.createVirtualRegister(&PPC::G8RC_and_G8RC_NOX0RegClass); + BuildMI(*I.getParent(), I, DbgLoc, TII.get(PPC::LDtocCPT), AddrReg) + .addConstantPoolIndex(CPI) + .addReg(PPC::X2); + + LoadInst = + &*(BuildMI(*I.getParent(), I, DbgLoc, TII.get(LoadOpcode), DstReg) + .addImm(0) + .addReg(AddrReg) + .addMemOperand(MMO)); + } else { + Register HaAddrReg = + MRI.createVirtualRegister(&PPC::G8RC_and_G8RC_NOX0RegClass); + BuildMI(*I.getParent(), I, DbgLoc, TII.get(PPC::ADDIStocHA8), HaAddrReg) + .addReg(PPC::X2) + .addConstantPoolIndex(CPI); + + if (CModel == CodeModel::Large) { + // For large code model, generate a LF[SD](LDtocL(CPI, ADDIStocHA8(X2, + // CPI))) + Register AddrReg = + MRI.createVirtualRegister(&PPC::G8RC_and_G8RC_NOX0RegClass); + BuildMI(*I.getParent(), I, DbgLoc, TII.get(PPC::LDtocL), AddrReg) + .addConstantPoolIndex(CPI) + .addReg(HaAddrReg); + + LoadInst = + &*(BuildMI(*I.getParent(), I, DbgLoc, TII.get(LoadOpcode), DstReg) + .addImm(0) + .addReg(AddrReg) + .addMemOperand(MMO)); + } else { + // For medium code model, generate a LF[SD](CPI, ADDIStocHA8(X2, CPI)) + LoadInst = + &*(BuildMI(*I.getParent(), I, DbgLoc, TII.get(LoadOpcode), DstReg) + .addConstantPoolIndex(CPI, 0, PPCII::MO_TOC_LO) + .addReg(HaAddrReg) + .addMemOperand(MMO)); + } + } + + constrainSelectedInstRegOperands(*LoadInst, TII, TRI, RBI); + I.eraseFromParent(); + + return true; +} + bool PPCInstructionSelector::select(MachineInstr &I) { auto &MBB = *I.getParent(); auto &MF = *MBB.getParent(); @@ -132,6 +229,15 @@ if (selectImpl(I, *CoverageInfo)) return true; + + unsigned Opcode = I.getOpcode(); + + switch (Opcode) { + default: + return false; + case TargetOpcode::G_FCONSTANT: + return materializeFP(I, MRI, MF); + } 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 @@ -29,7 +29,7 @@ .legalFor({S64}) .clampScalar(0, S64, S64); - getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV}) + getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FCONSTANT}) .legalFor({S32, S64}); 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 @@ -96,6 +96,15 @@ case TargetOpcode::G_CONSTANT: OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr}); break; + case TargetOpcode::G_FCONSTANT: { + LLT Ty = MRI.getType(MI.getOperand(0).getReg()); + unsigned Size = Ty.getSizeInBits(); + + assert((Size == 32 || Size == 64) && "Unsupported floating point types!\n"); + OperandsMapping = getOperandsMapping( + {getValueMapping(Size == 32 ? PMI_FPR32 : PMI_FPR64), nullptr}); + break; + } default: return getInvalidInstructionMapping(); } 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,14 @@ +; 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 +; BIT32: Only 64-bit is supported! + +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,54 @@ +; 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: lfs 1, .LCPI0_0@toc@l(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: lfd 1, .LCPI1_0@toc@l(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 +}