[llvm] [AMDGPU] Let SIOptimizeVGPRLiveRange handle AV-class virtual registers (PR #226527)

Pablo Reble via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 28 14:47:34 PDT 2026


https://github.com/reble updated https://github.com/llvm/llvm-project/pull/226527

>From d7ee1a38ace51188faf200eff32ffa72ecb9e65b Mon Sep 17 00:00:00 2001
From: Pablo Reble <pablo.reble at amd.com>
Date: Fri, 25 Sep 2026 10:11:55 -0500
Subject: [PATCH 1/2] [AMDGPU] Let SIOptimizeVGPRLiveRange handle AV-class
 virtual registers

---
 .../Target/AMDGPU/SIOptimizeVGPRLiveRange.cpp |  20 +-
 .../test/CodeGen/AMDGPU/a-v-flat-atomicrmw.ll |   2 +
 .../si-opt-vgpr-liverange-av-classes.mir      | 330 ++++++++++++++++++
 3 files changed, 347 insertions(+), 5 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-av-classes.mir

diff --git a/llvm/lib/Target/AMDGPU/SIOptimizeVGPRLiveRange.cpp b/llvm/lib/Target/AMDGPU/SIOptimizeVGPRLiveRange.cpp
index c72b40e14ee0e..e7755de608ade 100644
--- a/llvm/lib/Target/AMDGPU/SIOptimizeVGPRLiveRange.cpp
+++ b/llvm/lib/Target/AMDGPU/SIOptimizeVGPRLiveRange.cpp
@@ -108,6 +108,9 @@ class SIOptimizeVGPRLiveRange {
   // in.
   bool isLiveIntoMBB(Register Reg, const MachineBasicBlock *MBB) const;
 
+  // Is \p Reg a virtual register of a vector class without SGPRs?
+  bool isVectorVirtReg(Register Reg) const;
+
 public:
   SIOptimizeVGPRLiveRange(LiveIntervals *LIS, LiveVariables *LV,
                           MachineDominatorTree *MDT, MachineLoopInfo *Loops)
@@ -217,6 +220,13 @@ bool SIOptimizeVGPRLiveRange::isLiveIntoMBB(
   return LIS->isLiveInToMBB(LI, MBB);
 }
 
+bool SIOptimizeVGPRLiveRange::isVectorVirtReg(Register Reg) const {
+  if (!Reg.isVirtual())
+    return false;
+  const TargetRegisterClass *RC = MRI->getRegClass(Reg);
+  return TRI->hasVectorRegisters(RC) && !TRI->hasSGPRs(RC);
+}
+
 void SIOptimizeVGPRLiveRange::collectElseRegionBlocks(
     MachineBasicBlock *Flow, MachineBasicBlock *Endif,
     SmallSetVector<MachineBasicBlock *, 16> &Blocks) const {
@@ -274,8 +284,8 @@ void SIOptimizeVGPRLiveRange::collectCandidateRegisters(
           continue;
 
         Register MOReg = MO.getReg();
-        // We can only optimize AGPR/VGPR virtual register
-        if (MOReg.isPhysical() || !TRI->isVectorRegister(*MRI, MOReg))
+        // We can only optimize VGPR/AGPR/AV virtual registers.
+        if (!isVectorVirtReg(MOReg))
           continue;
 
         if (MO.readsReg()) {
@@ -313,7 +323,7 @@ void SIOptimizeVGPRLiveRange::collectCandidateRegisters(
         continue;
 
       Register Reg = MO.getReg();
-      if (Reg.isPhysical() || !TRI->isVectorRegister(*MRI, Reg))
+      if (!isVectorVirtReg(Reg))
         continue;
 
       if (isLiveIntoMBB(Reg, Endif)) {
@@ -396,8 +406,8 @@ void SIOptimizeVGPRLiveRange::collectWaterfallCandidateRegisters(
         continue;
 
       Register MOReg = MO.getReg();
-      // We can only optimize AGPR/VGPR virtual register
-      if (MOReg.isPhysical() || !TRI->isVectorRegister(*MRI, MOReg))
+      // We can only optimize VGPR/AGPR/AV virtual registers.
+      if (!isVectorVirtReg(MOReg))
         continue;
 
       if (MO.readsReg()) {
diff --git a/llvm/test/CodeGen/AMDGPU/a-v-flat-atomicrmw.ll b/llvm/test/CodeGen/AMDGPU/a-v-flat-atomicrmw.ll
index cb59bb925aab0..cd8d0122263b5 100644
--- a/llvm/test/CodeGen/AMDGPU/a-v-flat-atomicrmw.ll
+++ b/llvm/test/CodeGen/AMDGPU/a-v-flat-atomicrmw.ll
@@ -1519,6 +1519,7 @@ define void @flat_atomic_xchg_i64_noret_av(ptr %ptr) #0 {
 ; GFX90A-NEXT:    buffer_invl2
 ; GFX90A-NEXT:    buffer_wbinvl1_vol
 ; GFX90A-NEXT:    ; implicit-def: $vgpr0_vgpr1
+; GFX90A-NEXT:    ; implicit-def: $vgpr2_vgpr3
 ; GFX90A-NEXT:    s_andn2_saveexec_b64 s[4:5], s[4:5]
 ; GFX90A-NEXT:    s_cbranch_execz .LBB20_2
 ; GFX90A-NEXT:  .LBB20_4: ; %atomicrmw.private
@@ -1554,6 +1555,7 @@ define void @flat_atomic_xchg_i64_noret_av(ptr %ptr) #0 {
 ; GFX950-NEXT:    s_waitcnt vmcnt(0) lgkmcnt(0)
 ; GFX950-NEXT:    buffer_inv sc0 sc1
 ; GFX950-NEXT:    ; implicit-def: $vgpr0_vgpr1
+; GFX950-NEXT:    ; implicit-def: $vgpr2_vgpr3
 ; GFX950-NEXT:    s_andn2_saveexec_b64 s[0:1], s[0:1]
 ; GFX950-NEXT:    s_cbranch_execz .LBB20_2
 ; GFX950-NEXT:  .LBB20_4: ; %atomicrmw.private
diff --git a/llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-av-classes.mir b/llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-av-classes.mir
new file mode 100644
index 0000000000000..d331d81d14e80
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-av-classes.mir
@@ -0,0 +1,330 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=amdgpu9.0a -run-pass=si-opt-vgpr-liverange -verify-machineinstrs %s -o - | FileCheck %s
+# RUN: llc -mtriple=amdgpu9.0a -passes=si-opt-vgpr-liverange %s -o - | FileCheck %s
+
+# SIOptimizeVGPRLiveRange should handle virtual registers with AV classes the
+# same way as VGPR classes. %0 is killed in the else block, so its live range
+# through the else block is shortened with an undef PHI input in the Flow block.
+
+---
+name:            else_av_32
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: else_av_32
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.3(0x40000000), %bb.1(0x40000000)
+  ; CHECK-NEXT:   liveins: $vgpr0, $vgpr1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:vgpr_32 = COPY killed $vgpr1
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:vgpr_32 = COPY killed $vgpr0
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:av_32 = COPY killed [[COPY]]
+  ; CHECK-NEXT:   [[V_CMP_GT_I32_e64_:%[0-9]+]]:sreg_64 = V_CMP_GT_I32_e64 6, killed [[COPY1]], implicit $exec
+  ; CHECK-NEXT:   [[SI_IF:%[0-9]+]]:sreg_64 = SI_IF killed [[V_CMP_GT_I32_e64_]], %bb.1, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   S_BRANCH %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.4(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:av_32 = PHI undef %6:av_32, %bb.0, %7, %bb.3
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:av_32 = PHI [[COPY2]], %bb.0, undef %16:av_32, %bb.3
+  ; CHECK-NEXT:   [[SI_ELSE:%[0-9]+]]:sreg_64 = SI_ELSE killed [[SI_IF]], %bb.4, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   S_BRANCH %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:vgpr_32 = COPY killed [[PHI1]]
+  ; CHECK-NEXT:   [[V_ADD_F32_e32_:%[0-9]+]]:vgpr_32 = nofpexcept V_ADD_F32_e32 killed [[COPY3]], [[COPY3]], implicit $mode, implicit $exec
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:av_32 = COPY killed [[V_ADD_F32_e32_]]
+  ; CHECK-NEXT:   S_BRANCH %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY5:%[0-9]+]]:vgpr_32 = COPY killed [[COPY2]]
+  ; CHECK-NEXT:   [[V_MUL_F32_e32_:%[0-9]+]]:vgpr_32 = nofpexcept V_MUL_F32_e32 1077936128, killed [[COPY5]], implicit $mode, implicit $exec
+  ; CHECK-NEXT:   [[COPY6:%[0-9]+]]:av_32 = COPY killed [[V_MUL_F32_e32_]]
+  ; CHECK-NEXT:   S_BRANCH %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4:
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:av_32 = PHI [[PHI]], %bb.1, [[COPY4]], %bb.2
+  ; CHECK-NEXT:   SI_END_CF killed [[SI_ELSE]], implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   $vgpr0 = COPY killed [[PHI2]]
+  ; CHECK-NEXT:   SI_RETURN_TO_EPILOG killed $vgpr0
+  bb.0:
+    successors: %bb.3(0x40000000), %bb.1(0x40000000)
+    liveins: $vgpr0, $vgpr1
+
+    %10:vgpr_32 = COPY killed $vgpr1
+    %7:vgpr_32 = COPY killed $vgpr0
+    %0:av_32 = COPY killed %10
+    %14:sreg_64 = V_CMP_GT_I32_e64 6, killed %7, implicit $exec
+    %1:sreg_64 = SI_IF killed %14, %bb.1, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+    S_BRANCH %bb.3
+
+  bb.1:
+    successors: %bb.2(0x40000000), %bb.4(0x40000000)
+
+    %2:av_32 = PHI undef %11:av_32, %bb.0, %5, %bb.3
+    %3:sreg_64 = SI_ELSE killed %1, %bb.4, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+    S_BRANCH %bb.2
+
+  bb.2:
+    successors: %bb.4(0x80000000)
+
+    %20:vgpr_32 = COPY %0
+    %17:vgpr_32 = nofpexcept V_ADD_F32_e32 %20, %20, implicit $mode, implicit $exec
+    %4:av_32 = COPY killed %17
+    S_BRANCH %bb.4
+
+  bb.3:
+    successors: %bb.1(0x80000000)
+
+    %21:vgpr_32 = COPY %0
+    %16:vgpr_32 = nofpexcept V_MUL_F32_e32 1077936128, %21, implicit $mode, implicit $exec
+    %5:av_32 = COPY killed %16
+    S_BRANCH %bb.1
+
+  bb.4:
+    %6:av_32 = PHI %2, %bb.1, %4, %bb.2
+    SI_END_CF killed %3, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+    $vgpr0 = COPY killed %6
+    SI_RETURN_TO_EPILOG killed $vgpr0
+...
+
+---
+name:            else_av_64
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: else_av_64
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.3(0x40000000), %bb.1(0x40000000)
+  ; CHECK-NEXT:   liveins: $vgpr0, $vgpr2_vgpr3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:vreg_64_align2 = COPY killed $vgpr2_vgpr3
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:vgpr_32 = COPY killed $vgpr0
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:av_64_align2 = COPY killed [[COPY]]
+  ; CHECK-NEXT:   [[V_CMP_GT_I32_e64_:%[0-9]+]]:sreg_64 = V_CMP_GT_I32_e64 6, killed [[COPY1]], implicit $exec
+  ; CHECK-NEXT:   [[SI_IF:%[0-9]+]]:sreg_64 = SI_IF killed [[V_CMP_GT_I32_e64_]], %bb.1, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   S_BRANCH %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.4(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:av_64_align2 = PHI undef %6:av_64_align2, %bb.0, %7, %bb.3
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:av_64_align2 = PHI [[COPY2]], %bb.0, undef %16:av_64_align2, %bb.3
+  ; CHECK-NEXT:   [[SI_ELSE:%[0-9]+]]:sreg_64 = SI_ELSE killed [[SI_IF]], %bb.4, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   S_BRANCH %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:vreg_64_align2 = COPY killed [[PHI1]]
+  ; CHECK-NEXT:   [[V_ADD_F64_e64_:%[0-9]+]]:vreg_64_align2 = nofpexcept V_ADD_F64_e64 0, killed [[COPY3]], 0, [[COPY3]], 0, 0, implicit $mode, implicit $exec
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:av_64_align2 = COPY killed [[V_ADD_F64_e64_]]
+  ; CHECK-NEXT:   S_BRANCH %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY5:%[0-9]+]]:vreg_64_align2 = COPY killed [[COPY2]]
+  ; CHECK-NEXT:   [[V_MUL_F64_e64_:%[0-9]+]]:vreg_64_align2 = nofpexcept V_MUL_F64_e64 0, killed [[COPY5]], 0, [[COPY5]], 0, 0, implicit $mode, implicit $exec
+  ; CHECK-NEXT:   [[COPY6:%[0-9]+]]:av_64_align2 = COPY killed [[V_MUL_F64_e64_]]
+  ; CHECK-NEXT:   S_BRANCH %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4:
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:av_64_align2 = PHI [[PHI]], %bb.1, [[COPY4]], %bb.2
+  ; CHECK-NEXT:   SI_END_CF killed [[SI_ELSE]], implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   $vgpr0_vgpr1 = COPY killed [[PHI2]]
+  ; CHECK-NEXT:   SI_RETURN_TO_EPILOG killed $vgpr0_vgpr1
+  bb.0:
+    successors: %bb.3(0x40000000), %bb.1(0x40000000)
+    liveins: $vgpr0, $vgpr2_vgpr3
+
+    %10:vreg_64_align2 = COPY killed $vgpr2_vgpr3
+    %7:vgpr_32 = COPY killed $vgpr0
+    %0:av_64_align2 = COPY killed %10
+    %14:sreg_64 = V_CMP_GT_I32_e64 6, killed %7, implicit $exec
+    %1:sreg_64 = SI_IF killed %14, %bb.1, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+    S_BRANCH %bb.3
+
+  bb.1:
+    successors: %bb.2(0x40000000), %bb.4(0x40000000)
+
+    %2:av_64_align2 = PHI undef %11:av_64_align2, %bb.0, %5, %bb.3
+    %3:sreg_64 = SI_ELSE killed %1, %bb.4, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+    S_BRANCH %bb.2
+
+  bb.2:
+    successors: %bb.4(0x80000000)
+
+    %20:vreg_64_align2 = COPY %0
+    %17:vreg_64_align2 = nofpexcept V_ADD_F64_e64 0, %20, 0, %20, 0, 0, implicit $mode, implicit $exec
+    %4:av_64_align2 = COPY killed %17
+    S_BRANCH %bb.4
+
+  bb.3:
+    successors: %bb.1(0x80000000)
+
+    %21:vreg_64_align2 = COPY %0
+    %16:vreg_64_align2 = nofpexcept V_MUL_F64_e64 0, %21, 0, %21, 0, 0, implicit $mode, implicit $exec
+    %5:av_64_align2 = COPY killed %16
+    S_BRANCH %bb.1
+
+  bb.4:
+    %6:av_64_align2 = PHI %2, %bb.1, %4, %bb.2
+    SI_END_CF killed %3, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+    $vgpr0_vgpr1 = COPY killed %6
+    SI_RETURN_TO_EPILOG killed $vgpr0_vgpr1
+...
+
+# %0 has no use in the else block other than the incoming value of the endif
+# PHI. It is found by the endif PHI scan and gets an undef PHI input in the
+# Flow block.
+---
+name:            endif_phi_av_32
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: endif_phi_av_32
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.3(0x40000000), %bb.1(0x40000000)
+  ; CHECK-NEXT:   liveins: $vgpr0, $vgpr1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:vgpr_32 = COPY killed $vgpr1
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:vgpr_32 = COPY killed $vgpr0
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:av_32 = COPY killed [[COPY]]
+  ; CHECK-NEXT:   [[V_CMP_GT_I32_e64_:%[0-9]+]]:sreg_64 = V_CMP_GT_I32_e64 6, [[COPY1]], implicit $exec
+  ; CHECK-NEXT:   [[SI_IF:%[0-9]+]]:sreg_64 = SI_IF killed [[V_CMP_GT_I32_e64_]], %bb.1, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   S_BRANCH %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.4(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:av_32 = PHI undef %6:av_32, %bb.0, %7, %bb.3
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:av_32 = PHI [[COPY2]], %bb.0, undef %12:av_32, %bb.3
+  ; CHECK-NEXT:   [[SI_ELSE:%[0-9]+]]:sreg_64 = SI_ELSE killed [[SI_IF]], %bb.4, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   S_BRANCH %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   S_BRANCH %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[V_MUL_F32_e32_:%[0-9]+]]:vgpr_32 = nofpexcept V_MUL_F32_e32 1077936128, killed [[COPY1]], implicit $mode, implicit $exec
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:av_32 = COPY killed [[V_MUL_F32_e32_]]
+  ; CHECK-NEXT:   S_BRANCH %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4:
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:av_32 = PHI [[PHI]], %bb.1, [[PHI1]], %bb.2
+  ; CHECK-NEXT:   SI_END_CF killed [[SI_ELSE]], implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   $vgpr0 = COPY killed [[PHI2]]
+  ; CHECK-NEXT:   SI_RETURN_TO_EPILOG killed $vgpr0
+  bb.0:
+    successors: %bb.3(0x40000000), %bb.1(0x40000000)
+    liveins: $vgpr0, $vgpr1
+
+    %10:vgpr_32 = COPY killed $vgpr1
+    %7:vgpr_32 = COPY killed $vgpr0
+    %0:av_32 = COPY killed %10
+    %14:sreg_64 = V_CMP_GT_I32_e64 6, %7, implicit $exec
+    %1:sreg_64 = SI_IF killed %14, %bb.1, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+    S_BRANCH %bb.3
+
+  bb.1:
+    successors: %bb.2(0x40000000), %bb.4(0x40000000)
+
+    %2:av_32 = PHI undef %11:av_32, %bb.0, %5, %bb.3
+    %3:sreg_64 = SI_ELSE killed %1, %bb.4, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+    S_BRANCH %bb.2
+
+  bb.2:
+    successors: %bb.4(0x80000000)
+
+    S_BRANCH %bb.4
+
+  bb.3:
+    successors: %bb.1(0x80000000)
+
+    %16:vgpr_32 = nofpexcept V_MUL_F32_e32 1077936128, killed %7, implicit $mode, implicit $exec
+    %5:av_32 = COPY killed %16
+    S_BRANCH %bb.1
+
+  bb.4:
+    %6:av_32 = PHI %2, %bb.1, %0, %bb.2
+    SI_END_CF killed %3, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+    $vgpr0 = COPY killed %6
+    SI_RETURN_TO_EPILOG killed $vgpr0
+...
+
+# %1 is defined before the waterfall loop and only used inside it. It gets a
+# PHI in the loop header with an undef input from the loop latch.
+---
+name:            waterfall_av_32
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: waterfall_av_32
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $vgpr0, $vgpr1, $vgpr2, $sgpr0_sgpr1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:vgpr_32 = COPY killed $vgpr0
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:av_32 = COPY killed $vgpr1
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:vgpr_32 = COPY killed $vgpr2
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:sreg_64_xexec_xnull = COPY killed $sgpr0_sgpr1
+  ; CHECK-NEXT:   [[S_MOV_B64_:%[0-9]+]]:sreg_64_xexec = S_MOV_B64 $exec
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:vgpr_32 = PHI [[COPY]], %bb.0, undef %11:vgpr_32, %bb.2
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:av_32 = PHI [[COPY1]], %bb.0, undef %13:av_32, %bb.2
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:vgpr_32 = PHI [[COPY2]], %bb.0, undef %15:vgpr_32, %bb.2
+  ; CHECK-NEXT:   [[V_READFIRSTLANE_B32_:%[0-9]+]]:sreg_32_xm0 = V_READFIRSTLANE_B32 [[PHI]], implicit $exec
+  ; CHECK-NEXT:   [[V_CMP_EQ_U32_e64_:%[0-9]+]]:sreg_64_xexec = V_CMP_EQ_U32_e64 [[V_READFIRSTLANE_B32_]], killed [[PHI]], implicit $exec
+  ; CHECK-NEXT:   [[S_AND_SAVEEXEC_B64_:%[0-9]+]]:sreg_64_xexec = S_AND_SAVEEXEC_B64 killed [[V_CMP_EQ_U32_e64_]], implicit-def $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.3(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:vgpr_32 = COPY killed [[PHI1]]
+  ; CHECK-NEXT:   [[V_ADD_U32_e32_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e32 killed [[V_READFIRSTLANE_B32_]], killed [[COPY4]], implicit $exec
+  ; CHECK-NEXT:   GLOBAL_STORE_DWORD_SADDR killed [[PHI2]], killed [[V_ADD_U32_e32_]], [[COPY3]], 0, 0, implicit $exec
+  ; CHECK-NEXT:   $exec = S_XOR_B64_term $exec, killed [[S_AND_SAVEEXEC_B64_]], implicit-def dead $scc
+  ; CHECK-NEXT:   SI_WATERFALL_LOOP %bb.1, implicit $exec
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3:
+  ; CHECK-NEXT:   $exec = S_MOV_B64 killed [[S_MOV_B64_]]
+  ; CHECK-NEXT:   SI_RETURN
+  bb.0:
+    successors: %bb.1(0x80000000)
+    liveins: $vgpr0, $vgpr1, $vgpr2, $sgpr0_sgpr1
+
+    %0:vgpr_32 = COPY killed $vgpr0
+    %1:av_32 = COPY killed $vgpr1
+    %2:vgpr_32 = COPY killed $vgpr2
+    %3:sreg_64_xexec_xnull = COPY killed $sgpr0_sgpr1
+    %4:sreg_64_xexec = S_MOV_B64 $exec
+
+  bb.1:
+    successors: %bb.2(0x80000000)
+
+    %5:sreg_32_xm0 = V_READFIRSTLANE_B32 %0, implicit $exec
+    %6:sreg_64_xexec = V_CMP_EQ_U32_e64 %5, %0, implicit $exec
+    %7:sreg_64_xexec = S_AND_SAVEEXEC_B64 killed %6, implicit-def $exec, implicit-def dead $scc, implicit $exec
+
+  bb.2:
+    successors: %bb.1(0x40000000), %bb.3(0x40000000)
+
+    %8:vgpr_32 = COPY %1
+    %9:vgpr_32 = V_ADD_U32_e32 killed %5, killed %8, implicit $exec
+    GLOBAL_STORE_DWORD_SADDR %2, killed %9, %3, 0, 0, implicit $exec
+    $exec = S_XOR_B64_term $exec, killed %7, implicit-def dead $scc
+    SI_WATERFALL_LOOP %bb.1, implicit $exec
+
+  bb.3:
+    $exec = S_MOV_B64 killed %4
+    SI_RETURN
+...

>From f3395d655468140fbc4413733e0fed657cbcb643 Mon Sep 17 00:00:00 2001
From: Pablo Reble <pablo.reble at amd.com>
Date: Mon, 28 Sep 2026 16:47:19 -0500
Subject: [PATCH 2/2] Update
 llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-av-classes.mir

Co-authored-by: Matt Arsenault <arsenm2 at gmail.com>
---
 llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-av-classes.mir | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-av-classes.mir b/llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-av-classes.mir
index d331d81d14e80..4723835a006f5 100644
--- a/llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-av-classes.mir
+++ b/llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-av-classes.mir
@@ -1,5 +1,5 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
-# RUN: llc -mtriple=amdgpu9.0a -run-pass=si-opt-vgpr-liverange -verify-machineinstrs %s -o - | FileCheck %s
+# RUN: llc -mtriple=amdgpu9.0a -run-pass=si-opt-vgpr-liverange %s -o - | FileCheck %s
 # RUN: llc -mtriple=amdgpu9.0a -passes=si-opt-vgpr-liverange %s -o - | FileCheck %s
 
 # SIOptimizeVGPRLiveRange should handle virtual registers with AV classes the



More information about the llvm-commits mailing list