Compare commits

...

1 commit

Author SHA1 Message Date
Shilei Tian
aaabd24839 [AMDGPU] Support partial and empty WWM pools for SGPR spills
SGPR lane spilling currently treats the WWM VGPR pool as all-or-nothing. This
can fail compilation when the requested pool cannot be formed, even though
scratch spilling or a smaller spillable pool could make progress.

This PR lets ordinary SGPR spills fall back to scratch when the pool is empty
and lets WWM register allocation use a nonempty partial pool. It keeps the
full-pool requirement for strict WWM/WQM and explicit spill-carrier
preallocation.

The no-pool fallback is recorded in SIMachineFunctionInfo so frame lowering can
provide enough emergency scavenging slots. The state is also serialized to
preserve the behavior across MIR round trips.
2026-08-01 18:23:56 -04:00
12 changed files with 549 additions and 61 deletions

View file

@ -1793,10 +1793,16 @@ void SIFrameLowering::processFunctionBeforeFrameFinalized(
// Add an emergency spill slot
RS->addScavengingFrameIndex(FuncInfo->getScavengeFI(MFI, *TRI));
// If we are spilling SGPRs to memory with a large frame, we may need a
// second VGPR emergency frame index.
if (HaveSGPRToVMemSpill &&
allocateScavengingFrameIndexesNearIncomingSP(MF)) {
if (HaveSGPRToVMemSpill && FuncInfo->hasNoWWMPoolSGPRSpillFallback()) {
// The no-WWM-pool fallback can reach SGPR-to-memory lowering while an
// ordinary frame-index scavenge is live. It may then need one slot for
// its temporary VGPR and another for recursive address materialization.
RS->addScavengingFrameIndex(MFI.CreateSpillStackObject(4, Align(4)));
RS->addScavengingFrameIndex(MFI.CreateSpillStackObject(4, Align(4)));
} else if (HaveSGPRToVMemSpill &&
allocateScavengingFrameIndexesNearIncomingSP(MF)) {
// Existing large-frame SGPR-to-memory spills need one additional VGPR
// emergency frame index.
RS->addScavengingFrameIndex(MFI.CreateSpillStackObject(4, Align(4)));
}
}

View file

@ -20,6 +20,7 @@
#include "GCNSubtarget.h"
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
#include "SIMachineFunctionInfo.h"
#include "SIPreAllocateWWMRegs.h"
#include "SISpillUtils.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/MachineCycleAnalysis.h"
@ -80,7 +81,9 @@ public:
void updateLaneVGPRDomInstr(
int FI, MachineBasicBlock *MBB, MachineBasicBlock::iterator InsertPt,
DenseMap<Register, LaneVGPRInsertPt> &LaneVGPRDomInstr);
void determineRegsForWWMAllocation(MachineFunction &MF, BitVector &RegMask);
SmallVector<MCRegister> determineRegsForWWMAllocation(MachineFunction &MF);
void assignWWMRegs(MachineFunction &MF, ArrayRef<MCRegister> WWMRegCandidates,
bool RequiresFullWWMPool);
};
class SILowerSGPRSpillsLegacy : public MachineFunctionPass {
@ -372,42 +375,64 @@ void SILowerSGPRSpills::updateLaneVGPRDomInstr(
}
}
void SILowerSGPRSpills::determineRegsForWWMAllocation(MachineFunction &MF,
BitVector &RegMask) {
// Determine an optimal number of VGPRs for WWM allocation. The complement
// list will be available for allocating other VGPR virtual registers.
SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
SmallVector<MCRegister>
SILowerSGPRSpills::determineRegsForWWMAllocation(MachineFunction &MF) {
SmallVector<MCRegister> WWMRegCandidates;
if (!MaxNumVGPRsForWwmAllocation)
return WWMRegCandidates;
MachineRegisterInfo &MRI = MF.getRegInfo();
BitVector ReservedRegs = TRI->getReservedRegs(MF);
BitVector NonWwmAllocMask(TRI->getNumRegs());
const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
unsigned MaxNumVGPRs = ST.getMaxNumVectorRegs(MF.getFunction()).first;
// FIXME: MaxNumVGPRsForWwmAllocation might need to be adjusted in the future
// to have a balanced allocation between WWM values and per-thread vector
// register operands.
unsigned NumRegs = MaxNumVGPRsForWwmAllocation;
NumRegs =
std::min(static_cast<unsigned>(MFI->getSGPRSpillVGPRs().size()), NumRegs);
auto [MaxNumVGPRs, MaxNumAGPRs] = ST.getMaxNumVectorRegs(MF.getFunction());
// Try to use the highest available registers for now. Later after
// vgpr-regalloc, they can be shifted to the lowest range.
unsigned I = 0;
for (unsigned Reg = AMDGPU::VGPR0 + MaxNumVGPRs - 1;
(I < NumRegs) && (Reg >= AMDGPU::VGPR0); --Reg) {
WWMRegCandidates.size() < MaxNumVGPRsForWwmAllocation &&
Reg >= AMDGPU::VGPR0;
--Reg) {
if (!ReservedRegs.test(Reg) &&
!MRI.isPhysRegUsed(Reg, /*SkipRegMaskTest=*/true)) {
TRI->markSuperRegs(RegMask, Reg);
++I;
}
!MRI.isPhysRegUsed(Reg, /*SkipRegMaskTest=*/true))
WWMRegCandidates.push_back(Reg);
}
if (I != NumRegs) {
return WWMRegCandidates;
}
void SILowerSGPRSpills::assignWWMRegs(MachineFunction &MF,
ArrayRef<MCRegister> WWMRegCandidates,
bool RequiresFullWWMPool) {
SIMachineFunctionInfo *FuncInfo = MF.getInfo<SIMachineFunctionInfo>();
if (FuncInfo->getSGPRSpillVGPRs().empty())
return;
BitVector WwmRegMask(TRI->getNumRegs());
unsigned DesiredPoolSize =
std::min(static_cast<unsigned>(FuncInfo->getSGPRSpillVGPRs().size()),
static_cast<unsigned>(MaxNumVGPRsForWwmAllocation));
unsigned SelectedPoolSize =
std::min<unsigned>(DesiredPoolSize, WWMRegCandidates.size());
// WWM register candidates are ordered high-to-low, so take the highest
// available registers when the desired pool is smaller than the candidate
// list.
for (MCRegister Reg : WWMRegCandidates.take_front(SelectedPoolSize))
TRI->markSuperRegs(WwmRegMask, Reg);
if (RequiresFullWWMPool && SelectedPoolSize != DesiredPoolSize) {
// Reserve an arbitrary register and report the error.
TRI->markSuperRegs(RegMask, AMDGPU::VGPR0);
TRI->markSuperRegs(WwmRegMask, AMDGPU::VGPR0);
MF.getFunction().getContext().emitError(
"cannot find enough VGPRs for wwm-regalloc");
}
BitVector NonWwmRegMask(WwmRegMask);
NonWwmRegMask.flip().clearBitsNotInMask(TRI->getAllVGPRRegMask());
// The complement set will be the registers for non-wwm (per-thread) vgpr
// allocation.
FuncInfo->updateNonWWMRegMask(NonWwmRegMask);
}
bool SILowerSGPRSpillsLegacy::runOnMachineFunction(MachineFunction &MF) {
@ -465,8 +490,19 @@ bool SILowerSGPRSpills::run(MachineFunction &MF) {
// To track the IMPLICIT_DEF insertion point for the lane vgprs.
DenseMap<Register, LaneVGPRInsertPt> LaneVGPRDomInstr;
// Defer ordinary spills until physical CSR spills have reserved their
// lane VGPRs and the WWM allocation pool can be selected.
SmallVector<MachineInstr *> OrdinarySGPRSpills;
bool HasStrictWWMRegion = false;
for (MachineBasicBlock &MBB : MF) {
for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) {
if (MI.getOpcode() == AMDGPU::ENTER_STRICT_WWM ||
MI.getOpcode() == AMDGPU::ENTER_STRICT_WQM) {
HasStrictWWMRegion = true;
continue;
}
if (!TII->isSGPRSpill(MI))
continue;
@ -500,18 +536,39 @@ bool SILowerSGPRSpills::run(MachineFunction &MF) {
llvm_unreachable(
"failed to spill SGPR to physical VGPR lane when allocated");
}
} else {
MachineInstrSpan MIS(&MI, &MBB);
if (FuncInfo->allocateSGPRSpillToVGPRLane(MF, FI)) {
bool Spilled = TRI->eliminateSGPRToVGPRSpillFrameIndex(
MI, FI, nullptr, Indexes, LIS);
if (!Spilled)
llvm_unreachable(
"failed to spill SGPR to virtual VGPR lane when allocated");
SpillFIs.set(FI);
updateLaneVGPRDomInstr(FI, &MBB, MIS.begin(), LaneVGPRDomInstr);
SpilledToVirtVGPRLanes = true;
}
} else
OrdinarySGPRSpills.push_back(&MI);
}
}
// Select candidates once, before ordinary lane lowering creates virtual
// VGPRs and changes the number of registers desired for the WWM pool.
SmallVector<MCRegister> WWMRegCandidates;
// These non-spillable WWM users retain the old all-or-nothing pool policy.
const bool RequiresFullWWMPool =
HasStrictWWMRegion || isPreallocateSGPRSpillVGPRsEnabled(MF);
if (!OrdinarySGPRSpills.empty())
WWMRegCandidates = determineRegsForWWMAllocation(MF);
const bool ShouldLowerOrdinarySpillsToVGPRLanes =
RequiresFullWWMPool || !WWMRegCandidates.empty();
if (!ShouldLowerOrdinarySpillsToVGPRLanes && !OrdinarySGPRSpills.empty())
FuncInfo->setNoWWMPoolSGPRSpillFallback();
if (ShouldLowerOrdinarySpillsToVGPRLanes) {
for (MachineInstr *MI : OrdinarySGPRSpills) {
int FI = TII->getNamedOperand(*MI, AMDGPU::OpName::addr)->getIndex();
if (FuncInfo->allocateSGPRSpillToVGPRLane(MF, FI)) {
MachineBasicBlock *MBB = MI->getParent();
MachineInstrSpan MIS(MI, MBB);
bool Spilled = TRI->eliminateSGPRToVGPRSpillFrameIndex(
*MI, FI, nullptr, Indexes, LIS);
if (!Spilled)
llvm_unreachable(
"failed to spill SGPR to virtual VGPR lane when allocated");
SpillFIs.set(FI);
updateLaneVGPRDomInstr(FI, MBB, MIS.begin(), LaneVGPRDomInstr);
SpilledToVirtVGPRLanes = true;
}
}
}
@ -538,20 +595,9 @@ bool SILowerSGPRSpills::run(MachineFunction &MF) {
}
}
// Determine the registers for WWM allocation and also compute the register
// mask for non-wwm VGPR allocation.
if (FuncInfo->getSGPRSpillVGPRs().size()) {
BitVector WwmRegMask(TRI->getNumRegs());
determineRegsForWWMAllocation(MF, WwmRegMask);
BitVector NonWwmRegMask(WwmRegMask);
NonWwmRegMask.flip().clearBitsNotInMask(TRI->getAllVGPRRegMask());
// The complement set will be the registers for non-wwm (per-thread) vgpr
// allocation.
FuncInfo->updateNonWWMRegMask(NonWwmRegMask);
}
// Assign the WWM pool from the pre-selected candidates and compute the
// complement mask for per-thread VGPR allocation.
assignWWMRegs(MF, WWMRegCandidates, RequiresFullWWMPool);
for (MachineBasicBlock &MBB : MF)
clearDebugInfoForSpillFIs(MFI, MBB, SpillFIs);

