LLVM 20.0.0git
SPIRVEmitNonSemanticDI.cpp
Go to the documentation of this file.
3#include "SPIRV.h"
5#include "SPIRVRegisterInfo.h"
7#include "SPIRVUtils.h"
23#include "llvm/IR/Metadata.h"
24#include "llvm/PassRegistry.h"
26#include "llvm/Support/Path.h"
27
28#define DEBUG_TYPE "spirv-nonsemantic-debug-info"
29
30namespace llvm {
32 static char ID;
36
37 bool runOnMachineFunction(MachineFunction &MF) override;
38
39private:
40 bool IsGlobalDIEmitted = false;
41 bool emitGlobalDI(MachineFunction &MF);
42};
43} // namespace llvm
44
45using namespace llvm;
46
48 "SPIRV NonSemantic.Shader.DebugInfo.100 emitter", false, false)
49
51
54 return new SPIRVEmitNonSemanticDI(TM);
55}
56
58 : MachineFunctionPass(ID), TM(TM) {
60}
61
64}
65
70 Float = 3,
71 Signed = 4,
74 UnsignedChar = 7
75};
76
79 ESSL = 1,
80 GLSL = 2,
83 HLSL = 5,
85 SYCL = 7,
86 HERO_C = 8,
87 NZSL = 9,
88 WGSL = 10,
89 Slang = 11,
90 Zig = 12
91};
92
93bool 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;
104 SmallVector<int64_t> LLVMSourceLanguages;
105 int64_t DwarfVersion = 0;
106 int64_t DebugInfoVersion = 0;
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
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
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));
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
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(
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
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}
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock & MBB
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file contains constants used for implementing Dwarf debug support.
const HexagonInstrInfo * TII
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
This file declares the MachineIRBuilder class.
unsigned const TargetRegisterInfo * TRI
This file contains the declarations for metadata subclasses.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
SI Pre allocate WWM Registers
BaseTypeAttributeEncoding
#define DEBUG_TYPE
This file defines the SmallPtrSet class.
This file defines the SmallString class.
DIType * getType() const
This class represents an Operation in the Expression.
Record of a variable value-assignment, aka a non instruction representation of the dbg....
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
Definition: LowLevelType.h:42
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
Tracking metadata reference owned by Metadata.
Definition: Metadata.h:891
bool equalsStr(StringRef Str) const
Definition: Metadata.h:913
iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Helper class to build MachineInstr.
bool constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
Definition: MachineInstr.h:69
This class contains meta information specific to a module.
const Module * getModule() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
A tuple of MDNodes.
Definition: Metadata.h:1731
iterator_range< op_iterator > operands()
Definition: Metadata.h:1827
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Holds all the information related to register banks.
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, const MachineFunction &MF)
Register getSPIRVTypeID(const SPIRVType *SpirvType) const
SPIRVType * getOrCreateSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, SPIRV::AccessQualifier::AccessQualifier AQ=SPIRV::AccessQualifier::ReadWrite, bool EmitIR=true)
Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder, SPIRVType *SpvType, bool EmitIR=true, bool ZeroAsNull=true)
const SPIRVInstrInfo * getInstrInfo() const override
SPIRVGlobalRegistry * getSPIRVGlobalRegistry() const
const SPIRVRegisterInfo * getRegisterInfo() const override
const RegisterBankInfo * getRegBankInfo() const override
const SPIRVSubtarget * getSubtargetImpl() const
size_type size() const
Definition: SmallPtrSet.h:94
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Definition: SmallPtrSet.h:384
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:519
size_t size() const
Definition: SmallVector.h:78
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:937
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
static Type * getVoidTy(LLVMContext &C)
static IntegerType * getInt32Ty(LLVMContext &C)
Stores all information relating to a compile unit, be it in its original instance in the object file ...
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition: Path.cpp:456
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
MachineFunctionPass * createSPIRVEmitNonSemanticDIPass(SPIRVTargetMachine *TM)
unsigned char Boolean
Definition: ConvertUTF.h:131
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
Definition: SPIRVUtils.cpp:211
void initializeSPIRVEmitNonSemanticDIPass(PassRegistry &)
void addStringImm(const StringRef &Str, MCInst &Inst)
Definition: SPIRVUtils.cpp:54
static auto filterDbgVars(iterator_range< simple_ilist< DbgRecord >::iterator > R)
Filter the DbgRecord range to DbgVariableRecord types only and downcast.
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...