[llvm-branch-commits] [llvm] [ConstantFolding] Non-constrained functions in strictfp (PR #190478)
Serge Pavlov via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sat Apr 4 11:18:44 PDT 2026
https://github.com/spavloff created https://github.com/llvm/llvm-project/pull/190478
Non-constrained function calls, allowed in strictfp functions by PR188297, are equivalent to their constrained counterparts with dynamic rounding and strict exception handling. When constant folding the calls of these functions, some cases cannot be folded due to unknown rounding mode or floting-point exceptions that can be lost. This change adapts constant folding for these case.
>From 5845d8e0323798d17430513cb3d1ef73a062fb6e Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Fri, 27 Mar 2026 23:49:55 +0700
Subject: [PATCH] [ConstantFolding] Non-constrained functions in strictfp
Non-constrained function calls, allowed in strictfp functions by
PR188297, are equivalent to their constrained counterparts with dynamic
rounding and strict exception handling. When constant folding the calls
of these functions, some cases cannot be folded due to unknown rounding
mode or floting-point exceptions that can be lost. This change adapts
constant folding for these case.
---
llvm/include/llvm/IR/InstrTypes.h | 9 +
llvm/lib/Analysis/ConstantFolding.cpp | 137 +++++---
.../InstSimplify/constfold-strictfp.ll | 306 ++++++++++++++++++
3 files changed, 402 insertions(+), 50 deletions(-)
create mode 100644 llvm/test/Transforms/InstSimplify/constfold-strictfp.ll
diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index 938b82ba891ce..40e7decf007fa 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -2352,6 +2352,15 @@ class CallBase : public Instruction {
}
};
+/// Check if the provided call is inside a function with attribute StrictFP.
+inline std::optional<bool> isCalledFromStrictFPFunction(const CallBase *Call) {
+ if (!Call)
+ return std::nullopt;
+ if (const BasicBlock *BB = Call->getParent())
+ if (const Function *F = BB->getParent())
+ return F->getAttributes().hasFnAttr(Attribute::StrictFP);
+}
+
template <>
struct OperandTraits<CallBase> : public VariadicOperandTraits<CallBase> {};
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 9dbab56348411..eddab280e58d8 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1704,29 +1704,13 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
// Floating point operations cannot be folded in strictfp functions in
// general case. They can be folded if FP environment is known to compiler.
- case Intrinsic::minnum:
- case Intrinsic::maxnum:
- case Intrinsic::minimum:
- case Intrinsic::maximum:
+#define FUNCTION(NAME, R, D) case Intrinsic::NAME:
+#include "llvm/IR/FloatingPointOps.def"
+
+ case Intrinsic::exp10:
case Intrinsic::minimumnum:
case Intrinsic::maximumnum:
- case Intrinsic::log:
- case Intrinsic::log2:
- case Intrinsic::log10:
- case Intrinsic::exp:
- case Intrinsic::exp2:
- case Intrinsic::exp10:
- case Intrinsic::sqrt:
- case Intrinsic::sin:
- case Intrinsic::cos:
case Intrinsic::sincos:
- case Intrinsic::sinh:
- case Intrinsic::cosh:
- case Intrinsic::atan:
- case Intrinsic::pow:
- case Intrinsic::powi:
- case Intrinsic::ldexp:
- case Intrinsic::fma:
case Intrinsic::fmuladd:
case Intrinsic::frexp:
case Intrinsic::fptoui_sat:
@@ -1940,15 +1924,6 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
case Intrinsic::fabs:
case Intrinsic::copysign:
case Intrinsic::is_fpclass:
- // Non-constrained variants of rounding operations means default FP
- // environment, they can be folded in any case.
- case Intrinsic::ceil:
- case Intrinsic::floor:
- case Intrinsic::round:
- case Intrinsic::roundeven:
- case Intrinsic::trunc:
- case Intrinsic::nearbyint:
- case Intrinsic::rint:
case Intrinsic::canonicalize:
// Constrained intrinsics can be folded if FP environment is known
@@ -2461,6 +2436,10 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
if (auto *Op = dyn_cast<ConstantFP>(Operands[0])) {
APFloat U = Op->getValueAPF();
+ // If the call is not contained in a function, assume as if it was in
+ // a StrictFP function, because this is more restrictive.
+ bool IsStrictFP = isCalledFromStrictFPFunction(Call).value_or(true);
+
if (IntrinsicID == Intrinsic::wasm_trunc_signed ||
IntrinsicID == Intrinsic::wasm_trunc_unsigned) {
bool Signed = IntrinsicID == Intrinsic::wasm_trunc_signed;
@@ -2513,34 +2492,47 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
// Use internal versions of these intrinsics.
- if (IntrinsicID == Intrinsic::nearbyint || IntrinsicID == Intrinsic::rint ||
- IntrinsicID == Intrinsic::roundeven) {
- U.roundToIntegral(APFloat::rmNearestTiesToEven);
+ if (IntrinsicID == Intrinsic::nearbyint || IntrinsicID == Intrinsic::rint) {
+ // If the result of rounding is precise with some rounding mode, it
+ // would be precise with any.
+ APFloat::opStatus St = U.roundToIntegral(APFloat::rmNearestTiesToEven);
+ if (IsStrictFP && St != APFloat::opOK)
+ return nullptr;
return ConstantFP::get(Ty, U);
}
if (IntrinsicID == Intrinsic::round) {
- U.roundToIntegral(APFloat::rmNearestTiesToAway);
+ APFloat::opStatus St = U.roundToIntegral(APFloat::rmNearestTiesToAway);
+ if (IsStrictFP && St != APFloat::opOK)
+ return nullptr;
return ConstantFP::get(Ty, U);
}
if (IntrinsicID == Intrinsic::roundeven) {
- U.roundToIntegral(APFloat::rmNearestTiesToEven);
+ APFloat::opStatus St = U.roundToIntegral(APFloat::rmNearestTiesToEven);
+ if (IsStrictFP && St != APFloat::opOK)
+ return nullptr;
return ConstantFP::get(Ty, U);
}
if (IntrinsicID == Intrinsic::ceil) {
- U.roundToIntegral(APFloat::rmTowardPositive);
+ APFloat::opStatus St = U.roundToIntegral(APFloat::rmTowardPositive);
+ if (IsStrictFP && St != APFloat::opOK)
+ return nullptr;
return ConstantFP::get(Ty, U);
}
if (IntrinsicID == Intrinsic::floor) {
- U.roundToIntegral(APFloat::rmTowardNegative);
+ APFloat::opStatus St = U.roundToIntegral(APFloat::rmTowardNegative);
+ if (IsStrictFP && St != APFloat::opOK)
+ return nullptr;
return ConstantFP::get(Ty, U);
}
if (IntrinsicID == Intrinsic::trunc) {
- U.roundToIntegral(APFloat::rmTowardZero);
+ APFloat::opStatus St = U.roundToIntegral(APFloat::rmTowardZero);
+ if (IsStrictFP && St != APFloat::opOK)
+ return nullptr;
return ConstantFP::get(Ty, U);
}
@@ -2562,46 +2554,53 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
return ConstantFP::get(Ty, minimum(FractU, AlmostOne));
}
- // Rounding operations (floor, trunc, ceil, round and nearbyint) do not
- // raise FP exceptions, unless the argument is signaling NaN.
+ // Determine rounding mode to be used in the evaluation.
+ RoundingMode RM =
+ IsStrictFP ? RoundingMode::Dynamic : RoundingMode::NearestTiesToEven;
+ if (auto CI = dyn_cast<ConstrainedFPIntrinsic>(Call)) {
+ if (Intrinsic::hasConstrainedFPRoundingModeOperand(IntrinsicID))
+ if (auto MaybeRounding = CI->getRoundingMode())
+ RM = *MaybeRounding;
+ }
- std::optional<APFloat::roundingMode> RM;
+ bool IsConstrainedRoundingOp = false;
switch (IntrinsicID) {
default:
break;
case Intrinsic::experimental_constrained_nearbyint:
- case Intrinsic::experimental_constrained_rint: {
- auto CI = cast<ConstrainedFPIntrinsic>(Call);
- RM = CI->getRoundingMode();
- if (!RM || *RM == RoundingMode::Dynamic)
+ case Intrinsic::experimental_constrained_rint:
+ if (RM == RoundingMode::Dynamic)
return nullptr;
+ IsConstrainedRoundingOp = true;
break;
- }
case Intrinsic::experimental_constrained_round:
RM = APFloat::rmNearestTiesToAway;
+ IsConstrainedRoundingOp = true;
break;
case Intrinsic::experimental_constrained_ceil:
RM = APFloat::rmTowardPositive;
+ IsConstrainedRoundingOp = true;
break;
case Intrinsic::experimental_constrained_floor:
RM = APFloat::rmTowardNegative;
+ IsConstrainedRoundingOp = true;
break;
case Intrinsic::experimental_constrained_trunc:
RM = APFloat::rmTowardZero;
+ IsConstrainedRoundingOp = true;
break;
}
- if (RM) {
+ if (IsConstrainedRoundingOp) {
auto CI = cast<ConstrainedFPIntrinsic>(Call);
+ std::optional<fp::ExceptionBehavior> EB = CI->getExceptionBehavior();
if (U.isFinite()) {
- APFloat::opStatus St = U.roundToIntegral(*RM);
+ APFloat::opStatus St = U.roundToIntegral(RM);
if (IntrinsicID == Intrinsic::experimental_constrained_rint &&
- St == APFloat::opInexact) {
- std::optional<fp::ExceptionBehavior> EB = CI->getExceptionBehavior();
+ (St == APFloat::opInexact)) {
if (EB == fp::ebStrict)
return nullptr;
}
} else if (U.isSignaling()) {
- std::optional<fp::ExceptionBehavior> EB = CI->getExceptionBehavior();
if (EB && *EB != fp::ebIgnore)
return nullptr;
U = APFloat::getQNaN(U.getSemantics());
@@ -2717,6 +2716,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
return ConstantFP::getNaN(Ty);
if (U.isExactlyValue(1.0))
return ConstantFP::getZero(Ty);
+ if (RM != RoundingMode::NearestTiesToEven)
+ return nullptr;
return ConstantFoldFP(log, APF, Ty);
case Intrinsic::log2:
if (U.isZero())
@@ -2725,6 +2726,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
return ConstantFP::getNaN(Ty);
if (U.isExactlyValue(1.0))
return ConstantFP::getZero(Ty);
+ if (RM != RoundingMode::NearestTiesToEven)
+ return nullptr;
// TODO: What about hosts that lack a C99 library?
return ConstantFoldFP(log2, APF, Ty);
case Intrinsic::log10:
@@ -2734,30 +2737,50 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
return ConstantFP::getNaN(Ty);
if (U.isExactlyValue(1.0))
return ConstantFP::getZero(Ty);
+ if (RM != RoundingMode::NearestTiesToEven)
+ return nullptr;
// TODO: What about hosts that lack a C99 library?
return ConstantFoldFP(log10, APF, Ty);
case Intrinsic::exp:
+ if (RM != RoundingMode::NearestTiesToEven)
+ return nullptr;
return ConstantFoldFP(exp, APF, Ty);
case Intrinsic::exp2:
+ if (RM != RoundingMode::NearestTiesToEven)
+ return nullptr;
// Fold exp2(x) as pow(2, x), in case the host lacks a C99 library.
return ConstantFoldBinaryFP(pow, APFloat(2.0), APF, Ty);
case Intrinsic::exp10:
+ if (RM != RoundingMode::NearestTiesToEven)
+ return nullptr;
// Fold exp10(x) as pow(10, x), in case the host lacks a C99 library.
return ConstantFoldBinaryFP(pow, APFloat(10.0), APF, Ty);
case Intrinsic::sin:
+ if (RM != RoundingMode::NearestTiesToEven)
+ return nullptr;
return ConstantFoldFP(sin, APF, Ty);
case Intrinsic::cos:
+ if (RM != RoundingMode::NearestTiesToEven)
+ return nullptr;
return ConstantFoldFP(cos, APF, Ty);
case Intrinsic::sinh:
+ if (RM != RoundingMode::NearestTiesToEven)
+ return nullptr;
return ConstantFoldFP(sinh, APF, Ty);
case Intrinsic::cosh:
+ if (RM != RoundingMode::NearestTiesToEven)
+ return nullptr;
return ConstantFoldFP(cosh, APF, Ty);
case Intrinsic::atan:
// Implement optional behavior from C's Annex F for +/-0.0.
if (U.isZero())
return ConstantFP::get(Ty, U);
+ if (RM != RoundingMode::NearestTiesToEven)
+ return nullptr;
return ConstantFoldFP(atan, APF, Ty);
case Intrinsic::sqrt:
+ if (RM != RoundingMode::NearestTiesToEven)
+ return nullptr;
return ConstantFoldFP(sqrt, APF, Ty);
// NVVM Intrinsics:
@@ -3307,6 +3330,8 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
if (const auto *Op1 = dyn_cast<ConstantFP>(Operands[0])) {
const APFloat &Op1V = Op1->getValueAPF();
+ bool IsStrictFP = isCalledFromStrictFPFunction(Call).value_or(true);
+
if (const auto *Op2 = dyn_cast<ConstantFP>(Operands[1])) {
if (Op2->getType() != Op1->getType())
return nullptr;
@@ -3345,6 +3370,9 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
return nullptr;
}
+ if (IsStrictFP && (Op1V.isSignaling() || Op2V.isSignaling()))
+ return nullptr;
+
switch (IntrinsicID) {
default:
break;
@@ -3546,6 +3574,8 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
} else if (auto *Op2C = dyn_cast<ConstantInt>(Operands[1])) {
switch (IntrinsicID) {
case Intrinsic::ldexp: {
+ if (IsStrictFP)
+ return nullptr;
return ConstantFP::get(
Ty->getContext(),
scalbn(Op1V, Op2C->getSExtValue(), APFloat::rmNearestTiesToEven));
@@ -3566,6 +3596,8 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
return ConstantInt::get(Ty, Result);
}
case Intrinsic::powi: {
+ if (IsStrictFP)
+ return nullptr;
int Exp = static_cast<int>(Op2C->getSExtValue());
switch (Ty->getTypeID()) {
case Type::HalfTyID:
@@ -3930,6 +3962,8 @@ static Constant *ConstantFoldScalarCall3(StringRef Name,
if (const auto *ConstrIntr = dyn_cast<ConstrainedFPIntrinsic>(Call)) {
RoundingMode RM = getEvaluationRoundingMode(ConstrIntr);
+ if (RM == RoundingMode::Dynamic)
+ return nullptr;
APFloat Res = C1;
APFloat::opStatus St;
switch (IntrinsicID) {
@@ -3960,6 +3994,9 @@ static Constant *ConstantFoldScalarCall3(StringRef Name,
}
case Intrinsic::fma:
case Intrinsic::fmuladd: {
+ if (isCalledFromStrictFPFunction(Call).value_or(true) &&
+ (C1.isSignaling() || C2.isSignaling() || C3.isSignaling()))
+ return nullptr;
APFloat V = C1;
V.fusedMultiplyAdd(C2, C3, APFloat::rmNearestTiesToEven);
return ConstantFP::get(Ty, V);
diff --git a/llvm/test/Transforms/InstSimplify/constfold-strictfp.ll b/llvm/test/Transforms/InstSimplify/constfold-strictfp.ll
new file mode 100644
index 0000000000000..4896476f4aa1e
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/constfold-strictfp.ll
@@ -0,0 +1,306 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+; These tests check constant folding of the floating-point intrinsics, when
+; they are used in strictfp functions.
+
+; floor(10.0) is folded to 10.0
+define double @floor_exact() #0 {
+; CHECK-LABEL: define double @floor_exact(
+; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.floor.f64(double 1.000000e+01)
+; CHECK-NEXT: ret double 1.000000e+01
+;
+entry:
+ %result = call double @llvm.floor.f64(double 1.000000e+01)
+ ret double %result
+}
+
+; floor(SNAN) is NOT folded due to 'Invalid' exception. This is required by C Standard.
+define double @floor_snan() #0 {
+; CHECK-LABEL: define double @floor_snan(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.floor.f64(double 0x7FF4000000000000)
+; CHECK-NEXT: ret double [[RESULT]]
+;
+entry:
+ %result = call double @llvm.floor.f64(double 0x7ff4000000000000)
+ ret double %result
+}
+
+; floor(10.1) is folded to 10.0 despite the possible 'Inexact' exception allowed by POSIX.
+define double @floor_inexact() #0 {
+; CHECK-LABEL: define double @floor_inexact(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.floor.f64(double 1.010000e+01)
+; CHECK-NEXT: ret double [[RESULT]]
+;
+entry:
+ %result = call double @llvm.floor.f64(double 1.010000e+01)
+ ret double %result
+}
+
+; floor(+0.0) is folded to +0.0
+define double @floor_poszero() #0 {
+; CHECK-LABEL: define double @floor_poszero(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.floor.f64(double 0.000000e+00)
+; CHECK-NEXT: ret double 0.000000e+00
+;
+entry:
+ %result = call double @llvm.floor.f64(double 0.0)
+ ret double %result
+}
+
+; floor(-0.0) is folded to -0.0
+define double @floor_negzero() #0 {
+; CHECK-LABEL: define double @floor_negzero(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.floor.f64(double -0.000000e+00)
+; CHECK-NEXT: ret double -0.000000e+00
+;
+entry:
+ %result = call double @llvm.floor.f64(double -0.0)
+ ret double %result
+}
+
+; floor(+inf) is folded to +inf
+define double @floor_posinf() #0 {
+; CHECK-LABEL: define double @floor_posinf(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.floor.f64(double 0x7FF0000000000000)
+; CHECK-NEXT: ret double 0x7FF0000000000000
+;
+entry:
+ %result = call double @llvm.floor.f64(double 0x7ff0000000000000)
+ ret double %result
+}
+
+; floor(-inf) is folded to -inf
+define double @floor_neginf() #0 {
+; CHECK-LABEL: define double @floor_neginf(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.floor.f64(double 0xFFF0000000000000)
+; CHECK-NEXT: ret double 0xFFF0000000000000
+;
+entry:
+ %result = call double @llvm.floor.f64(double 0xfff0000000000000)
+ ret double %result
+}
+
+; ceil(10.0) is folded to 10.0
+define double @ceil_exact() #0 {
+; CHECK-LABEL: define double @ceil_exact(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.ceil.f64(double 1.000000e+01)
+; CHECK-NEXT: ret double 1.000000e+01
+;
+entry:
+ %result = call double @llvm.ceil.f64(double 1.000000e+01)
+ ret double %result
+}
+
+; ceil(SNAN) is NOT folded due to 'Invalid' exception. This is required by C Standard.
+define double @fceil_snan() #0 {
+; CHECK-LABEL: define double @fceil_snan(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.ceil.f64(double 0x7FF4000000000000)
+; CHECK-NEXT: ret double [[RESULT]]
+;
+entry:
+ %result = call double @llvm.ceil.f64(double 0x7ff4000000000000)
+ ret double %result
+}
+
+; trunc(10.0) is folded to 10.0
+define double @trunc_exact() #0 {
+; CHECK-LABEL: define double @trunc_exact(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.trunc.f64(double 1.000000e+01)
+; CHECK-NEXT: ret double 1.000000e+01
+;
+entry:
+ %result = call double @llvm.trunc.f64(double 1.000000e+01)
+ ret double %result
+}
+
+; trunc(SNAN) is NOT folded due to 'Invalid' exception. This is required by C Standard.
+define double @ftrunc_snan() #0 {
+; CHECK-LABEL: define double @ftrunc_snan(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.trunc.f64(double 0x7FF4000000000000)
+; CHECK-NEXT: ret double [[RESULT]]
+;
+entry:
+ %result = call double @llvm.trunc.f64(double 0x7ff4000000000000)
+ ret double %result
+}
+
+; round(10.0) is folded to 10.0
+define double @round_exact() #0 {
+; CHECK-LABEL: define double @round_exact(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.round.f64(double 1.000000e+01)
+; CHECK-NEXT: ret double 1.000000e+01
+;
+entry:
+ %result = call double @llvm.round.f64(double 1.000000e+01)
+ ret double %result
+}
+
+; round(SNAN) is NOT folded due to 'Invalid' exception. This is required by C Standard.
+define double @round_snan() #0 {
+; CHECK-LABEL: define double @round_snan(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.round.f64(double 0x7FF4000000000000)
+; CHECK-NEXT: ret double [[RESULT]]
+;
+entry:
+ %result = call double @llvm.round.f64(double 0x7ff4000000000000)
+ ret double %result
+}
+
+; roundeven(10.0) is folded to 10.0
+define double @roundeven_exact() #0 {
+; CHECK-LABEL: define double @roundeven_exact(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.roundeven.f64(double 1.000000e+01)
+; CHECK-NEXT: ret double 1.000000e+01
+;
+entry:
+ %result = call double @llvm.roundeven.f64(double 1.000000e+01)
+ ret double %result
+}
+
+; roundeven(SNAN) is NOT folded due to 'Invalid' exception. This is required by C Standard.
+define double @roundeven_snan() #0 {
+; CHECK-LABEL: define double @roundeven_snan(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.roundeven.f64(double 0x7FF4000000000000)
+; CHECK-NEXT: ret double [[RESULT]]
+;
+entry:
+ %result = call double @llvm.roundeven.f64(double 0x7ff4000000000000)
+ ret double %result
+}
+
+; nearbyint(10.0) is folded to 10.0
+define double @nearbyint_exact() #0 {
+; CHECK-LABEL: define double @nearbyint_exact(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.nearbyint.f64(double 1.000000e+01)
+; CHECK-NEXT: ret double 1.000000e+01
+;
+entry:
+ %result = call double @llvm.nearbyint.f64(double 1.000000e+01)
+ ret double %result
+}
+
+; nearbyint(SNAN) is NOT folded due to 'Invalid' exception. This is required by C Standard.
+define double @nearbyint_snan() #0 {
+; CHECK-LABEL: define double @nearbyint_snan(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.nearbyint.f64(double 0x7FF4000000000000)
+; CHECK-NEXT: ret double [[RESULT]]
+;
+entry:
+ %result = call double @llvm.nearbyint.f64(double 0x7ff4000000000000)
+ ret double %result
+}
+
+; nearbyint(10.1) is NOT folded because rounding mode is unknown at compile time.
+define double @nearbyint_inexact() #0 {
+; CHECK-LABEL: define double @nearbyint_inexact(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.nearbyint.f64(double 1.010000e+01)
+; CHECK-NEXT: ret double [[RESULT]]
+;
+entry:
+ %result = call double @llvm.nearbyint.f64(double 1.010000e+01)
+ ret double %result
+}
+
+; rint(10.0) is folded to 10.0
+define double @rint_exact() #0 {
+; CHECK-LABEL: define double @rint_exact(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.rint.f64(double 1.000000e+01)
+; CHECK-NEXT: ret double 1.000000e+01
+;
+entry:
+ %result = call double @llvm.rint.f64(double 1.000000e+01)
+ ret double %result
+}
+
+; rint(SNAN) is NOT folded due to 'Invalid' exception. This is required by C Standard.
+define double @rint_snan() #0 {
+; CHECK-LABEL: define double @rint_snan(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.rint.f64(double 0x7FF4000000000000)
+; CHECK-NEXT: ret double [[RESULT]]
+;
+entry:
+ %result = call double @llvm.rint.f64(double 0x7ff4000000000000)
+ ret double %result
+}
+
+; rint(10.1) is NOT folded because rounding mode is unknown at compile time.
+define double @rint_inexact() #0 {
+; CHECK-LABEL: define double @rint_inexact(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.rint.f64(double 1.010000e+01)
+; CHECK-NEXT: ret double [[RESULT]]
+;
+entry:
+ %result = call double @llvm.rint.f64(double 1.010000e+01)
+ ret double %result
+}
+
+; log(1.0) is folded to 0.0, because this is an exact value.
+define double @sin_exact() #0 {
+; CHECK-LABEL: define double @sin_exact(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.log.f64(double 1.000000e+00)
+; CHECK-NEXT: ret double 0.000000e+00
+;
+entry:
+ %result = call double @llvm.log.f64(double 1.0)
+ ret double %result
+}
+
+; log(2.0) is NOT folded, because rounding mode is unknown at compile time.
+define double @sin_inexact() #0 {
+; CHECK-LABEL: define double @sin_inexact(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.log.f64(double 2.000000e+00)
+; CHECK-NEXT: ret double [[RESULT]]
+;
+entry:
+ %result = call double @llvm.log.f64(double 2.0)
+ ret double %result
+}
+
+attributes #0 = { strictfp }
More information about the llvm-branch-commits
mailing list