xref: /llvm-project/llvm/lib/Target/AMDGPU/AMDGPUMCResourceInfo.cpp (revision 82944595fa5509fdbd574318e9041f2edab32e5f)
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 
15 #include "AMDGPUMCResourceInfo.h"
16 #include "Utils/AMDGPUBaseInfo.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/MC/MCAsmInfo.h"
19 #include "llvm/MC/MCContext.h"
20 #include "llvm/MC/MCSymbol.h"
21 #include "llvm/Target/TargetMachine.h"
22 
23 using namespace llvm;
24 
25 MCSymbol *MCResourceInfo::getSymbol(StringRef FuncName, ResourceInfoKind RIK,
26                                     MCContext &OutContext, bool IsLocal) {
27   auto GOCS = [FuncName, &OutContext, IsLocal](StringRef Suffix) {
28     StringRef Prefix =
29         IsLocal ? OutContext.getAsmInfo()->getPrivateGlobalPrefix() : "";
30     return OutContext.getOrCreateSymbol(Twine(Prefix) + FuncName +
31                                         Twine(Suffix));
32   };
33   switch (RIK) {
34   case RIK_NumVGPR:
35     return GOCS(".num_vgpr");
36   case RIK_NumAGPR:
37     return GOCS(".num_agpr");
38   case RIK_NumSGPR:
39     return GOCS(".numbered_sgpr");
40   case RIK_PrivateSegSize:
41     return GOCS(".private_seg_size");
42   case RIK_UsesVCC:
43     return GOCS(".uses_vcc");
44   case RIK_UsesFlatScratch:
45     return GOCS(".uses_flat_scratch");
46   case RIK_HasDynSizedStack:
47     return GOCS(".has_dyn_sized_stack");
48   case RIK_HasRecursion:
49     return GOCS(".has_recursion");
50   case RIK_HasIndirectCall:
51     return GOCS(".has_indirect_call");
52   }
53   llvm_unreachable("Unexpected ResourceInfoKind.");
54 }
55 
56 const MCExpr *MCResourceInfo::getSymRefExpr(StringRef FuncName,
57                                             ResourceInfoKind RIK,
58                                             MCContext &Ctx, bool IsLocal) {
59   return MCSymbolRefExpr::create(getSymbol(FuncName, RIK, Ctx, IsLocal), Ctx);
60 }
61 
62 void MCResourceInfo::assignMaxRegs(MCContext &OutContext) {
63   // Assign expression to get the max register use to the max_num_Xgpr symbol.
64   MCSymbol *MaxVGPRSym = getMaxVGPRSymbol(OutContext);
65   MCSymbol *MaxAGPRSym = getMaxAGPRSymbol(OutContext);
66   MCSymbol *MaxSGPRSym = getMaxSGPRSymbol(OutContext);
67 
68   auto assignMaxRegSym = [&OutContext](MCSymbol *Sym, int32_t RegCount) {
69     const MCExpr *MaxExpr = MCConstantExpr::create(RegCount, OutContext);
70     Sym->setVariableValue(MaxExpr);
71   };
72 
73   assignMaxRegSym(MaxVGPRSym, MaxVGPR);
74   assignMaxRegSym(MaxAGPRSym, MaxAGPR);
75   assignMaxRegSym(MaxSGPRSym, MaxSGPR);
76 }
77 
78 void MCResourceInfo::reset() { *this = MCResourceInfo(); }
79 
80 void MCResourceInfo::finalize(MCContext &OutContext) {
81   assert(!Finalized && "Cannot finalize ResourceInfo again.");
82   Finalized = true;
83   assignMaxRegs(OutContext);
84 }
85 
86 MCSymbol *MCResourceInfo::getMaxVGPRSymbol(MCContext &OutContext) {
87   return OutContext.getOrCreateSymbol("amdgpu.max_num_vgpr");
88 }
89 
90 MCSymbol *MCResourceInfo::getMaxAGPRSymbol(MCContext &OutContext) {
91   return OutContext.getOrCreateSymbol("amdgpu.max_num_agpr");
92 }
93 
94 MCSymbol *MCResourceInfo::getMaxSGPRSymbol(MCContext &OutContext) {
95   return OutContext.getOrCreateSymbol("amdgpu.max_num_sgpr");
96 }
97 
98 void MCResourceInfo::assignResourceInfoExpr(
99     int64_t LocalValue, ResourceInfoKind RIK, AMDGPUMCExpr::VariantKind Kind,
100     const MachineFunction &MF, const SmallVectorImpl<const Function *> &Callees,
101     MCContext &OutContext) {
102   const TargetMachine &TM = MF.getTarget();
103   bool IsLocal = MF.getFunction().hasLocalLinkage();
104   MCSymbol *FnSym = TM.getSymbol(&MF.getFunction());
105   const MCConstantExpr *LocalConstExpr =
106       MCConstantExpr::create(LocalValue, OutContext);
107   const MCExpr *SymVal = LocalConstExpr;
108   MCSymbol *Sym = getSymbol(FnSym->getName(), RIK, OutContext, IsLocal);
109   if (!Callees.empty()) {
110     SmallVector<const MCExpr *, 8> ArgExprs;
111     SmallPtrSet<const Function *, 8> Seen;
112     ArgExprs.push_back(LocalConstExpr);
113 
114     for (const Function *Callee : Callees) {
115       if (!Seen.insert(Callee).second)
116         continue;
117 
118       bool IsCalleeLocal = Callee->hasLocalLinkage();
119       MCSymbol *CalleeFnSym = TM.getSymbol(&Callee->getFunction());
120       MCSymbol *CalleeValSym =
121           getSymbol(CalleeFnSym->getName(), RIK, OutContext, IsCalleeLocal);
122 
123       // Avoid constructing recursive definitions by detecting whether `Sym` is
124       // found transitively within any of its `CalleeValSym`.
125       if (!CalleeValSym->isVariable() ||
126           !CalleeValSym->getVariableValue(/*isUsed=*/false)
127                ->isSymbolUsedInExpression(Sym)) {
128         ArgExprs.push_back(MCSymbolRefExpr::create(CalleeValSym, OutContext));
129       } else {
130         // In case of recursion: make sure to use conservative register counts
131         // (i.e., specifically for VGPR/SGPR/AGPR).
132         switch (RIK) {
133         default:
134           break;
135         case RIK_NumVGPR:
136           ArgExprs.push_back(MCSymbolRefExpr::create(
137               getMaxVGPRSymbol(OutContext), OutContext));
138           break;
139         case RIK_NumSGPR:
140           ArgExprs.push_back(MCSymbolRefExpr::create(
141               getMaxSGPRSymbol(OutContext), OutContext));
142           break;
143         case RIK_NumAGPR:
144           ArgExprs.push_back(MCSymbolRefExpr::create(
145               getMaxAGPRSymbol(OutContext), OutContext));
146           break;
147         }
148       }
149     }
150     if (ArgExprs.size() > 1)
151       SymVal = AMDGPUMCExpr::create(Kind, ArgExprs, OutContext);
152   }
153   Sym->setVariableValue(SymVal);
154 }
155 
156 void MCResourceInfo::gatherResourceInfo(
157     const MachineFunction &MF,
158     const AMDGPUResourceUsageAnalysis::SIFunctionResourceInfo &FRI,
159     MCContext &OutContext) {
160   // Worst case VGPR use for non-hardware-entrypoints.
161   MCSymbol *MaxVGPRSym = getMaxVGPRSymbol(OutContext);
162   MCSymbol *MaxAGPRSym = getMaxAGPRSymbol(OutContext);
163   MCSymbol *MaxSGPRSym = getMaxSGPRSymbol(OutContext);
164   bool IsLocal = MF.getFunction().hasLocalLinkage();
165 
166   if (!AMDGPU::isEntryFunctionCC(MF.getFunction().getCallingConv())) {
167     addMaxVGPRCandidate(FRI.NumVGPR);
168     addMaxAGPRCandidate(FRI.NumAGPR);
169     addMaxSGPRCandidate(FRI.NumExplicitSGPR);
170   }
171 
172   const TargetMachine &TM = MF.getTarget();
173   MCSymbol *FnSym = TM.getSymbol(&MF.getFunction());
174 
175   auto SetMaxReg = [&](MCSymbol *MaxSym, int32_t numRegs,
176                        ResourceInfoKind RIK) {
177     if (!FRI.HasIndirectCall) {
178       assignResourceInfoExpr(numRegs, RIK, AMDGPUMCExpr::AGVK_Max, MF,
179                              FRI.Callees, OutContext);
180     } else {
181       const MCExpr *SymRef = MCSymbolRefExpr::create(MaxSym, OutContext);
182       MCSymbol *LocalNumSym =
183           getSymbol(FnSym->getName(), RIK, OutContext, IsLocal);
184       const MCExpr *MaxWithLocal = AMDGPUMCExpr::createMax(
185           {MCConstantExpr::create(numRegs, OutContext), SymRef}, OutContext);
186       LocalNumSym->setVariableValue(MaxWithLocal);
187     }
188   };
189 
190   SetMaxReg(MaxVGPRSym, FRI.NumVGPR, RIK_NumVGPR);
191   SetMaxReg(MaxAGPRSym, FRI.NumAGPR, RIK_NumAGPR);
192   SetMaxReg(MaxSGPRSym, FRI.NumExplicitSGPR, RIK_NumSGPR);
193 
194   {
195     // The expression for private segment size should be: FRI.PrivateSegmentSize
196     // + max(FRI.Callees, FRI.CalleeSegmentSize)
197     SmallVector<const MCExpr *, 8> ArgExprs;
198     MCSymbol *Sym =
199         getSymbol(FnSym->getName(), RIK_PrivateSegSize, OutContext, IsLocal);
200     if (FRI.CalleeSegmentSize)
201       ArgExprs.push_back(
202           MCConstantExpr::create(FRI.CalleeSegmentSize, OutContext));
203 
204     SmallPtrSet<const Function *, 8> Seen;
205     Seen.insert(&MF.getFunction());
206     for (const Function *Callee : FRI.Callees) {
207       if (!Seen.insert(Callee).second)
208         continue;
209       if (!Callee->isDeclaration()) {
210         bool IsCalleeLocal = Callee->hasLocalLinkage();
211         MCSymbol *CalleeFnSym = TM.getSymbol(&Callee->getFunction());
212         MCSymbol *CalleeValSym =
213             getSymbol(CalleeFnSym->getName(), RIK_PrivateSegSize, OutContext,
214                       IsCalleeLocal);
215 
216         // Avoid constructing recursive definitions by detecting whether `Sym`
217         // is found transitively within any of its `CalleeValSym`.
218         if (!CalleeValSym->isVariable() ||
219             !CalleeValSym->getVariableValue(/*isUsed=*/false)
220                  ->isSymbolUsedInExpression(Sym)) {
221           ArgExprs.push_back(MCSymbolRefExpr::create(CalleeValSym, OutContext));
222         }
223       }
224     }
225     const MCExpr *localConstExpr =
226         MCConstantExpr::create(FRI.PrivateSegmentSize, OutContext);
227     if (!ArgExprs.empty()) {
228       const AMDGPUMCExpr *transitiveExpr =
229           AMDGPUMCExpr::createMax(ArgExprs, OutContext);
230       localConstExpr =
231           MCBinaryExpr::createAdd(localConstExpr, transitiveExpr, OutContext);
232     }
233     Sym->setVariableValue(localConstExpr);
234   }
235 
236   auto SetToLocal = [&](int64_t LocalValue, ResourceInfoKind RIK) {
237     MCSymbol *Sym = getSymbol(FnSym->getName(), RIK, OutContext, IsLocal);
238     Sym->setVariableValue(MCConstantExpr::create(LocalValue, OutContext));
239   };
240 
241   if (!FRI.HasIndirectCall) {
242     assignResourceInfoExpr(FRI.UsesVCC, ResourceInfoKind::RIK_UsesVCC,
243                            AMDGPUMCExpr::AGVK_Or, MF, FRI.Callees, OutContext);
244     assignResourceInfoExpr(FRI.UsesFlatScratch,
245                            ResourceInfoKind::RIK_UsesFlatScratch,
246                            AMDGPUMCExpr::AGVK_Or, MF, FRI.Callees, OutContext);
247     assignResourceInfoExpr(FRI.HasDynamicallySizedStack,
248                            ResourceInfoKind::RIK_HasDynSizedStack,
249                            AMDGPUMCExpr::AGVK_Or, MF, FRI.Callees, OutContext);
250     assignResourceInfoExpr(FRI.HasRecursion, ResourceInfoKind::RIK_HasRecursion,
251                            AMDGPUMCExpr::AGVK_Or, MF, FRI.Callees, OutContext);
252     assignResourceInfoExpr(FRI.HasIndirectCall,
253                            ResourceInfoKind::RIK_HasIndirectCall,
254                            AMDGPUMCExpr::AGVK_Or, MF, FRI.Callees, OutContext);
255   } else {
256     SetToLocal(FRI.UsesVCC, ResourceInfoKind::RIK_UsesVCC);
257     SetToLocal(FRI.UsesFlatScratch, ResourceInfoKind::RIK_UsesFlatScratch);
258     SetToLocal(FRI.HasDynamicallySizedStack,
259                ResourceInfoKind::RIK_HasDynSizedStack);
260     SetToLocal(FRI.HasRecursion, ResourceInfoKind::RIK_HasRecursion);
261     SetToLocal(FRI.HasIndirectCall, ResourceInfoKind::RIK_HasIndirectCall);
262   }
263 }
264 
265 const MCExpr *MCResourceInfo::createTotalNumVGPRs(const MachineFunction &MF,
266                                                   MCContext &Ctx) {
267   const TargetMachine &TM = MF.getTarget();
268   MCSymbol *FnSym = TM.getSymbol(&MF.getFunction());
269   bool IsLocal = MF.getFunction().hasLocalLinkage();
270   return AMDGPUMCExpr::createTotalNumVGPR(
271       getSymRefExpr(FnSym->getName(), RIK_NumAGPR, Ctx, IsLocal),
272       getSymRefExpr(FnSym->getName(), RIK_NumVGPR, Ctx, IsLocal), Ctx);
273 }
274 
275 const MCExpr *MCResourceInfo::createTotalNumSGPRs(const MachineFunction &MF,
276                                                   bool hasXnack,
277                                                   MCContext &Ctx) {
278   const TargetMachine &TM = MF.getTarget();
279   MCSymbol *FnSym = TM.getSymbol(&MF.getFunction());
280   bool IsLocal = MF.getFunction().hasLocalLinkage();
281   return MCBinaryExpr::createAdd(
282       getSymRefExpr(FnSym->getName(), RIK_NumSGPR, Ctx, IsLocal),
283       AMDGPUMCExpr::createExtraSGPRs(
284           getSymRefExpr(FnSym->getName(), RIK_UsesVCC, Ctx, IsLocal),
285           getSymRefExpr(FnSym->getName(), RIK_UsesFlatScratch, Ctx, IsLocal),
286           hasXnack, Ctx),
287       Ctx);
288 }
289