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/SetVector.h"
15#include "llvm/ADT/SmallVectorExtras.h"
16#include "llvm/ADT/Twine.h"
17#include "llvm/BinaryFormat/Dwarf.h"
18#include "llvm/CodeGen/AsmPrinter.h"
19#include "llvm/CodeGen/MachineFunction.h"
20#include "llvm/CodeGen/MachineInstr.h"
21#include "llvm/IR/DebugInfo.h"
22#include "llvm/IR/DebugInfoMetadata.h"
23#include "llvm/IR/DebugProgramInstruction.h"
24#include "llvm/IR/GlobalVariable.h"
25#include "llvm/IR/InstIterator.h"
26#include "llvm/IR/Instructions.h"
27#include "llvm/IR/Module.h"
28#include "llvm/MC/MCInst.h"
29#include "llvm/MC/MCStreamer.h"
30#include "llvm/Support/ErrorHandling.h"
31#include "llvm/Support/Path.h"
32#include <cassert>
33
34using namespace llvm;
35
36namespace {
37
38/// Look up \p Key in a register map and return its value, or std::nullopt when
39/// the key is absent.
40template <typename MapT>
41static std::optional<MCRegister> lookupOptReg(const MapT &Map,
42 typename MapT::key_type Key) {
43 auto It = Map.find(Key);
44 if (It == Map.end())
45 return std::nullopt;
46 assert(It->second.isValid() && "invalid register stored in map");
47 return It->second;
48}
49
50/// Partition \p Ty into \p BasicTypes, \p PointerTypes, \p SubroutineTypes,
51/// \p VectorTypes, \p ArrayTypes, \p CompositeTypes, and \p TypedefTypes for
52/// NSDI emission. Used when iterating DebugInfoFinder.types(); each DI node is
53/// seen once, so no recursion into pointer bases. Other composites and the
54/// remaining derived kinds are ignored because they are not yet supported.
55/// Only types that are supported (later used) are partitioned.
56static void
57partitionTypes(const DIType *Ty, SmallVector<const DIBasicType *> &BasicTypes,
58 SmallVector<const DIDerivedType *> &PointerTypes,
59 SmallVector<const DISubroutineType *> &SubroutineTypes,
60 SmallVector<const DICompositeType *> &VectorTypes,
61 SmallVector<const DICompositeType *> &ArrayTypes,
62 SmallVector<const DICompositeType *> &CompositeTypes,
63 SmallVector<const DIDerivedType *> &TypedefTypes) {
64 if (const auto *BT = dyn_cast<DIBasicType>(Val: Ty)) {
65 BasicTypes.push_back(Elt: BT);
66 return;
67 }
68 if (const auto *ST = dyn_cast<DISubroutineType>(Val: Ty)) {
69 SubroutineTypes.push_back(Elt: ST);
70 return;
71 }
72 if (const auto *CT = dyn_cast<DICompositeType>(Val: Ty)) {
73 if (CT->getTag() == dwarf::DW_TAG_array_type) {
74 // A vector is an array with DINode::FlagVector. A plain array is the
75 // same tag without it. A matrix is also lowered to a DW_TAG_array_type
76 // (two subranges), so it is indistinguishable from a 2D array here and
77 // is emitted as a DebugTypeArray.
78 //
79 // FIXME: Emitting a matrix as a DebugTypeArray is valid but loses the
80 // matrix shape. DWARF has no matrix tag, so distinguishing a matrix needs
81 // a new DINode flag analogous to FlagVector, set on the array, plus a way
82 // to carry column-major vs row-major traits. Array-of-vectors alone would
83 // not disambiguate a matrix from a genuine array of vectors. Once the
84 // frontend marks matrices, route them to a DebugTypeMatrix path here.
85 if (CT->isVector())
86 VectorTypes.push_back(Elt: CT);
87 else
88 ArrayTypes.push_back(Elt: CT);
89 } else if (CT->getTag() == dwarf::DW_TAG_structure_type ||
90 CT->getTag() == dwarf::DW_TAG_class_type ||
91 CT->getTag() == dwarf::DW_TAG_union_type) {
92 CompositeTypes.push_back(Elt: CT);
93 }
94 return;
95 }
96 const auto *DT = dyn_cast<DIDerivedType>(Val: Ty);
97 if (DT && DT->getTag() == dwarf::DW_TAG_pointer_type)
98 PointerTypes.push_back(Elt: DT);
99 else if (DT && DT->getTag() == dwarf::DW_TAG_typedef)
100 TypedefTypes.push_back(Elt: DT);
101}
102
103enum : uint32_t {
104 NSDIFlagIsProtected = 1u << 0,
105 NSDIFlagIsPrivate = 1u << 1,
106 NSDIFlagIsPublic = NSDIFlagIsPrivate | NSDIFlagIsProtected,
107 NSDIFlagIsLocal = 1u << 2,
108 NSDIFlagIsDefinition = 1u << 3,
109 NSDIFlagFwdDecl = 1u << 4,
110 NSDIFlagArtificial = 1u << 5,
111 NSDIFlagExplicit = 1u << 6,
112 NSDIFlagPrototyped = 1u << 7,
113 NSDIFlagObjectPointer = 1u << 8,
114 NSDIFlagStaticMember = 1u << 9,
115 NSDIFlagIndirectVariable = 1u << 10,
116 NSDIFlagLValueReference = 1u << 11,
117 NSDIFlagRValueReference = 1u << 12,
118 NSDIFlagIsOptimized = 1u << 13,
119 NSDIFlagIsEnumClass = 1u << 14,
120 NSDIFlagTypePassByValue = 1u << 15,
121 NSDIFlagTypePassByReference = 1u << 16,
122 NSDIFlagUnknownPhysicalLayout = 1u << 17,
123};
124
125static uint32_t mapDIFlagsToNonSemantic(DINode::DIFlags DFlags) {
126 uint32_t Flags = 0;
127 if ((DFlags & DINode::FlagAccessibility) == DINode::FlagPublic)
128 Flags |= NSDIFlagIsPublic;
129 if ((DFlags & DINode::FlagAccessibility) == DINode::FlagProtected)
130 Flags |= NSDIFlagIsProtected;
131 if ((DFlags & DINode::FlagAccessibility) == DINode::FlagPrivate)
132 Flags |= NSDIFlagIsPrivate;
133 if (DFlags & DINode::FlagFwdDecl)
134 Flags |= NSDIFlagFwdDecl;
135 if (DFlags & DINode::FlagArtificial)
136 Flags |= NSDIFlagArtificial;
137 if (DFlags & DINode::FlagExplicit)
138 Flags |= NSDIFlagExplicit;
139 if (DFlags & DINode::FlagPrototyped)
140 Flags |= NSDIFlagPrototyped;
141 if (DFlags & DINode::FlagObjectPointer)
142 Flags |= NSDIFlagObjectPointer;
143 if (DFlags & DINode::FlagStaticMember)
144 Flags |= NSDIFlagStaticMember;
145 if (DFlags & DINode::FlagLValueReference)
146 Flags |= NSDIFlagLValueReference;
147 if (DFlags & DINode::FlagRValueReference)
148 Flags |= NSDIFlagRValueReference;
149 if (DFlags & DINode::FlagTypePassByValue)
150 Flags |= NSDIFlagTypePassByValue;
151 if (DFlags & DINode::FlagTypePassByReference)
152 Flags |= NSDIFlagTypePassByReference;
153 if (DFlags & DINode::FlagEnumClass)
154 Flags |= NSDIFlagIsEnumClass;
155 return Flags;
156}
157
158static uint32_t transDebugFlags(const DINode *DN) {
159 uint32_t Flags = 0;
160 if (const auto *GV = dyn_cast<DIGlobalVariable>(Val: DN)) {
161 if (GV->isLocalToUnit())
162 Flags |= NSDIFlagIsLocal;
163 if (GV->isDefinition())
164 Flags |= NSDIFlagIsDefinition;
165 }
166 if (const auto *SP = dyn_cast<DISubprogram>(Val: DN)) {
167 if (SP->isLocalToUnit())
168 Flags |= NSDIFlagIsLocal;
169 if (SP->isOptimized())
170 Flags |= NSDIFlagIsOptimized;
171 if (SP->isDefinition())
172 Flags |= NSDIFlagIsDefinition;
173 Flags |= mapDIFlagsToNonSemantic(DFlags: SP->getFlags());
174 }
175 if (DN->getTag() == dwarf::DW_TAG_reference_type)
176 Flags |= NSDIFlagLValueReference;
177 if (DN->getTag() == dwarf::DW_TAG_rvalue_reference_type)
178 Flags |= NSDIFlagRValueReference;
179 if (const auto *Ty = dyn_cast<DIType>(Val: DN))
180 Flags |= mapDIFlagsToNonSemantic(DFlags: Ty->getFlags());
181 if (const auto *LV = dyn_cast<DILocalVariable>(Val: DN))
182 Flags |= mapDIFlagsToNonSemantic(DFlags: LV->getFlags());
183 return Flags;
184}
185
186// Map a DWARF composite tag to a NonSemantic.Shader.DebugInfo Composite Type
187// value: Class 0, Structure 1, Union 2.
188static uint32_t mapCompositeTypeTag(unsigned Tag) {
189 switch (Tag) {
190 case dwarf::DW_TAG_class_type:
191 return 0;
192 case dwarf::DW_TAG_structure_type:
193 return 1;
194 case dwarf::DW_TAG_union_type:
195 return 2;
196 default:
197 reportFatalInternalError(reason: "unexpected DWARF composite tag " + Twine(Tag) +
198 ". Expecting 0, 1 or 2");
199 }
200}
201
202static const MachineInstr *
203findLastFunctionOpVariableDeclaration(const MachineFunction &MF,
204 SPIRV::ModuleAnalysisInfo &MAI) {
205
206 // We iterate over the instructions to find the last OpVariable instruction if
207 // any. The following SPIRV rule is used to terminate the traversal earlier:
208 // SPIR-V 2.16.1, Function Structure: "All OpVariable instructions in a
209 // function must be in the first block in the function. These instructions,
210 // together with any intermixed OpLine and OpNoLine instructions, must be the
211 // first instructions in that block."
212 const MachineInstr *LastOpVariable = nullptr;
213 bool SeenOpVariable = false;
214 for (const MachineInstr &MI : MF.front()) {
215 if (MI.getOpcode() == SPIRV::OpVariable) {
216 SeenOpVariable = true;
217 if (!MAI.getSkipEmission(MI: &MI))
218 LastOpVariable = &MI;
219 continue;
220 }
221
222 bool CanInterleaveWithOpVariable =
223 MI.getOpcode() == SPIRV::OpLine || MI.getOpcode() == SPIRV::OpNoLine;
224 if (SeenOpVariable && !CanInterleaveWithOpVariable &&
225 !MAI.getSkipEmission(MI: &MI))
226 break;
227 }
228 return LastOpVariable;
229}
230
231} // namespace
232
233SPIRVNonSemanticDebugHandler::SPIRVNonSemanticDebugHandler(AsmPrinter &AP)
234 : DebugHandlerBase(&AP) {}
235
236// Map DWARF source language codes to NonSemantic.Shader.DebugInfo.100 source
237// language codes. Values are from the SourceLanguage enum in the
238// NonSemantic.Shader.DebugInfo.100 specification, section 4.3.
239unsigned SPIRVNonSemanticDebugHandler::toNSDISrcLang(unsigned DwarfSrcLang) {
240 switch (DwarfSrcLang) {
241 case dwarf::DW_LANG_OpenCL:
242 return 3; // OpenCL_C
243 case dwarf::DW_LANG_OpenCL_CPP:
244 return 4; // OpenCL_CPP
245 case dwarf::DW_LANG_CPP_for_OpenCL:
246 return 6; // CPP_for_OpenCL
247 case dwarf::DW_LANG_GLSL:
248 return 2; // GLSL
249 case dwarf::DW_LANG_HLSL:
250 return 5; // HLSL
251 case dwarf::DW_LANG_SYCL:
252 return 7; // SYCL
253 case dwarf::DW_LANG_Zig:
254 return 12; // Zig
255 default:
256 return 0; // Unknown
257 }
258}
259
260// Collect distinct DILocations from LLVM IR. DebugLine pre-emission and MIR
261// lookups assume every machine-instruction debug location already appeared
262// here; a codegen-only location would not be collected and emission will be
263// skipped.
264static void collectUniqueDebugLocations(const Module &M,
265 SetVector<const DILocation *> &Out) {
266 for (const Function &F : M) {
267 if (!F.getSubprogram())
268 continue;
269 for (const Instruction &I : instructions(F)) {
270 if (const DILocation *DL = I.getDebugLoc().get())
271 Out.insert(X: DL);
272 for (DbgRecord &DR : I.getDbgRecordRange())
273 if (const DILocation *DL = DR.getDebugLoc().get())
274 Out.insert(X: DL);
275 }
276 }
277}
278
279void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
280 // The base class sets Asm = nullptr when the module has no compile units,
281 // and initializes lexical scope tracking otherwise.
282 DebugHandlerBase::beginModule(M);
283
284 if (!Asm)
285 return;
286
287 CompileUnits.clear();
288 BasicTypes.clear();
289 PointerTypes.clear();
290 SubroutineTypes.clear();
291 VectorTypes.clear();
292 ArrayTypes.clear();
293 CompositeTypes.clear();
294 TypedefTypes.clear();
295 SubprogramDeclarations.clear();
296 SubprogramDefinitions.clear();
297 UniqueDebugLocations.clear();
298 GlobalVariableDebugInfoMap.clear();
299 DebugFunctionDeclarationRegs.clear();
300 DebugFunctionRegs.clear();
301 ScopeToPathOpStringReg.clear();
302 CUToCompilationUnitDbgReg.clear();
303 DebugSourceRegByFileStr.clear();
304 DebugTypeRegs.clear();
305 OpStringContentCache.clear();
306 I32ConstantCache.clear();
307 DebugTypeFunctionCache.clear();
308 GlobalDIEmitted = false;
309 GlobalNSDIEnabled = false;
310 CurrentMAI = nullptr;
311#ifndef NDEBUG
312 NonSemanticOpStringsSectionEmitted = false;
313#endif
314 CachedDebugInfoNoneReg = MCRegister();
315 CachedEmptyStringReg = MCRegister();
316 CachedOpTypeVoidReg = MCRegister();
317 CachedOpTypeInt32Reg = MCRegister();
318
319 // Collect compile-unit info: file paths and source languages.
320 for (const DICompileUnit *CU : M->debug_compile_units()) {
321 const DIFile *File = CU->getFile();
322 CompileUnitInfo Info;
323 Info.TheCU = CU;
324 if (sys::path::is_absolute(path: File->getFilename()))
325 Info.FilePath = File->getFilename();
326 else
327 sys::path::append(path&: Info.FilePath, a: File->getDirectory(),
328 b: File->getFilename());
329 // getName() returns the language code regardless of whether the name is
330 // versioned. getUnversionedName() would assert on versioned names.
331 Info.SpirvSourceLanguage = toNSDISrcLang(DwarfSrcLang: CU->getSourceLanguage().getName());
332 CompileUnits.push_back(Elt: std::move(Info));
333 }
334
335 // Collect DWARF version from module flags. For CodeView modules there is no
336 // "Dwarf Version" flag; DwarfVersion remains 0, which is the correct value
337 // for the DebugCompilationUnit DWARF Version operand in that case.
338 if (const NamedMDNode *Flags = M->getNamedMetadata(Name: "llvm.module.flags")) {
339 for (const auto *Op : Flags->operands()) {
340 const MDOperand &NameOp = Op->getOperand(I: 1);
341 if (NameOp.equalsStr(Str: "Dwarf Version"))
342 DwarfVersion =
343 cast<ConstantInt>(
344 Val: cast<ConstantAsMetadata>(Val: Op->getOperand(I: 2))->getValue())
345 ->getSExtValue();
346 }
347 }
348
349 // Find all debug info types that may be referenced by NSDI instructions.
350 DebugInfoFinder Finder;
351 Finder.processModule(M: *M);
352 llvm::for_each(Range: Finder.types(), F: [&](DIType *Ty) {
353 partitionTypes(Ty, BasicTypes, PointerTypes, SubroutineTypes, VectorTypes,
354 ArrayTypes, CompositeTypes, TypedefTypes);
355 });
356
357 for (const DISubprogram *SP : Finder.subprograms()) {
358 if (SP->isDefinition())
359 SubprogramDefinitions.push_back(Elt: SP);
360 else
361 SubprogramDeclarations.push_back(Elt: SP);
362 }
363
364 // Walk LLVM globals to map each DIGlobalVariable to its llvm::GlobalVariable.
365 DenseMap<const DIGlobalVariable *, const GlobalVariable *> DIGVToLLVMGV;
366 for (const GlobalVariable &G : M->globals()) {
367 SmallVector<DIGlobalVariableExpression *> GVEs;
368 G.getDebugInfo(GVs&: GVEs);
369 for (DIGlobalVariableExpression *GVE : GVEs) {
370 if (const DIGlobalVariable *GV = GVE->getVariable()) {
371 DIGVToLLVMGV.try_emplace(Key: GV, Args: &G);
372 }
373 }
374 }
375
376 for (const DIGlobalVariableExpression *GVE : Finder.global_variables()) {
377 const DIGlobalVariable *GV = GVE->getVariable();
378 const DIExpression *Expr = GVE->getExpression();
379 GlobalVariableDebugInfoMap.try_emplace(
380 Key: GV, Args: GlobalVariableDebugInfo{.Expr: Expr, .LLVMGV: DIGVToLLVMGV.lookup(Val: GV)});
381 }
382
383 collectUniqueDebugLocations(M: *M, Out&: UniqueDebugLocations);
384}
385
386void SPIRVNonSemanticDebugHandler::prepareModuleOutput(
387 const SPIRVSubtarget &ST, SPIRV::ModuleAnalysisInfo &MAI) {
388 if (CompileUnits.empty())
389 return;
390 if (!ST.canUseExtension(E: SPIRV::Extension::SPV_KHR_non_semantic_info))
391 return;
392
393 // Add the extension to requirements so OpExtension is output.
394 MAI.Reqs.addExtension(ToAdd: SPIRV::Extension::SPV_KHR_non_semantic_info);
395
396 // Add the NonSemantic.Shader.DebugInfo.100 entry to ExtInstSetMap so that
397 // outputOpExtInstImports() emits the OpExtInstImport instruction. Allocate a
398 // fresh result ID for it now; the same ID is used in emitExtInst() operands.
399 if (!MAI.ExtInstSetMap.count(Val: NSSet))
400 MAI.ExtInstSetMap[NSSet] = MAI.getNextIDRegister();
401}
402
403void SPIRVNonSemanticDebugHandler::emitMCInst(MCInst &Inst) {
404 Asm->OutStreamer->emitInstruction(Inst, STI: Asm->getSubtargetInfo());
405}
406
407MCRegister
408SPIRVNonSemanticDebugHandler::emitOpString(StringRef S,
409 SPIRV::ModuleAnalysisInfo &MAI) {
410 MCRegister Reg = MAI.getNextIDRegister();
411 MCInst Inst;
412 Inst.setOpcode(SPIRV::OpString);
413 Inst.addOperand(Op: MCOperand::createReg(Reg));
414 addStringImm(Str: S, Inst);
415 emitMCInst(Inst);
416 return Reg;
417}
418
419MCRegister SPIRVNonSemanticDebugHandler::emitOpStringIfNew(
420 StringRef S, SPIRV::ModuleAnalysisInfo &MAI) {
421#ifndef NDEBUG
422 assert(!NonSemanticOpStringsSectionEmitted &&
423 "emitOpStringIfNew is only valid while emitting SPIR-V section 7");
424#endif
425 auto [It, Inserted] = OpStringContentCache.try_emplace(Key: S, Args: MCRegister());
426 if (Inserted)
427 It->second = emitOpString(S, MAI);
428
429 return It->second;
430}
431
432MCRegister SPIRVNonSemanticDebugHandler::getCachedOpStringReg(StringRef S) {
433#ifndef NDEBUG
434 assert(NonSemanticOpStringsSectionEmitted &&
435 "getCachedOpStringReg requires emitNonSemanticDebugStrings() first");
436#endif
437 auto It = OpStringContentCache.find(Key: S);
438 assert(It != OpStringContentCache.end() &&
439 "NSDI OpString missing from cache; emitNonSemanticDebugStrings must "
440 "cache every string used in section 10");
441 return It->second;
442}
443
444MCRegister SPIRVNonSemanticDebugHandler::emitAndCacheScopePathOpStringReg(
445 const DIScope *Scope, SPIRV::ModuleAnalysisInfo &MAI) {
446 auto [It, Inserted] = ScopeToPathOpStringReg.try_emplace(Key: Scope, Args: MCRegister());
447 if (Inserted)
448 It->second = emitOpStringIfNew(S: getDebugFullPath(Scope), MAI);
449 return It->second;
450}
451
452MCRegister SPIRVNonSemanticDebugHandler::getCachedScopePathOpStringReg(
453 const DIScope *Scope, bool UseEmptyPathIfNullScope) {
454 if (!Scope) {
455 assert(UseEmptyPathIfNullScope &&
456 "null scope path lookup requires UseEmptyPathIfNullScope");
457 assert(CachedEmptyStringReg.isValid() &&
458 "empty path OpString must be cached in emitNonSemanticDebugStrings");
459 return CachedEmptyStringReg;
460 }
461 auto It = ScopeToPathOpStringReg.find(Val: Scope);
462 assert(It != ScopeToPathOpStringReg.end() &&
463 "path OpString must be cached in emitNonSemanticDebugStrings");
464 MCRegister FileStrReg = It->second;
465 assert(FileStrReg.isValid() && "path OpString id must be valid once cached");
466 return FileStrReg;
467}
468
469MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI32(
470 uint32_t Value, MCRegister I32TypeReg, SPIRV::ModuleAnalysisInfo &MAI) {
471 auto [It, Inserted] = I32ConstantCache.try_emplace(Key: Value);
472 if (!Inserted)
473 return It->second;
474
475 MCRegister Reg = MAI.getNextIDRegister();
476 It->second = Reg;
477 MCInst Inst;
478 Inst.setOpcode(SPIRV::OpConstantI);
479 Inst.addOperand(Op: MCOperand::createReg(Reg));
480 Inst.addOperand(Op: MCOperand::createReg(Reg: I32TypeReg));
481 Inst.addOperand(Op: MCOperand::createImm(Val: static_cast<int64_t>(Value)));
482 emitMCInst(Inst);
483 return Reg;
484}
485
486MCRegister SPIRVNonSemanticDebugHandler::emitExtInst(
487 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
488 MCRegister VoidTypeReg, MCRegister ExtInstSetReg,
489 ArrayRef<MCRegister> Operands, SPIRV::ModuleAnalysisInfo &MAI) {
490 MCRegister Reg = MAI.getNextIDRegister();
491 MCInst Inst;
492 Inst.setOpcode(SPIRV::OpExtInst);
493 Inst.addOperand(Op: MCOperand::createReg(Reg));
494 Inst.addOperand(Op: MCOperand::createReg(Reg: VoidTypeReg));
495 Inst.addOperand(Op: MCOperand::createReg(Reg: ExtInstSetReg));
496 Inst.addOperand(Op: MCOperand::createImm(Val: static_cast<int64_t>(Opcode)));
497 for (MCRegister R : Operands)
498 Inst.addOperand(Op: MCOperand::createReg(Reg: R));
499 emitMCInst(Inst);
500 return Reg;
501}
502
503MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugTypeFunction(
504 ArrayRef<MCRegister> Ops, MCRegister VoidTypeReg, MCRegister ExtInstSetReg,
505 SPIRV::ModuleAnalysisInfo &MAI) {
506 auto [It, Inserted] =
507 DebugTypeFunctionCache.try_emplace(Key: SmallVector<MCRegister, 8>(Ops));
508 if (!Inserted)
509 return It->second;
510
511 MCRegister Reg = emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugTypeFunction,
512 VoidTypeReg, ExtInstSetReg, Operands: Ops, MAI);
513 It->second = Reg;
514 return Reg;
515}
516
517MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeVoidReg(
518 SPIRV::ModuleAnalysisInfo &MAI) {
519 if (!CachedOpTypeVoidReg.isValid())
520 CachedOpTypeVoidReg = findOrEmitOpTypeVoid(MAI);
521 return CachedOpTypeVoidReg;
522}
523
524MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeInt32Reg(
525 SPIRV::ModuleAnalysisInfo &MAI) {
526 if (!CachedOpTypeInt32Reg.isValid())
527 CachedOpTypeInt32Reg = findOrEmitOpTypeInt32(MAI);
528 return CachedOpTypeInt32Reg;
529}
530
531MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeVoid(
532 SPIRV::ModuleAnalysisInfo &MAI) {
533 for (const MachineInstr *MI : MAI.getMSInstrs(MSType: SPIRV::MB_TypeConstVars)) {
534 if (MI->getOpcode() == SPIRV::OpTypeVoid)
535 return MAI.getRegisterAlias(MF: MI->getMF(), Reg: MI->getOperand(i: 0).getReg());
536 }
537 MCRegister Reg = MAI.getNextIDRegister();
538 MCInst Inst;
539 Inst.setOpcode(SPIRV::OpTypeVoid);
540 Inst.addOperand(Op: MCOperand::createReg(Reg));
541 emitMCInst(Inst);
542 return Reg;
543}
544
545MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt32(
546 SPIRV::ModuleAnalysisInfo &MAI) {
547 for (const MachineInstr *MI : MAI.getMSInstrs(MSType: SPIRV::MB_TypeConstVars)) {
548 if (MI->getOpcode() == SPIRV::OpTypeInt &&
549 MI->getOperand(i: 1).getImm() == 32 && MI->getOperand(i: 2).getImm() == 0)
550 return MAI.getRegisterAlias(MF: MI->getMF(), Reg: MI->getOperand(i: 0).getReg());
551 }
552 MCRegister Reg = MAI.getNextIDRegister();
553 MCInst Inst;
554 Inst.setOpcode(SPIRV::OpTypeInt);
555 Inst.addOperand(Op: MCOperand::createReg(Reg));
556 Inst.addOperand(Op: MCOperand::createImm(Val: 32)); // width
557 Inst.addOperand(Op: MCOperand::createImm(Val: 0)); // signedness (unsigned)
558 emitMCInst(Inst);
559 return Reg;
560}
561
562std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypePointer(
563 const DIDerivedType *PT, MCRegister ExtInstSetReg,
564 SPIRV::ModuleAnalysisInfo &MAI) {
565 // A DWARF address space is required to determine the SPIR-V storage class.
566 // Skip pointer types that do not carry one.
567 if (!PT->getDWARFAddressSpace().has_value())
568 return std::nullopt;
569
570 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
571 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
572 MCRegister DebugTypePointerFlagsReg =
573 emitOpConstantI32(Value: transDebugFlags(DN: PT), I32TypeReg, MAI);
574
575 // For SPIR-V targets, Clang sets DwarfAddressSpace to the LLVM IR address
576 // space, which addressSpaceToStorageClass expects.
577 const auto &ST = static_cast<const SPIRVSubtarget &>(Asm->getSubtargetInfo());
578 MCRegister StorageClassReg = emitOpConstantI32(
579 Value: addressSpaceToStorageClass(AddrSpace: PT->getDWARFAddressSpace().value(), STI: ST),
580 I32TypeReg, MAI);
581
582 if (const DIType *BaseTy = PT->getBaseType()) {
583 auto BaseIt = DebugTypeRegs.find(Val: BaseTy);
584 if (BaseIt != DebugTypeRegs.end())
585 return emitExtInst(
586 Opcode: SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg,
587 ExtInstSetReg,
588 Operands: {BaseIt->second, StorageClassReg, DebugTypePointerFlagsReg}, MAI);
589 // Unsupported type, no DebugType* id available.
590 return std::nullopt;
591 }
592 // No getBaseType() (typical for void*): use DebugInfoNone as Base Type,
593 // same as SPIRV-LLVM-Translator (see issue #109287 and the DISABLED
594 // spirv-val run in debug-type-pointer.ll). spirv-val may still reject this
595 // encoding; see https://github.com/KhronosGroup/SPIRV-Registry/pull/287.
596 return emitExtInst(
597 Opcode: SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg, ExtInstSetReg,
598 Operands: {CachedDebugInfoNoneReg, StorageClassReg, DebugTypePointerFlagsReg}, MAI);
599}
600
601std::optional<MCRegister>
602SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
603 const DISubroutineType *ST, MCRegister ExtInstSetReg,
604 SPIRV::ModuleAnalysisInfo &MAI) {
605 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
606 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
607 MCRegister DebugTypeFunctionFlagsReg =
608 emitOpConstantI32(Value: transDebugFlags(DN: ST), I32TypeReg, MAI);
609 DITypeArray TA = ST->getTypeArray();
610 SmallVector<MCRegister, 8> Ops;
611 Ops.push_back(Elt: DebugTypeFunctionFlagsReg);
612 // Empty DI type tuple: no explicit return or parameter slots (hand-written IR
613 // may use !{}). Emit void-only prototype. Same as SPIRV-LLVM-Translator when
614 // DISubroutineType::getTypeArray() has zero elements.
615 if (TA.empty()) {
616 Ops.push_back(Elt: VoidTypeReg);
617 } else {
618 for (unsigned I = 0, E = TA.size(); I != E; ++I) {
619 bool IsReturnType = (I == 0);
620 auto OptReg = mapDISignatureTypeToReg(Ty: TA[I], VoidTypeReg, ReturnType: IsReturnType);
621 // No emitted DebugType* id for this slot (e.g., pointer that
622 // was skipped due missing address space, etc.).
623 if (!OptReg)
624 return std::nullopt;
625 Ops.push_back(Elt: *OptReg);
626 }
627 }
628 return getOrEmitDebugTypeFunction(Ops, VoidTypeReg, ExtInstSetReg, MAI);
629}
630
631// Match SPIRV-LLVM-Translator's selection logic for the Parent operand.
632std::optional<MCRegister>
633SPIRVNonSemanticDebugHandler::resolveDebugFunctionParent(
634 const DISubprogram *SP) const {
635 const DIScope *Scope = SP->getScope();
636 if (Scope && !isa<DIFile>(Val: Scope)) {
637 // TODO: Complete with other lookups once other scopes are supported
638 // (subclasses of DIScope).
639 const DIType *Ty = dyn_cast<DIType>(Val: Scope);
640 if (!Ty)
641 return std::nullopt;
642 return lookupOptReg(Map: DebugTypeRegs, Key: Ty);
643 }
644
645 const DICompileUnit *ParentCU = SP->getUnit();
646 if (!ParentCU && !CompileUnits.empty())
647 ParentCU = CompileUnits[0].TheCU;
648 if (!ParentCU)
649 return std::nullopt;
650 return lookupOptReg(Map: CUToCompilationUnitDbgReg, Key: ParentCU);
651}
652
653std::optional<MCRegister> SPIRVNonSemanticDebugHandler::resolveTypeScopeParent(
654 const DIScope *Scope) const {
655 // When the scope is itself a type (e.g. a struct nested in another struct),
656 // the parent is that enclosing type's debug id.
657 if (const auto *Ty = dyn_cast_or_null<DIType>(Val: Scope))
658 return lookupOptReg(Map: DebugTypeRegs, Key: Ty);
659
660 // For a file, compile-unit, namespace, or absent scope, the parent is the
661 // first module DebugCompilationUnit.
662 if (CompileUnits.empty())
663 return std::nullopt;
664
665 return lookupOptReg(Map: CUToCompilationUnitDbgReg, Key: CompileUnits[0].TheCU);
666}
667
668std::optional<MCRegister>
669SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration(
670 const DISubprogram *SP, MCRegister VoidTypeReg, MCRegister I32TypeReg,
671 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
672 assert(SP && "SP must not be null in emitDebugFunctionDeclaration");
673 assert(!SP->isDefinition() &&
674 "SP must not be a definition in emitDebugFunctionDeclaration");
675
676 // The IR verifier already enforces that this cannot be null.
677 const DISubroutineType *ST = SP->getType();
678
679 auto FnTyRegOpt = lookupOptReg(Map: DebugTypeRegs, Key: ST);
680 if (!FnTyRegOpt)
681 return std::nullopt;
682 MCRegister FnTyReg = *FnTyRegOpt;
683
684 auto ParentRegOpt = resolveDebugFunctionParent(SP);
685 if (!ParentRegOpt)
686 return std::nullopt;
687
688 MCRegister ParentReg = *ParentRegOpt;
689
690 MCRegister FileStrReg = getCachedScopePathOpStringReg(Scope: SP);
691
692 MCRegister NameReg = getCachedOpStringReg(S: SP->getName());
693 MCRegister LinkageReg = getCachedOpStringReg(S: SP->getLinkageName());
694 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
695 ExtInstSetReg, MAI);
696
697 MCRegister LineReg =
698 emitOpConstantI32(Value: static_cast<uint32_t>(SP->getLine()), I32TypeReg, MAI);
699 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
700
701 uint32_t FlagsVal = transDebugFlags(DN: SP);
702 // TODO: When composite scopes are DebugFunctionDeclaration parents (available
703 // in DebugTypeRegs), sync declaration Flags with SPIRV-LLVM-Translator.
704 FlagsVal &= ~NSDIFlagIsDefinition;
705 MCRegister FlagsReg = emitOpConstantI32(Value: FlagsVal, I32TypeReg, MAI);
706
707 return emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugFunctionDeclaration,
708 VoidTypeReg, ExtInstSetReg,
709 Operands: {NameReg, FnTyReg, SrcReg, LineReg, ColReg, ParentReg,
710 LinkageReg, FlagsReg},
711 MAI);
712}
713
714std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugFunction(
715 const DISubprogram *SP, MCRegister VoidTypeReg, MCRegister I32TypeReg,
716 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
717 assert(SP && "SP must not be null in emitDebugFunction");
718 assert(SP->isDefinition() && "SP must be a definition in emitDebugFunction");
719
720 const DISubroutineType *ST = SP->getType();
721 auto FnTyRegOpt = lookupOptReg(Map: DebugTypeRegs, Key: ST);
722 if (!FnTyRegOpt)
723 return std::nullopt;
724
725 auto ParentRegOpt = resolveDebugFunctionParent(SP);
726 if (!ParentRegOpt)
727 return std::nullopt;
728
729 MCRegister NameReg = getCachedOpStringReg(S: SP->getName());
730 MCRegister LinkageReg = getCachedOpStringReg(S: SP->getLinkageName());
731 MCRegister FileStrReg = getCachedScopePathOpStringReg(Scope: SP);
732 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
733 ExtInstSetReg, MAI);
734
735 MCRegister LineReg =
736 emitOpConstantI32(Value: static_cast<uint32_t>(SP->getLine()), I32TypeReg, MAI);
737 // LLVM's DISubprogram has no column field but SPIR-V expects one in
738 // DebugFunction.
739 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
740 MCRegister FlagsReg = emitOpConstantI32(Value: transDebugFlags(DN: SP), I32TypeReg, MAI);
741 MCRegister ScopeLineReg = emitOpConstantI32(
742 Value: static_cast<uint32_t>(SP->getScopeLine()), I32TypeReg, MAI);
743
744 SmallVector<MCRegister, 10> Ops = {NameReg, *FnTyRegOpt, SrcReg,
745 LineReg, ColReg, *ParentRegOpt,
746 LinkageReg, FlagsReg, ScopeLineReg};
747
748 if (const DISubprogram *Decl = SP->getDeclaration()) {
749 if (auto DeclRegOpt = lookupOptReg(Map: DebugFunctionDeclarationRegs, Key: Decl))
750 Ops.push_back(Elt: *DeclRegOpt);
751 }
752
753 return emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugFunction, VoidTypeReg,
754 ExtInstSetReg, Operands: Ops, MAI);
755}
756
757std::optional<MCRegister> SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg(
758 const DIType *Ty, MCRegister VoidTypeReg, bool ReturnType) {
759 if (!Ty) {
760 if (ReturnType)
761 return VoidTypeReg;
762 assert(CachedDebugInfoNoneReg.isValid() &&
763 "DebugInfoNone must be emitted before DISubroutineType operands");
764 return CachedDebugInfoNoneReg;
765 }
766 return lookupOptReg(Map: DebugTypeRegs, Key: Ty);
767}
768
769MCRegister SPIRVNonSemanticDebugHandler::resolveGlobalVariableParent(
770 const DIGlobalVariable *) const {
771 // TODO: When this backend emits debug instructions for namespace, subprogram,
772 // compilation units, and module scopes return GV->getScope()'s debug id.
773
774 // !CompileUnits.empty() was already checked before staring the emission of
775 // NSDI instructions.
776 assert(!CompileUnits.empty() &&
777 "resolveGlobalVariableParent requires non-empty CompileUnits");
778 std::optional<MCRegister> ParentRegOpt =
779 lookupOptReg(Map: CUToCompilationUnitDbgReg, Key: CompileUnits[0].TheCU);
780 assert(ParentRegOpt && "DebugCompilationUnit must be emitted before "
781 "resolveGlobalVariableParent");
782 // Fallback: first module compile unit (SPIRV-LLVM-Translator default).
783 return *ParentRegOpt;
784}
785
786// Unimplemented no-op; see emitDebugExpression declaration.
787std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugExpression(
788 const DIExpression *, MCRegister, MCRegister, SPIRV::ModuleAnalysisInfo &) {
789 return std::nullopt;
790}
791
792std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
793 const DIGlobalVariable *GV, const GlobalVariableDebugInfo &Info,
794 MCRegister VoidTypeReg, MCRegister I32TypeReg, MCRegister ExtInstSetReg,
795 SPIRV::ModuleAnalysisInfo &MAI) {
796 assert(GV && "GV must not be null in emitDebugGlobalVariable");
797
798 MCRegister ParentReg = resolveGlobalVariableParent(GV);
799
800 // TyReg: DebugInfoNone when GV has no DI type (as done in
801 // SPIRV-LLVM-Translator). Declarations (isDefinition: false) can have null
802 // getType() while definitions must have a non-null one (enforced by the IR
803 // verifier).
804 MCRegister TyReg = CachedDebugInfoNoneReg;
805 if (const DIType *Ty = GV->getType()) {
806 auto TyRegOpt = lookupOptReg(Map: DebugTypeRegs, Key: Ty);
807 if (!TyRegOpt)
808 return std::nullopt;
809 TyReg = *TyRegOpt;
810 }
811
812 std::optional<MCRegister> StaticMemberRegOpt;
813 if (const DIDerivedType *SM = GV->getStaticDataMemberDeclaration()) {
814 StaticMemberRegOpt = lookupOptReg(Map: DebugTypeRegs, Key: SM);
815 if (!StaticMemberRegOpt)
816 return std::nullopt;
817 }
818
819 MCRegister NameReg = getCachedOpStringReg(S: GV->getName());
820 MCRegister LinkageReg = getCachedOpStringReg(S: GV->getLinkageName());
821 MCRegister FileStrReg = getCachedScopePathOpStringReg(
822 Scope: GV->getFile(), /*UseEmptyPathIfNullScope=*/true);
823 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
824 ExtInstSetReg, MAI);
825
826 MCRegister LineReg =
827 emitOpConstantI32(Value: static_cast<uint32_t>(GV->getLine()), I32TypeReg, MAI);
828 // DIGlobalVariable or DIGlobalVariableExpression metadata carry no column
829 // field. Column is hardcoded to 0 (because it can't be determined), matching
830 // SPIRV-LLVM-Translator.
831 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
832
833 // Variable: @g OpVariable id when !dbg matches; else a DebugExpression for
834 // the GVE init value when no @g exists; else DebugInfoNone.
835 MCRegister VariableReg = CachedDebugInfoNoneReg;
836 if (const GlobalVariable *LLVMGV = Info.LLVMGV) {
837 MCRegister GVReg = MAI.getGlobalObjReg(GO: LLVMGV);
838 if (GVReg.isValid())
839 VariableReg = GVReg;
840 } else if (Info.Expr) {
841 if (auto ExprReg =
842 emitDebugExpression(Info.Expr, VoidTypeReg, ExtInstSetReg, MAI))
843 VariableReg = *ExprReg;
844 }
845
846 MCRegister FlagsReg = emitOpConstantI32(Value: transDebugFlags(DN: GV), I32TypeReg, MAI);
847
848 SmallVector<MCRegister, 10> Ops = {NameReg, TyReg, SrcReg,
849 LineReg, ColReg, ParentReg,
850 LinkageReg, VariableReg, FlagsReg};
851
852 if (StaticMemberRegOpt)
853 Ops.push_back(Elt: *StaticMemberRegOpt);
854
855 return emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugGlobalVariable,
856 VoidTypeReg, ExtInstSetReg, Operands: Ops, MAI);
857}
858
859std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeVector(
860 const DICompositeType *VT, MCRegister ExtInstSetReg,
861 SPIRV::ModuleAnalysisInfo &MAI) {
862 const auto *BaseTy = dyn_cast_or_null<DIBasicType>(Val: VT->getBaseType());
863 if (!BaseTy)
864 return std::nullopt;
865 auto BTIt = DebugTypeRegs.find(Val: BaseTy);
866 if (BTIt == DebugTypeRegs.end())
867 return std::nullopt;
868
869 // DebugTypeVector models only 1D vectors (multi-subrange types cannot be
870 // encoded).
871 DINodeArray Elements = VT->getElements();
872 if (Elements.size() != 1)
873 return std::nullopt;
874 const auto *SR = cast<DISubrange>(Val: Elements[0]);
875 const auto *CI = dyn_cast_if_present<ConstantInt *>(Val: SR->getCount());
876 if (!CI)
877 return std::nullopt;
878
879 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
880 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
881 MCRegister CountReg = emitOpConstantI32(
882 Value: static_cast<uint32_t>(CI->getZExtValue()), I32TypeReg, MAI);
883 return emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugTypeVector, VoidTypeReg,
884 ExtInstSetReg, Operands: {BTIt->second, CountReg}, MAI);
885}
886
887std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeArray(
888 const DICompositeType *AT, MCRegister ExtInstSetReg,
889 SPIRV::ModuleAnalysisInfo &MAI) {
890 // The element (base) type must already be in DebugTypeRegs. Unlike
891 // DebugTypeVector, the element may be any debug type, not only a basic type.
892 auto BaseRegOpt = lookupOptReg(Map: DebugTypeRegs, Key: AT->getBaseType());
893 if (!BaseRegOpt)
894 return std::nullopt;
895
896 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
897 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
898
899 SmallVector<MCRegister> Ops;
900 Ops.push_back(Elt: *BaseRegOpt);
901
902 // One component count per DISubrange, in DWARF subrange order. Emit 0 for
903 // counts that are not a compile-time constant (dynamic arrays). This matches
904 // OpTypeRuntimeArray.
905 for (const DINode *Element : AT->getElements()) {
906 const auto *SR = dyn_cast<DISubrange>(Val: Element);
907 if (!SR)
908 continue;
909 // A DIVariable count (a variable-length array) is not a ConstantInt, so it
910 // maps to 0 here. DebugTypeArray also allows a DebugLocalVariable or
911 // DebugGlobalVariable id for it, but no frontend we target emits one. A
912 // constant wider than 32 bits maps to 0 too, since the count operand is a
913 // 32-bit OpConstant and such an array cannot occur in a shader.
914 uint32_t Count = 0;
915 if (const auto *CI = dyn_cast_if_present<ConstantInt *>(Val: SR->getCount())) {
916 const APInt &Value = CI->getValue();
917 if (Value.getActiveBits() <= 32)
918 Count = static_cast<uint32_t>(Value.getZExtValue());
919 }
920 Ops.push_back(Elt: emitOpConstantI32(Value: Count, I32TypeReg, MAI));
921 }
922
923 return emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugTypeArray, VoidTypeReg,
924 ExtInstSetReg, Operands: Ops, MAI);
925}
926
927std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeMember(
928 const DIDerivedType *M, MCRegister VoidTypeReg, MCRegister I32TypeReg,
929 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
930 // The member type must already be in DebugTypeRegs.
931 auto TyRegOpt = lookupOptReg(Map: DebugTypeRegs, Key: M->getBaseType());
932 if (!TyRegOpt)
933 return std::nullopt;
934
935 MCRegister NameReg = getCachedOpStringReg(S: M->getName());
936 MCRegister FileStrReg = getCachedScopePathOpStringReg(
937 Scope: M->getFile(), /*UseEmptyPathIfNullScope=*/true);
938 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
939 ExtInstSetReg, MAI);
940 MCRegister LineReg =
941 emitOpConstantI32(Value: static_cast<uint32_t>(M->getLine()), I32TypeReg, MAI);
942
943 // DIDerivedType members carry no column, so emit 0.
944 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
945 MCRegister OffsetReg = emitOpConstantI32(
946 Value: static_cast<uint32_t>(M->getOffsetInBits()), I32TypeReg, MAI);
947 MCRegister SizeReg = emitOpConstantI32(
948 Value: static_cast<uint32_t>(M->getSizeInBits()), I32TypeReg, MAI);
949 MCRegister FlagsReg = emitOpConstantI32(Value: transDebugFlags(DN: M), I32TypeReg, MAI);
950
951 // In NonSemantic.Shader.DebugInfo a DebugTypeMember has no Parent operand:
952 // only the composite references its members. This is by design, it drops the
953 // Parent that OpenCL.DebugInfo.100 had, and it avoids a composite/member
954 // reference cycle.
955 //
956 // FIXME: Static members are not handled yet: their constant initializer is
957 // available but is not emitted as the optional Value operand, and under DWARF
958 // 5 a static member is tagged DW_TAG_variable, which the caller's member loop
959 // skips.
960 return emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugTypeMember, VoidTypeReg,
961 ExtInstSetReg,
962 Operands: {NameReg, *TyRegOpt, SrcReg, LineReg, ColReg, OffsetReg,
963 SizeReg, FlagsReg},
964 MAI);
965}
966
967std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeComposite(
968 const DICompositeType *CT, ArrayRef<MCRegister> MemberRegs,
969 MCRegister VoidTypeReg, MCRegister I32TypeReg, MCRegister ExtInstSetReg,
970 SPIRV::ModuleAnalysisInfo &MAI) {
971 auto ParentRegOpt = resolveTypeScopeParent(Scope: CT->getScope());
972 if (!ParentRegOpt)
973 return std::nullopt;
974
975 MCRegister NameReg = getCachedOpStringReg(S: CT->getName());
976 MCRegister LinkageReg = getCachedOpStringReg(S: CT->getIdentifier());
977 MCRegister FileStrReg = getCachedScopePathOpStringReg(
978 Scope: CT->getFile(), /*UseEmptyPathIfNullScope=*/true);
979 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
980 ExtInstSetReg, MAI);
981
982 MCRegister TagReg =
983 emitOpConstantI32(Value: mapCompositeTypeTag(Tag: CT->getTag()), I32TypeReg, MAI);
984 MCRegister LineReg =
985 emitOpConstantI32(Value: static_cast<uint32_t>(CT->getLine()), I32TypeReg, MAI);
986 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
987
988 // A forward declaration has no known size or members: Size is DebugInfoNone.
989 MCRegister SizeReg = CachedDebugInfoNoneReg;
990 if (!CT->isForwardDecl())
991 SizeReg = emitOpConstantI32(Value: static_cast<uint32_t>(CT->getSizeInBits()),
992 I32TypeReg, MAI);
993
994 MCRegister FlagsReg = emitOpConstantI32(Value: transDebugFlags(DN: CT), I32TypeReg, MAI);
995
996 SmallVector<MCRegister> Ops = {NameReg, TagReg, SrcReg,
997 LineReg, ColReg, *ParentRegOpt,
998 LinkageReg, SizeReg, FlagsReg};
999 Ops.append(in_start: MemberRegs.begin(), in_end: MemberRegs.end());
1000 return emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugTypeComposite, VoidTypeReg,
1001 ExtInstSetReg, Operands: Ops, MAI);
1002}
1003
1004std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypedef(
1005 const DIDerivedType *TD, MCRegister VoidTypeReg, MCRegister I32TypeReg,
1006 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
1007 // The underlying (base) type must already be in DebugTypeRegs.
1008 auto BaseRegOpt = lookupOptReg(Map: DebugTypeRegs, Key: TD->getBaseType());
1009 if (!BaseRegOpt)
1010 return std::nullopt;
1011
1012 MCRegister NameReg = getCachedOpStringReg(S: TD->getName());
1013 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1014 Scope: TD->getFile(), /*UseEmptyPathIfNullScope=*/true);
1015 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1016 ExtInstSetReg, MAI);
1017 MCRegister LineReg =
1018 emitOpConstantI32(Value: static_cast<uint32_t>(TD->getLine()), I32TypeReg, MAI);
1019 // DIDerivedType typedefs carry no column, so emit 0.
1020 MCRegister ColReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
1021
1022 // Parent must be a lexical scope. Valid NSDI lexical scopes are
1023 // DebugCompilationUnit, DebugFunction, DebugLexicalBlock, or
1024 // DebugTypeComposite.
1025 //
1026 // FIXME: We currently only emit DebugCompilationUnit, so the compile unit is
1027 // the only parent available today.
1028 MCRegister ParentReg;
1029 if (const auto *Ty = dyn_cast_or_null<DIType>(Val: TD->getScope()))
1030 if (auto TyRegOpt = lookupOptReg(Map: DebugTypeRegs, Key: Ty))
1031 ParentReg = *TyRegOpt;
1032 if (!ParentReg.isValid()) {
1033 assert(!CompileUnits.empty() &&
1034 "emitDebugTypedef requires a compile unit for the Parent operand");
1035 auto CURegOpt =
1036 lookupOptReg(Map: CUToCompilationUnitDbgReg, Key: CompileUnits[0].TheCU);
1037 assert(CURegOpt && "DebugCompilationUnit must be emitted before typedefs");
1038 ParentReg = *CURegOpt;
1039 }
1040
1041 return emitExtInst(
1042 Opcode: SPIRV::NonSemanticExtInst::DebugTypedef, VoidTypeReg, ExtInstSetReg,
1043 Operands: {NameReg, *BaseRegOpt, SrcReg, LineReg, ColReg, ParentReg}, MAI);
1044}
1045
1046void SPIRVNonSemanticDebugHandler::emitNonSemanticDebugStrings(
1047 SPIRV::ModuleAnalysisInfo &MAI) {
1048 if (CompileUnits.empty())
1049 return;
1050 // Check that prepareModuleOutput() registered the extended instruction set.
1051 // If the subtarget does not support the extension, neither strings nor ext
1052 // insts are emitted.
1053 if (!MAI.getExtInstSetReg(SetNum: NSSet).isValid())
1054 return;
1055
1056 for (const CompileUnitInfo &Info : CompileUnits) {
1057 if (Info.TheCU) {
1058 MCRegister PathReg = emitOpStringIfNew(S: Info.FilePath, MAI);
1059 ScopeToPathOpStringReg[Info.TheCU] = PathReg;
1060 if (const DIFile *F = Info.TheCU->getFile())
1061 ScopeToPathOpStringReg[F] = PathReg;
1062 }
1063 }
1064
1065 for (const DIBasicType *BT : BasicTypes)
1066 emitOpStringIfNew(S: BT->getName(), MAI);
1067
1068 for (const DISubprogram *SP : concat<const DISubprogram *>(
1069 Ranges&: SubprogramDeclarations, Ranges&: SubprogramDefinitions)) {
1070 emitOpStringIfNew(S: SP->getName(), MAI);
1071 emitOpStringIfNew(S: SP->getLinkageName(), MAI);
1072 emitAndCacheScopePathOpStringReg(Scope: SP, MAI);
1073 }
1074
1075 // Cache the OpStrings each DebugTypeComposite and its DebugTypeMembers use:
1076 // the composite name, identifier (linkage name), and path, plus each member
1077 // name and path.
1078 for (const DICompositeType *CT : CompositeTypes) {
1079 emitOpStringIfNew(S: CT->getName(), MAI);
1080 emitOpStringIfNew(S: CT->getIdentifier(), MAI);
1081 emitAndCacheScopePathOpStringReg(Scope: CT->getFile(), MAI);
1082 for (const DINode *Element : CT->getElements()) {
1083 const auto *M = dyn_cast<DIDerivedType>(Val: Element);
1084 if (!M || M->getTag() != dwarf::DW_TAG_member)
1085 continue;
1086 emitOpStringIfNew(S: M->getName(), MAI);
1087 emitAndCacheScopePathOpStringReg(Scope: M->getFile(), MAI);
1088 }
1089 }
1090
1091 // Cache the name and path OpStrings each DebugTypedef uses.
1092 for (const DIDerivedType *TD : TypedefTypes) {
1093 emitOpStringIfNew(S: TD->getName(), MAI);
1094 emitAndCacheScopePathOpStringReg(Scope: TD->getFile(), MAI);
1095 }
1096
1097 for (const auto &[GV, _] : GlobalVariableDebugInfoMap) {
1098 emitOpStringIfNew(S: GV->getName(), MAI);
1099 emitOpStringIfNew(S: GV->getLinkageName(), MAI);
1100 emitAndCacheScopePathOpStringReg(Scope: GV->getFile(), MAI);
1101 }
1102
1103 for (const DILocation *DL : UniqueDebugLocations)
1104 emitAndCacheScopePathOpStringReg(Scope: DL->getScope(), MAI);
1105
1106 CachedEmptyStringReg = emitOpStringIfNew(S: "", MAI);
1107
1108#ifndef NDEBUG
1109 NonSemanticOpStringsSectionEmitted = true;
1110#endif
1111}
1112
1113void SPIRVNonSemanticDebugHandler::emitDebugFunctionDefinition(
1114 MCRegister DebugFunctionReg, MCRegister OpFunctionReg,
1115 SPIRV::ModuleAnalysisInfo &MAI) {
1116 assert(DebugFunctionReg.isValid() && OpFunctionReg.isValid() &&
1117 "DebugFunctionDefinition operands must be valid");
1118 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1119 MCRegister ExtInstSetReg = MAI.getExtInstSetReg(SetNum: NSSet);
1120 emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugFunctionDefinition, VoidTypeReg,
1121 ExtInstSetReg, Operands: {DebugFunctionReg, OpFunctionReg}, MAI);
1122}
1123
1124void SPIRVNonSemanticDebugHandler::resetPerFunctionDebugState() {
1125 CurrentMF = nullptr;
1126 LastFunctionOpVariable = nullptr;
1127 DebugFunctionDefinitionEmitted = false;
1128 LastLineMI = nullptr;
1129}
1130
1131void SPIRVNonSemanticDebugHandler::preparePerFunctionDebug(
1132 const MachineFunction *MF) {
1133 resetPerFunctionDebugState();
1134 if (!GlobalNSDIEnabled || !CurrentMAI)
1135 return;
1136
1137 CurrentMF = MF;
1138
1139 if (MF->getFunction()
1140 .getFnAttribute(SPIRV_BACKEND_SERVICE_FUN_NAME)
1141 .isValid())
1142 return;
1143
1144 const DISubprogram *SP = MF->getFunction().getSubprogram();
1145 if (!SP || !SP->isDefinition())
1146 return;
1147
1148 // DebugFunctionDefinition is emitted after the last function-level
1149 // OpVariable. If there are none, it is emitted after the entry OpLabel.
1150 LastFunctionOpVariable =
1151 findLastFunctionOpVariableDeclaration(MF: *MF, MAI&: *CurrentMAI);
1152}
1153
1154void SPIRVNonSemanticDebugHandler::tryEmitDebugFunctionDefinition(
1155 SPIRV::ModuleAnalysisInfo &MAI) {
1156 if (DebugFunctionDefinitionEmitted || !GlobalNSDIEnabled)
1157 return;
1158
1159 assert(CurrentMF && "no current MachineFunction");
1160 const Function &F = CurrentMF->getFunction();
1161 const DISubprogram *SP = F.getSubprogram();
1162 if (!SP || !SP->isDefinition())
1163 return;
1164
1165 auto DFIt = DebugFunctionRegs.find(Val: SP);
1166 if (DFIt == DebugFunctionRegs.end())
1167 return;
1168
1169 MCRegister OpFunctionReg = MAI.getGlobalObjReg(GO: &F);
1170 if (!OpFunctionReg.isValid())
1171 return;
1172
1173 emitDebugFunctionDefinition(DebugFunctionReg: DFIt->second, OpFunctionReg, MAI);
1174 DebugFunctionDefinitionEmitted = true;
1175}
1176
1177void SPIRVNonSemanticDebugHandler::beginFunctionImpl(
1178 const MachineFunction *MF) {
1179 preparePerFunctionDebug(MF);
1180}
1181
1182void SPIRVNonSemanticDebugHandler::endFunctionImpl(const MachineFunction *MF) {
1183 (void)MF;
1184 resetPerFunctionDebugState();
1185}
1186
1187void SPIRVNonSemanticDebugHandler::beginInstruction(const MachineInstr *MI) {
1188 assert(CurMI == nullptr && "CurMI must be null");
1189 CurMI = MI;
1190
1191 if (!DebugFunctionDefinitionEmitted)
1192 return;
1193 emitDebugLineForInstruction(MI);
1194}
1195
1196static bool isMergeInstruction(unsigned Opcode) {
1197 return Opcode == SPIRV::OpSelectionMerge || Opcode == SPIRV::OpLoopMerge ||
1198 Opcode == SPIRV::OpLoopControlINTEL;
1199}
1200
1201static bool isDebugLineTarget(const MachineInstr *MI,
1202 SPIRV::ModuleAnalysisInfo &MAI) {
1203 if (MAI.getSkipEmission(MI))
1204 return false;
1205 switch (MI->getOpcode()) {
1206 case SPIRV::OpFunction:
1207 case SPIRV::OpFunctionParameter:
1208 case SPIRV::OpFunctionEnd:
1209 case SPIRV::OpLabel:
1210 case SPIRV::OpPhi:
1211 return false;
1212 default:
1213 return true;
1214 }
1215}
1216
1217static const MachineInstr *
1218findAdjacentEmittedInstruction(const MachineInstr *MI,
1219 SPIRV::ModuleAnalysisInfo &MAI, bool Forward) {
1220 for (const MachineInstr *Adj = Forward ? MI->getNextNode()
1221 : MI->getPrevNode();
1222 Adj; Adj = Forward ? Adj->getNextNode() : Adj->getPrevNode()) {
1223 if (MAI.getSkipEmission(MI: Adj))
1224 continue;
1225 return Adj;
1226 }
1227 return nullptr;
1228}
1229
1230void SPIRVNonSemanticDebugHandler::emitDebugLineForInstruction(
1231 const MachineInstr *MI) {
1232 assert(DebugFunctionDefinitionEmitted &&
1233 "DebugFunctionDefinition must be emitted");
1234 assert(CurrentMAI && "CurrentMAI must be set");
1235
1236 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
1237
1238 // Structural opcodes don't require a DebugLine, other opcodes might have
1239 // already been emitted in the module scope.
1240 if (!isDebugLineTarget(MI, MAI))
1241 return;
1242
1243 // DebugLine can be emitted before a merge instruction, but not after it
1244 // (nothing may sit between the merge and its terminator). We can use either
1245 // the merge's or the terminator's debug info; we emit the terminator's one.
1246 const MachineInstr *Prev = findAdjacentEmittedInstruction(MI, MAI, Forward: false);
1247 if (Prev && isMergeInstruction(Opcode: Prev->getOpcode()))
1248 return;
1249
1250 if (isMergeInstruction(Opcode: MI->getOpcode())) {
1251 // Use the terminator's debug info; when we reach it later, the check
1252 // above skips it.
1253 MI = findAdjacentEmittedInstruction(MI, MAI, Forward: true);
1254 assert(MI && "Merge instruction must be followed by a terminator");
1255 }
1256
1257 // The range of DebugLine must be reset at each basic block boundary.
1258 if (LastLineMI && MI->getParent() != LastLineMI->getParent())
1259 LastLineMI = nullptr;
1260
1261 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1262 MCRegister ExtInstSetReg = MAI.getExtInstSetReg(SetNum: NSSet);
1263
1264 const DILocation *DL = MI->getDebugLoc().get();
1265 if (!DL) {
1266 // No location for the current instruction
1267 if (LastLineMI) {
1268 // Close the current DebugLine region.
1269 emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugNoLine, VoidTypeReg,
1270 ExtInstSetReg, Operands: {}, MAI);
1271 LastLineMI = nullptr;
1272 }
1273 // No DebugLine region to close.
1274 return;
1275 }
1276
1277 // At this point, there is a location for the current instruction.
1278 // If it matches the last emitted DebugLine, no new DebugLine region is
1279 // needed. Otherwise, emit a new DebugLine region and update LastLineMI.
1280
1281 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1282 Scope: DL->getScope(), /*UseEmptyPathIfNullScope=*/true);
1283 unsigned Line = DL->getLine();
1284 unsigned Col = DL->getColumn();
1285
1286 MCRegister SrcReg = DebugSourceRegByFileStr.lookup(Val: FileStrReg.id());
1287 MCRegister LineReg = I32ConstantCache.lookup(Val: Line);
1288 MCRegister ColStartReg = I32ConstantCache.lookup(Val: Col);
1289 MCRegister ColEndReg = I32ConstantCache.lookup(Val: Col + 1);
1290
1291 // The elements of each collected DILocation (DebugSource, line/column
1292 // constants) are pre-emitted from LLVM-IR instruction !dbg attachments and
1293 // debug-program records; MIR is expected to reuse those same locations (or
1294 // carry none). A lookup miss means codegen attached a source position whose
1295 // elements were never pre-emitted, and debug-line emission is skipped.
1296 if (!SrcReg.isValid() || !LineReg.isValid() || !ColStartReg.isValid() ||
1297 !ColEndReg.isValid())
1298 return;
1299
1300 // Current location matches the last emitted DebugLine region.
1301 if (LastLineMI && MI->getDebugLoc() == LastLineMI->getDebugLoc())
1302 return;
1303
1304 // A new DebugLine region is needed. Emit it and update LastLineMI.
1305 emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugLine, VoidTypeReg, ExtInstSetReg,
1306 Operands: {SrcReg, LineReg, LineReg, ColStartReg, ColEndReg}, MAI);
1307
1308 LastLineMI = MI;
1309}
1310
1311void SPIRVNonSemanticDebugHandler::endInstruction() {
1312 const MachineInstr *MI = CurMI;
1313 CurMI = nullptr;
1314
1315 if (!MI || !GlobalNSDIEnabled || DebugFunctionDefinitionEmitted || !CurrentMF)
1316 return;
1317
1318 if (MI != LastFunctionOpVariable)
1319 return;
1320
1321 // If this is the last function-level OpVariable, emit the
1322 // DebugFunctionDefinition. Otherwise, we had already done it before right
1323 // after the OpLabel (see notifyEntryLabelEmitted).
1324 assert(CurrentMAI && "CurrentMAI must be set");
1325 tryEmitDebugFunctionDefinition(MAI&: *CurrentMAI);
1326}
1327
1328void SPIRVNonSemanticDebugHandler::notifyEntryLabelEmitted(
1329 const MachineFunction &MF) {
1330 if (!GlobalNSDIEnabled || DebugFunctionDefinitionEmitted || !CurrentMF)
1331 return;
1332
1333 assert(CurrentMF == &MF &&
1334 "notification does not match the current MachineFunction");
1335
1336 if (LastFunctionOpVariable)
1337 return;
1338
1339 // If there are no function-level OpVariables, emit the
1340 // DebugFunctionDefinition. Otherwise, DebugFunctionDefinition is emitted
1341 // after the last OpVariable (see endInstruction).
1342 tryEmitDebugFunctionDefinition(MAI&: *CurrentMAI);
1343}
1344
1345void SPIRVNonSemanticDebugHandler::emitNonSemanticGlobalDebugInfo(
1346 SPIRV::ModuleAnalysisInfo &MAI) {
1347 if (GlobalDIEmitted)
1348 return;
1349
1350 GlobalDIEmitted = true;
1351
1352 if (CompileUnits.empty()) {
1353 GlobalNSDIEnabled = false;
1354 return;
1355 }
1356
1357 // Retrieve the ext inst set register allocated by prepareModuleOutput().
1358 MCRegister ExtInstSetReg = MAI.getExtInstSetReg(SetNum: NSSet);
1359 if (!ExtInstSetReg.isValid()) {
1360 GlobalNSDIEnabled = false;
1361 return;
1362 }
1363
1364#ifndef NDEBUG
1365 assert(NonSemanticOpStringsSectionEmitted &&
1366 "emitNonSemanticDebugStrings() must run before "
1367 "emitNonSemanticGlobalDebugInfo()");
1368#endif
1369
1370 CurrentMAI = &MAI;
1371
1372 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1373 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
1374
1375 CachedDebugInfoNoneReg = emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugInfoNone,
1376 VoidTypeReg, ExtInstSetReg, Operands: {}, MAI);
1377
1378 // Emit integer constants shared across all NSDI instructions. The constant
1379 // cache ensures each value is emitted at most once even when referenced from
1380 // multiple instructions. All constants are pre-emitted before any DebugSource
1381 // so that the output order is: constants, then
1382 // DebugSource+DebugCompilationUnit pairs. This keeps OpConstant instructions
1383 // grouped before the OpExtInst instructions.
1384
1385 // The Version operand of DebugCompilationUnit is the version of the
1386 // NonSemantic.Shader.DebugInfo instruction set, which is 100 for
1387 // "NonSemantic.Shader.DebugInfo.100" (NonSemanticShaderDebugInfo100Version).
1388 MCRegister DebugInfoVersionReg = emitOpConstantI32(Value: 100, I32TypeReg, MAI);
1389 MCRegister DwarfVersionReg =
1390 emitOpConstantI32(Value: static_cast<uint32_t>(DwarfVersion), I32TypeReg, MAI);
1391
1392 // Pre-emit source language constants for all compile units before entering
1393 // the DebugSource loop.
1394 SmallVector<MCRegister> SrcLangRegs =
1395 map_to_vector(C&: CompileUnits, F: [&](const CompileUnitInfo &Info) {
1396 return emitOpConstantI32(Value: Info.SpirvSourceLanguage, I32TypeReg, MAI);
1397 });
1398
1399 // Emit DebugSource and DebugCompilationUnit for each compile unit.
1400 for (auto [Info, SrcLangReg] : llvm::zip(t&: CompileUnits, u&: SrcLangRegs)) {
1401 MCRegister FileStrReg = ScopeToPathOpStringReg.lookup(Val: Info.TheCU);
1402 assert(FileStrReg.isValid() &&
1403 "CU path OpString must be emitted in emitNonSemanticDebugStrings");
1404 MCRegister DebugSourceReg = getOrEmitDebugSourceForFileStrReg(
1405 FileStrReg, VoidTypeReg, ExtInstSetReg, MAI);
1406 MCRegister CUDbgReg = emitExtInst(
1407 Opcode: SPIRV::NonSemanticExtInst::DebugCompilationUnit, VoidTypeReg,
1408 ExtInstSetReg,
1409 Operands: {DebugInfoVersionReg, DwarfVersionReg, DebugSourceReg, SrcLangReg},
1410 MAI);
1411 if (Info.TheCU)
1412 CUToCompilationUnitDbgReg[Info.TheCU] = CUDbgReg;
1413 }
1414
1415 // Zero constant used as the Flags operand in DebugTypeBasic and
1416 // DebugTypePointer. Cached with other i32 constants.
1417 MCRegister I32ZeroReg = emitOpConstantI32(Value: 0, I32TypeReg, MAI);
1418
1419 DebugTypeRegs.clear();
1420
1421 for (const DIBasicType *BT : BasicTypes) {
1422 MCRegister NameReg = getCachedOpStringReg(S: BT->getName());
1423 MCRegister SizeReg = emitOpConstantI32(
1424 Value: static_cast<uint32_t>(BT->getSizeInBits()), I32TypeReg, MAI);
1425
1426 // Map DWARF base type encodings to NSDI encoding codes per
1427 // NonSemantic.Shader.DebugInfo.100 specification, section 4.5.
1428 unsigned Encoding = 0; // Unspecified
1429 switch (BT->getEncoding()) {
1430 case dwarf::DW_ATE_address:
1431 Encoding = 1;
1432 break;
1433 case dwarf::DW_ATE_boolean:
1434 Encoding = 2;
1435 break;
1436 case dwarf::DW_ATE_float:
1437 Encoding = 3;
1438 break;
1439 case dwarf::DW_ATE_signed:
1440 Encoding = 4;
1441 break;
1442 case dwarf::DW_ATE_signed_char:
1443 Encoding = 5;
1444 break;
1445 case dwarf::DW_ATE_unsigned:
1446 Encoding = 6;
1447 break;
1448 case dwarf::DW_ATE_unsigned_char:
1449 Encoding = 7;
1450 break;
1451 }
1452 MCRegister EncodingReg = emitOpConstantI32(Value: Encoding, I32TypeReg, MAI);
1453
1454 MCRegister BTReg = emitExtInst(
1455 Opcode: SPIRV::NonSemanticExtInst::DebugTypeBasic, VoidTypeReg, ExtInstSetReg,
1456 Operands: {NameReg, SizeReg, EncodingReg, I32ZeroReg}, MAI);
1457 DebugTypeRegs[BT] = BTReg;
1458 }
1459
1460 // Emit DebugTypeVector for each collected vector type.
1461 for (const DICompositeType *VT : VectorTypes) {
1462 if (auto VecReg = emitDebugTypeVector(VT, ExtInstSetReg, MAI))
1463 DebugTypeRegs[VT] = *VecReg;
1464 }
1465
1466 // Emit DebugTypePointer for each referenced pointer type.
1467 for (const DIDerivedType *PT : PointerTypes) {
1468 if (auto PtrReg = emitDebugTypePointer(PT, ExtInstSetReg, MAI))
1469 DebugTypeRegs[PT] = *PtrReg;
1470 }
1471
1472 // Emit DebugTypeArray for each collected array type. Placed after the basic,
1473 // vector, and pointer types so an array over any of them can resolve its
1474 // element id. An array whose element type was not emitted is skipped.
1475 for (const DICompositeType *AT : ArrayTypes) {
1476 if (auto ArrReg = emitDebugTypeArray(AT, ExtInstSetReg, MAI))
1477 DebugTypeRegs[AT] = *ArrReg;
1478 }
1479
1480 // Emit DebugTypeFunction for each distinct DISubroutineType.
1481 for (const DISubroutineType *ST : SubroutineTypes) {
1482 if (auto FnTyReg =
1483 emitDebugTypeFunctionForSubroutineType(ST, ExtInstSetReg, MAI))
1484 DebugTypeRegs[ST] = *FnTyReg;
1485 }
1486
1487 // Emit DebugTypedef for each typedef. Placed after the other type loops so a
1488 // typedef can resolve its underlying type. A typedef whose base type is not
1489 // emitted is skipped. A typedef whose base is another typedef emitted later
1490 // in this same pass is also skipped, the emission-order gap tracked in
1491 // https://github.com/llvm/llvm-project/issues/211850.
1492 for (const DIDerivedType *TD : TypedefTypes) {
1493 if (auto TDReg =
1494 emitDebugTypedef(TD, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI))
1495 DebugTypeRegs[TD] = *TDReg;
1496 }
1497
1498 // Emit DebugFunctionDeclaration for DISubprogram declarations.
1499 for (const DISubprogram *SP : SubprogramDeclarations) {
1500 if (auto DeclReg = emitDebugFunctionDeclaration(SP, VoidTypeReg, I32TypeReg,
1501 ExtInstSetReg, MAI))
1502 DebugFunctionDeclarationRegs[SP] = *DeclReg;
1503 }
1504
1505 // Emit DebugTypeMember and DebugTypeComposite for each struct, class, or
1506 // union. Each member is emitted before the composite that lists it, so the
1507 // Members operand references already-defined ids. A member whose type is not
1508 // in DebugTypeRegs is skipped.
1509 for (const DICompositeType *CT : CompositeTypes) {
1510 SmallVector<MCRegister> MemberRegs;
1511 for (const DINode *Element : CT->getElements()) {
1512 const auto *M = dyn_cast<DIDerivedType>(Val: Element);
1513 if (!M || M->getTag() != dwarf::DW_TAG_member)
1514 continue;
1515 if (auto MemberReg = emitDebugTypeMember(M, VoidTypeReg, I32TypeReg,
1516 ExtInstSetReg, MAI))
1517 MemberRegs.push_back(Elt: *MemberReg);
1518 }
1519 if (auto CompReg = emitDebugTypeComposite(CT, MemberRegs, VoidTypeReg,
1520 I32TypeReg, ExtInstSetReg, MAI))
1521 DebugTypeRegs[CT] = *CompReg;
1522 }
1523
1524 // Emit DebugFunction for DISubprogram definitions.
1525 for (const DISubprogram *SP : SubprogramDefinitions) {
1526 if (auto FnReg =
1527 emitDebugFunction(SP, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI))
1528 DebugFunctionRegs[SP] = *FnReg;
1529 }
1530
1531 // Emit DebugGlobalVariable for each collected DIGlobalVariable.
1532 for (const auto &[GV, Info] : GlobalVariableDebugInfoMap)
1533 emitDebugGlobalVariable(GV, Info, VoidTypeReg, I32TypeReg, ExtInstSetReg,
1534 MAI);
1535
1536 for (const DILocation *DL : UniqueDebugLocations) {
1537 emitOpConstantI32(Value: DL->getLine(), I32TypeReg, MAI);
1538 emitOpConstantI32(Value: DL->getColumn(), I32TypeReg, MAI);
1539 emitOpConstantI32(Value: DL->getColumn() + 1, I32TypeReg, MAI);
1540 MCRegister FileStrReg =
1541 getCachedScopePathOpStringReg(Scope: DL->getScope(),
1542 /*UseEmptyPathIfNullScope=*/true);
1543 getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg, ExtInstSetReg,
1544 MAI);
1545 }
1546
1547 GlobalNSDIEnabled = true;
1548}
1549
1550SmallString<128>
1551SPIRVNonSemanticDebugHandler::getDebugFullPath(const DIScope *Scope) const {
1552 SmallString<128> Out;
1553 if (!Scope)
1554 return Out;
1555 StringRef Filename = Scope->getFilename();
1556 const auto Style = sys::path::Style::native;
1557 if (sys::path::is_absolute(path: Filename, style: Style))
1558 Out.assign(in_start: Filename.begin(), in_end: Filename.end());
1559 else {
1560 StringRef Dir = Scope->getDirectory();
1561 Out.assign(in_start: Dir.begin(), in_end: Dir.end());
1562 sys::path::append(path&: Out, style: Style, a: Filename);
1563 }
1564 return Out;
1565}
1566
1567MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugSourceForFileStrReg(
1568 MCRegister FileStrReg, MCRegister VoidTypeReg, MCRegister ExtInstSetReg,
1569 SPIRV::ModuleAnalysisInfo &MAI) {
1570 const unsigned Key = FileStrReg.id();
1571 auto It = DebugSourceRegByFileStr.find(Val: Key);
1572 if (It != DebugSourceRegByFileStr.end())
1573 return It->second;
1574
1575 MCRegister DS = emitExtInst(Opcode: SPIRV::NonSemanticExtInst::DebugSource,
1576 VoidTypeReg, ExtInstSetReg, Operands: {FileStrReg}, MAI);
1577 DebugSourceRegByFileStr[Key] = DS;
1578 return DS;
1579}
1580