@@ -34,6 +34,186 @@ SPDX-License-Identifier: MIT
3434
3535#include " Probe/Assertion.h"
3636
37+ //
38+ // / GenXDebugInfo
39+ // / -------------
40+ // /
41+ // / The goal of the pass is to provide debug information for each generated
42+ // / genisa instruction (if such information is available). The debug
43+ // / information is encoded in DWARF format.
44+ // /
45+ // / Ultimately, the pass gets data from 2 sources:
46+ // /
47+ // / 1. LLVM debug information encoded in LLVM IR itself. It captures the
48+ // / important pieces of the source language's Abstract Syntax Tree and
49+ // / maps it onto LLVM code.
50+ // / LLVM framework should maintain it automatically, given that we follow
51+ // / relatively simple rules while designing IR transformations:
52+ // / https://llvm.org/docs/HowToUpdateDebugInfo.html
53+ // /
54+ // / 2. Debug information obtained from the finalizer. This information is
55+ // / encoded in some proprietary format (blob) and contains the following:
56+ // / a. mapping between vISA and genISA instructions
57+ // / b. live intervals of the virtual registers, information about spilled
58+ // / values, etc.
59+ // / c. call frame information
60+ // /
61+ // / The pass feeds the above information to the DebugInfo library which in turn
62+ // / produces the final DWARF.
63+ // /
64+ // / Operation of the pass
65+ // / ^^^^^^^^^^^^^^^^^^^^^
66+ // /
67+ // / The pass assumes that some data is already being made available by other
68+ // / passes/analysis.
69+ // /
70+ // / * FunctionGroupAnalysis:
71+ // / provides information about the overall "structure"
72+ // / of the program: functions, stack calls, indirect calls, subroutines and
73+ // / relationships.
74+ // /
75+ // / * GenXModule:
76+ // / 1. for each LLVM Function provides information about
77+ // / LLVM instruction -> vISA instructions mapping. This information is
78+ // / produced/maintained during operation of CISABuilder pass.
79+ // / 2. for each LLVM Function provides access to a corresponding
80+ // / *VISAKernel* object.
81+ // /
82+ // / * GenXVisaRegAlloc:
83+ // / provides the mapping between LLVM values and virtual registers.
84+ // /
85+ // / * GenXCisaBuilder:
86+ // / provides access to VISABuilder, which allows us to have access to
87+ // / VISAKernel objects (some Functions from LLVM IR, like the ones
88+ // / representing kernel spawns these) that contain:
89+ // / a. debug information maintained by finalizer (see above)
90+ // / b. the respected gen binaries
91+ // /
92+ // / Data Structures
93+ // / ^^^^^^^^^^^^^^^
94+ // /
95+ // / Since data is aggregated from different sources, some extra data structures
96+ // / are used to simplify bookkeeping.
97+ // /
98+ // / - *genx::di::VisaMapping*
99+ // / provides the mapping from LLMV IR instruction to vISA instruction index,
100+ // / that represents the first vISA instruction spawned by the LLVM IR
101+ // / instruction. A single LLVM IR instruction can spawn several
102+ // / vISA instructions - currently the number of spawned instructions is
103+ // / derived implicitly (which is not always correct but works in most of the
104+ // / cases).
105+ // /
106+ // / - *ProgramInfo*
107+ // / A transient object that groups several llvm Functions that are eventually
108+ // / get compiled into a single gen entity. A separate elf file with the
109+ // / debug information is generated for each gen entity.
110+ // /
111+ // / The grouping is done as follows:
112+ // / - We piggyback on FunctionGroup analysis. Each kernel function becomes the
113+ // / head of the group. Different FunctionGroups always result in different
114+ // / *ProgramInfo* objects. However, a single FunctionGroup can be split even
115+ // / further. This can happen if we have an indirect call to some function. In
116+ // / this case, this function shall is compiled into a separate gen object
117+ // / (and a separate VISAKernel is produced aswell).
118+ // /
119+ // / The above approach does not work correctly in all cases. See
120+ // / *KNOWN ISSUES* section.
121+ // /
122+ // / - *CompiledVisaWrapper*
123+ // / For an arbitrary pair of llvm IR Function and VISAKernel objects,
124+ // / does the following:
125+ // / + Validates that IR Function and VISAKernel object are related (that is
126+ // / the vISA spawned by IR Function is owned by the VISAKernel.
127+ // / + Extracts Gen Binary.
128+ // / + Extracts Debug Info Blob from finalizer and decodes it.
129+ // /
130+ // / *GenXFunction*
131+ // / An object that loosely resembles MachineFunctoin from the LLVM Machine IR.
132+ // / This is an object that for a given LLVM IR Function can access to:
133+ // / - LLVM IR Function
134+ // / - VisaMapping
135+ // / - Subtarget
136+ // / - CompiledVisaWrapper
137+ // / - GenXVisaRegAlloc
138+ // / GenXFunctoin serves as a primary method to communicate with the DebugInfo
139+ // / library. The data these objects hold allow us to reason about the debug
140+ // / information for any Gen construct (instruction, variable, etc).
141+ // /
142+ // / Examples
143+ // / ^^^^^^^^
144+ // /
145+ // / Examples below use the following naming conventions:
146+ // / K* - kernel function
147+ // / L* - subroutine (non-inlined function)
148+ // / S* - simple stack call
149+ // / I* - indirectly-called function
150+ // /
151+ // / FunctionGroup construction peculiarities.
152+ // /
153+ // / When function groups are constructed, we do some peculiar transformations.
154+ // /
155+ // / Case_1 (FG):
156+ // / Source Code: { K1 calls L1, K2 calls L1 }
157+ // / IR after function groups: { G1 = {K1, L1}, G2 = { K2, L1'} },
158+ // / where L1' is a clone of L1.
159+ // / Case_2 (FG):
160+ // / Source Code: { K1 calls S_1, both call L1 }.
161+ // / IR after function groups: { G1 = {K1, L1, S1, L1' } }.
162+ // / Case_3 (FG):
163+ // / Source Code: { K1 calls I1 and I2 }.
164+ // / IR after function grups { G1 = {K1}, G2 = {I1}, G3={I2} }.
165+ // /
166+ // / VISA/genISA construction peculiarities.
167+ // /
168+ // / Case 1:
169+ // / Source code: K1, K1.
170+ // / Compilation phase:
171+ // / two function groups are created, K1 and K2 are heads.
172+ // / two different VISAKernel produced.
173+ // / DebugInfoGeneration:
174+ // / Decoded Debug info for each VISAKernel contains:
175+ // / one compiled object description.
176+ // / two "*.elf" files are created.
177+ // /
178+ // / Case 2:
179+ // / Source code: K1, S1. K1 calls S1.
180+ // / Compilation phase:
181+ // / 1 function group is created, K1 is the head.
182+ // / 1 VISAKernel and 1 VISAFunction are created.
183+ // / DebugInfoGeneratation:
184+ // / Decoded debug info contains *2* compiled objects.
185+ // / Each object has separate vISA indexes - visa instructions are
186+ // / counted separately. Still, both are compiled into the same gen
187+ // / object, so only one "*.elf" file is emitted.
188+ // /
189+ // / Case 3:
190+ // / Source code: K1, I1. K1 calls I1
191+ // / Compilation phase:
192+ // / 1 function group is created, K1 is the head.
193+ // / Somehow 2 VISAKernels are created.
194+ // / DebugInfoGeneratation:
195+ // / Decoded debug info contains *1* compiled objects (but we have 2
196+ // / VISAKernel).
197+ // / In the end, we emit two "*.elf" files.
198+ // /
199+ // / KNOWN ISSUES
200+ // / ^^^^^^^^^^^^
201+ // /
202+ // / Note: see the "Examples" section for the description of the used naming
203+ // / convention.
204+ // /
205+ // / Case 1: (debug info can't be emitted)
206+ // / Source code: *K1*, *L1* *K1* calls *L1*.
207+ // / Compilation phase:
208+ // / 1 function group is created.
209+ // / 1 VISAKernel produced.
210+ // / DebugInfoGeneration:
211+ // / 1 *ProgramInfo* created { K1, L1}.
212+ // / Decoded Debug info contains 1 compiled object, that has 1 subroutines.
213+ // /
214+ // / Problem: way to map LLVM Function onto subroutine is not implemented.
215+ // ===----------------------------------------------------------------------===//
216+
37217#define DEBUG_TYPE " GENX_DEBUG_INFO"
38218
39219using namespace llvm ;
0 commit comments