Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVEmitNonSemanticDI.cpp
213799 views
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;
35
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 *
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
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
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
359