[llvm] Fix #51923: x86 sse fp to int sat lowering (PR #199416)

via llvm-commits llvm-commits at lists.llvm.org
Sun May 24 05:51:25 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: Panadulek

<details>
<summary>Changes</summary>

# Task
  [X86][SSE] Improve ISD::FP_TO_*INT_SAT vector lowering

  # Problem
  As noted in the issue description, we currently fall back to scalarizing  FP_TO_INT_SAT  conversions for 32-bit
  vector types. We were failing to take advantage of native SSE behavior for out-of-range integer results,
  leading
  to severely unoptimized and bloated machine code.

  # Solution
  Implemented fully vectorized custom lowering paths for  v4i32   FP_TO_SINT_SAT  and  FP_TO_UINT_SAT  on SSE2.
  For signed conversions, the implementation makes direct use of the  cvttps2dq  hardware behavior (which
  naturally clamps out-of-range lower bounds to  INT_MIN  via the indefinite integer output) and efficiently
  patches positive overflow and  NaN  cases with bitwise masks. For unsigned conversions, it uses  maxps  with   
  0.0  to cleanly drop negatives and  NaN  before natively expanding to  FP_TO_UINT , managing the upper bound
  saturation with a simple mask.

  # Tests
  Added a comprehensive suite of edge-case tests in  fp-to-int-sat-vector-sse2.ll  ensuring correct vectorized
  behavior
  for  NaN ,  +/- Inf ,  0.0 , and exact precision limits. Updated existing Golden Masters using 
  update_llc_test_checks.py . Fully verified by passing the entire  ninja check-llvm-codegen-x86  test suite with
  0
  regressions.


---

Patch is 53.19 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/199416.diff


5 Files Affected:

- (modified) llvm/lib/Target/X86/X86ISelLowering.cpp (+70-1) 
- (added) llvm/test/CodeGen/X86/fp-to-int-sat-vector-sse2.ll (+113) 
- (modified) llvm/test/CodeGen/X86/fpclamptosat_vec.ll (+226-404) 
- (modified) llvm/test/CodeGen/X86/fptosi-sat-vector-128.ll (+21-108) 
- (modified) llvm/test/CodeGen/X86/fptoui-sat-vector-128.ll (+32-93) 


``````````diff
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 1af8eea0c23c6..ef7a076804eeb 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -319,6 +319,8 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
       setOperationAction(ISD::FP_TO_UINT_SAT, MVT::i64, Custom);
       setOperationAction(ISD::FP_TO_SINT_SAT, MVT::i64, Custom);
     }
