1//===-- SPIRVNonSemanticDebugHandler.cpp - 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#include "SPIRVNonSemanticDebugHandler.h"
11#include "MCTargetDesc/SPIRVMCTargetDesc.h"
12#include "SPIRVSubtarget.h"
13#include "SPIRVUtils.h"
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/ADT/STLFunctionalExtras.h"
16#include "llvm/ADT/SetVector.h"
17#include "llvm/ADT/SmallPtrSet.h"
18#include "llvm/ADT/SmallVectorExtras.h"
19#include "llvm/ADT/Twine.h"
20#include "llvm/BinaryFormat/Dwarf.h"
21#include "llvm/CodeGen/AsmPrinter.h"
22#include "llvm/CodeGen/MachineDominators.h"
23#include "llvm/CodeGen/MachineFunction.h"
24#include "llvm/CodeGen/MachineInstr.h"
25#include "llvm/CodeGen/MachineModuleInfo.h"
26#include "llvm/IR/DebugInfo.h"
27#include "llvm/IR/DebugInfoMetadata.h"
28#include "llvm/IR/DebugProgramInstruction.h"
29#include "llvm/IR/GlobalVariable.h"
30#include "llvm/IR/InstIterator.h"
31#include "llvm/IR/Instructions.h"
32#include "llvm/IR/Module.h"
33#include "llvm/MC/MCInst.h"
34#include "llvm/MC/MCStreamer.h"
35#include "llvm/Support/ErrorHandling.h"
36#include "llvm/Support/MathExtras.h"
37#include "llvm/Support/Path.h"
38#include <cassert>
39
40using namespace llvm;
41
42namespace {
43
44/// Look up \p Key in a register map and return its value, or std::nullopt when
45/// the key is absent.
46template <typename MapT>
47static std::optional<MCRegister> lookupOptReg(const MapT &Map,
48 typename MapT::key_type Key) {
49 auto It = Map.find(Key);
50 if (It == Map.end())
51 return std::nullopt;
52 assert(It->second.isValid() && "invalid register stored in map");
53 return It->second;
54}
55
56enum : uint32_t {
57 NSDIFlagIsProtected = 1u << 0,
58 NSDIFlagIsPrivate = 1u << 1,
59 NSDIFlagIsPublic = NSDIFlagIsPrivate | NSDIFlagIsProtected,
60 NSDIFlagIsLocal = 1u << 2,
61 NSDIFlagIsDefinition = 1u << 3,
62 NSDIFlagFwdDecl = 1u << 4,
63 NSDIFlagArtificial = 1u << 5,
64 NSDIFlagExplicit = 1u << 6,
65 NSDIFlagPrototyped = 1u << 7,
66 NSDIFlagObjectPointer = 1u << 8,
67 NSDIFlagStaticMember = 1u << 9,
68 NSDIFlagIndirectVariable = 1u << 10,
69 NSDIFlagLValueReference = 1u << 11,
70 NSDIFlagRValueReference = 1u << 12,
71 NSDIFlagIsOptimized = 1u << 13,
72 NSDIFlagIsEnumClass = 1u << 14,
73 NSDIFlagTypePassByValue = 1u << 15,
74 NSDIFlagTypePassByReference = 1u << 16,
75 NSDIFlagUnknownPhysicalLayout = 1u << 17,
76};
77
78static uint32_t mapDIFlagsToNonSemantic(DINode::DIFlags DFlags) {
79 uint32_t Flags = 0;
80 if ((DFlags & DINode::FlagAccessibility) == DINode::FlagPublic)
81 Flags |= NSDIFlagIsPublic;
82 if ((DFlags & DINode::FlagAccessibility) == DINode::FlagProtected)
83 Flags |= NSDIFlagIsProtected;
84 if ((DFlags & DINode::FlagAccessibility) == DINode::FlagPrivate)
85 Flags |= NSDIFlagIsPrivate;
86 if (DFlags & DINode::FlagFwdDecl)
87 Flags |= NSDIFlagFwdDecl;
88 if (DFlags & DINode::FlagArtificial)
89 Flags |= NSDIFlagArtificial;
90 if (DFlags & DINode::FlagExplicit)
91 Flags |= NSDIFlagExplicit;
92 if (DFlags & DINode::FlagPrototyped)
93 Flags |= NSDIFlagPrototyped;
94 if (DFlags & DINode::FlagObjectPointer)
95 Flags |= NSDIFlagObjectPointer;
96 if (DFlags & DINode::FlagStaticMember)
97 Flags |= NSDIFlagStaticMember;
98 if (DFlags & DINode::FlagLValueReference)
99 Flags |= NSDIFlagLValueReference;
100 if (DFlags & DINode::FlagRValueReference)
101 Flags |= NSDIFlagRValueReference;
102 if (DFlags & DINode::FlagTypePassByValue)
103 Flags |= NSDIFlagTypePassByValue;
104 if (DFlags & DINode::FlagTypePassByReference)
105 Flags |= NSDIFlagTypePassByReference;
106 if (DFlags & DINode::FlagEnumClass)
107 Flags |= NSDIFlagIsEnumClass;
108 return Flags;
109}
110
111static uint32_t transDebugFlags(const DINode *DN) {
112 uint32_t Flags = 0;
113 if (const auto *GV = dyn_cast<DIGlobalVariable>(Val: DN)) {
114 if (GV->isLocalToUnit())
115 Flags |= NSDIFlagIsLocal;
116 if (GV->isDefinition())
117 Flags |= NSDIFlagIsDefinition;
118 }
119 if (const auto *SP = dyn_cast<DISubprogram>(Val: DN)) {
120 if (SP->isLocalToUnit())
121 Flags |= NSDIFlagIsLocal;
122 if (SP->isOptimized())
123 Flags |= NSDIFlagIsOptimized;
124 if (SP->isDefinition())
125 Flags |= NSDIFlagIsDefinition;
126 Flags |= mapDIFlagsToNonSemantic(DFlags: SP->getFlags());
127 }
128 if (DN->getTag() == dwarf::DW_TAG_reference_type)
129 Flags |= NSDIFlagLValueReference;
130 if (DN->getTag() == dwarf::DW_TAG_rvalue_reference_type)
131 Flags |= NSDIFlagRValueReference;
132 if (const auto *Ty = dyn_cast<DIType>(Val: DN))
133 Flags |= mapDIFlagsToNonSemantic(DFlags: Ty->getFlags());
134 if (const auto *LV = dyn_cast<DILocalVariable>(Val: DN))
135 Flags |= mapDIFlagsToNonSemantic(DFlags: LV->getFlags());
136 return Flags;
137}
138
139// Map a DWARF composite tag to a NonSemantic.Shader.DebugInfo Composite Type
140// value: Class 0, Structure 1, Union 2.
141static uint32_t mapCompositeTypeTag(unsigned Tag) {
142 switch (Tag) {
143 case dwarf::DW_TAG_class_type:
144 return 0;
145 case dwarf::DW_TAG_structure_type:
146 return 1;
147 case dwarf::DW_TAG_union_type:
148 return 2;
149 default:
150 reportFatalInternalError(reason: "unexpected DWARF composite tag " + Twine(Tag) +
151 ". Expecting 0, 1 or 2");
152 }
153}
154
155static const MachineInstr *
156findLastFunctionOpVariableDeclaration(const MachineFunction &MF,
157 SPIRV::ModuleAnalysisInfo &MAI) {
158
159 // We iterate over the instructions to find the last OpVariable instruction if
160 // any. The following SPIRV rule is used to terminate the traversal earlier:
161 // SPIR-V 2.16.1, Function Structure: "All OpVariable instructions in a
162 // function must be in the first block in the function. These instructions,
163 // together with any intermixed OpLine and OpNoLine instructions, must be the
164 // first instructions in that block."
165 const MachineInstr *LastOpVariable = nullptr;
166 bool SeenOpVariable = false;
167 for (const MachineInstr &MI : MF.front()) {
168 if (MI.getOpcode() == SPIRV::OpVariable) {
169 SeenOpVariable = true;
170 if (!MAI.getSkipEmission(MI: &MI))
171 LastOpVariable = &MI;
172 continue;
173 }
174
175 bool CanInterleaveWithOpVariable =
176 MI.getOpcode() == SPIRV::OpLine || MI.getOpcode() == SPIRV::OpNoLine;
177 if (SeenOpVariable && !CanInterleaveWithOpVariable &&
178 !MAI.getSkipEmission(MI: &MI))
179 break;
180 }
181 return LastOpVariable;
182}
183
184} // namespace
185
186SPIRVNonSemanticDebugHandler::SPIRVNonSemanticDebugHandler(AsmPrinter &AP)
187 : DebugHandlerBase(&AP) {}
188
189// Map DWARF source language codes to NonSemantic.Shader.DebugInfo.100 source
190// language codes. Values are from the SourceLanguage enum in the
191// NonSemantic.Shader.DebugInfo.100 specification, section 4.3.
192unsigned SPIRVNonSemanticDebugHandler::toNSDISrcLang(unsigned DwarfSrcLang) {
193 switch (DwarfSrcLang) {
194 case dwarf::DW_LANG_OpenCL:
195 return 3; // OpenCL_C
196 case dwarf::DW_LANG_OpenCL_CPP:
197 return 4; // OpenCL_CPP
198 case dwarf::DW_LANG_CPP_for_OpenCL:
199 return 6; // CPP_for_OpenCL
200 case dwarf::DW_LANG_GLSL:
201 return 2; // GLSL
202 case dwarf::DW_LANG_HLSL:
203 return 5; // HLSL
204 case dwarf::DW_LANG_SYCL:
205 return 7; // SYCL
206 case dwarf::DW_LANG_Zig:
207 return 12; // Zig
208 default:
209 return 0; // Unknown
210 }
211}
212
213static bool isBooleanType(const DIBasicType *BT) {
214 return BT->getEncoding() == dwarf::DW_ATE_boolean;
215}
216
217// \p Value truncated to the width of \p BT, or 0 or 1 for a boolean.
218static uint64_t constantBits(uint64_t Value, const DIBasicType *BT) {
219 // A boolean is one of two values and a DIBasicType may give it no size, so
220 // masking to its width would turn every true into a false.
221 if (isBooleanType(BT))
222 return Value != 0;
223 unsigned Width = BT->getSizeInBits();
224 return Width >= 64 ? Value : Value & ((uint64_t(1) << Width) - 1);
225}
226
227// \p Value truncated to the width of \p BT. APInt::getZExtValue() asserts
228// above 64 bits, so the truncation comes first.
229static uint64_t constantBits(const APInt &Value, const DIBasicType *BT) {
230 unsigned Width = isBooleanType(BT) ? 1 : BT->getSizeInBits();
231 return constantBits(Value: Value.getActiveBits() > 64
232 ? Value.trunc(width: std::min(a: Width, b: 64u)).getZExtValue()
233 : Value.getZExtValue(),
234 BT);
235}
236
237// The DIBasicType that \p Ty resolves to through any typedefs, or null.
238static const DIBasicType *stripToScalarType(const DIType *Ty) {
239 // A cv-qualified type gets no DebugType, so its variable has no
240 // DebugLocalVariable and its records are dropped.
241 //
242 // Since visitDIDerivedType accepts a cyclic typedef chain, this stops once it
243 // reaches an already seen type.
244 SmallPtrSet<const DIDerivedType *, 4> Seen;
245 while (const auto *DT = dyn_cast_or_null<DIDerivedType>(Val: Ty)) {
246 if (DT->getTag() != dwarf::DW_TAG_typedef || !Seen.insert(Ptr: DT).second)
247 return nullptr;
248 Ty = DT->getBaseType();
249 }
250
251 const auto *BT = dyn_cast_or_null<DIBasicType>(Val: Ty);
252 if (!BT)
253 return nullptr;
254
255 // OpTypeBool carries no width, so a boolean of any size is accepted.
256 if (isBooleanType(BT))
257 return BT;
258
259 unsigned Size = BT->getSizeInBits();
260 switch (BT->getEncoding()) {
261 case dwarf::DW_ATE_signed:
262 case dwarf::DW_ATE_unsigned:
263 case dwarf::DW_ATE_signed_char:
264 case dwarf::DW_ATE_unsigned_char:
265 return Size == 8 || Size == 16 || Size == 32 || Size == 64 ? BT : nullptr;
266 case dwarf::DW_ATE_float:
267 // SPIR-V has no 8-bit float.
268 return Size == 16 || Size == 32 || Size == 64 ? BT : nullptr;
269 default:
270 return nullptr;
271 }
272}
273
274// Collect distinct DILocations and DILocalVariables from LLVM IR.
275//
276// DILocations come from instruction debug locations and from the debug records
277// attached to them. DebugLine pre-emission and MIR lookups assume every
278// machine-instruction debug location already appeared here; a codegen-only
279// location would not be collected and emission will be skipped.
280//
281// DILocalVariables come from the DbgVariableRecords attached to instructions
282// and from the retained nodes of each DISubprogram. Retained nodes are needed
283// because a variable with no remaining debug record (e.g. optimized away) must
284// still get a DebugLocalVariable.
285static void collectDebugLocationsAndLocalVariables(
286 const Module &M, SetVector<const DILocation *> &Locations,
287 SetVector<const DILocalVariable *> &LVs) {
288 for (const Function &F : M) {
289 const DISubprogram *SP = F.getSubprogram();
290 if (!SP)
291 continue;
292 for (const MDNode *N : SP->getRetainedNodes())
293 if (const auto *LV = dyn_cast_or_null<DILocalVariable>(Val: N))
294 LVs.insert(X: LV);
295 for (const Instruction &I : instructions(F)) {
296 if (const DILocation *DL = I.getDebugLoc().get())
297 Locations.insert(X: DL);
298 for (DbgRecord &DR : I.getDbgRecordRange()) {
299 if (const DILocation *DL = DR.getDebugLoc().get())
300 Locations.insert(X: DL);
301 if (const auto *DVR = dyn_cast<DbgVariableRecord>(Val: &DR))
302 if (const DILocalVariable *LV = DVR->getVariable())
303 LVs.insert(X: LV);
304 }
305 }
306 }
307}
308
309// Insert \p S and its enclosing DILexicalBlock/DINamespace chain into \p Out,
310// parent before child, so single-pass emission never needs a forward
311// reference for the Parent operand.
312static void collectLexicalBlockChain(const DIScope *S,
313 SetVector<const DIScope *> &Out) {
314 // Walk up child-first, then insert in reverse to get parents in first.
315 SmallVector<const DIScope *, 8> Chain;
316 while (S && !Out.contains(key: S) && isa<DILexicalBlock, DINamespace>(Val: S)) {
317 Chain.push_back(Elt: S);
318 S = S->getScope();
319 }
320 Out.insert(Start: Chain.rbegin(), End: Chain.rend());
321}
322
323void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
324 // The base class sets Asm = nullptr when the module has no compile units,
325 // and initializes lexical scope tracking otherwise.
326 DebugHandlerBase::beginModule(M);
327
328 if (!Asm)
329 return;
330
331 CompileUnits.clear();
332 DebugTypes.clear();
333 SubprogramDeclarations.clear();
334 SubprogramDefinitions.clear();
335 UniqueDebugLocations.clear();
336 GlobalVariableDebugInfoMap.clear();
337 LocalVariables.clear();
338 DebugLocalVariableRegs.clear();
339 DebugExpressionRegs.clear();
340 LexicalBlocks.clear();
341 DebugScopeRegs.clear();
342 ScopesInProgress.clear();
343 FailedScopes.clear();
344 DebugInlinedAtRegs.clear();
345 ScopeToPathOpStringReg.clear();
346 DebugSourceRegByFileStr.clear();
347 OpStringContentCache.clear();
348 ScalarTypeCache.clear();
349 ScalarConstantCache.clear();
350 ConstantValueRegs.clear();
351 DebugOperationCache.clear();
352 DebugExpressionCache.clear();
353 ModuleScopeIds.clear();
354 GlobalDIEmitted = false;
355 GlobalNSDIEnabled = false;
356 CurrentMAI = nullptr;
357#ifndef NDEBUG
358 NonSemanticOpStringsSectionEmitted = false;
359#endif
360 CachedDebugInfoNoneReg = MCRegister();
361 CachedEmptyStringReg = MCRegister();
362 CachedOpTypeVoidReg = MCRegister();
363 CachedOpTypeInt32Reg = MCRegister();
364
365 // Collect compile-unit info: file paths and source languages.
366 for (const DICompileUnit *CU : M->debug_compile_units()) {
367 const DIFile *File = CU->getFile();
368 CompileUnitInfo Info;
369 Info.TheCU = CU;
370 if (sys::path::is_absolute(path: File->getFilename()))
371 Info.FilePath = File->getFilename();
372 else
373 sys::path::append(path&: Info.FilePath, a: File->getDirectory(),
374 b: File->getFilename());
375 // getName() returns the language code regardless of whether the name is
376 // versioned. getUnversionedName() would assert on versioned names.
377 Info.SpirvSourceLanguage = toNSDISrcLang(DwarfSrcLang: CU->getSourceLanguage().getName());
378 CompileUnits.push_back(Elt: std::move(Info));
379 }
380
381 // Collect DWARF version from module flags. For CodeView modules there is no
382 // "Dwarf Version" flag; DwarfVersion remains 0, which is the correct value
383 // for the DebugCompilationUnit DWARF Version operand in that case.
384 if (const NamedMDNode *Flags = M->getNamedMetadata(Name: "llvm.module.flags")) {
385 for (const auto *Op : Flags->operands()) {
386 const MDOperand &NameOp = Op->getOperand(I: 1);
387 if (NameOp.equalsStr(Str: "Dwarf Version"))
388 DwarfVersion =
389 cast<ConstantInt>(
390 Val: cast<ConstantAsMetadata>(Val: Op->getOperand(I: 2))->getValue())
391 ->getSExtValue();
392 }
393 }
394
395 // Find all debug info types that may be referenced by NSDI instructions.
396 DebugInfoFinder Finder;
397 Finder.processModule(M: *M);
398 DebugTypes.assign(in_start: Finder.types().begin(), in_end: Finder.types().end());
399
400 for (const DISubprogram *SP : Finder.subprograms()) {
401 if (SP->isDefinition())
402 SubprogramDefinitions.push_back(Elt: SP);
403 else
404 SubprogramDeclarations.push_back(Elt: SP);
405 }
406
407 // Walk LLVM globals to map each DIGlobalVariable to its llvm::GlobalVariable.
408 DenseMap<const DIGlobalVariable *, const GlobalVariable *> DIGVToLLVMGV;
409 for (const GlobalVariable &G : M->globals()) {
410 SmallVector<DIGlobalVariableExpression *> GVEs;
411 G.getDebugInfo(GVs&: GVEs);
412 for (DIGlobalVariableExpression *GVE : GVEs) {
413 if (const DIGlobalVariable *GV = GVE->getVariable()) {
414 DIGVToLLVMGV.try_emplace(Key: GV, Args: &G);
415 }
416 }
417 }
418
419 for (const DIGlobalVariableExpression *GVE : Finder.global_variables()) {
420 const DIGlobalVariable *GV = GVE->getVariable();
421 const DIExpression *Expr = GVE->getExpression();
422 GlobalVariableDebugInfoMap.try_emplace(
423 Key: GV, Args: GlobalVariableDebugInfo{.Expr: Expr, .LLVMGV: DIGVToLLVMGV.lookup(Val: GV)});
424 }
425
426 collectDebugLocationsAndLocalVariables(M: *M, Locations&: UniqueDebugLocations,
427 LVs&: LocalVariables);
428
429 // DILexicalBlock and DINamespace scopes are lowered to DebugLexicalBlock.
430 // Collect them in parent-before-child order so they can be later emitted in a
431 // single pass.
432 for (const DIScope *S : Finder.scopes())
433 collectLexicalBlockChain(S, Out&: LexicalBlocks);
434}
435
436// The emitted SPIR-V id of \p MI, or an invalid register when \p MI defines
437// no result.
438static MCRegister getResultId(const MachineInstr &MI,
439 SPIRV::ModuleAnalysisInfo &MAI) {
440 if (MI.getNumOperands() == 0 || !MI.getOperand(i: 0).isReg() ||
441 !MI.getOperand(i: 0).isDef())
442 return MCRegister();
443 return MAI.getRegisterAlias(MF: MI.getMF(), Reg: MI.getOperand(i: 0).getReg());
444}
445
446void SPIRVNonSemanticDebugHandler::prepareModuleOutput(
447 const SPIRVSubtarget &ST, SPIRV::ModuleAnalysisInfo &MAI) {
448 if (CompileUnits.empty())
449 return;
450 if (!ST.canUseExtension(E: SPIRV::Extension::SPV_KHR_non_semantic_info))
451 return;
452
453 // Add the extension to requirements so OpExtension is output.
454 MAI.Reqs.addExtension(ToAdd: SPIRV::Extension::SPV_KHR_non_semantic_info);
455
456 // Add the NonSemantic.Shader.DebugInfo.100 entry to ExtInstSetMap so that
457 // outputOpExtInstImports() emits the OpExtInstImport instruction. Allocate a
458 // fresh result ID for it now; the same ID is used in emitExtInst() operands.
459 if (!MAI.ExtInstSetMap.count(Val: NSSet))
460 MAI.ExtInstSetMap[NSSet] = MAI.getNextIDRegister();
461
462 for (const MachineInstr *MI : MAI.getMSInstrs(MSType: SPIRV::MB_TypeConstVars)) {
463 if (MCRegister Id = getResultId(MI: *MI, MAI))
464 ModuleScopeIds.insert(V: Id);
465 }
466}
467
468void SPIRVNonSemanticDebugHandler::emitMCInst(MCInst &Inst) {
469 Asm->OutStreamer->emitInstruction(Inst, STI: Asm->getSubtargetInfo());
470}
471
472MCRegister
473SPIRVNonSemanticDebugHandler::emitOpString(StringRef S,
474 SPIRV::ModuleAnalysisInfo &MAI) {
475 MCRegister Reg = MAI.getNextIDRegister();
476 MCInst Inst;
477 Inst.setOpcode(SPIRV::OpString);
478 Inst.addOperand(Op: MCOperand::createReg(Reg));
479 addStringImm(Str: S, Inst);
480 emitMCInst(Inst);
481 return Reg;
482}
483
484MCRegister SPIRVNonSemanticDebugHandler::emitOpStringIfNew(
485 StringRef S, SPIRV::ModuleAnalysisInfo &MAI) {
486#ifndef NDEBUG
487 assert(!NonSemanticOpStringsSectionEmitted &&
488 "emitOpStringIfNew is only valid while emitting SPIR-V section 7");
489#endif
490 auto [It, Inserted] = OpStringContentCache.try_emplace(Key: S, Args: MCRegister());
491 if (Inserted)
492 It->second = emitOpString(S, MAI);
493
494 return It->second;
495}
496
497MCRegister SPIRVNonSemanticDebugHandler::getCachedOpStringReg(StringRef S) {
498#ifndef NDEBUG
499 assert(NonSemanticOpStringsSectionEmitted &&
500 "getCachedOpStringReg requires emitNonSemanticDebugStrings() first");
501#endif
502 auto It = OpStringContentCache.find(Key: S);
503 assert(It != OpStringContentCache.end() &&
504 "NSDI OpString missing from cache; emitNonSemanticDebugStrings must "
505 "cache every string used in section 10");
506 return It->second;
507}
508
509MCRegister SPIRVNonSemanticDebugHandler::emitAndCacheScopePathOpStringReg(
510 const DIScope *Scope, SPIRV::ModuleAnalysisInfo &MAI) {
511 auto [It, Inserted] = ScopeToPathOpStringReg.try_emplace(Key: Scope, Args: MCRegister());
512 if (Inserted)
513 It->second = emitOpStringIfNew(S: getDebugFullPath(Scope), MAI);
514 return It->second;
515}
516
517MCRegister SPIRVNonSemanticDebugHandler::getCachedScopePathOpStringReg(
518 const DIScope *Scope, bool UseEmptyPathIfNullScope) {
519 if (!Scope) {
520 assert(UseEmptyPathIfNullScope &&
521 "null scope path lookup requires UseEmptyPathIfNullScope");
522 assert(CachedEmptyStringReg.isValid() &&
523 "empty path OpString must be cached in emitNonSemanticDebugStrings");
524 return CachedEmptyStringReg;
525 }
526 auto It = ScopeToPathOpStringReg.find(Val: Scope);
527 assert(It != ScopeToPathOpStringReg.end() &&
528 "path OpString must be cached in emitNonSemanticDebugStrings");
529 MCRegister FileStrReg = It->second;
530 assert(FileStrReg.isValid() && "path OpString id must be valid once cached");
531 return FileStrReg;
532}
533
534MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI32(
535 uint32_t Value, MCRegister I32TypeReg, SPIRV::ModuleAnalysisInfo &MAI) {
536 return findOrEmitConstant(Opcode: SPIRV::OpConstantI, TypeReg: I32TypeReg, Value,
537 /*Width=*/32, MAI);
538}
539
540MCRegister SPIRVNonSemanticDebugHandler::emitExtInst(
541 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
542 MCRegister VoidTypeReg, MCRegister ExtInstSetReg,
543 ArrayRef<MCRegister> Operands, SPIRV::ModuleAnalysisInfo &MAI) {
544 MCRegister Reg = MAI.getNextIDRegister();
545 MCInst Inst;
546 Inst.setOpcode(SPIRV::OpExtInst);
547 Inst.addOperand(Op: MCOperand::createReg(Reg));
548 Inst.addOperand(Op: MCOperand::createReg(Reg: VoidTypeReg));
549 Inst.addOperand(Op: MCOperand::createReg(Reg: ExtInstSetReg));
550 Inst.addOperand(Op: MCOperand::createImm(Val: static_cast<int64_t>(Opcode)));
551 for (MCRegister R : Operands)
552 Inst.addOperand(Op: MCOperand::createReg(Reg: R));
553 emitMCInst(Inst);
554 return Reg;
555}
556
557MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeVoidReg(
558 SPIRV::ModuleAnalysisInfo &MAI) {
559 if (!CachedOpTypeVoidReg.isValid())
560 CachedOpTypeVoidReg = findOrEmitOpTypeVoid(MAI);
561 return CachedOpTypeVoidReg;
562}
563
564MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeInt32Reg(
565 SPIRV::ModuleAnalysisInfo &MAI) {
566 if (!CachedOpTypeInt32Reg.isValid())
567 CachedOpTypeInt32Reg = findOrEmitOpTypeInt32(MAI);
568 return CachedOpTypeInt32Reg;
569}
570
571MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeVoid(
572 SPIRV::ModuleAnalysisInfo &MAI) {
573 for (const MachineInstr *MI : MAI.getMSInstrs(MSType: SPIRV::MB_TypeConstVars)) {
574 if (MI->getOpcode() == SPIRV::OpTypeVoid)
575 return MAI.getRegisterAlias(MF: MI->getMF(), Reg: MI->getOperand(i: 0).getReg());
576 }
577 MCRegister Reg = MAI.getNextIDRegister();
578 MCInst Inst;
579 Inst.setOpcode(SPIRV::OpTypeVoid);
580 Inst.addOperand(Op: MCOperand::createReg(Reg));
581 emitMCInst(Inst);
582 return Reg;
583}
584
585// Whether declaring \p BT's SPIR-V type would require a capability. The type
586// width determines the requirement: Int8, Int16, Int64, Float16 and Float64 in
587// SPIRVModuleAnalysis::collectReqs(). A boolean and a 32-bit scalar are free.
588static bool scalarTypeNeedsCapability(const DIBasicType *BT) {
589 if (isBooleanType(BT))
590 return false;
591 unsigned Width = BT->getSizeInBits();
592 return Width != 32;
593}
594
595MCRegister SPIRVNonSemanticDebugHandler::findOrEmitScalarType(
596 const DIBasicType *BT, SPIRV::ModuleAnalysisInfo &MAI) {
597 bool IsBool = isBooleanType(BT);
598 bool IsFloat = BT->getEncoding() == dwarf::DW_ATE_float;
599 unsigned Opcode = IsBool ? SPIRV::OpTypeBool
600 : IsFloat ? SPIRV::OpTypeFloat
601 : SPIRV::OpTypeInt;
602 // Two DIBasicTypes can describe one SPIR-V type, and OpTypeBool has no
603 // width, so the key is the opcode and the width rather than the node.
604 int64_t Width = IsBool ? 0 : BT->getSizeInBits();
605
606 // OpTypeInt 32 0 is already owned by getOrEmitOpTypeInt32Reg(), which every
607 // line and column constant needs. Declaring a second one is a duplicate type
608 // declaration, which the validator rejects.
609 if (Opcode == SPIRV::OpTypeInt && Width == 32)
610 return getOrEmitOpTypeInt32Reg(MAI);
611
612 auto [CacheIt, Inserted] =
613 ScalarTypeCache.try_emplace(Key: {Opcode, Width}, Args: MCRegister());
614 if (!Inserted)
615 return CacheIt->second;
616
617 // The backend writes every integer type with signedness 0, so a signed and
618 // an unsigned DIBasicType of the same width share one OpTypeInt.
619 for (const MachineInstr *MI : MAI.getMSInstrs(MSType: SPIRV::MB_TypeConstVars)) {
620 if (MI->getOpcode() != Opcode)
621 continue;
622 if (IsBool || (MI->getOperand(i: 1).getImm() == Width &&
623 (IsFloat || MI->getOperand(i: 2).getImm() == 0))) {
624 CacheIt->second =
625 MAI.getRegisterAlias(MF: MI->getMF(), Reg: MI->getOperand(i: 0).getReg());
626 return CacheIt->second;
627 }
628 }
629
630 // A non-semantic instruction "has no semantic impact, and can be safely
631 // removed from the module", so debug info must leave the module's
632 // requirements alone. Declaring OpTypeInt 64 forces Int64, which Vulkan ties
633 // to a device feature, so this returns nothing if the type requires a new
634 // capability.
635 if (scalarTypeNeedsCapability(BT))
636 return MCRegister();
637
638 MCRegister Reg = MAI.getNextIDRegister();
639 MCInst Inst;
640 Inst.setOpcode(Opcode);
641 Inst.addOperand(Op: MCOperand::createReg(Reg));
642 if (!IsBool) {
643 Inst.addOperand(Op: MCOperand::createImm(Val: Width));
644 if (!IsFloat)
645 Inst.addOperand(Op: MCOperand::createImm(Val: 0));
646 }
647 emitMCInst(Inst);
648 CacheIt->second = Reg;
649 return Reg;
650}
651
652// Whether the constant \p MI holds \p Value, read as two words when \p IsWide.
653static bool constantHasValue(const MachineInstr &MI, uint64_t Value,
654 bool IsWide) {
655 unsigned Words = IsWide ? 2 : 1;
656 if (MI.getNumOperands() < 2 + Words)
657 return false;
658 uint64_t Found = 0;
659 for (unsigned I = 0; I < Words; ++I) {
660 if (!MI.getOperand(i: 2 + I).isImm())
661 return false;
662 Found |= static_cast<uint64_t>(
663 static_cast<uint32_t>(MI.getOperand(i: 2 + I).getImm()))
664 << (32 * I);
665 }
666 return Found == Value;
667}
668
669MCRegister SPIRVNonSemanticDebugHandler::findModuleConstant(
670 unsigned Opcode, MCRegister TypeReg, uint64_t Value, bool IsBool,
671 bool IsWide, SPIRV::ModuleAnalysisInfo &MAI) {
672 for (const MachineInstr *MI : MAI.getMSInstrs(MSType: SPIRV::MB_TypeConstVars)) {
673 if (MI->getOpcode() != Opcode || MI->getNumOperands() < 2)
674 continue;
675 if (MAI.getRegisterAlias(MF: MI->getMF(), Reg: MI->getOperand(i: 1).getReg()) !=
676 TypeReg)
677 continue;
678 // A boolean holds its value in its opcode, so there is nothing to compare.
679 if (!IsBool && !constantHasValue(MI: *MI, Value, IsWide))
680 continue;
681 return MAI.getRegisterAlias(MF: MI->getMF(), Reg: MI->getOperand(i: 0).getReg());
682 }
683 return MCRegister();
684}
685
686// \p Width is 0 for a boolean, whose value lives in \p Opcode.
687MCRegister SPIRVNonSemanticDebugHandler::findOrEmitConstant(
688 unsigned Opcode, MCRegister TypeReg, uint64_t Value, unsigned Width,
689 SPIRV::ModuleAnalysisInfo &MAI) {
690 bool IsBool = Width == 0;
691 bool IsWide = Width == 64;
692
693 auto [CacheIt, Inserted] =
694 ScalarConstantCache.try_emplace(Key: {TypeReg.id(), Value}, Args: MCRegister());
695 if (!Inserted)
696 return CacheIt->second;
697
698 MCRegister Found =
699 findModuleConstant(Opcode, TypeReg, Value, IsBool, IsWide, MAI);
700 if (Found.isValid()) {
701 CacheIt->second = Found;
702 return Found;
703 }
704
705 MCRegister Reg = MAI.getNextIDRegister();
706 MCInst Inst;
707 Inst.setOpcode(Opcode);
708 Inst.addOperand(Op: MCOperand::createReg(Reg));
709 Inst.addOperand(Op: MCOperand::createReg(Reg: TypeReg));
710 if (!IsBool) {
711 // OpConstant's Value is "the bit pattern for the constant. Types 32 bits
712 // wide or smaller take one word. Larger types take multiple words, with
713 // low-order words appearing first" (SPIR-V specification, OpConstant).
714 Inst.addOperand(Op: MCOperand::createImm(Val: static_cast<int64_t>(Lo_32(Value))));
715 if (IsWide) {
716 Inst.addOperand(Op: MCOperand::createImm(Val: static_cast<int64_t>(Hi_32(Value))));
717 } else if (Width == 16) {
718 // A 16-bit float takes one word, the same as a 32-bit one, so the text
719 // printer needs the width to pick the right APFloat semantics.
720 Inst.setFlags(SPIRV::INST_PRINTER_WIDTH16);
721 }
722 }
723 emitMCInst(Inst);
724 CacheIt->second = Reg;
725 return Reg;
726}
727
728MCRegister SPIRVNonSemanticDebugHandler::findOrEmitScalarConstant(
729 const DIBasicType *BT, uint64_t Value, SPIRV::ModuleAnalysisInfo &MAI) {
730 MCRegister TypeReg = findOrEmitScalarType(BT, MAI);
731 if (!TypeReg.isValid())
732 return MCRegister();
733
734 bool IsBool = isBooleanType(BT);
735 bool IsFloat = BT->getEncoding() == dwarf::DW_ATE_float;
736 unsigned Opcode =
737 IsBool ? (Value ? SPIRV::OpConstantTrue : SPIRV::OpConstantFalse)
738 : IsFloat ? SPIRV::OpConstantF
739 : SPIRV::OpConstantI;
740 return findOrEmitConstant(Opcode, TypeReg, Value,
741 Width: IsBool ? 0 : BT->getSizeInBits(), MAI);
742}
743
744MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt32(
745 SPIRV::ModuleAnalysisInfo &MAI) {
746 for (const MachineInstr *MI : MAI.getMSInstrs(MSType: SPIRV::MB_TypeConstVars)) {
747 if (MI->getOpcode() == SPIRV::OpTypeInt &&
748 MI->getOperand(i: 1).getImm() == 32 && MI->getOperand(i: 2).getImm() == 0)
749 return MAI.getRegisterAlias(MF: MI->getMF(), Reg: MI->getOperand(i: 0).getReg());
750 }
751 MCRegister Reg = MAI.getNextIDRegister();
752 MCInst Inst;
753 Inst.setOpcode(SPIRV::OpTypeInt);
754 Inst.addOperand(Op: MCOperand::createReg(Reg));
755 Inst.addOperand(Op: MCOperand::createImm(Val: 32)); // width
756 Inst.addOperand(Op: MCOperand::createImm(Val: 0)); // signedness (unsigned)
757 emitMCInst(Inst);
758 return Reg;
759}
760
761// Each node emits its dependencies first. E.g. for `void f() { struct L; }`,
762// node L emits f, then L. For `struct S { S *p; }`, S* is a back edge, so S
763// is emitted without member p.
764SPIRVNonSemanticDebugHandler::EmitResult
765SPIRVNonSemanticDebugHandler::getOrCreateDebugScope(const DIScope *S) {
766 if (!S || FailedScopes.contains(Ptr: S))
767 return EmitResult::unsupported();
768 if (auto Reg = lookupOptReg(Map: DebugScopeRegs, Key: S))
769 return EmitResult::emitted(R: *Reg);
770
771 // Mark the node as in progress while its dependencies are resolved/emitted.
772 // This also prevents cycles from happening.
773 if (!ScopesInProgress.insert(Ptr: S).second)
774 return EmitResult::inProgress();
775 EmitResult R = emitDebugScope(S);
776 ScopesInProgress.erase(Ptr: S);
777 assert((!R || !GlobalNSDIEnabled) &&
778 "debug type or scope created after module-scope NSDI emission");
779 if (R)
780 DebugScopeRegs[S] = R.Reg;
781 else if (R.Status == EmitStatus::Unsupported)
782 FailedScopes.insert(Ptr: S);
783 return R;
784}
785
786SPIRVNonSemanticDebugHandler::EmitResult
787SPIRVNonSemanticDebugHandler::emitDebugTypeBasic(
788 const DIBasicType *BT, MCRegister VoidTypeReg, MCRegister I32TypeReg,
789 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
790 if (!isUInt<32>(x: BT->getSizeInBits()))
791 return EmitResult::unsupported();
792
793 MCRegister NameReg = getCachedOpStringReg(S: BT->getName());
794 MCRegister SizeReg = emitOpConstantI32(
795 Value: static_cast<uint32_t>(BT->getSizeInBits()), I32TypeReg, MAI);
796
797 // Map DWARF base type encodings to NSDI encoding codes per
798 // NonSemantic.Shader.DebugInfo.100 specification, section 4.5.
799 unsigned Encoding = 0; // Unspecified
800 switch (BT->getEncoding()) {
801 case dwarf::DW_ATE_address:
802 Encoding = 1;
803 break;
804 case dwarf::DW_ATE_boolean:
805 Encoding = 2;
806 break;
807 case dwarf::DW_ATE_float:
808 Encoding = 3;
809 break;
810 case dwarf::DW_ATE_signed:
811 Encoding = 4;
812 break;
813 case dwarf::DW_ATE_signed_char:
814 Encoding = 5;
815 break;
816 case dwarf::DW_ATE_unsigned:
817 Encoding = 6;
818 break;
819 case dwarf::DW_ATE_unsigned_char:
820 Encoding = 7;
821 break;
822 }
823 MCRegister EncodingReg = emitOpConstantI32(Value: Encoding, I32TypeReg, MAI);
824 MCRegister FlagsReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
825 return EmitResult::emitted(R: emitExtInst(
826 Opcode: SPIRV::NonSemanticExtInst::DebugTypeBasic, VoidTypeReg, ExtInstSetReg,
827 Operands: {NameReg, SizeReg, EncodingReg, FlagsReg}, MAI));
828}
829
830SPIRVNonSemanticDebugHandler::EmitResult
831SPIRVNonSemanticDebugHandler::emitDebugScope(const DIScope *S) {
832 assert(CurrentMAI && "emitDebugScope requires CurrentMAI");
833 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
834 MCRegister ExtInstSetReg = MAI.getExtInstSetReg(SetNum: NSSet);
835 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
836 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
837
838 if (const auto *BT = dyn_cast<DIBasicType>(Val: S))
839 return emitDebugTypeBasic(BT, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
840 if (const auto *ST = dyn_cast<DISubroutineType>(Val: S))
841 return emitDebugTypeFunctionForSubroutineType(ST, ExtInstSetReg, MAI);
842 if (const auto *CT = dyn_cast<DICompositeType>(Val: S))
843 return emitDebugTypeForCompositeType(CT, VoidTypeReg, I32TypeReg,
844 ExtInstSetReg, MAI);
845 if (const auto *DT = dyn_cast<DIDerivedType>(Val: S))
846 return emitDebugTypeForDerivedType(DT, VoidTypeReg, I32TypeReg,
847 ExtInstSetReg, MAI);
848 if (isa<DILexicalBlock, DINamespace>(Val: S))
849 return emitDebugLexicalBlock(S, VoidTypeReg, I32TypeReg, ExtInstSetReg,
850 MAI);
851 if (const auto *SP = dyn_cast<DISubprogram>(Val: S)) {
852 if (SP->isDefinition())
853 return emitDebugFunction(SP, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
854 return emitDebugFunctionDeclaration(SP, VoidTypeReg, I32TypeReg,
855 ExtInstSetReg, MAI);
856 }
857 return EmitResult::unsupported();
858}
859
860SPIRVNonSemanticDebugHandler::EmitResult
861SPIRVNonSemanticDebugHandler::emitDebugTypeForCompositeType(
862 const DICompositeType *CT, MCRegister VoidTypeReg, MCRegister I32TypeReg,
863 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
864 switch (CT->getTag()) {
865 case dwarf::DW_TAG_array_type:
866 // A vector is an array with DINode::FlagVector. A plain array is the
867 // same tag without it. A matrix is also lowered to a DW_TAG_array_type
868 // (two subranges), so it is indistinguishable from a 2D array here and
869 // is emitted as a DebugTypeArray.
870 //
871 // FIXME: Emitting a matrix as a DebugTypeArray is valid but loses the
872 // matrix shape. DWARF has no matrix tag, so distinguishing a matrix needs
873 // a new DINode flag analogous to FlagVector, set on the array, plus a way
874 // to carry column-major vs row-major traits. Array-of-vectors alone would
875 // not disambiguate a matrix from a genuine array of vectors. Once the
876 // frontend marks matrices, route them to a DebugTypeMatrix path here.
877 if (CT->isVector())
878 return emitDebugTypeVector(VT: CT, ExtInstSetReg, MAI);
879 return emitDebugTypeArray(AT: CT, ExtInstSetReg, MAI);
880 case dwarf::DW_TAG_structure_type:
881 case dwarf::DW_TAG_class_type:
882 case dwarf::DW_TAG_union_type:
883 return emitDebugTypeComposite(CT, VoidTypeReg, I32TypeReg, ExtInstSetReg,
884 MAI);
885 default:
886 return EmitResult::unsupported();
887 }
888}
889
890SPIRVNonSemanticDebugHandler::EmitResult
891SPIRVNonSemanticDebugHandler::emitDebugTypeForDerivedType(
892 const DIDerivedType *DT, MCRegister VoidTypeReg, MCRegister I32TypeReg,
893 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
894 switch (DT->getTag()) {
895 case dwarf::DW_TAG_pointer_type:
896 return emitDebugTypePointer(PT: DT, ExtInstSetReg, MAI);
897 case dwarf::DW_TAG_typedef:
898 return emitDebugTypedef(TD: DT, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
899 default:
900 return EmitResult::unsupported();
901 }
902}
903
904SPIRVNonSemanticDebugHandler::EmitResult
905SPIRVNonSemanticDebugHandler::emitDebugTypePointer(
906 const DIDerivedType *PT, MCRegister ExtInstSetReg,
907 SPIRV::ModuleAnalysisInfo &MAI) {
908 // A DWARF address space is required to determine the SPIR-V storage class.
909 // Skip pointer types that do not carry one.
910 if (!PT->getDWARFAddressSpace().has_value())
911 return EmitResult::unsupported();
912
913 MCRegister BaseReg;
914 if (const DIType *BaseTy = PT->getBaseType()) {
915 EmitResult Base = getOrCreateDebugScope(S: BaseTy);
916 if (!Base)
917 return Base;
918 BaseReg = Base.Reg;
919 } else {
920 // No getBaseType() (typical for void*): use DebugInfoNone as Base Type,
921 // same as SPIRV-LLVM-Translator (see issue #109287 and the DISABLED
922 // spirv-val run in debug-type-pointer.ll). spirv-val may still reject this
923 // encoding; see https://github.com/KhronosGroup/SPIRV-Registry/pull/287.
924 BaseReg = CachedDebugInfoNoneReg;
925 }
926
927 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
928 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
929 MCRegister DebugTypePointerFlagsReg =
930 emitOpConstantI32(Value: transDebugFlags(DN: PT), I32TypeReg, MAI);
931
932 // For SPIR-V targets, Clang sets DwarfAddressSpace to the LLVM IR address
933 // space, which addressSpaceToStorageClass expects.
934 const auto &ST = static_cast<const SPIRVSubtarget &>(Asm->getSubtargetInfo());
935 MCRegister StorageClassReg = emitOpConstantI32(
936 Value: addressSpaceToStorageClass(AddrSpace: PT->getDWARFAddressSpace().value(), STI: ST),
937 I32TypeReg, MAI);
938
939 return EmitResult::emitted(R: emitExtInst(
940 Opcode: SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg, ExtInstSetReg,
941 Operands: {BaseReg, StorageClassReg, DebugTypePointerFlagsReg}, MAI));
942}
943
944SPIRVNonSemanticDebugHandler::EmitResult
945SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
946 const DISubroutineType *ST, MCRegister ExtInstSetReg,
947 SPIRV::ModuleAnalysisInfo &MAI) {
948 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
949 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
950 MCRegister DebugTypeFunctionFlagsReg =
951 emitOpConstantI32(Value: transDebugFlags(DN: ST), I32TypeReg, MAI);
952 DITypeArray TA = ST->getTypeArray();
953 SmallVector<MCRegister, 8> Ops;
954 Ops.push_back(Elt: DebugTypeFunctionFlagsReg);
955 // Empty DI type tuple: no explicit return or parameter slots (hand-written IR
956 // may use !{}). Emit void-only prototype. Same as SPIRV-LLVM-Translator when
957 // DISubroutineType::getTypeArray() has zero elements.
958 if (TA.empty()) {
959 Ops.push_back(Elt: VoidTypeReg);
960 } else {
961 for (unsigned I = 0, E = TA.size(); I != E; ++I) {
962 bool IsReturnType = (I == 0);
963 EmitResult Slot =
964 mapDISignatureTypeToReg(Ty: TA[I], VoidTypeReg, ReturnType: IsReturnType);
965 // No emitted DebugType* id for this slot (e.g., pointer that
966 // was skipped due missing address space, etc.).
967 if (!Slot)
968 return Slot;
969 Ops.push_back(Elt: Slot.Reg);
970 }
971 }
972 return EmitResult::emitted(
973 R: emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugTypeFunction, VoidTypeReg,
974 ExtInstSetReg, Operands: Ops, MAI));
975}
976
977// Match SPIRV-LLVM-Translator's selection logic for the Parent operand.
978SPIRVNonSemanticDebugHandler::EmitResult
979SPIRVNonSemanticDebugHandler::resolveScope(const DIScope *Scope,
980 const DICompileUnit *FallbackCU) {
981 // DebugLexicalBlockDiscriminator cannot be used as a scope, so unwrap it.
982 while (const auto *DLBF = dyn_cast_or_null<DILexicalBlockFile>(Val: Scope))
983 Scope = DLBF->getScope();
984
985 if (isa_and_nonnull<DIType, DILexicalBlock, DINamespace, DISubprogram>(Val: Scope))
986 return getOrCreateDebugScope(S: Scope);
987
988 // For a file, compile-unit, or absent scope, fall back to a compile unit.
989 auto CUResult = [](std::optional<MCRegister> Reg) {
990 return Reg ? EmitResult::emitted(R: *Reg) : EmitResult::unsupported();
991 };
992 if (FallbackCU)
993 return CUResult(lookupOptReg(Map: DebugScopeRegs, Key: FallbackCU));
994
995 if (CompileUnits.empty())
996 return EmitResult::unsupported();
997
998 return CUResult(lookupOptReg(Map: DebugScopeRegs, Key: CompileUnits[0].TheCU));
999}
1000
1001SPIRVNonSemanticDebugHandler::EmitResult
1002SPIRVNonSemanticDebugHandler::emitDebugLexicalBlock(
1003 const DIScope *S, MCRegister VoidTypeReg, MCRegister I32TypeReg,
1004 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
1005 assert((isa<DILexicalBlock, DINamespace>(S)) &&
1006 "S must be a DILexicalBlock or DINamespace in emitDebugLexicalBlock");
1007 EmitResult Parent = resolveScope(Scope: S->getScope());
1008 if (!Parent)
1009 return Parent;
1010
1011 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1012 Scope: S->getFile(), /*UseEmptyPathIfNullScope=*/true);
1013 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1014 ExtInstSetReg, MAI);
1015
1016 SmallVector<MCRegister, 5> Ops;
1017 if (const auto *LB = dyn_cast<DILexicalBlock>(Val: S)) {
1018 MCRegister LineReg = emitOpConstantI32(Value: static_cast<uint32_t>(LB->getLine()),
1019 I32TypeReg, MAI);
1020 MCRegister ColReg = emitOpConstantI32(
1021 Value: static_cast<uint32_t>(LB->getColumn()), I32TypeReg, MAI);
1022 Ops = {SrcReg, LineReg, ColReg, Parent.Reg};
1023 } else {
1024 const auto *NS = cast<DINamespace>(Val: S);
1025 // DINamespace carries no line/column info.
1026 MCRegister LineReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
1027 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
1028 MCRegister NameReg = getCachedOpStringReg(S: NS->getName());
1029 Ops = {SrcReg, LineReg, ColReg, Parent.Reg, NameReg};
1030 }
1031
1032 return EmitResult::emitted(
1033 R: emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugLexicalBlock, VoidTypeReg,
1034 ExtInstSetReg, Operands: Ops, MAI));
1035}
1036
1037MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugInlinedAt(
1038 const DILocation *IA, MCRegister VoidTypeReg, MCRegister I32TypeReg,
1039 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
1040 assert(IA && "IA must not be null in getOrEmitDebugInlinedAt");
1041
1042 if (MCRegister Cached = DebugInlinedAtRegs.lookup(Val: IA))
1043 return Cached;
1044
1045 EmitResult Scope = resolveScope(Scope: IA->getScope());
1046 if (!Scope)
1047 return MCRegister();
1048
1049 MCRegister LineReg =
1050 emitOpConstantI32(Value: static_cast<uint32_t>(IA->getLine()), I32TypeReg, MAI);
1051
1052 SmallVector<MCRegister, 3> Ops{LineReg, Scope.Reg};
1053 // Recurse before building this instruction's operands so an outer
1054 // inlined-at link is always available.
1055 if (const DILocation *Outer = IA->getInlinedAt()) {
1056 MCRegister OuterReg = getOrEmitDebugInlinedAt(
1057 IA: Outer, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
1058 if (!OuterReg.isValid())
1059 return MCRegister();
1060 Ops.push_back(Elt: OuterReg);
1061 }
1062
1063 MCRegister Reg = emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugInlinedAt,
1064 VoidTypeReg, ExtInstSetReg, Operands: Ops, MAI);
1065 DebugInlinedAtRegs[IA] = Reg;
1066 return Reg;
1067}
1068
1069SPIRVNonSemanticDebugHandler::EmitResult
1070SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration(
1071 const DISubprogram *SP, MCRegister VoidTypeReg, MCRegister I32TypeReg,
1072 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
1073 assert(SP && "SP must not be null in emitDebugFunctionDeclaration");
1074 assert(!SP->isDefinition() &&
1075 "SP must not be a definition in emitDebugFunctionDeclaration");
1076
1077 // The IR verifier already enforces that this cannot be null.
1078 EmitResult FnTy = getOrCreateDebugScope(S: SP->getType());
1079 if (!FnTy)
1080 return FnTy;
1081
1082 EmitResult Parent = resolveScope(Scope: SP->getScope(), FallbackCU: SP->getUnit());
1083 if (!Parent)
1084 return Parent;
1085
1086 MCRegister FileStrReg = getCachedScopePathOpStringReg(Scope: SP);
1087
1088 MCRegister NameReg = getCachedOpStringReg(S: SP->getName());
1089 MCRegister LinkageReg = getCachedOpStringReg(S: SP->getLinkageName());
1090 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1091 ExtInstSetReg, MAI);
1092
1093 MCRegister LineReg =
1094 emitOpConstantI32(Value: static_cast<uint32_t>(SP->getLine()), I32TypeReg, MAI);
1095 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
1096
1097 uint32_t FlagsVal = transDebugFlags(DN: SP);
1098 // TODO: When composite scopes are DebugFunctionDeclaration parents (available
1099 // in DebugScopeRegs), sync declaration Flags with SPIRV-LLVM-Translator.
1100 FlagsVal &= ~NSDIFlagIsDefinition;
1101 MCRegister FlagsReg = emitOpConstantI32(Value: FlagsVal, I32TypeReg, MAI);
1102
1103 return EmitResult::emitted(
1104 R: emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugFunctionDeclaration,
1105 VoidTypeReg, ExtInstSetReg,
1106 Operands: {NameReg, FnTy.Reg, SrcReg, LineReg, ColReg, Parent.Reg,
1107 LinkageReg, FlagsReg},
1108 MAI));
1109}
1110
1111SPIRVNonSemanticDebugHandler::EmitResult
1112SPIRVNonSemanticDebugHandler::emitDebugFunction(
1113 const DISubprogram *SP, MCRegister VoidTypeReg, MCRegister I32TypeReg,
1114 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
1115 assert(SP && "SP must not be null in emitDebugFunction");
1116 assert(SP->isDefinition() && "SP must be a definition in emitDebugFunction");
1117
1118 EmitResult FnTy = getOrCreateDebugScope(S: SP->getType());
1119 if (!FnTy)
1120 return FnTy;
1121
1122 EmitResult Parent = resolveScope(Scope: SP->getScope(), FallbackCU: SP->getUnit());
1123 if (!Parent)
1124 return Parent;
1125
1126 MCRegister NameReg = getCachedOpStringReg(S: SP->getName());
1127 MCRegister LinkageReg = getCachedOpStringReg(S: SP->getLinkageName());
1128 MCRegister FileStrReg = getCachedScopePathOpStringReg(Scope: SP);
1129 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1130 ExtInstSetReg, MAI);
1131
1132 MCRegister LineReg =
1133 emitOpConstantI32(Value: static_cast<uint32_t>(SP->getLine()), I32TypeReg, MAI);
1134 // LLVM's DISubprogram has no column field but SPIR-V expects one in
1135 // DebugFunction.
1136 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
1137 MCRegister FlagsReg = emitOpConstantI32(Value: transDebugFlags(DN: SP), I32TypeReg, MAI);
1138 MCRegister ScopeLineReg = emitOpConstantI32(
1139 Value: static_cast<uint32_t>(SP->getScopeLine()), I32TypeReg, MAI);
1140
1141 SmallVector<MCRegister, 10> Ops = {NameReg, FnTy.Reg, SrcReg,
1142 LineReg, ColReg, Parent.Reg,
1143 LinkageReg, FlagsReg, ScopeLineReg};
1144
1145 if (const DISubprogram *Decl = SP->getDeclaration()) {
1146 EmitResult DeclRes = getOrCreateDebugScope(S: Decl);
1147 if (DeclRes)
1148 Ops.push_back(Elt: DeclRes.Reg);
1149 }
1150
1151 return EmitResult::emitted(
1152 R: emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugFunction, VoidTypeReg,
1153 ExtInstSetReg, Operands: Ops, MAI));
1154}
1155
1156SPIRVNonSemanticDebugHandler::EmitResult
1157SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg(const DIType *Ty,
1158 MCRegister VoidTypeReg,
1159 bool ReturnType) {
1160 if (!Ty) {
1161 if (ReturnType)
1162 return EmitResult::emitted(R: VoidTypeReg);
1163 assert(CachedDebugInfoNoneReg.isValid() &&
1164 "DebugInfoNone must be emitted before DISubroutineType operands");
1165 return EmitResult::emitted(R: CachedDebugInfoNoneReg);
1166 }
1167 return getOrCreateDebugScope(S: Ty);
1168}
1169
1170// NonSemantic.Shader.DebugInfo.100 debug operation encodings
1171// (section 4.5, "Debug Operations").
1172enum class NonSemanticDebugOp : uint32_t {
1173 Deref = 0,
1174 Plus = 1,
1175 Minus = 2,
1176 PlusUconst = 3,
1177 BitPiece = 4,
1178 Swap = 5,
1179 Xderef = 6,
1180 StackValue = 7,
1181 Constu = 8,
1182 Fragment = 9
1183};
1184
1185static std::optional<NonSemanticDebugOp>
1186mapDwarfOpToNonSemanticOp(uint64_t DwarfOp) {
1187 switch (DwarfOp) {
1188 case dwarf::DW_OP_deref:
1189 return NonSemanticDebugOp::Deref;
1190 case dwarf::DW_OP_plus:
1191 return NonSemanticDebugOp::Plus;
1192 case dwarf::DW_OP_minus:
1193 return NonSemanticDebugOp::Minus;
1194 case dwarf::DW_OP_plus_uconst:
1195 return NonSemanticDebugOp::PlusUconst;
1196 case dwarf::DW_OP_bit_piece:
1197 return NonSemanticDebugOp::BitPiece;
1198 case dwarf::DW_OP_swap:
1199 return NonSemanticDebugOp::Swap;
1200 case dwarf::DW_OP_xderef:
1201 return NonSemanticDebugOp::Xderef;
1202 case dwarf::DW_OP_stack_value:
1203 return NonSemanticDebugOp::StackValue;
1204 case dwarf::DW_OP_constu:
1205 return NonSemanticDebugOp::Constu;
1206 case dwarf::DW_OP_LLVM_fragment:
1207 return NonSemanticDebugOp::Fragment;
1208 default:
1209 return std::nullopt;
1210 }
1211}
1212
1213// The DebugOperation operand values for \p Op. Each becomes an OpConstant of
1214// OpTypeInt 32 0, so every argument must fit in 32 bits.
1215static std::optional<SmallVector<uint32_t, 3>>
1216mapExprOperand(const DIExpression::ExprOperand &Op) {
1217 std::optional<NonSemanticDebugOp> NSOp =
1218 mapDwarfOpToNonSemanticOp(DwarfOp: Op.getOp());
1219 if (!NSOp)
1220 return std::nullopt;
1221
1222 SmallVector<uint32_t, 3> Operands{static_cast<uint32_t>(*NSOp)};
1223 for (unsigned I = 0, E = Op.getNumArgs(); I != E; ++I) {
1224 uint64_t Arg = Op.getArg(I);
1225 if (!isUInt<32>(x: Arg))
1226 return std::nullopt;
1227 Operands.push_back(Elt: static_cast<uint32_t>(Arg));
1228 }
1229 return Operands;
1230}
1231
1232std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugOperation(
1233 const DIExpression::ExprOperand &Op, MCRegister VoidTypeReg,
1234 MCRegister I32TypeReg, MCRegister ExtInstSetReg,
1235 SPIRV::ModuleAnalysisInfo &MAI) {
1236 std::optional<SmallVector<uint32_t, 3>> Key = mapExprOperand(Op);
1237 if (!Key)
1238 return std::nullopt;
1239
1240 auto [It, Inserted] = DebugOperationCache.try_emplace(Key: std::move(*Key));
1241 if (!Inserted)
1242 return It->second;
1243
1244 SmallVector<MCRegister, 3> Operands;
1245 for (uint32_t V : It->first)
1246 Operands.push_back(Elt: emitOpConstantI32(Value: V, I32TypeReg, MAI));
1247 MCRegister Reg = emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugOperation,
1248 VoidTypeReg, ExtInstSetReg, Operands, MAI);
1249 It->second = Reg;
1250 return Reg;
1251}
1252
1253std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugExpression(
1254 const DIExpression *Expr, MCRegister VoidTypeReg, MCRegister I32TypeReg,
1255 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
1256 assert(Expr && "Expr must not be null in emitDebugExpression");
1257
1258 SmallVector<MCRegister> OperationRegs;
1259 for (const DIExpression::ExprOperand &Op : Expr->expr_ops()) {
1260 std::optional<MCRegister> OpReg =
1261 emitDebugOperation(Op, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
1262 if (!OpReg)
1263 return std::nullopt;
1264 OperationRegs.push_back(Elt: *OpReg);
1265 }
1266
1267 auto [It, Inserted] =
1268 DebugExpressionCache.try_emplace(Key: std::move(OperationRegs));
1269 if (!Inserted)
1270 return It->second;
1271
1272 MCRegister Reg = emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugExpression,
1273 VoidTypeReg, ExtInstSetReg, Operands: It->first, MAI);
1274 It->second = Reg;
1275 return Reg;
1276}
1277
1278std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
1279 const DIGlobalVariable *GV, const GlobalVariableDebugInfo &Info,
1280 MCRegister VoidTypeReg, MCRegister I32TypeReg, MCRegister ExtInstSetReg,
1281 SPIRV::ModuleAnalysisInfo &MAI) {
1282 assert(GV && "GV must not be null in emitDebugGlobalVariable");
1283
1284 EmitResult Parent = resolveScope(Scope: GV->getScope());
1285 if (!Parent)
1286 return std::nullopt;
1287
1288 MCRegister ParentReg = Parent.Reg;
1289
1290 // TyReg: DebugInfoNone when GV has no DI type (as done in
1291 // SPIRV-LLVM-Translator). Declarations (isDefinition: false) can have null
1292 // getType() while definitions must have a non-null one (enforced by the IR
1293 // verifier).
1294 MCRegister TyReg = CachedDebugInfoNoneReg;
1295 if (const DIType *Ty = GV->getType()) {
1296 auto TyRegOpt = lookupOptReg(Map: DebugScopeRegs, Key: Ty);
1297 if (!TyRegOpt)
1298 return std::nullopt;
1299 TyReg = *TyRegOpt;
1300 }
1301
1302 std::optional<MCRegister> StaticMemberRegOpt;
1303 if (const DIDerivedType *SM = GV->getStaticDataMemberDeclaration()) {
1304 StaticMemberRegOpt = lookupOptReg(Map: DebugScopeRegs, Key: SM);
1305 if (!StaticMemberRegOpt)
1306 return std::nullopt;
1307 }
1308
1309 MCRegister NameReg = getCachedOpStringReg(S: GV->getName());
1310 MCRegister LinkageReg = getCachedOpStringReg(S: GV->getLinkageName());
1311 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1312 Scope: GV->getFile(), /*UseEmptyPathIfNullScope=*/true);
1313 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1314 ExtInstSetReg, MAI);
1315
1316 MCRegister LineReg =
1317 emitOpConstantI32(Value: static_cast<uint32_t>(GV->getLine()), I32TypeReg, MAI);
1318 // DIGlobalVariable or DIGlobalVariableExpression metadata carry no column
1319 // field. Column is hardcoded to 0 (because it can't be determined), matching
1320 // SPIRV-LLVM-Translator.
1321 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
1322
1323 // Variable: @g OpVariable id when !dbg matches; else a DebugExpression for
1324 // the GVE init value when no @g exists and the expression is non-empty; else
1325 // DebugInfoNone. As per spec, the DebugExpression must contain the constant
1326 // value of the variable that was optimized out. An empty expression contains
1327 // no value, so we emit DebugInfoNone instead.
1328 MCRegister VariableReg = CachedDebugInfoNoneReg;
1329 if (const GlobalVariable *LLVMGV = Info.LLVMGV) {
1330 MCRegister GVReg = MAI.getGlobalObjReg(GO: LLVMGV);
1331 if (GVReg.isValid())
1332 VariableReg = GVReg;
1333 } else if (Info.Expr && Info.Expr->getNumElements() != 0) {
1334 if (auto ExprReg = emitDebugExpression(Expr: Info.Expr, VoidTypeReg, I32TypeReg,
1335 ExtInstSetReg, MAI))
1336 VariableReg = *ExprReg;
1337 }
1338
1339 MCRegister FlagsReg = emitOpConstantI32(Value: transDebugFlags(DN: GV), I32TypeReg, MAI);
1340
1341 SmallVector<MCRegister, 10> Ops = {NameReg, TyReg, SrcReg,
1342 LineReg, ColReg, ParentReg,
1343 LinkageReg, VariableReg, FlagsReg};
1344
1345 if (StaticMemberRegOpt)
1346 Ops.push_back(Elt: *StaticMemberRegOpt);
1347
1348 return emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugGlobalVariable,
1349 VoidTypeReg, ExtInstSetReg, Operands: Ops, MAI);
1350}
1351
1352std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugLocalVariable(
1353 const DILocalVariable *LV, MCRegister VoidTypeReg, MCRegister I32TypeReg,
1354 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
1355 assert(LV && "LV must not be null in emitDebugLocalVariable");
1356
1357 EmitResult Parent = resolveScope(Scope: LV->getScope());
1358 if (!Parent)
1359 return std::nullopt;
1360
1361 MCRegister TyReg = CachedDebugInfoNoneReg;
1362 if (const DIType *Ty = LV->getType()) {
1363 auto TyRegOpt = lookupOptReg(Map: DebugScopeRegs, Key: Ty);
1364 if (!TyRegOpt)
1365 return std::nullopt;
1366 TyReg = *TyRegOpt;
1367 }
1368
1369 MCRegister NameReg = getCachedOpStringReg(S: LV->getName());
1370 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1371 Scope: LV->getFile(), /*UseEmptyPathIfNullScope=*/true);
1372 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1373 ExtInstSetReg, MAI);
1374 MCRegister LineReg =
1375 emitOpConstantI32(Value: static_cast<uint32_t>(LV->getLine()), I32TypeReg, MAI);
1376 // DILocalVariable has no column field. Column is hardcoded to 0.
1377 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
1378 MCRegister FlagsReg = emitOpConstantI32(Value: transDebugFlags(DN: LV), I32TypeReg, MAI);
1379
1380 SmallVector<MCRegister, 8> Ops = {NameReg, TyReg, SrcReg, LineReg,
1381 ColReg, Parent.Reg, FlagsReg};
1382 if (unsigned Arg = LV->getArg())
1383 Ops.push_back(Elt: emitOpConstantI32(Value: Arg, I32TypeReg, MAI));
1384
1385 return emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugLocalVariable, VoidTypeReg,
1386 ExtInstSetReg, Operands: Ops, MAI);
1387}
1388
1389SPIRVNonSemanticDebugHandler::EmitResult
1390SPIRVNonSemanticDebugHandler::emitDebugTypeVector(
1391 const DICompositeType *VT, MCRegister ExtInstSetReg,
1392 SPIRV::ModuleAnalysisInfo &MAI) {
1393 const auto *BaseTy = dyn_cast_or_null<DIBasicType>(Val: VT->getBaseType());
1394 if (!BaseTy)
1395 return EmitResult::unsupported();
1396
1397 // DebugTypeVector models only 1D vectors (multi-subrange types cannot be
1398 // encoded).
1399 DINodeArray Elements = VT->getElements();
1400 if (Elements.size() != 1)
1401 return EmitResult::unsupported();
1402 const auto *SR = cast<DISubrange>(Val: Elements[0]);
1403 const auto *CI = dyn_cast_if_present<ConstantInt *>(Val: SR->getCount());
1404 if (!CI)
1405 return EmitResult::unsupported();
1406
1407 EmitResult Base = getOrCreateDebugScope(S: BaseTy);
1408 if (!Base)
1409 return Base;
1410
1411 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1412 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
1413 MCRegister CountReg = emitOpConstantI32(
1414 Value: static_cast<uint32_t>(CI->getZExtValue()), I32TypeReg, MAI);
1415 return EmitResult::emitted(
1416 R: emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugTypeVector, VoidTypeReg,
1417 ExtInstSetReg, Operands: {Base.Reg, CountReg}, MAI));
1418}
1419
1420SPIRVNonSemanticDebugHandler::EmitResult
1421SPIRVNonSemanticDebugHandler::emitDebugTypeArray(
1422 const DICompositeType *AT, MCRegister ExtInstSetReg,
1423 SPIRV::ModuleAnalysisInfo &MAI) {
1424 // Unlike DebugTypeVector, the element may be any debug type, not only a
1425 // basic type. Create it first so this array names an id that already exists.
1426 EmitResult Base = getOrCreateDebugScope(S: AT->getBaseType());
1427 if (!Base)
1428 return Base;
1429
1430 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1431 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
1432
1433 SmallVector<MCRegister> Ops;
1434 Ops.push_back(Elt: Base.Reg);
1435
1436 // One component count per DISubrange, in DWARF subrange order. Emit 0 for
1437 // counts that are not a compile-time constant (dynamic arrays). This matches
1438 // OpTypeRuntimeArray.
1439 for (const DINode *Element : AT->getElements()) {
1440 const auto *SR = dyn_cast<DISubrange>(Val: Element);
1441 if (!SR)
1442 continue;
1443 // A DIVariable count (a variable-length array) is not a ConstantInt, so it
1444 // maps to 0 here. DebugTypeArray also allows a DebugLocalVariable or
1445 // DebugGlobalVariable id for it, but no frontend we target emits one. A
1446 // constant wider than 32 bits maps to 0 too, since the count operand is a
1447 // 32-bit OpConstant and such an array cannot occur in a shader.
1448 uint32_t Count = 0;
1449 if (const auto *CI = dyn_cast_if_present<ConstantInt *>(Val: SR->getCount())) {
1450 const APInt &Value = CI->getValue();
1451 if (Value.getActiveBits() <= 32)
1452 Count = static_cast<uint32_t>(Value.getZExtValue());
1453 }
1454 Ops.push_back(Elt: emitOpConstantI32(Value: Count, I32TypeReg, MAI));
1455 }
1456
1457 return EmitResult::emitted(
1458 R: emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugTypeArray, VoidTypeReg,
1459 ExtInstSetReg, Operands: Ops, MAI));
1460}
1461
1462std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeMember(
1463 const DIDerivedType *M, MCRegister VoidTypeReg, MCRegister I32TypeReg,
1464 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
1465 EmitResult Ty = getOrCreateDebugScope(S: M->getBaseType());
1466 if (!Ty)
1467 return std::nullopt;
1468
1469 if (!isUInt<32>(x: M->getOffsetInBits()) || !isUInt<32>(x: M->getSizeInBits()))
1470 return std::nullopt;
1471
1472 MCRegister NameReg = getCachedOpStringReg(S: M->getName());
1473 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1474 Scope: M->getFile(), /*UseEmptyPathIfNullScope=*/true);
1475 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1476 ExtInstSetReg, MAI);
1477 MCRegister LineReg =
1478 emitOpConstantI32(Value: static_cast<uint32_t>(M->getLine()), I32TypeReg, MAI);
1479
1480 // DIDerivedType members carry no column, so emit 0.
1481 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
1482 MCRegister OffsetReg = emitOpConstantI32(
1483 Value: static_cast<uint32_t>(M->getOffsetInBits()), I32TypeReg, MAI);
1484 MCRegister SizeReg = emitOpConstantI32(
1485 Value: static_cast<uint32_t>(M->getSizeInBits()), I32TypeReg, MAI);
1486 MCRegister FlagsReg = emitOpConstantI32(Value: transDebugFlags(DN: M), I32TypeReg, MAI);
1487
1488 // In NonSemantic.Shader.DebugInfo a DebugTypeMember has no Parent operand:
1489 // only the composite references its members. This is by design, it drops the
1490 // Parent that OpenCL.DebugInfo.100 had, and it avoids a composite/member
1491 // reference cycle.
1492 //
1493 // FIXME: Static members are not handled yet: their constant initializer is
1494 // available but is not emitted as the optional Value operand, and under DWARF
1495 // 5 a static member is tagged DW_TAG_variable, which the caller's member loop
1496 // skips.
1497 return emitExtInst(
1498 Opcode: SPIRV::NonSemanticExtInst::DebugTypeMember, VoidTypeReg, ExtInstSetReg,
1499 Operands: {NameReg, Ty.Reg, SrcReg, LineReg, ColReg, OffsetReg, SizeReg, FlagsReg},
1500 MAI);
1501}
1502
1503SPIRVNonSemanticDebugHandler::EmitResult
1504SPIRVNonSemanticDebugHandler::emitDebugTypeComposite(
1505 const DICompositeType *CT, MCRegister VoidTypeReg, MCRegister I32TypeReg,
1506 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
1507 // Parent and size before any member: a failure must stream nothing, or a
1508 // retry would emit the members again.
1509 EmitResult Parent = resolveScope(Scope: CT->getScope());
1510 if (!Parent)
1511 return Parent;
1512
1513 if (!isUInt<32>(x: CT->getSizeInBits()))
1514 return EmitResult::unsupported();
1515
1516 SmallVector<MCRegister, 8> MemberRegs;
1517 for (const DINode *Element : CT->getElements()) {
1518 const auto *M = dyn_cast<DIDerivedType>(Val: Element);
1519 if (!M || M->getTag() != dwarf::DW_TAG_member)
1520 continue;
1521 if (auto MemberReg =
1522 emitDebugTypeMember(M, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI))
1523 MemberRegs.push_back(Elt: *MemberReg);
1524 }
1525
1526 MCRegister NameReg = getCachedOpStringReg(S: CT->getName());
1527 MCRegister LinkageReg = getCachedOpStringReg(S: CT->getIdentifier());
1528 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1529 Scope: CT->getFile(), /*UseEmptyPathIfNullScope=*/true);
1530 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1531 ExtInstSetReg, MAI);
1532
1533 MCRegister TagReg =
1534 emitOpConstantI32(Value: mapCompositeTypeTag(Tag: CT->getTag()), I32TypeReg, MAI);
1535 MCRegister LineReg =
1536 emitOpConstantI32(Value: static_cast<uint32_t>(CT->getLine()), I32TypeReg, MAI);
1537 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
1538
1539 // A forward declaration has no known size or members: Size is DebugInfoNone.
1540 MCRegister SizeReg = CachedDebugInfoNoneReg;
1541 if (!CT->isForwardDecl())
1542 SizeReg = emitOpConstantI32(Value: static_cast<uint32_t>(CT->getSizeInBits()),
1543 I32TypeReg, MAI);
1544
1545 MCRegister FlagsReg = emitOpConstantI32(Value: transDebugFlags(DN: CT), I32TypeReg, MAI);
1546
1547 SmallVector<MCRegister> Ops = {NameReg, TagReg, SrcReg,
1548 LineReg, ColReg, Parent.Reg,
1549 LinkageReg, SizeReg, FlagsReg};
1550 Ops.append(in_start: MemberRegs.begin(), in_end: MemberRegs.end());
1551 return EmitResult::emitted(
1552 R: emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugTypeComposite, VoidTypeReg,
1553 ExtInstSetReg, Operands: Ops, MAI));
1554}
1555
1556SPIRVNonSemanticDebugHandler::EmitResult
1557SPIRVNonSemanticDebugHandler::emitDebugTypedef(const DIDerivedType *TD,
1558 MCRegister VoidTypeReg,
1559 MCRegister I32TypeReg,
1560 MCRegister ExtInstSetReg,
1561 SPIRV::ModuleAnalysisInfo &MAI) {
1562 EmitResult Base = getOrCreateDebugScope(S: TD->getBaseType());
1563 if (!Base)
1564 return Base;
1565
1566 MCRegister NameReg = getCachedOpStringReg(S: TD->getName());
1567 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1568 Scope: TD->getFile(), /*UseEmptyPathIfNullScope=*/true);
1569 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1570 ExtInstSetReg, MAI);
1571 MCRegister LineReg =
1572 emitOpConstantI32(Value: static_cast<uint32_t>(TD->getLine()), I32TypeReg, MAI);
1573 // DIDerivedType typedefs carry no column, so emit 0.
1574 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
1575
1576 // Parent must be a lexical scope. Valid NSDI lexical scopes are
1577 // DebugCompilationUnit, DebugFunction, DebugLexicalBlock, or
1578 // DebugTypeComposite.
1579 EmitResult Parent = resolveScope(Scope: TD->getScope());
1580 if (!Parent)
1581 return Parent;
1582
1583 return EmitResult::emitted(R: emitExtInst(
1584 Opcode: SPIRV::NonSemanticExtInst::DebugTypedef, VoidTypeReg, ExtInstSetReg,
1585 Operands: {NameReg, Base.Reg, SrcReg, LineReg, ColReg, Parent.Reg}, MAI));
1586}
1587
1588void SPIRVNonSemanticDebugHandler::emitNonSemanticDebugStrings(
1589 SPIRV::ModuleAnalysisInfo &MAI) {
1590 if (CompileUnits.empty())
1591 return;
1592 // Check that prepareModuleOutput() registered the extended instruction set.
1593 // If the subtarget does not support the extension, neither strings nor ext
1594 // insts are emitted.
1595 if (!MAI.getExtInstSetReg(SetNum: NSSet).isValid())
1596 return;
1597
1598 for (const CompileUnitInfo &Info : CompileUnits) {
1599 if (Info.TheCU) {
1600 MCRegister PathReg = emitOpStringIfNew(S: Info.FilePath, MAI);
1601 ScopeToPathOpStringReg[Info.TheCU] = PathReg;
1602 if (const DIFile *F = Info.TheCU->getFile())
1603 ScopeToPathOpStringReg[F] = PathReg;
1604 }
1605 }
1606
1607 for (const DISubprogram *SP : concat<const DISubprogram *>(
1608 Ranges&: SubprogramDeclarations, Ranges&: SubprogramDefinitions)) {
1609 emitOpStringIfNew(S: SP->getName(), MAI);
1610 emitOpStringIfNew(S: SP->getLinkageName(), MAI);
1611 emitAndCacheScopePathOpStringReg(Scope: SP, MAI);
1612 }
1613
1614 for (const DIType *Ty : DebugTypes) {
1615 if (const auto *BT = dyn_cast<DIBasicType>(Val: Ty)) {
1616 emitOpStringIfNew(S: BT->getName(), MAI);
1617 continue;
1618 }
1619 if (const auto *CT = dyn_cast<DICompositeType>(Val: Ty)) {
1620 // Cache the OpStrings each DebugTypeComposite and its DebugTypeMembers
1621 // use: the composite name, identifier (linkage name), and path, plus
1622 // each member name and path. Arrays and vectors have no such strings.
1623 if (CT->getTag() != dwarf::DW_TAG_structure_type &&
1624 CT->getTag() != dwarf::DW_TAG_class_type &&
1625 CT->getTag() != dwarf::DW_TAG_union_type)
1626 continue;
1627 emitOpStringIfNew(S: CT->getName(), MAI);
1628 emitOpStringIfNew(S: CT->getIdentifier(), MAI);
1629 emitAndCacheScopePathOpStringReg(Scope: CT->getFile(), MAI);
1630 for (const DINode *Element : CT->getElements()) {
1631 const auto *M = dyn_cast<DIDerivedType>(Val: Element);
1632 if (!M || M->getTag() != dwarf::DW_TAG_member)
1633 continue;
1634 emitOpStringIfNew(S: M->getName(), MAI);
1635 emitAndCacheScopePathOpStringReg(Scope: M->getFile(), MAI);
1636 }
1637 continue;
1638 }
1639 // Cache the name and path OpStrings each DebugTypedef uses.
1640 const auto *TD = dyn_cast<DIDerivedType>(Val: Ty);
1641 if (TD && TD->getTag() == dwarf::DW_TAG_typedef) {
1642 emitOpStringIfNew(S: TD->getName(), MAI);
1643 emitAndCacheScopePathOpStringReg(Scope: TD->getFile(), MAI);
1644 }
1645 }
1646
1647 for (const auto &[GV, _] : GlobalVariableDebugInfoMap) {
1648 emitOpStringIfNew(S: GV->getName(), MAI);
1649 emitOpStringIfNew(S: GV->getLinkageName(), MAI);
1650 emitAndCacheScopePathOpStringReg(Scope: GV->getFile(), MAI);
1651 }
1652
1653 for (const DILocalVariable *LV : LocalVariables) {
1654 emitOpStringIfNew(S: LV->getName(), MAI);
1655 emitAndCacheScopePathOpStringReg(Scope: LV->getFile(), MAI);
1656 }
1657
1658 // Cache the path OpString each DebugLexicalBlock uses (source file), plus
1659 // the Name OpString for the DINamespace case.
1660 for (const DIScope *S : LexicalBlocks) {
1661 emitAndCacheScopePathOpStringReg(Scope: S->getFile(), MAI);
1662 if (const auto *NS = dyn_cast<DINamespace>(Val: S))
1663 emitOpStringIfNew(S: NS->getName(), MAI);
1664 }
1665
1666 for (const DILocation *DL : UniqueDebugLocations)
1667 emitAndCacheScopePathOpStringReg(Scope: DL->getScope(), MAI);
1668
1669 CachedEmptyStringReg = emitOpStringIfNew(S: "", MAI);
1670
1671#ifndef NDEBUG
1672 NonSemanticOpStringsSectionEmitted = true;
1673#endif
1674}
1675
1676void SPIRVNonSemanticDebugHandler::emitDebugFunctionDefinition(
1677 MCRegister DebugFunctionReg, MCRegister OpFunctionReg,
1678 SPIRV::ModuleAnalysisInfo &MAI) {
1679 assert(DebugFunctionReg.isValid() && OpFunctionReg.isValid() &&
1680 "DebugFunctionDefinition operands must be valid");
1681 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1682 MCRegister ExtInstSetReg = MAI.getExtInstSetReg(SetNum: NSSet);
1683 emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugFunctionDefinition, VoidTypeReg,
1684 ExtInstSetReg, Operands: {DebugFunctionReg, OpFunctionReg}, MAI);
1685}
1686
1687void SPIRVNonSemanticDebugHandler::resetPerFunctionDebugState() {
1688 CurrentMF = nullptr;
1689 LastFunctionOpVariable = nullptr;
1690 DebugFunctionDefinitionEmitted = false;
1691 LastLineMI = nullptr;
1692 LastScopeMI = nullptr;
1693 Records.clear();
1694}
1695
1696void SPIRVNonSemanticDebugHandler::preparePerFunctionDebug(
1697 const MachineFunction *MF) {
1698 resetPerFunctionDebugState();
1699 if (!GlobalNSDIEnabled || !CurrentMAI)
1700 return;
1701
1702 CurrentMF = MF;
1703
1704 if (MF->getFunction()
1705 .getFnAttribute(SPIRV_BACKEND_SERVICE_FUN_NAME)
1706 .isValid())
1707 return;
1708
1709 const DISubprogram *SP = MF->getFunction().getSubprogram();
1710 if (!SP || !SP->isDefinition())
1711 return;
1712
1713 // DebugFunctionDefinition is emitted after the last function-level
1714 // OpVariable. If there are none, it is emitted after the entry OpLabel.
1715 LastFunctionOpVariable =
1716 findLastFunctionOpVariableDeclaration(MF: *MF, MAI&: *CurrentMAI);
1717
1718 analyzeDebugRecords(MF: *MF);
1719}
1720
1721void SPIRVNonSemanticDebugHandler::tryEmitDebugFunctionDefinition(
1722 SPIRV::ModuleAnalysisInfo &MAI) {
1723 if (DebugFunctionDefinitionEmitted || !GlobalNSDIEnabled)
1724 return;
1725
1726 assert(CurrentMF && "no current MachineFunction");
1727 const Function &F = CurrentMF->getFunction();
1728 const DISubprogram *SP = F.getSubprogram();
1729 if (!SP || !SP->isDefinition())
1730 return;
1731
1732 auto DFIt = DebugScopeRegs.find(Val: SP);
1733 if (DFIt == DebugScopeRegs.end())
1734 return;
1735
1736 MCRegister OpFunctionReg = MAI.getGlobalObjReg(GO: &F);
1737 if (!OpFunctionReg.isValid())
1738 return;
1739
1740 emitDebugFunctionDefinition(DebugFunctionReg: DFIt->second, OpFunctionReg, MAI);
1741 DebugFunctionDefinitionEmitted = true;
1742}
1743
1744void SPIRVNonSemanticDebugHandler::beginFunctionImpl(
1745 const MachineFunction *MF) {
1746 preparePerFunctionDebug(MF);
1747}
1748
1749void SPIRVNonSemanticDebugHandler::endFunctionImpl(const MachineFunction *MF) {
1750 (void)MF;
1751 resetPerFunctionDebugState();
1752}
1753
1754void SPIRVNonSemanticDebugHandler::beginInstruction(const MachineInstr *MI) {
1755 assert(CurMI == nullptr && "CurMI must be null");
1756 CurMI = MI;
1757
1758 if (!DebugFunctionDefinitionEmitted)
1759 return;
1760
1761 emitAnalyzedRecords(Anchor: MI);
1762
1763 std::optional<const MachineInstr *> Target = resolveDebugLocTarget(MI);
1764 if (!Target)
1765 return;
1766
1767 (void)emitDebugScopeForInstruction(MI: *Target);
1768 emitDebugLineForInstruction(MI: *Target);
1769}
1770
1771// The register that holds the variable's address in \p MI, or std::nullopt
1772// when \p MI is not a declare this backend can describe.
1773//
1774// The spec requires DebugDeclare's Variable operand to be "the <id> of an
1775// OpVariable instruction that defines the local variable". MIR has no
1776// DBG_DECLARE, so what this looks for is an indirect DBG_VALUE whose location
1777// register an OpVariable defines.
1778static std::optional<Register>
1779getDebugDeclareStorageReg(const MachineInstr &MI) {
1780 // #dbg_declare is an indirect DBG_VALUE in MIR; #dbg_value is normally a
1781 // direct one except for the variadic case.
1782 if (!MI.isIndirectDebugValue())
1783 return std::nullopt;
1784
1785 // A variadic #dbg_value becomes DBG_VALUE $noreg, 0, ... which is indirect
1786 // too, and $noreg is not virtual.
1787 Register LocReg = MI.getDebugOperand(Index: 0).getReg();
1788 if (!LocReg.isVirtual())
1789 return std::nullopt;
1790
1791 // DebugDeclare can only encode the address of an OpVariable.
1792 // Other legitimate #dbg_declare cannot be encoded.
1793 // Examples: an access chain for a field, an OpFunctionParameter for a byval
1794 // argument, or a module-scope constant for a null or fixed address.
1795
1796 // LocReg may also have no def at all: erasing dead storage leaves the
1797 // DBG_VALUE pointing at an undefined register. MachineVerifier permits that
1798 // because LiveDebugVariables normally clears it, but this pipeline has no
1799 // register allocation, so LiveDebugVariables never runs.
1800 const MachineInstr *Def = MI.getMF()->getRegInfo().getUniqueVRegDef(Reg: LocReg);
1801 if (!Def || Def->getOpcode() != SPIRV::OpVariable)
1802 return std::nullopt;
1803
1804 return LocReg;
1805}
1806
1807void SPIRVNonSemanticDebugHandler::emitDebugBinding(
1808 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
1809 const MachineInstr *MI, MCRegister LocationReg) {
1810 assert(DebugFunctionDefinitionEmitted &&
1811 "DebugFunctionDefinition must be emitted");
1812 assert(CurrentMAI && "CurrentMAI must be set");
1813
1814 auto VarRegOpt = lookupOptReg(Map: DebugLocalVariableRegs, Key: MI->getDebugVariable());
1815 if (!VarRegOpt)
1816 return;
1817
1818 auto ExprRegOpt = lookupOptReg(Map: DebugExpressionRegs, Key: MI->getDebugExpression());
1819 if (!ExprRegOpt)
1820 return;
1821
1822 if (!emitDebugScopeForInstruction(MI))
1823 return;
1824 emitDebugLineForInstruction(MI);
1825
1826 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
1827 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1828 MCRegister ExtInstSetReg = MAI.getExtInstSetReg(SetNum: NSSet);
1829 emitExtInst(Opcode, VoidTypeReg, ExtInstSetReg,
1830 Operands: {*VarRegOpt, LocationReg, *ExprRegOpt}, MAI);
1831}
1832
1833// The scalar type and value of the constant \p MI assigns, or nullopt when
1834// this backend cannot name it.
1835static std::optional<std::pair<const DIBasicType *, uint64_t>>
1836getConstantDbgValueBits(const MachineInstr &MI) {
1837 if (!MI.isNonListDebugValue() || MI.isIndirectDebugValue())
1838 return std::nullopt;
1839
1840 const MachineOperand &Value = MI.getDebugOperand(Index: 0);
1841 if (!Value.isImm() && !Value.isCImm() && !Value.isFPImm())
1842 return std::nullopt;
1843
1844 const DILocalVariable *LV = MI.getDebugVariable();
1845 const DIBasicType *BT = LV ? stripToScalarType(Ty: LV->getType()) : nullptr;
1846 if (!BT)
1847 return std::nullopt;
1848
1849 uint64_t Bits;
1850 if (Value.isImm())
1851 Bits = constantBits(Value: static_cast<uint64_t>(Value.getImm()), BT);
1852 else if (Value.isCImm())
1853 Bits = constantBits(Value: Value.getCImm()->getValue(), BT);
1854 else
1855 Bits = constantBits(Value: Value.getFPImm()->getValueAPF().bitcastToAPInt(), BT);
1856 return std::make_pair(x&: BT, y&: Bits);
1857}
1858
1859std::optional<MCRegister> SPIRVNonSemanticDebugHandler::getConstantValueReg(
1860 const MachineInstr &MI) const {
1861 std::optional<std::pair<const DIBasicType *, uint64_t>> Const =
1862 getConstantDbgValueBits(MI);
1863 if (!Const)
1864 return std::nullopt;
1865
1866 auto It = ConstantValueRegs.find(Val: *Const);
1867 if (It == ConstantValueRegs.end() || !It->second.isValid())
1868 return std::nullopt;
1869 return It->second;
1870}
1871
1872static std::optional<Register> getDebugValueReg(const MachineInstr &MI) {
1873 if (!MI.isNonListDebugValue() || MI.isIndirectDebugValue())
1874 return std::nullopt;
1875
1876 const MachineOperand &Value = MI.getDebugOperand(Index: 0);
1877 if (!Value.isReg())
1878 return std::nullopt;
1879
1880 Register ValueReg = Value.getReg();
1881 if (!ValueReg.isVirtual())
1882 return std::nullopt;
1883
1884 const MachineInstr *Def = MI.getMF()->getRegInfo().getUniqueVRegDef(Reg: ValueReg);
1885 if (!Def || (Def->isPseudo() && !Def->isPHI()) || Def->isMetaInstruction() ||
1886 Def->getNumOperands() == 0 || !Def->getOperand(i: 0).isReg() ||
1887 !Def->getOperand(i: 0).isDef() || Def->getOperand(i: 0).getReg() != ValueReg)
1888 return std::nullopt;
1889
1890 return ValueReg;
1891}
1892
1893static bool isMergeInstruction(unsigned Opcode) {
1894 return Opcode == SPIRV::OpSelectionMerge || Opcode == SPIRV::OpLoopMerge ||
1895 Opcode == SPIRV::OpLoopControlINTEL;
1896}
1897
1898// Whether \p MI becomes a SPIR-V instruction in the output.
1899static bool isEmitted(const MachineInstr *MI, SPIRV::ModuleAnalysisInfo &MAI) {
1900 return !MI->isMetaInstruction() && !MAI.getSkipEmission(MI);
1901}
1902
1903static bool isDebugLocTarget(const MachineInstr *MI,
1904 SPIRV::ModuleAnalysisInfo &MAI) {
1905 if (!isEmitted(MI, MAI))
1906 return false;
1907 switch (MI->getOpcode()) {
1908 case SPIRV::OpFunction:
1909 case SPIRV::OpFunctionParameter:
1910 case SPIRV::OpFunctionEnd:
1911 case SPIRV::OpLabel:
1912 case TargetOpcode::PHI:
1913 return false;
1914 default:
1915 return true;
1916 }
1917}
1918
1919static const MachineInstr *
1920findAdjacentEmittedInstruction(const MachineInstr *MI,
1921 SPIRV::ModuleAnalysisInfo &MAI, bool Forward) {
1922 for (const MachineInstr *Adj = Forward ? MI->getNextNode()
1923 : MI->getPrevNode();
1924 Adj; Adj = Forward ? Adj->getNextNode() : Adj->getPrevNode()) {
1925 if (!isEmitted(MI: Adj, MAI))
1926 continue;
1927 return Adj;
1928 }
1929 return nullptr;
1930}
1931
1932std::optional<const MachineInstr *>
1933SPIRVNonSemanticDebugHandler::resolveDebugLocTarget(const MachineInstr *MI) {
1934 assert(CurrentMAI && "CurrentMAI must be set");
1935 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
1936
1937 // Structural opcodes don't require a DebugLine/DebugScope, other opcodes
1938 // might have already been emitted in the module scope.
1939 if (!isDebugLocTarget(MI, MAI))
1940 return std::nullopt;
1941
1942 // DebugLine/DebugScope can be emitted before a merge instruction, but not
1943 // after it (nothing may sit between the merge and its terminator). We can
1944 // use either the merge's or the terminator's debug info; we emit the
1945 // terminator's one.
1946 const MachineInstr *Prev = findAdjacentEmittedInstruction(MI, MAI, Forward: false);
1947 if (Prev && isMergeInstruction(Opcode: Prev->getOpcode()))
1948 return std::nullopt;
1949
1950 if (isMergeInstruction(Opcode: MI->getOpcode())) {
1951 // Use the terminator's debug info; when we reach it later, the check
1952 // above skips it.
1953 MI = findAdjacentEmittedInstruction(MI, MAI, Forward: true);
1954 assert(MI && "Merge instruction must be followed by a terminator");
1955 // The assert is compiled out in a release build, and returning MI there
1956 // would give an engaged optional holding null.
1957 if (!MI)
1958 return std::nullopt;
1959 }
1960
1961 return MI;
1962}
1963
1964void SPIRVNonSemanticDebugHandler::resolveDebugRecord(
1965 const MachineInstr &MI, const MachineInstr *LastEmitted,
1966 const MachineDominatorTree &DomTree) {
1967 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
1968 const MachineFunction &MF = *MI.getMF();
1969
1970 // A record sits at its own position, except in a merge region: nothing may
1971 // be emitted between a merge and its terminator, so it belongs ahead of the
1972 // merge.
1973 const MachineInstr *Anchor =
1974 LastEmitted && isMergeInstruction(Opcode: LastEmitted->getOpcode()) ? LastEmitted
1975 : &MI;
1976
1977 // A #dbg_declare reaches Machine IR as an indirect DBG_VALUE. Its storage is
1978 // an OpVariable in the entry block, so it is in the output by the time any
1979 // record naming it is reached.
1980 if (std::optional<Register> LocReg = getDebugDeclareStorageReg(MI)) {
1981 MCRegister StorageReg = MAI.getRegisterAlias(MF: &MF, Reg: *LocReg);
1982 if (StorageReg.isValid())
1983 placeRecord(Opcode: SPIRV::NonSemanticExtInst::DebugDeclare, MI, LocationReg: StorageReg,
1984 Anchor);
1985 return;
1986 }
1987
1988 if (std::optional<MCRegister> ConstReg = getConstantValueReg(MI)) {
1989 placeRecord(Opcode: SPIRV::NonSemanticExtInst::DebugValue, MI, LocationReg: *ConstReg, Anchor);
1990 return;
1991 }
1992
1993 std::optional<Register> ValReg = getDebugValueReg(MI);
1994 if (!ValReg)
1995 return;
1996 MCRegister ValueReg = MAI.getRegisterAlias(MF: &MF, Reg: *ValReg);
1997 if (!ValueReg.isValid())
1998 return;
1999
2000 // NonSemantic.Shader.DebugInfo states that "Forward references are not
2001 // allowed, to be compliant with SPV_KHR_non_semantic_info", so the id has to
2002 // be in the output already. A module section precedes every function body.
2003 //
2004 // For anything else, SPIR-V requires a definition in a function block to
2005 // dominate a non-phi use, and requires a block to precede every block it
2006 // dominates, so a dominating definition is also one already printed. A
2007 // record naming a definition that does not dominate it is dropped.
2008 const MachineInstr *Def = MF.getRegInfo().getUniqueVRegDef(Reg: *ValReg);
2009 if (ModuleScopeIds.contains(V: ValueReg) ||
2010 (isEmitted(MI: Def, MAI) && DomTree.dominates(A: Def, B: &MI)))
2011 placeRecord(Opcode: SPIRV::NonSemanticExtInst::DebugValue, MI, LocationReg: ValueReg, Anchor);
2012}
2013
2014void SPIRVNonSemanticDebugHandler::analyzeDebugRecords(
2015 const MachineFunction &MF) {
2016 assert(CurrentMAI && "CurrentMAI must be set");
2017
2018 // Built on the first record rather than required as an analysis pass, which
2019 // would build a tree for every SPIR-V compilation.
2020 std::optional<MachineDominatorTree> DomTree;
2021
2022 for (const MachineBasicBlock &MBB : MF) {
2023 const MachineInstr *LastEmitted = nullptr;
2024 for (const MachineInstr &MI : MBB) {
2025 if (MI.isDebugValueLike()) {
2026 if (!DomTree)
2027 DomTree.emplace(args&: const_cast<MachineFunction &>(MF));
2028 resolveDebugRecord(MI, LastEmitted, DomTree: *DomTree);
2029 }
2030
2031 if (isEmitted(MI: &MI, MAI&: *CurrentMAI))
2032 LastEmitted = &MI;
2033 }
2034 }
2035}
2036
2037void SPIRVNonSemanticDebugHandler::placeRecord(
2038 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
2039 const MachineInstr &MI, MCRegister LocationReg,
2040 const MachineInstr *Anchor) {
2041 Records[Anchor].push_back(Elt: {.MI: &MI, .Opcode: Opcode, .LocationReg: LocationReg});
2042}
2043
2044void SPIRVNonSemanticDebugHandler::emitAnalyzedRecords(
2045 const MachineInstr *Anchor) {
2046 auto It = Records.find(Val: Anchor);
2047 if (It == Records.end())
2048 return;
2049 for (const DebugRecord &R : It->second)
2050 emitDebugBinding(Opcode: R.Opcode, MI: R.MI, LocationReg: R.LocationReg);
2051}
2052
2053bool SPIRVNonSemanticDebugHandler::emitDebugScopeForInstruction(
2054 const MachineInstr *MI) {
2055 assert(DebugFunctionDefinitionEmitted &&
2056 "DebugFunctionDefinition must be emitted");
2057 assert(CurrentMAI && "CurrentMAI must be set");
2058
2059 // The region is implicitly closed at each basic block boundary, so a
2060 // LastScopeMI from another block must be dropped before it is read below:
2061 // the new block needs its own DebugScope, and has no region left to close.
2062 if (LastScopeMI && MI->getParent() != LastScopeMI->getParent())
2063 LastScopeMI = nullptr;
2064
2065 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
2066 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
2067 MCRegister ExtInstSetReg = MAI.getExtInstSetReg(SetNum: NSSet);
2068
2069 const DILocation *CurDL = MI->getDebugLoc().get();
2070 if (!CurDL) {
2071 // No location for the current instruction.
2072 if (LastScopeMI) {
2073 // Close the current DebugScope region.
2074 emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugNoScope, VoidTypeReg,
2075 ExtInstSetReg, Operands: {}, MAI);
2076 LastScopeMI = nullptr;
2077 }
2078 return true;
2079 }
2080
2081 const DIScope *CurScope = CurDL->getScope();
2082 const DILocation *CurInlinedAt = CurDL->getInlinedAt();
2083
2084 if (LastScopeMI) {
2085 const DILocation *LastDL = LastScopeMI->getDebugLoc().get();
2086 if (LastDL->getScope() == CurScope &&
2087 LastDL->getInlinedAt() == CurInlinedAt)
2088 return true;
2089 }
2090
2091 EmitResult CurScopeRes = resolveScope(Scope: CurScope);
2092 if (!CurScopeRes)
2093 return false;
2094
2095 SmallVector<MCRegister, 2> Ops{CurScopeRes.Reg};
2096 if (CurInlinedAt) {
2097 // If the global emission did not include this inlined-at case, we skip it.
2098 MCRegister InlinedReg = DebugInlinedAtRegs.lookup(Val: CurInlinedAt);
2099 if (!InlinedReg.isValid())
2100 return false;
2101 Ops.push_back(Elt: InlinedReg);
2102 }
2103
2104 // A new DebugScope region is needed.
2105 emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugScope, VoidTypeReg, ExtInstSetReg,
2106 Operands: Ops, MAI);
2107
2108 LastScopeMI = MI;
2109 return true;
2110}
2111
2112void SPIRVNonSemanticDebugHandler::emitDebugLineForInstruction(
2113 const MachineInstr *MI) {
2114 assert(DebugFunctionDefinitionEmitted &&
2115 "DebugFunctionDefinition must be emitted");
2116 assert(CurrentMAI && "CurrentMAI must be set");
2117
2118 // The region is implicitly closed at each basic block boundary, so a
2119 // LastLineMI from another block must be dropped before it is read below:
2120 // the new block needs its own DebugLine, and has no region left to close.
2121 if (LastLineMI && MI->getParent() != LastLineMI->getParent())
2122 LastLineMI = nullptr;
2123
2124 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
2125 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
2126 MCRegister ExtInstSetReg = MAI.getExtInstSetReg(SetNum: NSSet);
2127
2128 const DILocation *DL = MI->getDebugLoc().get();
2129 if (!DL) {
2130 // No location for the current instruction
2131 if (LastLineMI) {
2132 // Close the current DebugLine region.
2133 emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugNoLine, VoidTypeReg,
2134 ExtInstSetReg, Operands: {}, MAI);
2135 LastLineMI = nullptr;
2136 }
2137 // No DebugLine region to close.
2138 return;
2139 }
2140
2141 // At this point, there is a location for the current instruction.
2142 // If it matches the last emitted DebugLine, no new DebugLine region is
2143 // needed. Otherwise, emit a new DebugLine region and update LastLineMI.
2144
2145 MCRegister FileStrReg = getCachedScopePathOpStringReg(
2146 Scope: DL->getScope(), /*UseEmptyPathIfNullScope=*/true);
2147 unsigned Line = DL->getLine();
2148 unsigned Col = DL->getColumn();
2149
2150 unsigned I32TypeId = CachedOpTypeInt32Reg.id();
2151 MCRegister SrcReg = DebugSourceRegByFileStr.lookup(Val: FileStrReg.id());
2152 MCRegister LineReg = ScalarConstantCache.lookup(Val: {I32TypeId, Line});
2153 MCRegister ColStartReg = ScalarConstantCache.lookup(Val: {I32TypeId, Col});
2154 MCRegister ColEndReg = ScalarConstantCache.lookup(Val: {I32TypeId, Col + 1});
2155
2156 // The elements of each collected DILocation (DebugSource, line/column
2157 // constants) are pre-emitted from LLVM-IR instruction !dbg attachments and
2158 // debug-program records; MIR is expected to reuse those same locations (or
2159 // carry none). A lookup miss means codegen attached a source position whose
2160 // elements were never pre-emitted, and debug-line emission is skipped.
2161 if (!SrcReg.isValid() || !LineReg.isValid() || !ColStartReg.isValid() ||
2162 !ColEndReg.isValid())
2163 return;
2164
2165 // Current location matches the last emitted DebugLine region.
2166 if (LastLineMI && MI->getDebugLoc() == LastLineMI->getDebugLoc())
2167 return;
2168
2169 // A new DebugLine region is needed.
2170 emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugLine, VoidTypeReg, ExtInstSetReg,
2171 Operands: {SrcReg, LineReg, LineReg, ColStartReg, ColEndReg}, MAI);
2172
2173 LastLineMI = MI;
2174}
2175
2176void SPIRVNonSemanticDebugHandler::endInstruction() {
2177 const MachineInstr *MI = CurMI;
2178 CurMI = nullptr;
2179
2180 if (!MI || !GlobalNSDIEnabled || !CurrentMF)
2181 return;
2182
2183 if (DebugFunctionDefinitionEmitted || MI != LastFunctionOpVariable)
2184 return;
2185
2186 // If this is the last function-level OpVariable, emit the
2187 // DebugFunctionDefinition. Otherwise, we had already done it before right
2188 // after the OpLabel (see notifyEntryLabelEmitted).
2189 assert(CurrentMAI && "CurrentMAI must be set");
2190 tryEmitDebugFunctionDefinition(MAI&: *CurrentMAI);
2191}
2192
2193void SPIRVNonSemanticDebugHandler::notifyEntryLabelEmitted(
2194 const MachineFunction &MF) {
2195 if (!GlobalNSDIEnabled || DebugFunctionDefinitionEmitted || !CurrentMF)
2196 return;
2197
2198 assert(CurrentMF == &MF &&
2199 "notification does not match the current MachineFunction");
2200
2201 if (LastFunctionOpVariable)
2202 return;
2203
2204 // If there are no function-level OpVariables, emit the
2205 // DebugFunctionDefinition. Otherwise, DebugFunctionDefinition is emitted
2206 // after the last OpVariable (see endInstruction).
2207 tryEmitDebugFunctionDefinition(MAI&: *CurrentMAI);
2208}
2209
2210static void forEachDebugValueLike(const MachineModuleInfo &ModuleInfo,
2211 function_ref<void(const MachineInstr &)> Fn) {
2212 for (const Function &F : *ModuleInfo.getModule()) {
2213 const MachineFunction *MF = ModuleInfo.getMachineFunction(F);
2214 if (!MF)
2215 continue;
2216 for (const MachineBasicBlock &MBB : *MF)
2217 for (const MachineInstr &MI : MBB)
2218 if (MI.isDebugValueLike())
2219 Fn(MI);
2220 }
2221}
2222
2223void SPIRVNonSemanticDebugHandler::collectDebugExpressions(
2224 SetVector<const DIExpression *> &Out) const {
2225 MachineModuleInfo *ModuleInfo = Asm->MMI;
2226 assert(ModuleInfo && "MachineModuleInfo must be set during module output");
2227
2228 forEachDebugValueLike(ModuleInfo: *ModuleInfo, Fn: [&](const MachineInstr &MI) {
2229 Out.insert(X: MI.getDebugExpression());
2230 });
2231}
2232
2233void SPIRVNonSemanticDebugHandler::emitNonSemanticGlobalDebugInfo(
2234 SPIRV::ModuleAnalysisInfo &MAI) {
2235 if (GlobalDIEmitted)
2236 return;
2237
2238 GlobalDIEmitted = true;
2239
2240 if (CompileUnits.empty()) {
2241 GlobalNSDIEnabled = false;
2242 return;
2243 }
2244
2245 // Retrieve the ext inst set register allocated by prepareModuleOutput().
2246 MCRegister ExtInstSetReg = MAI.getExtInstSetReg(SetNum: NSSet);
2247 if (!ExtInstSetReg.isValid()) {
2248 GlobalNSDIEnabled = false;
2249 return;
2250 }
2251
2252#ifndef NDEBUG
2253 assert(NonSemanticOpStringsSectionEmitted &&
2254 "emitNonSemanticDebugStrings() must run before "
2255 "emitNonSemanticGlobalDebugInfo()");
2256#endif
2257
2258 CurrentMAI = &MAI;
2259
2260 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
2261 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
2262
2263 CachedDebugInfoNoneReg = emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugInfoNone,
2264 VoidTypeReg, ExtInstSetReg, Operands: {}, MAI);
2265
2266 // Emit integer constants shared across all NSDI instructions. The constant
2267 // cache ensures each value is emitted at most once even when referenced from
2268 // multiple instructions. All constants are pre-emitted before any DebugSource
2269 // so that the output order is: constants, then
2270 // DebugSource+DebugCompilationUnit pairs. This keeps OpConstant instructions
2271 // grouped before the OpExtInst instructions.
2272
2273 // The Version operand of DebugCompilationUnit is the version of the
2274 // NonSemantic.Shader.DebugInfo instruction set, which is 100 for
2275 // "NonSemantic.Shader.DebugInfo.100" (NonSemanticShaderDebugInfo100Version).
2276 MCRegister DebugInfoVersionReg = emitOpConstantI32(Value: 100, I32TypeReg, MAI);
2277 MCRegister DwarfVersionReg =
2278 emitOpConstantI32(Value: static_cast<uint32_t>(DwarfVersion), I32TypeReg, MAI);
2279
2280 // Pre-emit source language constants for all compile units before entering
2281 // the DebugSource loop.
2282 SmallVector<MCRegister> SrcLangRegs =
2283 map_to_vector(C&: CompileUnits, F: [&](const CompileUnitInfo &Info) {
2284 return emitOpConstantI32(Value: Info.SpirvSourceLanguage, I32TypeReg, MAI);
2285 });
2286
2287 // Emit DebugSource and DebugCompilationUnit for each compile unit.
2288 for (auto [Info, SrcLangReg] : llvm::zip(t&: CompileUnits, u&: SrcLangRegs)) {
2289 MCRegister FileStrReg = ScopeToPathOpStringReg.lookup(Val: Info.TheCU);
2290 assert(FileStrReg.isValid() &&
2291 "CU path OpString must be emitted in emitNonSemanticDebugStrings");
2292 MCRegister DebugSourceReg = getOrEmitDebugSourceForFileStrReg(
2293 FileStrReg, VoidTypeReg, ExtInstSetReg, MAI);
2294 MCRegister CUDbgReg = emitExtInst(
2295 Opcode: SPIRV::NonSemanticExtInst::DebugCompilationUnit, VoidTypeReg,
2296 ExtInstSetReg,
2297 Operands: {DebugInfoVersionReg, DwarfVersionReg, DebugSourceReg, SrcLangReg},
2298 MAI);
2299 if (Info.TheCU)
2300 DebugScopeRegs[Info.TheCU] = CUDbgReg;
2301 }
2302
2303 for (const DIScope *S :
2304 make_filter_range(Range&: LexicalBlocks, Pred: IsaPred<DINamespace>))
2305 getOrCreateDebugScope(S);
2306 for (const DIType *Ty : DebugTypes)
2307 getOrCreateDebugScope(S: Ty);
2308 for (const DISubprogram *SP : concat<const DISubprogram *>(
2309 Ranges&: SubprogramDeclarations, Ranges&: SubprogramDefinitions))
2310 getOrCreateDebugScope(S: SP);
2311 for (const DIScope *S :
2312 make_filter_range(Range&: LexicalBlocks, Pred: IsaPred<DILexicalBlock>))
2313 getOrCreateDebugScope(S);
2314
2315 // Emit DebugLocalVariable after DebugFunction and their lexical blocks so the
2316 // Parent operand can resolve. Record the ids for DebugDeclare.
2317 for (const DILocalVariable *LV : LocalVariables)
2318 if (auto LVReg = emitDebugLocalVariable(LV, VoidTypeReg, I32TypeReg,
2319 ExtInstSetReg, MAI))
2320 DebugLocalVariableRegs[LV] = *LVReg;
2321
2322 // Opcodes like DebugDeclare are part of the function body, but
2323 // DebugExpression is not. For such opcodes, we collect the expressions
2324 // directly from the MIR to avoid inconsistencies with those in the LLVM IR
2325 // module.
2326 SetVector<const DIExpression *> Expressions;
2327 collectDebugExpressions(Out&: Expressions);
2328 for (const DIExpression *Expr : Expressions)
2329 if (auto ExprReg = emitDebugExpression(Expr, VoidTypeReg, I32TypeReg,
2330 ExtInstSetReg, MAI))
2331 DebugExpressionRegs[Expr] = *ExprReg;
2332
2333 // Emit DebugGlobalVariable for each collected DIGlobalVariable.
2334 for (const auto &[GV, Info] : GlobalVariableDebugInfoMap)
2335 emitDebugGlobalVariable(GV, Info, VoidTypeReg, I32TypeReg, ExtInstSetReg,
2336 MAI);
2337
2338 // Emit DebugInlinedAt allowing recursive inlining.
2339 for (const DILocation *DL : UniqueDebugLocations)
2340 if (const DILocation *IA = DL->getInlinedAt())
2341 getOrEmitDebugInlinedAt(IA, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
2342
2343 // Repeating the lookups emitDebugBinding() performs emits a type and a
2344 // constant only for an assignment that will reach a DebugValue.
2345 MachineModuleInfo *ModuleInfo = Asm->MMI;
2346 assert(ModuleInfo && "MachineModuleInfo must be set during module output");
2347 forEachDebugValueLike(ModuleInfo: *ModuleInfo, Fn: [&](const MachineInstr &MI) {
2348 std::optional<std::pair<const DIBasicType *, uint64_t>> Const =
2349 getConstantDbgValueBits(MI);
2350 if (!Const)
2351 return;
2352 if (!DebugLocalVariableRegs.contains(Val: MI.getDebugVariable()) ||
2353 !DebugExpressionRegs.contains(Val: MI.getDebugExpression()))
2354 return;
2355 auto [It, Inserted] = ConstantValueRegs.try_emplace(Key: *Const, Args: MCRegister());
2356 if (Inserted)
2357 It->second = findOrEmitScalarConstant(BT: Const->first, Value: Const->second, MAI);
2358 if (!It->second.isValid())
2359 ConstantValueRegs.erase(I: It);
2360 });
2361
2362 for (const DILocation *DL : UniqueDebugLocations) {
2363 emitOpConstantI32(Value: DL->getLine(), I32TypeReg, MAI);
2364 emitOpConstantI32(Value: DL->getColumn(), I32TypeReg, MAI);
2365 emitOpConstantI32(Value: DL->getColumn() + 1, I32TypeReg, MAI);
2366 MCRegister FileStrReg =
2367 getCachedScopePathOpStringReg(Scope: DL->getScope(),
2368 /*UseEmptyPathIfNullScope=*/true);
2369 getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg, ExtInstSetReg,
2370 MAI);
2371 }
2372
2373 GlobalNSDIEnabled = true;
2374}
2375
2376SmallString<128>
2377SPIRVNonSemanticDebugHandler::getDebugFullPath(const DIScope *Scope) const {
2378 SmallString<128> Out;
2379 if (!Scope)
2380 return Out;
2381 StringRef Filename = Scope->getFilename();
2382 const auto Style = sys::path::Style::native;
2383 if (sys::path::is_absolute(path: Filename, style: Style))
2384 Out.assign(in_start: Filename.begin(), in_end: Filename.end());
2385 else {
2386 StringRef Dir = Scope->getDirectory();
2387 Out.assign(in_start: Dir.begin(), in_end: Dir.end());
2388 sys::path::append(path&: Out, style: Style, a: Filename);
2389 }
2390 return Out;
2391}
2392
2393MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugSourceForFileStrReg(
2394 MCRegister FileStrReg, MCRegister VoidTypeReg, MCRegister ExtInstSetReg,
2395 SPIRV::ModuleAnalysisInfo &MAI) {
2396 const unsigned Key = FileStrReg.id();
2397 auto It = DebugSourceRegByFileStr.find(Val: Key);
2398 if (It != DebugSourceRegByFileStr.end())
2399 return It->second;
2400
2401 MCRegister DS = emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugSource,
2402 VoidTypeReg, ExtInstSetReg, Operands: {FileStrReg}, MAI);
2403 DebugSourceRegByFileStr[Key] = DS;
2404 return DS;
2405}
2406