[llvm] [AMDGPU] Improve codegen for uniform f16<-->i32 conversions (PR #176833)

Syadus Sefat via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 21 10:16:25 PST 2026


https://github.com/mssefat updated https://github.com/llvm/llvm-project/pull/176833

>From 46f534ee3c36ac922aa76927a040c34ce6627f2f Mon Sep 17 00:00:00 2001
From: mssefat <syadus.sefat at gmail.com>
Date: Mon, 19 Jan 2026 16:43:34 -0600
Subject: [PATCH] [AMDGPU] Improve codegen for uniform f16<-->i32 conversions

---
 llvm/lib/Target/AMDGPU/SOPInstructions.td     | 11 +++
 llvm/test/CodeGen/AMDGPU/scalar-float-sop1.ll | 95 ++++++-------------
 2 files changed, 41 insertions(+), 65 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SOPInstructions.td b/llvm/lib/Target/AMDGPU/SOPInstructions.td
index 99b352bdf6765..030496e1ca8dd 100644
--- a/llvm/lib/Target/AMDGPU/SOPInstructions.td
+++ b/llvm/lib/Target/AMDGPU/SOPInstructions.td
@@ -475,6 +475,17 @@ let SubtargetPredicate = HasSALUFloatInsts, AddedComplexity = 9 in {
                  (S_CVT_I32_F32 $src0)>;
     def : GCNPat<(i16 (UniformUnaryFrag<fp_to_uint> f32:$src0)),
                  (S_CVT_U32_F32 $src0)>;
+    // f16 -> i32 : form chain f16 -> f32 -> i32
+    def : GCNPat<(i32 (UniformUnaryFrag<fp_to_sint> f16:$src0)),
+                 (S_CVT_I32_F32 (S_CVT_F32_F16 $src0))>;
+    def : GCNPat<(i32 (UniformUnaryFrag<fp_to_uint> f16:$src0)),
+                 (S_CVT_U32_F32 (S_CVT_F32_F16 $src0))>;
+
+    // i32 -> f16 : form chain i32 -> f32 -> f16
+    def : GCNPat<(f16 (UniformUnaryFrag<sint_to_fp> i32:$src0)),
+                 (S_CVT_F16_F32 (S_CVT_F32_I32 $src0))>;
+    def : GCNPat<(f16 (UniformUnaryFrag<uint_to_fp> i32:$src0)),
+                 (S_CVT_F16_F32 (S_CVT_F32_U32 $src0))>;
 }
 
 let hasSideEffects = 1 in {
diff --git a/llvm/test/CodeGen/AMDGPU/scalar-float-sop1.ll b/llvm/test/CodeGen/AMDGPU/scalar-float-sop1.ll
index b28f1010c3c69..3fd3ba18d3847 100644
--- a/llvm/test/CodeGen/AMDGPU/scalar-float-sop1.ll
+++ b/llvm/test/CodeGen/AMDGPU/scalar-float-sop1.ll
@@ -1,8 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc -global-isel=0 -mtriple=amdgcn -mcpu=gfx1150 < %s | FileCheck %s --check-prefixes=CHECK,SDAG,SDAG-GFX11
-; RUN: llc -global-isel=1 -mtriple=amdgcn -mcpu=gfx1150 < %s | FileCheck %s --check-prefixes=CHECK,GISEL,GISEL-GFX11
-; RUN: llc -global-isel=0 -mtriple=amdgcn -mcpu=gfx1200 < %s | FileCheck %s --check-prefixes=CHECK,SDAG,SDAG-GFX12
-; RUN: llc -global-isel=1 -mtriple=amdgcn -mcpu=gfx1200 < %s | FileCheck %s --check-prefixes=CHECK,GISEL,GISEL-GFX12
+; RUN: llc -global-isel=0 -mtriple=amdgcn -mcpu=gfx1150 < %s | FileCheck %s --check-prefixes=CHECK,SDAG
+; RUN: llc -global-isel=1 -mtriple=amdgcn -mcpu=gfx1150 < %s | FileCheck %s --check-prefixes=CHECK,GISEL-GFX11
+; RUN: llc -global-isel=0 -mtriple=amdgcn -mcpu=gfx1200 < %s | FileCheck %s --check-prefixes=CHECK,SDAG
+; RUN: llc -global-isel=1 -mtriple=amdgcn -mcpu=gfx1200 < %s | FileCheck %s --check-prefixes=CHECK,GISEL-GFX12
 
 define amdgpu_vs float @sitofp_i32_to_f32(i32 inreg %val) {
 ; CHECK-LABEL: sitofp_i32_to_f32:
@@ -185,13 +185,12 @@ define amdgpu_vs half @frint_f16(half inreg %val) {
 }
 
 define amdgpu_vs i32 @fptosi_f16_to_i32(half inreg %x) {
-; SDAG-GFX11-LABEL: fptosi_f16_to_i32:
-; SDAG-GFX11:       ; %bb.0:
-; SDAG-GFX11-NEXT:    v_cvt_f32_f16_e32 v0, s0
-; SDAG-GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
-; SDAG-GFX11-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; SDAG-GFX11-NEXT:    v_readfirstlane_b32 s0, v0
-; SDAG-GFX11-NEXT:    ; return to shader part epilog
+; SDAG-LABEL: fptosi_f16_to_i32:
+; SDAG:       ; %bb.0:
+; SDAG-NEXT:    s_cvt_f32_f16 s0, s0
+; SDAG-NEXT:    s_delay_alu instid0(SALU_CYCLE_3)
+; SDAG-NEXT:    s_cvt_i32_f32 s0, s0
+; SDAG-NEXT:    ; return to shader part epilog
 ;
 ; GISEL-GFX11-LABEL: fptosi_f16_to_i32:
 ; GISEL-GFX11:       ; %bb.0:
@@ -201,15 +200,6 @@ define amdgpu_vs i32 @fptosi_f16_to_i32(half inreg %x) {
 ; GISEL-GFX11-NEXT:    v_readfirstlane_b32 s0, v0
 ; GISEL-GFX11-NEXT:    ; return to shader part epilog
 ;
-; SDAG-GFX12-LABEL: fptosi_f16_to_i32:
-; SDAG-GFX12:       ; %bb.0:
-; SDAG-GFX12-NEXT:    v_cvt_f32_f16_e32 v0, s0
-; SDAG-GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
-; SDAG-GFX12-NEXT:    v_cvt_i32_f32_e32 v0, v0
-; SDAG-GFX12-NEXT:    v_readfirstlane_b32 s0, v0
-; SDAG-GFX12-NEXT:    s_wait_alu depctr_va_sdst(0)
-; SDAG-GFX12-NEXT:    ; return to shader part epilog
-;
 ; GISEL-GFX12-LABEL: fptosi_f16_to_i32:
 ; GISEL-GFX12:       ; %bb.0:
 ; GISEL-GFX12-NEXT:    v_cvt_f32_f16_e32 v0, s0
@@ -223,13 +213,12 @@ define amdgpu_vs i32 @fptosi_f16_to_i32(half inreg %x) {
 }
 
 define amdgpu_vs i32 @fptoui_f16_to_i32(half inreg %x) {
-; SDAG-GFX11-LABEL: fptoui_f16_to_i32:
-; SDAG-GFX11:       ; %bb.0:
-; SDAG-GFX11-NEXT:    v_cvt_f32_f16_e32 v0, s0
-; SDAG-GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
-; SDAG-GFX11-NEXT:    v_cvt_u32_f32_e32 v0, v0
-; SDAG-GFX11-NEXT:    v_readfirstlane_b32 s0, v0
-; SDAG-GFX11-NEXT:    ; return to shader part epilog
+; SDAG-LABEL: fptoui_f16_to_i32:
+; SDAG:       ; %bb.0:
+; SDAG-NEXT:    s_cvt_f32_f16 s0, s0
+; SDAG-NEXT:    s_delay_alu instid0(SALU_CYCLE_3)
+; SDAG-NEXT:    s_cvt_u32_f32 s0, s0
+; SDAG-NEXT:    ; return to shader part epilog
 ;
 ; GISEL-GFX11-LABEL: fptoui_f16_to_i32:
 ; GISEL-GFX11:       ; %bb.0:
@@ -239,15 +228,6 @@ define amdgpu_vs i32 @fptoui_f16_to_i32(half inreg %x) {
 ; GISEL-GFX11-NEXT:    v_readfirstlane_b32 s0, v0
 ; GISEL-GFX11-NEXT:    ; return to shader part epilog
 ;
-; SDAG-GFX12-LABEL: fptoui_f16_to_i32:
-; SDAG-GFX12:       ; %bb.0:
-; SDAG-GFX12-NEXT:    v_cvt_f32_f16_e32 v0, s0
-; SDAG-GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
-; SDAG-GFX12-NEXT:    v_cvt_u32_f32_e32 v0, v0
-; SDAG-GFX12-NEXT:    v_readfirstlane_b32 s0, v0
-; SDAG-GFX12-NEXT:    s_wait_alu depctr_va_sdst(0)
-; SDAG-GFX12-NEXT:    ; return to shader part epilog
-;
 ; GISEL-GFX12-LABEL: fptoui_f16_to_i32:
 ; GISEL-GFX12:       ; %bb.0:
 ; GISEL-GFX12-NEXT:    v_cvt_f32_f16_e32 v0, s0
@@ -261,12 +241,13 @@ define amdgpu_vs i32 @fptoui_f16_to_i32(half inreg %x) {
 }
 
 define amdgpu_vs half @sitofp_i32_to_f16(i32 inreg %x) {
-; SDAG-GFX11-LABEL: sitofp_i32_to_f16:
-; SDAG-GFX11:       ; %bb.0:
-; SDAG-GFX11-NEXT:    v_cvt_f32_i32_e32 v0, s0
-; SDAG-GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; SDAG-GFX11-NEXT:    v_cvt_f16_f32_e32 v0.l, v0
-; SDAG-GFX11-NEXT:    ; return to shader part epilog
+; SDAG-LABEL: sitofp_i32_to_f16:
+; SDAG:       ; %bb.0:
+; SDAG-NEXT:    s_cvt_f32_i32 s0, s0
+; SDAG-NEXT:    s_delay_alu instid0(SALU_CYCLE_3) | instskip(NEXT) | instid1(SALU_CYCLE_3)
+; SDAG-NEXT:    s_cvt_f16_f32 s0, s0
+; SDAG-NEXT:    v_mov_b32_e32 v0, s0
+; SDAG-NEXT:    ; return to shader part epilog
 ;
 ; GISEL-GFX11-LABEL: sitofp_i32_to_f16:
 ; GISEL-GFX11:       ; %bb.0:
@@ -275,13 +256,6 @@ define amdgpu_vs half @sitofp_i32_to_f16(i32 inreg %x) {
 ; GISEL-GFX11-NEXT:    v_cvt_f16_f32_e32 v0.l, v0
 ; GISEL-GFX11-NEXT:    ; return to shader part epilog
 ;
-; SDAG-GFX12-LABEL: sitofp_i32_to_f16:
-; SDAG-GFX12:       ; %bb.0:
-; SDAG-GFX12-NEXT:    v_cvt_f32_i32_e32 v0, s0
-; SDAG-GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; SDAG-GFX12-NEXT:    v_cvt_f16_f32_e32 v0, v0
-; SDAG-GFX12-NEXT:    ; return to shader part epilog
-;
 ; GISEL-GFX12-LABEL: sitofp_i32_to_f16:
 ; GISEL-GFX12:       ; %bb.0:
 ; GISEL-GFX12-NEXT:    v_cvt_f32_i32_e32 v0, s0
@@ -293,12 +267,13 @@ define amdgpu_vs half @sitofp_i32_to_f16(i32 inreg %x) {
 }
 
 define amdgpu_vs half @uitofp_i32_to_f16(i32 inreg %x) {
-; SDAG-GFX11-LABEL: uitofp_i32_to_f16:
-; SDAG-GFX11:       ; %bb.0:
-; SDAG-GFX11-NEXT:    v_cvt_f32_u32_e32 v0, s0
-; SDAG-GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; SDAG-GFX11-NEXT:    v_cvt_f16_f32_e32 v0.l, v0
-; SDAG-GFX11-NEXT:    ; return to shader part epilog
+; SDAG-LABEL: uitofp_i32_to_f16:
+; SDAG:       ; %bb.0:
+; SDAG-NEXT:    s_cvt_f32_u32 s0, s0
+; SDAG-NEXT:    s_delay_alu instid0(SALU_CYCLE_3) | instskip(NEXT) | instid1(SALU_CYCLE_3)
+; SDAG-NEXT:    s_cvt_f16_f32 s0, s0
+; SDAG-NEXT:    v_mov_b32_e32 v0, s0
+; SDAG-NEXT:    ; return to shader part epilog
 ;
 ; GISEL-GFX11-LABEL: uitofp_i32_to_f16:
 ; GISEL-GFX11:       ; %bb.0:
@@ -307,13 +282,6 @@ define amdgpu_vs half @uitofp_i32_to_f16(i32 inreg %x) {
 ; GISEL-GFX11-NEXT:    v_cvt_f16_f32_e32 v0.l, v0
 ; GISEL-GFX11-NEXT:    ; return to shader part epilog
 ;
-; SDAG-GFX12-LABEL: uitofp_i32_to_f16:
-; SDAG-GFX12:       ; %bb.0:
-; SDAG-GFX12-NEXT:    v_cvt_f32_u32_e32 v0, s0
-; SDAG-GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; SDAG-GFX12-NEXT:    v_cvt_f16_f32_e32 v0, v0
-; SDAG-GFX12-NEXT:    ; return to shader part epilog
-;
 ; GISEL-GFX12-LABEL: uitofp_i32_to_f16:
 ; GISEL-GFX12:       ; %bb.0:
 ; GISEL-GFX12-NEXT:    v_cvt_f32_u32_e32 v0, s0
@@ -332,6 +300,3 @@ declare half @llvm.ceil.f16(half)
 declare half @llvm.floor.f16(half)
 declare half @llvm.trunc.f16(half)
 declare half @llvm.rint.f16(half)
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; GISEL: {{.*}}
-; SDAG: {{.*}}



More information about the llvm-commits mailing list