From 4494d69862451827cf0a64a101c279728626fb84 Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Tue, 18 Oct 2016 19:47:57 +0000 Subject: [PATCH] GlobalISel: support floating-point constants on AArch64. Patch from Ahmed Bougacha. llvm-svn: 284523 --- .../Target/AArch64/AArch64InstructionSelector.cpp | 81 ++++++++++++++++++++-- .../AArch64/GlobalISel/arm64-instructionselect.mir | 35 ++++++++++ 2 files changed, 109 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp index 1f2be90..ebfd78b 100644 --- a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -513,14 +513,81 @@ bool AArch64InstructionSelector::select(MachineInstr &I) const { return constrainSelectedInstRegOperands(*MIB.getInstr(), TII, TRI, RBI); } + case TargetOpcode::G_FCONSTANT: case TargetOpcode::G_CONSTANT: { - if (Ty.getSizeInBits() <= 32) - I.setDesc(TII.get(AArch64::MOVi32imm)); - else if (Ty.getSizeInBits() <= 64) - I.setDesc(TII.get(AArch64::MOVi64imm)); - else - return false; - return constrainSelectedInstRegOperands(I, TII, TRI, RBI); + const bool isFP = Opcode == TargetOpcode::G_FCONSTANT; + + const LLT s32 = LLT::scalar(32); + const LLT s64 = LLT::scalar(64); + const LLT p0 = LLT::pointer(0, 64); + + const unsigned DefReg = I.getOperand(0).getReg(); + const LLT DefTy = MRI.getType(DefReg); + const unsigned DefSize = DefTy.getSizeInBits(); + const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI); + + // FIXME: Redundant check, but even less readable when factored out. + if (isFP) { + if (Ty != s32 && Ty != s64) { + DEBUG(dbgs() << "Unable to materialize FP " << Ty + << " constant, expected: " << s32 << " or " << s64 + << '\n'); + return false; + } + + if (RB.getID() != AArch64::FPRRegBankID) { + DEBUG(dbgs() << "Unable to materialize FP " << Ty + << " constant on bank: " << RB << ", expected: FPR\n"); + return false; + } + } else { + if (Ty != s32 && Ty != s64 && Ty != p0) { + DEBUG(dbgs() << "Unable to materialize integer " << Ty + << " constant, expected: " << s32 << ", " << s64 << ", or " + << p0 << '\n'); + return false; + } + + if (RB.getID() != AArch64::GPRRegBankID) { + DEBUG(dbgs() << "Unable to materialize integer " << Ty + << " constant on bank: " << RB << ", expected: GPR\n"); + return false; + } + } + + const unsigned MovOpc = + DefSize == 32 ? AArch64::MOVi32imm : AArch64::MOVi64imm; + + I.setDesc(TII.get(MovOpc)); + + if (isFP) { + const TargetRegisterClass &GPRRC = + DefSize == 32 ? AArch64::GPR32RegClass : AArch64::GPR64RegClass; + const TargetRegisterClass &FPRRC = + DefSize == 32 ? AArch64::FPR32RegClass : AArch64::FPR64RegClass; + + const unsigned DefGPRReg = MRI.createVirtualRegister(&GPRRC); + MachineOperand &RegOp = I.getOperand(0); + RegOp.setReg(DefGPRReg); + + BuildMI(MBB, std::next(I.getIterator()), I.getDebugLoc(), + TII.get(AArch64::COPY)) + .addDef(DefReg) + .addUse(DefGPRReg); + + if (!RBI.constrainGenericRegister(DefReg, FPRRC, MRI)) { + DEBUG(dbgs() << "Failed to constrain G_FCONSTANT def operand\n"); + return false; + } + + MachineOperand &ImmOp = I.getOperand(1); + // FIXME: Is going through int64_t always correct? + ImmOp.ChangeToImmediate( + ImmOp.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue()); + } + + constrainSelectedInstRegOperands(I, TII, TRI, RBI); + return true; } case TargetOpcode::G_FRAME_INDEX: { diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir b/llvm/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir index 2d34dfe..6ea29f0 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir @@ -103,6 +103,9 @@ define i32 @const_s32() { ret i32 42 } define i64 @const_s64() { ret i64 1234567890123 } + define i32 @fconst_s32() { ret i32 42 } + define i64 @fconst_s64() { ret i64 1234567890123 } + define i8* @gep(i8* %in) { ret i8* undef } @var_local = global i8 0 @@ -1879,6 +1882,38 @@ body: | ... --- +# CHECK-LABEL: name: fconst_s32 +name: fconst_s32 +legalized: true +regBankSelected: true +registers: + - { id: 0, class: fpr } + +# CHECK: body: +# CHECK: [[TMP:%[0-9]+]] = MOVi32imm 1080033280 +# CHECK: %0 = COPY [[TMP]] +body: | + bb.0: + %0(s32) = G_FCONSTANT float 3.5 +... + +--- +# CHECK-LABEL: name: fconst_s64 +name: fconst_s64 +legalized: true +regBankSelected: true +registers: + - { id: 0, class: fpr } + +# CHECK: body: +# CHECK: [[TMP:%[0-9]+]] = MOVi64imm 4607182418800017408 +# CHECK: %0 = COPY [[TMP]] +body: | + bb.0: + %0(s64) = G_FCONSTANT double 1.0 +... + +--- # CHECK-LABEL: name: gep name: gep legalized: true -- 2.7.4