LLVM 23.0.0git
AMDGPUMCResourceInfo.cpp
Go to the documentation of this file.
1//===- AMDGPUMCResourceInfo.cpp --- MC Resource Info ----------------------===//
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/// \brief MC infrastructure to propagate the function level resource usage
11/// info.
12///
13//===----------------------------------------------------------------------===//
14
17#include "llvm/ADT/StringRef.h"
18#include "llvm/MC/MCAsmInfo.h"
19#include "llvm/MC/MCContext.h"
20#include "llvm/MC/MCSymbol.h"
22
23#define DEBUG_TYPE "amdgpu-mc-resource-usage"
24
25using namespace llvm;
26
28 MCContext &OutContext) {
29 auto GOCS = [FuncName, &OutContext](StringRef Suffix) {
30 StringRef Prefix = OutContext.getAsmInfo()->getInternalSymbolPrefix();
31 return OutContext.getOrCreateSymbol(Twine(Prefix) + FuncName +
32 Twine(Suffix));
33 };
34 switch (RIK) {
35 case RIK_NumVGPR:
36 return GOCS(".num_vgpr");
37 case RIK_NumAGPR:
38 return GOCS(".num_agpr");
39 case RIK_NumSGPR:
40 return GOCS(".numbered_sgpr");
42 return GOCS(".num_named_barrier");
44 return GOCS(".private_seg_size");
45 case RIK_UsesVCC:
46 return GOCS(".uses_vcc");
48 return GOCS(".uses_flat_scratch");
50 return GOCS(".has_dyn_sized_stack");
52 return GOCS(".has_recursion");
54 return GOCS(".has_indirect_call");
55 }
56 llvm_unreachable("Unexpected ResourceInfoKind.");
57}
58
61 MCContext &Ctx) {
62 return MCSymbolRefExpr::create(getSymbol(FuncName, RIK, Ctx), Ctx);
63}
64
65void MCResourceInfo::assignMaxRegs(MCContext &OutContext) {
66 // Assign expression to get the max register use to the max_num_Xgpr symbol.
67 MCSymbol *MaxVGPRSym = getMaxVGPRSymbol(OutContext);
68 MCSymbol *MaxAGPRSym = getMaxAGPRSymbol(OutContext);
69 MCSymbol *MaxSGPRSym = getMaxSGPRSymbol(OutContext);
70 MCSymbol *MaxNamedBarrierSym = getMaxNamedBarrierSymbol(OutContext);
71
72 auto assignMaxRegSym = [&OutContext](MCSymbol *Sym, int32_t RegCount) {
73 const MCExpr *MaxExpr = MCConstantExpr::create(RegCount, OutContext);
74 Sym->setVariableValue(MaxExpr);
75 };
76
77 assignMaxRegSym(MaxVGPRSym, MaxVGPR);
78 assignMaxRegSym(MaxAGPRSym, MaxAGPR);
79 assignMaxRegSym(MaxSGPRSym, MaxSGPR);
80 assignMaxRegSym(MaxNamedBarrierSym, MaxNamedBarrier);
81}
82
84
86 assert(!Finalized && "Cannot finalize ResourceInfo again.");
87 Finalized = true;
88 assignMaxRegs(OutContext);
89}
90
92 return OutContext.getOrCreateSymbol("amdgpu.max_num_vgpr");
93}
94
96 return OutContext.getOrCreateSymbol("amdgpu.max_num_agpr");
97}
98
100 return OutContext.getOrCreateSymbol("amdgpu.max_num_sgpr");
101}
102
104 return OutContext.getOrCreateSymbol("amdgpu.max_num_named_barrier");
105}
106
107// Tries to flatten recursive call register resource gathering. Simple cycle
108// avoiding dfs to find the constants in the propagated symbols.
109// Assumes:
110// - RecSym has been confirmed to recurse (this means the callee symbols should
111// all be populated, started at RecSym).
112// - Shape of the resource symbol's MCExpr (`max` args are order agnostic):
113// RecSym.MCExpr := max(<constant>+, <callee_symbol>*)
114const MCExpr *MCResourceInfo::flattenedCycleMax(MCSymbol *RecSym,
115 ResourceInfoKind RIK,
116 MCContext &OutContext) {
119 int64_t Maximum = 0;
120
121 const MCExpr *RecExpr = RecSym->getVariableValue();
122 WorkList.push_back(RecExpr);
123
124 while (!WorkList.empty()) {
125 const MCExpr *CurExpr = WorkList.pop_back_val();
126 switch (CurExpr->getKind()) {
127 default: {
128 // Assuming the recursion is of shape `max(<constant>, <callee_symbol>)`
129 // where <callee_symbol> will eventually recurse. If this condition holds,
130 // the recursion occurs within some other (possibly unresolvable) MCExpr,
131 // thus using the worst case value then.
132 if (!AMDGPUMCExpr::isSymbolUsedInExpression(RecSym, CurExpr)) {
133 LLVM_DEBUG(dbgs() << "MCResUse: " << RecSym->getName()
134 << ": Recursion in unexpected sub-expression, using "
135 "module maximum\n");
136 switch (RIK) {
137 default:
138 break;
139 case RIK_NumVGPR:
140 return MCSymbolRefExpr::create(getMaxVGPRSymbol(OutContext),
141 OutContext);
142 break;
143 case RIK_NumSGPR:
144 return MCSymbolRefExpr::create(getMaxSGPRSymbol(OutContext),
145 OutContext);
146 break;
147 case RIK_NumAGPR:
148 return MCSymbolRefExpr::create(getMaxAGPRSymbol(OutContext),
149 OutContext);
150 break;
151 }
152 }
153 break;
154 }
156 int64_t Val = cast<MCConstantExpr>(CurExpr)->getValue();
157 Maximum = std::max(Maximum, Val);
158 break;
159 }
161 const MCSymbolRefExpr *SymExpr = cast<MCSymbolRefExpr>(CurExpr);
162 const MCSymbol &SymRef = SymExpr->getSymbol();
163 if (SymRef.isVariable()) {
164 const MCExpr *SymVal = SymRef.getVariableValue();
165 if (Seen.insert(SymVal).second)
166 WorkList.push_back(SymVal);
167 }
168 break;
169 }
171 const AMDGPUMCExpr *TargetExpr = cast<AMDGPUMCExpr>(CurExpr);
172 if (TargetExpr->getKind() == AMDGPUMCExpr::VariantKind::AGVK_Max) {
173 for (auto &Arg : TargetExpr->getArgs())
174 WorkList.push_back(Arg);
175 }
176 break;
177 }
178 }
179 }
180
181 LLVM_DEBUG(dbgs() << "MCResUse: " << RecSym->getName()
182 << ": Using flattened max: << " << Maximum << '\n');
183
184 return MCConstantExpr::create(Maximum, OutContext);
185}
186
187void MCResourceInfo::assignResourceInfoExpr(
188 int64_t LocalValue, ResourceInfoKind RIK, AMDGPUMCExpr::VariantKind Kind,
189 const MachineFunction &MF, const SmallVectorImpl<const Function *> &Callees,
190 MCContext &OutContext) {
191 const TargetMachine &TM = MF.getTarget();
192 MCSymbol *FnSym = TM.getSymbol(&MF.getFunction());
193 const MCConstantExpr *LocalConstExpr =
194 MCConstantExpr::create(LocalValue, OutContext);
195 const MCExpr *SymVal = LocalConstExpr;
196 MCSymbol *Sym = getSymbol(FnSym->getName(), RIK, OutContext);
197 LLVM_DEBUG(dbgs() << "MCResUse: " << Sym->getName() << ": Adding "
198 << LocalValue << " as function local usage\n");
199 if (!Callees.empty()) {
201 SmallPtrSet<const Function *, 8> Seen;
202 ArgExprs.push_back(LocalConstExpr);
203
204 for (const Function *Callee : Callees) {
205 if (!Seen.insert(Callee).second)
206 continue;
207
208 MCSymbol *CalleeFnSym = TM.getSymbol(&Callee->getFunction());
209 MCSymbol *CalleeValSym =
210 getSymbol(CalleeFnSym->getName(), RIK, OutContext);
211
212 // Avoid constructing recursive definitions by detecting whether `Sym` is
213 // found transitively within any of its `CalleeValSym`.
214 if (!CalleeValSym->isVariable() ||
216 Sym, CalleeValSym->getVariableValue())) {
217 LLVM_DEBUG(dbgs() << "MCResUse: " << Sym->getName() << ": Adding "
218 << CalleeValSym->getName() << " as callee\n");
219 ArgExprs.push_back(MCSymbolRefExpr::create(CalleeValSym, OutContext));
220 } else {
221 LLVM_DEBUG(dbgs() << "MCResUse: " << Sym->getName()
222 << ": Recursion found, attempt flattening of cycle "
223 "for resource usage\n");
224 // In case of recursion for vgpr/sgpr/agpr resource usage: try to
225 // flatten and use the max of the call cycle. May still end up emitting
226 // module max if not fully resolvable.
227 switch (RIK) {
228 default:
229 break;
230 case RIK_NumVGPR:
231 case RIK_NumSGPR:
232 case RIK_NumAGPR:
233 ArgExprs.push_back(flattenedCycleMax(CalleeValSym, RIK, OutContext));
234 break;
237 getMaxNamedBarrierSymbol(OutContext), OutContext));
238 break;
239 }
240 }
241 }
242 if (ArgExprs.size() > 1)
243 SymVal = AMDGPUMCExpr::create(Kind, ArgExprs, OutContext);
244 }
245 Sym->setVariableValue(SymVal);
246}
247
249 const MachineFunction &MF,
251 MCContext &OutContext) {
252 // Worst case VGPR use for non-hardware-entrypoints.
253 MCSymbol *MaxVGPRSym = getMaxVGPRSymbol(OutContext);
254 MCSymbol *MaxAGPRSym = getMaxAGPRSymbol(OutContext);
255 MCSymbol *MaxSGPRSym = getMaxSGPRSymbol(OutContext);
256 MCSymbol *MaxNamedBarrierSym = getMaxNamedBarrierSymbol(OutContext);
257
263 }
264
265 const TargetMachine &TM = MF.getTarget();
266 MCSymbol *FnSym = TM.getSymbol(&MF.getFunction());
267
268 LLVM_DEBUG(dbgs() << "MCResUse: Gathering resource information for "
269 << FnSym->getName() << '\n');
270 LLVM_DEBUG({
271 if (!FRI.Callees.empty()) {
272 dbgs() << "MCResUse: Callees:\n";
273 for (const Function *Callee : FRI.Callees) {
274 MCSymbol *CalleeFnSym = TM.getSymbol(&Callee->getFunction());
275 dbgs() << "MCResUse: " << CalleeFnSym->getName() << '\n';
276 }
277 }
278 });
279
280 auto SetMaxReg = [&](MCSymbol *MaxSym, int32_t numRegs,
281 ResourceInfoKind RIK) {
282 if (!FRI.HasIndirectCall) {
283 assignResourceInfoExpr(numRegs, RIK, AMDGPUMCExpr::AGVK_Max, MF,
284 FRI.Callees, OutContext);
285 } else {
286 const MCExpr *SymRef = MCSymbolRefExpr::create(MaxSym, OutContext);
287 MCSymbol *LocalNumSym = getSymbol(FnSym->getName(), RIK, OutContext);
288 const MCExpr *MaxWithLocal = AMDGPUMCExpr::createMax(
289 {MCConstantExpr::create(numRegs, OutContext), SymRef}, OutContext);
290 LocalNumSym->setVariableValue(MaxWithLocal);
291 LLVM_DEBUG(dbgs() << "MCResUse: " << LocalNumSym->getName()
292 << ": Indirect callee within, using module maximum\n");
293 }
294 };
295
296 LLVM_DEBUG(dbgs() << "MCResUse: " << FnSym->getName() << '\n');
297 SetMaxReg(MaxVGPRSym, FRI.NumVGPR, RIK_NumVGPR);
298 SetMaxReg(MaxAGPRSym, FRI.NumAGPR, RIK_NumAGPR);
299 SetMaxReg(MaxSGPRSym, FRI.NumExplicitSGPR, RIK_NumSGPR);
300 SetMaxReg(MaxNamedBarrierSym, FRI.NumNamedBarrier, RIK_NumNamedBarrier);
301
302 {
303 // The expression for private segment size should be: FRI.PrivateSegmentSize
304 // + max(FRI.Callees, FRI.CalleeSegmentSize)
306 MCSymbol *Sym = getSymbol(FnSym->getName(), RIK_PrivateSegSize, OutContext);
307 if (FRI.CalleeSegmentSize) {
308 LLVM_DEBUG(dbgs() << "MCResUse: " << Sym->getName() << ": Adding "
309 << FRI.CalleeSegmentSize
310 << " for indirect/recursive callees within\n");
311 ArgExprs.push_back(
313 }
314
316 Seen.insert(&MF.getFunction());
317 for (const Function *Callee : FRI.Callees) {
318 if (!Seen.insert(Callee).second)
319 continue;
320 if (!Callee->isDeclaration()) {
321 MCSymbol *CalleeFnSym = TM.getSymbol(&Callee->getFunction());
322 MCSymbol *CalleeValSym =
323 getSymbol(CalleeFnSym->getName(), RIK_PrivateSegSize, OutContext);
324
325 // Avoid constructing recursive definitions by detecting whether `Sym`
326 // is found transitively within any of its `CalleeValSym`.
327 if (!CalleeValSym->isVariable() ||
329 Sym, CalleeValSym->getVariableValue())) {
330 LLVM_DEBUG(dbgs() << "MCResUse: " << Sym->getName() << ": Adding "
331 << CalleeValSym->getName() << " as callee\n");
332 ArgExprs.push_back(MCSymbolRefExpr::create(CalleeValSym, OutContext));
333 }
334 }
335 }
336 const MCExpr *localConstExpr =
338 LLVM_DEBUG(dbgs() << "MCResUse: " << Sym->getName() << ": Adding "
339 << FRI.PrivateSegmentSize
340 << " as function local usage\n");
341 if (!ArgExprs.empty()) {
342 const AMDGPUMCExpr *transitiveExpr =
343 AMDGPUMCExpr::createMax(ArgExprs, OutContext);
344 localConstExpr =
345 MCBinaryExpr::createAdd(localConstExpr, transitiveExpr, OutContext);
346 }
347 Sym->setVariableValue(localConstExpr);
348 }
349
350 auto SetToLocal = [&](int64_t LocalValue, ResourceInfoKind RIK) {
351 MCSymbol *Sym = getSymbol(FnSym->getName(), RIK, OutContext);
353 dbgs() << "MCResUse: " << Sym->getName() << ": Adding " << LocalValue
354 << ", no further propagation as indirect callee found within\n");
355 Sym->setVariableValue(MCConstantExpr::create(LocalValue, OutContext));
356 };
357
358 if (!FRI.HasIndirectCall) {
359 assignResourceInfoExpr(FRI.UsesVCC, ResourceInfoKind::RIK_UsesVCC,
360 AMDGPUMCExpr::AGVK_Or, MF, FRI.Callees, OutContext);
361 assignResourceInfoExpr(FRI.UsesFlatScratch,
363 AMDGPUMCExpr::AGVK_Or, MF, FRI.Callees, OutContext);
364 assignResourceInfoExpr(FRI.HasDynamicallySizedStack,
366 AMDGPUMCExpr::AGVK_Or, MF, FRI.Callees, OutContext);
367 assignResourceInfoExpr(FRI.HasRecursion, ResourceInfoKind::RIK_HasRecursion,
368 AMDGPUMCExpr::AGVK_Or, MF, FRI.Callees, OutContext);
369 assignResourceInfoExpr(FRI.HasIndirectCall,
371 AMDGPUMCExpr::AGVK_Or, MF, FRI.Callees, OutContext);
372 } else {
373 SetToLocal(FRI.UsesVCC, ResourceInfoKind::RIK_UsesVCC);
375 SetToLocal(FRI.HasDynamicallySizedStack,
379 }
380}
381
383 MCContext &Ctx) {
384 const TargetMachine &TM = MF.getTarget();
385 MCSymbol *FnSym = TM.getSymbol(&MF.getFunction());
387 getSymRefExpr(FnSym->getName(), RIK_NumAGPR, Ctx),
388 getSymRefExpr(FnSym->getName(), RIK_NumVGPR, Ctx), Ctx);
389}
390
392 bool hasXnack,
393 MCContext &Ctx) {
394 const TargetMachine &TM = MF.getTarget();
395 MCSymbol *FnSym = TM.getSymbol(&MF.getFunction());
397 getSymRefExpr(FnSym->getName(), RIK_NumSGPR, Ctx),
399 getSymRefExpr(FnSym->getName(), RIK_UsesVCC, Ctx),
400 getSymRefExpr(FnSym->getName(), RIK_UsesFlatScratch, Ctx), hasXnack,
401 Ctx),
402 Ctx);
403}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MC infrastructure to propagate the function level resource usage info.
#define LLVM_DEBUG(...)
Definition Debug.h:114
AMDGPU target specific MCExpr operations.
ArrayRef< const MCExpr * > getArgs() const
static const AMDGPUMCExpr * createMax(ArrayRef< const MCExpr * > Args, MCContext &Ctx)
static const AMDGPUMCExpr * createTotalNumVGPR(const MCExpr *NumAGPR, const MCExpr *NumVGPR, MCContext &Ctx)
static const AMDGPUMCExpr * create(VariantKind Kind, ArrayRef< const MCExpr * > Args, MCContext &Ctx)
static const AMDGPUMCExpr * createExtraSGPRs(const MCExpr *VCCUsed, const MCExpr *FlatScrUsed, bool XNACKUsed, MCContext &Ctx)
Allow delayed MCExpr resolve of ExtraSGPRs (in case VCCUsed or FlatScrUsed are unresolvable but neede...
VariantKind getKind() const
static bool isSymbolUsedInExpression(const MCSymbol *Sym, const MCExpr *E)
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
Definition Function.h:272
StringRef getInternalSymbolPrefix() const
Definition MCAsmInfo.h:552
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:343
static LLVM_ABI const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition MCExpr.cpp:212
Context object for machine code objects.
Definition MCContext.h:83
const MCAsmInfo * getAsmInfo() const
Definition MCContext.h:409
LLVM_ABI MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
Base class for the full range of assembler expressions which are needed for parsing.
Definition MCExpr.h:34
@ Constant
Constant expressions.
Definition MCExpr.h:42
@ SymbolRef
References to labels and assigned expressions.
Definition MCExpr.h:43
@ Target
Target specific expression.
Definition MCExpr.h:46
ExprKind getKind() const
Definition MCExpr.h:85
MCResourceInfo()=default
MCSymbol * getMaxNamedBarrierSymbol(MCContext &OutContext)
void addMaxSGPRCandidate(int32_t candidate)
const MCExpr * getSymRefExpr(StringRef FuncName, ResourceInfoKind RIK, MCContext &Ctx)
MCSymbol * getMaxSGPRSymbol(MCContext &OutContext)
void addMaxNamedBarrierCandidate(int32_t candidate)
MCSymbol * getMaxAGPRSymbol(MCContext &OutContext)
const MCExpr * createTotalNumVGPRs(const MachineFunction &MF, MCContext &Ctx)
void finalize(MCContext &OutContext)
void addMaxAGPRCandidate(int32_t candidate)
MCSymbol * getMaxVGPRSymbol(MCContext &OutContext)
const MCExpr * createTotalNumSGPRs(const MachineFunction &MF, bool hasXnack, MCContext &Ctx)
MCSymbol * getSymbol(StringRef FuncName, ResourceInfoKind RIK, MCContext &OutContext)
void addMaxVGPRCandidate(int32_t candidate)
void gatherResourceInfo(const MachineFunction &MF, const AMDGPUResourceUsageAnalysisWrapperPass::FunctionResourceInfo &FRI, MCContext &OutContext)
AMDGPUResourceUsageAnalysis gathers resource usage on a per-function granularity.
const MCSymbol & getSymbol() const
Definition MCExpr.h:227
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:214
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
StringRef getName() const
getName - Get the symbol name.
Definition MCSymbol.h:188
bool isVariable() const
isVariable - Check if this is a variable symbol.
Definition MCSymbol.h:267
LLVM_ABI void setVariableValue(const MCExpr *Value)
Definition MCSymbol.cpp:50
const MCExpr * getVariableValue() const
Get the expression of the variable symbol.
Definition MCSymbol.h:270
Function & getFunction()
Return the LLVM function that this machine code represents.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
Primary interface to the complete machine description for the target machine.
MCSymbol * getSymbol(const GlobalValue *GV) const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_READNONE constexpr bool isEntryFunctionCC(CallingConv::ID CC)
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
AMDGPUResourceUsageAnalysisImpl::SIFunctionResourceInfo FunctionResourceInfo