1 /*========================== begin_copyright_notice ============================
2
3 Copyright (C) 2017-2021 Intel Corporation
4
5 SPDX-License-Identifier: MIT
6
7 ============================= end_copyright_notice ===========================*/
8
9 #include "Compiler/CodeGenPublic.h"
10 #include "Compiler/CISACodeGen/PassTimer.hpp"
11 #include "Compiler/CISACodeGen/TimeStatsCounter.h"
12 #include "common/Stats.hpp"
13 #include "common/debug/Dump.hpp"
14 #include "common/shaderOverride.hpp"
15 #include "common/IntrinsicAnnotator.hpp"
16 #include "common/LLVMUtils.h"
17
18 #include "common/LLVMWarningsPush.hpp"
19 #include <llvm/IRReader/IRReader.h>
20 #include <llvm/Support/SourceMgr.h>
21 #include <llvmWrapper/ADT/StringRef.h>
22 #include "common/LLVMWarningsPop.hpp"
23
24 using namespace IGC;
25 using namespace IGC::Debug;
26 using namespace llvm;
27
getPassToggles(std::bitset<1024> & toggles)28 bool getPassToggles(std::bitset<1024>& toggles)
29 {
30 const char* passToggles = IGC_GET_REGKEYSTRING(DisablePassToggles);
31 if (passToggles != nullptr && strlen(passToggles) > 0)
32 {
33 std::string szBin;
34 std::string szHexLL;
35 unsigned int len = 0;
36 unsigned long long x = 0;
37 std::string szHex = passToggles;
38 for (size_t i = 0; i < szHex.size(); i += 16)
39 {
40 szHexLL = szHex.substr(i, 16);
41 len = szHexLL.size() * 4;
42 x = std::stoull(szHexLL, nullptr, 16);
43 szBin += std::bitset<64>(x).to_string().substr(64 - len, len);
44 }
45
46 toggles = std::bitset<1024>(szBin);
47 return true;
48 }
49
50 return false;
51 }
52
createFlushPass(llvm::Pass * pass,Dump & dump)53 llvm::Pass* createFlushPass(llvm::Pass* pass, Dump& dump)
54 {
55 // Choose an appropriate pass to preserve the original order of pass execution in the pass manager
56 switch (pass->getPassKind())
57 {
58 case PT_Function:
59 return new FunctionFlushDumpPass(dump);
60 case PT_Module:
61 return new ModuleFlushDumpPass(dump);
62 case PT_Region:
63 case PT_Loop:
64 case PT_CallGraphSCC:
65 // flushing for analysis passes is not required
66 break;
67 case PT_PassManager:
68 default:
69 // internal pass managers are not considered in the context
70 break;
71 }
72 return nullptr;
73 }
74
add(Pass * P)75 void IGCPassManager::add(Pass *P)
76 {
77 //check only once
78 static bool checkedToggles = false;
79 static bool hasToggles = false;
80 static std::bitset<1024> toggles;
81 if (!checkedToggles)
82 {
83 checkedToggles = true;
84 hasToggles = getPassToggles(toggles);
85 }
86 if (hasToggles && m_pContext->m_numPasses < 1024 && toggles[m_pContext->m_numPasses])
87 {
88 errs() << "Skipping pass: '" << P->getPassName() << "\n";
89 m_pContext->m_numPasses++;
90 return;
91 }
92
93 if (IGC_IS_FLAG_ENABLED(ShaderDisableOptPassesAfter)
94 && m_pContext->m_numPasses > IGC_GET_FLAG_VALUE(ShaderDisableOptPassesAfter)
95 && m_name == "OPT") {
96 errs() << "Skipping optimization pass: '" << P->getPassName()
97 << "' (threshold: " << IGC_GET_FLAG_VALUE(ShaderDisableOptPassesAfter) << ").\n";
98 return;
99 }
100
101 if (isPrintBefore(P))
102 {
103 addPrintPass(P, true);
104 }
105
106 if (IGC_REGKEY_OR_FLAG_ENABLED(DumpTimeStatsPerPass, TIME_STATS_PER_PASS))
107 {
108 PassManager::add(createTimeStatsIGCPass(m_pContext, m_name + '_' + std::string(P->getPassName()), STATS_COUNTER_START));
109 }
110
111 PassManager::add(P);
112
113 if (IGC_REGKEY_OR_FLAG_ENABLED(DumpTimeStatsPerPass, TIME_STATS_PER_PASS))
114 {
115 PassManager::add(createTimeStatsIGCPass(m_pContext, m_name + '_' + std::string(P->getPassName()), STATS_COUNTER_END));
116 }
117
118 if (isPrintAfter(P))
119 {
120 addPrintPass(P, false);
121 }
122 }
123
124 // List: a comma/semicolon-separated list of pass names.
125 // N: a pass name
126 // return true if N is in List.
isInList(const StringRef & N,const StringRef & List) const127 bool IGCPassManager::isInList(const StringRef& N, const StringRef& List) const
128 {
129 StringRef Separators(",;");
130 size_t startPos = 0;
131 while (startPos != StringRef::npos)
132 {
133 size_t endPos = List.find_first_of(Separators, startPos);
134 size_t len = (endPos != StringRef::npos ? endPos - startPos : endPos);
135 StringRef Name = List.substr(startPos, len);
136 if (IGCLLVM::equals_insensitive(Name,N))
137 {
138 return true;
139 }
140 startPos = (endPos != StringRef::npos ? endPos + 1 : StringRef::npos);
141 }
142 return false;
143 }
144
isPrintBefore(Pass * P)145 bool IGCPassManager::isPrintBefore(Pass* P)
146 {
147 if (IGC_IS_FLAG_ENABLED(PrintBefore))
148 {
149 // PrintBefore=N0,N1,N2 : comma-separate list of pass names
150 // or pass command args registered in passInfo.
151 StringRef passNameList(IGC_GET_REGKEYSTRING(PrintBefore));
152 StringRef PN = P->getPassName();
153 if (IGCLLVM::equals_insensitive(passNameList, "all") || isInList(PN, passNameList))
154 return true;
155
156 // further check passInfo
157 if (const PassInfo* PI = Pass::lookupPassInfo(P->getPassID()))
158 {
159 return isInList(PI->getPassArgument(), passNameList);
160 }
161 }
162 return false;
163 }
164
isPrintAfter(Pass * P)165 bool IGCPassManager::isPrintAfter(Pass* P)
166 {
167 if (IGC_IS_FLAG_ENABLED(ShaderDumpEnableAll))
168 {
169 return true;
170 }
171 if (IGC_IS_FLAG_ENABLED(PrintAfter))
172 {
173 // PrintAfter=N0,N1,N2 : comma-separate list of pass names or
174 // or pass command args registered in passInfo.
175 StringRef passNameList(IGC_GET_REGKEYSTRING(PrintAfter));
176 StringRef PN = P->getPassName();
177 if (IGCLLVM::equals_insensitive(passNameList, "all") || isInList(PN, passNameList))
178 return true;
179
180 // further check passInfo
181 if (const PassInfo* PI = Pass::lookupPassInfo(P->getPassID()))
182 {
183 return isInList(PI->getPassArgument(), passNameList);
184 }
185 }
186 return false;
187 }
188
addPrintPass(Pass * P,bool isBefore)189 void IGCPassManager::addPrintPass(Pass* P, bool isBefore)
190 {
191 std::string passName =
192 m_name + (isBefore ? "_before_" : "_after_") + std::string(P->getPassName());
193 auto name =
194 IGC::Debug::DumpName(IGC::Debug::GetShaderOutputName())
195 .Type(m_pContext->type)
196 .Hash(m_pContext->hash)
197 .Pass(passName, m_pContext->m_numPasses++)
198 .StagedInfo(m_pContext)
199 .Extension("ll");
200
201 if (!name.allow())
202 return;
203
204 // The dump object needs to be on the Heap because it owns the stream, and the stream
205 // is taken by reference into the printer pass. If the Dump object had been on the
206 // stack, then that reference would go bad as soon as we exit this scope, and then
207 // the printer pass would access an invalid pointer later on when we call PassManager::run()
208 m_irDumps.emplace_front(name, IGC::Debug::DumpType::PASS_IR_TEXT);
209 PassManager::add(P->createPrinterPass(m_irDumps.front().stream(), ""));
210
211 llvm::Pass* flushPass = createFlushPass(P, m_irDumps.front());
212 if (nullptr != flushPass)
213 {
214 PassManager::add(flushPass);
215 }
216 }
217
DumpLLVMIR(IGC::CodeGenContext * pContext,const char * dumpName)218 void DumpLLVMIR(IGC::CodeGenContext* pContext, const char* dumpName)
219 {
220 SetCurrentDebugHash(pContext->hash.asmHash);
221
222 if (IGC_IS_FLAG_ENABLED(DumpLLVMIR))
223 {
224 pContext->getMetaDataUtils()->save(*pContext->getLLVMContext());
225 serialize(*(pContext->getModuleMetaData()), pContext->getModule());
226 using namespace IGC::Debug;
227 auto name =
228 DumpName(IGC::Debug::GetShaderOutputName())
229 .Hash(pContext->hash)
230 .Type(pContext->type)
231 .Pass(dumpName)
232 .Retry(pContext->m_retryManager.GetRetryId())
233 .Extension("ll");
234 auto new_annotator = IntrinsicAnnotator();
235 auto annotator = (pContext->annotater != nullptr) ? pContext->annotater : &new_annotator;
236 DumpLLVMIRText(
237 pContext->getModule(),
238 name,
239 annotator);
240 }
241 if (IGC_IS_FLAG_ENABLED(ShaderOverride))
242 {
243 auto name =
244 DumpName(IGC::Debug::GetShaderOutputName())
245 .Hash(pContext->hash)
246 .Type(pContext->type)
247 .Pass(dumpName)
248 .Extension("ll");
249 SMDiagnostic Err;
250 std::string fileName = name.overridePath();
251 FILE* fp = fopen(fileName.c_str(), "r");
252 if (fp != nullptr)
253 {
254 fclose(fp);
255 errs() << "Override shader: " << fileName << "\n";
256 Module* mod = parseIRFile(fileName, Err, *pContext->getLLVMContext()).release();
257 if (mod)
258 {
259 pContext->deleteModule();
260 pContext->setModule(mod);
261 deserialize(*(pContext->getModuleMetaData()), mod);
262 appendToShaderOverrideLogFile(fileName, "OVERRIDEN: ");
263 }
264 else
265 {
266 std::stringstream ss;
267 ss << "Parse IR failed.\n";
268 ss << Err.getLineNo() << ": "
269 << Err.getLineContents().str() << "\n"
270 << Err.getMessage().str() << "\n";
271
272 std::string str = ss.str();
273 errs() << str;
274 appendToShaderOverrideLogFile(fileName, str.c_str());
275 }
276 }
277 }
278 }
279