[llvm] [AMDGPU] Use the reserved EXEC copy register for emergency SGPR spills (PR #221972)

Pankaj Dwivedi via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 9 05:20:25 PDT 2026


https://github.com/PankajDwivedi-25 updated https://github.com/llvm/llvm-project/pull/221972

>From 19a05ae0e9fe4e58a44e2a806cd144f214ff0e71 Mon Sep 17 00:00:00 2001
From: padivedi <pankajkumar.divedi at amd.com>
Date: Wed, 9 Sep 2026 17:49:19 +0530
Subject: [PATCH] [AMDGPU] Scale the frame register in place when lowering
 scalar frame indices

---
 llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp     |  80 +++++++-
 .../AMDGPU/sgpr-scavenge-fi-stack-id.ll       |  26 +--
 ...to-vmem-scc-clobber-reserved-exec-copy.mir | 184 ++++++++++++++++++
 3 files changed, 260 insertions(+), 30 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/sgpr-spill-to-vmem-scc-clobber-reserved-exec-copy.mir

diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
index f570aa4e2f6fb..7dee87df9f998 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
@@ -3419,11 +3419,40 @@ bool SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
       bool IsCopy = MI->getOpcode() == AMDGPU::V_MOV_B32_e32 ||
                     MI->getOpcode() == AMDGPU::V_MOV_B32_e64 ||
                     MI->getOpcode() == AMDGPU::S_MOV_B32;
-      Register ResultReg =
-          IsCopy ? MI->getOperand(0).getReg()
-                 : RS->scavengeRegisterBackwards(*RC, MI, false, 0);
 
       int64_t Offset = FrameInfo.getObjectOffset(Index);
+      int64_t ScaledOffset = -Offset * ST.getWavefrontSize();
+
+      // Scaling FrameReg in place is the last resort when there is nothing to
+      // scavenge. It has to be undone after MI, which is only possible while MI
+      // does not use FrameReg for anything besides the frame index, and while
+      // the offset can be folded back in wave space. A second frame index on MI
+      // would be lowered while FrameReg is still scaled, so keep away from it.
+      bool HasOneFrameIndex =
+          llvm::count_if(MI->operands(), [](const MachineOperand &MO) {
+            return MO.isFI();
+          }) == 1;
+      bool CanUseFrameRegAsScratch =
+          IsSALU && !LiveSCC && FrameReg && HasOneFrameIndex &&
+          !MI->readsRegister(FrameReg, this) &&
+          !MI->modifiesRegister(FrameReg, this) && isInt<32>(ScaledOffset);
+
+      bool RestoreFrameReg = false;
+      Register ResultReg;
+      if (IsCopy) {
+        ResultReg = MI->getOperand(0).getReg();
+      } else {
+        ResultReg = RS->scavengeRegisterBackwards(*RC, MI, false, 0,
+                                                  /*AllowSpill=*/false);
+        if (!ResultReg && CanUseFrameRegAsScratch) {
+          // Spilling an SGPR here instead would flip EXEC with S_NOT, and that
+          // clobbers the SCC MI may be defining for a later use.
+          ResultReg = FrameReg;
+          RestoreFrameReg = true;
+        } else if (!ResultReg) {
+          ResultReg = RS->scavengeRegisterBackwards(*RC, MI, false, 0);
+        }
+      }
 
       // The carry-out lane of Add is unused, so it is safe to write with
       // S_MOV_B32 even into a VGPR.
@@ -3512,7 +3541,11 @@ bool SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
                                       : RS->scavengeRegisterBackwards(
                                             AMDGPU::SReg_32_XM0RegClass, MI,
                                             false, 0, /*AllowSpill=*/false);
-          Register ScaledReg = TmpScaledReg.isValid() ? TmpScaledReg : FrameReg;
+          // A scalar result is already materialized in ResultReg, which holds
+          // the scavenged register, or FrameReg itself if nothing was free.
+          Register ScaledReg = TmpScaledReg;
+          if (!ScaledReg)
+            ScaledReg = IsSALU ? ResultReg : FrameReg;
           Register TmpResultReg = ScaledReg;
 
           if (!LiveSCC) {
@@ -3590,8 +3623,10 @@ bool SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
           if (!IsSALU)
             BuildMI(*MBB, MI, DL, TII->get(AMDGPU::COPY), ResultReg)
                 .addReg(TmpResultReg, RegState::Kill);
-          // If there were truly no free SGPRs, we need to undo everything.
-          if (!TmpScaledReg.isValid()) {
+          // If there were truly no free SGPRs, we need to undo everything. A
+          // scalar result keeps using FrameReg until MI has consumed it, so it
+          // is put back after MI instead.
+          if (!TmpScaledReg.isValid() && !IsSALU) {
             BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_ADD_I32), ScaledReg)
                 .addReg(ScaledReg, RegState::Kill)
                 .addImm(-Offset);
@@ -3602,12 +3637,43 @@ bool SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
         }
       }
 
