diff --git a/llvm/include/llvm/IR/IntrinsicInst.h b/llvm/include/llvm/IR/IntrinsicInst.h --- a/llvm/include/llvm/IR/IntrinsicInst.h +++ b/llvm/include/llvm/IR/IntrinsicInst.h @@ -492,6 +492,9 @@ class ConstrainedFPCmpIntrinsic : public ConstrainedFPIntrinsic { public: FCmpInst::Predicate getPredicate() const; + bool isSignaling() const { + return getIntrinsicID() == Intrinsic::experimental_constrained_fcmps; + } // Methods for support type inquiry through isa, cast, and dyn_cast: static bool classof(const IntrinsicInst *I) { diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1512,6 +1512,8 @@ 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; @@ -1783,12 +1785,12 @@ // 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 @@ -2286,6 +2288,25 @@ return nullptr; } +static Constant *evaluateCompare(const ConstrainedFPIntrinsic *Call) { + APFloat::opStatus St = APFloat::opOK; + auto *FCmp = cast(Call); + FCmpInst::Predicate Cond = FCmp->getPredicate(); + const APFloat &Op1 = cast(FCmp->getOperand(0))->getValueAPF(); + const APFloat &Op2 = cast(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(FCmp), St)) + return ConstantInt::get(Call->getType(), Result); + return nullptr; +} + static Constant *ConstantFoldScalarCall2(StringRef Name, Intrinsic::ID IntrinsicID, Type *Ty, @@ -2314,8 +2335,6 @@ } if (const auto *Op1 = dyn_cast(Operands[0])) { - if (!Ty->isFloatingPointTy()) - return nullptr; const APFloat &Op1V = Op1->getValueAPF(); if (const auto *Op2 = dyn_cast(Operands[1])) { @@ -2345,6 +2364,9 @@ 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(ConstrIntr), St)) diff --git a/llvm/test/Transforms/InstSimplify/constfold-constrained.ll b/llvm/test/Transforms/InstSimplify/constfold-constrained.ll --- a/llvm/test/Transforms/InstSimplify/constfold-constrained.ll +++ b/llvm/test/Transforms/InstSimplify/constfold-constrained.ll @@ -421,8 +421,7 @@ 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 @@ -432,8 +431,7 @@ 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 @@ -443,8 +441,7 @@ 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 @@ -454,8 +451,7 @@ 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 @@ -465,8 +461,7 @@ 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 @@ -476,8 +471,7 @@ 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 @@ -512,7 +506,7 @@ ; 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