1#include "MCTargetDesc/SPIRVBaseInfo.h"
2#include "MCTargetDesc/SPIRVMCTargetDesc.h"
3#include "SPIRV.h"
4#include "SPIRVGlobalRegistry.h"
5#include "SPIRVRegisterInfo.h"
6#include "SPIRVTargetMachine.h"
7#include "SPIRVUtils.h"
8#include "llvm/ADT/SetVector.h"
9#include "llvm/ADT/SmallString.h"
10#include "llvm/BinaryFormat/Dwarf.h"
11#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
12#include "llvm/CodeGen/MachineBasicBlock.h"
13#include "llvm/CodeGen/MachineFunction.h"
14#include "llvm/CodeGen/MachineFunctionPass.h"
15#include "llvm/CodeGen/MachineInstr.h"
16#include "llvm/CodeGen/MachineInstrBuilder.h"
17#include "llvm/CodeGen/MachineModuleInfo.h"
18#include "llvm/CodeGen/MachineOperand.h"
19#include "llvm/CodeGen/MachineRegisterInfo.h"
20#include "llvm/CodeGen/Register.h"
21#include "llvm/IR/DebugInfoMetadata.h"
22#include "llvm/IR/DebugProgramInstruction.h"
23#include "llvm/IR/Metadata.h"
24#include "llvm/Support/Casting.h"
25#include "llvm/Support/Path.h"
26
27#define DEBUG_TYPE "spirv-nonsemantic-debug-info"
28
29using namespace llvm;
30
31namespace {
32struct SPIRVEmitNonSemanticDI : public MachineFunctionPass {
33 static char ID;
34 SPIRVTargetMachine *TM;
35 SPIRVEmitNonSemanticDI(SPIRVTargetMachine *TM = nullptr)
36 : MachineFunctionPass(ID), TM(TM) {}
37
38 bool runOnMachineFunction(MachineFunction &MF) override;
39
40private:
41 bool IsGlobalDIEmitted = false;
42 bool emitGlobalDI(MachineFunction &MF);
43};
44} // anonymous namespace
45
46INITIALIZE_PASS(SPIRVEmitNonSemanticDI, DEBUG_TYPE,
47 "SPIRV NonSemantic.Shader.DebugInfo.100 emitter", false, false)
48
49char SPIRVEmitNonSemanticDI::ID = 0;
50
51MachineFunctionPass *
52llvm::createSPIRVEmitNonSemanticDIPass(SPIRVTargetMachine *TM) {
53 return new SPIRVEmitNonSemanticDI(TM);
54}
55
56enum BaseTypeAttributeEncoding {
57 Unspecified = 0,
58 Address = 1,
59 Boolean = 2,
60 Float = 3,
61 Signed = 4,
62 SignedChar = 5,
63 Unsigned = 6,
64 UnsignedChar = 7
65};
66
67enum SourceLanguage {
68 Unknown = 0,
69 ESSL = 1,
70 GLSL = 2,
71 OpenCL_C = 3,
72 OpenCL_CPP = 4,
73 HLSL = 5,
74 CPP_for_OpenCL = 6,
75 SYCL = 7,
76 HERO_C = 8,
77 NZSL = 9,
78 WGSL = 10,
79 Slang = 11,
80 Zig = 12
81};
82
83bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {
84 // If this MachineFunction doesn't have any BB repeat procedure
85 // for the next
86 if (MF.begin() == MF.end()) {
87 IsGlobalDIEmitted = false;
88 return false;
89 }
90
91 // Required variables to get from metadata search
92 LLVMContext *Context;
93 SmallVector<SmallString<128>> FilePaths;
94 SmallVector<int64_t> LLVMSourceLanguages;
95 int64_t DwarfVersion = 0;
96 int64_t DebugInfoVersion = 0;
97 SetVector<DIBasicType *> BasicTypes;
98 SetVector<DIDerivedType *> PointerDerivedTypes;
99 // Searching through the Module metadata to find nescessary
100 // information like DwarfVersion or SourceLanguage
101 {
102 const MachineModuleInfo &MMI =
103 getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
104 const Module *M = MMI.getModule();
105 Context = &M->getContext();
106 const NamedMDNode *DbgCu = M->getNamedMetadata(Name: "llvm.dbg.cu");
107 if (!DbgCu)
108 return false;
109 // NonSemantic.Shader.DebugInfo.100 requires SPV_KHR_non_semantic_info.
110 // Bail out if the extension is not available for this target. Targets that
111 // do not enable this extension by default should enable it explicitly with
112 // --spirv-ext=+SPV_KHR_non_semantic_info.
113 if (!TM->getSubtargetImpl()->canUseExtension(
114 E: SPIRV::Extension::SPV_KHR_non_semantic_info))
115 return false;
116 for (const auto *Op : DbgCu->operands()) {
117 if (const auto *CompileUnit = dyn_cast<DICompileUnit>(Val: Op)) {
118 DIFile *File = CompileUnit->getFile();
119 FilePaths.emplace_back();
120 sys::path::append(path&: FilePaths.back(), a: File->getDirectory(),
121 b: File->getFilename());
122 LLVMSourceLanguages.push_back(
123 Elt: CompileUnit->getSourceLanguage().getUnversionedName());
124 }
125 }
126 const NamedMDNode *ModuleFlags = M->getNamedMetadata(Name: "llvm.module.flags");
127 assert(ModuleFlags && "Expected llvm.module.flags metadata to be present");
128 for (const auto *Op : ModuleFlags->operands()) {
129 const MDOperand &MaybeStrOp = Op->getOperand(I: 1);
130 if (MaybeStrOp.equalsStr(Str: "Dwarf Version"))
131 DwarfVersion =
132 cast<ConstantInt>(
133 Val: cast<ConstantAsMetadata>(Val: Op->getOperand(I: 2))->getValue())
134 ->getSExtValue();
135 else if (MaybeStrOp.equalsStr(Str: "Debug Info Version"))
136 DebugInfoVersion =
137 cast<ConstantInt>(
138 Val: cast<ConstantAsMetadata>(Val: Op->getOperand(I: 2))->getValue())
139 ->getSExtValue();
140 }
141
142 // This traversal is the only supported way to access
143 // instruction related DI metadata like DIBasicType
144 for (auto &F : *M) {
145 for (auto &BB : F) {
146 for (auto &I : BB) {
147 for (DbgVariableRecord &DVR : filterDbgVars(R: I.getDbgRecordRange())) {
148 DILocalVariable *LocalVariable = DVR.getVariable();
149 if (auto *BasicType =
150 dyn_cast<DIBasicType>(Val: LocalVariable->getType())) {
151 BasicTypes.insert(X: BasicType);
152 } else if (auto *DerivedType =
153 dyn_cast<DIDerivedType>(Val: LocalVariable->getType())) {
154 if (DerivedType->getTag() == dwarf::DW_TAG_pointer_type) {
155 PointerDerivedTypes.insert(X: DerivedType);
156 // DIBasicType can be unreachable from DbgRecord and only
157 // pointed on from other DI types
158 // DerivedType->getBaseType is null when pointer
159 // is representing a void type
160 if (auto *BT = dyn_cast_or_null<DIBasicType>(
161 Val: DerivedType->getBaseType()))
162 BasicTypes.insert(X: BT);
163 }
164 }
165 }
166 }
167 }
168 }
169 }
170 // NonSemantic.Shader.DebugInfo.100 global DI instruction emitting
171 {
172 // Required LLVM variables for emitting logic
173 const SPIRVInstrInfo *TII = TM->getSubtargetImpl()->getInstrInfo();
174 const SPIRVRegisterInfo *TRI = TM->getSubtargetImpl()->getRegisterInfo();
175 const RegisterBankInfo *RBI = TM->getSubtargetImpl()->getRegBankInfo();
176 SPIRVGlobalRegistry *GR = TM->getSubtargetImpl()->getSPIRVGlobalRegistry();
177 MachineRegisterInfo &MRI = MF.getRegInfo();
178 MachineBasicBlock &MBB = *MF.begin();
179
180 // To correct placement of a OpLabel instruction during SPIRVAsmPrinter
181 // emission all new instructions needs to be placed after OpFunction
182 // and before first terminator
183 MachineIRBuilder MIRBuilder(MBB, MBB.getFirstTerminator());
184
185 const auto EmitOpString = [&](StringRef SR) {
186 const Register StrReg = MRI.createVirtualRegister(RegClass: &SPIRV::IDRegClass);
187 MRI.setType(VReg: StrReg, Ty: LLT::scalar(SizeInBits: 32));
188 MachineInstrBuilder MIB = MIRBuilder.buildInstr(Opcode: SPIRV::OpString);
189 MIB.addDef(RegNo: StrReg);
190 addStringImm(Str: SR, MIB);
191 return StrReg;
192 };
193
194 const SPIRVTypeInst VoidTy =
195 GR->getOrCreateSPIRVType(Type: Type::getVoidTy(C&: *Context), MIRBuilder,
196 AQ: SPIRV::AccessQualifier::ReadWrite, EmitIR: false);
197
198 const auto EmitDIInstruction =
199 [&](SPIRV::NonSemanticExtInst::NonSemanticExtInst Inst,
200 std::initializer_list<Register> Registers) {
201 const Register InstReg =
202 MRI.createVirtualRegister(RegClass: &SPIRV::IDRegClass);
203 MRI.setType(VReg: InstReg, Ty: LLT::scalar(SizeInBits: 32));
204 MachineInstrBuilder MIB =
205 MIRBuilder.buildInstr(Opcode: SPIRV::OpExtInst)
206 .addDef(RegNo: InstReg)
207 .addUse(RegNo: GR->getSPIRVTypeID(SpirvType: VoidTy))
208 .addImm(Val: static_cast<int64_t>(
209 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100))
210 .addImm(Val: Inst);
211 for (auto Reg : Registers) {
212 MIB.addUse(RegNo: Reg);
213 }
214 MIB.constrainAllUses(TII: *TII, TRI: *TRI, RBI: *RBI);
215 GR->assignSPIRVTypeToVReg(Type: VoidTy, VReg: InstReg, MF);
216 return InstReg;
217 };
218
219 const SPIRVTypeInst I32Ty =
220 GR->getOrCreateSPIRVType(Type: Type::getInt32Ty(C&: *Context), MIRBuilder,
221 AQ: SPIRV::AccessQualifier::ReadWrite, EmitIR: false);
222
223 const Register DwarfVersionReg =
224 GR->buildConstantInt(Val: DwarfVersion, MIRBuilder, SpvType: I32Ty, EmitIR: false);
225
226 const Register DebugInfoVersionReg =
227 GR->buildConstantInt(Val: DebugInfoVersion, MIRBuilder, SpvType: I32Ty, EmitIR: false);
228
229 for (unsigned Idx = 0; Idx < LLVMSourceLanguages.size(); ++Idx) {
230 const Register FilePathStrReg = EmitOpString(FilePaths[Idx]);
231
232 const Register DebugSourceResIdReg = EmitDIInstruction(
233 SPIRV::NonSemanticExtInst::DebugSource, {FilePathStrReg});
234
235 SourceLanguage SpirvSourceLanguage = SourceLanguage::Unknown;
236 switch (LLVMSourceLanguages[Idx]) {
237 case dwarf::DW_LANG_OpenCL:
238 SpirvSourceLanguage = SourceLanguage::OpenCL_C;
239 break;
240 case dwarf::DW_LANG_OpenCL_CPP:
241 SpirvSourceLanguage = SourceLanguage::OpenCL_CPP;
242 break;
243 case dwarf::DW_LANG_CPP_for_OpenCL:
244 SpirvSourceLanguage = SourceLanguage::CPP_for_OpenCL;
245 break;
246 case dwarf::DW_LANG_GLSL:
247 SpirvSourceLanguage = SourceLanguage::GLSL;
248 break;
249 case dwarf::DW_LANG_HLSL:
250 SpirvSourceLanguage = SourceLanguage::HLSL;
251 break;
252 case dwarf::DW_LANG_SYCL:
253 SpirvSourceLanguage = SourceLanguage::SYCL;
254 break;
255 case dwarf::DW_LANG_Zig:
256 SpirvSourceLanguage = SourceLanguage::Zig;
257 }
258
259 const Register SourceLanguageReg =
260 GR->buildConstantInt(Val: SpirvSourceLanguage, MIRBuilder, SpvType: I32Ty, EmitIR: false);
261
262 [[maybe_unused]]
263 const Register DebugCompUnitResIdReg =
264 EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugCompilationUnit,
265 {DebugInfoVersionReg, DwarfVersionReg,
266 DebugSourceResIdReg, SourceLanguageReg});
267 }
268
269 // We aren't extracting any DebugInfoFlags now so we
270 // emitting zero to use as <id>Flags argument for DebugBasicType
271 const Register I32ZeroReg =
272 GR->buildConstantInt(Val: 0, MIRBuilder, SpvType: I32Ty, EmitIR: false, ZeroAsNull: false);
273
274 // We need to store pairs because further instructions reference
275 // the DIBasicTypes and size will be always small so there isn't
276 // need for any kind of map
277 SmallVector<std::pair<const DIBasicType *const, const Register>, 12>
278 BasicTypeRegPairs;
279 for (auto *BasicType : BasicTypes) {
280 const Register BasicTypeStrReg = EmitOpString(BasicType->getName());
281
282 const Register ConstIntBitwidthReg = GR->buildConstantInt(
283 Val: BasicType->getSizeInBits(), MIRBuilder, SpvType: I32Ty, EmitIR: false);
284
285 uint64_t AttributeEncoding = BaseTypeAttributeEncoding::Unspecified;
286 switch (BasicType->getEncoding()) {
287 case dwarf::DW_ATE_signed:
288 AttributeEncoding = BaseTypeAttributeEncoding::Signed;
289 break;
290 case dwarf::DW_ATE_unsigned:
291 AttributeEncoding = BaseTypeAttributeEncoding::Unsigned;
292 break;
293 case dwarf::DW_ATE_unsigned_char:
294 AttributeEncoding = BaseTypeAttributeEncoding::UnsignedChar;
295 break;
296 case dwarf::DW_ATE_signed_char:
297 AttributeEncoding = BaseTypeAttributeEncoding::SignedChar;
298 break;
299 case dwarf::DW_ATE_float:
300 AttributeEncoding = BaseTypeAttributeEncoding::Float;
301 break;
302 case dwarf::DW_ATE_boolean:
303 AttributeEncoding = BaseTypeAttributeEncoding::Boolean;
304 break;
305 case dwarf::DW_ATE_address:
306 AttributeEncoding = BaseTypeAttributeEncoding::Address;
307 }
308
309 const Register AttributeEncodingReg =
310 GR->buildConstantInt(Val: AttributeEncoding, MIRBuilder, SpvType: I32Ty, EmitIR: false);
311
312 const Register BasicTypeReg =
313 EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugTypeBasic,
314 {BasicTypeStrReg, ConstIntBitwidthReg,
315 AttributeEncodingReg, I32ZeroReg});
316 BasicTypeRegPairs.emplace_back(Args&: BasicType, Args: BasicTypeReg);
317 }
318
319 if (PointerDerivedTypes.size()) {
320 for (const auto *PointerDerivedType : PointerDerivedTypes) {
321
322 assert(PointerDerivedType->getDWARFAddressSpace().has_value());
323 const Register StorageClassReg = GR->buildConstantInt(
324 Val: addressSpaceToStorageClass(
325 AddrSpace: PointerDerivedType->getDWARFAddressSpace().value(),
326 STI: *TM->getSubtargetImpl()),
327 MIRBuilder, SpvType: I32Ty, EmitIR: false);
328
329 // If the Pointer is representing a void type it's getBaseType
330 // is a nullptr
331 const auto *MaybeNestedBasicType =
332 dyn_cast_or_null<DIBasicType>(Val: PointerDerivedType->getBaseType());
333 if (MaybeNestedBasicType) {
334 for (const auto &BasicTypeRegPair : BasicTypeRegPairs) {
335 const auto &[DefinedBasicType, BasicTypeReg] = BasicTypeRegPair;
336 if (DefinedBasicType == MaybeNestedBasicType) {
337 [[maybe_unused]]
338 const Register DebugPointerTypeReg = EmitDIInstruction(
339 SPIRV::NonSemanticExtInst::DebugTypePointer,
340 {BasicTypeReg, StorageClassReg, I32ZeroReg});
341 }
342 }
343 } else {
344 const Register DebugInfoNoneReg =
345 EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugInfoNone, {});
346 [[maybe_unused]]
347 const Register DebugPointerTypeReg = EmitDIInstruction(
348 SPIRV::NonSemanticExtInst::DebugTypePointer,
349 {DebugInfoNoneReg, StorageClassReg, I32ZeroReg});
350 }
351 }
352 }
353 }
354 return true;
355}
356
357bool SPIRVEmitNonSemanticDI::runOnMachineFunction(MachineFunction &MF) {
358 bool Res = false;
359 // emitGlobalDI needs to be executed only once to avoid
360 // emitting duplicates
361 if (!IsGlobalDIEmitted) {
362 IsGlobalDIEmitted = true;
363 Res = emitGlobalDI(MF);
364 }
365 return Res;
366}
367