[llvm] [InstCombine] Fold redundant FP clamp selects; relax min-max-pattern bailout in visitFCmp (PR #173452)
Wenju He via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 24 14:51:56 PST 2025
https://github.com/wenju-he updated https://github.com/llvm/llvm-project/pull/173452
>From 05678b90bfae7c73c6cea73279d08b0ab89b6698 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Wed, 24 Dec 2025 06:38:16 +0100
Subject: [PATCH 1/6] [InstCombine] Fold redundant FP clamp selects; relax
min-max-pattern bailout in visitFCmp()
visitFCmp() previously bailed out when a following select matched a clamp
pattern. This blocks simplifications when the clamp is provably redundant.
This PR allows simplification for clamp selects of flavor SPF_FMAXNUM/
SPF_FMINNUM when one arm is a constant and the other is a sitofp/uitofp
of an integer value, and the constant equals the exact min/max of that
integer domain:
* SPF_FMAXNUM (pattern max(X,C)): redundant if C is the minimum integer
mapped exactly to FP (e.g. X = sitofp i8, C = -128.0f).
* SPF_FMINNUM (pattern min(X,C)): redundant if C is the maximum integer
mapped exactly to FP (e.g. X = uitofp i8, C = 255.0f).
---
.../InstCombine/InstCombineCompares.cpp | 38 +++++++++++++++-
.../Transforms/InstCombine/fcmp-select.ll | 44 +++++++++++++++++++
2 files changed, 81 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 7f1ced9505b9b..67d36bcd5f0c1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -8679,6 +8679,40 @@ static Instruction *foldFCmpWithFloorAndCeil(FCmpInst &I,
return nullptr;
}
+/// Returns true if a select that implements a min/max is redundant and
+/// select result can be replaced with its non-constant operand, e.g.,
+/// select ( (si/ui-to-fp A) <= C ), C, (si/ui-to-fp A)
+/// where C is the FP constant equal to the minimum integer value
+/// representable by A.
+static bool isMinMaxCmpSelectEliminable(SelectPatternFlavor Flavor, Value *A,
+ Value *B) {
+ Constant *C = dyn_cast<Constant>(B);
+ if (isa<Constant>(A) || !C)
+ return false;
+
+ if (C->getType()->isVectorTy())
+ C = C->getSplatValue();
+ auto *CFP = dyn_cast_or_null<ConstantFP>(C);
+ if (!CFP)
+ return false;
+
+ auto *I = dyn_cast<Instruction>(A);
+ if (!I || !(I->getOpcode() == Instruction::SIToFP ||
+ I->getOpcode() == Instruction::UIToFP))
+ return false;
+
+ bool IsUnsigned = I->getOpcode() == Instruction::UIToFP;
+ unsigned BitWidth =
+ I->getOperand(0)->getType()->getScalarType()->getIntegerBitWidth();
+ APSInt MinOrMaxInt = (Flavor == SPF_FMAXNUM)
+ ? APSInt::getMinValue(BitWidth, IsUnsigned)
+ : APSInt::getMaxValue(BitWidth, IsUnsigned);
+ APSInt ToInt(BitWidth, IsUnsigned);
+ bool IsExact;
+ CFP->getValueAPF().convertToInteger(ToInt, APFloat::rmTowardZero, &IsExact);
+ return IsExact && ToInt == MinOrMaxInt;
+}
+
Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
bool Changed = false;
@@ -8762,7 +8796,9 @@ Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
if (SelectInst *SI = dyn_cast<SelectInst>(I.user_back())) {
Value *A, *B;
SelectPatternResult SPR = matchSelectPattern(SI, A, B);
- if (SPR.Flavor != SPF_UNKNOWN)
+ if (SPR.Flavor != SPF_UNKNOWN &&
+ !((SPR.Flavor == SPF_FMAXNUM || SPR.Flavor == SPF_FMINNUM) &&
+ isMinMaxCmpSelectEliminable(SPR.Flavor, A, B)))
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/fcmp-select.ll b/llvm/test/Transforms/InstCombine/fcmp-select.ll
index b622c8636eccb..65ef5de3117fc 100644
--- a/llvm/test/Transforms/InstCombine/fcmp-select.ll
+++ b/llvm/test/Transforms/InstCombine/fcmp-select.ll
@@ -303,3 +303,47 @@ define float @test_select_nnan_nsz_fcmp_ult(float %x) {
%sel = select nnan nsz i1 %cmp, float %x, float -0.000000e+00
ret float %sel
}
+
+define float @test_select_fcmp_sitofp_max(i8 %x) {
+; CHECK-LABEL: @test_select_fcmp_sitofp_max(
+; CHECK-NEXT: [[TMP2:%.*]] = sitofp i8 [[TMP0:%.*]] to float
+; CHECK-NEXT: ret float [[TMP2]]
+;
+ %f = sitofp i8 %x to float
+ %cmp = fcmp ole float %f, -1.280000e+02
+ %sel = select i1 %cmp, float -1.280000e+02, float %f
+ ret float %sel
+}
+
+define <2 x float> @test_select_fcmp_sitofp_max_vec(<2 x i8> %x) {
+; CHECK-LABEL: @test_select_fcmp_sitofp_max_vec(
+; CHECK-NEXT: [[F:%.*]] = sitofp <2 x i8> [[X:%.*]] to <2 x float>
+; CHECK-NEXT: ret <2 x float> [[F]]
+;
+ %f = sitofp <2 x i8> %x to <2 x float>
+ %cmp = fcmp ole <2 x float> %f, splat (float -1.280000e+02)
+ %sel = select <2 x i1> %cmp, <2 x float> splat (float -1.280000e+02), <2 x float> %f
+ ret <2 x float> %sel
+}
+
+define float @test_select_fcmp_sitofp_min(i8 %x) {
+; CHECK-LABEL: @test_select_fcmp_sitofp_min(
+; CHECK-NEXT: [[TMP2:%.*]] = sitofp i8 [[TMP0:%.*]] to float
+; CHECK-NEXT: ret float [[TMP2]]
+;
+ %f = sitofp i8 %x to float
+ %cmp = fcmp oge float %f, 1.270000e+02
+ %sel = select i1 %cmp, float 1.270000e+02, float %f
+ ret float %sel
+}
+
+define float @test_select_fcmp_uitofp_min(i8 %x) {
+; CHECK-LABEL: @test_select_fcmp_uitofp_min(
+; CHECK-NEXT: [[TMP2:%.*]] = uitofp i8 [[TMP0:%.*]] to float
+; CHECK-NEXT: ret float [[TMP2]]
+;
+ %f = uitofp i8 %x to float
+ %cmp = fcmp oge float %f, 2.550000e+02
+ %sel = select i1 %cmp, float 2.550000e+02, float %f
+ ret float %sel
+}
>From 488c5ef8f65415b07d55fb65c4b25bb5e13b023c Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Wed, 24 Dec 2025 06:59:01 +0100
Subject: [PATCH 2/6] run update_test_checks.py
---
llvm/test/Transforms/InstCombine/fcmp-select.ll | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/fcmp-select.ll b/llvm/test/Transforms/InstCombine/fcmp-select.ll
index 65ef5de3117fc..bb41f18c74f5f 100644
--- a/llvm/test/Transforms/InstCombine/fcmp-select.ll
+++ b/llvm/test/Transforms/InstCombine/fcmp-select.ll
@@ -306,8 +306,8 @@ define float @test_select_nnan_nsz_fcmp_ult(float %x) {
define float @test_select_fcmp_sitofp_max(i8 %x) {
; CHECK-LABEL: @test_select_fcmp_sitofp_max(
-; CHECK-NEXT: [[TMP2:%.*]] = sitofp i8 [[TMP0:%.*]] to float
-; CHECK-NEXT: ret float [[TMP2]]
+; CHECK-NEXT: [[F:%.*]] = sitofp i8 [[X:%.*]] to float
+; CHECK-NEXT: ret float [[F]]
;
%f = sitofp i8 %x to float
%cmp = fcmp ole float %f, -1.280000e+02
@@ -328,8 +328,8 @@ define <2 x float> @test_select_fcmp_sitofp_max_vec(<2 x i8> %x) {
define float @test_select_fcmp_sitofp_min(i8 %x) {
; CHECK-LABEL: @test_select_fcmp_sitofp_min(
-; CHECK-NEXT: [[TMP2:%.*]] = sitofp i8 [[TMP0:%.*]] to float
-; CHECK-NEXT: ret float [[TMP2]]
+; CHECK-NEXT: [[F:%.*]] = sitofp i8 [[X:%.*]] to float
+; CHECK-NEXT: ret float [[F]]
;
%f = sitofp i8 %x to float
%cmp = fcmp oge float %f, 1.270000e+02
@@ -339,8 +339,8 @@ define float @test_select_fcmp_sitofp_min(i8 %x) {
define float @test_select_fcmp_uitofp_min(i8 %x) {
; CHECK-LABEL: @test_select_fcmp_uitofp_min(
-; CHECK-NEXT: [[TMP2:%.*]] = uitofp i8 [[TMP0:%.*]] to float
-; CHECK-NEXT: ret float [[TMP2]]
+; CHECK-NEXT: [[F:%.*]] = uitofp i8 [[X:%.*]] to float
+; CHECK-NEXT: ret float [[F]]
;
%f = uitofp i8 %x to float
%cmp = fcmp oge float %f, 2.550000e+02
>From 4187b0008b2433f7db8276578ce014c800fe7dfd Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Wed, 24 Dec 2025 14:47:11 +0800
Subject: [PATCH 3/6] Update
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Co-authored-by: Copilot <175728472+Copilot at users.noreply.github.com>
---
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 67d36bcd5f0c1..0d2f21b4917b1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -8704,13 +8704,13 @@ static bool isMinMaxCmpSelectEliminable(SelectPatternFlavor Flavor, Value *A,
bool IsUnsigned = I->getOpcode() == Instruction::UIToFP;
unsigned BitWidth =
I->getOperand(0)->getType()->getScalarType()->getIntegerBitWidth();
- APSInt MinOrMaxInt = (Flavor == SPF_FMAXNUM)
+ APSInt IntBoundary = (Flavor == SPF_FMAXNUM)
? APSInt::getMinValue(BitWidth, IsUnsigned)
: APSInt::getMaxValue(BitWidth, IsUnsigned);
APSInt ToInt(BitWidth, IsUnsigned);
bool IsExact;
CFP->getValueAPF().convertToInteger(ToInt, APFloat::rmTowardZero, &IsExact);
- return IsExact && ToInt == MinOrMaxInt;
+ return IsExact && ToInt == IntBoundary;
}
Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
>From e81cbb339ffc7c33d8c44e8062de40a53a179f52 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Thu, 25 Dec 2025 06:33:35 +0800
Subject: [PATCH 4/6] Update
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Co-authored-by: Yingwei Zheng <dtcxzyw at qq.com>
---
.../lib/Transforms/InstCombine/InstCombineCompares.cpp | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 0d2f21b4917b1..0e127952799ec 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -8686,14 +8686,8 @@ static Instruction *foldFCmpWithFloorAndCeil(FCmpInst &I,
/// representable by A.
static bool isMinMaxCmpSelectEliminable(SelectPatternFlavor Flavor, Value *A,
Value *B) {
- Constant *C = dyn_cast<Constant>(B);
- if (isa<Constant>(A) || !C)
- return false;
-
- if (C->getType()->isVectorTy())
- C = C->getSplatValue();
- auto *CFP = dyn_cast_or_null<ConstantFP>(C);
- if (!CFP)
+ ConstantFP *CFP;
+ if (!match(B, m_APFloat(CFP)))
return false;
auto *I = dyn_cast<Instruction>(A);
>From 938153cd409d95abe043554eedd24b7bb9ab0dbd Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Thu, 25 Dec 2025 06:33:45 +0800
Subject: [PATCH 5/6] Update
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Co-authored-by: Yingwei Zheng <dtcxzyw at qq.com>
---
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 0e127952799ec..5a598e3701bfa 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -8697,7 +8697,7 @@ static bool isMinMaxCmpSelectEliminable(SelectPatternFlavor Flavor, Value *A,
bool IsUnsigned = I->getOpcode() == Instruction::UIToFP;
unsigned BitWidth =
- I->getOperand(0)->getType()->getScalarType()->getIntegerBitWidth();
+ I->getOperand(0)->getType()->getScalarSizeInBits();
APSInt IntBoundary = (Flavor == SPF_FMAXNUM)
? APSInt::getMinValue(BitWidth, IsUnsigned)
: APSInt::getMaxValue(BitWidth, IsUnsigned);
>From f5af3a08ecea97001ca5abcfa7dc26fb70072909 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Wed, 24 Dec 2025 23:51:39 +0100
Subject: [PATCH 6/6] fix build
---
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 5a598e3701bfa..a73b4ea98c5c3 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -8686,8 +8686,8 @@ static Instruction *foldFCmpWithFloorAndCeil(FCmpInst &I,
/// representable by A.
static bool isMinMaxCmpSelectEliminable(SelectPatternFlavor Flavor, Value *A,
Value *B) {
- ConstantFP *CFP;
- if (!match(B, m_APFloat(CFP)))
+ const APFloat *APF;
+ if (!match(B, m_APFloat(APF)))
return false;
auto *I = dyn_cast<Instruction>(A);
@@ -8696,14 +8696,13 @@ static bool isMinMaxCmpSelectEliminable(SelectPatternFlavor Flavor, Value *A,
return false;
bool IsUnsigned = I->getOpcode() == Instruction::UIToFP;
- unsigned BitWidth =
- I->getOperand(0)->getType()->getScalarSizeInBits();
+ unsigned BitWidth = I->getOperand(0)->getType()->getScalarSizeInBits();
APSInt IntBoundary = (Flavor == SPF_FMAXNUM)
? APSInt::getMinValue(BitWidth, IsUnsigned)
: APSInt::getMaxValue(BitWidth, IsUnsigned);
APSInt ToInt(BitWidth, IsUnsigned);
bool IsExact;
- CFP->getValueAPF().convertToInteger(ToInt, APFloat::rmTowardZero, &IsExact);
+ APF->convertToInteger(ToInt, APFloat::rmTowardZero, &IsExact);
return IsExact && ToInt == IntBoundary;
}
More information about the llvm-commits
mailing list