Path: blob/main/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVEmitNonSemanticDI.cpp
213799 views
#include "MCTargetDesc/SPIRVBaseInfo.h"1#include "MCTargetDesc/SPIRVMCTargetDesc.h"2#include "SPIRV.h"3#include "SPIRVGlobalRegistry.h"4#include "SPIRVRegisterInfo.h"5#include "SPIRVTargetMachine.h"6#include "SPIRVUtils.h"7#include "llvm/ADT/SmallPtrSet.h"8#include "llvm/ADT/SmallString.h"9#include "llvm/BinaryFormat/Dwarf.h"10#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"11#include "llvm/CodeGen/MachineBasicBlock.h"12#include "llvm/CodeGen/MachineFunction.h"13#include "llvm/CodeGen/MachineFunctionPass.h"14#include "llvm/CodeGen/MachineInstr.h"15#include "llvm/CodeGen/MachineInstrBuilder.h"16#include "llvm/CodeGen/MachineModuleInfo.h"17#include "llvm/CodeGen/MachineOperand.h"18#include "llvm/CodeGen/MachineRegisterInfo.h"19#include "llvm/CodeGen/Register.h"20#include "llvm/IR/DebugInfoMetadata.h"21#include "llvm/IR/DebugProgramInstruction.h"22#include "llvm/IR/Metadata.h"23#include "llvm/Support/Casting.h"24#include "llvm/Support/Path.h"2526#define DEBUG_TYPE "spirv-nonsemantic-debug-info"2728using namespace llvm;2930namespace {31struct SPIRVEmitNonSemanticDI : public MachineFunctionPass {32static char ID;33SPIRVTargetMachine *TM;34SPIRVEmitNonSemanticDI(SPIRVTargetMachine *TM = nullptr)35: MachineFunctionPass(ID), TM(TM) {}3637bool runOnMachineFunction(MachineFunction &MF) override;3839private:40bool IsGlobalDIEmitted = false;41bool emitGlobalDI(MachineFunction &MF);42};43} // anonymous namespace4445INITIALIZE_PASS(SPIRVEmitNonSemanticDI, DEBUG_TYPE,46"SPIRV NonSemantic.Shader.DebugInfo.100 emitter", false, false)4748char SPIRVEmitNonSemanticDI::ID = 0;4950MachineFunctionPass *51llvm::createSPIRVEmitNonSemanticDIPass(SPIRVTargetMachine *TM) {52return new SPIRVEmitNonSemanticDI(TM);53}5455enum BaseTypeAttributeEncoding {56Unspecified = 0,57Address = 1,58Boolean = 2,59Float = 3,60Signed = 4,61SignedChar = 5,62Unsigned = 6,63UnsignedChar = 764};6566enum SourceLanguage {67Unknown = 0,68ESSL = 1,69GLSL = 2,70OpenCL_C = 3,71OpenCL_CPP = 4,72HLSL = 5,73CPP_for_OpenCL = 6,74SYCL = 7,75HERO_C = 8,76NZSL = 9,77WGSL = 10,78Slang = 11,79Zig = 1280};8182bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {83// If this MachineFunction doesn't have any BB repeat procedure84// for the next85if (MF.begin() == MF.end()) {86IsGlobalDIEmitted = false;87return false;88}8990// Required variables to get from metadata search91LLVMContext *Context;92SmallVector<SmallString<128>> FilePaths;93SmallVector<int64_t> LLVMSourceLanguages;94int64_t DwarfVersion = 0;95int64_t DebugInfoVersion = 0;96SmallPtrSet<DIBasicType *, 12> BasicTypes;97SmallPtrSet<DIDerivedType *, 12> PointerDerivedTypes;98// Searching through the Module metadata to find nescessary99// information like DwarfVersion or SourceLanguage100{101const MachineModuleInfo &MMI =102getAnalysis<MachineModuleInfoWrapperPass>().getMMI();103const Module *M = MMI.getModule();104Context = &M->getContext();105const NamedMDNode *DbgCu = M->getNamedMetadata("llvm.dbg.cu");106if (!DbgCu)107return false;108for (const auto *Op : DbgCu->operands()) {109if (const auto *CompileUnit = dyn_cast<DICompileUnit>(Op)) {110DIFile *File = CompileUnit->getFile();111FilePaths.emplace_back();112sys::path::append(FilePaths.back(), File->getDirectory(),113File->getFilename());114LLVMSourceLanguages.push_back(CompileUnit->getSourceLanguage());115}116}117const NamedMDNode *ModuleFlags = M->getNamedMetadata("llvm.module.flags");118for (const auto *Op : ModuleFlags->operands()) {119const MDOperand &MaybeStrOp = Op->getOperand(1);120if (MaybeStrOp.equalsStr("Dwarf Version"))121DwarfVersion =122cast<ConstantInt>(123cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())124->getSExtValue();125else if (MaybeStrOp.equalsStr("Debug Info Version"))126DebugInfoVersion =127cast<ConstantInt>(128cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())129->getSExtValue();130}131132// This traversal is the only supported way to access133// instruction related DI metadata like DIBasicType134for (auto &F : *M) {135for (auto &BB : F) {136for (auto &I : BB) {137for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {138DILocalVariable *LocalVariable = DVR.getVariable();139if (auto *BasicType =140dyn_cast<DIBasicType>(LocalVariable->getType())) {141BasicTypes.insert(BasicType);142} else if (auto *DerivedType =143dyn_cast<DIDerivedType>(LocalVariable->getType())) {144if (DerivedType->getTag() == dwarf::DW_TAG_pointer_type) {145PointerDerivedTypes.insert(DerivedType);146// DIBasicType can be unreachable from DbgRecord and only147// pointed on from other DI types148// DerivedType->getBaseType is null when pointer149// is representing a void type150if (auto *BT = dyn_cast_or_null<DIBasicType>(151DerivedType->getBaseType()))152BasicTypes.insert(BT);153}154}155}156}157}158}159}160// NonSemantic.Shader.DebugInfo.100 global DI instruction emitting161{162// Required LLVM variables for emitting logic163const SPIRVInstrInfo *TII = TM->getSubtargetImpl()->getInstrInfo();164const SPIRVRegisterInfo *TRI = TM->getSubtargetImpl()->getRegisterInfo();165const RegisterBankInfo *RBI = TM->getSubtargetImpl()->getRegBankInfo();166SPIRVGlobalRegistry *GR = TM->getSubtargetImpl()->getSPIRVGlobalRegistry();167MachineRegisterInfo &MRI = MF.getRegInfo();168MachineBasicBlock &MBB = *MF.begin();169170// To correct placement of a OpLabel instruction during SPIRVAsmPrinter171// emission all new instructions needs to be placed after OpFunction172// and before first terminator173MachineIRBuilder MIRBuilder(MBB, MBB.getFirstTerminator());174175const auto EmitOpString = [&](StringRef SR) {176const Register StrReg = MRI.createVirtualRegister(&SPIRV::IDRegClass);177MRI.setType(StrReg, LLT::scalar(32));178MachineInstrBuilder MIB = MIRBuilder.buildInstr(SPIRV::OpString);179MIB.addDef(StrReg);180addStringImm(SR, MIB);181return StrReg;182};183184const SPIRVType *VoidTy =185GR->getOrCreateSPIRVType(Type::getVoidTy(*Context), MIRBuilder,186SPIRV::AccessQualifier::ReadWrite, false);187188const auto EmitDIInstruction =189[&](SPIRV::NonSemanticExtInst::NonSemanticExtInst Inst,190std::initializer_list<Register> Registers) {191const Register InstReg =192MRI.createVirtualRegister(&SPIRV::IDRegClass);193MRI.setType(InstReg, LLT::scalar(32));194MachineInstrBuilder MIB =195MIRBuilder.buildInstr(SPIRV::OpExtInst)196.addDef(InstReg)197.addUse(GR->getSPIRVTypeID(VoidTy))198.addImm(static_cast<int64_t>(199SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100))200.addImm(Inst);201for (auto Reg : Registers) {202MIB.addUse(Reg);203}204MIB.constrainAllUses(*TII, *TRI, *RBI);205GR->assignSPIRVTypeToVReg(VoidTy, InstReg, MF);206return InstReg;207};208209const SPIRVType *I32Ty =210GR->getOrCreateSPIRVType(Type::getInt32Ty(*Context), MIRBuilder,211SPIRV::AccessQualifier::ReadWrite, false);212213const Register DwarfVersionReg =214GR->buildConstantInt(DwarfVersion, MIRBuilder, I32Ty, false);215216const Register DebugInfoVersionReg =217GR->buildConstantInt(DebugInfoVersion, MIRBuilder, I32Ty, false);218219for (unsigned Idx = 0; Idx < LLVMSourceLanguages.size(); ++Idx) {220const Register FilePathStrReg = EmitOpString(FilePaths[Idx]);221222const Register DebugSourceResIdReg = EmitDIInstruction(223SPIRV::NonSemanticExtInst::DebugSource, {FilePathStrReg});224225SourceLanguage SpirvSourceLanguage = SourceLanguage::Unknown;226switch (LLVMSourceLanguages[Idx]) {227case dwarf::DW_LANG_OpenCL:228SpirvSourceLanguage = SourceLanguage::OpenCL_C;229break;230case dwarf::DW_LANG_OpenCL_CPP:231SpirvSourceLanguage = SourceLanguage::OpenCL_CPP;232break;233case dwarf::DW_LANG_CPP_for_OpenCL:234SpirvSourceLanguage = SourceLanguage::CPP_for_OpenCL;235break;236case dwarf::DW_LANG_GLSL:237SpirvSourceLanguage = SourceLanguage::GLSL;238break;239case dwarf::DW_LANG_HLSL:240SpirvSourceLanguage = SourceLanguage::HLSL;241break;242case dwarf::DW_LANG_SYCL:243SpirvSourceLanguage = SourceLanguage::SYCL;244break;245case dwarf::DW_LANG_Zig:246SpirvSourceLanguage = SourceLanguage::Zig;247}248249const Register SourceLanguageReg =250GR->buildConstantInt(SpirvSourceLanguage, MIRBuilder, I32Ty, false);251252[[maybe_unused]]253const Register DebugCompUnitResIdReg =254EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugCompilationUnit,255{DebugInfoVersionReg, DwarfVersionReg,256DebugSourceResIdReg, SourceLanguageReg});257}258259// We aren't extracting any DebugInfoFlags now so we260// emitting zero to use as <id>Flags argument for DebugBasicType261const Register I32ZeroReg =262GR->buildConstantInt(0, MIRBuilder, I32Ty, false, false);263264// We need to store pairs because further instructions reference265// the DIBasicTypes and size will be always small so there isn't266// need for any kind of map267SmallVector<std::pair<const DIBasicType *const, const Register>, 12>268BasicTypeRegPairs;269for (auto *BasicType : BasicTypes) {270const Register BasicTypeStrReg = EmitOpString(BasicType->getName());271272const Register ConstIntBitwidthReg = GR->buildConstantInt(273BasicType->getSizeInBits(), MIRBuilder, I32Ty, false);274275uint64_t AttributeEncoding = BaseTypeAttributeEncoding::Unspecified;276switch (BasicType->getEncoding()) {277case dwarf::DW_ATE_signed:278AttributeEncoding = BaseTypeAttributeEncoding::Signed;279break;280case dwarf::DW_ATE_unsigned:281AttributeEncoding = BaseTypeAttributeEncoding::Unsigned;282break;283case dwarf::DW_ATE_unsigned_char:284AttributeEncoding = BaseTypeAttributeEncoding::UnsignedChar;285break;286case dwarf::DW_ATE_signed_char:287AttributeEncoding = BaseTypeAttributeEncoding::SignedChar;288break;289case dwarf::DW_ATE_float:290AttributeEncoding = BaseTypeAttributeEncoding::Float;291break;292case dwarf::DW_ATE_boolean:293AttributeEncoding = BaseTypeAttributeEncoding::Boolean;294break;295case dwarf::DW_ATE_address:296AttributeEncoding = BaseTypeAttributeEncoding::Address;297}298299const Register AttributeEncodingReg =300GR->buildConstantInt(AttributeEncoding, MIRBuilder, I32Ty, false);301302const Register BasicTypeReg =303EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugTypeBasic,304{BasicTypeStrReg, ConstIntBitwidthReg,305AttributeEncodingReg, I32ZeroReg});306BasicTypeRegPairs.emplace_back(BasicType, BasicTypeReg);307}308309if (PointerDerivedTypes.size()) {310for (const auto *PointerDerivedType : PointerDerivedTypes) {311312assert(PointerDerivedType->getDWARFAddressSpace().has_value());313const Register StorageClassReg = GR->buildConstantInt(314addressSpaceToStorageClass(315PointerDerivedType->getDWARFAddressSpace().value(),316*TM->getSubtargetImpl()),317MIRBuilder, I32Ty, false);318319// If the Pointer is representing a void type it's getBaseType320// is a nullptr321const auto *MaybeNestedBasicType =322dyn_cast_or_null<DIBasicType>(PointerDerivedType->getBaseType());323if (MaybeNestedBasicType) {324for (const auto &BasicTypeRegPair : BasicTypeRegPairs) {325const auto &[DefinedBasicType, BasicTypeReg] = BasicTypeRegPair;326if (DefinedBasicType == MaybeNestedBasicType) {327[[maybe_unused]]328const Register DebugPointerTypeReg = EmitDIInstruction(329SPIRV::NonSemanticExtInst::DebugTypePointer,330{BasicTypeReg, StorageClassReg, I32ZeroReg});331}332}333} else {334const Register DebugInfoNoneReg =335EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugInfoNone, {});336[[maybe_unused]]337const Register DebugPointerTypeReg = EmitDIInstruction(338SPIRV::NonSemanticExtInst::DebugTypePointer,339{DebugInfoNoneReg, StorageClassReg, I32ZeroReg});340}341}342}343}344return true;345}346347bool SPIRVEmitNonSemanticDI::runOnMachineFunction(MachineFunction &MF) {348bool Res = false;349// emitGlobalDI needs to be executed only once to avoid350// emitting duplicates351if (!IsGlobalDIEmitted) {352IsGlobalDIEmitted = true;353Res = emitGlobalDI(MF);354}355return Res;356}357358359