[llvm] AMDGPU: Add SALU support for llvm.fptrunc.round f32 to f16 (PR #203406)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 12 09:18:59 PDT 2026


https://github.com/vangthao95 updated https://github.com/llvm/llvm-project/pull/203406

>From 14b56188f1abb3ffc3aea280644c98a93fee6863 Mon Sep 17 00:00:00 2001
From: Vang Thao <Vang.Thao at amd.com>
Date: Thu, 11 Jun 2026 17:06:38 -0400
Subject: [PATCH 1/2] AMDGPU: Add SALU support for llvm.fptrunc.round f32 to
 f16

---
 llvm/lib/Target/AMDGPU/SIInstructions.td      |   8 +
 llvm/lib/Target/AMDGPU/SIModeRegister.cpp     |   9 +-
 .../test/CodeGen/AMDGPU/llvm.fptrunc.round.ll | 576 +++++++++++++++++-
 3 files changed, 591 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIInstructions.td b/llvm/lib/Target/AMDGPU/SIInstructions.td
index 272b84f1c665c..8131519a892f5 100644
--- a/llvm/lib/Target/AMDGPU/SIInstructions.td
+++ b/llvm/lib/Target/AMDGPU/SIInstructions.td
@@ -296,6 +296,10 @@ def FPTRUNC_ROUND_F32_F64_PSEUDO : VPseudoInstSI <(outs VGPR_32:$vdst),
   (ins VReg_64:$src0, i32imm:$round)>;
 } // End Uses = [MODE, EXEC]
 
+let SubtargetPredicate = HasSALUFloatInsts, Uses = [MODE] in
+def FPTRUNC_ROUND_F16_F32_SALU_PSEUDO : SPseudoInstSI <(outs SReg_32:$sdst),
+  (ins SReg_32:$src0, i32imm:$round)>;
+
 let True16Predicate = NotHasTrue16BitInsts in
 def : GCNPat <(f16 (fptrunc_round f32:$src0, (i32 SupportedRoundMode:$round))),
      (FPTRUNC_ROUND_F16_F32_PSEUDO $src0, (as_hw_round_mode $round))>;
@@ -308,6 +312,10 @@ let True16Predicate = UseRealTrue16Insts in
 def : GCNPat <(f16 (fptrunc_round (f32 (VOP3OpSelMods f32:$src0, i32:$src0_modifiers)), (i32 SupportedRoundMode:$round))),
      (FPTRUNC_ROUND_F16_F32_PSEUDO_t16_e64 $src0_modifiers, $src0, (as_hw_round_mode $round))>;
 
+let SubtargetPredicate = HasSALUFloatInsts, AddedComplexity = 9 in
+def : GCNPat <(f16 (UniformBinFrag<fptrunc_round> f32:$src0, (i32 SupportedRoundMode:$round))),
+     (FPTRUNC_ROUND_F16_F32_SALU_PSEUDO $src0, (as_hw_round_mode $round))>;
+
 let True16Predicate = NotUseRealTrue16Insts in
 def : GCNPat <(f16 (fptrunc_round f32:$src0, (i32 RtzRoundMode))),
      (V_CVT_PKRTZ_F16_F32_e32 $src0, (IMPLICIT_DEF))>;
diff --git a/llvm/lib/Target/AMDGPU/SIModeRegister.cpp b/llvm/lib/Target/AMDGPU/SIModeRegister.cpp
index dc723986badc7..f9b33b4175c2f 100644
--- a/llvm/lib/Target/AMDGPU/SIModeRegister.cpp
+++ b/llvm/lib/Target/AMDGPU/SIModeRegister.cpp
@@ -174,7 +174,8 @@ Status SIModeRegister::getInstructionMode(MachineInstr &MI,
       Opcode == AMDGPU::FPTRUNC_ROUND_F16_F32_PSEUDO ||
       Opcode == AMDGPU::FPTRUNC_ROUND_F16_F32_PSEUDO_fake16_e32 ||
       Opcode == AMDGPU::FPTRUNC_ROUND_F16_F32_PSEUDO_t16_e64 ||
-      Opcode == AMDGPU::FPTRUNC_ROUND_F32_F64_PSEUDO) {
+      Opcode == AMDGPU::FPTRUNC_ROUND_F32_F64_PSEUDO ||
+      Opcode == AMDGPU::FPTRUNC_ROUND_F16_F32_SALU_PSEUDO) {
     switch (Opcode) {
     case AMDGPU::V_INTERP_P1LL_F16:
     case AMDGPU::V_INTERP_P1LV_F16:
@@ -206,6 +207,12 @@ Status SIModeRegister::getInstructionMode(MachineInstr &MI,
       MI.setDesc(TII->get(AMDGPU::V_CVT_F32_F64_e32));
       return Status(FP_ROUND_MODE_DP(3), FP_ROUND_MODE_DP(Mode));
     }
+    case AMDGPU::FPTRUNC_ROUND_F16_F32_SALU_PSEUDO: {
+      unsigned Mode = MI.getOperand(2).getImm();
+      MI.removeOperand(2);
+      MI.setDesc(TII->get(AMDGPU::S_CVT_F16_F32));
+      return Status(FP_ROUND_MODE_DP(3), FP_ROUND_MODE_DP(Mode));
+    }
     default:
       return DefaultStatus;
     }
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.fptrunc.round.ll b/llvm/test/CodeGen/AMDGPU/llvm.fptrunc.round.ll
index 3ec47962a53fe..749f304be2e0f 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.fptrunc.round.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.fptrunc.round.ll
@@ -3,7 +3,9 @@
 ; RUN: llc -global-isel=0 -mtriple=amdgcn -mcpu=gfx1010 < %s | FileCheck -check-prefixes=CHECK,SDAG %s
 ; RUN: llc -global-isel=0 -mtriple=amdgcn -mcpu=gfx1100 -mattr=+real-true16 < %s | FileCheck -check-prefixes=CHECK,GFX11-SDAG %s
 ; RUN: llc -global-isel=1 -mtriple=amdgcn -mcpu=gfx1100 < %s | FileCheck -check-prefixes=CHECK,GFX11-GISEL %s
-; RUN: llc -global-isel -mtriple=amdgcn -mcpu=gfx1030 < %s | FileCheck -check-prefixes=CHECK,GISEL %s
+; RUN: llc -global-isel=1 -mtriple=amdgcn -mcpu=gfx1030 < %s | FileCheck -check-prefixes=CHECK,GISEL %s
+; RUN: llc -global-isel=0 -mtriple=amdgcn -mcpu=gfx1200 < %s | FileCheck -check-prefixes=GFX12,GFX12-SDAG %s
+; RUN: llc -global-isel=1 -mtriple=amdgcn -mcpu=gfx1200 < %s | FileCheck -check-prefixes=GFX12,GFX12-GISEL %s
 
 define amdgpu_gs half @v_fptrunc_round_f32_to_f16_tonearest(float %a) {
 ; SDAG-LABEL: v_fptrunc_round_f32_to_f16_tonearest:
@@ -25,6 +27,11 @@ define amdgpu_gs half @v_fptrunc_round_f32_to_f16_tonearest(float %a) {
 ; GISEL:       ; %bb.0:
 ; GISEL-NEXT:    v_cvt_f16_f32_e32 v0, v0
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-LABEL: v_fptrunc_round_f32_to_f16_tonearest:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-NEXT:    ; return to shader part epilog
   %res = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.tonearest")
   ret half %res
 }
@@ -53,6 +60,12 @@ define amdgpu_gs half @v_fptrunc_round_f32_to_f16_upward(float %a) {
 ; GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_MODE, 2, 1), 1
 ; GISEL-NEXT:    v_cvt_f16_f32_e32 v0, v0
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-LABEL: v_fptrunc_round_f32_to_f16_upward:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-NEXT:    ; return to shader part epilog
   %res = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.upward")
   ret half %res
 }
@@ -81,6 +94,12 @@ define amdgpu_gs half @v_fptrunc_round_f32_to_f16_downward(float %a) {
 ; GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_MODE, 3, 1), 1
 ; GISEL-NEXT:    v_cvt_f16_f32_e32 v0, v0
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-LABEL: v_fptrunc_round_f32_to_f16_downward:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-NEXT:    ; return to shader part epilog
   %res = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.downward")
   ret half %res
 }
