summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Target/ARM/ARMISelLowering.cpp66
-rw-r--r--llvm/lib/Target/ARM/ARMISelLowering.h5
-rw-r--r--llvm/lib/Target/ARM/ARMInstrVFP.td14
-rw-r--r--llvm/test/CodeGen/ARM/fp-intrinsics.ll459
4 files changed, 526 insertions, 18 deletions
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 1e6f7d88920..8e4bb91d53b 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -1354,6 +1354,14 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
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.
@@ -1552,7 +1560,9 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
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";
@@ -4344,13 +4354,16 @@ SDValue ARMTargetLowering::getARMCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
/// 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);
}
@@ -9222,6 +9235,51 @@ static void ReplaceCMP_SWAP_64Results(SDNode *N,
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<CondCodeSDNode>(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()) {
@@ -9315,6 +9373,8 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
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();
}
}
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h
index cc74e5d875d..6061a65d3b8 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.h
+++ b/llvm/lib/Target/ARM/ARMISelLowering.h
@@ -84,7 +84,9 @@ class VectorType;
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.
@@ -729,6 +731,7 @@ class VectorType;
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<SDValue> &Results,
SelectionDAG &DAG) const;
@@ -817,7 +820,7 @@ class VectorType;
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;
diff --git a/llvm/lib/Target/ARM/ARMInstrVFP.td b/llvm/lib/Target/ARM/ARMInstrVFP.td
index a41a483d1a4..f1d1d8a8916 100644
--- a/llvm/lib/Target/ARM/ARMInstrVFP.td
+++ b/llvm/lib/Target/ARM/ARMInstrVFP.td
@@ -21,6 +21,8 @@ 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_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 @@ let Defs = [FPSCR_NZCV] in {
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 VCMPES : ASuI<0b11101, 0b11, 0b0100, 0b11, 0,
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 @@ let Defs = [FPSCR_NZCV] in {
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 VCMPEZD : ADuI<0b11101, 0b11, 0b0101, 0b11, 0,
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 VCMPEZS : ASuI<0b11101, 0b11, 0b0101, 0b11, 0,
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;
}
diff --git a/llvm/test/CodeGen/ARM/fp-intrinsics.ll b/llvm/test/CodeGen/ARM/fp-intrinsics.ll
index 9a15a626e28..4352548ef3c 100644
--- a/llvm/test/CodeGen/ARM/fp-intrinsics.ll
+++ b/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 @@ define i32 @fptosi_f32(float %x) #0 {
; 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 @@ define float @trunc_f32(float %x) #0 {
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 @@ define i32 @fptosi_f64(double %x) #0 {
; 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 @@ define double @trunc_f64(double %x) #0 {
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 @@ define double @fpext_f32(float %x) #0 {
; 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.lround.f32(float, metadata)
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.lround.f64(double, metadata)
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)
OpenPOWER on IntegriCloud