Skip to content

Conversation

@arsenm
Copy link
Contributor

@arsenm arsenm commented Jan 1, 2026

This already recognized that if both inputs are positive, the
result is positive. Extend this to the mirror situation with
negative inputs.

Also special case fadd x, x. Canonically, fmul x, 2 is fadd x, x.
We can tell the sign bit won't change, and 0 will propagate.

Copy link
Contributor Author

arsenm commented Jan 1, 2026

@arsenm arsenm added the floating-point Floating-point math label Jan 1, 2026 — with Graphite App
@arsenm arsenm marked this pull request as ready for review January 1, 2026 09:48
@arsenm arsenm requested a review from nikic as a code owner January 1, 2026 09:48
@llvmbot llvmbot added llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms labels Jan 1, 2026
@llvmbot
Copy link
Member

llvmbot commented Jan 1, 2026

@llvm/pr-subscribers-llvm-analysis

Author: Matt Arsenault (arsenm)

Changes

This already recognized that if both inputs are positive, the
result is positive. Extend this to the mirror situation with
negative inputs.

Also special case fadd x, x. Canonically, fmul x, 2 is fadd x, x.
We can tell the sign bit won't change, and 0 will propagate.


Full diff: https://github.com/llvm/llvm-project/pull/174123.diff

2 Files Affected:

  • (modified) llvm/lib/Analysis/ValueTracking.cpp (+24-4)
  • (modified) llvm/test/Transforms/Attributor/nofpclass.ll (+23-23)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index cf7c6796f76c7..df435df311d0c 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5619,14 +5619,22 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
     computeKnownFPClass(Op->getOperand(1), DemandedElts, InterestedSrcs,
                         KnownRHS, Q, Depth + 1);
 
+    // Special case fadd x, x, which is the canonical form of fmul x, 2.
+    bool SameOperands = Op->getOperand(0) == Op->getOperand(1);
+    if (SameOperands)
+      KnownLHS = KnownRHS;
+
     if ((WantNaN && KnownRHS.isKnownNeverNaN()) ||
         (WantNegative && KnownRHS.cannotBeOrderedLessThanZero()) ||
         WantNegZero || Opc == Instruction::FSub) {
 
-      // RHS is canonically cheaper to compute. Skip inspecting the LHS if
-      // there's no point.
-      computeKnownFPClass(Op->getOperand(0), DemandedElts, InterestedSrcs,
-                          KnownLHS, Q, Depth + 1);
+      if (!SameOperands) {
+        // RHS is canonically cheaper to compute. Skip inspecting the LHS if
+        // there's no point.
+        computeKnownFPClass(Op->getOperand(0), DemandedElts, InterestedSrcs,
+                            KnownLHS, Q, Depth + 1);
+      }
+
       // Adding positive and negative infinity produces NaN.
       // TODO: Check sign of infinities.
       if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
@@ -5640,6 +5648,10 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
         if (KnownLHS.cannotBeOrderedLessThanZero() &&
             KnownRHS.cannotBeOrderedLessThanZero())
           Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
+        if (KnownLHS.cannotBeOrderedGreaterThanZero() &&
+            KnownRHS.cannotBeOrderedGreaterThanZero())
+          Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask);
+
         if (!F)
           break;
 
@@ -5647,6 +5659,14 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
             Op->getType()->getScalarType()->getFltSemantics();
         DenormalMode Mode = F->getDenormalMode(FltSem);
 