+      if (RestoreFrameReg) {
+        // Put FrameReg back now that MI has consumed the scaled address.
+        // S_MUL_I32 undoes the scaling without writing SCC, which S_LSHL_B32
+        // would. When MI leaves SCC live, fold the offset back with the carry
+        // sequence that smuggles SCC through bit 0, which the scaling has just
+        // cleared.
+        MachineBasicBlock::iterator InsPt = std::next(MI);
+        BuildMI(*MBB, InsPt, DL, TII->get(AMDGPU::S_MUL_I32), FrameReg)
+            .addReg(FrameReg)
+            .addImm(ST.getWavefrontSize());
+
+        bool SCCLiveAfterMI = MI->definesRegister(AMDGPU::SCC, this) &&
+                              !MI->registerDefIsDead(AMDGPU::SCC, this);
+        if (Offset && !SCCLiveAfterMI) {
+          BuildMI(*MBB, InsPt, DL, TII->get(AMDGPU::S_ADD_I32), FrameReg)
+              .addReg(FrameReg)
+              .addImm(ScaledOffset);
+        } else if (Offset) {
+          BuildMI(*MBB, InsPt, DL, TII->get(AMDGPU::S_ADDC_U32), FrameReg)
+              .addReg(FrameReg)
+              .addImm(ScaledOffset);
+          BuildMI(*MBB, InsPt, DL, TII->get(AMDGPU::S_BITCMP1_B32))
+              .addReg(FrameReg)
+              .addImm(0);
+          BuildMI(*MBB, InsPt, DL, TII->get(AMDGPU::S_BITSET0_B32), FrameReg)
+              .addImm(0)
+              .addReg(FrameReg);
+        }
+      }
+
       // Don't introduce an extra copy if we're just materializing in a mov.
       if (IsCopy) {
         MI->eraseFromParent();
         return true;
       }
-      FIOp->ChangeToRegister(ResultReg, false, false, true);
+      // FrameReg is restored after MI, so MI does not kill it.
+      FIOp->ChangeToRegister(ResultReg, false, false, !RestoreFrameReg);
       return false;
     }
 
