From: Viktoria Maximova Date: Mon, 4 May 2026 13:36:24 +0200 Subject: [12/13] [Backport to 22] Fix DebugTypeFunction void return type (#3718) Origin: upstream, https://github.com/KhronosGroup/SPIRV-LLVM-Translator/commit/71d1484dd985b2950e3ec09d7e1e4092b2eeae6b All DebugInfo specs (core SPIR-V, OpenCL.DebugInfo.100, NonSemantic.Shader.DebugInfo.*) require the `ReturnType` operand of `DebugTypeFunction` to reference a valid type. For void-returning functions the translator was emitting `DebugInfoNone` instead of `VoidTy`. Also fix the same issue in existing reverse-translation test inputs that were generated by the Writer with the bug in place. `spirv-val` on the NonSemantic path cannot be enabled yet due to other spec-compliance issues to be fixed in subsequent changes. AI-assisted: Claude Sonnet 4.6 (commercial SaaS) --- lib/SPIRV/LLVMToSPIRVDbgTran.cpp | 21 ++++++------ .../DebugInfoSubrangeWithOnlyCount.spt | 2 +- .../DebugInfoTypeFunctionVoidReturn.ll | 32 +++++++++++++++++++ test/DebugInfo/DebugInfoTypeVector.spvasm | 2 +- test/DebugInfo/Generic/tu-member-opaque.spt | 2 +- .../Shader200/FortranArrayNoType.spt | 2 +- .../NonSemantic/Shader200/InlineNamespace.ll | 3 ++ 7 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 test/DebugInfo/DebugInfoTypeFunctionVoidReturn.ll diff --git a/lib/SPIRV/LLVMToSPIRVDbgTran.cpp b/lib/SPIRV/LLVMToSPIRVDbgTran.cpp index 7462da8d..8cc50ea9 100644 --- a/lib/SPIRV/LLVMToSPIRVDbgTran.cpp +++ b/lib/SPIRV/LLVMToSPIRVDbgTran.cpp @@ -903,16 +903,17 @@ LLVMToSPIRVDbgTran::transDbgSubroutineType(const DISubroutineType *FT) { DITypeRefArray Types = FT->getTypeArray(); const size_t NumElements = Types.size(); - if (NumElements) { - Ops.resize(1 + NumElements); - // First element of the TypeArray is the type of the return value, - // followed by types of the function arguments' types. - // The same order is preserved in SPIRV. - for (unsigned I = 0; I < NumElements; ++I) - Ops[ReturnTypeIdx + I] = transDbgEntry(Types[I])->getId(); - } else { // void foo(); - Ops[ReturnTypeIdx] = getVoidTy()->getId(); - } + + // First element of the TypeArray is the return type (null means void), + // followed by the formal argument types. The same order is used in SPIR-V. + // All DebugInfo specs require ReturnType to reference a valid type, so map + // a null (or absent) return type to VoidTy rather than DebugInfoNone. + Ops.resize(ReturnTypeIdx + std::max(NumElements, 1)); + Ops[ReturnTypeIdx] = (NumElements && Types[0]) + ? transDbgEntry(Types[0])->getId() + : getVoidTy()->getId(); + for (unsigned I = 1; I < NumElements; ++I) + Ops[ReturnTypeIdx + I] = transDbgEntry(Types[I])->getId(); if (isNonSemanticDebugInfo()) transformToConstant(Ops, {FlagsIdx}); diff --git a/test/DebugInfo/DebugInfoSubrangeWithOnlyCount.spt b/test/DebugInfo/DebugInfoSubrangeWithOnlyCount.spt index 67d2a519..6f52dafa 100644 --- a/test/DebugInfo/DebugInfoSubrangeWithOnlyCount.spt +++ b/test/DebugInfo/DebugInfoSubrangeWithOnlyCount.spt @@ -57,7 +57,7 @@ 5 ExtInst 3 27 2 DebugInfoNone 7 ExtInst 3 30 2 DebugSource 29 27 9 ExtInst 3 31 2 DebugCompilationUnit 65536 4 30 21 -7 ExtInst 3 32 2 DebugTypeFunction 0 27 +7 ExtInst 3 32 2 DebugTypeFunction 0 3 8 ExtInst 3 35 2 DebugTypeBasic 33 34 3 7 ExtInst 3 36 2 DebugTypeArray 35 11 ; Count = 1000 8 ExtInst 3 37 2 DebugTypePointer 36 4294967295 0 diff --git a/test/DebugInfo/DebugInfoTypeFunctionVoidReturn.ll b/test/DebugInfo/DebugInfoTypeFunctionVoidReturn.ll new file mode 100644 index 00000000..ebc38a18 --- /dev/null +++ b/test/DebugInfo/DebugInfoTypeFunctionVoidReturn.ll @@ -0,0 +1,32 @@ +; Test that DebugTypeFunction uses VoidTy (not DebugInfoNone) as the return +; type for void-returning functions, per all DebugInfo specs. + +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: spirv-val %t.spv +; RUN: llvm-spirv %t.bc -spirv-text -o - | FileCheck %s --check-prefix=CHECK-SPIRV + +; CHECK-SPIRV: TypeVoid [[#VoidTy:]] +; CHECK-SPIRV: DebugTypeFunction [[#]] [[#VoidTy]] + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "spir64-unknown-unknown" + +define dso_local void @_Z3foov() #0 !dbg !10 { + ret void, !dbg !14 +} + +attributes #0 = { noinline nounwind optnone uwtable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "example.cpp", directory: "/app") +!8 = !{i32 7, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !13) +!11 = !DISubroutineType(types: !12) +!12 = !{null} +!13 = !{} +!14 = !DILocation(line: 1, column: 13, scope: !10) diff --git a/test/DebugInfo/DebugInfoTypeVector.spvasm b/test/DebugInfo/DebugInfoTypeVector.spvasm index 5599c768..91bb1eb5 100644 --- a/test/DebugInfo/DebugInfoTypeVector.spvasm +++ b/test/DebugInfo/DebugInfoTypeVector.spvasm @@ -74,7 +74,7 @@ %38 = OpExtInst %void %2 DebugSource %36 %37 %39 = OpExtInst %void %2 DebugTypedef %31 %35 %38 0 0 %30 %40 = OpExtInst %void %2 DebugTypePointer %39 CrossWorkgroup None - %41 = OpExtInst %void %2 DebugTypeFunction None %15 %40 + %41 = OpExtInst %void %2 DebugTypeFunction None %void %40 %45 = OpExtInst %void %2 DebugTypeBasic %43 %uint_32 Unsigned %46 = OpExtInst %void %2 DebugTypedef %42 %45 %38 0 0 %30 %49 = OpExtInst %void %2 DebugSource %48 %28 diff --git a/test/DebugInfo/Generic/tu-member-opaque.spt b/test/DebugInfo/Generic/tu-member-opaque.spt index d25dfd64..e731cd63 100644 --- a/test/DebugInfo/Generic/tu-member-opaque.spt +++ b/test/DebugInfo/Generic/tu-member-opaque.spt @@ -51,7 +51,7 @@ 5 ExtInst 3 7 2 DebugInfoNone 7 ExtInst 3 10 2 DebugSource 9 7 9 ExtInst 3 11 2 DebugCompilationUnit 65536 0 10 12 -7 ExtInst 3 12 2 DebugTypeFunction 0 7 +7 ExtInst 3 12 2 DebugTypeFunction 0 3 7 ExtInst 3 16 2 DebugSource 15 7 8 ExtInst 3 21 2 DebugTypeBasic 20 18 4 14 ExtInst 3 23 2 DebugTypeMember 19 21 16 2 0 13 22 18 0 diff --git a/test/DebugInfo/NonSemantic/Shader200/FortranArrayNoType.spt b/test/DebugInfo/NonSemantic/Shader200/FortranArrayNoType.spt index 70e9635a..a0915d09 100644 --- a/test/DebugInfo/NonSemantic/Shader200/FortranArrayNoType.spt +++ b/test/DebugInfo/NonSemantic/Shader200/FortranArrayNoType.spt @@ -48,7 +48,7 @@ 6 ExtInst 3 14 2 DebugStoragePath 13 10 ExtInst 3 18 2 DebugCompilationUnit 15 16 8 17 13 5 ExtInst 3 19 2 DebugInfoNone -7 ExtInst 3 21 2 DebugTypeFunction 20 19 +7 ExtInst 3 21 2 DebugTypeFunction 20 3 15 ExtInst 3 26 2 DebugFunction 22 21 8 24 20 18 23 25 24 19 5 ExtInst 3 30 2 DebugInfoNone 6 ExtInst 3 32 2 DebugOperation 31 diff --git a/test/DebugInfo/NonSemantic/Shader200/InlineNamespace.ll b/test/DebugInfo/NonSemantic/Shader200/InlineNamespace.ll index 8b2f7cd1..47ed171d 100644 --- a/test/DebugInfo/NonSemantic/Shader200/InlineNamespace.ll +++ b/test/DebugInfo/NonSemantic/Shader200/InlineNamespace.ll @@ -22,9 +22,12 @@ ; CHECK-SPIRV: String [[#StrOuter:]] "Outer" ; CHECK-SPIRV: String [[#StrInner:]] "Inner" +; CHECK-SPIRV: TypeVoid [[#VoidTy:]] ; CHECK-SPIRV: TypeBool [[#TypeBool:]] ; CHECK-SPIRV: ConstantTrue [[#TypeBool]] [[#ConstTrue:]] ; CHECK-SPIRV: ConstantFalse [[#TypeBool]] [[#ConstFalse:]] +; Void-returning function: ReturnType must be VoidTy, not DebugInfoNone. +; CHECK-SPIRV: ExtInst [[#VoidTy]] [[#]] [[#]] DebugTypeFunction [[#]] [[#VoidTy]] ; CHECK-SPIRV: ExtInst [[#]] [[#]] [[#]] DebugLexicalBlock [[#]] [[#]] [[#]] [[#]] [[#StrOuter]] [[#ConstTrue]] ; CHECK-SPIRV: ExtInst [[#]] [[#]] [[#]] DebugLexicalBlock [[#]] [[#]] [[#]] [[#]] [[#StrInner]] [[#ConstFalse]] -- 2.55.0