[llvm-branch-commits] [llvm] ValueTracking: Rule out nan for fdiv self special case (PR #174857)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Jan 8 09:13:55 PST 2026


https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/174857

>From 5bb93c09faa05f24ecf4a86f78ca07dc0ad155c7 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 6 Jan 2026 09:22:14 +0100
Subject: [PATCH] ValueTracking: Rule out nan for fdiv self special case

Addresses TODO for signaling nan handling.
---
 llvm/lib/Analysis/ValueTracking.cpp           | 22 +++++++++++++++++--
 .../Transforms/Attributor/nofpclass-fdiv.ll   | 18 +++++++--------
 .../Transforms/Attributor/nofpclass-frem.ll   | 18 +++++++--------
 3 files changed, 38 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 4776020df0bc5..964adfcb761dd 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5642,9 +5642,10 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
   }
   case Instruction::FDiv:
   case Instruction::FRem: {
+    const bool WantNan = (InterestedClasses & fcNan) != fcNone;
+
     if (Op->getOperand(0) == Op->getOperand(1) &&
         isGuaranteedNotToBeUndef(Op->getOperand(0), Q.AC, Q.CxtI, Q.DT)) {
-      // TODO: Could filter out snan if we inspect the operand
       if (Op->getOpcode() == Instruction::FDiv) {
         // X / X is always exactly 1.0 or a NaN.
         Known.KnownFPClasses = fcNan | fcPosNormal;
@@ -5653,10 +5654,27 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
         Known.KnownFPClasses = fcNan | fcZero;
       }
 
+      if (!WantNan)
+        break;
+
+      KnownFPClass KnownSrc;
+      computeKnownFPClass(Op->getOperand(0), DemandedElts,
+                          fcNan | fcInf | fcZero | fcSubnormal, KnownSrc, Q,
+                          Depth + 1);
+      const Function *F = cast<Instruction>(Op)->getFunction();
+      const fltSemantics &FltSem =
+          Op->getType()->getScalarType()->getFltSemantics();
+
+      if (KnownSrc.isKnownNever(fcNan) && KnownSrc.isKnownNeverInfinity() &&
+          KnownSrc.isKnownNeverLogicalZero(F ? F->getDenormalMode(FltSem)
+                                             : DenormalMode::getDynamic()))
+        Known.knownNot(fcNan);
+      else if (KnownSrc.isKnownNever(fcSNan))
+        Known.knownNot(fcSNan);
+
       break;
     }
 
-    const bool WantNan = (InterestedClasses & fcNan) != fcNone;
     const bool WantNegative = (InterestedClasses & fcNegative) != fcNone;
     const bool WantPositive =
         Opc == Instruction::FRem && (InterestedClasses & fcPositive) != fcNone;
diff --git a/llvm/test/Transforms/Attributor/nofpclass-fdiv.ll b/llvm/test/Transforms/Attributor/nofpclass-fdiv.ll
index 8efed69d9d7c4..fbf302b48cd3a 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-fdiv.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-fdiv.ll
@@ -376,7 +376,7 @@ define float @ret_fdiv_same_operands_maybe_undef(float %arg) #0 {
 }
 
 define float @ret_fdiv_same_operands_nosnan(float noundef nofpclass(snan) %arg) #0 {
-; CHECK-LABEL: define noundef nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_nosnan
+; CHECK-LABEL: define noundef nofpclass(snan inf zero sub nnorm) float @ret_fdiv_same_operands_nosnan
 ; CHECK-SAME: (float noundef nofpclass(snan) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -396,7 +396,7 @@ define float @ret_fdiv_same_operands_noqnan(float noundef nofpclass(qnan) %arg)
 }
 
 define float @ret_fdiv_same_operands_nonan(float noundef nofpclass(nan) %arg) #0 {
-; CHECK-LABEL: define noundef nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_nonan
+; CHECK-LABEL: define noundef nofpclass(snan inf zero sub nnorm) float @ret_fdiv_same_operands_nonan
 ; CHECK-SAME: (float noundef nofpclass(nan) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -406,7 +406,7 @@ define float @ret_fdiv_same_operands_nonan(float noundef nofpclass(nan) %arg) #0
 }
 
 define float @ret_fdiv_same_operands_nonan_noinf(float noundef nofpclass(nan inf) %arg) #0 {