+        if (SameOperands) {
+          // Doubling 0 will give the same 0.
+          if (KnownRHS.isKnownNeverLogicalPosZero(Mode))
+            Known.knownNot(fcPosZero);
+          if (KnownRHS.isKnownNeverLogicalNegZero(Mode))
+            Known.knownNot(fcNegZero);
+        }
+
         // (fadd x, 0.0) is guaranteed to return +0.0, not -0.0.
         if ((KnownLHS.isKnownNeverLogicalNegZero(Mode) ||
              KnownRHS.isKnownNeverLogicalNegZero(Mode)) &&
diff --git a/llvm/test/Transforms/Attributor/nofpclass.ll b/llvm/test/Transforms/Attributor/nofpclass.ll
index a0f418a70457b..209eaae1a167e 100644
--- a/llvm/test/Transforms/Attributor/nofpclass.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass.ll
@@ -3043,7 +3043,7 @@ define float @fadd_double_no_inf(float nofpclass(inf) %arg) {
 
 define float @fadd_double_no_zero(float nofpclass(zero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(nzero) float @fadd_double_no_zero
+; CHECK-LABEL: define nofpclass(zero) float @fadd_double_no_zero
 ; CHECK-SAME: (float nofpclass(zero) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3076,7 +3076,7 @@ define float @fadd_double_known_positive(float nofpclass(ninf nnorm nsub nzero)
 
 define float @fadd_double_known_positive_non0(float nofpclass(ninf nnorm nsub zero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @fadd_double_known_positive_non0
+; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @fadd_double_known_positive_non0
 ; CHECK-SAME: (float nofpclass(ninf zero nsub nnorm) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3087,7 +3087,7 @@ define float @fadd_double_known_positive_non0(float nofpclass(ninf nnorm nsub ze
 
 define float @fadd_double_known_negative_or_zero(float nofpclass(pinf pnorm psub) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_known_negative_or_zero
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_double_known_negative_or_zero
 ; CHECK-SAME: (float nofpclass(pinf psub pnorm) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3098,7 +3098,7 @@ define float @fadd_double_known_negative_or_zero(float nofpclass(pinf pnorm psub
 
 define float @fadd_double_known_negative(float nofpclass(pinf pnorm psub pzero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_known_negative
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @fadd_double_known_negative
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3109,7 +3109,7 @@ define float @fadd_double_known_negative(float nofpclass(pinf pnorm psub pzero)
 
 define float @fadd_double_known_negative_non0(float nofpclass(pinf pnorm psub zero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(nzero) float @fadd_double_known_negative_non0
+; CHECK-LABEL: define nofpclass(pinf zero psub pnorm) float @fadd_double_known_negative_non0
 ; CHECK-SAME: (float nofpclass(pinf zero psub pnorm) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3164,7 +3164,7 @@ define float @fadd_double_no_nnorm_nsub(float nofpclass(nnorm nsub) %arg) {
 
 define float @fadd_double_no_nopsub_pzero(float nofpclass(psub pzero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_no_nopsub_pzero
+; CHECK-LABEL: define nofpclass(pzero) float @fadd_double_no_nopsub_pzero
 ; CHECK-SAME: (float nofpclass(pzero psub) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3186,7 +3186,7 @@ define float @fadd_double_no_nonsub_nzero(float nofpclass(nsub nzero) %arg) {
 
 define float @fadd_double_no_nopsub_pzero_daz(float nofpclass(psub pzero) %arg) #0 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_no_nopsub_pzero_daz
+; CHECK-LABEL: define nofpclass(pzero) float @fadd_double_no_nopsub_pzero_daz
 ; CHECK-SAME: (float nofpclass(pzero psub) [[ARG:%.*]]) #[[ATTR10]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3197,7 +3197,7 @@ define float @fadd_double_no_nopsub_pzero_daz(float nofpclass(psub pzero) %arg)
 
 define float @fadd_double_no_nonsub_nzero_daz(float nofpclass(nsub nzero) %arg) #0 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_no_nonsub_nzero_daz
+; CHECK-LABEL: define nofpclass(nzero) float @fadd_double_no_nonsub_nzero_daz
 ; CHECK-SAME: (float nofpclass(nzero nsub) [[ARG:%.*]]) #[[ATTR10]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3219,7 +3219,7 @@ define float @fadd_double_no_nopsub_pzero_dynamic(float nofpclass(psub pzero) %a
 
 define float @fadd_double_no_nonsub_nzero_dynamic(float nofpclass(nsub nzero) %arg) #6 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_no_nonsub_nzero_dynamic
+; CHECK-LABEL: define nofpclass(nzero) float @fadd_double_no_nonsub_nzero_dynamic
 ; CHECK-SAME: (float nofpclass(nzero nsub) [[ARG:%.*]]) #[[ATTR17]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3230,7 +3230,7 @@ define float @fadd_double_no_nonsub_nzero_dynamic(float nofpclass(nsub nzero) %a
 
 define float @fadd_double_known_positive_nonsub_ieee(float nofpclass(ninf nnorm sub zero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @fadd_double_known_positive_nonsub_ieee
+; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @fadd_double_known_positive_nonsub_ieee
 ; CHECK-SAME: (float nofpclass(ninf zero sub nnorm) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3241,7 +3241,7 @@ define float @fadd_double_known_positive_nonsub_ieee(float nofpclass(ninf nnorm
 
 define float @fadd_double_known_positive_nonsub_daz(float nofpclass(ninf nnorm sub zero) %arg) #0 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @fadd_double_known_positive_nonsub_daz
+; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @fadd_double_known_positive_nonsub_daz
 ; CHECK-SAME: (float nofpclass(ninf zero sub nnorm) [[ARG:%.*]]) #[[ATTR10]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3252,7 +3252,7 @@ define float @fadd_double_known_positive_nonsub_daz(float nofpclass(ninf nnorm s
 
 define float @fadd_double_known_positive_nonsub_dynamic(float nofpclass(ninf nnorm sub zero) %arg) #6 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @fadd_double_known_positive_nonsub_dynamic
+; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @fadd_double_known_positive_nonsub_dynamic
 ; CHECK-SAME: (float nofpclass(ninf zero sub nnorm) [[ARG:%.*]]) #[[ATTR17]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3263,7 +3263,7 @@ define float @fadd_double_known_positive_nonsub_dynamic(float nofpclass(ninf nno
 
 define float @fadd_double_known_negative_nonsub_ieee(float nofpclass(pinf pnorm sub zero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(nzero) float @fadd_double_known_negative_nonsub_ieee
+; CHECK-LABEL: define nofpclass(pinf zero psub pnorm) float @fadd_double_known_negative_nonsub_ieee
 ; CHECK-SAME: (float nofpclass(pinf zero sub pnorm) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3274,7 +3274,7 @@ define float @fadd_double_known_negative_nonsub_ieee(float nofpclass(pinf pnorm
 
 define float @fadd_double_known_negative_nonsub_daz(float nofpclass(pinf pnorm sub zero) %arg) #0 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_known_negative_nonsub_daz
+; CHECK-LABEL: define nofpclass(pinf zero psub pnorm) float @fadd_double_known_negative_nonsub_daz
 ; CHECK-SAME: (float nofpclass(pinf zero sub pnorm) [[ARG:%.*]]) #[[ATTR10]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3285,7 +3285,7 @@ define float @fadd_double_known_negative_nonsub_daz(float nofpclass(pinf pnorm s
 
 define float @fadd_double_known_negative_nonsub_dynamic(float nofpclass(pinf pnorm sub zero) %arg) #6 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_known_negative_nonsub_dynamic
+; CHECK-LABEL: define nofpclass(pinf zero psub pnorm) float @fadd_double_known_negative_nonsub_dynamic
 ; CHECK-SAME: (float nofpclass(pinf zero sub pnorm) [[ARG:%.*]]) #[[ATTR17]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3351,7 +3351,7 @@ define float @fadd_known_negative_rhs(float %arg0, float nofpclass(pinf psub pno
 
 define float @fadd_known_negative(float nofpclass(pinf psub pnorm) %arg0, float nofpclass(pinf psub pnorm) %arg1) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative
 ; CHECK-SAME: (float nofpclass(pinf psub pnorm) [[ARG0:%.*]], float nofpclass(pinf psub pnorm) [[ARG1:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3362,7 +3362,7 @@ define float @fadd_known_negative(float nofpclass(pinf psub pnorm) %arg0, float
 
 define float @fadd_known_negative_daz(float nofpclass(pinf psub pnorm) %arg0, float nofpclass(pinf psub pnorm) %arg1) #0 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_daz
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_daz
 ; CHECK-SAME: (float nofpclass(pinf psub pnorm) [[ARG0:%.*]], float nofpclass(pinf psub pnorm) [[ARG1:%.*]]) #[[ATTR10]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3373,7 +3373,7 @@ define float @fadd_known_negative_daz(float nofpclass(pinf psub pnorm) %arg0, fl
 
 define float @fadd_known_negative_pzero_lhs(float nofpclass(pinf psub pnorm pzero) %arg0, float nofpclass(pinf psub pnorm) %arg1) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_pzero_lhs
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_pzero_lhs
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(pinf psub pnorm) [[ARG1:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3384,7 +3384,7 @@ define float @fadd_known_negative_pzero_lhs(float nofpclass(pinf psub pnorm pzer
 
 define float @fadd_known_negative_pzero_rhs(float nofpclass(pinf psub pnorm) %arg0, float nofpclass(pinf psub pnorm pzero) %arg1) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_pzero_rhs
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_pzero_rhs
 ; CHECK-SAME: (float nofpclass(pinf psub pnorm) [[ARG0:%.*]], float nofpclass(pinf pzero psub pnorm) [[ARG1:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3395,7 +3395,7 @@ define float @fadd_known_negative_pzero_rhs(float nofpclass(pinf psub pnorm) %ar
 
 define float @fadd_known_negative_pzero(float nofpclass(pinf psub pnorm pzero) %arg0, float nofpclass(pinf psub pnorm pzero) %arg1) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_pzero
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_pzero
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(pinf pzero psub pnorm) [[ARG1:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3406,7 +3406,7 @@ define float @fadd_known_negative_pzero(float nofpclass(pinf psub pnorm pzero) %
 
 define float @fadd_known_negative_pzero_ftz_daz(float nofpclass(pinf psub pnorm pzero) %arg0, float nofpclass(pinf psub pnorm pzero) %arg1) #0 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_pzero_ftz_daz
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_pzero_ftz_daz
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(pinf pzero psub pnorm) [[ARG1:%.*]]) #[[ATTR10]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3417,7 +3417,7 @@ define float @fadd_known_negative_pzero_ftz_daz(float nofpclass(pinf psub pnorm
 
 define float @fadd_known_negative_pzero_ftz(float nofpclass(pinf psub pnorm pzero) %arg0, float nofpclass(pinf psub pnorm pzero) %arg1) #1 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_pzero_ftz
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_pzero_ftz
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(pinf pzero psub pnorm) [[ARG1:%.*]]) #[[ATTR13]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3428,7 +3428,7 @@ define float @fadd_known_negative_pzero_ftz(float nofpclass(pinf psub pnorm pzer
 
 define float @fadd_known_negative_pzero_daz(float nofpclass(pinf psub pnorm pzero) %arg0, float nofpclass(pinf psub pnorm pzero) %arg1) #2 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_pzero_daz
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_pzero_daz
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(pinf pzero psub pnorm) [[ARG1:%.*]]) #[[ATTR11]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]

@llvmbot
Copy link
Member

llvmbot commented Jan 1, 2026

@llvm/pr-subscribers-llvm-transforms

Author: Matt Arsenault (arsenm)

Changes

This already recognized that if both inputs are positive, the
result is positive. Extend this to the mirror situation with
negative inputs.

Also special case fadd x, x. Canonically, fmul x, 2 is fadd x, x.
We can tell the sign bit won't change, and 0 will propagate.


Full diff: https://github.com/llvm/llvm-project/pull/174123.diff

2 Files Affected:

  • (modified) llvm/lib/Analysis/ValueTracking.cpp (+24-4)
  • (modified) llvm/test/Transforms/Attributor/nofpclass.ll (+23-23)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index cf7c6796f76c7..df435df311d0c 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5619,14 +5619,22 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
     computeKnownFPClass(Op->getOperand(1), DemandedElts, InterestedSrcs,
                         KnownRHS, Q, Depth + 1);
 
+    // Special case fadd x, x, which is the canonical form of fmul x, 2.
+    bool SameOperands = Op->getOperand(0) == Op->getOperand(1);
+    if (SameOperands)
+      KnownLHS = KnownRHS;
+
     if ((WantNaN && KnownRHS.isKnownNeverNaN()) ||
         (WantNegative && KnownRHS.cannotBeOrderedLessThanZero()) ||
         WantNegZero || Opc == Instruction::FSub) {
 
-      // RHS is canonically cheaper to compute. Skip inspecting the LHS if
-      // there's no point.
-      computeKnownFPClass(Op->getOperand(0), DemandedElts, InterestedSrcs,
-                          KnownLHS, Q, Depth + 1);
+      if (!SameOperands) {
+        // RHS is canonically cheaper to compute. Skip inspecting the LHS if
+        // there's no point.
+        computeKnownFPClass(Op->getOperand(0), DemandedElts, InterestedSrcs,
+                            KnownLHS, Q, Depth + 1);
+      }
+
       // Adding positive and negative infinity produces NaN.
       // TODO: Check sign of infinities.
       if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
@@ -5640,6 +5648,10 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
         if (KnownLHS.cannotBeOrderedLessThanZero() &&
             KnownRHS.cannotBeOrderedLessThanZero())
           Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
+        if (KnownLHS.cannotBeOrderedGreaterThanZero() &&
+            KnownRHS.cannotBeOrderedGreaterThanZero())
+          Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask);
+
         if (!F)
           break;
 
@@ -5647,6 +5659,14 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
             Op->getType()->getScalarType()->getFltSemantics();
         DenormalMode Mode = F->getDenormalMode(FltSem);
 
+        if (SameOperands) {
+          // Doubling 0 will give the same 0.
+          if (KnownRHS.isKnownNeverLogicalPosZero(Mode))
+            Known.knownNot(fcPosZero);
+          if (KnownRHS.isKnownNeverLogicalNegZero(Mode))
+            Known.knownNot(fcNegZero);
+        }
+
         // (fadd x, 0.0) is guaranteed to return +0.0, not -0.0.
         if ((KnownLHS.isKnownNeverLogicalNegZero(Mode) ||
              KnownRHS.isKnownNeverLogicalNegZero(Mode)) &&
diff --git a/llvm/test/Transforms/Attributor/nofpclass.ll b/llvm/test/Transforms/Attributor/nofpclass.ll
index a0f418a70457b..209eaae1a167e 100644
--- a/llvm/test/Transforms/Attributor/nofpclass.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass.ll
@@ -3043,7 +3043,7 @@ define float @fadd_double_no_inf(float nofpclass(inf) %arg) {
 
 define float @fadd_double_no_zero(float nofpclass(zero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(nzero) float @fadd_double_no_zero
+; CHECK-LABEL: define nofpclass(zero) float @fadd_double_no_zero
 ; CHECK-SAME: (float nofpclass(zero) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3076,7 +3076,7 @@ define float @fadd_double_known_positive(float nofpclass(ninf nnorm nsub nzero)
 
 define float @fadd_double_known_positive_non0(float nofpclass(ninf nnorm nsub zero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @fadd_double_known_positive_non0
+; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @fadd_double_known_positive_non0
 ; CHECK-SAME: (float nofpclass(ninf zero nsub nnorm) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3087,7 +3087,7 @@ define float @fadd_double_known_positive_non0(float nofpclass(ninf nnorm nsub ze
 
 define float @fadd_double_known_negative_or_zero(float nofpclass(pinf pnorm psub) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_known_negative_or_zero
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_double_known_negative_or_zero
 ; CHECK-SAME: (float nofpclass(pinf psub pnorm) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3098,7 +3098,7 @@ define float @fadd_double_known_negative_or_zero(float nofpclass(pinf pnorm psub
 
 define float @fadd_double_known_negative(float nofpclass(pinf pnorm psub pzero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_known_negative
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @fadd_double_known_negative
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3109,7 +3109,7 @@ define float @fadd_double_known_negative(float nofpclass(pinf pnorm psub pzero)
 
 define float @fadd_double_known_negative_non0(float nofpclass(pinf pnorm psub zero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(nzero) float @fadd_double_known_negative_non0
+; CHECK-LABEL: define nofpclass(pinf zero psub pnorm) float @fadd_double_known_negative_non0
 ; CHECK-SAME: (float nofpclass(pinf zero psub pnorm) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3164,7 +3164,7 @@ define float @fadd_double_no_nnorm_nsub(float nofpclass(nnorm nsub) %arg) {
 
 define float @fadd_double_no_nopsub_pzero(float nofpclass(psub pzero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_no_nopsub_pzero
+; CHECK-LABEL: define nofpclass(pzero) float @fadd_double_no_nopsub_pzero
 ; CHECK-SAME: (float nofpclass(pzero psub) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3186,7 +3186,7 @@ define float @fadd_double_no_nonsub_nzero(float nofpclass(nsub nzero) %arg) {
 
 define float @fadd_double_no_nopsub_pzero_daz(float nofpclass(psub pzero) %arg) #0 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_no_nopsub_pzero_daz
+; CHECK-LABEL: define nofpclass(pzero) float @fadd_double_no_nopsub_pzero_daz
 ; CHECK-SAME: (float nofpclass(pzero psub) [[ARG:%.*]]) #[[ATTR10]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3197,7 +3197,7 @@ define float @fadd_double_no_nopsub_pzero_daz(float nofpclass(psub pzero) %arg)
 
 define float @fadd_double_no_nonsub_nzero_daz(float nofpclass(nsub nzero) %arg) #0 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_no_nonsub_nzero_daz
+; CHECK-LABEL: define nofpclass(nzero) float @fadd_double_no_nonsub_nzero_daz
 ; CHECK-SAME: (float nofpclass(nzero nsub) [[ARG:%.*]]) #[[ATTR10]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3219,7 +3219,7 @@ define float @fadd_double_no_nopsub_pzero_dynamic(float nofpclass(psub pzero) %a
 
 define float @fadd_double_no_nonsub_nzero_dynamic(float nofpclass(nsub nzero) %arg) #6 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_no_nonsub_nzero_dynamic
+; CHECK-LABEL: define nofpclass(nzero) float @fadd_double_no_nonsub_nzero_dynamic
 ; CHECK-SAME: (float nofpclass(nzero nsub) [[ARG:%.*]]) #[[ATTR17]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3230,7 +3230,7 @@ define float @fadd_double_no_nonsub_nzero_dynamic(float nofpclass(nsub nzero) %a
 
 define float @fadd_double_known_positive_nonsub_ieee(float nofpclass(ninf nnorm sub zero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @fadd_double_known_positive_nonsub_ieee
+; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @fadd_double_known_positive_nonsub_ieee
 ; CHECK-SAME: (float nofpclass(ninf zero sub nnorm) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3241,7 +3241,7 @@ define float @fadd_double_known_positive_nonsub_ieee(float nofpclass(ninf nnorm
 
 define float @fadd_double_known_positive_nonsub_daz(float nofpclass(ninf nnorm sub zero) %arg) #0 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @fadd_double_known_positive_nonsub_daz
+; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @fadd_double_known_positive_nonsub_daz
 ; CHECK-SAME: (float nofpclass(ninf zero sub nnorm) [[ARG:%.*]]) #[[ATTR10]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3252,7 +3252,7 @@ define float @fadd_double_known_positive_nonsub_daz(float nofpclass(ninf nnorm s
 
 define float @fadd_double_known_positive_nonsub_dynamic(float nofpclass(ninf nnorm sub zero) %arg) #6 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @fadd_double_known_positive_nonsub_dynamic
+; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @fadd_double_known_positive_nonsub_dynamic
 ; CHECK-SAME: (float nofpclass(ninf zero sub nnorm) [[ARG:%.*]]) #[[ATTR17]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3263,7 +3263,7 @@ define float @fadd_double_known_positive_nonsub_dynamic(float nofpclass(ninf nno
 
 define float @fadd_double_known_negative_nonsub_ieee(float nofpclass(pinf pnorm sub zero) %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define nofpclass(nzero) float @fadd_double_known_negative_nonsub_ieee
+; CHECK-LABEL: define nofpclass(pinf zero psub pnorm) float @fadd_double_known_negative_nonsub_ieee
 ; CHECK-SAME: (float nofpclass(pinf zero sub pnorm) [[ARG:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3274,7 +3274,7 @@ define float @fadd_double_known_negative_nonsub_ieee(float nofpclass(pinf pnorm
 
 define float @fadd_double_known_negative_nonsub_daz(float nofpclass(pinf pnorm sub zero) %arg) #0 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_known_negative_nonsub_daz
+; CHECK-LABEL: define nofpclass(pinf zero psub pnorm) float @fadd_double_known_negative_nonsub_daz
 ; CHECK-SAME: (float nofpclass(pinf zero sub pnorm) [[ARG:%.*]]) #[[ATTR10]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3285,7 +3285,7 @@ define float @fadd_double_known_negative_nonsub_daz(float nofpclass(pinf pnorm s
 
 define float @fadd_double_known_negative_nonsub_dynamic(float nofpclass(pinf pnorm sub zero) %arg) #6 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_double_known_negative_nonsub_dynamic
+; CHECK-LABEL: define nofpclass(pinf zero psub pnorm) float @fadd_double_known_negative_nonsub_dynamic
 ; CHECK-SAME: (float nofpclass(pinf zero sub pnorm) [[ARG:%.*]]) #[[ATTR17]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3351,7 +3351,7 @@ define float @fadd_known_negative_rhs(float %arg0, float nofpclass(pinf psub pno
 
 define float @fadd_known_negative(float nofpclass(pinf psub pnorm) %arg0, float nofpclass(pinf psub pnorm) %arg1) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative
 ; CHECK-SAME: (float nofpclass(pinf psub pnorm) [[ARG0:%.*]], float nofpclass(pinf psub pnorm) [[ARG1:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3362,7 +3362,7 @@ define float @fadd_known_negative(float nofpclass(pinf psub pnorm) %arg0, float
 
 define float @fadd_known_negative_daz(float nofpclass(pinf psub pnorm) %arg0, float nofpclass(pinf psub pnorm) %arg1) #0 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_daz
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_daz
 ; CHECK-SAME: (float nofpclass(pinf psub pnorm) [[ARG0:%.*]], float nofpclass(pinf psub pnorm) [[ARG1:%.*]]) #[[ATTR10]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3373,7 +3373,7 @@ define float @fadd_known_negative_daz(float nofpclass(pinf psub pnorm) %arg0, fl
 
 define float @fadd_known_negative_pzero_lhs(float nofpclass(pinf psub pnorm pzero) %arg0, float nofpclass(pinf psub pnorm) %arg1) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_pzero_lhs
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_pzero_lhs
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(pinf psub pnorm) [[ARG1:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3384,7 +3384,7 @@ define float @fadd_known_negative_pzero_lhs(float nofpclass(pinf psub pnorm pzer
 
 define float @fadd_known_negative_pzero_rhs(float nofpclass(pinf psub pnorm) %arg0, float nofpclass(pinf psub pnorm pzero) %arg1) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_pzero_rhs
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_pzero_rhs
 ; CHECK-SAME: (float nofpclass(pinf psub pnorm) [[ARG0:%.*]], float nofpclass(pinf pzero psub pnorm) [[ARG1:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3395,7 +3395,7 @@ define float @fadd_known_negative_pzero_rhs(float nofpclass(pinf psub pnorm) %ar
 
 define float @fadd_known_negative_pzero(float nofpclass(pinf psub pnorm pzero) %arg0, float nofpclass(pinf psub pnorm pzero) %arg1) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_pzero
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_pzero
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(pinf pzero psub pnorm) [[ARG1:%.*]]) #[[ATTR3]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3406,7 +3406,7 @@ define float @fadd_known_negative_pzero(float nofpclass(pinf psub pnorm pzero) %
 
 define float @fadd_known_negative_pzero_ftz_daz(float nofpclass(pinf psub pnorm pzero) %arg0, float nofpclass(pinf psub pnorm pzero) %arg1) #0 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_pzero_ftz_daz
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_pzero_ftz_daz
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(pinf pzero psub pnorm) [[ARG1:%.*]]) #[[ATTR10]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3417,7 +3417,7 @@ define float @fadd_known_negative_pzero_ftz_daz(float nofpclass(pinf psub pnorm
 
 define float @fadd_known_negative_pzero_ftz(float nofpclass(pinf psub pnorm pzero) %arg0, float nofpclass(pinf psub pnorm pzero) %arg1) #1 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_pzero_ftz
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_pzero_ftz
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(pinf pzero psub pnorm) [[ARG1:%.*]]) #[[ATTR13]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]
@@ -3428,7 +3428,7 @@ define float @fadd_known_negative_pzero_ftz(float nofpclass(pinf psub pnorm pzer
 
 define float @fadd_known_negative_pzero_daz(float nofpclass(pinf psub pnorm pzero) %arg0, float nofpclass(pinf psub pnorm pzero) %arg1) #2 {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @fadd_known_negative_pzero_daz
+; CHECK-LABEL: define nofpclass(pinf psub pnorm) float @fadd_known_negative_pzero_daz
 ; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[ARG0:%.*]], float nofpclass(pinf pzero psub pnorm) [[ARG1:%.*]]) #[[ATTR11]] {
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[ADD]]

@arsenm arsenm force-pushed the users/arsenm/valuetracking/special-case-computeknownfpclass-double branch from ee0ed27 to e63cc4a Compare January 2, 2026 10:50
@arsenm arsenm force-pushed the users/arsenm/valuetracking/special-case-computeknownfpclass-double-baseline-tests branch 2 times, most recently from 49f636b to c742955 Compare January 2, 2026 13:26
@arsenm arsenm force-pushed the users/arsenm/valuetracking/special-case-computeknownfpclass-double branch from e63cc4a to 0f22814 Compare January 2, 2026 13:26
Copy link
Member

@dtcxzyw dtcxzyw left a comment

Choose a reason for hiding this comment

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

LGTM

KnownRHS.isKnownNeverLogicalNegZero(Mode)) &&
// Make sure output negative denormal can't flush to -0
outputDenormalIsIEEEOrPosZero(*F, Op->getType()))
(Mode.Output == DenormalMode::IEEE ||
Copy link
Member

Choose a reason for hiding this comment

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

It also holds for DenormalMode::PreserveSign.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No? If the sign is preserved this will flush to -0

Copy link
Member

Choose a reason for hiding this comment

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

But KnownLHS.isKnownNeverLogicalNegZero(Mode) && KnownRHS.isKnownNeverLogicalNegZero(Mode) guarantees that the result is never -0 before flushing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is handling the split mode case. The input denormal wasn't flushed to 0, but the output denormal will be

Base automatically changed from users/arsenm/valuetracking/special-case-computeknownfpclass-double-baseline-tests to main January 3, 2026 10:14
arsenm added 5 commits January 3, 2026 11:15
This already recognized that if both inputs are positive, the
result is positive. Extend this to the mirror situation with
negative inputs.

Also special case fadd x, x. Canonically, fmul x, 2 is fadd x, x.
We can tell the sign bit won't change, and 0 will propagate.
@arsenm arsenm force-pushed the users/arsenm/valuetracking/special-case-computeknownfpclass-double branch from 06e76fd to 107b4d4 Compare January 3, 2026 10:27
@arsenm arsenm enabled auto-merge (squash) January 3, 2026 10:55
@arsenm arsenm merged commit 5cbc6a6 into main Jan 3, 2026
9 of 10 checks passed
@arsenm arsenm deleted the users/arsenm/valuetracking/special-case-computeknownfpclass-double branch January 3, 2026 10:57
boomanaiden154 added a commit that referenced this pull request Jan 3, 2026
…s." (#174290)

Reverts #174123

This caused test failures within LLVM libc. They can be reproduced by
doing a libc build against a clang with this commit included and running
`ninja -k 0 libc.test.src.math.smoke.log1p_test.__unit__
libc.test.src.math.smoke.log1p_test.__unit__.__NO_FMA_OPT`.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Jan 3, 2026
…KnownFPClass." (#174290)

Reverts llvm/llvm-project#174123

This caused test failures within LLVM libc. They can be reproduced by
doing a libc build against a clang with this commit included and running
`ninja -k 0 libc.test.src.math.smoke.log1p_test.__unit__
libc.test.src.math.smoke.log1p_test.__unit__.__NO_FMA_OPT`.
lntue added a commit that referenced this pull request Jan 5, 2026
The previous checks will fail with
#174123.
See
#174290 (comment)
for the discussion.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Jan 5, 2026
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Jan 6, 2026
…#174123)

This already recognized that if both inputs are positive, the
result is positive. Extend this to the mirror situation with
negative inputs.

Also special case fadd x, x. Canonically, fmul x, 2 is fadd x, x.
We can tell the sign bit won't change, and 0 will propagate.
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Jan 6, 2026
…s." (llvm#174290)

Reverts llvm#174123

This caused test failures within LLVM libc. They can be reproduced by
doing a libc build against a clang with this commit included and running
`ninja -k 0 libc.test.src.math.smoke.log1p_test.__unit__
libc.test.src.math.smoke.log1p_test.__unit__.__NO_FMA_OPT`.
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Jan 6, 2026
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:analysis Includes value tracking, cost tables and constant folding llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants