[llvm] [InstCombine] Preserve the sign bit of NaN in `SimplifyDemandedUseFPClass` (PR #137287)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 25 00:42:44 PDT 2025
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/137287
>From e94b6c30c014910b79a60f175c7577e4aa0e9b2c Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 25 Apr 2025 13:55:20 +0800
Subject: [PATCH 1/3] [InstCombine] Preserve the sign bit of NaN in
`SimplifyDemandedUseFPClass`
---
.../InstCombineSimplifyDemanded.cpp | 4 ++--
.../InstCombine/simplify-demanded-fpclass.ll | 24 ++++++++-----------
2 files changed, 12 insertions(+), 16 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 2c8939b5a0514..63b342ee43aea 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2013,13 +2013,13 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(
if (SimplifyDemandedFPClass(I, 0, DemandedMaskAnySign, Known, Depth + 1))
return I;
- if ((DemandedMask & fcPositive) == fcNone) {
+ if ((DemandedMask & fcNegative) == DemandedMask) {
// Roundabout way of replacing with fneg(fabs)
I->setOperand(1, ConstantFP::get(VTy, -1.0));
return I;
}
- if ((DemandedMask & fcNegative) == fcNone) {
+ if ((DemandedMask & fcPositive) == DemandedMask) {
// Roundabout way of replacing with fabs
I->setOperand(1, ConstantFP::getZero(VTy));
return I;
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
index ad88287f1d99e..0b0a2157926a0 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
@@ -682,8 +682,7 @@ define nofpclass(inf) float @ret_nofpclass_inf__copysign_negative_select_pinf_rh
define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives_copysign(float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives_copysign
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
-; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
+; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %x, float %unknown.sign)
@@ -694,8 +693,7 @@ define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives_copysig
define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives_copysign_nnan_flag(float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives_copysign_nnan_flag
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = call nnan float @llvm.fabs.f32(float [[X]])
-; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg nnan float [[TMP1]]
+; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call nnan float @llvm.copysign.f32(float %x, float %unknown.sign)
@@ -718,7 +716,7 @@ define nofpclass(nan pinf pnorm psub pzero) float @ret_nofpclass_nopositives_non
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_copysign(float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives_copysign
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
-; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call float @llvm.copysign.f32(float %x, float %unknown.sign)
@@ -729,7 +727,7 @@ define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_copysig
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_copysign_nnan_flag(float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives_copysign_nnan_flag
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
-; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call nnan float @llvm.copysign.f32(float %x, float %unknown.sign)
@@ -763,7 +761,7 @@ define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives__copysi
define nofpclass(inf nnorm nsub nzero) float @ret_nofpclass_no_negatives_noinf__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_nofpclass_no_negatives_noinf__copysign_unknown_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
-; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
@@ -775,8 +773,7 @@ define nofpclass(inf nnorm nsub nzero) float @ret_nofpclass_no_negatives_noinf__
define nofpclass(inf pnorm psub pzero) float @ret_nofpclass_no_positives_noinf__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_nofpclass_no_positives_noinf__copysign_unknown_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
-; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
+; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
@@ -788,8 +785,8 @@ define nofpclass(inf pnorm psub pzero) float @ret_nofpclass_no_positives_noinf__
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_no_negatives__copysign_unknown_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
-; CHECK-NEXT: [[COPYSIGN:%.*]] = select i1 [[COND]], float [[TMP1]], float 0x7FF0000000000000
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[SELECT]], float [[UNKNOWN_SIGN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
@@ -801,9 +798,8 @@ define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives__copys
define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_no_positives__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_no_positives__copysign_unknown_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
-; CHECK-NEXT: [[DOTNEG:%.*]] = fneg float [[TMP1]]
-; CHECK-NEXT: [[COPYSIGN:%.*]] = select i1 [[COND]], float [[DOTNEG]], float 0xFFF0000000000000
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[SELECT]], float [[UNKNOWN_SIGN]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
>From 6c3097dc8551a20478af23178cf735d3a387d5ae Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 25 Apr 2025 13:58:55 +0800
Subject: [PATCH 2/3] [InstCombine] Handle FMF in `SimplifyDemandedUseFPClass`
---
.../InstCombine/InstCombineSimplifyDemanded.cpp | 15 +++++++++++----
.../InstCombine/simplify-demanded-fpclass.ll | 5 +++--
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 63b342ee43aea..a48854a191cae 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -1959,9 +1959,11 @@ static Constant *getFPClassConstant(Type *Ty, FPClassTest Mask) {
}
}
-Value *InstCombinerImpl::SimplifyDemandedUseFPClass(
- Value *V, const FPClassTest DemandedMask, KnownFPClass &Known,
- unsigned Depth, Instruction *CxtI) {
+Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Value *V,
+ FPClassTest DemandedMask,
+ KnownFPClass &Known,
+ unsigned Depth,
+ Instruction *CxtI) {
assert(Depth <= MaxAnalysisRecursionDepth && "Limit Search Depth");
Type *VTy = V->getType();
@@ -1985,7 +1987,12 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(
if (!I->hasOneUse())
return nullptr;
- // TODO: Should account for nofpclass/FastMathFlags on current instruction
+ if (auto *FPOp = dyn_cast<FPMathOperator>(I)) {
+ if (FPOp->hasNoNaNs())
+ DemandedMask &= ~fcNan;
+ if (FPOp->hasNoInfs())
+ DemandedMask &= ~fcInf;
+ }
switch (I->getOpcode()) {
case Instruction::FNeg: {
if (SimplifyDemandedFPClass(I, 0, llvm::fneg(DemandedMask), Known,
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
index 0b0a2157926a0..b3f508f5ace33 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
@@ -693,7 +693,8 @@ define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives_copysig
define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives_copysign_nnan_flag(float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives_copysign_nnan_flag
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
-; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT: [[TMP1:%.*]] = call nnan float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg nnan float [[TMP1]]
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call nnan float @llvm.copysign.f32(float %x, float %unknown.sign)
@@ -727,7 +728,7 @@ define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_copysig
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_copysign_nnan_flag(float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives_copysign_nnan_flag
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
-; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%copysign = call nnan float @llvm.copysign.f32(float %x, float %unknown.sign)
>From 81c9a92e67b57bfb079997c27f479b0af1720188 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 25 Apr 2025 15:42:25 +0800
Subject: [PATCH 3/3] Add more tests. NFC.
---
.../InstCombine/simplify-demanded-fpclass.ll | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
index b3f508f5ace33..df60078dbf452 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
@@ -678,7 +678,7 @@ define nofpclass(inf) float @ret_nofpclass_inf__copysign_negative_select_pinf_rh
ret float %copysign
}
-; can fold to fneg(fabs(x))
+; can't fold to fneg(fabs(x))
define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives_copysign(float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives_copysign
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
@@ -702,6 +702,18 @@ define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives_copysig
}
; can fold to fneg(fabs(x))
+define nofpclass(pnorm psub pzero) float @ret_nofpclass_nopositive_finites_copysign_nnan_ninf_flag(float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(pzero psub pnorm) float @ret_nofpclass_nopositive_finites_copysign_nnan_ninf_flag
+; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = call nnan ninf float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg nnan ninf float [[TMP1]]
+; CHECK-NEXT: ret float [[COPYSIGN]]
+;
+ %copysign = call nnan ninf float @llvm.copysign.f32(float %x, float %unknown.sign)
+ ret float %copysign
+}
+
+; can't fold to fneg(fabs(x))
define nofpclass(nan pinf pnorm psub pzero) float @ret_nofpclass_nopositives_nonan_copysign(float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_nofpclass_nopositives_nonan_copysign
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
@@ -713,7 +725,7 @@ define nofpclass(nan pinf pnorm psub pzero) float @ret_nofpclass_nopositives_non
ret float %copysign
}
-; can fold to fabs(x)
+; can't fold to fabs(x)
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_copysign(float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives_copysign
; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
More information about the llvm-commits
mailing list