[llvm] [ValueTraking] Improve KnownFPClass for fadd. Handle infinity signs and strict sign cases (PR #190559)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Apr 5 16:28:15 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
@llvm/pr-subscribers-llvm-support
Author: Max Graey (MaxGraey)
<details>
<summary>Changes</summary>
Improve KnownFPClass reasoning for fadd:
- Refine NaN handling for infinities by checking opposite-sign cases;
- Infer non-zero results for strictly positive/negative operands;
- Itroduce `cannotBeOrderedLessEqZero` as pair to `cannotBeOrderedGreaterEqZero`;
---
Full diff: https://github.com/llvm/llvm-project/pull/190559.diff
4 Files Affected:
- (modified) llvm/include/llvm/Support/KnownFPClass.h (+11)
- (modified) llvm/lib/Support/KnownFPClass.cpp (+15-3)
- (modified) llvm/test/Transforms/InstCombine/fcmp.ll (+44)
- (modified) llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fadd.ll (+2-2)
``````````diff
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/190559
More information about the llvm-commits
mailing list