diff --git a/llvm/lib/Target/PowerPC/GISel/PPCGenRegisterBankInfo.def b/llvm/lib/Target/PowerPC/GISel/PPCGenRegisterBankInfo.def --- a/llvm/lib/Target/PowerPC/GISel/PPCGenRegisterBankInfo.def +++ b/llvm/lib/Target/PowerPC/GISel/PPCGenRegisterBankInfo.def @@ -16,6 +16,10 @@ /* StartIdx, Length, RegBank */ // 0: GPR 64-bit value. {0, 64, PPC::GPRRegBank}, + // 1: FPR 32-bit value + {0, 32, PPC::FPRRegBank}, + // 2: FPR 64-bit value + {0, 64, PPC::FPRRegBank}, }; // ValueMappings. @@ -37,6 +41,14 @@ {&PPCGenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1}, {&PPCGenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1}, {&PPCGenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1}, + // 2: FPR 32-bit value. + {&PPCGenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1}, + {&PPCGenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1}, + {&PPCGenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1}, + // 3: FPR 64-bit value. + {&PPCGenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1}, + {&PPCGenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1}, + {&PPCGenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1}, }; // TODO Too simple! 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 @@ -75,18 +75,49 @@ { } +static const TargetRegisterClass *getRegClass(LLT Ty, const RegisterBank *RB) { + if (RB->getID() == PPC::GPRRegBankID) { + if (Ty.getSizeInBits() == 64) + return &PPC::G8RCRegClass; + } + if (RB->getID() == PPC::FPRRegBankID) { + if (Ty.getSizeInBits() == 32) + return &PPC::F4RCRegClass; + if (Ty.getSizeInBits() == 64) + return &PPC::F8RCRegClass; + } + + llvm_unreachable("Unknown RegBank!"); +} + static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) { Register DstReg = I.getOperand(0).getReg(); - Register SrcReg = I.getOperand(1).getReg(); - if (!Register::isPhysicalRegister(DstReg)) - if (!RBI.constrainGenericRegister(DstReg, PPC::G8RCRegClass, MRI)) - return false; - if (!Register::isPhysicalRegister(SrcReg)) - if (!RBI.constrainGenericRegister(SrcReg, PPC::G8RCRegClass, MRI)) + if (DstReg.isPhysical()) + return true; + + const RegisterBank *DstRegBank = RBI.getRegBank(DstReg, MRI, TRI); + const TargetRegisterClass *DstRC = + getRegClass(MRI.getType(DstReg), DstRegBank); + + // No need to constrain SrcReg. It will get constrained when we hit another of + // its use or its defs. + // Copies do not have constraints. + const TargetRegisterClass *OldRC = MRI.getRegClassOrNull(DstReg); + + // We need to (further) constrain the DstReg if: + // 1: There is no register class for the DstReg in the COPY instruction. + // 2: Or the register class for the DstReg in the COPY instruction is a super + // class of the one inferred from the register bank. + if (!OldRC || !DstRC->hasSubClassEq(OldRC)) { + if (!RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { + LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) + << " operand\n"); return false; + } + } return true; } 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 @@ -19,6 +19,7 @@ PPCLegalizerInfo::PPCLegalizerInfo(const PPCSubtarget &ST) { using namespace TargetOpcode; + const LLT S32 = LLT::scalar(32); const LLT S64 = LLT::scalar(64); getActionDefinitionsBuilder(G_IMPLICIT_DEF).legalFor({S64}); getActionDefinitionsBuilder(G_CONSTANT) @@ -27,5 +28,9 @@ getActionDefinitionsBuilder({G_AND, G_OR, G_XOR}) .legalFor({S64}) .clampScalar(0, S64, S64); + + getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV}) + .legalFor({S32, S64}); + getLegacyLegalizerInfo().computeTables(); } diff --git a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h --- a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h +++ b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h @@ -29,6 +29,8 @@ enum PartialMappingIdx { PMI_None = -1, PMI_GPR64 = 1, + PMI_FPR32 = 2, + PMI_FPR64 = 3, PMI_Min = PMI_GPR64, }; 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 @@ -36,6 +36,15 @@ case PPC::G8RC_NOX0RegClassID: case PPC::G8RC_and_G8RC_NOX0RegClassID: return getRegBank(PPC::GPRRegBankID); + case PPC::VSFRCRegClassID: + case PPC::SPILLTOVSRRC_and_VSFRCRegClassID: + case PPC::SPILLTOVSRRC_and_VFRCRegClassID: + case PPC::SPILLTOVSRRC_and_F4RCRegClassID: + case PPC::F8RCRegClassID: + case PPC::VFRCRegClassID: + case PPC::VSSRCRegClassID: + case PPC::F4RCRegClassID: + return getRegBank(PPC::FPRRegBankID); default: llvm_unreachable("Unexpected register class"); } @@ -47,8 +56,7 @@ // Try the default logic for non-generic instructions that are either copies // or already have some operands assigned to banks. - if ((Opc != TargetOpcode::COPY && !isPreISelGenericOpcode(Opc)) || - Opc == TargetOpcode::G_PHI) { + if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) { const RegisterBankInfo::InstructionMapping &Mapping = getInstrMappingImpl(MI); if (Mapping.isValid()) @@ -74,26 +82,20 @@ "This code is for instructions with 3 or less operands"); OperandsMapping = getValueMapping(PMI_GPR64); break; - case TargetOpcode::G_CONSTANT: - OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr}); - break; - case TargetOpcode::COPY: { - Register DstReg = MI.getOperand(0).getReg(); + case TargetOpcode::G_FADD: + case TargetOpcode::G_FSUB: + case TargetOpcode::G_FMUL: + case TargetOpcode::G_FDIV: { Register SrcReg = MI.getOperand(1).getReg(); - const RegisterBank *DstRB = getRegBank(DstReg, MRI, TRI); - const RegisterBank *SrcRB = getRegBank(SrcReg, MRI, TRI); - if (!DstRB) - DstRB = SrcRB; - else if (!SrcRB) - SrcRB = DstRB; - assert(DstRB && SrcRB && "Both RegBank were nullptr"); - unsigned Size = getSizeInBits(DstReg, MRI, TRI); - Cost = copyCost(*DstRB, *SrcRB, Size); - OperandsMapping = getCopyMapping(DstRB->getID(), SrcRB->getID(), Size); - // We only care about the mapping of the destination. - NumOperands = 1; + unsigned Size = getSizeInBits(SrcReg, MRI, TRI); + + assert((Size == 32 || Size == 64) && "Unsupported floating point types!\n"); + OperandsMapping = getValueMapping(Size == 32 ? PMI_FPR32 : PMI_FPR64); break; } + case TargetOpcode::G_CONSTANT: + OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr}); + break; default: return getInvalidInstructionMapping(); } diff --git a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td --- a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td +++ b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td @@ -13,3 +13,5 @@ /// General Purpose Registers def GPRRegBank : RegisterBank<"GPR", [G8RC, G8RC_NOX0]>; +/// Floating point Registers +def FPRRegBank : RegisterBank<"FPR", [VSSRC]>; diff --git a/llvm/test/CodeGen/PowerPC/GlobalISel/float-arithmetic.ll b/llvm/test/CodeGen/PowerPC/GlobalISel/float-arithmetic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/GlobalISel/float-arithmetic.ll @@ -0,0 +1,53 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -global-isel -o - \ +; RUN: -ppc-vsr-nums-as-vr -ppc-asm-full-reg-names < %s | FileCheck %s + +define float @float_add(float %a, float %b) { +; CHECK-LABEL: float_add: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xsaddsp f1, f1, f2 +; CHECK-NEXT: blr +entry: + %add = fadd float %a, %b + ret float %add +} + +define double @double_add(double %a, double %b) { +; CHECK-LABEL: double_add: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xsadddp f1, f1, f2 +; CHECK-NEXT: blr +entry: + %add = fadd double %a, %b + ret double %add +} + +define float @float_sub(float %a, float %b) { +; CHECK-LABEL: float_sub: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xssubsp f1, f1, f2 +; CHECK-NEXT: blr +entry: + %sub = fsub float %a, %b + ret float %sub +} + +define float @float_mul(float %a, float %b) { +; CHECK-LABEL: float_mul: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xsmulsp f1, f1, f2 +; CHECK-NEXT: blr +entry: + %mul = fmul float %a, %b + ret float %mul +} + +define float @float_div(float %a, float %b) { +; CHECK-LABEL: float_div: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xsdivsp f1, f1, f2 +; CHECK-NEXT: blr +entry: + %div = fdiv float %a, %b + ret float %div +}