[llvm] [SPIRV] Emit NonSemantic DebugGlobalVariable (PR #207230)
Manuel Carrasco via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 13 05:07:27 PDT 2026
https://github.com/mgcarrasco updated https://github.com/llvm/llvm-project/pull/207230
>From 5e7551a6ebd39aa3f51b40c6f3fe17d9b7d14f69 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Thu, 2 Jul 2026 11:59:38 -0500
Subject: [PATCH 1/9] [SPIRV] Emit NonSemantic DebugGlobalVariable
Add emitDebugGlobalVariable to the NSDI handler, translating each
DIGlobalVariable to a DebugGlobalVariable ext inst.
---
.../SPIRV/SPIRVNonSemanticDebugHandler.cpp | 122 ++++++++++++++++++
.../SPIRV/SPIRVNonSemanticDebugHandler.h | 53 ++++++++
...g-global-variable-default-address-space.ll | 43 ++++++
.../debug-global-variable-init-expr.ll | 42 ++++++
.../debug-global-variable-no-backing-var.ll | 42 ++++++
.../debug-global-variable-no-type.ll | 47 +++++++
...ebug-global-variable-skip-static-member.ll | 39 ++++++
...g-global-variable-skip-type-not-in-regs.ll | 34 +++++
.../SPIRV/debug-info/debug-global-variable.ll | 53 ++++++++
9 files changed, 475 insertions(+)
create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-default-address-space.ll
create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-init-expr.ll
create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-backing-var.ll
create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-type.ll
create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-skip-static-member.ll
create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-skip-type-not-in-regs.ll
create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index 7303288aaea16..42c784d0a461d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
@@ -16,6 +16,7 @@
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCStreamer.h"
@@ -194,6 +195,9 @@ void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
SubroutineTypes.clear();
VectorTypes.clear();
SubprogramDeclarations.clear();
+ GlobalVariables.clear();
+ DIGVToLLVMGV.clear();
+ DIGVToInitExpr.clear();
DebugFunctionDeclarationRegs.clear();
ScopeToPathOpStringReg.clear();
CUToCompilationUnitDbgReg.clear();
@@ -251,6 +255,27 @@ void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
if (!SP->isDefinition())
SubprogramDeclarations.push_back(SP);
}
+
+ // Map DIGlobalVariable -> llvm::GlobalVariable for globals that attach !dbg.
+ // The link lives on the IR global (via DIGlobalVariableExpression); DIGV
+ // metadata has no back-reference to its @g.
+ for (const GlobalVariable &G : M->globals()) {
+ SmallVector<DIGlobalVariableExpression *, 4> GVEs;
+ G.getDebugInfo(GVEs);
+ for (DIGlobalVariableExpression *GVE : GVEs)
+ DIGVToLLVMGV.try_emplace(GVE->getVariable(), &G);
+ }
+
+ // DebugInfoFinder deduplicates expressions but not by their pointed
+ // variables. We use a SmallSetVector to deduplicate them.
+ for (const DIGlobalVariableExpression *GVE : Finder.global_variables()) {
+ GlobalVariables.insert(GVE->getVariable());
+ const DIGlobalVariable *GV = GVE->getVariable();
+ const DIExpression *Expr = GVE->getExpression();
+ // For Variable operand of DebugExpression type in DebugGlobalVariable.
+ if (GV && Expr && Expr->getNumElements())
+ DIGVToInitExpr.try_emplace(GV, Expr);
+ }
}
void SPIRVNonSemanticDebugHandler::prepareModuleOutput(
@@ -561,6 +586,90 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg(
return lookupOptReg(DebugTypeRegs, Ty);
}
+std::optional<MCRegister>
+SPIRVNonSemanticDebugHandler::resolveGlobalVariableParent(
+ const DIGlobalVariable *GV) const {
+ // TODO: When this backend emits debug instructions for namespace, subprogram,
+ // and module scopes, return GV->getScope()'s debug id.
+
+ // Fallback: first module compile unit (SPIRV-LLVM-Translator default).
+ if (CompileUnits.empty())
+ return std::nullopt;
+ return lookupOptReg(CUToCompilationUnitDbgReg, CompileUnits[0].TheCU);
+}
+
+// Unimplemented no-op; see emitDebugExpression declaration.
+std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugExpression(
+ const DIExpression *, MCRegister, MCRegister, SPIRV::ModuleAnalysisInfo &) {
+ return std::nullopt;
+}
+
+std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
+ const DIGlobalVariable *GV, MCRegister VoidTypeReg, MCRegister I32TypeReg,
+ MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
+ assert(GV && "GV must not be null in emitDebugGlobalVariable");
+
+ auto ParentRegOpt = resolveGlobalVariableParent(GV);
+ if (!ParentRegOpt)
+ return std::nullopt;
+
+ // TyReg: DebugInfoNone when GV has no DI type (as done in
+ // SPIRV-LLVM-Translator). Declarations (isDefinition: false) can have null
+ // getType() while definitions must have a non-null one (enforced by the IR
+ // verifier).
+ MCRegister TyReg = CachedDebugInfoNoneReg;
+ if (const DIType *Ty = GV->getType()) {
+ auto TyRegOpt = lookupOptReg(DebugTypeRegs, Ty);
+ if (!TyRegOpt)
+ return std::nullopt;
+ TyReg = *TyRegOpt;
+ }
+
+ std::optional<MCRegister> StaticMemberRegOpt;
+ if (const DIDerivedType *SM = GV->getStaticDataMemberDeclaration()) {
+ StaticMemberRegOpt = lookupOptReg(DebugTypeRegs, SM);
+ if (!StaticMemberRegOpt)
+ return std::nullopt;
+ }
+
+ MCRegister NameReg = getCachedOpStringReg(GV->getName());
+ MCRegister LinkageReg = getCachedOpStringReg(GV->getLinkageName());
+ MCRegister FileStrReg = getCachedOpStringReg(getDebugFullPath(GV->getFile()));
+ MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
+ ExtInstSetReg, MAI);
+
+ MCRegister LineReg =
+ emitOpConstantI32(static_cast<uint32_t>(GV->getLine()), I32TypeReg, MAI);
+ // DIGlobalVariable metadata carries no column field.
+ // Column is hardcoded to 0, matching SPIRV-LLVM-Translator.
+ MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
+
+ // Variable: @g OpVariable id when !dbg matches; else a DebugExpression for
+ // the GVE init value when no @g exists; else DebugInfoNone.
+ MCRegister VariableReg = CachedDebugInfoNoneReg;
+ if (const GlobalVariable *LLVMGV = DIGVToLLVMGV.lookup(GV)) {
+ MCRegister GVReg = MAI.getGlobalObjReg(LLVMGV);
+ if (GVReg.isValid())
+ VariableReg = GVReg;
+ } else if (const DIExpression *InitExpr = DIGVToInitExpr.lookup(GV)) {
+ if (auto ExprReg =
+ emitDebugExpression(InitExpr, VoidTypeReg, ExtInstSetReg, MAI))
+ VariableReg = *ExprReg;
+ }
+
+ MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(GV), I32TypeReg, MAI);
+
+ SmallVector<MCRegister, 10> Ops = {NameReg, TyReg, SrcReg,
+ LineReg, ColReg, *ParentRegOpt,
+ LinkageReg, VariableReg, FlagsReg};
+
+ if (StaticMemberRegOpt)
+ Ops.push_back(*StaticMemberRegOpt);
+
+ return emitExtInst(SPIRV::NonSemanticExtInst::DebugGlobalVariable,
+ VoidTypeReg, ExtInstSetReg, Ops, MAI);
+}
+
std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeVector(
const DICompositeType *VT, MCRegister ExtInstSetReg,
SPIRV::ModuleAnalysisInfo &MAI) {
@@ -619,6 +728,15 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticDebugStrings(
ScopeToPathOpStringReg[SP] = emitOpStringIfNew(getDebugFullPath(SP), MAI);
}
+ for (const DIGlobalVariable *GV : GlobalVariables) {
+ emitOpStringIfNew(GV->getName(), MAI);
+ emitOpStringIfNew(GV->getLinkageName(), MAI);
+ SmallString<128> Path = getDebugFullPath(GV->getFile());
+ MCRegister PathReg = emitOpStringIfNew(Path, MAI);
+ if (const DIFile *F = GV->getFile())
+ ScopeToPathOpStringReg[F] = PathReg;
+ }
+
#ifndef NDEBUG
NonSemanticOpStringsSectionEmitted = true;
#endif
@@ -756,6 +874,10 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticGlobalDebugInfo(
ExtInstSetReg, MAI))
DebugFunctionDeclarationRegs[SP] = *DeclReg;
}
+
+ // Emit DebugGlobalVariable for each collected DIGlobalVariable.
+ for (const DIGlobalVariable *GV : GlobalVariables)
+ emitDebugGlobalVariable(GV, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
}
SmallString<128>
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
index ceb5573b55873..d0bbea07e73f8 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
@@ -21,6 +21,7 @@
#include "MCTargetDesc/SPIRVBaseInfo.h"
#include "SPIRVModuleAnalysis.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
@@ -32,6 +33,7 @@
namespace llvm {
+class GlobalVariable;
class SPIRVSubtarget;
/// AsmPrinter handler that emits NonSemantic.Shader.DebugInfo.100 (NSDI)
@@ -75,6 +77,21 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
// in beginModule() for DebugFunctionDeclaration emission.
SmallVector<const DISubprogram *> SubprogramDeclarations;
+ // DIGlobalVariable nodes for DebugGlobalVariable emission; SmallSetVector
+ // dedupes (see beginModule()).
+ SmallSetVector<const DIGlobalVariable *, 8> GlobalVariables;
+
+ // Maps a DIGlobalVariable to the llvm::GlobalVariable it describes, when the
+ // module has one with matching debug info. Used to fill the Variable operand
+ // of DebugGlobalVariable with the global's SPIR-V result id. Absent
+ // entries fall back to DebugInfoNone.
+ DenseMap<const DIGlobalVariable *, const GlobalVariable *> DIGVToLLVMGV;
+
+ // First non-empty DIExpression per DIGV from the CU global list (finder
+ // order). For Variable operand of DebugExpression type in
+ // DebugGlobalVariable, when supported.
+ DenseMap<const DIGlobalVariable *, const DIExpression *> DIGVToInitExpr;
+
// DebugFunctionDeclaration result id per emitted declaration DISubprogram
// (only entries where emission succeeded).
DenseMap<const DISubprogram *, MCRegister> DebugFunctionDeclarationRegs;
@@ -256,6 +273,42 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
MCRegister I32TypeReg, MCRegister ExtInstSetReg,
SPIRV::ModuleAnalysisInfo &MAI);
+ /// Emit \c DebugGlobalVariable for the source global variable \p GV.
+ ///
+ /// (\c SPIRVDebug::Operand::GlobalVariable): Name, Type, Source, Line,
+ /// Column, Parent, Linkage Name, Variable, Flags, and an optional Static
+ /// Member Declaration. Line, Column, and Flags are emitted as \c OpConstant
+ /// ids as required for non-semantic debug info.
+ ///
+ /// \c DebugInfoNone is used for two operands when LLVM has no value to
+ /// supply:
+ /// \c Type when \p GV is a declaration with no DI type (e.g. \c extern void;
+ /// valid IR, \c isDefinition: false); \c Variable when no \c
+ /// llvm::GlobalVariable in this module carries \p GV in its \c !dbg metadata.
+ ///
+ /// \returns The result id register on success. Returns \c std::nullopt and
+ /// emits nothing if a non-null \p GV type was not emitted in \c
+ /// DebugTypeRegs,
+ /// \p GV has a static data member declaration that was not emitted in
+ /// \c DebugTypeRegs, or \c resolveGlobalVariableParent returns no id for the
+ /// \c Parent operand.
+ std::optional<MCRegister>
+ emitDebugGlobalVariable(const DIGlobalVariable *GV, MCRegister VoidTypeReg,
+ MCRegister I32TypeReg, MCRegister ExtInstSetReg,
+ SPIRV::ModuleAnalysisInfo &MAI);
+
+ /// Resolve the \c Parent operand for \c DebugGlobalVariable.
+ std::optional<MCRegister>
+ resolveGlobalVariableParent(const DIGlobalVariable *GV) const;
+
+ /// Emit \c DebugExpression for \p Expr. Unimplemented: defined as a no-op
+ /// (\returns \c std::nullopt, emits nothing) so \c emitDebugGlobalVariable
+ /// can complete Variable-operand resolution for the opcodes we support today.
+ std::optional<MCRegister> emitDebugExpression(const DIExpression *Expr,
+ MCRegister VoidTypeReg,
+ MCRegister ExtInstSetReg,
+ SPIRV::ModuleAnalysisInfo &MAI);
+
/// Emit \c DebugTypeVector for the vector composite type \p VT.
///
/// \returns The result id register on success. Returns \c std::nullopt and
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-default-address-space.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-default-address-space.ll
new file mode 100644
index 0000000000000..590462a4859c3
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-default-address-space.ll
@@ -0,0 +1,43 @@
+; RUN: llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; A default-address-space global with !dbg. Such globals do not become a
+; module-scope OpVariable (they are turned into function-local copies), so no
+; result id is registered for them. The DIGlobalVariable is still emitted, but
+; its Variable operand falls back to DebugInfoNone.
+
+; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
+; CHECK-DAG: [[I32T:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: [[NAME:%[0-9]+]] = OpString "localas"
+; CHECK-DAG: [[STR_INT:%[0-9]+]] = OpString "int"
+; CHECK-DAG: [[C42:%[0-9]+]] = OpConstant [[I32T]] 42
+; CHECK-DAG: [[NONE:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugInfoNone
+; CHECK-DAG: [[DS:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugSource
+; CHECK-DAG: [[DTI:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugTypeBasic [[STR_INT]]
+; CHECK-DAG: OpExtInst [[VOID]] [[EXT]] DebugGlobalVariable [[NAME]] [[DTI]] [[DS]] [[C42]] {{%[0-9]+}} {{%[0-9]+}} [[NAME]] [[NONE]]
+
+target triple = "spirv64-unknown-unknown"
+
+ at g = dso_local global i32 0, align 4, !dbg !0
+
+define spir_func void @f() !dbg !9 {
+entry:
+ ret void, !dbg !10
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "localas", linkageName: "localas", scope: !2, file: !3, line: 42, type: !8, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "t.c", directory: "/tmp")
+!4 = !{!0}
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 1, type: !16, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2)
+!10 = !DILocation(line: 2, column: 1, scope: !9)
+!12 = !{i32 7, !"Dwarf Version", i32 5}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !DISubroutineType(cc: DW_CC_LLVM_SpirFunction, types: !17)
+!17 = !{null}
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-init-expr.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-init-expr.ll
new file mode 100644
index 0000000000000..fb83a6350ce03
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-init-expr.ll
@@ -0,0 +1,42 @@
+; RUN: llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; A DIGlobalVariable with no backing llvm::GlobalVariable but whose
+; DIGlobalVariableExpression carries a non-empty DIExpression (a constant
+; initializer). Since DebugExpression emission is not implemented, the Variable
+; operand falls back to DebugInfoNone. Flags encode IsLocal|IsDefinition (12).
+
+; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
+; CHECK-DAG: [[I32T:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: [[NAME:%[0-9]+]] = OpString "constg"
+; CHECK-DAG: [[STR_INT:%[0-9]+]] = OpString "int"
+; CHECK-DAG: [[C42:%[0-9]+]] = OpConstant [[I32T]] 42
+; CHECK-DAG: [[C12:%[0-9]+]] = OpConstant [[I32T]] 12
+; CHECK-DAG: [[NONE:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugInfoNone
+; CHECK-DAG: [[DS:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugSource
+; CHECK-DAG: [[DTI:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugTypeBasic [[STR_INT]]
+; CHECK-DAG: OpExtInst [[VOID]] [[EXT]] DebugGlobalVariable [[NAME]] [[DTI]] [[DS]] [[C42]] {{%[0-9]+}} {{%[0-9]+}} [[NAME]] [[NONE]] [[C12]]
+
+target triple = "spirv64-unknown-unknown"
+
+define spir_func void @f() !dbg !9 {
+entry:
+ ret void, !dbg !10
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_constu, 42, DW_OP_stack_value))
+!1 = distinct !DIGlobalVariable(name: "constg", linkageName: "constg", scope: !2, file: !3, line: 42, type: !8, isLocal: true, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "t.c", directory: "/tmp")
+!4 = !{!0}
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 1, type: !16, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2)
+!10 = !DILocation(line: 2, column: 1, scope: !9)
+!12 = !{i32 7, !"Dwarf Version", i32 5}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !DISubroutineType(cc: DW_CC_LLVM_SpirFunction, types: !17)
+!17 = !{null}
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-backing-var.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-backing-var.ll
new file mode 100644
index 0000000000000..d77c0887e8cc4
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-backing-var.ll
@@ -0,0 +1,42 @@
+; RUN: llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; A DIGlobalVariable listed in the compile unit's globals but with no backing
+; llvm::GlobalVariable in the module and an empty DIExpression. The Type operand
+; still resolves (int), but the Variable operand falls back to DebugInfoNone.
+
+; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
+; CHECK-DAG: [[I32T:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: [[NAME:%[0-9]+]] = OpString "novar"
+; CHECK-DAG: [[STR_INT:%[0-9]+]] = OpString "int"
+; CHECK-DAG: [[C0:%[0-9]+]] = OpConstant [[I32T]] 0
+; CHECK-DAG: [[C42:%[0-9]+]] = OpConstant [[I32T]] 42
+; CHECK-DAG: [[NONE:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugInfoNone
+; CHECK-DAG: [[DS:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugSource
+; CHECK-DAG: [[CU:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugCompilationUnit {{.*}} [[DS]] [[C0]]
+; CHECK-DAG: [[DTI:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugTypeBasic [[STR_INT]]
+; CHECK-DAG: OpExtInst [[VOID]] [[EXT]] DebugGlobalVariable [[NAME]] [[DTI]] [[DS]] [[C42]] [[C0]] [[CU]] [[NAME]] [[NONE]]
+
+target triple = "spirv64-unknown-unknown"
+
+define spir_func void @f() !dbg !9 {
+entry:
+ ret void, !dbg !10
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "novar", linkageName: "novar", scope: !2, file: !3, line: 42, type: !8, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "t.c", directory: "/tmp")
+!4 = !{!0}
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 1, type: !16, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2)
+!10 = !DILocation(line: 2, column: 1, scope: !9)
+!12 = !{i32 7, !"Dwarf Version", i32 5}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !DISubroutineType(cc: DW_CC_LLVM_SpirFunction, types: !17)
+!17 = !{null}
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-type.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-type.ll
new file mode 100644
index 0000000000000..a0b3df4632aba
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-type.ll
@@ -0,0 +1,47 @@
+; RUN: llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+
+; This is an edge case: IR that is valid but cannot be correctly encoded in SPIRV.
+
+; A DIGlobalVariable declaration with a null type (isDefinition: false, which the
+; IR verifier permits) and no backing llvm::GlobalVariable. The Type operand
+; falls back to DebugInfoNone, and the Variable operand also falls back to
+; DebugInfoNone because no @g carries this DIGlobalVariable and its
+; DIGlobalVariableExpression has an empty DIExpression.
+;
+; No spirv-val run: DebugInfoNone is not accepted as the Type operand of
+; DebugGlobalVariable by the validator, so this null-type fallback path emits
+; SPIR-V that does not pass spirv-val today.
+
+; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
+; CHECK-DAG: [[I32T:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: [[PATH:%[0-9]+]] = OpString "{{[/\\]}}tmp{{[/\\]}}t.c"
+; CHECK-DAG: [[NAME:%[0-9]+]] = OpString "notype"
+; CHECK-DAG: [[C0:%[0-9]+]] = OpConstant [[I32T]] 0
+; CHECK-DAG: [[C42:%[0-9]+]] = OpConstant [[I32T]] 42
+; CHECK-DAG: [[NONE:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugInfoNone
+; CHECK-DAG: [[DS:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugSource [[PATH]]
+; CHECK-DAG: [[CU:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugCompilationUnit {{.*}} [[DS]] [[C0]]
+; CHECK-DAG: OpExtInst [[VOID]] [[EXT]] DebugGlobalVariable [[NAME]] [[NONE]] [[DS]] [[C42]] [[C0]] [[CU]] [[NAME]] [[NONE]] [[C0]]
+
+target triple = "spirv64-unknown-unknown"
+
+define spir_func void @f() !dbg !9 {
+entry:
+ ret void, !dbg !10
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "notype", linkageName: "notype", scope: !2, file: !3, line: 42, type: null, isLocal: false, isDefinition: false)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "t.c", directory: "/tmp")
+!4 = !{!0}
+!9 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 1, type: !16, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2)
+!10 = !DILocation(line: 2, column: 1, scope: !9)
+!12 = !{i32 7, !"Dwarf Version", i32 5}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !DISubroutineType(cc: DW_CC_LLVM_SpirFunction, types: !17)
+!17 = !{null}
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-skip-static-member.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-skip-static-member.ll
new file mode 100644
index 0000000000000..f8b4cc38c8951
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-skip-static-member.ll
@@ -0,0 +1,39 @@
+; RUN: llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; A DIGlobalVariable that is the definition of a static data member. Its
+; declaration DIDerivedType (DW_TAG_member) is not emitted into DebugTypeRegs
+; (member types are not supported yet), so the Static Member Declaration operand
+; cannot be resolved and the whole DebugGlobalVariable is skipped.
+
+; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+; CHECK-DAG: OpExtInst {{.*}} DebugCompilationUnit
+; CHECK-NOT: DebugGlobalVariable
+
+target triple = "spirv64-unknown-unknown"
+
+ at g = dso_local addrspace(1) global i32 0, align 4, !dbg !0
+
+define spir_func void @f() !dbg !9 {
+entry:
+ ret void, !dbg !10
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "member", linkageName: "member", scope: !2, file: !3, line: 42, type: !8, isLocal: false, isDefinition: true, declaration: !20)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "t.cpp", directory: "/tmp")
+!4 = !{!0}
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 1, type: !16, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2)
+!10 = !DILocation(line: 2, column: 1, scope: !9)
+!12 = !{i32 7, !"Dwarf Version", i32 5}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !DISubroutineType(cc: DW_CC_LLVM_SpirFunction, types: !17)
+!17 = !{null}
+!20 = !DIDerivedType(tag: DW_TAG_member, name: "member", scope: !21, file: !3, line: 2, baseType: !8, flags: DIFlagStaticMember)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !3, line: 1, size: 8, elements: !22, identifier: "_ZTS1A")
+!22 = !{!20}
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-skip-type-not-in-regs.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-skip-type-not-in-regs.ll
new file mode 100644
index 0000000000000..e170b9656efd3
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-skip-type-not-in-regs.ll
@@ -0,0 +1,34 @@
+; RUN: llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; A DIGlobalVariable whose type is a structure composite that is not yet
+; supported and thus never emitted into DebugTypeRegs. The whole
+; DebugGlobalVariable is skipped rather than referencing a missing type id.
+
+; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+; CHECK-DAG: OpExtInst {{.*}} DebugCompilationUnit
+; CHECK-NOT: DebugGlobalVariable
+
+target triple = "spirv64-unknown-unknown"
+
+define spir_func void @f() !dbg !9 {
+entry:
+ ret void, !dbg !10
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "structg", linkageName: "structg", scope: !2, file: !3, line: 42, type: !8, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "t.c", directory: "/tmp")
+!4 = !{!0}
+!8 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !3, line: 1, size: 32, elements: !18)
+!9 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 1, type: !16, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2)
+!10 = !DILocation(line: 2, column: 1, scope: !9)
+!12 = !{i32 7, !"Dwarf Version", i32 5}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!16 = !DISubroutineType(cc: DW_CC_LLVM_SpirFunction, types: !17)
+!17 = !{null}
+!18 = !{}
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll
new file mode 100644
index 0000000000000..6985dd6e4de69
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll
@@ -0,0 +1,53 @@
+; RUN: llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; Exercise NonSemantic DebugGlobalVariable for a module global with !dbg.
+; The global uses address space 1 so the backend emits a module-scope
+; CrossWorkgroup OpVariable (default-AS globals become function-local copies).
+
+; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
+; CHECK-DAG: [[I32T:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: [[PATH:%[0-9]+]] = OpString "{{[/\\]}}AAAAAAAAAA{{[/\\]}}BBBBBBBB{{[/\\]}}CCCCCCCCC{{[/\\]}}debug-global-variable.c"
+; CHECK-DAG: [[NAME:%[0-9]+]] = OpString "counter"
+; CHECK-DAG: [[STR_INT:%[0-9]+]] = OpString "int"
+; CHECK-DAG: [[C100:%[0-9]+]] = OpConstant [[I32T]] 100
+; CHECK-DAG: [[C5:%[0-9]+]] = OpConstant [[I32T]] 5
+; CHECK-DAG: [[C0:%[0-9]+]] = OpConstant [[I32T]] 0
+; CHECK-DAG: [[C42:%[0-9]+]] = OpConstant [[I32T]] 42
+; CHECK-DAG: [[C32:%[0-9]+]] = OpConstant [[I32T]] 32
+; CHECK-DAG: [[C4ENC:%[0-9]+]] = OpConstant [[I32T]] 4
+; CHECK-DAG: [[DS:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugSource [[PATH]]
+; CHECK-DAG: [[CU:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugCompilationUnit [[C100]] [[C5]] [[DS]] [[C0]]
+; CHECK-DAG: [[DTI:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugTypeBasic [[STR_INT]] [[C32]] [[C4ENC]] [[C0]]
+; CHECK-DAG: [[GV:%[0-9]+]] = OpVariable {{.*}} CrossWorkgroup
+; CHECK-DAG: OpExtInst [[VOID]] [[EXT]] DebugGlobalVariable [[NAME]] [[DTI]] [[DS]] [[C42]] [[C0]] [[CU]] [[NAME]] [[GV]]
+
+target triple = "spirv64-unknown-unknown"
+
+ at g_value = dso_local addrspace(1) global i32 0, align 4, !dbg !0
+
+define spir_func void @use_global() !dbg !9 {
+entry:
+ %v = load i32, ptr addrspace(1) @g_value, align 4, !dbg !10
+ ret void, !dbg !11
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13, !14, !15}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "counter", linkageName: "counter", scope: !2, file: !3, line: 42, type: !8, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version XX.X", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "debug-global-variable.c", directory: "/AAAAAAAAAA/BBBBBBBB/CCCCCCCCC", checksumkind: CSK_MD5, checksum: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
+!4 = !{!0}
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = distinct !DISubprogram(name: "use_global", linkageName: "use_global", scope: !3, file: !3, line: 1, type: !16, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2)
+!10 = !DILocation(line: 2, column: 3, scope: !9)
+!11 = !DILocation(line: 3, column: 1, scope: !9)
+!12 = !{i32 7, !"Dwarf Version", i32 5}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!14 = !{i32 1, !"wchar_size", i32 4}
+!15 = !{i32 7, !"frame-pointer", i32 2}
+!16 = !DISubroutineType(cc: DW_CC_LLVM_SpirFunction, types: !17)
+!17 = !{!8}
>From 0911e6dac8fae5e837b654a0ef2760b369624297 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Fri, 10 Jul 2026 07:54:37 -0500
Subject: [PATCH 2/9] [review] Simplify code for scope path handling.
---
.../SPIRV/SPIRVNonSemanticDebugHandler.cpp | 31 ++++++++++++++-----
.../SPIRV/SPIRVNonSemanticDebugHandler.h | 10 ++++++
2 files changed, 33 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index 42c784d0a461d..432e4c19e6d8d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
@@ -211,6 +211,7 @@ void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
NonSemanticOpStringsSectionEmitted = false;
#endif
CachedDebugInfoNoneReg = MCRegister();
+ CachedEmptyStringReg = MCRegister();
CachedOpTypeVoidReg = MCRegister();
CachedOpTypeInt32Reg = MCRegister();
@@ -338,6 +339,23 @@ MCRegister SPIRVNonSemanticDebugHandler::getCachedOpStringReg(StringRef S) {
return It->second;
}
+MCRegister SPIRVNonSemanticDebugHandler::getCachedScopePathOpStringReg(
+ const DIScope *Scope, bool UseEmptyPathIfNullScope) {
+ if (!Scope) {
+ assert(UseEmptyPathIfNullScope &&
+ "null scope path lookup requires UseEmptyPathIfNullScope");
+ assert(CachedEmptyStringReg.isValid() &&
+ "empty path OpString must be cached in emitNonSemanticDebugStrings");
+ return CachedEmptyStringReg;
+ }
+ auto It = ScopeToPathOpStringReg.find(Scope);
+ assert(It != ScopeToPathOpStringReg.end() &&
+ "path OpString must be cached in emitNonSemanticDebugStrings");
+ MCRegister FileStrReg = It->second;
+ assert(FileStrReg.isValid() && "path OpString id must be valid once cached");
+ return FileStrReg;
+}
+
MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI32(
uint32_t Value, MCRegister I32TypeReg, SPIRV::ModuleAnalysisInfo &MAI) {
auto [It, Inserted] = I32ConstantCache.try_emplace(Value);
@@ -544,13 +562,7 @@ SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration(
MCRegister ParentReg = *ParentRegOpt;
- auto PathStrIt = ScopeToPathOpStringReg.find(SP);
- assert(PathStrIt != ScopeToPathOpStringReg.end() &&
- "declaration path OpString must be cached in "
- "emitNonSemanticDebugStrings");
- MCRegister FileStrReg = PathStrIt->second;
- assert(FileStrReg.isValid() &&
- "declaration path OpString id must be valid once cached");
+ MCRegister FileStrReg = getCachedScopePathOpStringReg(SP);
MCRegister NameReg = getCachedOpStringReg(SP->getName());
MCRegister LinkageReg = getCachedOpStringReg(SP->getLinkageName());
@@ -634,7 +646,8 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
MCRegister NameReg = getCachedOpStringReg(GV->getName());
MCRegister LinkageReg = getCachedOpStringReg(GV->getLinkageName());
- MCRegister FileStrReg = getCachedOpStringReg(getDebugFullPath(GV->getFile()));
+ MCRegister FileStrReg = getCachedScopePathOpStringReg(
+ GV->getFile(), /*UseEmptyPathIfNullScope=*/true);
MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
ExtInstSetReg, MAI);
@@ -737,6 +750,8 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticDebugStrings(
ScopeToPathOpStringReg[F] = PathReg;
}
+ CachedEmptyStringReg = emitOpStringIfNew("", MAI);
+
#ifndef NDEBUG
NonSemanticOpStringsSectionEmitted = true;
#endif
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
index d0bbea07e73f8..635c25a8e9dc8 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
@@ -120,6 +120,8 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
bool NonSemanticOpStringsSectionEmitted = false;
#endif
+ MCRegister CachedEmptyStringReg;
+
MCRegister CachedDebugInfoNoneReg;
MCRegister CachedOpTypeVoidReg;
@@ -209,6 +211,14 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
/// Section 10 only: lookup OpString id from cache; asserts if missing or if
/// section 7 did not complete.
MCRegister getCachedOpStringReg(StringRef S);
+
+ /// Section 10 only: lookup path \c OpString id for \p Scope from
+ /// \c ScopeToPathOpStringReg; asserts if missing or invalid. When
+ /// \p UseEmptyPathIfNullScope is true and \p Scope is null, returns
+ /// \c CachedEmptyStringReg instead.
+ MCRegister
+ getCachedScopePathOpStringReg(const DIScope *Scope,
+ bool UseEmptyPathIfNullScope = false);
MCRegister emitOpConstantI32(uint32_t Value, MCRegister I32TypeReg,
SPIRV::ModuleAnalysisInfo &MAI);
MCRegister emitExtInst(SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
>From bac33a04873e44eac9ec1eb28f92631d4ee326bb Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Fri, 10 Jul 2026 08:53:26 -0500
Subject: [PATCH 3/9] [review] Improve comment.
---
llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index 432e4c19e6d8d..9216b0f26fa93 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
@@ -653,8 +653,9 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
MCRegister LineReg =
emitOpConstantI32(static_cast<uint32_t>(GV->getLine()), I32TypeReg, MAI);
- // DIGlobalVariable metadata carries no column field.
- // Column is hardcoded to 0, matching SPIRV-LLVM-Translator.
+ // DIGlobalVariable or DIGlobalVariableExpression metadata carry no column
+ // field. Column is hardcoded to 0 (because it can't be determined), matching
+ // SPIRV-LLVM-Translator.
MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
// Variable: @g OpVariable id when !dbg matches; else a DebugExpression for
>From ae1b3826de23236d2647d210f011d875bed110f4 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Mon, 13 Jul 2026 05:21:45 -0500
Subject: [PATCH 4/9] [reivews] Simplify processing.
---
.../SPIRV/SPIRVNonSemanticDebugHandler.cpp | 48 ++++++++++---------
.../SPIRV/SPIRVNonSemanticDebugHandler.h | 29 ++++-------
2 files changed, 35 insertions(+), 42 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index 9216b0f26fa93..7ee2c8b476a3a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
@@ -195,9 +195,7 @@ void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
SubroutineTypes.clear();
VectorTypes.clear();
SubprogramDeclarations.clear();
- GlobalVariables.clear();
- DIGVToLLVMGV.clear();
- DIGVToInitExpr.clear();
+ GlobalVariableDebugInfoMap.clear();
DebugFunctionDeclarationRegs.clear();
ScopeToPathOpStringReg.clear();
CUToCompilationUnitDbgReg.clear();
@@ -257,25 +255,27 @@ void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
SubprogramDeclarations.push_back(SP);
}
- // Map DIGlobalVariable -> llvm::GlobalVariable for globals that attach !dbg.
- // The link lives on the IR global (via DIGlobalVariableExpression); DIGV
- // metadata has no back-reference to its @g.
+ // SPIR-V supports at most one DIGlobalVariableExpression per DIGlobalVariable
+ // (see DebugGlobalVariable opcode). Walk LLVM globals to map each
+ // DIGlobalVariable (returned by DIFinder) to its llvm::GlobalVariable,
+ // keeping only the first expression attached to each LLVM global.
+ DenseMap<const DIGlobalVariable *, const GlobalVariable *> DIGVToLLVMGV;
for (const GlobalVariable &G : M->globals()) {
- SmallVector<DIGlobalVariableExpression *, 4> GVEs;
+ SmallVector<DIGlobalVariableExpression *> GVEs;
G.getDebugInfo(GVEs);
- for (DIGlobalVariableExpression *GVE : GVEs)
- DIGVToLLVMGV.try_emplace(GVE->getVariable(), &G);
+ for (DIGlobalVariableExpression *GVE : GVEs) {
+ if (const DIGlobalVariable *GV = GVE->getVariable()) {
+ DIGVToLLVMGV.try_emplace(GV, &G);
+ break;
+ }
+ }
}
- // DebugInfoFinder deduplicates expressions but not by their pointed
- // variables. We use a SmallSetVector to deduplicate them.
for (const DIGlobalVariableExpression *GVE : Finder.global_variables()) {
- GlobalVariables.insert(GVE->getVariable());
const DIGlobalVariable *GV = GVE->getVariable();
const DIExpression *Expr = GVE->getExpression();
- // For Variable operand of DebugExpression type in DebugGlobalVariable.
- if (GV && Expr && Expr->getNumElements())
- DIGVToInitExpr.try_emplace(GV, Expr);
+ GlobalVariableDebugInfoMap.try_emplace(
+ GV, GlobalVariableDebugInfo{Expr, DIGVToLLVMGV.lookup(GV)});
}
}
@@ -617,8 +617,9 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugExpression(
}
std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
- const DIGlobalVariable *GV, MCRegister VoidTypeReg, MCRegister I32TypeReg,
- MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
+ const DIGlobalVariable *GV, const GlobalVariableDebugInfo &Info,
+ MCRegister VoidTypeReg, MCRegister I32TypeReg, MCRegister ExtInstSetReg,
+ SPIRV::ModuleAnalysisInfo &MAI) {
assert(GV && "GV must not be null in emitDebugGlobalVariable");
auto ParentRegOpt = resolveGlobalVariableParent(GV);
@@ -661,13 +662,13 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
// Variable: @g OpVariable id when !dbg matches; else a DebugExpression for
// the GVE init value when no @g exists; else DebugInfoNone.
MCRegister VariableReg = CachedDebugInfoNoneReg;
- if (const GlobalVariable *LLVMGV = DIGVToLLVMGV.lookup(GV)) {
+ if (const GlobalVariable *LLVMGV = Info.LLVMGV) {
MCRegister GVReg = MAI.getGlobalObjReg(LLVMGV);
if (GVReg.isValid())
VariableReg = GVReg;
- } else if (const DIExpression *InitExpr = DIGVToInitExpr.lookup(GV)) {
+ } else if (Info.Expr) {
if (auto ExprReg =
- emitDebugExpression(InitExpr, VoidTypeReg, ExtInstSetReg, MAI))
+ emitDebugExpression(Info.Expr, VoidTypeReg, ExtInstSetReg, MAI))
VariableReg = *ExprReg;
}
@@ -742,7 +743,7 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticDebugStrings(
ScopeToPathOpStringReg[SP] = emitOpStringIfNew(getDebugFullPath(SP), MAI);
}
- for (const DIGlobalVariable *GV : GlobalVariables) {
+ for (const auto &[GV, _] : GlobalVariableDebugInfoMap) {
emitOpStringIfNew(GV->getName(), MAI);
emitOpStringIfNew(GV->getLinkageName(), MAI);
SmallString<128> Path = getDebugFullPath(GV->getFile());
@@ -892,8 +893,9 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticGlobalDebugInfo(
}
// Emit DebugGlobalVariable for each collected DIGlobalVariable.
- for (const DIGlobalVariable *GV : GlobalVariables)
- emitDebugGlobalVariable(GV, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
+ for (const auto &[GV, Info] : GlobalVariableDebugInfoMap)
+ emitDebugGlobalVariable(GV, Info, VoidTypeReg, I32TypeReg, ExtInstSetReg,
+ MAI);
}
SmallString<128>
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
index 635c25a8e9dc8..e385a5fbcaa8b 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
@@ -21,7 +21,6 @@
#include "MCTargetDesc/SPIRVBaseInfo.h"
#include "SPIRVModuleAnalysis.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
@@ -77,20 +76,12 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
// in beginModule() for DebugFunctionDeclaration emission.
SmallVector<const DISubprogram *> SubprogramDeclarations;
- // DIGlobalVariable nodes for DebugGlobalVariable emission; SmallSetVector
- // dedupes (see beginModule()).
- SmallSetVector<const DIGlobalVariable *, 8> GlobalVariables;
-
- // Maps a DIGlobalVariable to the llvm::GlobalVariable it describes, when the
- // module has one with matching debug info. Used to fill the Variable operand
- // of DebugGlobalVariable with the global's SPIR-V result id. Absent
- // entries fall back to DebugInfoNone.
- DenseMap<const DIGlobalVariable *, const GlobalVariable *> DIGVToLLVMGV;
-
- // First non-empty DIExpression per DIGV from the CU global list (finder
- // order). For Variable operand of DebugExpression type in
- // DebugGlobalVariable, when supported.
- DenseMap<const DIGlobalVariable *, const DIExpression *> DIGVToInitExpr;
+ struct GlobalVariableDebugInfo {
+ const DIExpression *Expr = nullptr;
+ const GlobalVariable *LLVMGV = nullptr;
+ };
+ DenseMap<const DIGlobalVariable *, GlobalVariableDebugInfo>
+ GlobalVariableDebugInfoMap;
// DebugFunctionDeclaration result id per emitted declaration DISubprogram
// (only entries where emission succeeded).
@@ -302,10 +293,10 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
/// \p GV has a static data member declaration that was not emitted in
/// \c DebugTypeRegs, or \c resolveGlobalVariableParent returns no id for the
/// \c Parent operand.
- std::optional<MCRegister>
- emitDebugGlobalVariable(const DIGlobalVariable *GV, MCRegister VoidTypeReg,
- MCRegister I32TypeReg, MCRegister ExtInstSetReg,
- SPIRV::ModuleAnalysisInfo &MAI);
+ std::optional<MCRegister> emitDebugGlobalVariable(
+ const DIGlobalVariable *GV, const GlobalVariableDebugInfo &Info,
+ MCRegister VoidTypeReg, MCRegister I32TypeReg, MCRegister ExtInstSetReg,
+ SPIRV::ModuleAnalysisInfo &MAI);
/// Resolve the \c Parent operand for \c DebugGlobalVariable.
std::optional<MCRegister>
>From 70671685602fe6d0fb1cebea8f8788c766ec13ba Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Mon, 13 Jul 2026 05:41:20 -0500
Subject: [PATCH 5/9] [review] improve test.
---
.../debug-info/debug-global-variable-default-address-space.ll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-default-address-space.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-default-address-space.ll
index 590462a4859c3..1dcb5cc97b025 100644
--- a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-default-address-space.ll
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-default-address-space.ll
@@ -9,7 +9,7 @@
; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
; CHECK-DAG: [[I32T:%[0-9]+]] = OpTypeInt 32 0
-; CHECK-DAG: [[NAME:%[0-9]+]] = OpString "localas"
+; CHECK-DAG: [[NAME:%[0-9]+]] = OpString "g"
; CHECK-DAG: [[STR_INT:%[0-9]+]] = OpString "int"
; CHECK-DAG: [[C42:%[0-9]+]] = OpConstant [[I32T]] 42
; CHECK-DAG: [[NONE:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugInfoNone
@@ -30,7 +30,7 @@ entry:
!llvm.module.flags = !{!12, !13}
!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
-!1 = distinct !DIGlobalVariable(name: "localas", linkageName: "localas", scope: !2, file: !3, line: 42, type: !8, isLocal: false, isDefinition: true)
+!1 = distinct !DIGlobalVariable(name: "g", linkageName: "g", scope: !2, file: !3, line: 42, type: !8, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
!3 = !DIFile(filename: "t.c", directory: "/tmp")
!4 = !{!0}
>From b4eab005bc1814c9b01656471bb0cd08e6c44734 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Mon, 13 Jul 2026 06:20:33 -0500
Subject: [PATCH 6/9] [reviews] Improve test.
---
.../SPIRV/debug-info/debug-global-variable-no-type.ll | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-type.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-type.ll
index a0b3df4632aba..88e350b1ad89e 100644
--- a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-type.ll
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-type.ll
@@ -1,4 +1,5 @@
; RUN: llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | not spirv-val 2>&1 | FileCheck %s --check-prefix=VAL-ERR %}
; This is an edge case: IR that is valid but cannot be correctly encoded in SPIRV.
@@ -8,9 +9,11 @@
; DebugInfoNone because no @g carries this DIGlobalVariable and its
; DIGlobalVariableExpression has an empty DIExpression.
;
-; No spirv-val run: DebugInfoNone is not accepted as the Type operand of
-; DebugGlobalVariable by the validator, so this null-type fallback path emits
-; SPIR-V that does not pass spirv-val today.
+; spirv-val rejects DebugInfoNone as the Type operand of DebugGlobalVariable
+; (the Variable operand may use DebugInfoNone; see
+; debug-global-variable-default-address-space.ll).
+
+; VAL-ERR: DebugGlobalVariable{{.*}}expected operand Type is not a valid debug type
; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
>From bfd7efa6620f006a17cdf771b8c2a2cb22f83ca7 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Mon, 13 Jul 2026 06:23:31 -0500
Subject: [PATCH 7/9] [review] Improve test.
---
llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll
index 6985dd6e4de69..1a7f31b295175 100644
--- a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll
@@ -9,7 +9,7 @@
; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
; CHECK-DAG: [[I32T:%[0-9]+]] = OpTypeInt 32 0
; CHECK-DAG: [[PATH:%[0-9]+]] = OpString "{{[/\\]}}AAAAAAAAAA{{[/\\]}}BBBBBBBB{{[/\\]}}CCCCCCCCC{{[/\\]}}debug-global-variable.c"
-; CHECK-DAG: [[NAME:%[0-9]+]] = OpString "counter"
+; CHECK-DAG: [[NAME:%[0-9]+]] = OpString "g_value"
; CHECK-DAG: [[STR_INT:%[0-9]+]] = OpString "int"
; CHECK-DAG: [[C100:%[0-9]+]] = OpConstant [[I32T]] 100
; CHECK-DAG: [[C5:%[0-9]+]] = OpConstant [[I32T]] 5
@@ -37,7 +37,7 @@ entry:
!llvm.module.flags = !{!12, !13, !14, !15}
!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
-!1 = distinct !DIGlobalVariable(name: "counter", linkageName: "counter", scope: !2, file: !3, line: 42, type: !8, isLocal: false, isDefinition: true)
+!1 = distinct !DIGlobalVariable(name: "g_value", linkageName: "g_value", scope: !2, file: !3, line: 42, type: !8, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version XX.X", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
!3 = !DIFile(filename: "debug-global-variable.c", directory: "/AAAAAAAAAA/BBBBBBBB/CCCCCCCCC", checksumkind: CSK_MD5, checksum: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
!4 = !{!0}
>From 5e32e43dac16b4ad0edaba38b235470d87b2d203 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Mon, 13 Jul 2026 06:26:51 -0500
Subject: [PATCH 8/9] Update flag.
---
llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll
index 1a7f31b295175..2e0cb197310ad 100644
--- a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable.ll
@@ -15,13 +15,14 @@
; CHECK-DAG: [[C5:%[0-9]+]] = OpConstant [[I32T]] 5
; CHECK-DAG: [[C0:%[0-9]+]] = OpConstant [[I32T]] 0
; CHECK-DAG: [[C42:%[0-9]+]] = OpConstant [[I32T]] 42
+; CHECK-DAG: [[C8:%[0-9]+]] = OpConstant [[I32T]] 8
; CHECK-DAG: [[C32:%[0-9]+]] = OpConstant [[I32T]] 32
; CHECK-DAG: [[C4ENC:%[0-9]+]] = OpConstant [[I32T]] 4
; CHECK-DAG: [[DS:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugSource [[PATH]]
; CHECK-DAG: [[CU:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugCompilationUnit [[C100]] [[C5]] [[DS]] [[C0]]
; CHECK-DAG: [[DTI:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugTypeBasic [[STR_INT]] [[C32]] [[C4ENC]] [[C0]]
; CHECK-DAG: [[GV:%[0-9]+]] = OpVariable {{.*}} CrossWorkgroup
-; CHECK-DAG: OpExtInst [[VOID]] [[EXT]] DebugGlobalVariable [[NAME]] [[DTI]] [[DS]] [[C42]] [[C0]] [[CU]] [[NAME]] [[GV]]
+; CHECK-DAG: OpExtInst [[VOID]] [[EXT]] DebugGlobalVariable [[NAME]] [[DTI]] [[DS]] [[C42]] [[C0]] [[CU]] [[NAME]] [[GV]] [[C8]]
target triple = "spirv64-unknown-unknown"
>From f5b97e2bd1bc57a7c6777a56ef17085009e85f5c Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Mon, 13 Jul 2026 07:07:03 -0500
Subject: [PATCH 9/9] Update test.
---
.../SPIRV/debug-info/debug-global-variable-no-type.ll | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-type.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-type.ll
index 88e350b1ad89e..55591c60063cd 100644
--- a/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-type.ll
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-global-variable-no-type.ll
@@ -1,19 +1,11 @@
; RUN: llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | not spirv-val 2>&1 | FileCheck %s --check-prefix=VAL-ERR %}
-
-; This is an edge case: IR that is valid but cannot be correctly encoded in SPIRV.
+; RUN: %if spirv-tools %{ llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; A DIGlobalVariable declaration with a null type (isDefinition: false, which the
; IR verifier permits) and no backing llvm::GlobalVariable. The Type operand
; falls back to DebugInfoNone, and the Variable operand also falls back to
; DebugInfoNone because no @g carries this DIGlobalVariable and its
; DIGlobalVariableExpression has an empty DIExpression.
-;
-; spirv-val rejects DebugInfoNone as the Type operand of DebugGlobalVariable
-; (the Variable operand may use DebugInfoNone; see
-; debug-global-variable-default-address-space.ll).
-
-; VAL-ERR: DebugGlobalVariable{{.*}}expected operand Type is not a valid debug type
; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
More information about the llvm-commits
mailing list