[llvm] [SPIRV] Addition of extension SPV_KHR_non_semantic_info and SPV_KHR_relaxed_extended_instruction (PR #165302)

Dmitry Sidorov via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 7 03:22:56 PST 2025


================
@@ -175,185 +422,1398 @@ 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;
-    };
+    SmallVector<std::pair<const DIBasicType *const, const Register>, 12>
+        BasicTypeRegPairs;
+    SmallVector<std::pair<const DICompositeType *const, const Register>, 12>
+        CompositeTypeRegPairs;
+    SmallVector<std::pair<const DIFile *const, const Register>, 12>
+        SourceRegPairs;
+    SmallVector<std::pair<const DIScope *const, const Register>, 12>
+        ScopeRegPairs;
+    SmallVector<std::pair<const DISubroutineType *const, const Register>, 12>
+        SubRoutineTypeRegPairs;
 
     const SPIRVType *VoidTy =
         GR->getOrCreateSPIRVType(Type::getVoidTy(*Context), MIRBuilder,
                                  SPIRV::AccessQualifier::ReadWrite, false);
-
-    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;
-        };
-
     const SPIRVType *I32Ty =
         GR->getOrCreateSPIRVType(Type::getInt32Ty(*Context), MIRBuilder,
                                  SPIRV::AccessQualifier::ReadWrite, false);
 
+    const Register I32ZeroReg =
+        GR->buildConstantInt(1, MIRBuilder, I32Ty, false);
+
     const Register DwarfVersionReg =
         GR->buildConstantInt(DwarfVersion, MIRBuilder, I32Ty, false);
 
     const Register DebugInfoVersionReg =
         GR->buildConstantInt(DebugInfoVersion, MIRBuilder, I32Ty, false);
 
