[llvm] [KnownFPClass] Refine sNaN handling for KnownFPClass (PR #216086)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 13 10:51:41 PDT 2026
https://github.com/ZERICO2005 updated https://github.com/llvm/llvm-project/pull/216086
>From f505133d823b3359f034866c7b05a4201cbe9830 Mon Sep 17 00:00:00 2001
From: zerico <zerico2005 at gmail.com>
Date: Thu, 13 Aug 2026 11:51:20 -0600
Subject: [PATCH] [KnownFPClass] Refactor sNaN handling for KnownFPClass
---
llvm/include/llvm/Support/KnownFPClass.h | 26 +++++++++++---
llvm/lib/Analysis/ValueTracking.cpp | 2 +-
llvm/lib/Support/KnownFPClass.cpp | 36 +++++++++----------
.../Transforms/Attributor/nofpclass-trig.ll | 10 ++++++
4 files changed, 49 insertions(+), 25 deletions(-)
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 956141b9449a2..dadf4133d826b 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -268,7 +268,7 @@ struct KnownFPClass {
// X * X is always non-negative or a NaN.
Known.knownNot(fcNegative);
- Known.propagateNaN(Src);
+ Known.propagateNonNaN(Src);
return Known;
}
@@ -380,16 +380,34 @@ struct KnownFPClass {
return Known;
}
+ // Propagate knowledge that an operation cannot introduce a signaling NaN.
+ void propagateNonSNaN(const KnownFPClass &Src) {
+ if (Src.isKnownNever(fcSNan))
+ knownNot(fcSNan);
+ }
+
+ // Propagate knowledge that an operation cannot introduce a signaling NaN.
+ void propagateNonSNaN(const KnownFPClass &LHS, const KnownFPClass &RHS) {
+ if (LHS.isKnownNever(fcSNan) && RHS.isKnownNever(fcSNan))
+ knownNot(fcSNan);
+ }
+
// Propagate knowledge that a non-NaN source implies the result can also not
// be a NaN. For unconstrained operations, signaling nans are not guaranteed
// to be quieted but cannot be introduced.
- void propagateNaN(const KnownFPClass &Src, bool PreserveSign = false) {
+ void propagateNonNaN(const KnownFPClass &Src, bool PreserveSign = false) {
+ propagateNonSNaN(Src);
if (Src.isKnownNever(fcNan)) {
knownNot(fcNan);
if (PreserveSign)
SignBit = Src.SignBit;
- } else if (Src.isKnownNever(fcSNan))
- knownNot(fcSNan);
+ }
+ }
+
+ void propagateNonNaN(const KnownFPClass &LHS, const KnownFPClass &RHS) {
+ propagateNonSNaN(LHS, RHS);
+ if (LHS.isKnownNeverNaN() && RHS.isKnownNeverNaN())
+ knownNot(fcNan);
}
// Propagate knowledge for operations whose result sign is the xor of the
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 28d47d8f7df27..9c8e1281ae626 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5659,7 +5659,7 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedClasses,
KnownSrc, Q, Depth + 1);
- Known.propagateNaN(KnownSrc);
+ Known.propagateNonNaN(KnownSrc);
Type *EltTy = II->getType()->getScalarType();
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 0d72e2317ef6f..42f53a9ed92d3 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -506,7 +506,7 @@ KnownFPClass KnownFPClass::exp(const KnownFPClass &KnownSrc) {
KnownFPClass Known;
Known.knownNot(fcNegative);
- Known.propagateNaN(KnownSrc);
+ Known.propagateNonNaN(KnownSrc);
if (KnownSrc.cannotBeOrderedLessThanZero()) {
// If the source is positive this cannot underflow.
@@ -526,7 +526,7 @@ KnownFPClass KnownFPClass::exp(const KnownFPClass &KnownSrc) {
void KnownFPClass::propagateCanonicalizingSrc(const KnownFPClass &Src,
DenormalMode Mode) {
propagateDenormal(Src, Mode);
- propagateNaN(Src, /*PreserveSign=*/true);
+ propagateNonNaN(Src, /*PreserveSign=*/true);
}
KnownFPClass KnownFPClass::log(const KnownFPClass &KnownSrc,
@@ -553,8 +553,8 @@ KnownFPClass KnownFPClass::sqrt(const KnownFPClass &KnownSrc,
if (KnownSrc.isKnownNeverPosInfinity())
Known.knownNot(fcPosInf);
- if (KnownSrc.isKnownNever(fcSNan))
- Known.knownNot(fcSNan);
+
+ Known.propagateNonSNaN(KnownSrc);
// Any negative value besides -0 returns a nan.
if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero())
@@ -606,7 +606,7 @@ KnownFPClass KnownFPClass::sinh(const KnownFPClass &KnownSrc) {
if (KnownSrc.isKnownNever(fcNegative))
Known.knownNot(fcNegative);
- Known.propagateNaN(KnownSrc);
+ Known.propagateNonNaN(KnownSrc);
return Known;
}
@@ -618,7 +618,7 @@ KnownFPClass KnownFPClass::cosh(const KnownFPClass &KnownSrc) {
// zero, or subnormal.
Known.knownNot(fcNegative | fcZero | fcSubnormal);
- Known.propagateNaN(KnownSrc);
+ Known.propagateNonNaN(KnownSrc);
return Known;
}
@@ -633,7 +633,7 @@ KnownFPClass KnownFPClass::tanh(const KnownFPClass &KnownSrc) {
if (KnownSrc.isKnownNever(fcNegative))
Known.knownNot(fcNegative);
- Known.propagateNaN(KnownSrc);
+ Known.propagateNonNaN(KnownSrc);
return Known;
}
@@ -644,8 +644,7 @@ KnownFPClass KnownFPClass::asin(const KnownFPClass &KnownSrc) {
// asin is bounded to [-pi/2, pi/2], never Inf.
Known.knownNot(fcInf);
- if (KnownSrc.isKnownNever(fcSNan))
- Known.knownNot(fcSNan);
+ Known.propagateNonSNaN(KnownSrc);
// asin is sign-preserving.
if (KnownSrc.isKnownNever(fcNegative))
@@ -663,8 +662,7 @@ KnownFPClass KnownFPClass::acos(const KnownFPClass &KnownSrc) {
Known.knownNot(fcInf);
Known.knownNot(fcNegative);
- if (KnownSrc.isKnownNever(fcSNan))
- Known.knownNot(fcSNan);
+ Known.propagateNonSNaN(KnownSrc);
// NaN propagates. acos(x) is also NaN for |x| > 1, so we cannot rule
// out NaN without knowing the source is in [-1, 1].
@@ -681,7 +679,7 @@ KnownFPClass KnownFPClass::atan(const KnownFPClass &KnownSrc) {
if (KnownSrc.isKnownNever(fcNegative))
Known.knownNot(fcNegative);
- Known.propagateNaN(KnownSrc);
+ Known.propagateNonNaN(KnownSrc);
return Known;
}
@@ -693,9 +691,7 @@ KnownFPClass KnownFPClass::atan2(const KnownFPClass &KnownLHS,
// atan2 result is in (-pi, pi], never Inf.
Known.knownNot(fcInf);
- // NaN if either operand is NaN.
- if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN())
- Known.knownNot(fcNan);
+ Known.propagateNonNaN(KnownLHS, KnownRHS);
return Known;
}
@@ -730,7 +726,7 @@ KnownFPClass KnownFPClass::fptrunc(const KnownFPClass &KnownSrc) {
if (KnownSrc.cannotBeOrderedLessThanZero())
Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
- Known.propagateNaN(KnownSrc, true);
+ Known.propagateNonNaN(KnownSrc, true);
// Infinity needs a range check.
return Known;
@@ -744,7 +740,7 @@ KnownFPClass KnownFPClass::roundToIntegral(const KnownFPClass &KnownSrc,
// Integer results cannot be subnormal.
Known.knownNot(fcSubnormal);
- Known.propagateNaN(KnownSrc, true);
+ Known.propagateNonNaN(KnownSrc, true);
// Pass through infinities, except PPC_FP128 is a special case for
// intrinsics other than trunc.
@@ -787,7 +783,7 @@ KnownFPClass KnownFPClass::frexp_mant(const KnownFPClass &KnownSrc,
Known.knownNot(fcPosInf);
}
- Known.propagateNaN(KnownSrc);
+ Known.propagateNonNaN(KnownSrc);
return Known;
}
@@ -796,7 +792,7 @@ KnownFPClass KnownFPClass::ldexp(const KnownFPClass &KnownSrc,
const APInt &ConstantRangeExpMax,
const fltSemantics &Flt, DenormalMode Mode) {
KnownFPClass Known;
- Known.propagateNaN(KnownSrc, /*PropagateSign=*/true);
+ Known.propagateNonNaN(KnownSrc, /*PreserveSign=*/true);
// Sign is preserved, but underflows may produce zeroes.
if (KnownSrc.isKnownNever(fcNegative))
@@ -848,7 +844,7 @@ KnownFPClass KnownFPClass::ldexp(const KnownFPClass &KnownSrc,
KnownFPClass KnownFPClass::powi(const KnownFPClass &KnownSrc,
const KnownBits &ExponentKnownBits) {
KnownFPClass Known;
- Known.propagateNaN(KnownSrc);
+ Known.propagateNonNaN(KnownSrc);
if (ExponentKnownBits.isZero()) {
// powi(QNaN, 0) returns 1.0, and powi(SNaN, 0) may non-deterministically
diff --git a/llvm/test/Transforms/Attributor/nofpclass-trig.ll b/llvm/test/Transforms/Attributor/nofpclass-trig.ll
index f4eb5ffc3c71b..a2d6a19975041 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-trig.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-trig.ll
@@ -218,3 +218,13 @@ define float @ret_atan2_nonan(float nofpclass(nan) %arg0, float nofpclass(nan) %
%call = call float @llvm.atan2.f32(float %arg0, float %arg1)
ret float %call
}
+
+define float @ret_atan2_nosnan(float nofpclass(snan) %arg0, float nofpclass(snan) %arg1) {
+; CHECK-LABEL: define nofpclass(snan inf) float @ret_atan2_nosnan
+; CHECK-SAME: (float nofpclass(snan) [[ARG0:%.*]], float nofpclass(snan) [[ARG1:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(snan inf) float @llvm.atan2.f32(float nofpclass(snan) [[ARG0]], float nofpclass(snan) [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %arg0, float %arg1)
+ ret float %call
+}
More information about the llvm-commits
mailing list