Skip to content

[KnownFPClass] Improve fadd/fsub deductions around infinity classes - #239064

Draft
ZERICO2005 wants to merge 3 commits into
llvm:mainfrom
ZERICO2005:fadd_inf
Draft

ZERICO2005 wants to merge 3 commits into
llvm:mainfrom
ZERICO2005:fadd_inf

Conversation

@ZERICO2005

@ZERICO2005 ZERICO2005 commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Improved fadd/fsub deductions for ruling out infinity. Additionally, we don't need to worry if one of the inputs is infinity when ruling out finite classes, because adding or subtracting infinity will only result in infinity or NaN.

Also adds test coverage for fadd/fsub NaN deductions.

AI Disclosure:
I used Claude Opus 5 to help write the tests and to help analyze the correctness of the changes.

@ZERICO2005
ZERICO2005 requested a review from tgymnich November 5, 2026 03:05
@ZERICO2005 ZERICO2005 added the floating-point Floating-point math label Nov 5, 2026
@llvmorg-github-actions llvmorg-github-actions Bot added llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:support llvm:transforms labels Nov 5, 2026
@llvmorg-github-actions

llvmorg-github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-support

Author: Eric Ross (ZERICO2005)

Changes

Improve fadd/fsub deductions for ruling out infinity. Additionally, we don't need to worry if one of the inputs is infinity when ruling out finite classes, because adding or subtracting infinity will only result in infinity or NaN.

Also adds test coverage for fadd/fsub NaN deductions.


Patch is 57.90 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/239064.diff