+    SPIRVCodeGenContext Ctx(MIRBuilder, MRI, GR, VoidTy, I32Ty, TII, TRI, RBI,
+                            MF, I32ZeroReg, TM, SourceRegPairs, ScopeRegPairs,
+                            SubRoutineTypeRegPairs, BasicTypeRegPairs,
+                            CompositeTypeRegPairs);
+
     for (unsigned Idx = 0; Idx < LLVMSourceLanguages.size(); ++Idx) {
-      const Register FilePathStrReg = EmitOpString(FilePaths[Idx]);
-
-      const Register DebugSourceResIdReg = EmitDIInstruction(
-          SPIRV::NonSemanticExtInst::DebugSource, {FilePathStrReg});
-
-      SourceLanguage SpirvSourceLanguage = SourceLanguage::Unknown;
-      switch (LLVMSourceLanguages[Idx]) {
-      case dwarf::DW_LANG_OpenCL:
-        SpirvSourceLanguage = SourceLanguage::OpenCL_C;
-        break;
-      case dwarf::DW_LANG_OpenCL_CPP:
-        SpirvSourceLanguage = SourceLanguage::OpenCL_CPP;
-        break;
-      case dwarf::DW_LANG_CPP_for_OpenCL:
-        SpirvSourceLanguage = SourceLanguage::CPP_for_OpenCL;
-        break;
-      case dwarf::DW_LANG_GLSL:
-        SpirvSourceLanguage = SourceLanguage::GLSL;
-        break;
-      case dwarf::DW_LANG_HLSL:
-        SpirvSourceLanguage = SourceLanguage::HLSL;
-        break;
-      case dwarf::DW_LANG_SYCL:
-        SpirvSourceLanguage = SourceLanguage::SYCL;
-        break;
-      case dwarf::DW_LANG_Zig:
-        SpirvSourceLanguage = SourceLanguage::Zig;
+      emitSingleCompilationUnit(FilePaths[Idx], LLVMSourceLanguages[Idx], Ctx,
+                                DebugInfoVersionReg, DwarfVersionReg,
+                                DebugSourceResIdReg, DebugCompUnitResIdReg);
+
+      if (const DISubprogram *SP = Ctx.MF.getFunction().getSubprogram()) {
+        if (const DIFile *File = SP->getFile())
+          Ctx.GR->addDebugValue(File, DebugCompUnitResIdReg);
+        if (const DICompileUnit *Unit = SP->getUnit())
+          Ctx.GR->addDebugValue(Unit, DebugCompUnitResIdReg);
+      }
+    }
+    emitDebugMacroDefs(MF, Ctx);
+    emitDebugBuildIdentifier(BuildIdentifier, Ctx);
+    emitDebugStoragePath(BuildStoragePath, Ctx);
+    emitDebugBasicTypes(Collector.BasicTypes, Ctx);
+
+    emitSubroutineTypes(Collector.SubRoutineTypes, Ctx);
+    emitSubprograms(Collector.SubPrograms, Ctx);
+    emitLexicalScopes(Collector.LexicalScopes, Ctx);
+    emitDebugPointerTypes(Collector.PointerDerivedTypes, Ctx);
+    emitDebugArrayTypes(Collector.ArrayTypes, Ctx);
+    emitAllDebugTypeComposites(Collector.CompositeTypes, Ctx);
+    emitDebugTypeEnum(Collector.EnumTypes, Ctx);
+    emitAllTemplateDebugInstructions(Collector.CompositeTypesWithTemplates,
+                                     Ctx);
+    emitDebugQualifiedTypes(Collector.QualifiedDerivedTypes, Ctx);
+    emitDebugTypedefs(Collector.TypedefTypes, Ctx);
+    emitDebugTypePtrToMember(Collector.PtrToMemberTypes, Ctx);
+    emitAllDebugGlobalVariables(MF, Ctx);
+    emitDebugImportedEntities(Collector.ImportedEntities, Ctx);
+  }
+  return true;
+}
+
+bool SPIRVEmitNonSemanticDI::runOnMachineFunction(MachineFunction &MF) {
+  bool Res = false;
+  if (!IsGlobalDIEmitted) {
+    IsGlobalDIEmitted = true;
+    Res = emitGlobalDI(MF);
+  }
+  return Res;
+}
+
+Register SPIRVEmitNonSemanticDI::EmitOpString(StringRef SR,
+                                              SPIRVCodeGenContext &Ctx) {
+  const Register StrReg = Ctx.MRI.createVirtualRegister(&SPIRV::IDRegClass);
+  Ctx.MRI.setType(StrReg, LLT::scalar(32));
+  MachineInstrBuilder MIB = Ctx.MIRBuilder.buildInstr(SPIRV::OpString);
+  MIB.addDef(StrReg);
+  addStringImm(SR, MIB);
+  return StrReg;
+}
+
+Register SPIRVEmitNonSemanticDI::EmitDIInstruction(
+    SPIRV::NonSemanticExtInst::NonSemanticExtInst Inst,
+    ArrayRef<Register> Operands, SPIRVCodeGenContext &Ctx, bool HasForwardRef,
+    Register DefReg) {
+
+  Register InstReg = DefReg;
+  if (!InstReg.isValid()) {
+    InstReg = Ctx.MRI.createVirtualRegister(&SPIRV::IDRegClass);
+    Ctx.MRI.setType(InstReg, LLT::scalar(32));
+  }
+
+  unsigned Opcode =
+      HasForwardRef ? SPIRV::OpExtInstWithForwardRefsKHR : SPIRV::OpExtInst;
+  MachineInstrBuilder MIB =
+      Ctx.MIRBuilder.buildInstr(Opcode)
+          .addDef(InstReg)
+          .addUse(Ctx.GR->getSPIRVTypeID(Ctx.VoidTy))
+          .addImm(static_cast<int64_t>(
+              SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100))
+          .addImm(Inst);
+  for (auto Reg : Operands) {
+    MIB.addUse(Reg);
+  }
+  MIB.constrainAllUses(*Ctx.TII, *Ctx.TRI, *Ctx.RBI);
+  Ctx.GR->assignSPIRVTypeToVReg(Ctx.VoidTy, InstReg, Ctx.MF);
+
+  // If we were passed a valid DefReg, it was a placeholder.
+  // Now that we've emitted the instruction that defines it, resolve it.
+  if (DefReg.isValid() && Ctx.GR->isForwardPlaceholder(DefReg))
+    Ctx.GR->resolveForwardPlaceholder(DefReg);
+
+  return InstReg;
+}
+
+uint32_t SPIRVEmitNonSemanticDI::transDebugFlags(const DINode *DN) {
+  uint32_t Flags = 0;
+  if (const DIGlobalVariable *GV = dyn_cast<DIGlobalVariable>(DN)) {
+    if (GV->isLocalToUnit())
+      Flags |= Flag::FlagIsLocal;
+    if (GV->isDefinition())
+      Flags |= Flag::FlagIsDefinition;
+  }
+  if (const DISubprogram *DS = dyn_cast<DISubprogram>(DN)) {
+    if (DS->isLocalToUnit())
+      Flags |= Flag::FlagIsLocal;
+    if (DS->isOptimized())
+      Flags |= Flag::FlagIsOptimized;
+    if (DS->isDefinition())
+      Flags |= Flag::FlagIsDefinition;
+    Flags |= mapDebugFlags(DS->getFlags());
+  }
+  if (DN->getTag() == dwarf::DW_TAG_reference_type)
+    Flags |= Flag::FlagIsLValueReference;
+  if (DN->getTag() == dwarf::DW_TAG_rvalue_reference_type)
+    Flags |= Flag::FlagIsRValueReference;
+  if (const DIType *DT = dyn_cast<DIType>(DN))
+    Flags |= mapDebugFlags(DT->getFlags());
+  if (const DILocalVariable *DLocVar = dyn_cast<DILocalVariable>(DN))
+    Flags |= mapDebugFlags(DLocVar->getFlags());
+
+  return Flags;
+}
+
+uint32_t SPIRVEmitNonSemanticDI::mapDebugFlags(DINode::DIFlags DFlags) {
+  uint32_t Flags = 0;
+  if ((DFlags & DINode::FlagAccessibility) == DINode::FlagPublic)
+    Flags |= Flag::FlagIsPublic;
+  if ((DFlags & DINode::FlagAccessibility) == DINode::FlagProtected)
+    Flags |= Flag::FlagIsProtected;
+  if ((DFlags & DINode::FlagAccessibility) == DINode::FlagPrivate)
+    Flags |= Flag::FlagIsPrivate;
+
+  if (DFlags & DINode::FlagFwdDecl)
+    Flags |= Flag::FlagIsFwdDecl;
+  if (DFlags & DINode::FlagArtificial)
+    Flags |= Flag::FlagIsArtificial;
+  if (DFlags & DINode::FlagExplicit)
+    Flags |= Flag::FlagIsExplicit;
+  if (DFlags & DINode::FlagPrototyped)
+    Flags |= Flag::FlagIsPrototyped;
+  if (DFlags & DINode::FlagObjectPointer)
+    Flags |= Flag::FlagIsObjectPointer;
+  if (DFlags & DINode::FlagStaticMember)
+    Flags |= Flag::FlagIsStaticMember;
+  // inderect variable flag ?
+  if (DFlags & DINode::FlagLValueReference)
+    Flags |= Flag::FlagIsLValueReference;
+  if (DFlags & DINode::FlagRValueReference)
+    Flags |= Flag::FlagIsRValueReference;
+  if (DFlags & DINode::FlagTypePassByValue)
+    Flags |= Flag::FlagTypePassByValue;
+  if (DFlags & DINode::FlagTypePassByReference)
+    Flags |= Flag::FlagTypePassByReference;
+  if (DFlags & DINode::FlagEnumClass)
+    Flags |= Flag::FlagIsEnumClass;
+  return Flags;
+}
+
+void SPIRVEmitNonSemanticDI::emitDebugTypeEnum(
+    const SmallPtrSetImpl<const DICompositeType *> &EnumTypes,
+    SPIRVCodeGenContext &Ctx) {
+  for (auto *EnumTy : EnumTypes) {
+    if (!EnumTy || EnumTy->getTag() != dwarf::DW_TAG_enumeration_type)
+      continue;
+    if (Register Existing = Ctx.GR->getDebugValue(EnumTy); Existing.isValid())
+      continue;
+    Register NameStr = EmitOpString(EnumTy->getName(), Ctx);
+    bool UnderlyingTypeIsFwd = false;
+    Register UnderlyingTypeReg = findBaseTypeRegisterRecursive(
+        EnumTy->getBaseType(), Ctx, UnderlyingTypeIsFwd);
+    if (!UnderlyingTypeReg.isValid()) {
+      UnderlyingTypeReg = EmitDIInstruction(
+          SPIRV::NonSemanticExtInst::DebugInfoNone, {}, Ctx, false);
+      UnderlyingTypeIsFwd = false;
+    }
+    Register SourceReg =
+        findRegisterFromMap(EnumTy->getFile(), Ctx.SourceRegPairs);
+    if (!SourceReg.isValid()) {
+      SourceReg = EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugInfoNone,
+                                    {}, Ctx, false);
+    }
+    Register Line = Ctx.GR->buildConstantInt(EnumTy->getLine(), Ctx.MIRBuilder,
+                                             Ctx.I32Ty, false);
+    Register Column =
+        Ctx.GR->buildConstantInt(1, Ctx.MIRBuilder, Ctx.I32Ty, false);
+
+    Register ParentReg = Ctx.GR->getDebugValue(EnumTy->getScope());
+    if (!ParentReg.isValid()) {
+      llvm::errs() << "Warning: Could not find Parent scope register for Enum: "
+                   << EnumTy->getName() << "\n";
+      ParentReg = Ctx.GR->getDebugValue(EnumTy->getFile());
+      if (!ParentReg.isValid()) {
+        ParentReg = EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugInfoNone,
+                                      {}, Ctx, false);
       }
+    }
+    Register Size = Ctx.GR->buildConstantInt(EnumTy->getSizeInBits(),
+                                             Ctx.MIRBuilder, Ctx.I32Ty, false);
+    uint32_t Flags = transDebugFlags(EnumTy);
+    Register FlagsReg =
+        Ctx.GR->buildConstantInt(Flags, Ctx.MIRBuilder, Ctx.I32Ty, false);
+    SmallVector<Register, 16> EnumOperands;
+    for (Metadata *MD : EnumTy->getElements()) {
+      if (auto *E = dyn_cast<DIEnumerator>(MD)) {
+        Register Val = Ctx.GR->buildConstantInt(
+            E->getValue().getZExtValue(), Ctx.MIRBuilder, Ctx.I32Ty, false);
+        Register Name = EmitOpString(E->getName(), Ctx);
+        EnumOperands.push_back(Val);
+        EnumOperands.push_back(Name);
+      }
+    }
+    SmallVector<Register, 12> Ops = {
+        NameStr, UnderlyingTypeReg, SourceReg, Line,
+        Column,  ParentReg,         Size,      FlagsReg};
+    Ops.append(EnumOperands);
+    bool HasForwardRef = UnderlyingTypeIsFwd;
+    Register DefReg = Ctx.GR->getDebugValue(EnumTy);
+    Register Res = EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugTypeEnum,
+                                     Ops, Ctx, HasForwardRef, DefReg);
+    Ctx.GR->addDebugValue(EnumTy, Res);
+    Ctx.CompositeTypeRegPairs.emplace_back(EnumTy, Res);
+  }
+}
+
+void SPIRVEmitNonSemanticDI::emitSingleCompilationUnit(
+    StringRef FilePath, int64_t Language, SPIRVCodeGenContext &Ctx,
+    Register DebugInfoVersionReg, Register DwarfVersionReg,
+    Register &DebugSourceResIdReg, Register &DebugCompUnitResIdReg) {
+
+  const Register FilePathStrReg = EmitOpString(FilePath, Ctx);
 
-      const Register SourceLanguageReg =
-          GR->buildConstantInt(SpirvSourceLanguage, MIRBuilder, I32Ty, false);
+  const Function *F = &Ctx.MF.getFunction();
+  const DISubprogram *SP = F ? F->getSubprogram() : nullptr;
+  const DIFile *FileMDNode = nullptr;
+  if (SP)
+    FileMDNode = SP->getFile();
 
-      [[maybe_unused]]
-      const Register DebugCompUnitResIdReg =
-          EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugCompilationUnit,
-                            {DebugInfoVersionReg, DwarfVersionReg,
-                             DebugSourceResIdReg, SourceLanguageReg});
+  std::string FileMDContents;
+  if (FileMDNode && FileMDNode->getRawFile() &&
+      FileMDNode->getSource().has_value())
+    FileMDContents = FileMDNode->getSource().value().str();
+
+  if (FileMDContents.empty()) {
+    DebugSourceResIdReg = EmitDIInstruction(
+        SPIRV::NonSemanticExtInst::DebugSource, {FilePathStrReg}, Ctx, false);
+  } else {
+    constexpr size_t MaxNumWords = UINT16_MAX - 2;
+    constexpr size_t MaxStrSize = MaxNumWords * 4 - 1;
+    std::string RemainingSource = FileMDContents;
+    std::string FirstChunk = RemainingSource.substr(0, MaxStrSize);
+    const Register FirstTextStrReg = EmitOpString(FirstChunk, Ctx);
+    DebugSourceResIdReg =
+        EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugSource,
+                          {FilePathStrReg, FirstTextStrReg}, Ctx, false);
+
+    RemainingSource.erase(0, FirstChunk.size());
+
+    while (!RemainingSource.empty()) {
+      std::string NextChunk = RemainingSource.substr(0, MaxStrSize);
+      const Register ContinuedStrReg = EmitOpString(NextChunk, Ctx);
+      EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugSourceContinued,
+                        {ContinuedStrReg}, Ctx, false);
+      RemainingSource.erase(0, NextChunk.size());
     }
