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