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

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 05:08:05 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-amdgpu

Author: Pankaj Dwivedi (PankajDwivedi-25)

<details>
<summary>Changes</summary>

When frame index elimination runs out of SGPRs it emergency-spills one to
memory, and that spill flips EXEC with s_not_b64, which clobbers SCC. If SCC is
live the compiler gives up with "unhandled SGPR spill to memory". Hold on to the
SGPR already reserved for EXEC copies so the spill can use s_mov_b64 instead.

---

Patch is 23.20 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/221972.diff


8 Files Affected:

- (modified) llvm/lib/Target/AMDGPU/SIFrameLowering.cpp (+71-2) 
- (modified) llvm/lib/Target/AMDGPU/SIFrameLowering.h (+5) 
- (modified) llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp (+7-3) 
- (modified) llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp (+14-4) 
- (modified) llvm/test/CodeGen/AMDGPU/branch-relax-spill.ll (+3-2) 
- (modified) llvm/test/CodeGen/AMDGPU/bug-undef-spilled-agpr.mir (+10-8) 
- (modified) llvm/test/CodeGen/AMDGPU/eliminate-frame-index-select.ll (+4-2) 
- (added) llvm/test/CodeGen/AMDGPU/sgpr-spill-to-vmem-scc-clobber-reserved-exec-copy.mir (+92) 


