summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp28
-rw-r--r--clang/test/CodeGen/fpconstrained-cmp-double.c151
-rw-r--r--clang/test/CodeGen/fpconstrained-cmp-float.c151
-rw-r--r--llvm/include/llvm/IR/IRBuilder.h41
4 files changed, 360 insertions, 11 deletions
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 4adaca8ae57..4338d1c3dcd 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -798,17 +798,17 @@ public:
// Comparisons.
Value *EmitCompare(const BinaryOperator *E, llvm::CmpInst::Predicate UICmpOpc,
llvm::CmpInst::Predicate SICmpOpc,
- llvm::CmpInst::Predicate FCmpOpc);
-#define VISITCOMP(CODE, UI, SI, FP) \
+ llvm::CmpInst::Predicate FCmpOpc, bool IsSignaling);
+#define VISITCOMP(CODE, UI, SI, FP, SIG) \
Value *VisitBin##CODE(const BinaryOperator *E) { \
return EmitCompare(E, llvm::ICmpInst::UI, llvm::ICmpInst::SI, \
- llvm::FCmpInst::FP); }
- VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT)
- VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT)
- VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE)
- VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE)
- VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ)
- VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE)
+ llvm::FCmpInst::FP, SIG); }
+ VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT, true)
+ VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT, true)
+ VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE, true)
+ VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE, true)
+ VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ, false)
+ VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE, false)
#undef VISITCOMP
Value *VisitBinAssign (const BinaryOperator *E);
@@ -3804,7 +3804,8 @@ static llvm::Intrinsic::ID GetIntrinsic(IntrinsicType IT,
Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
llvm::CmpInst::Predicate UICmpOpc,
llvm::CmpInst::Predicate SICmpOpc,
- llvm::CmpInst::Predicate FCmpOpc) {
+ llvm::CmpInst::Predicate FCmpOpc,
+ bool IsSignaling) {
TestAndClearIgnoreResultAssign();
Value *Result;
QualType LHSTy = E->getLHS()->getType();
@@ -3900,7 +3901,10 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
if (BOInfo.isFixedPointBinOp()) {
Result = EmitFixedPointBinOp(BOInfo);
} else if (LHS->getType()->isFPOrFPVectorTy()) {
- Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp");
+ if (!IsSignaling)
+ Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp");
+ else
+ Result = Builder.CreateFCmpS(FCmpOpc, LHS, RHS, "cmp");
} else if (LHSTy->hasSignedIntegerRepresentation()) {
Result = Builder.CreateICmp(SICmpOpc, LHS, RHS, "cmp");
} else {
@@ -3957,6 +3961,8 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
Value *ResultR, *ResultI;
if (CETy->isRealFloatingType()) {
+ // As complex comparisons can only be equality comparisons, they
+ // are never signaling comparisons.
ResultR = Builder.CreateFCmp(FCmpOpc, LHS.first, RHS.first, "cmp.r");
ResultI = Builder.CreateFCmp(FCmpOpc, LHS.second, RHS.second, "cmp.i");
} else {
diff --git a/clang/test/CodeGen/fpconstrained-cmp-double.c b/clang/test/CodeGen/fpconstrained-cmp-double.c
new file mode 100644
index 00000000000..2819970a3fc
--- /dev/null
+++ b/clang/test/CodeGen/fpconstrained-cmp-double.c
@@ -0,0 +1,151 @@
+// RUN: %clang_cc1 -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=FCMP
+// RUN: %clang_cc1 -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=EXCEPT
+// RUN: %clang_cc1 -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=MAYTRAP
+// RUN: %clang_cc1 -frounding-math -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=IGNORE
+// RUN: %clang_cc1 -frounding-math -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=EXCEPT
+// RUN: %clang_cc1 -frounding-math -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=MAYTRAP
+
+_Bool QuietEqual(double f1, double f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietEqual(double %f1, double %f2)
+
+ // FCMP: fcmp oeq double %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"oeq", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"oeq", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"oeq", metadata !"fpexcept.maytrap")
+ return f1 == f2;
+
+ // CHECK: ret
+}
+
+_Bool QuietNotEqual(double f1, double f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietNotEqual(double %f1, double %f2)
+
+ // FCMP: fcmp une double %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"une", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"une", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"une", metadata !"fpexcept.maytrap")
+ return f1 != f2;
+
+ // CHECK: ret
+}
+
+_Bool SignalingLess(double f1, double f2) {
+ // CHECK-LABEL: define {{.*}}i1 @SignalingLess(double %f1, double %f2)
+
+ // FCMP: fcmp olt double %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmps.f64(double %{{.*}}, double %{{.*}}, metadata !"olt", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmps.f64(double %{{.*}}, double %{{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmps.f64(double %{{.*}}, double %{{.*}}, metadata !"olt", metadata !"fpexcept.maytrap")
+ return f1 < f2;
+
+ // CHECK: ret
+}
+
+_Bool SignalingLessEqual(double f1, double f2) {
+ // CHECK-LABEL: define {{.*}}i1 @SignalingLessEqual(double %f1, double %f2)
+
+ // FCMP: fcmp ole double %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmps.f64(double %{{.*}}, double %{{.*}}, metadata !"ole", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmps.f64(double %{{.*}}, double %{{.*}}, metadata !"ole", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmps.f64(double %{{.*}}, double %{{.*}}, metadata !"ole", metadata !"fpexcept.maytrap")
+ return f1 <= f2;
+
+ // CHECK: ret
+}
+
+_Bool SignalingGreater(double f1, double f2) {
+ // CHECK-LABEL: define {{.*}}i1 @SignalingGreater(double %f1, double %f2)
+
+ // FCMP: fcmp ogt double %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmps.f64(double %{{.*}}, double %{{.*}}, metadata !"ogt", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmps.f64(double %{{.*}}, double %{{.*}}, metadata !"ogt", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmps.f64(double %{{.*}}, double %{{.*}}, metadata !"ogt", metadata !"fpexcept.maytrap")
+ return f1 > f2;
+
+ // CHECK: ret
+}
+
+_Bool SignalingGreaterEqual(double f1, double f2) {
+ // CHECK-LABEL: define {{.*}}i1 @SignalingGreaterEqual(double %f1, double %f2)
+
+ // FCMP: fcmp oge double %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmps.f64(double %{{.*}}, double %{{.*}}, metadata !"oge", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmps.f64(double %{{.*}}, double %{{.*}}, metadata !"oge", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmps.f64(double %{{.*}}, double %{{.*}}, metadata !"oge", metadata !"fpexcept.maytrap")
+ return f1 >= f2;
+
+ // CHECK: ret
+}
+
+_Bool QuietLess(double f1, double f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietLess(double %f1, double %f2)
+
+ // FCMP: fcmp olt double %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"olt", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"olt", metadata !"fpexcept.maytrap")
+ return __builtin_isless(f1, f2);
+
+ // CHECK: ret
+}
+
+_Bool QuietLessEqual(double f1, double f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietLessEqual(double %f1, double %f2)
+
+ // FCMP: fcmp ole double %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"ole", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"ole", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"ole", metadata !"fpexcept.maytrap")
+ return __builtin_islessequal(f1, f2);
+
+ // CHECK: ret
+}
+
+_Bool QuietGreater(double f1, double f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietGreater(double %f1, double %f2)
+
+ // FCMP: fcmp ogt double %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"ogt", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"ogt", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"ogt", metadata !"fpexcept.maytrap")
+ return __builtin_isgreater(f1, f2);
+
+ // CHECK: ret
+}
+
+_Bool QuietGreaterEqual(double f1, double f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietGreaterEqual(double %f1, double %f2)
+
+ // FCMP: fcmp oge double %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"oge", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"oge", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"oge", metadata !"fpexcept.maytrap")
+ return __builtin_isgreaterequal(f1, f2);
+
+ // CHECK: ret
+}
+
+_Bool QuietLessGreater(double f1, double f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietLessGreater(double %f1, double %f2)
+
+ // FCMP: fcmp one double %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"one", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"one", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"one", metadata !"fpexcept.maytrap")
+ return __builtin_islessgreater(f1, f2);
+
+ // CHECK: ret
+}
+
+_Bool QuietUnordered(double f1, double f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietUnordered(double %f1, double %f2)
+
+ // FCMP: fcmp uno double %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"uno", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"uno", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f64(double %{{.*}}, double %{{.*}}, metadata !"uno", metadata !"fpexcept.maytrap")
+ return __builtin_isunordered(f1, f2);
+
+ // CHECK: ret
+}
+
diff --git a/clang/test/CodeGen/fpconstrained-cmp-float.c b/clang/test/CodeGen/fpconstrained-cmp-float.c
new file mode 100644
index 00000000000..0265fc54c02
--- /dev/null
+++ b/clang/test/CodeGen/fpconstrained-cmp-float.c
@@ -0,0 +1,151 @@
+// RUN: %clang_cc1 -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=FCMP
+// RUN: %clang_cc1 -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=EXCEPT
+// RUN: %clang_cc1 -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=MAYTRAP
+// RUN: %clang_cc1 -frounding-math -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=IGNORE
+// RUN: %clang_cc1 -frounding-math -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=EXCEPT
+// RUN: %clang_cc1 -frounding-math -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=MAYTRAP
+
+_Bool QuietEqual(float f1, float f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietEqual(float %f1, float %f2)
+
+ // FCMP: fcmp oeq float %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"oeq", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"oeq", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"oeq", metadata !"fpexcept.maytrap")
+ return f1 == f2;
+
+ // CHECK: ret
+}
+
+_Bool QuietNotEqual(float f1, float f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietNotEqual(float %f1, float %f2)
+
+ // FCMP: fcmp une float %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"une", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"une", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"une", metadata !"fpexcept.maytrap")
+ return f1 != f2;
+
+ // CHECK: ret
+}
+
+_Bool SignalingLess(float f1, float f2) {
+ // CHECK-LABEL: define {{.*}}i1 @SignalingLess(float %f1, float %f2)
+
+ // FCMP: fcmp olt float %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmps.f32(float %{{.*}}, float %{{.*}}, metadata !"olt", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmps.f32(float %{{.*}}, float %{{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmps.f32(float %{{.*}}, float %{{.*}}, metadata !"olt", metadata !"fpexcept.maytrap")
+ return f1 < f2;
+
+ // CHECK: ret
+}
+
+_Bool SignalingLessEqual(float f1, float f2) {
+ // CHECK-LABEL: define {{.*}}i1 @SignalingLessEqual(float %f1, float %f2)
+
+ // FCMP: fcmp ole float %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmps.f32(float %{{.*}}, float %{{.*}}, metadata !"ole", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmps.f32(float %{{.*}}, float %{{.*}}, metadata !"ole", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmps.f32(float %{{.*}}, float %{{.*}}, metadata !"ole", metadata !"fpexcept.maytrap")
+ return f1 <= f2;
+
+ // CHECK: ret
+}
+
+_Bool SignalingGreater(float f1, float f2) {
+ // CHECK-LABEL: define {{.*}}i1 @SignalingGreater(float %f1, float %f2)
+
+ // FCMP: fcmp ogt float %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmps.f32(float %{{.*}}, float %{{.*}}, metadata !"ogt", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmps.f32(float %{{.*}}, float %{{.*}}, metadata !"ogt", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmps.f32(float %{{.*}}, float %{{.*}}, metadata !"ogt", metadata !"fpexcept.maytrap")
+ return f1 > f2;
+
+ // CHECK: ret
+}
+
+_Bool SignalingGreaterEqual(float f1, float f2) {
+ // CHECK-LABEL: define {{.*}}i1 @SignalingGreaterEqual(float %f1, float %f2)
+
+ // FCMP: fcmp oge float %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmps.f32(float %{{.*}}, float %{{.*}}, metadata !"oge", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmps.f32(float %{{.*}}, float %{{.*}}, metadata !"oge", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmps.f32(float %{{.*}}, float %{{.*}}, metadata !"oge", metadata !"fpexcept.maytrap")
+ return f1 >= f2;
+
+ // CHECK: ret
+}
+
+_Bool QuietLess(float f1, float f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietLess(float %f1, float %f2)
+
+ // FCMP: fcmp olt float %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"olt", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"olt", metadata !"fpexcept.maytrap")
+ return __builtin_isless(f1, f2);
+
+ // CHECK: ret
+}
+
+_Bool QuietLessEqual(float f1, float f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietLessEqual(float %f1, float %f2)
+
+ // FCMP: fcmp ole float %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"ole", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"ole", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"ole", metadata !"fpexcept.maytrap")
+ return __builtin_islessequal(f1, f2);
+
+ // CHECK: ret
+}
+
+_Bool QuietGreater(float f1, float f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietGreater(float %f1, float %f2)
+
+ // FCMP: fcmp ogt float %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"ogt", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"ogt", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"ogt", metadata !"fpexcept.maytrap")
+ return __builtin_isgreater(f1, f2);
+
+ // CHECK: ret
+}
+
+_Bool QuietGreaterEqual(float f1, float f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietGreaterEqual(float %f1, float %f2)
+
+ // FCMP: fcmp oge float %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"oge", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"oge", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"oge", metadata !"fpexcept.maytrap")
+ return __builtin_isgreaterequal(f1, f2);
+
+ // CHECK: ret
+}
+
+_Bool QuietLessGreater(float f1, float f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietLessGreater(float %f1, float %f2)
+
+ // FCMP: fcmp one float %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"one", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"one", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"one", metadata !"fpexcept.maytrap")
+ return __builtin_islessgreater(f1, f2);
+
+ // CHECK: ret
+}
+
+_Bool QuietUnordered(float f1, float f2) {
+ // CHECK-LABEL: define {{.*}}i1 @QuietUnordered(float %f1, float %f2)
+
+ // FCMP: fcmp uno float %{{.*}}, %{{.*}}
+ // IGNORE: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"uno", metadata !"fpexcept.ignore")
+ // EXCEPT: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"uno", metadata !"fpexcept.strict")
+ // MAYTRAP: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"uno", metadata !"fpexcept.maytrap")
+ return __builtin_isunordered(f1, f2);
+
+ // CHECK: ret
+}
+
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 1abdf2242b5..90353365a96 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -1195,6 +1195,18 @@ private:
return MetadataAsValue::get(Context, ExceptMDS);
}
+ Value *getConstrainedFPPredicate(CmpInst::Predicate Predicate) {
+ assert(CmpInst::isFPPredicate(Predicate) &&
+ Predicate != CmpInst::FCMP_FALSE &&
+ Predicate != CmpInst::FCMP_TRUE &&
+ "Invalid constrained FP comparison predicate!");
+
+ StringRef PredicateStr = CmpInst::getPredicateName(Predicate);
+ auto *PredicateMDS = MDString::get(Context, PredicateStr);
+
+ return MetadataAsValue::get(Context, PredicateMDS);
+ }
+
public:
Value *CreateAdd(Value *LHS, Value *RHS, const Twine &Name = "",
bool HasNUW = false, bool HasNSW = false) {
@@ -2351,12 +2363,41 @@ public:
Value *CreateFCmp(CmpInst::Predicate P, Value *LHS, Value *RHS,
const Twine &Name = "", MDNode *FPMathTag = nullptr) {
+ if (IsFPConstrained)
+ return CreateConstrainedFPCmp(Intrinsic::experimental_constrained_fcmp,
+ P, LHS, RHS, Name);
+
+ if (auto *LC = dyn_cast<Constant>(LHS))
+ if (auto *RC = dyn_cast<Constant>(RHS))
+ return Insert(Folder.CreateFCmp(P, LC, RC), Name);
+ return Insert(setFPAttrs(new FCmpInst(P, LHS, RHS), FPMathTag, FMF), Name);
+ }
+
+ Value *CreateFCmpS(CmpInst::Predicate P, Value *LHS, Value *RHS,
+ const Twine &Name = "", MDNode *FPMathTag = nullptr) {
+ if (IsFPConstrained)
+ return CreateConstrainedFPCmp(Intrinsic::experimental_constrained_fcmps,
+ P, LHS, RHS, Name);
+
if (auto *LC = dyn_cast<Constant>(LHS))
if (auto *RC = dyn_cast<Constant>(RHS))
return Insert(Folder.CreateFCmp(P, LC, RC), Name);
return Insert(setFPAttrs(new FCmpInst(P, LHS, RHS), FPMathTag, FMF), Name);
}
+ CallInst *CreateConstrainedFPCmp(
+ Intrinsic::ID ID, CmpInst::Predicate P, Value *L, Value *R,
+ const Twine &Name = "",
+ Optional<fp::ExceptionBehavior> Except = None) {
+ Value *PredicateV = getConstrainedFPPredicate(P);
+ Value *ExceptV = getConstrainedFPExcept(Except);
+
+ CallInst *C = CreateIntrinsic(ID, {L->getType()},
+ {L, R, PredicateV, ExceptV}, nullptr, Name);
+ setConstrainedFPCallAttr(C);
+ return C;
+ }
+
//===--------------------------------------------------------------------===//
// Instruction creation methods: Other Instructions
//===--------------------------------------------------------------------===//
OpenPOWER on IntegriCloud