[llvm] [AMDGPU] Set SGPR spill stack IDs when creating spill slots (PR #197628)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 8 05:13:21 PDT 2026
https://github.com/woruyu updated https://github.com/llvm/llvm-project/pull/197628
>From aa310a5524e11c978de5cabec5b707d729730679 Mon Sep 17 00:00:00 2001
From: woruyu <1214539920 at qq.com>
Date: Mon, 8 Jun 2026 20:13:01 +0800
Subject: [PATCH] fix: all
---
llvm/include/llvm/CodeGen/MachineFrameInfo.h | 4 +-
.../include/llvm/CodeGen/TargetRegisterInfo.h | 8 +
llvm/include/llvm/Target/Target.td | 3 +
llvm/lib/CodeGen/MachineFrameInfo.cpp | 5 +-
llvm/lib/CodeGen/PrologEpilogInserter.cpp | 3 +-
llvm/lib/CodeGen/RegAllocFast.cpp | 3 +-
llvm/lib/CodeGen/VirtRegMap.cpp | 3 +-
llvm/lib/Target/AMDGPU/SIInstrInfo.cpp | 10 +-
llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp | 8 +-
llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp | 8 +-
llvm/lib/Target/AMDGPU/SIRegisterInfo.td | 1 +
.../AMDGPU/sgpr-scavenge-fi-stack-id.ll | 294 ++++++++++++++++++
.../TableGen/RegisterInfoEmitter-errors.td | 10 +-
llvm/unittests/CodeGen/MachineInstrTest.cpp | 2 +-
.../TableGen/Common/CodeGenRegisters.cpp | 7 +-
llvm/utils/TableGen/Common/CodeGenRegisters.h | 1 +
llvm/utils/TableGen/RegisterInfoEmitter.cpp | 1 +
17 files changed, 351 insertions(+), 20 deletions(-)
create mode 100644 llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll
diff --git a/llvm/include/llvm/CodeGen/MachineFrameInfo.h b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
index 22729e736fbd3..9cafbf5a1ce6c 100644
--- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -833,7 +833,9 @@ class MachineFrameInfo {
/// Create a new statically sized stack object that represents a spill slot,
/// returning a nonnegative identifier to represent it.
- LLVM_ABI int CreateSpillStackObject(uint64_t Size, Align Alignment);
+ LLVM_ABI int
+ CreateSpillStackObject(uint64_t Size, Align Alignment,
+ TargetStackID::Value StackID = TargetStackID::Default);
/// Remove or mark dead a statically sized stack object.
void RemoveStackObject(int ObjectIdx) {
diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 7c3c56552b82c..8ae24ff84401e 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -21,6 +21,7 @@
#include "llvm/ADT/iterator_range.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/RegisterBank.h"
+#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/MC/LaneBitmask.h"
#include "llvm/MC/MCRegisterInfo.h"
@@ -61,6 +62,7 @@ class TargetRegisterClass {
/// Configurable target specific flags.
const uint8_t TSFlags;
+ const uint8_t SpillStackID;
/// Whether the class supports two (or more) disjunct subregister indices.
const bool HasDisjunctSubRegs;
/// Whether a combination of subregisters can cover every register in the
@@ -319,6 +321,12 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
return Align(getRegClassInfo(RC).SpillAlignment / 8);
}
+ /// Return the stack ID for spill slots holding a spilled copy of a register
+ /// from this class.
+ TargetStackID::Value getSpillStackID(const TargetRegisterClass &RC) const {
+ return static_cast<TargetStackID::Value>(RC.SpillStackID);
+ }
+
/// Return true if the given TargetRegisterClass has the ValueType T.
bool isTypeLegalForClass(const TargetRegisterClass &RC, MVT T) const {
for (auto I = legalclasstypes_begin(RC); *I != MVT::Other; ++I)
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 4e973ece07e8e..a02a4209f86fe 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -398,6 +398,9 @@ class RegisterClass<string namespace, list<ValueType> regTypes, int alignment,
// classes will be resolved in the order defined by this value, with lower values
// taking precedence over higher ones. Ties are resolved by enumeration order.
int BaseClassOrder = ?;
+
+ // Stack ID to use for spill slots of this register class.
+ int SpillStackID = 0;
}
// The memberList in a RegisterClass is a dag of set operations. TableGen
diff --git a/llvm/lib/CodeGen/MachineFrameInfo.cpp b/llvm/lib/CodeGen/MachineFrameInfo.cpp
index aed68afb4eb1b..515c95006af00 100644
--- a/llvm/lib/CodeGen/MachineFrameInfo.cpp
+++ b/llvm/lib/CodeGen/MachineFrameInfo.cpp
@@ -63,9 +63,10 @@ int MachineFrameInfo::CreateStackObject(uint64_t Size, Align Alignment,
return Index;
}
-int MachineFrameInfo::CreateSpillStackObject(uint64_t Size, Align Alignment) {
+int MachineFrameInfo::CreateSpillStackObject(uint64_t Size, Align Alignment,
+ TargetStackID::Value StackID) {
Alignment = clampStackAlignment(!StackRealignable, Alignment, StackAlignment);
- CreateStackObject(Size, Alignment, true);
+ CreateStackObject(Size, Alignment, true, nullptr, StackID);
int Index = (int)Objects.size() - NumFixedObjects - 1;
ensureMaxAlignment(Alignment);
return Index;
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 68fd54cf00146..d9557a3958978 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -523,7 +523,8 @@ static void assignCalleeSavedSpillSlots(MachineFunction &F,
// the TargetRegisterClass if the stack alignment is smaller. Use the
// min.
Alignment = std::min(Alignment, TFI->getStackAlign());
- FrameIdx = MFI.CreateStackObject(Size, Alignment, true);
+ FrameIdx = MFI.CreateStackObject(Size, Alignment, true, nullptr,
+ RegInfo->getSpillStackID(*RC));
MFI.setIsCalleeSavedObjectIndex(FrameIdx, true);
} else {
// Spill it to the stack where we must.
diff --git a/llvm/lib/CodeGen/RegAllocFast.cpp b/llvm/lib/CodeGen/RegAllocFast.cpp
index dc505114ae6d7..f10283272f1d9 100644
--- a/llvm/lib/CodeGen/RegAllocFast.cpp
+++ b/llvm/lib/CodeGen/RegAllocFast.cpp
@@ -494,7 +494,8 @@ int RegAllocFastImpl::getStackSpaceFor(Register VirtReg) {
if (Alignment > CurrentAlign && !TRI->canRealignStack(MF))
Alignment = CurrentAlign;
- int FrameIdx = MFI->CreateSpillStackObject(Size, Alignment);
+ int FrameIdx =
+ MFI->CreateSpillStackObject(Size, Alignment, TRI->getSpillStackID(RC));
// Assign the slot.
StackSlotForVirtReg[VirtReg] = FrameIdx;
diff --git a/llvm/lib/CodeGen/VirtRegMap.cpp b/llvm/lib/CodeGen/VirtRegMap.cpp
index 972bd8f550e8b..5a10a31050186 100644
--- a/llvm/lib/CodeGen/VirtRegMap.cpp
+++ b/llvm/lib/CodeGen/VirtRegMap.cpp
@@ -102,7 +102,8 @@ unsigned VirtRegMap::createSpillSlot(const TargetRegisterClass *RC) {
if (Alignment > CurrentAlign && !TRI->canRealignStack(*MF)) {
Alignment = CurrentAlign;
}
- int SS = MF->getFrameInfo().CreateSpillStackObject(Size, Alignment);
+ int SS = MF->getFrameInfo().CreateSpillStackObject(Size, Alignment,
+ TRI->getSpillStackID(*RC));
++NumSpillSlots;
return SS;
}
diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
index 3b72ba4bd4967..417ed4b6a22ed 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
@@ -1737,7 +1737,8 @@ void SIInstrInfo::storeRegToStackSlotImpl(
MachineRegisterInfo &MRI = MF->getRegInfo();
if (RI.isSGPRClass(RC)) {
- MFI->setHasSpilledSGPRs();
+ if (FrameInfo.getStackID(FrameIndex) == TargetStackID::SGPRSpill)
+ MFI->setHasSpilledSGPRs();
assert(SrcReg != AMDGPU::M0 && "m0 should not be spilled");
assert(SrcReg != AMDGPU::EXEC_LO && SrcReg != AMDGPU::EXEC_HI &&
SrcReg != AMDGPU::EXEC && "exec should not be spilled");
@@ -1759,8 +1760,6 @@ void SIInstrInfo::storeRegToStackSlotImpl(
.addMemOperand(MMO)
.addReg(MFI->getStackPtrOffsetReg(), RegState::Implicit);
- if (RI.spillSGPRToVGPR())
- FrameInfo.setStackID(FrameIndex, TargetStackID::SGPRSpill);
return;
}
@@ -1949,7 +1948,8 @@ void SIInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
FrameInfo.getObjectAlign(FrameIndex));
if (RI.isSGPRClass(RC)) {
- MFI->setHasSpilledSGPRs();
+ if (FrameInfo.getStackID(FrameIndex) == TargetStackID::SGPRSpill)
+ MFI->setHasSpilledSGPRs();
assert(DestReg != AMDGPU::M0 && "m0 should not be reloaded into");
assert(DestReg != AMDGPU::EXEC_LO && DestReg != AMDGPU::EXEC_HI &&
DestReg != AMDGPU::EXEC && "exec should not be spilled");
@@ -1962,8 +1962,6 @@ void SIInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
MRI.constrainRegClass(DestReg, &AMDGPU::SReg_32_XM0_XEXECRegClass);
}
- if (RI.spillSGPRToVGPR())
- FrameInfo.setStackID(FrameIndex, TargetStackID::SGPRSpill);
BuildMI(MBB, MI, DL, OpDesc, DestReg)
.addFrameIndex(FrameIndex) // addr
.addMemOperand(MMO)
diff --git a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
index defac5304e7d4..48a38b1ffd460 100644
--- a/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
@@ -265,7 +265,8 @@ bool SILowerSGPRSpills::spillCalleeSavedRegs(
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
int JunkFI = MFI.CreateStackObject(TRI->getSpillSize(*RC),
- TRI->getSpillAlign(*RC), true);
+ TRI->getSpillAlign(*RC), true,
+ nullptr, TRI->getSpillStackID(*RC));
CSI.emplace_back(Reg, JunkFI);
CalleeSavedFIs.push_back(JunkFI);
@@ -277,8 +278,9 @@ bool SILowerSGPRSpills::spillCalleeSavedRegs(
// can be emitted appropriately.
if (SpillRetAddrReg) {
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(RetAddrReg);
- int JunkFI = MFI.CreateStackObject(TRI->getSpillSize(*RC),
- TRI->getSpillAlign(*RC), true);
+ int JunkFI =
+ MFI.CreateStackObject(TRI->getSpillSize(*RC), TRI->getSpillAlign(*RC),
+ true, nullptr, TRI->getSpillStackID(*RC));
CSI.push_back(CalleeSavedInfo(RetAddrReg, JunkFI));
CalleeSavedFIs.push_back(JunkFI);
}
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
index 7557205fb5317..6e72e082fb9bc 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
@@ -2569,7 +2569,9 @@ bool SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
case AMDGPU::SI_SPILL_S96_SAVE:
case AMDGPU::SI_SPILL_S64_SAVE:
case AMDGPU::SI_SPILL_S32_SAVE: {
- return spillSGPR(MI, Index, RS, nullptr, nullptr, false, false, NeedsCFI);
+ return spillSGPR(MI, Index, RS, nullptr, nullptr,
+ FrameInfo.getStackID(Index) == TargetStackID::SGPRSpill,
+ false, NeedsCFI);
}
// SGPR register restore
@@ -2587,7 +2589,9 @@ bool SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
case AMDGPU::SI_SPILL_S96_RESTORE:
case AMDGPU::SI_SPILL_S64_RESTORE:
case AMDGPU::SI_SPILL_S32_RESTORE: {
- return restoreSGPR(MI, Index, RS);
+ return restoreSGPR(MI, Index, RS, nullptr, nullptr,
+ FrameInfo.getStackID(Index) ==
+ TargetStackID::SGPRSpill);
}
// VGPR register spill
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
index a0a7fb62f9159..f3e0a597c4db8 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
@@ -116,6 +116,7 @@ class SIRegisterClass <string n, list<ValueType> rTypes, int Align, dag rList>
let TSFlags{2} = HasVGPR;
let TSFlags{3} = HasAGPR;
let TSFlags{4} = HasSGPR;
+ let SpillStackID = !if(HasSGPR, 1, 0); // TargetStackID::SGPRSpill
// RA will use RegisterClass AllocationPriority amongst other info (e.g. ordering in the basic block)
// to decide which registers to try to assign first. Usually, this RegisterClass priority is given
diff --git a/llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll b/llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll
new file mode 100644
index 0000000000000..96a20e686ab60
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll
@@ -0,0 +1,294 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -O1 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -verify-machineinstrs < %s | FileCheck %s
+
+define void @sgpr_scavenge_fi_stack_id(double %input, i1 %enter_fma_path, i1 %repeat_outer_loop, i1 %enter_sgpr_loop, i1 %enter_inner_loop, i1 %exit_inner_loop, i1 %zero_fma_result) {
+; CHECK-LABEL: sgpr_scavenge_fi_stack_id:
+; CHECK: ; %bb.0: ; %entry
+; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT: s_xor_saveexec_b64 s[4:5], -1
+; CHECK-NEXT: buffer_store_dword v10, off, s[0:3], s32 offset:4 ; 4-byte Folded Spill
+; CHECK-NEXT: s_mov_b64 exec, s[4:5]
+; CHECK-NEXT: v_writelane_b32 v10, s30, 0
+; CHECK-NEXT: v_writelane_b32 v10, s31, 1
+; CHECK-NEXT: v_and_b32_e32 v2, 1, v2
+; CHECK-NEXT: v_cmp_eq_u32_e64 s[10:11], 1, v2
+; CHECK-NEXT: v_and_b32_e32 v2, 1, v4
+; CHECK-NEXT: v_cmp_eq_u32_e64 s[12:13], 1, v2
+; CHECK-NEXT: v_and_b32_e32 v2, 1, v3
+; CHECK-NEXT: v_and_b32_e32 v7, 1, v7
+; CHECK-NEXT: v_and_b32_e32 v6, 1, v6
+; CHECK-NEXT: v_and_b32_e32 v5, 1, v5
+; CHECK-NEXT: v_cmp_eq_u32_e64 s[14:15], 1, v2
+; CHECK-NEXT: v_cmp_eq_u32_e64 s[4:5], 1, v7
+; CHECK-NEXT: v_cmp_eq_u32_e64 s[6:7], 1, v6
+; CHECK-NEXT: v_cmp_eq_u32_e64 s[8:9], 1, v5
+; CHECK-NEXT: s_xor_b64 s[16:17], s[14:15], -1
+; CHECK-NEXT: s_xor_b64 s[18:19], s[12:13], -1
+; CHECK-NEXT: s_xor_b64 s[22:23], s[10:11], -1
+; CHECK-NEXT: s_mov_b64 s[20:21], 0
+; CHECK-NEXT: s_mov_b32 s25, 0x3fe62e42
+; CHECK-NEXT: s_mov_b32 s24, 0xfefa39ef
+; CHECK-NEXT: s_mov_b32 s27, 0x3c7abc9e
+; CHECK-NEXT: s_mov_b32 s26, 0x3b39803f
+; CHECK-NEXT: v_mov_b32_e32 v6, 0
+; CHECK-NEXT: s_mov_b32 s28, 0
+; CHECK-NEXT: s_mov_b32 s29, 0x7ff00000
+; CHECK-NEXT: s_mov_b32 s41, 0x40417e50
+; CHECK-NEXT: s_mov_b32 s40, 0xa9dc6553
+; CHECK-NEXT: s_mov_b32 s42, 0
+; CHECK-NEXT: s_mov_b32 s43, 0x7ff80000
+; CHECK-NEXT: s_branch .LBB0_2
+; CHECK-NEXT: .LBB0_1: ; %loop.exit.guard
+; CHECK-NEXT: ; in Loop: Header=BB0_2 Depth=1
+; CHECK-NEXT: s_or_b64 exec, exec, s[46:47]
+; CHECK-NEXT: s_and_b64 s[44:45], exec, s[44:45]
+; CHECK-NEXT: s_or_b64 s[20:21], s[44:45], s[20:21]
+; CHECK-NEXT: s_andn2_b64 exec, exec, s[20:21]
+; CHECK-NEXT: s_cbranch_execz .LBB0_21
+; CHECK-NEXT: .LBB0_2: ; %outer_latch
+; CHECK-NEXT: ; =>This Loop Header: Depth=1
+; CHECK-NEXT: ; Child Loop BB0_4 Depth 2
+; CHECK-NEXT: ; Child Loop BB0_8 Depth 3
+; CHECK-NEXT: ; Child Loop BB0_11 Depth 4
+; CHECK-NEXT: ; Child Loop BB0_13 Depth 5
+; CHECK-NEXT: s_mov_b64 s[46:47], 0
+; CHECK-NEXT: ; implicit-def: $sgpr44_sgpr45
+; CHECK-NEXT: ; implicit-def: $sgpr56_sgpr57
+; CHECK-NEXT: s_branch .LBB0_4
+; CHECK-NEXT: .LBB0_3: ; %Flow11
+; CHECK-NEXT: ; in Loop: Header=BB0_4 Depth=2
+; CHECK-NEXT: s_or_b64 exec, exec, s[60:61]
+; CHECK-NEXT: s_and_b64 s[58:59], exec, s[58:59]
+; CHECK-NEXT: s_or_b64 s[46:47], s[58:59], s[46:47]
+; CHECK-NEXT: s_andn2_b64 s[44:45], s[44:45], exec
+; CHECK-NEXT: s_and_b64 s[58:59], s[56:57], exec
+; CHECK-NEXT: s_or_b64 s[44:45], s[44:45], s[58:59]
+; CHECK-NEXT: s_andn2_b64 exec, exec, s[46:47]
+; CHECK-NEXT: s_cbranch_execz .LBB0_1
+; CHECK-NEXT: .LBB0_4: ; %outer_header
+; CHECK-NEXT: ; Parent Loop BB0_2 Depth=1
+; CHECK-NEXT: ; => This Loop Header: Depth=2
+; CHECK-NEXT: ; Child Loop BB0_8 Depth 3
+; CHECK-NEXT: ; Child Loop BB0_11 Depth 4
+; CHECK-NEXT: ; Child Loop BB0_13 Depth 5
+; CHECK-NEXT: s_mov_b64 s[58:59], -1
+; CHECK-NEXT: s_mov_b64 s[62:63], -1
+; CHECK-NEXT: s_and_saveexec_b64 s[60:61], s[10:11]
+; CHECK-NEXT: s_cbranch_execz .LBB0_19
+; CHECK-NEXT: ; %bb.5: ; %fma_setup
+; CHECK-NEXT: ; in Loop: Header=BB0_4 Depth=2
+; CHECK-NEXT: v_fma_f64 v[2:3], v[0:1], s[24:25], 0
+; CHECK-NEXT: v_fmac_f64_e64 v[2:3], 0, s[26:27]
+; CHECK-NEXT: s_mov_b64 s[62:63], 0
+; CHECK-NEXT: ; implicit-def: $sgpr72_sgpr73
+; CHECK-NEXT: ; implicit-def: $sgpr74_sgpr75
+; CHECK-NEXT: ; implicit-def: $sgpr76_sgpr77
+; CHECK-NEXT: s_branch .LBB0_8
+; CHECK-NEXT: .LBB0_6: ; %Flow9
+; CHECK-NEXT: ; in Loop: Header=BB0_8 Depth=3
+; CHECK-NEXT: s_or_b64 exec, exec, s[88:89]
+; CHECK-NEXT: s_andn2_b64 s[76:77], s[76:77], exec
+; CHECK-NEXT: s_and_b64 s[88:89], s[92:93], exec
+; CHECK-NEXT: s_or_b64 s[76:77], s[76:77], s[88:89]
+; CHECK-NEXT: s_andn2_b64 s[74:75], s[74:75], exec
+; CHECK-NEXT: s_and_b64 s[88:89], s[90:91], exec
+; CHECK-NEXT: s_or_b64 s[74:75], s[74:75], s[88:89]
+; CHECK-NEXT: .LBB0_7: ; %Flow8
+; CHECK-NEXT: ; in Loop: Header=BB0_8 Depth=3
+; CHECK-NEXT: s_or_b64 exec, exec, s[78:79]
+; CHECK-NEXT: s_and_b64 s[78:79], exec, s[74:75]
+; CHECK-NEXT: s_or_b64 s[62:63], s[78:79], s[62:63]
+; CHECK-NEXT: s_andn2_b64 s[72:73], s[72:73], exec
+; CHECK-NEXT: s_and_b64 s[78:79], s[76:77], exec
+; CHECK-NEXT: s_or_b64 s[72:73], s[72:73], s[78:79]
+; CHECK-NEXT: s_andn2_b64 exec, exec, s[62:63]
+; CHECK-NEXT: s_cbranch_execz .LBB0_18
+; CHECK-NEXT: .LBB0_8: ; %sgpr_loop_header
+; CHECK-NEXT: ; Parent Loop BB0_2 Depth=1
+; CHECK-NEXT: ; Parent Loop BB0_4 Depth=2
+; CHECK-NEXT: ; => This Loop Header: Depth=3
+; CHECK-NEXT: ; Child Loop BB0_11 Depth 4
+; CHECK-NEXT: ; Child Loop BB0_13 Depth 5
+; CHECK-NEXT: s_or_b64 s[76:77], s[76:77], exec
+; CHECK-NEXT: s_or_b64 s[74:75], s[74:75], exec
+; CHECK-NEXT: s_and_saveexec_b64 s[78:79], s[12:13]
+; CHECK-NEXT: s_cbranch_execz .LBB0_7
+; CHECK-NEXT: ; %bb.9: ; %sgpr_pressure_loop.preheader
+; CHECK-NEXT: ; in Loop: Header=BB0_8 Depth=3
+; CHECK-NEXT: s_mov_b64 s[90:91], 0
+; CHECK-NEXT: ; implicit-def: $sgpr88_sgpr89
+; CHECK-NEXT: s_branch .LBB0_11
+; CHECK-NEXT: .LBB0_10: ; %Flow7
+; CHECK-NEXT: ; in Loop: Header=BB0_11 Depth=4
+; CHECK-NEXT: s_xor_b64 s[94:95], s[94:95], -1
+; CHECK-NEXT: s_and_b64 s[92:93], exec, s[92:93]
+; CHECK-NEXT: s_or_b64 s[90:91], s[92:93], s[90:91]
+; CHECK-NEXT: s_andn2_b64 s[88:89], s[88:89], exec
+; CHECK-NEXT: s_and_b64 s[92:93], s[94:95], exec
+; CHECK-NEXT: s_or_b64 s[88:89], s[88:89], s[92:93]
+; CHECK-NEXT: s_andn2_b64 exec, exec, s[90:91]
+; CHECK-NEXT: s_cbranch_execz .LBB0_16
+; CHECK-NEXT: .LBB0_11: ; %sgpr_pressure_loop
+; CHECK-NEXT: ; Parent Loop BB0_2 Depth=1
+; CHECK-NEXT: ; Parent Loop BB0_4 Depth=2
+; CHECK-NEXT: ; Parent Loop BB0_8 Depth=3
+; CHECK-NEXT: ; => This Loop Header: Depth=4
+; CHECK-NEXT: ; Child Loop BB0_13 Depth 5
+; CHECK-NEXT: s_and_saveexec_b64 s[92:93], s[8:9]
+; CHECK-NEXT: s_cbranch_execz .LBB0_14
+; CHECK-NEXT: ; %bb.12: ; %inner_stack_loop.preheader
+; CHECK-NEXT: ; in Loop: Header=BB0_11 Depth=4
+; CHECK-NEXT: v_cndmask_b32_e64 v5, v3, 0, s[4:5]
+; CHECK-NEXT: v_cndmask_b32_e64 v4, v2, 0, s[4:5]
+; CHECK-NEXT: v_cndmask_b32_e64 v5, v5, 0, s[14:15]
+; CHECK-NEXT: v_cndmask_b32_e64 v4, v4, 0, s[14:15]
+; CHECK-NEXT: v_mul_f64 v[4:5], v[4:5], s[28:29]
+; CHECK-NEXT: v_mul_f64 v[4:5], v[4:5], s[40:41]
+; CHECK-NEXT: s_mov_b32 vcc_lo, 0
+; CHECK-NEXT: s_mov_b64 s[94:95], 0
+; CHECK-NEXT: v_mul_f64 v[4:5], v[4:5], s[42:43]
+; CHECK-NEXT: .LBB0_13: ; %inner_stack_loop
+; CHECK-NEXT: ; Parent Loop BB0_2 Depth=1
+; CHECK-NEXT: ; Parent Loop BB0_4 Depth=2
+; CHECK-NEXT: ; Parent Loop BB0_8 Depth=3
+; CHECK-NEXT: ; Parent Loop BB0_11 Depth=4
+; 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: 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_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
+; CHECK-NEXT: buffer_store_dword v8, off, s[0:3], 0
+; CHECK-NEXT: buffer_store_dword v6, v7, s[0:3], 0 offen
+; CHECK-NEXT: buffer_store_dword v6, v7, s[0:3], 0 offen offset:4
+; CHECK-NEXT: s_andn2_b64 exec, exec, s[94:95]
+; CHECK-NEXT: s_cbranch_execnz .LBB0_13
+; CHECK-NEXT: .LBB0_14: ; %Flow
+; CHECK-NEXT: ; in Loop: Header=BB0_11 Depth=4
+; CHECK-NEXT: s_or_b64 exec, exec, s[92:93]
+; CHECK-NEXT: s_mov_b64 s[92:93], -1
+; CHECK-NEXT: s_mov_b64 s[94:95], -1
+; CHECK-NEXT: s_cbranch_execz .LBB0_10
+; CHECK-NEXT: ; %bb.15: ; %sgpr_loop_merge
+; CHECK-NEXT: ; in Loop: Header=BB0_11 Depth=4
+; CHECK-NEXT: s_mov_b64 s[94:95], 0
+; CHECK-NEXT: s_orn2_b64 s[92:93], s[22:23], exec
+; CHECK-NEXT: s_branch .LBB0_10
+; CHECK-NEXT: .LBB0_16: ; %loop.exit.guard6
+; CHECK-NEXT: ; in Loop: Header=BB0_8 Depth=3
+; CHECK-NEXT: s_or_b64 exec, exec, s[90:91]
+; CHECK-NEXT: s_mov_b64 s[90:91], -1
+; CHECK-NEXT: s_mov_b64 s[92:93], 0
+; CHECK-NEXT: s_and_saveexec_b64 s[94:95], s[88:89]
+; CHECK-NEXT: s_xor_b64 s[88:89], exec, s[94:95]
+; CHECK-NEXT: s_cbranch_execz .LBB0_6
+; CHECK-NEXT: ; %bb.17: ; %after_sgpr_loop
+; CHECK-NEXT: ; in Loop: Header=BB0_8 Depth=3
+; CHECK-NEXT: s_mov_b64 s[92:93], exec
+; CHECK-NEXT: s_orn2_b64 s[90:91], s[18:19], exec
+; CHECK-NEXT: s_branch .LBB0_6
+; CHECK-NEXT: .LBB0_18: ; %loop.exit.guard5
+; CHECK-NEXT: ; in Loop: Header=BB0_4 Depth=2
+; CHECK-NEXT: s_or_b64 exec, exec, s[62:63]
+; CHECK-NEXT: s_orn2_b64 s[62:63], s[72:73], exec
+; CHECK-NEXT: .LBB0_19: ; %Flow10
+; CHECK-NEXT: ; in Loop: Header=BB0_4 Depth=2
+; CHECK-NEXT: s_or_b64 exec, exec, s[60:61]
+; CHECK-NEXT: s_or_b64 s[56:57], s[56:57], exec
+; CHECK-NEXT: s_and_saveexec_b64 s[60:61], s[62:63]
+; CHECK-NEXT: s_cbranch_execz .LBB0_3
+; CHECK-NEXT: ; %bb.20: ; %outer_exit
+; CHECK-NEXT: ; in Loop: Header=BB0_4 Depth=2
+; CHECK-NEXT: s_andn2_b64 s[56:57], s[56:57], exec
+; CHECK-NEXT: s_orn2_b64 s[58:59], s[16:17], exec
+; CHECK-NEXT: s_branch .LBB0_3
+; CHECK-NEXT: .LBB0_21: ; %DummyReturnBlock
+; CHECK-NEXT: s_or_b64 exec, exec, s[20:21]
+; CHECK-NEXT: v_readlane_b32 s30, v10, 0
+; CHECK-NEXT: v_readlane_b32 s31, v10, 1
+; CHECK-NEXT: s_xor_saveexec_b64 s[4:5], -1
+; CHECK-NEXT: buffer_load_dword v10, off, s[0:3], s32 offset:4 ; 4-byte Folded Reload
+; CHECK-NEXT: s_mov_b64 exec, s[4:5]
+; CHECK-NEXT: s_waitcnt vmcnt(0)
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+entry:
+ %private_slot = alloca i8, align 1, addrspace(5)
+ br label %outer_latch
+
+outer_latch: ; preds = %outer_exit, %entry
+ br label %outer_header
+
+outer_header: ; preds = %outer_exit, %outer_latch
+ br i1 %enter_fma_path, label %fma_setup, label %outer_exit
+
+fma_setup: ; preds = %outer_header
+ %first_fma = call double @llvm.fma.f64(double %input, double f0x3FE62E42FEFA39EF, double 0.000000e+00)
+ %second_fma = call double @llvm.fma.f64(double 0.000000e+00, double f0x3C7ABC9E3B39803F, double %first_fma)
+ br label %sgpr_loop_header
+
+sgpr_loop_header: ; preds = %after_sgpr_loop, %fma_setup
+ br i1 %enter_sgpr_loop, label %sgpr_pressure_loop, label %outer_exit
+
+sgpr_pressure_loop: ; preds = %sgpr_loop_merge, %sgpr_loop_header
+ %carried_sgpr_vec = phi <2 x i32> [ %next_sgpr_vec, %sgpr_loop_merge ], [ zeroinitializer, %sgpr_loop_header ]
+ %selected_fma = select i1 %zero_fma_result, double 0.000000e+00, double %second_fma
+ %new_sgpr_vec = insertelement <2 x i32> zeroinitializer, i32 0, i32 0
+ br i1 %enter_inner_loop, label %inner_stack_loop, label %sgpr_loop_merge
+
+inner_stack_loop: ; preds = %inner_stack_loop, %sgpr_pressure_loop
+ %stack_offset = phi i32 [ 0, %sgpr_pressure_loop ], [ 1, %inner_stack_loop ]
+ %selected_fp = select i1 %repeat_outer_loop, double 0.000000e+00, double %selected_fma
+ %inf_mul = fmul double +inf, %selected_fp
+ %scaled_mul = fmul double %inf_mul, f0x40417E50A9DC6553
+ %nan_mul = fmul double %scaled_mul, +qnan
+ %private_gep = getelementptr [8 x i8], ptr addrspace(5) %private_slot, i32 %stack_offset
+ %private_load = load double, ptr addrspace(5) %private_gep, align 1
+ %spill_value = fmul double %nan_mul, %private_load
+ store double %spill_value, ptr addrspace(5) null, align 1
+ %indexed_null = getelementptr i8, ptr addrspace(5) null, i32 %stack_offset
+ store double 0.000000e+00, ptr addrspace(5) %indexed_null, align 1
+ br i1 %exit_inner_loop, label %inner_done, label %inner_stack_loop
+
+inner_done: ; preds = %inner_stack_loop
+ br label %sgpr_loop_merge
+
+sgpr_loop_merge: ; preds = %inner_done, %sgpr_pressure_loop
+ %next_sgpr_vec = phi <2 x i32> [ %new_sgpr_vec, %inner_done ], [ %carried_sgpr_vec, %sgpr_pressure_loop ]
+ br i1 %enter_fma_path, label %sgpr_pressure_loop, label %after_sgpr_loop
+
+after_sgpr_loop: ; preds = %sgpr_loop_merge
+ br i1 %enter_sgpr_loop, label %sgpr_loop_header, label %outer_exit
+
+outer_exit: ; preds = %after_sgpr_loop, %sgpr_loop_header, %outer_header
+ br i1 %repeat_outer_loop, label %outer_header, label %outer_latch
+}
+
+declare double @llvm.fma.f64(double, double, double)
diff --git a/llvm/test/TableGen/RegisterInfoEmitter-errors.td b/llvm/test/TableGen/RegisterInfoEmitter-errors.td
index cb1a1e9136e95..b0b9a2fbbda86 100644
--- a/llvm/test/TableGen/RegisterInfoEmitter-errors.td
+++ b/llvm/test/TableGen/RegisterInfoEmitter-errors.td
@@ -4,6 +4,7 @@
// RUN: not llvm-tblgen -gen-register-info -I %p/../../include %s -DERROR3 2>&1 | FileCheck %s --check-prefix=ERROR3
// RUN: not llvm-tblgen -gen-register-info -I %p/../../include %s -DERROR4 2>&1 | FileCheck %s --check-prefix=ERROR4
// RUN: not llvm-tblgen -gen-register-bank -I %p/../../include %s -DERROR5 2>&1 | FileCheck %s --check-prefix=ERROR5
+// RUN: not llvm-tblgen -gen-register-info -I %p/../../include %s -DERROR6 2>&1 | FileCheck %s --check-prefix=ERROR6
include "llvm/Target/Target.td"
@@ -13,7 +14,11 @@ foreach Index = 0-15 in {
def R#Index : Register <"r"#Index>;
}
-def GPR32 : RegisterClass<"MyTarget", [i32], 32, (sequence "R%u", 0, 15)>;
+def GPR32 : RegisterClass<"MyTarget", [i32], 32, (sequence "R%u", 0, 15)> {
+#ifdef ERROR6
+ let SpillStackID = 256;
+#endif
+}
def sub0 : SubRegIndex<32, 0>;
def sub1 : SubRegIndex<32, 32>;
@@ -55,3 +60,6 @@ def R0_R1 : RegisterWithSubRegs<"r0_r1", [R0]> {
// ERROR5: error: No register banks defined
#endif
+#ifdef ERROR6
+// ERROR6: error: SpillStackID out of range [0,255]
+#endif
diff --git a/llvm/unittests/CodeGen/MachineInstrTest.cpp b/llvm/unittests/CodeGen/MachineInstrTest.cpp
index 47e260104775f..7e1fd091fa1c3 100644
--- a/llvm/unittests/CodeGen/MachineInstrTest.cpp
+++ b/llvm/unittests/CodeGen/MachineInstrTest.cpp
@@ -593,7 +593,7 @@ TEST(MachineInstrTest, SpliceOperands) {
// test tied operands
MCRegisterClass MRC{
0, 0, 0, 0, 0, 0, 0, 0, /*Allocatable=*/true, /*BaseClass=*/true};
- TargetRegisterClass RC{&MRC, 0, 0, {}, 0, 0, 0, 0, 0, 0, 0, 0};
+ TargetRegisterClass RC{&MRC, 0, 0, {}, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// MachineRegisterInfo will be very upset if these registers aren't
// allocatable.
assert(RC.isAllocatable() && "unusable TargetRegisterClass");
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
index 6f089bab7a89d..506d9b2ee8d7c 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
@@ -730,6 +730,10 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank,
int CopyCostParsed = R->getValueAsInt("CopyCost");
Allocatable = R->getValueAsBit("isAllocatable");
AltOrderSelect = R->getValueAsString("AltOrderSelect");
+ int SpillStackIDParsed = R->getValueAsInt("SpillStackID");
+ if (!isUInt<8>(SpillStackIDParsed))
+ PrintFatalError(R->getLoc(), "SpillStackID out of range [0,255]");
+ SpillStackID = SpillStackIDParsed;
int AllocationPriority = R->getValueAsInt("AllocationPriority");
if (!isUInt<5>(AllocationPriority))
PrintFatalError(R->getLoc(), "AllocationPriority out of range [0,31]");
@@ -757,7 +761,7 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank,
: Members(*Props.Members), TheDef(nullptr), Name(Name.str()),
RegsWithSuperRegsTopoSigs(RegBank.getNumTopoSigs()), EnumValue(-1),
RSI(Props.RSI), CopyCost(0), Allocatable(true), AllocationPriority(0),
- GlobalPriority(false), TSFlags(0) {
+ GlobalPriority(false), TSFlags(0), SpillStackID(0) {
MemberBV.resize(RegBank.getRegisters().size());
Artificial = true;
GeneratePressureSet = false;
@@ -794,6 +798,7 @@ void CodeGenRegisterClass::inheritProperties(CodeGenRegBank &RegBank) {
AllocationPriority = Super.AllocationPriority;
GlobalPriority = Super.GlobalPriority;
TSFlags = Super.TSFlags;
+ SpillStackID = Super.SpillStackID;
GeneratePressureSet |= Super.GeneratePressureSet;
// Copy all allocation orders, filter out foreign registers from the larger
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.h b/llvm/utils/TableGen/Common/CodeGenRegisters.h
index 1de5973084fdd..9a8c5aa25137c 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.h
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.h
@@ -374,6 +374,7 @@ class CodeGenRegisterClass {
uint8_t AllocationPriority;
bool GlobalPriority;
uint8_t TSFlags;
+ uint8_t SpillStackID;
/// Contains the combination of the lane masks of all subregisters.
LaneBitmask LaneMask;
/// True if there are at least 2 subregisters which do not interfere.
diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
index cb5b72e0c64b8..fa845c24aa720 100644
--- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp
@@ -1514,6 +1514,7 @@ void RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, raw_ostream &MainOS,
OS << ",\n " << (unsigned)RC.AllocationPriority << ",\n "
<< (RC.GlobalPriority ? "true" : "false") << ",\n "
<< format("0x%02x", RC.TSFlags) << ", /* TSFlags */\n "
+ << (unsigned)RC.SpillStackID << ", /* SpillStackID */\n "
<< (RC.HasDisjunctSubRegs ? "true" : "false")
<< ", /* HasDisjunctSubRegs */\n "
<< (RC.CoveredBySubRegs ? "true" : "false")
More information about the llvm-commits
mailing list