diff --git a/llvm/lib/Target/ARM/ARMInstructionSelector.cpp b/llvm/lib/Target/ARM/ARMInstructionSelector.cpp index 538060d4334b..dcdd0e83550f 100644 --- a/llvm/lib/Target/ARM/ARMInstructionSelector.cpp +++ b/llvm/lib/Target/ARM/ARMInstructionSelector.cpp @@ -54,9 +54,17 @@ static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, DstSize <= SrcSize)) && "Copy with different width?!"); - assert(RegBank->getID() == ARM::GPRRegBankID && "Unsupported reg bank"); + assert((RegBank->getID() == ARM::GPRRegBankID || + RegBank->getID() == ARM::FPRRegBankID) && + "Unsupported reg bank"); + const TargetRegisterClass *RC = &ARM::GPRRegClass; + if (RegBank->getID() == ARM::FPRRegBankID) { + assert(DstSize == 32 && "Only 32-bit FP values are supported"); + RC = &ARM::SPRRegClass; + } + // No need to constrain SrcReg. It will get constrained when // we hit another of its uses or its defs. // Copies do not have constraints. @@ -177,6 +185,13 @@ bool ARMInstructionSelector::select(MachineInstr &I) const { I.setDesc(TII.get(ARM::ADDrr)); MIB.add(predOps(ARMCC::AL)).add(condCodeOp()); break; + case G_FADD: + if (!TII.getSubtarget().hasVFP2() || + TII.getSubtarget().useNEONForSinglePrecisionFP()) + return false; + I.setDesc(TII.get(ARM::VADDS)); + MIB.add(predOps(ARMCC::AL)); + break; case G_FRAME_INDEX: // Add 0 to the given frame index and hope it will eventually be folded into // the user(s). diff --git a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp index d1276df57b18..af44cbf50f05 100644 --- a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp +++ b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp @@ -48,5 +48,9 @@ ARMLegalizerInfo::ARMLegalizerInfo() { setAction({Op, 1, Ty}, Legal); } + // FIXME: This is a bit sloppy, but for now we'll just rely on the instruction + // selector to complain if it doesn't support floating point. + setAction({G_FADD, s32}, Legal); + computeTables(); } diff --git a/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp b/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp index f65b6787697b..dc111069921b 100644 --- a/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp +++ b/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp @@ -33,9 +33,11 @@ using namespace llvm; namespace llvm { namespace ARM { RegisterBankInfo::PartialMapping GPRPartialMapping{0, 32, GPRRegBank}; +RegisterBankInfo::PartialMapping FPRPartialMapping{0, 32, FPRRegBank}; RegisterBankInfo::ValueMapping ValueMappings[] = { - {&GPRPartialMapping, 1}, {&GPRPartialMapping, 1}, {&GPRPartialMapping, 1}}; + {&GPRPartialMapping, 1}, {&GPRPartialMapping, 1}, {&GPRPartialMapping, 1}, + {&FPRPartialMapping, 1}, {&FPRPartialMapping, 1}, {&FPRPartialMapping, 1}}; } // end namespace arm } // end namespace llvm @@ -82,6 +84,9 @@ const RegisterBank &ARMRegisterBankInfo::getRegBankFromRegClass( case GPRnopcRegClassID: case tGPR_and_tcGPRRegClassID: return getRegBank(ARM::GPRRegBankID); + case SPR_8RegClassID: + case SPRRegClassID: + return getRegBank(ARM::FPRRegBankID); default: llvm_unreachable("Unsupported register kind"); } @@ -115,6 +120,9 @@ ARMRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { // the real world we would use different mappings. OperandsMapping = &ARM::ValueMappings[0]; break; + case G_FADD: + OperandsMapping = &ARM::ValueMappings[3]; + break; case G_FRAME_INDEX: OperandsMapping = getOperandsMapping({&ARM::ValueMappings[0], nullptr}); break; diff --git a/llvm/lib/Target/ARM/ARMRegisterBanks.td b/llvm/lib/Target/ARM/ARMRegisterBanks.td index a2b3a7943c16..b8e0347ef62d 100644 --- a/llvm/lib/Target/ARM/ARMRegisterBanks.td +++ b/llvm/lib/Target/ARM/ARMRegisterBanks.td @@ -11,3 +11,4 @@ //===----------------------------------------------------------------------===// def GPRRegBank : RegisterBank<"GPRB", [GPR, GPRwithAPSR]>; +def FPRRegBank : RegisterBank<"FPRB", [SPR]>; diff --git a/llvm/test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir b/llvm/test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir index ab2ddf88ff39..8d18513766d3 100644 --- a/llvm/test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir +++ b/llvm/test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir @@ -9,7 +9,11 @@ define void @test_add_s16() { ret void } define void @test_add_s32() { ret void } + define void @test_fadd_s32() #0 { ret void } + define void @test_load_from_stack() { ret void } + + attributes #0 = { "target-features"="+vfp2" } ... --- name: test_zext_s1 @@ -217,6 +221,39 @@ body: | ; CHECK: BX_RET 14, _, implicit %r0 ... --- +name: test_fadd_s32 +# CHECK-LABEL: name: test_fadd_s32 +legalized: true +regBankSelected: true +selected: false +# CHECK: selected: true +registers: + - { id: 0, class: fprb } + - { id: 1, class: fprb } + - { id: 2, class: fprb } +# CHECK: id: 0, class: spr +# CHECK: id: 1, class: spr +# CHECK: id: 2, class: spr +body: | + bb.0: + liveins: %s0, %s1 + + %0(s32) = COPY %s0 + ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0 + + %1(s32) = COPY %s1 + ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1 + + %2(s32) = G_FADD %0, %1 + ; CHECK: [[VREGSUM:%[0-9]+]] = VADDS [[VREGX]], [[VREGY]], 14, _ + + %s0 = COPY %2(s32) + ; CHECK: %s0 = COPY [[VREGSUM]] + + BX_RET 14, _, implicit %s0 + ; CHECK: BX_RET 14, _, implicit %s0 +... +--- name: test_load_from_stack # CHECK-LABEL: name: test_load_from_stack legalized: true diff --git a/llvm/test/CodeGen/ARM/GlobalISel/arm-legalizer.mir b/llvm/test/CodeGen/ARM/GlobalISel/arm-legalizer.mir index 249a0b037952..f187e8869300 100644 --- a/llvm/test/CodeGen/ARM/GlobalISel/arm-legalizer.mir +++ b/llvm/test/CodeGen/ARM/GlobalISel/arm-legalizer.mir @@ -9,6 +9,8 @@ define void @test_load_from_stack() { ret void } define void @test_legal_loads() { ret void } + + define void @test_fadd_s32() { ret void } ... --- name: test_sext_s8 @@ -190,3 +192,28 @@ body: | %5(p0) = G_LOAD %0(p0) BX_RET 14, _ ... +--- +name: test_fadd_s32 +# CHECK-LABEL: name: test_fadd_s32 +legalized: false +# CHECK: legalized: true +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +body: | + bb.0: + liveins: %r0, %r1 + + %0(s32) = COPY %r0 + %1(s32) = COPY %r1 + %2(s32) = G_FADD %0, %1 + ; G_FADD with s32 is legal, so we should find it unchanged in the output + ; CHECK: {{%[0-9]+}}(s32) = G_FADD {{%[0-9]+, %[0-9]+}} + %r0 = COPY %2(s32) + BX_RET 14, _, implicit %r0 + +... diff --git a/llvm/test/CodeGen/ARM/GlobalISel/arm-regbankselect.mir b/llvm/test/CodeGen/ARM/GlobalISel/arm-regbankselect.mir index ba6880f3e433..c66aa3cb937d 100644 --- a/llvm/test/CodeGen/ARM/GlobalISel/arm-regbankselect.mir +++ b/llvm/test/CodeGen/ARM/GlobalISel/arm-regbankselect.mir @@ -6,6 +6,8 @@ define void @test_add_s1() { ret void } define void @test_loads() { ret void } + + define void @test_fadd_s32() { ret void } ... --- name: test_add_s32 @@ -144,3 +146,29 @@ body: | BX_RET 14, _, implicit %r0 ... +--- +name: test_fadd_s32 +# CHECK-LABEL: name: test_fadd_s32 +legalized: true +regBankSelected: false +selected: false +# CHECK: registers: +# CHECK: - { id: 0, class: fprb } +# CHECK: - { id: 1, class: fprb } +# CHECK: - { id: 2, class: fprb } + +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +body: | + bb.0: + liveins: %r0, %r1 + + %0(s32) = COPY %s0 + %1(s32) = COPY %s1 + %2(s32) = G_FADD %0, %1 + %s0 = COPY %2(s32) + BX_RET 14, _, implicit %r0 + +...