16
16
#include " GCNSubtarget.h"
17
17
#include " MCTargetDesc/AMDGPUMCTargetDesc.h"
18
18
#include " SIDefines.h"
19
- #include " llvm/ADT/STLExtras .h"
19
+ #include " llvm/ADT/DepthFirstIterator .h"
20
20
#include " llvm/CodeGen/MachineBasicBlock.h"
21
21
#include " llvm/CodeGen/MachineOperand.h"
22
22
using namespace llvm ;
@@ -29,60 +29,76 @@ class AMDGPUReleaseVGPRs : public MachineFunctionPass {
29
29
public:
30
30
static char ID;
31
31
32
- const SIInstrInfo *SII;
33
- const SIRegisterInfo *TRI;
34
-
35
32
AMDGPUReleaseVGPRs () : MachineFunctionPass(ID) {}
36
33
37
34
void getAnalysisUsage (AnalysisUsage &AU) const override {
38
35
AU.setPreservesAll ();
39
36
MachineFunctionPass::getAnalysisUsage (AU);
40
37
}
41
38
42
- // Used to cache the result of isLastInstructionVMEMStore for each block
43
- using BlockVMEMStoreType = DenseMap<MachineBasicBlock *, bool >;
44
- BlockVMEMStoreType BlockVMEMStore;
45
-
46
- // Return true if the last instruction referencing a vgpr in this MBB
47
- // is a VMEM store, otherwise return false.
48
- // Visit previous basic blocks to find this last instruction if needed.
49
- // Because this pass is late in the pipeline, it is expected that the
39
+ // Track if the last instruction referencing a vgpr in a MBB is a VMEM
40
+ // store. Because this pass is late in the pipeline, it is expected that the
50
41
// last vgpr use will likely be one of vmem store, ds, exp.
51
42
// Loads and others vgpr operations would have been
52
43
// deleted by this point, except for complex control flow involving loops.
53
44
// This is why we are just testing the type of instructions rather
54
45
// than the operands.
55
- bool isLastVGPRUseVMEMStore (MachineBasicBlock &MBB) {
56
- // Use the cache to break infinite loop and save some time. Initialize to
57
- // false in case we have a cycle.
58
- BlockVMEMStoreType::iterator It;
59
- bool Inserted;
60
- std::tie (It, Inserted) = BlockVMEMStore.insert ({&MBB, false });
61
- bool &CacheEntry = It->second ;
62
- if (!Inserted)
63
- return CacheEntry;
64
-
65
- for (auto &MI : reverse (MBB.instrs ())) {
66
- // If it's a VMEM store, a vgpr will be used, return true.
67
- if ((SIInstrInfo::isVMEM (MI) || SIInstrInfo::isFLAT (MI)) && MI.mayStore ())
68
- return CacheEntry = true ;
69
-
70
- // If it's referencing a VGPR but is not a VMEM store, return false.
71
- if (SIInstrInfo::isDS (MI) || SIInstrInfo::isEXP (MI) ||
72
- SIInstrInfo::isVMEM (MI) || SIInstrInfo::isFLAT (MI) ||
73
- SIInstrInfo::isVALU (MI))
74
- return CacheEntry = false ;
46
+ class LastVGPRUseIsVMEMStore {
47
+ BitVector BlockVMEMStore;
48
+
49
+ static Optional<bool > lastVGPRUseIsStore (const MachineBasicBlock &MBB) {
50
+ for (auto &MI : reverse (MBB.instrs ())) {
51
+ // If it's a VMEM store, a VGPR will be used, return true.
52
+ if ((SIInstrInfo::isVMEM (MI) || SIInstrInfo::isFLAT (MI)) &&
53
+ MI.mayStore ())
54
+ return true ;
55
+
56
+ // If it's referencing a VGPR but is not a VMEM store, return false.
57
+ if (SIInstrInfo::isDS (MI) || SIInstrInfo::isEXP (MI) ||
58
+ SIInstrInfo::isVMEM (MI) || SIInstrInfo::isFLAT (MI) ||
59
+ SIInstrInfo::isVALU (MI))
60
+ return false ;
61
+ }
62
+ // Wait until the values are propagated from the predecessors
63
+ return None;
75
64
}
76
65
77
- // Recursive call into parent blocks. Look into predecessors if there is no
78
- // vgpr used in this block.
79
- return CacheEntry = llvm::any_of (MBB.predecessors (),
80
- [this ](MachineBasicBlock *Parent) {
81
- return isLastVGPRUseVMEMStore (*Parent);
82
- });
83
- }
66
+ public:
67
+ LastVGPRUseIsVMEMStore (const MachineFunction &MF)
68
+ : BlockVMEMStore(MF.getNumBlockIDs()) {
69
+
70
+ df_iterator_default_set<const MachineBasicBlock *> Visited;
71
+ SmallVector<const MachineBasicBlock *> EndWithVMEMStoreBlocks;
72
+
73
+ for (const auto &MBB : MF) {
74
+ auto LastUseIsStore = lastVGPRUseIsStore (MBB);
75
+ if (!LastUseIsStore.has_value ())
76
+ continue ;
77
+
78
+ if (*LastUseIsStore) {
79
+ EndWithVMEMStoreBlocks.push_back (&MBB);
80
+ } else {
81
+ Visited.insert (&MBB);
82
+ }
83
+ }
84
+
85
+ for (const auto *MBB : EndWithVMEMStoreBlocks) {
86
+ for (const auto *Succ : depth_first_ext (MBB, Visited)) {
87
+ BlockVMEMStore[Succ->getNumber ()] = true ;
88
+ }
89
+ }
90
+ }
91
+
92
+ // Return true if the last instruction referencing a vgpr in this MBB
93
+ // is a VMEM store, otherwise return false.
94
+ bool isLastVGPRUseVMEMStore (const MachineBasicBlock &MBB) const {
95
+ return BlockVMEMStore[MBB.getNumber ()];
96
+ }
97
+ };
84
98
85
- bool runOnMachineBasicBlock (MachineBasicBlock &MBB) {
99
+ static bool
100
+ runOnMachineBasicBlock (MachineBasicBlock &MBB, const SIInstrInfo *SII,
101
+ const LastVGPRUseIsVMEMStore &BlockVMEMStore) {
86
102
87
103
bool Changed = false ;
88
104
@@ -93,7 +109,7 @@ class AMDGPUReleaseVGPRs : public MachineFunctionPass {
93
109
// If the last instruction using a VGPR in the block is a VMEM store,
94
110
// release VGPRs. The VGPRs release will be placed just before ending
95
111
// the program
96
- if (isLastVGPRUseVMEMStore (MBB)) {
112
+ if (BlockVMEMStore. isLastVGPRUseVMEMStore (MBB)) {
97
113
BuildMI (MBB, MI, DebugLoc (), SII->get (AMDGPU::S_SENDMSG))
98
114
.addImm (AMDGPU::SendMsg::ID_DEALLOC_VGPRS_GFX11Plus);
99
115
Changed = true ;
@@ -117,16 +133,14 @@ class AMDGPUReleaseVGPRs : public MachineFunctionPass {
117
133
LLVM_DEBUG (dbgs () << " AMDGPUReleaseVGPRs running on " << MF.getName ()
118
134
<< " \n " );
119
135
120
- SII = ST.getInstrInfo ();
121
- TRI = ST. getRegisterInfo ( );
136
+ const SIInstrInfo * SII = ST.getInstrInfo ();
137
+ LastVGPRUseIsVMEMStore BlockVMEMStore (MF );
122
138
123
139
bool Changed = false ;
124
140
for (auto &MBB : MF) {
125
- Changed |= runOnMachineBasicBlock (MBB);
141
+ Changed |= runOnMachineBasicBlock (MBB, SII, BlockVMEMStore );
126
142
}
127
143
128
- BlockVMEMStore.clear ();
129
-
130
144
return Changed;
131
145
}
132
146
};
0 commit comments