[llvm] [DWARF] Emit a minimal line-table for totally empty functions (PR #107267)
Jeremy Morse via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 5 07:50:07 PDT 2024
https://github.com/jmorse updated https://github.com/llvm/llvm-project/pull/107267
>From 60750e7c4459e1164894e2acb4bded6b9bcbc246 Mon Sep 17 00:00:00 2001
From: Jeremy Morse <jeremy.morse at sony.com>
Date: Mon, 2 Sep 2024 17:01:47 +0100
Subject: [PATCH 1/5] [DebugInfo] Don't search scope chain to find Subprogram
Seemingly this goes back to fd07a2af23c in 2015 -- I anticipate that back
then the metadata layout was radically different. But nowadays at least, we
can just directly look up the subprogram.
---
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index f111b4aea06f1b..1d57b5e4400dc2 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -2199,11 +2199,10 @@ DebugLoc DwarfDebug::emitInitialLocDirective(const MachineFunction &MF,
// Ensure the compile unit is created if the function is called before
// beginFunction().
- (void)getOrCreateDwarfCompileUnit(
- MF.getFunction().getSubprogram()->getUnit());
+ DISubprogram *SP = MF.getFunction().getSubprogram();
+ (void)getOrCreateDwarfCompileUnit(SP->getUnit());
// We'd like to list the prologue as "not statements" but GDB behaves
// poorly if we do that. Revisit this with caution/GDB (7.5+) testing.
- const DISubprogram *SP = PrologEndLoc->getInlinedAtScope()->getSubprogram();
::recordSourceLine(*Asm, SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT,
CUID, getDwarfVersion(), getUnits());
return PrologEndLoc;
>From dca325e510ea60fc772c0e2ace1dffdd9d8d664d Mon Sep 17 00:00:00 2001
From: Jeremy Morse <jeremy.morse at sony.com>
Date: Mon, 2 Sep 2024 17:30:35 +0100
Subject: [PATCH 2/5] [DebugInfo] Identify end of prologue by instruction
Currently, we identify the end of the prologue as being "the instruction
that first has *this* DebugLoc". It works well enough, but I feel
identifying a position in a function is best communicated by a
MachineInstr. Plus, I've got some patches coming that depend upon this.
---
llvm/include/llvm/CodeGen/DebugHandlerBase.h | 2 +-
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 23 ++++++++++----------
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h | 6 +++--
3 files changed, 17 insertions(+), 14 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/DebugHandlerBase.h b/llvm/include/llvm/CodeGen/DebugHandlerBase.h
index 85046c200ff9b1..d39e7e68cb2558 100644
--- a/llvm/include/llvm/CodeGen/DebugHandlerBase.h
+++ b/llvm/include/llvm/CodeGen/DebugHandlerBase.h
@@ -74,7 +74,7 @@ class DebugHandlerBase {
/// This location indicates end of function prologue and beginning of
/// function body.
- DebugLoc PrologEndLoc;
+ const MachineInstr *PrologEndLoc;
/// This block includes epilogue instructions.
const MachineBasicBlock *EpilogBeginBlock = nullptr;
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 1d57b5e4400dc2..f8515ab6ff11fa 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -2114,9 +2114,9 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
// (The new location might be an explicit line 0, which we do emit.)
if (DL.getLine() == 0 && LastAsmLine == 0)
return;
- if (DL == PrologEndLoc) {
+ if (MI == PrologEndLoc) {
Flags |= DWARF2_FLAG_PROLOGUE_END | DWARF2_FLAG_IS_STMT;
- PrologEndLoc = DebugLoc();
+ PrologEndLoc = nullptr;
}
// If the line changed, we call that a new statement; unless we went to
// line 0 and came back, in which case it is not a new statement.
@@ -2132,10 +2132,11 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
PrevInstLoc = DL;
}
-static std::pair<DebugLoc, bool> findPrologueEndLoc(const MachineFunction *MF) {
+static std::pair<const MachineInstr *, bool>
+findPrologueEndLoc(const MachineFunction *MF) {
// First known non-DBG_VALUE and non-frame setup location marks
// the beginning of the function body.
- DebugLoc LineZeroLoc;
+ const MachineInstr *LineZeroLoc = nullptr;
const Function &F = MF->getFunction();
// Some instructions may be inserted into prologue after this function. Must
@@ -2152,9 +2153,9 @@ static std::pair<DebugLoc, bool> findPrologueEndLoc(const MachineFunction *MF) {
// meaningful breakpoint. If none is found, return the first
// location after the frame setup.
if (MI.getDebugLoc().getLine())
- return std::make_pair(MI.getDebugLoc(), IsEmptyPrologue);
+ return std::make_pair(&MI, IsEmptyPrologue);
- LineZeroLoc = MI.getDebugLoc();
+ LineZeroLoc = &MI;
}
IsEmptyPrologue = false;
}
@@ -2185,10 +2186,10 @@ static void recordSourceLine(AsmPrinter &Asm, unsigned Line, unsigned Col,
Discriminator, Fn);
}
-DebugLoc DwarfDebug::emitInitialLocDirective(const MachineFunction &MF,
- unsigned CUID) {
- std::pair<DebugLoc, bool> PrologEnd = findPrologueEndLoc(&MF);
- DebugLoc PrologEndLoc = PrologEnd.first;
+const MachineInstr *
+DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) {
+ std::pair<const MachineInstr *, bool> PrologEnd = findPrologueEndLoc(&MF);
+ const MachineInstr *PrologEndLoc = PrologEnd.first;
bool IsEmptyPrologue = PrologEnd.second;
// Get beginning of function.
@@ -2207,7 +2208,7 @@ DebugLoc DwarfDebug::emitInitialLocDirective(const MachineFunction &MF,
CUID, getDwarfVersion(), getUnits());
return PrologEndLoc;
}
- return DebugLoc();
+ return nullptr;
}
// Gather pre-function debug information. Assumes being called immediately
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 6e379396ea079e..19f5b677bb8d06 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -724,8 +724,10 @@ class DwarfDebug : public DebugHandlerBase {
/// Emit all Dwarf sections that should come after the content.
void endModule() override;
- /// Emits inital debug location directive.
- DebugLoc emitInitialLocDirective(const MachineFunction &MF, unsigned CUID);
+ /// Emits inital debug location directive. Returns instruction at which
+ /// the function prologue ends.
+ const MachineInstr *emitInitialLocDirective(const MachineFunction &MF,
+ unsigned CUID);
/// Process beginning of an instruction.
void beginInstruction(const MachineInstr *MI) override;
>From b72309c2de3af54f201cf0ba339c107658c01fcd Mon Sep 17 00:00:00 2001
From: Jeremy Morse <jeremy.morse at sony.com>
Date: Tue, 3 Sep 2024 11:29:36 +0100
Subject: [PATCH 3/5] [DebugInfo] Give functions with no source locations a
scope-line
In degenerate but legal inputs, we can have functions that have no source
locations at all -- all the DebugLocs attached to instructions are empty.
LLVM didn't produce any source location for the function; with this patch
it will at least emit the function-scope source location. Demonstrated by
empty-line-info.ll
The XCOFF test modified has similar symptoms -- with this patch, the size
of the ".dwline" section grows a bit, thus shifting some of the file
internal offsets, which I've updated.
---
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 30 ++++++------
.../aix-xcoff-exception-section-debug.ll | 8 ++--
llvm/test/DebugInfo/X86/empty-line-info.ll | 46 +++++++++++++++++++
3 files changed, 65 insertions(+), 19 deletions(-)
create mode 100644 llvm/test/DebugInfo/X86/empty-line-info.ll
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index f8515ab6ff11fa..e9649f9ff81658 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -2192,23 +2192,23 @@ DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) {
const MachineInstr *PrologEndLoc = PrologEnd.first;
bool IsEmptyPrologue = PrologEnd.second;
- // Get beginning of function.
- if (PrologEndLoc) {
- // If the prolog is empty, no need to generate scope line for the proc.
- if (IsEmptyPrologue)
+ // If the prolog is empty, no need to generate scope line for the proc.
+ if (IsEmptyPrologue)
+ // In degenerate cases, we can have functions with no source locations
+ // at all. These want a scope line, to avoid a totally empty function.
+ // Thus, only skip scope line if there's location to place prologue_end.
+ if (PrologEndLoc)
return PrologEndLoc;
- // Ensure the compile unit is created if the function is called before
- // beginFunction().
- DISubprogram *SP = MF.getFunction().getSubprogram();
- (void)getOrCreateDwarfCompileUnit(SP->getUnit());
- // We'd like to list the prologue as "not statements" but GDB behaves
- // poorly if we do that. Revisit this with caution/GDB (7.5+) testing.
- ::recordSourceLine(*Asm, SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT,
- CUID, getDwarfVersion(), getUnits());
- return PrologEndLoc;
- }
- return nullptr;
+ // Ensure the compile unit is created if the function is called before
+ // beginFunction().
+ DISubprogram *SP = MF.getFunction().getSubprogram();
+ (void)getOrCreateDwarfCompileUnit(SP->getUnit());
+ // We'd like to list the prologue as "not statements" but GDB behaves
+ // poorly if we do that. Revisit this with caution/GDB (7.5+) testing.
+ ::recordSourceLine(*Asm, SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT,
+ CUID, getDwarfVersion(), getUnits());
+ return PrologEndLoc;
}
// Gather pre-function debug information. Assumes being called immediately
diff --git a/llvm/test/CodeGen/PowerPC/aix-xcoff-exception-section-debug.ll b/llvm/test/CodeGen/PowerPC/aix-xcoff-exception-section-debug.ll
index bc6e9f35019828..9c5d560e27f91e 100644
--- a/llvm/test/CodeGen/PowerPC/aix-xcoff-exception-section-debug.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-xcoff-exception-section-debug.ll
@@ -40,7 +40,7 @@ define dso_local void @test__trap_annotation_debug(i32 %a) !dbg !4 {
; SYMS32-NEXT: NumberOfAuxEntries: 2
; SYMS32-NEXT: Function Auxiliary Entry {
; SYMS32-NEXT: Index: [[#IND+1]]
-; SYMS32-NEXT: OffsetToExceptionTable: 0x2A8
+; SYMS32-NEXT: OffsetToExceptionTable: 0x2B8
; SYMS32-NEXT: SizeOfFunction: 0xC
; SYMS32-NEXT: PointerToLineNum: 0x0
; SYMS32-NEXT: SymbolIndexOfNextBeyond: [[#IND+3]]
@@ -67,7 +67,7 @@ define dso_local void @test__trap_annotation_debug(i32 %a) !dbg !4 {
; SYMS32-NEXT: NumberOfAuxEntries: 2
; SYMS32-NEXT: Function Auxiliary Entry {
; SYMS32-NEXT: Index: [[#IND+4]]
-; SYMS32-NEXT: OffsetToExceptionTable: 0x2B4
+; SYMS32-NEXT: OffsetToExceptionTable: 0x2C4
; SYMS32-NEXT: SizeOfFunction: 0x34
; SYMS32-NEXT: PointerToLineNum: 0x0
; SYMS32-NEXT: SymbolIndexOfNextBeyond: [[#IND+6]]
@@ -93,7 +93,7 @@ define dso_local void @test__trap_annotation_debug(i32 %a) !dbg !4 {
; SYMS64-NEXT: NumberOfAuxEntries: 3
; SYMS64-NEXT: Exception Auxiliary Entry {
; SYMS64-NEXT: Index: [[#IND+1]]
-; SYMS64-NEXT: OffsetToExceptionTable: 0x398
+; SYMS64-NEXT: OffsetToExceptionTable: 0x3AC
; SYMS64-NEXT: SizeOfFunction: 0x18
; SYMS64-NEXT: SymbolIndexOfNextBeyond: [[#IND+4]]
; SYMS64-NEXT: Auxiliary Type: AUX_EXCEPT (0xFF)
@@ -126,7 +126,7 @@ define dso_local void @test__trap_annotation_debug(i32 %a) !dbg !4 {
; SYMS64-NEXT: NumberOfAuxEntries: 3
; SYMS64-NEXT: Exception Auxiliary Entry {
; SYMS64-NEXT: Index: [[#IND+5]]
-; SYMS64-NEXT: OffsetToExceptionTable: 0x3AC
+; SYMS64-NEXT: OffsetToExceptionTable: 0x3C0
; SYMS64-NEXT: SizeOfFunction: 0x68
; SYMS64-NEXT: SymbolIndexOfNextBeyond: [[#IND+8]]
; SYMS64-NEXT: Auxiliary Type: AUX_EXCEPT (0xFF)
diff --git a/llvm/test/DebugInfo/X86/empty-line-info.ll b/llvm/test/DebugInfo/X86/empty-line-info.ll
new file mode 100644
index 00000000000000..68cf08f18ffeb8
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/empty-line-info.ll
@@ -0,0 +1,46 @@
+; RUN: llc %s -o - -mtriple=x86_64-unknown-linux-gnu | FileCheck %s
+
+;; Test that, even though there are no source locations attached to the foo
+;; function, we still give it the start-of-function source location of the
+;; definition line. Otherwise, this function would have no entry in the
+;; line table at all.
+
+; CHECK-LABEL: foo:
+; CHECK-NEXT: .Lfunc_begin0:
+; CHECK-NEXT: .file 0 "." "foobar.c"
+; CHECK-NEXT: .loc 0 1 0
+
+define dso_local noundef i32 @foo(ptr nocapture noundef writeonly %bar) local_unnamed_addr !dbg !10 {
+entry:
+ store i32 0, ptr %bar, align 4
+ ret i32 0
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "foobar.c", directory: ".")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+!9 = !{!"clang"}
+!10 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !15)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13, !14}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64)
+!15 = !{!16}
+!16 = !DILocalVariable(name: "bar", arg: 1, scope: !10, file: !1, line: 1, type: !14)
+!17 = !DILocation(line: 0, scope: !10)
+!18 = !DILocation(line: 2, column: 8, scope: !10)
+!19 = !{!20, !20, i64 0}
+!20 = !{!"int", !21, i64 0}
+!21 = !{!"omnipotent char", !22, i64 0}
+!22 = !{!"Simple C/C++ TBAA"}
+!23 = !DILocation(line: 3, column: 3, scope: !10)
>From 9a0bec82f6c4df9b5e1507eda6f315c4ae20ae8d Mon Sep 17 00:00:00 2001
From: Jeremy Morse <jeremy.morse at sony.com>
Date: Thu, 5 Sep 2024 12:55:34 +0100
Subject: [PATCH 4/5] clang-format, remove some unnecessary metadata
---
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 4 ++--
llvm/test/DebugInfo/X86/empty-line-info.ll | 11 +----------
2 files changed, 3 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index e9649f9ff81658..b51e6981ade695 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -2206,8 +2206,8 @@ DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) {
(void)getOrCreateDwarfCompileUnit(SP->getUnit());
// We'd like to list the prologue as "not statements" but GDB behaves
// poorly if we do that. Revisit this with caution/GDB (7.5+) testing.
- ::recordSourceLine(*Asm, SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT,
- CUID, getDwarfVersion(), getUnits());
+ ::recordSourceLine(*Asm, SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT, CUID,
+ getDwarfVersion(), getUnits());
return PrologEndLoc;
}
diff --git a/llvm/test/DebugInfo/X86/empty-line-info.ll b/llvm/test/DebugInfo/X86/empty-line-info.ll
index 68cf08f18ffeb8..0bb30712f189d3 100644
--- a/llvm/test/DebugInfo/X86/empty-line-info.ll
+++ b/llvm/test/DebugInfo/X86/empty-line-info.ll
@@ -17,18 +17,13 @@ entry:
}
!llvm.dbg.cu = !{!0}
-!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.module.flags = !{!2, !3}
!llvm.ident = !{!9}
!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "foobar.c", directory: ".")
!2 = !{i32 7, !"Dwarf Version", i32 5}
!3 = !{i32 2, !"Debug Info Version", i32 3}
-!4 = !{i32 1, !"wchar_size", i32 4}
-!5 = !{i32 8, !"PIC Level", i32 2}
-!6 = !{i32 7, !"PIE Level", i32 2}
-!7 = !{i32 7, !"uwtable", i32 2}
-!8 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
!9 = !{!"clang"}
!10 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !15)
!11 = !DISubroutineType(types: !12)
@@ -39,8 +34,4 @@ entry:
!16 = !DILocalVariable(name: "bar", arg: 1, scope: !10, file: !1, line: 1, type: !14)
!17 = !DILocation(line: 0, scope: !10)
!18 = !DILocation(line: 2, column: 8, scope: !10)
-!19 = !{!20, !20, i64 0}
-!20 = !{!"int", !21, i64 0}
-!21 = !{!"omnipotent char", !22, i64 0}
-!22 = !{!"Simple C/C++ TBAA"}
!23 = !DILocation(line: 3, column: 3, scope: !10)
>From fd7fc3a2cd79a332d1c6b26958840b855af8f28f Mon Sep 17 00:00:00 2001
From: Jeremy Morse <jeremy.morse at sony.com>
Date: Thu, 5 Sep 2024 15:39:39 +0100
Subject: [PATCH 5/5] Add check-lines for terminating this opening line number
---
llvm/test/CodeGen/X86/pseudo_cmov_lower2.ll | 6 +++
llvm/test/DebugInfo/X86/empty-line-info.ll | 42 ++++++++++++++++++---
2 files changed, 42 insertions(+), 6 deletions(-)
diff --git a/llvm/test/CodeGen/X86/pseudo_cmov_lower2.ll b/llvm/test/CodeGen/X86/pseudo_cmov_lower2.ll
index f2c1269143fbc5..19253d67c14945 100644
--- a/llvm/test/CodeGen/X86/pseudo_cmov_lower2.ll
+++ b/llvm/test/CodeGen/X86/pseudo_cmov_lower2.ll
@@ -198,14 +198,20 @@ declare void @llvm.dbg.value(metadata, metadata, metadata)
; Like the test for @foo1, but check that the inserted dbg.value does not
; affect codegen. The CHECK items below should always be identical to @foo1,
; minus the DEBUG_VALUE line and changes in labels..
+; We produce a scope-line source location for the entry block, and then
+; explicitly terminate it in the second block, as there are no other source
+; locations in the function.
define double @foo1_g(float %p1, double %p2, double %p3) nounwind !dbg !4 {
; CHECK-LABEL: foo1_g:
+; CHECK: .file 1 "." "test.c"
+; CHECK-NEXT: .loc 1 3 0
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: xorps %xmm3, %xmm3
; CHECK-NEXT: ucomiss %xmm3, %xmm0
; CHECK-NEXT: movsd {{.*#+}} xmm0 = [1.25E+0,0.0E+0]
; CHECK-NEXT: jae .LBB6_1
; CHECK-NEXT: # %bb.2: # %entry
+; CHECK-NEXT: .loc 1 0 0 is_stmt 0
; CHECK-NEXT: addsd %xmm2, %xmm0
; CHECK-NEXT: jmp .LBB6_3
; CHECK-NEXT: .LBB6_1:
diff --git a/llvm/test/DebugInfo/X86/empty-line-info.ll b/llvm/test/DebugInfo/X86/empty-line-info.ll
index 0bb30712f189d3..e726e5c882460c 100644
--- a/llvm/test/DebugInfo/X86/empty-line-info.ll
+++ b/llvm/test/DebugInfo/X86/empty-line-info.ll
@@ -1,14 +1,16 @@
-; RUN: llc %s -o - -mtriple=x86_64-unknown-linux-gnu | FileCheck %s
+; RUN: llc -O2 %s -o - -mtriple=x86_64-unknown-linux-gnu | FileCheck %s --check-prefix=OPTS
+; RUN: llc -O0 %s -o - -mtriple=x86_64-unknown-linux-gnu | FileCheck %s --check-prefix=UNOPT
;; Test that, even though there are no source locations attached to the foo
;; function, we still give it the start-of-function source location of the
;; definition line. Otherwise, this function would have no entry in the
;; line table at all.
-; CHECK-LABEL: foo:
-; CHECK-NEXT: .Lfunc_begin0:
-; CHECK-NEXT: .file 0 "." "foobar.c"
-; CHECK-NEXT: .loc 0 1 0
+; OPTS-LABEL: foo:
+; OPTS-NEXT: .Lfunc_begin0:
+; OPTS-NEXT: .file 0 "." "foobar.c"
+; OPTS-NEXT: .loc 0 1 0
+; OPTS-LABEL: bar:
define dso_local noundef i32 @foo(ptr nocapture noundef writeonly %bar) local_unnamed_addr !dbg !10 {
entry:
@@ -16,6 +18,29 @@ entry:
ret i32 0
}
+;; In a function with no source location, but multiple blocks, there will be
+;; an opening scope-line, but it'll be automagically terminated when we switch
+;; to a new block. Test for this behaviour, and preserve the unconditional
+;; branch by compiling -O0.
+
+; UNOPT-LABEL: bar:
+; UNOPT-NEXT: .Lfunc_begin1:
+; UNOPT-NEXT: .loc 0 11 0
+; UNOPT-LABEL: %bb.0:
+; UNOPT-NEXT: movq %rdi, -8(%rsp)
+; UNOPT-NEXT: jmp .LBB1_1
+; UNOPT-LABEL: .LBB1_1:
+; UNOPT-NEXT: .loc 1 0 0 is_stmt 0
+; UNOPT-NEXT: movq -8(%rsp), %rax
+
+define dso_local noundef i32 @bar(ptr nocapture noundef writeonly %baz) local_unnamed_addr !dbg !20 {
+entry:
+ br label %bb1
+bb1:
+ store i32 0, ptr %baz, align 4
+ ret i32 0
+}
+
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!2, !3}
!llvm.ident = !{!9}
@@ -34,4 +59,9 @@ entry:
!16 = !DILocalVariable(name: "bar", arg: 1, scope: !10, file: !1, line: 1, type: !14)
!17 = !DILocation(line: 0, scope: !10)
!18 = !DILocation(line: 2, column: 8, scope: !10)
-!23 = !DILocation(line: 3, column: 3, scope: !10)
+!20 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 11, type: !11, scopeLine: 11, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !25)
+!25 = !{!26}
+!26 = !DILocalVariable(name: "bar", arg: 1, scope: !20, file: !1, line: 11, type: !14)
+!27 = !DILocation(line: 0, scope: !20)
+!28 = !DILocation(line: 12, column: 8, scope: !20)
+
More information about the llvm-commits
mailing list