1 //===- AMDGPUMCResourceInfo.cpp --- MC Resource Info ----------------------===//
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
7 //===----------------------------------------------------------------------===//
10 /// \brief MC infrastructure to propagate the function level resource usage
13 //===----------------------------------------------------------------------===//
15 #include "AMDGPUMCResourceInfo.h"
16 #include "Utils/AMDGPUBaseInfo.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/MC/MCContext.h"
19 #include "llvm/MC/MCSymbol.h"
20 #include "llvm/Target/TargetMachine.h"
24 MCSymbol
*MCResourceInfo::getSymbol(StringRef FuncName
, ResourceInfoKind RIK
,
25 MCContext
&OutContext
) {
26 auto GOCS
= [FuncName
, &OutContext
](StringRef Suffix
) {
27 return OutContext
.getOrCreateSymbol(FuncName
+ Twine(Suffix
));
31 return GOCS(".num_vgpr");
33 return GOCS(".num_agpr");
35 return GOCS(".numbered_sgpr");
36 case RIK_PrivateSegSize
:
37 return GOCS(".private_seg_size");
39 return GOCS(".uses_vcc");
40 case RIK_UsesFlatScratch
:
41 return GOCS(".uses_flat_scratch");
42 case RIK_HasDynSizedStack
:
43 return GOCS(".has_dyn_sized_stack");
44 case RIK_HasRecursion
:
45 return GOCS(".has_recursion");
46 case RIK_HasIndirectCall
:
47 return GOCS(".has_indirect_call");
49 llvm_unreachable("Unexpected ResourceInfoKind.");
52 const MCExpr
*MCResourceInfo::getSymRefExpr(StringRef FuncName
,
55 return MCSymbolRefExpr::create(getSymbol(FuncName
, RIK
, Ctx
), Ctx
);
58 void MCResourceInfo::assignMaxRegs(MCContext
&OutContext
) {
59 // Assign expression to get the max register use to the max_num_Xgpr symbol.
60 MCSymbol
*MaxVGPRSym
= getMaxVGPRSymbol(OutContext
);
61 MCSymbol
*MaxAGPRSym
= getMaxAGPRSymbol(OutContext
);
62 MCSymbol
*MaxSGPRSym
= getMaxSGPRSymbol(OutContext
);
64 auto assignMaxRegSym
= [&OutContext
](MCSymbol
*Sym
, int32_t RegCount
) {
65 const MCExpr
*MaxExpr
= MCConstantExpr::create(RegCount
, OutContext
);
66 Sym
->setVariableValue(MaxExpr
);
69 assignMaxRegSym(MaxVGPRSym
, MaxVGPR
);
70 assignMaxRegSym(MaxAGPRSym
, MaxAGPR
);
71 assignMaxRegSym(MaxSGPRSym
, MaxSGPR
);
74 void MCResourceInfo::reset() { *this = MCResourceInfo(); }
76 void MCResourceInfo::finalize(MCContext
&OutContext
) {
77 assert(!Finalized
&& "Cannot finalize ResourceInfo again.");
79 assignMaxRegs(OutContext
);
82 MCSymbol
*MCResourceInfo::getMaxVGPRSymbol(MCContext
&OutContext
) {
83 return OutContext
.getOrCreateSymbol("amdgpu.max_num_vgpr");
86 MCSymbol
*MCResourceInfo::getMaxAGPRSymbol(MCContext
&OutContext
) {
87 return OutContext
.getOrCreateSymbol("amdgpu.max_num_agpr");
90 MCSymbol
*MCResourceInfo::getMaxSGPRSymbol(MCContext
&OutContext
) {
91 return OutContext
.getOrCreateSymbol("amdgpu.max_num_sgpr");
94 void MCResourceInfo::assignResourceInfoExpr(
95 int64_t LocalValue
, ResourceInfoKind RIK
, AMDGPUMCExpr::VariantKind Kind
,
96 const MachineFunction
&MF
, const SmallVectorImpl
<const Function
*> &Callees
,
97 MCContext
&OutContext
) {
98 const TargetMachine
&TM
= MF
.getTarget();
99 MCSymbol
*FnSym
= TM
.getSymbol(&MF
.getFunction());
100 const MCConstantExpr
*LocalConstExpr
=
101 MCConstantExpr::create(LocalValue
, OutContext
);
102 const MCExpr
*SymVal
= LocalConstExpr
;
103 MCSymbol
*Sym
= getSymbol(FnSym
->getName(), RIK
, OutContext
);
104 if (!Callees
.empty()) {
105 SmallVector
<const MCExpr
*, 8> ArgExprs
;
106 SmallPtrSet
<const Function
*, 8> Seen
;
107 ArgExprs
.push_back(LocalConstExpr
);
109 for (const Function
*Callee
: Callees
) {
110 if (!Seen
.insert(Callee
).second
)
113 MCSymbol
*CalleeFnSym
= TM
.getSymbol(&Callee
->getFunction());
114 MCSymbol
*CalleeValSym
=
115 getSymbol(CalleeFnSym
->getName(), RIK
, OutContext
);
117 // Avoid constructing recursive definitions by detecting whether `Sym` is
118 // found transitively within any of its `CalleeValSym`.
119 if (!CalleeValSym
->isVariable() ||
120 !CalleeValSym
->getVariableValue(/*isUsed=*/false)
121 ->isSymbolUsedInExpression(Sym
)) {
122 ArgExprs
.push_back(MCSymbolRefExpr::create(CalleeValSym
, OutContext
));
124 // In case of recursion: make sure to use conservative register counts
125 // (i.e., specifically for VGPR/SGPR/AGPR).
130 ArgExprs
.push_back(MCSymbolRefExpr::create(
131 getMaxVGPRSymbol(OutContext
), OutContext
));
134 ArgExprs
.push_back(MCSymbolRefExpr::create(
135 getMaxSGPRSymbol(OutContext
), OutContext
));
138 ArgExprs
.push_back(MCSymbolRefExpr::create(
139 getMaxAGPRSymbol(OutContext
), OutContext
));
144 if (ArgExprs
.size() > 1)
145 SymVal
= AMDGPUMCExpr::create(Kind
, ArgExprs
, OutContext
);
147 Sym
->setVariableValue(SymVal
);
150 void MCResourceInfo::gatherResourceInfo(
151 const MachineFunction
&MF
,
152 const AMDGPUResourceUsageAnalysis::SIFunctionResourceInfo
&FRI
,
153 MCContext
&OutContext
) {
154 // Worst case VGPR use for non-hardware-entrypoints.
155 MCSymbol
*MaxVGPRSym
= getMaxVGPRSymbol(OutContext
);
156 MCSymbol
*MaxAGPRSym
= getMaxAGPRSymbol(OutContext
);
157 MCSymbol
*MaxSGPRSym
= getMaxSGPRSymbol(OutContext
);
159 if (!AMDGPU::isEntryFunctionCC(MF
.getFunction().getCallingConv())) {
160 addMaxVGPRCandidate(FRI
.NumVGPR
);
161 addMaxAGPRCandidate(FRI
.NumAGPR
);
162 addMaxSGPRCandidate(FRI
.NumExplicitSGPR
);
165 const TargetMachine
&TM
= MF
.getTarget();
166 MCSymbol
*FnSym
= TM
.getSymbol(&MF
.getFunction());
168 auto SetMaxReg
= [&](MCSymbol
*MaxSym
, int32_t numRegs
,
169 ResourceInfoKind RIK
) {
170 if (!FRI
.HasIndirectCall
) {
171 assignResourceInfoExpr(numRegs
, RIK
, AMDGPUMCExpr::AGVK_Max
, MF
,
172 FRI
.Callees
, OutContext
);
174 const MCExpr
*SymRef
= MCSymbolRefExpr::create(MaxSym
, OutContext
);
175 MCSymbol
*LocalNumSym
= getSymbol(FnSym
->getName(), RIK
, OutContext
);
176 const MCExpr
*MaxWithLocal
= AMDGPUMCExpr::createMax(
177 {MCConstantExpr::create(numRegs
, OutContext
), SymRef
}, OutContext
);
178 LocalNumSym
->setVariableValue(MaxWithLocal
);
182 SetMaxReg(MaxVGPRSym
, FRI
.NumVGPR
, RIK_NumVGPR
);
183 SetMaxReg(MaxAGPRSym
, FRI
.NumAGPR
, RIK_NumAGPR
);
184 SetMaxReg(MaxSGPRSym
, FRI
.NumExplicitSGPR
, RIK_NumSGPR
);
187 // The expression for private segment size should be: FRI.PrivateSegmentSize
188 // + max(FRI.Callees, FRI.CalleeSegmentSize)
189 SmallVector
<const MCExpr
*, 8> ArgExprs
;
190 MCSymbol
*Sym
= getSymbol(FnSym
->getName(), RIK_PrivateSegSize
, OutContext
);
191 if (FRI
.CalleeSegmentSize
)
193 MCConstantExpr::create(FRI
.CalleeSegmentSize
, OutContext
));
195 SmallPtrSet
<const Function
*, 8> Seen
;
196 Seen
.insert(&MF
.getFunction());
197 for (const Function
*Callee
: FRI
.Callees
) {
198 if (!Seen
.insert(Callee
).second
)
200 if (!Callee
->isDeclaration()) {
201 MCSymbol
*CalleeFnSym
= TM
.getSymbol(&Callee
->getFunction());
202 MCSymbol
*CalleeValSym
=
203 getSymbol(CalleeFnSym
->getName(), RIK_PrivateSegSize
, OutContext
);
205 // Avoid constructing recursive definitions by detecting whether `Sym`
206 // is found transitively within any of its `CalleeValSym`.
207 if (!CalleeValSym
->isVariable() ||
208 !CalleeValSym
->getVariableValue(/*isUsed=*/false)
209 ->isSymbolUsedInExpression(Sym
)) {
210 ArgExprs
.push_back(MCSymbolRefExpr::create(CalleeValSym
, OutContext
));
214 const MCExpr
*localConstExpr
=
215 MCConstantExpr::create(FRI
.PrivateSegmentSize
, OutContext
);
216 if (!ArgExprs
.empty()) {
217 const AMDGPUMCExpr
*transitiveExpr
=
218 AMDGPUMCExpr::createMax(ArgExprs
, OutContext
);
220 MCBinaryExpr::createAdd(localConstExpr
, transitiveExpr
, OutContext
);
222 Sym
->setVariableValue(localConstExpr
);
225 auto SetToLocal
= [&](int64_t LocalValue
, ResourceInfoKind RIK
) {
226 MCSymbol
*Sym
= getSymbol(FnSym
->getName(), RIK
, OutContext
);
227 Sym
->setVariableValue(MCConstantExpr::create(LocalValue
, OutContext
));
230 if (!FRI
.HasIndirectCall
) {
231 assignResourceInfoExpr(FRI
.UsesVCC
, ResourceInfoKind::RIK_UsesVCC
,
232 AMDGPUMCExpr::AGVK_Or
, MF
, FRI
.Callees
, OutContext
);
233 assignResourceInfoExpr(FRI
.UsesFlatScratch
,
234 ResourceInfoKind::RIK_UsesFlatScratch
,
235 AMDGPUMCExpr::AGVK_Or
, MF
, FRI
.Callees
, OutContext
);
236 assignResourceInfoExpr(FRI
.HasDynamicallySizedStack
,
237 ResourceInfoKind::RIK_HasDynSizedStack
,
238 AMDGPUMCExpr::AGVK_Or
, MF
, FRI
.Callees
, OutContext
);
239 assignResourceInfoExpr(FRI
.HasRecursion
, ResourceInfoKind::RIK_HasRecursion
,
240 AMDGPUMCExpr::AGVK_Or
, MF
, FRI
.Callees
, OutContext
);
241 assignResourceInfoExpr(FRI
.HasIndirectCall
,
242 ResourceInfoKind::RIK_HasIndirectCall
,
243 AMDGPUMCExpr::AGVK_Or
, MF
, FRI
.Callees
, OutContext
);
245 SetToLocal(FRI
.UsesVCC
, ResourceInfoKind::RIK_UsesVCC
);
246 SetToLocal(FRI
.UsesFlatScratch
, ResourceInfoKind::RIK_UsesFlatScratch
);
247 SetToLocal(FRI
.HasDynamicallySizedStack
,
248 ResourceInfoKind::RIK_HasDynSizedStack
);
249 SetToLocal(FRI
.HasRecursion
, ResourceInfoKind::RIK_HasRecursion
);
250 SetToLocal(FRI
.HasIndirectCall
, ResourceInfoKind::RIK_HasIndirectCall
);
254 const MCExpr
*MCResourceInfo::createTotalNumVGPRs(const MachineFunction
&MF
,
256 const TargetMachine
&TM
= MF
.getTarget();
257 MCSymbol
*FnSym
= TM
.getSymbol(&MF
.getFunction());
258 return AMDGPUMCExpr::createTotalNumVGPR(
259 getSymRefExpr(FnSym
->getName(), RIK_NumAGPR
, Ctx
),
260 getSymRefExpr(FnSym
->getName(), RIK_NumVGPR
, Ctx
), Ctx
);
263 const MCExpr
*MCResourceInfo::createTotalNumSGPRs(const MachineFunction
&MF
,
266 const TargetMachine
&TM
= MF
.getTarget();
267 MCSymbol
*FnSym
= TM
.getSymbol(&MF
.getFunction());
268 return MCBinaryExpr::createAdd(
269 getSymRefExpr(FnSym
->getName(), RIK_NumSGPR
, Ctx
),
270 AMDGPUMCExpr::createExtraSGPRs(
271 getSymRefExpr(FnSym
->getName(), RIK_UsesVCC
, Ctx
),
272 getSymRefExpr(FnSym
->getName(), RIK_UsesFlatScratch
, Ctx
), hasXnack
,