[llvm] [NVPTX] Fix for LTO dwarf emission when multiple CUs with a mix of DebugDirectivesOnly and NoDebug (PR #190371)

Daniel Donenfeld via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 3 10:42:17 PDT 2026


https://github.com/daniel-donenfeld created https://github.com/llvm/llvm-project/pull/190371

Only emit the initial .loc dwarf directive if the CU requires debug information. When a module contains multiple CUs where one is DebugDirectiveOnly and the rest are NoDebug, we attempt to emit dwarf for the NoDebug compile units leading to an assertion when calling emitDwarfFile0Directive when in getOrCreateDwarfCompileUnit. I added a lit test for this case which used to assert.

>From 5a9852e41b31b26d6d8f59c2496750200dc0d4cd Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Wed, 1 Apr 2026 13:32:54 +0000
Subject: [PATCH] Fix for LTO issue when multiple CU with mix of
 DebugDirectivesOnly and NoDebug

---
 llvm/include/llvm/IR/DebugInfoMetadata.h  |  1 +
 llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp |  6 ++-
 llvm/test/DebugInfo/NVPTX/no-debug-loc.ll | 46 +++++++++++++++++++++++
 3 files changed, 52 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/DebugInfo/NVPTX/no-debug-loc.ll

diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index e28b47d87d4e5..77307294f1be2 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -2123,6 +2123,7 @@ class DICompileUnit : public DIScope {
   DebugEmissionKind getEmissionKind() const {
     return (DebugEmissionKind)EmissionKind;
   }
+  bool isNoDebug() const { return EmissionKind == NoDebug; }
   bool isDebugDirectivesOnly() const {
     return EmissionKind == DebugDirectivesOnly;
   }
diff --git a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
index 9e7a58498040e..8ffdfe749ed7b 100644
--- a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
@@ -377,7 +377,11 @@ void NVPTXAsmPrinter::emitFunctionEntryLabel() {
   // Emit initial .loc debug directive for correct relocation symbol data.
   if (const DISubprogram *SP = MF->getFunction().getSubprogram()) {
     assert(SP->getUnit());
-    if (!SP->getUnit()->isDebugDirectivesOnly())
+    // NoDebug and DebugDirectivesOnly do not require emitting the initial loc
+    // directive. NoDebug does not require any debug directives and the initial
+    // loc directive is not needed for DebugDirectivesOnly as it is redundant
+    // assuming this is a non-empty function.
+    if (!SP->getUnit()->isDebugDirectivesOnly() && !SP->getUnit()->isNoDebug())
       emitInitialRawDwarfLocDirective(*MF);
   }
 }
diff --git a/llvm/test/DebugInfo/NVPTX/no-debug-loc.ll b/llvm/test/DebugInfo/NVPTX/no-debug-loc.ll
new file mode 100644
index 0000000000000..8b4a4039cac6e
--- /dev/null
+++ b/llvm/test/DebugInfo/NVPTX/no-debug-loc.ll
@@ -0,0 +1,46 @@
+; RUN: llc < %s -mtriple=nvptx64-nvidia-cuda | FileCheck %s
+; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64-nvidia-cuda | %ptxas-verify %}
+
+;; When a module contains multiple CUs where one is DebugDirectiveOnly and
+;; the rest are NoDebug, we would attempt to emit dwarf directives for the
+;; NoDebug CUs leading to an assertion. This test verifies that we only emit
+;; dwarf directives for the DebugDirectiveOnly CU.
+
+define i32 @foo(i32 %a, i32 %b) !dbg !5 {
+
+; CHECK:     .loc    [[FILE:[0-9]+]] 26 0          // debug_directives_only.cu:26:0
+; CHECK-NOT: .loc    [[FILE]]        26 0          // debug_directives_only.cu:26:0
+; CHECK:     .loc    [[FILE]]        40 22         // debug_directives_only.cu:40:22
+
+  %add = add i32 %b, %a, !dbg !8
+  ret i32 %add, !dbg !8
+}
+
+define i32 @bar(i32 %a, i32 %b) !dbg !40 {
+
+; CHECK-NOT: .loc
+
+  %add = add i32 %b, %a, !dbg !41
+  ret i32 %add, !dbg !41
+}
+
+; CHECK:     .file   [[FILE]] "/test/directory/debug_directives_only.cu"
+; CHECK-NOT: .file   {{[0-9]*}} "/test/directory/no_debug.cu"
+
+!llvm.dbg.cu = !{!0, !2}
+!nvvm.annotations = !{}
+!llvm.module.flags = !{!4}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: DebugDirectivesOnly)
+!1 = !DIFile(filename: "debug_directives_only.cu", directory: "/test/directory/")
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: NoDebug)
+!3 = !DIFile(filename: "no_debug.cu", directory: "/test/directory/")
+!4 = !{i32 1, !"Debug Info Version", i32 3}
+!5 = distinct !DISubprogram(name: "kernel", linkageName: "foo", scope: !1, file: !1, line: 123, type: !6, scopeLine: 26, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
+!6 = !DISubroutineType(types: !7)
+!7 = !{}
+!8 = !DILocation(line: 40, column: 22, scope: !31)
+!31 = distinct !DILexicalBlock(scope: !5, file: !1, line: 3, column: 17)
+!40 = distinct !DISubprogram(name: "kernel", linkageName: "bar", scope: !3, file: !3, line: 234, type: !6, scopeLine: 26, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!41 = !DILocation(line: 40, column: 22, scope: !42)
+!42 = distinct !DILexicalBlock(scope: !40, file: !3, line: 6, column: 8)



More information about the llvm-commits mailing list