[llvm] [SPIR-V] Fix DebugScope resolving DILexicalBlockFile to DebugCompilationUnit (PR #228259)

via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 1 14:50:00 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-spir-v

Author: Jinsong Ji (jsji)

<details>
<summary>Changes</summary>

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@<!-- -->anthropic.com>


---
Full diff: https://github.com/llvm/llvm-project/pull/228259.diff


2 Files Affected:

- (modified) llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp (+5) 
- (added) llvm/test/CodeGen/SPIRV/debug-info/debug-scope-lexical-block-file.ll (+45) 


``````````diff
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)

``````````

</details>


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


More information about the llvm-commits mailing list