forked from OSchip/llvm-project
[FPEnv] Generate constrained FP comparisons from clang
Update the IRBuilder to generate constrained FP comparisons in CreateFCmp when IsFPConstrained is true, similar to the other places in the IRBuilder. Also, add a new CreateFCmpS to emit signaling FP comparisons, and use it in clang where comparisons are supposed to be signaling (currently, only when emitting code for the <, <=, >, >= operators). Note that there is currently no way to add fast-math flags to a constrained FP comparison, since this is implemented as an intrinsic call that returns a boolean type, and FMF are only allowed for calls returning a floating-point type. However, given the discussion around https://bugs.llvm.org/show_bug.cgi?id=42179, it seems that FCmp itself really shouldn't have any FMF either, so this is probably OK. Reviewed by: craig.topper Differential Revision: https://reviews.llvm.org/D71467
This commit is contained in:
parent
9ba1512748
commit
76e9c2a987
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
Loading…
Reference in New Issue