[AMDGPU] Set SGPR spill stack IDs when creating spill slots (#197628)
### Summary This PR resolves https://github.com/llvm/llvm-project/issues/195092. Teach register classes to describe the StackID to use for their spill slots, and use it when creating spill frame objects. This lets AMDGPU SGPR spill slots be marked as TargetStackID::SGPRSpill at construction time instead of patching the frame object later while emitting spill instructions. Also handle SGPR callee-saved spill slots created directly by SILowerSGPRSpills, which bypass the generic PEI spill slot creation path. Without this, late SGPR scavenging can see an SGPR spill pseudo using a default-stack frame index and trip the SGPRSpill assertion.
This commit is contained in:
parent
44714f90d8
commit
eac7bb4573
17 changed files with 351 additions and 20 deletions
|
|
@ -833,7 +833,9 @@ public:
|
|||
|
||||
/// 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) {
|
||||
|
|
|
|||
|
|
@ -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 @@ public:
|
|||
|
||||
/// 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 @@ public:
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
294
llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll
Normal file
294
llvm/test/CodeGen/AMDGPU/sgpr-scavenge-fi-stack-id.ll
Normal file
|
|
@ -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 < %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)
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -374,6 +374,7 @@ public:
|
|||
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.
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in a new issue