``````````diff
diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
index 92fb77b1e6436..e9de8d013eee3 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
@@ -1859,9 +1859,18 @@ void SIFrameLowering::determinePrologEpilogSGPRSaves(
   const TargetRegisterClass &RC = *TRI->getWaveMaskRegClass();
 
   Register ReservedRegForExecCopy = MFI->getSGPRForEXECCopy();
-  if (NeedExecCopyReservedReg ||
+  bool NeedExecCopy =
+      NeedExecCopyReservedReg ||
       (ReservedRegForExecCopy &&
-       MRI.isPhysRegUsed(ReservedRegForExecCopy, /*SkipRegMaskTest=*/true))) {
+       MRI.isPhysRegUsed(ReservedRegForExecCopy, /*SkipRegMaskTest=*/true));
+
+  // An SGPR spill during frame index elimination needs the register too. The
+  // code below still hands it back if a scratch SGPR turns out to be free.
+  if (!NeedExecCopy && ReservedRegForExecCopy &&
+      mayNeedExecCopyForScalarFrameIndex(MF))
+    NeedExecCopy = true;
+
+  if (NeedExecCopy) {
     MRI.reserveReg(ReservedRegForExecCopy, TRI);
     Register UnusedScratchReg = findUnusedRegister(MRI, LiveUnits, RC);
     if (UnusedScratchReg) {
@@ -1924,6 +1933,66 @@ void SIFrameLowering::determinePrologEpilogSGPRSaves(
   }
 }
 
+// Match an instruction whose frame index eliminateFrameIndex has to materialize
+// into a scavenged SGPR while SCC is live.
+static bool hasScalarFrameIndexWithLiveSCC(const SIInstrInfo &TII,
+                                           const SIRegisterInfo &TRI,
+                                           const MachineInstr &MI) {
+  if (TII.isMUBUF(MI))
+    return false;
+
+  // A move reuses its own destination instead of scavenging. Keep in sync with
+  // the IsCopy handling in SIRegisterInfo::eliminateFrameIndex.
+  unsigned Opcode = MI.getOpcode();
+  if (Opcode == AMDGPU::S_MOV_B32 || Opcode == AMDGPU::V_MOV_B32_e32 ||
+      Opcode == AMDGPU::V_MOV_B32_e64)
+    return false;
+
+  bool HasScalarFrameIndex = false;
+  for (unsigned OpNo = 0, E = MI.getNumExplicitOperands(); OpNo != E; ++OpNo) {
+    if (!MI.getOperand(OpNo).isFI())
+      continue;
+    const TargetRegisterClass *RC = TII.getRegClass(MI.getDesc(), OpNo);
+    if (RC && SIRegisterInfo::isSGPRClass(RC)) {
+      HasScalarFrameIndex = true;
+      break;
+    }
+  }
+
+  if (!HasScalarFrameIndex)
+    return false;
+
+  // The spill and the reload land on either side of MI. An indefinite answer is
+  // not worth a register: the spill still reports rather than miscompiles.
+  const MachineBasicBlock &MBB = *MI.getParent();
+  MachineBasicBlock::const_iterator I(MI);
+  return MBB.computeRegisterLiveness(&TRI, AMDGPU::SCC, I) ==
+             MachineBasicBlock::LQR_Live ||
+         MBB.computeRegisterLiveness(&TRI, AMDGPU::SCC, std::next(I)) ==
+             MachineBasicBlock::LQR_Live;
+}
+
+bool SIFrameLowering::mayNeedExecCopyForScalarFrameIndex(
+    const MachineFunction &MF) const {
+  const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
+  // Frame indices need no scalar temporary at the bottom of the stack, nor with
+  // flat scratch.
+  if (ST.hasFlatScratchEnabled() ||
+      MF.getInfo<SIMachineFunctionInfo>()->isBottomOfStack())
+    return false;
+
+  const SIInstrInfo &TII = *ST.getInstrInfo();
+  const SIRegisterInfo &TRI = *ST.getRegisterInfo();
+  for (const MachineBasicBlock &MBB : MF) {
+    for (const MachineInstr &MI : MBB) {
+      if (hasScalarFrameIndexWithLiveSCC(TII, TRI, MI))
+        return true;
+    }
+  }
+
+  return false;
+}
+
 // Only report VGPRs to generic code.
 void SIFrameLowering::determineCalleeSaves(MachineFunction &MF,
                                            BitVector &SavedVGPRs,
diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.h b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
index 38bf3fee0cf7b..b6af267309212 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
@@ -48,6 +48,11 @@ class SIFrameLowering final : public AMDGPUFrameLowering {
                             const DebugLoc &DL, LiveRegUnits &LiveUnits,
                             Register FrameReg,
                             Register FramePtrRegScratchCopy) const;
+
+  /// Return true if frame index elimination may have to spill an SGPR to
+  /// memory while SCC is live. Such a spill needs a register to hold EXEC.
+  bool mayNeedExecCopyForScalarFrameIndex(const MachineFunction &MF) const;
+
   bool
   assignCalleeSavedSpillSlots(MachineFunction &MF,
                               const TargetRegisterInfo *TRI,
diff --git a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
index d0a57e163d29a..dd730a1019995 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -449,6 +449,7 @@ bool SILowerSGPRSpills::run(MachineFunction &MF) {
   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
   TII = ST.getInstrInfo();
   TRI = &TII->getRegisterInfo();
+  const SIFrameLowering *TFI = ST.getFrameLowering();
 
   assert(SaveBlocks.empty() && RestoreBlocks.empty());
 
@@ -610,14 +611,17 @@ bool SILowerSGPRSpills::run(MachineFunction &MF) {
     MadeChange = true;
   }
 
-  if (SpilledToVirtVGPRLanes) {
+  // Frame index elimination may need the register to keep SCC alive across an
+  // SGPR spill to memory, and nothing can free one up after this point.
+  if (SpilledToVirtVGPRLanes || TFI->mayNeedExecCopyForScalarFrameIndex(MF)) {
     const TargetRegisterClass *RC = TRI->getWaveMaskRegClass();
     // Shift back the reserved SGPR for EXEC copy into the lowest range.
     // This SGPR is reserved to handle the whole-wave spill/copy operations
     // that might get inserted during vgpr regalloc.
+    Register ExecCopyReg = FuncInfo->getSGPRForEXECCopy();
     Register UnusedLowSGPR = TRI->findUnusedRegister(MRI, RC, MF);
-    if (UnusedLowSGPR && TRI->getHWRegIndex(UnusedLowSGPR) <
-                             TRI->getHWRegIndex(FuncInfo->getSGPRForEXECCopy()))
+    if (UnusedLowSGPR && (!ExecCopyReg || TRI->getHWRegIndex(UnusedLowSGPR) <
+                                              TRI->getHWRegIndex(ExecCopyReg)))
       FuncInfo->setSGPRForEXECCopy(UnusedLowSGPR);
   } else {
     // No SGPR spills to virtual VGPR lanes and hence there won't be any WWM
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
index f570aa4e2f6fb..4acdc5a9f939f 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
@@ -222,6 +222,18 @@ struct SGPRSpillBuilder {
     RS->setRegUsed(SuperReg);
     SavedExecReg = RS->scavengeRegisterBackwards(RC, MI, false, 0, false);
 
+    // With no SGPR left to scavenge, fall back to the register reserved for
+    // EXEC copies; the S_NOT below would clobber SCC instead. Being reserved it
+    // is invisible to the scavenger, so ask the block whether it is free:
+    // inline asm can still name it.
+    if (!SavedExecReg) {
+      MCRegister ExecCopyReg = MFI.getSGPRForEXECCopy();
+      if (ExecCopyReg &&
+          MBB->computeRegisterLiveness(&TRI, ExecCopyReg, MI, UINT_MAX) ==
+              MachineBasicBlock::LQR_Dead)
+        SavedExecReg = ExecCopyReg;
+    }
+
     int64_t VGPRLanes = getPerVGPRData().VGPRLanes;
 
     if (SavedExecReg) {
@@ -236,8 +248,7 @@ struct SGPRSpillBuilder {
       TRI.buildVGPRSpillLoadStore(*this, TmpVGPRIndex, 0, /*IsLoad*/ false);
     } else {
       // The modify and restore of exec clobber SCC, which we would have to save
-      // and restore. FIXME: We probably would need to reserve a register for
-      // this.
+      // and restore.
       if (RS->isRegUsed(AMDGPU::SCC))
         emitUnsupportedError(MF.getFunction(), *MI,
                              "unhandled SGPR spill to memory");
@@ -312,8 +323,7 @@ struct SGPRSpillBuilder {
       TRI.buildVGPRSpillLoadStore(*this, Index, Offset, IsLoad);
     } else {
       // The modify and restore of exec clobber SCC, which we would have to save
-      // and restore. FIXME: We probably would need to reserve a register for
-      // this.
+      // and restore.
       if (RS->isRegUsed(AMDGPU::SCC))
         emitUnsupportedError(MF.getFunction(), *MI,
                              "unhandled SGPR spill to memory");
diff --git a/llvm/test/CodeGen/AMDGPU/branch-relax-spill.ll b/llvm/test/CodeGen/AMDGPU/branch-relax-spill.ll
index 305b44fa39b2c..01669d9f15dbb 100644
--- a/llvm/test/CodeGen/AMDGPU/branch-relax-spill.ll
+++ b/llvm/test/CodeGen/AMDGPU/branch-relax-spill.ll
@@ -325,7 +325,8 @@ define amdgpu_kernel void @spill(ptr addrspace(1) %arg, i32 %cnd) #0 {
 ; CHECK-NEXT:    ;;#ASMEND
 ; CHECK-NEXT:    s_cbranch_scc0 .LBB0_1
 ; CHECK-NEXT:  ; %bb.3: ; %entry
-; CHECK-NEXT:    s_not_b64 exec, exec
+; CHECK-NEXT:    s_mov_b64 s[100:101], exec
+; CHECK-NEXT:    s_mov_b64 exec, 3
 ; CHECK-NEXT:    buffer_store_dword v0, off, s[96:99], 0
 ; CHECK-NEXT:    v_writelane_b32 v0, s0, 0
 ; CHECK-NEXT:    v_writelane_b32 v0, s1, 1
@@ -350,7 +351,7 @@ define amdgpu_kernel void @spill(ptr addrspace(1) %arg, i32 %cnd) #0 {
 ; CHECK-NEXT:    v_readlane_b32 s0, v0, 0
 ; CHECK-NEXT:    v_readlane_b32 s1, v0, 1
 ; CHECK-NEXT:    buffer_load_dword v0, off, s[96:99], 0
-; CHECK-NEXT:    s_not_b64 exec, exec
+; CHECK-NEXT:    s_mov_b64 exec, s[100:101]
 ; CHECK-NEXT:  .LBB0_2: ; %bb3
 ; CHECK-NEXT:    ;;#ASMSTART
 ; CHECK-NEXT:    ; reg use s0
diff --git a/llvm/test/CodeGen/AMDGPU/bug-undef-spilled-agpr.mir b/llvm/test/CodeGen/AMDGPU/bug-undef-spilled-agpr.mir
index 5c564decd1e7d..7510909eb1442 100644
--- a/llvm/test/CodeGen/AMDGPU/bug-undef-spilled-agpr.mir
+++ b/llvm/test/CodeGen/AMDGPU/bug-undef-spilled-agpr.mir
@@ -22,20 +22,22 @@ body:             |
   ; GCN-NEXT:   frame-setup CFI_INSTRUCTION llvm_def_aspace_cfa $sgpr32, 0, 6
   ; GCN-NEXT:   frame-setup CFI_INSTRUCTION llvm_register_pair $pc_reg, $sgpr30, 32, $sgpr31, 32
   ; GCN-NEXT:   frame-setup CFI_INSTRUCTION undefined $agpr0
+  ; GCN-NEXT:   frame-setup CFI_INSTRUCTION undefined $sgpr6
+  ; GCN-NEXT:   frame-setup CFI_INSTRUCTION undefined $sgpr7
   ; GCN-NEXT:   frame-setup CFI_INSTRUCTION undefined $sgpr14
-  ; GCN-NEXT:   $sgpr4_sgpr5 = S_XOR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
+  ; GCN-NEXT:   $sgpr6_sgpr7 = S_XOR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
   ; GCN-NEXT:   $vgpr63 = V_ACCVGPR_READ_B32_e64 $agpr0, implicit $exec
   ; GCN-NEXT:   BUFFER_STORE_DWORD_OFFSET $vgpr63, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 0, 0, 0, implicit $exec :: ("amdgpu-thread-private" store (s32) into %stack.2, addrspace 5)
   ; GCN-NEXT:   frame-setup CFI_INSTRUCTION offset $agpr0, 0
   ; GCN-NEXT:   $exec = S_MOV_B64 -1
   ; GCN-NEXT:   BUFFER_STORE_DWORD_OFFSET killed $vgpr62, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 4, 0, 0, implicit $exec :: ("amdgpu-thread-private" store (s32) into %stack.3, addrspace 5)
   ; GCN-NEXT:   frame-setup CFI_INSTRUCTION offset $vgpr62, 256
-  ; GCN-NEXT:   $exec = S_MOV_B64 killed $sgpr4_sgpr5
+  ; GCN-NEXT:   $exec = S_MOV_B64 killed $sgpr6_sgpr7
   ; GCN-NEXT:   renamable $vgpr62 = IMPLICIT_DEF
   ; GCN-NEXT:   $vgpr62 = SI_SPILL_S32_TO_VGPR $sgpr15, 0, killed $vgpr62
-  ; GCN-NEXT:   $noreg = S_OR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
+  ; GCN-NEXT:   $sgpr6_sgpr7 = S_OR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
   ; GCN-NEXT:   renamable $agpr0 = lr-split COPY killed renamable $vgpr62
-  ; GCN-NEXT:   $exec = S_MOV_B64 killed $noreg
+  ; GCN-NEXT:   $exec = S_MOV_B64 killed $sgpr6_sgpr7
   ; GCN-NEXT:   renamable $vgpr62 = IMPLICIT_DEF
   ; GCN-NEXT:   dead renamable $vgpr62 = V_AND_B32_e32 1, killed $vgpr62, implicit $exec
   ; GCN-NEXT: {{  $}}
@@ -57,19 +59,19 @@ body:             |
   ; GCN-NEXT:   successors: %bb.2(0x80000000)
   ; GCN-NEXT:   liveins: $agpr0
   ; GCN-NEXT: {{  $}}
-  ; GCN-NEXT:   $noreg = S_OR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
+  ; GCN-NEXT:   $sgpr6_sgpr7 = S_OR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
   ; GCN-NEXT:   renamable $vgpr62 = lr-split COPY renamable $agpr0
-  ; GCN-NEXT:   $exec = S_MOV_B64 killed $noreg
+  ; GCN-NEXT:   $exec = S_MOV_B64 killed $sgpr6_sgpr7
   ; GCN-NEXT:   $sgpr14 = SI_RESTORE_S32_FROM_VGPR killed $vgpr62, 1
   ; GCN-NEXT:   S_BRANCH %bb.2
   ; GCN-NEXT: {{  $}}
   ; GCN-NEXT: bb.4:
-  ; GCN-NEXT:   $sgpr4_sgpr5 = S_XOR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
+  ; GCN-NEXT:   $sgpr6_sgpr7 = S_XOR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
   ; GCN-NEXT:   $vgpr63 = BUFFER_LOAD_DWORD_OFFSET $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 0, 0, 0, implicit $exec :: ("amdgpu-thread-private" load (s32) from %stack.2, addrspace 5)
   ; GCN-NEXT:   $agpr0 = V_ACCVGPR_WRITE_B32_e64 killed $vgpr63, implicit $exec
   ; GCN-NEXT:   $exec = S_MOV_B64 -1
   ; GCN-NEXT:   $vgpr62 = BUFFER_LOAD_DWORD_OFFSET $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 4, 0, 0, implicit $exec :: ("amdgpu-thread-private" load (s32) from %stack.3, addrspace 5)
-  ; GCN-NEXT:   $exec = S_MOV_B64 killed $sgpr4_sgpr5
+  ; GCN-NEXT:   $exec = S_MOV_B64 killed $sgpr6_sgpr7
   ; GCN-NEXT:   SI_RETURN
   bb.0:
     liveins: $sgpr12, $sgpr13, $sgpr14, $sgpr15
diff --git a/llvm/test/CodeGen/AMDGPU/eliminate-frame-index-select.ll b/llvm/test/CodeGen/AMDGPU/eliminate-frame-index-select.ll
index d7caf2293d560..6350cc89cf91e 100644
--- a/llvm/test/CodeGen/AMDGPU/eliminate-frame-index-select.ll
+++ b/llvm/test/CodeGen/AMDGPU/eliminate-frame-index-select.ll
@@ -17,11 +17,12 @@ define void @wobble() #0 {
 ; CHECK-NEXT:    s_or_saveexec_b32 s17, -1
 ; CHECK-NEXT:    buffer_store_dword v43, off, s[0:3], s33 offset:24 ; 4-byte Folded Spill
 ; CHECK-NEXT:    s_mov_b32 exec_lo, s17
-; CHECK-NEXT:    v_writelane_b32 v43, s16, 15
+; CHECK-NEXT:    v_writelane_b32 v43, s16, 16
 ; CHECK-NEXT:    s_addk_i32 s32, 0x400
 ; CHECK-NEXT:    buffer_store_dword v40, off, s[0:3], s33 offset:8 ; 4-byte Folded Spill
 ; CHECK-NEXT:    buffer_store_dword v41, off, s[0:3], s33 offset:4 ; 4-byte Folded Spill
 ; CHECK-NEXT:    buffer_store_dword v42, off, s[0:3], s33 ; 4-byte Folded Spill
+; CHECK-NEXT:    v_writelane_b32 v43, s55, 15
 ; CHECK-NEXT:    v_writelane_b32 v43, s34, 0
 ; CHECK-NEXT:    v_writelane_b32 v43, s35, 1
 ; CHECK-NEXT:    v_writelane_b32 v43, s36, 2
@@ -107,7 +108,8 @@ define void @wobble() #0 {
 ; CHECK-NEXT:    v_readlane_b32 s35, v43, 1
 ; CHECK-NEXT:    v_readlane_b32 s34, v43, 0
 ; CHECK-NEXT:    s_mov_b32 s32, s33
-; CHECK-NEXT:    v_readlane_b32 s4, v43, 15
+; CHECK-NEXT:    v_readlane_b32 s4, v43, 16
+; CHECK-NEXT:    v_readlane_b32 s55, v43, 15
 ; CHECK-NEXT:    s_or_saveexec_b32 s5, -1
 ; CHECK-NEXT:    buffer_load_dword v43, off, s[0:3], s33 offset:24 ; 4-byte Folded Reload
 ; CHECK-NEXT:    s_mov_b32 exec_lo, s5
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..df6a9e2842db8
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/sgpr-spill-to-vmem-scc-clobber-reserved-exec-copy.mir
@@ -0,0 +1,92 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -run-pass=prolog-epilog -o - %s 2>&1 | FileCheck %s
+
+# The frame index operand of the S_SUB_U32 has to be materialized into a scalar
+# register, and with every other SGPR live the scavenger frees one by spilling
+# it to memory. That spill flips EXEC, so it may only run if it can save EXEC
+# somewhere first: the S_SUBB_U32 below consumes the carry that S_SUB_U32
+# produces, and S_NOT_B64 would destroy it. The register held back for EXEC
+# copies covers this, so the sequence uses S_MOV_B64 and SCC survives.
+
+---
+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:   liveins: $vgpr0, $vgpr0
+  ; 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:   $sgpr4_sgpr5 = S_XOR_SAVEEXEC_B64 -1, implicit-def $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   BUFFER_STORE_DWORD_OFFSET $vgpr0, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 64, 0, 0, implicit $exec :: ("amdgpu-thread-private" store (s32) into %stack.2, addrspace 5)
+  ; CHECK-NEXT:   frame-setup CFI_INSTRUCTION offset $vgpr0, 4096
+  ; CHECK-NEXT:   $exec = S_MOV_B64 killed $sgpr4_sgpr5
+  ; CHECK-NEXT:   $vgpr0 = SI_SPILL_S32_TO_VGPR $sgpr100, 0, undef $vgpr0
+  ; CHECK-NEXT:   frame-setup CFI_INSTRUCTION llvm_vector_registers $sgpr100, $vgpr0, 0, 32
+  ; CHECK-NEXT:   $vgpr0 = SI_SPILL_S32_TO_VGPR $sgpr101, 1, undef $vgpr0
+  ; CHECK-NEXT:   frame-setup CFI_INSTRUCTION llvm_vector_registers $sgpr101, $vgpr0, 1, 32
+  ; CHECK-NEXT:   S_BRANCH %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT:   liveins: $vcc, $vgpr0, $sgpr96_sgpr97_sgpr98_sgpr99, $sgpr84_sgpr85_sgpr86_sgpr87_sgpr88_sgpr89_sgpr90_sgpr91_sgpr92_sgpr93_sgpr94_sgpr95, $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
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   $sgpr100_sgpr101 = S_MOV_B64 $exec
+  ; CHECK-NEXT:   $exec = S_MOV_B64 1, implicit-def $vgpr1
+  ; CHECK-NEXT:   BUFFER_STORE_DWORD_OFFSET killed $vgpr1, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 68, 0, 0, implicit $exec :: ("amdgpu-thread-private" store (s32) into %stack.3, addrspace 5)
+  ; CHECK-NEXT:   $vgpr1 = SI_SPILL_S32_TO_VGPR killed $sgpr4, 0, undef $vgpr1
+  ; CHECK-NEXT:   BUFFER_STORE_DWORD_OFFSET killed $vgpr1, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 68, 0, 0, implicit $exec :: ("amdgpu-thread-private" store (s32) into %stack.3, addrspace 5)
+  ; CHECK-NEXT:   $vgpr1 = BUFFER_LOAD_DWORD_OFFSET $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 68, 0, 0, implicit $exec :: ("amdgpu-thread-private" load (s32) from %stack.3, addrspace 5)
+  ; CHECK-NEXT:   $exec = S_MOV_B64 killed $sgpr100_sgpr101, implicit killed $vgpr1
+  ; CHECK-NEXT:   $sgpr4 = S_LSHR_B32 $sgpr32, 6, implicit-def dead $scc
+  ; CHECK-NEXT:   renamable $vcc_lo = S_SUB_U32 killed renamable $vcc_lo, killed $sgpr4, implicit-def $scc
+  ; CHECK-NEXT:   $sgpr100_sgpr101 = S_MOV_B64 $exec
+  ; CHECK-NEXT:   $exec = S_MOV_B64 1, implicit-def $vgpr2
+  ; CHECK-NEXT:   BUFFER_STORE_DWORD_OFFSET killed $vgpr2, $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 68, 0, 0, implicit $exec :: ("amdgpu-thread-private" store (s32) into %stack.3, addrspace 5)
+  ; CHECK-NEXT:   $vgpr2 = BUFFER_LOAD_DWORD_OFFSET $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 68, 0, 0, implicit $exec :: ("amdgpu-thread-private" load (s32) from %stack.3, addrspace 5)
+  ; CHECK-NEXT:   $sgpr4 = SI_RESTORE_S32_FROM_VGPR killed $vgpr2, 0
+  ; CHECK-NEXT:   $vgpr2 = BUFFER_LOAD_DWORD_OFFSET $sgpr0_sgpr1_sgpr2_sgpr3, $sgpr32, 68, 0, 0, implicit $exec :: ("amdgpu-thread-private" load (s32) from %stack.3, addrspace 5)
+  ; CHECK-NEXT:   $exec = S_MOV_B64 killed $sgpr100_sgpr101, implicit killed $vgpr2
+  ; 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_...
[truncated]

``````````

</details>


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


More information about the llvm-commits mailing list