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,6 +10,7 @@ /// PowerPC. //===----------------------------------------------------------------------===// +#include "PPC.h" #include "PPCInstrInfo.h" #include "PPCRegisterBankInfo.h" #include "PPCSubtarget.h" @@ -43,6 +44,12 @@ /// selector for the patterns that do not require complex C++. bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; + bool selectFPToInt(MachineInstr &I, MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const; + bool selectIntToFP(MachineInstr &I, MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const; + + const PPCSubtarget &STI; const PPCInstrInfo &TII; const PPCRegisterInfo &TRI; const PPCRegisterBankInfo &RBI; @@ -65,7 +72,7 @@ PPCInstructionSelector::PPCInstructionSelector(const PPCTargetMachine &TM, const PPCSubtarget &STI, const PPCRegisterBankInfo &RBI) - : TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), RBI(RBI), + : STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), RBI(RBI), #define GET_GLOBALISEL_PREDICATES_INIT #include "PPCGenGlobalISel.inc" #undef GET_GLOBALISEL_PREDICATES_INIT @@ -114,6 +121,63 @@ return true; } +bool PPCInstructionSelector::selectIntToFP(MachineInstr &I, + MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const { + if (!STI.hasDirectMove() || !STI.isPPC64() || !STI.hasFPCVT()) + return false; + + const DebugLoc &DbgLoc = I.getDebugLoc(); + const Register DstReg = I.getOperand(0).getReg(); + const Register SrcReg = I.getOperand(1).getReg(); + + Register MoveReg = MRI.createVirtualRegister(&PPC::VSFRCRegClass); + + // For now, only handle the case for 64 bit integer. + BuildMI(MBB, I, DbgLoc, TII.get(PPC::MTVSRD), MoveReg).addReg(SrcReg); + + bool IsSingle = MRI.getType(DstReg).getSizeInBits() == 32; + bool IsSigned = I.getOpcode() == TargetOpcode::G_SITOFP; + unsigned ConvOp = IsSingle ? (IsSigned ? PPC::XSCVSXDSP : PPC::XSCVUXDSP) + : (IsSigned ? PPC::XSCVSXDDP : PPC::XSCVUXDDP); + + MachineInstr *MI = + BuildMI(MBB, I, DbgLoc, TII.get(ConvOp), DstReg).addReg(MoveReg); + + I.eraseFromParent(); + return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); +} + +bool PPCInstructionSelector::selectFPToInt(MachineInstr &I, + MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const { + if (!STI.hasDirectMove() || !STI.isPPC64() || !STI.hasFPCVT()) + return false; + + const DebugLoc &DbgLoc = I.getDebugLoc(); + const Register DstReg = I.getOperand(0).getReg(); + const Register SrcReg = I.getOperand(1).getReg(); + + Register CopyReg = MRI.createVirtualRegister(&PPC::VSFRCRegClass); + BuildMI(MBB, I, DbgLoc, TII.get(TargetOpcode::COPY), CopyReg).addReg(SrcReg); + + Register ConvReg = MRI.createVirtualRegister(&PPC::VSFRCRegClass); + + bool IsSigned = I.getOpcode() == TargetOpcode::G_FPTOSI; + + // single-precision is stored as double-precision on PPC in registers, so + // always use double-precision convertions. + unsigned ConvOp = IsSigned ? PPC::XSCVDPSXDS : PPC::XSCVDPUXDS; + + BuildMI(MBB, I, DbgLoc, TII.get(ConvOp), ConvReg).addReg(CopyReg); + + MachineInstr *MI = + BuildMI(MBB, I, DbgLoc, TII.get(PPC::MFVSRD), DstReg).addReg(ConvReg); + + I.eraseFromParent(); + return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); +} + bool PPCInstructionSelector::select(MachineInstr &I) { auto &MBB = *I.getParent(); auto &MF = *MBB.getParent(); @@ -128,6 +192,19 @@ if (selectImpl(I, *CoverageInfo)) return true; + + unsigned Opcode = I.getOpcode(); + + switch (Opcode) { + default: + return false; + case TargetOpcode::G_SITOFP: + case TargetOpcode::G_UITOFP: + return selectIntToFP(I, MBB, MRI); + case TargetOpcode::G_FPTOSI: + case TargetOpcode::G_FPTOUI: + return selectFPToInt(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 @@ -35,5 +35,11 @@ getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV}) .legalFor({S32, S64}); + getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI}) + .legalForCartesianProduct({S64}, {S32, S64}); + + getActionDefinitionsBuilder({G_SITOFP, G_UITOFP}) + .legalForCartesianProduct({S32, S64}, {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 @@ -99,6 +99,26 @@ case TargetOpcode::G_CONSTANT: OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr}); break; + case TargetOpcode::G_FPTOUI: + case TargetOpcode::G_FPTOSI: { + Register SrcReg = MI.getOperand(1).getReg(); + unsigned Size = getSizeInBits(SrcReg, MRI, TRI); + + OperandsMapping = getOperandsMapping( + {getValueMapping(PMI_GPR64), + getValueMapping(Size == 32 ? PMI_FPR32 : PMI_FPR64)}); + break; + } + case TargetOpcode::G_UITOFP: + case TargetOpcode::G_SITOFP: { + Register SrcReg = MI.getOperand(0).getReg(); + unsigned Size = getSizeInBits(SrcReg, MRI, TRI); + + OperandsMapping = + getOperandsMapping({getValueMapping(Size == 32 ? PMI_FPR32 : PMI_FPR64), + getValueMapping(PMI_GPR64)}); + break; + } default: return getInvalidInstructionMapping(); } diff --git a/llvm/test/CodeGen/PowerPC/GlobalISel/float-integer-conv.ll b/llvm/test/CodeGen/PowerPC/GlobalISel/float-integer-conv.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/GlobalISel/float-integer-conv.ll @@ -0,0 +1,92 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py + +; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -global-isel -ppc-vsr-nums-as-vr \ +; RUN: -ppc-asm-full-reg-names -verify-machineinstrs -o - < %s | FileCheck %s + +define i64 @fptosi_float_i64(float %i) { +; CHECK-LABEL: fptosi_float_i64: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xscvdpsxds f0, f1 +; CHECK-NEXT: mffprd r3, f0 +; CHECK-NEXT: blr +entry: + %conv = fptosi float %i to i64 + ret i64 %conv +} + +define i64 @fptosi_double_i64(double %i) { +; CHECK-LABEL: fptosi_double_i64: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xscvdpsxds f0, f1 +; CHECK-NEXT: mffprd r3, f0 +; CHECK-NEXT: blr +entry: + %conv = fptosi double %i to i64 + ret i64 %conv +} + +define i64 @fptoui_float_i64(float %i) { +; CHECK-LABEL: fptoui_float_i64: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xscvdpuxds f0, f1 +; CHECK-NEXT: mffprd r3, f0 +; CHECK-NEXT: blr +entry: + %conv = fptoui float %i to i64 + ret i64 %conv +} + +define i64 @fptoui_double_i64(double %i) { +; CHECK-LABEL: fptoui_double_i64: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xscvdpuxds f0, f1 +; CHECK-NEXT: mffprd r3, f0 +; CHECK-NEXT: blr +entry: + %conv = fptoui double %i to i64 + ret i64 %conv +} + +define float @sitofp_i64_float(i64 %i) { +; CHECK-LABEL: sitofp_i64_float: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfprd f0, r3 +; CHECK-NEXT: xscvsxdsp f1, f0 +; CHECK-NEXT: blr +entry: + %conv = sitofp i64 %i to float + ret float %conv +} + +define double @sitofp_i64_double(i64 %i) { +; CHECK-LABEL: sitofp_i64_double: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfprd f0, r3 +; CHECK-NEXT: xscvsxddp f1, f0 +; CHECK-NEXT: blr +entry: + %conv = sitofp i64 %i to double + ret double %conv +} + +define float @uitofp_i64_float(i64 %i) { +; CHECK-LABEL: uitofp_i64_float: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfprd f0, r3 +; CHECK-NEXT: xscvuxdsp f1, f0 +; CHECK-NEXT: blr +entry: + %conv = uitofp i64 %i to float + ret float %conv +} + +define double @uitofp_i64_double(i64 %i) { +; CHECK-LABEL: uitofp_i64_double: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfprd f0, r3 +; CHECK-NEXT: xscvuxddp f1, f0 +; CHECK-NEXT: blr +entry: + %conv = uitofp i64 %i to double + ret double %conv +}