From 39382427f1095f089d73a7dd3d9a371dea75b781 Mon Sep 17 00:00:00 2001 From: Evan Cheng Date: Wed, 28 Oct 2009 01:44:26 +0000 Subject: [PATCH] Use fconsts and fconstd to materialize small fp constants. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@85362 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMISelLowering.cpp | 57 +++++++++++++++++++++ lib/Target/ARM/ARMISelLowering.h | 13 +++++ lib/Target/ARM/ARMInstrVFP.td | 44 ++++++++++++++++ lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp | 39 +++++++++++--- lib/Target/ARM/AsmPrinter/ARMInstPrinter.h | 2 + test/CodeGen/ARM/fpconsts.ll | 33 ++++++++++++ 6 files changed, 182 insertions(+), 6 deletions(-) create mode 100644 test/CodeGen/ARM/fpconsts.ll diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 6a264fdfc44..5f4b4365fdf 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -3990,3 +3990,60 @@ ARMTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { // The ARM target isn't yet aware of offsets. return false; } + +int ARM::getVFPf32Imm(const APFloat &FPImm) { + APInt Imm = FPImm.bitcastToAPInt(); + uint32_t Sign = Imm.lshr(31).getZExtValue() & 1; + int32_t Exp = (Imm.lshr(23).getSExtValue() & 0xff) - 127; // -126 to 127 + int64_t Mantissa = Imm.getZExtValue() & 0x7fffff; // 23 bits + + // We can handle 4 bits of mantissa. + // mantissa = (16+UInt(e:f:g:h))/16. + if (Mantissa & 0x7ffff) + return -1; + Mantissa >>= 19; + if ((Mantissa & 0xf) != Mantissa) + return -1; + + // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 + if (Exp < -3 || Exp > 4) + return -1; + Exp = ((Exp+3) & 0x7) ^ 4; + + return ((int)Sign << 7) | (Exp << 4) | Mantissa; +} + +int ARM::getVFPf64Imm(const APFloat &FPImm) { + APInt Imm = FPImm.bitcastToAPInt(); + uint64_t Sign = Imm.lshr(63).getZExtValue() & 1; + int64_t Exp = (Imm.lshr(52).getSExtValue() & 0x7ff) - 1023; // -1022 to 1023 + uint64_t Mantissa = Imm.getZExtValue() & 0xfffffffffffffLL; + + // We can handle 4 bits of mantissa. + // mantissa = (16+UInt(e:f:g:h))/16. + if (Mantissa & 0xffffffffffffLL) + return -1; + Mantissa >>= 48; + if ((Mantissa & 0xf) != Mantissa) + return -1; + + // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 + if (Exp < -3 || Exp > 4) + return -1; + Exp = ((Exp+3) & 0x7) ^ 4; + + return ((int)Sign << 7) | (Exp << 4) | Mantissa; +} + +/// isFPImmLegal - Returns true if the target can instruction select the +/// specified FP immediate natively. If false, the legalizer will +/// materialize the FP immediate as a load from a constant pool. +bool ARMTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { + if (!Subtarget->hasVFP3()) + return false; + if (VT == MVT::f32) + return ARM::getVFPf32Imm(Imm) != -1; + if (VT == MVT::f64) + return ARM::getVFPf64Imm(Imm) != -1; + return false; +} diff --git a/lib/Target/ARM/ARMISelLowering.h b/lib/Target/ARM/ARMISelLowering.h index 7d85f458d8e..ac962c1a8a2 100644 --- a/lib/Target/ARM/ARMISelLowering.h +++ b/lib/Target/ARM/ARMISelLowering.h @@ -137,6 +137,13 @@ namespace llvm { /// return the constant being splatted. The ByteSize field indicates the /// number of bytes of each element [1248]. SDValue getVMOVImm(SDNode *N, unsigned ByteSize, SelectionDAG &DAG); + + /// getVFPf32Imm / getVFPf64Imm - If the given fp immediate can be + /// materialized with a VMOV.f32 / VMOV.f64 (i.e. fconsts / fconstd) + /// instruction, returns its 8-bit integer representation. Otherwise, + /// returns -1. + int getVFPf32Imm(const APFloat &FPImm); + int getVFPf64Imm(const APFloat &FPImm); } //===--------------------------------------------------------------------===// @@ -224,6 +231,12 @@ namespace llvm { bool isShuffleMaskLegal(const SmallVectorImpl &M, EVT VT) const; bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; + + /// isFPImmLegal - Returns true if the target can instruction select the + /// specified FP immediate natively. If false, the legalizer will + /// materialize the FP immediate as a load from a constant pool. + virtual bool isFPImmLegal(const APFloat &Imm, EVT VT) const; + private: /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can /// make the right decision when generating code for different targets. diff --git a/lib/Target/ARM/ARMInstrVFP.td b/lib/Target/ARM/ARMInstrVFP.td index f994190b90d..b739c639ad4 100644 --- a/lib/Target/ARM/ARMInstrVFP.td +++ b/lib/Target/ARM/ARMInstrVFP.td @@ -30,6 +30,26 @@ def arm_cmpfp : SDNode<"ARMISD::CMPFP", SDT_ARMCmp, [SDNPOutFlag]>; def arm_cmpfp0 : SDNode<"ARMISD::CMPFPw0",SDT_CMPFP0, [SDNPOutFlag]>; def arm_fmdrr : SDNode<"ARMISD::FMDRR", SDT_FMDRR>; +//===----------------------------------------------------------------------===// +// Operand Definitions. +// + + +def vfp_f32imm : Operand, + PatLeaf<(f32 fpimm), [{ + return ARM::getVFPf32Imm(N->getValueAPF()) != -1; + }]> { + let PrintMethod = "printVFPf32ImmOperand"; +} + +def vfp_f64imm : Operand, + PatLeaf<(f64 fpimm), [{ + return ARM::getVFPf64Imm(N->getValueAPF()) != -1; + }]> { + let PrintMethod = "printVFPf64ImmOperand"; +} + + //===----------------------------------------------------------------------===// // Load / store Instructions. // @@ -408,3 +428,27 @@ def FMSTAT : VFPAI<(outs), (ins), VFPMiscFrm, IIC_fpSTAT, "fmstat", "", let Inst{7} = 0; let Inst{4} = 1; } + + +// Materialize FP immediates. VFP3 only. +def FCONSTS : VFPAI<(outs SPR:$dst), (ins vfp_f32imm:$imm), + VFPMiscFrm, IIC_VMOVImm, + "fconsts", "\t$dst, $imm", + [(set SPR:$dst, vfp_f32imm:$imm)]>, Requires<[HasVFP3]> { + let Inst{27-23} = 0b11101; + let Inst{21-20} = 0b11; + let Inst{11-9} = 0b101; + let Inst{8} = 0; + let Inst{7-4} = 0b0000; +} + +def FCONSTD : VFPAI<(outs DPR:$dst), (ins vfp_f64imm:$imm), + VFPMiscFrm, IIC_VMOVImm, + "fconstd", "\t$dst, $imm", + [(set DPR:$dst, vfp_f64imm:$imm)]>, Requires<[HasVFP3]> { + let Inst{27-23} = 0b11101; + let Inst{21-20} = 0b11; + let Inst{11-9} = 0b101; + let Inst{8} = 1; + let Inst{7-4} = 0b0000; +} diff --git a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp index d017f742bc2..8cbc4201587 100644 --- a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp @@ -135,6 +135,8 @@ namespace { void printJT2BlockOperand(const MachineInstr *MI, int OpNum); void printTBAddrMode(const MachineInstr *MI, int OpNum); void printNoHashImmediate(const MachineInstr *MI, int OpNum); + void printVFPf32ImmOperand(const MachineInstr *MI, int OpNum); + void printVFPf64ImmOperand(const MachineInstr *MI, int OpNum); virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode); @@ -393,9 +395,11 @@ static void printSOImm(formatted_raw_ostream &O, int64_t V, bool VerboseAsm, if (Rot) { O << "#" << Imm << ", " << Rot; // Pretty printed version. - if (VerboseAsm) - O << ' ' << MAI->getCommentString() - << ' ' << (int)ARM_AM::rotr32(Imm, Rot); + if (VerboseAsm) { + O.PadToColumn(MAI->getCommentColumn()); + O << MAI->getCommentString() << ' '; + O << (int)ARM_AM::rotr32(Imm, Rot); + } } else { O << "#" << Imm; } @@ -970,6 +974,26 @@ void ARMAsmPrinter::printNoHashImmediate(const MachineInstr *MI, int OpNum) { O << MI->getOperand(OpNum).getImm(); } +void ARMAsmPrinter::printVFPf32ImmOperand(const MachineInstr *MI, int OpNum) { + const ConstantFP *FP = MI->getOperand(OpNum).getFPImm(); + O << ARM::getVFPf32Imm(FP->getValueAPF()); + if (VerboseAsm) { + O.PadToColumn(MAI->getCommentColumn()); + O << MAI->getCommentString() << ' '; + WriteAsOperand(O, FP, /*PrintType=*/false); + } +} + +void ARMAsmPrinter::printVFPf64ImmOperand(const MachineInstr *MI, int OpNum) { + const ConstantFP *FP = MI->getOperand(OpNum).getFPImm(); + O << ARM::getVFPf64Imm(FP->getValueAPF()); + if (VerboseAsm) { + O.PadToColumn(MAI->getCommentColumn()); + O << MAI->getCommentString() << ' '; + WriteAsOperand(O, FP, /*PrintType=*/false); + } +} + bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode){ // Does this asm operand have a single letter operand modifier? @@ -1182,7 +1206,8 @@ void ARMAsmPrinter::PrintGlobalVariable(const GlobalVariable* GVar) { EmitAlignment(Align, GVar); O << name << ":"; if (VerboseAsm) { - O << "\t\t\t\t" << MAI->getCommentString() << ' '; + O.PadToColumn(MAI->getCommentColumn()); + O << MAI->getCommentString() << ' '; WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent()); } O << '\n'; @@ -1205,7 +1230,8 @@ void ARMAsmPrinter::PrintGlobalVariable(const GlobalVariable* GVar) { O << "," << (MAI->getAlignmentIsInBytes() ? (1 << Align) : Align); } if (VerboseAsm) { - O << "\t\t" << MAI->getCommentString() << " "; + O.PadToColumn(MAI->getCommentColumn()); + O << MAI->getCommentString() << ' '; WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent()); } O << "\n"; @@ -1243,7 +1269,8 @@ void ARMAsmPrinter::PrintGlobalVariable(const GlobalVariable* GVar) { EmitAlignment(Align, GVar); O << name << ":"; if (VerboseAsm) { - O << "\t\t\t\t" << MAI->getCommentString() << " "; + O.PadToColumn(MAI->getCommentColumn()); + O << MAI->getCommentString() << ' '; WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent()); } O << "\n"; diff --git a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h index 492513768b2..5bf966b8272 100644 --- a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h +++ b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h @@ -78,6 +78,8 @@ public: void printJT2BlockOperand(const MCInst *MI, unsigned OpNum) {} void printTBAddrMode(const MCInst *MI, unsigned OpNum) {} void printNoHashImmediate(const MCInst *MI, unsigned OpNum); + void printVFPf32ImmOperand(const MCInst *MI, int OpNum) {} + void printVFPf64ImmOperand(const MCInst *MI, int OpNum) {} void printPCLabel(const MCInst *MI, unsigned OpNum); // FIXME: Implement. diff --git a/test/CodeGen/ARM/fpconsts.ll b/test/CodeGen/ARM/fpconsts.ll new file mode 100644 index 00000000000..6a3a6d815d8 --- /dev/null +++ b/test/CodeGen/ARM/fpconsts.ll @@ -0,0 +1,33 @@ +; RUN: llc < %s -march=arm -mattr=+vfp3 | FileCheck %s + +define arm_apcscc float @t1(float %x) nounwind readnone optsize { +entry: +; CHECK: t1: +; CHECK: fconsts s1, 16 + %0 = fadd float %x, 4.000000e+00 + ret float %0 +} + +define arm_apcscc double @t2(double %x) nounwind readnone optsize { +entry: +; CHECK: t2: +; CHECK: fconstd d1, 8 + %0 = fadd double %x, 3.000000e+00 + ret double %0 +} + +define arm_apcscc double @t3(double %x) nounwind readnone optsize { +entry: +; CHECK: t3: +; CHECK: fconstd d1, 170 + %0 = fmul double %x, -1.300000e+01 + ret double %0 +} + +define arm_apcscc float @t4(float %x) nounwind readnone optsize { +entry: +; CHECK: t4: +; CHECK: fconsts s1, 184 + %0 = fmul float %x, -2.400000e+01 + ret float %0 +}