case Intrinsic::experimental_constrained_trunc:
case Intrinsic::experimental_constrained_nearbyint:
case Intrinsic::experimental_constrained_rint:
+ case Intrinsic::experimental_constrained_fcmp:
+ case Intrinsic::experimental_constrained_fcmps:
return true;
default:
return false;
// If evaluation raised FP exception, the result can depend on rounding
// mode. If the latter is unknown, folding is not possible.
- if (!ORM || *ORM == RoundingMode::Dynamic)
+ if (ORM && *ORM == RoundingMode::Dynamic)
return false;
// If FP exceptions are ignored, fold the call, even if such exception is
// raised.
- if (!EB || *EB != fp::ExceptionBehavior::ebStrict)
+ if (EB && *EB != fp::ExceptionBehavior::ebStrict)
return true;
// Leave the calculation for runtime so that exception flags be correctly set
return nullptr;
}
+static Constant *evaluateCompare(const ConstrainedFPIntrinsic *Call) {
+ APFloat::opStatus St = APFloat::opOK;
+ auto *FCmp = cast<ConstrainedFPCmpIntrinsic>(Call);
+ FCmpInst::Predicate Cond = FCmp->getPredicate();
+ const APFloat &Op1 = cast<ConstantFP>(FCmp->getOperand(0))->getValueAPF();
+ const APFloat &Op2 = cast<ConstantFP>(FCmp->getOperand(1))->getValueAPF();
+ if (FCmp->isSignaling()) {
+ if (Op1.isNaN() || Op2.isNaN())
+ St = APFloat::opInvalidOp;
+ } else {
+ if (Op1.isSignaling() || Op2.isSignaling())
+ St = APFloat::opInvalidOp;
+ }
+ bool Result = FCmpInst::compare(Op1, Op2, Cond);
+ if (mayFoldConstrained(const_cast<ConstrainedFPCmpIntrinsic *>(FCmp), St))
+ return ConstantInt::get(Call->getType(), Result);
+ return nullptr;
+}
+
static Constant *ConstantFoldScalarCall2(StringRef Name,
Intrinsic::ID IntrinsicID,
Type *Ty,
}
if (const auto *Op1 = dyn_cast<ConstantFP>(Operands[0])) {
- if (!Ty->isFloatingPointTy())
- return nullptr;
const APFloat &Op1V = Op1->getValueAPF();
if (const auto *Op2 = dyn_cast<ConstantFP>(Operands[1])) {
case Intrinsic::experimental_constrained_frem:
St = Res.mod(Op2V);
break;
+ case Intrinsic::experimental_constrained_fcmp:
+ case Intrinsic::experimental_constrained_fcmps:
+ return evaluateCompare(ConstrIntr);
}
if (mayFoldConstrained(const_cast<ConstrainedFPIntrinsic *>(ConstrIntr),
St))
define i1 @cmp_eq_01() #0 {
; CHECK-LABEL: @cmp_eq_01(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[RESULT:%.*]] = call i1 @llvm.experimental.constrained.fcmp.f64(double 1.000000e+00, double 2.000000e+00, metadata !"oeq", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret i1 [[RESULT]]
+; CHECK-NEXT: ret i1 false
;
entry:
%result = call i1 @llvm.experimental.constrained.fcmp.f64(double 1.0, double 2.0, metadata !"oeq", metadata !"fpexcept.ignore") #0
define i1 @cmp_eq_02() #0 {
; CHECK-LABEL: @cmp_eq_02(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[RESULT:%.*]] = call i1 @llvm.experimental.constrained.fcmp.f64(double 2.000000e+00, double 2.000000e+00, metadata !"oeq", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret i1 [[RESULT]]
+; CHECK-NEXT: ret i1 true
;
entry:
%result = call i1 @llvm.experimental.constrained.fcmp.f64(double 2.0, double 2.0, metadata !"oeq", metadata !"fpexcept.ignore") #0
define i1 @cmp_eq_03() #0 {
; CHECK-LABEL: @cmp_eq_03(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[RESULT:%.*]] = call i1 @llvm.experimental.constrained.fcmp.f64(double 2.000000e+00, double 0x7FF8000000000000, metadata !"oeq", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret i1 [[RESULT]]
+; CHECK-NEXT: ret i1 false
;
entry:
%result = call i1 @llvm.experimental.constrained.fcmp.f64(double 2.0, double 0x7ff8000000000000, metadata !"oeq", metadata !"fpexcept.ignore") #0
define i1 @cmp_eq_04() #0 {
; CHECK-LABEL: @cmp_eq_04(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[RESULT:%.*]] = call i1 @llvm.experimental.constrained.fcmp.f64(double 2.000000e+00, double 0x7FF4000000000000, metadata !"oeq", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret i1 [[RESULT]]
+; CHECK-NEXT: ret i1 false
;
entry:
%result = call i1 @llvm.experimental.constrained.fcmp.f64(double 2.0, double 0x7ff4000000000000, metadata !"oeq", metadata !"fpexcept.ignore") #0
define i1 @cmp_eq_05() #0 {
; CHECK-LABEL: @cmp_eq_05(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[RESULT:%.*]] = call i1 @llvm.experimental.constrained.fcmps.f64(double 2.000000e+00, double 0x7FF8000000000000, metadata !"oeq", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret i1 [[RESULT]]
+; CHECK-NEXT: ret i1 false
;
entry:
%result = call i1 @llvm.experimental.constrained.fcmps.f64(double 2.0, double 0x7ff8000000000000, metadata !"oeq", metadata !"fpexcept.ignore") #0
define i1 @cmp_eq_06() #0 {
; CHECK-LABEL: @cmp_eq_06(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[RESULT:%.*]] = call i1 @llvm.experimental.constrained.fcmps.f64(double 2.000000e+00, double 0x7FF4000000000000, metadata !"oeq", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret i1 [[RESULT]]
+; CHECK-NEXT: ret i1 false
;
entry:
%result = call i1 @llvm.experimental.constrained.fcmps.f64(double 2.0, double 0x7ff4000000000000, metadata !"oeq", metadata !"fpexcept.ignore") #0
; CHECK-LABEL: @cmp_eq_nan_03(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[RESULT:%.*]] = call i1 @llvm.experimental.constrained.fcmp.f64(double 0x7FF8000000000000, double 1.000000e+00, metadata !"oeq", metadata !"fpexcept.strict") #[[ATTR0]]
-; CHECK-NEXT: ret i1 [[RESULT]]
+; CHECK-NEXT: ret i1 false
;
entry:
%result = call i1 @llvm.experimental.constrained.fcmp.f64(double 0x7ff8000000000000, double 1.0, metadata !"oeq", metadata !"fpexcept.strict") #0