[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:57 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;
+ }
----------------
MrSidims wrote:
Per spec it's not allowed to have DebugInfoNone to be Source. Note: llvm-spirv may be has such lowering, if so - it's a bug there as well as in other cases, where it relaxes rules for DebugInfoNone.
Correct behaviour is to skip debug info instruction.
https://github.com/llvm/llvm-project/pull/165302
More information about the llvm-commits
mailing list