5 Files Affected:

  • (modified) llvm/lib/Support/KnownFPClass.cpp (+20-7)
  • (modified) llvm/test/Transforms/Attributor/nofpclass-fadd-fsub.ll (+342-12)
  • (modified) llvm/test/Transforms/Attributor/nofpclass-fma.ll (+74-54)
  • (modified) llvm/test/Transforms/Attributor/nofpclass-powi.ll (+1-1)
  • (modified) llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-exp.ll (+2-2)
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index f9d8dd1ec20b9..5b0097774fb94 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -498,19 +498,32 @@ static KnownFPClass fadd_impl(const KnownFPClass &KnownLHS,
                               const KnownFPClass &KnownRHS, bool IsFMA) {
   KnownFPClass Known;
 
-  if (KnownLHS.cannotBeOrderedLessThanZero() &&
-      KnownRHS.cannotBeOrderedLessThanZero()) {
-    Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
+  // Rule out infinity.
+  if (KnownLHS.isKnownNever(fcPosInf) && KnownRHS.isKnownNever(fcPosInf) &&
+      (KnownLHS.isKnownNever(fcPosSubnormal | fcPosNormal) ||
+       KnownRHS.isKnownNever(fcPosSubnormal | fcPosNormal)))
+    Known.knownNot(fcPosInf);
+  if (KnownLHS.isKnownNever(fcNegInf) && KnownRHS.isKnownNever(fcNegInf) &&
+      (KnownLHS.isKnownNever(fcNegSubnormal | fcNegNormal) ||
+       KnownRHS.isKnownNever(fcNegSubnormal | fcNegNormal)))
+    Known.knownNot(fcNegInf);
+
+  // Rule out finite.
+  // The only reason this is valid for fma is because fmul will never report a
+  // result where normal is ruled out but overflow is possible (different from
+  // exact infinity).
+  if (KnownLHS.isKnownNever(fcNegSubnormal | fcNegNormal) &&
+      KnownRHS.isKnownNever(fcNegSubnormal | fcNegNormal)) {
+    Known.knownNot(fcNegSubnormal | fcNegNormal);
 
     // This can't underflow if one of the operands is known normal.
     if (KnownLHS.isKnownNever(fcZero | fcPosSubnormal) ||
         KnownRHS.isKnownNever(fcZero | fcPosSubnormal))
       Known.knownNot(fcZero | fcPosSubnormal);
   }
-
-  if (KnownLHS.cannotBeOrderedGreaterThanZero() &&
-      KnownRHS.cannotBeOrderedGreaterThanZero()) {
-    Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask);
+  if (KnownLHS.isKnownNever(fcPosSubnormal | fcPosNormal) &&
+      KnownRHS.isKnownNever(fcPosSubnormal | fcPosNormal)) {
+    Known.knownNot(fcPosSubnormal | fcPosNormal);
 
     // This can't underflow if one of the operands is known normal.
     if (KnownLHS.isKnownNever(fcZero | fcNegSubnormal) ||
diff --git a/llvm/test/Transforms/Attributor/nofpclass-fadd-fsub.ll b/llvm/test/Transforms/Attributor/nofpclass-fadd-fsub.ll
index 2385e189c1130..0d83ec12ff151 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-fadd-fsub.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-fadd-fsub.ll
@@ -631,8 +631,6 @@ define float @fadd_known_positive_normal_dapz(float nofpclass(ninf nnorm nzero)
   ret float %add
 }
 
-
-
 define float @fadd_self(float noundef %arg) {
 ; CHECK-LABEL: define noundef float @fadd_self(
 ; CHECK-SAME: float noundef [[ARG:%.*]]) #[[ATTR0]] {
@@ -774,7 +772,7 @@ define float @fadd_self_no_noninf_nnorm(float noundef nofpclass(ninf nnorm) %arg
 }
 
 define float @fadd_self_no_pnorm_psub(float noundef nofpclass(pnorm psub) %arg) {
-; CHECK-LABEL: define noundef nofpclass(psub) float @fadd_self_no_pnorm_psub(
+; CHECK-LABEL: define noundef nofpclass(psub pnorm) float @fadd_self_no_pnorm_psub(
 ; CHECK-SAME: float noundef nofpclass(psub pnorm) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -784,7 +782,7 @@ define float @fadd_self_no_pnorm_psub(float noundef nofpclass(pnorm psub) %arg)
 }
 
 define float @fadd_self_no_nnorm_nsub(float noundef nofpclass(nnorm nsub) %arg) {
-; CHECK-LABEL: define noundef nofpclass(nsub) float @fadd_self_no_nnorm_nsub(
+; CHECK-LABEL: define noundef nofpclass(nsub nnorm) float @fadd_self_no_nnorm_nsub(
 ; CHECK-SAME: float noundef nofpclass(nsub nnorm) [[ARG:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -1208,8 +1206,6 @@ define float @fadd_self_no_zero__output_only_is_dynamic(float noundef nofpclass(
   ret float %add
 }
 
-
-
 define float @fadd_self_no_zero__output_only_is_ftpz(float noundef nofpclass(zero) %arg) #4 {
 ; CHECK-LABEL: define noundef nofpclass(nzero) float @fadd_self_no_zero__output_only_is_ftpz(
 ; CHECK-SAME: float noundef nofpclass(zero) [[ARG:%.*]]) #[[ATTR5]] {
@@ -1295,7 +1291,7 @@ define half @known_negative_normal_or_inf__fadd__known_negative_or_nan(half nofp
 }
 
 define float @fsub__lhs_nzero__rhs_psub(float nofpclass(nan inf pzero sub norm) %lhs, float nofpclass(nan inf zero nsub norm) %rhs) {
-; CHECK-LABEL: define nofpclass(nan pinf nzero psub pnorm) float @fsub__lhs_nzero__rhs_psub(
+; CHECK-LABEL: define nofpclass(nan inf nzero psub pnorm) float @fsub__lhs_nzero__rhs_psub(
 ; CHECK-SAME: float nofpclass(nan inf pzero sub norm) [[LHS:%.*]], float nofpclass(nan inf zero nsub norm) [[RHS:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[LHS]], [[RHS]]
 ; CHECK-NEXT:    ret float [[SUB]]
@@ -1306,7 +1302,7 @@ define float @fsub__lhs_nzero__rhs_psub(float nofpclass(nan inf pzero sub norm)
 
 ; We shall not rule out negative zero: -0.0 - dapz(psub) == -0.0 - +0.0 == -0.0
 define float @fsub__lhs_nzero__rhs_psub__mode_ieee_dapz(float nofpclass(nan inf pzero sub norm) %lhs, float nofpclass(nan inf zero nsub norm) %rhs) #5 {
-; CHECK-LABEL: define nofpclass(nan pinf psub pnorm) float @fsub__lhs_nzero__rhs_psub__mode_ieee_dapz(
+; CHECK-LABEL: define nofpclass(nan inf psub pnorm) float @fsub__lhs_nzero__rhs_psub__mode_ieee_dapz(
 ; CHECK-SAME: float nofpclass(nan inf pzero sub norm) [[LHS:%.*]], float nofpclass(nan inf zero nsub norm) [[RHS:%.*]]) #[[ATTR7]] {
 ; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[LHS]], [[RHS]]
 ; CHECK-NEXT:    ret float [[SUB]]
@@ -1317,7 +1313,7 @@ define float @fsub__lhs_nzero__rhs_psub__mode_ieee_dapz(float nofpclass(nan inf
 
 ; We shall not rule out negative zero: -0.0 - daz(psub) == -0.0 - +0.0 == -0.0
 define float @fsub__lhs_nzero__rhs_psub__mode_ieee_daz(float nofpclass(nan inf pzero sub norm) %lhs, float nofpclass(nan inf zero nsub norm) %rhs) #2 {
-; CHECK-LABEL: define nofpclass(nan pinf psub pnorm) float @fsub__lhs_nzero__rhs_psub__mode_ieee_daz(
+; CHECK-LABEL: define nofpclass(nan inf psub pnorm) float @fsub__lhs_nzero__rhs_psub__mode_ieee_daz(
 ; CHECK-SAME: float nofpclass(nan inf pzero sub norm) [[LHS:%.*]], float nofpclass(nan inf zero nsub norm) [[RHS:%.*]]) #[[ATTR4]] {
 ; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[LHS]], [[RHS]]
 ; CHECK-NEXT:    ret float [[SUB]]
@@ -1327,7 +1323,7 @@ define float @fsub__lhs_nzero__rhs_psub__mode_ieee_daz(float nofpclass(nan inf p
 }
 
 define float @fsub__lhs_nzero__rhs_psub__mode_ftpz_dapz(float nofpclass(nan inf pzero sub norm) %lhs, float nofpclass(nan inf zero nsub norm) %rhs) #3 {
-; CHECK-LABEL: define nofpclass(nan pinf psub pnorm) float @fsub__lhs_nzero__rhs_psub__mode_ftpz_dapz(
+; CHECK-LABEL: define nofpclass(nan inf psub pnorm) float @fsub__lhs_nzero__rhs_psub__mode_ftpz_dapz(
 ; CHECK-SAME: float nofpclass(nan inf pzero sub norm) [[LHS:%.*]], float nofpclass(nan inf zero nsub norm) [[RHS:%.*]]) #[[ATTR2]] {
 ; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[LHS]], [[RHS]]
 ; CHECK-NEXT:    ret float [[SUB]]
@@ -1337,7 +1333,7 @@ define float @fsub__lhs_nzero__rhs_psub__mode_ftpz_dapz(float nofpclass(nan inf
 }
 
 define float @fsub__lhs_nzero__rhs_psub__mode_dynamic_dapz(float nofpclass(nan inf pzero sub norm) %lhs, float nofpclass(nan inf zero nsub norm) %rhs) #7 {
-; CHECK-LABEL: define nofpclass(nan pinf psub pnorm) float @fsub__lhs_nzero__rhs_psub__mode_dynamic_dapz(
+; CHECK-LABEL: define nofpclass(nan inf psub pnorm) float @fsub__lhs_nzero__rhs_psub__mode_dynamic_dapz(
 ; CHECK-SAME: float nofpclass(nan inf pzero sub norm) [[LHS:%.*]], float nofpclass(nan inf zero nsub norm) [[RHS:%.*]]) #[[ATTR10:[0-9]+]] {
 ; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[LHS]], [[RHS]]
 ; CHECK-NEXT:    ret float [[SUB]]
@@ -1347,7 +1343,7 @@ define float @fsub__lhs_nzero__rhs_psub__mode_dynamic_dapz(float nofpclass(nan i
 }
 
 define float @fsub__lhs_nzero__rhs_psub__mode_dynamic_dynamic(float nofpclass(nan inf pzero sub norm) %lhs, float nofpclass(nan inf zero nsub norm) %rhs) #6 {
-; CHECK-LABEL: define nofpclass(nan pinf psub pnorm) float @fsub__lhs_nzero__rhs_psub__mode_dynamic_dynamic(
+; CHECK-LABEL: define nofpclass(nan inf psub pnorm) float @fsub__lhs_nzero__rhs_psub__mode_dynamic_dynamic(
 ; CHECK-SAME: float nofpclass(nan inf pzero sub norm) [[LHS:%.*]], float nofpclass(nan inf zero nsub norm) [[RHS:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[LHS]], [[RHS]]
 ; CHECK-NEXT:    ret float [[SUB]]
@@ -1356,6 +1352,340 @@ define float @fsub__lhs_nzero__rhs_psub__mode_dynamic_dynamic(float nofpclass(na
   ret float %sub
 }
 
+;-------------------------------------------------------------------------------
+
+; Rule out NaN.
+
+define float @fadd__no_nan_ninf__no_nan_ninf(float nofpclass(nan ninf) %lhs, float nofpclass(nan ninf) %rhs) {
+; CHECK-LABEL: define nofpclass(nan) float @fadd__no_nan_ninf__no_nan_ninf(
+; CHECK-SAME: float nofpclass(nan ninf) [[LHS:%.*]], float nofpclass(nan ninf) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_nan_pinf__no_nan_ninf(float nofpclass(nan pinf) %lhs, float nofpclass(nan ninf) %rhs) {
+; CHECK-LABEL: define nofpclass(snan) float @fadd__no_nan_pinf__no_nan_ninf(
+; CHECK-SAME: float nofpclass(nan pinf) [[LHS:%.*]], float nofpclass(nan ninf) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_nan_ninf__no_nan_pinf(float nofpclass(nan ninf) %lhs, float nofpclass(nan pinf) %rhs) {
+; CHECK-LABEL: define nofpclass(snan) float @fadd__no_nan_ninf__no_nan_pinf(
+; CHECK-SAME: float nofpclass(nan ninf) [[LHS:%.*]], float nofpclass(nan pinf) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_nan_pinf__no_nan_pinf(float nofpclass(nan pinf) %lhs, float nofpclass(nan pinf) %rhs) {
+; CHECK-LABEL: define nofpclass(nan) float @fadd__no_nan_pinf__no_nan_pinf(
+; CHECK-SAME: float nofpclass(nan pinf) [[LHS:%.*]], float nofpclass(nan pinf) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fsub__no_nan_ninf__no_nan_ninf(float nofpclass(nan ninf) %lhs, float nofpclass(nan ninf) %rhs) {
+; CHECK-LABEL: define nofpclass(snan) float @fsub__no_nan_ninf__no_nan_ninf(
+; CHECK-SAME: float nofpclass(nan ninf) [[LHS:%.*]], float nofpclass(nan ninf) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[SUB]]
+;
+  %sub = fsub float %lhs, %rhs
+  ret float %sub
+}
+
+define float @fsub__no_nan_pinf__no_nan_ninf(float nofpclass(nan pinf) %lhs, float nofpclass(nan ninf) %rhs) {
+; CHECK-LABEL: define nofpclass(nan) float @fsub__no_nan_pinf__no_nan_ninf(
+; CHECK-SAME: float nofpclass(nan pinf) [[LHS:%.*]], float nofpclass(nan ninf) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[SUB]]
+;
+  %sub = fsub float %lhs, %rhs
+  ret float %sub
+}
+
+define float @fsub__no_nan_ninf__no_nan_pinf(float nofpclass(nan ninf) %lhs, float nofpclass(nan pinf) %rhs) {
+; CHECK-LABEL: define nofpclass(nan) float @fsub__no_nan_ninf__no_nan_pinf(
+; CHECK-SAME: float nofpclass(nan ninf) [[LHS:%.*]], float nofpclass(nan pinf) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[SUB]]
+;
+  %sub = fsub float %lhs, %rhs
+  ret float %sub
+}
+
+define float @fsub__no_nan_pinf__no_nan_pinf(float nofpclass(nan pinf) %lhs, float nofpclass(nan pinf) %rhs) {
+; CHECK-LABEL: define nofpclass(snan) float @fsub__no_nan_pinf__no_nan_pinf(
+; CHECK-SAME: float nofpclass(nan pinf) [[LHS:%.*]], float nofpclass(nan pinf) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[SUB]]
+;
+  %sub = fsub float %lhs, %rhs
+  ret float %sub
+}
+
+;-------------------------------------------------------------------------------
+
+; Rule out infinity.
+
+define float @fadd__no_pinf_psub_pnorm__no_pinf(float nofpclass(pinf psub pnorm) %lhs, float nofpclass(pinf) %rhs) {
+; CHECK-LABEL: define nofpclass(pinf) float @fadd__no_pinf_psub_pnorm__no_pinf(
+; CHECK-SAME: float nofpclass(pinf psub pnorm) [[LHS:%.*]], float nofpclass(pinf) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_pinf__no_pinf_psub_pnorm(float nofpclass(pinf) %lhs, float nofpclass(pinf psub pnorm) %rhs) {
+; CHECK-LABEL: define nofpclass(pinf) float @fadd__no_pinf__no_pinf_psub_pnorm(
+; CHECK-SAME: float nofpclass(pinf) [[LHS:%.*]], float nofpclass(pinf psub pnorm) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_pinf_pnorm__no_pinf(float nofpclass(pinf pnorm) %lhs, float nofpclass(pinf) %rhs) {
+; CHECK-LABEL: define float @fadd__no_pinf_pnorm__no_pinf(
+; CHECK-SAME: float nofpclass(pinf pnorm) [[LHS:%.*]], float nofpclass(pinf) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_pinf__no_pinf_pnorm(float nofpclass(pinf) %lhs, float nofpclass(pinf pnorm) %rhs) {
+; CHECK-LABEL: define float @fadd__no_pinf__no_pinf_pnorm(
+; CHECK-SAME: float nofpclass(pinf) [[LHS:%.*]], float nofpclass(pinf pnorm) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_pinf_pnorm__no_pinf_pnorm(float nofpclass(pinf pnorm) %lhs, float nofpclass(pinf pnorm) %rhs) {
+; CHECK-LABEL: define float @fadd__no_pinf_pnorm__no_pinf_pnorm(
+; CHECK-SAME: float nofpclass(pinf pnorm) [[LHS:%.*]], float nofpclass(pinf pnorm) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_ninf_nsub_nnorm__no_ninf(float nofpclass(ninf nsub nnorm) %lhs, float nofpclass(ninf) %rhs) {
+; CHECK-LABEL: define nofpclass(ninf) float @fadd__no_ninf_nsub_nnorm__no_ninf(
+; CHECK-SAME: float nofpclass(ninf nsub nnorm) [[LHS:%.*]], float nofpclass(ninf) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_ninf__no_ninf_nsub_nnorm(float nofpclass(ninf) %lhs, float nofpclass(ninf nsub nnorm) %rhs) {
+; CHECK-LABEL: define nofpclass(ninf) float @fadd__no_ninf__no_ninf_nsub_nnorm(
+; CHECK-SAME: float nofpclass(ninf) [[LHS:%.*]], float nofpclass(ninf nsub nnorm) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_ninf_nnorm__no_ninf(float nofpclass(ninf nnorm) %lhs, float nofpclass(ninf) %rhs) {
+; CHECK-LABEL: define float @fadd__no_ninf_nnorm__no_ninf(
+; CHECK-SAME: float nofpclass(ninf nnorm) [[LHS:%.*]], float nofpclass(ninf) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_ninf__no_ninf_nnorm(float nofpclass(ninf) %lhs, float nofpclass(ninf nnorm) %rhs) {
+; CHECK-LABEL: define float @fadd__no_ninf__no_ninf_nnorm(
+; CHECK-SAME: float nofpclass(ninf) [[LHS:%.*]], float nofpclass(ninf nnorm) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_ninf_nnorm__no_ninf_nnorm(float nofpclass(ninf nnorm) %lhs, float nofpclass(ninf nnorm) %rhs) {
+; CHECK-LABEL: define float @fadd__no_ninf_nnorm__no_ninf_nnorm(
+; CHECK-SAME: float nofpclass(ninf nnorm) [[LHS:%.*]], float nofpclass(ninf nnorm) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+;-------------------------------------------------------------------------------
+
+; Rule out normal and subnormal classes.
+
+define float @fadd__no_psub_pnorm__no_psub_pnorm(float nofpclass(psub pnorm) %lhs, float nofpclass(psub pnorm) %rhs) {
+; CHECK-LABEL: define nofpclass(psub pnorm) float @fadd__no_psub_pnorm__no_psub_pnorm(
+; CHECK-SAME: float nofpclass(psub pnorm) [[LHS:%.*]], float nofpclass(psub pnorm) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_zero_sub_pnorm__no_psub_pnorm(float nofpclass(zero sub pnorm) %lhs, float nofpclass(psub pnorm) %rhs) {
+; CHECK-LABEL: define nofpclass(zero sub pnorm) float @fadd__no_zero_sub_pnorm__no_psub_pnorm(
+; CHECK-SAME: float nofpclass(zero sub pnorm) [[LHS:%.*]], float nofpclass(psub pnorm) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_psub_pnorm__no_zero_sub_pnorm(float nofpclass(psub pnorm) %lhs, float nofpclass(zero sub pnorm) %rhs) {
+; CHECK-LABEL: define nofpclass(zero sub pnorm) float @fadd__no_psub_pnorm__no_zero_sub_pnorm(
+; CHECK-SAME: float nofpclass(psub pnorm) [[LHS:%.*]], float nofpclass(zero sub pnorm) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_zero_psub_pnorm__no_psub_pnorm(float nofpclass(zero psub pnorm) %lhs, float nofpclass(psub pnorm) %rhs) {
+; CHECK-LABEL: define nofpclass(nzero psub pnorm) float @fadd__no_zero_psub_pnorm__no_psub_pnorm(
+; CHECK-SAME: float nofpclass(zero psub pnorm) [[LHS:%.*]], float nofpclass(psub pnorm) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_psub_pnorm__no_zero_psub_pnorm(float nofpclass(psub pnorm) %lhs, float nofpclass(zero psub pnorm) %rhs) {
+; CHECK-LABEL: define nofpclass(nzero psub pnorm) float @fadd__no_psub_pnorm__no_zero_psub_pnorm(
+; CHECK-SAME: float nofpclass(psub pnorm) [[LHS:%.*]], float nofpclass(zero psub pnorm) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_psub_pnorm__no_pnorm(float nofpclass(psub pnorm) %lhs, float nofpclass(pnorm) %rhs) {
+; CHECK-LABEL: define float @fadd__no_psub_pnorm__no_pnorm(
+; CHECK-SAME: float nofpclass(psub pnorm) [[LHS:%.*]], float nofpclass(pnorm) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_pnorm__no_psub_pnorm(float nofpclass(pnorm) %lhs, float nofpclass(psub pnorm) %rhs) {
+; CHECK-LABEL: define float @fadd__no_pnorm__no_psub_pnorm(
+; CHECK-SAME: float nofpclass(pnorm) [[LHS:%.*]], float nofpclass(psub pnorm) [[RHS:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %lhs, %rhs
+  ret float %add
+}
+
+define float @fadd__no_nsub_nnorm__no_nsub_nnorm(float nofpclass(nsub nnorm) %lhs, float nofpclass(nsub nnorm) %rhs) {
+; CHECK-LABEL: define nofpclass(nsub nnorm) float @...
[truncated]

Comment on lines +1078 to +1079
define half @ret_fma_square__nan_inf__any(half noundef nofpclass(zero sub norm) %arg0, half %arg1) {
; CHECK-LABEL: define half @ret_fma_square__nan_inf__any(

@ZERICO2005 ZERICO2005 Nov 5, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only other case where we could rule out negative infinity for fma_square, since NaN + -inf and +inf + -inf are both NaN. It is not a very useful deduction to go after however, and I just included it for coverage.

@@ -486,7 +486,7 @@ define <4 x float> @powi_v4f32_i32_constint_odd(<4 x float> %arg) {
}

define <4 x float> @powi_v4f32_i32_regression(<4 x float> %arg) {
; CHECK-LABEL: define nofpclass(nzero) <4 x float> @powi_v4f32_i32_regression
; CHECK-LABEL: define nofpclass(ninf nzero) <4 x float> @powi_v4f32_i32_regression

@ZERICO2005 ZERICO2005 Nov 5, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

powi(x, 4) produces positive | nan, and (positive | nan) - 1.0 is not negative infinity.

if (KnownLHS.cannotBeOrderedLessThanZero() &&
KnownRHS.cannotBeOrderedLessThanZero()) {
Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
// Rule out infinity.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes are also valid for fma, but I will handle them separately after this PR is merged #240081

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

floating-point Floating-point math llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:support llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant