1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
/*========================== begin_copyright_notice ============================
Copyright (C) 2023 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
#include "IGCLivenessAnalysis.h"
char IGCFunctionExternalRegPressureAnalysis::ID = 0;
// Register pass to igc-opt
#define PASS_FLAG2 "igc-external-pressure-analysis"
#define PASS_DESCRIPTION2 \
"computes full dataflow liveness analysis & and register pressure " \
"estimator"
#define PASS_CFG_ONLY2 false
#define PASS_ANALYSIS2 true
IGC_INITIALIZE_PASS_BEGIN(IGCFunctionExternalRegPressureAnalysis, PASS_FLAG2, PASS_DESCRIPTION2,
PASS_CFG_ONLY2, PASS_ANALYSIS2)
IGC_INITIALIZE_PASS_DEPENDENCY(CodeGenContextWrapper)
IGC_INITIALIZE_PASS_DEPENDENCY(MetaDataUtilsWrapper)
IGC_INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
IGC_INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
IGC_INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
IGC_INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
IGC_INITIALIZE_PASS_END(IGCFunctionExternalRegPressureAnalysis, PASS_FLAG2, PASS_DESCRIPTION2,
PASS_CFG_ONLY2, PASS_ANALYSIS2)
#define PRINT(str) llvm::errs() << str
IGCFunctionExternalRegPressureAnalysis::IGCFunctionExternalRegPressureAnalysis() : ModulePass(ID) {
initializeIGCFunctionExternalRegPressureAnalysisPass(*PassRegistry::getPassRegistry());
};
std::unique_ptr<WIAnalysisRunner> IGCFunctionExternalRegPressureAnalysis::runWIAnalysis(Function &F) {
TranslationTable TT;
TT.run(F);
auto *DT = &getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
auto *PDT = &getAnalysis<PostDominatorTreeWrapperPass>(F).getPostDomTree();
auto *LI = &getAnalysis<LoopInfoWrapperPass>(F).getLoopInfo();
auto WI = std::make_unique<WIAnalysisRunner>(&F, LI, DT, PDT, MDUtils, CGCtx, ModMD, &TT);
WI->run();
return WI;
}
void IGCFunctionExternalRegPressureAnalysis::generateTableOfPressure(llvm::Module &M) {
// basic preprocessing, scan all of the functions,
// collect callsite pressure for eash callsite
for (auto &F : M) {
if(F.isDeclaration()) continue;
unsigned int SIMD = numLanes(bestGuessSIMDSize(&F));
livenessAnalysis(F);
std::unique_ptr<WIAnalysisRunner> WI = runWIAnalysis(F);
for (auto &BB : F) {
std::unique_ptr<InsideBlockPressureMap> PressureMap;
for (auto &I : BB) {
auto *Call = llvm::dyn_cast<CallInst>(&I);
if (!Call) continue;
if (Call->getCallingConv() != CallingConv::SPIR_FUNC) continue;
if (!SetOfDefinitions.count(Call->getCalledFunction())) continue;
if(!PressureMap)
PressureMap = getPressureMapForBB(BB, SIMD, *WI);
CallSitePressure[Call] = (*PressureMap)[&I];
}
}
}
llvm::SmallVector<llvm::Function *, 16> PostOrder;
CallGraph& CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
auto ExtNode = CG.getExternalCallingNode();
for (auto I = po_begin(ExtNode), E = po_end(ExtNode); I != E; ++I) {
auto CGNode = *I;
if (auto F = CGNode->getFunction()) {
if (F->isDeclaration())
continue;
// Ignore externally linked functions and stackcall functions
if (F->hasFnAttribute("referenced-indirectly") ||
F->hasFnAttribute("invoke_simd_target") ||
F->hasFnAttribute("hasRecursion") ||
F->hasFnAttribute("visaStackCall"))
continue;
PostOrder.push_back(F);
}
}
// now it's REVERSE POST ORDER
// we will use it to process external pressure for a function
std::reverse(PostOrder.begin(), PostOrder.end());
for (auto El : PostOrder) {
unsigned int MaxPressure = 0;
// top level functions won't go inside this cycle
// noone is calling them
for (auto U : El->users()) {
CallInst *Callsite = llvm::dyn_cast<CallInst>(U);
if(!Callsite) continue;
// at this point, because we process in a specific order, every function
// that could potentially call our function, should be processed already
// and we know its external pressure, for a top level function it will be 0
// and we will process them first
unsigned int ExternalPressure = CallSitePressure[Callsite] + ExternalFunctionPressure[Callsite->getFunction()];
MaxPressure = std::max(MaxPressure, ExternalPressure);
}
ExternalFunctionPressure[El] = MaxPressure;
}
}
bool IGCFunctionExternalRegPressureAnalysis::runOnModule(llvm::Module &M) {
FGA = getAnalysisIfAvailable<GenXFunctionGroupAnalysis>();
CGCtx = getAnalysis<CodeGenContextWrapper>().getCodeGenContext();
MDUtils = getAnalysis<MetaDataUtilsWrapper>().getMetaDataUtils();
ModMD = getAnalysis<MetaDataUtilsWrapper>().getModuleMetaData();
// simple check, we take every definition that we have in our module
// and remember it, later we will check, if we have no calls to those
// definitions, we don't have to compute external pressure
for (auto &F : M) {
if(F.isDeclaration()) continue;
if(F.getCallingConv() != CallingConv::SPIR_FUNC) continue;
SetOfDefinitions.insert(&F);
}
if(!SetOfDefinitions.size())
return false;
generateTableOfPressure(M);
return true;
}
|