From f488f84a49dd8f3f7c86925d62ad65948bd13969 Mon Sep 17 00:00:00 2001 From: Jessica Paquette Date: Wed, 1 May 2019 22:39:43 +0000 Subject: [PATCH] [GlobalISel][AArch64] Use fmov for G_FCONSTANT when possible This adds support for using fmov rather than a standard mov to materialize G_FCONSTANT when it's safe to do so. Update arm64-fast-isel-materialize.ll and select-constant.mir to show that the selection is correct. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@359734 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../AArch64/AArch64InstructionSelector.cpp | 48 ++++++++++++++++++- .../AArch64/GlobalISel/select-constant.mir | 10 ++-- .../AArch64/arm64-fast-isel-materialize.ll | 11 +++++ 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/lib/Target/AArch64/AArch64InstructionSelector.cpp b/lib/Target/AArch64/AArch64InstructionSelector.cpp index ae668ddac40..76bbd9489af 100644 --- a/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ b/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -118,6 +118,12 @@ private: unsigned VecReg, unsigned LaneIdx, MachineIRBuilder &MIRBuilder) const; + /// Helper function for selecting G_FCONSTANT. If the G_FCONSTANT can be + /// materialized using a FMOV instruction, then update MI and return it. + /// Otherwise, do nothing and return a nullptr. + MachineInstr *emitFMovForFConstant(MachineInstr &MI, + MachineRegisterInfo &MRI) const; + ComplexRendererFns selectArithImmed(MachineOperand &Root) const; ComplexRendererFns selectAddrModeUnscaled(MachineOperand &Root, @@ -1178,14 +1184,18 @@ bool AArch64InstructionSelector::select(MachineInstr &I, const unsigned MovOpc = DefSize == 32 ? AArch64::MOVi32imm : AArch64::MOVi64imm; - I.setDesc(TII.get(MovOpc)); - if (isFP) { + // Either emit a FMOV, or emit a copy to emit a normal mov. const TargetRegisterClass &GPRRC = DefSize == 32 ? AArch64::GPR32RegClass : AArch64::GPR64RegClass; const TargetRegisterClass &FPRRC = DefSize == 32 ? AArch64::FPR32RegClass : AArch64::FPR64RegClass; + // Can we use a FMOV instruction to represent the immediate? + if (emitFMovForFConstant(I, MRI)) + return true; + + // Nope. Emit a copy and use a normal mov instead. const unsigned DefGPRReg = MRI.createVirtualRegister(&GPRRC); MachineOperand &RegOp = I.getOperand(0); RegOp.setReg(DefGPRReg); @@ -1209,6 +1219,7 @@ bool AArch64InstructionSelector::select(MachineInstr &I, I.getOperand(1).ChangeToImmediate(Val); } + I.setDesc(TII.get(MovOpc)); constrainSelectedInstRegOperands(I, TII, TRI, RBI); return true; } @@ -2716,6 +2727,39 @@ MachineInstr *AArch64InstructionSelector::emitVectorConcat( return &*InsElt; } +MachineInstr *AArch64InstructionSelector::emitFMovForFConstant( + MachineInstr &I, MachineRegisterInfo &MRI) const { + assert(I.getOpcode() == TargetOpcode::G_FCONSTANT && + "Expected a G_FCONSTANT!"); + MachineOperand &ImmOp = I.getOperand(1); + unsigned DefSize = MRI.getType(I.getOperand(0).getReg()).getSizeInBits(); + + // Only handle 32 and 64 bit defs for now. + if (DefSize != 32 && DefSize != 64) + return nullptr; + + // Don't handle null values using FMOV. + if (ImmOp.getFPImm()->isNullValue()) + return nullptr; + + // Get the immediate representation for the FMOV. + const APFloat &ImmValAPF = ImmOp.getFPImm()->getValueAPF(); + int Imm = DefSize == 32 ? AArch64_AM::getFP32Imm(ImmValAPF) + : AArch64_AM::getFP64Imm(ImmValAPF); + + // If this is -1, it means the immediate can't be represented as the requested + // floating point value. Bail. + if (Imm == -1) + return nullptr; + + // Update MI to represent the new FMOV instruction, constrain it, and return. + ImmOp.ChangeToImmediate(Imm); + unsigned MovOpc = DefSize == 32 ? AArch64::FMOVSi : AArch64::FMOVDi; + I.setDesc(TII.get(MovOpc)); + constrainSelectedInstRegOperands(I, TII, TRI, RBI); + return &I; +} + bool AArch64InstructionSelector::tryOptVectorDup(MachineInstr &I) const { // Try to match a vector splat operation into a dup instruction. // We're looking for this pattern: diff --git a/test/CodeGen/AArch64/GlobalISel/select-constant.mir b/test/CodeGen/AArch64/GlobalISel/select-constant.mir index e046aa290c1..234957a8f8e 100644 --- a/test/CodeGen/AArch64/GlobalISel/select-constant.mir +++ b/test/CodeGen/AArch64/GlobalISel/select-constant.mir @@ -55,9 +55,8 @@ registers: body: | bb.0: ; CHECK-LABEL: name: fconst_s32 - ; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1080033280 - ; CHECK: [[COPY:%[0-9]+]]:fpr32 = COPY [[MOVi32imm]] - ; CHECK: $s0 = COPY [[COPY]] + ; CHECK: [[FMOVSi:%[0-9]+]]:fpr32 = FMOVSi 12 + ; CHECK: $s0 = COPY [[FMOVSi]] %0(s32) = G_FCONSTANT float 3.5 $s0 = COPY %0(s32) ... @@ -72,9 +71,8 @@ registers: body: | bb.0: ; CHECK-LABEL: name: fconst_s64 - ; CHECK: [[MOVi64imm:%[0-9]+]]:gpr64 = MOVi64imm 4607182418800017408 - ; CHECK: [[COPY:%[0-9]+]]:fpr64 = COPY [[MOVi64imm]] - ; CHECK: $d0 = COPY [[COPY]] + ; CHECK: [[FMOVDi:%[0-9]+]]:fpr64 = FMOVDi 112 + ; CHECK: $d0 = COPY [[FMOVDi]] %0(s64) = G_FCONSTANT double 1.0 $d0 = COPY %0(s64) ... diff --git a/test/CodeGen/AArch64/arm64-fast-isel-materialize.ll b/test/CodeGen/AArch64/arm64-fast-isel-materialize.ll index 234731cfa24..3a8a31be152 100644 --- a/test/CodeGen/AArch64/arm64-fast-isel-materialize.ll +++ b/test/CodeGen/AArch64/arm64-fast-isel-materialize.ll @@ -1,27 +1,38 @@ ; RUN: llc -O0 -fast-isel -fast-isel-abort=1 -verify-machineinstrs -mtriple=arm64-apple-darwin < %s | FileCheck %s +; RUN: llc -O0 -global-isel -fast-isel-abort=2 -pass-remarks-missed=gisel* -verify-machineinstrs -mtriple=arm64-apple-darwin %s -o - 2>&1 | FileCheck %s --check-prefixes=GISEL,FALLBACK + +; FALLBACK-NOT: remark: ; Materialize using fmov define float @fmov_float1() { ; CHECK-LABEL: fmov_float1 ; CHECK: fmov s0, #1.25000000 +; GISEL-LABEL: fmov_float1 +; GISEL: fmov s0, #1.25000000 ret float 1.250000e+00 } define float @fmov_float2() { ; CHECK-LABEL: fmov_float2 ; CHECK: fmov s0, wzr +; GISEL-LABEL: fmov_float2 +; GISEL: fmov s0, wzr ret float 0.0e+00 } define double @fmov_double1() { ; CHECK-LABEL: fmov_double1 ; CHECK: fmov d0, #1.25000000 +; GISEL-LABEL: fmov_double1 +; GISEL: fmov d0, #1.25000000 ret double 1.250000e+00 } define double @fmov_double2() { ; CHECK-LABEL: fmov_double2 ; CHECK: fmov d0, xzr +; GISEL-LABEL: fmov_double2 +; GISEL: fmov d0, xzr ret double 0.0e+00 } -- 2.50.1