Index: llvm/lib/Target/ARM/ARMISelLowering.h =================================================================== --- llvm/lib/Target/ARM/ARMISelLowering.h +++ llvm/lib/Target/ARM/ARMISelLowering.h @@ -84,7 +84,9 @@ CMN, // ARM CMN instructions. CMPZ, // ARM compare that sets only Z flag. CMPFP, // ARM VFP compare instruction, sets FPSCR. + CMPFPE, // ARM VFP signalling compare instruction, sets FPSCR. CMPFPw0, // ARM VFP compare against zero instruction, sets FPSCR. + CMPFPEw0, // ARM VFP signalling compare against zero instruction, sets FPSCR. FMSTAT, // ARM fmstat instruction. CMOV, // ARM conditional move instructions. @@ -733,6 +735,7 @@ SDValue LowerFP_EXTEND(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG) const; SDValue LowerINT_TO_FP(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFSETCC(SDValue Op, SelectionDAG &DAG) const; void lowerABS(SDNode *N, SmallVectorImpl &Results, SelectionDAG &DAG) const; void LowerLOAD(SDNode *N, SmallVectorImpl &Results, @@ -823,7 +826,7 @@ SDValue getARMCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue &ARMcc, SelectionDAG &DAG, const SDLoc &dl) const; SDValue getVFPCmp(SDValue LHS, SDValue RHS, SelectionDAG &DAG, - const SDLoc &dl) const; + const SDLoc &dl, bool Signaling = false) const; SDValue duplicateCmp(SDValue Cmp, SelectionDAG &DAG) const; SDValue OptimizeVFPBrcond(SDValue Op, SelectionDAG &DAG) const; Index: llvm/lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- llvm/lib/Target/ARM/ARMISelLowering.cpp +++ llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -1356,6 +1356,14 @@ setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand); setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand); } + + // Strict floating-point comparisons need custom lowering. + setOperationAction(ISD::STRICT_FSETCC, MVT::f16, Custom); + setOperationAction(ISD::STRICT_FSETCCS, MVT::f16, Custom); + setOperationAction(ISD::STRICT_FSETCC, MVT::f32, Custom); + setOperationAction(ISD::STRICT_FSETCCS, MVT::f32, Custom); + setOperationAction(ISD::STRICT_FSETCC, MVT::f64, Custom); + setOperationAction(ISD::STRICT_FSETCCS, MVT::f64, Custom); } // Use __sincos_stret if available. @@ -1554,7 +1562,9 @@ case ARMISD::CMN: return "ARMISD::CMN"; case ARMISD::CMPZ: return "ARMISD::CMPZ"; case ARMISD::CMPFP: return "ARMISD::CMPFP"; + case ARMISD::CMPFPE: return "ARMISD::CMPFPE"; case ARMISD::CMPFPw0: return "ARMISD::CMPFPw0"; + case ARMISD::CMPFPEw0: return "ARMISD::CMPFPEw0"; case ARMISD::BCC_i64: return "ARMISD::BCC_i64"; case ARMISD::FMSTAT: return "ARMISD::FMSTAT"; @@ -4349,13 +4359,16 @@ /// Returns a appropriate VFP CMP (fcmp{s|d}+fmstat) for the given operands. SDValue ARMTargetLowering::getVFPCmp(SDValue LHS, SDValue RHS, - SelectionDAG &DAG, const SDLoc &dl) const { + SelectionDAG &DAG, const SDLoc &dl, + bool Signaling) const { assert(Subtarget->hasFP64() || RHS.getValueType() != MVT::f64); SDValue Cmp; if (!isFloatingPointZero(RHS)) - Cmp = DAG.getNode(ARMISD::CMPFP, dl, MVT::Glue, LHS, RHS); + Cmp = DAG.getNode(Signaling ? ARMISD::CMPFPE : ARMISD::CMPFP, + dl, MVT::Glue, LHS, RHS); else - Cmp = DAG.getNode(ARMISD::CMPFPw0, dl, MVT::Glue, LHS); + Cmp = DAG.getNode(Signaling ? ARMISD::CMPFPEw0 : ARMISD::CMPFPw0, + dl, MVT::Glue, LHS); return DAG.getNode(ARMISD::FMSTAT, dl, MVT::Glue, Cmp); } @@ -9273,6 +9286,51 @@ Results.push_back(SDValue(CmpSwap, 2)); } +SDValue ARMTargetLowering::LowerFSETCC(SDValue Op, SelectionDAG &DAG) const { + SDLoc dl(Op); + EVT VT = Op.getValueType(); + SDValue Chain = Op.getOperand(0); + SDValue LHS = Op.getOperand(1); + SDValue RHS = Op.getOperand(2); + ISD::CondCode CC = cast(Op.getOperand(3))->get(); + bool IsSignaling = Op.getOpcode() == ISD::STRICT_FSETCCS; + + // If we don't have instructions of this float type then soften to a libcall + // and use SETCC instead. + if (isUnsupportedFloatingType(LHS.getValueType())) { + DAG.getTargetLoweringInfo().softenSetCCOperands( + DAG, LHS.getValueType(), LHS, RHS, CC, dl, LHS, RHS, Chain, IsSignaling); + if (!RHS.getNode()) { + RHS = DAG.getConstant(0, dl, LHS.getValueType()); + CC = ISD::SETNE; + } + SDValue Result = DAG.getNode(ISD::SETCC, dl, VT, LHS, RHS, + DAG.getCondCode(CC)); + return DAG.getMergeValues({Result, Chain}, dl); + } + + ARMCC::CondCodes CondCode, CondCode2; + FPCCToARMCC(CC, CondCode, CondCode2); + + // FIXME: Chain is not handled correctly here. Currently the FPSCR is implicit + // in CMPFP and CMPFPE, but instead it should be made explicit by these + // instructions using a chain instead of glue. This would also fix the problem + // here (and also in LowerSELECT_CC) where we generate two comparisons when + // CondCode2 != AL. + SDValue True = DAG.getConstant(1, dl, VT); + SDValue False = DAG.getConstant(0, dl, VT); + SDValue ARMcc = DAG.getConstant(CondCode, dl, MVT::i32); + SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); + SDValue Cmp = getVFPCmp(LHS, RHS, DAG, dl, IsSignaling); + SDValue Result = getCMOV(dl, VT, False, True, ARMcc, CCR, Cmp, DAG); + if (CondCode2 != ARMCC::AL) { + ARMcc = DAG.getConstant(CondCode2, dl, MVT::i32); + Cmp = getVFPCmp(LHS, RHS, DAG, dl, IsSignaling); + Result = getCMOV(dl, VT, Result, True, ARMcc, CCR, Cmp, DAG); + } + return DAG.getMergeValues({Result, Chain}, dl); +} + SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { LLVM_DEBUG(dbgs() << "Lowering node: "; Op.dump()); switch (Op.getOpcode()) { @@ -9366,6 +9424,8 @@ case ISD::FP_ROUND: return LowerFP_ROUND(Op, DAG); case ISD::STRICT_FP_EXTEND: case ISD::FP_EXTEND: return LowerFP_EXTEND(Op, DAG); + case ISD::STRICT_FSETCC: + case ISD::STRICT_FSETCCS: return LowerFSETCC(Op, DAG); case ARMISD::WIN__DBZCHK: return SDValue(); } } Index: llvm/lib/Target/ARM/ARMInstrVFP.td =================================================================== --- llvm/lib/Target/ARM/ARMInstrVFP.td +++ llvm/lib/Target/ARM/ARMInstrVFP.td @@ -21,6 +21,8 @@ def arm_fmstat : SDNode<"ARMISD::FMSTAT", SDTNone, [SDNPInGlue, SDNPOutGlue]>; def arm_cmpfp : SDNode<"ARMISD::CMPFP", SDT_ARMCmp, [SDNPOutGlue]>; def arm_cmpfp0 : SDNode<"ARMISD::CMPFPw0", SDT_CMPFP0, [SDNPOutGlue]>; +def arm_cmpfpe : SDNode<"ARMISD::CMPFPE", SDT_ARMCmp, [SDNPOutGlue]>; +def arm_cmpfpe0: SDNode<"ARMISD::CMPFPEw0",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>; @@ -548,12 +550,12 @@ def VCMPED : ADuI<0b11101, 0b11, 0b0100, 0b11, 0, (outs), (ins DPR:$Dd, DPR:$Dm), IIC_fpCMP64, "vcmpe", ".f64\t$Dd, $Dm", - [/* For disassembly only; pattern left blank */]>; + [(arm_cmpfpe DPR:$Dd, (f64 DPR:$Dm))]>; def VCMPES : ASuI<0b11101, 0b11, 0b0100, 0b11, 0, (outs), (ins SPR:$Sd, SPR:$Sm), IIC_fpCMP32, "vcmpe", ".f32\t$Sd, $Sm", - [/* For disassembly only; pattern left blank */]> { + [(arm_cmpfpe SPR:$Sd, SPR:$Sm)]> { // Some single precision VFP instructions may be executed on both NEON and // VFP pipelines on A8. let D = VFPNeonA8Domain; @@ -562,7 +564,7 @@ def VCMPEH : AHuI<0b11101, 0b11, 0b0100, 0b11, 0, (outs), (ins HPR:$Sd, HPR:$Sm), IIC_fpCMP16, "vcmpe", ".f16\t$Sd, $Sm", - [/* For disassembly only; pattern left blank */]>; + [(arm_cmpfpe HPR:$Sd, HPR:$Sm)]>; def VCMPD : ADuI<0b11101, 0b11, 0b0100, 0b01, 0, (outs), (ins DPR:$Dd, DPR:$Dm), @@ -611,7 +613,7 @@ def VCMPEZD : ADuI<0b11101, 0b11, 0b0101, 0b11, 0, (outs), (ins DPR:$Dd), IIC_fpCMP64, "vcmpe", ".f64\t$Dd, #0", - [/* For disassembly only; pattern left blank */]> { + [(arm_cmpfpe0 (f64 DPR:$Dd))]> { let Inst{3-0} = 0b0000; let Inst{5} = 0; } @@ -619,7 +621,7 @@ def VCMPEZS : ASuI<0b11101, 0b11, 0b0101, 0b11, 0, (outs), (ins SPR:$Sd), IIC_fpCMP32, "vcmpe", ".f32\t$Sd, #0", - [/* For disassembly only; pattern left blank */]> { + [(arm_cmpfpe0 SPR:$Sd)]> { let Inst{3-0} = 0b0000; let Inst{5} = 0; @@ -631,7 +633,7 @@ def VCMPEZH : AHuI<0b11101, 0b11, 0b0101, 0b11, 0, (outs), (ins HPR:$Sd), IIC_fpCMP16, "vcmpe", ".f16\t$Sd, #0", - [/* For disassembly only; pattern left blank */]> { + [(arm_cmpfpe0 HPR:$Sd)]> { let Inst{3-0} = 0b0000; let Inst{5} = 0; } Index: llvm/test/CodeGen/ARM/fp-intrinsics.ll =================================================================== --- llvm/test/CodeGen/ARM/fp-intrinsics.ll +++ llvm/test/CodeGen/ARM/fp-intrinsics.ll @@ -8,9 +8,8 @@ ; hardware being present or absent work as expected (i.e. we get an instruction ; when one is available, otherwise a libcall). -; FIXME: Tests fails as various things in CodeGen and Target/ARM need fixing. -; XFAIL: * - +; FIXME: We're not generating the right instructions for some of these +; operations (see further FIXMEs down below). ; Single-precision intrinsics @@ -71,7 +70,7 @@ ; CHECK-LABEL: fptoui_f32: ; CHECK-NOSP: bl __aeabi_f2uiz -; CHECK-SP: vcvt.u32.f32 +; FIXME-CHECK-SP: vcvt.u32.f32 define i32 @fptoui_f32(float %x) #0 { %val = call i32 @llvm.experimental.constrained.fptoui.f32(float %x, metadata !"fpexcept.strict") #0 ret i32 %val @@ -240,6 +239,226 @@ ret float %val } +; CHECK-LABEL: fcmp_olt_f32: +; CHECK-NOSP: bl __aeabi_fcmplt +; CHECK-SP: vcmp.f32 +define i32 @fcmp_olt_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"olt", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_ole_f32: +; CHECK-NOSP: bl __aeabi_fcmple +; CHECK-SP: vcmp.f32 +define i32 @fcmp_ole_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"ole", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_ogt_f32: +; CHECK-NOSP: bl __aeabi_fcmpgt +; CHECK-SP: vcmp.f32 +define i32 @fcmp_ogt_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"ogt", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_oge_f32: +; CHECK-NOSP: bl __aeabi_fcmpge +; CHECK-SP: vcmp.f32 +define i32 @fcmp_oge_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"oge", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_oeq_f32: +; CHECK-NOSP: bl __aeabi_fcmpeq +; CHECK-SP: vcmp.f32 +define i32 @fcmp_oeq_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"oeq", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_one_f32: +; CHECK-NOSP: bl __aeabi_fcmpeq +; CHECK-NOSP: bl __aeabi_fcmpun +; CHECK-SP: vcmp.f32 +define i32 @fcmp_one_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"one", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_ult_f32: +; CHECK-NOSP: bl __aeabi_fcmpge +; CHECK-SP: vcmp.f32 +define i32 @fcmp_ult_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"ult", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_ule_f32: +; CHECK-NOSP: bl __aeabi_fcmpgt +; CHECK-SP: vcmp.f32 +define i32 @fcmp_ule_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"ule", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_ugt_f32: +; CHECK-NOSP: bl __aeabi_fcmple +; CHECK-SP: vcmp.f32 +define i32 @fcmp_ugt_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"ugt", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_uge_f32: +; CHECK-NOSP: bl __aeabi_fcmplt +; CHECK-SP: vcmp.f32 +define i32 @fcmp_uge_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"uge", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_ueq_f32: +; CHECK-NOSP: bl __aeabi_fcmpeq +; CHECK-NOSP: bl __aeabi_fcmpun +; CHECK-SP: vcmp.f32 +define i32 @fcmp_ueq_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"ueq", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_une_f32: +; CHECK-NOSP: bl __aeabi_fcmpeq +; CHECK-SP: vcmp.f32 +define i32 @fcmp_une_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(float %a, float %b, metadata !"une", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_olt_f32: +; CHECK-NOSP: bl __aeabi_fcmplt +; CHECK-SP: vcmpe.f32 +define i32 @fcmps_olt_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"olt", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_ole_f32: +; CHECK-NOSP: bl __aeabi_fcmple +; CHECK-SP: vcmpe.f32 +define i32 @fcmps_ole_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"ole", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_ogt_f32: +; CHECK-NOSP: bl __aeabi_fcmpgt +; CHECK-SP: vcmpe.f32 +define i32 @fcmps_ogt_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"ogt", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_oge_f32: +; CHECK-NOSP: bl __aeabi_fcmpge +; CHECK-SP: vcmpe.f32 +define i32 @fcmps_oge_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"oge", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_oeq_f32: +; CHECK-NOSP: bl __aeabi_fcmpeq +; CHECK-SP: vcmpe.f32 +define i32 @fcmps_oeq_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"oeq", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_one_f32: +; CHECK-NOSP: bl __aeabi_fcmpeq +; CHECK-NOSP: bl __aeabi_fcmpun +; CHECK-SP: vcmpe.f32 +define i32 @fcmps_one_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"one", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_ult_f32: +; CHECK-NOSP: bl __aeabi_fcmpge +; CHECK-SP: vcmpe.f32 +define i32 @fcmps_ult_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"ult", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_ule_f32: +; CHECK-NOSP: bl __aeabi_fcmpgt +; CHECK-SP: vcmpe.f32 +define i32 @fcmps_ule_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"ule", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_ugt_f32: +; CHECK-NOSP: bl __aeabi_fcmple +; CHECK-SP: vcmpe.f32 +define i32 @fcmps_ugt_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"ugt", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_uge_f32: +; CHECK-NOSP: bl __aeabi_fcmplt +; CHECK-SP: vcmpe.f32 +define i32 @fcmps_uge_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"uge", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_ueq_f32: +; CHECK-NOSP: bl __aeabi_fcmpeq +; CHECK-NOSP: bl __aeabi_fcmpun +; CHECK-SP: vcmpe.f32 +define i32 @fcmps_ueq_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"ueq", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_une_f32: +; CHECK-NOSP: bl __aeabi_fcmpeq +; CHECK-SP: vcmpe.f32 +define i32 @fcmps_une_f32(float %a, float %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f32(float %a, float %b, metadata !"une", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + ; Double-precision intrinsics @@ -300,7 +519,7 @@ ; CHECK-LABEL: fptoui_f64: ; CHECK-NODP: bl __aeabi_d2uiz -; CHECK-DP: vcvt.u32.f64 +; FIXME-CHECK-DP: vcvt.u32.f64 define i32 @fptoui_f64(double %x) #0 { %val = call i32 @llvm.experimental.constrained.fptoui.f64(double %x, metadata !"fpexcept.strict") #0 ret i32 %val @@ -469,6 +688,226 @@ ret double %val } +; CHECK-LABEL: fcmp_olt_f64: +; CHECK-NODP: bl __aeabi_dcmplt +; CHECK-DP: vcmp.f64 +define i32 @fcmp_olt_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"olt", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_ole_f64: +; CHECK-NODP: bl __aeabi_dcmple +; CHECK-DP: vcmp.f64 +define i32 @fcmp_ole_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"ole", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_ogt_f64: +; CHECK-NODP: bl __aeabi_dcmpgt +; CHECK-DP: vcmp.f64 +define i32 @fcmp_ogt_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"ogt", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_oge_f64: +; CHECK-NODP: bl __aeabi_dcmpge +; CHECK-DP: vcmp.f64 +define i32 @fcmp_oge_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"oge", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_oeq_f64: +; CHECK-NODP: bl __aeabi_dcmpeq +; CHECK-DP: vcmp.f64 +define i32 @fcmp_oeq_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"oeq", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_one_f64: +; CHECK-NODP-DAG: bl __aeabi_dcmpeq +; CHECK-NODP-DAG: bl __aeabi_dcmpun +; CHECK-DP: vcmp.f64 +define i32 @fcmp_one_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"one", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_ult_f64: +; CHECK-NODP: bl __aeabi_dcmpge +; CHECK-DP: vcmp.f64 +define i32 @fcmp_ult_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"ult", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_ule_f64: +; CHECK-NODP: bl __aeabi_dcmpgt +; CHECK-DP: vcmp.f64 +define i32 @fcmp_ule_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"ule", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_ugt_f64: +; CHECK-NODP: bl __aeabi_dcmple +; CHECK-DP: vcmp.f64 +define i32 @fcmp_ugt_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"ugt", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_uge_f64: +; CHECK-NODP: bl __aeabi_dcmplt +; CHECK-DP: vcmp.f64 +define i32 @fcmp_uge_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"uge", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_ueq_f64: +; CHECK-NODP-DAG: bl __aeabi_dcmpeq +; CHECK-NODP-DAG: bl __aeabi_dcmpun +; CHECK-DP: vcmp.f64 +define i32 @fcmp_ueq_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"ueq", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmp_une_f64: +; CHECK-NODP: bl __aeabi_dcmpeq +; CHECK-DP: vcmp.f64 +define i32 @fcmp_une_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(double %a, double %b, metadata !"une", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_olt_f64: +; CHECK-NODP: bl __aeabi_dcmplt +; CHECK-DP: vcmpe.f64 +define i32 @fcmps_olt_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"olt", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_ole_f64: +; CHECK-NODP: bl __aeabi_dcmple +; CHECK-DP: vcmpe.f64 +define i32 @fcmps_ole_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"ole", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_ogt_f64: +; CHECK-NODP: bl __aeabi_dcmpgt +; CHECK-DP: vcmpe.f64 +define i32 @fcmps_ogt_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"ogt", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_oge_f64: +; CHECK-NODP: bl __aeabi_dcmpge +; CHECK-DP: vcmpe.f64 +define i32 @fcmps_oge_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"oge", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_oeq_f64: +; CHECK-NODP: bl __aeabi_dcmpeq +; CHECK-DP: vcmpe.f64 +define i32 @fcmps_oeq_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"oeq", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_one_f64: +; CHECK-NODP-DAG: bl __aeabi_dcmpeq +; CHECK-NODP-DAG: bl __aeabi_dcmpun +; CHECK-DP: vcmpe.f64 +define i32 @fcmps_one_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"one", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_ult_f64: +; CHECK-NODP: bl __aeabi_dcmpge +; CHECK-DP: vcmpe.f64 +define i32 @fcmps_ult_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"ult", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_ule_f64: +; CHECK-NODP: bl __aeabi_dcmpgt +; CHECK-DP: vcmpe.f64 +define i32 @fcmps_ule_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"ule", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_ugt_f64: +; CHECK-NODP: bl __aeabi_dcmple +; CHECK-DP: vcmpe.f64 +define i32 @fcmps_ugt_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"ugt", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_uge_f64: +; CHECK-NODP: bl __aeabi_dcmplt +; CHECK-DP: vcmpe.f64 +define i32 @fcmps_uge_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"uge", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_ueq_f64: +; CHECK-NODP-DAG: bl __aeabi_dcmpeq +; CHECK-NODP-DAG: bl __aeabi_dcmpun +; CHECK-DP: vcmpe.f64 +define i32 @fcmps_ueq_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"ueq", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + +; CHECK-LABEL: fcmps_une_f64: +; CHECK-NODP: bl __aeabi_dcmpeq +; CHECK-DP: vcmpe.f64 +define i32 @fcmps_une_f64(double %a, double %b) #0 { + %cmp = call i1 @llvm.experimental.constrained.fcmps.f64(double %a, double %b, metadata !"une", metadata !"fpexcept.strict") #0 + %conv = zext i1 %cmp to i32 + ret i32 %conv +} + ; Single/Double conversion intrinsics @@ -490,15 +929,15 @@ ; CHECK-LABEL: sitofp_f32_i32: ; CHECK-NOSP: bl __aeabi_i2f -; CHECK-SP: vcvt.f32.s32 +; FIXME-CHECK-SP: vcvt.f32.s32 define float @sitofp_f32_i32(i32 %x) #0 { %val = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %x, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 ret float %val } ; CHECK-LABEL: sitofp_f64_i32: -; CHECK-NODP: bl __aeabi_i2d -; CHECK-DP: vcvt.f64.s32 +; FIXME-CHECK-NODP: bl __aeabi_i2d +; FIXME-CHECK-DP: vcvt.f64.s32 define double @sitofp_f64_i32(i32 %x) #0 { %val = call double @llvm.experimental.constrained.sitofp.f64.i32(i32 %x, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 ret double %val @@ -537,6 +976,8 @@ declare i32 @llvm.experimental.constrained.llround.f32(float, metadata) declare float @llvm.experimental.constrained.round.f32(float, metadata) declare float @llvm.experimental.constrained.trunc.f32(float, metadata) +declare i1 @llvm.experimental.constrained.fcmps.f32(float, float, metadata, metadata) +declare i1 @llvm.experimental.constrained.fcmp.f32(float, float, metadata, metadata) declare double @llvm.experimental.constrained.fadd.f64(double, double, metadata, metadata) declare double @llvm.experimental.constrained.fsub.f64(double, double, metadata, metadata) @@ -568,6 +1009,8 @@ declare i32 @llvm.experimental.constrained.llround.f64(double, metadata) declare double @llvm.experimental.constrained.round.f64(double, metadata) declare double @llvm.experimental.constrained.trunc.f64(double, metadata) +declare i1 @llvm.experimental.constrained.fcmps.f64(double, double, metadata, metadata) +declare i1 @llvm.experimental.constrained.fcmp.f64(double, double, metadata, metadata) declare float @llvm.experimental.constrained.fptrunc.f32.f64(double, metadata, metadata) declare double @llvm.experimental.constrained.fpext.f64.f32(float, metadata)