LLVM 23.0.0git
SPIRVNonSemanticDebugHandler.cpp
Go to the documentation of this file.
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
12#include "SPIRVSubtarget.h"
13#include "SPIRVUtils.h"
17#include "llvm/IR/DebugInfo.h"
19#include "llvm/IR/Module.h"
20#include "llvm/MC/MCInst.h"
21#include "llvm/MC/MCStreamer.h"
23#include "llvm/Support/Path.h"
24#include <cassert>
25
26using namespace llvm;
27
28namespace {
29
30/// Look up \p Key in a register map and return its value, or std::nullopt when
31/// the key is absent.
32template <typename MapT>
33static std::optional<MCRegister> lookupOptReg(const MapT &Map,
34 typename MapT::key_type Key) {
35 auto It = Map.find(Key);
36 if (It == Map.end())
37 return std::nullopt;
38 assert(It->second.isValid() && "invalid register stored in map");
39 return It->second;
40}
41
42/// Partition \p Ty into \p BasicTypes, \p PointerTypes, \p SubroutineTypes,
43/// and \p VectorTypes for NSDI emission. Used when iterating
44/// DebugInfoFinder.types(); each DI node is seen once, so no recursion into
45/// pointer bases. Other composites and non-pointer derived kinds are ignored
46/// because they are not yet supported. Only types that are supported (later
47/// used) are partitioned.
48static void
49partitionTypes(const DIType *Ty, SmallVector<const DIBasicType *> &BasicTypes,
53 if (const auto *BT = dyn_cast<DIBasicType>(Ty)) {
54 BasicTypes.push_back(BT);
55 return;
56 }
57 if (const auto *ST = dyn_cast<DISubroutineType>(Ty)) {
58 SubroutineTypes.push_back(ST);
59 return;
60 }
61 if (const auto *CT = dyn_cast<DICompositeType>(Ty)) {
62 if (CT->getTag() == dwarf::DW_TAG_array_type && CT->isVector())
63 VectorTypes.push_back(CT);
64 return;
65 }
66 const auto *DT = dyn_cast<DIDerivedType>(Ty);
67 if (DT && DT->getTag() == dwarf::DW_TAG_pointer_type)
68 PointerTypes.push_back(DT);
69}
70
71enum : uint32_t {
72 NSDIFlagIsProtected = 1u << 0,
73 NSDIFlagIsPrivate = 1u << 1,
74 NSDIFlagIsPublic = NSDIFlagIsPrivate | NSDIFlagIsProtected,
75 NSDIFlagIsLocal = 1u << 2,
76 NSDIFlagIsDefinition = 1u << 3,
77 NSDIFlagFwdDecl = 1u << 4,
78 NSDIFlagArtificial = 1u << 5,
79 NSDIFlagExplicit = 1u << 6,
80 NSDIFlagPrototyped = 1u << 7,
81 NSDIFlagObjectPointer = 1u << 8,
82 NSDIFlagStaticMember = 1u << 9,
83 NSDIFlagIndirectVariable = 1u << 10,
84 NSDIFlagLValueReference = 1u << 11,
85 NSDIFlagRValueReference = 1u << 12,
86 NSDIFlagIsOptimized = 1u << 13,
87 NSDIFlagIsEnumClass = 1u << 14,
88 NSDIFlagTypePassByValue = 1u << 15,
89 NSDIFlagTypePassByReference = 1u << 16,
90 NSDIFlagUnknownPhysicalLayout = 1u << 17,
91};
92
93static uint32_t mapDIFlagsToNonSemantic(DINode::DIFlags DFlags) {
94 uint32_t Flags = 0;
95 if ((DFlags & DINode::FlagAccessibility) == DINode::FlagPublic)
96 Flags |= NSDIFlagIsPublic;
97 if ((DFlags & DINode::FlagAccessibility) == DINode::FlagProtected)
98 Flags |= NSDIFlagIsProtected;
99 if ((DFlags & DINode::FlagAccessibility) == DINode::FlagPrivate)
100 Flags |= NSDIFlagIsPrivate;
101 if (DFlags & DINode::FlagFwdDecl)
102 Flags |= NSDIFlagFwdDecl;
103 if (DFlags & DINode::FlagArtificial)
104 Flags |= NSDIFlagArtificial;
105 if (DFlags & DINode::FlagExplicit)
106 Flags |= NSDIFlagExplicit;
107 if (DFlags & DINode::FlagPrototyped)
108 Flags |= NSDIFlagPrototyped;
109 if (DFlags & DINode::FlagObjectPointer)
110 Flags |= NSDIFlagObjectPointer;
111 if (DFlags & DINode::FlagStaticMember)
112 Flags |= NSDIFlagStaticMember;
113 if (DFlags & DINode::FlagLValueReference)
114 Flags |= NSDIFlagLValueReference;
115 if (DFlags & DINode::FlagRValueReference)
116 Flags |= NSDIFlagRValueReference;
117 if (DFlags & DINode::FlagTypePassByValue)
118 Flags |= NSDIFlagTypePassByValue;
119 if (DFlags & DINode::FlagTypePassByReference)
120 Flags |= NSDIFlagTypePassByReference;
121 if (DFlags & DINode::FlagEnumClass)
122 Flags |= NSDIFlagIsEnumClass;
123 return Flags;
124}
125
126static uint32_t transDebugFlags(const DINode *DN) {
127 uint32_t Flags = 0;
128 if (const auto *GV = dyn_cast<DIGlobalVariable>(DN)) {
129 if (GV->isLocalToUnit())
130 Flags |= NSDIFlagIsLocal;
131 if (GV->isDefinition())
132 Flags |= NSDIFlagIsDefinition;
133 }
134 if (const auto *SP = dyn_cast<DISubprogram>(DN)) {
135 if (SP->isLocalToUnit())
136 Flags |= NSDIFlagIsLocal;
137 if (SP->isOptimized())
138 Flags |= NSDIFlagIsOptimized;
139 if (SP->isDefinition())
140 Flags |= NSDIFlagIsDefinition;
141 Flags |= mapDIFlagsToNonSemantic(SP->getFlags());
142 }
143 if (DN->getTag() == dwarf::DW_TAG_reference_type)
144 Flags |= NSDIFlagLValueReference;
145 if (DN->getTag() == dwarf::DW_TAG_rvalue_reference_type)
146 Flags |= NSDIFlagRValueReference;
147 if (const auto *Ty = dyn_cast<DIType>(DN))
148 Flags |= mapDIFlagsToNonSemantic(Ty->getFlags());
149 if (const auto *LV = dyn_cast<DILocalVariable>(DN))
150 Flags |= mapDIFlagsToNonSemantic(LV->getFlags());
151 return Flags;
152}
153
154} // namespace
155
158
159// Map DWARF source language codes to NonSemantic.Shader.DebugInfo.100 source
160// language codes. Values are from the SourceLanguage enum in the
161// NonSemantic.Shader.DebugInfo.100 specification, section 4.3.
162unsigned SPIRVNonSemanticDebugHandler::toNSDISrcLang(unsigned DwarfSrcLang) {
163 switch (DwarfSrcLang) {
164 case dwarf::DW_LANG_OpenCL:
165 return 3; // OpenCL_C
166 case dwarf::DW_LANG_OpenCL_CPP:
167 return 4; // OpenCL_CPP
168 case dwarf::DW_LANG_CPP_for_OpenCL:
169 return 6; // CPP_for_OpenCL
170 case dwarf::DW_LANG_GLSL:
171 return 2; // GLSL
172 case dwarf::DW_LANG_HLSL:
173 return 5; // HLSL
174 case dwarf::DW_LANG_SYCL:
175 return 7; // SYCL
176 case dwarf::DW_LANG_Zig:
177 return 12; // Zig
178 default:
179 return 0; // Unknown
180 }
181}
182
184 // The base class sets Asm = nullptr when the module has no compile units,
185 // and initializes lexical scope tracking otherwise.
187
188 if (!Asm)
189 return;
190
191 CompileUnits.clear();
192 BasicTypes.clear();
193 PointerTypes.clear();
194 SubroutineTypes.clear();
195 VectorTypes.clear();
196 SubprogramDeclarations.clear();
197 DebugFunctionDeclarationRegs.clear();
198 ScopeToPathOpStringReg.clear();
199 CUToCompilationUnitDbgReg.clear();
200 DebugSourceRegByFileStr.clear();
201 DebugTypeRegs.clear();
202 OpStringContentCache.clear();
203 I32ConstantCache.clear();
204 DebugTypeFunctionCache.clear();
205 GlobalDIEmitted = false;
206#ifndef NDEBUG
207 NonSemanticOpStringsSectionEmitted = false;
208#endif
209 CachedDebugInfoNoneReg = MCRegister();
210 CachedOpTypeVoidReg = MCRegister();
211 CachedOpTypeInt32Reg = MCRegister();
212
213 // Collect compile-unit info: file paths and source languages.
214 for (const DICompileUnit *CU : M->debug_compile_units()) {
215 const DIFile *File = CU->getFile();
216 CompileUnitInfo Info;
217 Info.TheCU = CU;
218 if (sys::path::is_absolute(File->getFilename()))
219 Info.FilePath = File->getFilename();
220 else
221 sys::path::append(Info.FilePath, File->getDirectory(),
222 File->getFilename());
223 // getName() returns the language code regardless of whether the name is
224 // versioned. getUnversionedName() would assert on versioned names.
225 Info.SpirvSourceLanguage = toNSDISrcLang(CU->getSourceLanguage().getName());
226 CompileUnits.push_back(std::move(Info));
227 }
228
229 // Collect DWARF version from module flags. For CodeView modules there is no
230 // "Dwarf Version" flag; DwarfVersion remains 0, which is the correct value
231 // for the DebugCompilationUnit DWARF Version operand in that case.
232 if (const NamedMDNode *Flags = M->getNamedMetadata("llvm.module.flags")) {
233 for (const auto *Op : Flags->operands()) {
234 const MDOperand &NameOp = Op->getOperand(1);
235 if (NameOp.equalsStr("Dwarf Version"))
236 DwarfVersion =
238 cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
239 ->getSExtValue();
240 }
241 }
242
243 // Find all debug info types that may be referenced by NSDI instructions.
244 DebugInfoFinder Finder;
245 Finder.processModule(*M);
246 llvm::for_each(Finder.types(), [&](DIType *Ty) {
247 partitionTypes(Ty, BasicTypes, PointerTypes, SubroutineTypes, VectorTypes);
248 });
249
250 for (const DISubprogram *SP : Finder.subprograms()) {
251 if (!SP->isDefinition())
252 SubprogramDeclarations.push_back(SP);
253 }
254}
255
258 if (CompileUnits.empty())
259 return;
260 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_non_semantic_info))
261 return;
262
263 // Add the extension to requirements so OpExtension is output.
264 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_non_semantic_info);
265
266 // Add the NonSemantic.Shader.DebugInfo.100 entry to ExtInstSetMap so that
267 // outputOpExtInstImports() emits the OpExtInstImport instruction. Allocate a
268 // fresh result ID for it now; the same ID is used in emitExtInst() operands.
269 constexpr unsigned NSSet = static_cast<unsigned>(
270 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100);
271 if (!MAI.ExtInstSetMap.count(NSSet))
272 MAI.ExtInstSetMap[NSSet] = MAI.getNextIDRegister();
273}
274
275void SPIRVNonSemanticDebugHandler::emitMCInst(MCInst &Inst) {
276 Asm->OutStreamer->emitInstruction(Inst, Asm->getSubtargetInfo());
277}
278
280SPIRVNonSemanticDebugHandler::emitOpString(StringRef S,
283 MCInst Inst;
284 Inst.setOpcode(SPIRV::OpString);
286 addStringImm(S, Inst);
287 emitMCInst(Inst);
288 return Reg;
289}
290
291MCRegister SPIRVNonSemanticDebugHandler::emitOpStringIfNew(
293#ifndef NDEBUG
294 assert(!NonSemanticOpStringsSectionEmitted &&
295 "emitOpStringIfNew is only valid while emitting SPIR-V section 7");
296#endif
297 auto [It, Inserted] = OpStringContentCache.try_emplace(S, MCRegister());
298 if (Inserted)
299 It->second = emitOpString(S, MAI);
300
301 return It->second;
302}
303
304MCRegister SPIRVNonSemanticDebugHandler::getCachedOpStringReg(StringRef S) {
305#ifndef NDEBUG
306 assert(NonSemanticOpStringsSectionEmitted &&
307 "getCachedOpStringReg requires emitNonSemanticDebugStrings() first");
308#endif
309 auto It = OpStringContentCache.find(S);
310 assert(It != OpStringContentCache.end() &&
311 "NSDI OpString missing from cache; emitNonSemanticDebugStrings must "
312 "cache every string used in section 10");
313 return It->second;
314}
315
316MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI32(
317 uint32_t Value, MCRegister I32TypeReg, SPIRV::ModuleAnalysisInfo &MAI) {
318 auto [It, Inserted] = I32ConstantCache.try_emplace(Value);
319 if (!Inserted)
320 return It->second;
321
322 MCRegister Reg = MAI.getNextIDRegister();
323 It->second = Reg;
324 MCInst Inst;
325 Inst.setOpcode(SPIRV::OpConstantI);
327 Inst.addOperand(MCOperand::createReg(I32TypeReg));
328 Inst.addOperand(MCOperand::createImm(static_cast<int64_t>(Value)));
329 emitMCInst(Inst);
330 return Reg;
331}
332
333MCRegister SPIRVNonSemanticDebugHandler::emitExtInst(
334 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
335 MCRegister VoidTypeReg, MCRegister ExtInstSetReg,
337 MCRegister Reg = MAI.getNextIDRegister();
338 MCInst Inst;
339 Inst.setOpcode(SPIRV::OpExtInst);
341 Inst.addOperand(MCOperand::createReg(VoidTypeReg));
342 Inst.addOperand(MCOperand::createReg(ExtInstSetReg));
343 Inst.addOperand(MCOperand::createImm(static_cast<int64_t>(Opcode)));
344 for (MCRegister R : Operands)
346 emitMCInst(Inst);
347 return Reg;
348}
349
350MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugTypeFunction(
351 ArrayRef<MCRegister> Ops, MCRegister VoidTypeReg, MCRegister ExtInstSetReg,
353 auto [It, Inserted] =
354 DebugTypeFunctionCache.try_emplace(SmallVector<MCRegister, 8>(Ops));
355 if (!Inserted)
356 return It->second;
357
358 MCRegister Reg = emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeFunction,
359 VoidTypeReg, ExtInstSetReg, Ops, MAI);
360 It->second = Reg;
361 return Reg;
362}
363
364MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeVoidReg(
366 if (!CachedOpTypeVoidReg.isValid())
367 CachedOpTypeVoidReg = findOrEmitOpTypeVoid(MAI);
368 return CachedOpTypeVoidReg;
369}
370
371MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeInt32Reg(
373 if (!CachedOpTypeInt32Reg.isValid())
374 CachedOpTypeInt32Reg = findOrEmitOpTypeInt32(MAI);
375 return CachedOpTypeInt32Reg;
376}
377
378MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeVoid(
380 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars)) {
381 if (MI->getOpcode() == SPIRV::OpTypeVoid)
382 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
383 }
384 MCRegister Reg = MAI.getNextIDRegister();
385 MCInst Inst;
386 Inst.setOpcode(SPIRV::OpTypeVoid);
388 emitMCInst(Inst);
389 return Reg;
390}
391
392MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt32(
394 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars)) {
395 if (MI->getOpcode() == SPIRV::OpTypeInt &&
396 MI->getOperand(1).getImm() == 32 && MI->getOperand(2).getImm() == 0)
397 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
398 }
399 MCRegister Reg = MAI.getNextIDRegister();
400 MCInst Inst;
401 Inst.setOpcode(SPIRV::OpTypeInt);
403 Inst.addOperand(MCOperand::createImm(32)); // width
404 Inst.addOperand(MCOperand::createImm(0)); // signedness (unsigned)
405 emitMCInst(Inst);
406 return Reg;
407}
408
409std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypePointer(
410 const DIDerivedType *PT, MCRegister ExtInstSetReg,
412 // A DWARF address space is required to determine the SPIR-V storage class.
413 // Skip pointer types that do not carry one.
414 if (!PT->getDWARFAddressSpace().has_value())
415 return std::nullopt;
416
417 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
418 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
419 MCRegister DebugTypePointerFlagsReg =
420 emitOpConstantI32(transDebugFlags(PT), I32TypeReg, MAI);
421
422 // For SPIR-V targets, Clang sets DwarfAddressSpace to the LLVM IR address
423 // space, which addressSpaceToStorageClass expects.
424 const auto &ST = static_cast<const SPIRVSubtarget &>(Asm->getSubtargetInfo());
425 MCRegister StorageClassReg = emitOpConstantI32(
426 addressSpaceToStorageClass(PT->getDWARFAddressSpace().value(), ST),
427 I32TypeReg, MAI);
428
429 if (const DIType *BaseTy = PT->getBaseType()) {
430 auto BaseIt = DebugTypeRegs.find(BaseTy);
431 if (BaseIt != DebugTypeRegs.end())
432 return emitExtInst(
433 SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg,
434 ExtInstSetReg,
435 {BaseIt->second, StorageClassReg, DebugTypePointerFlagsReg}, MAI);
436 // Unsupported type, no DebugType* id available.
437 return std::nullopt;
438 }
439 // No getBaseType() (typical for void*): use DebugInfoNone as Base Type,
440 // same as SPIRV-LLVM-Translator (see issue #109287 and the DISABLED
441 // spirv-val run in debug-type-pointer.ll). spirv-val may still reject this
442 // encoding; see https://github.com/KhronosGroup/SPIRV-Registry/pull/287.
443 return emitExtInst(
444 SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg, ExtInstSetReg,
445 {CachedDebugInfoNoneReg, StorageClassReg, DebugTypePointerFlagsReg}, MAI);
446}
447
448std::optional<MCRegister>
449SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
450 const DISubroutineType *ST, MCRegister ExtInstSetReg,
452 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
453 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
454 MCRegister DebugTypeFunctionFlagsReg =
455 emitOpConstantI32(transDebugFlags(ST), I32TypeReg, MAI);
456 DITypeArray TA = ST->getTypeArray();
458 Ops.push_back(DebugTypeFunctionFlagsReg);
459 // Empty DI type tuple: no explicit return or parameter slots (hand-written IR
460 // may use !{}). Emit void-only prototype. Same as SPIRV-LLVM-Translator when
461 // DISubroutineType::getTypeArray() has zero elements.
462 if (TA.empty()) {
463 Ops.push_back(VoidTypeReg);
464 } else {
465 for (unsigned I = 0, E = TA.size(); I != E; ++I) {
466 bool IsReturnType = (I == 0);
467 auto OptReg = mapDISignatureTypeToReg(TA[I], VoidTypeReg, IsReturnType);
468 // No emitted DebugType* id for this slot (e.g., pointer that
469 // was skipped due missing address space, etc.).
470 if (!OptReg)
471 return std::nullopt;
472 Ops.push_back(*OptReg);
473 }
474 }
475 return getOrEmitDebugTypeFunction(Ops, VoidTypeReg, ExtInstSetReg, MAI);
476}
477
478// Match SPIRV-LLVM-Translator's selection logic for the Parent operand.
479std::optional<MCRegister>
480SPIRVNonSemanticDebugHandler::resolveDebugFunctionDeclarationParent(
481 const DISubprogram *SP) const {
482 const DIScope *Scope = SP->getScope();
483 if (Scope && !isa<DIFile>(Scope)) {
484 // TODO: Complete with other lookups once other scopes are supported
485 // (subclasses of DIScope).
486 const DIType *Ty = dyn_cast<DIType>(Scope);
487 if (!Ty)
488 return std::nullopt;
489 return lookupOptReg(DebugTypeRegs, Ty);
490 }
491
492 const DICompileUnit *ParentCU = SP->getUnit();
493 if (!ParentCU && !CompileUnits.empty())
494 ParentCU = CompileUnits[0].TheCU;
495 if (!ParentCU)
496 return std::nullopt;
497 return lookupOptReg(CUToCompilationUnitDbgReg, ParentCU);
498}
499
500std::optional<MCRegister>
501SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration(
502 const DISubprogram *SP, MCRegister VoidTypeReg, MCRegister I32TypeReg,
503 MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
504 assert(SP && "SP must not be null in emitDebugFunctionDeclaration");
505 assert(!SP->isDefinition() &&
506 "SP must not be a definition in emitDebugFunctionDeclaration");
507
508 // The IR verifier already enforces that this cannot be null.
509 const DISubroutineType *ST = SP->getType();
510
511 auto FnTyRegOpt = lookupOptReg(DebugTypeRegs, ST);
512 if (!FnTyRegOpt)
513 return std::nullopt;
514 MCRegister FnTyReg = *FnTyRegOpt;
515
516 auto ParentRegOpt = resolveDebugFunctionDeclarationParent(SP);
517 if (!ParentRegOpt)
518 return std::nullopt;
519
520 MCRegister ParentReg = *ParentRegOpt;
521
522 auto PathStrIt = ScopeToPathOpStringReg.find(SP);
523 assert(PathStrIt != ScopeToPathOpStringReg.end() &&
524 "declaration path OpString must be cached in "
525 "emitNonSemanticDebugStrings");
526 MCRegister FileStrReg = PathStrIt->second;
527 assert(FileStrReg.isValid() &&
528 "declaration path OpString id must be valid once cached");
529
530 MCRegister NameReg = getCachedOpStringReg(SP->getName());
531 MCRegister LinkageReg = getCachedOpStringReg(SP->getLinkageName());
532 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
533 ExtInstSetReg, MAI);
534
535 MCRegister LineReg =
536 emitOpConstantI32(static_cast<uint32_t>(SP->getLine()), I32TypeReg, MAI);
537 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
538
539 uint32_t FlagsVal = transDebugFlags(SP);
540 // TODO: When composite scopes are DebugFunctionDeclaration parents (available
541 // in DebugTypeRegs), sync declaration Flags with SPIRV-LLVM-Translator.
542 FlagsVal &= ~NSDIFlagIsDefinition;
543 MCRegister FlagsReg = emitOpConstantI32(FlagsVal, I32TypeReg, MAI);
544
545 return emitExtInst(SPIRV::NonSemanticExtInst::DebugFunctionDeclaration,
546 VoidTypeReg, ExtInstSetReg,
547 {NameReg, FnTyReg, SrcReg, LineReg, ColReg, ParentReg,
548 LinkageReg, FlagsReg},
549 MAI);
550}
551
552std::optional<MCRegister> SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg(
553 const DIType *Ty, MCRegister VoidTypeReg, bool ReturnType) {
554 if (!Ty) {
555 if (ReturnType)
556 return VoidTypeReg;
557 assert(CachedDebugInfoNoneReg.isValid() &&
558 "DebugInfoNone must be emitted before DISubroutineType operands");
559 return CachedDebugInfoNoneReg;
560 }
561 return lookupOptReg(DebugTypeRegs, Ty);
562}
563
564std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeVector(
565 const DICompositeType *VT, MCRegister ExtInstSetReg,
567 const auto *BaseTy = dyn_cast_or_null<DIBasicType>(VT->getBaseType());
568 if (!BaseTy)
569 return std::nullopt;
570 auto BTIt = DebugTypeRegs.find(BaseTy);
571 if (BTIt == DebugTypeRegs.end())
572 return std::nullopt;
573
574 // DebugTypeVector models only 1D vectors (multi-subrange types cannot be
575 // encoded).
576 DINodeArray Elements = VT->getElements();
577 if (Elements.size() != 1)
578 return std::nullopt;
579 const auto *SR = cast<DISubrange>(Elements[0]);
580 const auto *CI = dyn_cast_if_present<ConstantInt *>(SR->getCount());
581 if (!CI)
582 return std::nullopt;
583
584 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
585 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
586 MCRegister CountReg = emitOpConstantI32(
587 static_cast<uint32_t>(CI->getZExtValue()), I32TypeReg, MAI);
588 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeVector, VoidTypeReg,
589 ExtInstSetReg, {BTIt->second, CountReg}, MAI);
590}
591
594 if (CompileUnits.empty())
595 return;
596 // Check that prepareModuleOutput() registered the extended instruction set.
597 // If the subtarget does not support the extension, neither strings nor ext
598 // insts are emitted.
599 constexpr unsigned NSSet = static_cast<unsigned>(
600 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100);
601 if (!MAI.getExtInstSetReg(NSSet).isValid())
602 return;
603
604 for (const CompileUnitInfo &Info : CompileUnits) {
605 if (Info.TheCU) {
606 MCRegister PathReg = emitOpStringIfNew(Info.FilePath, MAI);
607 ScopeToPathOpStringReg[Info.TheCU] = PathReg;
608 if (const DIFile *F = Info.TheCU->getFile())
609 ScopeToPathOpStringReg[F] = PathReg;
610 }
611 }
612
613 for (const DIBasicType *BT : BasicTypes)
614 emitOpStringIfNew(BT->getName(), MAI);
615
616 for (const DISubprogram *SP : SubprogramDeclarations) {
617 emitOpStringIfNew(SP->getName(), MAI);
618 emitOpStringIfNew(SP->getLinkageName(), MAI);
619 ScopeToPathOpStringReg[SP] = emitOpStringIfNew(getDebugFullPath(SP), MAI);
620 }
621
622#ifndef NDEBUG
623 NonSemanticOpStringsSectionEmitted = true;
624#endif
625}
626
629 if (GlobalDIEmitted || CompileUnits.empty())
630 return;
631 GlobalDIEmitted = true;
632
633 // Retrieve the ext inst set register allocated by prepareModuleOutput().
634 constexpr unsigned NSSet = static_cast<unsigned>(
635 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100);
636 MCRegister ExtInstSetReg = MAI.getExtInstSetReg(NSSet);
637 if (!ExtInstSetReg.isValid())
638 return; // Extension not available.
639
640#ifndef NDEBUG
641 assert(NonSemanticOpStringsSectionEmitted &&
642 "emitNonSemanticDebugStrings() must run before "
643 "emitNonSemanticGlobalDebugInfo()");
644#endif
645
646 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
647 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
648
649 CachedDebugInfoNoneReg = emitExtInst(SPIRV::NonSemanticExtInst::DebugInfoNone,
650 VoidTypeReg, ExtInstSetReg, {}, MAI);
651
652 // Emit integer constants shared across all NSDI instructions. The constant
653 // cache ensures each value is emitted at most once even when referenced from
654 // multiple instructions. All constants are pre-emitted before any DebugSource
655 // so that the output order is: constants, then
656 // DebugSource+DebugCompilationUnit pairs. This keeps OpConstant instructions
657 // grouped before the OpExtInst instructions.
658
659 // The Version operand of DebugCompilationUnit is the version of the
660 // NonSemantic.Shader.DebugInfo instruction set, which is 100 for
661 // "NonSemantic.Shader.DebugInfo.100" (NonSemanticShaderDebugInfo100Version).
662 MCRegister DebugInfoVersionReg = emitOpConstantI32(100, I32TypeReg, MAI);
663 MCRegister DwarfVersionReg =
664 emitOpConstantI32(static_cast<uint32_t>(DwarfVersion), I32TypeReg, MAI);
665
666 // Pre-emit source language constants for all compile units before entering
667 // the DebugSource loop.
668 SmallVector<MCRegister> SrcLangRegs =
669 map_to_vector(CompileUnits, [&](const CompileUnitInfo &Info) {
670 return emitOpConstantI32(Info.SpirvSourceLanguage, I32TypeReg, MAI);
671 });
672
673 // Emit DebugSource and DebugCompilationUnit for each compile unit.
674 for (auto [Info, SrcLangReg] : llvm::zip(CompileUnits, SrcLangRegs)) {
675 MCRegister FileStrReg = ScopeToPathOpStringReg.lookup(Info.TheCU);
676 assert(FileStrReg.isValid() &&
677 "CU path OpString must be emitted in emitNonSemanticDebugStrings");
678 MCRegister DebugSourceReg = getOrEmitDebugSourceForFileStrReg(
679 FileStrReg, VoidTypeReg, ExtInstSetReg, MAI);
680 MCRegister CUDbgReg = emitExtInst(
681 SPIRV::NonSemanticExtInst::DebugCompilationUnit, VoidTypeReg,
682 ExtInstSetReg,
683 {DebugInfoVersionReg, DwarfVersionReg, DebugSourceReg, SrcLangReg},
684 MAI);
685 if (Info.TheCU)
686 CUToCompilationUnitDbgReg[Info.TheCU] = CUDbgReg;
687 }
688
689 // Zero constant used as the Flags operand in DebugTypeBasic and
690 // DebugTypePointer. Cached with other i32 constants.
691 MCRegister I32ZeroReg = emitOpConstantI32(0, I32TypeReg, MAI);
692
693 DebugTypeRegs.clear();
694
695 for (const DIBasicType *BT : BasicTypes) {
696 MCRegister NameReg = getCachedOpStringReg(BT->getName());
697 MCRegister SizeReg = emitOpConstantI32(
698 static_cast<uint32_t>(BT->getSizeInBits()), I32TypeReg, MAI);
699
700 // Map DWARF base type encodings to NSDI encoding codes per
701 // NonSemantic.Shader.DebugInfo.100 specification, section 4.5.
702 unsigned Encoding = 0; // Unspecified
703 switch (BT->getEncoding()) {
704 case dwarf::DW_ATE_address:
705 Encoding = 1;
706 break;
707 case dwarf::DW_ATE_boolean:
708 Encoding = 2;
709 break;
710 case dwarf::DW_ATE_float:
711 Encoding = 3;
712 break;
713 case dwarf::DW_ATE_signed:
714 Encoding = 4;
715 break;
716 case dwarf::DW_ATE_signed_char:
717 Encoding = 5;
718 break;
719 case dwarf::DW_ATE_unsigned:
720 Encoding = 6;
721 break;
722 case dwarf::DW_ATE_unsigned_char:
723 Encoding = 7;
724 break;
725 }
726 MCRegister EncodingReg = emitOpConstantI32(Encoding, I32TypeReg, MAI);
727
728 MCRegister BTReg = emitExtInst(
729 SPIRV::NonSemanticExtInst::DebugTypeBasic, VoidTypeReg, ExtInstSetReg,
730 {NameReg, SizeReg, EncodingReg, I32ZeroReg}, MAI);
731 DebugTypeRegs[BT] = BTReg;
732 }
733
734 // Emit DebugTypeVector for each collected vector type.
735 for (const DICompositeType *VT : VectorTypes) {
736 if (auto VecReg = emitDebugTypeVector(VT, ExtInstSetReg, MAI))
737 DebugTypeRegs[VT] = *VecReg;
738 }
739
740 // Emit DebugTypePointer for each referenced pointer type.
741 for (const DIDerivedType *PT : PointerTypes) {
742 if (auto PtrReg = emitDebugTypePointer(PT, ExtInstSetReg, MAI))
743 DebugTypeRegs[PT] = *PtrReg;
744 }
745
746 // Emit DebugTypeFunction for each distinct DISubroutineType.
747 for (const DISubroutineType *ST : SubroutineTypes) {
748 if (auto FnTyReg =
749 emitDebugTypeFunctionForSubroutineType(ST, ExtInstSetReg, MAI))
750 DebugTypeRegs[ST] = *FnTyReg;
751 }
752
753 // Emit DebugFunctionDeclaration for DISubprogram declarations.
754 for (const DISubprogram *SP : SubprogramDeclarations) {
755 if (auto DeclReg = emitDebugFunctionDeclaration(SP, VoidTypeReg, I32TypeReg,
756 ExtInstSetReg, MAI))
757 DebugFunctionDeclarationRegs[SP] = *DeclReg;
758 }
759}
760
762SPIRVNonSemanticDebugHandler::getDebugFullPath(const DIScope *Scope) const {
764 if (!Scope)
765 return Out;
766 StringRef Filename = Scope->getFilename();
767 const auto Style = sys::path::Style::native;
769 Out.assign(Filename.begin(), Filename.end());
770 else {
771 StringRef Dir = Scope->getDirectory();
772 Out.assign(Dir.begin(), Dir.end());
773 sys::path::append(Out, Style, Filename);
774 }
775 return Out;
776}
777
778MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugSourceForFileStrReg(
779 MCRegister FileStrReg, MCRegister VoidTypeReg, MCRegister ExtInstSetReg,
781 const unsigned Key = FileStrReg.id();
782 auto It = DebugSourceRegByFileStr.find(Key);
783 if (It != DebugSourceRegByFileStr.end())
784 return It->second;
785
786 MCRegister DS = emitExtInst(SPIRV::NonSemanticExtInst::DebugSource,
787 VoidTypeReg, ExtInstSetReg, {FileStrReg}, MAI);
788 DebugSourceRegByFileStr[Key] = DS;
789 return DS;
790}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
BitTracker BT
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains constants used for implementing Dwarf debug support.
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
static constexpr StringLiteral Filename
This file defines less commonly used SmallVector utilities.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
This class is intended to be used as a driving class for all asm writers.
Definition AsmPrinter.h:91
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition AsmPrinter.h:106
const MCSubtargetInfo & getSubtargetInfo() const
Return information about subtarget.
Basic type, like 'int' or 'float'.
DINodeArray getElements() const
DIType * getBaseType() const
Tagged DWARF-like metadata node.
LLVM_ABI dwarf::Tag getTag() const
DIFlags
Debug info flags.
Base class for scope-like contexts.
Subprogram description. Uses SubclassData1.
Type array for a subprogram.
Base class for types.
AsmPrinter * Asm
Target of debug info emission.
void beginModule(Module *M) override
Utility to find all debug info in a module.
Definition DebugInfo.h:105
LLVM_ABI void processModule(const Module &M)
Process entire module and collect debug info anchors.
iterator_range< subprogram_iterator > subprograms() const
Definition DebugInfo.h:152
iterator_range< type_iterator > types() const
Definition DebugInfo.h:158
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
void addOperand(const MCOperand Op)
Definition MCInst.h:215
void setOpcode(unsigned Op)
Definition MCInst.h:201
static MCOperand createReg(MCRegister Reg)
Definition MCInst.h:138
static MCOperand createImm(int64_t Val)
Definition MCInst.h:145
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
constexpr bool isValid() const
Definition MCRegister.h:84
constexpr unsigned id() const
Definition MCRegister.h:82
Tracking metadata reference owned by Metadata.
Definition Metadata.h:891
bool equalsStr(StringRef Str) const
Definition Metadata.h:913
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
A tuple of MDNodes.
Definition Metadata.h:1749
void emitNonSemanticDebugStrings(SPIRV::ModuleAnalysisInfo &MAI)
Emit OpString instructions for all NSDI file paths and basic type names into the debug section (secti...
void beginModule(Module *M) override
Collect compile-unit metadata from the module.
void emitNonSemanticGlobalDebugInfo(SPIRV::ModuleAnalysisInfo &MAI)
Emit module-scope NSDI instructions (DebugSource, DebugCompilationUnit, DebugTypeBasic,...
void prepareModuleOutput(const SPIRVSubtarget &ST, SPIRV::ModuleAnalysisInfo &MAI)
Add SPV_KHR_non_semantic_info extension and NonSemantic.Shader.DebugInfo.100 ext inst set entry to MA...
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
void assign(StringRef RHS)
Assign from a StringRef.
Definition SmallString.h:51
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
iterator begin() const
Definition StringRef.h:114
iterator end() const
Definition StringRef.h:116
LLVM Value Representation.
Definition Value.h:75
LLVM_ABI bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
Definition Path.cpp:688
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition Path.cpp:467
This is an optimization pass for GlobalISel generic memory operations.
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
Definition STLExtras.h:830
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1732
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
auto map_to_vector(ContainerTy &&C, FuncTy &&F)
Map a range to a SmallVector with element types deduced from the mapping.
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
Definition Casting.h:732
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
void addStringImm(const StringRef &Str, MCInst &Inst)
MCRegister getExtInstSetReg(unsigned SetNum)
DenseMap< unsigned, MCRegister > ExtInstSetMap
InstrList & getMSInstrs(unsigned MSType)
MCRegister getRegisterAlias(const MachineFunction *MF, Register Reg)
void addExtension(Extension::Extension ToAdd)