LLVM 22.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"
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;
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
53 return new SPIRVEmitNonSemanticDI(TM);
54}
55
66
69 ESSL = 1,
70 GLSL = 2,
73 HLSL = 5,
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;
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 assert(ModuleFlags && "Expected llvm.module.flags metadata to be present");
120 for (const auto *Op : ModuleFlags->operands()) {
121 const MDOperand &MaybeStrOp = Op->getOperand(1);
122 if (MaybeStrOp.equalsStr("Dwarf Version"))
123 DwarfVersion =
125 cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
126 ->getSExtValue();
127 else if (MaybeStrOp.equalsStr("Debug Info Version"))
128 DebugInfoVersion =
130 cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
131 ->getSExtValue();
132 }
133
134 // This traversal is the only supported way to access
135 // instruction related DI metadata like DIBasicType
136 for (auto &F : *M) {
137 for (auto &BB : F) {
138 for (auto &I : BB) {
139 for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {
140 DILocalVariable *LocalVariable = DVR.getVariable();
141 if (auto *BasicType =
142 dyn_cast<DIBasicType>(LocalVariable->getType())) {
143 BasicTypes.insert(BasicType);
144 } else if (auto *DerivedType =
145 dyn_cast<DIDerivedType>(LocalVariable->getType())) {
146 if (DerivedType->getTag() == dwarf::DW_TAG_pointer_type) {
147 PointerDerivedTypes.insert(DerivedType);
148 // DIBasicType can be unreachable from DbgRecord and only
149 // pointed on from other DI types
150 // DerivedType->getBaseType is null when pointer
151 // is representing a void type
153 DerivedType->getBaseType()))
154 BasicTypes.insert(BT);
155 }
156 }
157 }
158 }
159 }
160 }
161 }
162 // NonSemantic.Shader.DebugInfo.100 global DI instruction emitting
163 {
164 // Required LLVM variables for emitting logic
165 const SPIRVInstrInfo *TII = TM->getSubtargetImpl()->getInstrInfo();
166 const SPIRVRegisterInfo *TRI = TM->getSubtargetImpl()->getRegisterInfo();
167 const RegisterBankInfo *RBI = TM->getSubtargetImpl()->getRegBankInfo();
168 SPIRVGlobalRegistry *GR = TM->getSubtargetImpl()->getSPIRVGlobalRegistry();
169 MachineRegisterInfo &MRI = MF.getRegInfo();
170 MachineBasicBlock &MBB = *MF.begin();
171
172 // To correct placement of a OpLabel instruction during SPIRVAsmPrinter
173 // emission all new instructions needs to be placed after OpFunction
174 // and before first terminator
175 MachineIRBuilder MIRBuilder(MBB, MBB.getFirstTerminator());
176
177 const auto EmitOpString = [&](StringRef SR) {
178 const Register StrReg = MRI.createVirtualRegister(&SPIRV::IDRegClass);
179 MRI.setType(StrReg, LLT::scalar(32));
180 MachineInstrBuilder MIB = MIRBuilder.buildInstr(SPIRV::OpString);
181 MIB.addDef(StrReg);
182 addStringImm(SR, MIB);
183 return StrReg;
184 };
185
186 const SPIRVType *VoidTy =
187 GR->getOrCreateSPIRVType(Type::getVoidTy(*Context), MIRBuilder,
188 SPIRV::AccessQualifier::ReadWrite, false);
189
190 const auto EmitDIInstruction =
191 [&](SPIRV::NonSemanticExtInst::NonSemanticExtInst Inst,
192 std::initializer_list<Register> Registers) {
193 const Register InstReg =
194 MRI.createVirtualRegister(&SPIRV::IDRegClass);
195 MRI.setType(InstReg, LLT::scalar(32));
196 MachineInstrBuilder MIB =
197 MIRBuilder.buildInstr(SPIRV::OpExtInst)
198 .addDef(InstReg)
199 .addUse(GR->getSPIRVTypeID(VoidTy))
200 .addImm(static_cast<int64_t>(
201 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100))
202 .addImm(Inst);
203 for (auto Reg : Registers) {
204 MIB.addUse(Reg);
205 }
206 MIB.constrainAllUses(*TII, *TRI, *RBI);
207 GR->assignSPIRVTypeToVReg(VoidTy, InstReg, MF);
208 return InstReg;
209 };
210
211 const SPIRVType *I32Ty =
212 GR->getOrCreateSPIRVType(Type::getInt32Ty(*Context), MIRBuilder,
213 SPIRV::AccessQualifier::ReadWrite, false);
214
215 const Register DwarfVersionReg =
216 GR->buildConstantInt(DwarfVersion, MIRBuilder, I32Ty, false);
217
218 const Register DebugInfoVersionReg =
219 GR->buildConstantInt(DebugInfoVersion, MIRBuilder, I32Ty, false);
220
221 for (unsigned Idx = 0; Idx < LLVMSourceLanguages.size(); ++Idx) {
222 const Register FilePathStrReg = EmitOpString(FilePaths[Idx]);
223
224 const Register DebugSourceResIdReg = EmitDIInstruction(
225 SPIRV::NonSemanticExtInst::DebugSource, {FilePathStrReg});
226
227 SourceLanguage SpirvSourceLanguage = SourceLanguage::Unknown;
228 switch (LLVMSourceLanguages[Idx]) {
229 case dwarf::DW_LANG_OpenCL:
230 SpirvSourceLanguage = SourceLanguage::OpenCL_C;
231 break;
232 case dwarf::DW_LANG_OpenCL_CPP:
233 SpirvSourceLanguage = SourceLanguage::OpenCL_CPP;
234 break;
235 case dwarf::DW_LANG_CPP_for_OpenCL:
236 SpirvSourceLanguage = SourceLanguage::CPP_for_OpenCL;
237 break;
238 case dwarf::DW_LANG_GLSL:
239 SpirvSourceLanguage = SourceLanguage::GLSL;
240 break;
241 case dwarf::DW_LANG_HLSL:
242 SpirvSourceLanguage = SourceLanguage::HLSL;
243 break;
244 case dwarf::DW_LANG_SYCL:
245 SpirvSourceLanguage = SourceLanguage::SYCL;
246 break;
247 case dwarf::DW_LANG_Zig:
248 SpirvSourceLanguage = SourceLanguage::Zig;
249 }
250
251 const Register SourceLanguageReg =
252 GR->buildConstantInt(SpirvSourceLanguage, MIRBuilder, I32Ty, false);
253
254 [[maybe_unused]]
255 const Register DebugCompUnitResIdReg =
256 EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugCompilationUnit,
257 {DebugInfoVersionReg, DwarfVersionReg,
258 DebugSourceResIdReg, SourceLanguageReg});
259 }
260
261 // We aren't extracting any DebugInfoFlags now so we
262 // emitting zero to use as <id>Flags argument for DebugBasicType
263 const Register I32ZeroReg =
264 GR->buildConstantInt(0, MIRBuilder, I32Ty, false, false);
265
266 // We need to store pairs because further instructions reference
267 // the DIBasicTypes and size will be always small so there isn't
268 // need for any kind of map
270 BasicTypeRegPairs;
271 for (auto *BasicType : BasicTypes) {
272 const Register BasicTypeStrReg = EmitOpString(BasicType->getName());
273
274 const Register ConstIntBitwidthReg = GR->buildConstantInt(
275 BasicType->getSizeInBits(), MIRBuilder, I32Ty, false);
276
277 uint64_t AttributeEncoding = BaseTypeAttributeEncoding::Unspecified;
278 switch (BasicType->getEncoding()) {
279 case dwarf::DW_ATE_signed:
280 AttributeEncoding = BaseTypeAttributeEncoding::Signed;
281 break;
282 case dwarf::DW_ATE_unsigned:
283 AttributeEncoding = BaseTypeAttributeEncoding::Unsigned;
284 break;
285 case dwarf::DW_ATE_unsigned_char:
286 AttributeEncoding = BaseTypeAttributeEncoding::UnsignedChar;
287 break;
288 case dwarf::DW_ATE_signed_char:
289 AttributeEncoding = BaseTypeAttributeEncoding::SignedChar;
290 break;
291 case dwarf::DW_ATE_float:
292 AttributeEncoding = BaseTypeAttributeEncoding::Float;
293 break;
294 case dwarf::DW_ATE_boolean:
295 AttributeEncoding = BaseTypeAttributeEncoding::Boolean;
296 break;
297 case dwarf::DW_ATE_address:
298 AttributeEncoding = BaseTypeAttributeEncoding::Address;
299 }
300
301 const Register AttributeEncodingReg =
302 GR->buildConstantInt(AttributeEncoding, MIRBuilder, I32Ty, false);
303
304 const Register BasicTypeReg =
305 EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugTypeBasic,
306 {BasicTypeStrReg, ConstIntBitwidthReg,
307 AttributeEncodingReg, I32ZeroReg});
308 BasicTypeRegPairs.emplace_back(BasicType, BasicTypeReg);
309 }
310
311 if (PointerDerivedTypes.size()) {
312 for (const auto *PointerDerivedType : PointerDerivedTypes) {
313
314 assert(PointerDerivedType->getDWARFAddressSpace().has_value());
315 const Register StorageClassReg = GR->buildConstantInt(
317 PointerDerivedType->getDWARFAddressSpace().value(),
318 *TM->getSubtargetImpl()),
319 MIRBuilder, I32Ty, false);
320
321 // If the Pointer is representing a void type it's getBaseType
322 // is a nullptr
323 const auto *MaybeNestedBasicType =
324 dyn_cast_or_null<DIBasicType>(PointerDerivedType->getBaseType());
325 if (MaybeNestedBasicType) {
326 for (const auto &BasicTypeRegPair : BasicTypeRegPairs) {
327 const auto &[DefinedBasicType, BasicTypeReg] = BasicTypeRegPair;
328 if (DefinedBasicType == MaybeNestedBasicType) {
329 [[maybe_unused]]
330 const Register DebugPointerTypeReg = EmitDIInstruction(
331 SPIRV::NonSemanticExtInst::DebugTypePointer,
332 {BasicTypeReg, StorageClassReg, I32ZeroReg});
333 }
334 }
335 } else {
336 const Register DebugInfoNoneReg =
337 EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugInfoNone, {});
338 [[maybe_unused]]
339 const Register DebugPointerTypeReg = EmitDIInstruction(
340 SPIRV::NonSemanticExtInst::DebugTypePointer,
341 {DebugInfoNoneReg, StorageClassReg, I32ZeroReg});
342 }
343 }
344 }
345 }
346 return true;
347}
348
349bool SPIRVEmitNonSemanticDI::runOnMachineFunction(MachineFunction &MF) {
350 bool Res = false;
351 // emitGlobalDI needs to be executed only once to avoid
352 // emitting duplicates
353 if (!IsGlobalDIEmitted) {
354 IsGlobalDIEmitted = true;
355 Res = emitGlobalDI(MF);
356 }
357 return Res;
358}
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
BitTracker BT
This file contains constants used for implementing Dwarf debug support.
#define DEBUG_TYPE
const HexagonInstrInfo * TII
#define F(x, y, z)
Definition MD5.cpp:55
#define I(x, y, z)
Definition MD5.cpp:58
Machine Check Debug Module
This file declares the MachineIRBuilder class.
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
This file contains the declarations for metadata subclasses.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
SI Pre allocate WWM Registers
BaseTypeAttributeEncoding
This file defines the SmallPtrSet class.
This file defines the SmallString class.
DIType * getType() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
bool equalsStr(StringRef Str) const
Definition Metadata.h:921
LLVM_ABI 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.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
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.
const Module * getModule() const
iterator_range< op_iterator > operands()
Definition Metadata.h:1849
void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, const MachineFunction &MF)
SPIRVType * getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
Register getSPIRVTypeID(const SPIRVType *SpirvType) const
Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder, SPIRVType *SpvType, bool EmitIR, 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:99
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
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:456
This is an optimization pass for GlobalISel generic memory operations.
MachineFunctionPass * createSPIRVEmitNonSemanticDIPass(SPIRVTargetMachine *TM)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:649
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:759
const MachineInstr SPIRVType
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
unsigned char Boolean
Definition ConvertUTF.h:132
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:565
void addStringImm(const StringRef &Str, MCInst &Inst)
static auto filterDbgVars(iterator_range< simple_ilist< DbgRecord >::iterator > R)
Filter the DbgRecord range to DbgVariableRecord types only and downcast.