Skip to content

Commit

Permalink
[SPIR-V] Emit DebugTypeBasic for NonSemantic DI (#106980)
Browse files Browse the repository at this point in the history
The commit introduces support for fundamental DI instruction. Metadata
handlers required for this instruction is stored inside debug records
(https://llvm.org/docs/SourceLevelDebugging.html) parts of the module
which rises the necessity of it's traversal.
  • Loading branch information
bwlodarcz authored Sep 17, 2024
1 parent 48498ec commit f99bb02
Show file tree
Hide file tree
Showing 4 changed files with 350 additions and 35 deletions.
147 changes: 114 additions & 33 deletions llvm/lib/Target/SPIRV/SPIRVEmitNonSemanticDI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
#include "SPIRVGlobalRegistry.h"
#include "SPIRVRegisterInfo.h"
#include "SPIRVTargetMachine.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
Expand All @@ -13,7 +15,10 @@
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Register.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugProgramInstruction.h"
#include "llvm/IR/Metadata.h"
#include "llvm/PassRegistry.h"
#include "llvm/Support/Casting.h"
Expand Down Expand Up @@ -57,6 +62,17 @@ SPIRVEmitNonSemanticDI::SPIRVEmitNonSemanticDI() : MachineFunctionPass(ID) {
initializeSPIRVEmitNonSemanticDIPass(*PassRegistry::getPassRegistry());
}

enum BaseTypeAttributeEncoding {
Unspecified = 0,
Address = 1,
Boolean = 2,
Float = 3,
Signed = 4,
SignedChar = 5,
Unsigned = 6,
UnsignedChar = 7
};

bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {
// If this MachineFunction doesn't have any BB repeat procedure
// for the next
Expand All @@ -71,7 +87,7 @@ bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {
unsigned SourceLanguage = 0;
int64_t DwarfVersion = 0;
int64_t DebugInfoVersion = 0;

SmallPtrSet<DIBasicType *, 12> BasicTypes;
// Searching through the Module metadata to find nescessary
// information like DwarfVersion or SourceLanguage
{
Expand Down Expand Up @@ -104,6 +120,21 @@ bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {
cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
->getSExtValue();
}

// This traversal is the only supported way to access
// instruction related DI metadata like DIBasicType
for (auto &F : *M) {
for (auto &BB : F) {
for (auto &I : BB) {
for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {
DILocalVariable *LocalVariable = DVR.getVariable();
if (auto *BasicType =
dyn_cast<DIBasicType>(LocalVariable->getType()))
BasicTypes.insert(BasicType);
}
}
}
}
}
// NonSemantic.Shader.DebugInfo.100 global DI instruction emitting
{
Expand All @@ -120,29 +151,45 @@ bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {
// and before first terminator
MachineIRBuilder MIRBuilder(MBB, MBB.getFirstTerminator());

const auto EmitOpString = [&](StringRef SR) {
const Register StrReg = MRI.createVirtualRegister(&SPIRV::IDRegClass);
MRI.setType(StrReg, LLT::scalar(32));
MachineInstrBuilder MIB = MIRBuilder.buildInstr(SPIRV::OpString);
MIB.addDef(StrReg);
addStringImm(SR, MIB);
return StrReg;
};

// Emit OpString with FilePath which is required by DebugSource
const Register StrReg = MRI.createVirtualRegister(&SPIRV::IDRegClass);
MRI.setType(StrReg, LLT::scalar(32));
MachineInstrBuilder MIB = MIRBuilder.buildInstr(SPIRV::OpString);
MIB.addDef(StrReg);
addStringImm(FilePath, MIB);
const Register FilePathStrReg = EmitOpString(FilePath);

const SPIRVType *VoidTy =
GR->getOrCreateSPIRVType(Type::getVoidTy(*Context), MIRBuilder);

const auto EmitDIInstruction =
[&](SPIRV::NonSemanticExtInst::NonSemanticExtInst Inst,
std::initializer_list<Register> Registers) {
const Register InstReg =
MRI.createVirtualRegister(&SPIRV::IDRegClass);
MRI.setType(InstReg, LLT::scalar(32));
MachineInstrBuilder MIB =
MIRBuilder.buildInstr(SPIRV::OpExtInst)
.addDef(InstReg)
.addUse(GR->getSPIRVTypeID(VoidTy))
.addImm(static_cast<int64_t>(
SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100))
.addImm(Inst);
for (auto Reg : Registers) {
MIB.addUse(Reg);
}
MIB.constrainAllUses(*TII, *TRI, *RBI);
GR->assignSPIRVTypeToVReg(VoidTy, InstReg, MF);
return InstReg;
};

// Emit DebugSource which is required by DebugCompilationUnit
const Register DebugSourceResIdReg =
MRI.createVirtualRegister(&SPIRV::IDRegClass);
MRI.setType(DebugSourceResIdReg, LLT::scalar(32));
MIB = MIRBuilder.buildInstr(SPIRV::OpExtInst)
.addDef(DebugSourceResIdReg)
.addUse(GR->getSPIRVTypeID(VoidTy))
.addImm(static_cast<int64_t>(
SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100))
.addImm(SPIRV::NonSemanticExtInst::DebugSource)
.addUse(StrReg);
MIB.constrainAllUses(*TII, *TRI, *RBI);
GR->assignSPIRVTypeToVReg(VoidTy, DebugSourceResIdReg, MF);
const Register DebugSourceResIdReg = EmitDIInstruction(
SPIRV::NonSemanticExtInst::DebugSource, {FilePathStrReg});

const SPIRVType *I32Ty =
GR->getOrCreateSPIRVType(Type::getInt32Ty(*Context), MIRBuilder);
Expand All @@ -156,22 +203,56 @@ bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {
const Register SourceLanguageReg =
GR->buildConstantInt(SourceLanguage, MIRBuilder, I32Ty, false);

// Emit DebugCompilationUnit
[[maybe_unused]]
const Register DebugCompUnitResIdReg =
MRI.createVirtualRegister(&SPIRV::IDRegClass);
MRI.setType(DebugCompUnitResIdReg, LLT::scalar(32));
MIB = MIRBuilder.buildInstr(SPIRV::OpExtInst)
.addDef(DebugCompUnitResIdReg)
.addUse(GR->getSPIRVTypeID(VoidTy))
.addImm(static_cast<int64_t>(
SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100))
.addImm(SPIRV::NonSemanticExtInst::DebugCompilationUnit)
.addUse(DebugInfoVersionReg)
.addUse(DwarfVersionReg)
.addUse(DebugSourceResIdReg)
.addUse(SourceLanguageReg);
MIB.constrainAllUses(*TII, *TRI, *RBI);
GR->assignSPIRVTypeToVReg(VoidTy, DebugCompUnitResIdReg, MF);
EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugCompilationUnit,
{DebugInfoVersionReg, DwarfVersionReg,
DebugSourceResIdReg, SourceLanguageReg});

// We aren't extracting any DebugInfoFlags now so we
// emitting zero to use as <id>Flags argument for DebugBasicType
const Register I32ZeroReg =
GR->buildConstantInt(0, MIRBuilder, I32Ty, false);

for (auto *BasicType : BasicTypes) {
const Register BasicTypeStrReg = EmitOpString(BasicType->getName());

const Register ConstIntBitwidthReg = GR->buildConstantInt(
BasicType->getSizeInBits(), MIRBuilder, I32Ty, false);

uint64_t AttributeEncoding = BaseTypeAttributeEncoding::Unspecified;
switch (BasicType->getEncoding()) {
case dwarf::DW_ATE_signed:
AttributeEncoding = BaseTypeAttributeEncoding::Signed;
break;
case dwarf::DW_ATE_unsigned:
AttributeEncoding = BaseTypeAttributeEncoding::Unsigned;
break;
case dwarf::DW_ATE_unsigned_char:
AttributeEncoding = BaseTypeAttributeEncoding::UnsignedChar;
break;
case dwarf::DW_ATE_signed_char:
AttributeEncoding = BaseTypeAttributeEncoding::SignedChar;
break;
case dwarf::DW_ATE_float:
AttributeEncoding = BaseTypeAttributeEncoding::Float;
break;
case dwarf::DW_ATE_boolean:
AttributeEncoding = BaseTypeAttributeEncoding::Boolean;
break;
case dwarf::DW_ATE_address:
AttributeEncoding = BaseTypeAttributeEncoding::Address;
}

const Register AttributeEncodingReg =
GR->buildConstantInt(AttributeEncoding, MIRBuilder, I32Ty, false);

[[maybe_unused]]
const Register BasicTypeReg =
EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugTypeBasic,
{BasicTypeStrReg, ConstIntBitwidthReg,
AttributeEncodingReg, I32ZeroReg});
}
}
return true;
}
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,8 @@ void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) {
MachineOperand Ins = MI.getOperand(3);
namespace NS = SPIRV::NonSemanticExtInst;
static constexpr int64_t GlobalNonSemanticDITy[] = {
NS::DebugSource, NS::DebugCompilationUnit};
NS::DebugSource, NS::DebugCompilationUnit, NS::DebugInfoNone,
NS::DebugTypeBasic};
bool IsGlobalDI = false;
for (unsigned Idx = 0; Idx < std::size(GlobalNonSemanticDITy); ++Idx)
IsGlobalDI |= Ins.getImm() == GlobalNonSemanticDITy[Idx];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
; RUN: llc --verify-machineinstrs --spv-emit-nonsemantic-debug-info --spirv-ext=+SPV_KHR_non_semantic_info --print-after=spirv-nonsemantic-debug-info -O0 -mtriple=spirv64-unknown-unknown %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-MIR
; RUN: llc --verify-machineinstrs --spv-emit-nonsemantic-debug-info --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
; RUN: llc --verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_non_semantic_info %s -o - | FileCheck %s --check-prefix=CHECK-OPTION
; RUN: %if spirv-tools %{ llc --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; RUN: %if spirv-tools %{ llc --verify-machineinstrs --spv-emit-nonsemantic-debug-info --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}

; CHECK-MIR-DAG: [[type_void:%[0-9]+\:type]] = OpTypeVoid
; CHECK-MIR-DAG: [[type_i64:%[0-9]+\:type\(s64\)]] = OpTypeInt 32, 0
Expand Down
Loading

0 comments on commit f99bb02

Please sign in to comment.