LLVM 24.0.0git
SPIRVNonSemanticDebugHandler.h
Go to the documentation of this file.
1//===-- SPIRVNonSemanticDebugHandler.h - NSDI AsmPrinter handler -*- C++
2//-*-===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9//
10// This file declares SPIRVNonSemanticDebugHandler, a DebugHandlerBase subclass
11// that emits NonSemantic.Shader.DebugInfo.100 instructions in the SPIR-V
12// AsmPrinter. It replaces SPIRVEmitNonSemanticDI, which was a
13// MachineFunctionPass, with a handler that controls instruction placement
14// directly instead of routing through SPIRVModuleAnalysis.
15//
16//===----------------------------------------------------------------------===//
17
18#ifndef LLVM_LIB_TARGET_SPIRV_SPIRVNONSEMANTICDEBUGHANDLER_H
19#define LLVM_LIB_TARGET_SPIRV_SPIRVNONSEMANTICDEBUGHANDLER_H
20
22#include "SPIRVModuleAnalysis.h"
23#include "llvm/ADT/DenseMap.h"
24#include "llvm/ADT/DenseSet.h"
25#include "llvm/ADT/SetVector.h"
29#include "llvm/ADT/StringMap.h"
32#include "llvm/MC/MCInst.h"
33#include "llvm/MC/MCRegister.h"
34#include <optional>
35#include <type_traits>
36#include <utility>
37
38namespace llvm {
39
40class GlobalVariable;
41struct SPIRVOptions;
43class SPIRVSubtarget;
44
45/// AsmPrinter handler that emits NonSemantic.Shader.DebugInfo.100 (NSDI)
46/// instructions for the SPIR-V backend. Registered with SPIRVAsmPrinter when
47/// the module contains debug info (llvm.dbg.cu).
48///
49/// Call sequence:
50/// - beginModule() collects compile-unit metadata.
51/// - prepareModuleOutput() adds the extension and ext-inst set to MAI.
52/// - emitNonSemanticDebugStrings() emits NSDI OpStrings in section 7.
53/// - emitNonSemanticGlobalDebugInfo() emits module-scope NSDI and sets
54/// GlobalNSDIEnabled.
55/// - beginFunctionImpl() prepares per-function DebugFunctionDefinition state
56/// and runs analyzeDebugRecords() over the whole function.
57/// - endInstruction() emits DebugFunctionDefinition after the last function-
58/// level OpVariable; SPIRVAsmPrinter calls notifyEntryLabelEmitted() after
59/// the synthesized entry OpLabel when there are no OpVariables.
60/// - beginInstruction() emits the DebugScope and DebugLine for the instruction
61/// being printed, and the DebugDeclare and DebugValue anchored on it.
62/// - endFunctionImpl() resets per-function state.
64 const SPIRVOptions &CLOpts;
65
66 static constexpr unsigned NSSet = static_cast<unsigned>(
67 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100);
68
69 struct CompileUnitInfo {
70 const DICompileUnit *TheCU = nullptr;
71 SmallString<128> FilePath;
72 unsigned SpirvSourceLanguage = 0; // NonSemantic.Shader.DebugInfo.100 source
73 // language code (section 4.3)
74 };
76 int64_t DwarfVersion = 0;
77
79
80 // Compile unit whose enums list names each enum. DIBuilder gives a file-scope
81 // enum a null scope, so this list is the only record of its unit.
83
84 // NonSemantic debug instruction result id per emitted scope.
86
87 enum class EmitStatus {
88 Emitted,
89 Unsupported,
90 InProgress,
91 };
92
93 // One scope instruction, built but not yet emitted. getOrCreateDebugScope
94 // is the only place that emits it.
95 struct PreparedScope {
96 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode{};
98
99 PreparedScope() = default;
100 PreparedScope(SPIRV::NonSemanticExtInst::NonSemanticExtInst Op,
102 : Opcode(Op), Operands(Ops.begin(), Ops.end()) {}
103 };
104
105 // Status plus a payload. Value is set only when the status is Emitted, so
106 // InProgress and Unsupported carry no id and no PreparedScope. The payload
107 // is an id for a scope that already exists, and a PreparedScope for an
108 // instruction that getOrCreateDebugScope has not emitted yet.
109 template <typename T> struct EmitResult {
110 EmitStatus Status = EmitStatus::Unsupported;
111 std::optional<T> Value;
112
113 static EmitResult emitted(T V) {
114 EmitResult R;
115 R.Status = EmitStatus::Emitted;
116 R.Value = std::move(V);
117 return R;
118 }
119 static EmitResult unsupported() { return {}; }
120 static EmitResult inProgress() {
121 EmitResult R;
122 R.Status = EmitStatus::InProgress;
123 return R;
124 }
125
126 template <typename U>
127 static EmitResult failure(const EmitResult<U> &Other) {
128 assert(!Other && "failure() requires a non-emitted result");
129 EmitResult R;
130 R.Status = Other.Status;
131 return R;
132 }
133
134 explicit operator bool() const {
135 assert(Value.has_value() == (Status == EmitStatus::Emitted) &&
136 "payload is set exactly when the result is emitted");
137 if constexpr (std::is_same_v<T, MCRegister>)
138 assert(!Value || Value->isValid());
139 return Status == EmitStatus::Emitted;
140 }
141 };
142
143 // Used to track which scopes are in progress, and which operands are used by
144 // a forward references. Operands must be later defined even if the scope
145 // fails to emit.
146 struct InProgressScope {
147 MCRegister Id;
148 bool ForwardReferenced = false;
149 };
150
151 // Types and scopes whose instruction is currently being built.
153
154 // True when -spirv-debug-scope-forward-refs is set and prepareModuleOutput
155 // saw SPV_KHR_relaxed_extended_instruction.
156 bool HasRelaxedExtInst = false;
157
158 // Types and scopes that are not supported.
160
161 // DISubprogram nodes collected in beginModule().
163
164 // Distinct DILocations from instruction !dbg attachments and debug program
165 // records (#dbg_declare, #dbg_value, #dbg_assign, #dbg_label).
166 SetVector<const DILocation *> UniqueDebugLocations;
167
168 struct GlobalVariableDebugInfo {
169 const DIExpression *Expr = nullptr;
170 const GlobalVariable *LLVMGV = nullptr;
171 };
173 GlobalVariableDebugInfoMap;
174
175 // Distinct DILocalVariable nodes collected in beginModule() from dbg records
176 // and from DISubprogram retained nodes.
178
179 // DebugLocalVariable result id per variable that module-scope emission
180 // actually emitted. DebugDeclare needs it for its Local Variable operand; a
181 // variable missing here (skipped type or scope) gets no declare.
183
184 // DebugExpression result id per DIExpression that could be lowered. An
185 // expression missing here uses operations with no NonSemantic counterpart,
186 // so declares referencing it are skipped rather than described wrongly.
188
189 // Distinct DILexicalBlock, DINamespace, and DILexicalBlockFile scopes,
190 // parent-before-child order, collected in beginModule().
191 SetVector<const DIScope *> LexicalBlocks;
192
193 // DebugInlinedAt result id per DILocation used as an inlined-at chain link.
195
196 // Path \c OpString result id per \c DIScope (CU, \c DIFile, declaration
197 // \c DISubprogram, …). Filled during \c emitNonSemanticDebugStrings() using
198 // \c getDebugFullPath + \c emitOpStringIfNew; section 10 uses it for
199 // \c DebugSource without recomputing path text.
200 DenseMap<const DIScope *, MCRegister> ScopeToPathOpStringReg;
201
202 // DebugSource result id keyed by path \c OpString id (\c MCRegister::id()),
203 // deduplicating when the same file string is reused.
204 DenseMap<unsigned, MCRegister> DebugSourceRegByFileStr;
205
206 // Maps OpString contents to result id. Populated only by emitOpStringIfNew()
207 // during section 7; section 10 uses getCachedOpStringReg() (lookup only).
208 StringMap<MCRegister> OpStringContentCache;
209
210#ifndef NDEBUG // Only declare the variable for debugging purposes.
211 // True after emitNonSemanticDebugStrings() emitted the NSDI OpStrings for
212 // this module. SPIRVAsmPrinter calls that before
213 // emitNonSemanticGlobalDebugInfo().
214 bool NonSemanticOpStringsSectionEmitted = false;
215#endif
216
217 MCRegister CachedEmptyStringReg;
218
219 MCRegister CachedDebugInfoNoneReg;
220
221 MCRegister CachedOpTypeVoidReg;
222
223 MCRegister CachedOpTypeInt32Reg;
224
225 // Result id per SPIR-V scalar type this handler needed, keyed by opcode and
226 // width. MB_TypeConstVars holds only what module analysis collected, so a
227 // type emitted here has to be remembered separately to stay unique.
229
230 // Result id per scalar constant, keyed by its type's id and its bits. Keying
231 // on the type lets two DIBasicTypes describing it share a constant.
233
234 // Result id per collected constant, keyed by its type and bits. Filled
235 // during module-scope emission, since an OpConstant has to precede every
236 // function body that names it.
238 ConstantValueRegs;
239
240 // Cache of already-emitted DebugOperation instructions, keyed by NonSemantic
241 // opcode followed by the 32-bit operation arguments. Inline size 3 is the
242 // spec maximum (opcode plus at most two operands: BitPiece, Fragment).
243 DenseMap<SmallVector<uint32_t, 3>, MCRegister> DebugOperationCache;
244
245 // Cache of already-emitted DebugExpression instructions, keyed by the
246 // DebugOperation result ids in operand order. Useful for debug values
247 // and global-variable init expressions.
248 DenseMap<SmallVector<MCRegister>, MCRegister> DebugExpressionCache;
249
250 // True once emitNonSemanticGlobalDebugInfo() has run. Both
251 // SPIRVAsmPrinter::emitFunctionHeader() and emitEndOfAsmFile() may call
252 // outputModuleSections(), each guarded by ModuleSectionsEmitted, so only
253 // one fires. This flag provides a secondary guard in case the call sites
254 // change.
255 bool GlobalDIEmitted = false;
256
257 // True when emitNonSemanticGlobalDebugInfo() completed module-scope NSDI
258 // emission for this module.
259 bool GlobalNSDIEnabled = false;
260
261 SPIRV::ModuleAnalysisInfo *CurrentMAI = nullptr;
262
263 const MachineFunction *CurrentMF = nullptr;
264
265 const MachineInstr *LastFunctionOpVariable = nullptr;
266
267 bool DebugFunctionDefinitionEmitted = false;
268
269 // Instruction that opened the DebugLine / DebugScope region currently in
270 // effect, or nullptr when no region is open. The two are tracked separately
271 // because a DebugScope region usually spans several DebugLine regions, and
272 // either one can skip emission on a cache miss.
273 const MachineInstr *LastLineMI = nullptr;
274 const MachineInstr *LastScopeMI = nullptr;
275
276 // Result ids in MB_TypeConstVars, which precedes every function body. Filled
277 // once per module in prepareModuleOutput().
278 DenseSet<MCRegister> ModuleScopeIds;
279
280 /// A DebugDeclare or DebugValue waiting for its anchor to be printed.
281 struct DebugRecord {
282 const MachineInstr *MI; ///< The DBG_VALUE this came from.
283 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode;
284 MCRegister LocationReg; ///< The Variable or Value operand.
285 };
286
287 // Records to emit before their anchor is printed, built once per function by
288 // analyzeDebugRecords() and only read afterwards.
290
291public:
293
294 /// Collect compile-unit metadata from the module. Called by
295 /// AsmPrinter::doInitialization() via the handler list. No emission.
296 void beginModule(Module *M) override;
297
298 /// Emit OpString instructions for all NSDI file paths and basic type names
299 /// into the debug section (section 7 of the SPIR-V module layout). Must be
300 /// called from SPIRVAsmPrinter::outputDebugSourceAndStrings(), after
301 /// prepareModuleOutput() has registered the ext inst set. Registers are
302 /// stored in \c OpStringContentCache and \c ScopeToPathOpStringReg;
303 /// \c emitNonSemanticGlobalDebugInfo() resolves them via
304 /// \c getCachedOpStringReg() and path maps.
306
307 /// Add SPV_KHR_non_semantic_info extension and
308 /// NonSemantic.Shader.DebugInfo.100 ext inst set entry to MAI. Must be called
309 /// before outputGlobalRequirements() and outputOpExtInstImports() in
310 /// SPIRVAsmPrinter::outputModuleSections().
311 void prepareModuleOutput(const SPIRVSubtarget &ST,
313
314 /// Emit module-scope NSDI instructions (DebugSource, DebugCompilationUnit,
315 /// DebugTypeBasic, DebugTypePointer, DebugTypeFunction,
316 /// DebugFunctionDeclaration, DebugFunction). Called by
317 /// SPIRVAsmPrinter::outputModuleSections() at section 10 in place of
318 /// outputModuleSection(MB_NonSemanticGlobalDI). Requires
319 /// emitNonSemanticDebugStrings() to have run first when NSDI strings apply.
320 /// Sets \c GlobalNSDIEnabled when module-scope NSDI emission completes.
322
323 /// Called after the synthesized entry \c OpLabel has been emitted.
325
326protected:
327 // All module-level output is driven by emitNonSemanticGlobalDebugInfo(),
328 // called explicitly from SPIRVAsmPrinter::outputModuleSections(). Nothing
329 // needs to happen in the AsmPrinterHandler::endModule() callback.
330 void endModule() override {}
331
332 // DebugHandlerBase stores MMI as a pointer copy from Asm->MMI at construction
333 // time (DebugHandlerBase.cpp: `MMI(Asm->MMI)`). The handler is constructed
334 // before AsmPrinter::doInitialization() runs, so Asm->MMI is null at that
335 // point and MMI remains null for this handler's entire lifetime. Do not call
336 // the base-class beginInstruction/endInstruction — they dereference MMI to
337 // create temp symbols for label tracking and would crash.
338 // Future local NSDI that needs MCContext must use
339 // Asm->OutStreamer->getContext() rather than MMI->getContext().
340 void beginInstruction(const MachineInstr *MI) override;
341 void endInstruction() override;
342
343 // Override beginFunctionImpl(), not beginFunction():
344 // DebugHandlerBase::beginFunction() populates LScopes and DbgValues needed
345 // for future DebugLine emission.
346 void beginFunctionImpl(const MachineFunction *MF) override;
347 void endFunctionImpl(const MachineFunction *MF) override;
348
349private:
350 void emitDebugFunctionDefinition(MCRegister DebugFunctionReg,
351 MCRegister OpFunctionReg,
353
354 void resetPerFunctionDebugState();
355
356 /// Resolve the instruction that a per-instruction DebugLine/DebugScope
357 /// update should attach to: \p MI adjusted forward past a merge
358 /// instruction to its terminator, or \c std::nullopt if \p MI is not a
359 /// valid attachment point (skip-emission, or one of the structural opcodes
360 /// that can never carry DebugLine/DebugScope: OpFunction,
361 /// OpFunctionParameter, OpFunctionEnd, OpLabel, OpPhi).
362 std::optional<const MachineInstr *>
363 resolveDebugLocTarget(const MachineInstr *MI);
364
365 /// Open the DebugScope region \p MI belongs to, closing the previous one.
366 ///
367 /// \returns False when \p MI's scope has no \c DebugScope, or its chain no
368 /// \c DebugInlinedAt, leaving the open region someone else's.
369 bool emitDebugScopeForInstruction(const MachineInstr *MI);
370 void emitDebugLineForInstruction(const MachineInstr *MI);
371 void preparePerFunctionDebug(const MachineFunction *MF);
372 void tryEmitDebugFunctionDefinition(SPIRV::ModuleAnalysisInfo &MAI);
373
374 void emitMCInst(MCInst &Inst);
375 MCRegister emitOpString(StringRef S, SPIRV::ModuleAnalysisInfo &MAI);
376
377 /// Section 7 only: emit OpString and cache it if not already present. Must
378 /// not be called after NonSemanticOpStringsSectionEmitted is set. Returns
379 /// the path (or string) \c OpString result id.
380 MCRegister emitOpStringIfNew(StringRef S, SPIRV::ModuleAnalysisInfo &MAI);
381
382 /// Section 10 only: lookup OpString id from cache; asserts if missing or if
383 /// section 7 did not complete.
384 MCRegister getCachedOpStringReg(StringRef S);
385
386 /// Section 7 only: emit the path \c OpString for \p Scope and cache it under
387 /// \p Scope. Returns the \c OpString result id. A \p Scope already seen
388 /// returns the cached id without rebuilding the path. A null \p Scope maps to
389 /// the empty path and is cached like any other, though section 10 reads it
390 /// through \c getCachedScopePathOpStringReg, which handles null separately.
391 MCRegister emitAndCacheScopePathOpStringReg(const DIScope *Scope,
393
394 /// Section 10 only: lookup path \c OpString id for \p Scope from
395 /// \c ScopeToPathOpStringReg; asserts if missing or invalid. When
396 /// \p UseEmptyPathIfNullScope is true and \p Scope is null, returns
397 /// \c CachedEmptyStringReg instead.
399 getCachedScopePathOpStringReg(const DIScope *Scope,
400 bool UseEmptyPathIfNullScope = false);
401 MCRegister emitOpConstantI32(uint32_t Value, MCRegister I32TypeReg,
403
404 /// Mark in-progress scopes named by \p Operands. Return true when any
405 /// operand is such an id. A marked id needs a definition if that scope fails.
406 bool markForwardReferencedOperands(ArrayRef<MCRegister> Operands);
407
408 MCRegister emitExtInst(SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
409 MCRegister VoidTypeReg, MCRegister ExtInstSetReg,
412 std::optional<MCRegister> ResultReg = std::nullopt);
413
414 /// Return OpTypeVoid id for this module (lazy lookup / emit, then cache).
415 MCRegister getOrEmitOpTypeVoidReg(SPIRV::ModuleAnalysisInfo &MAI);
416
417 /// Return OpTypeInt 32 0 id for this module (lazy lookup / emit, then cache).
418 MCRegister getOrEmitOpTypeInt32Reg(SPIRV::ModuleAnalysisInfo &MAI);
419
420 /// Find OpTypeVoid in the already-emitted TypeConstVars section, or emit one
421 /// if the module does not contain it (e.g. no void-returning functions).
422 MCRegister findOrEmitOpTypeVoid(SPIRV::ModuleAnalysisInfo &MAI);
423
424 /// Find OpTypeInt 32 0 in the already-emitted TypeConstVars section, or emit
425 /// one if the module does not contain it.
426 MCRegister findOrEmitOpTypeInt32(SPIRV::ModuleAnalysisInfo &MAI);
427
428 /// Return the id for the type or scope \p S, emitting it and the types and
429 /// scopes it names first. One already in \c DebugScopeRegs is Emitted. A null
430 /// \p S or one in \c FailedScopes is Unsupported. Entering a scope reserves
431 /// its result id. A back edge (\p S already in \c ScopesInProgress) returns
432 /// that id when \c HasRelaxedExtInst is set, and InProgress otherwise. If
433 /// emission fails after an emitted instruction used that id, it is defined as
434 /// DebugInfoNone. An id that nothing named stays undefined. An Unsupported
435 /// result is recorded in \c FailedScopes; an InProgress one is not, so a
436 /// later walk can retry it.
437 EmitResult<MCRegister> getOrCreateDebugScope(const DIScope *S);
438
439 /// Build the instruction for \p S. Only \c getOrCreateDebugScope calls this
440 /// and emits it.
441 EmitResult<PreparedScope> emitDebugScope(const DIScope *S);
442
443 /// Build the \c DebugType* instruction for \p CT, picked by its tag.
444 EmitResult<PreparedScope> emitDebugTypeForCompositeType(
445 const DICompositeType *CT, MCRegister VoidTypeReg, MCRegister I32TypeReg,
446 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI);
447
448 /// Build the \c DebugType* instruction for \p DT, picked by its tag.
449 EmitResult<PreparedScope>
450 emitDebugTypeForDerivedType(const DIDerivedType *DT, MCRegister VoidTypeReg,
451 MCRegister I32TypeReg, MCRegister ExtInstSetReg,
453
454 /// Build \c DebugTypeBasic for \p BT. Unsupported when the size does not fit
455 /// in 32 bits.
456 EmitResult<PreparedScope> emitDebugTypeBasic(const DIBasicType *BT,
457 MCRegister I32TypeReg,
459
460 /// Build \c DebugTypePointer for \p PT. Unsupported without a DWARF address
461 /// space, which gives the storage class.
462 EmitResult<PreparedScope>
463 emitDebugTypePointer(const DIDerivedType *PT, SPIRV::ModuleAnalysisInfo &MAI);
464
465 /// Build one DebugTypeFunction for ST when every DI operand maps to a debug
466 /// type id; otherwise build nothing and return the first failing slot's
467 /// status.
468 EmitResult<PreparedScope>
469 emitDebugTypeFunctionForSubroutineType(const DISubroutineType *ST,
471
472 /// Build \c DebugFunctionDeclaration for the non-defining subprogram \p SP.
473 EmitResult<PreparedScope>
474 emitDebugFunctionDeclaration(const DISubprogram *SP, MCRegister VoidTypeReg,
475 MCRegister I32TypeReg, MCRegister ExtInstSetReg,
477
478 /// Build \c DebugFunction for the defining subprogram \p SP.
479 EmitResult<PreparedScope> emitDebugFunction(const DISubprogram *SP,
480 MCRegister VoidTypeReg,
481 MCRegister I32TypeReg,
482 MCRegister ExtInstSetReg,
484
485 /// Emit \c DebugLocalVariable for the source local variable \p LV:
486 /// Name, Type, Source, Line, Column, Parent, Flags, and an optional Arg
487 /// Number. Line, Column, Flags, and Arg Number are emitted as \c OpConstant
488 /// ids as required for non-semantic debug info. Column is always 0:
489 /// \c DILocalVariable has no column field.
490 ///
491 /// Arg Number is appended when \p LV is a parameter.
492 ///
493 /// \returns The result id register on success. Returns \c std::nullopt and
494 /// emits nothing if \p LV's scope is not an emitted local scope,
495 /// if a non-null type was not emitted in \c DebugScopeRegs, or if
496 /// \c resolveScope returns no id for the Parent operand.
497 std::optional<MCRegister>
498 emitDebugLocalVariable(const DILocalVariable *LV, MCRegister VoidTypeReg,
499 MCRegister I32TypeReg, MCRegister ExtInstSetReg,
501
502 /// Emit \c DebugGlobalVariable for the source global variable \p GV.
503 ///
504 /// (\c SPIRVDebug::Operand::GlobalVariable): Name, Type, Source, Line,
505 /// Column, Parent, Linkage Name, Variable, Flags, and an optional Static
506 /// Member Declaration. Line, Column, and Flags are emitted as \c OpConstant
507 /// ids as required for non-semantic debug info.
508 ///
509 /// \c DebugInfoNone is used for two operands when LLVM has no value to
510 /// supply:
511 /// \c Type when \p GV is a declaration with no DI type (e.g. \c extern void;
512 /// valid IR, \c isDefinition: false); \c Variable when no \c
513 /// llvm::GlobalVariable in this module carries \p GV in its \c !dbg metadata.
514 ///
515 /// \returns The result id register on success. Returns \c std::nullopt and
516 /// emits nothing if a non-null \p GV type was not emitted in \c
517 /// DebugScopeRegs, or \p GV has a static data member declaration that was not
518 /// emitted in \c DebugScopeRegs.
519 std::optional<MCRegister> emitDebugGlobalVariable(
520 const DIGlobalVariable *GV, const GlobalVariableDebugInfo &Info,
521 MCRegister VoidTypeReg, MCRegister I32TypeReg, MCRegister ExtInstSetReg,
523
524 /// Collect the \c DIExpression of every debug value in the module
525 /// (\c DBG_VALUE, \c DBG_VALUE_LIST, \c DBG_INSTR_REF), in MIR order.
526 ///
527 /// Reads MIR rather than IR because only MIR shows which debug values
528 /// survived codegen and in what form, and because an expression synthesized
529 /// during lowering never appears in the IR at all. Must be called from
530 /// module-scope emission, which is where the resulting \c DebugExpression
531 /// instructions have to be emitted. The debug values come from
532 /// \c SPIRVModuleAnalysis, which sees every \c MachineFunction.
533 ///
534 /// Deliberately independent of what the consumers can currently emit, so
535 /// that adding an instruction that needs an expression (\c DebugValue) needs
536 /// no change here. The cost is a \c DebugExpression that nothing references
537 /// yet, for a debug value no instruction is emitted for.
538 void collectDebugExpressions(const SPIRV::ModuleAnalysisInfo &MAI,
540
541 /// Emit one \c DebugOperation for \p Op, reusing a cached result id when the
542 /// same opcode and arguments were already emitted.
543 ///
544 /// \returns The result id register on success. Returns \c std::nullopt and
545 /// emits nothing if \p Op has no NonSemantic counterpart, or carries an
546 /// argument too large for the 32-bit \c OpConstant operands this set
547 /// requires.
548 std::optional<MCRegister>
549 emitDebugOperation(const DIExpression::ExprOperand &Op,
550 MCRegister VoidTypeReg, MCRegister I32TypeReg,
551 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI);
552
553 /// Emit one \c DebugOperation per element of \p Expr followed by the
554 /// \c DebugExpression that lists them. Reuses a cached \c DebugExpression
555 /// when that sequence of \c DebugOperation ids was already emitted. An
556 /// empty \p Expr yields a \c DebugExpression with no operands, which is
557 /// what a plain \c !DIExpression() means.
558 ///
559 /// Must be called from module-scope emission only: \c DebugExpression and
560 /// \c DebugOperation are not in the spec's list of instructions allowed
561 /// inside a function, and forward references were removed in Rev 2.
562 ///
563 /// \returns The result id register on success. Returns \c std::nullopt and
564 /// does not emit the \c DebugExpression if any element has no NonSemantic
565 /// counterpart, or carries an argument too large for the 32-bit \c OpConstant
566 /// operands this set requires.
567 std::optional<MCRegister> emitDebugExpression(const DIExpression *Expr,
568 MCRegister VoidTypeReg,
569 MCRegister I32TypeReg,
570 MCRegister ExtInstSetReg,
572
573 /// Fill \c Records from the debug records in \p MF.
574 ///
575 /// Where a record may legally sit is a property of the whole function, and
576 /// emission is unbuffered, so it is settled here rather than while printing.
577 void analyzeDebugRecords(const MachineFunction &MF);
578
579 /// Place the single record \p MI. \p LastEmitted is the nearest preceding
580 /// instruction in this block that reaches the output, or null when there is
581 /// none.
582 ///
583 /// Places nothing when this backend cannot name the record: an unavailable
584 /// location, a declare whose storage is not an \c OpVariable, a constant
585 /// with no module-scope id, a physical register, a variadic value, an
586 /// instruction reference, or a definition that does not dominate \p MI.
587 void resolveDebugRecord(const MachineInstr &MI,
588 const MachineInstr *LastEmitted,
589 const MachineDominatorTree &DomTree);
590
591 /// Store \p MI on \p Anchor, to emit before \p Anchor is printed.
592 void placeRecord(SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
593 const MachineInstr &MI, MCRegister LocationReg,
594 const MachineInstr *Anchor);
595
596 void emitAnalyzedRecords(const MachineInstr *Anchor);
597
598 /// The \c OpConstant id for the constant \p MI assigns, or \c std::nullopt
599 /// when \p MI assigns no constant this backend emitted.
600 std::optional<MCRegister> getConstantValueReg(const MachineInstr &MI) const;
601
602 /// Result id of the constant \p Opcode of type \p TypeReg holding
603 /// \p Value in \c MB_TypeConstVars, or an invalid register when the module
604 /// does not already define it.
605 MCRegister findModuleConstant(unsigned Opcode, MCRegister TypeReg,
606 uint64_t Value, bool IsBool, bool IsWide,
608
609 /// Result id of the SPIR-V type for \p BT, reusing one from
610 /// \c MB_TypeConstVars when the module already defines it. Invalid when
611 /// declaring it would require a capability the module does not have, since
612 /// debug info must not change what the module requires.
613 MCRegister findOrEmitScalarType(const DIBasicType *BT,
615
616 /// Result id of the constant \p Value, with \p BT giving both the SPIR-V
617 /// type and the opcode. Invalid when the type may not be created.
618 MCRegister findOrEmitScalarConstant(const DIBasicType *BT, uint64_t Value,
620
621 /// Result id of the constant \p Value of type \p TypeReg, reusing one from
622 /// \c MB_TypeConstVars or from an earlier call when either already has it.
623 MCRegister findOrEmitConstant(unsigned Opcode, MCRegister TypeReg,
624 uint64_t Value, unsigned Width,
626
627 /// Emit \p Opcode naming \p MI's variable, \p LocationReg and \p MI's
628 /// expression, after \p MI's own \c DebugScope and \c DebugLine. Emits
629 /// nothing when \p MI's variable has no \c DebugLocalVariable, its
630 /// expression no \c DebugExpression, or its scope no id.
631 void emitDebugBinding(SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
632 const MachineInstr *MI, MCRegister LocationReg);
633
634 /// Build \c DebugTypeVector for the vector composite type \p VT.
635 ///
636 /// \returns Emitted when the operands are ready. Unsupported, building
637 /// nothing, if \p VT has no \c DIBasicType base type, if \p VT has more than
638 /// one \c DISubrange element, or if the component count is not a
639 /// compile-time constant. If the base cannot be emitted, returns its status.
640 EmitResult<PreparedScope> emitDebugTypeVector(const DICompositeType *VT,
642
643 /// Build \c DebugTypeArray for the array composite type \p AT.
644 ///
645 /// Operands are the element (base) type id followed by one Component Count
646 /// per \c DISubrange, in DWARF subrange order. A count that is not a
647 /// compile-time constant is 0, matching \c OpTypeRuntimeArray. A matrix
648 /// arrives here as a multi-subrange array and is built with one count per
649 /// dimension.
650 ///
651 /// \returns Emitted when the operands are ready. If \p AT's element type
652 /// cannot be emitted, builds nothing and returns the element's status.
653 EmitResult<PreparedScope> emitDebugTypeArray(const DICompositeType *AT,
655
656 /// Build \c DebugTypeMember for the data member \p M (a \c DIDerivedType with
657 /// \c DW_TAG_member). Operands: Name, Type, Source, Line, Column, Offset,
658 /// Size, Flags. NonSemantic \c DebugTypeMember carries no Parent operand: the
659 /// enclosing \c DebugTypeComposite references its members, not the reverse.
660 ///
661 /// \returns Emitted when the operands are ready. Returns the base's status
662 /// and builds nothing if \p M's type cannot be emitted.
663 EmitResult<PreparedScope> emitDebugTypeMember(const DIDerivedType *M,
664 MCRegister VoidTypeReg,
665 MCRegister I32TypeReg,
666 MCRegister ExtInstSetReg,
668
669 /// Build \c DebugTypeComposite for the struct, class, or union \p CT, after a
670 /// \c DebugTypeMember for each data member whose type can be emitted. A
671 /// forward declaration uses \c DebugInfoNone for Size and no members.
672 ///
673 /// \returns Emitted when the operands are ready. Builds nothing and returns
674 /// the parent's status if the Parent scope cannot be resolved, or
675 /// Unsupported if the size does not fit in 32 bits. Both are checked before
676 /// any member is streamed. A member whose type fails is dropped, whatever
677 /// the reason, and does not fail the composite.
678 EmitResult<PreparedScope>
679 emitDebugTypeComposite(const DICompositeType *CT, MCRegister VoidTypeReg,
680 MCRegister I32TypeReg, MCRegister ExtInstSetReg,
682
683 /// Build \c DebugTypeEnum for the enumeration type \p ET. Operands: Name,
684 /// Underlying Type, Source, Line, Column, Parent, Size, Flags, then a Value
685 /// and Name pair per enumerator. Uses \c DebugInfoNone for Underlying Type
686 /// when \p ET has no base type, and drops an enumerator whose value does not
687 /// fit in a 32-bit integer.
688 ///
689 /// \returns An Emitted result when the operands are ready. An Unsupported
690 /// result, building nothing, if the size is 0 or does not fit in 32 bits.
691 /// If the base or Parent fail, it returns code for the one that failed.
692 EmitResult<PreparedScope> emitDebugTypeEnum(const DICompositeType *ET,
693 MCRegister VoidTypeReg,
694 MCRegister I32TypeReg,
695 MCRegister ExtInstSetReg,
697
698 /// Build \c DebugTypedef for the typedef derived type \p TD (a \c
699 /// DIDerivedType with \c DW_TAG_typedef). Operands: Name, Base Type, Source,
700 /// Line, Column, Parent. Parent is the enclosing type when \c TD->getScope()
701 /// is an emitted \c DIType, otherwise the first module \c
702 /// DebugCompilationUnit.
703 ///
704 /// \returns The base's or Parent's status if either fails.
705 EmitResult<PreparedScope> emitDebugTypedef(const DIDerivedType *TD,
706 MCRegister VoidTypeReg,
707 MCRegister I32TypeReg,
708 MCRegister ExtInstSetReg,
710
711 /// Map a \c DISubroutineType::getTypeArray() element to an operand register
712 /// for
713 /// \c DebugTypeFunction. A non-null \p Ty is created through
714 /// \c getOrCreateDebugScope, and its status is returned. A null \p Ty is not
715 /// a \c getOrCreateDebugScope call and is always Emitted.
716 ///
717 /// LLVM encodes a void return as a null first element (and may use null in
718 /// later slots). NonSemantic \c DebugTypeFunction
719 /// requires a concrete return-type operand, so when \p ReturnType is true and
720 /// \p Ty is null, this returns \p VoidTypeReg (\c OpTypeVoid). When
721 /// \p ReturnType is false and \p Ty is null, this returns
722 /// \c CachedDebugInfoNoneReg (\c DebugInfoNone).
723 EmitResult<MCRegister> mapDISignatureTypeToReg(const DIType *Ty,
724 MCRegister VoidTypeReg,
725 bool ReturnType);
726
727 /// Map a DWARF source language code to a NonSemantic.Shader.DebugInfo.100
728 /// source language code.
729 static unsigned toNSDISrcLang(unsigned DwarfSrcLang);
730
731 /// Build a full path from debug \p Scope for OpString / DebugSource, matching
732 /// SPIRV-LLVM-Translator \c getFullPath (OCLUtil.h): \c DIScope::getFilename,
733 /// \c getDirectory, and \c sys::path::Style::native. Works for any \c DIScope
734 /// that carries file path fields (e.g. \c DIFile, \c DISubprogram,
735 /// \c DICompileUnit). Returns an empty path when \p Scope is null.
736 SmallString<128> getDebugFullPath(const DIScope *Scope) const;
737
738 /// Return an existing \c DebugSource id for file path \c OpString \p
739 /// FileStrReg or emit \c DebugSource and cache it (keyed by \p FileStrReg
740 /// id).
741 MCRegister getOrEmitDebugSourceForFileStrReg(MCRegister FileStrReg,
742 MCRegister VoidTypeReg,
743 MCRegister ExtInstSetReg,
745
746 /// Map \p Scope to the NonSemantic debug id used as a \c Parent operand.
747 ///
748 /// A \c DIType, \c DILexicalBlock, \c DINamespace, or \c DISubprogram scope
749 /// is created through \c getOrCreateDebugScope. When
750 /// \c -spirv-debug-lexical-block-discriminator-scope is enabled, a
751 /// \c DILexicalBlockFile is also created this way, becoming a
752 /// \c DebugLexicalBlockDiscriminator; otherwise it is unwrapped to its
753 /// enclosing scope first. When \p Scope is null, a \c DIFile, or another
754 /// scope without a dedicated debug instruction, it falls back to
755 /// \p FallbackCU or the first module \c DebugCompilationUnit recorded in
756 /// \c DebugScopeRegs; no such compile unit is Unsupported.
757 EmitResult<MCRegister>
758 resolveScope(const DIScope *Scope, const DICompileUnit *FallbackCU = nullptr);
759
760 /// Build \c DebugLexicalBlock for \p S, which must be a \c DILexicalBlock or
761 /// a \c DINamespace. A \c DILexicalBlock supplies Line/Column
762 /// from \c getLine()/getColumn(); a \c DINamespace has neither, so both are
763 /// 0, and its Name is appended as an extra \c OpString operand.
764 ///
765 /// \returns Emitted when the operands are ready. If \c resolveScope cannot
766 /// emit \c S->getScope(), builds nothing and returns that status.
767 EmitResult<PreparedScope>
768 emitDebugLexicalBlock(const DIScope *S, MCRegister VoidTypeReg,
769 MCRegister I32TypeReg, MCRegister ExtInstSetReg,
771
772 /// Build \c DebugLexicalBlockDiscriminator for \p LBF.
773 /// Operands are Source, Discriminator, and Parent (\c LBF->getScope()).
774 EmitResult<PreparedScope> emitDebugLexicalBlockDiscriminator(
775 const DILexicalBlockFile *LBF, MCRegister VoidTypeReg,
776 MCRegister I32TypeReg, MCRegister ExtInstSetReg,
778
779 /// Return a cached \c DebugInlinedAt id for \p IA, or emit one (recursing
780 /// into \c IA->getInlinedAt() first for the optional Inlined operand, so
781 /// outer frames are always emitted before the inner frame that references
782 /// them). Must run after \c DebugScopeRegs is populated, since the Scope
783 /// operand is resolved through \c resolveScope. \c DebugInlinedAt is not in
784 /// the spec's in-block instruction list, so this is only ever called from
785 /// module-scope emission (\c emitNonSemanticGlobalDebugInfo), never from
786 /// per-instruction emission.
787 ///
788 /// \returns An invalid (default-constructed) \c MCRegister, and emits
789 /// nothing, if \p IA's Scope does not resolve.
790 MCRegister getOrEmitDebugInlinedAt(const DILocation *IA,
791 MCRegister VoidTypeReg,
792 MCRegister I32TypeReg,
793 MCRegister ExtInstSetReg,
795};
796
797} // namespace llvm
798
799#endif // LLVM_LIB_TARGET_SPIRV_SPIRVNONSEMANTICDEBUGHANDLER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the StringMap class.
uint64_t uint64_t
static Error unsupported(const char *Str, const Triple &T)
Definition MachO.cpp:79
BitTracker BT
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
IRTranslator LLVM IR MI
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define T
static NVPTX::Scope resolveScope(NVPTX::Scope S, const NVPTXSubtarget *T)
SI Fold Operands
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallString class.
This file defines the SmallVector class.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
This class is intended to be used as a driving class for all asm writers.
Definition AsmPrinter.h:95
Basic type, like 'int' or 'float'.
A lightweight wrapper around an expression operand.
DWARF expression.
Base class for scope-like contexts.
Subprogram description. Uses SubclassData1.
Type array for a subprogram.
Base class for types.
Implements a dense probed hash-table based set.
Definition DenseSet.h:283
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
Representation of each machine instruction.
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:39
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
void beginInstruction(const MachineInstr *MI) override
Process beginning of an instruction.
void endModule() override
Emit all sections that should come after the content.
void emitNonSemanticDebugStrings(SPIRV::ModuleAnalysisInfo &MAI)
Emit OpString instructions for all NSDI file paths and basic type names into the debug section (secti...
void beginModule(Module *M) override
Collect compile-unit metadata from the module.
void endFunctionImpl(const MachineFunction *MF) override
void beginFunctionImpl(const MachineFunction *MF) override
void emitNonSemanticGlobalDebugInfo(SPIRV::ModuleAnalysisInfo &MAI)
Emit module-scope NSDI instructions (DebugSource, DebugCompilationUnit, DebugTypeBasic,...
void prepareModuleOutput(const SPIRVSubtarget &ST, SPIRV::ModuleAnalysisInfo &MAI)
Add SPV_KHR_non_semantic_info extension and NonSemantic.Shader.DebugInfo.100 ext inst set entry to MA...
void endInstruction() override
Process end of an instruction.
void notifyEntryLabelEmitted(const MachineFunction &MF)
Called after the synthesized entry OpLabel has been emitted.
A vector that has set insertion semantics.
Definition SetVector.h:57
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:28
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition StringMap.h:129
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
LLVM Value Representation.
Definition Value.h:75
This is an optimization pass for GlobalISel generic memory operations.
LogicalResult failure(bool IsFailure=true)
Utility function to generate a LogicalResult.
@ Other
Any other memory.
Definition ModRef.h:68
DWARFExpression::Operation Op