diff --git a/llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll b/llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll
index 4d33d0020fff0..72736e1da863a 100644
--- a/llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll
+++ b/llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll
@@ -155,34 +155,14 @@ define void @sgpr_scavenge_fi_stack_id(double %input, i1 %enter_fma_path, i1 %re
 ; CHECK-NEXT:    ; => This Inner Loop Header: Depth=5
 ; CHECK-NEXT:    s_and_b64 s[30:31], exec, s[6:7]
 ; CHECK-NEXT:    s_or_b64 s[94:95], s[30:31], s[94:95]
-; CHECK-NEXT:    s_not_b64 exec, exec
-; CHECK-NEXT:    buffer_store_dword v7, off, s[0:3], s32 offset:8
-; CHECK-NEXT:    v_writelane_b32 v7, s4, 0
-; CHECK-NEXT:    buffer_store_dword v7, off, s[0:3], s32 offset:8
-; CHECK-NEXT:    s_not_b64 exec, exec
-; CHECK-NEXT:    buffer_store_dword v7, off, s[0:3], s32 offset:8
-; CHECK-NEXT:    s_not_b64 exec, exec
-; CHECK-NEXT:    buffer_load_dword v7, off, s[0:3], s32 offset:8
-; CHECK-NEXT:    s_waitcnt vmcnt(0)
-; CHECK-NEXT:    s_not_b64 exec, exec
-; CHECK-NEXT:    s_lshr_b32 s4, s32, 6
-; CHECK-NEXT:    s_lshl3_add_u32 vcc_hi, vcc_lo, s4
-; CHECK-NEXT:    s_not_b64 exec, exec
-; CHECK-NEXT:    buffer_store_dword v8, off, s[0:3], s32 offset:8
-; CHECK-NEXT:    buffer_load_dword v8, off, s[0:3], s32 offset:8
-; CHECK-NEXT:    s_not_b64 exec, exec
-; CHECK-NEXT:    buffer_load_dword v8, off, s[0:3], s32 offset:8
-; CHECK-NEXT:    s_not_b64 exec, exec
-; CHECK-NEXT:    s_waitcnt vmcnt(0)
-; CHECK-NEXT:    v_readlane_b32 s4, v8, 0
-; CHECK-NEXT:    buffer_load_dword v8, off, s[0:3], s32 offset:8
-; CHECK-NEXT:    s_waitcnt vmcnt(0)
-; CHECK-NEXT:    s_not_b64 exec, exec
+; CHECK-NEXT:    s_lshr_b32 s32, s32, 6
+; CHECK-NEXT:    s_lshl3_add_u32 vcc_hi, vcc_lo, s32
 ; CHECK-NEXT:    v_mov_b32_e32 v7, vcc_hi
 ; CHECK-NEXT:    buffer_load_dword v8, v7, s[0:3], 0 offen
 ; CHECK-NEXT:    buffer_load_dword v9, v7, s[0:3], 0 offen offset:4
 ; CHECK-NEXT:    v_mov_b32_e32 v7, vcc_lo
 ; CHECK-NEXT:    s_mov_b32 vcc_lo, 1
+; CHECK-NEXT:    s_mul_i32 s32, s32, 64
 ; CHECK-NEXT:    s_waitcnt vmcnt(0)
 ; CHECK-NEXT:    v_mul_f64 v[8:9], v[4:5], v[8:9]
 ; CHECK-NEXT:    buffer_store_dword v9, off, s[0:3], 0 offset:4
diff --git a/llvm/test/CodeGen/AMDGPU/sgpr-spill-to-vmem-scc-clobber-reserved-exec-copy.mir b/llvm/test/CodeGen/AMDGPU/sgpr-spill-to-vmem-scc-clobber-reserved-exec-copy.mir
new file mode 100644
index 0000000000000..413500e32d91f
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/sgpr-spill-to-vmem-scc-clobber-reserved-exec-copy.mir
@@ -0,0 +1,184 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=amdgpu9.0a-amd-amdhsa -run-pass=prolog-epilog -o - %s 2>&1 | FileCheck %s
+---
+name:            scc_live_across_scalar_frame_index
+alignment:       4
+tracksRegLiveness: true
+frameInfo:
+  maxAlignment:    16
+stack:
+  - { id: 0, size: 64, alignment: 16 }
+machineFunctionInfo:
+  isEntryFunction: false
+  scratchRSrcReg:  '$sgpr0_sgpr1_sgpr2_sgpr3'
+  frameOffsetReg:  '$sgpr33'
+  stackPtrOffsetReg: '$sgpr32'
+  sgprForEXECCopy: '$sgpr100_sgpr101'
+  occupancy:       2
+body:             |
+  ; CHECK-LABEL: name: scc_live_across_scalar_frame_index
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   frame-setup CFI_INSTRUCTION llvm_def_aspace_cfa $sgpr32, 0, 6
+  ; CHECK-NEXT:   frame-setup CFI_INSTRUCTION llvm_register_pair $pc_reg, $sgpr30, 32, $sgpr31, 32
+  ; CHECK-NEXT:   S_BRANCH %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT:   liveins: $sgpr4_sgpr5_sgpr6_sgpr7_sgpr8_sgpr9_sgpr10_sgpr11_sgpr12_sgpr13_sgpr14_sgpr15_sgpr16_sgpr17_sgpr18_sgpr19, $sgpr20_sgpr21_sgpr22_sgpr23_sgpr24_sgpr25_sgpr26_sgpr27_sgpr28_sgpr29_sgpr30_sgpr31_sgpr32_sgpr33_sgpr34_sgpr35, $sgpr36_sgpr37_sgpr38_sgpr39_sgpr40_sgpr41_sgpr42_sgpr43_sgpr44_sgpr45_sgpr46_sgpr47_sgpr48_sgpr49_sgpr50_sgpr51, $sgpr52_sgpr53_sgpr54_sgpr55_sgpr56_sgpr57_sgpr58_sgpr59_sgpr60_sgpr61_sgpr62_sgpr63_sgpr64_sgpr65_sgpr66_sgpr67, $sgpr68_sgpr69_sgpr70_sgpr71_sgpr72_sgpr73_sgpr74_sgpr75_sgpr76_sgpr77_sgpr78_sgpr79_sgpr80_sgpr81_sgpr82_sgpr83, $sgpr84_sgpr85_sgpr86_sgpr87_sgpr88_sgpr89_sgpr90_sgpr91_sgpr92_sgpr93_sgpr94_sgpr95, $sgpr96_sgpr97_sgpr98_sgpr99, $vcc
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   $sgpr32 = S_LSHR_B32 $sgpr32, 6, implicit-def dead $scc
+  ; CHECK-NEXT:   renamable $vcc_lo = S_SUB_U32 killed renamable $vcc_lo, $sgpr32, implicit-def $scc
+  ; CHECK-NEXT:   $sgpr32 = S_MUL_I32 $sgpr32, 64
+  ; CHECK-NEXT:   renamable $vcc_hi = S_SUBB_U32 killed renamable $vcc_hi, renamable $sgpr97, implicit-def dead $scc, implicit $scc
+  ; CHECK-NEXT:   S_NOP 0, implicit killed $sgpr4_sgpr5_sgpr6_sgpr7_sgpr8_sgpr9_sgpr10_sgpr11_sgpr12_sgpr13_sgpr14_sgpr15_sgpr16_sgpr17_sgpr18_sgpr19, implicit killed $sgpr20_sgpr21_sgpr22_sgpr23_sgpr24_sgpr25_sgpr26_sgpr27_sgpr28_sgpr29_sgpr30_sgpr31_sgpr32_sgpr33_sgpr34_sgpr35, implicit killed $sgpr36_sgpr37_sgpr38_sgpr39_sgpr40_sgpr41_sgpr42_sgpr43_sgpr44_sgpr45_sgpr46_sgpr47_sgpr48_sgpr49_sgpr50_sgpr51, implicit killed $sgpr52_sgpr53_sgpr54_sgpr55_sgpr56_sgpr57_sgpr58_sgpr59_sgpr60_sgpr61_sgpr62_sgpr63_sgpr64_sgpr65_sgpr66_sgpr67, implicit killed $sgpr68_sgpr69_sgpr70_sgpr71_sgpr72_sgpr73_sgpr74_sgpr75_sgpr76_sgpr77_sgpr78_sgpr79_sgpr80_sgpr81_sgpr82_sgpr83, implicit killed $sgpr84_sgpr85_sgpr86_sgpr87_sgpr88_sgpr89_sgpr90_sgpr91_sgpr92_sgpr93_sgpr94_sgpr95, implicit killed $sgpr96_sgpr97_sgpr98_sgpr99
+  ; CHECK-NEXT:   S_BRANCH %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   liveins: $vcc
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   S_ENDPGM 0, implicit $vcc
+  bb.0:
+    S_BRANCH %bb.1
+
+  bb.1:
+    liveins: $sgpr4_sgpr5_sgpr6_sgpr7_sgpr8_sgpr9_sgpr10_sgpr11_sgpr12_sgpr13_sgpr14_sgpr15_sgpr16_sgpr17_sgpr18_sgpr19, $sgpr20_sgpr21_sgpr22_sgpr23_sgpr24_sgpr25_sgpr26_sgpr27_sgpr28_sgpr29_sgpr30_sgpr31_sgpr32_sgpr33_sgpr34_sgpr35, $sgpr36_sgpr37_sgpr38_sgpr39_sgpr40_sgpr41_sgpr42_sgpr43_sgpr44_sgpr45_sgpr46_sgpr47_sgpr48_sgpr49_sgpr50_sgpr51, $sgpr52_sgpr53_sgpr54_sgpr55_sgpr56_sgpr57_sgpr58_sgpr59_sgpr60_sgpr61_sgpr62_sgpr63_sgpr64_sgpr65_sgpr66_sgpr67, $sgpr68_sgpr69_sgpr70_sgpr71_sgpr72_sgpr73_sgpr74_sgpr75_sgpr76_sgpr77_sgpr78_sgpr79_sgpr80_sgpr81_sgpr82_sgpr83, $sgpr84_sgpr85_sgpr86_sgpr87_sgpr88_sgpr89_sgpr90_sgpr91_sgpr92_sgpr93_sgpr94_sgpr95, $sgpr96_sgpr97_sgpr98_sgpr99, $vcc
+
+    renamable $vcc_lo = S_SUB_U32 killed renamable $vcc_lo, %stack.0, implicit-def $scc
+    renamable $vcc_hi = S_SUBB_U32 killed renamable $vcc_hi, renamable $sgpr97, implicit-def dead $scc, implicit $scc
+    S_NOP 0, implicit killed $sgpr4_sgpr5_sgpr6_sgpr7_sgpr8_sgpr9_sgpr10_sgpr11_sgpr12_sgpr13_sgpr14_sgpr15_sgpr16_sgpr17_sgpr18_sgpr19, implicit killed $sgpr20_sgpr21_sgpr22_sgpr23_sgpr24_sgpr25_sgpr26_sgpr27_sgpr28_sgpr29_sgpr30_sgpr31_sgpr32_sgpr33_sgpr34_sgpr35, implicit killed $sgpr36_sgpr37_sgpr38_sgpr39_sgpr40_sgpr41_sgpr42_sgpr43_sgpr44_sgpr45_sgpr46_sgpr47_sgpr48_sgpr49_sgpr50_sgpr51, implicit killed $sgpr52_sgpr53_sgpr54_sgpr55_sgpr56_sgpr57_sgpr58_sgpr59_sgpr60_sgpr61_sgpr62_sgpr63_sgpr64_sgpr65_sgpr66_sgpr67, implicit killed $sgpr68_sgpr69_sgpr70_sgpr71_sgpr72_sgpr73_sgpr74_sgpr75_sgpr76_sgpr77_sgpr78_sgpr79_sgpr80_sgpr81_sgpr82_sgpr83, implicit killed $sgpr84_sgpr85_sgpr86_sgpr87_sgpr88_sgpr89_sgpr90_sgpr91_sgpr92_sgpr93_sgpr94_sgpr95, implicit killed $sgpr96_sgpr97_sgpr98_sgpr99
+    S_BRANCH %bb.2
+
+  bb.2:
+    liveins: $vcc
+
+    S_ENDPGM 0, implicit $vcc
+...
+
+# The frame index has a non-zero offset here, so the offset has to be folded
+# back into the frame register too. That addition writes SCC, so it is done
+# with the carry sequence that smuggles SCC through bit 0.
+
+---
+name:            scc_live_across_scalar_frame_index_nonzero_offset
+alignment:       4
+tracksRegLiveness: true
+frameInfo:
+  maxAlignment:    16
+stack:
+  - { id: 0, size: 64, alignment: 16 }
+  - { id: 1, size: 64, alignment: 16 }
+machineFunctionInfo:
+  isEntryFunction: false
+  scratchRSrcReg:  '$sgpr0_sgpr1_sgpr2_sgpr3'
+  frameOffsetReg:  '$sgpr33'
+  stackPtrOffsetReg: '$sgpr32'
+  sgprForEXECCopy: '$sgpr100_sgpr101'
+  occupancy:       2
+body:             |
+  ; CHECK-LABEL: name: scc_live_across_scalar_frame_index_nonzero_offset
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   frame-setup CFI_INSTRUCTION llvm_def_aspace_cfa $sgpr32, 0, 6
+  ; CHECK-NEXT:   frame-setup CFI_INSTRUCTION llvm_register_pair $pc_reg, $sgpr30, 32, $sgpr31, 32
+  ; CHECK-NEXT:   S_BRANCH %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT:   liveins: $sgpr4_sgpr5_sgpr6_sgpr7_sgpr8_sgpr9_sgpr10_sgpr11_sgpr12_sgpr13_sgpr14_sgpr15_sgpr16_sgpr17_sgpr18_sgpr19, $sgpr20_sgpr21_sgpr22_sgpr23_sgpr24_sgpr25_sgpr26_sgpr27_sgpr28_sgpr29_sgpr30_sgpr31_sgpr32_sgpr33_sgpr34_sgpr35, $sgpr36_sgpr37_sgpr38_sgpr39_sgpr40_sgpr41_sgpr42_sgpr43_sgpr44_sgpr45_sgpr46_sgpr47_sgpr48_sgpr49_sgpr50_sgpr51, $sgpr52_sgpr53_sgpr54_sgpr55_sgpr56_sgpr57_sgpr58_sgpr59_sgpr60_sgpr61_sgpr62_sgpr63_sgpr64_sgpr65_sgpr66_sgpr67, $sgpr68_sgpr69_sgpr70_sgpr71_sgpr72_sgpr73_sgpr74_sgpr75_sgpr76_sgpr77_sgpr78_sgpr79_sgpr80_sgpr81_sgpr82_sgpr83, $sgpr84_sgpr85_sgpr86_sgpr87_sgpr88_sgpr89_sgpr90_sgpr91_sgpr92_sgpr93_sgpr94_sgpr95, $sgpr96_sgpr97_sgpr98_sgpr99, $vcc
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   $sgpr32 = S_LSHR_B32 $sgpr32, 6, implicit-def $scc
+  ; CHECK-NEXT:   $sgpr32 = S_ADD_I32 killed $sgpr32, 64, implicit-def $scc
+  ; CHECK-NEXT:   renamable $vcc_lo = S_SUB_U32 killed renamable $vcc_lo, $sgpr32, implicit-def $scc
+  ; CHECK-NEXT:   $sgpr32 = S_MUL_I32 $sgpr32, 64
+  ; CHECK-NEXT:   $sgpr32 = S_ADDC_U32 $sgpr32, -4096, implicit-def $scc, implicit $scc
+  ; CHECK-NEXT:   S_BITCMP1_B32 $sgpr32, 0, implicit-def $scc
+  ; CHECK-NEXT:   $sgpr32 = S_BITSET0_B32 0, $sgpr32
+  ; CHECK-NEXT:   renamable $vcc_hi = S_SUBB_U32 killed renamable $vcc_hi, renamable $sgpr97, implicit-def dead $scc, implicit $scc
+  ; CHECK-NEXT:   S_NOP 0, implicit killed $sgpr4_sgpr5_sgpr6_sgpr7_sgpr8_sgpr9_sgpr10_sgpr11_sgpr12_sgpr13_sgpr14_sgpr15_sgpr16_sgpr17_sgpr18_sgpr19, implicit killed $sgpr20_sgpr21_sgpr22_sgpr23_sgpr24_sgpr25_sgpr26_sgpr27_sgpr28_sgpr29_sgpr30_sgpr31_sgpr32_sgpr33_sgpr34_sgpr35, implicit killed $sgpr36_sgpr37_sgpr38_sgpr39_sgpr40_sgpr41_sgpr42_sgpr43_sgpr44_sgpr45_sgpr46_sgpr47_sgpr48_sgpr49_sgpr50_sgpr51, implicit killed $sgpr52_sgpr53_sgpr54_sgpr55_sgpr56_sgpr57_sgpr58_sgpr59_sgpr60_sgpr61_sgpr62_sgpr63_sgpr64_sgpr65_sgpr66_sgpr67, implicit killed $sgpr68_sgpr69_sgpr70_sgpr71_sgpr72_sgpr73_sgpr74_sgpr75_sgpr76_sgpr77_sgpr78_sgpr79_sgpr80_sgpr81_sgpr82_sgpr83, implicit killed $sgpr84_sgpr85_sgpr86_sgpr87_sgpr88_sgpr89_sgpr90_sgpr91_sgpr92_sgpr93_sgpr94_sgpr95, implicit killed $sgpr96_sgpr97_sgpr98_sgpr99
+  ; CHECK-NEXT:   S_BRANCH %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   liveins: $vcc
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   S_ENDPGM 0, implicit $vcc
+  bb.0:
+    S_BRANCH %bb.1
+
+  bb.1:
+    liveins: $sgpr4_sgpr5_sgpr6_sgpr7_sgpr8_sgpr9_sgpr10_sgpr11_sgpr12_sgpr13_sgpr14_sgpr15_sgpr16_sgpr17_sgpr18_sgpr19, $sgpr20_sgpr21_sgpr22_sgpr23_sgpr24_sgpr25_sgpr26_sgpr27_sgpr28_sgpr29_sgpr30_sgpr31_sgpr32_sgpr33_sgpr34_sgpr35, $sgpr36_sgpr37_sgpr38_sgpr39_sgpr40_sgpr41_sgpr42_sgpr43_sgpr44_sgpr45_sgpr46_sgpr47_sgpr48_sgpr49_sgpr50_sgpr51, $sgpr52_sgpr53_sgpr54_sgpr55_sgpr56_sgpr57_sgpr58_sgpr59_sgpr60_sgpr61_sgpr62_sgpr63_sgpr64_sgpr65_sgpr66_sgpr67, $sgpr68_sgpr69_sgpr70_sgpr71_sgpr72_sgpr73_sgpr74_sgpr75_sgpr76_sgpr77_sgpr78_sgpr79_sgpr80_sgpr81_sgpr82_sgpr83, $sgpr84_sgpr85_sgpr86_sgpr87_sgpr88_sgpr89_sgpr90_sgpr91_sgpr92_sgpr93_sgpr94_sgpr95, $sgpr96_sgpr97_sgpr98_sgpr99, $vcc
+
+    renamable $vcc_lo = S_SUB_U32 killed renamable $vcc_lo, %stack.1, implicit-def $scc
+    renamable $vcc_hi = S_SUBB_U32 killed renamable $vcc_hi, renamable $sgpr97, implicit-def dead $scc, implicit $scc
+    S_NOP 0, implicit killed $sgpr4_sgpr5_sgpr6_sgpr7_sgpr8_sgpr9_sgpr10_sgpr11_sgpr12_sgpr13_sgpr14_sgpr15_sgpr16_sgpr17_sgpr18_sgpr19, implicit killed $sgpr20_sgpr21_sgpr22_sgpr23_sgpr24_sgpr25_sgpr26_sgpr27_sgpr28_sgpr29_sgpr30_sgpr31_sgpr32_sgpr33_sgpr34_sgpr35, implicit killed $sgpr36_sgpr37_sgpr38_sgpr39_sgpr40_sgpr41_sgpr42_sgpr43_sgpr44_sgpr45_sgpr46_sgpr47_sgpr48_sgpr49_sgpr50_sgpr51, implicit killed $sgpr52_sgpr53_sgpr54_sgpr55_sgpr56_sgpr57_sgpr58_sgpr59_sgpr60_sgpr61_sgpr62_sgpr63_sgpr64_sgpr65_sgpr66_sgpr67, implicit killed $sgpr68_sgpr69_sgpr70_sgpr71_sgpr72_sgpr73_sgpr74_sgpr75_sgpr76_sgpr77_sgpr78_sgpr79_sgpr80_sgpr81_sgpr82_sgpr83, implicit killed $sgpr84_sgpr85_sgpr86_sgpr87_sgpr88_sgpr89_sgpr90_sgpr91_sgpr92_sgpr93_sgpr94_sgpr95, implicit killed $sgpr96_sgpr97_sgpr98_sgpr99
+    S_BRANCH %bb.2
+
+  bb.2:
+    liveins: $vcc
+
+    S_ENDPGM 0, implicit $vcc
+...
+
+# Same non-zero offset, but nothing uses SCC after the instruction, so the
+# offset can be folded back with a plain add.
+
+---
+name:            scc_dead_after_scalar_frame_index_nonzero_offset
+alignment:       4
+tracksRegLiveness: true
+frameInfo:
+  maxAlignment:    16
+stack:
+  - { id: 0, size: 64, alignment: 16 }
+  - { id: 1, size: 64, alignment: 16 }
+machineFunctionInfo:
+  isEntryFunction: false
+  scratchRSrcReg:  '$sgpr0_sgpr1_sgpr2_sgpr3'
+  frameOffsetReg:  '$sgpr33'
+  stackPtrOffsetReg: '$sgpr32'
+  sgprForEXECCopy: '$sgpr100_sgpr101'
+  occupancy:       2
+body:             |
+  ; CHECK-LABEL: name: scc_dead_after_scalar_frame_index_nonzero_offset
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   frame-setup CFI_INSTRUCTION llvm_def_aspace_cfa $sgpr32, 0, 6
+  ; CHECK-NEXT:   frame-setup CFI_INSTRUCTION llvm_register_pair $pc_reg, $sgpr30, 32, $sgpr31, 32
+  ; CHECK-NEXT:   S_BRANCH %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT:   liveins: $sgpr4_sgpr5_sgpr6_sgpr7_sgpr8_sgpr9_sgpr10_sgpr11_sgpr12_sgpr13_sgpr14_sgpr15_sgpr16_sgpr17_sgpr18_sgpr19, $sgpr20_sgpr21_sgpr22_sgpr23_sgpr24_sgpr25_sgpr26_sgpr27_sgpr28_sgpr29_sgpr30_sgpr31_sgpr32_sgpr33_sgpr34_sgpr35, $sgpr36_sgpr37_sgpr38_sgpr39_sgpr40_sgpr41_sgpr42_sgpr43_sgpr44_sgpr45_sgpr46_sgpr47_sgpr48_sgpr49_sgpr50_sgpr51, $sgpr52_sgpr53_sgpr54_sgpr55_sgpr56_sgpr57_sgpr58_sgpr59_sgpr60_sgpr61_sgpr62_sgpr63_sgpr64_sgpr65_sgpr66_sgpr67, $sgpr68_sgpr69_sgpr70_sgpr71_sgpr72_sgpr73_sgpr74_sgpr75_sgpr76_sgpr77_sgpr78_sgpr79_sgpr80_sgpr81_sgpr82_sgpr83, $sgpr84_sgpr85_sgpr86_sgpr87_sgpr88_sgpr89_sgpr90_sgpr91_sgpr92_sgpr93_sgpr94_sgpr95, $sgpr96_sgpr97_sgpr98_sgpr99, $vcc
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   $sgpr32 = S_LSHR_B32 $sgpr32, 6, implicit-def $scc
+  ; CHECK-NEXT:   $sgpr32 = S_ADD_I32 killed $sgpr32, 64, implicit-def $scc
+  ; CHECK-NEXT:   renamable $vcc_lo = S_SUB_U32 killed renamable $vcc_lo, $sgpr32, implicit-def dead $scc
+  ; CHECK-NEXT:   $sgpr32 = S_MUL_I32 $sgpr32, 64
+  ; CHECK-NEXT:   $sgpr32 = S_ADD_I32 $sgpr32, -4096, implicit-def $scc
+  ; CHECK-NEXT:   renamable $vcc_hi = S_SUB_U32 killed renamable $vcc_hi, renamable $sgpr97, implicit-def dead $scc
+  ; CHECK-NEXT:   S_NOP 0, implicit killed $sgpr4_sgpr5_sgpr6_sgpr7_sgpr8_sgpr9_sgpr10_sgpr11_sgpr12_sgpr13_sgpr14_sgpr15_sgpr16_sgpr17_sgpr18_sgpr19, implicit killed $sgpr20_sgpr21_sgpr22_sgpr23_sgpr24_sgpr25_sgpr26_sgpr27_sgpr28_sgpr29_sgpr30_sgpr31_sgpr32_sgpr33_sgpr34_sgpr35, implicit killed $sgpr36_sgpr37_sgpr38_sgpr39_sgpr40_sgpr41_sgpr42_sgpr43_sgpr44_sgpr45_sgpr46_sgpr47_sgpr48_sgpr49_sgpr50_sgpr51, implicit killed $sgpr52_sgpr53_sgpr54_sgpr55_sgpr56_sgpr57_sgpr58_sgpr59_sgpr60_sgpr61_sgpr62_sgpr63_sgpr64_sgpr65_sgpr66_sgpr67, implicit killed $sgpr68_sgpr69_sgpr70_sgpr71_sgpr72_sgpr73_sgpr74_sgpr75_sgpr76_sgpr77_sgpr78_sgpr79_sgpr80_sgpr81_sgpr82_sgpr83, implicit killed $sgpr84_sgpr85_sgpr86_sgpr87_sgpr88_sgpr89_sgpr90_sgpr91_sgpr92_sgpr93_sgpr94_sgpr95, implicit killed $sgpr96_sgpr97_sgpr98_sgpr99
+  ; CHECK-NEXT:   S_BRANCH %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   liveins: $vcc
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   S_ENDPGM 0, implicit $vcc
+  bb.0:
+    S_BRANCH %bb.1
+
+  bb.1:
+    liveins: $sgpr4_sgpr5_sgpr6_sgpr7_sgpr8_sgpr9_sgpr10_sgpr11_sgpr12_sgpr13_sgpr14_sgpr15_sgpr16_sgpr17_sgpr18_sgpr19, $sgpr20_sgpr21_sgpr22_sgpr23_sgpr24_sgpr25_sgpr26_sgpr27_sgpr28_sgpr29_sgpr30_sgpr31_sgpr32_sgpr33_sgpr34_sgpr35, $sgpr36_sgpr37_sgpr38_sgpr39_sgpr40_sgpr41_sgpr42_sgpr43_sgpr44_sgpr45_sgpr46_sgpr47_sgpr48_sgpr49_sgpr50_sgpr51, $sgpr52_sgpr53_sgpr54_sgpr55_sgpr56_sgpr57_sgpr58_sgpr59_sgpr60_sgpr61_sgpr62_sgpr63_sgpr64_sgpr65_sgpr66_sgpr67, $sgpr68_sgpr69_sgpr70_sgpr71_sgpr72_sgpr73_sgpr74_sgpr75_sgpr76_sgpr77_sgpr78_sgpr79_sgpr80_sgpr81_sgpr82_sgpr83, $sgpr84_sgpr85_sgpr86_sgpr87_sgpr88_sgpr89_sgpr90_sgpr91_sgpr92_sgpr93_sgpr94_sgpr95, $sgpr96_sgpr97_sgpr98_sgpr99, $vcc
+
+    renamable $vcc_lo = S_SUB_U32 killed renamable $vcc_lo, %stack.1, implicit-def dead $scc
+    renamable $vcc_hi = S_SUB_U32 killed renamable $vcc_hi, renamable $sgpr97, implicit-def dead $scc
+    S_NOP 0, implicit killed $sgpr4_sgpr5_sgpr6_sgpr7_sgpr8_sgpr9_sgpr10_sgpr11_sgpr12_sgpr13_sgpr14_sgpr15_sgpr16_sgpr17_sgpr18_sgpr19, implicit killed $sgpr20_sgpr21_sgpr22_sgpr23_sgpr24_sgpr25_sgpr26_sgpr27_sgpr28_sgpr29_sgpr30_sgpr31_sgpr32_sgpr33_sgpr34_sgpr35, implicit killed $sgpr36_sgpr37_sgpr38_sgpr39_sgpr40_sgpr41_sgpr42_sgpr43_sgpr44_sgpr45_sgpr46_sgpr47_sgpr48_sgpr49_sgpr50_sgpr51, implicit killed $sgpr52_sgpr53_sgpr54_sgpr55_sgpr56_sgpr57_sgpr58_sgpr59_sgpr60_sgpr61_sgpr62_sgpr63_sgpr64_sgpr65_sgpr66_sgpr67, implicit killed $sgpr68_sgpr69_sgpr70_sgpr71_sgpr72_sgpr73_sgpr74_sgpr75_sgpr76_sgpr77_sgpr78_sgpr79_sgpr80_sgpr81_sgpr82_sgpr83, implicit killed $sgpr84_sgpr85_sgpr86_sgpr87_sgpr88_sgpr89_sgpr90_sgpr91_sgpr92_sgpr93_sgpr94_sgpr95, implicit killed $sgpr96_sgpr97_sgpr98_sgpr99
+    S_BRANCH %bb.2
+
+  bb.2:
+    liveins: $vcc
+
+    S_ENDPGM 0, implicit $vcc
+...



More information about the llvm-commits mailing list