-; CHECK-LABEL: define noundef nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_noinf
+; CHECK-LABEL: define noundef nofpclass(snan inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_noinf
 ; CHECK-SAME: (float noundef nofpclass(nan inf) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -416,7 +416,7 @@ define float @ret_fdiv_same_operands_nonan_noinf(float noundef nofpclass(nan inf
 }
 
 define float @ret_fdiv_same_operands_nonan_nozero(float noundef nofpclass(nan zero) %arg) #0 {
-; CHECK-LABEL: define noundef nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_nozero
+; CHECK-LABEL: define noundef nofpclass(snan inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_nozero
 ; CHECK-SAME: (float noundef nofpclass(nan zero) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -426,7 +426,7 @@ define float @ret_fdiv_same_operands_nonan_nozero(float noundef nofpclass(nan ze
 }
 
 define float @ret_fdiv_same_operands_nonan_noinf_nozero(float noundef nofpclass(nan inf zero) %arg) #0 {
-; CHECK-LABEL: define noundef nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_noinf_nozero
+; CHECK-LABEL: define noundef nofpclass(nan inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_noinf_nozero
 ; CHECK-SAME: (float noundef nofpclass(nan inf zero) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -436,7 +436,7 @@ define float @ret_fdiv_same_operands_nonan_noinf_nozero(float noundef nofpclass(
 }
 
 define float @ret_fdiv_same_operands_nonan_noinf_nozero_nosub(float noundef nofpclass(nan inf zero) %arg) #0 {
-; CHECK-LABEL: define noundef nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_noinf_nozero_nosub
+; CHECK-LABEL: define noundef nofpclass(nan inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_noinf_nozero_nosub
 ; CHECK-SAME: (float noundef nofpclass(nan inf zero) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -447,7 +447,7 @@ define float @ret_fdiv_same_operands_nonan_noinf_nozero_nosub(float noundef nofp
 
 ; May be nan if denormal is flushed
 define float @ret_fdiv_same_operands_nonan_noinf_nozero__daz(float noundef nofpclass(nan inf zero) %arg) #1 {
-; CHECK-LABEL: define noundef nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_noinf_nozero__daz
+; CHECK-LABEL: define noundef nofpclass(snan inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_noinf_nozero__daz
 ; CHECK-SAME: (float noundef nofpclass(nan inf zero) [[ARG:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -458,7 +458,7 @@ define float @ret_fdiv_same_operands_nonan_noinf_nozero__daz(float noundef nofpc
 
 ; Can't have a flushed input
 define float @ret_fdiv_same_operands_nonan_noinf_nozero_nosub__daz(float noundef nofpclass(nan inf sub zero) %arg) #1 {
-; CHECK-LABEL: define noundef nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_noinf_nozero_nosub__daz
+; CHECK-LABEL: define noundef nofpclass(nan inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_noinf_nozero_nosub__daz
 ; CHECK-SAME: (float noundef nofpclass(nan inf zero sub) [[ARG:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -469,7 +469,7 @@ define float @ret_fdiv_same_operands_nonan_noinf_nozero_nosub__daz(float noundef
 
 ; Can't have a flushed input
 define float @ret_fdiv_same_operands_nonan_noinf_nozero_nosub__dynamic(float noundef nofpclass(nan inf sub zero) %arg) #3 {
-; CHECK-LABEL: define noundef nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_noinf_nozero_nosub__dynamic
+; CHECK-LABEL: define noundef nofpclass(nan inf zero sub nnorm) float @ret_fdiv_same_operands_nonan_noinf_nozero_nosub__dynamic
 ; CHECK-SAME: (float noundef nofpclass(nan inf zero sub) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FDIV]]
diff --git a/llvm/test/Transforms/Attributor/nofpclass-frem.ll b/llvm/test/Transforms/Attributor/nofpclass-frem.ll
index 36c3ae108c1f8..2c442c10289f5 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-frem.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-frem.ll
@@ -376,7 +376,7 @@ define float @ret_frem_same_operands_maybe_undef(float %arg) #0 {
 }
 
 define float @ret_frem_same_operands_nosnan(float noundef nofpclass(snan) %arg) #0 {
-; CHECK-LABEL: define noundef nofpclass(inf sub norm) float @ret_frem_same_operands_nosnan
+; CHECK-LABEL: define noundef nofpclass(snan inf sub norm) float @ret_frem_same_operands_nosnan
 ; CHECK-SAME: (float noundef nofpclass(snan) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FREM:%.*]] = frem float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FREM]]
@@ -396,7 +396,7 @@ define float @ret_frem_same_operands_noqnan(float noundef nofpclass(qnan) %arg)
 }
 
 define float @ret_frem_same_operands_nonan(float noundef nofpclass(nan) %arg) #0 {
-; CHECK-LABEL: define noundef nofpclass(inf sub norm) float @ret_frem_same_operands_nonan
+; CHECK-LABEL: define noundef nofpclass(snan inf sub norm) float @ret_frem_same_operands_nonan
 ; CHECK-SAME: (float noundef nofpclass(nan) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FREM:%.*]] = frem float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FREM]]
@@ -406,7 +406,7 @@ define float @ret_frem_same_operands_nonan(float noundef nofpclass(nan) %arg) #0
 }
 
 define float @ret_frem_same_operands_nonan_noinf(float noundef nofpclass(nan inf) %arg) #0 {
-; CHECK-LABEL: define noundef nofpclass(inf sub norm) float @ret_frem_same_operands_nonan_noinf
+; CHECK-LABEL: define noundef nofpclass(snan inf sub norm) float @ret_frem_same_operands_nonan_noinf
 ; CHECK-SAME: (float noundef nofpclass(nan inf) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FREM:%.*]] = frem float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FREM]]
@@ -416,7 +416,7 @@ define float @ret_frem_same_operands_nonan_noinf(float noundef nofpclass(nan inf
 }
 
 define float @ret_frem_same_operands_nonan_nozero(float noundef nofpclass(nan zero) %arg) #0 {
-; CHECK-LABEL: define noundef nofpclass(inf sub norm) float @ret_frem_same_operands_nonan_nozero
+; CHECK-LABEL: define noundef nofpclass(snan inf sub norm) float @ret_frem_same_operands_nonan_nozero
 ; CHECK-SAME: (float noundef nofpclass(nan zero) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FREM:%.*]] = frem float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FREM]]
@@ -426,7 +426,7 @@ define float @ret_frem_same_operands_nonan_nozero(float noundef nofpclass(nan ze
 }
 
 define float @ret_frem_same_operands_nonan_noinf_nozero(float noundef nofpclass(nan inf zero) %arg) #0 {
-; CHECK-LABEL: define noundef nofpclass(inf sub norm) float @ret_frem_same_operands_nonan_noinf_nozero
+; CHECK-LABEL: define noundef nofpclass(nan inf sub norm) float @ret_frem_same_operands_nonan_noinf_nozero
 ; CHECK-SAME: (float noundef nofpclass(nan inf zero) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FREM:%.*]] = frem float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FREM]]
@@ -436,7 +436,7 @@ define float @ret_frem_same_operands_nonan_noinf_nozero(float noundef nofpclass(
 }
 
 define float @ret_frem_same_operands_nonan_noinf_nozero_nosub(float noundef nofpclass(nan inf zero) %arg) #0 {
-; CHECK-LABEL: define noundef nofpclass(inf sub norm) float @ret_frem_same_operands_nonan_noinf_nozero_nosub
+; CHECK-LABEL: define noundef nofpclass(nan inf sub norm) float @ret_frem_same_operands_nonan_noinf_nozero_nosub
 ; CHECK-SAME: (float noundef nofpclass(nan inf zero) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FREM:%.*]] = frem float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FREM]]
@@ -447,7 +447,7 @@ define float @ret_frem_same_operands_nonan_noinf_nozero_nosub(float noundef nofp
 
 ; May be nan if denormal is flushed
 define float @ret_frem_same_operands_nonan_noinf_nozero__daz(float noundef nofpclass(nan inf zero) %arg) #1 {
-; CHECK-LABEL: define noundef nofpclass(inf sub norm) float @ret_frem_same_operands_nonan_noinf_nozero__daz
+; CHECK-LABEL: define noundef nofpclass(snan inf sub norm) float @ret_frem_same_operands_nonan_noinf_nozero__daz
 ; CHECK-SAME: (float noundef nofpclass(nan inf zero) [[ARG:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[FREM:%.*]] = frem float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FREM]]
@@ -458,7 +458,7 @@ define float @ret_frem_same_operands_nonan_noinf_nozero__daz(float noundef nofpc
 
 ; Can't have a flushed input
 define float @ret_frem_same_operands_nonan_noinf_nozero_nosub__daz(float noundef nofpclass(nan inf sub zero) %arg) #1 {
-; CHECK-LABEL: define noundef nofpclass(inf sub norm) float @ret_frem_same_operands_nonan_noinf_nozero_nosub__daz
+; CHECK-LABEL: define noundef nofpclass(nan inf sub norm) float @ret_frem_same_operands_nonan_noinf_nozero_nosub__daz
 ; CHECK-SAME: (float noundef nofpclass(nan inf zero sub) [[ARG:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[FREM:%.*]] = frem float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FREM]]
@@ -469,7 +469,7 @@ define float @ret_frem_same_operands_nonan_noinf_nozero_nosub__daz(float noundef
 
 ; Can't have a flushed input
 define float @ret_frem_same_operands_nonan_noinf_nozero_nosub__dynamic(float noundef nofpclass(nan inf sub zero) %arg) #3 {
-; CHECK-LABEL: define noundef nofpclass(inf sub norm) float @ret_frem_same_operands_nonan_noinf_nozero_nosub__dynamic
+; CHECK-LABEL: define noundef nofpclass(nan inf sub norm) float @ret_frem_same_operands_nonan_noinf_nozero_nosub__dynamic
 ; CHECK-SAME: (float noundef nofpclass(nan inf zero sub) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[FREM:%.*]] = frem float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[FREM]]



More information about the llvm-branch-commits mailing list