LLVM 24.0.0git
AMDGPUSetWavePriority.cpp
Go to the documentation of this file.
1//===- AMDGPUSetWavePriority.cpp - Set wave priority ----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// Pass to temporarily raise the wave priority beginning the start of
11/// the shader function until its last VMEM instructions to allow younger
12/// waves to issue their VMEM instructions as well.
13//
14//===----------------------------------------------------------------------===//
15
16#include "AMDGPU.h"
17#include "GCNSubtarget.h"
18#include "SIInstrInfo.h"
22
23using namespace llvm;
24
25#define DEBUG_TYPE "amdgpu-set-wave-priority"
26
27namespace {
28
29struct MBBInfo {
30 MBBInfo() = default;
31 unsigned NumVALUInstsAtStart = 0;
32 bool MayReachVMEMLoad = false;
33 MachineInstr *LastVMEMLoad = nullptr;
34};
35
37
38class AMDGPUSetWavePriority {
39public:
40 bool run(MachineFunction &MF);
41
42private:
43 MachineInstr *BuildSetprioMI(MachineBasicBlock &MBB,
45 unsigned priority) const;
46
47 const SIInstrInfo *TII;
48};
49
50class AMDGPUSetWavePriorityLegacy : public MachineFunctionPass {
51public:
52 static char ID;
53
54 AMDGPUSetWavePriorityLegacy() : MachineFunctionPass(ID) {}
55
56 StringRef getPassName() const override { return "Set wave priority"; }
57
58 bool runOnMachineFunction(MachineFunction &MF) override {
59 if (skipFunction(MF.getFunction()))
60 return false;
61
62 return AMDGPUSetWavePriority().run(MF);
63 }
64};
65
66} // End anonymous namespace.
67
68INITIALIZE_PASS(AMDGPUSetWavePriorityLegacy, DEBUG_TYPE, "Set wave priority",
69 false, false)
70
71char AMDGPUSetWavePriorityLegacy::ID = 0;
72
74 return new AMDGPUSetWavePriorityLegacy();
75}
76
78AMDGPUSetWavePriority::BuildSetprioMI(MachineBasicBlock &MBB,
80 unsigned priority) const {
81 return BuildMI(MBB, I, DebugLoc(), TII->get(AMDGPU::S_SETPRIO))
82 .addImm(priority);
83}
84
85// Checks that for every predecessor Pred that can reach a VMEM load,
86// none of Pred's successors can reach a VMEM load.
88 MBBInfoSet &MBBInfos) {
89 for (const MachineBasicBlock *Pred : MBB.predecessors()) {
90 if (!MBBInfos[Pred].MayReachVMEMLoad)
91 continue;
92 for (const MachineBasicBlock *Succ : Pred->successors()) {
93 if (MBBInfos[Succ].MayReachVMEMLoad)
94 return false;
95 }
96 }
97 return true;
98}
99
100static bool isVMEMLoad(const MachineInstr &MI) {
101 return SIInstrInfo::isVMEM(MI) && MI.mayLoad();
102}
103
104PreservedAnalyses
112
113bool AMDGPUSetWavePriority::run(MachineFunction &MF) {
114 const unsigned HighPriority = 3;
115 const unsigned LowPriority = 0;
116
117 Function &F = MF.getFunction();
118 if (!AMDGPU::isEntryFunctionCC(F.getCallingConv()))
119 return false;
120
121 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
122 TII = ST.getInstrInfo();
123
124 unsigned VALUInstsThreshold =
125 ST.getCLOpts().set_wave_priority_valu_insts_threshold;
126 Attribute A = F.getFnAttribute("amdgpu-wave-priority-threshold");
127 if (A.isValid())
128 A.getValueAsString().getAsInteger(0, VALUInstsThreshold);
129
130 // Find VMEM loads that may be executed before long-enough sequences of
131 // VALU instructions. We currently assume that backedges/loops, branch
132 // probabilities and other details can be ignored, so we essentially
133 // determine the largest number of VALU instructions along every
134 // possible path from the start of the function that may potentially be
135 // executed provided no backedge is ever taken.
136 MBBInfoSet MBBInfos;
137 for (MachineBasicBlock *MBB : post_order(&MF)) {
138 bool AtStart = true;
139 unsigned MaxNumVALUInstsInMiddle = 0;
140 unsigned NumVALUInstsAtEnd = 0;
141 for (MachineInstr &MI : *MBB) {
142 if (isVMEMLoad(MI)) {
143 AtStart = false;
144 MBBInfo &Info = MBBInfos[MBB];
145 Info.NumVALUInstsAtStart = 0;
146 MaxNumVALUInstsInMiddle = 0;
147 NumVALUInstsAtEnd = 0;
148 Info.LastVMEMLoad = &MI;
149 } else if (SIInstrInfo::isDS(MI)) {
150 AtStart = false;
151 MaxNumVALUInstsInMiddle =
152 std::max(MaxNumVALUInstsInMiddle, NumVALUInstsAtEnd);
153 NumVALUInstsAtEnd = 0;
154 } else if (SIInstrInfo::isVALU(MI, /*AllowLDSDMA=*/false)) {
155 if (AtStart)
156 ++MBBInfos[MBB].NumVALUInstsAtStart;
157 ++NumVALUInstsAtEnd;
158 }
159 }
160
161 bool SuccsMayReachVMEMLoad = false;
162 unsigned NumFollowingVALUInsts = 0;
163 for (const MachineBasicBlock *Succ : MBB->successors()) {
164 const MBBInfo &SuccInfo = MBBInfos[Succ];
165 SuccsMayReachVMEMLoad |= SuccInfo.MayReachVMEMLoad;
166 NumFollowingVALUInsts =
167 std::max(NumFollowingVALUInsts, SuccInfo.NumVALUInstsAtStart);
168 }
169 MBBInfo &Info = MBBInfos[MBB];
170 if (AtStart)
171 Info.NumVALUInstsAtStart += NumFollowingVALUInsts;
172 NumVALUInstsAtEnd += NumFollowingVALUInsts;
173
174 unsigned MaxNumVALUInsts =
175 std::max(MaxNumVALUInstsInMiddle, NumVALUInstsAtEnd);
176 Info.MayReachVMEMLoad =
177 SuccsMayReachVMEMLoad ||
178 (Info.LastVMEMLoad && MaxNumVALUInsts >= VALUInstsThreshold);
179 }
180
181 MachineBasicBlock &Entry = MF.front();
182 if (!MBBInfos[&Entry].MayReachVMEMLoad)
183 return false;
184
185 // Raise the priority at the beginning of the shader.
186 MachineBasicBlock::iterator I = Entry.begin(), E = Entry.end();
187 while (I != E && !SIInstrInfo::isVALU(*I, /*AllowLDSDMA=*/false) &&
188 !I->isTerminator())
189 ++I;
190 BuildSetprioMI(Entry, I, HighPriority);
191
192 // Lower the priority on edges where control leaves blocks from which
193 // the VMEM loads are reachable.
194 SmallPtrSet<MachineBasicBlock *, 16> PriorityLoweringBlocks;
195 for (MachineBasicBlock &MBB : MF) {
196 if (MBBInfos[&MBB].MayReachVMEMLoad) {
197 if (MBB.succ_empty())
198 PriorityLoweringBlocks.insert(&MBB);
199 continue;
200 }
201
203 for (MachineBasicBlock *Pred : MBB.predecessors()) {
204 if (MBBInfos[Pred].MayReachVMEMLoad)
205 PriorityLoweringBlocks.insert(Pred);
206 }
207 continue;
208 }
209
210 // Where lowering the priority in predecessors is not possible, the
211 // block receiving control either was not part of a loop in the first
212 // place or the loop simplification/canonicalization pass should have
213 // already tried to split the edge and insert a preheader, and if for
214 // whatever reason it failed to do so, then this leaves us with the
215 // only option of lowering the priority within the loop.
216 PriorityLoweringBlocks.insert(&MBB);
217 }
218
219 for (MachineBasicBlock *MBB : PriorityLoweringBlocks) {
220 MachineInstr *LastVMEMLoad = MBBInfos[MBB].LastVMEMLoad;
221 BuildSetprioMI(*MBB,
222 LastVMEMLoad
223 ? std::next(MachineBasicBlock::iterator(LastVMEMLoad))
224 : MBB->begin(),
225 LowPriority);
226 }
227
228 return true;
229}
SDValue Pred
static bool CanLowerPriorityDirectlyInPredecessors(const MachineBasicBlock &MBB, MBBInfoSet &MBBInfos)
static bool isVMEMLoad(const MachineInstr &MI)
MachineBasicBlock & MBB
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
AMD GCN specific subclass of TargetSubtarget.
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
Interface definition for SIInstrInfo.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
Functions, function parameters, and return types can have attributes to indicate how they should be t...
Definition Attributes.h:106
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
iterator_range< succ_iterator > successors()
iterator_range< pred_iterator > predecessors()
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineBasicBlock & front() const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Representation of each machine instruction.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
static bool isDS(const MachineInstr &MI)
static bool isVMEM(const MachineInstr &MI)
static bool isVALU(const MachineInstr &MI, bool AllowLDSDMA)
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
LLVM_READNONE constexpr bool isEntryFunctionCC(CallingConv::ID CC)
@ Entry
Definition COFF.h:862
This is an optimization pass for GlobalISel generic memory operations.
FunctionPass * createAMDGPUSetWavePriorityPass()
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
auto post_order(const T &G)
Post-order traversal of a graph.