360 lines · cpp
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 29using namespace llvm;30 31namespace {32struct 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 40private:41 bool IsGlobalDIEmitted = false;42 bool emitGlobalDI(MachineFunction &MF);43};44} // anonymous namespace45 46INITIALIZE_PASS(SPIRVEmitNonSemanticDI, DEBUG_TYPE,47 "SPIRV NonSemantic.Shader.DebugInfo.100 emitter", false, false)48 49char SPIRVEmitNonSemanticDI::ID = 0;50 51MachineFunctionPass *52llvm::createSPIRVEmitNonSemanticDIPass(SPIRVTargetMachine *TM) {53 return new SPIRVEmitNonSemanticDI(TM);54}55 56enum BaseTypeAttributeEncoding {57 Unspecified = 0,58 Address = 1,59 Boolean = 2,60 Float = 3,61 Signed = 4,62 SignedChar = 5,63 Unsigned = 6,64 UnsignedChar = 765};66 67enum 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 = 1281};82 83bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {84 // If this MachineFunction doesn't have any BB repeat procedure85 // for the next86 if (MF.begin() == MF.end()) {87 IsGlobalDIEmitted = false;88 return false;89 }90 91 // Required variables to get from metadata search92 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 nescessary100 // information like DwarfVersion or SourceLanguage101 {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(116 CompileUnit->getSourceLanguage().getUnversionedName());117 }118 }119 const NamedMDNode *ModuleFlags = M->getNamedMetadata("llvm.module.flags");120 assert(ModuleFlags && "Expected llvm.module.flags metadata to be present");121 for (const auto *Op : ModuleFlags->operands()) {122 const MDOperand &MaybeStrOp = Op->getOperand(1);123 if (MaybeStrOp.equalsStr("Dwarf Version"))124 DwarfVersion =125 cast<ConstantInt>(126 cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())127 ->getSExtValue();128 else if (MaybeStrOp.equalsStr("Debug Info Version"))129 DebugInfoVersion =130 cast<ConstantInt>(131 cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())132 ->getSExtValue();133 }134 135 // This traversal is the only supported way to access136 // instruction related DI metadata like DIBasicType137 for (auto &F : *M) {138 for (auto &BB : F) {139 for (auto &I : BB) {140 for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {141 DILocalVariable *LocalVariable = DVR.getVariable();142 if (auto *BasicType =143 dyn_cast<DIBasicType>(LocalVariable->getType())) {144 BasicTypes.insert(BasicType);145 } else if (auto *DerivedType =146 dyn_cast<DIDerivedType>(LocalVariable->getType())) {147 if (DerivedType->getTag() == dwarf::DW_TAG_pointer_type) {148 PointerDerivedTypes.insert(DerivedType);149 // DIBasicType can be unreachable from DbgRecord and only150 // pointed on from other DI types151 // DerivedType->getBaseType is null when pointer152 // is representing a void type153 if (auto *BT = dyn_cast_or_null<DIBasicType>(154 DerivedType->getBaseType()))155 BasicTypes.insert(BT);156 }157 }158 }159 }160 }161 }162 }163 // NonSemantic.Shader.DebugInfo.100 global DI instruction emitting164 {165 // Required LLVM variables for emitting logic166 const SPIRVInstrInfo *TII = TM->getSubtargetImpl()->getInstrInfo();167 const SPIRVRegisterInfo *TRI = TM->getSubtargetImpl()->getRegisterInfo();168 const RegisterBankInfo *RBI = TM->getSubtargetImpl()->getRegBankInfo();169 SPIRVGlobalRegistry *GR = TM->getSubtargetImpl()->getSPIRVGlobalRegistry();170 MachineRegisterInfo &MRI = MF.getRegInfo();171 MachineBasicBlock &MBB = *MF.begin();172 173 // To correct placement of a OpLabel instruction during SPIRVAsmPrinter174 // emission all new instructions needs to be placed after OpFunction175 // and before first terminator176 MachineIRBuilder MIRBuilder(MBB, MBB.getFirstTerminator());177 178 const auto EmitOpString = [&](StringRef SR) {179 const Register StrReg = MRI.createVirtualRegister(&SPIRV::IDRegClass);180 MRI.setType(StrReg, LLT::scalar(32));181 MachineInstrBuilder MIB = MIRBuilder.buildInstr(SPIRV::OpString);182 MIB.addDef(StrReg);183 addStringImm(SR, MIB);184 return StrReg;185 };186 187 const SPIRVType *VoidTy =188 GR->getOrCreateSPIRVType(Type::getVoidTy(*Context), MIRBuilder,189 SPIRV::AccessQualifier::ReadWrite, false);190 191 const auto EmitDIInstruction =192 [&](SPIRV::NonSemanticExtInst::NonSemanticExtInst Inst,193 std::initializer_list<Register> Registers) {194 const Register InstReg =195 MRI.createVirtualRegister(&SPIRV::IDRegClass);196 MRI.setType(InstReg, LLT::scalar(32));197 MachineInstrBuilder MIB =198 MIRBuilder.buildInstr(SPIRV::OpExtInst)199 .addDef(InstReg)200 .addUse(GR->getSPIRVTypeID(VoidTy))201 .addImm(static_cast<int64_t>(202 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100))203 .addImm(Inst);204 for (auto Reg : Registers) {205 MIB.addUse(Reg);206 }207 MIB.constrainAllUses(*TII, *TRI, *RBI);208 GR->assignSPIRVTypeToVReg(VoidTy, InstReg, MF);209 return InstReg;210 };211 212 const SPIRVType *I32Ty =213 GR->getOrCreateSPIRVType(Type::getInt32Ty(*Context), MIRBuilder,214 SPIRV::AccessQualifier::ReadWrite, false);215 216 const Register DwarfVersionReg =217 GR->buildConstantInt(DwarfVersion, MIRBuilder, I32Ty, false);218 219 const Register DebugInfoVersionReg =220 GR->buildConstantInt(DebugInfoVersion, MIRBuilder, I32Ty, false);221 222 for (unsigned Idx = 0; Idx < LLVMSourceLanguages.size(); ++Idx) {223 const Register FilePathStrReg = EmitOpString(FilePaths[Idx]);224 225 const Register DebugSourceResIdReg = EmitDIInstruction(226 SPIRV::NonSemanticExtInst::DebugSource, {FilePathStrReg});227 228 SourceLanguage SpirvSourceLanguage = SourceLanguage::Unknown;229 switch (LLVMSourceLanguages[Idx]) {230 case dwarf::DW_LANG_OpenCL:231 SpirvSourceLanguage = SourceLanguage::OpenCL_C;232 break;233 case dwarf::DW_LANG_OpenCL_CPP:234 SpirvSourceLanguage = SourceLanguage::OpenCL_CPP;235 break;236 case dwarf::DW_LANG_CPP_for_OpenCL:237 SpirvSourceLanguage = SourceLanguage::CPP_for_OpenCL;238 break;239 case dwarf::DW_LANG_GLSL:240 SpirvSourceLanguage = SourceLanguage::GLSL;241 break;242 case dwarf::DW_LANG_HLSL:243 SpirvSourceLanguage = SourceLanguage::HLSL;244 break;245 case dwarf::DW_LANG_SYCL:246 SpirvSourceLanguage = SourceLanguage::SYCL;247 break;248 case dwarf::DW_LANG_Zig:249 SpirvSourceLanguage = SourceLanguage::Zig;250 }251 252 const Register SourceLanguageReg =253 GR->buildConstantInt(SpirvSourceLanguage, MIRBuilder, I32Ty, false);254 255 [[maybe_unused]]256 const Register DebugCompUnitResIdReg =257 EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugCompilationUnit,258 {DebugInfoVersionReg, DwarfVersionReg,259 DebugSourceResIdReg, SourceLanguageReg});260 }261 262 // We aren't extracting any DebugInfoFlags now so we263 // emitting zero to use as <id>Flags argument for DebugBasicType264 const Register I32ZeroReg =265 GR->buildConstantInt(0, MIRBuilder, I32Ty, false, false);266 267 // We need to store pairs because further instructions reference268 // the DIBasicTypes and size will be always small so there isn't269 // need for any kind of map270 SmallVector<std::pair<const DIBasicType *const, const Register>, 12>271 BasicTypeRegPairs;272 for (auto *BasicType : BasicTypes) {273 const Register BasicTypeStrReg = EmitOpString(BasicType->getName());274 275 const Register ConstIntBitwidthReg = GR->buildConstantInt(276 BasicType->getSizeInBits(), MIRBuilder, I32Ty, false);277 278 uint64_t AttributeEncoding = BaseTypeAttributeEncoding::Unspecified;279 switch (BasicType->getEncoding()) {280 case dwarf::DW_ATE_signed:281 AttributeEncoding = BaseTypeAttributeEncoding::Signed;282 break;283 case dwarf::DW_ATE_unsigned:284 AttributeEncoding = BaseTypeAttributeEncoding::Unsigned;285 break;286 case dwarf::DW_ATE_unsigned_char:287 AttributeEncoding = BaseTypeAttributeEncoding::UnsignedChar;288 break;289 case dwarf::DW_ATE_signed_char:290 AttributeEncoding = BaseTypeAttributeEncoding::SignedChar;291 break;292 case dwarf::DW_ATE_float:293 AttributeEncoding = BaseTypeAttributeEncoding::Float;294 break;295 case dwarf::DW_ATE_boolean:296 AttributeEncoding = BaseTypeAttributeEncoding::Boolean;297 break;298 case dwarf::DW_ATE_address:299 AttributeEncoding = BaseTypeAttributeEncoding::Address;300 }301 302 const Register AttributeEncodingReg =303 GR->buildConstantInt(AttributeEncoding, MIRBuilder, I32Ty, false);304 305 const Register BasicTypeReg =306 EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugTypeBasic,307 {BasicTypeStrReg, ConstIntBitwidthReg,308 AttributeEncodingReg, I32ZeroReg});309 BasicTypeRegPairs.emplace_back(BasicType, BasicTypeReg);310 }311 312 if (PointerDerivedTypes.size()) {313 for (const auto *PointerDerivedType : PointerDerivedTypes) {314 315 assert(PointerDerivedType->getDWARFAddressSpace().has_value());316 const Register StorageClassReg = GR->buildConstantInt(317 addressSpaceToStorageClass(318 PointerDerivedType->getDWARFAddressSpace().value(),319 *TM->getSubtargetImpl()),320 MIRBuilder, I32Ty, false);321 322 // If the Pointer is representing a void type it's getBaseType323 // is a nullptr324 const auto *MaybeNestedBasicType =325 dyn_cast_or_null<DIBasicType>(PointerDerivedType->getBaseType());326 if (MaybeNestedBasicType) {327 for (const auto &BasicTypeRegPair : BasicTypeRegPairs) {328 const auto &[DefinedBasicType, BasicTypeReg] = BasicTypeRegPair;329 if (DefinedBasicType == MaybeNestedBasicType) {330 [[maybe_unused]]331 const Register DebugPointerTypeReg = EmitDIInstruction(332 SPIRV::NonSemanticExtInst::DebugTypePointer,333 {BasicTypeReg, StorageClassReg, I32ZeroReg});334 }335 }336 } else {337 const Register DebugInfoNoneReg =338 EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugInfoNone, {});339 [[maybe_unused]]340 const Register DebugPointerTypeReg = EmitDIInstruction(341 SPIRV::NonSemanticExtInst::DebugTypePointer,342 {DebugInfoNoneReg, StorageClassReg, I32ZeroReg});343 }344 }345 }346 }347 return true;348}349 350bool SPIRVEmitNonSemanticDI::runOnMachineFunction(MachineFunction &MF) {351 bool Res = false;352 // emitGlobalDI needs to be executed only once to avoid353 // emitting duplicates354 if (!IsGlobalDIEmitted) {355 IsGlobalDIEmitted = true;356 Res = emitGlobalDI(MF);357 }358 return Res;359}360