LLVM 24.0.0git
AMDGPUResourceUsageAnalysis.cpp
Go to the documentation of this file.
1//===- AMDGPUResourceUsageAnalysis.h ---- analysis of resources -----------===//
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 Analyzes how many registers and other resources are used by
11/// functions.
12///
13/// The results of this analysis are used to fill the register usage, flat
14/// usage, etc. into hardware registers.
15///
16//===----------------------------------------------------------------------===//
17
19#include "AMDGPU.h"
20#include "AMDGPUTargetMachine.h"
21#include "GCNSubtarget.h"
26#include "llvm/IR/GlobalValue.h"
28
29using namespace llvm;
30using namespace llvm::AMDGPU;
31
32#define DEBUG_TYPE "amdgpu-resource-usage"
33
37
39 "Function register usage analysis", true, true)
40
41static const Function *getCalleeFunction(const MachineOperand &Op) {
42 if (Op.isImm()) {
43 assert(Op.getImm() == 0);
44 return nullptr;
45 }
46 return cast<Function>(Op.getGlobal()->stripPointerCastsAndAliases());
47}
48
50 const SIInstrInfo &TII, unsigned Reg) {
51 for (const MachineOperand &UseOp : MRI.reg_operands(Reg)) {
52 if (!UseOp.isImplicit() || !TII.isFLAT(*UseOp.getParent()))
53 return true;
54 }
55
56 return false;
57}
58
60 MachineFunction &MF) {
62 if (!TPC)
63 return false;
64
65 const auto &TM = TPC->getTM<GCNTargetMachine>();
66 const MCSubtargetInfo &STI = TM.getMCSubtargetInfo();
67
68 // By default, for code object v5 and later, track only the minimum scratch
69 // size
70 const AMDGPUOptions &CLOpts = TM.getCLOpts();
71 bool MinScratch = AMDGPU::getAMDHSACodeObjectVersion(
73 STI.getTargetTriple().getOS() == Triple::AMDPAL;
74 uint32_t AssumedStackSizeForDynamicSizeObjects =
75 CLOpts.assume_dynamic_stack_object_size.value_or(MinScratch ? 0 : 4096);
76 uint32_t AssumedStackSizeForExternalCall =
77 CLOpts.assume_external_call_stack_size.value_or(MinScratch ? 0 : 16384);
78
80 MF, AssumedStackSizeForDynamicSizeObjects,
81 AssumedStackSizeForExternalCall);
82
83 return false;
84}
85
86AnalysisKey AMDGPUResourceUsageAnalysis::Key;
90 const MCSubtargetInfo &STI = TM.getMCSubtargetInfo();
91
92 // By default, for code object v5 and later, track only the minimum scratch
93 // size
94 const AMDGPUOptions &CLOpts = TM.getCLOpts();
95 bool MinScratch = AMDGPU::getAMDHSACodeObjectVersion(
98 uint32_t AssumedStackSizeForDynamicSizeObjects =
99 CLOpts.assume_dynamic_stack_object_size.value_or(MinScratch ? 0 : 4096);
100 uint32_t AssumedStackSizeForExternalCall =
101 CLOpts.assume_external_call_stack_size.value_or(MinScratch ? 0 : 16384);
102
104 MF, AssumedStackSizeForDynamicSizeObjects,
105 AssumedStackSizeForExternalCall);
106}
107
110 const MachineFunction &MF, uint32_t AssumedStackSizeForDynamicSizeObjects,
111 uint32_t AssumedStackSizeForExternalCall) const {
113
115 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
116 const MachineFrameInfo &FrameInfo = MF.getFrameInfo();
117 const MachineRegisterInfo &MRI = MF.getRegInfo();
118 const SIInstrInfo *TII = ST.getInstrInfo();
119 const SIRegisterInfo &TRI = TII->getRegisterInfo();
120
121 Info.UsesFlatScratch = MRI.isPhysRegUsed(AMDGPU::FLAT_SCR_LO) ||
122 MRI.isPhysRegUsed(AMDGPU::FLAT_SCR_HI) ||
123 MRI.isLiveIn(MFI->getPreloadedReg(
125
126 Info.NumNamedBarrier = MFI->getNumNamedBarriers();
127
128 // Even if FLAT_SCRATCH is implicitly used, it has no effect if flat
129 // instructions aren't used to access the scratch buffer. Inline assembly may
130 // need it though.
131 //
132 // If we only have implicit uses of flat_scr on flat instructions, it is not
133 // really needed.
134 if (Info.UsesFlatScratch && !MFI->getUserSGPRInfo().hasFlatScratchInit() &&
135 (!hasAnyNonFlatUseOfReg(MRI, *TII, AMDGPU::FLAT_SCR) &&
136 !hasAnyNonFlatUseOfReg(MRI, *TII, AMDGPU::FLAT_SCR_LO) &&
137 !hasAnyNonFlatUseOfReg(MRI, *TII, AMDGPU::FLAT_SCR_HI))) {
138 Info.UsesFlatScratch = false;
139 }
140
141 Info.PrivateSegmentSize = FrameInfo.getStackSize();
142
143 // Assume a big number if there are any unknown sized objects.
144 Info.HasDynamicallySizedStack = FrameInfo.hasVarSizedObjects();
145 if (Info.HasDynamicallySizedStack)
146 Info.PrivateSegmentSize += AssumedStackSizeForDynamicSizeObjects;
147
148 if (MFI->isStackRealigned())
149 Info.PrivateSegmentSize += FrameInfo.getMaxAlign().value();
150
151 Info.UsesVCC =
152 MRI.isPhysRegUsed(AMDGPU::VCC_LO) || MRI.isPhysRegUsed(AMDGPU::VCC_HI);
153 Info.NumExplicitSGPR = TRI.getNumUsedPhysRegs(MRI, AMDGPU::SGPR_32RegClass,
154 /*IncludeCalls=*/false);
155 if (ST.hasMAIInsts())
156 Info.NumAGPR = TRI.getNumUsedPhysRegs(MRI, AMDGPU::AGPR_32RegClass,
157 /*IncludeCalls=*/false);
158
159 // If there are no calls, MachineRegisterInfo can tell us the used register
160 // count easily.
161 // A tail call isn't considered a call for MachineFrameInfo's purposes.
162 if (!FrameInfo.hasCalls() && !FrameInfo.hasTailCall()) {
163 Info.NumVGPR = TRI.getNumUsedPhysRegs(MRI, AMDGPU::VGPR_32RegClass,
164 /*IncludeCalls=*/false);
165 return Info;
166 }
167
168 int32_t MaxVGPR = -1;
169 Info.CalleeSegmentSize = 0;
170
171 for (const MachineBasicBlock &MBB : MF) {
172 for (const MachineInstr &MI : MBB) {
173 for (unsigned I = 0; I < MI.getNumOperands(); ++I) {
174 const MachineOperand &MO = MI.getOperand(I);
175
176 if (!MO.isReg())
177 continue;
178
179 Register Reg = MO.getReg();
180 switch (Reg) {
181 case AMDGPU::NoRegister:
182 assert(MI.isDebugInstr() &&
183 "Instruction uses invalid noreg register");
184 continue;
185
186 case AMDGPU::XNACK_MASK:
187 case AMDGPU::XNACK_MASK_LO:
188 case AMDGPU::XNACK_MASK_HI:
189 llvm_unreachable("xnack_mask registers should not be used");
190
191 case AMDGPU::LDS_DIRECT:
192 llvm_unreachable("lds_direct register should not be used");
193
194 case AMDGPU::TBA:
195 case AMDGPU::TBA_LO:
196 case AMDGPU::TBA_HI:
197 case AMDGPU::TMA:
198 case AMDGPU::TMA_LO:
199 case AMDGPU::TMA_HI:
200 llvm_unreachable("trap handler registers should not be used");
201
202 case AMDGPU::SRC_VCCZ:
203 llvm_unreachable("src_vccz register should not be used");
204
205 case AMDGPU::SRC_EXECZ:
206 llvm_unreachable("src_execz register should not be used");
207
208 case AMDGPU::SRC_SCC:
209 llvm_unreachable("src_scc register should not be used");
210
211 default:
212 break;
213 }
214
215 const TargetRegisterClass *RC = TRI.getPhysRegBaseClass(Reg);
216 assert((!RC || TRI.isVGPRClass(RC) || TRI.isSGPRClass(RC) ||
217 TRI.isAGPRClass(RC) || AMDGPU::TTMP_32RegClass.contains(Reg) ||
218 AMDGPU::TTMP_64RegClass.contains(Reg) ||
219 AMDGPU::TTMP_128RegClass.contains(Reg) ||
220 AMDGPU::TTMP_256RegClass.contains(Reg) ||
221 AMDGPU::TTMP_512RegClass.contains(Reg)) &&
222 "Unknown register class");
223
224 if (!RC || !TRI.isVGPRClass(RC))
225 continue;
226
227 if (MI.isCall() || MI.isMetaInstruction())
228 continue;
229
230 unsigned Width = divideCeil(TRI.getRegSizeInBits(*RC), 32);
231 unsigned HWReg = TRI.getHWRegIndex(Reg);
232 int MaxUsed = HWReg + Width - 1;
233 MaxVGPR = std::max(MaxUsed, MaxVGPR);
234 }
235
236 if (MI.isCall()) {
237 // Pseudo used just to encode the underlying global. Is there a better
238 // way to track this?
239
240 // TODO: Some of the generic call-like pseudos do not encode the callee,
241 // so we overly conservatively treat this as an indirect call.
242 const MachineOperand *CalleeOp =
243 TII->getNamedOperand(MI, AMDGPU::OpName::callee);
244
245 const Function *Callee =
246 CalleeOp ? getCalleeFunction(*CalleeOp) : nullptr;
247
248 auto isSameFunction = [](const MachineFunction &MF, const Function *F) {
249 return F == &MF.getFunction();
250 };
251
252 if (Callee && !isSameFunction(MF, Callee))
253 Info.Callees.push_back(Callee);
254
255 bool IsIndirect = !Callee || Callee->isDeclaration();
256 Info.HasIndirectCall |= IsIndirect;
257
258 bool IsChainCall = MI.getOpcode() == AMDGPU::SI_TCRETURN_CHAIN;
259 Info.HasNonChainIndirectCall |= (!IsChainCall && IsIndirect);
260
261 // In object linking mode the linker has the full cross-TU view. It
262 // propagates resource usage across both direct calls to external
263 // declarations and true indirect calls. Skip the compile-time
264 // conservative assumptions so that the locally emitted metadata
265 // describes this function's own usage only.
267 continue;
268
269 // FIXME: Call site could have norecurse on it
270 if (!Callee || !Callee->doesNotRecurse()) {
271 Info.HasRecursion = true;
272
273 // TODO: If we happen to know there is no stack usage in the
274 // callgraph, we don't need to assume an infinitely growing stack.
275 if (!MI.isReturn()) {
276 // We don't need to assume an unknown stack size for tail calls.
277
278 // FIXME: This only benefits in the case where the kernel does not
279 // directly call the tail called function. If a kernel directly
280 // calls a tail recursive function, we'll assume maximum stack size
281 // based on the regular call instruction.
282 Info.CalleeSegmentSize = std::max(
283 Info.CalleeSegmentSize,
284 static_cast<uint64_t>(AssumedStackSizeForExternalCall));
285 }
286 }
287
288 if (IsIndirect) {
289 Info.CalleeSegmentSize =
290 std::max(Info.CalleeSegmentSize,
291 static_cast<uint64_t>(AssumedStackSizeForExternalCall));
292
293 // Register usage of indirect calls gets handled later
294 Info.UsesVCC = true;
295 Info.UsesFlatScratch = ST.hasFlatAddressSpace();
296 Info.HasDynamicallySizedStack = true;
297 }
298 }
299 }
300 }
301
302 Info.NumVGPR = MaxVGPR + 1;
303
304 return Info;
305}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
static bool hasAnyNonFlatUseOfReg(const MachineRegisterInfo &MRI, const SIInstrInfo &TII, unsigned Reg)
Analyzes how many registers and other resources are used by functions.
The AMDGPU TargetMachine interface definition for hw codegen targets.
MachineBasicBlock & MBB
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
Register Reg
Register const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
MachineRegisterInfo & MRI
Target-Independent Code Generator Pass Configuration Options pass.
Result run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
AMDGPUResourceUsageAnalysisImpl::SIFunctionResourceInfo Result
Module * getParent()
Get the module that this global value is contained inside of...
Generic base class for all target subtargets.
const Triple & getTargetTriple() const
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
AnalysisType * getAnalysisIfAvailable() const
getAnalysisIfAvailable<AnalysisType>() - Subclasses use this function to get analysis information tha...
Wrapper class representing virtual and physical registers.
Definition Register.h:20
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
GCNUserSGPRUsageInfo & getUserSGPRInfo()
MCRegister getPreloadedReg(AMDGPUFunctionArgInfo::PreloadedValue Value) const
OSType getOS() const
Get the parsed operating system type of this triple.
Definition Triple.h:525
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned getAMDHSACodeObjectVersion(const Module &M)
This is an optimization pass for GlobalISel generic memory operations.
char & AMDGPUResourceUsageAnalysisID
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:389
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
SIFunctionResourceInfo analyzeResourceUsage(const MachineFunction &MF, uint32_t AssumedStackSizeForDynamicSizeObjects, uint32_t AssumedStackSizeForExternalCall) const
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition Analysis.h:29