+  }
+  Ctx.SourceRegPairs.emplace_back(FileMDNode, DebugSourceResIdReg);
 
-    // 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, false);
+  SourceLanguage SpirvSourceLanguage = SourceLanguage::Unknown;
+  switch (Language) {
+  case dwarf::DW_LANG_OpenCL:
+    SpirvSourceLanguage = SourceLanguage::OpenCL_C;
+    break;
+  case dwarf::DW_LANG_OpenCL_CPP:
+    SpirvSourceLanguage = SourceLanguage::OpenCL_CPP;
+    break;
+  case dwarf::DW_LANG_CPP_for_OpenCL:
+    SpirvSourceLanguage = SourceLanguage::CPP_for_OpenCL;
+    break;
+  case dwarf::DW_LANG_GLSL:
+    SpirvSourceLanguage = SourceLanguage::GLSL;
+    break;
+  case dwarf::DW_LANG_HLSL:
+    SpirvSourceLanguage = SourceLanguage::HLSL;
+    break;
+  case dwarf::DW_LANG_SYCL:
+    SpirvSourceLanguage = SourceLanguage::SYCL;
+    break;
+  case dwarf::DW_LANG_Zig:
+    SpirvSourceLanguage = SourceLanguage::Zig;
+    break;
+  case dwarf::DW_LANG_C_plus_plus_14:
+    SpirvSourceLanguage = SourceLanguage::CPP;
+    break;
+  default:
+    SpirvSourceLanguage = SourceLanguage::Unknown;
+    break;
+  }
 
