Skip to content

[ValueTracking] Fix computeKnownFPClass handling of nsz#186315

Open
cardigan1008 wants to merge 15 commits intollvm:mainfrom
cardigan1008:fix-185920
Open

[ValueTracking] Fix computeKnownFPClass handling of nsz#186315
cardigan1008 wants to merge 15 commits intollvm:mainfrom
cardigan1008:fix-185920

Conversation

@cardigan1008
Copy link
Copy Markdown
Member

@cardigan1008 cardigan1008 commented Mar 13, 2026

Fixes #151303
Fixes #185920

This patch fixes incorrect nofpclass inference in ValueTracking for floating-point operations with nsz.

With nsz, +0.0 and -0.0 are interchangeable for the current operation. Update computeKnownFPClass to expand a known single zero sign to include both pzero and nzero under nsz, so later nofpclass inference does not preserve signed-zero-specific facts.

@cardigan1008 cardigan1008 requested a review from nikic as a code owner March 13, 2026 05:00
@llvmbot llvmbot added llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms labels Mar 13, 2026
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Mar 13, 2026

@llvm/pr-subscribers-llvm-transforms

Author: Yunbo Ni (cardigan1008)

Changes

Fixes #185920

This patch improves nofpclass inference in ValueTracking for floating-point arithmetic with nsz.

When nsz is present, distinctions between +0.0 and -0.0 are not semantically observable, so nofpclass reasoning should avoid deriving sign-sensitive zero properties from such operations.


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

2 Files Affected:

  • (modified) llvm/lib/Analysis/ValueTracking.cpp (+4-1)
  • (modified) llvm/test/Transforms/Attributor/nofpclass.ll (+11)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 0672dc889b640..25a8a8166d3af 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5588,7 +5588,10 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
       DenormalMode Mode =
           F ? F->getDenormalMode(FltSem) : DenormalMode::getDynamic();
 
