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;
42class SPIRVSubtarget;
43
44/// AsmPrinter handler that emits NonSemantic.Shader.DebugInfo.100 (NSDI)
45/// instructions for the SPIR-V backend. Registered with SPIRVAsmPrinter when
46/// the module contains debug info (llvm.dbg.cu).
47///
48/// Call sequence:
49/// - beginModule() collects compile-unit metadata.
50/// - prepareModuleOutput() adds the extension and ext-inst set to MAI.
51/// - emitNonSemanticDebugStrings() emits NSDI OpStrings in section 7.
52/// - emitNonSemanticGlobalDebugInfo() emits module-scope NSDI and sets
53/// GlobalNSDIEnabled.
54/// - beginFunctionImpl() prepares per-function DebugFunctionDefinition state
55/// and runs analyzeDebugRecords() over the whole function.
56/// - endInstruction() emits DebugFunctionDefinition after the last function-
57/// level OpVariable; SPIRVAsmPrinter calls notifyEntryLabelEmitted() after
58/// the synthesized entry OpLabel when there are no OpVariables.
59/// - beginInstruction() emits the DebugScope and DebugLine for the instruction
60/// being printed, and the DebugDeclare and DebugValue anchored on it.
61/// - endFunctionImpl() resets per-function state.
63 static constexpr unsigned NSSet = static_cast<unsigned>(
64 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100);
65
66 struct CompileUnitInfo {
67 const DICompileUnit *TheCU = nullptr;
68 SmallString<128> FilePath;
69 unsigned SpirvSourceLanguage = 0; // NonSemantic.Shader.DebugInfo.100 source
70 // language code (section 4.3)
71 };
73 int64_t DwarfVersion = 0;
74
76
77 // NonSemantic debug instruction result id per emitted scope.
79
80 enum class EmitStatus {
81 Emitted,
82 Unsupported,
83 InProgress,
84 };
85
86 // One scope instruction, built but not yet emitted. getOrCreateDebugScope
87 // is the only place that emits it.
88 struct PreparedScope {
89 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode{};
91
92 PreparedScope() = default;
93 PreparedScope(SPIRV::NonSemanticExtInst::NonSemanticExtInst Op,
95 : Opcode(Op), Operands(Ops.begin(), Ops.end()) {}
96 };
97
98 // Status plus a payload. Value is set only when the status is Emitted, so
99 // InProgress and Unsupported carry no id and no PreparedScope. The payload
100 // is an id for a scope that already exists, and a PreparedScope for an
101 // instruction that getOrCreateDebugScope has not emitted yet.
102 template <typename T> struct EmitResult {
103 EmitStatus Status = EmitStatus::Unsupported;
104 std::optional<T> Value;
105
106 static EmitResult emitted(T V) {
107 EmitResult R;
108 R.Status = EmitStatus::Emitted;
109 R.Value = std::move(V);
110 return R;
111 }
112 static EmitResult unsupported() { return {}; }
113 static EmitResult inProgress() {
114 EmitResult R;
115 R.Status = EmitStatus::InProgress;
116 return R;
117 }
118
119 template <typename U>
120 static EmitResult failure(const EmitResult<U> &Other) {
121 assert(!Other && "failure() requires a non-emitted result");
122 EmitResult R;
123 R.Status = Other.Status;
124 return R;
125 }
126
127 explicit operator bool() const {
128 assert(Value.has_value() == (Status == EmitStatus::Emitted) &&
129 "payload is set exactly when the result is emitted");
130 if constexpr (std::is_same_v<T, MCRegister>)
131 assert(!Value || Value->isValid());
132 return Status == EmitStatus::Emitted;
133 }
134 };
135
136 // Types and scopes whose instruction is currently being built.
137 SmallPtrSet<const DIScope *, 8> ScopesInProgress;
138
139 // Types and scopes that are not supported.
141
142 // DISubprogram nodes collected in beginModule().
144
145 // Distinct DILocations from instruction !dbg attachments and debug program
146 // records (#dbg_declare, #dbg_value, #dbg_assign, #dbg_label).
147 SetVector<const DILocation *> UniqueDebugLocations;
148
149 struct GlobalVariableDebugInfo {
150 const DIExpression *Expr = nullptr;
151 const GlobalVariable *LLVMGV = nullptr;
152 };
154 GlobalVariableDebugInfoMap;
155
156 // Distinct DILocalVariable nodes collected in beginModule() from dbg records
157 // and from DISubprogram retained nodes.
159
160 // DebugLocalVariable result id per variable that module-scope emission
161 // actually emitted. DebugDeclare needs it for its Local Variable operand; a
162 // variable missing here (skipped type or scope) gets no declare.
164
165 // DebugExpression result id per DIExpression that could be lowered. An
166 // expression missing here uses operations with no NonSemantic counterpart,
167 // so declares referencing it are skipped rather than described wrongly.
169
170 // Distinct DILexicalBlock and DINamespace scopes, parent-before-child
171 // order, collected in beginModule() for DebugLexicalBlock emission.
172 SetVector<const DIScope *> LexicalBlocks;
173
174 // DebugInlinedAt result id per DILocation used as an inlined-at chain link.
176
177 // Path \c OpString result id per \c DIScope (CU, \c DIFile, declaration
178 // \c DISubprogram, …). Filled during \c emitNonSemanticDebugStrings() using
179 // \c getDebugFullPath + \c emitOpStringIfNew; section 10 uses it for
180 // \c DebugSource without recomputing path text.
181 DenseMap<const DIScope *, MCRegister> ScopeToPathOpStringReg;
182
183 // DebugSource result id keyed by path \c OpString id (\c MCRegister::id()),
184 // deduplicating when the same file string is reused.
185 DenseMap<unsigned, MCRegister> DebugSourceRegByFileStr;
186
187 // Maps OpString contents to result id. Populated only by emitOpStringIfNew()
188 // during section 7; section 10 uses getCachedOpStringReg() (lookup only).
189 StringMap<MCRegister> OpStringContentCache;
190
191#ifndef NDEBUG // Only declare the variable for debugging purposes.
192 // True after emitNonSemanticDebugStrings() emitted the NSDI OpStrings for
193 // this module. SPIRVAsmPrinter calls that before
194 // emitNonSemanticGlobalDebugInfo().
195 bool NonSemanticOpStringsSectionEmitted = false;
196#endif
197
198 MCRegister CachedEmptyStringReg;
199
200 MCRegister CachedDebugInfoNoneReg;
201
202 MCRegister CachedOpTypeVoidReg;
203
204 MCRegister CachedOpTypeInt32Reg;
205
206 // Result id per SPIR-V scalar type this handler needed, keyed by opcode and
207 // width. MB_TypeConstVars holds only what module analysis collected, so a
208 // type emitted here has to be remembered separately to stay unique.
210
211 // Result id per scalar constant, keyed by its type's id and its bits. Keying
212 // on the type lets two DIBasicTypes describing it share a constant.
214
215 // Result id per collected constant, keyed by its type and bits. Filled
216 // during module-scope emission, since an OpConstant has to precede every
217 // function body that names it.
219 ConstantValueRegs;
220
221 // Cache of already-emitted DebugOperation instructions, keyed by NonSemantic
222 // opcode followed by the 32-bit operation arguments. Inline size 3 is the
223 // spec maximum (opcode plus at most two operands: BitPiece, Fragment).
224 DenseMap<SmallVector<uint32_t, 3>, MCRegister> DebugOperationCache;
225
226 // Cache of already-emitted DebugExpression instructions, keyed by the
227 // DebugOperation result ids in operand order. Useful for debug values
228 // and global-variable init expressions.
229 DenseMap<SmallVector<MCRegister>, MCRegister> DebugExpressionCache;
230
231 // True once emitNonSemanticGlobalDebugInfo() has run. Both
232 // SPIRVAsmPrinter::emitFunctionHeader() and emitEndOfAsmFile() may call
233 // outputModuleSections(), each guarded by ModuleSectionsEmitted, so only
234 // one fires. This flag provides a secondary guard in case the call sites
235 // change.
236 bool GlobalDIEmitted = false;
237
238 // True when emitNonSemanticGlobalDebugInfo() completed module-scope NSDI
239 // emission for this module.
240 bool GlobalNSDIEnabled = false;
241
242 SPIRV::ModuleAnalysisInfo *CurrentMAI = nullptr;
243
244 const MachineFunction *CurrentMF = nullptr;
245
246 const MachineInstr *LastFunctionOpVariable = nullptr;
247
248 bool DebugFunctionDefinitionEmitted = false;
249
250 // Instruction that opened the DebugLine / DebugScope region currently in
251 // effect, or nullptr when no region is open. The two are tracked separately
252 // because a DebugScope region usually spans several DebugLine regions, and
253 // either one can skip emission on a cache miss.
254 const MachineInstr *LastLineMI = nullptr;
255 const MachineInstr *LastScopeMI = nullptr;
256
257 // Result ids in MB_TypeConstVars, which precedes every function body. Filled
258 // once per module in prepareModuleOutput().
259 DenseSet<MCRegister> ModuleScopeIds;
260
261 /// A DebugDeclare or DebugValue waiting for its anchor to be printed.
262 struct DebugRecord {
263 const MachineInstr *MI; ///< The DBG_VALUE this came from.
264 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode;
265 MCRegister LocationReg; ///< The Variable or Value operand.
266 };
267
268 // Records to emit before their anchor is printed, built once per function by
269 // analyzeDebugRecords() and only read afterwards.
271
272public:
274
275 /// Collect compile-unit metadata from the module. Called by
276 /// AsmPrinter::doInitialization() via the handler list. No emission.
277 void beginModule(Module *M) override;
278
279 /// Emit OpString instructions for all NSDI file paths and basic type names
280 /// into the debug section (section 7 of the SPIR-V module layout). Must be
281 /// called from SPIRVAsmPrinter::outputDebugSourceAndStrings(), after
282 /// prepareModuleOutput() has registered the ext inst set. Registers are
283 /// stored in \c OpStringContentCache and \c ScopeToPathOpStringReg;
284 /// \c emitNonSemanticGlobalDebugInfo() resolves them via
285 /// \c getCachedOpStringReg() and path maps.
287
288 /// Add SPV_KHR_non_semantic_info extension and
289 /// NonSemantic.Shader.DebugInfo.100 ext inst set entry to MAI. Must be called
290 /// before outputGlobalRequirements() and outputOpExtInstImports() in
291 /// SPIRVAsmPrinter::outputModuleSections().
292 void prepareModuleOutput(const SPIRVSubtarget &ST,
294
295 /// Emit module-scope NSDI instructions (DebugSource, DebugCompilationUnit,
296 /// DebugTypeBasic, DebugTypePointer, DebugTypeFunction,
297 /// DebugFunctionDeclaration, DebugFunction). Called by
298 /// SPIRVAsmPrinter::outputModuleSections() at section 10 in place of
299 /// outputModuleSection(MB_NonSemanticGlobalDI). Requires
300 /// emitNonSemanticDebugStrings() to have run first when NSDI strings apply.
301 /// Sets \c GlobalNSDIEnabled when module-scope NSDI emission completes.
303
304 /// Called after the synthesized entry \c OpLabel has been emitted.
306
307protected:
308 // All module-level output is driven by emitNonSemanticGlobalDebugInfo(),
309 // called explicitly from SPIRVAsmPrinter::outputModuleSections(). Nothing
310 // needs to happen in the AsmPrinterHandler::endModule() callback.
311 void endModule() override {}
312
313 // DebugHandlerBase stores MMI as a pointer copy from Asm->MMI at construction
314 // time (DebugHandlerBase.cpp: `MMI(Asm->MMI)`). The handler is constructed
315 // before AsmPrinter::doInitialization() runs, so Asm->MMI is null at that
316 // point and MMI remains null for this handler's entire lifetime. Do not call
317 // the base-class beginInstruction/endInstruction — they dereference MMI to
318 // create temp symbols for label tracking and would crash.
319 // Future local NSDI that needs MCContext must use
320 // Asm->OutStreamer->getContext() rather than MMI->getContext().
321 void beginInstruction(const MachineInstr *MI) override;
322 void endInstruction() override;
323
324 // Override beginFunctionImpl(), not beginFunction():
325 // DebugHandlerBase::beginFunction() populates LScopes and DbgValues needed
326 // for future DebugLine emission.
327 void beginFunctionImpl(const MachineFunction *MF) override;
328 void endFunctionImpl(const MachineFunction *MF) override;
329
330private:
331 void emitDebugFunctionDefinition(MCRegister DebugFunctionReg,
332 MCRegister OpFunctionReg,
334
335 void resetPerFunctionDebugState();
336
337 /// Resolve the instruction that a per-instruction DebugLine/DebugScope
338 /// update should attach to: \p MI adjusted forward past a merge
339 /// instruction to its terminator, or \c std::nullopt if \p MI is not a
340 /// valid attachment point (skip-emission, or one of the structural opcodes
341 /// that can never carry DebugLine/DebugScope: OpFunction,
342 /// OpFunctionParameter, OpFunctionEnd, OpLabel, OpPhi).
343 std::optional<const MachineInstr *>
344 resolveDebugLocTarget(const MachineInstr *MI);
345
346 /// Open the DebugScope region \p MI belongs to, closing the previous one.
347 ///
348 /// \returns False when \p MI's scope has no \c DebugScope, or its chain no
349 /// \c DebugInlinedAt, leaving the open region someone else's.
350 bool emitDebugScopeForInstruction(const MachineInstr *MI);
351 void emitDebugLineForInstruction(const MachineInstr *MI);
352 void preparePerFunctionDebug(const MachineFunction *MF);
353 void tryEmitDebugFunctionDefinition(SPIRV::ModuleAnalysisInfo &MAI);
354
355 void emitMCInst(MCInst &Inst);
356 MCRegister emitOpString(StringRef S, SPIRV::ModuleAnalysisInfo &MAI);
357
358 /// Section 7 only: emit OpString and cache it if not already present. Must
359 /// not be called after NonSemanticOpStringsSectionEmitted is set. Returns
360 /// the path (or string) \c OpString result id.
361 MCRegister emitOpStringIfNew(StringRef S, SPIRV::ModuleAnalysisInfo &MAI);
362
363 /// Section 10 only: lookup OpString id from cache; asserts if missing or if
364 /// section 7 did not complete.
365 MCRegister getCachedOpStringReg(StringRef S);
366
367 /// Section 7 only: emit the path \c OpString for \p Scope and cache it under
368 /// \p Scope. Returns the \c OpString result id. A \p Scope already seen
369 /// returns the cached id without rebuilding the path. A null \p Scope maps to
370 /// the empty path and is cached like any other, though section 10 reads it
371 /// through \c getCachedScopePathOpStringReg, which handles null separately.
372 MCRegister emitAndCacheScopePathOpStringReg(const DIScope *Scope,
374
375 /// Section 10 only: lookup path \c OpString id for \p Scope from
376 /// \c ScopeToPathOpStringReg; asserts if missing or invalid. When
377 /// \p UseEmptyPathIfNullScope is true and \p Scope is null, returns
378 /// \c CachedEmptyStringReg instead.
380 getCachedScopePathOpStringReg(const DIScope *Scope,
381 bool UseEmptyPathIfNullScope = false);
382 MCRegister emitOpConstantI32(uint32_t Value, MCRegister I32TypeReg,
384 MCRegister emitExtInst(SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
385 MCRegister VoidTypeReg, MCRegister ExtInstSetReg,
388
389 /// Return OpTypeVoid id for this module (lazy lookup / emit, then cache).
390 MCRegister getOrEmitOpTypeVoidReg(SPIRV::ModuleAnalysisInfo &MAI);
391
392 /// Return OpTypeInt 32 0 id for this module (lazy lookup / emit, then cache).
393 MCRegister getOrEmitOpTypeInt32Reg(SPIRV::ModuleAnalysisInfo &MAI);
394
395 /// Find OpTypeVoid in the already-emitted TypeConstVars section, or emit one
396 /// if the module does not contain it (e.g. no void-returning functions).
397 MCRegister findOrEmitOpTypeVoid(SPIRV::ModuleAnalysisInfo &MAI);
398
399 /// Find OpTypeInt 32 0 in the already-emitted TypeConstVars section, or emit
400 /// one if the module does not contain it.
401 MCRegister findOrEmitOpTypeInt32(SPIRV::ModuleAnalysisInfo &MAI);
402
403 /// Return the id for the type or scope \p S, emitting it and the types and
404 /// scopes it names first. One already in \c DebugScopeRegs is Emitted. A null
405 /// \p S or one in \c FailedScopes is Unsupported. One already in
406 /// \c ScopesInProgress is the back edge of a cycle and is InProgress; nothing
407 /// is emitted for that edge. An Unsupported result is recorded in
408 /// \c FailedScopes, an InProgress one is not.
409 EmitResult<MCRegister> getOrCreateDebugScope(const DIScope *S);
410
411 /// Build the instruction for \p S. Only \c getOrCreateDebugScope calls this
412 /// and emits it.
413 EmitResult<PreparedScope> emitDebugScope(const DIScope *S);
414
415 /// Build the \c DebugType* instruction for \p CT, picked by its tag.
416 EmitResult<PreparedScope> emitDebugTypeForCompositeType(
417 const DICompositeType *CT, MCRegister VoidTypeReg, MCRegister I32TypeReg,
418 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI);
419
420 /// Build the \c DebugType* instruction for \p DT, picked by its tag.
421 EmitResult<PreparedScope>
422 emitDebugTypeForDerivedType(const DIDerivedType *DT, MCRegister VoidTypeReg,
423 MCRegister I32TypeReg, MCRegister ExtInstSetReg,
425
426 /// Build \c DebugTypeBasic for \p BT. Unsupported when the size does not fit
427 /// in 32 bits.
428 EmitResult<PreparedScope> emitDebugTypeBasic(const DIBasicType *BT,
429 MCRegister I32TypeReg,
431
432 /// Build \c DebugTypePointer for \p PT. Unsupported without a DWARF address
433 /// space, which gives the storage class.
434 EmitResult<PreparedScope>
435 emitDebugTypePointer(const DIDerivedType *PT, SPIRV::ModuleAnalysisInfo &MAI);
436
437 /// Build one DebugTypeFunction for ST when every DI operand maps to a debug
438 /// type id; otherwise build nothing and return the first failing slot's
439 /// status.
440 EmitResult<PreparedScope>
441 emitDebugTypeFunctionForSubroutineType(const DISubroutineType *ST,
443
444 /// Build \c DebugFunctionDeclaration for the non-defining subprogram \p SP.
445 EmitResult<PreparedScope>
446 emitDebugFunctionDeclaration(const DISubprogram *SP, MCRegister VoidTypeReg,
447 MCRegister I32TypeReg, MCRegister ExtInstSetReg,
449
450 /// Build \c DebugFunction for the defining subprogram \p SP.
451 EmitResult<PreparedScope> emitDebugFunction(const DISubprogram *SP,
452 MCRegister VoidTypeReg,
453 MCRegister I32TypeReg,
454 MCRegister ExtInstSetReg,
456
457 /// Emit \c DebugLocalVariable for the source local variable \p LV:
458 /// Name, Type, Source, Line, Column, Parent, Flags, and an optional Arg
459 /// Number. Line, Column, Flags, and Arg Number are emitted as \c OpConstant
460 /// ids as required for non-semantic debug info. Column is always 0:
461 /// \c DILocalVariable has no column field.
462 ///
463 /// Arg Number is appended when \p LV is a parameter.
464 ///
465 /// \returns The result id register on success. Returns \c std::nullopt and
466 /// emits nothing if \p LV's scope is not an emitted local scope,
467 /// if a non-null type was not emitted in \c DebugScopeRegs, or if
468 /// \c resolveScope returns no id for the Parent operand.
469 std::optional<MCRegister>
470 emitDebugLocalVariable(const DILocalVariable *LV, MCRegister VoidTypeReg,
471 MCRegister I32TypeReg, MCRegister ExtInstSetReg,
473
474 /// Emit \c DebugGlobalVariable for the source global variable \p GV.
475 ///
476 /// (\c SPIRVDebug::Operand::GlobalVariable): Name, Type, Source, Line,
477 /// Column, Parent, Linkage Name, Variable, Flags, and an optional Static
478 /// Member Declaration. Line, Column, and Flags are emitted as \c OpConstant
479 /// ids as required for non-semantic debug info.
480 ///
481 /// \c DebugInfoNone is used for two operands when LLVM has no value to
482 /// supply:
483 /// \c Type when \p GV is a declaration with no DI type (e.g. \c extern void;
484 /// valid IR, \c isDefinition: false); \c Variable when no \c
485 /// llvm::GlobalVariable in this module carries \p GV in its \c !dbg metadata.
486 ///
487 /// \returns The result id register on success. Returns \c std::nullopt and
488 /// emits nothing if a non-null \p GV type was not emitted in \c
489 /// DebugScopeRegs, or \p GV has a static data member declaration that was not
490 /// emitted in \c DebugScopeRegs.
491 std::optional<MCRegister> emitDebugGlobalVariable(
492 const DIGlobalVariable *GV, const GlobalVariableDebugInfo &Info,
493 MCRegister VoidTypeReg, MCRegister I32TypeReg, MCRegister ExtInstSetReg,
495
496 /// Collect the \c DIExpression of every debug value in the module
497 /// (\c DBG_VALUE, \c DBG_VALUE_LIST, \c DBG_INSTR_REF), in MIR order.
498 ///
499 /// Reads MIR rather than IR because only MIR shows which debug values
500 /// survived codegen and in what form, and because an expression synthesized
501 /// during lowering never appears in the IR at all. Must be called from
502 /// module-scope emission, which is where the resulting \c DebugExpression
503 /// instructions have to be emitted; every \c MachineFunction is still
504 /// reachable at that point through \c MachineModuleInfo.
505 ///
506 /// Deliberately independent of what the consumers can currently emit, so
507 /// that adding an instruction that needs an expression (\c DebugValue) needs
508 /// no change here. The cost is a \c DebugExpression that nothing references
509 /// yet, for a debug value no instruction is emitted for.
510 void collectDebugExpressions(SetVector<const DIExpression *> &Out) const;
511
512 /// Emit one \c DebugOperation for \p Op, reusing a cached result id when the
513 /// same opcode and arguments were already emitted.
514 ///
515 /// \returns The result id register on success. Returns \c std::nullopt and
516 /// emits nothing if \p Op has no NonSemantic counterpart, or carries an
517 /// argument too large for the 32-bit \c OpConstant operands this set
518 /// requires.
519 std::optional<MCRegister>
520 emitDebugOperation(const DIExpression::ExprOperand &Op,
521 MCRegister VoidTypeReg, MCRegister I32TypeReg,
522 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI);
523
524 /// Emit one \c DebugOperation per element of \p Expr followed by the
525 /// \c DebugExpression that lists them. Reuses a cached \c DebugExpression
526 /// when that sequence of \c DebugOperation ids was already emitted. An
527 /// empty \p Expr yields a \c DebugExpression with no operands, which is
528 /// what a plain \c !DIExpression() means.
529 ///
530 /// Must be called from module-scope emission only: \c DebugExpression and
531 /// \c DebugOperation are not in the spec's list of instructions allowed
532 /// inside a function, and forward references were removed in Rev 2.
533 ///
534 /// \returns The result id register on success. Returns \c std::nullopt and
535 /// does not emit the \c DebugExpression if any element has no NonSemantic
536 /// counterpart, or carries an argument too large for the 32-bit \c OpConstant
537 /// operands this set requires.
538 std::optional<MCRegister> emitDebugExpression(const DIExpression *Expr,
539 MCRegister VoidTypeReg,
540 MCRegister I32TypeReg,
541 MCRegister ExtInstSetReg,
543
544 /// Fill \c Records from the debug records in \p MF.
545 ///
546 /// Where a record may legally sit is a property of the whole function, and
547 /// emission is unbuffered, so it is settled here rather than while printing.
548 void analyzeDebugRecords(const MachineFunction &MF);
549
550 /// Place the single record \p MI. \p LastEmitted is the nearest preceding
551 /// instruction in this block that reaches the output, or null when there is
552 /// none.
553 ///
554 /// Places nothing when this backend cannot name the record: an unavailable
555 /// location, a declare whose storage is not an \c OpVariable, a constant
556 /// with no module-scope id, a physical register, a variadic value, an
557 /// instruction reference, or a definition that does not dominate \p MI.
558 void resolveDebugRecord(const MachineInstr &MI,
559 const MachineInstr *LastEmitted,
560 const MachineDominatorTree &DomTree);
561
562 /// Store \p MI on \p Anchor, to emit before \p Anchor is printed.
563 void placeRecord(SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
564 const MachineInstr &MI, MCRegister LocationReg,
565 const MachineInstr *Anchor);
566
567 void emitAnalyzedRecords(const MachineInstr *Anchor);
568
569 /// The \c OpConstant id for the constant \p MI assigns, or \c std::nullopt
570 /// when \p MI assigns no constant this backend emitted.
571 std::optional<MCRegister> getConstantValueReg(const MachineInstr &MI) const;
572
573 /// Result id of the constant \p Opcode of type \p TypeReg holding
574 /// \p Value in \c MB_TypeConstVars, or an invalid register when the module
575 /// does not already define it.
576 MCRegister findModuleConstant(unsigned Opcode, MCRegister TypeReg,
577 uint64_t Value, bool IsBool, bool IsWide,
579
580 /// Result id of the SPIR-V type for \p BT, reusing one from
581 /// \c MB_TypeConstVars when the module already defines it. Invalid when
582 /// declaring it would require a capability the module does not have, since
583 /// debug info must not change what the module requires.
584 MCRegister findOrEmitScalarType(const DIBasicType *BT,
586
587 /// Result id of the constant \p Value, with \p BT giving both the SPIR-V
588 /// type and the opcode. Invalid when the type may not be created.
589 MCRegister findOrEmitScalarConstant(const DIBasicType *BT, uint64_t Value,
591
592 /// Result id of the constant \p Value of type \p TypeReg, reusing one from
593 /// \c MB_TypeConstVars or from an earlier call when either already has it.
594 MCRegister findOrEmitConstant(unsigned Opcode, MCRegister TypeReg,
595 uint64_t Value, unsigned Width,
597
598 /// Emit \p Opcode naming \p MI's variable, \p LocationReg and \p MI's
599 /// expression, after \p MI's own \c DebugScope and \c DebugLine. Emits
600 /// nothing when \p MI's variable has no \c DebugLocalVariable, its
601 /// expression no \c DebugExpression, or its scope no id.
602 void emitDebugBinding(SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
603 const MachineInstr *MI, MCRegister LocationReg);
604
605 /// Build \c DebugTypeVector for the vector composite type \p VT.
606 ///
607 /// \returns Emitted when the operands are ready. Unsupported, building
608 /// nothing, if \p VT has no \c DIBasicType base type, if \p VT has more than
609 /// one \c DISubrange element, or if the component count is not a
610 /// compile-time constant. If the base cannot be emitted, returns its status.
611 EmitResult<PreparedScope> emitDebugTypeVector(const DICompositeType *VT,
613
614 /// Build \c DebugTypeArray for the array composite type \p AT.
615 ///
616 /// Operands are the element (base) type id followed by one Component Count
617 /// per \c DISubrange, in DWARF subrange order. A count that is not a
618 /// compile-time constant is 0, matching \c OpTypeRuntimeArray. A matrix
619 /// arrives here as a multi-subrange array and is built with one count per
620 /// dimension.
621 ///
622 /// \returns Emitted when the operands are ready. If \p AT's element type
623 /// cannot be emitted, builds nothing and returns the element's status.
624 EmitResult<PreparedScope> emitDebugTypeArray(const DICompositeType *AT,
626
627 /// Build \c DebugTypeMember for the data member \p M (a \c DIDerivedType with
628 /// \c DW_TAG_member). Operands: Name, Type, Source, Line, Column, Offset,
629 /// Size, Flags. NonSemantic \c DebugTypeMember carries no Parent operand: the
630 /// enclosing \c DebugTypeComposite references its members, not the reverse.
631 ///
632 /// \returns Emitted when the operands are ready. Returns the base's status
633 /// and builds nothing if \p M's type cannot be emitted.
634 EmitResult<PreparedScope> emitDebugTypeMember(const DIDerivedType *M,
635 MCRegister VoidTypeReg,
636 MCRegister I32TypeReg,
637 MCRegister ExtInstSetReg,
639
640 /// Build \c DebugTypeComposite for the struct, class, or union \p CT, after a
641 /// \c DebugTypeMember for each data member whose type can be emitted. A
642 /// forward declaration uses \c DebugInfoNone for Size and no members.
643 ///
644 /// \returns Emitted when the operands are ready. Builds nothing and returns
645 /// the parent's status if the Parent scope cannot be resolved, or
646 /// Unsupported if the size does not fit in 32 bits. Both are checked before
647 /// any member is streamed. A member whose type fails is dropped, whatever
648 /// the reason, and does not fail the composite.
649 EmitResult<PreparedScope>
650 emitDebugTypeComposite(const DICompositeType *CT, MCRegister VoidTypeReg,
651 MCRegister I32TypeReg, MCRegister ExtInstSetReg,
653
654 /// Build \c DebugTypedef for the typedef derived type \p TD (a \c
655 /// DIDerivedType with \c DW_TAG_typedef). Operands: Name, Base Type, Source,
656 /// Line, Column, Parent. Parent is the enclosing type when \c TD->getScope()
657 /// is an emitted \c DIType, otherwise the first module \c
658 /// DebugCompilationUnit.
659 ///
660 /// \returns The base's or Parent's status if either fails.
661 EmitResult<PreparedScope> emitDebugTypedef(const DIDerivedType *TD,
662 MCRegister VoidTypeReg,
663 MCRegister I32TypeReg,
664 MCRegister ExtInstSetReg,
666
667 /// Map a \c DISubroutineType::getTypeArray() element to an operand register
668 /// for
669 /// \c DebugTypeFunction. A non-null \p Ty is created through
670 /// \c getOrCreateDebugScope, and its status is returned. A null \p Ty is not
671 /// a \c getOrCreateDebugScope call and is always Emitted.
672 ///
673 /// LLVM encodes a void return as a null first element (and may use null in
674 /// later slots). NonSemantic \c DebugTypeFunction
675 /// requires a concrete return-type operand, so when \p ReturnType is true and
676 /// \p Ty is null, this returns \p VoidTypeReg (\c OpTypeVoid). When
677 /// \p ReturnType is false and \p Ty is null, this returns
678 /// \c CachedDebugInfoNoneReg (\c DebugInfoNone).
679 EmitResult<MCRegister> mapDISignatureTypeToReg(const DIType *Ty,
680 MCRegister VoidTypeReg,
681 bool ReturnType);
682
683 /// Map a DWARF source language code to a NonSemantic.Shader.DebugInfo.100
684 /// source language code.
685 static unsigned toNSDISrcLang(unsigned DwarfSrcLang);
686
687 /// Build a full path from debug \p Scope for OpString / DebugSource, matching
688 /// SPIRV-LLVM-Translator \c getFullPath (OCLUtil.h): \c DIScope::getFilename,
689 /// \c getDirectory, and \c sys::path::Style::native. Works for any \c DIScope
690 /// that carries file path fields (e.g. \c DIFile, \c DISubprogram,
691 /// \c DICompileUnit). Returns an empty path when \p Scope is null.
692 SmallString<128> getDebugFullPath(const DIScope *Scope) const;
693
694 /// Return an existing \c DebugSource id for file path \c OpString \p
695 /// FileStrReg or emit \c DebugSource and cache it (keyed by \p FileStrReg
696 /// id).
697 MCRegister getOrEmitDebugSourceForFileStrReg(MCRegister FileStrReg,
698 MCRegister VoidTypeReg,
699 MCRegister ExtInstSetReg,
701
702 /// Map \p Scope to the NonSemantic debug id used as a \c Parent operand.
703 ///
704 /// A \c DIType, \c DILexicalBlock, \c DINamespace, or \c DISubprogram scope
705 /// is created through \c getOrCreateDebugScope. When \p Scope is null, a
706 /// \c DIFile, or another scope without a dedicated debug instruction, falls
707 /// back to \p FallbackCU or the first module \c DebugCompilationUnit recorded
708 /// in \c DebugScopeRegs; no such compile unit is Unsupported.
709 EmitResult<MCRegister>
710 resolveScope(const DIScope *Scope, const DICompileUnit *FallbackCU = nullptr);
711
712 /// Build \c DebugLexicalBlock for \p S, which must be a \c DILexicalBlock or
713 /// a \c DINamespace. A \c DILexicalBlock supplies Line/Column
714 /// from \c getLine()/getColumn(); a \c DINamespace has neither, so both are
715 /// 0, and its Name is appended as an extra \c OpString operand.
716 ///
717 /// \returns Emitted when the operands are ready. If \c resolveScope cannot
718 /// emit \c S->getScope(), builds nothing and returns that status.
719 EmitResult<PreparedScope>
720 emitDebugLexicalBlock(const DIScope *S, MCRegister VoidTypeReg,
721 MCRegister I32TypeReg, MCRegister ExtInstSetReg,
723
724 /// Return a cached \c DebugInlinedAt id for \p IA, or emit one (recursing
725 /// into \c IA->getInlinedAt() first for the optional Inlined operand, so
726 /// outer frames are always emitted before the inner frame that references
727 /// them). Must run after \c DebugScopeRegs is populated, since the Scope
728 /// operand is resolved through \c resolveScope. \c DebugInlinedAt is not in
729 /// the spec's in-block instruction list, so this is only ever called from
730 /// module-scope emission (\c emitNonSemanticGlobalDebugInfo), never from
731 /// per-instruction emission.
732 ///
733 /// \returns An invalid (default-constructed) \c MCRegister, and emits
734 /// nothing, if \p IA's Scope does not resolve.
735 MCRegister getOrEmitDebugInlinedAt(const DILocation *IA,
736 MCRegister VoidTypeReg,
737 MCRegister I32TypeReg,
738 MCRegister ExtInstSetReg,
740};
741
742} // namespace llvm
743
744#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:281
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:38
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:26
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