-    // 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;
+  const Register SourceLanguageReg = Ctx.GR->buildConstantInt(
+      SpirvSourceLanguage, Ctx.MIRBuilder, Ctx.I32Ty, false);
+
+  DebugCompUnitResIdReg =
+      EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugCompilationUnit,
+                        {DebugInfoVersionReg, DwarfVersionReg,
+                         DebugSourceResIdReg, SourceLanguageReg},
+                        Ctx, false);
+}
+
+Register SPIRVEmitNonSemanticDI::findEmittedBasicTypeReg(
+    const DIType *BaseType,
+    const SmallVectorImpl<std::pair<const DIBasicType *const, const Register>>
+        &BasicTypeRegPairs) {
+  const DIType *Ty = BaseType;
+
+  while (Ty && !isa<DIBasicType>(Ty)) {
+    if (auto *Derived = dyn_cast<DIDerivedType>(Ty))
+      if (Derived->getBaseType())
+        Ty = Derived->getBaseType();
+      else
+        return Register();
+    else
+      return Register();
+  }
+
+  if (const auto *BT = dyn_cast<DIBasicType>(Ty)) {
+    StringRef Name = BT->getName();
+    uint64_t Size = BT->getSizeInBits();
+
+    for (const auto &[DefinedBT, Reg] : BasicTypeRegPairs) {
+      if (DefinedBT->getName() == Name && DefinedBT->getSizeInBits() == Size)
+        return Reg;
+    }
+  }
+  return Register();
+}
+
+Register SPIRVEmitNonSemanticDI::findEmittedCompositeTypeReg(
+    const DIType *BaseType,
+    const SmallVectorImpl<std::pair<const DICompositeType *const,
+                                    const Register>> &CompositeTypeRegPairs) {
+
+  StringRef Name = BaseType->getName();
+  uint64_t Size = BaseType->getSizeInBits();
+  unsigned Tag = BaseType->getTag();
+
+  for (const auto &[DefinedCT, Reg] : CompositeTypeRegPairs) {
+    if (DefinedCT->getName() == Name && DefinedCT->getSizeInBits() == Size &&
+        DefinedCT->getTag() == Tag)
+      return Reg;
+  }
+
+  return Register();
+}
+
+void SPIRVEmitNonSemanticDI::emitDebugBuildIdentifier(
+    StringRef BuildIdentifier, SPIRVCodeGenContext &Ctx) {
+  if (BuildIdentifier.empty())
+    return;
+
+  const Register BuildIdStrReg = EmitOpString(BuildIdentifier, Ctx);
+  uint32_t Flags = 0;
+  if (BuildIdentifier.contains("IdentifierPossibleDuplicates"))
+    Flags |= (1 << 0);
+  const Register FlagsReg =
+      Ctx.GR->buildConstantInt(Flags, Ctx.MIRBuilder, Ctx.I32Ty, false, false);
+
+  EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugBuildIdentifier,
+                    {BuildIdStrReg, FlagsReg}, Ctx, false);
+}
+
+void SPIRVEmitNonSemanticDI::emitDebugStoragePath(StringRef BuildStoragePath,
+                                                  SPIRVCodeGenContext &Ctx) {
+  if (!BuildStoragePath.empty()) {
+    const Register PathStrReg = EmitOpString(BuildStoragePath, Ctx);
+    EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugStoragePath, {PathStrReg},
+                      Ctx, false);
+  }
+}
+
+void SPIRVEmitNonSemanticDI::emitDebugBasicTypes(
+    const SmallPtrSetImpl<DIBasicType *> &BasicTypes,
+    SPIRVCodeGenContext &Ctx) {
+  // 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
+  for (auto *BasicType : BasicTypes) {
+    if (!BasicType)
+      continue;
+    const Register BasicTypeStrReg = EmitOpString(BasicType->getName(), Ctx);
+
+    const Register ConstIntBitwidthReg = Ctx.GR->buildConstantInt(
+        BasicType->getSizeInBits(), Ctx.MIRBuilder, Ctx.I32Ty, false, 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 = Ctx.GR->buildConstantInt(
+        AttributeEncoding, Ctx.MIRBuilder, Ctx.I32Ty, false, false);
+
+    const Register FlagsReg = Ctx.GR->buildConstantInt(
+        transDebugFlags(BasicType), Ctx.MIRBuilder, Ctx.I32Ty, false, false);
+
+    [[maybe_unused]]
+    const Register BasicTypeReg = EmitDIInstruction(
+        SPIRV::NonSemanticExtInst::DebugTypeBasic,
+        {BasicTypeStrReg, ConstIntBitwidthReg, AttributeEncodingReg, FlagsReg},
+        Ctx, false);
+    Ctx.GR->addDebugValue(BasicType, BasicTypeReg);
+    Ctx.BasicTypeRegPairs.emplace_back(BasicType, BasicTypeReg);
+  }
+}
+
+void SPIRVEmitNonSemanticDI::emitDebugPointerTypes(
+    const SmallPtrSetImpl<DIDerivedType *> &PointerDerivedTypes,
+    SPIRVCodeGenContext &Ctx) {
+
+  if (PointerDerivedTypes.empty())
+    return;
+
+  for (const auto *PointerDerivedType : PointerDerivedTypes) {
+    uint64_t DWARFAddrSpace = 0;
+    if (PointerDerivedType->getDWARFAddressSpace().has_value())
+      DWARFAddrSpace = PointerDerivedType->getDWARFAddressSpace().value();
+    else {
+      LLVM_DEBUG(dbgs() << "Warning: pointer DI has no DWARF address space; "
+                        << "falling back to 0 (generic)\n");
+    }
+    const Register StorageClassReg = Ctx.GR->buildConstantInt(
+        addressSpaceToStorageClass(DWARFAddrSpace, *Ctx.TM->getSubtargetImpl()),
+        Ctx.MIRBuilder, Ctx.I32Ty, false);
+    const uint32_t Flags = transDebugFlags(PointerDerivedType);
+    const Register FlagsReg = Ctx.GR->buildConstantInt(Flags, Ctx.MIRBuilder,
+                                                       Ctx.I32Ty, false, false);
+
+    const DIType *BaseTy = PointerDerivedType->getBaseType();
+    bool HasForwardRef = false;
+    Register BaseTypeReg =
+        findBaseTypeRegisterRecursive(BaseTy, Ctx, HasForwardRef);
+
+    if (!BaseTypeReg.isValid()) {
+      llvm::errs() << "Warning: Failed to find or create placeholder for base "
+                      "type of pointer.\n";
+      BaseTypeReg = EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugInfoNone,
+                                      {}, Ctx, false);
+      HasForwardRef = false;
+    }
+    const Register DebugPointerTypeReg = EmitDIInstruction(
+        SPIRV::NonSemanticExtInst::DebugTypePointer,
+        {BaseTypeReg, StorageClassReg, FlagsReg}, Ctx, HasForwardRef);
+
+    Ctx.GR->addDebugValue(PointerDerivedType, DebugPointerTypeReg);
+  }
+}
+
+void SPIRVEmitNonSemanticDI::emitLexicalScopes(
+    const SmallPtrSetImpl<DIScope *> &LexicalScopes, SPIRVCodeGenContext &Ctx) {
+  for (DIScope *Scope : LexicalScopes) {
+    if (!Scope)
+      continue;
+
+    SmallVector<Register, 4> Operands;
+    Register ScopeSourceReg =
+        findRegisterFromMap(Scope->getFile(), Ctx.SourceRegPairs);
+    Register ScopeParentReg =
+        findRegisterFromMap(Scope->getScope(), Ctx.ScopeRegPairs);
+
+    Operands.push_back(ScopeSourceReg);
+
+    if (auto *LBF = dyn_cast<DILexicalBlockFile>(Scope)) {
+      Register Discriminator = Ctx.GR->buildConstantInt(
+          LBF->getDiscriminator(), Ctx.MIRBuilder, Ctx.I32Ty, false, false);
+
+      Operands.push_back(Discriminator);
+      Operands.push_back(ScopeParentReg);
+
+      EmitDIInstruction(
+          SPIRV::NonSemanticExtInst::DebugLexicalBlockDiscriminator, Operands,
+          Ctx, false);
+
+    } else if (auto *LB = dyn_cast<DILexicalBlock>(Scope)) {
+      Operands.push_back(Ctx.GR->buildConstantInt(LB->getLine(), Ctx.MIRBuilder,
+                                                  Ctx.I32Ty, false, false));
+      Operands.push_back(Ctx.GR->buildConstantInt(
+          LB->getColumn(), Ctx.MIRBuilder, Ctx.I32Ty, false, false));
+      Operands.push_back(ScopeParentReg);
+
+      Register LexicalScopeReg = EmitDIInstruction(
+          SPIRV::NonSemanticExtInst::DebugLexicalBlock, Operands, Ctx, false);
+
+      Ctx.ScopeRegPairs.emplace_back(Scope, LexicalScopeReg);
+    }
+  }
+}
+
+void SPIRVEmitNonSemanticDI::emitSubroutineTypes(
+    const SmallPtrSet<DISubroutineType *, 12> &SubRoutineTypes,
+    SPIRVCodeGenContext &Ctx) {
+
+  for (const auto *SubroutineType : SubRoutineTypes) {
+    SmallVector<Register, 6> TypeRegs;
+    bool HasForwardRef = false;
+
+    const Register FlagsReg =
+        Ctx.GR->buildConstantInt(transDebugFlags(SubroutineType),
+                                 Ctx.MIRBuilder, Ctx.I32Ty, false, false);
+
+    DITypeRefArray Types = SubroutineType->getTypeArray();
+    const DIType *RetTy =
+        Types.size() > 0 ? dyn_cast_or_null<DIType>(Types[0]) : nullptr;
+    Register RetTypeReg;
+    bool RetTyIsFwd = false;
+    if (RetTy) {
+      RetTypeReg = findBaseTypeRegisterRecursive(RetTy, Ctx, RetTyIsFwd);
+    }
+    if (!RetTypeReg.isValid()) {
+      const SPIRVType *VoidTy = Ctx.GR->getOrCreateSPIRVType(
+          Type::getVoidTy(Ctx.MF.getFunction().getContext()), Ctx.MIRBuilder,
+          SPIRV::AccessQualifier::ReadWrite, false);
+      RetTypeReg = VoidTy->getOperand(0).getReg();
+      RetTyIsFwd = false;
+    }
+    TypeRegs.push_back(RetTypeReg);
+    if (RetTyIsFwd)
+      HasForwardRef = true;
+    for (unsigned I = 1; I < Types.size(); ++I) {
+      if (const DIType *ParamTy = dyn_cast_or_null<DIType>(Types[I])) {
+        bool ParamTyIsFwd = false;
+        Register ParamTypeReg =
+            findBaseTypeRegisterRecursive(ParamTy, Ctx, ParamTyIsFwd);
+
+        if (!ParamTypeReg.isValid()) {
+          llvm::errs()
+              << "Warning: Could not find type for function parameter.\n";
+          const SPIRVType *VoidTy = Ctx.GR->getOrCreateSPIRVType(
+              Type::getVoidTy(Ctx.MF.getFunction().getContext()),
+              Ctx.MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false);
+          ParamTypeReg = VoidTy->getOperand(0).getReg();
+          ParamTyIsFwd = false;
+        }
+        TypeRegs.push_back(ParamTypeReg);
+        if (ParamTyIsFwd)
+          HasForwardRef = true;
+      } else {
+        const SPIRVType *VoidTy = Ctx.GR->getOrCreateSPIRVType(
+            Type::getVoidTy(Ctx.MF.getFunction().getContext()), Ctx.MIRBuilder,
+            SPIRV::AccessQualifier::ReadWrite, false);
+        Register TypeReg = VoidTy->getOperand(0).getReg();
+        TypeRegs.push_back(TypeReg);
       }
+    }
+    Register DefReg = Ctx.GR->getDebugValue(SubroutineType);
+    SmallVector<Register, 6> Operands;
+    Operands.push_back(FlagsReg);
+    Operands.append(TypeRegs);
+    const Register FuncTypeReg =
+        EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugTypeFunction,
+                          Operands, Ctx, HasForwardRef, DefReg);
+    Ctx.GR->addDebugValue(SubroutineType, FuncTypeReg);
+    Ctx.SubRoutineTypeRegPairs.emplace_back(SubroutineType, FuncTypeReg);
+  }
+}
 