@@ -105,6 +124,16 @@ define amdgpu_gs half @v_fptrunc_round_f32_to_f16_towardzero(float %a) {
 ; GISEL:       ; %bb.0:
 ; GISEL-NEXT:    v_cvt_pkrtz_f16_f32_e32 v0, v0, v0
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: v_fptrunc_round_f32_to_f16_towardzero:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    v_cvt_pk_rtz_f16_f32_e64 v0, v0, s0
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: v_fptrunc_round_f32_to_f16_towardzero:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    v_cvt_pk_rtz_f16_f32_e32 v0, v0, v0
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %res = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.towardzero")
   ret half %res
 }
@@ -131,6 +160,11 @@ define amdgpu_gs <2 x half> @v_fptrunc_round_f32_to_v2f16_towardzero(float %a, f
 ; GISEL-NEXT:    v_cvt_pkrtz_f16_f32_e32 v1, v1, v0
 ; GISEL-NEXT:    v_pack_b32_f16 v0, v0, v1
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-LABEL: v_fptrunc_round_f32_to_v2f16_towardzero:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    v_cvt_pk_rtz_f16_f32_e32 v0, v0, v1
+; GFX12-NEXT:    ; return to shader part epilog
   %lo = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.towardzero")
   %hi = call half @llvm.fptrunc.round.f16.f32(float %b, metadata !"round.towardzero")
   %tmp = insertelement <2 x half> poison, half %lo, i32 0
@@ -158,6 +192,16 @@ define amdgpu_gs <2 x half> @v_fptrunc_round_poison_to_v2f16_towardzero(float %a
 ; GISEL:       ; %bb.0:
 ; GISEL-NEXT:    v_cvt_pkrtz_f16_f32_e32 v0, v0, v0
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: v_fptrunc_round_poison_to_v2f16_towardzero:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    v_cvt_pk_rtz_f16_f32_e64 v0, v0, s0
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: v_fptrunc_round_poison_to_v2f16_towardzero:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    v_cvt_pk_rtz_f16_f32_e32 v0, v0, v0
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %lo = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.towardzero")
   %tmp = insertelement <2 x half> poison, half %lo, i32 0
   ret <2 x half> %tmp
@@ -190,6 +234,20 @@ define amdgpu_gs <2 x half> @v_fptrunc_round_constant_to_v2f16_towardzero(float
 ; GISEL-NEXT:    v_cvt_pkrtz_f16_f32_e32 v0, v0, v0
 ; GISEL-NEXT:    v_pack_b32_f16 v0, v0, 1.0
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: v_fptrunc_round_constant_to_v2f16_towardzero:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    v_cvt_pk_rtz_f16_f32_e64 v0, v0, s0
+; GFX12-SDAG-NEXT:    v_mov_b16_e32 v0.h, 0x3c00
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: v_fptrunc_round_constant_to_v2f16_towardzero:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    v_cvt_pk_rtz_f16_f32_e32 v0, v0, v0
+; GFX12-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-GISEL-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GFX12-GISEL-NEXT:    v_lshl_or_b32 v0, 0x3c00, 16, v0
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %lo = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.towardzero")
   %tmp = insertelement <2 x half> poison, half %lo, i32 0
   %res = insertelement <2 x half> %tmp, half 1.0, i32 1
@@ -250,6 +308,20 @@ define amdgpu_gs void @v_fptrunc_round_f32_to_f16_upward_multiple_calls(float %a
 ; GISEL-NEXT:    v_add_f16_e32 v0, v1, v0
 ; GISEL-NEXT:    global_store_short v[2:3], v0, off
 ; GISEL-NEXT:    s_endpgm
+;
+; GFX12-LABEL: v_fptrunc_round_f32_to_f16_upward_multiple_calls:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-NEXT:    v_cvt_f16_f32_e64 v0.h, v1
+; GFX12-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 2
+; GFX12-NEXT:    v_cvt_f16_f32_e64 v1.l, v1
+; GFX12-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 0
+; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT:    v_add_f16_e32 v0.l, v0.l, v0.h
+; GFX12-NEXT:    v_add_f16_e32 v0.l, v1.l, v0.l
+; GFX12-NEXT:    global_store_b16 v[2:3], v0, off
+; GFX12-NEXT:    s_endpgm
   %res1 = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.upward")
   %res2 = call half @llvm.fptrunc.round.f16.f32(float %b, metadata !"round.upward")
   %res3 = call half @llvm.fptrunc.round.f16.f32(float %b, metadata !"round.downward")
@@ -313,6 +385,20 @@ define amdgpu_gs void @v_fptrunc_round_f32_to_f16_downward_multiple_calls(float
 ; GISEL-NEXT:    v_add_f16_e32 v0, v1, v0
 ; GISEL-NEXT:    global_store_short v[2:3], v0, off
 ; GISEL-NEXT:    s_endpgm
+;
+; GFX12-LABEL: v_fptrunc_round_f32_to_f16_downward_multiple_calls:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-NEXT:    v_cvt_f16_f32_e64 v4.l, v0
+; GFX12-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 2
+; GFX12-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-NEXT:    v_cvt_f16_f32_e64 v0.h, v1
+; GFX12-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 0
+; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT:    v_add_f16_e32 v0.l, v4.l, v0.l
+; GFX12-NEXT:    v_add_f16_e32 v0.l, v0.h, v0.l
+; GFX12-NEXT:    global_store_b16 v[2:3], v0, off
+; GFX12-NEXT:    s_endpgm
   %res1 = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.upward")
   %res2 = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.downward")
   %res3 = call half @llvm.fptrunc.round.f16.f32(float %b, metadata !"round.downward")
@@ -372,6 +458,32 @@ define amdgpu_gs void @v_fptrunc_round_f32_to_f16_towardzero_multiple_calls(floa
 ; GISEL-NEXT:    v_add_f16_e32 v0, v1, v0
 ; GISEL-NEXT:    global_store_short v[2:3], v0, off
 ; GISEL-NEXT:    s_endpgm
+;
+; GFX12-SDAG-LABEL: v_fptrunc_round_f32_to_f16_towardzero_multiple_calls:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    v_cvt_pk_rtz_f16_f32_e64 v4, v0, s0
+; GFX12-SDAG-NEXT:    v_cvt_pk_rtz_f16_f32_e64 v5, v1, s0
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v0.l, v1
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 0
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-SDAG-NEXT:    v_add_f16_e32 v0.h, v4.l, v5.l
+; GFX12-SDAG-NEXT:    v_add_f16_e32 v0.l, v0.l, v0.h
+; GFX12-SDAG-NEXT:    global_store_b16 v[2:3], v0, off
+; GFX12-SDAG-NEXT:    s_endpgm
+;
+; GFX12-GISEL-LABEL: v_fptrunc_round_f32_to_f16_towardzero_multiple_calls:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    v_cvt_pk_rtz_f16_f32_e32 v4, v0, v0
+; GFX12-GISEL-NEXT:    v_cvt_pk_rtz_f16_f32_e32 v5, v1, v0
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, v1
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 0
+; GFX12-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-GISEL-NEXT:    v_add_f16_e32 v0.h, v4.l, v5.l
+; GFX12-GISEL-NEXT:    v_add_f16_e32 v0.l, v0.l, v0.h
+; GFX12-GISEL-NEXT:    global_store_b16 v[2:3], v0, off
+; GFX12-GISEL-NEXT:    s_endpgm
   %res1 = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.towardzero")
   %res2 = call half @llvm.fptrunc.round.f16.f32(float %b, metadata !"round.towardzero")
   %res3 = call half @llvm.fptrunc.round.f16.f32(float %b, metadata !"round.upward")
@@ -417,6 +529,24 @@ define amdgpu_gs i32 @s_fptrunc_round_f32_to_f16_upward(float inreg %a, ptr addr
 ; GISEL-NEXT:    v_and_b32_e32 v0, 0xffff, v0
 ; GISEL-NEXT:    v_readfirstlane_b32 s0, v0
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: s_fptrunc_round_f32_to_f16_upward:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s0, s0
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(SALU_CYCLE_3)
+; GFX12-SDAG-NEXT:    s_and_b32 s0, 0xffff, s0
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: s_fptrunc_round_f32_to_f16_upward:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, s0
+; GFX12-GISEL-NEXT:    v_mov_b16_e32 v0.h, 0
+; GFX12-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-GISEL-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX12-GISEL-NEXT:    s_wait_alu depctr_va_sdst(0)
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %res = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.upward")
   %bitcast = bitcast half %res to i16
   %ret = zext i16 %bitcast to i32
@@ -459,6 +589,24 @@ define amdgpu_gs i32 @s_fptrunc_round_f32_to_f16_downward(float inreg %a, ptr ad
 ; GISEL-NEXT:    v_and_b32_e32 v0, 0xffff, v0
 ; GISEL-NEXT:    v_readfirstlane_b32 s0, v0
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: s_fptrunc_round_f32_to_f16_downward:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s0, s0
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(SALU_CYCLE_3)
+; GFX12-SDAG-NEXT:    s_and_b32 s0, 0xffff, s0
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: s_fptrunc_round_f32_to_f16_downward:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, s0
+; GFX12-GISEL-NEXT:    v_mov_b16_e32 v0.h, 0
+; GFX12-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-GISEL-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX12-GISEL-NEXT:    s_wait_alu depctr_va_sdst(0)
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %res = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.downward")
   %bitcast = bitcast half %res to i16
   %ret = zext i16 %bitcast to i32
@@ -523,6 +671,35 @@ define amdgpu_gs void @s_fptrunc_round_f32_to_f16_upward_multiple_calls(float in
 ; GISEL-NEXT:    v_add_f16_e32 v2, v3, v2
 ; GISEL-NEXT:    global_store_short v[0:1], v2, off
 ; GISEL-NEXT:    s_endpgm
+;
+; GFX12-SDAG-LABEL: s_fptrunc_round_f32_to_f16_upward_multiple_calls:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s0, s0
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s2, s1
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 2
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s1, s1
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 0
+; GFX12-SDAG-NEXT:    s_add_f16 s0, s0, s2
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(SALU_CYCLE_3) | instskip(NEXT) | instid1(SALU_CYCLE_3)
+; GFX12-SDAG-NEXT:    s_add_f16 s0, s1, s0
+; GFX12-SDAG-NEXT:    v_mov_b16_e32 v2.l, s0
+; GFX12-SDAG-NEXT:    global_store_b16 v[0:1], v2, off
+; GFX12-SDAG-NEXT:    s_endpgm
+;
+; GFX12-GISEL-LABEL: s_fptrunc_round_f32_to_f16_upward_multiple_calls:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v2.l, s0
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v2.h, s1
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 2
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v3.l, s1
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 0
+; GFX12-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-GISEL-NEXT:    v_add_f16_e32 v2.l, v2.l, v2.h
+; GFX12-GISEL-NEXT:    v_add_f16_e32 v2.l, v3.l, v2.l
+; GFX12-GISEL-NEXT:    global_store_b16 v[0:1], v2, off
+; GFX12-GISEL-NEXT:    s_endpgm
   %res1 = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.upward")
   %res2 = call half @llvm.fptrunc.round.f16.f32(float %b, metadata !"round.upward")
   %res3 = call half @llvm.fptrunc.round.f16.f32(float %b, metadata !"round.downward")
@@ -564,6 +741,22 @@ define amdgpu_gs <2 x half> @v_fptrunc_round_v2f32_to_v2f16_upward(<2 x float> %
 ; GISEL-NEXT:    v_cvt_f16_f32_e32 v1, v1
 ; GISEL-NEXT:    v_pack_b32_f16 v0, v0, v1
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: v_fptrunc_round_v2f32_to_v2f16_upward:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.h, v1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.l, v0
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-SDAG-NEXT:    v_mov_b32_e32 v0, v1
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: v_fptrunc_round_v2f32_to_v2f16_upward:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.h, v1
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %res = call <2 x half> @llvm.fptrunc.round.v2f16.v2f32(<2 x float> %a, metadata !"round.upward")
   ret <2 x half> %res
 }
@@ -600,6 +793,22 @@ define amdgpu_gs <2 x half> @v_fptrunc_round_v2f32_to_v2f16_downward(<2 x float>
 ; GISEL-NEXT:    v_cvt_f16_f32_e32 v1, v1
 ; GISEL-NEXT:    v_pack_b32_f16 v0, v0, v1
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: v_fptrunc_round_v2f32_to_v2f16_downward:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.h, v1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.l, v0
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-SDAG-NEXT:    v_mov_b32_e32 v0, v1
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: v_fptrunc_round_v2f32_to_v2f16_downward:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.h, v1
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %res = call <2 x half> @llvm.fptrunc.round.v2f16.v2f32(<2 x float> %a, metadata !"round.downward")
   ret <2 x half> %res
 }
@@ -676,6 +885,40 @@ define amdgpu_gs void @v_fptrunc_round_v2f32_to_v2f16_upward_multiple_calls(<2 x
 ; GISEL-NEXT:    v_pk_add_f16 v0, v1, v0
 ; GISEL-NEXT:    global_store_dword v[4:5], v0, off
 ; GISEL-NEXT:    s_endpgm
+;
+; GFX12-SDAG-LABEL: v_fptrunc_round_v2f32_to_v2f16_upward_multiple_calls:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.h, v1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.l, v0
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v0.h, v3
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v0.l, v2
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 2
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.h, v3
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.l, v2
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 0
+; GFX12-SDAG-NEXT:    v_pk_add_f16 v0, v1, v0
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-SDAG-NEXT:    v_pk_add_f16 v0, v3, v0
+; GFX12-SDAG-NEXT:    global_store_b32 v[4:5], v0, off
+; GFX12-SDAG-NEXT:    s_endpgm
+;
+; GFX12-GISEL-LABEL: v_fptrunc_round_v2f32_to_v2f16_upward_multiple_calls:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.h, v1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.l, v2
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.h, v3
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 2
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v2.l, v2
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v2.h, v3
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 0
+; GFX12-GISEL-NEXT:    v_pk_add_f16 v0, v0, v1
+; GFX12-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-GISEL-NEXT:    v_pk_add_f16 v0, v2, v0
+; GFX12-GISEL-NEXT:    global_store_b32 v[4:5], v0, off
+; GFX12-GISEL-NEXT:    s_endpgm
   %res1 = call <2 x half> @llvm.fptrunc.round.v2f16.v2f32(<2 x float> %a, metadata !"round.upward")
   %res2 = call <2 x half> @llvm.fptrunc.round.v2f16.v2f32(<2 x float> %b, metadata !"round.upward")
   %res3 = call <2 x half> @llvm.fptrunc.round.v2f16.v2f32(<2 x float> %b, metadata !"round.downward")
@@ -737,6 +980,30 @@ define amdgpu_gs <2 x i32> @s_fptrunc_round_v2f32_to_v2f16_upward(<2 x float> in
 ; GISEL-NEXT:    v_readfirstlane_b32 s0, v0
 ; GISEL-NEXT:    v_readfirstlane_b32 s1, v1
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: s_fptrunc_round_v2f32_to_v2f16_upward:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s0, s0
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s1, s1
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(SALU_CYCLE_2) | instskip(NEXT) | instid1(SALU_CYCLE_2)
+; GFX12-SDAG-NEXT:    s_and_b32 s0, 0xffff, s0
+; GFX12-SDAG-NEXT:    s_and_b32 s1, 0xffff, s1
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: s_fptrunc_round_v2f32_to_v2f16_upward:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    v_mov_b16_e32 v0.h, 0
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, s0
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.l, s1
+; GFX12-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_3)
+; GFX12-GISEL-NEXT:    v_mov_b16_e32 v1.h, v0.h
+; GFX12-GISEL-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX12-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_2)
+; GFX12-GISEL-NEXT:    v_readfirstlane_b32 s1, v1
+; GFX12-GISEL-NEXT:    s_wait_alu depctr_va_sdst(0)
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %res = call <2 x half> @llvm.fptrunc.round.v2f16.v2f32(<2 x float> %a, metadata !"round.upward")
   %bitcast = bitcast <2 x half> %res to <2 x i16>
   %ret = zext <2 x i16> %bitcast to <2 x i32>
@@ -795,6 +1062,30 @@ define amdgpu_gs <2 x i32> @s_fptrunc_round_v2f32_to_v2f16_downward(<2 x float>
 ; GISEL-NEXT:    v_readfirstlane_b32 s0, v0
 ; GISEL-NEXT:    v_readfirstlane_b32 s1, v1
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: s_fptrunc_round_v2f32_to_v2f16_downward:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s0, s0
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s1, s1
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(SALU_CYCLE_2) | instskip(NEXT) | instid1(SALU_CYCLE_2)
+; GFX12-SDAG-NEXT:    s_and_b32 s0, 0xffff, s0
+; GFX12-SDAG-NEXT:    s_and_b32 s1, 0xffff, s1
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: s_fptrunc_round_v2f32_to_v2f16_downward:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    v_mov_b16_e32 v0.h, 0
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, s0
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.l, s1
+; GFX12-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_3)
+; GFX12-GISEL-NEXT:    v_mov_b16_e32 v1.h, v0.h
+; GFX12-GISEL-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX12-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_2)
+; GFX12-GISEL-NEXT:    v_readfirstlane_b32 s1, v1
+; GFX12-GISEL-NEXT:    s_wait_alu depctr_va_sdst(0)
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %res = call <2 x half> @llvm.fptrunc.round.v2f16.v2f32(<2 x float> %a, metadata !"round.downward")
   %bitcast = bitcast <2 x half> %res to <2 x i16>
   %ret = zext <2 x i16> %bitcast to <2 x i32>
@@ -884,6 +1175,44 @@ define amdgpu_gs void @s_fptrunc_round_v2f32_to_v2f16_upward_multiple_calls(<2 x
 ; GISEL-NEXT:    v_pk_add_f16 v2, v3, v2
 ; GISEL-NEXT:    global_store_dword v[0:1], v2, off
 ; GISEL-NEXT:    s_endpgm
+;
+; GFX12-SDAG-LABEL: s_fptrunc_round_v2f32_to_v2f16_upward_multiple_calls:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s1, s1
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s0, s0
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s4, s3
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s5, s2
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 2
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s3, s3
+; GFX12-SDAG-NEXT:    s_cvt_f16_f32 s2, s2
+; GFX12-SDAG-NEXT:    s_pack_ll_b32_b16 s0, s0, s1
+; GFX12-SDAG-NEXT:    s_pack_ll_b32_b16 s1, s5, s4
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 0
+; GFX12-SDAG-NEXT:    v_pk_add_f16 v2, s0, s1
+; GFX12-SDAG-NEXT:    s_pack_ll_b32_b16 s0, s2, s3
+; GFX12-SDAG-NEXT:    s_wait_alu depctr_sa_sdst(0)
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-SDAG-NEXT:    v_pk_add_f16 v2, s0, v2
+; GFX12-SDAG-NEXT:    global_store_b32 v[0:1], v2, off
+; GFX12-SDAG-NEXT:    s_endpgm
+;
+; GFX12-GISEL-LABEL: s_fptrunc_round_v2f32_to_v2f16_upward_multiple_calls:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v2.l, s0
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v2.h, s1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v3.l, s2
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v3.h, s3
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 2
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v4.l, s2
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v4.h, s3
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 0
+; GFX12-GISEL-NEXT:    v_pk_add_f16 v2, v2, v3
+; GFX12-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-GISEL-NEXT:    v_pk_add_f16 v2, v4, v2
+; GFX12-GISEL-NEXT:    global_store_b32 v[0:1], v2, off
+; GFX12-GISEL-NEXT:    s_endpgm
   %res1 = call <2 x half> @llvm.fptrunc.round.v2f16.v2f32(<2 x float> %a, metadata !"round.upward")
   %res2 = call <2 x half> @llvm.fptrunc.round.v2f16.v2f32(<2 x float> %b, metadata !"round.upward")
   %res3 = call <2 x half> @llvm.fptrunc.round.v2f16.v2f32(<2 x float> %b, metadata !"round.downward")
@@ -929,6 +1258,24 @@ define amdgpu_gs <3 x half> @v_fptrunc_round_v3f32_to_v3f16_upward(<3 x float> %
 ; GISEL-NEXT:    v_pack_b32_f16 v0, v0, v1
 ; GISEL-NEXT:    v_cvt_f16_f32_e32 v1, v2
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: v_fptrunc_round_v3f32_to_v3f16_upward:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.h, v1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.l, v0
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.l, v2
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_2)
+; GFX12-SDAG-NEXT:    v_mov_b32_e32 v0, v3
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: v_fptrunc_round_v3f32_to_v3f16_upward:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.h, v1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.l, v2
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %res = call <3 x half> @llvm.fptrunc.round.v3f16.v3f32(<3 x float> %a, metadata !"round.upward")
   ret <3 x half> %res
 }
@@ -969,6 +1316,24 @@ define amdgpu_gs <3 x half> @v_fptrunc_round_v3f32_to_v3f16_downward(<3 x float>
 ; GISEL-NEXT:    v_pack_b32_f16 v0, v0, v1
 ; GISEL-NEXT:    v_cvt_f16_f32_e32 v1, v2
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: v_fptrunc_round_v3f32_to_v3f16_downward:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.h, v1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.l, v0
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.l, v2
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_2)
+; GFX12-SDAG-NEXT:    v_mov_b32_e32 v0, v3
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: v_fptrunc_round_v3f32_to_v3f16_downward:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.h, v1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.l, v2
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %res = call <3 x half> @llvm.fptrunc.round.v3f16.v3f32(<3 x float> %a, metadata !"round.downward")
   ret <3 x half> %res
 }
@@ -1015,6 +1380,26 @@ define amdgpu_gs <4 x half> @v_fptrunc_round_v4f32_to_v4f16_upward(<4 x float> %
 ; GISEL-NEXT:    v_pack_b32_f16 v0, v0, v1
 ; GISEL-NEXT:    v_pack_b32_f16 v1, v2, v3
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: v_fptrunc_round_v4f32_to_v4f16_upward:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.h, v3
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.h, v1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.l, v0
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.l, v2
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-SDAG-NEXT:    v_dual_mov_b32 v0, v1 :: v_dual_mov_b32 v1, v3
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: v_fptrunc_round_v4f32_to_v4f16_upward:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.h, v1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.l, v2
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.h, v3
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %res = call <4 x half> @llvm.fptrunc.round.v4f16.v4f32(<4 x float> %a, metadata !"round.upward")
   ret <4 x half> %res
 }
@@ -1061,6 +1446,26 @@ define amdgpu_gs <4 x half> @v_fptrunc_round_v4f32_to_v4f16_downward(<4 x float>
 ; GISEL-NEXT:    v_pack_b32_f16 v0, v0, v1
 ; GISEL-NEXT:    v_pack_b32_f16 v1, v2, v3
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: v_fptrunc_round_v4f32_to_v4f16_downward:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.h, v3
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.h, v1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.l, v0
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.l, v2
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-SDAG-NEXT:    v_dual_mov_b32 v0, v1 :: v_dual_mov_b32 v1, v3
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: v_fptrunc_round_v4f32_to_v4f16_downward:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.h, v1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.l, v2
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.h, v3
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %res = call <4 x half> @llvm.fptrunc.round.v4f16.v4f32(<4 x float> %a, metadata !"round.downward")
   ret <4 x half> %res
 }
@@ -1128,6 +1533,35 @@ define amdgpu_gs <8 x half> @v_fptrunc_round_v8f32_to_v8f16_upward(<8 x float> %
 ; GISEL-NEXT:    v_pack_b32_f16 v2, v4, v5
 ; GISEL-NEXT:    v_pack_b32_f16 v3, v6, v7
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: v_fptrunc_round_v8f32_to_v8f16_upward:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v7.h, v7
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v5.h, v5
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.h, v3
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.h, v1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.l, v0
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.l, v2
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v5.l, v4
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v7.l, v6
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX12-SDAG-NEXT:    v_dual_mov_b32 v0, v1 :: v_dual_mov_b32 v1, v3
+; GFX12-SDAG-NEXT:    v_dual_mov_b32 v2, v5 :: v_dual_mov_b32 v3, v7
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: v_fptrunc_round_v8f32_to_v8f16_upward:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.h, v1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.l, v2
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.h, v3
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v2.l, v4
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v2.h, v5
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v3.l, v6
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v3.h, v7
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %res = call <8 x half> @llvm.fptrunc.round.v8f16.v8f32(<8 x float> %a, metadata !"round.upward")
   ret <8 x half> %res
 }
@@ -1195,6 +1629,35 @@ define amdgpu_gs <8 x half> @v_fptrunc_round_v8f32_to_v8f16_downward(<8 x float>
 ; GISEL-NEXT:    v_pack_b32_f16 v2, v4, v5
 ; GISEL-NEXT:    v_pack_b32_f16 v3, v6, v7
 ; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: v_fptrunc_round_v8f32_to_v8f16_downward:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v7.h, v7
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v5.h, v5
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.h, v3
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.h, v1
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v1.l, v0
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v3.l, v2
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v5.l, v4
+; GFX12-SDAG-NEXT:    v_cvt_f16_f32_e64 v7.l, v6
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX12-SDAG-NEXT:    v_dual_mov_b32 v0, v1 :: v_dual_mov_b32 v1, v3
+; GFX12-SDAG-NEXT:    v_dual_mov_b32 v2, v5 :: v_dual_mov_b32 v3, v7
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: v_fptrunc_round_v8f32_to_v8f16_downward:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.l, v0
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v0.h, v1
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.l, v2
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v1.h, v3
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v2.l, v4
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v2.h, v5
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v3.l, v6
+; GFX12-GISEL-NEXT:    v_cvt_f16_f32_e64 v3.h, v7
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
   %res = call <8 x half> @llvm.fptrunc.round.v8f16.v8f32(<8 x float> %a, metadata !"round.downward")
   ret <8 x half> %res
 }
@@ -1204,6 +1667,11 @@ define amdgpu_gs float @v_fptrunc_round_f64_to_f32_tonearest(double %a) {
 ; CHECK:       ; %bb.0:
 ; CHECK-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
 ; CHECK-NEXT:    ; return to shader part epilog
+;
+; GFX12-LABEL: v_fptrunc_round_f64_to_f32_tonearest:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; GFX12-NEXT:    ; return to shader part epilog
   %res = call float @llvm.fptrunc.round.f32.f64(double %a, metadata !"round.tonearest")
   ret float %res
 }
@@ -1214,6 +1682,12 @@ define amdgpu_gs float @v_fptrunc_round_f64_to_f32_upward(double %a) {
 ; CHECK-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_MODE, 2, 1), 1
 ; CHECK-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
 ; CHECK-NEXT:    ; return to shader part epilog
+;
+; GFX12-LABEL: v_fptrunc_round_f64_to_f32_upward:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; GFX12-NEXT:    ; return to shader part epilog
   %res = call float @llvm.fptrunc.round.f32.f64(double %a, metadata !"round.upward")
   ret float %res
 }
@@ -1224,6 +1698,12 @@ define amdgpu_gs float @v_fptrunc_round_f64_to_f32_downward(double %a) {
 ; CHECK-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_MODE, 3, 1), 1
 ; CHECK-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
 ; CHECK-NEXT:    ; return to shader part epilog
+;
+; GFX12-LABEL: v_fptrunc_round_f64_to_f32_downward:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; GFX12-NEXT:    ; return to shader part epilog
   %res = call float @llvm.fptrunc.round.f32.f64(double %a, metadata !"round.downward")
   ret float %res
 }
@@ -1234,6 +1714,100 @@ define amdgpu_gs float @v_fptrunc_round_f64_to_f32_towardzero(double %a) {
 ; CHECK-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_MODE, 2, 2), 3
 ; CHECK-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
 ; CHECK-NEXT:    ; return to shader part epilog
+;
+; GFX12-LABEL: v_fptrunc_round_f64_to_f32_towardzero:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 3
+; GFX12-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; GFX12-NEXT:    ; return to shader part epilog
   %res = call float @llvm.fptrunc.round.f32.f64(double %a, metadata !"round.towardzero")
   ret float %res
 }
+
+define amdgpu_gs float @s_fptrunc_round_f64_to_f32_upward(double inreg %a) {
+; SDAG-LABEL: s_fptrunc_round_f64_to_f32_upward:
+; SDAG:       ; %bb.0:
+; SDAG-NEXT:    v_mov_b32_e32 v0, s0
+; SDAG-NEXT:    v_mov_b32_e32 v1, s1
+; SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_MODE, 2, 1), 1
+; SDAG-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX11-SDAG-LABEL: s_fptrunc_round_f64_to_f32_upward:
+; GFX11-SDAG:       ; %bb.0:
+; GFX11-SDAG-NEXT:    v_dual_mov_b32 v0, s0 :: v_dual_mov_b32 v1, s1
+; GFX11-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_MODE, 2, 1), 1
+; GFX11-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-SDAG-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; GFX11-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX11-GISEL-LABEL: s_fptrunc_round_f64_to_f32_upward:
+; GFX11-GISEL:       ; %bb.0:
+; GFX11-GISEL-NEXT:    v_dual_mov_b32 v0, s0 :: v_dual_mov_b32 v1, s1
+; GFX11-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_MODE, 2, 1), 1
+; GFX11-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-GISEL-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; GFX11-GISEL-NEXT:    ; return to shader part epilog
+;
+; GISEL-LABEL: s_fptrunc_round_f64_to_f32_upward:
+; GISEL:       ; %bb.0:
+; GISEL-NEXT:    v_mov_b32_e32 v0, s0
+; GISEL-NEXT:    v_mov_b32_e32 v1, s1
+; GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_MODE, 2, 1), 1
+; GISEL-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-LABEL: s_fptrunc_round_f64_to_f32_upward:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    v_dual_mov_b32 v0, s0 :: v_dual_mov_b32 v1, s1
+; GFX12-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 1), 1
+; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; GFX12-NEXT:    ; return to shader part epilog
+  %res = call float @llvm.fptrunc.round.f32.f64(double %a, metadata !"round.upward")
+  ret float %res
+}
+
+define amdgpu_gs float @s_fptrunc_round_f64_to_f32_downward(double inreg %a) {
+; SDAG-LABEL: s_fptrunc_round_f64_to_f32_downward:
+; SDAG:       ; %bb.0:
+; SDAG-NEXT:    v_mov_b32_e32 v0, s0
+; SDAG-NEXT:    v_mov_b32_e32 v1, s1
+; SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_MODE, 3, 1), 1
+; SDAG-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX11-SDAG-LABEL: s_fptrunc_round_f64_to_f32_downward:
+; GFX11-SDAG:       ; %bb.0:
+; GFX11-SDAG-NEXT:    v_dual_mov_b32 v0, s0 :: v_dual_mov_b32 v1, s1
+; GFX11-SDAG-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_MODE, 3, 1), 1
+; GFX11-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-SDAG-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; GFX11-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX11-GISEL-LABEL: s_fptrunc_round_f64_to_f32_downward:
+; GFX11-GISEL:       ; %bb.0:
+; GFX11-GISEL-NEXT:    v_dual_mov_b32 v0, s0 :: v_dual_mov_b32 v1, s1
+; GFX11-GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_MODE, 3, 1), 1
+; GFX11-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-GISEL-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; GFX11-GISEL-NEXT:    ; return to shader part epilog
+;
+; GISEL-LABEL: s_fptrunc_round_f64_to_f32_downward:
+; GISEL:       ; %bb.0:
+; GISEL-NEXT:    v_mov_b32_e32 v0, s0
+; GISEL-NEXT:    v_mov_b32_e32 v1, s1
+; GISEL-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_MODE, 3, 1), 1
+; GISEL-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-LABEL: s_fptrunc_round_f64_to_f32_downward:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    v_dual_mov_b32 v0, s0 :: v_dual_mov_b32 v1, s1
+; GFX12-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 3, 1), 1
+; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT:    v_cvt_f32_f64_e32 v0, v[0:1]
+; GFX12-NEXT:    ; return to shader part epilog
+  %res = call float @llvm.fptrunc.round.f32.f64(double %a, metadata !"round.downward")
+  ret float %res
+}

