diff options
author | Christof Douma <Christof.Douma@arm.com> | 2018-03-23 13:02:03 +0000 |
---|---|---|
committer | Christof Douma <Christof.Douma@arm.com> | 2018-03-23 13:02:03 +0000 |
commit | 4a025cc79d30ba67485cb56639ec89913fce2969 (patch) | |
tree | 48364051d83cdeda06c5044a88a5e6ea04ae59c4 /llvm/lib/Target/ARM | |
parent | f73c3ece7f1004dd5c1b8351a90172258018dd12 (diff) | |
download | bcm5719-llvm-4a025cc79d30ba67485cb56639ec89913fce2969.tar.gz bcm5719-llvm-4a025cc79d30ba67485cb56639ec89913fce2969.zip |
[ARM] Support float literals under XO
When targeting execute-only and fp-armv8, float constants in a compare
resulted in instruction selection failures. This is now fixed by using
vmov.f32 where possible, otherwise the floating point constant is
lowered into a integer constant that is moved into a floating point
register.
This patch also restores using fpcmp with immediate 0 under fp-armv8.
Change-Id: Ie87229706f4ed879a0c0cf66631b6047ed6c6443
llvm-svn: 328313
Diffstat (limited to 'llvm/lib/Target/ARM')
-rw-r--r-- | llvm/lib/Target/ARM/ARMISelLowering.cpp | 37 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMISelLowering.h | 1 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMInstrVFP.td | 4 |
3 files changed, 30 insertions, 12 deletions
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index 762da041244..414ade7fa6f 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -1283,6 +1283,7 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { case ARMISD::VMOVDRR: return "ARMISD::VMOVDRR"; case ARMISD::VMOVhr: return "ARMISD::VMOVhr"; case ARMISD::VMOVrh: return "ARMISD::VMOVrh"; + case ARMISD::VMOVSR: return "ARMISD::VMOVSR"; case ARMISD::EH_SJLJ_SETJMP: return "ARMISD::EH_SJLJ_SETJMP"; case ARMISD::EH_SJLJ_LONGJMP: return "ARMISD::EH_SJLJ_LONGJMP"; @@ -4518,9 +4519,10 @@ SDValue ARMTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const { bool InvalidOnQNaN; FPCCToARMCC(CC, CondCode, CondCode2, InvalidOnQNaN); - // Try to generate VMAXNM/VMINNM on ARMv8. - if (Subtarget->hasFPARMv8() && (TrueVal.getValueType() == MVT::f32 || - TrueVal.getValueType() == MVT::f64)) { + // Try to generate VMAXNM/VMINNM on ARMv8. Except if we compare to a zero. + // This ensures we use CMPFPw0 instead of CMPFP in such case. + if (Subtarget->hasFPARMv8() && !isFloatingPointZero(RHS) && + (TrueVal.getValueType() == MVT::f32 || TrueVal.getValueType() == MVT::f64)) { bool swpCmpOps = false; bool swpVselOps = false; checkVSELConstraints(CC, CondCode, swpCmpOps, swpVselOps); @@ -5942,23 +5944,34 @@ static SDValue isNEONModifiedImm(uint64_t SplatBits, uint64_t SplatUndef, SDValue ARMTargetLowering::LowerConstantFP(SDValue Op, SelectionDAG &DAG, const ARMSubtarget *ST) const { - bool IsDouble = Op.getValueType() == MVT::f64; + EVT VT = Op.getValueType(); + bool IsDouble = (VT == MVT::f64); ConstantFPSDNode *CFP = cast<ConstantFPSDNode>(Op); const APFloat &FPVal = CFP->getValueAPF(); // Prevent floating-point constants from using literal loads // when execute-only is enabled. if (ST->genExecuteOnly()) { + // If we can represent the constant as an immediate, don't lower it + if (isFPImmLegal(FPVal, VT)) + return Op; + // Otherwise, construct as integer, and move to float register APInt INTVal = FPVal.bitcastToAPInt(); SDLoc DL(CFP); - if (IsDouble) { - SDValue Lo = DAG.getConstant(INTVal.trunc(32), DL, MVT::i32); - SDValue Hi = DAG.getConstant(INTVal.lshr(32).trunc(32), DL, MVT::i32); - if (!ST->isLittle()) - std::swap(Lo, Hi); - return DAG.getNode(ARMISD::VMOVDRR, DL, MVT::f64, Lo, Hi); - } else { - return DAG.getConstant(INTVal, DL, MVT::i32); + switch (VT.getSimpleVT().SimpleTy) { + default: + llvm_unreachable("Unknown floating point type!"); + break; + case MVT::f64: { + SDValue Lo = DAG.getConstant(INTVal.trunc(32), DL, MVT::i32); + SDValue Hi = DAG.getConstant(INTVal.lshr(32).trunc(32), DL, MVT::i32); + if (!ST->isLittle()) + std::swap(Lo, Hi); + return DAG.getNode(ARMISD::VMOVDRR, DL, MVT::f64, Lo, Hi); + } + case MVT::f32: + return DAG.getNode(ARMISD::VMOVSR, DL, VT, + DAG.getConstant(INTVal, DL, MVT::i32)); } } diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h index b196e2344ea..d3d3ac29c67 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.h +++ b/llvm/lib/Target/ARM/ARMISelLowering.h @@ -102,6 +102,7 @@ class VectorType; VMOVRRD, // double to two gprs. VMOVDRR, // Two gprs to double. + VMOVSR, // move gpr to single, used for f32 literal constructed in a gpr EH_SJLJ_SETJMP, // SjLj exception handling setjmp. EH_SJLJ_LONGJMP, // SjLj exception handling longjmp. diff --git a/llvm/lib/Target/ARM/ARMInstrVFP.td b/llvm/lib/Target/ARM/ARMInstrVFP.td index 8731a7fdce9..e6a7730d467 100644 --- a/llvm/lib/Target/ARM/ARMInstrVFP.td +++ b/llvm/lib/Target/ARM/ARMInstrVFP.td @@ -17,11 +17,14 @@ def SDT_VMOVDRR : SDTypeProfile<1, 2, [SDTCisVT<0, f64>, SDTCisVT<1, i32>, def SDT_VMOVRRD : SDTypeProfile<2, 1, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>, SDTCisVT<2, f64>]>; +def SDT_VMOVSR : SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisVT<1, i32>]>; + def arm_fmstat : SDNode<"ARMISD::FMSTAT", SDTNone, [SDNPInGlue, SDNPOutGlue]>; def arm_cmpfp : SDNode<"ARMISD::CMPFP", SDT_ARMFCmp, [SDNPOutGlue]>; def arm_cmpfp0 : SDNode<"ARMISD::CMPFPw0", SDT_CMPFP0, [SDNPOutGlue]>; def arm_fmdrr : SDNode<"ARMISD::VMOVDRR", SDT_VMOVDRR>; def arm_fmrrd : SDNode<"ARMISD::VMOVRRD", SDT_VMOVRRD>; +def arm_vmovsr : SDNode<"ARMISD::VMOVSR", SDT_VMOVSR>; def SDT_VMOVhr : SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisVT<1, i32>] >; def SDT_VMOVrh : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisFP<1>] >; @@ -1066,6 +1069,7 @@ def VMOVSR : AVConv4I<0b11100000, 0b1010, // pipelines. let D = VFPNeonDomain; } +def : Pat<(arm_vmovsr GPR:$Rt), (VMOVSR GPR:$Rt)>; let hasSideEffects = 0 in { def VMOVRRD : AVConv3I<0b11000101, 0b1011, |