[llvm] [AMDGPU] Use `v_cvt_pk_*` instructions for i16_f32 saturated conversions (PR #202680)

Igor Wodiany via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 12 03:40:04 PDT 2026


https://github.com/IgWod updated https://github.com/llvm/llvm-project/pull/202680

>From 457ceae5e06934ac2af881bcf2cf3f5de78f8f30 Mon Sep 17 00:00:00 2001
From: Igor Wodiany <igor.wodiany at amd.com>
Date: Thu, 9 Apr 2026 13:07:14 +0100
Subject: [PATCH 1/3] [AMDGPU] Use v_cvt_pk_* instructions for saturated
 conversions

---
 llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp |   3 +
 .../lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp |   8 +-
 .../AMDGPU/AMDGPURegBankLegalizeRules.cpp     |   7 +-
 llvm/lib/Target/AMDGPU/SOPInstructions.td     |  15 +
 llvm/lib/Target/AMDGPU/VOP3PInstructions.td   |  46 ++
 llvm/test/CodeGen/AMDGPU/fptosi-sat-scalar.ll |  96 ++--
 llvm/test/CodeGen/AMDGPU/fptosi-sat-vector.ll | 418 ++++++++++++------
 llvm/test/CodeGen/AMDGPU/fptoui-sat-scalar.ll |  45 +-
 llvm/test/CodeGen/AMDGPU/fptoui-sat-vector.ll | 356 +++++++++++----
 9 files changed, 696 insertions(+), 298 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
index 78fcd0fd24b6f..9a64e1e6365ac 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
@@ -3949,6 +3949,9 @@ SDValue AMDGPUTargetLowering::LowerFP_TO_INT_SAT(const SDValue Op,
   if (DstVT == MVT::i16 && SatWidth == DstWidth && SrcVT == MVT::f16)
     return Op;
 
+  if (DstVT == MVT::i16 && SatWidth == 16 && SrcVT == MVT::f32)
+    return Op;
+
   // Perform all saturation at selected width (i16 or i32) and truncate
   if (SatWidth < DstWidth && SatWidth <= 32) {
     // For f16 conversion with sub-i16 saturation perform saturation
diff --git a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
index e341392ae068a..b4461f2e990a2 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
@@ -1210,14 +1210,18 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
 
   // clang-format off
   auto &FPToISat = getActionDefinitionsBuilder({G_FPTOSI_SAT, G_FPTOUI_SAT})
-    .legalFor({{S32, S32}, {S32, S64}})
-    .legalFor(ST.has16BitInsts(),{{S16, S16}})
+    .legalFor({{S32, S32}, {S32, S64}, {S16, S32}})
+    .legalFor(ST.has16BitInsts(), {{S16, S16}})
+    .legalFor(ST.hasGFX11Insts(), {{V2S16, V2S32}})
     .narrowScalarFor({{S64, S16}}, changeTo(0, S32));
 
   // If available, widen width <16 to i16, intead of i32 so v_cvt_i16/u16_f16 can be used.
   if (ST.has16BitInsts())
     FPToISat.minScalarIf(typeIs(1, S16), 0, S16);
 
+  if (ST.hasGFX11Insts())
+    FPToISat.clampMaxNumElements(0, S16, 2);
+
   FPToISat.minScalar(1, S32);
   FPToISat.minScalar(0, S32)
        .widenScalarToNextPow2(0, 32)
diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
index 60eb33b64fc0d..33f40df05ba44 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
@@ -1502,11 +1502,16 @@ RegBankLegalizeRules::RegBankLegalizeRules(const GCNSubtarget &_ST,
       .Any({{UniS32, S16}, {{Sgpr32}, {Sgpr16}}}, hasSALUFloat)
       .Any({{UniS32, S16}, {{UniInVgprS32}, {Vgpr16}}}, !hasSALUFloat)
       .Any({{DivS32, S16}, {{Vgpr32}, {Vgpr16}}})
+      .Any({{UniS16, S32}, {{Sgpr16}, {Sgpr32}}}, hasSALUFloat)
+      .Any({{UniS16, S32}, {{UniInVgprS16}, {Vgpr32}}}, !hasSALUFloat)
+      .Any({{DivS16, S32}, {{Vgpr16}, {Vgpr32}}})
       .Any({{UniS32, S32}, {{Sgpr32}, {Sgpr32}}}, hasSALUFloat)
       .Any({{UniS32, S32}, {{UniInVgprS32}, {Vgpr32}}}, !hasSALUFloat)
       .Any({{DivS32, S32}, {{Vgpr32}, {Vgpr32}}})
       .Any({{UniS32, S64}, {{UniInVgprS32}, {Vgpr64}}})
-      .Any({{DivS32, S64}, {{Vgpr32}, {Vgpr64}}});
+      .Any({{DivS32, S64}, {{Vgpr32}, {Vgpr64}}})
+      .Any({{UniV2S16, V2S32}, {{UniInVgprV2S16}, {SgprV2S32}}})
+      .Any({{DivV2S16, V2S32}, {{VgprV2S16}, {VgprV2S32}}});
 
   addRulesForGOpcs({G_UITOFP, G_SITOFP})
       .Any({{UniS16, S16}, {{UniInVgprS16}, {Vgpr16}}})
diff --git a/llvm/lib/Target/AMDGPU/SOPInstructions.td b/llvm/lib/Target/AMDGPU/SOPInstructions.td
index ef4333ef055cd..a486bf7df52c7 100644
--- a/llvm/lib/Target/AMDGPU/SOPInstructions.td
+++ b/llvm/lib/Target/AMDGPU/SOPInstructions.td
@@ -724,6 +724,21 @@ def S_MAX_U32 : SOP2_32 <"s_max_u32",
 } // End isCommutable = 1
 } // End Defs = [SCC]
 
+// f32 -> i16 saturated conversions. Required because those conversions
+// are kept legal for the V_CVT_PK_[IU]16_F32 packed patterns.
+class SOP_FPToUSatPat<dag lhs, int hi> : GCNPat<
+  lhs, (S_MIN_U32 (S_CVT_U32_F32 (f32 $src0)), (i32 hi))>;
+class SOP_FPToSSatPat<dag lhs, int hi, int lo> : GCNPat<
+  lhs, (S_MAX_I32 (S_MIN_I32 (S_CVT_I32_F32 (f32 $src0)), (i32 hi)),
+                  (i32 lo))>;
+
+let SubtargetPredicate = HasSALUFloatInsts, AddedComplexity = 9 in {
+  def : SOP_FPToUSatPat<(i16 (UniformBinFrag<fp_to_uint_sat> f32:$src0, i16)),
+                       0xffff>;
+  def : SOP_FPToSSatPat<(i16 (UniformBinFrag<fp_to_sint_sat> f32:$src0, i16)),
+                       0x7fff, 0xffff8000>;
+}
+
 let SubtargetPredicate = isGFX12Plus in {
   def S_ADD_U64 : SOP2_64<"s_add_u64">{
     let isCommutable = 1;
diff --git a/llvm/lib/Target/AMDGPU/VOP3PInstructions.td b/llvm/lib/Target/AMDGPU/VOP3PInstructions.td
index 5371d7fce8812..5718eb503d5c8 100644
--- a/llvm/lib/Target/AMDGPU/VOP3PInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VOP3PInstructions.td
@@ -3139,3 +3139,49 @@ defm V_DOT8_U32_U4  : VOP3P_Real_gfx10_gfx11_gfx12_gfx13<0x19>;
 
 defm V_DOT4_I32_I8  : VOP3P_Real_gfx10 <0x16>;
 defm V_DOT8_I32_I4  : VOP3P_Real_gfx10 <0x18>;
+
+//===----------------------------------------------------------------------===//
+// GFX11+ Patterns
+//===----------------------------------------------------------------------===//
+
+// Packed f32 -> i16 saturated conversion.
+multiclass CvtPkF32ToI16Pat<SDPatternOperator dagOp, Instruction inst> {
+  def : GCNPat<(v2i16 (build_vector
+                  (i16 (dagOp (f32 (VOP3Mods f32:$src0, i32:$src0_modifiers)), i16)),
+                  (i16 (dagOp (f32 (VOP3Mods f32:$src1, i32:$src1_modifiers)), i16)))),
+               (inst $src0_modifiers, $src0, $src1_modifiers, $src1)>;
+  def : GCNPat<(v2i16 (dagOp (v2f32 VReg_64:$src), i16)),
+               (inst 0, (EXTRACT_SUBREG VReg_64:$src, sub0),
+                     0, (EXTRACT_SUBREG VReg_64:$src, sub1))>;
+  def : GCNPat<(v2i16 (dagOp (v2f32 SReg_64:$src), i16)),
+               (inst 0, (EXTRACT_SUBREG SReg_64:$src, sub0),
+                     0, (EXTRACT_SUBREG SReg_64:$src, sub1))>;
+}
+
+multiclass FPToIntSatI16Pat<dag lhs, dag rhs> {
+  let True16Predicate = UseRealTrue16Insts in
+    def : GCNPat<lhs, (EXTRACT_SUBREG rhs, lo16)>;
+  let True16Predicate = NotUseRealTrue16Insts in
+    def : GCNPat<lhs, rhs>;
+}
+
+multiclass FPToSSatI16Pat<dag lhs, int hi, int lo> {
+  defm : FPToIntSatI16Pat<lhs,
+      (V_MED3_I32_e64 (V_CVT_I32_F32_e64 $src0_modifiers, $src0),
+                      (V_MOV_B32_e32 (i32 lo)), (S_MOV_B32 (i32 hi)))>;
+}
+multiclass FPToUSatI16Pat<dag lhs, int hi> {
+  defm : FPToIntSatI16Pat<lhs,
+      (V_MIN_U32_e64 (V_CVT_U32_F32_e64 $src0_modifiers, $src0), (i32 hi))>;
+}
+
+let SubtargetPredicate = isGFX11Plus in {
+  // f32 -> i16 saturated conversion.
+  defm : CvtPkF32ToI16Pat<fp_to_sint_sat, V_CVT_PK_I16_F32_e64>;
+  defm : CvtPkF32ToI16Pat<fp_to_uint_sat, V_CVT_PK_U16_F32_e64>;
+}
+
+// Fallback for f32 -> i16 saturated conversion. Required because
+// f32 -> i16 has to be legal so that the packed pattern above can match.
+defm : FPToSSatI16Pat<(i16 (fp_to_sint_sat (f32 (VOP3Mods f32:$src0, i32:$src0_modifiers)), i16)), 0x7fff, 0x8000>;
+defm : FPToUSatI16Pat<(i16 (fp_to_uint_sat (f32 (VOP3Mods f32:$src0, i32:$src0_modifiers)), i16)), 0xffff>;
diff --git a/llvm/test/CodeGen/AMDGPU/fptosi-sat-scalar.ll b/llvm/test/CodeGen/AMDGPU/fptosi-sat-scalar.ll
index 92cad3f0f4bf3..c75f36e7df7d4 100644
--- a/llvm/test/CodeGen/AMDGPU/fptosi-sat-scalar.ll
+++ b/llvm/test/CodeGen/AMDGPU/fptosi-sat-scalar.ll
@@ -132,26 +132,26 @@ define i16 @test_signed_i16_f32(float %f) nounwind {
 ; GFX7-GI:       ; %bb.0:
 ; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX7-GI-NEXT:    v_mov_b32_e32 v1, 0x7fff
-; GFX7-GI-NEXT:    v_mov_b32_e32 v2, 0xffff8000
-; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v2, v1
+; GFX7-GI-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX7-GI-NEXT:    v_mov_b32_e32 v1, 0x8000
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v1, s4
 ; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: test_signed_i16_f32:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX9-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX9-NEXT:    s_movk_i32 s4, 0x8000
-; GFX9-NEXT:    v_mov_b32_e32 v1, 0x7fff
-; GFX9-NEXT:    v_med3_i32 v0, v0, s4, v1
+; GFX9-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX9-NEXT:    v_mov_b32_e32 v1, 0x8000
+; GFX9-NEXT:    v_med3_i32 v0, v0, v1, s4
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX11-LABEL: test_signed_i16_f32:
 ; GFX11:       ; %bb.0:
 ; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX11-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX11-NEXT:    s_movk_i32 s0, 0x8000
-; GFX11-NEXT:    v_med3_i32 v0, v0, s0, 0x7fff
+; GFX11-NEXT:    v_mov_b32_e32 v1, 0x8000
+; GFX11-NEXT:    v_med3_i32 v0, v0, v1, 0x7fff
 ; GFX11-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX12-ISEL-LABEL: test_signed_i16_f32:
@@ -162,9 +162,8 @@ define i16 @test_signed_i16_f32(float %f) nounwind {
 ; GFX12-ISEL-NEXT:    s_wait_bvhcnt 0x0
 ; GFX12-ISEL-NEXT:    s_wait_kmcnt 0x0
 ; GFX12-ISEL-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX12-ISEL-NEXT:    s_movk_i32 s0, 0x8000
-; GFX12-ISEL-NEXT:    s_wait_alu depctr_sa_sdst(0)
-; GFX12-ISEL-NEXT:    v_med3_i32 v0, v0, s0, 0x7fff
+; GFX12-ISEL-NEXT:    v_mov_b32_e32 v1, 0x8000
+; GFX12-ISEL-NEXT:    v_med3_i32 v0, v0, v1, 0x7fff
 ; GFX12-ISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX12-GI-LABEL: test_signed_i16_f32:
@@ -174,8 +173,8 @@ define i16 @test_signed_i16_f32(float %f) nounwind {
 ; GFX12-GI-NEXT:    s_wait_samplecnt 0x0
 ; GFX12-GI-NEXT:    s_wait_bvhcnt 0x0
 ; GFX12-GI-NEXT:    s_wait_kmcnt 0x0
+; GFX12-GI-NEXT:    v_mov_b32_e32 v1, 0x8000
 ; GFX12-GI-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX12-GI-NEXT:    v_mov_b32_e32 v1, 0xffff8000
 ; GFX12-GI-NEXT:    v_med3_i32 v0, v0, v1, 0x7fff
 ; GFX12-GI-NEXT:    s_setpc_b64 s[30:31]
     %x = call i16 @llvm.fptosi.sat.i16.f32(float %f)
@@ -548,57 +547,43 @@ define i16 @test_s_signed_i16_f32(float inreg %f) nounwind {
 ; GFX7-GI:       ; %bb.0:
 ; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, s16
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s4, v0
-; GFX7-GI-NEXT:    s_min_i32 s4, s4, 0x7fff
-; GFX7-GI-NEXT:    s_max_i32 s4, s4, 0xffff8000
-; GFX7-GI-NEXT:    v_mov_b32_e32 v0, s4
+; GFX7-GI-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX7-GI-NEXT:    v_mov_b32_e32 v1, 0x8000
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v1, s4
 ; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: test_s_signed_i16_f32:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX9-NEXT:    v_cvt_i32_f32_e32 v0, s16
-; GFX9-NEXT:    s_movk_i32 s4, 0x8000
-; GFX9-NEXT:    v_mov_b32_e32 v1, 0x7fff
-; GFX9-NEXT:    v_med3_i32 v0, v0, s4, v1
+; GFX9-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX9-NEXT:    v_mov_b32_e32 v1, 0x8000
+; GFX9-NEXT:    v_med3_i32 v0, v0, v1, s4
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX11-LABEL: test_s_signed_i16_f32:
 ; GFX11:       ; %bb.0:
 ; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX11-NEXT:    v_cvt_i32_f32_e32 v0, s0
-; GFX11-NEXT:    s_movk_i32 s0, 0x8000
-; GFX11-NEXT:    v_med3_i32 v0, v0, s0, 0x7fff
+; GFX11-NEXT:    v_mov_b32_e32 v1, 0x8000
+; GFX11-NEXT:    v_med3_i32 v0, v0, v1, 0x7fff
 ; GFX11-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX12-ISEL-LABEL: test_s_signed_i16_f32:
-; GFX12-ISEL:       ; %bb.0:
-; GFX12-ISEL-NEXT:    s_wait_loadcnt_dscnt 0x0
-; GFX12-ISEL-NEXT:    s_wait_expcnt 0x0
-; GFX12-ISEL-NEXT:    s_wait_samplecnt 0x0
-; GFX12-ISEL-NEXT:    s_wait_bvhcnt 0x0
-; GFX12-ISEL-NEXT:    s_wait_kmcnt 0x0
-; GFX12-ISEL-NEXT:    v_mov_b32_e32 v0, 0x7fff
-; GFX12-ISEL-NEXT:    s_cvt_i32_f32 s0, s0
-; GFX12-ISEL-NEXT:    s_wait_alu depctr_sa_sdst(0)
-; GFX12-ISEL-NEXT:    v_med3_i32 v0, 0xffff8000, s0, v0
-; GFX12-ISEL-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX12-GI-LABEL: test_s_signed_i16_f32:
-; GFX12-GI:       ; %bb.0:
-; GFX12-GI-NEXT:    s_wait_loadcnt_dscnt 0x0
-; GFX12-GI-NEXT:    s_wait_expcnt 0x0
-; GFX12-GI-NEXT:    s_wait_samplecnt 0x0
-; GFX12-GI-NEXT:    s_wait_bvhcnt 0x0
-; GFX12-GI-NEXT:    s_wait_kmcnt 0x0
-; GFX12-GI-NEXT:    s_cvt_i32_f32 s0, s0
-; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
-; GFX12-GI-NEXT:    s_min_i32 s0, s0, 0x7fff
-; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
-; GFX12-GI-NEXT:    s_max_i32 s0, s0, 0xffff8000
-; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
-; GFX12-GI-NEXT:    v_mov_b32_e32 v0, s0
-; GFX12-GI-NEXT:    s_setpc_b64 s[30:31]
+; GFX12-LABEL: test_s_signed_i16_f32:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    s_cvt_i32_f32 s0, s0
+; GFX12-NEXT:    s_wait_alu depctr_sa_sdst(0)
+; GFX12-NEXT:    s_min_i32 s0, s0, 0x7fff
+; GFX12-NEXT:    s_wait_alu depctr_sa_sdst(0)
+; GFX12-NEXT:    s_max_i32 s0, s0, 0xffff8000
+; GFX12-NEXT:    s_wait_alu depctr_sa_sdst(0)
+; GFX12-NEXT:    v_mov_b32_e32 v0, s0
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
     %x = call i16 @llvm.fptosi.sat.i16.f32(float %f)
     ret i16 %x
 }
@@ -1845,10 +1830,10 @@ define i16 @test_signed_i16_f16(half %f) nounwind {
 ; GFX7-GI:       ; %bb.0:
 ; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, v0
-; GFX7-GI-NEXT:    v_mov_b32_e32 v1, 0x7fff
-; GFX7-GI-NEXT:    v_mov_b32_e32 v2, 0xffff8000
+; GFX7-GI-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX7-GI-NEXT:    v_mov_b32_e32 v1, 0x8000
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v2, v1
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v1, s4
 ; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: test_signed_i16_f16:
@@ -2254,11 +2239,10 @@ define i16 @test_s_signed_i16_f16(half inreg %f) nounwind {
 ; GFX7-GI:       ; %bb.0:
 ; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s16
+; GFX7-GI-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX7-GI-NEXT:    v_mov_b32_e32 v1, 0x8000
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s4, v0
-; GFX7-GI-NEXT:    s_min_i32 s4, s4, 0x7fff
-; GFX7-GI-NEXT:    s_max_i32 s4, s4, 0xffff8000
-; GFX7-GI-NEXT:    v_mov_b32_e32 v0, s4
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v1, s4
 ; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: test_s_signed_i16_f16:
diff --git a/llvm/test/CodeGen/AMDGPU/fptosi-sat-vector.ll b/llvm/test/CodeGen/AMDGPU/fptosi-sat-vector.ll
index a893711ce0942..89e09d80f1134 100644
--- a/llvm/test/CodeGen/AMDGPU/fptosi-sat-vector.ll
+++ b/llvm/test/CodeGen/AMDGPU/fptosi-sat-vector.ll
@@ -2873,26 +2873,26 @@ define <4 x i16> @test_signed_v4f16_v4i16(<4 x half> %f) {
 ; GFX7-GI-LABEL: test_signed_v4f16_v4i16:
 ; GFX7-GI:       ; %bb.0:
 ; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v2, v0
-; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v0, 16, v0
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, v0
+; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v2, 16, v0
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v2, v2
 ; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v3, 16, v1
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, v0
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v3, v3
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, v1
-; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v0
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v2, v2
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v0
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v3, v3
-; GFX7-GI-NEXT:    v_mov_b32_e32 v4, 0x7fff
-; GFX7-GI-NEXT:    v_mov_b32_e32 v5, 0xffff8000
+; GFX7-GI-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX7-GI-NEXT:    v_mov_b32_e32 v4, 0x8000
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v1, v1
-; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v5, v4
-; GFX7-GI-NEXT:    v_med3_i32 v2, v2, v5, v4
-; GFX7-GI-NEXT:    v_and_b32_e32 v0, 0xffff, v0
-; GFX7-GI-NEXT:    v_med3_i32 v3, v3, v5, v4
+; GFX7-GI-NEXT:    v_med3_i32 v2, v2, v4, s4
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v4, s4
 ; GFX7-GI-NEXT:    v_and_b32_e32 v2, 0xffff, v2
-; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v0, 16, v0
-; GFX7-GI-NEXT:    v_med3_i32 v1, v1, v5, v4
-; GFX7-GI-NEXT:    v_or_b32_e32 v0, v2, v0
+; GFX7-GI-NEXT:    v_med3_i32 v3, v3, v4, s4
+; GFX7-GI-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v2, 16, v2
+; GFX7-GI-NEXT:    v_med3_i32 v1, v1, v4, s4
+; GFX7-GI-NEXT:    v_or_b32_e32 v0, v0, v2
 ; GFX7-GI-NEXT:    v_and_b32_e32 v2, 0xffff, v3
 ; GFX7-GI-NEXT:    v_and_b32_e32 v1, 0xffff, v1
 ; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v2, 16, v2
@@ -3778,37 +3778,35 @@ define <4 x i16> @test_s_signed_v4f16_v4i16(<4 x half> inreg %f) {
 ; GFX7-GI:       ; %bb.0:
 ; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s16
-; GFX7-GI-NEXT:    s_lshr_b32 s4, s16, 16
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, s4
-; GFX7-GI-NEXT:    s_lshr_b32 s4, s17, 16
+; GFX7-GI-NEXT:    s_lshr_b32 s5, s16, 16
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v2, s5
+; GFX7-GI-NEXT:    s_lshr_b32 s5, s17, 16
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v2, s17
-; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v1, v1
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v3, s17
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v4, s5
+; GFX7-GI-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX7-GI-NEXT:    v_mov_b32_e32 v1, 0x8000
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v1, s4
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v2, v2
 ; GFX7-GI-NEXT:    v_readfirstlane_b32 s5, v0
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s4
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s6, v1
-; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v1, v2
-; GFX7-GI-NEXT:    s_min_i32 s4, s6, 0x7fff
-; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX7-GI-NEXT:    s_min_i32 s5, s5, 0x7fff
-; GFX7-GI-NEXT:    s_max_i32 s4, s4, 0xffff8000
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s6, v1
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v3
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v3, v4
+; GFX7-GI-NEXT:    v_med3_i32 v2, v2, v1, s4
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s6, v2
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v1, s4
 ; GFX7-GI-NEXT:    v_readfirstlane_b32 s7, v0
-; GFX7-GI-NEXT:    s_max_i32 s5, s5, 0xffff8000
-; GFX7-GI-NEXT:    s_min_i32 s6, s6, 0x7fff
-; GFX7-GI-NEXT:    s_min_i32 s7, s7, 0x7fff
-; GFX7-GI-NEXT:    s_and_b32 s4, s4, 0xffff
-; GFX7-GI-NEXT:    s_max_i32 s6, s6, 0xffff8000
-; GFX7-GI-NEXT:    s_max_i32 s7, s7, 0xffff8000
-; GFX7-GI-NEXT:    s_and_b32 s5, s5, 0xffff
-; GFX7-GI-NEXT:    s_lshl_b32 s4, s4, 16
-; GFX7-GI-NEXT:    s_or_b32 s4, s5, s4
-; GFX7-GI-NEXT:    s_and_b32 s5, s6, 0xffff
-; GFX7-GI-NEXT:    s_and_b32 s6, s7, 0xffff
+; GFX7-GI-NEXT:    v_med3_i32 v0, v3, v1, s4
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s4, v0
+; GFX7-GI-NEXT:    s_and_b32 s6, 0xffff, s6
+; GFX7-GI-NEXT:    s_and_b32 s5, 0xffff, s5
 ; GFX7-GI-NEXT:    s_lshl_b32 s6, s6, 16
+; GFX7-GI-NEXT:    s_and_b32 s4, 0xffff, s4
 ; GFX7-GI-NEXT:    s_or_b32 s5, s5, s6
-; GFX7-GI-NEXT:    v_mov_b32_e32 v0, s4
-; GFX7-GI-NEXT:    v_mov_b32_e32 v1, s5
+; GFX7-GI-NEXT:    s_and_b32 s6, 0xffff, s7
+; GFX7-GI-NEXT:    s_lshl_b32 s4, s4, 16
+; GFX7-GI-NEXT:    s_or_b32 s4, s6, s4
+; GFX7-GI-NEXT:    v_mov_b32_e32 v0, s5
+; GFX7-GI-NEXT:    v_mov_b32_e32 v1, s4
 ; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: test_s_signed_v4f16_v4i16:
@@ -3896,12 +3894,12 @@ define <4 x i16> @test_s_signed_v4f16_v4i16(<4 x half> inreg %f) {
 ; GFX12-GI-NEXT:    s_wait_bvhcnt 0x0
 ; GFX12-GI-NEXT:    s_wait_kmcnt 0x0
 ; GFX12-GI-NEXT:    s_lshr_b32 s2, s0, 16
-; GFX12-GI-NEXT:    s_lshr_b32 s3, s1, 16
 ; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v0.l, s0
+; GFX12-GI-NEXT:    s_lshr_b32 s0, s1, 16
 ; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
 ; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v1.l, s2
 ; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v2.l, s1
-; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v3.l, s3
+; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v3.l, s0
 ; GFX12-GI-NEXT:    v_readfirstlane_b32 s0, v0
 ; GFX12-GI-NEXT:    v_readfirstlane_b32 s1, v1
 ; GFX12-GI-NEXT:    v_readfirstlane_b32 s2, v2
@@ -4697,8 +4695,8 @@ define <8 x i16> @test_signed_v8f16_v8i16(<8 x half> %f) {
 ; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v4, 16, v0
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v4, v4
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, v0
 ; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v5, 16, v1
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, v0
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v5, v5
 ; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v6, 16, v2
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, v1
@@ -4709,33 +4707,33 @@ define <8 x i16> @test_signed_v8f16_v8i16(<8 x half> %f) {
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v2, v2
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v5, v5
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v7, v7
-; GFX7-GI-NEXT:    v_mov_b32_e32 v8, 0x7fff
-; GFX7-GI-NEXT:    v_mov_b32_e32 v9, 0xffff8000
+; GFX7-GI-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX7-GI-NEXT:    v_mov_b32_e32 v8, 0x8000
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v1, v1
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v3, v3
-; GFX7-GI-NEXT:    v_med3_i32 v4, v4, v9, v8
+; GFX7-GI-NEXT:    v_med3_i32 v4, v4, v8, s4
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v6, v6
-; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v9, v8
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v8, s4
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v2, v2
 ; GFX7-GI-NEXT:    v_and_b32_e32 v4, 0xffff, v4
-; GFX7-GI-NEXT:    v_med3_i32 v5, v5, v9, v8
+; GFX7-GI-NEXT:    v_med3_i32 v5, v5, v8, s4
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v7, v7
 ; GFX7-GI-NEXT:    v_and_b32_e32 v0, 0xffff, v0
 ; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v4, 16, v4
-; GFX7-GI-NEXT:    v_med3_i32 v1, v1, v9, v8
+; GFX7-GI-NEXT:    v_med3_i32 v1, v1, v8, s4
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v3, v3
 ; GFX7-GI-NEXT:    v_or_b32_e32 v0, v0, v4
 ; GFX7-GI-NEXT:    v_and_b32_e32 v4, 0xffff, v5
-; GFX7-GI-NEXT:    v_med3_i32 v6, v6, v9, v8
+; GFX7-GI-NEXT:    v_med3_i32 v6, v6, v8, s4
 ; GFX7-GI-NEXT:    v_and_b32_e32 v1, 0xffff, v1
 ; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v4, 16, v4
-; GFX7-GI-NEXT:    v_med3_i32 v2, v2, v9, v8
+; GFX7-GI-NEXT:    v_med3_i32 v2, v2, v8, s4
 ; GFX7-GI-NEXT:    v_or_b32_e32 v1, v1, v4
 ; GFX7-GI-NEXT:    v_and_b32_e32 v4, 0xffff, v6
-; GFX7-GI-NEXT:    v_med3_i32 v7, v7, v9, v8
+; GFX7-GI-NEXT:    v_med3_i32 v7, v7, v8, s4
 ; GFX7-GI-NEXT:    v_and_b32_e32 v2, 0xffff, v2
 ; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v4, 16, v4
-; GFX7-GI-NEXT:    v_med3_i32 v3, v3, v9, v8
+; GFX7-GI-NEXT:    v_med3_i32 v3, v3, v8, s4
 ; GFX7-GI-NEXT:    v_or_b32_e32 v2, v2, v4
 ; GFX7-GI-NEXT:    v_and_b32_e32 v4, 0xffff, v7
 ; GFX7-GI-NEXT:    v_and_b32_e32 v3, 0xffff, v3
@@ -6244,70 +6242,64 @@ define <8 x i16> @test_s_signed_v8f16_v8i16(<8 x half> inreg %f) {
 ; GFX7-GI-LABEL: test_s_signed_v8f16_v8i16:
 ; GFX7-GI:       ; %bb.0:
 ; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s16
 ; GFX7-GI-NEXT:    s_lshr_b32 s4, s16, 16
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s16
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, s4
-; GFX7-GI-NEXT:    s_lshr_b32 s5, s17, 16
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v3, s17
+; GFX7-GI-NEXT:    s_movk_i32 s4, 0x7fff
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX7-GI-NEXT:    s_lshr_b32 s4, s18, 16
-; GFX7-GI-NEXT:    s_lshr_b32 s6, s19, 16
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s7, v0
-; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v1
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, s17
-; GFX7-GI-NEXT:    s_min_i32 s7, s7, 0x7fff
-; GFX7-GI-NEXT:    s_max_i32 s7, s7, 0xffff8000
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v1, v1
+; GFX7-GI-NEXT:    v_mov_b32_e32 v2, 0x8000
+; GFX7-GI-NEXT:    s_lshr_b32 s5, s17, 16
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v2, s4
 ; GFX7-GI-NEXT:    v_readfirstlane_b32 s8, v0
-; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v1
+; GFX7-GI-NEXT:    v_med3_i32 v0, v1, v2, s4
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, s5
-; GFX7-GI-NEXT:    s_min_i32 s5, s8, 0x7fff
-; GFX7-GI-NEXT:    s_max_i32 s5, s5, 0xffff8000
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s8, v0
-; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v1
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, s18
-; GFX7-GI-NEXT:    s_min_i32 s8, s8, 0x7fff
-; GFX7-GI-NEXT:    s_and_b32 s5, s5, 0xffff
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s9, v0
-; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v1
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, s4
-; GFX7-GI-NEXT:    s_min_i32 s4, s9, 0x7fff
-; GFX7-GI-NEXT:    s_max_i32 s4, s4, 0xffff8000
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s9, v0
-; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v1
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, s19
-; GFX7-GI-NEXT:    s_max_i32 s8, s8, 0xffff8000
-; GFX7-GI-NEXT:    s_min_i32 s9, s9, 0x7fff
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s10, v0
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s6
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v3, v3
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s5, v0
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s18
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v1, v1
-; GFX7-GI-NEXT:    s_min_i32 s6, s10, 0x7fff
-; GFX7-GI-NEXT:    s_max_i32 s6, s6, 0xffff8000
+; GFX7-GI-NEXT:    s_lshr_b32 s6, s18, 16
+; GFX7-GI-NEXT:    v_med3_i32 v3, v3, v2, s4
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s9, v3
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v3, s6
 ; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s10, v1
-; GFX7-GI-NEXT:    s_and_b32 s7, s7, 0xffff
+; GFX7-GI-NEXT:    v_med3_i32 v1, v1, v2, s4
+; GFX7-GI-NEXT:    s_lshr_b32 s7, s19, 16
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s6, v1
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, s19
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v3, v3
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v4, s7
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v2, s4
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s7, v0
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v1
+; GFX7-GI-NEXT:    v_med3_i32 v1, v3, v2, s4
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v3, v4
+; GFX7-GI-NEXT:    s_and_b32 s5, 0xffff, s5
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v2, s4
+; GFX7-GI-NEXT:    s_and_b32 s8, 0xffff, s8
 ; GFX7-GI-NEXT:    s_lshl_b32 s5, s5, 16
+; GFX7-GI-NEXT:    s_and_b32 s6, 0xffff, s6
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s10, v1
 ; GFX7-GI-NEXT:    v_readfirstlane_b32 s11, v0
-; GFX7-GI-NEXT:    s_min_i32 s11, s11, 0x7fff
-; GFX7-GI-NEXT:    s_and_b32 s4, s4, 0xffff
-; GFX7-GI-NEXT:    s_max_i32 s9, s9, 0xffff8000
-; GFX7-GI-NEXT:    s_min_i32 s10, s10, 0x7fff
-; GFX7-GI-NEXT:    s_max_i32 s11, s11, 0xffff8000
-; GFX7-GI-NEXT:    s_or_b32 s5, s7, s5
-; GFX7-GI-NEXT:    s_and_b32 s7, s8, 0xffff
-; GFX7-GI-NEXT:    s_lshl_b32 s4, s4, 16
-; GFX7-GI-NEXT:    s_and_b32 s6, s6, 0xffff
-; GFX7-GI-NEXT:    s_max_i32 s10, s10, 0xffff8000
-; GFX7-GI-NEXT:    s_or_b32 s4, s7, s4
-; GFX7-GI-NEXT:    s_and_b32 s7, s9, 0xffff
+; GFX7-GI-NEXT:    v_med3_i32 v0, v3, v2, s4
+; GFX7-GI-NEXT:    s_or_b32 s5, s8, s5
+; GFX7-GI-NEXT:    s_and_b32 s8, 0xffff, s9
 ; GFX7-GI-NEXT:    s_lshl_b32 s6, s6, 16
-; GFX7-GI-NEXT:    s_and_b32 s8, s11, 0xffff
-; GFX7-GI-NEXT:    s_or_b32 s6, s7, s6
-; GFX7-GI-NEXT:    s_and_b32 s7, s10, 0xffff
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s4, v0
+; GFX7-GI-NEXT:    s_or_b32 s6, s8, s6
+; GFX7-GI-NEXT:    s_and_b32 s8, 0xffff, s10
+; GFX7-GI-NEXT:    s_and_b32 s7, 0xffff, s7
 ; GFX7-GI-NEXT:    s_lshl_b32 s8, s8, 16
+; GFX7-GI-NEXT:    s_and_b32 s4, 0xffff, s4
 ; GFX7-GI-NEXT:    s_or_b32 s7, s7, s8
+; GFX7-GI-NEXT:    s_and_b32 s8, 0xffff, s11
+; GFX7-GI-NEXT:    s_lshl_b32 s4, s4, 16
+; GFX7-GI-NEXT:    s_or_b32 s4, s8, s4
 ; GFX7-GI-NEXT:    v_mov_b32_e32 v0, s5
-; GFX7-GI-NEXT:    v_mov_b32_e32 v1, s4
-; GFX7-GI-NEXT:    v_mov_b32_e32 v2, s6
-; GFX7-GI-NEXT:    v_mov_b32_e32 v3, s7
+; GFX7-GI-NEXT:    v_mov_b32_e32 v1, s6
+; GFX7-GI-NEXT:    v_mov_b32_e32 v2, s7
+; GFX7-GI-NEXT:    v_mov_b32_e32 v3, s4
 ; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: test_s_signed_v8f16_v8i16:
@@ -6439,36 +6431,37 @@ define <8 x i16> @test_s_signed_v8f16_v8i16(<8 x half> inreg %f) {
 ; GFX12-GI-NEXT:    s_wait_samplecnt 0x0
 ; GFX12-GI-NEXT:    s_wait_bvhcnt 0x0
 ; GFX12-GI-NEXT:    s_wait_kmcnt 0x0
-; GFX12-GI-NEXT:    s_lshr_b32 s4, s0, 16
 ; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v0.l, s0
+; GFX12-GI-NEXT:    s_lshr_b32 s4, s0, 16
+; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v2.l, s1
+; GFX12-GI-NEXT:    s_lshr_b32 s1, s1, 16
 ; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
 ; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v1.l, s4
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v0.l, s1
+; GFX12-GI-NEXT:    s_lshr_b32 s1, s2, 16
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s5, v2
+; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
 ; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v2.l, s1
-; GFX12-GI-NEXT:    s_lshr_b32 s5, s1, 16
-; GFX12-GI-NEXT:    s_lshr_b32 s0, s2, 16
 ; GFX12-GI-NEXT:    s_lshr_b32 s1, s3, 16
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s4, v0
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s6, v1
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s7, v2
-; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
-; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v0.l, s5
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s4, v1
 ; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v1.l, s2
-; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v2.l, s0
 ; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v3.l, s3
+; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
 ; GFX12-GI-NEXT:    v_cvt_i16_f16_e32 v4.l, s1
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s0, v0
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s1, v1
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s2, v2
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s3, v3
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s5, v4
-; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s4, s4, s6
-; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s0, s7, s0
-; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s1, s1, s2
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s1, v0
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s3, v2
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s2, v1
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s6, v3
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s7, v4
+; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s0, s0, s4
+; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s1, s5, s1
+; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s2, s2, s3
 ; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
-; GFX12-GI-NEXT:    v_dual_mov_b32 v0, s4 :: v_dual_mov_b32 v1, s0
-; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s2, s3, s5
+; GFX12-GI-NEXT:    v_dual_mov_b32 v0, s0 :: v_dual_mov_b32 v1, s1
+; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s3, s6, s7
 ; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
-; GFX12-GI-NEXT:    v_dual_mov_b32 v2, s1 :: v_dual_mov_b32 v3, s2
+; GFX12-GI-NEXT:    v_dual_mov_b32 v2, s2 :: v_dual_mov_b32 v3, s3
 ; GFX12-GI-NEXT:    s_setpc_b64 s[30:31]
     %x = call <8 x i16> @llvm.fptosi.sat.v8f16.v8i16(<8 x half> %f)
     ret <8 x i16> %x
@@ -6689,6 +6682,185 @@ define <8 x i64> @test_s_signed_v8f16_v8i64(<8 x half> inreg %f) {
     ret <8 x i64> %x
 }
 
+;
+; Float to signed 16-bit
+;
+
+define <4 x i16> @test_signed_v4f32_v4i16(<4 x float> %f) {
+; GFX7-ISEL-LABEL: test_signed_v4f32_v4i16:
+; GFX7-ISEL:       ; %bb.0:
+; GFX7-ISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-ISEL-NEXT:    v_cvt_i32_f32_e32 v1, v1
+; GFX7-ISEL-NEXT:    v_cvt_i32_f32_e32 v0, v0
+; GFX7-ISEL-NEXT:    v_cvt_i32_f32_e32 v3, v3
+; GFX7-ISEL-NEXT:    v_cvt_i32_f32_e32 v2, v2
+; GFX7-ISEL-NEXT:    s_movk_i32 s4, 0x8000
+; GFX7-ISEL-NEXT:    v_mov_b32_e32 v4, 0x7fff
+; GFX7-ISEL-NEXT:    v_med3_i32 v1, v1, s4, v4
+; GFX7-ISEL-NEXT:    v_med3_i32 v0, v0, s4, v4
+; GFX7-ISEL-NEXT:    v_med3_i32 v3, v3, s4, v4
+; GFX7-ISEL-NEXT:    v_med3_i32 v2, v2, s4, v4
+; GFX7-ISEL-NEXT:    v_lshlrev_b32_e32 v1, 16, v1
+; GFX7-ISEL-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GFX7-ISEL-NEXT:    v_lshlrev_b32_e32 v3, 16, v3
+; GFX7-ISEL-NEXT:    v_or_b32_e32 v0, v0, v1
+; GFX7-ISEL-NEXT:    v_and_b32_e32 v1, 0xffff, v2
+; GFX7-ISEL-NEXT:    v_or_b32_e32 v1, v1, v3
+; GFX7-ISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX7-GI-LABEL: test_signed_v4f32_v4i16:
+; GFX7-GI:       ; %bb.0:
+; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v1, v1
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, v0
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v2, v2
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v3, v3
+; GFX7-GI-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX7-GI-NEXT:    v_mov_b32_e32 v4, 0x8000
+; GFX7-GI-NEXT:    v_med3_i32 v1, v1, v4, s4
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v4, s4
+; GFX7-GI-NEXT:    v_and_b32_e32 v1, 0xffff, v1
+; GFX7-GI-NEXT:    v_med3_i32 v2, v2, v4, s4
+; GFX7-GI-NEXT:    v_med3_i32 v3, v3, v4, s4
+; GFX7-GI-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v1, 16, v1
+; GFX7-GI-NEXT:    v_or_b32_e32 v0, v0, v1
+; GFX7-GI-NEXT:    v_and_b32_e32 v1, 0xffff, v2
+; GFX7-GI-NEXT:    v_and_b32_e32 v2, 0xffff, v3
+; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v2, 16, v2
+; GFX7-GI-NEXT:    v_or_b32_e32 v1, v1, v2
+; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: test_signed_v4f32_v4i16:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_cvt_i32_f32_e32 v2, v2
+; GFX9-NEXT:    v_cvt_i32_f32_e32 v3, v3
+; GFX9-NEXT:    v_cvt_i32_f32_e32 v0, v0
+; GFX9-NEXT:    v_cvt_i32_f32_e32 v1, v1
+; GFX9-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX9-NEXT:    v_mov_b32_e32 v4, 0x8000
+; GFX9-NEXT:    v_med3_i32 v2, v2, v4, s4
+; GFX9-NEXT:    v_med3_i32 v3, v3, v4, s4
+; GFX9-NEXT:    v_med3_i32 v0, v0, v4, s4
+; GFX9-NEXT:    v_med3_i32 v1, v1, v4, s4
+; GFX9-NEXT:    s_mov_b32 s4, 0x5040100
+; GFX9-NEXT:    v_perm_b32 v0, v1, v0, s4
+; GFX9-NEXT:    v_perm_b32 v1, v3, v2, s4
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: test_signed_v4f32_v4i16:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_cvt_pk_i16_f32 v0, v0, v1
+; GFX11-NEXT:    v_cvt_pk_i16_f32 v1, v2, v3
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: test_signed_v4f32_v4i16:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_cvt_pk_i16_f32 v0, v0, v1
+; GFX12-NEXT:    v_cvt_pk_i16_f32 v1, v2, v3
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+    %x = call <4 x i16> @llvm.fptosi.sat.v4f32.v4i16(<4 x float> %f)
+    ret <4 x i16> %x
+}
+
+define <4 x i16> @test_s_signed_v4f32_v4i16(<4 x float> inreg %f) {
+; GFX7-ISEL-LABEL: test_s_signed_v4f32_v4i16:
+; GFX7-ISEL:       ; %bb.0:
+; GFX7-ISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-ISEL-NEXT:    v_cvt_i32_f32_e32 v0, s19
+; GFX7-ISEL-NEXT:    s_movk_i32 s4, 0x8000
+; GFX7-ISEL-NEXT:    v_mov_b32_e32 v1, 0x7fff
+; GFX7-ISEL-NEXT:    v_cvt_i32_f32_e32 v2, s18
+; GFX7-ISEL-NEXT:    v_med3_i32 v0, v0, s4, v1
+; GFX7-ISEL-NEXT:    v_cvt_i32_f32_e32 v3, s17
+; GFX7-ISEL-NEXT:    v_lshlrev_b32_e32 v4, 16, v0
+; GFX7-ISEL-NEXT:    v_cvt_i32_f32_e32 v0, s16
+; GFX7-ISEL-NEXT:    v_med3_i32 v2, v2, s4, v1
+; GFX7-ISEL-NEXT:    v_med3_i32 v3, v3, s4, v1
+; GFX7-ISEL-NEXT:    v_lshlrev_b32_e32 v3, 16, v3
+; GFX7-ISEL-NEXT:    v_med3_i32 v0, v0, s4, v1
+; GFX7-ISEL-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GFX7-ISEL-NEXT:    v_and_b32_e32 v1, 0xffff, v2
+; GFX7-ISEL-NEXT:    v_or_b32_e32 v0, v0, v3
+; GFX7-ISEL-NEXT:    v_or_b32_e32 v1, v1, v4
+; GFX7-ISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX7-GI-LABEL: test_s_signed_v4f32_v4i16:
+; GFX7-GI:       ; %bb.0:
+; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, s16
+; GFX7-GI-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX7-GI-NEXT:    v_mov_b32_e32 v1, 0x8000
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v2, s17
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v1, s4
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s5, v0
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v0, s18
+; GFX7-GI-NEXT:    v_cvt_i32_f32_e32 v3, s19
+; GFX7-GI-NEXT:    v_med3_i32 v2, v2, v1, s4
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s6, v2
+; GFX7-GI-NEXT:    v_med3_i32 v0, v0, v1, s4
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s7, v0
+; GFX7-GI-NEXT:    v_med3_i32 v0, v3, v1, s4
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s4, v0
+; GFX7-GI-NEXT:    s_and_b32 s6, 0xffff, s6
+; GFX7-GI-NEXT:    s_and_b32 s5, 0xffff, s5
+; GFX7-GI-NEXT:    s_lshl_b32 s6, s6, 16
+; GFX7-GI-NEXT:    s_and_b32 s4, 0xffff, s4
+; GFX7-GI-NEXT:    s_or_b32 s5, s5, s6
+; GFX7-GI-NEXT:    s_and_b32 s6, 0xffff, s7
+; GFX7-GI-NEXT:    s_lshl_b32 s4, s4, 16
+; GFX7-GI-NEXT:    s_or_b32 s4, s6, s4
+; GFX7-GI-NEXT:    v_mov_b32_e32 v0, s5
+; GFX7-GI-NEXT:    v_mov_b32_e32 v1, s4
+; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: test_s_signed_v4f32_v4i16:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_cvt_i32_f32_e32 v0, s19
+; GFX9-NEXT:    v_cvt_i32_f32_e32 v2, s18
+; GFX9-NEXT:    v_cvt_i32_f32_e32 v3, s17
+; GFX9-NEXT:    v_cvt_i32_f32_e32 v4, s16
+; GFX9-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX9-NEXT:    v_mov_b32_e32 v1, 0x8000
+; GFX9-NEXT:    v_med3_i32 v5, v0, v1, s4
+; GFX9-NEXT:    v_med3_i32 v2, v2, v1, s4
+; GFX9-NEXT:    v_med3_i32 v0, v3, v1, s4
+; GFX9-NEXT:    v_med3_i32 v1, v4, v1, s4
+; GFX9-NEXT:    v_and_b32_e32 v1, 0xffff, v1
+; GFX9-NEXT:    v_lshl_or_b32 v0, v0, 16, v1
+; GFX9-NEXT:    v_and_b32_e32 v1, 0xffff, v2
+; GFX9-NEXT:    v_lshl_or_b32 v1, v5, 16, v1
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: test_s_signed_v4f32_v4i16:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_cvt_pk_i16_f32 v0, s0, s1
+; GFX11-NEXT:    v_cvt_pk_i16_f32 v1, s2, s3
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: test_s_signed_v4f32_v4i16:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_cvt_pk_i16_f32 v0, s0, s1
+; GFX12-NEXT:    v_cvt_pk_i16_f32 v1, s2, s3
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+    %x = call <4 x i16> @llvm.fptosi.sat.v4f32.v4i16(<4 x float> %f)
+    ret <4 x i16> %x
+}
+
 ;
 ; Float to signed 8-bit
 ;
diff --git a/llvm/test/CodeGen/AMDGPU/fptoui-sat-scalar.ll b/llvm/test/CodeGen/AMDGPU/fptoui-sat-scalar.ll
index 2b02c54f780ac..6a4c3d2d4cc51 100644
--- a/llvm/test/CodeGen/AMDGPU/fptoui-sat-scalar.ll
+++ b/llvm/test/CodeGen/AMDGPU/fptoui-sat-scalar.ll
@@ -379,21 +379,12 @@ define i8 @test_s_unsigned_i8_f32(float inreg %f) nounwind {
 }
 
 define i16 @test_s_unsigned_i16_f32(float inreg %f) nounwind {
-; GFX7-ISEL-LABEL: test_s_unsigned_i16_f32:
-; GFX7-ISEL:       ; %bb.0:
-; GFX7-ISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-ISEL-NEXT:    v_cvt_u32_f32_e32 v0, s16
-; GFX7-ISEL-NEXT:    v_min_u32_e32 v0, 0xffff, v0
-; GFX7-ISEL-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX7-GI-LABEL: test_s_unsigned_i16_f32:
-; GFX7-GI:       ; %bb.0:
-; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, s16
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s4, v0
-; GFX7-GI-NEXT:    s_min_u32 s4, s4, 0xffff
-; GFX7-GI-NEXT:    v_mov_b32_e32 v0, s4
-; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
+; GFX7-LABEL: test_s_unsigned_i16_f32:
+; GFX7:       ; %bb.0:
+; GFX7-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-NEXT:    v_cvt_u32_f32_e32 v0, s16
+; GFX7-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX7-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: test_s_unsigned_i16_f32:
 ; GFX9:       ; %bb.0:
@@ -1755,23 +1746,13 @@ define i8 @test_s_unsigned_i8_f16(half inreg %f) nounwind {
 }
 
 define i16 @test_s_unsigned_i16_f16(half inreg %f) nounwind {
-; GFX7-ISEL-LABEL: test_s_unsigned_i16_f16:
-; GFX7-ISEL:       ; %bb.0:
-; GFX7-ISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-ISEL-NEXT:    v_cvt_f32_f16_e32 v0, s16
-; GFX7-ISEL-NEXT:    v_cvt_u32_f32_e32 v0, v0
-; GFX7-ISEL-NEXT:    v_min_u32_e32 v0, 0xffff, v0
-; GFX7-ISEL-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX7-GI-LABEL: test_s_unsigned_i16_f16:
-; GFX7-GI:       ; %bb.0:
-; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s16
-; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, v0
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s4, v0
-; GFX7-GI-NEXT:    s_min_u32 s4, s4, 0xffff
-; GFX7-GI-NEXT:    v_mov_b32_e32 v0, s4
-; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
+; GFX7-LABEL: test_s_unsigned_i16_f16:
+; GFX7:       ; %bb.0:
+; GFX7-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-NEXT:    v_cvt_f32_f16_e32 v0, s16
+; GFX7-NEXT:    v_cvt_u32_f32_e32 v0, v0
+; GFX7-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX7-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: test_s_unsigned_i16_f16:
 ; GFX9:       ; %bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/fptoui-sat-vector.ll b/llvm/test/CodeGen/AMDGPU/fptoui-sat-vector.ll
index 14094c50e2290..94f4da379a038 100644
--- a/llvm/test/CodeGen/AMDGPU/fptoui-sat-vector.ll
+++ b/llvm/test/CodeGen/AMDGPU/fptoui-sat-vector.ll
@@ -2647,8 +2647,8 @@ define <4 x i16> @test_unsigned_v4f16_v4i16(<4 x half> %f) {
 ; GFX7-GI:       ; %bb.0:
 ; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v2, 16, v0
-; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v3, 16, v1
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v2, v2
+; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v3, 16, v1
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, v0
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v3, v3
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, v1
@@ -2658,11 +2658,15 @@ define <4 x i16> @test_unsigned_v4f16_v4i16(<4 x half> %f) {
 ; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v1, v1
 ; GFX7-GI-NEXT:    v_min_u32_e32 v2, 0xffff, v2
 ; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX7-GI-NEXT:    v_and_b32_e32 v2, 0xffff, v2
 ; GFX7-GI-NEXT:    v_min_u32_e32 v3, 0xffff, v3
+; GFX7-GI-NEXT:    v_and_b32_e32 v0, 0xffff, v0
 ; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v2, 16, v2
 ; GFX7-GI-NEXT:    v_min_u32_e32 v1, 0xffff, v1
 ; GFX7-GI-NEXT:    v_or_b32_e32 v0, v0, v2
-; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v2, 16, v3
+; GFX7-GI-NEXT:    v_and_b32_e32 v2, 0xffff, v3
+; GFX7-GI-NEXT:    v_and_b32_e32 v1, 0xffff, v1
+; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v2, 16, v2
 ; GFX7-GI-NEXT:    v_or_b32_e32 v1, v1, v2
 ; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
 ;
@@ -3485,22 +3489,26 @@ define <4 x i16> @test_s_unsigned_v4f16_v4i16(<4 x half> inreg %f) {
 ; GFX7-GI-NEXT:    s_lshr_b32 s4, s17, 16
 ; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, v0
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v2, s17
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v3, s4
 ; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v1, v1
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s5, v0
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s4
-; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v2, v2
-; GFX7-GI-NEXT:    s_min_u32 s4, s5, 0xffff
+; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s4, v0
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, v2
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v2, v3
+; GFX7-GI-NEXT:    v_min_u32_e32 v1, 0xffff, v1
 ; GFX7-GI-NEXT:    v_readfirstlane_b32 s5, v1
-; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, v0
-; GFX7-GI-NEXT:    s_min_u32 s5, s5, 0xffff
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s6, v2
-; GFX7-GI-NEXT:    s_lshl_b32 s5, s5, 16
+; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s6, v0
+; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v2
+; GFX7-GI-NEXT:    s_and_b32 s5, 0xffff, s5
 ; GFX7-GI-NEXT:    v_readfirstlane_b32 s7, v0
-; GFX7-GI-NEXT:    s_min_u32 s7, s7, 0xffff
-; GFX7-GI-NEXT:    s_min_u32 s6, s6, 0xffff
+; GFX7-GI-NEXT:    s_and_b32 s4, 0xffff, s4
+; GFX7-GI-NEXT:    s_lshl_b32 s5, s5, 16
 ; GFX7-GI-NEXT:    s_or_b32 s4, s4, s5
-; GFX7-GI-NEXT:    s_lshl_b32 s5, s7, 16
-; GFX7-GI-NEXT:    s_or_b32 s5, s6, s5
+; GFX7-GI-NEXT:    s_and_b32 s5, 0xffff, s6
+; GFX7-GI-NEXT:    s_and_b32 s6, 0xffff, s7
+; GFX7-GI-NEXT:    s_lshl_b32 s6, s6, 16
+; GFX7-GI-NEXT:    s_or_b32 s5, s5, s6
 ; GFX7-GI-NEXT:    v_mov_b32_e32 v0, s4
 ; GFX7-GI-NEXT:    v_mov_b32_e32 v1, s5
 ; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
@@ -3590,12 +3598,12 @@ define <4 x i16> @test_s_unsigned_v4f16_v4i16(<4 x half> inreg %f) {
 ; GFX12-GI-NEXT:    s_wait_bvhcnt 0x0
 ; GFX12-GI-NEXT:    s_wait_kmcnt 0x0
 ; GFX12-GI-NEXT:    s_lshr_b32 s2, s0, 16
-; GFX12-GI-NEXT:    s_lshr_b32 s3, s1, 16
 ; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v0.l, s0
+; GFX12-GI-NEXT:    s_lshr_b32 s0, s1, 16
 ; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
 ; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v1.l, s2
 ; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v2.l, s1
-; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v3.l, s3
+; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v3.l, s0
 ; GFX12-GI-NEXT:    v_readfirstlane_b32 s0, v0
 ; GFX12-GI-NEXT:    v_readfirstlane_b32 s1, v1
 ; GFX12-GI-NEXT:    v_readfirstlane_b32 s2, v2
@@ -4341,40 +4349,48 @@ define <8 x i16> @test_unsigned_v8f16_v8i16(<8 x half> %f) {
 ; GFX7-GI:       ; %bb.0:
 ; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v4, 16, v0
-; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v5, 16, v1
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v4, v4
-; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v6, 16, v2
+; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v5, 16, v1
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, v0
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v5, v5
-; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v7, 16, v3
+; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v6, 16, v2
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, v1
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v6, v6
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v2, v2
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v7, v7
 ; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v4, v4
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v3, v3
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v6, v6
+; GFX7-GI-NEXT:    v_lshrrev_b32_e32 v7, 16, v3
 ; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, v0
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v2, v2
 ; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v5, v5
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v7, v7
 ; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v1, v1
-; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v6, v6
-; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v2, v2
-; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v7, v7
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v3, v3
 ; GFX7-GI-NEXT:    v_min_u32_e32 v4, 0xffff, v4
-; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v3, v3
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v6, v6
 ; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v2, v2
+; GFX7-GI-NEXT:    v_and_b32_e32 v4, 0xffff, v4
 ; GFX7-GI-NEXT:    v_min_u32_e32 v5, 0xffff, v5
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v7, v7
+; GFX7-GI-NEXT:    v_and_b32_e32 v0, 0xffff, v0
 ; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v4, 16, v4
 ; GFX7-GI-NEXT:    v_min_u32_e32 v1, 0xffff, v1
-; GFX7-GI-NEXT:    v_min_u32_e32 v6, 0xffff, v6
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v3, v3
 ; GFX7-GI-NEXT:    v_or_b32_e32 v0, v0, v4
-; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v4, 16, v5
+; GFX7-GI-NEXT:    v_and_b32_e32 v4, 0xffff, v5
+; GFX7-GI-NEXT:    v_min_u32_e32 v6, 0xffff, v6
+; GFX7-GI-NEXT:    v_and_b32_e32 v1, 0xffff, v1
+; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v4, 16, v4
 ; GFX7-GI-NEXT:    v_min_u32_e32 v2, 0xffff, v2
-; GFX7-GI-NEXT:    v_min_u32_e32 v7, 0xffff, v7
 ; GFX7-GI-NEXT:    v_or_b32_e32 v1, v1, v4
-; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v4, 16, v6
+; GFX7-GI-NEXT:    v_and_b32_e32 v4, 0xffff, v6
+; GFX7-GI-NEXT:    v_min_u32_e32 v7, 0xffff, v7
+; GFX7-GI-NEXT:    v_and_b32_e32 v2, 0xffff, v2
+; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v4, 16, v4
 ; GFX7-GI-NEXT:    v_min_u32_e32 v3, 0xffff, v3
 ; GFX7-GI-NEXT:    v_or_b32_e32 v2, v2, v4
-; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v4, 16, v7
+; GFX7-GI-NEXT:    v_and_b32_e32 v4, 0xffff, v7
+; GFX7-GI-NEXT:    v_and_b32_e32 v3, 0xffff, v3
+; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v4, 16, v4
 ; GFX7-GI-NEXT:    v_or_b32_e32 v3, v3, v4
 ; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
 ;
@@ -5754,50 +5770,58 @@ define <8 x i16> @test_s_unsigned_v8f16_v8i16(<8 x half> inreg %f) {
 ; GFX7-GI-LABEL: test_s_unsigned_v8f16_v8i16:
 ; GFX7-GI:       ; %bb.0:
 ; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s16
 ; GFX7-GI-NEXT:    s_lshr_b32 s4, s16, 16
 ; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, s4
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s16
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v2, s17
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, v0
 ; GFX7-GI-NEXT:    s_lshr_b32 s5, s17, 16
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v2, s18
 ; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v1, v1
-; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, v0
-; GFX7-GI-NEXT:    s_lshr_b32 s4, s18, 16
-; GFX7-GI-NEXT:    s_lshr_b32 s6, s19, 16
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s8, v1
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, s5
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v2, v2
+; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v0
 ; GFX7-GI-NEXT:    v_readfirstlane_b32 s7, v0
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s17
-; GFX7-GI-NEXT:    s_min_u32 s5, s8, 0xffff
+; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v1
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, s5
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s5, v0
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s18
+; GFX7-GI-NEXT:    s_lshr_b32 s4, s18, 16
 ; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v1, v1
-; GFX7-GI-NEXT:    s_min_u32 s7, s7, 0xffff
+; GFX7-GI-NEXT:    v_min_u32_e32 v2, 0xffff, v2
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s8, v2
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v2, s4
 ; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, v0
+; GFX7-GI-NEXT:    v_min_u32_e32 v1, 0xffff, v1
+; GFX7-GI-NEXT:    s_lshr_b32 s6, s19, 16
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s4, v1
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, s19
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v2, v2
+; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v3, s6
+; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s6, v0
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, v1
+; GFX7-GI-NEXT:    v_min_u32_e32 v1, 0xffff, v2
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v2, v3
+; GFX7-GI-NEXT:    s_and_b32 s5, 0xffff, s5
+; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX7-GI-NEXT:    s_and_b32 s7, 0xffff, s7
 ; GFX7-GI-NEXT:    s_lshl_b32 s5, s5, 16
+; GFX7-GI-NEXT:    s_and_b32 s4, 0xffff, s4
 ; GFX7-GI-NEXT:    v_readfirstlane_b32 s9, v1
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v1, s4
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s8, v0
-; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, v2
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v2, s6
-; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v1, v1
-; GFX7-GI-NEXT:    s_min_u32 s4, s9, 0xffff
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s9, v0
-; GFX7-GI-NEXT:    v_cvt_f32_f16_e32 v0, s19
-; GFX7-GI-NEXT:    s_min_u32 s6, s9, 0xffff
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s9, v1
-; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v1, v2
-; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, v0
-; GFX7-GI-NEXT:    s_min_u32 s9, s9, 0xffff
-; GFX7-GI-NEXT:    s_or_b32 s5, s7, s5
-; GFX7-GI-NEXT:    v_readfirstlane_b32 s11, v1
 ; GFX7-GI-NEXT:    v_readfirstlane_b32 s10, v0
-; GFX7-GI-NEXT:    s_min_u32 s11, s11, 0xffff
-; GFX7-GI-NEXT:    s_lshl_b32 s7, s9, 16
-; GFX7-GI-NEXT:    s_min_u32 s8, s8, 0xffff
-; GFX7-GI-NEXT:    s_min_u32 s10, s10, 0xffff
+; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v2
+; GFX7-GI-NEXT:    s_or_b32 s5, s7, s5
+; GFX7-GI-NEXT:    s_and_b32 s7, 0xffff, s8
 ; GFX7-GI-NEXT:    s_lshl_b32 s4, s4, 16
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s11, v0
+; GFX7-GI-NEXT:    s_or_b32 s4, s7, s4
+; GFX7-GI-NEXT:    s_and_b32 s7, 0xffff, s9
+; GFX7-GI-NEXT:    s_and_b32 s6, 0xffff, s6
+; GFX7-GI-NEXT:    s_lshl_b32 s7, s7, 16
+; GFX7-GI-NEXT:    s_and_b32 s8, 0xffff, s11
 ; GFX7-GI-NEXT:    s_or_b32 s6, s6, s7
-; GFX7-GI-NEXT:    s_lshl_b32 s7, s11, 16
-; GFX7-GI-NEXT:    s_or_b32 s4, s8, s4
-; GFX7-GI-NEXT:    s_or_b32 s7, s10, s7
+; GFX7-GI-NEXT:    s_and_b32 s7, 0xffff, s10
+; GFX7-GI-NEXT:    s_lshl_b32 s8, s8, 16
+; GFX7-GI-NEXT:    s_or_b32 s7, s7, s8
 ; GFX7-GI-NEXT:    v_mov_b32_e32 v0, s5
 ; GFX7-GI-NEXT:    v_mov_b32_e32 v1, s4
 ; GFX7-GI-NEXT:    v_mov_b32_e32 v2, s6
@@ -5933,36 +5957,37 @@ define <8 x i16> @test_s_unsigned_v8f16_v8i16(<8 x half> inreg %f) {
 ; GFX12-GI-NEXT:    s_wait_samplecnt 0x0
 ; GFX12-GI-NEXT:    s_wait_bvhcnt 0x0
 ; GFX12-GI-NEXT:    s_wait_kmcnt 0x0
-; GFX12-GI-NEXT:    s_lshr_b32 s4, s0, 16
 ; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v0.l, s0
+; GFX12-GI-NEXT:    s_lshr_b32 s4, s0, 16
+; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v2.l, s1
+; GFX12-GI-NEXT:    s_lshr_b32 s1, s1, 16
 ; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
 ; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v1.l, s4
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v0.l, s1
+; GFX12-GI-NEXT:    s_lshr_b32 s1, s2, 16
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s5, v2
+; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
 ; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v2.l, s1
-; GFX12-GI-NEXT:    s_lshr_b32 s5, s1, 16
-; GFX12-GI-NEXT:    s_lshr_b32 s0, s2, 16
 ; GFX12-GI-NEXT:    s_lshr_b32 s1, s3, 16
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s4, v0
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s6, v1
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s7, v2
-; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
-; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v0.l, s5
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s4, v1
 ; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v1.l, s2
-; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v2.l, s0
 ; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v3.l, s3
+; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
 ; GFX12-GI-NEXT:    v_cvt_u16_f16_e32 v4.l, s1
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s0, v0
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s1, v1
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s2, v2
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s3, v3
-; GFX12-GI-NEXT:    v_readfirstlane_b32 s5, v4
-; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s4, s4, s6
-; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s0, s7, s0
-; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s1, s1, s2
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s1, v0
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s3, v2
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s2, v1
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s6, v3
+; GFX12-GI-NEXT:    v_readfirstlane_b32 s7, v4
+; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s0, s0, s4
+; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s1, s5, s1
+; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s2, s2, s3
 ; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
-; GFX12-GI-NEXT:    v_dual_mov_b32 v0, s4 :: v_dual_mov_b32 v1, s0
-; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s2, s3, s5
+; GFX12-GI-NEXT:    v_dual_mov_b32 v0, s0 :: v_dual_mov_b32 v1, s1
+; GFX12-GI-NEXT:    s_pack_ll_b32_b16 s3, s6, s7
 ; GFX12-GI-NEXT:    s_wait_alu depctr_sa_sdst(0)
-; GFX12-GI-NEXT:    v_dual_mov_b32 v2, s1 :: v_dual_mov_b32 v3, s2
+; GFX12-GI-NEXT:    v_dual_mov_b32 v2, s2 :: v_dual_mov_b32 v3, s3
 ; GFX12-GI-NEXT:    s_setpc_b64 s[30:31]
     %x = call <8 x i16> @llvm.fptoui.sat.v8f16.v8i16(<8 x half> %f)
     ret <8 x i16> %x
@@ -6174,6 +6199,169 @@ define <8 x i64> @test_s_unsigned_v8f16_v8i64(<8 x half> inreg %f) {
     ret <8 x i64> %x
 }
 
+;
+; Float to unsigned 16-bit
+;
+
+define <4 x i16> @test_unsigned_v4f32_v4i16(<4 x float> %f) {
+; GFX7-ISEL-LABEL: test_unsigned_v4f32_v4i16:
+; GFX7-ISEL:       ; %bb.0:
+; GFX7-ISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-ISEL-NEXT:    v_cvt_u32_f32_e32 v3, v3
+; GFX7-ISEL-NEXT:    v_cvt_u32_f32_e32 v1, v1
+; GFX7-ISEL-NEXT:    v_cvt_u32_f32_e32 v2, v2
+; GFX7-ISEL-NEXT:    v_cvt_u32_f32_e32 v0, v0
+; GFX7-ISEL-NEXT:    v_min_u32_e32 v3, 0xffff, v3
+; GFX7-ISEL-NEXT:    v_min_u32_e32 v1, 0xffff, v1
+; GFX7-ISEL-NEXT:    v_min_u32_e32 v2, 0xffff, v2
+; GFX7-ISEL-NEXT:    v_lshlrev_b32_e32 v3, 16, v3
+; GFX7-ISEL-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX7-ISEL-NEXT:    v_lshlrev_b32_e32 v1, 16, v1
+; GFX7-ISEL-NEXT:    v_or_b32_e32 v0, v0, v1
+; GFX7-ISEL-NEXT:    v_or_b32_e32 v1, v2, v3
+; GFX7-ISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX7-GI-LABEL: test_unsigned_v4f32_v4i16:
+; GFX7-GI:       ; %bb.0:
+; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v1, v1
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, v0
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v2, v2
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v3, v3
+; GFX7-GI-NEXT:    v_min_u32_e32 v1, 0xffff, v1
+; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX7-GI-NEXT:    v_and_b32_e32 v1, 0xffff, v1
+; GFX7-GI-NEXT:    v_min_u32_e32 v2, 0xffff, v2
+; GFX7-GI-NEXT:    v_min_u32_e32 v3, 0xffff, v3
+; GFX7-GI-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v1, 16, v1
+; GFX7-GI-NEXT:    v_or_b32_e32 v0, v0, v1
+; GFX7-GI-NEXT:    v_and_b32_e32 v1, 0xffff, v2
+; GFX7-GI-NEXT:    v_and_b32_e32 v2, 0xffff, v3
+; GFX7-GI-NEXT:    v_lshlrev_b32_e32 v2, 16, v2
+; GFX7-GI-NEXT:    v_or_b32_e32 v1, v1, v2
+; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: test_unsigned_v4f32_v4i16:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_cvt_u32_f32_e32 v2, v2
+; GFX9-NEXT:    v_cvt_u32_f32_e32 v3, v3
+; GFX9-NEXT:    v_cvt_u32_f32_e32 v0, v0
+; GFX9-NEXT:    v_cvt_u32_f32_e32 v1, v1
+; GFX9-NEXT:    v_min_u32_e32 v2, 0xffff, v2
+; GFX9-NEXT:    v_min_u32_e32 v3, 0xffff, v3
+; GFX9-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX9-NEXT:    v_min_u32_e32 v1, 0xffff, v1
+; GFX9-NEXT:    s_mov_b32 s4, 0x5040100
+; GFX9-NEXT:    v_perm_b32 v0, v1, v0, s4
+; GFX9-NEXT:    v_perm_b32 v1, v3, v2, s4
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: test_unsigned_v4f32_v4i16:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_cvt_pk_u16_f32 v0, v0, v1
+; GFX11-NEXT:    v_cvt_pk_u16_f32 v1, v2, v3
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: test_unsigned_v4f32_v4i16:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_cvt_pk_u16_f32 v0, v0, v1
+; GFX12-NEXT:    v_cvt_pk_u16_f32 v1, v2, v3
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+    %x = call <4 x i16> @llvm.fptoui.sat.v4f32.v4i16(<4 x float> %f)
+    ret <4 x i16> %x
+}
+
+define <4 x i16> @test_s_unsigned_v4f32_v4i16(<4 x float> inreg %f) {
+; GFX7-ISEL-LABEL: test_s_unsigned_v4f32_v4i16:
+; GFX7-ISEL:       ; %bb.0:
+; GFX7-ISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-ISEL-NEXT:    v_cvt_u32_f32_e32 v0, s18
+; GFX7-ISEL-NEXT:    v_cvt_u32_f32_e32 v1, s19
+; GFX7-ISEL-NEXT:    v_cvt_u32_f32_e32 v3, s17
+; GFX7-ISEL-NEXT:    v_min_u32_e32 v2, 0xffff, v0
+; GFX7-ISEL-NEXT:    v_cvt_u32_f32_e32 v0, s16
+; GFX7-ISEL-NEXT:    v_min_u32_e32 v1, 0xffff, v1
+; GFX7-ISEL-NEXT:    v_min_u32_e32 v3, 0xffff, v3
+; GFX7-ISEL-NEXT:    v_lshlrev_b32_e32 v1, 16, v1
+; GFX7-ISEL-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX7-ISEL-NEXT:    v_lshlrev_b32_e32 v3, 16, v3
+; GFX7-ISEL-NEXT:    v_or_b32_e32 v0, v0, v3
+; GFX7-ISEL-NEXT:    v_or_b32_e32 v1, v2, v1
+; GFX7-ISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX7-GI-LABEL: test_s_unsigned_v4f32_v4i16:
+; GFX7-GI:       ; %bb.0:
+; GFX7-GI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, s16
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v1, s17
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v2, s19
+; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s4, v0
+; GFX7-GI-NEXT:    v_cvt_u32_f32_e32 v0, s18
+; GFX7-GI-NEXT:    v_min_u32_e32 v1, 0xffff, v1
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s5, v1
+; GFX7-GI-NEXT:    s_and_b32 s5, 0xffff, s5
+; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s6, v0
+; GFX7-GI-NEXT:    v_min_u32_e32 v0, 0xffff, v2
+; GFX7-GI-NEXT:    v_readfirstlane_b32 s7, v0
+; GFX7-GI-NEXT:    s_and_b32 s4, 0xffff, s4
+; GFX7-GI-NEXT:    s_lshl_b32 s5, s5, 16
+; GFX7-GI-NEXT:    s_or_b32 s4, s4, s5
+; GFX7-GI-NEXT:    s_and_b32 s5, 0xffff, s6
+; GFX7-GI-NEXT:    s_and_b32 s6, 0xffff, s7
+; GFX7-GI-NEXT:    s_lshl_b32 s6, s6, 16
+; GFX7-GI-NEXT:    s_or_b32 s5, s5, s6
+; GFX7-GI-NEXT:    v_mov_b32_e32 v0, s4
+; GFX7-GI-NEXT:    v_mov_b32_e32 v1, s5
+; GFX7-GI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: test_s_unsigned_v4f32_v4i16:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_cvt_u32_f32_e32 v0, s19
+; GFX9-NEXT:    v_cvt_u32_f32_e32 v1, s18
+; GFX9-NEXT:    v_cvt_u32_f32_e32 v2, s17
+; GFX9-NEXT:    v_cvt_u32_f32_e32 v3, s16
+; GFX9-NEXT:    v_min_u32_e32 v4, 0xffff, v0
+; GFX9-NEXT:    v_min_u32_e32 v1, 0xffff, v1
+; GFX9-NEXT:    v_min_u32_e32 v0, 0xffff, v2
+; GFX9-NEXT:    v_min_u32_e32 v2, 0xffff, v3
+; GFX9-NEXT:    v_and_b32_e32 v2, 0xffff, v2
+; GFX9-NEXT:    v_and_b32_e32 v1, 0xffff, v1
+; GFX9-NEXT:    v_lshl_or_b32 v0, v0, 16, v2
+; GFX9-NEXT:    v_lshl_or_b32 v1, v4, 16, v1
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: test_s_unsigned_v4f32_v4i16:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_cvt_pk_u16_f32 v0, s0, s1
+; GFX11-NEXT:    v_cvt_pk_u16_f32 v1, s2, s3
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: test_s_unsigned_v4f32_v4i16:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_cvt_pk_u16_f32 v0, s0, s1
+; GFX12-NEXT:    v_cvt_pk_u16_f32 v1, s2, s3
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+    %x = call <4 x i16> @llvm.fptoui.sat.v4f32.v4i16(<4 x float> %f)
+    ret <4 x i16> %x
+}
+
 ;
 ; Float to unsigned 8-bit
 ;

>From 062b9c2dc75eeebedc073df3cd338b973a83b571 Mon Sep 17 00:00:00 2001
From: Igor Wodiany <igor.wodiany at amd.com>
Date: Fri, 12 Jun 2026 11:31:21 +0100
Subject: [PATCH 2/3] address comments

---
 llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp |  5 +--
 llvm/lib/Target/AMDGPU/VOP3PInstructions.td   | 29 +++++++++------
 llvm/test/CodeGen/AMDGPU/fptosi-sat-scalar.ll | 16 +++------
 llvm/test/CodeGen/AMDGPU/fptoui-sat-scalar.ll | 35 +++++++++++--------
 4 files changed, 44 insertions(+), 41 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
index 9a64e1e6365ac..fe774bce512d5 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
@@ -3946,10 +3946,7 @@ SDValue AMDGPUTargetLowering::LowerFP_TO_INT_SAT(const SDValue Op,
       (SrcVT == MVT::f32 || SrcVT == MVT::f64))
     return Op;
 
-  if (DstVT == MVT::i16 && SatWidth == DstWidth && SrcVT == MVT::f16)
-    return Op;
-
-  if (DstVT == MVT::i16 && SatWidth == 16 && SrcVT == MVT::f32)
+  if (DstVT == MVT::i16 && SatWidth == DstWidth && (SrcVT == MVT::f16 || SrcVT == MVT::f32))
     return Op;
 
   // Perform all saturation at selected width (i16 or i32) and truncate
diff --git a/llvm/lib/Target/AMDGPU/VOP3PInstructions.td b/llvm/lib/Target/AMDGPU/VOP3PInstructions.td
index 5718eb503d5c8..c6bb93889d8ab 100644
--- a/llvm/lib/Target/AMDGPU/VOP3PInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VOP3PInstructions.td
@@ -3144,25 +3144,30 @@ defm V_DOT8_I32_I4  : VOP3P_Real_gfx10 <0x18>;
 // GFX11+ Patterns
 //===----------------------------------------------------------------------===//
 
+multiclass FPToIntSatI16Pat<dag lhs, dag rhs> {
+  let True16Predicate = UseRealTrue16Insts in
+    def : GCNPat<lhs, (EXTRACT_SUBREG rhs, lo16)>;
+  let True16Predicate = NotUseRealTrue16Insts in
+    def : GCNPat<lhs, rhs>;
+}
+
 // Packed f32 -> i16 saturated conversion.
 multiclass CvtPkF32ToI16Pat<SDPatternOperator dagOp, Instruction inst> {
+  // Needed for SDAG as it uses build_vector.
   def : GCNPat<(v2i16 (build_vector
                   (i16 (dagOp (f32 (VOP3Mods f32:$src0, i32:$src0_modifiers)), i16)),
                   (i16 (dagOp (f32 (VOP3Mods f32:$src1, i32:$src1_modifiers)), i16)))),
                (inst $src0_modifiers, $src0, $src1_modifiers, $src1)>;
+  // Needed for GISel as ut legalizes V2S32 for both divergent and uniform cases.
   def : GCNPat<(v2i16 (dagOp (v2f32 VReg_64:$src), i16)),
                (inst 0, (EXTRACT_SUBREG VReg_64:$src, sub0),
                      0, (EXTRACT_SUBREG VReg_64:$src, sub1))>;
   def : GCNPat<(v2i16 (dagOp (v2f32 SReg_64:$src), i16)),
                (inst 0, (EXTRACT_SUBREG SReg_64:$src, sub0),
                      0, (EXTRACT_SUBREG SReg_64:$src, sub1))>;
-}
-
-multiclass FPToIntSatI16Pat<dag lhs, dag rhs> {
-  let True16Predicate = UseRealTrue16Insts in
-    def : GCNPat<lhs, (EXTRACT_SUBREG rhs, lo16)>;
-  let True16Predicate = NotUseRealTrue16Insts in
-    def : GCNPat<lhs, rhs>;
+  // Single value conversion: use a packed instruction with a dummy second input.
+  defm : FPToIntSatI16Pat<(i16 (dagOp (f32 (VOP3Mods f32:$src0, i32:$src0_modifiers)), i16)),
+                          (inst $src0_modifiers, $src0, 0, (f32 (IMPLICIT_DEF)))>;
 }
 
 multiclass FPToSSatI16Pat<dag lhs, int hi, int lo> {
@@ -3176,12 +3181,14 @@ multiclass FPToUSatI16Pat<dag lhs, int hi> {
 }
 
 let SubtargetPredicate = isGFX11Plus in {
-  // f32 -> i16 saturated conversion.
+  // f32 -> i16 saturated conversion (vector and scalar types).
   defm : CvtPkF32ToI16Pat<fp_to_sint_sat, V_CVT_PK_I16_F32_e64>;
   defm : CvtPkF32ToI16Pat<fp_to_uint_sat, V_CVT_PK_U16_F32_e64>;
 }
 
-// Fallback for f32 -> i16 saturated conversion. Required because
+// Fallback for f32 -> i16 saturated conversion on pre-GFX11. Required because
 // f32 -> i16 has to be legal so that the packed pattern above can match.
-defm : FPToSSatI16Pat<(i16 (fp_to_sint_sat (f32 (VOP3Mods f32:$src0, i32:$src0_modifiers)), i16)), 0x7fff, 0x8000>;
-defm : FPToUSatI16Pat<(i16 (fp_to_uint_sat (f32 (VOP3Mods f32:$src0, i32:$src0_modifiers)), i16)), 0xffff>;
+let SubtargetPredicate = isGFX6GFX7GFX8GFX9GFX10 in {
+  defm : FPToSSatI16Pat<(i16 (fp_to_sint_sat (f32 (VOP3Mods f32:$src0, i32:$src0_modifiers)), i16)), 0x7fff, 0x8000>;
+  defm : FPToUSatI16Pat<(i16 (fp_to_uint_sat (f32 (VOP3Mods f32:$src0, i32:$src0_modifiers)), i16)), 0xffff>;
+}
diff --git a/llvm/test/CodeGen/AMDGPU/fptosi-sat-scalar.ll b/llvm/test/CodeGen/AMDGPU/fptosi-sat-scalar.ll
index c75f36e7df7d4..4c6a54c734e85 100644
--- a/llvm/test/CodeGen/AMDGPU/fptosi-sat-scalar.ll
+++ b/llvm/test/CodeGen/AMDGPU/fptosi-sat-scalar.ll
@@ -149,9 +149,7 @@ define i16 @test_signed_i16_f32(float %f) nounwind {
 ; GFX11-LABEL: test_signed_i16_f32:
 ; GFX11:       ; %bb.0:
 ; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX11-NEXT:    v_mov_b32_e32 v1, 0x8000
-; GFX11-NEXT:    v_med3_i32 v0, v0, v1, 0x7fff
+; GFX11-NEXT:    v_cvt_pk_i16_f32 v0, v0, s0
 ; GFX11-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX12-ISEL-LABEL: test_signed_i16_f32:
@@ -161,9 +159,7 @@ define i16 @test_signed_i16_f32(float %f) nounwind {
 ; GFX12-ISEL-NEXT:    s_wait_samplecnt 0x0
 ; GFX12-ISEL-NEXT:    s_wait_bvhcnt 0x0
 ; GFX12-ISEL-NEXT:    s_wait_kmcnt 0x0
-; GFX12-ISEL-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX12-ISEL-NEXT:    v_mov_b32_e32 v1, 0x8000
-; GFX12-ISEL-NEXT:    v_med3_i32 v0, v0, v1, 0x7fff
+; GFX12-ISEL-NEXT:    v_cvt_pk_i16_f32 v0, v0, s0
 ; GFX12-ISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX12-GI-LABEL: test_signed_i16_f32:
@@ -173,9 +169,7 @@ define i16 @test_signed_i16_f32(float %f) nounwind {
 ; GFX12-GI-NEXT:    s_wait_samplecnt 0x0
 ; GFX12-GI-NEXT:    s_wait_bvhcnt 0x0
 ; GFX12-GI-NEXT:    s_wait_kmcnt 0x0
-; GFX12-GI-NEXT:    v_mov_b32_e32 v1, 0x8000
-; GFX12-GI-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; GFX12-GI-NEXT:    v_med3_i32 v0, v0, v1, 0x7fff
+; GFX12-GI-NEXT:    v_cvt_pk_i16_f32 v0, v0, v0
 ; GFX12-GI-NEXT:    s_setpc_b64 s[30:31]
     %x = call i16 @llvm.fptosi.sat.i16.f32(float %f)
     ret i16 %x
@@ -564,9 +558,7 @@ define i16 @test_s_signed_i16_f32(float inreg %f) nounwind {
 ; GFX11-LABEL: test_s_signed_i16_f32:
 ; GFX11:       ; %bb.0:
 ; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT:    v_cvt_i32_f32_e32 v0, s0
-; GFX11-NEXT:    v_mov_b32_e32 v1, 0x8000
-; GFX11-NEXT:    v_med3_i32 v0, v0, v1, 0x7fff
+; GFX11-NEXT:    v_cvt_pk_i16_f32 v0, s0, s0
 ; GFX11-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX12-LABEL: test_s_signed_i16_f32:
diff --git a/llvm/test/CodeGen/AMDGPU/fptoui-sat-scalar.ll b/llvm/test/CodeGen/AMDGPU/fptoui-sat-scalar.ll
index 6a4c3d2d4cc51..f7a98d7642b5e 100644
--- a/llvm/test/CodeGen/AMDGPU/fptoui-sat-scalar.ll
+++ b/llvm/test/CodeGen/AMDGPU/fptoui-sat-scalar.ll
@@ -108,20 +108,28 @@ define i16 @test_unsigned_i16_f32(float %f) nounwind {
 ; GFX11-LABEL: test_unsigned_i16_f32:
 ; GFX11:       ; %bb.0:
 ; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT:    v_cvt_u32_f32_e32 v0, v0
-; GFX11-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX11-NEXT:    v_cvt_pk_u16_f32 v0, v0, s0
 ; GFX11-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX12-LABEL: test_unsigned_i16_f32:
-; GFX12:       ; %bb.0:
-; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
-; GFX12-NEXT:    s_wait_expcnt 0x0
-; GFX12-NEXT:    s_wait_samplecnt 0x0
-; GFX12-NEXT:    s_wait_bvhcnt 0x0
-; GFX12-NEXT:    s_wait_kmcnt 0x0
-; GFX12-NEXT:    v_cvt_u32_f32_e32 v0, v0
-; GFX12-NEXT:    v_min_u32_e32 v0, 0xffff, v0
-; GFX12-NEXT:    s_setpc_b64 s[30:31]
+; GFX12-ISEL-LABEL: test_unsigned_i16_f32:
+; GFX12-ISEL:       ; %bb.0:
+; GFX12-ISEL-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-ISEL-NEXT:    s_wait_expcnt 0x0
+; GFX12-ISEL-NEXT:    s_wait_samplecnt 0x0
+; GFX12-ISEL-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-ISEL-NEXT:    s_wait_kmcnt 0x0
+; GFX12-ISEL-NEXT:    v_cvt_pk_u16_f32 v0, v0, s0
+; GFX12-ISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-GI-LABEL: test_unsigned_i16_f32:
+; GFX12-GI:       ; %bb.0:
+; GFX12-GI-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-GI-NEXT:    s_wait_expcnt 0x0
+; GFX12-GI-NEXT:    s_wait_samplecnt 0x0
+; GFX12-GI-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-GI-NEXT:    s_wait_kmcnt 0x0
+; GFX12-GI-NEXT:    v_cvt_pk_u16_f32 v0, v0, v0
+; GFX12-GI-NEXT:    s_setpc_b64 s[30:31]
     %x = call i16 @llvm.fptoui.sat.i16.f32(float %f)
     ret i16 %x
 }
@@ -396,8 +404,7 @@ define i16 @test_s_unsigned_i16_f32(float inreg %f) nounwind {
 ; GFX11-LABEL: test_s_unsigned_i16_f32:
 ; GFX11:       ; %bb.0:
 ; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT:    v_cvt_u32_f32_e32 v0, s0
-; GFX11-NEXT:    v_min_u32_e32 v0, 0xffff, v0
+; GFX11-NEXT:    v_cvt_pk_u16_f32 v0, s0, s0
 ; GFX11-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX12-LABEL: test_s_unsigned_i16_f32:

>From 68675fcc909c3fd33dbe018c68fe3fcc5d8b4ceb Mon Sep 17 00:00:00 2001
From: Igor Wodiany <igor.wodiany at amd.com>
Date: Fri, 12 Jun 2026 11:39:42 +0100
Subject: [PATCH 3/3] format

---
 llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
index fe774bce512d5..91e24b131a433 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
@@ -3946,7 +3946,8 @@ SDValue AMDGPUTargetLowering::LowerFP_TO_INT_SAT(const SDValue Op,
       (SrcVT == MVT::f32 || SrcVT == MVT::f64))
     return Op;
 
-  if (DstVT == MVT::i16 && SatWidth == DstWidth && (SrcVT == MVT::f16 || SrcVT == MVT::f32))
+  if (DstVT == MVT::i16 && SatWidth == DstWidth &&
+      (SrcVT == MVT::f16 || SrcVT == MVT::f32))
     return Op;
 
   // Perform all saturation at selected width (i16 or i32) and truncate



More information about the llvm-commits mailing list