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 materializeFP(MachineInstr &I, MachineRegisterInfo &MRI, + MachineFunction &MF); + 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 @@ -220,6 +225,82 @@ return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); } +bool PPCInstructionSelector::materializeFP(MachineInstr &I, + MachineRegisterInfo &MRI, + MachineFunction &MF) { + const DebugLoc &DbgLoc = I.getDebugLoc(); + + // 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 Size = MRI.getType(DstReg).getSizeInBits() / 8; + + // 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."); + + Register AddrReg = + MRI.createVirtualRegister(&PPC::G8RC_and_G8RC_NOX0RegClass); + MRI.setType(AddrReg, + LLT::pointer(0, MF.getDataLayout().getPointerSizeInBits())); + + // For now we only handle 64-bit Linux. + if (CModel == CodeModel::Small) { + // For small code model, generate LDtocCPT(CPI, X2). + BuildMI(*I.getParent(), I, DbgLoc, TII.get(PPC::LDtocCPT), AddrReg) + .addConstantPoolIndex(CPI) + .addReg(PPC::X2); + } 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 LDtocL(CPI, ADDIStocHA8(X2, CPI)) + BuildMI(*I.getParent(), I, DbgLoc, TII.get(PPC::LDtocL), AddrReg) + .addConstantPoolIndex(CPI) + .addReg(HaAddrReg); + } else { + // For medium code model, generate ADDItocL(CPI, ADDIStocHA8(X2, CPI)) + BuildMI(*I.getParent(), I, DbgLoc, TII.get(PPC::ADDItocL), AddrReg) + .addReg(HaAddrReg) + .addConstantPoolIndex(CPI); + } + } + + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo::getConstantPool(MF), MachineMemOperand::MOLoad, + MRI.getType(DstReg), Alignment); + + auto LoadInst = BuildMI(*I.getParent(), I, I.getDebugLoc(), + TII.get(TargetOpcode::G_LOAD), DstReg) + .addReg(AddrReg) + .addMemOperand(MMO); + + if (!select(*LoadInst)) + return false; + + I.eraseFromParent(); + return true; +} + bool PPCInstructionSelector::selectConst(MachineInstr &I, MachineBasicBlock &MBB, MachineRegisterInfo &MRI) const { @@ -415,6 +496,8 @@ case TargetOpcode::G_FPTOSI: case TargetOpcode::G_FPTOUI: return selectFPToInt(I, MBB, MRI); + case TargetOpcode::G_FCONSTANT: + return materializeFP(I, MRI, MF); case TargetOpcode::G_CONSTANT: return selectConst(I, MBB, MRI); case TargetOpcode::G_SEXT_INREG: 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 @@ -42,7 +42,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}); getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI}) 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,14 @@ 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(); + + OperandsMapping = getOperandsMapping( + {getValueMapping(Size == 32 ? PMI_FPR32 : PMI_FPR64), nullptr}); + break; + } case TargetOpcode::G_FPTOUI: case TargetOpcode::G_FPTOSI: { Register SrcReg = MI.getOperand(1).getReg(); 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: LLVM ERROR: cannot select: %0:fpr(s64) = G_FCONSTANT + +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 +}