[llvm] [SPIR-V] Fix DebugScope resolving DILexicalBlockFile to DebugCompilationUnit (PR #228259)
Jinsong Ji via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 1 14:49:17 PDT 2026
https://github.com/jsji created https://github.com/llvm/llvm-project/pull/228259
resolveScope() did not handle DILexicalBlockFile, which is a transparent
wrapper carrying file/discriminator info with no SPIR-V counterpart.
When emitDebugScopeForInstruction() encountered a DILocation whose scope
was a DILexicalBlockFile (wrapping a DISubprogram), resolveScope() fell
through to the compile-unit fallback. This emitted a DebugScope
referencing DebugCompilationUnit instead of DebugFunction, producing
malformed SPIR-V that crashed IGC during program compilation.
Fix by unwrapping DILexicalBlockFile to its underlying scope at the top
of resolveScope().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply at anthropic.com>
>From e6152555c5ff2537af6340ff5c4ef26a2383481d Mon Sep 17 00:00:00 2001
From: Jinsong Ji <jinsong.ji at intel.com>
Date: Thu, 1 Oct 2026 20:27:20 +0200
Subject: [PATCH] [SPIR-V] Fix DebugScope resolving DILexicalBlockFile to
DebugCompilationUnit
resolveScope() did not handle DILexicalBlockFile, which is a transparent
wrapper carrying file/discriminator info with no SPIR-V counterpart.
When emitDebugScopeForInstruction() encountered a DILocation whose scope
was a DILexicalBlockFile (wrapping a DISubprogram), resolveScope() fell
through to the compile-unit fallback. This emitted a DebugScope
referencing DebugCompilationUnit instead of DebugFunction, producing
malformed SPIR-V that crashed IGC during program compilation.
Fix by unwrapping DILexicalBlockFile to its underlying scope at the top
of resolveScope().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply at anthropic.com>
---
.../SPIRV/SPIRVNonSemanticDebugHandler.cpp | 5 +++
.../debug-scope-lexical-block-file.ll | 45 +++++++++++++++++++
2 files changed, 50 insertions(+)
create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/debug-scope-lexical-block-file.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index 053fee1d59b64..67e161e018b39 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
@@ -651,6 +651,11 @@ SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
std::optional<MCRegister> SPIRVNonSemanticDebugHandler::resolveScope(
const DIScope *Scope, const DICompileUnit *FallbackCU) const {
+ // DILexicalBlockFile is a transparent wrapper that carries file/discriminator
+ // info but has no SPIR-V counterpart. Unwrap to the underlying scope.
+ while (const auto *DLBF = dyn_cast_or_null<DILexicalBlockFile>(Scope))
+ Scope = DLBF->getScope();
+
if (isa_and_nonnull<DIType, DILexicalBlock, DINamespace, DISubprogram>(Scope))
return lookupOptReg(DebugScopeRegs, Scope);
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-scope-lexical-block-file.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-scope-lexical-block-file.ll
new file mode 100644
index 0000000000000..5973b8d500447
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-scope-lexical-block-file.ll
@@ -0,0 +1,45 @@
+; RUN: llc --verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_non_semantic_info %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 %}
+
+;; Verify that a DILocation whose scope is a DILexicalBlockFile resolves to the
+;; underlying DISubprogram's DebugFunction, not to the DebugCompilationUnit.
+;; DILexicalBlockFile is a transparent wrapper (file + discriminator) with no
+;; SPIR-V counterpart and must be unwrapped by resolveScope().
+
+; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
+; CHECK-DAG: [[DF:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugFunction {{.*}}
+
+; CHECK: OpFunction
+; CHECK: OpLabel
+; CHECK-NEXT: OpExtInst [[VOID]] [[EXT]] DebugFunctionDefinition [[DF]] {{%[0-9]+}}
+;; The DebugScope must reference the DebugFunction, not the DebugCompilationUnit.
+; CHECK-NEXT: OpExtInst [[VOID]] [[EXT]] DebugScope [[DF]]
+; CHECK: OpReturnValue
+; CHECK-NEXT: OpFunctionEnd
+
+target triple = "spirv64-unknown-unknown"
+
+define spir_func i32 @test_lbf(i32 %n) !dbg !5 {
+entry:
+ %r = add i32 %n, 1, !dbg !10
+ ret i32 %r, !dbg !10
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "test.c", directory: "/src")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+
+!4 = !DISubroutineType(types: !6)
+!5 = distinct !DISubprogram(name: "test_lbf", linkageName: "test_lbf", scope: !1, file: !1, line: 1, type: !4, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!6 = !{!7, !7}
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+
+;; DILexicalBlockFile wrapping the DISubprogram — the scope that triggered the bug.
+!8 = !DIFile(filename: "test-other.c", directory: "/src")
+!9 = !DILexicalBlockFile(scope: !5, file: !8, discriminator: 0)
+!10 = !DILocation(line: 3, column: 10, scope: !9)
More information about the llvm-commits
mailing list