[llvm] [InstCombine] Enable more fabs fold when the user ignores sign bit of zero/NaN (PR #139861)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Wed May 21 04:30:48 PDT 2025
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/139861
>From 7add1bcd02b1f72d580bb2e64a1fe4a8bdc085d9 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 14 May 2025 15:51:50 +0800
Subject: [PATCH 1/4] [InstCombine] Add pre-commit tests. NFC.
---
llvm/test/Transforms/InstCombine/fabs.ll | 109 +++++++++++++++++++++++
1 file changed, 109 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/fabs.ll b/llvm/test/Transforms/InstCombine/fabs.ll
index f449d4b8e6b37..e73d99e2900bb 100644
--- a/llvm/test/Transforms/InstCombine/fabs.ll
+++ b/llvm/test/Transforms/InstCombine/fabs.ll
@@ -1276,3 +1276,112 @@ define <2 x float> @test_select_neg_negx_x_wrong_type(<2 x float> %value) {
%value.addr.0.i = select i1 %a1, <2 x float> %fneg.i, <2 x float> %value
ret <2 x float> %value.addr.0.i
}
+
+define i1 @test_fabs_used_by_fcmp(float %x, float %y) {
+; CHECK-LABEL: @test_fabs_used_by_fcmp(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[SEL]], [[Y:%.*]]
+; CHECK-NEXT: ret i1 [[CMP2]]
+;
+ %cmp = fcmp oge float %x, 0.000000e+00
+ %neg = fneg float %x
+ %sel = select i1 %cmp, float %x, float %neg
+ %cmp2 = fcmp olt float %sel, %y
+ ret i1 %cmp2
+}
+
+define float @test_fabs_used_by_fpop_nnan_nsz(float %x, float %y) {
+; CHECK-LABEL: @test_fabs_used_by_fpop_nnan_nsz(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[ADD:%.*]] = fadd nnan nsz float [[SEL]], [[Y:%.*]]
+; CHECK-NEXT: ret float [[ADD]]
+;
+ %cmp = fcmp oge float %x, 0.000000e+00
+ %neg = fneg float %x
+ %sel = select i1 %cmp, float %x, float %neg
+ %add = fadd nnan nsz float %sel, %y
+ ret float %add
+}
+
+define i1 @test_fabs_fsub_used_by_fcmp(float %x, float %y) {
+; CHECK-LABEL: @test_fabs_fsub_used_by_fcmp(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[NEG:%.*]] = fsub float 0.000000e+00, [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[SEL]], [[Y:%.*]]
+; CHECK-NEXT: ret i1 [[CMP2]]
+;
+ %cmp = fcmp ogt float %x, 0.000000e+00
+ %neg = fsub float 0.000000e+00, %x
+ %sel = select i1 %cmp, float %x, float %neg
+ %cmp2 = fcmp olt float %sel, %y
+ ret i1 %cmp2
+}
+
+define float @test_fabs_fsub_used_by_fpop_nnan(float %x, float %y) {
+; CHECK-LABEL: @test_fabs_fsub_used_by_fpop_nnan(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[NEG:%.*]] = fsub float 0.000000e+00, [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[ADD:%.*]] = fadd nnan float [[SEL]], [[Y:%.*]]
+; CHECK-NEXT: ret float [[ADD]]
+;
+ %cmp = fcmp ogt float %x, 0.000000e+00
+ %neg = fsub float 0.000000e+00, %x
+ %sel = select i1 %cmp, float %x, float %neg
+ %add = fadd nnan float %sel, %y
+ ret float %add
+}
+
+; Negative tests
+
+define float @test_fabs_used_by_fpop_nnan(float %x, float %y) {
+; CHECK-LABEL: @test_fabs_used_by_fpop_nnan(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[ADD:%.*]] = fadd nnan float [[SEL]], [[Y:%.*]]
+; CHECK-NEXT: ret float [[ADD]]
+;
+ %cmp = fcmp oge float %x, 0.000000e+00
+ %neg = fneg float %x
+ %sel = select i1 %cmp, float %x, float %neg
+ %add = fadd nnan float %sel, %y
+ ret float %add
+}
+
+define float @test_fabs_used_by_fpop_nsz(float %x, float %y) {
+; CHECK-LABEL: @test_fabs_used_by_fpop_nsz(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[ADD:%.*]] = fadd nsz float [[SEL]], [[Y:%.*]]
+; CHECK-NEXT: ret float [[ADD]]
+;
+ %cmp = fcmp oge float %x, 0.000000e+00
+ %neg = fneg float %x
+ %sel = select i1 %cmp, float %x, float %neg
+ %add = fadd nsz float %sel, %y
+ ret float %add
+}
+
+define i1 @test_fabs_used_by_fcmp_multiuse(float %x, float %y) {
+; CHECK-LABEL: @test_fabs_used_by_fcmp_multiuse(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[SEL]], [[Y:%.*]]
+; CHECK-NEXT: call void @use(float [[SEL]])
+; CHECK-NEXT: ret i1 [[CMP2]]
+;
+ %cmp = fcmp oge float %x, 0.000000e+00
+ %neg = fneg float %x
+ %sel = select i1 %cmp, float %x, float %neg
+ %cmp2 = fcmp olt float %sel, %y
+ call void @use(float %sel)
+ ret i1 %cmp2
+}
>From cb419c7cbddce778673f3d4b414ed9b8064b8d6e Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 14 May 2025 16:33:28 +0800
Subject: [PATCH 2/4] [InstCombine] Enable more fabs fold when the user ignores
sign bit of zero/NaN
---
.../InstCombine/InstCombineSelect.cpp | 45 ++++++++++++++++++-
llvm/test/Transforms/InstCombine/fabs.ll | 16 ++-----
llvm/test/Transforms/InstCombine/fneg.ll | 6 +--
3 files changed, 50 insertions(+), 17 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index b5a40892694c1..2ef233bc25d72 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -2773,6 +2773,47 @@ Instruction *InstCombinerImpl::foldAndOrOfSelectUsingImpliedCond(Value *Op,
return nullptr;
}
+/// Return true if the sign bit of result can be ignored when the result is
+/// zero.
+static bool ignoreSignBitOfZero(Instruction &I) {
+ if (I.hasNoSignedZeros())
+ return true;
+
+ // Check if the sign bit is ignored by the only user.
+ if (!I.hasOneUse())
+ return false;
+ Instruction *User = I.user_back();
+
+ // fcmp treats both positive and negative zero as equal.
+ if (User->getOpcode() == Instruction::FCmp)
+ return true;
+
+ if (auto *FPOp = dyn_cast<FPMathOperator>(User))
+ return FPOp->hasNoSignedZeros();
+
+ return false;
+}
+
+/// Return true if the sign bit of result can be ignored when the result is NaN.
+static bool ignoreSignBitOfNaN(Instruction &I) {
+ if (I.hasNoNaNs())
+ return true;
+
+ // Check if the sign bit is ignored by the only user.
+ if (!I.hasOneUse())
+ return false;
+ Instruction *User = I.user_back();
+
+ // fcmp ignores the sign bit of NaN.
+ if (User->getOpcode() == Instruction::FCmp)
+ return true;
+
+ if (auto *FPOp = dyn_cast<FPMathOperator>(User))
+ return FPOp->hasNoNaNs();
+
+ return false;
+}
+
// Canonicalize select with fcmp to fabs(). -0.0 makes this tricky. We need
// fast-math-flags (nsz) or fsub with +0.0 (not fneg) for this to work.
static Instruction *foldSelectWithFCmpToFabs(SelectInst &SI,
@@ -2797,7 +2838,7 @@ static Instruction *foldSelectWithFCmpToFabs(SelectInst &SI,
// of NAN, but IEEE-754 specifies the signbit of NAN values with
// fneg/fabs operations.
if (match(TrueVal, m_FSub(m_PosZeroFP(), m_Specific(X))) &&
- (cast<FPMathOperator>(CondVal)->hasNoNaNs() || SI.hasNoNaNs() ||
+ (cast<FPMathOperator>(CondVal)->hasNoNaNs() || ignoreSignBitOfNaN(SI) ||
isKnownNeverNaN(X, /*Depth=*/0,
IC.getSimplifyQuery().getWithInstruction(
cast<Instruction>(CondVal))))) {
@@ -2844,7 +2885,7 @@ static Instruction *foldSelectWithFCmpToFabs(SelectInst &SI,
// Note: We require "nnan" for this fold because fcmp ignores the signbit
// of NAN, but IEEE-754 specifies the signbit of NAN values with
// fneg/fabs operations.
- if (!SI.hasNoSignedZeros() || !SI.hasNoNaNs())
+ if (!ignoreSignBitOfZero(SI) || !ignoreSignBitOfNaN(SI))
return nullptr;
if (Swap)
diff --git a/llvm/test/Transforms/InstCombine/fabs.ll b/llvm/test/Transforms/InstCombine/fabs.ll
index e73d99e2900bb..680c8fdee76d5 100644
--- a/llvm/test/Transforms/InstCombine/fabs.ll
+++ b/llvm/test/Transforms/InstCombine/fabs.ll
@@ -1279,9 +1279,7 @@ define <2 x float> @test_select_neg_negx_x_wrong_type(<2 x float> %value) {
define i1 @test_fabs_used_by_fcmp(float %x, float %y) {
; CHECK-LABEL: @test_fabs_used_by_fcmp(
-; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
-; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[SEL:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[SEL]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[CMP2]]
;
@@ -1294,9 +1292,7 @@ define i1 @test_fabs_used_by_fcmp(float %x, float %y) {
define float @test_fabs_used_by_fpop_nnan_nsz(float %x, float %y) {
; CHECK-LABEL: @test_fabs_used_by_fpop_nnan_nsz(
-; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
-; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[SEL:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[ADD:%.*]] = fadd nnan nsz float [[SEL]], [[Y:%.*]]
; CHECK-NEXT: ret float [[ADD]]
;
@@ -1309,9 +1305,7 @@ define float @test_fabs_used_by_fpop_nnan_nsz(float %x, float %y) {
define i1 @test_fabs_fsub_used_by_fcmp(float %x, float %y) {
; CHECK-LABEL: @test_fabs_fsub_used_by_fcmp(
-; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[X:%.*]], 0.000000e+00
-; CHECK-NEXT: [[NEG:%.*]] = fsub float 0.000000e+00, [[X]]
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[SEL:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[SEL]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[CMP2]]
;
@@ -1324,9 +1318,7 @@ define i1 @test_fabs_fsub_used_by_fcmp(float %x, float %y) {
define float @test_fabs_fsub_used_by_fpop_nnan(float %x, float %y) {
; CHECK-LABEL: @test_fabs_fsub_used_by_fpop_nnan(
-; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[X:%.*]], 0.000000e+00
-; CHECK-NEXT: [[NEG:%.*]] = fsub float 0.000000e+00, [[X]]
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[SEL:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[ADD:%.*]] = fadd nnan float [[SEL]], [[Y:%.*]]
; CHECK-NEXT: ret float [[ADD]]
;
diff --git a/llvm/test/Transforms/InstCombine/fneg.ll b/llvm/test/Transforms/InstCombine/fneg.ll
index 755beff9bf77a..a9d1b9a4ab837 100644
--- a/llvm/test/Transforms/InstCombine/fneg.ll
+++ b/llvm/test/Transforms/InstCombine/fneg.ll
@@ -709,7 +709,7 @@ define float @select_common_op_fneg_false(float %x, i1 %b) {
define float @fabs(float %a) {
; CHECK-LABEL: @fabs(
-; CHECK-NEXT: [[FNEG1:%.*]] = call nnan ninf nsz float @llvm.fabs.f32(float [[A:%.*]])
+; CHECK-NEXT: [[FNEG1:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]])
; CHECK-NEXT: ret float [[FNEG1]]
;
%fneg = fneg float %a
@@ -721,7 +721,7 @@ define float @fabs(float %a) {
define float @fnabs(float %a) {
; CHECK-LABEL: @fnabs(
-; CHECK-NEXT: [[TMP1:%.*]] = call fast float @llvm.fabs.f32(float [[A:%.*]])
+; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]])
; CHECK-NEXT: [[FNEG1:%.*]] = fneg fast float [[TMP1]]
; CHECK-NEXT: ret float [[FNEG1]]
;
@@ -734,7 +734,7 @@ define float @fnabs(float %a) {
define float @fnabs_1(float %a) {
; CHECK-LABEL: @fnabs_1(
-; CHECK-NEXT: [[TMP1:%.*]] = call fast float @llvm.fabs.f32(float [[A:%.*]])
+; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]])
; CHECK-NEXT: [[FNEG1:%.*]] = fneg fast float [[TMP1]]
; CHECK-NEXT: ret float [[FNEG1]]
;
>From 1b0fd5efc795fe027252116bcfade2ab020f3c98 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 21 May 2025 19:19:12 +0800
Subject: [PATCH 3/4] [InstCombine] Handle more fp op/intrinsics
---
.../InstCombine/InstCombineSelect.cpp | 74 +++++++++++++++----
llvm/test/Transforms/InstCombine/fabs.ll | 24 +++---
2 files changed, 69 insertions(+), 29 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 2ef233bc25d72..15bf8f398677a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -2782,16 +2782,31 @@ static bool ignoreSignBitOfZero(Instruction &I) {
// Check if the sign bit is ignored by the only user.
if (!I.hasOneUse())
return false;
- Instruction *User = I.user_back();
-
- // fcmp treats both positive and negative zero as equal.
- if (User->getOpcode() == Instruction::FCmp)
+ auto *FPOp = dyn_cast<FPMathOperator>(I.user_back());
+ if (!FPOp)
+ return false;
+ if (FPOp->hasNoSignedZeros())
return true;
- if (auto *FPOp = dyn_cast<FPMathOperator>(User))
- return FPOp->hasNoSignedZeros();
-
- return false;
+ switch (FPOp->getOpcode()) {
+ case Instruction::FCmp:
+ // fcmp treats both positive and negative zero as equal.
+ return true;
+ case Instruction::Call:
+ if (auto *II = dyn_cast<IntrinsicInst>(FPOp)) {
+ switch (II->getIntrinsicID()) {
+ case Intrinsic::fabs:
+ return true;
+ case Intrinsic::copysign:
+ return II->getArgOperand(0) == &I;
+ default:
+ return false;
+ }
+ }
+ return false;
+ default:
+ return false;
+ }
}
/// Return true if the sign bit of result can be ignored when the result is NaN.
@@ -2802,16 +2817,43 @@ static bool ignoreSignBitOfNaN(Instruction &I) {
// Check if the sign bit is ignored by the only user.
if (!I.hasOneUse())
return false;
- Instruction *User = I.user_back();
-
- // fcmp ignores the sign bit of NaN.
- if (User->getOpcode() == Instruction::FCmp)
+ auto *FPOp = dyn_cast<FPMathOperator>(I.user_back());
+ if (!FPOp)
+ return false;
+ if (FPOp->hasNoNaNs())
return true;
- if (auto *FPOp = dyn_cast<FPMathOperator>(User))
- return FPOp->hasNoNaNs();
-
- return false;
+ switch (FPOp->getOpcode()) {
+ case Instruction::FNeg:
+ case Instruction::Select:
+ case Instruction::PHI:
+ return false;
+ case Instruction::Call: {
+ if (auto *II = dyn_cast<IntrinsicInst>(FPOp)) {
+ switch (II->getIntrinsicID()) {
+ case Intrinsic::fabs:
+ return true;
+ case Intrinsic::copysign:
+ return II->getArgOperand(0) == &I;
+ case Intrinsic::maxnum:
+ case Intrinsic::minnum:
+ case Intrinsic::maximum:
+ case Intrinsic::minimum:
+ case Intrinsic::maximumnum:
+ case Intrinsic::minimumnum:
+ case Intrinsic::canonicalize:
+ return false;
+ default:
+ // Other proper FP intrinsics ignore the sign bit of NaN.
+ return true;
+ }
+ }
+ return false;
+ }
+ default:
+ // Other proper FP math operations ignore the sign bit of NaN.
+ return true;
+ }
}
// Canonicalize select with fcmp to fabs(). -0.0 makes this tricky. We need
diff --git a/llvm/test/Transforms/InstCombine/fabs.ll b/llvm/test/Transforms/InstCombine/fabs.ll
index 680c8fdee76d5..635dbd1a7b533 100644
--- a/llvm/test/Transforms/InstCombine/fabs.ll
+++ b/llvm/test/Transforms/InstCombine/fabs.ll
@@ -1329,35 +1329,33 @@ define float @test_fabs_fsub_used_by_fpop_nnan(float %x, float %y) {
ret float %add
}
-; Negative tests
-
-define float @test_fabs_used_by_fpop_nnan(float %x, float %y) {
-; CHECK-LABEL: @test_fabs_used_by_fpop_nnan(
-; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
-; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
-; CHECK-NEXT: [[ADD:%.*]] = fadd nnan float [[SEL]], [[Y:%.*]]
+define float @test_fabs_used_by_fpop_nsz(float %x, float %y) {
+; CHECK-LABEL: @test_fabs_used_by_fpop_nsz(
+; CHECK-NEXT: [[SEL:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT: [[ADD:%.*]] = fadd nsz float [[SEL]], [[Y:%.*]]
; CHECK-NEXT: ret float [[ADD]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
- %add = fadd nnan float %sel, %y
+ %add = fadd nsz float %sel, %y
ret float %add
}
-define float @test_fabs_used_by_fpop_nsz(float %x, float %y) {
-; CHECK-LABEL: @test_fabs_used_by_fpop_nsz(
+; Negative tests
+
+define float @test_fabs_used_by_fpop_nnan(float %x, float %y) {
+; CHECK-LABEL: @test_fabs_used_by_fpop_nnan(
; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
-; CHECK-NEXT: [[ADD:%.*]] = fadd nsz float [[SEL]], [[Y:%.*]]
+; CHECK-NEXT: [[ADD:%.*]] = fadd nnan float [[SEL]], [[Y:%.*]]
; CHECK-NEXT: ret float [[ADD]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
- %add = fadd nsz float %sel, %y
+ %add = fadd nnan float %sel, %y
ret float %add
}
>From 3eb71ff9e2190690da31e801cef94d846cd5a448 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 21 May 2025 19:29:20 +0800
Subject: [PATCH 4/4] [InstCombine] Add more tests. NFC.
---
.../InstCombine/InstCombineSelect.cpp | 3 +
llvm/test/Transforms/InstCombine/fabs.ll | 73 +++++++++++++++++++
2 files changed, 76 insertions(+)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 15bf8f398677a..8e7cc98fcfd02 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -2835,12 +2835,15 @@ static bool ignoreSignBitOfNaN(Instruction &I) {
return true;
case Intrinsic::copysign:
return II->getArgOperand(0) == &I;
+ // fmin/fmax returns one of its operands, so the sign bit cannot be
+ // ignored.
case Intrinsic::maxnum:
case Intrinsic::minnum:
case Intrinsic::maximum:
case Intrinsic::minimum:
case Intrinsic::maximumnum:
case Intrinsic::minimumnum:
+ // llvm.canonicalize preserves the sign bit of NaN.
case Intrinsic::canonicalize:
return false;
default:
diff --git a/llvm/test/Transforms/InstCombine/fabs.ll b/llvm/test/Transforms/InstCombine/fabs.ll
index 635dbd1a7b533..6aea41cc3ee60 100644
--- a/llvm/test/Transforms/InstCombine/fabs.ll
+++ b/llvm/test/Transforms/InstCombine/fabs.ll
@@ -1342,6 +1342,19 @@ define float @test_fabs_used_by_fpop_nsz(float %x, float %y) {
ret float %add
}
+define float @test_fabs_used_by_fcopysign_mag(float %x, float %y) {
+; CHECK-LABEL: @test_fabs_used_by_fcopysign_mag(
+; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT: ret float [[COPYSIGN]]
+;
+ %cmp = fcmp oge float %x, 0.000000e+00
+ %neg = fneg float %x
+ %sel = select i1 %cmp, float %x, float %neg
+ %copysign = call float @llvm.copysign.f32(float %sel, float %y)
+ ret float %copysign
+}
+
+
; Negative tests
define float @test_fabs_used_by_fpop_nnan(float %x, float %y) {
@@ -1375,3 +1388,63 @@ define i1 @test_fabs_used_by_fcmp_multiuse(float %x, float %y) {
call void @use(float %sel)
ret i1 %cmp2
}
+
+define float @test_fabs_used_by_fcopysign_sign(float %x, float %y) {
+; CHECK-LABEL: @test_fabs_used_by_fcopysign_sign(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[Y:%.*]], float [[SEL]])
+; CHECK-NEXT: ret float [[COPYSIGN]]
+;
+ %cmp = fcmp oge float %x, 0.000000e+00
+ %neg = fneg float %x
+ %sel = select i1 %cmp, float %x, float %neg
+ %copysign = call float @llvm.copysign.f32(float %y, float %sel)
+ ret float %copysign
+}
+
+define float @test_fabs_used_by_maxnum(float %x, float %y) {
+; CHECK-LABEL: @test_fabs_used_by_maxnum(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maxnum.f32(float [[Y:%.*]], float [[SEL]])
+; CHECK-NEXT: ret float [[MAX]]
+;
+ %cmp = fcmp oge float %x, 0.000000e+00
+ %neg = fneg float %x
+ %sel = select i1 %cmp, float %x, float %neg
+ %max = call float @llvm.maxnum.f32(float %y, float %sel)
+ ret float %max
+}
+
+define float @test_fabs_used_by_canonicalize(float %x) {
+; CHECK-LABEL: @test_fabs_used_by_canonicalize(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SEL]])
+; CHECK-NEXT: ret float [[CANON]]
+;
+ %cmp = fcmp oge float %x, 0.000000e+00
+ %neg = fneg float %x
+ %sel = select i1 %cmp, float %x, float %neg
+ %canon = call float @llvm.canonicalize.f32(float %sel)
+ ret float %canon
+}
+
+define float @test_fabs_used_by_select(float %x, i1 %cond) {
+; CHECK-LABEL: @test_fabs_used_by_select(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
+; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[COND:%.*]], float [[SEL]], float 0.000000e+00
+; CHECK-NEXT: ret float [[SEL2]]
+;
+ %cmp = fcmp oge float %x, 0.000000e+00
+ %neg = fneg float %x
+ %sel = select i1 %cmp, float %x, float %neg
+ %sel2 = select i1 %cond, float %sel, float 0.000000e+00
+ ret float %sel2
+}
More information about the llvm-commits
mailing list