[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