1 /*========================== begin_copyright_notice ============================
2
3 Copyright (C) 2020-2021 Intel Corporation
4
5 SPDX-License-Identifier: MIT
6
7 ============================= end_copyright_notice ===========================*/
8
9 #include "FunctionGroup.h"
10
11 #include "GenXDebugInfo.h"
12 #include "GenXTargetMachine.h"
13 #include "GenXVisaRegAlloc.h"
14
15 #include "vc/GenXOpts/Utils/KernelInfo.h"
16 #include "vc/Support/BackendConfig.h"
17 #include "vc/Support/GenXDiagnostic.h"
18
19 #include "visa/include/visaBuilder_interface.h"
20
21 #include "DebugInfo/StreamEmitter.hpp"
22 #include "DebugInfo/VISAIDebugEmitter.hpp"
23 #include "DebugInfo/VISAModule.hpp"
24
25 #include <llvm/Analysis/CallGraph.h>
26 #include <llvm/CodeGen/TargetPassConfig.h>
27 #include <llvm/IR/DebugInfoMetadata.h>
28 #include <llvm/IR/Function.h>
29 #include <llvm/IR/Instruction.h>
30 #include <llvm/IR/IntrinsicInst.h>
31 #include <llvm/InitializePasses.h>
32 #include <llvm/Support/CommandLine.h>
33 #include <llvm/Support/Casting.h>
34 #include <llvm/Support/Errc.h>
35 #include <llvm/Support/Error.h>
36
37 #include "llvmWrapper/IR/DerivedTypes.h"
38
39 #include "Probe/Assertion.h"
40
41 #include <unordered_set>
42
43 //
44 /// GenXDebugInfo
45 /// -------------
46 ///
47 /// The goal of the pass is to provide debug information for each generated
48 /// genisa instruction (if such information is available). The debug
49 /// information is encoded in DWARF format.
50 ///
51 /// Ultimately, the pass gets data from 2 sources:
52 ///
53 /// 1. LLVM debug information encoded in LLVM IR itself. It captures the
54 /// important pieces of the source language's Abstract Syntax Tree and
55 /// maps it onto LLVM code.
56 /// LLVM framework should maintain it automatically, given that we follow
57 /// relatively simple rules while designing IR transformations:
58 /// https://llvm.org/docs/HowToUpdateDebugInfo.html
59 ///
60 /// 2. Debug information obtained from the finalizer. This information is
61 /// encoded in some proprietary format (blob) and contains the following:
62 /// a. mapping between vISA and genISA instructions
63 /// b. live intervals of the virtual registers, information about spilled
64 /// values, etc.
65 /// c. call frame information
66 ///
67 /// The pass feeds the above information to the DebugInfo library which in turn
68 /// produces the final DWARF.
69 ///
70 /// Operation of the pass
71 /// ^^^^^^^^^^^^^^^^^^^^^
72 ///
73 /// The pass assumes that some data is already being made available by other
74 /// passes/analysis.
75 ///
76 /// * FunctionGroupAnalysis:
77 /// provides information about the overall "structure"
78 /// of the program: functions, stack calls, indirect calls, subroutines and
79 /// relationships.
80 ///
81 /// * GenXModule:
82 /// 1. for each LLVM Function provides information about
83 /// LLVM instruction -> vISA instructions mapping. This information is
84 /// produced/maintained during operation of CISABuilder pass.
85 /// 2. for each LLVM Function provides access to a corresponding
86 /// *VISAKernel* object.
87 ///
88 /// * GenXVisaRegAlloc:
89 /// provides the mapping between LLVM values and virtual registers.
90 ///
91 /// * GenXCisaBuilder:
92 /// provides access to VISABuilder, which allows us to have access to
93 /// VISAKernel objects (some Functions from LLVM IR, like the ones
94 /// representing kernel spawns these) that contain:
95 /// a. debug information maintained by finalizer (see above)
96 /// b. the respected gen binaries
97 ///
98 /// Data Structures
99 /// ^^^^^^^^^^^^^^^
100 ///
101 /// Since data is aggregated from different sources, some extra data structures
102 /// are used to simplify bookkeeping.
103 ///
104 /// - *genx::di::VisaMapping*
105 /// provides the mapping from LLMV IR instruction to vISA instruction index,
106 /// that represents the first vISA instruction spawned by the LLVM IR
107 /// instruction. A single LLVM IR instruction can spawn several
108 /// vISA instructions - currently the number of spawned instructions is
109 /// derived implicitly (which is not always correct but works in most of the
110 /// cases).
111 ///
112 /// - *ModuleToVisaTransformInfo*
113 /// Provides information about how LLVM IR functions are mapped onto various
114 /// vISA (and genISA) objects. Allows us to answer the following questions:
115 /// - Is a function a subroutine on vISA level?
116 /// - If a function is a subroutine, what LLVM IR function corresponds to
117 /// vISA-level "owner" of this subroutine. An "owner" in this case is
118 /// either VISAFunction or VISAKernel containing the subroutine.
119 /// - Is LLVM IR function a "primary" one? "primary" function is the one
120 /// that spawns vISA entity that gets compiled into a separate gen object
121 /// - For an arbitrary LLVM IR function, get a set of "primary" functions
122 /// that contain a compiled vISA corresponding to the function in question
123 /// compiled into their gen objects.
124 ///
125 /// - *ProgramInfo*
126 /// A transient object that groups several llvm Functions that are eventually
127 /// get compiled into a single gen entity. A separate elf file with the
128 /// debug information is generated for each gen entity.
129 /// The grouping is with a help of *ModuleToVisaTransformInfo* object.
130 ///
131 /// - *GenObjectWrapper*
132 /// Wrapper over the data produced by the finalizer after a kernel gets
133 /// compiled. Simplifies/Provides access to the following:
134 /// + gen binary (gen machine instructions)
135 /// + decoded *gen* debug info and raw gen debug info blob
136 /// + FINALIZER_INFO structure
137 ///
138 /// - *CompiledVisaWrapper*
139 /// For an arbitrary pair of llvm IR Function and VISAKernel objects,
140 /// does the following:
141 /// + Validates that IR Function and VISAKernel object are related (that is
142 /// the vISA spawned by IR Function is owned by the VISAKernel.
143 /// + Provides services to access *gen* debug info from an appropriate
144 /// compiled object (*gen* debug info concept).
145 ///
146 /// *GenXFunction*
147 /// An object that loosely resembles MachineFunction from the LLVM Machine IR.
148 /// This is an object that for a given LLVM IR Function provides access to:
149 /// - LLVM IR Function
150 /// - VisaMapping
151 /// - Subtarget
152 /// - data from CompiledVisaWrapper/GenObjectWrapper
153 /// - GenXVisaRegAlloc
154 /// GenXFunctoin serves as a primary method to communicate with the DebugInfo
155 /// library. The data these objects hold allow us to reason about the debug
156 /// information for any Gen construct (instruction, variable, etc).
157 ///
158 /// Examples
159 /// ^^^^^^^^
160 ///
161 /// Examples below use the following naming conventions:
162 /// K* - kernel function
163 /// L* - subroutine (non-inlined function)
164 /// S* - simple stack call
165 /// I* - indirectly-called function
166 ///
167 /// FunctionGroup construction peculiarities.
168 ///
169 /// When function groups are constructed, we do some peculiar transformations.
170 ///
171 /// Case_1 (FG):
172 /// Source Code: { K1 calls L1, K2 calls L1 }
173 /// IR after function groups: { G1 = {K1, L1}, G2 = { K2, L1'} },
174 /// where L1' is a clone of L1.
175 /// Case_2 (FG):
176 /// Source Code: { K1 calls S_1, both call L1 }.
177 /// IR after function groups: { G1 = {K1, L1, S1, L1' } }.
178 /// Case_3 (FG):
179 /// Source Code: { K1 calls I1 and I2 }.
180 /// IR after function grups { G1 = {K1}, G2 = {I1}, G3={I2} }.
181 ///
182 /// VISA/genISA construction peculiarities.
183 ///
184 /// Case 1:
185 /// Source code: K1, K2.
186 /// Compilation phase:
187 /// two function groups are created, K1 and K2 are heads.
188 /// two different VISAKernel produced.
189 /// DebugInfoGeneration:
190 /// Decoded Debug info for each VISAKernel contains:
191 /// one compiled object description.
192 /// two "*.elf" files are created.
193 ///
194 /// Case 2:
195 /// Source code: K1, S1. K1 calls S1.
196 /// Compilation phase:
197 /// 1 function group is created, K1 is the head.
198 /// 1 VISAKernel and 1 VISAFunction are created.
199 /// DebugInfoGeneratation:
200 /// Decoded debug info contains *2* compiled objects.
201 /// Each object has separate vISA indexes - visa instructions are
202 /// counted separately. Still, both are compiled into the same gen
203 /// object, so only one "*.elf" file is emitted.
204 ///
205 /// Case 3:
206 /// Source code: K1, I1. K1 calls I1
207 /// Compilation phase:
208 /// 1 function group is created, K1 is the head.
209 /// Somehow 2 VISAKernels are created.
210 /// DebugInfoGeneratation:
211 /// Decoded debug info contains *1* compiled objects (but we have 2
212 /// VISAKernel).
213 /// In the end, we emit two "*.elf" files.
214 ///
215 //===----------------------------------------------------------------------===//
216
217 #define DEBUG_TYPE "GENX_DEBUG_INFO"
218
219 using namespace llvm;
220
221 static cl::opt<bool>
222 DbgOpt_ValidationEnable("vc-dbginfo-enable-validation",
223 cl::init(false), cl::Hidden,
224 cl::desc("same as IGC_DebugInfoValidation"));
225 static cl::opt<bool>
226 DbgOpt_ZeBinCompatible("vc-experimental-dbg-info-zebin-compatible",
227 cl::init(false), cl::Hidden,
228 cl::desc("same as IGC_ZeBinCompatibleDebugging"));
229
230 static cl::opt<std::string> DbgOpt_VisaTransformInfoPath(
231 "vc-dump-module-to-visa-transform-info-path", cl::init(""), cl::Hidden,
232 cl::desc("filename into which MVTI is dumped"));
233
234 template <typename ContainerT>
235 using EmplaceTy = decltype(std::declval<ContainerT>().emplace());
236
237 template <typename ContainerT>
238 using CheckedEmplace = decltype(std::declval<EmplaceTy<ContainerT>>().second);
239
240 template <typename ContainerT>
241 using IsCheckedEmplace = std::is_same<bool, CheckedEmplace<ContainerT>>;
242
243 template <typename ContainerT>
244 using IsNonCheckedEmplace =
245 std::is_same<EmplaceTy<ContainerT>, typename ContainerT::iterator>;
246
247 // Naive function that checks the presence of copies.
248 // Container must be multimap-like, values must be comparable.
249 template <typename ContainerT>
hasCopy(const ContainerT & Container,typename ContainerT::iterator ToCheck)250 static bool hasCopy(const ContainerT &Container,
251 typename ContainerT::iterator ToCheck) {
252 auto Range = Container.equal_range(ToCheck->first);
253 auto Result = std::count_if(Range.first, Range.second, [ToCheck](auto It) {
254 return It.second == ToCheck->second;
255 });
256
257 return Result > 1;
258 }
259
260 // checkedEmplace for multimap-like containers. It will be called if
261 // Container.emplace() returns Container::iterator. For such containers, emplace
262 // will always happen and therefore copies can be silently inserted.
263 template <typename ContainerT, class... ArgsT>
264 static std::enable_if_t<IsNonCheckedEmplace<ContainerT>::value, void>
checkedEmplace(ContainerT & Container,ArgsT &&...Args)265 checkedEmplace(ContainerT &Container, ArgsT &&... Args) {
266 auto Result = Container.emplace(std::forward<ArgsT>(Args)...);
267 IGC_ASSERT_MESSAGE(!hasCopy(Container, Result),
268 "a copy of the existing element was emplaced");
269 (void)Result;
270 }
271
272 // checkedEmplace for map/set-like containers. If Container.emplace() returns a
273 // pair whose second element has bool type, this version will be called.
274 template <typename ContainerT, class... ArgsT>
275 static std::enable_if_t<IsCheckedEmplace<ContainerT>::value, void>
checkedEmplace(ContainerT & Container,ArgsT &&...Args)276 checkedEmplace(ContainerT &Container, ArgsT &&... Args) {
277 auto Result = Container.emplace(std::forward<ArgsT>(Args)...);
278 IGC_ASSERT_MESSAGE(Result.second, "unexpected insertion failure");
279 (void)Result;
280 }
281
compareFunctionNames(const Function * LF,const Function * RF)282 static bool compareFunctionNames(const Function *LF, const Function *RF) {
283 IGC_ASSERT(LF && RF);
284 return LF->getName() > RF->getName();
285 }
286
287 template <typename ContainerT>
288 static std::vector<const Function *>
extractSortedFunctions(const ContainerT & C)289 extractSortedFunctions(const ContainerT &C) {
290 std::vector<const Function *> Result;
291 std::transform(C.begin(), C.end(), std::back_inserter(Result),
292 [](const auto &It) { return It.first; });
293 std::sort(Result.begin(), Result.end(), compareFunctionNames);
294 return Result;
295 }
296
297 // NOTE: the term "program" is used to avoid a potential confusion
298 // since the term "kernel" may introduce some ambiguity.
299 // Here a "program" represents a kind of wrapper over a standalone vISA
300 // object (which currently is produced by function groups and
301 // visa-external functions) that finally gets compiled into a stand-alone
302 // gen entity (binary gen kernel) with some auxiliary information
303 struct ProgramInfo {
304 struct FunctionInfo {
305 const genx::di::VisaMapping &VisaMapping;
306 const Function &F;
307 };
308
309 const ModuleToVisaTransformInfo &MVTI;
310 VISAKernel &CompiledKernel;
311 std::vector<FunctionInfo> FIs;
312
getEntryPointProgramInfo313 const Function &getEntryPoint() const {
314 IGC_ASSERT(!FIs.empty());
315 return FIs.front().F;
316 }
317 };
318
319 //
320 // ModuleToVisaTransformInfo
321 // Proides information about how LLVM IR functions are mapped onto various
322 // vISA (and genISA) objects.
323 class ModuleToVisaTransformInfo {
324 using FunctionMapping =
325 std::unordered_map<const Function *, const Function *>;
326 using FunctionMultiMapping =
327 std::unordered_multimap<const Function *, const Function *>;
328 // Note: pointer to VISAKernel can represent either a true kernel or
329 // VISAFunction, depending on the context (this is vISA API limitation)
330 using FunctionToVisaMapping =
331 std::unordered_map<const Function *, VISAKernel *>;
332
333 // Records information about a subroutine and its "owner". The "owner" of
334 // a subroutine is LLVM IR function that spawned *VISAFunction* that contains
335 // vISA for the subroutine
336 FunctionMapping SubroutineOwnersInfo;
337 // "VisaSpanwer" is LLVM IR function that produce *VISAFunction*.
338 // Different "VISAFunctions" have their own vISA instructions enumerated
339 // separately, but they still can be compiled into a single gen object.
340 // does not allow to distiguish those easily).
341 FunctionToVisaMapping VisaSpawnerInfo;
342 // A separate gen object is usually produced by KernelFunctions -
343 // the relationsip between VisaFunction and KernelFunctions is
344 // captured by the FunctionOnwers
345 FunctionMultiMapping FunctionOwnersInfo;
346 // "Kernel functions" are functions that produce genISA object
347 // Usually these are FuntionGroup heads, but indirectly-called functions
348 // also spawn there own genISA object files
349 FunctionToVisaMapping KernelFunctionsInfo;
350 std::unordered_set<const Function *> SourceLevelKernels;
351
352 void extractSubroutineInfo(const Function &F, VISABuilder &VB,
353 const FunctionGroupAnalysis &FGA);
354 void extractVisaFunctionsEmitters(VISABuilder &VB,
355 const FunctionGroupAnalysis &FGA,
356 const CallGraph &CG);
357
358 void extractKernelFunctions(VISABuilder &VB,
359 const FunctionGroupAnalysis &FGA);
360 void propagatePrimaryEmitter(const CallGraphNode &CGNode,
361 const Function &PrimaryEmitter);
362
363 public:
364 void print(raw_ostream &OS) const;
365 void dump() const;
366
isSourceLevelKernel(const Function * F) const367 bool isSourceLevelKernel(const Function *F) const {
368 return SourceLevelKernels.find(F) != SourceLevelKernels.end();
369 }
isKernelFunction(const Function * F) const370 bool isKernelFunction(const Function *F) const {
371 return KernelFunctionsInfo.find(F) != KernelFunctionsInfo.end();
372 }
isSubroutine(const Function * F) const373 bool isSubroutine(const Function *F) const {
374 return SubroutineOwnersInfo.find(F) != SubroutineOwnersInfo.end();
375 }
isVisaFunctionSpawner(const Function * F) const376 bool isVisaFunctionSpawner(const Function *F) const {
377 return VisaSpawnerInfo.find(F) != VisaSpawnerInfo.end();
378 }
379 // Currently unused
380 // For a provided function returns visa object spawned by this function
381 // visa object can represent either VISAKernel or VISAFunction
getSpawnedVISAFunction(const Function * F) const382 VISAKernel *getSpawnedVISAFunction(const Function *F) const {
383 IGC_ASSERT(!isSubroutine(F));
384 auto SpawnedInfoIt = VisaSpawnerInfo.find(F);
385 IGC_ASSERT(SpawnedInfoIt != VisaSpawnerInfo.end());
386 return SpawnedInfoIt->second;
387 }
388 // Return a VISA object representing true *VISAKernel* that was spawned by a
389 // "kernel" function: IR kernel or indirectly called function.
getSpawnedVISAKernel(const Function * F) const390 VISAKernel *getSpawnedVISAKernel(const Function *F) const {
391 IGC_ASSERT_MESSAGE(isKernelFunction(F),
392 "kernel or indirectly called function is expected");
393 return KernelFunctionsInfo.at(F);
394 }
395 // return an "owner" (on vISA level) of the function representing a
396 // subroutine
getSubroutineOwner(const Function * F) const397 const Function *getSubroutineOwner(const Function *F) const {
398 IGC_ASSERT(isSubroutine(F));
399 auto SubInfoIt = SubroutineOwnersInfo.find(F);
400 IGC_ASSERT(SubInfoIt != SubroutineOwnersInfo.end());
401 return SubInfoIt->second;
402 }
403 // PrimaryEmitter is the function spawning gen object, that
404 // contains the vISA object emitted by the specified function
405 std::unordered_set<const Function *>
406 getPrimaryEmittersForVisa(const Function *F, bool Strict = true) const;
407
getPrimaryFunctions() const408 std::vector<const Function *> getPrimaryFunctions() const {
409 return extractSortedFunctions(KernelFunctionsInfo);
410 }
411
412 std::vector<const Function *>
413 getSecondaryFunctions(const Function *PrimaryFunction) const;
414
415 ModuleToVisaTransformInfo(VISABuilder &VB, const FunctionGroupAnalysis &FGA,
416 const CallGraph &CG);
417 };
418
419 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const420 void ModuleToVisaTransformInfo::dump() const {
421 print(errs());
422 errs() << "\n";
423 }
424 #endif
425
print(raw_ostream & OS) const426 void ModuleToVisaTransformInfo::print(raw_ostream &OS) const {
427
428 auto KernelFunctions = extractSortedFunctions(KernelFunctionsInfo);
429 auto Subroutines = extractSortedFunctions(SubroutineOwnersInfo);
430 auto VisaProducers = extractSortedFunctions(VisaSpawnerInfo);
431
432 // filter-out kernel functions
433 VisaProducers.erase(
434 std::remove_if(VisaProducers.begin(), VisaProducers.end(),
435 [this](const auto *F) { return isKernelFunction(F); }),
436 VisaProducers.end());
437
438 auto PrintFunctionSubroutines = [this, &OS, &Subroutines](const Function *F,
439 StringRef Prefix) {
440 unsigned Counter = 0;
441 for (const auto *LF : Subroutines) {
442 if (getSubroutineOwner(LF) != F)
443 continue;
444 OS << Prefix << "l." << Counter << " " << LF->getName() << "\n";
445 ++Counter;
446 }
447 };
448
449 for (size_t i = 0, NumKF = KernelFunctions.size(); i < NumKF; ++i) {
450 const auto *KF = KernelFunctions[i];
451 OS << "[" << i << "] " << KF->getName() << " "
452 << (SourceLevelKernels.count(KF) != 0 ? "(K)" : "(I)") << "\n";
453
454 PrintFunctionSubroutines(KF, " ");
455
456 unsigned SubIdx = 0;
457 for (const auto *VF : VisaProducers) {
458 if (!getPrimaryEmittersForVisa(VF).count(KF))
459 continue;
460 OS << " v." << SubIdx << " " << VF->getName() << "\n";
461 PrintFunctionSubroutines(VF, " ");
462 ++SubIdx;
463 }
464 }
465 }
getSecondaryFunctions(const Function * PrimaryFunction) const466 std::vector<const Function *> ModuleToVisaTransformInfo::getSecondaryFunctions(
467 const Function *PrimaryFunction) const {
468 auto IsSecondaryFunction = [PrimaryFunction, this](const Function *F) {
469 if (F == PrimaryFunction)
470 return false;
471 return getPrimaryEmittersForVisa(F).count(PrimaryFunction) > 0;
472 };
473 IGC_ASSERT(isKernelFunction(PrimaryFunction));
474 std::vector<const Function *> Result;
475 for (const auto &[F, VF] : SubroutineOwnersInfo) {
476 (void)VF;
477 if (IsSecondaryFunction(F))
478 Result.push_back(F);
479 }
480 for (const auto &[F, VF] : VisaSpawnerInfo) {
481 (void)VF;
482 if (IsSecondaryFunction(F))
483 Result.push_back(F);
484 }
485 std::sort(Result.begin(), Result.end(), compareFunctionNames);
486 return Result;
487 }
488
extractSubroutineInfo(const Function & F,VISABuilder & VB,const FunctionGroupAnalysis & FGA)489 void ModuleToVisaTransformInfo::extractSubroutineInfo(
490 const Function &F, VISABuilder &VB, const FunctionGroupAnalysis &FGA) {
491 IGC_ASSERT(isVisaFunctionSpawner(&F));
492 const auto *Gr = FGA.getAnyGroup(&F);
493 IGC_ASSERT(Gr);
494 for (const Function *SF : *Gr) {
495 if (isKernelFunction(SF))
496 continue;
497 if (genx::requiresStackCall(SF))
498 continue;
499 checkedEmplace(SubroutineOwnersInfo, SF, &F);
500 }
501 }
502
503 std::unordered_set<const Function *>
getPrimaryEmittersForVisa(const Function * F,bool Strict) const504 ModuleToVisaTransformInfo::getPrimaryEmittersForVisa(const Function *F,
505 bool Strict) const {
506 if (isSubroutine(F)) {
507 auto SubrInfoIt = SubroutineOwnersInfo.find(F);
508 IGC_ASSERT(SubrInfoIt != SubroutineOwnersInfo.end());
509 const Function *SubrOwner = SubrInfoIt->second;
510 IGC_ASSERT(SubrOwner);
511 IGC_ASSERT(!isSubroutine(SubrOwner));
512 return getPrimaryEmittersForVisa(SubrOwner);
513 }
514 auto InfoRange = FunctionOwnersInfo.equal_range(F);
515 std::unordered_set<const Function *> PrimaryEmitters;
516 std::transform(InfoRange.first, InfoRange.second,
517 std::inserter(PrimaryEmitters, PrimaryEmitters.end()),
518 [](auto It) { return It.second; });
519
520 if (Strict) {
521 IGC_ASSERT_MESSAGE(!PrimaryEmitters.empty(),
522 "could not get primary emitter");
523 }
524 return PrimaryEmitters;
525 }
526
propagatePrimaryEmitter(const CallGraphNode & CGNode,const Function & PrimaryEmitter)527 void ModuleToVisaTransformInfo::propagatePrimaryEmitter(
528 const CallGraphNode &CGNode, const Function &PrimaryEmitter) {
529 const Function *F = CGNode.getFunction();
530 if (!F)
531 return;
532 if (genx::requiresStackCall(F) && !genx::isReferencedIndirectly(F)) {
533 auto Range = FunctionOwnersInfo.equal_range(F);
534 auto Res =
535 std::find_if(Range.first, Range.second, [&PrimaryEmitter](auto Info) {
536 return Info.second == &PrimaryEmitter;
537 });
538 // F -> PrimaryEmitter was already inserted. It happens if a recursion
539 // exists.
540 if (Res != Range.second)
541 return;
542 LLVM_DEBUG(dbgs() << "setting <" << PrimaryEmitter.getName()
543 << "> as a host of the stack-callee <" << F->getName()
544 << ">\n");
545 checkedEmplace(FunctionOwnersInfo, F, &PrimaryEmitter);
546 }
547
548 for (const auto &CalleeCGNode : CGNode)
549 propagatePrimaryEmitter(*CalleeCGNode.second, PrimaryEmitter);
550 }
551
extractVisaFunctionsEmitters(VISABuilder & VB,const FunctionGroupAnalysis & FGA,const CallGraph & CG)552 void ModuleToVisaTransformInfo::extractVisaFunctionsEmitters(
553 VISABuilder &VB, const FunctionGroupAnalysis &FGA, const CallGraph &CG) {
554
555 // We've already collected kernels and indirect functions into
556 // `KernelFunctionsInfo`.
557 for (const auto &[F, VF] : KernelFunctionsInfo) {
558 (void)VF;
559 const auto *KFNode = CG[F];
560 IGC_ASSERT(KFNode);
561 propagatePrimaryEmitter(*KFNode, *F);
562 }
563 // Collect owned functions as a set of unique keys of FunctionOwnersInfo.
564 std::unordered_set<const Function *> OwnedFunctions;
565 std::transform(FunctionOwnersInfo.begin(), FunctionOwnersInfo.end(),
566 std::inserter(OwnedFunctions, OwnedFunctions.begin()),
567 [](auto Info) { return Info.first; });
568
569 for (const Function *F : OwnedFunctions) {
570 // Skip "KernelFunctions" because they have already been processed.
571 if (genx::isReferencedIndirectly(F) || genx::isKernel(F))
572 continue;
573 VISAKernel *VF = VB.GetVISAKernel(F->getName().str());
574 checkedEmplace(VisaSpawnerInfo, F, VF);
575 extractSubroutineInfo(*F, VB, FGA);
576 }
577 }
578
extractKernelFunctions(VISABuilder & VB,const FunctionGroupAnalysis & FGA)579 void ModuleToVisaTransformInfo::extractKernelFunctions(
580 VISABuilder &VB, const FunctionGroupAnalysis &FGA) {
581 for (const auto *FG : FGA.AllGroups()) {
582 for (const Function *F : *FG) {
583 if (!genx::isReferencedIndirectly(F) && !genx::isKernel(F))
584 continue;
585 VISAKernel *VF = VB.GetVISAKernel(F->getName().str());
586 if (genx::isKernel(F))
587 checkedEmplace(SourceLevelKernels, F);
588 checkedEmplace(KernelFunctionsInfo, F, VF);
589 checkedEmplace(VisaSpawnerInfo, F, VF);
590 checkedEmplace(FunctionOwnersInfo, F, F);
591
592 extractSubroutineInfo(*F, VB, FGA);
593 }
594 }
595 }
596
ModuleToVisaTransformInfo(VISABuilder & VB,const FunctionGroupAnalysis & FGA,const CallGraph & CG)597 ModuleToVisaTransformInfo::ModuleToVisaTransformInfo(
598 VISABuilder &VB, const FunctionGroupAnalysis &FGA, const CallGraph &CG) {
599 extractKernelFunctions(VB, FGA);
600 extractVisaFunctionsEmitters(VB, FGA, CG);
601
602 for (const auto *FG : FGA.AllGroups()) {
603 for (const Function *F : *FG) {
604 if (isSourceLevelKernel(F))
605 IGC_ASSERT(isKernelFunction(F) && isVisaFunctionSpawner(F) &&
606 !isSubroutine(F));
607 if (isKernelFunction(F))
608 IGC_ASSERT(isVisaFunctionSpawner(F) && !isSubroutine(F));
609 if (isVisaFunctionSpawner(F))
610 IGC_ASSERT(!isSubroutine(F));
611 if (isSubroutine(F))
612 IGC_ASSERT(!isVisaFunctionSpawner(F) && !isKernelFunction(F));
613 }
614 }
615 }
616
617 namespace {
618
619 class GenObjectWrapper {
620 FINALIZER_INFO *JitInfo = nullptr;
621 std::unique_ptr<IGC::DbgDecoder> DecodedDebugInfo;
622 // TODO: remove this once DbgDecoder is refactored
623 unsigned GenDbgInfoDataSize = 0;
624 void *GenDbgInfoDataPtr = nullptr;
625
626 int GenBinaryDataSize = 0;
627 void *GenBinaryDataPtr = nullptr;
628
629 const Function &EntryPoint;
630
631 std::string ErrMsg;
632
setError(const Twine & Msg)633 void setError(const Twine &Msg) {
634 ErrMsg.append((Msg + "<" + EntryPoint.getName().str() + ">").str());
635
636 LLVM_DEBUG(dbgs() << "GOW creation for <" << EntryPoint.getName()
637 << "> aborted: " << Msg.str());
638 }
639
640 public:
getEntryPoint() const641 const Function &getEntryPoint() const { return EntryPoint; }
642
getGenDebug() const643 ArrayRef<char> getGenDebug() const {
644 IGC_ASSERT(GenDbgInfoDataPtr);
645 return ArrayRef<char>(static_cast<char *>(GenDbgInfoDataPtr),
646 GenDbgInfoDataSize);
647 }
648
getGenBinary() const649 ArrayRef<char> getGenBinary() const {
650 IGC_ASSERT(GenBinaryDataPtr);
651 return ArrayRef<char>(static_cast<char *>(GenBinaryDataPtr),
652 GenBinaryDataSize);
653 }
654
getDecodedGenDbg() const655 const IGC::DbgDecoder &getDecodedGenDbg() const {
656 IGC_ASSERT(DecodedDebugInfo);
657 return *DecodedDebugInfo;
658 }
659
getJitInfo() const660 const FINALIZER_INFO &getJitInfo() const {
661 IGC_ASSERT(!hasErrors() && JitInfo);
662 return *JitInfo;
663 };
664
665 GenObjectWrapper(VISAKernel &VK, const Function &F);
~GenObjectWrapper()666 ~GenObjectWrapper() { releaseDebugInfoResources(); }
667
hasErrors() const668 bool hasErrors() const { return !ErrMsg.empty(); }
669
getError() const670 const std::string &getError() const { return ErrMsg; }
671
releaseDebugInfoResources()672 void releaseDebugInfoResources() {
673 if (!GenDbgInfoDataPtr) {
674 IGC_ASSERT(GenDbgInfoDataSize == 0);
675 return;
676 }
677 freeBlock(GenDbgInfoDataPtr);
678 GenDbgInfoDataPtr = nullptr;
679 GenDbgInfoDataSize = 0;
680 }
681
printDecodedGenXDebug(raw_ostream & OS)682 void printDecodedGenXDebug(raw_ostream &OS) {
683 IGC_ASSERT(!hasErrors());
684 LLVM_DEBUG(dbgs() << "GenXDebugInfo size: " << GenDbgInfoDataSize << "\n");
685 IGC::DbgDecoder(GenDbgInfoDataPtr).print(OS);
686 }
687 };
688
GenObjectWrapper(VISAKernel & VK,const Function & F)689 GenObjectWrapper::GenObjectWrapper(VISAKernel &VK, const Function &F)
690 : EntryPoint(F) {
691 if (VK.GetJitInfo(JitInfo) != 0) {
692 setError("could not extract jitter info");
693 return;
694 }
695 IGC_ASSERT(JitInfo);
696
697 // Extract Gen Binary (will need it for line table generation)
698 VK.GetGenxBinary(GenBinaryDataPtr, GenBinaryDataSize);
699 if (GenBinaryDataSize <= 0) {
700 setError("could not extract gen binary from finalizer");
701 return;
702 }
703
704 if (VK.GetGenxDebugInfo(GenDbgInfoDataPtr, GenDbgInfoDataSize) != 0) {
705 setError("could not get gen debug information from finalizer");
706 return;
707 }
708 if (!GenDbgInfoDataPtr) {
709 setError("gen debug information reported by finalizer is inconsistent");
710 return;
711 }
712 DecodedDebugInfo = std::make_unique<IGC::DbgDecoder>(GenDbgInfoDataPtr);
713 };
714
715 class CompiledVisaWrapper {
716
717 using FinalizedDI = IGC::DbgDecoder::DbgInfoFormat;
718
719 const GenObjectWrapper &GOW;
720 // underlying data is owned by DecodedDebugInfo, owned by GOW
721 const FinalizedDI *VisaKernelDI = nullptr;
722
723 std::string ErrMsg;
724
setErrorForFunction(const std::string & Err,const Function & F)725 void setErrorForFunction(const std::string &Err, const Function &F) {
726 ErrMsg.append(Err).append("<").append(F.getName().str()).append(">");
727
728 LLVM_DEBUG(dbgs() << "CW creation for <" << F.getName()
729 << "> aborted: " << ErrMsg);
730 }
731
732 public:
getJitInfo() const733 const FINALIZER_INFO &getJitInfo() const { return GOW.getJitInfo(); };
734
getFinalizerDI() const735 const FinalizedDI &getFinalizerDI() const {
736 IGC_ASSERT(ErrMsg.empty() && VisaKernelDI);
737 return *VisaKernelDI;
738 }
739
getDIDecoder() const740 const IGC::DbgDecoder &getDIDecoder() const { return GOW.getDecodedGenDbg(); }
741
getGenDebug() const742 ArrayRef<char> getGenDebug() const { return GOW.getGenDebug(); }
getGenBinary() const743 ArrayRef<char> getGenBinary() const { return GOW.getGenBinary(); }
744
getError() const745 const std::string &getError() const { return ErrMsg; }
746
hasErrors() const747 bool hasErrors() const { return !getError().empty(); }
748
749 CompiledVisaWrapper(CompiledVisaWrapper &&Other) = default;
CompiledVisaWrapper(const Function & F,StringRef CompiledObjectName,const GenObjectWrapper & GOWIn)750 CompiledVisaWrapper(const Function &F, StringRef CompiledObjectName,
751 const GenObjectWrapper &GOWIn)
752 : GOW(GOWIn) {
753 struct Gen2VisaIdx {
754 unsigned GenOffset;
755 unsigned VisaIdx;
756 };
757 LLVM_DEBUG(dbgs() << "creating CW for <" << F.getName() << ">, using <"
758 << CompiledObjectName
759 << "> as a CompiledObject moniker\n");
760 IGC_ASSERT(!GOW.hasErrors());
761
762 const auto &CO = GOW.getDecodedGenDbg().compiledObjs;
763 auto FoundCoIt = std::find_if(
764 CO.begin(), CO.end(), [&CompiledObjectName](const auto &DI) {
765 return CompiledObjectName == StringRef(DI.kernelName);
766 });
767 VisaKernelDI = (FoundCoIt == CO.end()) ? nullptr : &*FoundCoIt;
768 if (!VisaKernelDI) {
769 setErrorForFunction("could not find debug information for", F);
770 return;
771 }
772 if (VisaKernelDI->CISAIndexMap.empty()) {
773 setErrorForFunction("empty CisaIndexMap for", F);
774 return;
775 }
776
777 std::vector<Gen2VisaIdx> Gen2Visa;
778 std::transform(VisaKernelDI->CISAIndexMap.begin(),
779 VisaKernelDI->CISAIndexMap.end(),
780 std::back_inserter(Gen2Visa), [](const auto &V2G) {
781 return Gen2VisaIdx{V2G.second, V2G.first};
782 });
783
784 const auto &GenBinary = GOW.getGenBinary();
785 // Make Sure that gen isa indeces are inside GenBinary
786 const bool InBounds =
787 std::all_of(Gen2Visa.begin(), Gen2Visa.end(), [&](const auto &Idx) {
788 // <= Is because last index can be equal to the binary size
789 return Idx.GenOffset <= GenBinary.size();
790 });
791 if (!InBounds) {
792 setErrorForFunction("fatal error (debug info). inconsistent gen->visa "
793 "mapping: gen index is out of bounds",
794 F);
795 return;
796 }
797
798 // Make Sure that gen isa indeces are unique and sorted
799 const bool Sorted = std::is_sorted(
800 Gen2Visa.begin(), Gen2Visa.end(),
801 [](const auto &L, const auto &R) { return L.GenOffset < R.GenOffset; });
802 const bool Validated =
803 Sorted && (Gen2Visa.end() ==
804 std::adjacent_find(Gen2Visa.begin(), Gen2Visa.end(),
805 [](const auto &L, const auto &R) {
806 return L.GenOffset == R.GenOffset;
807 }));
808 if (!Validated) {
809 setErrorForFunction("fatal error (debug info). inconsistent gen->visa "
810 "mapping: gen index are not ordered properly",
811 F);
812 return;
813 }
814 }
815 };
816
817 class GenXFunction final : public IGC::VISAModule {
818
819 public:
GenXFunction(const GenXSubtarget & STIn,const GenXVisaRegAlloc & RAIn,const Function & F,CompiledVisaWrapper && CW,const genx::di::VisaMapping & V2I,const ModuleToVisaTransformInfo & MVTI,bool IsPrimary)820 GenXFunction(const GenXSubtarget &STIn, const GenXVisaRegAlloc &RAIn,
821 const Function &F, CompiledVisaWrapper &&CW,
822 const genx::di::VisaMapping &V2I,
823 const ModuleToVisaTransformInfo &MVTI, bool IsPrimary)
824 : F{F}, ST{STIn}, VisaMapping{V2I}, CompiledVisa{std::move(CW)}, RA{RAIn},
825 MVTI(MVTI), VISAModule(const_cast<Function *>(&F), IsPrimary) {
826
827 if (MVTI.isSubroutine(&F))
828 SetType(ObjectType::SUBROUTINE);
829 else if (MVTI.isKernelFunction(&F))
830 SetType(ObjectType::KERNEL);
831 else
832 SetType(ObjectType::STACKCALL_FUNC);
833 }
834
~GenXFunction()835 ~GenXFunction() {
836 LLVM_DEBUG(dbgs() << "~GenXFunction() called for " << F.getName() << "\n");
837 }
838
839 const IGC::DbgDecoder::DbgInfoFormat*
getCompileUnit(const IGC::DbgDecoder & VD) const840 getCompileUnit(const IGC::DbgDecoder& VD) const override {
841
842 StringRef CompiledObjectName;
843 if (MVTI.isSubroutine(&F)) {
844 IGC_ASSERT(GetType() == ObjectType::SUBROUTINE);
845 CompiledObjectName = MVTI.getSubroutineOwner(&F)->getName();
846 } else {
847 CompiledObjectName = F.getName();
848 }
849
850 auto FoundIt = std::find_if(VD.compiledObjs.begin(), VD.compiledObjs.end(),
851 [&CompiledObjectName](const auto &CO) {
852 return (CO.kernelName == CompiledObjectName);
853 });
854 if (FoundIt == VD.compiledObjs.end())
855 return nullptr;
856
857 return &*FoundIt;
858 }
859
getUnpaddedProgramSize() const860 unsigned int getUnpaddedProgramSize() const override {
861 return CompiledVisa.getGenBinary().size();
862 }
isLineTableOnly() const863 bool isLineTableOnly() const override {
864 IGC_ASSERT_MESSAGE(0, "isLineTableOnly()");
865 return false;
866 }
getPrivateBaseReg() const867 unsigned getPrivateBaseReg() const override {
868 IGC_ASSERT_MESSAGE(0, "getPrivateBaseReg() - not implemented");
869 return 0;
870 }
getGRFSizeInBytes() const871 unsigned getGRFSizeInBytes() const override {
872 return ST.getGRFByteSize();
873 }
getNumGRFs() const874 unsigned getNumGRFs() const override {
875 return CompiledVisa.getJitInfo().numGRFTotal;
876 }
getPointerSize() const877 unsigned getPointerSize() const override {
878 return F.getParent()->getDataLayout().getPointerSize();
879 }
getTypeSizeInBits(Type * Ty) const880 uint64_t getTypeSizeInBits(Type* Ty) const override {
881 return F.getParent()->getDataLayout().getTypeSizeInBits(Ty);
882 }
getGenDebug() const883 ArrayRef<char> getGenDebug() const override {
884 return CompiledVisa.getGenDebug();
885 }
getGenBinary() const886 ArrayRef<char> getGenBinary() const override {
887 return CompiledVisa.getGenBinary();
888 }
getDIDecoder() const889 const IGC::DbgDecoder &getDIDecoder() const {
890 return CompiledVisa.getDIDecoder();
891 }
getFinalizerDI() const892 const IGC::DbgDecoder::DbgInfoFormat &getFinalizerDI() const {
893 return CompiledVisa.getFinalizerDI();
894 }
895
getVisaMapping() const896 const genx::di::VisaMapping &getVisaMapping() const { return VisaMapping; }
897
898 std::vector<IGC::VISAVariableLocation>
GetVariableLocation(const Instruction * DbgInst) const899 GetVariableLocation(const Instruction *DbgInst) const override {
900
901 using Location = IGC::VISAVariableLocation;
902 auto EmptyLoc = [this](StringRef Reason) {
903 LLVM_DEBUG(dbgs() << " Empty Location Returned (" << Reason
904 << ")\n <<<\n");
905 std::vector<Location> Res;
906 Res.emplace_back(this);
907 return Res;
908 };
909 auto ConstantLoc = [this](const Constant *C) {
910 LLVM_DEBUG(dbgs() << " ConstantLoc\n <<<\n");
911 std::vector<Location> Res;
912 Res.emplace_back(C, this);
913 return Res;
914 };
915
916 IGC_ASSERT(isa<DbgInfoIntrinsic>(DbgInst));
917
918 LLVM_DEBUG(dbgs() << " >>>\n GetVariableLocation for " << *DbgInst << "\n");
919 const Value *DbgValue = nullptr;
920 const DIVariable *VarDescr = nullptr;
921 if (const auto *pDbgAddrInst = dyn_cast<DbgDeclareInst>(DbgInst)) {
922 DbgValue = pDbgAddrInst->getAddress();
923 VarDescr = pDbgAddrInst->getVariable();
924 } else if (const auto *pDbgValInst = dyn_cast<DbgValueInst>(DbgInst)) {
925 DbgValue = pDbgValInst->getValue();
926 VarDescr = pDbgValInst->getVariable();
927 } else {
928 return EmptyLoc("unsupported Debug Intrinsic");
929 }
930
931 IGC_ASSERT(VarDescr);
932 if (!DbgValue) {
933 if (const auto *LocalVar = dyn_cast<DILocalVariable>(VarDescr))
934 if (LocalVar->isParameter())
935 return EmptyLoc("unsupported parameter description");
936 return EmptyLoc("unsupported DbgInst");
937 }
938 IGC_ASSERT(DbgValue);
939 LLVM_DEBUG(dbgs() << " Value:" << *DbgValue << "\n");
940 LLVM_DEBUG(dbgs() << " Var: " << VarDescr->getName()
941 << "/Type:" << *VarDescr->getType() << "\n");
942 if (isa<UndefValue>(DbgValue)) {
943 return EmptyLoc("UndefValue");
944 }
945 if (auto *ConstVal = dyn_cast<Constant>(DbgValue)) {
946 return ConstantLoc(ConstVal);
947 }
948 auto *Reg = RA.getRegForValueUntyped(&F, const_cast<Value *>(DbgValue));
949 if (!Reg) {
950 return EmptyLoc("could not find virtual register");
951 }
952 const bool IsRegister = true;
953 const bool IsMemory = false;
954 const bool IsGlobalASI = false;
955 auto *VTy = dyn_cast<IGCLLVM::FixedVectorType>(DbgValue->getType());
956 unsigned NumElements = VTy ? VTy->getNumElements() : 1;
957 const bool IsVectorized = false;
958
959 std::vector<Location> Res;
960 // Source/IGC/DebugInfo/VISAModule.hpp:128
961 Res.emplace_back(GENERAL_REGISTER_BEGIN + Reg->Num, IsRegister,
962 IsMemory, NumElements, IsVectorized, IsGlobalASI, this);
963 return Res;
964 }
965
UpdateVisaId()966 void UpdateVisaId() override {
967 // do nothing (the moment we need to advance index is controlled explicitly)
968 }
ValidateVisaId()969 void ValidateVisaId() override {
970 // do nothing (we don't need validation since VISA is built already)
971 }
GetSIMDSize() const972 uint16_t GetSIMDSize() const override { return 1; }
973
getPrivateBase() const974 void* getPrivateBase() const override { return nullptr; };
setPrivateBase(void *)975 void setPrivateBase(void*) override {};
976
hasPTO() const977 bool hasPTO() const override { return false; }
getPTOReg() const978 int getPTOReg() const override { return -1; }
getFPReg() const979 int getFPReg() const override { return -1; }
getFPOffset() const980 uint64_t getFPOffset() const override { return 16; }
981
982 private:
983 const Function &F;
984 const GenXSubtarget &ST;
985 const genx::di::VisaMapping &VisaMapping;
986 CompiledVisaWrapper CompiledVisa;
987 const GenXVisaRegAlloc &RA;
988 const ModuleToVisaTransformInfo &MVTI;
989 };
990
processGenXFunction(IGC::IDebugEmitter & Emitter,GenXFunction & GF)991 static void processGenXFunction(IGC::IDebugEmitter &Emitter, GenXFunction &GF) {
992 Emitter.setCurrentVISA(&GF);
993 const auto &V2I = GF.getVisaMapping().V2I;
994 const auto &FDI = GF.getFinalizerDI();
995 for (auto MappingIt = V2I.cbegin(); MappingIt != V2I.cend(); ++MappingIt) {
996
997 // "NextIndex" is an index in vISA stream which points to an end
998 // of instructions sequence generated by a particular llvm instruction
999 // For istructions which do not produce any visa instructions
1000 // (like llvm.dbg.*) "NextIndex" should point to the "CurrentIndex"
1001 auto FindNextIndex = [&FDI, &V2I](decltype(MappingIt) ItCur) {
1002 auto *Inst = ItCur->Inst;
1003 if (isa<DbgInfoIntrinsic>(Inst)) {
1004 return ItCur->VisaIdx;
1005 }
1006 auto NextIt = std::next(ItCur);
1007 if (NextIt == V2I.end()) {
1008 IGC_ASSERT(!FDI.CISAIndexMap.empty());
1009 return FDI.CISAIndexMap.back().first;
1010 }
1011 return NextIt->VisaIdx;
1012 };
1013 auto VisaIndexCurr = MappingIt->VisaIdx;
1014 auto VisaIndexNext = FindNextIndex(MappingIt);
1015
1016 // Note: "index - 1" is because we mimic index values as if they were
1017 // before corresponding instructions were inserted
1018 GF.SetVISAId(VisaIndexCurr - 1);
1019 // we need this const_cast because of the flawed VISA Emitter API
1020 auto *Inst = const_cast<Instruction *>(MappingIt->Inst);
1021 Emitter.BeginInstruction(Inst);
1022 GF.SetVISAId(VisaIndexNext - 1);
1023 Emitter.EndInstruction(Inst);
1024
1025 LLVM_DEBUG(dbgs() << " VisaMapping: [" << VisaIndexCurr << ";"
1026 << VisaIndexNext << "):" << *Inst << "\n");
1027 }
1028 }
1029
1030 using GenXObjectHolder = std::unique_ptr<GenXFunction>;
buildGenXFunctionObject(const ModuleToVisaTransformInfo & MVTI,const GenObjectWrapper & GOW,const ProgramInfo::FunctionInfo & FI,const GenXSubtarget & ST,const GenXVisaRegAlloc & RA)1031 GenXObjectHolder buildGenXFunctionObject(const ModuleToVisaTransformInfo &MVTI,
1032 const GenObjectWrapper &GOW,
1033 const ProgramInfo::FunctionInfo &FI,
1034 const GenXSubtarget &ST,
1035 const GenXVisaRegAlloc &RA) {
1036 StringRef CompiledObjectName = FI.F.getName();
1037 if (MVTI.isSubroutine(&FI.F))
1038 CompiledObjectName = MVTI.getSubroutineOwner(&FI.F)->getName();
1039
1040 CompiledVisaWrapper CW(FI.F, CompiledObjectName, GOW);
1041 if (CW.hasErrors())
1042 vc::diagnose(FI.F.getContext(), "GenXDebugInfo", CW.getError());
1043
1044 bool IsPrimaryFunction = &GOW.getEntryPoint() == &FI.F;
1045 return std::make_unique<GenXFunction>(
1046 ST, RA, FI.F, std::move(CW), FI.VisaMapping, MVTI, IsPrimaryFunction);
1047 }
1048
1049 using GenXObjectHolderList = std::vector<GenXObjectHolder>;
translateProgramInfoToGenXFunctionObjects(const GenObjectWrapper & GOW,const ProgramInfo & PI,const GenXSubtarget & ST,const GenXVisaRegAlloc & RA)1050 GenXObjectHolderList translateProgramInfoToGenXFunctionObjects(
1051 const GenObjectWrapper &GOW, const ProgramInfo &PI, const GenXSubtarget &ST,
1052 const GenXVisaRegAlloc &RA) {
1053 const auto &MVTI = PI.MVTI;
1054 GenXObjectHolderList GenXFunctionHolders;
1055 std::transform(PI.FIs.begin(), PI.FIs.end(),
1056 std::back_inserter(GenXFunctionHolders),
1057 [&ST, &RA, &MVTI, &GOW](const auto &FI) {
1058 return buildGenXFunctionObject(MVTI, GOW, FI, ST, RA);
1059 });
1060 return GenXFunctionHolders;
1061 }
1062
1063 using GenXFunctionPtrList = std::vector<GenXFunction *>;
initializeDebugEmitter(IGC::IDebugEmitter & Emitter,const IGC::DebugEmitterOpts & DebugOpts,const ProgramInfo & PI,GenXObjectHolderList && GFsHolderIn)1064 GenXFunctionPtrList initializeDebugEmitter(
1065 IGC::IDebugEmitter &Emitter, const IGC::DebugEmitterOpts &DebugOpts,
1066 const ProgramInfo &PI, GenXObjectHolderList &&GFsHolderIn) {
1067
1068 GenXFunctionPtrList GFPointers;
1069 for (auto &&GF : GFsHolderIn) {
1070 GFPointers.push_back(GF.get());
1071
1072 if (GF->isPrimaryFunc()) {
1073 Emitter.Initialize(std::move(GF), DebugOpts);
1074 } else {
1075 Emitter.registerVISA(GFPointers.back());
1076 Emitter.resetModule(std::move(GF));
1077 }
1078 }
1079 // Currently Debug Info Emitter expects that GenXFunctions are
1080 // processed in the same order as they appear in the visa object
1081 // (in terms of genisa instructions order)
1082 std::sort(GFPointers.begin(), GFPointers.end(), [](auto *LGF, auto *RGF) {
1083 const auto &LDI = LGF->getFinalizerDI();
1084 const auto &RDI = RGF->getFinalizerDI();
1085 return LDI.relocOffset < RDI.relocOffset;
1086 });
1087 return GFPointers;
1088 }
1089
1090 } // namespace
1091
1092 namespace llvm {
1093
dumpDebugInfo(const GenXBackendConfig & BC,const StringRef KernelName,const ArrayRef<char> ElfBin,const ArrayRef<char> GenDbgBlob,const ArrayRef<char> ErrLog)1094 static void dumpDebugInfo(const GenXBackendConfig &BC,
1095 const StringRef KernelName,
1096 const ArrayRef<char> ElfBin,
1097 const ArrayRef<char> GenDbgBlob,
1098 const ArrayRef<char> ErrLog) {
1099 std::string Prefix = "dbginfo_";
1100 if (!BC.dbgInfoDumpsNameOverride().empty())
1101 Prefix.append(BC.dbgInfoDumpsNameOverride()).append("_");
1102
1103 vc::produceAuxiliaryShaderDumpFile(BC, Prefix + KernelName + "_dwarf.elf",
1104 ElfBin);
1105 vc::produceAuxiliaryShaderDumpFile(BC, Prefix + KernelName + "_gen.dump",
1106 GenDbgBlob);
1107 if (!ErrLog.empty())
1108 vc::produceAuxiliaryShaderDumpFile(BC, Prefix + KernelName + ".dbgerr",
1109 ErrLog);
1110 }
1111
processKernel(const IGC::DebugEmitterOpts & DebugOpts,const ProgramInfo & PI)1112 void GenXDebugInfo::processKernel(const IGC::DebugEmitterOpts &DebugOpts,
1113 const ProgramInfo &PI) {
1114
1115 IGC_ASSERT_MESSAGE(!PI.FIs.empty(),
1116 "Program must include at least one function");
1117 IGC_ASSERT_MESSAGE(PI.MVTI.getPrimaryEmittersForVisa(&PI.getEntryPoint())
1118 .count(&PI.getEntryPoint()) == 1,
1119 "The head of ProgramInfo is expected to be a kernel");
1120
1121 GenObjectWrapper GOW(PI.CompiledKernel, PI.getEntryPoint());
1122 if (GOW.hasErrors())
1123 vc::diagnose(GOW.getEntryPoint().getContext(), "GenXDebugInfo",
1124 GOW.getError());
1125
1126 LLVM_DEBUG(GOW.printDecodedGenXDebug(dbgs()));
1127
1128 auto Deleter = [](IGC::IDebugEmitter *Emitter) {
1129 IGC::IDebugEmitter::Release(Emitter);
1130 };
1131 using EmitterHolder = std::unique_ptr<IGC::IDebugEmitter, decltype(Deleter)>;
1132 EmitterHolder Emitter(IGC::IDebugEmitter::Create(), Deleter);
1133
1134 const auto &ST = getAnalysis<TargetPassConfig>()
1135 .getTM<GenXTargetMachine>()
1136 .getGenXSubtarget();
1137 auto *FGA = &getAnalysis<FunctionGroupAnalysis>();
1138 FunctionGroup *currentFG = FGA->getAnyGroup(&PI.FIs.front().F);
1139 auto &RA = (getAnalysis<GenXVisaRegAllocWrapper>().getFGPassImpl(currentFG));
1140
1141 GenXFunctionPtrList GFPointers = initializeDebugEmitter(
1142 *Emitter, DebugOpts, PI,
1143 translateProgramInfoToGenXFunctionObjects(GOW, PI, ST, RA));
1144
1145 auto &KF = GOW.getEntryPoint();
1146 IGC_ASSERT(ElfOutputs.count(&KF) == 0);
1147 auto &ElfBin = ElfOutputs[&KF];
1148
1149 for (auto *GF : GFPointers) {
1150 LLVM_DEBUG(dbgs() << "--- Processing GenXFunction: "
1151 << GF->getFunction()->getName().str() << " ---\n");
1152 processGenXFunction(*Emitter, *GF);
1153 bool ExpectMore = GF != GFPointers.back();
1154 LLVM_DEBUG(dbgs() << "--- Starting Debug Info Finalization (final: "
1155 << !ExpectMore << ") ---\n");
1156 auto Out = Emitter->Finalize(!ExpectMore, &GF->getDIDecoder());
1157 if (!ExpectMore) {
1158 ElfBin = std::move(Out);
1159 } else {
1160 IGC_ASSERT(Out.empty());
1161 }
1162 LLVM_DEBUG(dbgs() << "--- \\ Debug Info Finalized / ---\n");
1163 }
1164
1165 const auto &KernelName = KF.getName();
1166 LLVM_DEBUG(dbgs() << "got Debug Info for <" << KernelName.str() << "> "
1167 << "- " << ElfBin.size() << " bytes\n");
1168
1169 const auto &BC = getAnalysis<GenXBackendConfig>();
1170 if (BC.dbgInfoDumpsEnabled()) {
1171 const auto &ErrLog = Emitter->getErrors();
1172 dumpDebugInfo(BC, KernelName, ElfBin, GOW.getGenDebug(),
1173 {ErrLog.data(), ErrLog.size()});
1174 }
1175
1176 return;
1177 }
1178
cleanup()1179 void GenXDebugInfo::cleanup() {
1180 ElfOutputs.clear();
1181 }
1182
getAnalysisUsage(AnalysisUsage & AU) const1183 void GenXDebugInfo::getAnalysisUsage(AnalysisUsage &AU) const {
1184 AU.addRequired<FunctionGroupAnalysis>();
1185 AU.addRequired<GenXBackendConfig>();
1186 AU.addRequired<GenXModule>();
1187 AU.addRequired<TargetPassConfig>();
1188 AU.addRequired<GenXVisaRegAllocWrapper>();
1189 AU.addRequired<CallGraphWrapperPass>();
1190 AU.setPreservesAll();
1191 }
1192
processPrimaryFunction(const IGC::DebugEmitterOpts & Opts,const ModuleToVisaTransformInfo & MVTI,const GenXModule & GM,VISABuilder & VB,const Function & PF)1193 void GenXDebugInfo::processPrimaryFunction(
1194 const IGC::DebugEmitterOpts &Opts, const ModuleToVisaTransformInfo &MVTI,
1195 const GenXModule &GM, VISABuilder &VB, const Function &PF) {
1196 LLVM_DEBUG(dbgs() << "DbgInfo: processing <" << PF.getName() << ">\n");
1197 IGC_ASSERT(MVTI.isKernelFunction(&PF));
1198 VISAKernel *VKEntry = MVTI.getSpawnedVISAKernel(&PF);
1199 IGC_ASSERT(VKEntry);
1200
1201 using FunctionInfo = ProgramInfo::FunctionInfo;
1202 std::vector<FunctionInfo> FIs;
1203 FIs.push_back(FunctionInfo{*GM.getVisaMapping(&PF), PF});
1204 const auto &SecondaryFunctions = MVTI.getSecondaryFunctions(&PF);
1205 std::transform(SecondaryFunctions.begin(), SecondaryFunctions.end(),
1206 std::back_inserter(FIs), [&GM](const Function *F) {
1207 const auto &Mapping = *GM.getVisaMapping(F);
1208 return FunctionInfo{Mapping, *F};
1209 });
1210 processKernel(Opts, ProgramInfo{MVTI, *VKEntry, std::move(FIs)});
1211 }
1212
fillDbgInfoOptions(const GenXBackendConfig & BC,IGC::DebugEmitterOpts & DebugOpts)1213 static void fillDbgInfoOptions(const GenXBackendConfig &BC,
1214 IGC::DebugEmitterOpts &DebugOpts) {
1215 DebugOpts.DebugEnabled = true;
1216 DebugOpts.EmitDebugLoc = true;
1217
1218 if (BC.emitDebugInfoForZeBin() || DbgOpt_ZeBinCompatible) {
1219 DebugOpts.ZeBinCompatible = true;
1220 DebugOpts.EnableRelocation = true;
1221 DebugOpts.EnforceAMD64Machine = true;
1222 }
1223 if (BC.enableDebugInfoValidation() || DbgOpt_ValidationEnable) {
1224 DebugOpts.EnableDebugInfoValidation = true;
1225 }
1226 }
1227
runOnModule(Module & M)1228 bool GenXDebugInfo::runOnModule(Module &M) {
1229 auto &GM = getAnalysis<GenXModule>();
1230 // Note: we check that MVTI dumps were not requested here,
1231 // since it is possible to request those without the presence of
1232 // debug information
1233 if (!GM.emitDebugInformation() && DbgOpt_VisaTransformInfoPath.empty())
1234 return false;
1235
1236 const auto &BC = getAnalysis<GenXBackendConfig>();
1237 const FunctionGroupAnalysis &FGA = getAnalysis<FunctionGroupAnalysis>();
1238
1239 VISABuilder *VB = GM.GetCisaBuilder();
1240 if (GM.HasInlineAsm())
1241 VB = GM.GetVISAAsmReader();
1242 IGC_ASSERT(VB);
1243
1244 const auto &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
1245 ModuleToVisaTransformInfo MVTI(*VB, FGA, CG);
1246 if (!DbgOpt_VisaTransformInfoPath.empty()) {
1247 std::string SerializedMVTI;
1248 llvm::raw_string_ostream OS(SerializedMVTI);
1249 MVTI.print(OS);
1250 vc::produceAuxiliaryShaderDumpFile(BC, DbgOpt_VisaTransformInfoPath,
1251 OS.str());
1252 }
1253 LLVM_DEBUG(MVTI.print(dbgs()); dbgs() << "\n");
1254
1255 if (!GM.emitDebugInformation())
1256 return false;
1257
1258 IGC::DebugEmitterOpts DebugInfoOpts;
1259 fillDbgInfoOptions(BC, DebugInfoOpts);
1260
1261 for (const Function *PF : MVTI.getPrimaryFunctions())
1262 processPrimaryFunction(DebugInfoOpts, MVTI, GM, *VB, *PF);
1263
1264 return false;
1265 }
1266
1267 char GenXDebugInfo::ID = 0;
1268
createGenXDebugInfoPass()1269 ModulePass *createGenXDebugInfoPass() {
1270 initializeGenXDebugInfoPass(*PassRegistry::getPassRegistry());
1271 return new GenXDebugInfo;
1272 }
1273
1274 } // namespace llvm
1275
1276 INITIALIZE_PASS_BEGIN(GenXDebugInfo, "GenXDebugInfo", "GenXDebugInfo", false,
1277 true /*analysis*/)
1278 INITIALIZE_PASS_DEPENDENCY(FunctionGroupAnalysis)
1279 INITIALIZE_PASS_DEPENDENCY(GenXBackendConfig)
1280 INITIALIZE_PASS_DEPENDENCY(GenXModule)
1281 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
1282 INITIALIZE_PASS_DEPENDENCY(GenXVisaRegAllocWrapper)
1283 INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
1284 INITIALIZE_PASS_END(GenXDebugInfo, "GenXDebugInfo", "GenXDebugInfo", false,
1285 true /*analysis*/)
1286