>From 1130c9d694a8a2c0ee9c0df591d4a4cb315e944c Mon Sep 17 00:00:00 2001
From: Vang Thao <Vang.Thao at amd.com>
Date: Fri, 12 Jun 2026 11:55:35 -0400
Subject: [PATCH 2/2] Add round towards zero

---
 llvm/lib/Target/AMDGPU/SIInstructions.td      |   4 +
 .../test/CodeGen/AMDGPU/llvm.fptrunc.round.ll | 122 ++++++++++++++++++
 2 files changed, 126 insertions(+)

diff --git a/llvm/lib/Target/AMDGPU/SIInstructions.td b/llvm/lib/Target/AMDGPU/SIInstructions.td
index 8131519a892f5..3ac73ff033b16 100644
--- a/llvm/lib/Target/AMDGPU/SIInstructions.td
+++ b/llvm/lib/Target/AMDGPU/SIInstructions.td
@@ -336,6 +336,10 @@ let True16Predicate = UseRealTrue16Insts in
 def : GCNPat <(f16 (fptrunc_round f32:$src0, (i32 RtzRoundMode))),
      (EXTRACT_SUBREG (V_CVT_PKRTZ_F16_F32_e32 $src0, (IMPLICIT_DEF)), lo16)>;
 
+let SubtargetPredicate = HasSALUFloatInsts, AddedComplexity = 9 in
+def : GCNPat <(f16 (UniformBinFrag<fptrunc_round> f32:$src0, (i32 RtzRoundMode))),
+     (EXTRACT_SUBREG (S_CVT_PK_RTZ_F16_F32 $src0, $src0), lo16)>;
+
 def : GCNPat <(f32 (fptrunc_round f64:$src0, (i32 SupportedRoundMode:$round))),
      (FPTRUNC_ROUND_F32_F64_PSEUDO $src0, (as_hw_round_mode $round))>;
 
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.fptrunc.round.ll b/llvm/test/CodeGen/AMDGPU/llvm.fptrunc.round.ll
index 749f304be2e0f..975f24bd5b969 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.fptrunc.round.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.fptrunc.round.ll
@@ -613,6 +613,58 @@ define amdgpu_gs i32 @s_fptrunc_round_f32_to_f16_downward(float inreg %a, ptr ad
   ret i32 %ret
 }
 