-      if (Self && Opc == Instruction::FAdd) {
+      const FPMathOperator *FPop = cast<FPMathOperator>(Op);
+      bool HasNSZ = FPop->hasNoSignedZeros();
+
+      if (!HasNSZ && Self && Opc == Instruction::FAdd) {
         Known = KnownFPClass::fadd_self(KnownLHS, Mode);
       } else {
         // RHS is canonically cheaper to compute. Skip inspecting the LHS if
diff --git a/llvm/test/Transforms/Attributor/nofpclass.ll b/llvm/test/Transforms/Attributor/nofpclass.ll
index 507d0f3ff98f3..3946c9f88e41d 100644
--- a/llvm/test/Transforms/Attributor/nofpclass.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass.ll
@@ -3326,6 +3326,17 @@ define float @fadd_double_known_negative_nonsub_dynamic(float noundef nofpclass(
   ret float %add
 }
 
+define float @fadd_double_known_negative_zero_nsz(float noundef nofpclass(ninf pzero sub nnorm) %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define noundef nofpclass(ninf nsub nnorm) float @fadd_double_known_negative_zero_nsz
+; CHECK-SAME: (float noundef nofpclass(ninf pzero sub nnorm) [[ARG:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd nsz float [[ARG]], [[ARG]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd nsz float %arg, %arg
+  ret float %add
+}
+
 define float @fsub_self(float noundef %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
 ; CHECK-LABEL: define noundef float @fsub_self

@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Mar 13, 2026

@llvm/pr-subscribers-llvm-analysis

Author: Yunbo Ni (cardigan1008)

Changes

Fixes #185920

This patch improves nofpclass inference in ValueTracking for floating-point arithmetic with nsz.

When nsz is present, distinctions between +0.0 and -0.0 are not semantically observable, so nofpclass reasoning should avoid deriving sign-sensitive zero properties from such operations.


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

2 Files Affected:

  • (modified) llvm/lib/Analysis/ValueTracking.cpp (+4-1)
  • (modified) llvm/test/Transforms/Attributor/nofpclass.ll (+11)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 0672dc889b640..25a8a8166d3af 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5588,7 +5588,10 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
       DenormalMode Mode =
           F ? F->getDenormalMode(FltSem) : DenormalMode::getDynamic();
 
-      if (Self && Opc == Instruction::FAdd) {
+      const FPMathOperator *FPop = cast<FPMathOperator>(Op);
+      bool HasNSZ = FPop->hasNoSignedZeros();
+
+      if (!HasNSZ && Self && Opc == Instruction::FAdd) {
         Known = KnownFPClass::fadd_self(KnownLHS, Mode);
       } else {
         // RHS is canonically cheaper to compute. Skip inspecting the LHS if
diff --git a/llvm/test/Transforms/Attributor/nofpclass.ll b/llvm/test/Transforms/Attributor/nofpclass.ll
index 507d0f3ff98f3..3946c9f88e41d 100644
--- a/llvm/test/Transforms/Attributor/nofpclass.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass.ll
@@ -3326,6 +3326,17 @@ define float @fadd_double_known_negative_nonsub_dynamic(float noundef nofpclass(
   ret float %add
 }
 
+define float @fadd_double_known_negative_zero_nsz(float noundef nofpclass(ninf pzero sub nnorm) %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define noundef nofpclass(ninf nsub nnorm) float @fadd_double_known_negative_zero_nsz
+; CHECK-SAME: (float noundef nofpclass(ninf pzero sub nnorm) [[ARG:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd nsz float [[ARG]], [[ARG]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd nsz float %arg, %arg
+  ret float %add
+}
+
 define float @fsub_self(float noundef %arg) {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
 ; CHECK-LABEL: define noundef float @fsub_self

@nikic nikic requested review from arsenm and dtcxzyw March 16, 2026 12:00
@nikic nikic added the floating-point Floating-point math label Mar 16, 2026
Copy link
Copy Markdown
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.

It is a fragile way to fix the issue. nsz is always droppable.

I don't object to the fix. IIRC we have used similar workarounds for nsz in the tree.

Copy link
Copy Markdown
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

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

Hm... shouldn't we handle nsz generically somehow? If nsz is set, then for all inputs we need to treat treat a pzero known FP class as also including nzero and vice versa.

@arsenm
Copy link
Copy Markdown
Contributor

arsenm commented Mar 20, 2026

Title is misleading? This is fixing a correctness problem, not making the analysis result better?

Comment thread llvm/lib/Analysis/ValueTracking.cpp Outdated
Comment thread llvm/lib/Analysis/ValueTracking.cpp Outdated
@cardigan1008 cardigan1008 changed the title [ValueTracking] Improve nofpclass inference for nsz fadd [ValueTracking] Fix computeKnownFPClass handling of nsz Apr 10, 2026
@cardigan1008
Copy link
Copy Markdown
Member Author

Title is misleading? This is fixing a correctness problem, not making the analysis result better?

Updated the title and description.

@cardigan1008
Copy link
Copy Markdown
Member Author

Hm... shouldn't we handle nsz generically somehow? If nsz is set, then for all inputs we need to treat treat a pzero known FP class as also including nzero and vice versa.

Thanks for the suggestion. I've updated the fix to widen the zero with nsz set.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 10, 2026

🐧 Linux x64 Test Results

  • 194068 tests passed
  • 5111 tests skipped

✅ The build succeeded and all tests passed.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 10, 2026

🪟 Windows x64 Test Results

  • 133771 tests passed
  • 3128 tests skipped

✅ The build succeeded and all tests passed.

// With no-signed-zeros semantics, +0 and -0 are interchangeable.
// If the operation has nsz and only one sign of zero is possible in the
// result, the other must also be considered possible.
if (const auto *FPOp = dyn_cast_or_null<FPMathOperator>(Op)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This check was already performed above, can you do the flag check in the same place?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It will be late as the existing flag check is before fadd_self inference.

Comment thread llvm/lib/Analysis/ValueTracking.cpp Outdated
Comment thread llvm/lib/Analysis/ValueTracking.cpp
Comment thread llvm/test/Transforms/Attributor/nofpclass.ll
@cardigan1008 cardigan1008 requested a review from arsenm April 20, 2026 05:38
Comment thread llvm/lib/Analysis/ValueTracking.cpp Outdated
switch (II->getIntrinsicID()) {
case Intrinsic::fabs:
case Intrinsic::copysign:
return false;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The safer direction would be to list the cases where it is OK. You also already have the switch over all the opcodes directly in computeKnownFPClass. Can you keep this contained in computeKnownFPClass without a second set of opcode switch logic

@cardigan1008 cardigan1008 requested a review from arsenm April 22, 2026 07:15
@cardigan1008
Copy link
Copy Markdown
Member Author

Ping.

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.

[ValueTracking] computeKnownFPClass incorrectly infers !+0.0 for fadd nsz x, x [InstCombine] Incorrect fabs + nsz fold

5 participants