[llvm] [SPIR-V] Implementation of DebugLine for DI (PR #113541)

via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 24 03:17:42 PDT 2024


https://github.com/bwlodarcz created https://github.com/llvm/llvm-project/pull/113541

The commit introduces support for the DebugLine instruction from NonSemantic.Shader.DebugInfo.100 standard in backend.
It's also major architectural change of the SPIRVEmitNonSemanticDI.cpp with additional safe local abstraction layer to maintaining state.

This is still WiP.
This description will be updated with additional information before entering the PR phase.
 

>From 598ea9e697d111fe2690af518376f711f99d2265 Mon Sep 17 00:00:00 2001
From: "Wlodarczyk, Bertrand" <bertrand.wlodarczyk at intel.com>
Date: Thu, 24 Oct 2024 11:56:28 +0200
Subject: [PATCH] [SPIR-V] Implementation of DebugLine for DI

---
 .../Target/SPIRV/SPIRVEmitNonSemanticDI.cpp   | 677 ++++++++++++------
 .../SPIRV/debug-info/debug-type-pointer.ll    |  32 +-
 2 files changed, 473 insertions(+), 236 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitNonSemanticDI.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitNonSemanticDI.cpp
index d3e323efaee91b..b0ae0abe4928fa 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitNonSemanticDI.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitNonSemanticDI.cpp
@@ -5,17 +5,15 @@
 #include "SPIRVRegisterInfo.h"
 #include "SPIRVTargetMachine.h"
 #include "SPIRVUtils.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"
 #include "llvm/CodeGen/MachineFunctionPass.h"
-#include "llvm/CodeGen/MachineInstr.h"
 #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"
@@ -28,9 +26,9 @@
 #define DEBUG_TYPE "spirv-nonsemantic-debug-info"
 
 namespace llvm {
-struct SPIRVEmitNonSemanticDI : public MachineFunctionPass {
+struct SPIRVEmitNonSemanticDI : MachineFunctionPass {
   static char ID;
-  SPIRVTargetMachine *TM;
+  SPIRVTargetMachine *TM = nullptr;
   SPIRVEmitNonSemanticDI(SPIRVTargetMachine *TM);
   SPIRVEmitNonSemanticDI();
 
@@ -38,7 +36,8 @@ struct SPIRVEmitNonSemanticDI : public MachineFunctionPass {
 
 private:
   bool IsGlobalDIEmitted = false;
-  bool emitGlobalDI(MachineFunction &MF);
+  bool emitGlobalDI(MachineFunction &MF, const Module *M) const;
+  //bool emitLineDI(MachineFunction &MF);
 };
 } // namespace llvm
 
@@ -63,6 +62,9 @@ SPIRVEmitNonSemanticDI::SPIRVEmitNonSemanticDI() : MachineFunctionPass(ID) {
   initializeSPIRVEmitNonSemanticDIPass(*PassRegistry::getPassRegistry());
 }
 
+
+namespace {
+
 enum BaseTypeAttributeEncoding {
   Unspecified = 0,
   Address = 1,
@@ -90,149 +92,315 @@ enum SourceLanguage {
   Zig = 12
 };
 
-bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {
-  // If this MachineFunction doesn't have any BB repeat procedure
-  // for the next
-  if (MF.begin() == MF.end()) {
-    IsGlobalDIEmitted = false;
-    return false;
+enum TypesMapping {
+  Null = 0,
+  PrimitiveIntArray,
+  PrimitiveStringArray,
+  DebugSourceArray,
+  DebugCompilationUnitArray,
+  DebugTypeBasicArray,
+  DebugTypePointerArray,
+  DebugInfoNoneArray,
+  DebugLineArray
+};
+
+struct DebugSource {
+  size_t FileId;
+
+  explicit constexpr DebugSource(const size_t FileId) noexcept
+      : FileId(FileId) {}
+
+  explicit constexpr DebugSource(const ArrayRef<size_t> AR) : FileId(AR[0]) {}
+
+  friend bool operator==(const DebugSource &Lhs, const DebugSource &Rhs) {
+    return Lhs.FileId == Rhs.FileId;
   }
+};
 
-  // Required variables to get from metadata search
-  LLVMContext *Context;
-  SmallVector<SmallString<128>> FilePaths;
-  SmallVector<int64_t> LLVMSourceLanguages;
-  int64_t DwarfVersion = 0;
-  int64_t DebugInfoVersion = 0;
-  SmallPtrSet<DIBasicType *, 12> BasicTypes;
-  SmallPtrSet<DIDerivedType *, 12> PointerDerivedTypes;
-  // Searching through the Module metadata to find nescessary
-  // information like DwarfVersion or SourceLanguage
-  {
-    const MachineModuleInfo &MMI =
-        getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
-    const Module *M = MMI.getModule();
-    Context = &M->getContext();
-    const NamedMDNode *DbgCu = M->getNamedMetadata("llvm.dbg.cu");
-    if (!DbgCu)
-      return false;
-    for (const auto *Op : DbgCu->operands()) {
-      if (const auto *CompileUnit = dyn_cast<DICompileUnit>(Op)) {
-        DIFile *File = CompileUnit->getFile();
-        FilePaths.emplace_back();
-        sys::path::append(FilePaths.back(), File->getDirectory(),
-                          File->getFilename());
-        LLVMSourceLanguages.push_back(CompileUnit->getSourceLanguage());
-      }
-    }
-    const NamedMDNode *ModuleFlags = M->getNamedMetadata("llvm.module.flags");
-    for (const auto *Op : ModuleFlags->operands()) {
-      const MDOperand &MaybeStrOp = Op->getOperand(1);
-      if (MaybeStrOp.equalsStr("Dwarf Version"))
-        DwarfVersion =
-            cast<ConstantInt>(
-                cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
-                ->getSExtValue();
-      else if (MaybeStrOp.equalsStr("Debug Info Version"))
-        DebugInfoVersion =
-            cast<ConstantInt>(
-                cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
-                ->getSExtValue();
-    }
+struct DebugCompilationUnit {
+  size_t DebugInfoVersionId;
+  size_t DwarfVersionId;
+  size_t DebugSourceId;
+  size_t LanguageId;
+
+  constexpr DebugCompilationUnit(const size_t DebugInfoVersionId,
+                                 const size_t DwarfVersionId,
+                                 const size_t DebugSourceId,
+                                 const size_t LanguageId) noexcept
+      : DebugInfoVersionId(DebugInfoVersionId), DwarfVersionId(DwarfVersionId),
+        DebugSourceId(DebugSourceId), LanguageId(LanguageId) {}
+
+  explicit constexpr DebugCompilationUnit(const ArrayRef<size_t> AR) noexcept
+      : DebugInfoVersionId(AR[0]), DwarfVersionId(AR[1]), DebugSourceId(AR[2]),
+        LanguageId(AR[3]) {}
+
+  friend bool operator==(const DebugCompilationUnit &Lhs,
+                         const DebugCompilationUnit &Rhs) {
+    return Lhs.DebugInfoVersionId == Rhs.DebugInfoVersionId &
+           Lhs.DwarfVersionId == Rhs.DwarfVersionId &
+           Lhs.DebugSourceId == Rhs.DebugSourceId &
+           Lhs.LanguageId == Rhs.LanguageId;
+  }
+};
 
-    // 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);
-            } else if (auto *DerivedType =
-                           dyn_cast<DIDerivedType>(LocalVariable->getType())) {
-              if (DerivedType->getTag() == dwarf::DW_TAG_pointer_type) {
-                PointerDerivedTypes.insert(DerivedType);
-                // DIBasicType can be unreachable from DbgRecord and only
-                // pointed on from other DI types
-                // DerivedType->getBaseType is null when pointer
-                // is representing a void type
-                if (DerivedType->getBaseType())
-                  BasicTypes.insert(
-                      cast<DIBasicType>(DerivedType->getBaseType()));
-              }
-            }
-          }
-        }
-      }
+struct DebugTypeBasic {
+  size_t NameId;
+  size_t SizeId;
+  size_t BaseTypeEncodingId;
+  size_t FlagsId;
+
+  explicit constexpr DebugTypeBasic(const ArrayRef<size_t> AR)
+      : NameId(AR[0]), SizeId(AR[1]), BaseTypeEncodingId(AR[2]),
+        FlagsId(AR[3]) {}
+
+  friend bool operator==(const DebugTypeBasic &Lhs, const DebugTypeBasic &Rhs) {
+    return Lhs.NameId == Rhs.NameId && Lhs.SizeId == Rhs.SizeId &&
+           Lhs.BaseTypeEncodingId == Rhs.BaseTypeEncodingId &&
+           Lhs.FlagsId == Rhs.FlagsId;
+  }
+};
+
+struct DebugTypePointer {
+  size_t BaseTypeId;
+  size_t StorageClassId;
+  size_t FlagsId;
+
+  DebugTypePointer(const size_t BaseTypeId, const size_t StorageClassId,
+                   const size_t FlagsId) noexcept
+      : BaseTypeId(BaseTypeId), StorageClassId(StorageClassId),
+        FlagsId(FlagsId) {}
+
+  explicit DebugTypePointer(const ArrayRef<size_t> AR) noexcept
+      : BaseTypeId(AR[0]), StorageClassId(AR[1]), FlagsId(AR[2]) {}
+
+  friend bool operator==(const DebugTypePointer &Lhs,
+                         const DebugTypePointer &Rhs) {
+    return Lhs.BaseTypeId == Rhs.BaseTypeId &&
+           Lhs.StorageClassId == Rhs.StorageClassId &&
+           Lhs.FlagsId == Rhs.FlagsId;
+  }
+};
+
+struct DebugLine {
+  size_t DebugSourceId;
+  size_t LineStartId;
+  size_t LineEndId;
+  size_t ColumnStartId;
+  size_t ColumnEndId;
+};
+
+struct DebugInfoNone;
+
+template <typename T> struct DebugTypeContainer;
+
+template <> struct DebugTypeContainer<int64_t> {
+  static constexpr TypesMapping TM = PrimitiveIntArray;
+  static SmallVector<int64_t> Value;
+  static SmallVector<size_t> Back;
+};
+
+template <> struct DebugTypeContainer<StringRef> {
+  static constexpr TypesMapping TM = PrimitiveStringArray;
+  static SmallVector<StringRef> Value;
+  static SmallVector<size_t> Back;
+};
+
+template <> struct DebugTypeContainer<DebugSource> {
+  static constexpr TypesMapping TM = DebugSourceArray;
+  static constexpr SPIRV::NonSemanticExtInst::NonSemanticExtInst Inst =
+      SPIRV::NonSemanticExtInst::DebugSource;
+  static SmallVector<DebugSource> Value;
+  static SmallVector<size_t> Back;
+};
+
+template <> struct DebugTypeContainer<DebugCompilationUnit> {
+  static constexpr TypesMapping TM = DebugCompilationUnitArray;
+  static constexpr SPIRV::NonSemanticExtInst::NonSemanticExtInst Inst =
+      SPIRV::NonSemanticExtInst::DebugCompilationUnit;
+  static SmallVector<DebugCompilationUnit> Value;
+  static SmallVector<size_t> Back;
+};
+
+template <> struct DebugTypeContainer<DebugTypeBasic> {
+  static constexpr TypesMapping TM = DebugTypeBasicArray;
+  static constexpr SPIRV::NonSemanticExtInst::NonSemanticExtInst Inst =
+      SPIRV::NonSemanticExtInst::DebugTypeBasic;
+  static SmallVector<DebugTypeBasic> Value;
+  static SmallVector<size_t> Back;
+};
+
+template <> struct DebugTypeContainer<DebugTypePointer> {
+  static constexpr TypesMapping TM = DebugTypePointerArray;
+  static constexpr SPIRV::NonSemanticExtInst::NonSemanticExtInst Inst =
+      SPIRV::NonSemanticExtInst::DebugTypePointer;
+  static SmallVector<DebugTypePointer> Value;
+  static SmallVector<size_t> Back;
+};
+
+template <> struct DebugTypeContainer<DebugInfoNone> {
+  static constexpr TypesMapping TM = DebugInfoNoneArray;
+  static constexpr SPIRV::NonSemanticExtInst::NonSemanticExtInst Inst =
+      SPIRV::NonSemanticExtInst::DebugInfoNone;
+};
+
+SmallVector<int64_t> DebugTypeContainer<int64_t>::Value;
+SmallVector<StringRef> DebugTypeContainer<StringRef>::Value;
+SmallVector<DebugSource> DebugTypeContainer<DebugSource>::Value;
+SmallVector<DebugCompilationUnit>
+    DebugTypeContainer<DebugCompilationUnit>::Value;
+SmallVector<DebugTypeBasic> DebugTypeContainer<DebugTypeBasic>::Value;
+SmallVector<DebugTypePointer> DebugTypeContainer<DebugTypePointer>::Value;
+
+SmallVector<size_t> DebugTypeContainer<int64_t>::Back;
+SmallVector<size_t> DebugTypeContainer<StringRef>::Back;
+SmallVector<size_t> DebugTypeContainer<DebugSource>::Back;
+SmallVector<size_t> DebugTypeContainer<DebugCompilationUnit>::Back;
+SmallVector<size_t> DebugTypeContainer<DebugTypeBasic>::Back;
+SmallVector<size_t> DebugTypeContainer<DebugTypePointer>::Back;
+
+SmallVector<Register> Registers;
+SmallVector<std::pair<TypesMapping, unsigned>> Instructions;
+
+Register emitOpString(const StringRef SR, MachineIRBuilder &MIRBuilder) {
+  MachineRegisterInfo *MRI = MIRBuilder.getMRI();
+  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;
+}
+
+Register emitDIInstruction(SPIRV::NonSemanticExtInst::NonSemanticExtInst Inst,
+                           const ArrayRef<size_t> Ids,
+                           MachineIRBuilder &MIRBuilder,
+                           const SPIRVTargetMachine *const TM) {
+  const SPIRVInstrInfo *TII = TM->getSubtargetImpl()->getInstrInfo();
+  const SPIRVRegisterInfo *TRI = TM->getSubtargetImpl()->getRegisterInfo();
+  const RegisterBankInfo *RBI = TM->getSubtargetImpl()->getRegBankInfo();
+  SPIRVGlobalRegistry *GR = TM->getSubtargetImpl()->getSPIRVGlobalRegistry();
+  MachineRegisterInfo *MRI = MIRBuilder.getMRI();
+  const SPIRVType *VoidTy = GR->getOrCreateSPIRVType(
+      Type::getVoidTy(MIRBuilder.getContext()), MIRBuilder);
+  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(SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100)
+          .addImm(Inst);
+  for (auto Id : Ids) {
+    MIB.addUse(Registers[Id]);
+  }
+  MIB.constrainAllUses(*TII, *TRI, *RBI);
+  GR->assignSPIRVTypeToVReg(VoidTy, InstReg, MIRBuilder.getMF());
+  return InstReg;
+}
+
+template <typename T>
+std::pair<size_t, bool> helper(T Val, SmallVectorImpl<T> &SV) {
+  for (unsigned Idx = 0; Idx < SV.size(); ++Idx) {
+    if (Val == SV[Idx]) {
+      return {Idx, true};
     }
   }
-  // NonSemantic.Shader.DebugInfo.100 global DI instruction emitting
-  {
-    // Required LLVM variables for emitting logic
-    const SPIRVInstrInfo *TII = TM->getSubtargetImpl()->getInstrInfo();
-    const SPIRVRegisterInfo *TRI = TM->getSubtargetImpl()->getRegisterInfo();
-    const RegisterBankInfo *RBI = TM->getSubtargetImpl()->getRegBankInfo();
-    SPIRVGlobalRegistry *GR = TM->getSubtargetImpl()->getSPIRVGlobalRegistry();
-    MachineRegisterInfo &MRI = MF.getRegInfo();
-    MachineBasicBlock &MBB = *MF.begin();
-
-    // To correct placement of a OpLabel instruction during SPIRVAsmPrinter
-    // emission all new instructions needs to be placed after OpFunction
-    // 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;
-    };
-
-    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;
-        };
+  SV.emplace_back(Val);
+  return {SV.size() - 1, false};
+}
+
+size_t push(const int64_t Val, MachineIRBuilder &MIRBuilder,
+            const SPIRVTargetMachine *TM) {
+  auto &SV = DebugTypeContainer<int64_t>::Value;
+  const auto [ConcreteIdx, IsDuplicate] = helper(Val, SV);
+  if (IsDuplicate) {
+    return DebugTypeContainer<int64_t>::Back[ConcreteIdx];
+  }
+  Instructions.emplace_back(DebugTypeContainer<int64_t>::TM, ConcreteIdx);
+  SPIRVGlobalRegistry *GR = TM->getSubtargetImpl()->getSPIRVGlobalRegistry();
+  const SPIRVType *I32Ty = GR->getOrCreateSPIRVType(
+      Type::getInt32Ty(MIRBuilder.getContext()), MIRBuilder);
+  Registers.emplace_back(GR->buildConstantInt(Val, MIRBuilder, I32Ty, false));
+  DebugTypeContainer<int64_t>::Back.emplace_back(Instructions.size() - 1);
+  return Instructions.size() - 1;
+}
+
+size_t push(const StringRef Val, MachineIRBuilder &MIRBuilder) {
+  auto &SV = DebugTypeContainer<StringRef>::Value;
+  const auto [ConcreteIdx, IsDuplicate] = helper(Val, SV);
+  if (IsDuplicate) {
+    return DebugTypeContainer<StringRef>::Back[ConcreteIdx];
+  }
+  Instructions.emplace_back(DebugTypeContainer<StringRef>::TM, ConcreteIdx);
+  Registers.emplace_back(emitOpString(Val, MIRBuilder));
+  DebugTypeContainer<StringRef>::Back.emplace_back(Instructions.size() - 1);
+  return Instructions.size() - 1;
+}
 
-    const SPIRVType *I32Ty =
-        GR->getOrCreateSPIRVType(Type::getInt32Ty(*Context), MIRBuilder);
+template <typename T>
+constexpr size_t push(ArrayRef<size_t> Args, MachineIRBuilder &MIRBuilder,
+                      const SPIRVTargetMachine *TM) {
+  auto &SV = DebugTypeContainer<T>::Value;
+  const auto [ConcreteIdx, IsDuplicate] = helper(T(Args), SV);
+  if (IsDuplicate) {
+    return DebugTypeContainer<T>::Back[ConcreteIdx];
+  }
+  Instructions.emplace_back(DebugTypeContainer<T>::TM, ConcreteIdx);
+  Registers.emplace_back(
+      emitDIInstruction(DebugTypeContainer<T>::Inst, Args, MIRBuilder, TM));
+  DebugTypeContainer<T>::Back.emplace_back(Instructions.size() - 1);
+  return Instructions.size() - 1;
+}
 
-    const Register DwarfVersionReg =
-        GR->buildConstantInt(DwarfVersion, MIRBuilder, I32Ty, false);
+template <>
+size_t push<DebugInfoNone>(ArrayRef<size_t>, MachineIRBuilder &MIRBuilder,
+                           const SPIRVTargetMachine *TM) {
+  static std::optional<size_t> DebugInfoNoneIdx = std::nullopt;
+  if (!DebugInfoNoneIdx.has_value()) {
+    Instructions.emplace_back(DebugTypeContainer<DebugInfoNone>::TM, 0);
+    Registers.emplace_back(emitDIInstruction(
+        DebugTypeContainer<DebugInfoNone>::Inst, {}, MIRBuilder, TM));
+    DebugInfoNoneIdx.emplace(Instructions.size() - 1);
+  }
+  return DebugInfoNoneIdx.value();
+}
 
-    const Register DebugInfoVersionReg =
-        GR->buildConstantInt(DebugInfoVersion, MIRBuilder, I32Ty, false);
+size_t emitDebugCompilationUnits(const Module *M, MachineIRBuilder &MIRBuilder,
+                                 const SPIRVTargetMachine *TM) {
+  // TODO: Initialize assholes
+  std::optional<size_t> DwarfVersionId = std::nullopt;
+  std::optional<size_t> DebugInfoVersionId = std::nullopt;
+  const NamedMDNode *ModuleFlags = M->getNamedMetadata("llvm.module.flags");
+  for (const auto *Op : ModuleFlags->operands()) {
+    const MDOperand &MaybeStrOp = Op->getOperand(1);
+    if (MaybeStrOp.equalsStr("Dwarf Version")) {
+      const int64_t DwarfVersion =
+          cast<ConstantInt>(
+              cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
+              ->getSExtValue();
+      DwarfVersionId = push(DwarfVersion, MIRBuilder, TM);
+    } else if (MaybeStrOp.equalsStr("Debug Info Version")) {
+      const int64_t DebugInfoVersion =
+          cast<ConstantInt>(
+              cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
+              ->getSExtValue();
+      DebugInfoVersionId = push(DebugInfoVersion, MIRBuilder, TM);
+    }
+  }
 
-    for (unsigned Idx = 0; Idx < LLVMSourceLanguages.size(); ++Idx) {
-      const Register FilePathStrReg = EmitOpString(FilePaths[Idx]);
+  const NamedMDNode *DbgCu = M->getNamedMetadata("llvm.dbg.cu");
+  for (const auto *Op : DbgCu->operands()) {
+    if (const auto *CompileUnit = dyn_cast<DICompileUnit>(Op)) {
+      const DIFile *File = CompileUnit->getFile();
+      SmallString<128> FilePath;
+      sys::path::append(FilePath, File->getDirectory(), File->getFilename());
 
-      const Register DebugSourceResIdReg = EmitDIInstruction(
-          SPIRV::NonSemanticExtInst::DebugSource, {FilePathStrReg});
+      const size_t FilePathId = push(StringRef(FilePath.c_str()), MIRBuilder);
+      const size_t DebugSourceId =
+          push<DebugSource>({FilePathId}, MIRBuilder, TM);
 
-      SourceLanguage SpirvSourceLanguage = SourceLanguage::Unknown;
-      switch (LLVMSourceLanguages[Idx]) {
+      SourceLanguage SpirvSourceLanguage;
+      switch (CompileUnit->getSourceLanguage()) {
       case dwarf::DW_LANG_OpenCL:
         SpirvSourceLanguage = SourceLanguage::OpenCL_C;
         break;
@@ -253,99 +421,141 @@ bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {
         break;
       case dwarf::DW_LANG_Zig:
         SpirvSourceLanguage = SourceLanguage::Zig;
+        break;
+      default:
+        SpirvSourceLanguage = SourceLanguage::Unknown;
       }
 
-      const Register SourceLanguageReg =
-          GR->buildConstantInt(SpirvSourceLanguage, MIRBuilder, I32Ty, false);
-
-      [[maybe_unused]]
-      const Register DebugCompUnitResIdReg =
-          EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugCompilationUnit,
-                            {DebugInfoVersionReg, DwarfVersionReg,
-                             DebugSourceResIdReg, SourceLanguageReg});
+      size_t SpirvSourceLanguageId = push(SpirvSourceLanguage, MIRBuilder, TM);
+      push<DebugCompilationUnit>({DebugInfoVersionId.value(), DwarfVersionId.value(),
+                                  DebugSourceId, SpirvSourceLanguageId},
+                                 MIRBuilder, TM);
     }
+  }
+  return 0;
+}
 
-    // 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);
-
-    // We need to store pairs because further instructions reference
-    // the DIBasicTypes and size will be always small so there isn't
-    // need for any kind of map
-    SmallVector<std::pair<const DIBasicType *const, const Register>, 12>
-        BasicTypeRegPairs;
-    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;
-      }
+size_t emitDebugTypeBasic(const DIBasicType *BT, size_t I32ZeroIdx,
+                          MachineIRBuilder &MIRBuilder,
+                          const SPIRVTargetMachine *TM) {
+
+  const size_t BasicTypeStrId = push(BT->getName(), MIRBuilder);
+
+  const size_t ConstIntBitWidthId = push(BT->getSizeInBits(), MIRBuilder, TM);
+
+  uint64_t AttributeEncoding;
+  switch (BT->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;
+    break;
+  default:
+    AttributeEncoding = BaseTypeAttributeEncoding::Unspecified;
+  }
 
-      const Register AttributeEncodingReg =
-          GR->buildConstantInt(AttributeEncoding, MIRBuilder, I32Ty, false);
+  const size_t AttributeEncodingId = push(AttributeEncoding, MIRBuilder, TM);
 
-      const Register BasicTypeReg =
-          EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugTypeBasic,
-                            {BasicTypeStrReg, ConstIntBitwidthReg,
-                             AttributeEncodingReg, I32ZeroReg});
-      BasicTypeRegPairs.emplace_back(BasicType, BasicTypeReg);
-    }
+  return push<DebugTypeBasic>(
+      {BasicTypeStrId, ConstIntBitWidthId, AttributeEncodingId, I32ZeroIdx},
+      MIRBuilder, TM);
+}
+
+size_t emitDebugTypePointer(const DIDerivedType *DT, const size_t BasicTypeIdx,
+                            const size_t I32ZeroIdx,
+                            MachineIRBuilder &MIRBuilder,
+                            const SPIRVTargetMachine *TM) {
+  assert(DT->getDWARFAddressSpace().has_value());
+
+  size_t StorageClassIdx =
+      push(addressSpaceToStorageClass(DT->getDWARFAddressSpace().value(),
+                                      *TM->getSubtargetImpl()),
+           MIRBuilder, TM);
+
+  return push<DebugTypePointer>({BasicTypeIdx, StorageClassIdx, I32ZeroIdx},
+                                MIRBuilder, TM);
+}
 
-    if (PointerDerivedTypes.size()) {
-      for (const auto *PointerDerivedType : PointerDerivedTypes) {
-
-        assert(PointerDerivedType->getDWARFAddressSpace().has_value());
-        const Register StorageClassReg = GR->buildConstantInt(
-            addressSpaceToStorageClass(
-                PointerDerivedType->getDWARFAddressSpace().value(),
-                *TM->getSubtargetImpl()),
-            MIRBuilder, I32Ty, false);
-
-        // If the Pointer is representing a void type it's getBaseType
-        // is a nullptr
-        const auto *MaybeNestedBasicType =
-            cast_or_null<DIBasicType>(PointerDerivedType->getBaseType());
-        if (MaybeNestedBasicType) {
-          for (const auto &BasicTypeRegPair : BasicTypeRegPairs) {
-            const auto &[DefinedBasicType, BasicTypeReg] = BasicTypeRegPair;
-            if (DefinedBasicType == MaybeNestedBasicType) {
-              [[maybe_unused]]
-              const Register DebugPointerTypeReg = EmitDIInstruction(
-                  SPIRV::NonSemanticExtInst::DebugTypePointer,
-                  {BasicTypeReg, StorageClassReg, I32ZeroReg});
+size_t emitDebugTypePointer(const DIDerivedType *DT, const size_t I32ZeroIdx,
+                            MachineIRBuilder &MIRBuilder,
+                            const SPIRVTargetMachine *TM) {
+  assert(DT->getDWARFAddressSpace().has_value());
+
+  size_t StorageClassIdx =
+      push(addressSpaceToStorageClass(DT->getDWARFAddressSpace().value(),
+                                      *TM->getSubtargetImpl()),
+           MIRBuilder, TM);
+
+  // If the Pointer is representing a void type it's getBaseType
+  // is a nullptr
+  size_t DebugInfoNoneIdx = push<DebugInfoNone>({}, MIRBuilder, TM);
+  return push<DebugTypePointer>({DebugInfoNoneIdx, StorageClassIdx, I32ZeroIdx},
+                                MIRBuilder, TM);
+}
+} // namespace
+
+bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF,
+                                          const Module *M) const {
+  MachineBasicBlock &MBB = *MF.begin();
+
+  // To correct placement of a OpLabel instruction during SPIRVAsmPrinter
+  // emission all new instructions needs to be placed after OpFunction
+  // and before first terminator
+  MachineIRBuilder MIRBuilder(MBB, MBB.getFirstTerminator());
+
+  emitDebugCompilationUnits(M, MIRBuilder, TM);
+
+  for (auto &F : *M) {
+    for (auto &BB : F) {
+      for (auto &I : BB) {
+        for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {
+          const DILocalVariable *LocalVariable = DVR.getVariable();
+          if (const auto *BasicType =
+                  dyn_cast<DIBasicType>(LocalVariable->getType())) {
+            // We aren't extracting any DebugInfoFlags now so we're
+            // emitting zero to use as <id>Flags argument for DebugBasicType
+            const size_t I32ZeroIdx = push(0, MIRBuilder, TM);
+            emitDebugTypeBasic(BasicType, I32ZeroIdx, MIRBuilder, TM);
+            continue;
+          }
+          // Beware else if here. Types from previous scopes are
+          // counterintuitively still visible for the next ifs scopes.
+          if (const auto *DerivedType =
+                  dyn_cast<DIDerivedType>(LocalVariable->getType())) {
+            if (DerivedType->getTag() == dwarf::DW_TAG_pointer_type) {
+              const size_t I32ZeroIdx = push(0, MIRBuilder, TM);
+              // DIBasicType can be unreachable from DbgRecord and only
+              // pointed on from other DI types
+              // DerivedType->getBaseType is null when pointer
+              // is representing a void type
+              if (DerivedType->getBaseType()) {
+                const auto *BasicType =
+                    cast<DIBasicType>(DerivedType->getBaseType());
+                const size_t BTIdx =
+                    emitDebugTypeBasic(BasicType, I32ZeroIdx, MIRBuilder, TM);
+                emitDebugTypePointer(DerivedType, BTIdx, I32ZeroIdx, MIRBuilder,
+                                     TM);
+              } else {
+                emitDebugTypePointer(DerivedType, I32ZeroIdx, MIRBuilder, TM);
+              }
             }
           }
-        } else {
-          const Register DebugInfoNoneReg =
-              EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugInfoNone, {});
-          [[maybe_unused]]
-          const Register DebugPointerTypeReg = EmitDIInstruction(
-              SPIRV::NonSemanticExtInst::DebugTypePointer,
-              {DebugInfoNoneReg, StorageClassReg, I32ZeroReg});
         }
       }
     }
@@ -353,13 +563,34 @@ bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {
   return true;
 }
 
+// bool SPIRVEmitNonSemanticDI::emitLineDI(MachineFunction &MF) {
+//   for (auto &MBB : MF) {
+//     for (auto &MI : MBB) {
+//       if (MI.isDebugValue()) {
+//         DebugLoc DL = MI.getDebugLoc();
+//       }
+//     }
+//   }
+//   return false;
+// }
+
 bool SPIRVEmitNonSemanticDI::runOnMachineFunction(MachineFunction &MF) {
   bool Res = false;
   // emitGlobalDI needs to be executed only once to avoid
   // emitting duplicates
   if (!IsGlobalDIEmitted) {
+    if (MF.begin() == MF.end()) {
+      return false;
+    }
     IsGlobalDIEmitted = true;
-    Res = emitGlobalDI(MF);
+    const MachineModuleInfo &MMI =
+        getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
+    const Module *M = MMI.getModule();
+    const NamedMDNode *DbgCu = M->getNamedMetadata("llvm.dbg.cu");
+    if (!DbgCu)
+      return false;
+    Res = emitGlobalDI(MF, M);
   }
+  // Res |= emitLineDI(MF);
   return Res;
 }
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-type-pointer.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-type-pointer.ll
index b7e6e95f366cf7..d9ef3f59da3577 100644
--- a/llvm/test/CodeGen/SPIRV/debug-info/debug-type-pointer.ll
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-type-pointer.ll
@@ -28,19 +28,22 @@
 ; CHECK-MIR-DAG:   [[float:%[0-9]+\:id\(s32\)]] = OpExtInst [[void_type]], 3, 2, {{%[0-9]+\:[a-z0-9\(\)]+}}, [[i32_32]], [[enc_float]], [[i32_0]]
 ; CHECK-MIR-DAG:   [[double:%[0-9]+\:id\(s32\)]] = OpExtInst [[void_type]], 3, 2, {{%[0-9]+\:[a-z0-9\(\)]+}}, [[i32_64]], [[enc_float]], [[i32_0]]
 ; CHECK-MIR-DAG:   [[int:%[0-9]+\:id\(s32\)]] = OpExtInst [[void_type]], 3, 2, {{%[0-9]+\:[a-z0-9\(\)]+}}, [[i32_32]], [[enc_signed]], [[i32_0]]
-; CHECK-MIR:   OpExtInst [[void_type]], 3, 3, [[bool]], [[i32_8]], [[i32_0]]
-; CHECK-MIR:   OpExtInst [[void_type]], 3, 3, [[short]], [[i32_8]], [[i32_0]]
-; CHECK-MIR:   OpExtInst [[void_type]], 3, 3, [[char]], [[i32_8]], [[i32_0]]
-; CHECK-MIR:   OpExtInst [[void_type]], 3, 3, [[long]], [[i32_8]], [[i32_0]]
-; CHECK-MIR:   OpExtInst [[void_type]], 3, 3, [[unsigned_int]], [[i32_8]], [[i32_0]]
-; CHECK-MIR:   OpExtInst [[void_type]], 3, 3, [[unsigned_short]], [[i32_8]], [[i32_0]]
-; CHECK-MIR:   OpExtInst [[void_type]], 3, 3, [[unsigned_char]], [[i32_8]], [[i32_0]]
-; CHECK-MIR:   OpExtInst [[void_type]], 3, 3, [[unsigned_long]], [[i32_8]], [[i32_0]]
-; CHECK-MIR:   OpExtInst [[void_type]], 3, 3, [[float]], [[i32_8]], [[i32_0]]
-; CHECK-MIR:   OpExtInst [[void_type]], 3, 3, [[double]], [[i32_8]], [[i32_0]]
-; CHECK-MIR:   OpExtInst [[void_type]], 3, 3, [[int]], [[i32_5]], [[i32_0]]
-; CHECK-MIR:   [[debug_info_none:%[0-9]+\:id\(s32\)]] = OpExtInst [[void_type]], 3, 0
-; CHECK-MIR:   OpExtInst [[void_type]], 3, 3, [[debug_info_none]], [[i32_5]], [[i32_0]]
+; CHECK-MIR-DAG:   OpExtInst [[void_type]], 3, 3, [[bool]], [[i32_8]], [[i32_0]]
+; CHECK-MIR-DAG:   OpExtInst [[void_type]], 3, 3, [[short]], [[i32_8]], [[i32_0]]
+; CHECK-MIR-DAG:   OpExtInst [[void_type]], 3, 3, [[char]], [[i32_8]], [[i32_0]]
+; CHECK-MIR-DAG:   OpExtInst [[void_type]], 3, 3, [[long]], [[i32_8]], [[i32_0]]
+; CHECK-MIR-DAG:   OpExtInst [[void_type]], 3, 3, [[unsigned_int]], [[i32_8]], [[i32_0]]
+; CHECK-MIR-DAG:   OpExtInst [[void_type]], 3, 3, [[unsigned_short]], [[i32_8]], [[i32_0]]
+; CHECK-MIR-DAG:   OpExtInst [[void_type]], 3, 3, [[unsigned_char]], [[i32_8]], [[i32_0]]
+; CHECK-MIR-DAG:   OpExtInst [[void_type]], 3, 3, [[unsigned_long]], [[i32_8]], [[i32_0]]
+; CHECK-MIR-DAG:   OpExtInst [[void_type]], 3, 3, [[float]], [[i32_8]], [[i32_0]]
+; CHECK-MIR-DAG:   OpExtInst [[void_type]], 3, 3, [[double]], [[i32_8]], [[i32_0]]
+; CHECK-MIR-DAG:   OpExtInst [[void_type]], 3, 3, [[int]], [[i32_5]], [[i32_0]]
+; CHECK-MIR-DAG:   [[debug_info_none:%[0-9]+\:id\(s32\)]] = OpExtInst [[void_type]], 3, 0
+; CHECK-MIR-DAG:   OpExtInst [[void_type]], 3, 3, [[debug_info_none]], [[i32_5]], [[i32_0]]
+
+; Duplicates check
+; CHECK-MIR-NOT:   OpExtInst [[void_type]], 3, 3
 
 ; CHECK-SPIRV:	[[i32type:%[0-9]+]] = OpTypeInt 32 0
 ; CHECK-SPIRV-DAG:	[[i32_8:%[0-9]+]] = OpConstant [[i32type]] 8
@@ -79,6 +82,9 @@
 ; CHECK-SPIRV-DAG:	[[debug_info_none:%[0-9]+]] = OpExtInst {{%[0-9]+ %[0-9]+}} DebugInfoNone
 ; CHECK-SPIRV-DAG:	OpExtInst {{%[0-9]+ %[0-9]+}} DebugTypePointer [[debug_info_none]] [[i32_5]] [[i32_0]]
 
+; Duplicates check
+; CHECK-SPIRV-NOT:  OpExtInst {{%[0-9]+ %[0-9]+}} DebugTypePointer
+
 ; CHECK-OPTION-NOT: DebugTypePointer
 
 @gi0 = dso_local addrspace(1) global ptr addrspace(4) null, align 4, !dbg !0



More information about the llvm-commits mailing list