[llvm] [InstSimplify] Enable FAdd simplifications when user can ignore sign bit (PR #157757)

Vedant Paranjape via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 10 09:24:09 PDT 2025


https://github.com/VedantParanjape updated https://github.com/llvm/llvm-project/pull/157757

>From b230ed786191424bde3eb6411d193e2adf9fe086 Mon Sep 17 00:00:00 2001
From: Vedant Paranjape <vedantparanjape160201 at gmail.com>
Date: Tue, 9 Sep 2025 17:24:52 -0400
Subject: [PATCH 1/2] [InstSimplify] Enable FAdd simplifications when user can
 ignore sign bit

When FAdd result is used by fabs, we can safely ignore the sign bit of
fp zero. This patch enables an instruction simplification optimization
that folds fadd x, 0 ==> x, which would otherwise not work as the
compiler cannot prove that the zero isn't -0. But if the result of the
fadd is used by fabs we can simply ignore this and still do the
optimization.

Fixes #154238
---
 llvm/lib/Analysis/InstructionSimplify.cpp            |  4 +++-
 .../test/CodeGen/AMDGPU/fcanonicalize-elimination.ll |  5 ++---
 .../InstSimplify/fold-fadd-with-zero-gh154238.ll     | 12 ++++++++++++
 3 files changed, 17 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/Transforms/InstSimplify/fold-fadd-with-zero-gh154238.ll

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 5907e21065331..c49265d77dd4d 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -5710,7 +5710,9 @@ simplifyFAddInst(Value *Op0, Value *Op1, FastMathFlags FMF,
   // fadd X, 0 ==> X, when we know X is not -0
   if (canIgnoreSNaN(ExBehavior, FMF))
     if (match(Op1, m_PosZeroFP()) &&
-        (FMF.noSignedZeros() || cannotBeNegativeZero(Op0, Q)))
+        (FMF.noSignedZeros() || cannotBeNegativeZero(Op0, Q) ||
+         (Q.CxtI && !Q.CxtI->use_empty() &&
+          canIgnoreSignBitOfZero(*(Q.CxtI->use_begin())))))
       return Op0;
 
   if (!isDefaultFPEnvironment(ExBehavior, Rounding))
diff --git a/llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll b/llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll
index ab51693198a30..1973ede5a62a8 100644
--- a/llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll
+++ b/llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll
@@ -363,9 +363,8 @@ define amdgpu_kernel void @test_no_fold_canonicalize_fcopysign_value_f32(ptr add
 }
 
 ; GCN-LABEL: test_fold_canonicalize_fabs_value_f32:
-; GCN: v_and_b32_e32 [[V:v[0-9]+]], 0x7fffffff, v{{[0-9]+}}
-; GCN-NOT: v_mul
-; GCN-NOT: v_max
+; VI: v_mul_f32_e64 [[V:v[0-9]+]], 1.0, |[[V]]|
+; GFX9: v_max_f32_e64 [[V:v[0-9]+]], |[[V]]|, |[[V]]|
 ; GCN: {{flat|global}}_store_dword v{{.+}}, [[V]]
 define amdgpu_kernel void @test_fold_canonicalize_fabs_value_f32(ptr addrspace(1) %arg) {
   %id = tail call i32 @llvm.amdgcn.workitem.id.x()
diff --git a/llvm/test/Transforms/InstSimplify/fold-fadd-with-zero-gh154238.ll b/llvm/test/Transforms/InstSimplify/fold-fadd-with-zero-gh154238.ll
new file mode 100644
index 0000000000000..bb12328574dda
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/fold-fadd-with-zero-gh154238.ll
@@ -0,0 +1,12 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+define float @src(float %arg1) {
+; CHECK-LABEL: define float @src(
+; CHECK-SAME: float [[ARG1:%.*]]) {
+; CHECK-NEXT:    [[V3:%.*]] = call float @llvm.fabs.f32(float [[ARG1]])
+; CHECK-NEXT:    ret float [[V3]]
+;
+  %v2 = fadd float %arg1, 0.000000e+00
+  %v3 = call float @llvm.fabs.f32(float %v2)
+  ret float %v3
+}

>From f6e3f21c392eea63f53814efdf101efb51332140 Mon Sep 17 00:00:00 2001
From: Vedant Paranjape <vedantparanjape160201 at gmail.com>
Date: Wed, 10 Sep 2025 12:23:34 -0400
Subject: [PATCH 2/2] change canIgnoreSignBitOfZero/canIgnoreSignBitOfNaN to
 take an instruction instead of Use

---
 llvm/include/llvm/Analysis/ValueTracking.h           |  4 ++--
 llvm/lib/Analysis/InstructionSimplify.cpp            |  3 +--
 llvm/lib/Analysis/ValueTracking.cpp                  | 12 ++++++++++--
 .../lib/Transforms/InstCombine/InstCombineSelect.cpp | 10 ++++------
 4 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 15ff129deda13..9c5d6d6140488 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -312,11 +312,11 @@ LLVM_ABI std::optional<bool> computeKnownFPSignBit(const Value *V,
 
 /// Return true if the sign bit of the FP value can be ignored by the user when
 /// the value is zero.
-LLVM_ABI bool canIgnoreSignBitOfZero(const Use &U);
+LLVM_ABI bool canIgnoreSignBitOfZero(const Instruction &I);
 
 /// Return true if the sign bit of the FP value can be ignored by the user when
 /// the value is NaN.
-LLVM_ABI bool canIgnoreSignBitOfNaN(const Use &U);
+LLVM_ABI bool canIgnoreSignBitOfNaN(const Instruction &I);
 
 /// If the specified value can be set by repeating the same byte in memory,
 /// return the i8 value that it is represented with. This is true for all i8
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index c49265d77dd4d..195cd4c573b27 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -5711,8 +5711,7 @@ simplifyFAddInst(Value *Op0, Value *Op1, FastMathFlags FMF,
   if (canIgnoreSNaN(ExBehavior, FMF))
     if (match(Op1, m_PosZeroFP()) &&
         (FMF.noSignedZeros() || cannotBeNegativeZero(Op0, Q) ||
-         (Q.CxtI && !Q.CxtI->use_empty() &&
-          canIgnoreSignBitOfZero(*(Q.CxtI->use_begin())))))
+         (Q.CxtI && canIgnoreSignBitOfZero(*Q.CxtI))))
       return Op0;
 
   if (!isDefaultFPEnvironment(ExBehavior, Rounding))
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 07950f5341d6c..6d04d3e834cc5 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5977,7 +5977,11 @@ std::optional<bool> llvm::computeKnownFPSignBit(const Value *V,
   return Known.SignBit;
 }
 
-bool llvm::canIgnoreSignBitOfZero(const Use &U) {
+bool llvm::canIgnoreSignBitOfZero(const Instruction &I) {
+  if (I.use_empty())
+    return false;
+
+  auto &U = *I.use_begin();
   auto *User = cast<Instruction>(U.getUser());
   if (auto *FPOp = dyn_cast<FPMathOperator>(User)) {
     if (FPOp->hasNoSignedZeros())
@@ -6016,7 +6020,11 @@ bool llvm::canIgnoreSignBitOfZero(const Use &U) {
   }
 }
 
-bool llvm::canIgnoreSignBitOfNaN(const Use &U) {
+bool llvm::canIgnoreSignBitOfNaN(const Instruction &I) {
+  if (I.use_empty())
+    return false;
+
+  auto &U = *I.use_begin();
   auto *User = cast<Instruction>(U.getUser());
   if (auto *FPOp = dyn_cast<FPMathOperator>(User)) {
     if (FPOp->hasNoNaNs())
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index ba8b4c47e8f88..9fc4327fd1719 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -2982,7 +2982,7 @@ static Instruction *foldSelectWithFCmpToFabs(SelectInst &SI,
     //       fneg/fabs operations.
     if (match(TrueVal, m_FSub(m_PosZeroFP(), m_Specific(X))) &&
         (cast<FPMathOperator>(CondVal)->hasNoNaNs() || SI.hasNoNaNs() ||
-         (SI.hasOneUse() && canIgnoreSignBitOfNaN(*SI.use_begin())) ||
+         (SI.hasOneUse() && canIgnoreSignBitOfNaN(SI)) ||
          isKnownNeverNaN(X, IC.getSimplifyQuery().getWithInstruction(
                                 cast<Instruction>(CondVal))))) {
       if (!Swap && (Pred == FCmpInst::FCMP_OLE || Pred == FCmpInst::FCMP_ULE)) {
@@ -3029,10 +3029,9 @@ static Instruction *foldSelectWithFCmpToFabs(SelectInst &SI,
     //       of NAN, but IEEE-754 specifies the signbit of NAN values with
     //       fneg/fabs operations.
     if (!SI.hasNoSignedZeros() &&
-        (!SI.hasOneUse() || !canIgnoreSignBitOfZero(*SI.use_begin())))
+        (!SI.hasOneUse() || !canIgnoreSignBitOfZero(SI)))
       return nullptr;
-    if (!SI.hasNoNaNs() &&
-        (!SI.hasOneUse() || !canIgnoreSignBitOfNaN(*SI.use_begin())))
+    if (!SI.hasNoNaNs() && (!SI.hasOneUse() || !canIgnoreSignBitOfNaN(SI)))
       return nullptr;
 
     if (Swap)
@@ -4140,8 +4139,7 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
     // minnum/maxnum intrinsics.
     if (SIFPOp->hasNoNaNs() &&
         (SIFPOp->hasNoSignedZeros() ||
-         (SIFPOp->hasOneUse() &&
-          canIgnoreSignBitOfZero(*SIFPOp->use_begin())))) {
+         (SIFPOp->hasOneUse() && canIgnoreSignBitOfZero(SI)))) {
       Value *X, *Y;
       if (match(&SI, m_OrdOrUnordFMax(m_Value(X), m_Value(Y)))) {
         Value *BinIntr =



More information about the llvm-commits mailing list