+define amdgpu_gs i32 @s_fptrunc_round_f32_to_f16_towardzero(float inreg %a, ptr addrspace(1) %out) {
+; SDAG-LABEL: s_fptrunc_round_f32_to_f16_towardzero:
+; SDAG:       ; %bb.0:
+; SDAG-NEXT:    v_cvt_pkrtz_f16_f32_e32 v0, s0, v0
+; SDAG-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; SDAG-NEXT:    v_readfirstlane_b32 s0, v0
+; SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX11-SDAG-LABEL: s_fptrunc_round_f32_to_f16_towardzero:
+; GFX11-SDAG:       ; %bb.0:
+; GFX11-SDAG-NEXT:    v_cvt_pk_rtz_f16_f32_e64 v0, s0, s0
+; GFX11-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-SDAG-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GFX11-SDAG-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX11-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX11-GISEL-LABEL: s_fptrunc_round_f32_to_f16_towardzero:
+; GFX11-GISEL:       ; %bb.0:
+; GFX11-GISEL-NEXT:    v_cvt_pk_rtz_f16_f32_e32 v0, s0, v0
+; GFX11-GISEL-NEXT:    v_mov_b16_e32 v0.h, 0
+; GFX11-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-GISEL-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX11-GISEL-NEXT:    ; return to shader part epilog
+;
+; GISEL-LABEL: s_fptrunc_round_f32_to_f16_towardzero:
+; GISEL:       ; %bb.0:
+; GISEL-NEXT:    v_cvt_pkrtz_f16_f32_e32 v0, s0, v0
+; GISEL-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GISEL-NEXT:    v_readfirstlane_b32 s0, v0
+; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: s_fptrunc_round_f32_to_f16_towardzero:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_cvt_pk_rtz_f16_f32 s0, s0, s0
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(SALU_CYCLE_3)
+; GFX12-SDAG-NEXT:    s_and_b32 s0, 0xffff, s0
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: s_fptrunc_round_f32_to_f16_towardzero:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    v_cvt_pk_rtz_f16_f32_e32 v0, s0, v0
+; GFX12-GISEL-NEXT:    v_mov_b16_e32 v0.h, 0
+; GFX12-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-GISEL-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX12-GISEL-NEXT:    s_wait_alu depctr_va_sdst(0)
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
+  %res = call half @llvm.fptrunc.round.f16.f32(float %a, metadata !"round.towardzero")
+  %bitcast = bitcast half %res to i16
+  %ret = zext i16 %bitcast to i32
+  ret i32 %ret
+}
+
 define amdgpu_gs void @s_fptrunc_round_f32_to_f16_upward_multiple_calls(float inreg %a, float inreg %b, ptr addrspace(1) %out) {
 ; SDAG-LABEL: s_fptrunc_round_f32_to_f16_upward_multiple_calls:
 ; SDAG:       ; %bb.0:
@@ -1092,6 +1144,76 @@ define amdgpu_gs <2 x i32> @s_fptrunc_round_v2f32_to_v2f16_downward(<2 x float>
   ret <2 x i32> %ret
 }
 
+define amdgpu_gs <2 x i32> @s_fptrunc_round_v2f32_to_v2f16_towardzero(<2 x float> inreg %a, ptr addrspace(1) %out) {
+; SDAG-LABEL: s_fptrunc_round_v2f32_to_v2f16_towardzero:
+; SDAG:       ; %bb.0:
+; SDAG-NEXT:    v_cvt_pkrtz_f16_f32_e32 v0, s0, v0
+; SDAG-NEXT:    v_cvt_pkrtz_f16_f32_e32 v1, s1, v0
+; SDAG-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; SDAG-NEXT:    v_and_b32_e32 v1, 0xffff, v1
+; SDAG-NEXT:    v_readfirstlane_b32 s0, v0
+; SDAG-NEXT:    v_readfirstlane_b32 s1, v1
+; SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX11-SDAG-LABEL: s_fptrunc_round_v2f32_to_v2f16_towardzero:
+; GFX11-SDAG:       ; %bb.0:
+; GFX11-SDAG-NEXT:    v_cvt_pk_rtz_f16_f32_e64 v0, s0, s0
+; GFX11-SDAG-NEXT:    v_cvt_pk_rtz_f16_f32_e64 v1, s1, s0
+; GFX11-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GFX11-SDAG-NEXT:    v_and_b32_e32 v1, 0xffff, v1
+; GFX11-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX11-SDAG-NEXT:    v_readfirstlane_b32 s1, v1
+; GFX11-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX11-GISEL-LABEL: s_fptrunc_round_v2f32_to_v2f16_towardzero:
+; GFX11-GISEL:       ; %bb.0:
+; GFX11-GISEL-NEXT:    v_cvt_pk_rtz_f16_f32_e32 v0, s0, v0
+; GFX11-GISEL-NEXT:    v_mov_b16_e32 v0.h, 0
+; GFX11-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(VALU_DEP_2)
+; GFX11-GISEL-NEXT:    v_cvt_pk_rtz_f16_f32_e32 v1, s1, v0
+; GFX11-GISEL-NEXT:    v_mov_b16_e32 v1.h, v0.h
+; GFX11-GISEL-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX11-GISEL-NEXT:    v_readfirstlane_b32 s1, v1
+; GFX11-GISEL-NEXT:    ; return to shader part epilog
+;
+; GISEL-LABEL: s_fptrunc_round_v2f32_to_v2f16_towardzero:
+; GISEL:       ; %bb.0:
+; GISEL-NEXT:    v_cvt_pkrtz_f16_f32_e32 v0, s0, v0
+; GISEL-NEXT:    v_cvt_pkrtz_f16_f32_e32 v1, s1, v0
+; GISEL-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GISEL-NEXT:    v_and_b32_e32 v1, 0xffff, v1
+; GISEL-NEXT:    v_readfirstlane_b32 s0, v0
+; GISEL-NEXT:    v_readfirstlane_b32 s1, v1
+; GISEL-NEXT:    ; return to shader part epilog
+;
+; GFX12-SDAG-LABEL: s_fptrunc_round_v2f32_to_v2f16_towardzero:
+; GFX12-SDAG:       ; %bb.0:
+; GFX12-SDAG-NEXT:    s_cvt_pk_rtz_f16_f32 s0, s0, s0
+; GFX12-SDAG-NEXT:    s_cvt_pk_rtz_f16_f32 s1, s1, s1
+; GFX12-SDAG-NEXT:    s_delay_alu instid0(SALU_CYCLE_2) | instskip(NEXT) | instid1(SALU_CYCLE_2)
+; GFX12-SDAG-NEXT:    s_and_b32 s0, 0xffff, s0
+; GFX12-SDAG-NEXT:    s_and_b32 s1, 0xffff, s1
+; GFX12-SDAG-NEXT:    ; return to shader part epilog
+;
+; GFX12-GISEL-LABEL: s_fptrunc_round_v2f32_to_v2f16_towardzero:
+; GFX12-GISEL:       ; %bb.0:
+; GFX12-GISEL-NEXT:    v_cvt_pk_rtz_f16_f32_e32 v0, s0, v0
+; GFX12-GISEL-NEXT:    v_mov_b16_e32 v0.h, 0
+; GFX12-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(VALU_DEP_2)
+; GFX12-GISEL-NEXT:    v_cvt_pk_rtz_f16_f32_e32 v1, s1, v0
+; GFX12-GISEL-NEXT:    v_mov_b16_e32 v1.h, v0.h
+; GFX12-GISEL-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX12-GISEL-NEXT:    v_readfirstlane_b32 s1, v1
+; GFX12-GISEL-NEXT:    s_wait_alu depctr_va_sdst(0)
+; GFX12-GISEL-NEXT:    ; return to shader part epilog
+  %res = call <2 x half> @llvm.fptrunc.round.v2f16.v2f32(<2 x float> %a, metadata !"round.towardzero")
+  %bitcast = bitcast <2 x half> %res to <2 x i16>
+  %ret = zext <2 x i16> %bitcast to <2 x i32>
+  ret <2 x i32> %ret
+}
+
 define amdgpu_gs void @s_fptrunc_round_v2f32_to_v2f16_upward_multiple_calls(<2 x float> inreg %a, <2 x float> inreg %b, ptr addrspace(1) %out) {
 ; SDAG-LABEL: s_fptrunc_round_v2f32_to_v2f16_upward_multiple_calls:
 ; SDAG:       ; %bb.0:



More information about the llvm-commits mailing list