[ARM] GlobalISel: Add FPR reg bank

Add a register bank for floating point values and select simple instructions
using them (add, copies from GPR).

This assumes that the hardware can cope with a single precision add (VADDS)
instruction, so the legalizer will treat G_FADD as legal and the instruction
selector will refuse to select if the hardware doesn't support it. In the future
we'll want to be more careful about this, and legalize to libcalls if we have to
use soft float.

llvm-svn: 294442
This commit is contained in:
Diana Picus 2017-02-08 13:23:04 +00:00
parent e22fbcb264
commit 4fa83c03fd
7 changed files with 122 additions and 2 deletions

View File

@ -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).

View File

@ -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();
}

View File

@ -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;

View File

@ -11,3 +11,4 @@
//===----------------------------------------------------------------------===//
def GPRRegBank : RegisterBank<"GPRB", [GPR, GPRwithAPSR]>;
def FPRRegBank : RegisterBank<"FPRB", [SPR]>;

View File

@ -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

View File

@ -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
...

View File

@ -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
...