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