[llvm] [Support][ValueTraking] Improve KnownFPClass for fadd. Handle infinity signs and strict sign cases (PR #190559)

Max Graey via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 5 17:44:25 PDT 2026


https://github.com/MaxGraey updated https://github.com/llvm/llvm-project/pull/190559

>From 61e001c389095036b6bb09cad7514c5c02dc1b9e Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 6 Apr 2026 02:22:20 +0300
Subject: [PATCH 1/4] [KnownFPClass] more precise fadd

---
 llvm/include/llvm/Support/KnownFPClass.h      | 11 +++++
 llvm/lib/Support/KnownFPClass.cpp             | 18 ++++++--
 llvm/test/Transforms/InstCombine/fcmp.ll      | 44 +++++++++++++++++++
 .../simplify-demanded-fpclass-fadd.ll         |  4 +-
 4 files changed, 72 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index c48e0f8b7b65b..8986d4b17c854 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -127,6 +127,17 @@ struct KnownFPClass {
     return isKnownNever(OrderedGreaterThanZeroMask);
   }
 
+  /// Return true if it's known this can never be a positive value or a logical
+  /// 0.
+  ///
+  ///      NaN --> true
+  ///  x <= +0 --> false
+  ///     psub --> true if mode is ieee, false otherwise.
+  ///   x > +0 --> true
+  bool cannotBeOrderedLessEqZero(DenormalMode Mode) const {
+    return isKnownNever(fcNegative) && isKnownNeverLogicalPosZero(Mode);
+  }
+
   /// Return true if it's know this can never be a negative value or a logical
   /// 0.
   ///
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 4f704eabfc6ec..9a0644774cf50 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -292,16 +292,22 @@ static KnownFPClass fadd_impl(const KnownFPClass &KnownLHS,
                               const KnownFPClass &KnownRHS, DenormalMode Mode) {
   KnownFPClass Known;
 
-  // Adding positive and negative infinity produces NaN.
-  // TODO: Check sign of infinities.
+  // Adding positive and negative infinity produces NaN, but only if both
+  // opposite-sign infinity combinations are possible.
   if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
-      (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity()))
+      (KnownLHS.isKnownNever(fcPosInf) || KnownRHS.isKnownNever(fcNegInf)) &&
+      (KnownLHS.isKnownNever(fcNegInf) || KnownRHS.isKnownNever(fcPosInf)))
     Known.knownNot(fcNan);
 
   if (KnownLHS.cannotBeOrderedLessThanZero() &&
       KnownRHS.cannotBeOrderedLessThanZero()) {
     Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
 
+    // Adding two strictly positive values cannot produce zero.
+    if (KnownLHS.cannotBeOrderedGreaterEqZero(Mode) &&
+        KnownRHS.cannotBeOrderedGreaterEqZero(Mode))
+      Known.knownNot(fcZero);
+
     // This can't underflow if one of the operands is known normal.
     if (KnownLHS.isKnownNever(fcZero | fcPosSubnormal) ||
         KnownRHS.isKnownNever(fcZero | fcPosSubnormal))
@@ -312,6 +318,12 @@ static KnownFPClass fadd_impl(const KnownFPClass &KnownLHS,
       KnownRHS.cannotBeOrderedGreaterThanZero()) {
     Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask);
 
+    // Adding two strictly negative values cannot produce zero.
+    if (KnownLHS.cannotBeOrderedLessEqZero(Mode) &&
+        KnownRHS.cannotBeOrderedLessEqZero(Mode))
+      Known.knownNot(fcZero);
+
+
     // This can't underflow if one of the operands is known normal.
     if (KnownLHS.isKnownNever(fcZero | fcNegSubnormal) ||
         KnownRHS.isKnownNever(fcZero | fcNegSubnormal))
diff --git a/llvm/test/Transforms/InstCombine/fcmp.ll b/llvm/test/Transforms/InstCombine/fcmp.ll
index e3c43812cedd6..c0086c207eec2 100644
--- a/llvm/test/Transforms/InstCombine/fcmp.ll
+++ b/llvm/test/Transforms/InstCombine/fcmp.ll
@@ -1499,6 +1499,50 @@ define i1 @fcmp_fadd_zero_switched(float %x, float %y) {
   ret i1 %cmp
 }
 
+define i1 @fadd_posinf_posinf_ord() {
+; CHECK-LABEL: @fadd_posinf_posinf_ord(
+; CHECK-NEXT:    ret i1 true
+;
+  %add = fadd float 0x7FF0000000000000, 0x7FF0000000000000
+  %cmp = fcmp ord float %add, 0.000000e+00
+  ret i1 %cmp
+}
+
+define i1 @fadd_neginf_neginf_ord() {
+; CHECK-LABEL: @fadd_neginf_neginf_ord(
+; CHECK-NEXT:    ret i1 true
+;
+  %add = fadd float 0xFFF0000000000000, 0xFFF0000000000000
+  %cmp = fcmp ord float %add, 0.000000e+00
+  ret i1 %cmp
+}
+
+define i1 @fadd_strictly_positive_ne_zero(double %x, double %y) {
+; CHECK-LABEL: @fadd_strictly_positive_ne_zero(
+; CHECK-NEXT:    ret i1 false
+;
+  %ax = call double @llvm.fabs.f64(double %x)
+  %ay = call double @llvm.fabs.f64(double %y)
+  %px = fadd double %ax, 1.000000e+00
+  %py = fadd double %ay, 1.000000e+00
+  %add = fadd double %px, %py
+  %cmp = fcmp oeq double %add, 0.000000e+00
+  ret i1 %cmp
+}
+
+define i1 @fadd_strictly_negative_ne_zero(double %x, double %y) {
+; CHECK-LABEL: @fadd_strictly_negative_ne_zero(
+; CHECK-NEXT:    ret i1 false
+;
+  %ax = call double @llvm.fabs.f64(double %x)
+  %ay = call double @llvm.fabs.f64(double %y)
+  %nx = fsub double -1.000000e+00, %ax
+  %ny = fsub double -1.000000e+00, %ay
+  %add = fadd double %nx, %ny
+  %cmp = fcmp oeq double %add, 0.000000e+00
+  ret i1 %cmp
+}
+
 define <2 x i1> @fcmp_fadd_zero_vec(<2 x float> %x, <2 x float> %y) {
 ; CHECK-LABEL: @fcmp_fadd_zero_vec(
 ; CHECK-NEXT:    [[CMP:%.*]] = fcmp ugt <2 x float> [[X:%.*]], [[Y:%.*]]
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fadd.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fadd.ll
index eee3405e9b8cf..b7338f435531c 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fadd.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fadd.ll
@@ -490,7 +490,7 @@ define nofpclass(nzero) half @inferred_nan_output__fadd__no_pinf_no_nan__no_nan(
 define nofpclass(nzero) half @inferred_nan_output__fadd__no_pinf_no_nan__no_pinf_no_nan(half nofpclass(nan pinf) %x, half nofpclass(nan pinf) %y) {
 ; CHECK-LABEL: define nofpclass(nzero) half @inferred_nan_output__fadd__no_pinf_no_nan__no_pinf_no_nan(
 ; CHECK-SAME: half nofpclass(nan pinf) [[X:%.*]], half nofpclass(nan pinf) [[Y:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = fadd half [[X]], [[Y]]
+; CHECK-NEXT:    [[ADD:%.*]] = fadd nnan half [[X]], [[Y]]
 ; CHECK-NEXT:    ret half [[ADD]]
 ;
   %add = fadd half %x, %y
@@ -500,7 +500,7 @@ define nofpclass(nzero) half @inferred_nan_output__fadd__no_pinf_no_nan__no_pinf
 define nofpclass(nzero) half @inferred_nan_output__fadd__no_ninf_no_nan__no_ninf_no_nan(half nofpclass(nan ninf) %x, half nofpclass(nan ninf) %y) {
 ; CHECK-LABEL: define nofpclass(nzero) half @inferred_nan_output__fadd__no_ninf_no_nan__no_ninf_no_nan(
 ; CHECK-SAME: half nofpclass(nan ninf) [[X:%.*]], half nofpclass(nan ninf) [[Y:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = fadd half [[X]], [[Y]]
+; CHECK-NEXT:    [[ADD:%.*]] = fadd nnan half [[X]], [[Y]]
 ; CHECK-NEXT:    ret half [[ADD]]
 ;
   %add = fadd half %x, %y

>From d59315abd2b04216862b4fc7dcb95150723d8b16 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 6 Apr 2026 02:29:50 +0300
Subject: [PATCH 2/4] fix format

---
 llvm/lib/Support/KnownFPClass.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 9a0644774cf50..67d62328cb9bb 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -323,7 +323,6 @@ static KnownFPClass fadd_impl(const KnownFPClass &KnownLHS,
         KnownRHS.cannotBeOrderedLessEqZero(Mode))
       Known.knownNot(fcZero);
 
-
     // This can't underflow if one of the operands is known normal.
     if (KnownLHS.isKnownNever(fcZero | fcNegSubnormal) ||
         KnownRHS.isKnownNever(fcZero | fcNegSubnormal))

>From 05b0379fcde84f557bd746beda417a3708ede197 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 6 Apr 2026 03:20:30 +0300
Subject: [PATCH 3/4] update known-never-nan test

---
 llvm/test/Transforms/InstSimplify/known-never-nan.ll | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/llvm/test/Transforms/InstSimplify/known-never-nan.ll b/llvm/test/Transforms/InstSimplify/known-never-nan.ll
index 907eca0a856a8..98c873ac8a3de 100644
--- a/llvm/test/Transforms/InstSimplify/known-never-nan.ll
+++ b/llvm/test/Transforms/InstSimplify/known-never-nan.ll
@@ -340,10 +340,7 @@ define i1 @uitofp_add(i32 %arg0) {
 
 define i1 @uitofp_add_big(i1024 %arg0) {
 ; CHECK-LABEL: @uitofp_add_big(
-; CHECK-NEXT:    [[OP:%.*]] = uitofp i1024 [[ARG0:%.*]] to double
-; CHECK-NEXT:    [[ADD:%.*]] = fadd double [[OP]], [[OP]]
-; CHECK-NEXT:    [[TMP:%.*]] = fcmp ord double [[ADD]], [[ADD]]
-; CHECK-NEXT:    ret i1 [[TMP]]
+; CHECK-NEXT:    ret i1 true
 ;
   %op = uitofp i1024 %arg0 to double
   %add = fadd double %op, %op

>From b5c4c5272db48ca55548e31771ee975a45215c7f Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 6 Apr 2026 03:43:48 +0300
Subject: [PATCH 4/4] remove redundant code

---
 llvm/lib/Support/KnownFPClass.cpp        | 10 ------
 llvm/test/Transforms/InstCombine/fcmp.ll | 44 ------------------------
 2 files changed, 54 deletions(-)

diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 67d62328cb9bb..56da9880c733d 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -303,11 +303,6 @@ static KnownFPClass fadd_impl(const KnownFPClass &KnownLHS,
       KnownRHS.cannotBeOrderedLessThanZero()) {
     Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
 
-    // Adding two strictly positive values cannot produce zero.
-    if (KnownLHS.cannotBeOrderedGreaterEqZero(Mode) &&
-        KnownRHS.cannotBeOrderedGreaterEqZero(Mode))
-      Known.knownNot(fcZero);
-
     // This can't underflow if one of the operands is known normal.
     if (KnownLHS.isKnownNever(fcZero | fcPosSubnormal) ||
         KnownRHS.isKnownNever(fcZero | fcPosSubnormal))
@@ -318,11 +313,6 @@ static KnownFPClass fadd_impl(const KnownFPClass &KnownLHS,
       KnownRHS.cannotBeOrderedGreaterThanZero()) {
     Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask);
 
-    // Adding two strictly negative values cannot produce zero.
-    if (KnownLHS.cannotBeOrderedLessEqZero(Mode) &&
-        KnownRHS.cannotBeOrderedLessEqZero(Mode))
-      Known.knownNot(fcZero);
-
     // This can't underflow if one of the operands is known normal.
     if (KnownLHS.isKnownNever(fcZero | fcNegSubnormal) ||
         KnownRHS.isKnownNever(fcZero | fcNegSubnormal))
diff --git a/llvm/test/Transforms/InstCombine/fcmp.ll b/llvm/test/Transforms/InstCombine/fcmp.ll
index c0086c207eec2..e3c43812cedd6 100644
--- a/llvm/test/Transforms/InstCombine/fcmp.ll
+++ b/llvm/test/Transforms/InstCombine/fcmp.ll
@@ -1499,50 +1499,6 @@ define i1 @fcmp_fadd_zero_switched(float %x, float %y) {
   ret i1 %cmp
 }
 
-define i1 @fadd_posinf_posinf_ord() {
-; CHECK-LABEL: @fadd_posinf_posinf_ord(
-; CHECK-NEXT:    ret i1 true
-;
-  %add = fadd float 0x7FF0000000000000, 0x7FF0000000000000
-  %cmp = fcmp ord float %add, 0.000000e+00
-  ret i1 %cmp
-}
-
-define i1 @fadd_neginf_neginf_ord() {
-; CHECK-LABEL: @fadd_neginf_neginf_ord(
-; CHECK-NEXT:    ret i1 true
-;
-  %add = fadd float 0xFFF0000000000000, 0xFFF0000000000000
-  %cmp = fcmp ord float %add, 0.000000e+00
-  ret i1 %cmp
-}
-
-define i1 @fadd_strictly_positive_ne_zero(double %x, double %y) {
-; CHECK-LABEL: @fadd_strictly_positive_ne_zero(
-; CHECK-NEXT:    ret i1 false
-;
-  %ax = call double @llvm.fabs.f64(double %x)
-  %ay = call double @llvm.fabs.f64(double %y)
-  %px = fadd double %ax, 1.000000e+00
-  %py = fadd double %ay, 1.000000e+00
-  %add = fadd double %px, %py
-  %cmp = fcmp oeq double %add, 0.000000e+00
-  ret i1 %cmp
-}
-
-define i1 @fadd_strictly_negative_ne_zero(double %x, double %y) {
-; CHECK-LABEL: @fadd_strictly_negative_ne_zero(
-; CHECK-NEXT:    ret i1 false
-;
-  %ax = call double @llvm.fabs.f64(double %x)
-  %ay = call double @llvm.fabs.f64(double %y)
-  %nx = fsub double -1.000000e+00, %ax
-  %ny = fsub double -1.000000e+00, %ay
-  %add = fadd double %nx, %ny
-  %cmp = fcmp oeq double %add, 0.000000e+00
-  ret i1 %cmp
-}
-
 define <2 x i1> @fcmp_fadd_zero_vec(<2 x float> %x, <2 x float> %y) {
 ; CHECK-LABEL: @fcmp_fadd_zero_vec(
 ; CHECK-NEXT:    [[CMP:%.*]] = fcmp ugt <2 x float> [[X:%.*]], [[Y:%.*]]



More information about the llvm-commits mailing list