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