[llvm] [missed-opt][X86] Optimize fptosi+select down to a single cvttsd2si Instruction on X86 (PR #172710)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Jan 31 02:54:54 PST 2026
https://github.com/Bhuvan1527 updated https://github.com/llvm/llvm-project/pull/172710
>From 7c5b6cc16f20d56a6a3107137a971ad0c16d262e Mon Sep 17 00:00:00 2001
From: bhuvan1527 <balabhuvanvarma at gmail.com>
Date: Wed, 17 Dec 2025 23:52:40 +0530
Subject: [PATCH 1/4] [missed-opt][X86] Optimize fptosi+select down to a single
cvttsd2si Instruction on X86
When the program is of the form
`; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
define i32 @X86ConvF64ValToI32(double %f64_val) local_unnamed_addr #0 {
%abs_f64_val = tail call double @llvm.fabs.f64(double %f64_val)
%f64_to_i32_result = fptosi double %f64_val to i32
%result_is_in_range = fcmp olt double %abs_f64_val, 0x41E0000000000000
%result = select i1 %result_is_in_range, i32 %f64_to_i32_result, i32 -2147483648
ret i32 %result
}`
on X86, we can just emit a single cvttsd2si Instruction. However
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 39 +++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index ef94c198558c7..e6d4f43d2b49d 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -48149,6 +48149,45 @@ static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
bool CondConstantVector = ISD::isBuildVectorOfConstantSDNodes(Cond.getNode());
unsigned EltBitWidth = VT.getScalarSizeInBits();
+ // select in presence of fp_to_sint can be replaced with just fp_to_sint
+ // fold (SELECT (SETCC (FABS X), MAXFLOAT), (FP_TO_SINT X), INT_MIN)
+ // -> (FP_TO_SINT X)
+ if (Cond.getOpcode() == ISD::SETCC &&
+ Cond.getOperand(0).getOpcode() == ISD::FABS &&
+ Cond.getOperand(1).getOpcode() == ISD::ConstantFP) {
+
+ SDValue FpToInt = LHS;
+ SDValue ConstNode = RHS;
+ if (FpToInt.getOpcode() != ISD::FP_TO_SINT) {
+ std::swap(FpToInt, ConstNode);
+ }
+
+ if (FpToInt.getOpcode() != ISD::FP_TO_SINT) {
+ return SDValue();
+ }
+
+ if (!DAG.isConstantValueOfAnyType(ConstNode)) {
+ return SDValue();
+ }
+
+ SDValue T = Cond.getOperand(0).getOperand(0);
+ if (T != FpToInt.getOperand(0)) {
+ return SDValue();
+ }
+
+ EVT IntVT = FpToInt.getValueType();
+ APInt IntMin = APInt::getSignedMinValue(IntVT.getSizeInBits());
+
+ auto *C = cast<ConstantSDNode>(ConstNode);
+ if (C->getAPIntValue() != IntMin) {
+ return SDValue();
+ }
+
+ // check if the Maxfloat value is matching the value of CmpConst
+ return DAG.getNode(ISD::FP_TO_SINT, DL, FpToInt.getValueType(),
+ FpToInt.getOperand(0));
+ }
+
// Attempt to combine (select M, (sub 0, X), X) -> (sub (xor X, M), M).
// Limit this to cases of non-constant masks that createShuffleMaskFromVSELECT
// can't catch, plus vXi8 cases where we'd likely end up with BLENDV.
>From 601deec06d5913f92aad2df4309854c4d9d7cbcb Mon Sep 17 00:00:00 2001
From: bhuvan1527 <balabhuvanvarma at gmail.com>
Date: Wed, 17 Dec 2025 23:52:40 +0530
Subject: [PATCH 2/4] [missed-opt][X86] Optimize fptosi+select down to a single
cvttsd2si Instruction on X86
Utilized SDPatternMatch sd_match() method to identify the pattern,
(SELECT (SETCC (FABS X), MAXFLOAT), (FP_TO_SINT X), INT_MIN) and then convert into
FP_TO_SINT X on x86.
Had to add Unary_OPMatch for matching ISD::FABS.
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index e6d4f43d2b49d..7adc64daa98d7 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -48126,6 +48126,7 @@ static SDValue commuteSelect(SDNode *N, SelectionDAG &DAG, const SDLoc &DL,
static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
TargetLowering::DAGCombinerInfo &DCI,
const X86Subtarget &Subtarget) {
+
SDLoc DL(N);
SDValue Cond = N->getOperand(0);
SDValue LHS = N->getOperand(1);
@@ -48152,10 +48153,13 @@ static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
// select in presence of fp_to_sint can be replaced with just fp_to_sint
// fold (SELECT (SETCC (FABS X), MAXFLOAT), (FP_TO_SINT X), INT_MIN)
// -> (FP_TO_SINT X)
- if (Cond.getOpcode() == ISD::SETCC &&
- Cond.getOperand(0).getOpcode() == ISD::FABS &&
- Cond.getOperand(1).getOpcode() == ISD::ConstantFP) {
-
+ using namespace SDPatternMatch;
+ SDValue T;
+ SDValue FloatConst;
+ if (sd_match(Cond, m_SetCC(m_FAbs(m_Value(T)), m_Value(FloatConst),
+ m_SpecificCondCode(ISD::SETOLT)))) {
+ if (FloatConst.getOpcode() != ISD::ConstantFP)
+ return SDValue();
SDValue FpToInt = LHS;
SDValue ConstNode = RHS;
if (FpToInt.getOpcode() != ISD::FP_TO_SINT) {
@@ -48170,7 +48174,6 @@ static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
return SDValue();
}
- SDValue T = Cond.getOperand(0).getOperand(0);
if (T != FpToInt.getOperand(0)) {
return SDValue();
}
>From 028be8fb29394bfbf245a131a953f345e22e0de0 Mon Sep 17 00:00:00 2001
From: bhuvan1527 <balabhuvanvarma at gmail.com>
Date: Wed, 17 Dec 2025 23:52:40 +0530
Subject: [PATCH 3/4] [missed-opt][X86] Optimize fptosi+select down to a single
cvttsd2si Instruction on X86
Utilized SDPatternMatch sd_match() method to identify the pattern,
(SELECT (SETCC (FABS X), MAXFLOAT), (FP_TO_SINT X), INT_MIN) and then convert into
FP_TO_SINT X on x86.
Had to add Unary_OPMatch for matching ISD::FABS.
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 76 +++++++++++++++----
.../test/CodeGen/X86/fp_to_sint_SelectFold.ll | 32 ++++++++
2 files changed, 92 insertions(+), 16 deletions(-)
create mode 100644 llvm/test/CodeGen/X86/fp_to_sint_SelectFold.ll
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 7adc64daa98d7..dabdb52fbd1cc 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -48158,37 +48158,81 @@ static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
SDValue FloatConst;
if (sd_match(Cond, m_SetCC(m_FAbs(m_Value(T)), m_Value(FloatConst),
m_SpecificCondCode(ISD::SETOLT)))) {
- if (FloatConst.getOpcode() != ISD::ConstantFP)
- return SDValue();
SDValue FpToInt = LHS;
SDValue ConstNode = RHS;
- if (FpToInt.getOpcode() != ISD::FP_TO_SINT) {
+ if (FpToInt.getOpcode() != ISD::FP_TO_SINT)
std::swap(FpToInt, ConstNode);
- }
- if (FpToInt.getOpcode() != ISD::FP_TO_SINT) {
+ if (FpToInt.getOpcode() != ISD::FP_TO_SINT)
return SDValue();
- }
- if (!DAG.isConstantValueOfAnyType(ConstNode)) {
+ if (!DAG.isConstantValueOfAnyType(ConstNode))
return SDValue();
- }
- if (T != FpToInt.getOperand(0)) {
+ if (T != FpToInt.getOperand(0))
return SDValue();
- }
EVT IntVT = FpToInt.getValueType();
- APInt IntMin = APInt::getSignedMinValue(IntVT.getSizeInBits());
+ EVT FPVT = T.getValueType();
+
+ EVT IntEltVT = IntVT.isVector() ? IntVT.getVectorElementType() : IntVT;
+
+ EVT FPEltVT = FPVT.isVector() ? FPVT.getVectorElementType() : FPVT;
- auto *C = cast<ConstantSDNode>(ConstNode);
- if (C->getAPIntValue() != IntMin) {
+ if (!FPEltVT.isFloatingPoint())
+ return SDValue();
+
+ APInt IntMin = APInt::getSignedMinValue(IntEltVT.getSizeInBits());
+
+ if (!DAG.isConstantValueOfAnyType(ConstNode))
+ return SDValue();
+
+ if (auto *C = dyn_cast<ConstantSDNode>(ConstNode)) {
+ // scalar INT_MIN
+ if (C->getAPIntValue() != IntMin)
+ return SDValue();
+ } else if (ConstNode.getOpcode() == ISD::BUILD_VECTOR) {
+ // vector INT_MIN splat
+ for (unsigned Idx = 0, NumOperands = ConstNode.getNumOperands();
+ Idx != NumOperands; ++Idx) {
+ SDValue Op = ConstNode.getOperand(Idx);
+ auto *EltC = dyn_cast<ConstantSDNode>(Op);
+ if (!EltC || EltC->getAPIntValue() != IntMin)
+ return SDValue();
+ }
+ } else {
return SDValue();
}
- // check if the Maxfloat value is matching the value of CmpConst
- return DAG.getNode(ISD::FP_TO_SINT, DL, FpToInt.getValueType(),
- FpToInt.getOperand(0));
+ APFloat MaxAbsFP(FPEltVT.getFltSemantics(),
+ APInt::getZero(FPEltVT.getSizeInBits()));
+
+ (void)MaxAbsFP.convertFromAPInt(IntMin, false,
+ APFloat::rmNearestTiesToEven);
+
+ bool Match = false;
+
+ if (auto *CFP = dyn_cast<ConstantFPSDNode>(FloatConst)) {
+ // scalar constant
+ Match = CFP->getValueAPF() == MaxAbsFP;
+ } else if (FloatConst.getOpcode() == ISD::BUILD_VECTOR) {
+ // vector splat
+ Match = true;
+ for (unsigned Idx = 0, NumOperands = FloatConst.getNumOperands();
+ Idx != NumOperands; ++Idx) {
+ SDValue Op = FloatConst.getOperand(Idx);
+ auto *EltCFP = dyn_cast<ConstantFPSDNode>(Op);
+ if (!EltCFP || EltCFP->getValueAPF() != MaxAbsFP) {
+ Match = false;
+ break;
+ }
+ }
+ }
+
+ if (!Match)
+ return SDValue();
+
+ return DAG.getNode(ISD::FP_TO_SINT, DL, IntVT, T);
}
// Attempt to combine (select M, (sub 0, X), X) -> (sub (xor X, M), M).
diff --git a/llvm/test/CodeGen/X86/fp_to_sint_SelectFold.ll b/llvm/test/CodeGen/X86/fp_to_sint_SelectFold.ll
new file mode 100644
index 0000000000000..0bb87f8ddfa38
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fp_to_sint_SelectFold.ll
@@ -0,0 +1,32 @@
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu -mattr=+sse2 < %s | FileCheck %s
+
+define i32 @scalar_fptosi_fold(float %x) {
+; CHECK-LABEL: scalar_fptosi_fold:
+; CHECK-NOT: movsd
+; CHECK-NOT: andpd
+; CHECK: cvttss2si
+ %abs = call float @llvm.fabs.f32(float %x)
+ %cmp = fcmp olt float %abs, 2147483648.0
+ %conv = fptosi float %x to i32
+ %res = select i1 %cmp, i32 %conv, i32 -2147483648
+ ret i32 %res
+}
+
+define <4 x i32> @vector_fptosi_fold(<4 x float> %x) {
+; CHECK-LABEL: vector_fptosi_fold:
+; CHECK-NOT: cmpltps
+; CHECK-NOT: andps
+; CHECK: cvttps2dq
+ %abs = call <4 x float> @llvm.fabs.v4f32(<4 x float> %x)
+ %cmp = fcmp olt <4 x float> %abs,
+ <float 2147483648.0, float 2147483648.0,
+ float 2147483648.0, float 2147483648.0>
+ %conv = fptosi <4 x float> %x to <4 x i32>
+ %res = select <4 x i1> %cmp, <4 x i32> %conv,
+ <4 x i32> <i32 -2147483648, i32 -2147483648,
+ i32 -2147483648, i32 -2147483648>
+ ret <4 x i32> %res
+}
+
+declare float @llvm.fabs.f32(float)
+declare <4 x float> @llvm.fabs.v4f32(<4 x float>)
>From 6c1e73b793eeecc74a3f74a6dac0933079428a47 Mon Sep 17 00:00:00 2001
From: bhuvan1527 <balabhuvanvarma at gmail.com>
Date: Wed, 17 Dec 2025 23:52:40 +0530
Subject: [PATCH 4/4] [missed-opt][X86] Optimize fptosi+select down to a single
cvttsd2si Instruction on X86
Utilized SDPatternMatch sd_match() method to identify the pattern,
(SELECT (SETCC (FABS X), MAXFLOAT), (FP_TO_SINT X), INT_MIN) and then convert into
FP_TO_SINT X on x86.
Had to add Unary_OPMatch for matching ISD::FABS.
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 92 ++++---------------------
1 file changed, 12 insertions(+), 80 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index dabdb52fbd1cc..fa75568bbdd39 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -48124,9 +48124,8 @@ static SDValue commuteSelect(SDNode *N, SelectionDAG &DAG, const SDLoc &DL,
/// Do target-specific dag combines on SELECT and VSELECT nodes.
static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
- TargetLowering::DAGCombinerInfo &DCI,
- const X86Subtarget &Subtarget) {
-
+ TargetLowering::DAGCombinerInfo &DCI, const X86Subtarget &Subtarget) {
+ using namespace SDPatternMatch;
SDLoc DL(N);
SDValue Cond = N->getOperand(0);
SDValue LHS = N->getOperand(1);
@@ -48153,86 +48152,19 @@ static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
// select in presence of fp_to_sint can be replaced with just fp_to_sint
// fold (SELECT (SETCC (FABS X), MAXFLOAT), (FP_TO_SINT X), INT_MIN)
// -> (FP_TO_SINT X)
- using namespace SDPatternMatch;
- SDValue T;
- SDValue FloatConst;
- if (sd_match(Cond, m_SetCC(m_FAbs(m_Value(T)), m_Value(FloatConst),
+ SDValue X;
+ SDValue MaxFloat;
+ if (sd_match(Cond, m_SetCC(m_FAbs(m_Value(X)), m_Value(MaxFloat),
m_SpecificCondCode(ISD::SETOLT)))) {
- SDValue FpToInt = LHS;
- SDValue ConstNode = RHS;
- if (FpToInt.getOpcode() != ISD::FP_TO_SINT)
- std::swap(FpToInt, ConstNode);
-
- if (FpToInt.getOpcode() != ISD::FP_TO_SINT)
- return SDValue();
-
- if (!DAG.isConstantValueOfAnyType(ConstNode))
- return SDValue();
-
- if (T != FpToInt.getOperand(0))
- return SDValue();
-
- EVT IntVT = FpToInt.getValueType();
- EVT FPVT = T.getValueType();
-
- EVT IntEltVT = IntVT.isVector() ? IntVT.getVectorElementType() : IntVT;
-
- EVT FPEltVT = FPVT.isVector() ? FPVT.getVectorElementType() : FPVT;
-
- if (!FPEltVT.isFloatingPoint())
- return SDValue();
-
- APInt IntMin = APInt::getSignedMinValue(IntEltVT.getSizeInBits());
-
- if (!DAG.isConstantValueOfAnyType(ConstNode))
- return SDValue();
-
- if (auto *C = dyn_cast<ConstantSDNode>(ConstNode)) {
- // scalar INT_MIN
- if (C->getAPIntValue() != IntMin)
- return SDValue();
- } else if (ConstNode.getOpcode() == ISD::BUILD_VECTOR) {
- // vector INT_MIN splat
- for (unsigned Idx = 0, NumOperands = ConstNode.getNumOperands();
- Idx != NumOperands; ++Idx) {
- SDValue Op = ConstNode.getOperand(Idx);
- auto *EltC = dyn_cast<ConstantSDNode>(Op);
- if (!EltC || EltC->getAPIntValue() != IntMin)
- return SDValue();
- }
- } else {
- return SDValue();
- }
-
- APFloat MaxAbsFP(FPEltVT.getFltSemantics(),
- APInt::getZero(FPEltVT.getSizeInBits()));
-
- (void)MaxAbsFP.convertFromAPInt(IntMin, false,
- APFloat::rmNearestTiesToEven);
-
- bool Match = false;
-
- if (auto *CFP = dyn_cast<ConstantFPSDNode>(FloatConst)) {
- // scalar constant
- Match = CFP->getValueAPF() == MaxAbsFP;
- } else if (FloatConst.getOpcode() == ISD::BUILD_VECTOR) {
- // vector splat
- Match = true;
- for (unsigned Idx = 0, NumOperands = FloatConst.getNumOperands();
- Idx != NumOperands; ++Idx) {
- SDValue Op = FloatConst.getOperand(Idx);
- auto *EltCFP = dyn_cast<ConstantFPSDNode>(Op);
- if (!EltCFP || EltCFP->getValueAPF() != MaxAbsFP) {
- Match = false;
- break;
- }
+ APInt MinSignedInt = APInt::getSignedMinValue(EltBitWidth);
+ if(sd_match(LHS, m_FPToSI(m_Specific(X))) && sd_match(RHS, m_SpecificInt(MinSignedInt))){
+ MVT FPVT = X.getSimpleValueType();
+ APFloat MaxAbsFP(FPVT.getFltSemantics(),APInt::getZero(FPVT.getScalarSizeInBits()));
+ (void)MaxAbsFP.convertFromAPInt(MinSignedInt,false,APFloat::rmNearestTiesToEven);
+ if(sd_match(MaxFloat, m_SpecificFP(MaxAbsFP))){
+ return DAG.getNode(ISD::FP_TO_SINT, DL, VT, X);
}
}
-
- if (!Match)
- return SDValue();
-
- return DAG.getNode(ISD::FP_TO_SINT, DL, IntVT, T);
}
// Attempt to combine (select M, (sub 0, X), X) -> (sub (xor X, M), M).
More information about the llvm-commits
mailing list