[llvm] Implement support for NSDI DebugFunction opcode. (PR #211760)

Manuel Carrasco via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 30 07:01:54 PDT 2026


https://github.com/mgcarrasco updated https://github.com/llvm/llvm-project/pull/211760

>From 112360ef251d24ced1d64ea30a6d324b43a8f6b1 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Fri, 24 Jul 2026 04:42:51 -0500
Subject: [PATCH 1/5] Implement support for NSDI DebugFunction opcode.

---
 .../SPIRV/SPIRVNonSemanticDebugHandler.cpp    | 58 ++++++++++++++++++-
 .../SPIRV/SPIRVNonSemanticDebugHandler.h      | 28 ++++++---
 .../debug-function-namespace-scope.ll         | 41 +++++++++++++
 .../debug-function-with-declaration.ll        | 37 ++++++++++++
 .../SPIRV/debug-info/debug-function.ll        | 43 ++++++++++++++
 5 files changed, 199 insertions(+), 8 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/debug-function-namespace-scope.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/debug-function-with-declaration.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/debug-function.ll

diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index f22cc1a38a794..12783da9a34f3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
@@ -239,6 +239,7 @@ void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
   CompositeTypes.clear();
   TypedefTypes.clear();
   SubprogramDeclarations.clear();
+  SubprogramDefinitions.clear();
   GlobalVariableDebugInfoMap.clear();
   DebugFunctionDeclarationRegs.clear();
   ScopeToPathOpStringReg.clear();
@@ -296,7 +297,9 @@ void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
   });
 
   for (const DISubprogram *SP : Finder.subprograms()) {
-    if (!SP->isDefinition())
+    if (SP->isDefinition())
+      SubprogramDefinitions.push_back(SP);
+    else
       SubprogramDeclarations.push_back(SP);
   }
 
@@ -650,6 +653,49 @@ SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration(
                      MAI);
 }
 