View file

@ -739,6 +739,7 @@ yaml::SIMachineFunctionInfo::SIMachineFunctionInfo(
WaveLimiter(MFI.needsWaveLimiter()),
HasSpilledSGPRs(MFI.hasSpilledSGPRs()),
HasSpilledVGPRs(MFI.hasSpilledVGPRs()),
HasNoWWMPoolSGPRSpillFallback(MFI.hasNoWWMPoolSGPRSpillFallback()),
NumWaveDispatchSGPRs(MFI.getNumWaveDispatchSGPRs()),
NumWaveDispatchVGPRs(MFI.getNumWaveDispatchVGPRs()),
HighBitsOf32BitAddress(MFI.get32BitAddressHighBits()),
@ -798,6 +799,7 @@ bool SIMachineFunctionInfo::initializeBaseYamlFields(
WaveLimiter = YamlMFI.WaveLimiter;
HasSpilledSGPRs = YamlMFI.HasSpilledSGPRs;
HasSpilledVGPRs = YamlMFI.HasSpilledVGPRs;
HasNoWWMPoolSGPRSpillFallback = YamlMFI.HasNoWWMPoolSGPRSpillFallback;
NumWaveDispatchSGPRs = YamlMFI.NumWaveDispatchSGPRs;
NumWaveDispatchVGPRs = YamlMFI.NumWaveDispatchVGPRs;
BytesInStackArgArea = YamlMFI.BytesInStackArgArea;

View file

@ -272,6 +272,7 @@ struct SIMachineFunctionInfo final : public yaml::MachineFunctionInfo {
bool WaveLimiter = false;
bool HasSpilledSGPRs = false;
bool HasSpilledVGPRs = false;
bool HasNoWWMPoolSGPRSpillFallback = false;
uint16_t NumWaveDispatchSGPRs = 0;
uint16_t NumWaveDispatchVGPRs = 0;
uint32_t HighBitsOf32BitAddress = 0;
@ -334,6 +335,8 @@ template <> struct MappingTraits<SIMachineFunctionInfo> {
YamlIO.mapOptional("waveLimiter", MFI.WaveLimiter, false);
YamlIO.mapOptional("hasSpilledSGPRs", MFI.HasSpilledSGPRs, false);
YamlIO.mapOptional("hasSpilledVGPRs", MFI.HasSpilledVGPRs, false);
YamlIO.mapOptional("hasNoWWMPoolSGPRSpillFallback",
MFI.HasNoWWMPoolSGPRSpillFallback, false);
YamlIO.mapOptional("numWaveDispatchSGPRs", MFI.NumWaveDispatchSGPRs, false);
YamlIO.mapOptional("numWaveDispatchVGPRs", MFI.NumWaveDispatchVGPRs, false);
YamlIO.mapOptional("scratchRSrcReg", MFI.ScratchRSrcReg,
@ -613,6 +616,11 @@ private:
// frame, so save it here and add it to the RegScavenger later.
std::optional<int> ScavengeFI;
// Ordinary SGPR spills fell back to memory because no WWM VGPR pool was
// available. This path may require additional nested VGPR scavenging slots
// during frame-index elimination.
bool HasNoWWMPoolSGPRSpillFallback = false;
// Map each VGPR CSR to the mask needed to save and restore it using block
// load/store instructions. Only used if the subtarget feature for VGPR block
// load/store is enabled.
@ -853,6 +861,11 @@ public:
int getScavengeFI(MachineFrameInfo &MFI, const SIRegisterInfo &TRI);
std::optional<int> getOptionalScavengeFI() const { return ScavengeFI; }
void setNoWWMPoolSGPRSpillFallback() { HasNoWWMPoolSGPRSpillFallback = true; }
bool hasNoWWMPoolSGPRSpillFallback() const {
return HasNoWWMPoolSGPRSpillFallback;
}
unsigned getBytesInStackArgArea() const {
return BytesInStackArgArea;
}

View file

@ -35,6 +35,11 @@ static cl::opt<bool>
EnablePreallocateSGPRSpillVGPRs("amdgpu-prealloc-sgpr-spill-vgprs",
cl::init(false), cl::Hidden);
bool llvm::isPreallocateSGPRSpillVGPRsEnabled(const MachineFunction &MF) {
return EnablePreallocateSGPRSpillVGPRs ||
MF.getFunction().hasFnAttribute("amdgpu-prealloc-sgpr-spill-vgprs");
}
namespace {
class SIPreAllocateWWMRegs {
@ -221,9 +226,7 @@ bool SIPreAllocateWWMRegs::run(MachineFunction &MF) {
TRI = &TII->getRegisterInfo();
MRI = &MF.getRegInfo();
bool PreallocateSGPRSpillVGPRs =
EnablePreallocateSGPRSpillVGPRs ||
MF.getFunction().hasFnAttribute("amdgpu-prealloc-sgpr-spill-vgprs");
bool PreallocateSGPRSpillVGPRs = isPreallocateSGPRSpillVGPRsEnabled(MF);
bool RegsAssigned = false;

View file

@ -13,6 +13,8 @@
namespace llvm {
bool isPreallocateSGPRSpillVGPRsEnabled(const MachineFunction &MF);
class SIPreAllocateWWMRegsPass
: public RequiredPassInfoMixin<SIPreAllocateWWMRegsPass> {
public:

View file

@ -16,7 +16,10 @@
i64 ; vcc
}
; ERR-GCNTRACKERS: ran out of registers during register allocation
; With the tracker enabled, no separate WWM VGPR is available and the SGPR
; spill falls back to memory. This case cannot preserve EXEC because SCC is
; live and no SGPR can be scavenged.
; ERR-GCNTRACKERS: unhandled SGPR spill to memory
; GCN-NOT: ran out of registers during register allocation
; FIXME: GCN Trackers do not track pressure from PhysRegs, so scheduling is actually worse
@ -62,4 +65,3 @@ define void @scalar_mov_materializes_frame_index_no_live_scc_no_live_sgprs() #0
attributes #0 = { nounwind alignstack=64 "amdgpu-no-workitem-id-x" "amdgpu-no-workitem-id-y" "amdgpu-no-workitem-id-z" "amdgpu-waves-per-eu"="10,10" "no-realign-stack" }
attributes #1 = { nounwind alignstack=16 "amdgpu-no-workitem-id-x" "amdgpu-no-workitem-id-y" "amdgpu-no-workitem-id-z" "amdgpu-waves-per-eu"="10,10" "no-realign-stack" }

View file

@ -4,6 +4,10 @@
# Check that we allocate 2 emergency stack slots if we're spilling
# SGPRs to memory and potentially have an offset larger than fits in
# the addressing mode of the memory instructions.
#
# The no-WWM-pool fallback needs 3 emergency slots even for a small frame:
# one for an ordinary frame-index scavenge, one for the SGPR spill temporary,
# and one for recursive address materialization.
---
name: test
@ -49,3 +53,35 @@ body: |
renamable $sgpr10 = SI_SPILL_S32_RESTORE %stack.0, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
S_SETPC_B64 $sgpr30_sgpr31, implicit $scc
...
---
name: fallback_scavenging
tracksRegLiveness: true
frameInfo:
maxAlignment: 4
stack:
- { id: 0, type: spill-slot, size: 4, alignment: 4, stack-id: sgpr-spill }
machineFunctionInfo:
isEntryFunction: false
scratchRSrcReg: '$sgpr0_sgpr1_sgpr2_sgpr3'
stackPtrOffsetReg: '$sgpr32'
frameOffsetReg: '$sgpr33'
hasSpilledSGPRs: true
hasNoWWMPoolSGPRSpillFallback: true
body: |
bb.0:
liveins: $sgpr30_sgpr31, $sgpr10, $sgpr11
; CHECK-LABEL: name: fallback_scavenging
; CHECK: frameInfo:
; CHECK: stackSize: 16
; CHECK: stack:
; CHECK: - { id: 0,
; CHECK: - { id: 1,
; CHECK: - { id: 2,
; CHECK: - { id: 3,
; CHECK: machineFunctionInfo:
; CHECK: hasNoWWMPoolSGPRSpillFallback: true
S_CMP_EQ_U32 0, 0, implicit-def $scc
SI_SPILL_S32_SAVE killed $sgpr10, %stack.0, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
renamable $sgpr10 = SI_SPILL_S32_RESTORE %stack.0, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
S_SETPC_B64 $sgpr30_sgpr31, implicit $scc
...

View file

@ -1,8 +1,22 @@
; RUN: not llc -mtriple=amdgpu9.00-amd-amdhsa -stress-regalloc=2 -filetype=null %s 2>&1 | FileCheck %s
; RUN: llc -mtriple=amdgpu9.00-amd-amdhsa -stress-regalloc=2 -o - %s | FileCheck %s
; RUN: llc -mtriple=amdgpu9.00-amd-amdhsa -stress-regalloc=2 -stop-after=si-lower-sgpr-spills -o %t.mir %s
; RUN: FileCheck --check-prefix=MIR %s < %t.mir
; RUN: llc -mtriple=amdgpu9.00-amd-amdhsa -stress-regalloc=2 -start-after=si-lower-sgpr-spills -o - %t.mir | FileCheck --check-prefix=ROUNDTRIP %s
; A negative test to capture the expected error when the VGPRs are insufficient for wwm-regalloc.
; All allocatable VGPRs are mentioned by inline assembly. Ordinary SGPR spills
; must fall back to scratch memory when no separate WWM pool is available.
; CHECK: error: cannot find enough VGPRs for wwm-regalloc
; CHECK-LABEL: test:
; CHECK: buffer_store_dword {{.*}} ; 4-byte Folded Spill
; CHECK: buffer_load_dword {{.*}} ; 4-byte Folded Reload
; CHECK: s_endpgm
; CHECK: .amdhsa_private_segment_fixed_size 20
; MIR: hasNoWWMPoolSGPRSpillFallback: true
; ROUNDTRIP-LABEL: test:
; ROUNDTRIP: s_endpgm
; ROUNDTRIP: .amdhsa_private_segment_fixed_size 20
define amdgpu_kernel void @test(i32 %in) {
entry:

View file

@ -0,0 +1,213 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc -mtriple=amdgpu9.00-amd-amdhsa < %s | FileCheck %s
; All allocatable VGPRs are clobbered while several large SGPR values remain
; live. Verify end-to-end that SGPR spills use scratch when no WWM VGPR pool is
; available, without relying on register-allocation stress options.
define amdgpu_kernel void @repro(i32 %in) {
; CHECK-LABEL: repro:
; CHECK: ; %bb.0: ; %entry
; CHECK-NEXT: s_mov_b64 s[70:71], s[2:3]
; CHECK-NEXT: s_mov_b64 s[68:69], s[0:1]
; CHECK-NEXT: s_load_dword s0, s[8:9], 0x0
; CHECK-NEXT: s_add_u32 s68, s68, s17
; CHECK-NEXT: s_addc_u32 s69, s69, 0
; CHECK-NEXT: s_mov_b64 s[2:3], exec
; CHECK-NEXT: ;;#ASMSTART
; CHECK-NEXT: ;;#ASMEND
; CHECK-NEXT: ;;#ASMSTART
; CHECK-NEXT: ;;#ASMEND
; CHECK-NEXT: s_mov_b64 exec, 0xffffffff
; CHECK-NEXT: buffer_store_dword v0, off, s[68:71], 0 offset:256
; CHECK-NEXT: v_writelane_b32 v0, s36, 0
; CHECK-NEXT: v_writelane_b32 v0, s37, 1
; CHECK-NEXT: v_writelane_b32 v0, s38, 2
; CHECK-NEXT: v_writelane_b32 v0, s39, 3
; CHECK-NEXT: v_writelane_b32 v0, s40, 4
; CHECK-NEXT: v_writelane_b32 v0, s41, 5
; CHECK-NEXT: v_writelane_b32 v0, s42, 6
; CHECK-NEXT: v_writelane_b32 v0, s43, 7
; CHECK-NEXT: v_writelane_b32 v0, s44, 8
; CHECK-NEXT: v_writelane_b32 v0, s45, 9
; CHECK-NEXT: v_writelane_b32 v0, s46, 10
; CHECK-NEXT: v_writelane_b32 v0, s47, 11
; CHECK-NEXT: v_writelane_b32 v0, s48, 12
; CHECK-NEXT: v_writelane_b32 v0, s49, 13
; CHECK-NEXT: v_writelane_b32 v0, s50, 14
; CHECK-NEXT: v_writelane_b32 v0, s51, 15
; CHECK-NEXT: v_writelane_b32 v0, s52, 16
; CHECK-NEXT: v_writelane_b32 v0, s53, 17
; CHECK-NEXT: v_writelane_b32 v0, s54, 18
; CHECK-NEXT: v_writelane_b32 v0, s55, 19
; CHECK-NEXT: v_writelane_b32 v0, s56, 20
; CHECK-NEXT: v_writelane_b32 v0, s57, 21
; CHECK-NEXT: v_writelane_b32 v0, s58, 22
; CHECK-NEXT: v_writelane_b32 v0, s59, 23
; CHECK-NEXT: v_writelane_b32 v0, s60, 24
; CHECK-NEXT: v_writelane_b32 v0, s61, 25
; CHECK-NEXT: v_writelane_b32 v0, s62, 26
; CHECK-NEXT: v_writelane_b32 v0, s63, 27
; CHECK-NEXT: v_writelane_b32 v0, s64, 28
; CHECK-NEXT: v_writelane_b32 v0, s65, 29
; CHECK-NEXT: v_writelane_b32 v0, s66, 30
; CHECK-NEXT: v_writelane_b32 v0, s67, 31
; CHECK-NEXT: buffer_store_dword v0, off, s[68:71], 0 ; 4-byte Folded Spill
; CHECK-NEXT: buffer_load_dword v0, off, s[68:71], 0 offset:256
; CHECK-NEXT: s_waitcnt vmcnt(0)
; CHECK-NEXT: s_mov_b64 exec, s[2:3]
; CHECK-NEXT: s_waitcnt lgkmcnt(0)
; CHECK-NEXT: s_cmp_lg_u32 s0, 0
; CHECK-NEXT: ;;#ASMSTART
; CHECK-NEXT: ;;#ASMEND
; CHECK-NEXT: ;;#ASMSTART
; CHECK-NEXT: ;;#ASMEND
; CHECK-NEXT: s_cbranch_scc0 .LBB0_2
; CHECK-NEXT: ; %bb.1: ; %exit
; CHECK-NEXT: s_endpgm
; CHECK-NEXT: .LBB0_2: ; %use
; CHECK-NEXT: s_mov_b64 s[34:35], exec
; CHECK-NEXT: s_mov_b64 exec, 0xffffffff
; CHECK-NEXT: buffer_store_dword v0, off, s[68:71], 0 offset:256
; CHECK-NEXT: v_writelane_b32 v0, s36, 0
; CHECK-NEXT: v_writelane_b32 v0, s37, 1
; CHECK-NEXT: v_writelane_b32 v0, s38, 2
; CHECK-NEXT: v_writelane_b32 v0, s39, 3
; CHECK-NEXT: v_writelane_b32 v0, s40, 4
; CHECK-NEXT: v_writelane_b32 v0, s41, 5
; CHECK-NEXT: v_writelane_b32 v0, s42, 6
; CHECK-NEXT: v_writelane_b32 v0, s43, 7
; CHECK-NEXT: v_writelane_b32 v0, s44, 8
; CHECK-NEXT: v_writelane_b32 v0, s45, 9
; CHECK-NEXT: v_writelane_b32 v0, s46, 10
; CHECK-NEXT: v_writelane_b32 v0, s47, 11
; CHECK-NEXT: v_writelane_b32 v0, s48, 12
; CHECK-NEXT: v_writelane_b32 v0, s49, 13
; CHECK-NEXT: v_writelane_b32 v0, s50, 14
; CHECK-NEXT: v_writelane_b32 v0, s51, 15
; CHECK-NEXT: v_writelane_b32 v0, s52, 16
; CHECK-NEXT: v_writelane_b32 v0, s53, 17
; CHECK-NEXT: v_writelane_b32 v0, s54, 18
; CHECK-NEXT: v_writelane_b32 v0, s55, 19
; CHECK-NEXT: v_writelane_b32 v0, s56, 20
; CHECK-NEXT: v_writelane_b32 v0, s57, 21
; CHECK-NEXT: v_writelane_b32 v0, s58, 22
; CHECK-NEXT: v_writelane_b32 v0, s59, 23
; CHECK-NEXT: v_writelane_b32 v0, s60, 24
; CHECK-NEXT: v_writelane_b32 v0, s61, 25
; CHECK-NEXT: v_writelane_b32 v0, s62, 26
; CHECK-NEXT: v_writelane_b32 v0, s63, 27
; CHECK-NEXT: v_writelane_b32 v0, s64, 28
; CHECK-NEXT: v_writelane_b32 v0, s65, 29
; CHECK-NEXT: v_writelane_b32 v0, s66, 30
; CHECK-NEXT: v_writelane_b32 v0, s67, 31
; CHECK-NEXT: buffer_store_dword v0, off, s[68:71], 0 offset:128 ; 4-byte Folded Spill
; CHECK-NEXT: buffer_load_dword v0, off, s[68:71], 0 offset:256
; CHECK-NEXT: s_waitcnt vmcnt(0)
; CHECK-NEXT: s_mov_b64 exec, s[34:35]
; CHECK-NEXT: s_mov_b64 s[34:35], exec
; CHECK-NEXT: s_mov_b64 exec, 0xffffffff
; CHECK-NEXT: buffer_store_dword v0, off, s[68:71], 0 offset:256
; CHECK-NEXT: buffer_load_dword v0, off, s[68:71], 0 ; 4-byte Folded Reload
; CHECK-NEXT: s_waitcnt vmcnt(0)
; CHECK-NEXT: v_readlane_b32 s36, v0, 0
; CHECK-NEXT: v_readlane_b32 s37, v0, 1
; CHECK-NEXT: v_readlane_b32 s38, v0, 2
; CHECK-NEXT: v_readlane_b32 s39, v0, 3
; CHECK-NEXT: v_readlane_b32 s40, v0, 4
; CHECK-NEXT: v_readlane_b32 s41, v0, 5
; CHECK-NEXT: v_readlane_b32 s42, v0, 6
; CHECK-NEXT: v_readlane_b32 s43, v0, 7
; CHECK-NEXT: v_readlane_b32 s44, v0, 8
; CHECK-NEXT: v_readlane_b32 s45, v0, 9
; CHECK-NEXT: v_readlane_b32 s46, v0, 10
; CHECK-NEXT: v_readlane_b32 s47, v0, 11
; CHECK-NEXT: v_readlane_b32 s48, v0, 12
; CHECK-NEXT: v_readlane_b32 s49, v0, 13
; CHECK-NEXT: v_readlane_b32 s50, v0, 14
; CHECK-NEXT: v_readlane_b32 s51, v0, 15
; CHECK-NEXT: v_readlane_b32 s52, v0, 16
; CHECK-NEXT: v_readlane_b32 s53, v0, 17
; CHECK-NEXT: v_readlane_b32 s54, v0, 18
; CHECK-NEXT: v_readlane_b32 s55, v0, 19
; CHECK-NEXT: v_readlane_b32 s56, v0, 20
; CHECK-NEXT: v_readlane_b32 s57, v0, 21
; CHECK-NEXT: v_readlane_b32 s58, v0, 22
; CHECK-NEXT: v_readlane_b32 s59, v0, 23
; CHECK-NEXT: v_readlane_b32 s60, v0, 24
; CHECK-NEXT: v_readlane_b32 s61, v0, 25
; CHECK-NEXT: v_readlane_b32 s62, v0, 26
; CHECK-NEXT: v_readlane_b32 s63, v0, 27
; CHECK-NEXT: v_readlane_b32 s64, v0, 28
; CHECK-NEXT: v_readlane_b32 s65, v0, 29
; CHECK-NEXT: v_readlane_b32 s66, v0, 30
; CHECK-NEXT: v_readlane_b32 s67, v0, 31
; CHECK-NEXT: buffer_load_dword v0, off, s[68:71], 0 offset:256
; CHECK-NEXT: s_waitcnt vmcnt(0)
; CHECK-NEXT: s_mov_b64 exec, s[34:35]
; CHECK-NEXT: ;;#ASMSTART
; CHECK-NEXT: ;;#ASMEND
; CHECK-NEXT: ;;#ASMSTART
; CHECK-NEXT: ;;#ASMEND
; CHECK-NEXT: s_mov_b64 s[34:35], exec
; CHECK-NEXT: s_mov_b64 exec, 0xffffffff
; CHECK-NEXT: buffer_store_dword v0, off, s[68:71], 0 offset:256
; CHECK-NEXT: buffer_load_dword v0, off, s[68:71], 0 offset:128 ; 4-byte Folded Reload
; CHECK-NEXT: s_waitcnt vmcnt(0)
; CHECK-NEXT: v_readlane_b32 s0, v0, 0
; CHECK-NEXT: v_readlane_b32 s1, v0, 1
; CHECK-NEXT: v_readlane_b32 s2, v0, 2
; CHECK-NEXT: v_readlane_b32 s3, v0, 3
; CHECK-NEXT: v_readlane_b32 s4, v0, 4
; CHECK-NEXT: v_readlane_b32 s5, v0, 5
; CHECK-NEXT: v_readlane_b32 s6, v0, 6
; CHECK-NEXT: v_readlane_b32 s7, v0, 7
; CHECK-NEXT: v_readlane_b32 s8, v0, 8
; CHECK-NEXT: v_readlane_b32 s9, v0, 9
; CHECK-NEXT: v_readlane_b32 s10, v0, 10
; CHECK-NEXT: v_readlane_b32 s11, v0, 11
; CHECK-NEXT: v_readlane_b32 s12, v0, 12
; CHECK-NEXT: v_readlane_b32 s13, v0, 13
; CHECK-NEXT: v_readlane_b32 s14, v0, 14
; CHECK-NEXT: v_readlane_b32 s15, v0, 15
; CHECK-NEXT: v_readlane_b32 s16, v0, 16
; CHECK-NEXT: v_readlane_b32 s17, v0, 17
; CHECK-NEXT: v_readlane_b32 s18, v0, 18
; CHECK-NEXT: v_readlane_b32 s19, v0, 19
; CHECK-NEXT: v_readlane_b32 s20, v0, 20
; CHECK-NEXT: v_readlane_b32 s21, v0, 21
; CHECK-NEXT: v_readlane_b32 s22, v0, 22
; CHECK-NEXT: v_readlane_b32 s23, v0, 23
; CHECK-NEXT: v_readlane_b32 s24, v0, 24
; CHECK-NEXT: v_readlane_b32 s25, v0, 25
; CHECK-NEXT: v_readlane_b32 s26, v0, 26
; CHECK-NEXT: v_readlane_b32 s27, v0, 27
; CHECK-NEXT: v_readlane_b32 s28, v0, 28
; CHECK-NEXT: v_readlane_b32 s29, v0, 29
; CHECK-NEXT: v_readlane_b32 s30, v0, 30
; CHECK-NEXT: v_readlane_b32 s31, v0, 31
; CHECK-NEXT: buffer_load_dword v0, off, s[68:71], 0 offset:256
; CHECK-NEXT: s_waitcnt vmcnt(0)
; CHECK-NEXT: s_mov_b64 exec, s[34:35]
; CHECK-NEXT: ;;#ASMSTART
; CHECK-NEXT: ;;#ASMEND
; CHECK-NEXT: s_endpgm
entry:
call void asm sideeffect "", "~{v[0:7]},~{v[8:15]},~{v[16:23]},~{v[24:31]},~{v[32:39]},~{v[40:47]},~{v[48:55]},~{v[56:63]}" ()
%s0 = call <32 x i32> asm sideeffect "", "=s" ()
%s1 = call <32 x i32> asm sideeffect "", "=s" ()
%s2 = call <32 x i32> asm sideeffect "", "=s" ()
%cmp = icmp eq i32 %in, 0
br i1 %cmp, label %use, label %exit
use:
call void asm sideeffect "", "s"(<32 x i32> %s0)
call void asm sideeffect "", "s"(<32 x i32> %s1)
call void asm sideeffect "", "s"(<32 x i32> %s2)
br label %exit
exit:
ret void
}

View file

@ -0,0 +1,50 @@
# RUN: llc -mtriple=amdgpu9.00-amd-amdhsa -O0 -amdgpu-stress-vgpr=1 -amdgpu-num-vgprs-for-wwm-alloc=2 -start-before=si-lower-sgpr-spills -stop-after=regallocfast,1 -verify-machineinstrs -o - %s | FileCheck %s
# RUN: llc -mtriple=amdgpu9.00-amd-amdhsa -O0 -amdgpu-num-vgprs-for-wwm-alloc=0 -start-before=si-lower-sgpr-spills -stop-after=regallocfast,1 -verify-machineinstrs -o - %s | FileCheck --check-prefix=ZERO %s
# CHECK-LABEL: name: partial_pool
# CHECK-COUNT-2: flags: [ WWM_REG ]
# CHECK: renamable $vgpr0 = IMPLICIT_DEF
# CHECK: SI_SPILL_WWM_V32_SAVE $vgpr0
# CHECK: $vgpr0 = SI_SPILL_WWM_V32_RESTORE
# With an explicitly empty pool, otherwise available VGPRs must remain for the
# per-thread allocator and the SGPR spill pseudos must remain on the memory path.
# ZERO-LABEL: name: partial_pool
# ZERO-NOT: WWM_REG
# ZERO: SI_SPILL_S1024_SAVE
# ZERO: SI_SPILL_S32_SAVE
--- |
define amdgpu_kernel void @partial_pool() #0 {
ret void
}
attributes #0 = { "amdgpu-no-workitem-id-x" "amdgpu-no-workitem-id-y" "amdgpu-no-workitem-id-z" }
...
---
name: partial_pool
tracksRegLiveness: true
frameInfo:
maxAlignment: 4
stack:
- { id: 0, type: spill-slot, size: 128, alignment: 4, stack-id: sgpr-spill }
- { id: 1, type: spill-slot, size: 128, alignment: 4, stack-id: sgpr-spill }
- { id: 2, type: spill-slot, size: 4, alignment: 4, stack-id: sgpr-spill }
machineFunctionInfo:
isEntryFunction: true
scratchRSrcReg: '$sgpr0_sgpr1_sgpr2_sgpr3'
stackPtrOffsetReg: '$sgpr32'
frameOffsetReg: '$sgpr33'
hasSpilledSGPRs: true
body: |
bb.0:
liveins: $sgpr34, $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
SI_SPILL_S1024_SAVE killed $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, %stack.0, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
SI_SPILL_S1024_SAVE killed $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, %stack.1, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
SI_SPILL_S32_SAVE killed $sgpr34, %stack.2, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
renamable $sgpr34 = SI_SPILL_S32_RESTORE %stack.2, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
renamable $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 = SI_SPILL_S1024_RESTORE %stack.1, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
renamable $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 = SI_SPILL_S1024_RESTORE %stack.0, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
S_ENDPGM 0
...

View file

@ -0,0 +1,101 @@
# RUN: split-file %s %t
# RUN: not llc -mtriple=amdgpu9.00-amd-amdhsa -amdgpu-stress-vgpr=1 -amdgpu-num-vgprs-for-wwm-alloc=2 -run-pass=si-lower-sgpr-spills -o /dev/null %t/strict.mir 2>&1 | FileCheck %s
# RUN: not llc -mtriple=amdgpu9.00-amd-amdhsa -amdgpu-stress-vgpr=1 -amdgpu-num-vgprs-for-wwm-alloc=2 -amdgpu-prealloc-sgpr-spill-vgprs -run-pass=si-lower-sgpr-spills -o /dev/null %t/option.mir 2>&1 | FileCheck %s
# RUN: not llc -mtriple=amdgpu9.00-amd-amdhsa -amdgpu-stress-vgpr=1 -amdgpu-num-vgprs-for-wwm-alloc=2 -run-pass=si-lower-sgpr-spills -o /dev/null %t/attribute.mir 2>&1 | FileCheck %s
# CHECK: error: cannot find enough VGPRs for wwm-regalloc
#--- strict.mir
--- |
define amdgpu_kernel void @strict() #0 {
ret void
}
attributes #0 = { "amdgpu-no-workitem-id-x" "amdgpu-no-workitem-id-y" "amdgpu-no-workitem-id-z" }
...
---
name: strict
tracksRegLiveness: true
frameInfo:
maxAlignment: 4
stack:
- { id: 0, type: spill-slot, size: 128, alignment: 4, stack-id: sgpr-spill }
- { id: 1, type: spill-slot, size: 128, alignment: 4, stack-id: sgpr-spill }
- { id: 2, type: spill-slot, size: 4, alignment: 4, stack-id: sgpr-spill }
machineFunctionInfo:
isEntryFunction: true
scratchRSrcReg: '$sgpr0_sgpr1_sgpr2_sgpr3'
stackPtrOffsetReg: '$sgpr32'
frameOffsetReg: '$sgpr33'
hasSpilledSGPRs: true
body: |
bb.0:
liveins: $sgpr34, $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
%0:sreg_64 = ENTER_STRICT_WWM -1, implicit-def $exec, implicit-def $scc, implicit $exec
$exec = EXIT_STRICT_WWM killed %0
SI_SPILL_S1024_SAVE killed $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, %stack.0, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
SI_SPILL_S1024_SAVE killed $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, %stack.1, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
SI_SPILL_S32_SAVE killed $sgpr34, %stack.2, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
S_ENDPGM 0
...
#--- option.mir
--- |
define amdgpu_kernel void @option() #0 {
ret void
}
attributes #0 = { "amdgpu-no-workitem-id-x" "amdgpu-no-workitem-id-y" "amdgpu-no-workitem-id-z" }
...
---
name: option
tracksRegLiveness: true
frameInfo:
maxAlignment: 4
stack:
- { id: 0, type: spill-slot, size: 128, alignment: 4, stack-id: sgpr-spill }
- { id: 1, type: spill-slot, size: 128, alignment: 4, stack-id: sgpr-spill }
- { id: 2, type: spill-slot, size: 4, alignment: 4, stack-id: sgpr-spill }
machineFunctionInfo:
isEntryFunction: true
scratchRSrcReg: '$sgpr0_sgpr1_sgpr2_sgpr3'
stackPtrOffsetReg: '$sgpr32'
frameOffsetReg: '$sgpr33'
hasSpilledSGPRs: true
body: |
bb.0:
liveins: $sgpr34, $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
SI_SPILL_S1024_SAVE killed $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, %stack.0, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
SI_SPILL_S1024_SAVE killed $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, %stack.1, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
SI_SPILL_S32_SAVE killed $sgpr34, %stack.2, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
S_ENDPGM 0
...
#--- attribute.mir
--- |
define amdgpu_kernel void @attribute() #0 {
ret void
}
attributes #0 = { "amdgpu-no-workitem-id-x" "amdgpu-no-workitem-id-y" "amdgpu-no-workitem-id-z" "amdgpu-prealloc-sgpr-spill-vgprs" }
...
---
name: attribute
tracksRegLiveness: true
frameInfo:
maxAlignment: 4
stack:
- { id: 0, type: spill-slot, size: 128, alignment: 4, stack-id: sgpr-spill }
- { id: 1, type: spill-slot, size: 128, alignment: 4, stack-id: sgpr-spill }
- { id: 2, type: spill-slot, size: 4, alignment: 4, stack-id: sgpr-spill }
machineFunctionInfo:
isEntryFunction: true
scratchRSrcReg: '$sgpr0_sgpr1_sgpr2_sgpr3'
stackPtrOffsetReg: '$sgpr32'
frameOffsetReg: '$sgpr33'
hasSpilledSGPRs: true
body: |
bb.0:
liveins: $sgpr34, $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
SI_SPILL_S1024_SAVE killed $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, %stack.0, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
SI_SPILL_S1024_SAVE killed $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, %stack.1, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
SI_SPILL_S32_SAVE killed $sgpr34, %stack.2, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
S_ENDPGM 0
...