[llvm] [Support][ValueTraking] Improve KnownFPClass for fadd. Handle infinity signs (PR #190559)
Max Graey via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 6 06:36:06 PDT 2026
https://github.com/MaxGraey updated https://github.com/llvm/llvm-project/pull/190559
>From 567c7287409d28a5996ad187e3f9369c3dc73a79 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/3] [KnownFPClass] more precise fadd
---
llvm/include/llvm/Support/KnownFPClass.h | 11 +++++++++++
llvm/lib/Support/KnownFPClass.cpp | 7 ++++---
llvm/test/Transforms/InstCombine/is_fpclass.ll | 18 ++++++++++++++++++
.../simplify-demanded-fpclass-fadd.ll | 4 ++--
.../Transforms/InstSimplify/known-never-nan.ll | 5 +----
5 files changed, 36 insertions(+), 9 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..56da9880c733d 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -292,10 +292,11 @@ 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() &&
diff --git a/llvm/test/Transforms/InstCombine/is_fpclass.ll b/llvm/test/Transforms/InstCombine/is_fpclass.ll
index 70a7663e5768a..ae50f25a528e2 100644
--- a/llvm/test/Transforms/InstCombine/is_fpclass.ll
+++ b/llvm/test/Transforms/InstCombine/is_fpclass.ll
@@ -2616,6 +2616,24 @@ define i1 @test_class_is_posinf_noinf_src(float nofpclass(inf) %arg) {
ret i1 %class
}
+define i1 @test_fadd_no_nan_from_no_ninf(float nofpclass(nan ninf) %x, float nofpclass(nan ninf) %y) {
+; CHECK-LABEL: @test_fadd_no_nan_from_no_ninf(
+; CHECK-NEXT: ret i1 false
+;
+ %add = fadd float %x, %y
+ %class = call i1 @llvm.is.fpclass.f32(float %add, i32 3)
+ ret i1 %class
+}
+
+define i1 @test_fadd_no_nan_from_no_pinf(float nofpclass(nan pinf) %x, float nofpclass(nan pinf) %y) {
+; CHECK-LABEL: @test_fadd_no_nan_from_no_pinf(
+; CHECK-NEXT: ret i1 false
+;
+ %add = fadd float %x, %y
+ %class = call i1 @llvm.is.fpclass.f32(float %add, i32 3)
+ ret i1 %class
+}
+
define i1 @test_class_is_subnormal_nosub_src(float nofpclass(sub) %arg) {
; CHECK-LABEL: @test_class_is_subnormal_nosub_src(
; CHECK-NEXT: ret i1 false
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
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 b0dfaf5ef6db9743546679d186dd31ce87ff8b23 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 6 Apr 2026 16:31:39 +0300
Subject: [PATCH 2/3] move tests to nofpclass.ll
---
llvm/test/Transforms/Attributor/nofpclass.ll | 44 +++++++++++++++++++
.../test/Transforms/InstCombine/is_fpclass.ll | 18 --------
2 files changed, 44 insertions(+), 18 deletions(-)
diff --git a/llvm/test/Transforms/Attributor/nofpclass.ll b/llvm/test/Transforms/Attributor/nofpclass.ll
index efe0d7a0a0922..bb9bfb391c00d 100644
--- a/llvm/test/Transforms/Attributor/nofpclass.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass.ll
@@ -2297,6 +2297,50 @@ define float @fadd_known_positive_daz(float nofpclass(ninf nsub nnorm) %arg0, fl
ret float %add
}
+define float @test_fadd_no_nan_from_no_ninf(float nofpclass(nan ninf) %x, float nofpclass(nan ninf) %y) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define nofpclass(nan) float @test_fadd_no_nan_from_no_ninf
+; CHECK-SAME: (float nofpclass(nan ninf) [[X:%.*]], float nofpclass(nan ninf) [[Y:%.*]]) #[[ATTR:[0-9]+]] {
+; CHECK-NEXT: [[ADD:%.*]] = fadd float [[X]], [[Y]]
+; CHECK-NEXT: ret float [[ADD]]
+;
+ %add = fadd float %x, %y
+ ret float %add
+}
+
+define float @test_fadd_no_nan_from_no_pinf(float nofpclass(nan pinf) %x, float nofpclass(nan pinf) %y) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define nofpclass(nan) float @test_fadd_no_nan_from_no_pinf
+; CHECK-SAME: (float nofpclass(nan pinf) [[X:%.*]], float nofpclass(nan pinf) [[Y:%.*]]) #[[ATTR:[0-9]+]] {
+; CHECK-NEXT: [[ADD:%.*]] = fadd float [[X]], [[Y]]
+; CHECK-NEXT: ret float [[ADD]]
+;
+ %add = fadd float %x, %y
+ ret float %add
+}
+
+define float @test_fadd_may_nan_from_no_pinf_no_ninf(float nofpclass(nan pinf) %x, float nofpclass(nan ninf) %y) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define float @test_fadd_may_nan_from_no_pinf_no_ninf
+; CHECK-SAME: (float nofpclass(nan pinf) [[X:%.*]], float nofpclass(nan ninf) [[Y:%.*]]) #[[ATTR:[0-9]+]] {
+; CHECK-NEXT: [[ADD:%.*]] = fadd float [[X]], [[Y]]
+; CHECK-NEXT: ret float [[ADD]]
+;
+ %add = fadd float %x, %y
+ ret float %add
+}
+
+define float @test_fadd_may_nan_from_no_ninf_no_pinf(float nofpclass(nan ninf) %x, float nofpclass(nan pinf) %y) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define float @test_fadd_may_nan_from_no_ninf_no_pinf
+; CHECK-SAME: (float nofpclass(nan ninf) [[X:%.*]], float nofpclass(nan pinf) [[Y:%.*]]) #[[ATTR:[0-9]+]] {
+; CHECK-NEXT: [[ADD:%.*]] = fadd float [[X]], [[Y]]
+; CHECK-NEXT: ret float [[ADD]]
+;
+ %add = fadd float %x, %y
+ ret float %add
+}
+
define float @fadd_known_positive_nzero_lhs(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @fadd_known_positive_nzero_lhs
diff --git a/llvm/test/Transforms/InstCombine/is_fpclass.ll b/llvm/test/Transforms/InstCombine/is_fpclass.ll
index ae50f25a528e2..70a7663e5768a 100644
--- a/llvm/test/Transforms/InstCombine/is_fpclass.ll
+++ b/llvm/test/Transforms/InstCombine/is_fpclass.ll
@@ -2616,24 +2616,6 @@ define i1 @test_class_is_posinf_noinf_src(float nofpclass(inf) %arg) {
ret i1 %class
}
-define i1 @test_fadd_no_nan_from_no_ninf(float nofpclass(nan ninf) %x, float nofpclass(nan ninf) %y) {
-; CHECK-LABEL: @test_fadd_no_nan_from_no_ninf(
-; CHECK-NEXT: ret i1 false
-;
- %add = fadd float %x, %y
- %class = call i1 @llvm.is.fpclass.f32(float %add, i32 3)
- ret i1 %class
-}
-
-define i1 @test_fadd_no_nan_from_no_pinf(float nofpclass(nan pinf) %x, float nofpclass(nan pinf) %y) {
-; CHECK-LABEL: @test_fadd_no_nan_from_no_pinf(
-; CHECK-NEXT: ret i1 false
-;
- %add = fadd float %x, %y
- %class = call i1 @llvm.is.fpclass.f32(float %add, i32 3)
- ret i1 %class
-}
-
define i1 @test_class_is_subnormal_nosub_src(float nofpclass(sub) %arg) {
; CHECK-LABEL: @test_class_is_subnormal_nosub_src(
; CHECK-NEXT: ret i1 false
>From 9272876a117aa690c6c4a4c1f1176fa2ec3ab9a1 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Mon, 6 Apr 2026 16:35:52 +0300
Subject: [PATCH 3/3] =?UTF-8?q?=D0=B3use=20arg{0,1}=20naming=20instead=20x?=
=?UTF-8?q?,=20y=20for=20tests?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
llvm/test/Transforms/Attributor/nofpclass.ll | 32 ++++++++++----------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/llvm/test/Transforms/Attributor/nofpclass.ll b/llvm/test/Transforms/Attributor/nofpclass.ll
index bb9bfb391c00d..df1f4d11479ec 100644
--- a/llvm/test/Transforms/Attributor/nofpclass.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass.ll
@@ -2297,47 +2297,47 @@ define float @fadd_known_positive_daz(float nofpclass(ninf nsub nnorm) %arg0, fl
ret float %add
}
-define float @test_fadd_no_nan_from_no_ninf(float nofpclass(nan ninf) %x, float nofpclass(nan ninf) %y) {
+define float @test_fadd_no_nan_from_no_ninf(float nofpclass(nan ninf) %arg0, float nofpclass(nan ninf) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan) float @test_fadd_no_nan_from_no_ninf
-; CHECK-SAME: (float nofpclass(nan ninf) [[X:%.*]], float nofpclass(nan ninf) [[Y:%.*]]) #[[ATTR:[0-9]+]] {
-; CHECK-NEXT: [[ADD:%.*]] = fadd float [[X]], [[Y]]
+; CHECK-SAME: (float nofpclass(nan ninf) [[ARG0:%.*]], float nofpclass(nan ninf) [[ARG1:%.*]]) #[[ATTR:[0-9]+]] {
+; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[ADD]]
;
- %add = fadd float %x, %y
+ %add = fadd float %arg0, %arg1
ret float %add
}
-define float @test_fadd_no_nan_from_no_pinf(float nofpclass(nan pinf) %x, float nofpclass(nan pinf) %y) {
+define float @test_fadd_no_nan_from_no_pinf(float nofpclass(nan pinf) %arg0, float nofpclass(nan pinf) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan) float @test_fadd_no_nan_from_no_pinf
-; CHECK-SAME: (float nofpclass(nan pinf) [[X:%.*]], float nofpclass(nan pinf) [[Y:%.*]]) #[[ATTR:[0-9]+]] {
-; CHECK-NEXT: [[ADD:%.*]] = fadd float [[X]], [[Y]]
+; CHECK-SAME: (float nofpclass(nan pinf) [[ARG0:%.*]], float nofpclass(nan pinf) [[ARG1:%.*]]) #[[ATTR:[0-9]+]] {
+; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[ADD]]
;
- %add = fadd float %x, %y
+ %add = fadd float %arg0, %arg1
ret float %add
}
-define float @test_fadd_may_nan_from_no_pinf_no_ninf(float nofpclass(nan pinf) %x, float nofpclass(nan ninf) %y) {
+define float @test_fadd_may_nan_from_no_pinf_no_ninf(float nofpclass(nan pinf) %arg0, float nofpclass(nan ninf) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @test_fadd_may_nan_from_no_pinf_no_ninf
-; CHECK-SAME: (float nofpclass(nan pinf) [[X:%.*]], float nofpclass(nan ninf) [[Y:%.*]]) #[[ATTR:[0-9]+]] {
-; CHECK-NEXT: [[ADD:%.*]] = fadd float [[X]], [[Y]]
+; CHECK-SAME: (float nofpclass(nan pinf) [[ARG0:%.*]], float nofpclass(nan ninf) [[ARG1:%.*]]) #[[ATTR:[0-9]+]] {
+; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[ADD]]
;
- %add = fadd float %x, %y
+ %add = fadd float %arg0, %arg1
ret float %add
}
-define float @test_fadd_may_nan_from_no_ninf_no_pinf(float nofpclass(nan ninf) %x, float nofpclass(nan pinf) %y) {
+define float @test_fadd_may_nan_from_no_ninf_no_pinf(float nofpclass(nan ninf) %arg0, float nofpclass(nan pinf) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @test_fadd_may_nan_from_no_ninf_no_pinf
-; CHECK-SAME: (float nofpclass(nan ninf) [[X:%.*]], float nofpclass(nan pinf) [[Y:%.*]]) #[[ATTR:[0-9]+]] {
-; CHECK-NEXT: [[ADD:%.*]] = fadd float [[X]], [[Y]]
+; CHECK-SAME: (float nofpclass(nan ninf) [[ARG0:%.*]], float nofpclass(nan pinf) [[ARG1:%.*]]) #[[ATTR:[0-9]+]] {
+; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[ADD]]
;
- %add = fadd float %x, %y
+ %add = fadd float %arg0, %arg1
ret float %add
}
More information about the llvm-commits
mailing list