+std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugFunction(
+    const DISubprogram *SP, MCRegister VoidTypeReg, MCRegister I32TypeReg,
+    MCRegister ExtInstSetReg, SPIRV::ModuleAnalysisInfo &MAI) {
+  assert(SP && "SP must not be null in emitDebugFunction");
+  assert(SP->isDefinition() && "SP must be a definition in emitDebugFunction");
+
+  const DISubroutineType *ST = SP->getType();
+  auto FnTyRegOpt = lookupOptReg(DebugTypeRegs, ST);
+  if (!FnTyRegOpt)
+    return std::nullopt;
+
+  auto ParentRegOpt = resolveDebugFunctionDeclarationParent(SP);
+  if (!ParentRegOpt)
+    return std::nullopt;
+
+  MCRegister NameReg = getCachedOpStringReg(SP->getName());
+  MCRegister LinkageReg = getCachedOpStringReg(SP->getLinkageName());
+  MCRegister FileStrReg = getCachedScopePathOpStringReg(SP);
+  MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
+                                                        ExtInstSetReg, MAI);
+
+  MCRegister LineReg =
+      emitOpConstantI32(static_cast<uint32_t>(SP->getLine()), I32TypeReg, MAI);
+  // LLVM's DISubprogram has no column field but SPIR-V expects one in
+  // DebugFunction.
+  MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
+  MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(SP), I32TypeReg, MAI);
+  MCRegister ScopeLineReg = emitOpConstantI32(
+      static_cast<uint32_t>(SP->getScopeLine()), I32TypeReg, MAI);
+
+  SmallVector<MCRegister, 10> Ops = {NameReg,    *FnTyRegOpt, SrcReg,
+                                     LineReg,    ColReg,      *ParentRegOpt,
+                                     LinkageReg, FlagsReg,    ScopeLineReg};
+
+  if (const DISubprogram *Decl = SP->getDeclaration()) {
+    if (auto DeclRegOpt = lookupOptReg(DebugFunctionDeclarationRegs, Decl))
+      Ops.push_back(*DeclRegOpt);
+  }
+
+  return emitExtInst(SPIRV::NonSemanticExtInst::DebugFunction, VoidTypeReg,
+                     ExtInstSetReg, Ops, MAI);
+}
+
 std::optional<MCRegister> SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg(
     const DIType *Ty, MCRegister VoidTypeReg, bool ReturnType) {
   if (!Ty) {
@@ -991,6 +1037,12 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticDebugStrings(
     emitAndCacheScopePathOpStringReg(TD->getFile(), MAI);
   }
 
+  for (const DISubprogram *SP : SubprogramDefinitions) {
+    emitOpStringIfNew(SP->getName(), MAI);
+    emitOpStringIfNew(SP->getLinkageName(), MAI);
+    emitAndCacheScopePathOpStringReg(SP, MAI);
+  }
+
   for (const auto &[GV, _] : GlobalVariableDebugInfoMap) {
     emitOpStringIfNew(GV->getName(), MAI);
     emitOpStringIfNew(GV->getLinkageName(), MAI);
@@ -1175,6 +1227,10 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticGlobalDebugInfo(
       DebugTypeRegs[CT] = *CompReg;
   }
 
+  // Emit DebugFunction for DISubprogram definitions.
+  for (const DISubprogram *SP : SubprogramDefinitions)
+    emitDebugFunction(SP, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
+
   // Emit DebugGlobalVariable for each collected DIGlobalVariable.
   for (const auto &[GV, Info] : GlobalVariableDebugInfoMap)
     emitDebugGlobalVariable(GV, Info, VoidTypeReg, I32TypeReg, ExtInstSetReg,
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
index eb1469a5baf69..0dbfe945bb587 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
@@ -46,7 +46,8 @@ class SPIRVSubtarget;
 ///   emitNonSemanticGlobalDebugInfo() -- emit DebugSource,
 ///                                       DebugCompilationUnit, DebugTypeBasic,
 ///                                       DebugTypePointer, DebugTypeFunction,
-///                                       DebugFunctionDeclaration.
+///                                       DebugFunctionDeclaration,
+///                                       DebugFunction.
 ///   beginFunctionImpl()              -- no-op (no per-function DI yet).
 ///   endFunctionImpl()                -- no-op.
 class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
@@ -85,6 +86,10 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
   // in beginModule() for DebugFunctionDeclaration emission.
   SmallVector<const DISubprogram *> SubprogramDeclarations;
 
+  // DISubprogram nodes that are definitions, collected in beginModule() for
+  // DebugFunction emission.
+  SmallVector<const DISubprogram *> SubprogramDefinitions;
+
   struct GlobalVariableDebugInfo {
     const DIExpression *Expr = nullptr;
     const GlobalVariable *LLVMGV = nullptr;
@@ -168,7 +173,7 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
 
   /// Emit module-scope NSDI instructions (DebugSource, DebugCompilationUnit,
   /// DebugTypeBasic, DebugTypePointer, DebugTypeFunction,
-  /// DebugFunctionDeclaration). Called by
+  /// DebugFunctionDeclaration, DebugFunction). Called by
   /// SPIRVAsmPrinter::outputModuleSections() at section 10 in place of
   /// outputModuleSection(MB_NonSemanticGlobalDI). Requires
   /// emitNonSemanticDebugStrings() to have run first when NSDI strings apply.
@@ -191,12 +196,13 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
   void beginInstruction(const MachineInstr *MI) override {}
   void endInstruction() override {}
 
-  // TODO: Emit DebugFunction and DebugFunctionDefinition here once per-function
-  // NSDI emission is implemented. DebugHandlerBase::beginFunction() populates
-  // LScopes and DbgValues, which are needed for DebugLine emission. Do not
-  // override beginFunction() until that work is in place.
+  // TODO: Emit DebugFunctionDefinition here once per-function NSDI emission is
+  // implemented. DebugHandlerBase::beginFunction() populates LScopes and
+  // DbgValues, which are needed for DebugLine emission. Do not override
+  // beginFunction() until that work is in place.
   void beginFunctionImpl(const MachineFunction *MF) override {}
-  // TODO: Add per-function cleanup when DebugFunction emission is in place.
+  // TODO: Add per-function cleanup when DebugFunctionDefinition emission is in
+  // place.
   void endFunctionImpl(const MachineFunction *MF) override {}
 
 private:
@@ -291,6 +297,14 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
                                MCRegister I32TypeReg, MCRegister ExtInstSetReg,
                                SPIRV::ModuleAnalysisInfo &MAI);
 
+  /// Emit \c DebugFunction for a defining \c DISubprogram (\p SP must satisfy
+  /// \c isDefinition()).
+  std::optional<MCRegister> emitDebugFunction(const DISubprogram *SP,
+                                              MCRegister VoidTypeReg,
+                                              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,
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-function-namespace-scope.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-function-namespace-scope.ll
new file mode 100644
index 0000000000000..a9e9160435b37
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-function-namespace-scope.ll
@@ -0,0 +1,41 @@
+; 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 %}
+
+; DISubprogram definition scoped in a DINamespace. Namespace scopes are not yet
+; supported as DebugFunction Parent, so no DebugFunction is emitted.
+
+; CHECK: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
+; CHECK-DAG: [[I32:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: OpString "ns_fn"
+; CHECK-DAG: [[PATH:%[0-9]+]] = OpString "{{[/\\]}}tmp{{[/\\]}}namespace-scope-fn.c"
+; CHECK-DAG: [[C100:%[0-9]+]] = OpConstant [[I32]] 100
+; CHECK-DAG: [[C5:%[0-9]+]] = OpConstant [[I32]] 5
+; CHECK-DAG: [[C0:%[0-9]+]] = OpConstant [[I32]] 0
+; CHECK-DAG: [[DS:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugSource [[PATH]]
+; CHECK-DAG: OpExtInst [[VOID]] [[EXT]] DebugCompilationUnit [[C100]] [[C5]] [[DS]] [[C0]]
+; CHECK-DAG: OpExtInst [[VOID]] [[EXT]] DebugTypeFunction [[C0]] [[VOID]]
+; CHECK-NOT: DebugFunction
+
+target triple = "spirv64-unknown-unknown"
+
+define spir_func void @ns_fn() !dbg !9 {
+entry:
+  ret void
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "namespace-scope-fn.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "00000000000000000000000000000000")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 7, !"frame-pointer", i32 2}
+
+!6 = !DISubroutineType(cc: DW_CC_LLVM_SpirFunction, types: !7)
+!7 = !{}
+!8 = !DINamespace(name: "ns", scope: !1)
+
+!9 = distinct !DISubprogram(name: "ns_fn", linkageName: "ns_fn", scope: !8, file: !1, line: 2, type: !6, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-function-with-declaration.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-function-with-declaration.ll
new file mode 100644
index 0000000000000..7a9523010d6f9
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-function-with-declaration.ll
@@ -0,0 +1,37 @@
+; 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 %}
+
+; DebugFunction should reference the emitted DebugFunctionDeclaration when the
+; defining DISubprogram carries a declaration operand.
+
+; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
+; CHECK-DAG: [[NAME:%[0-9]+]] = OpString "add_one"
+; CHECK-DAG: [[DECL:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugFunctionDeclaration [[NAME]] {{.*}} [[NAME]] {{.*}}
+; CHECK-DAG: [[DF:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugFunction [[NAME]] {{.*}} [[DECL]]
+
+target triple = "spirv64-unknown-unknown"
+
+define spir_func i32 @add_one(i32 %value) !dbg !5 {
+entry:
+  %result = add i32 %value, 1
+  ret i32 %result, !dbg !8
+}
+
+!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, splitDebugInlining: false, nameTableKind: None, retainedTypes: !9)
+!1 = !DIFile(filename: "debug-function-with-declaration.c", directory: "/src")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+
+!4 = !DISubroutineType(types: !6)
+!6 = !{!7, !7}
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+
+!9 = !{!10}
+!10 = !DISubprogram(name: "add_one", linkageName: "add_one", scope: !1, file: !1, line: 1, type: !4, scopeLine: 1, flags: DIFlagPrototyped, spFlags: 0)
+
+!5 = distinct !DISubprogram(name: "add_one", linkageName: "add_one", scope: !1, file: !1, line: 1, type: !4, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !10)
+!8 = !DILocation(line: 3, column: 3, scope: !5)
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-function.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-function.ll
new file mode 100644
index 0000000000000..e71dc38829e94
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-function.ll
@@ -0,0 +1,43 @@
+; 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 %}
+
+; Exercise NonSemantic DebugFunction for a defined function (module scope).
+
+; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
+; CHECK-DAG: [[I32:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: [[PATH:%[0-9]+]] = OpString "/src/debug-function.c"
+; CHECK-DAG: [[NAME:%[0-9]+]] = OpString "add_one"
+; CHECK-DAG: [[C100:%[0-9]+]] = OpConstant [[I32]] 100
+; CHECK-DAG: [[C5:%[0-9]+]] = OpConstant [[I32]] 5
+; CHECK-DAG: [[C0:%[0-9]+]] = OpConstant [[I32]] 0
+; CHECK-DAG: [[C136:%[0-9]+]] = OpConstant [[I32]] 136
+; 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: [[INTNAME:%[0-9]+]] = OpString "int"
+; CHECK-DAG: [[INT:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugTypeBasic [[INTNAME]] {{.*}} [[C0]]
+; CHECK-DAG: [[TF:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugTypeFunction [[C0]] [[INT]] [[INT]]
+; CHECK-DAG: [[DF:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugFunction [[NAME]] [[TF]] [[DS]] {{.*}} [[C0]] [[CU]] [[NAME]] [[C136]] {{.*}}
+
+target triple = "spirv64-unknown-unknown"
+
+define spir_func i32 @add_one(i32 %value) !dbg !5 {
+entry:
+  %result = add i32 %value, 1
+  ret i32 %result, !dbg !8
+}
+
+!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, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "debug-function.c", directory: "/src")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+
+!4 = !DISubroutineType(types: !6)
+!6 = !{!7, !7}
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+
+!5 = distinct !DISubprogram(name: "add_one", linkageName: "add_one", scope: !1, file: !1, line: 1, type: !4, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!8 = !DILocation(line: 3, column: 3, scope: !5)

>From a6717b4a8d7ea0592420c3f5010970f52a494fc0 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Tue, 28 Jul 2026 07:15:41 -0500
Subject: [PATCH 2/5] Fix path separators.

---
 llvm/test/CodeGen/SPIRV/debug-info/debug-function.ll | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-function.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-function.ll
index e71dc38829e94..67ea1d4ffdeb1 100644
--- a/llvm/test/CodeGen/SPIRV/debug-info/debug-function.ll
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-function.ll
@@ -6,7 +6,7 @@
 ; CHECK-DAG: [[EXT:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
 ; CHECK-DAG: [[VOID:%[0-9]+]] = OpTypeVoid
 ; CHECK-DAG: [[I32:%[0-9]+]] = OpTypeInt 32 0
-; CHECK-DAG: [[PATH:%[0-9]+]] = OpString "/src/debug-function.c"
+; CHECK-DAG: [[PATH:%[0-9]+]] = OpString "{{[/\\]}}src{{[/\\]}}debug-function.c"
 ; CHECK-DAG: [[NAME:%[0-9]+]] = OpString "add_one"
 ; CHECK-DAG: [[C100:%[0-9]+]] = OpConstant [[I32]] 100
 ; CHECK-DAG: [[C5:%[0-9]+]] = OpConstant [[I32]] 5

>From 3a3fee2ee715ed46d4bbf541d403287fc9ec8b70 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Tue, 28 Jul 2026 08:14:48 -0500
Subject: [PATCH 3/5] Fix negative checks.

---
 .../SPIRV/debug-info/debug-function-namespace-scope.ll     | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-function-namespace-scope.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-function-namespace-scope.ll
index a9e9160435b37..e97c705abeb33 100644
--- a/llvm/test/CodeGen/SPIRV/debug-info/debug-function-namespace-scope.ll
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-function-namespace-scope.ll
@@ -1,4 +1,6 @@
-; RUN: llc --verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_non_semantic_info %s -o - | FileCheck %s
+; RUN: llc --verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_non_semantic_info %s -o %t.spt
+; RUN: FileCheck %s --check-prefix=CHECK --input-file %t.spt
+; RUN: FileCheck %s --check-prefix=NO-DBG-FUNC --input-file %t.spt
 ; 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 %}
 
 ; DISubprogram definition scoped in a DINamespace. Namespace scopes are not yet
@@ -15,7 +17,8 @@
 ; CHECK-DAG: [[DS:%[0-9]+]] = OpExtInst [[VOID]] [[EXT]] DebugSource [[PATH]]
 ; CHECK-DAG: OpExtInst [[VOID]] [[EXT]] DebugCompilationUnit [[C100]] [[C5]] [[DS]] [[C0]]
 ; CHECK-DAG: OpExtInst [[VOID]] [[EXT]] DebugTypeFunction [[C0]] [[VOID]]
-; CHECK-NOT: DebugFunction
+
+; NO-DBG-FUNC-NOT: DebugFunction
 
 target triple = "spirv64-unknown-unknown"
 

>From 15c7658165573ad6071f445cf7cd4a7b2de366a8 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Tue, 28 Jul 2026 08:19:05 -0500
Subject: [PATCH 4/5] Rename function.

---
 .../Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp    |  6 +++---
 llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h | 12 ++++++------
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index 12783da9a34f3..9c071120a27b7 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
@@ -572,7 +572,7 @@ SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
 
 // Match SPIRV-LLVM-Translator's selection logic for the Parent operand.
 std::optional<MCRegister>
-SPIRVNonSemanticDebugHandler::resolveDebugFunctionDeclarationParent(
+SPIRVNonSemanticDebugHandler::resolveDebugFunctionParent(
     const DISubprogram *SP) const {
   const DIScope *Scope = SP->getScope();
   if (Scope && !isa<DIFile>(Scope)) {
@@ -623,7 +623,7 @@ SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration(
     return std::nullopt;
   MCRegister FnTyReg = *FnTyRegOpt;
 
-  auto ParentRegOpt = resolveDebugFunctionDeclarationParent(SP);
+  auto ParentRegOpt = resolveDebugFunctionParent(SP);
   if (!ParentRegOpt)
     return std::nullopt;
 
@@ -664,7 +664,7 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugFunction(
   if (!FnTyRegOpt)
     return std::nullopt;
 
-  auto ParentRegOpt = resolveDebugFunctionDeclarationParent(SP);
+  auto ParentRegOpt = resolveDebugFunctionParent(SP);
   if (!ParentRegOpt)
     return std::nullopt;
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
index 0dbfe945bb587..5da526587df91 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
@@ -290,7 +290,7 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
   /// DISubroutineType type, the signature type was not emitted in \c
   /// DebugTypeRegs, no path
   /// \c OpString was recorded for \p SP in section 7, or
-  /// \c resolveDebugFunctionDeclarationParent returns no id for the \c Parent
+  /// \c resolveDebugFunctionParent returns no id for the \c Parent
   /// operand.
   std::optional<MCRegister>
   emitDebugFunctionDeclaration(const DISubprogram *SP, MCRegister VoidTypeReg,
@@ -436,15 +436,15 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
                                                MCRegister ExtInstSetReg,
                                                SPIRV::ModuleAnalysisInfo &MAI);
 
-  /// Resolve the \c Parent operand for \c DebugFunctionDeclaration: an emitted
-  /// debug type id when \c SP->getScope() is a \c DIType in \c DebugTypeRegs,
-  /// otherwise \c DebugCompilationUnit for \c SP->getUnit() (or the first
-  /// module CU when \c unit: is absent).
+  /// Resolve the \c Parent operand for \c DebugFunctionDeclaration and
+  /// \c DebugFunction: an emitted debug type id when \c SP->getScope() is a
+  /// \c DIType in \c DebugTypeRegs, otherwise \c DebugCompilationUnit for
+  /// \c SP->getUnit() (or the first module CU when \c unit: is absent).
   /// \returns \c std::nullopt when the scope requires a parent we cannot supply
   /// (non-file scope that is not a mapped \c DIType) or the CU has no emitted
   /// id.
   std::optional<MCRegister>
-  resolveDebugFunctionDeclarationParent(const DISubprogram *SP) const;
+  resolveDebugFunctionParent(const DISubprogram *SP) const;
 
   /// Resolve the \c Parent operand for a type instruction (\c
   /// DebugTypeComposite) from its \p Scope: an emitted debug type id when \p

>From 99315866c22316da15d1a5d9884fb4c2e33c3336 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Tue, 28 Jul 2026 08:23:12 -0500
Subject: [PATCH 5/5] Simplify loops.

---
 llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index 9c071120a27b7..d0b7f67866acb 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
@@ -1009,7 +1009,8 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticDebugStrings(
   for (const DIBasicType *BT : BasicTypes)
     emitOpStringIfNew(BT->getName(), MAI);
 
-  for (const DISubprogram *SP : SubprogramDeclarations) {
+  for (const DISubprogram *SP : concat<const DISubprogram *>(
+           SubprogramDeclarations, SubprogramDefinitions)) {
     emitOpStringIfNew(SP->getName(), MAI);
     emitOpStringIfNew(SP->getLinkageName(), MAI);
     emitAndCacheScopePathOpStringReg(SP, MAI);
@@ -1037,12 +1038,6 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticDebugStrings(
     emitAndCacheScopePathOpStringReg(TD->getFile(), MAI);
   }
 
-  for (const DISubprogram *SP : SubprogramDefinitions) {
-    emitOpStringIfNew(SP->getName(), MAI);
-    emitOpStringIfNew(SP->getLinkageName(), MAI);
-    emitAndCacheScopePathOpStringReg(SP, MAI);
-  }
-
   for (const auto &[GV, _] : GlobalVariableDebugInfoMap) {
     emitOpStringIfNew(GV->getName(), MAI);
     emitOpStringIfNew(GV->getLinkageName(), MAI);



More information about the llvm-commits mailing list