+    setOperationAction(ISD::FP_TO_UINT_SAT, MVT::v4i32, Custom);
+    setOperationAction(ISD::FP_TO_SINT_SAT, MVT::v4i32, Custom);
   }
   if (Subtarget.hasAVX10_2()) {
     for (MVT VT : {MVT::v8i8, MVT::v16i8, MVT::v32i8}) {
@@ -22820,8 +22822,75 @@ X86TargetLowering::LowerFP_TO_INT_SAT(SDValue Op, SelectionDAG &DAG) const {
     SDValue Res = DAG.getNode(IsSigned ? X86ISD::CVTTP2IBS : X86ISD::CVTTP2IUBS,
                               dl, VecI16VT, Src);
     return DAG.getNode(ISD::TRUNCATE, dl, DstVT, Res);
-  }
+  } else if (DstVT == MVT::v4i32 && Subtarget.hasSSE2()) {
+    unsigned SatWidth = SatVT.getScalarSizeInBits();
+    assert(SatWidth <= 32 && "Expected saturation width no wider than result element");
+
+    if (SatWidth == 32) {
+      if (IsSigned) {
+        SDValue Cvt = DAG.getNode(ISD::FP_TO_SINT, dl, DstVT, Src);
+        APFloat PosOvfBoundFlt(SrcVT.getScalarType().getFltSemantics());
+        PosOvfBoundFlt.convertFromAPInt(APInt::getSignedMinValue(32), /*IsSigned=*/true, APFloat::rmTowardZero);
+        PosOvfBoundFlt.changeSign();
+        SDValue PosOvfBound = DAG.getConstantFP(PosOvfBoundFlt, dl, SrcVT);
+        SDValue PosOvf = DAG.getSetCC(dl, DstVT, Src, PosOvfBound, ISD::SETOGE);
+        SDValue IntMax = DAG.getConstant(APInt::getSignedMaxValue(32), dl, DstVT);
+        SDValue Fixed = DAG.getSelect(dl, DstVT, PosOvf, IntMax, Cvt);
+        SDValue IsNaN = DAG.getSetCC(dl, DstVT, Src, Src, ISD::SETUO);
+        SDValue Zero = DAG.getConstant(0, dl, DstVT);
+        return DAG.getSelect(dl, DstVT, IsNaN, Zero, Fixed);
+      } else {
+        SDValue ZeroFP = DAG.getConstantFP(0.0, dl, SrcVT);
+        SDValue Clamped = DAG.getNode(X86ISD::FMAX, dl, SrcVT, Src, ZeroFP);
+        APFloat OvfBoundFlt(SrcVT.getScalarType().getFltSemantics());
+        OvfBoundFlt.convertFromAPInt(APInt::getOneBitSet(33, 32), /*IsSigned=*/false, APFloat::rmTowardZero);
+        SDValue OvfBound = DAG.getConstantFP(OvfBoundFlt, dl, SrcVT);
+        SDValue IsOvf = DAG.getSetCC(dl, DstVT, Clamped, OvfBound, ISD::SETOGE);
+        SDValue Cvt = DAG.getNode(ISD::FP_TO_UINT, dl, DstVT, Clamped);
+        SDValue UintMax = DAG.getConstant(APInt::getMaxValue(32), dl, DstVT);
+        return DAG.getSelect(dl, DstVT, IsOvf, UintMax, Cvt);
+      }
+    }
+
+    APInt MinInt = IsSigned ? APInt::getSignedMinValue(SatWidth)
+                            : APInt::getMinValue(SatWidth);
+    APInt MaxInt = IsSigned ? APInt::getSignedMaxValue(SatWidth)
+                            : APInt::getMaxValue(SatWidth);
+
+    const fltSemantics &Sem = SrcVT.getFltSemantics();
+    APFloat MinFloat(Sem);
+    APFloat MaxFloat(Sem);
+    // Only use the FMAX/FMIN clamp path when both bounds are exactly
+    // representable in the source float type. If either is inexact, fall back
+    // to generic lowering.
+    bool AreExactFloatBounds =
+        !(MinFloat.convertFromAPInt(MinInt, IsSigned, APFloat::rmTowardZero) &
+          APFloat::opInexact) &&
+        !(MaxFloat.convertFromAPInt(MaxInt, IsSigned, APFloat::rmTowardZero) &
+          APFloat::opInexact);
+    if (!AreExactFloatBounds)
+      return SDValue();
+
+    SDValue MaxC = DAG.getConstantFP(MaxFloat, dl, SrcVT);
+    SDValue MinC = DAG.getConstantFP(MinFloat, dl, SrcVT);
+
+    // Clamp from below. X86ISD::FMAX returns the second operand when either
+    // input is NaN, so NaN maps to MinC here.
+    SDValue ClampedBottom = DAG.getNode(X86ISD::FMAX, dl, SrcVT, Src, MinC);
+    // Clamp from above. NaN (now MinC) is already in range and passes through.
+    SDValue ClampedTop = DAG.getNode(X86ISD::FMIN, dl, SrcVT, ClampedBottom, MaxC);
+    SDValue Result = DAG.getNode(FpToIntOpcode, dl, DstVT, ClampedTop);
 
+    // For signed saturation, NaN was mapped to MinC, so FP_TO_SINT produces
+    // INT_MIN. ISD::FP_TO_SINT_SAT requires NaN -> 0; fix with a zero-select.
+    // For unsigned saturation, MinC == 0.0, so NaN -> 0.0 -> 0: already correct.
+    if (IsSigned) {
+      SDValue Zero = DAG.getConstant(0, dl, DstVT);
+      SDValue IsNaN = DAG.getSetCC(dl, DstVT, Src, Src, ISD::SETUO);
+      return DAG.getSelect(dl, DstVT, IsNaN, Zero, Result);
+    }
+    return Result;
+  }
   // This code is only for floats and doubles. Fall back to generic code for
   // anything else.
   if (!isScalarFPTypeInSSEReg(SrcVT) || isBF16orSoftF16(SrcVT, Subtarget))
diff --git a/llvm/test/CodeGen/X86/fp-to-int-sat-vector-sse2.ll b/llvm/test/CodeGen/X86/fp-to-int-sat-vector-sse2.ll
new file mode 100644
index 0000000000000..b9ae1157f991f
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fp-to-int-sat-vector-sse2.ll
@@ -0,0 +1,113 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=x86_64 -mattr=+sse2,-avx | FileCheck %s --check-prefix=SSE2
+
+declare <4 x i32> @llvm.fptosi.sat.v4i32.v4f32(<4 x float>)
+declare <4 x i32> @llvm.fptoui.sat.v4i32.v4f32(<4 x float>)
+
+; 1. Base case variables
+define <4 x i32> @test_signed_var(<4 x float> %f) {
+; SSE2-LABEL: test_signed_var:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movaps {{.*#+}} xmm1 = [2.14748365E+9,2.14748365E+9,2.14748365E+9,2.14748365E+9]
+; SSE2-NEXT:    cmpleps %xmm0, %xmm1
+; SSE2-NEXT:    cvttps2dq %xmm0, %xmm2
+; SSE2-NEXT:    movaps %xmm1, %xmm3
+; SSE2-NEXT:    andnps %xmm2, %xmm3
+; SSE2-NEXT:    andps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; SSE2-NEXT:    orps %xmm3, %xmm1
+; SSE2-NEXT:    cmpunordps %xmm0, %xmm0
+; SSE2-NEXT:    andnps %xmm1, %xmm0
+; SSE2-NEXT:    retq
+  %x = call <4 x i32> @llvm.fptosi.sat.v4i32.v4f32(<4 x float> %f)
+  ret <4 x i32> %x
+}
+
+define <4 x i32> @test_unsigned_var(<4 x float> %f) {
+; SSE2-LABEL: test_unsigned_var:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    xorps %xmm1, %xmm1
+; SSE2-NEXT:    maxps %xmm1, %xmm0
+; SSE2-NEXT:    cvttps2dq %xmm0, %xmm2
+; SSE2-NEXT:    movaps {{.*#+}} xmm1 = [4.2949673E+9,4.2949673E+9,4.2949673E+9,4.2949673E+9]
+; SSE2-NEXT:    cmpleps %xmm0, %xmm1
+; SSE2-NEXT:    orps %xmm2, %xmm1
+; SSE2-NEXT:    psrad $31, %xmm2
+; SSE2-NEXT:    subps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; SSE2-NEXT:    cvttps2dq %xmm0, %xmm0
+; SSE2-NEXT:    pand %xmm2, %xmm0
+; SSE2-NEXT:    orps %xmm0, %xmm1
+; SSE2-NEXT:    movaps %xmm1, %xmm0
+; SSE2-NEXT:    retq
+  %x = call <4 x i32> @llvm.fptoui.sat.v4i32.v4f32(<4 x float> %f)
+  ret <4 x i32> %x
+}
+
+; 2. Signed edge cases
+define <4 x i32> @test_signed_edge1() {
+  ; NaN, +Inf, -Inf, 0.0
+; SSE2-LABEL: test_signed_edge1:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    cvttps2dq {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; SSE2-NEXT:    movaps {{.*#+}} xmm0 = [u,u,NaN,u]
+; SSE2-NEXT:    shufps {{.*#+}} xmm0 = xmm0[0,2],xmm1[2,3]
+; SSE2-NEXT:    andps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; SSE2-NEXT:    retq
+  %x = call <4 x i32> @llvm.fptosi.sat.v4i32.v4f32(<4 x float> <float 0x7FF8000000000000, float 0x7FF0000000000000, float 0xFFF0000000000000, float 0.0>)
+  ret <4 x i32> %x
+}
+
+define <4 x i32> @test_signed_edge2() {
+  ; exact limits and slight overflow
+  ; 2^31, < -2^31, max f32 < 2^31, -2^31
+; SSE2-LABEL: test_signed_edge2:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    movaps {{.*#+}} xmm1 = [2147483647,2147483647,2147483647,2147483647]
+; SSE2-NEXT:    cvttps2dq {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; SSE2-NEXT:    movss {{.*#+}} xmm0 = xmm1[0],xmm0[1,2,3]
+; SSE2-NEXT:    retq
+  %x = call <4 x i32> @llvm.fptosi.sat.v4i32.v4f32(<4 x float> <float 2147483648.0, float -2147483904.0, float 2147483520.0, float -2147483648.0>)
+  ret <4 x i32> %x
+}
+
+; 3. Unsigned edge cases
+define <4 x i32> @test_unsigned_edge1() {
+  ; NaN, -1.0, +Inf, 0.0
+; SSE2-LABEL: test_unsigned_edge1:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    xorps %xmm0, %xmm0
+; SSE2-NEXT:    movaps {{.*#+}} xmm1 = [NaN,-1.0E+0,+Inf,0.0E+0]
+; SSE2-NEXT:    maxps %xmm0, %xmm1
+; SSE2-NEXT:    cvttps2dq %xmm1, %xmm2
+; SSE2-NEXT:    movaps {{.*#+}} xmm0 = [4.2949673E+9,4.2949673E+9,4.2949673E+9,4.2949673E+9]
+; SSE2-NEXT:    cmpleps %xmm1, %xmm0
+; SSE2-NEXT:    orps %xmm2, %xmm0
+; SSE2-NEXT:    psrad $31, %xmm2
+; SSE2-NEXT:    subps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; SSE2-NEXT:    cvttps2dq %xmm1, %xmm1
+; SSE2-NEXT:    pand %xmm2, %xmm1
+; SSE2-NEXT:    orps %xmm1, %xmm0
+; SSE2-NEXT:    retq
+  %x = call <4 x i32> @llvm.fptoui.sat.v4i32.v4f32(<4 x float> <float 0x7FF8000000000000, float -1.0, float 0x7FF0000000000000, float 0.0>)
+  ret <4 x i32> %x
+}
+
+define <4 x i32> @test_unsigned_edge2() {
+  ; slight below zero, > 2^32, max f32 < 2^32, 2^32 exact
+; SSE2-LABEL: test_unsigned_edge2:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    xorps %xmm0, %xmm0
+; SSE2-NEXT:    movaps {{.*#+}} xmm1 = [-5.0E-1,4.2949673E+9,4.29496704E+9,4.2949673E+9]
+; SSE2-NEXT:    maxps %xmm0, %xmm1
+; SSE2-NEXT:    cvttps2dq %xmm1, %xmm2
+; SSE2-NEXT:    movaps {{.*#+}} xmm0 = [4.2949673E+9,4.2949673E+9,4.2949673E+9,4.2949673E+9]
+; SSE2-NEXT:    cmpleps %xmm1, %xmm0
+; SSE2-NEXT:    orps %xmm2, %xmm0
+; SSE2-NEXT:    psrad $31, %xmm2
+; SSE2-NEXT:    subps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; SSE2-NEXT:    cvttps2dq %xmm1, %xmm1
+; SSE2-NEXT:    pand %xmm2, %xmm1
+; SSE2-NEXT:    orps %xmm1, %xmm0
+; SSE2-NEXT:    retq
+  %x = call <4 x i32> @llvm.fptoui.sat.v4i32.v4f32(<4 x float> <float -0.5, float 4294967296.0, float 4294967040.0, float 4294967296.0>)
+  ret <4 x i32> %x
+}
diff --git a/llvm/test/CodeGen/X86/fpclamptosat_vec.ll b/llvm/test/CodeGen/X86/fpclamptosat_vec.ll
index 991ce33e58b4c..f8d7eece7c70c 100644
--- a/llvm/test/CodeGen/X86/fpclamptosat_vec.ll
+++ b/llvm/test/CodeGen/X86/fpclamptosat_vec.ll
@@ -227,106 +227,26 @@ entry:
 define <4 x i32> @stest_f32i32(<4 x float> %x) nounwind {
 ; SSE-LABEL: stest_f32i32:
 ; SSE:       # %bb.0: # %entry
-; SSE-NEXT:    movaps %xmm0, %xmm1
-; SSE-NEXT:    shufps {{.*#+}} xmm1 = xmm1[3,3],xmm0[3,3]
-; SSE-NEXT:    cvttss2si %xmm1, %rax
-; SSE-NEXT:    movq %rax, %xmm1
-; SSE-NEXT:    movaps %xmm0, %xmm2
-; SSE-NEXT:    unpckhpd {{.*#+}} xmm2 = xmm2[1],xmm0[1]
-; SSE-NEXT:    cvttss2si %xmm2, %rax
-; SSE-NEXT:    movq %rax, %xmm2
-; SSE-NEXT:    punpcklqdq {{.*#+}} xmm2 = xmm2[0],xmm1[0]
-; SSE-NEXT:    cvttss2si %xmm0, %rax
-; SSE-NEXT:    movq %rax, %xmm4
-; SSE-NEXT:    shufps {{.*#+}} xmm0 = xmm0[1,1,1,1]
-; SSE-NEXT:    cvttss2si %xmm0, %rax
-; SSE-NEXT:    movq %rax, %xmm0
-; SSE-NEXT:    punpcklqdq {{.*#+}} xmm4 = xmm4[0],xmm0[0]
-; SSE-NEXT:    movdqa {{.*#+}} xmm3 = [2147483647,2147483647]
-; SSE-NEXT:    movdqa {{.*#+}} xmm0 = [2147483648,2147483648]
-; SSE-NEXT:    movdqa %xmm4, %xmm1
-; SSE-NEXT:    pxor %xmm0, %xmm1
-; SSE-NEXT:    pshufd {{.*#+}} xmm5 = xmm1[1,1,3,3]
-; SSE-NEXT:    pxor %xmm6, %xmm6
-; SSE-NEXT:    pcmpeqd %xmm6, %xmm5
-; SSE-NEXT:    movdqa {{.*#+}} xmm7 = [4294967295,4294967295]
-; SSE-NEXT:    movdqa %xmm7, %xmm8
-; SSE-NEXT:    pcmpgtd %xmm1, %xmm8
-; SSE-NEXT:    pshufd {{.*#+}} xmm9 = xmm8[0,0,2,2]
-; SSE-NEXT:    pand %xmm5, %xmm9
-; SSE-NEXT:    pshufd {{.*#+}} xmm1 = xmm8[1,1,3,3]
-; SSE-NEXT:    por %xmm9, %xmm1
-; SSE-NEXT:    pand %xmm1, %xmm4
-; SSE-NEXT:    pandn %xmm3, %xmm1
-; SSE-NEXT:    por %xmm4, %xmm1
-; SSE-NEXT:    movdqa %xmm2, %xmm4
-; SSE-NEXT:    pxor %xmm0, %xmm4
-; SSE-NEXT:    pshufd {{.*#+}} xmm5 = xmm4[1,1,3,3]
-; SSE-NEXT:    pcmpeqd %xmm6, %xmm5
-; SSE-NEXT:    pcmpgtd %xmm4, %xmm7
-; SSE-NEXT:    pshufd {{.*#+}} xmm4 = xmm7[0,0,2,2]
-; SSE-NEXT:    pand %xmm5, %xmm4
-; SSE-NEXT:    pshufd {{.*#+}} xmm5 = xmm7[1,1,3,3]
-; SSE-NEXT:    por %xmm4, %xmm5
-; SSE-NEXT:    pand %xmm5, %xmm2
-; SSE-NEXT:    pandn %xmm3, %xmm5
-; SSE-NEXT:    por %xmm2, %xmm5
-; SSE-NEXT:    movdqa {{.*#+}} xmm2 = [18446744071562067968,18446744071562067968]
-; SSE-NEXT:    movdqa %xmm5, %xmm3
-; SSE-NEXT:    pxor %xmm0, %xmm3
-; SSE-NEXT:    pshufd {{.*#+}} xmm4 = xmm3[1,1,3,3]
-; SSE-NEXT:    pcmpeqd %xmm6, %xmm6
-; SSE-NEXT:    pcmpeqd %xmm6, %xmm4
-; SSE-NEXT:    movdqa {{.*#+}} xmm7 = [18446744069414584320,18446744069414584320]
-; SSE-NEXT:    pcmpgtd %xmm7, %xmm3
-; SSE-NEXT:    pshufd {{.*#+}} xmm8 = xmm3[0,0,2,2]
-; SSE-NEXT:    pand %xmm4, %xmm8
-; SSE-NEXT:    pshufd {{.*#+}} xmm3 = xmm3[1,1,3,3]
-; SSE-NEXT:    por %xmm8, %xmm3
-; SSE-NEXT:    pand %xmm3, %xmm5
-; SSE-NEXT:    pandn %xmm2, %xmm3
-; SSE-NEXT:    por %xmm5, %xmm3
-; SSE-NEXT:    pxor %xmm1, %xmm0
-; SSE-NEXT:    pshufd {{.*#+}} xmm4 = xmm0[1,1,3,3]
-; SSE-NEXT:    pcmpeqd %xmm6, %xmm4
-; SSE-NEXT:    pcmpgtd %xmm7, %xmm0
-; SSE-NEXT:    pshufd {{.*#+}} xmm5 = xmm0[0,0,2,2]
-; SSE-NEXT:    pand %xmm4, %xmm5
-; SSE-NEXT:    pshufd {{.*#+}} xmm0 = xmm0[1,1,3,3]
-; SSE-NEXT:    por %xmm5, %xmm0
-; SSE-NEXT:    pand %xmm0, %xmm1
-; SSE-NEXT:    pandn %xmm2, %xmm0
-; SSE-NEXT:    por %xmm1, %xmm0
-; SSE-NEXT:    shufps {{.*#+}} xmm0 = xmm0[0,2],xmm3[0,2]
+; SSE-NEXT:    movaps {{.*#+}} xmm1 = [2.14748365E+9,2.14748365E+9,2.14748365E+9,2.14748365E+9]
+; SSE-NEXT:    cmpleps %xmm0, %xmm1
+; SSE-NEXT:    cvttps2dq %xmm0, %xmm2
+; SSE-NEXT:    movaps %xmm1, %xmm3
+; SSE-NEXT:    andnps %xmm2, %xmm3
+; SSE-NEXT:    andps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; SSE-NEXT:    orps %xmm3, %xmm1
+; SSE-NEXT:    cmpunordps %xmm0, %xmm0
+; SSE-NEXT:    andnps %xmm1, %xmm0
 ; SSE-NEXT:    retq
 ;
 ; AVX2-LABEL: stest_f32i32:
 ; AVX2:       # %bb.0: # %entry
-; AVX2-NEXT:    vshufps {{.*#+}} xmm1 = xmm0[3,3,3,3]
-; AVX2-NEXT:    vcvttss2si %xmm1, %rax
-; AVX2-NEXT:    vmovq %rax, %xmm1
-; AVX2-NEXT:    vshufpd {{.*#+}} xmm2 = xmm0[1,0]
-; AVX2-NEXT:    vcvttss2si %xmm2, %rax
-; AVX2-NEXT:    vmovq %rax, %xmm2
-; AVX2-NEXT:    vpunpcklqdq {{.*#+}} xmm1 = xmm2[0],xmm1[0]
-; AVX2-NEXT:    vcvttss2si %xmm0, %rax
-; AVX2-NEXT:    vmovq %rax, %xmm2
-; AVX2-NEXT:    vmovshdup {{.*#+}} xmm0 = xmm0[1,1,3,3]
-; AVX2-NEXT:    vcvttss2si %xmm0, %rax
-; AVX2-NEXT:    vmovq %rax, %xmm0
-; AVX2-NEXT:    vpunpcklqdq {{.*#+}} xmm0 = xmm2[0],xmm0[0]
-; AVX2-NEXT:    vinserti128 $1, %xmm1, %ymm0, %ymm0
-; AVX2-NEXT:    vpbroadcastq {{.*#+}} ymm1 = [2147483647,2147483647,2147483647,2147483647]
-; AVX2-NEXT:    vpcmpgtq %ymm0, %ymm1, %ymm2
-; AVX2-NEXT:    vblendvpd %ymm2, %ymm0, %ymm1, %ymm0
-; AVX2-NEXT:    vpbroadcastq {{.*#+}} ymm1 = [18446744071562067968,18446744071562067968,18446744071562067968,18446744071562067968]
-; AVX2-NEXT:    vpcmpgtq %ymm1, %ymm0, %ymm2
-; AVX2-NEXT:    vblendvpd %ymm2, %ymm0, %ymm1, %ymm0
-; AVX2-NEXT:    vbroadcastf128 {{.*#+}} ymm1 = [0,2,4,6,0,2,4,6]
-; AVX2-NEXT:    # ymm1 = mem[0,1,0,1]
-; AVX2-NEXT:    vpermps %ymm0, %ymm1, %ymm0
-; AVX2-NEXT:    # kill: def $xmm0 killed $xmm0 killed $ymm0
-; AVX2-NEXT:    vzeroupper
+; AVX2-NEXT:    vbroadcastss {{.*#+}} xmm1 = [2.14748365E+9,2.14748365E+9,2.14748365E+9,2.14748365E+9]
+; AVX2-NEXT:    vcmpleps %xmm0, %xmm1, %xmm1
+; AVX2-NEXT:    vcvttps2dq %xmm0, %xmm2
+; AVX2-NEXT:    vbroadcastss {{.*#+}} xmm3 = [2147483647,2147483647,2147483647,2147483647]
+; AVX2-NEXT:    vblendvps %xmm1, %xmm3, %xmm2, %xmm1
+; AVX2-NEXT:    vcmpunordps %xmm0, %xmm0, %xmm0
+; AVX2-NEXT:    vandnps %xmm1, %xmm0, %xmm0
 ; AVX2-NEXT:    retq
 ;
 ; AVX512-LABEL: stest_f32i32:
@@ -604,130 +524,121 @@ entry:
 define <4 x i32> @stest_f16i32(<4 x half> %x) nounwind {
 ; SSE-LABEL: stest_f16i32:
 ; SSE:       # %bb.0: # %entry
-; SSE-NEXT:    subq $72, %rsp
-; SSE-NEXT:    movdqa %xmm0, (%rsp) # 16-byte Spill
+; SSE-NEXT:    pushq %rbp
+; SSE-NEXT:    pushq %r14
+; SSE-NEXT:    pushq %rbx
+; SSE-NEXT:    subq $64, %rsp
+; SSE-NEXT:    movdqa %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
 ; SSE-NEXT:    movdqa %xmm0, %xmm1
 ; SSE-NEXT:    psrld $16, %xmm1
 ; SSE-NEXT:    movdqa %xmm1, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
 ; SSE-NEXT:    movdqa %xmm0, %xmm1
 ; SSE-NEXT:    shufps {{.*#+}} xmm1 = xmm1[1,1],xmm0[1,1]
-; SSE-NEXT:    movaps %xmm1, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
+; SSE-NEXT:    movaps %xmm1, (%rsp) # 16-byte Spill
 ; SSE-NEXT:    psrlq $48, %xmm0
 ; SSE-NEXT:    callq __extendhfsf2 at PLT
-; SSE-NEXT:    cvttss2si %xmm0, %rax
-; SSE-NEXT:    movq %rax, %xmm0
-; SSE-NEXT:    movdqa %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
-; SSE-NEXT:    movaps {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Reload
-; SSE-NEXT:    callq __extendhfsf2 at PLT
-; SSE-NEXT:    cvttss2si %xmm0, %rax
-; SSE-NEXT:    movq %rax, %xmm0
-; SSE-NEXT:    punpcklqdq {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Folded Reload
-; SSE-NEXT:    # xmm0 = xmm0[0],mem[0]
+; SSE-NEXT:    cvttss2si %xmm0, %eax
+; SSE-NEXT:    ucomiss {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; SSE-NEXT:    movl $-2147483648, %ebx # imm = 0x80000000
+; SSE-NEXT:    cmovbl %ebx, %eax
+; SSE-NEXT:    ucomiss {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; SSE-NEXT:    movl $2147483647, %ebp # imm = 0x7FFFFFFF
+; SSE-NEXT:    cmoval %ebp, %eax
+; SSE-NEXT:    xorl %r14d, %r14d
+; SSE-NEXT:    ucomiss %xmm0, %xmm0
+; SSE-NEXT:    cmovpl %r14d, %eax
+; SSE-NEXT:    movd %eax, %xmm0
 ; SSE-NEXT:    movdqa %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
 ; SSE-NEXT:    movaps (%rsp), %xmm0 # 16-byte Reload
 ; SSE-NEXT:    callq __extendhfsf2 at PLT
-; SSE-NEXT:    cvttss2si %xmm0, %rax
-; SSE-NEXT:    movq %rax, %xmm0
+; SSE-NEXT:    cvttss2si %xmm0, %eax
+; SSE-NEXT:    ucomiss {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; SSE-NEXT:    cmovbl %ebx, %eax
+; SSE-NEXT:    ucomiss {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; SSE-NEXT:    cmoval %ebp, %eax
+; SSE-NEXT:    ucomiss %xmm0, %xmm0
+; SSE-NEXT:    cmovpl %r14d, %eax
+; SSE-NEXT:    movd %eax, %xmm0
+; SSE-NEXT:    punpckldq {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Folded Reload
+; SSE-NEXT:    # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
 ; SSE-NEXT:    movdqa %xmm0, (%rsp) # 16-byte Spill
 ; SSE-NEXT:    movaps {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 16-byte Reload
 ; SSE-NEXT:    callq __extendhfsf2 at PLT
-; SSE-NEXT:    cvttss2si %xmm0, %rax
-; SSE-NEXT:    movq %rax, %xmm0
-; SSE-NEXT:    movdqa (%rsp), %xmm3 # 16-byte Reload
-; SSE-NEXT:    punpcklqdq {{.*#+}} xmm3 = xmm3[0],xmm0[0]
-; SSE-NEXT:    movdqa {{.*#+}} xmm2 = [2147483647,2147483647]
-; SSE-NEXT:    movdqa {{.*#+}} xmm0 = [2147483648,2147483648]
-; SSE-NEXT:    movdqa %xmm3, %xmm1
-; SSE-NEXT:    movdqa %xmm3, %xmm8
-; SSE-NEXT:    pxor %xmm0, %xmm1
-; SSE-NEXT:    pshufd {{.*#+}} xmm3 = xmm1[1,1,3,3]
-; SSE-NEXT:    pxor %xmm4, %xmm4
-; SSE-NEXT:    pcmpeqd %xmm4, %xmm3
-; SSE-NEXT:    movdqa {{.*#+}} xmm5 = [4294967295,4294967295]
-; SSE-NEXT:    movdqa %xmm5, %xmm6
-; SSE-NEXT:    pcmpgtd %xmm1, %xmm6
-; SSE-NEXT:    pshufd {{.*#+}} xmm7 = xmm6[0,0,2,2]
-; SSE-NEXT:    pand %xmm3, %xmm7
-; SSE-NEXT:    pshufd {{.*#+}} xmm1 = xmm6[1,1,3,3]
-; SSE-NEXT:    por %xmm7, %xmm1
-; SSE-NEXT:    pand %xmm1, %xmm8
-; SSE-NEXT:    pandn %xmm2, %xmm1
-; SSE-NEXT:    por %xmm8, %xmm1
-; SSE-NEXT:    movdqa {{[-0-9]+}}(%r{{[sb]}}p), %xmm7 # 16-byte Reload
-; SSE-NEXT:    movdqa %xmm7, %xmm3
-; SSE-NEXT:    pxor %xmm0, %xmm3
-; SSE-NEXT:    pshufd {{.*#+}} xmm6 = xmm3[1,1,3,3]
-; SSE-NEXT:    pcmpeqd %xmm4, %xmm6
-; SSE-NEXT:    pcmpgtd %xmm3, %xmm5
-; SSE-NEXT:    pshufd {{.*#+}} xmm3 = xmm5[0,0,2,2]
-; SSE-NEXT:    pand %xmm6, %xmm3
-; SSE-NEXT:    pshufd {{.*#+}} xmm4 = xmm5[1,1,3,3]
-; SSE-NEXT:    por %xmm3, %xmm4
-; SSE-NEXT:    movdqa %xmm7, %xmm3
-; SSE-NEXT:    pand %xmm4, %xmm3
-; SSE-NEXT:    pandn %xmm2, %xmm4
-; SSE-NEXT:    por %xmm3, %xmm4
-; SSE-NEXT:    movdqa {{.*#+}} xmm2 = [18446744071562067968,18446744071562067968]
-; SSE-NEXT:    movdqa %xmm4, %xmm3
-; SSE-NEXT:    pxor %xmm0, %xmm3
-; SSE-NEXT:    pshufd {{.*#+}} xmm5 = xmm3[1,1,3,3]
-; SSE-NEXT:    pcmpeqd %xmm6, %xmm6
-; SSE-NEXT:    pcmpeqd %xmm6, %xmm5
-; SSE-NEXT:    movdqa {{.*#+}} xmm7 = [18446744069414584320,18446744069414584320]
-; SSE-NEXT:    pcmpgtd %xmm7, %xmm3
-; SSE-NEXT:    pshufd {{.*#+}} xmm8 = xmm3[0,0,2,2]
-; SSE-NEXT:    pand %xmm5, %xmm8
-; SSE-NEXT:    pshufd {{.*#+}} xmm3 = xmm3[1,1,3,3]
-; SSE-NEXT:    por %xmm8, %xmm3
-; SSE-NEXT:    pand %xmm3, %xmm4
-; SSE-NEXT:    pandn %xmm2, %xmm3
-; SSE-NEXT:    por %xmm4, %xmm3
-; SSE-NEXT:    pxor %xmm1, %xmm0
-; SSE-NEXT:    pshufd {{.*#+}} xmm4 = xmm0[1,1,3,3]
-; SSE-NEXT:    pcmpeqd %xmm6, %xmm4
-; SS...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/199416


More information about the llvm-commits mailing list