[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