[llvm] [AMDGPU] SIFoldOperands: Add REQ_SEQUENCE subregister use fold (PR #188451)

Frederik Harwath via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 28 08:01:14 PDT 2026


================
@@ -0,0 +1,114 @@
+# NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs -mcpu=gfx900 -start-before si-fold-operands -o - %s | FileCheck --check-prefix=GCN %s
+
+--- |
+  define amdgpu_kernel void @sdwa_reg_sequence_add_shr_i32() {
+  ; GCN-LABEL: sdwa_reg_sequence_add_shr_i32:
+  ; GCN:       ; %bb.0:
+  ; GCN-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+  ; GCN-NEXT:    flat_load_dword v2, v[2:3] glc
+  ; GCN-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
+  ; GCN-NEXT:    buffer_wbinvl1_vol
+  ; GCN-NEXT:    v_mov_b32_e32 v3, 0x7b
+  ; GCN-NEXT:    v_add_co_u32_sdwa v2, vcc, v3, v2 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:DWORD src1_sel:WORD_1
+  ; GCN-NEXT:    flat_store_dword v[0:1], v2
+  ; GCN-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
+  ; GCN-NEXT:    s_setpc_b64 s[30:31]
+    ret void
+  }
+
+  define amdgpu_kernel void @sdwa_reg_sequence_and_add_co() {
+  ; GCN-LABEL: sdwa_reg_sequence_and_add_co:
+  ; GCN:       ; %bb.0:
+  ; GCN-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+  ; GCN-NEXT:    v_add_u32_e32 v1, 10, v0
+  ; GCN-NEXT:    v_add_u32_e32 v0, 20, v0
+  ; GCN-NEXT:    v_add_co_u32_sdwa v0, vcc, v1, v0 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:DWORD src1_sel:BYTE_0
+  ; GCN-NEXT:    v_addc_co_u32_e64 v1, s[0:1], 0, 0, vcc
+  ; GCN-NEXT:    global_store_dwordx2 v[0:1], v[0:1], off
+  ; GCN-NEXT:    s_endpgm
+    ret void
+  }
+
+  define amdgpu_kernel void @sdwa_reg_sequence_composed_subregs() {
+  ; GCN-LABEL: sdwa_reg_sequence_composed_subregs:
+  ; GCN:       ; %bb.0:
+  ; GCN-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+  ; GCN-NEXT:    v_add_u32_e32 v0, 20, v2
+  ; GCN-NEXT:    v_mov_b32_e32 v1, 0
+  ; GCN-NEXT:    v_add_co_u32_sdwa v0, vcc, v1, v0 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:DWORD src1_sel:BYTE_0
+  ; GCN-NEXT:    v_addc_co_u32_e64 v1, s[0:1], 0, 0, vcc
+  ; GCN-NEXT:    global_store_dwordx2 v[0:1], v[0:1], off
+  ; GCN-NEXT:    s_endpgm
+    ret void
+  }
+...
+
+---
+name: sdwa_reg_sequence_add_shr_i32
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $vgpr0_vgpr1, $vgpr2_vgpr3, $sgpr30_sgpr31
+
+    %0:vreg_64 = COPY $vgpr0_vgpr1
+    %1:vreg_64 = COPY $vgpr2_vgpr3
+    %2:sreg_64 = COPY $sgpr30_sgpr31
+    %3:vgpr_32 = FLAT_LOAD_DWORD %1, 0, 0, implicit $exec, implicit $flat_scr
+    %4:sreg_32_xm0 = S_MOV_B32 123
+    %5:vgpr_32 = V_LSHRREV_B32_e64 16, %3, implicit $exec
+    %6:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+    %7:vreg_64 = REG_SEQUENCE %5, %subreg.sub0, %6, %subreg.sub1
+    %8:vgpr_32 = V_ADD_CO_U32_e32 %4, killed %7.sub0, implicit-def $vcc, implicit $exec
+    FLAT_STORE_DWORD %0, %8, 0, 0, implicit $exec, implicit $flat_scr
+    $sgpr30_sgpr31 = COPY %2
+    S_SETPC_B64_return $sgpr30_sgpr31
+...
+
+---
+name: sdwa_reg_sequence_and_add_co
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $vgpr0
+
+    %0:vgpr_32 = COPY $vgpr0
+    %1:vgpr_32 = V_ADD_U32_e64 %0, 10, 0, implicit $exec
+    %2:vgpr_32 = V_ADD_U32_e64 %0, 20, 0, implicit $exec
+    %3:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+    %4:vreg_64 = REG_SEQUENCE %1, %subreg.sub0, %3, %subreg.sub1
+    %5:sreg_32 = S_MOV_B32 255
+    %6:vgpr_32 = V_AND_B32_e64 killed %2, killed %5, implicit $exec
+    %7:vreg_64 = REG_SEQUENCE %6, %subreg.sub0, %3, %subreg.sub1
+    %8:vgpr_32, %9:sreg_64_xexec = V_ADD_CO_U32_e64 %4.sub0, %7.sub0, 0, implicit $exec
+    %10:vgpr_32, dead %11:sreg_64_xexec = V_ADDC_U32_e64 0, 0, killed %9, 0, implicit $exec
----------------
frederik-h wrote:

> > In any case the correct solution looks like rewrite registers to avoid reg_sequences, not add additional logic in every pass to look at transitive users of reg_sequence
> 
> That's a good point, I think. For some reason, there were many seemingly redundant REG_SEQUENCEs in another example I had right after DAG->DAG Isel. I have not looked further into that example.. yet..

I have a patch that adds a similar optimization (not integrated with the existing copy optimizations where it does not seem to fit in, but as an additional step) to the one from this PR to peephole-opt. That's probably desirable then? I noticed that the register pressure issue that we discussed elsewhere is essentially caused by returning subregister sources to the coalescable copy optimization for REG_SEQUENCES; see my draft PR #194628 .

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


More information about the llvm-commits mailing list