-      const Register AttributeEncodingReg =
-          GR->buildConstantInt(AttributeEncoding, MIRBuilder, I32Ty, false);
-
-      const Register BasicTypeReg =
-          EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugTypeBasic,
-                            {BasicTypeStrReg, ConstIntBitwidthReg,
-                             AttributeEncodingReg, I32ZeroReg});
-      BasicTypeRegPairs.emplace_back(BasicType, BasicTypeReg);
-    }
-
-    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 =
-            dyn_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});
-            }
-          }
+void SPIRVEmitNonSemanticDI::emitSubprograms(
+    const SmallPtrSet<DISubprogram *, 12> &SubPrograms,
+    SPIRVCodeGenContext &Ctx) {
+
+  for (const auto *SubProgram : SubPrograms) {
+    SmallVector<Register, 10> Operands;
+
+    Operands.push_back(EmitOpString(SubProgram->getName(), Ctx));
+    Operands.push_back(
+        findRegisterFromMap(SubProgram->getType(), Ctx.SubRoutineTypeRegPairs));
+    Operands.push_back(
+        findRegisterFromMap(SubProgram->getFile(), Ctx.SourceRegPairs));
+    Operands.push_back(Ctx.GR->buildConstantInt(
+        SubProgram->getLine(), Ctx.MIRBuilder, Ctx.I32Ty, false, false));
+    Operands.push_back(Ctx.I32ZeroReg);
+    Operands.push_back(Ctx.GR->getDebugValue(SubProgram->getFile()));
+    Operands.push_back(EmitOpString(SubProgram->getLinkageName(), Ctx));
+    Operands.push_back(Ctx.GR->buildConstantInt(
+        SubProgram->getFlags(), Ctx.MIRBuilder, Ctx.I32Ty, false, false));
+
+    if (!SubProgram->isDefinition()) {
+      EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugFunctionDeclaration,
+                        Operands, Ctx, false);
+    } else {
+      Operands.push_back(Ctx.GR->buildConstantInt(
+          SubProgram->getScopeLine(), Ctx.MIRBuilder, Ctx.I32Ty, false, false));
+      const Register FuncReg = EmitDIInstruction(
+          SPIRV::NonSemanticExtInst::DebugFunction, Operands, Ctx, false);
+
+      Ctx.ScopeRegPairs.emplace_back(dynamic_cast<const DIScope *>(SubProgram),
+                                     FuncReg);
+    }
+  }
+}
+
+uint32_t SPIRVEmitNonSemanticDI::mapTagToQualifierEncoding(unsigned Tag) {
+  switch (Tag) {
+  case dwarf::DW_TAG_const_type:
+    return QualifierTypeAttributeEncoding::ConstType;
+  case dwarf::DW_TAG_volatile_type:
+    return QualifierTypeAttributeEncoding::VolatileType;
+  case dwarf::DW_TAG_restrict_type:
+    return QualifierTypeAttributeEncoding::RestrictType;
+  case dwarf::DW_TAG_atomic_type:
+    return QualifierTypeAttributeEncoding::AtomicType;
+  default:
+    llvm_unreachable("Unknown DWARF tag for DebugTypeQualifier");
+  }
+}
+
+uint32_t SPIRVEmitNonSemanticDI::mapImportedTagToEncoding(
+    const DIImportedEntity *Imported) {
+  switch (Imported->getTag()) {
+  case dwarf::DW_TAG_imported_module:
+    return ImportedEnityAttributeEncoding::ImportedModule;
+  case dwarf::DW_TAG_imported_declaration:
+    return ImportedEnityAttributeEncoding::ImportedDeclaration;
+  default:
+    llvm_unreachable("Unknown DWARF tag for DebugImportedEntity");
+  }
+}
+
+void SPIRVEmitNonSemanticDI::emitDebugQualifiedTypes(
+    const SmallPtrSetImpl<DIDerivedType *> &QualifiedDerivedTypes,
+    SPIRVCodeGenContext &Ctx) {
+  if (!QualifiedDerivedTypes.empty()) {
+    for (const auto *QualifiedDT : QualifiedDerivedTypes) {
+      bool IsForwardRef = false;
+      Register BaseTypeReg = findBaseTypeRegisterRecursive(
+          QualifiedDT->getBaseType(), Ctx, IsForwardRef);
+
+      if (!BaseTypeReg.isValid()) {
+        llvm::errs()
+            << "Warning: Could not find base type for DebugTypeQualifier.\n";
+        BaseTypeReg = EmitDIInstruction(
+            SPIRV::NonSemanticExtInst::DebugInfoNone, {}, Ctx, false);
+        IsForwardRef = false;
+      }
+
+      const uint32_t QualifierValue =
+          mapTagToQualifierEncoding(QualifiedDT->getTag());
+      const Register QualifierConstReg = Ctx.GR->buildConstantInt(
+          QualifierValue, Ctx.MIRBuilder, Ctx.I32Ty, false, false);
+
+      Register DefReg = Ctx.GR->getDebugValue(QualifiedDT);
+
+      const Register DebugQualifiedTypeReg = EmitDIInstruction(
+          SPIRV::NonSemanticExtInst::DebugTypeQualifier,
+          {BaseTypeReg, QualifierConstReg}, Ctx, IsForwardRef, DefReg);
+
+      Ctx.GR->addDebugValue(QualifiedDT, DebugQualifiedTypeReg);
+    }
+  }
+}
+
+void SPIRVEmitNonSemanticDI::emitDebugTypedefs(
+    const SmallPtrSetImpl<DIDerivedType *> &TypedefTypes,
+    SPIRVCodeGenContext &Ctx) {
+  for (const auto *TypedefDT : TypedefTypes) {
+    bool HasForwardRef = false;
+    Register BaseTypeReg = findBaseTypeRegisterRecursive(
+        TypedefDT->getBaseType(), Ctx, HasForwardRef);
+
+    if (!BaseTypeReg.isValid()) {
+      llvm::errs() << "Warning: Could not find base type for Typedef: "
+                   << TypedefDT->getName() << "\n";
+      BaseTypeReg = EmitDIInstruction(SPIRV::NonSemanticExtInst::DebugInfoNone,
+                                      {}, Ctx, false);
+      HasForwardRef = false;
+    }
----------------
MrSidims wrote:

Grey area. Fine with leaving it as is for void*

https://github.com/llvm/llvm-project/pull/165302


More information about the llvm-commits mailing list