Skip to content

Commit 7a930ce

Browse files
authored
[DWARF] Emit a minimal line-table for totally empty functions (#107267)
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.
1 parent 959d840 commit 7a930ce

File tree

4 files changed

+92
-19
lines changed

4 files changed

+92
-19
lines changed

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2191,23 +2191,23 @@ DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) {
21912191
const MachineInstr *PrologEndLoc = PrologEnd.first;
21922192
bool IsEmptyPrologue = PrologEnd.second;
21932193

2194-
// Get beginning of function.
2195-
if (PrologEndLoc) {
2196-
// If the prolog is empty, no need to generate scope line for the proc.
2197-
if (IsEmptyPrologue)
2194+
// If the prolog is empty, no need to generate scope line for the proc.
2195+
if (IsEmptyPrologue)
2196+
// In degenerate cases, we can have functions with no source locations
2197+
// at all. These want a scope line, to avoid a totally empty function.
2198+
// Thus, only skip scope line if there's location to place prologue_end.
2199+
if (PrologEndLoc)
21982200
return PrologEndLoc;
21992201

2200-
// Ensure the compile unit is created if the function is called before
2201-
// beginFunction().
2202-
DISubprogram *SP = MF.getFunction().getSubprogram();
2203-
(void)getOrCreateDwarfCompileUnit(SP->getUnit());
2204-
// We'd like to list the prologue as "not statements" but GDB behaves
2205-
// poorly if we do that. Revisit this with caution/GDB (7.5+) testing.
2206-
::recordSourceLine(*Asm, SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT,
2207-
CUID, getDwarfVersion(), getUnits());
2208-
return PrologEndLoc;
2209-
}
2210-
return nullptr;
2202+
// Ensure the compile unit is created if the function is called before
2203+
// beginFunction().
2204+
DISubprogram *SP = MF.getFunction().getSubprogram();
2205+
(void)getOrCreateDwarfCompileUnit(SP->getUnit());
2206+
// We'd like to list the prologue as "not statements" but GDB behaves
2207+
// poorly if we do that. Revisit this with caution/GDB (7.5+) testing.
2208+
::recordSourceLine(*Asm, SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT,
2209+
CUID, getDwarfVersion(), getUnits());
2210+
return PrologEndLoc;
22112211
}
22122212

22132213
// Gather pre-function debug information. Assumes being called immediately

llvm/test/CodeGen/PowerPC/aix-xcoff-exception-section-debug.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ define dso_local void @test__trap_annotation_debug(i32 %a) !dbg !4 {
4040
; SYMS32-NEXT: NumberOfAuxEntries: 2
4141
; SYMS32-NEXT: Function Auxiliary Entry {
4242
; SYMS32-NEXT: Index: [[#IND+1]]
43-
; SYMS32-NEXT: OffsetToExceptionTable: 0x2A8
43+
; SYMS32-NEXT: OffsetToExceptionTable: 0x2B8
4444
; SYMS32-NEXT: SizeOfFunction: 0xC
4545
; SYMS32-NEXT: PointerToLineNum: 0x0
4646
; SYMS32-NEXT: SymbolIndexOfNextBeyond: [[#IND+3]]
@@ -67,7 +67,7 @@ define dso_local void @test__trap_annotation_debug(i32 %a) !dbg !4 {
6767
; SYMS32-NEXT: NumberOfAuxEntries: 2
6868
; SYMS32-NEXT: Function Auxiliary Entry {
6969
; SYMS32-NEXT: Index: [[#IND+4]]
70-
; SYMS32-NEXT: OffsetToExceptionTable: 0x2B4
70+
; SYMS32-NEXT: OffsetToExceptionTable: 0x2C4
7171
; SYMS32-NEXT: SizeOfFunction: 0x34
7272
; SYMS32-NEXT: PointerToLineNum: 0x0
7373
; SYMS32-NEXT: SymbolIndexOfNextBeyond: [[#IND+6]]
@@ -93,7 +93,7 @@ define dso_local void @test__trap_annotation_debug(i32 %a) !dbg !4 {
9393
; SYMS64-NEXT: NumberOfAuxEntries: 3
9494
; SYMS64-NEXT: Exception Auxiliary Entry {
9595
; SYMS64-NEXT: Index: [[#IND+1]]
96-
; SYMS64-NEXT: OffsetToExceptionTable: 0x398
96+
; SYMS64-NEXT: OffsetToExceptionTable: 0x3AC
9797
; SYMS64-NEXT: SizeOfFunction: 0x18
9898
; SYMS64-NEXT: SymbolIndexOfNextBeyond: [[#IND+4]]
9999
; SYMS64-NEXT: Auxiliary Type: AUX_EXCEPT (0xFF)
@@ -126,7 +126,7 @@ define dso_local void @test__trap_annotation_debug(i32 %a) !dbg !4 {
126126
; SYMS64-NEXT: NumberOfAuxEntries: 3
127127
; SYMS64-NEXT: Exception Auxiliary Entry {
128128
; SYMS64-NEXT: Index: [[#IND+5]]
129-
; SYMS64-NEXT: OffsetToExceptionTable: 0x3AC
129+
; SYMS64-NEXT: OffsetToExceptionTable: 0x3C0
130130
; SYMS64-NEXT: SizeOfFunction: 0x68
131131
; SYMS64-NEXT: SymbolIndexOfNextBeyond: [[#IND+8]]
132132
; SYMS64-NEXT: Auxiliary Type: AUX_EXCEPT (0xFF)

llvm/test/CodeGen/X86/pseudo_cmov_lower2.ll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,20 @@ declare void @llvm.dbg.value(metadata, metadata, metadata)
198198
; Like the test for @foo1, but check that the inserted dbg.value does not
199199
; affect codegen. The CHECK items below should always be identical to @foo1,
200200
; minus the DEBUG_VALUE line and changes in labels..
201+
; We produce a scope-line source location for the entry block, and then
202+
; explicitly terminate it in the second block, as there are no other source
203+
; locations in the function.
201204
define double @foo1_g(float %p1, double %p2, double %p3) nounwind !dbg !4 {
202205
; CHECK-LABEL: foo1_g:
206+
; CHECK: .file 1 "." "test.c"
207+
; CHECK-NEXT: .loc 1 3 0
203208
; CHECK: # %bb.0: # %entry
204209
; CHECK-NEXT: xorps %xmm3, %xmm3
205210
; CHECK-NEXT: ucomiss %xmm3, %xmm0
206211
; CHECK-NEXT: movsd {{.*#+}} xmm0 = [1.25E+0,0.0E+0]
207212
; CHECK-NEXT: jae .LBB6_1
208213
; CHECK-NEXT: # %bb.2: # %entry
214+
; CHECK-NEXT: .loc 1 0 0 is_stmt 0
209215
; CHECK-NEXT: addsd %xmm2, %xmm0
210216
; CHECK-NEXT: jmp .LBB6_3
211217
; CHECK-NEXT: .LBB6_1:
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
; RUN: llc -O2 %s -o - -mtriple=x86_64-unknown-linux-gnu | FileCheck %s --check-prefix=OPTS
2+
; RUN: llc -O0 %s -o - -mtriple=x86_64-unknown-linux-gnu | FileCheck %s --check-prefix=UNOPT
3+
4+
;; Test that, even though there are no source locations attached to the foo
5+
;; function, we still give it the start-of-function source location of the
6+
;; definition line. Otherwise, this function would have no entry in the
7+
;; line table at all.
8+
9+
; OPTS-LABEL: foo:
10+
; OPTS-NEXT: .Lfunc_begin0:
11+
; OPTS-NEXT: .file 0 "." "foobar.c"
12+
; OPTS-NEXT: .loc 0 1 0
13+
; OPTS-LABEL: bar:
14+
15+
define dso_local noundef i32 @foo(ptr nocapture noundef writeonly %bar) local_unnamed_addr !dbg !10 {
16+
entry:
17+
store i32 0, ptr %bar, align 4
18+
ret i32 0
19+
}
20+
21+
;; In a function with no source location, but multiple blocks, there will be
22+
;; an opening scope-line, but it'll be automagically terminated when we switch
23+
;; to a new block. Test for this behaviour, and preserve the unconditional
24+
;; branch by compiling -O0.
25+
26+
; UNOPT-LABEL: bar:
27+
; UNOPT-NEXT: .Lfunc_begin1:
28+
; UNOPT-NEXT: .loc 0 11 0
29+
; UNOPT-LABEL: %bb.0:
30+
; UNOPT-NEXT: movq %rdi, -8(%rsp)
31+
; UNOPT-NEXT: jmp .LBB1_1
32+
; UNOPT-LABEL: .LBB1_1:
33+
; UNOPT-NEXT: .loc 1 0 0 is_stmt 0
34+
; UNOPT-NEXT: movq -8(%rsp), %rax
35+
36+
define dso_local noundef i32 @bar(ptr nocapture noundef writeonly %baz) local_unnamed_addr !dbg !20 {
37+
entry:
38+
br label %bb1
39+
bb1:
40+
store i32 0, ptr %baz, align 4
41+
ret i32 0
42+
}
43+
44+
!llvm.dbg.cu = !{!0}
45+
!llvm.module.flags = !{!2, !3}
46+
!llvm.ident = !{!9}
47+
48+
!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
49+
!1 = !DIFile(filename: "foobar.c", directory: ".")
50+
!2 = !{i32 7, !"Dwarf Version", i32 5}
51+
!3 = !{i32 2, !"Debug Info Version", i32 3}
52+
!9 = !{!"clang"}
53+
!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)
54+
!11 = !DISubroutineType(types: !12)
55+
!12 = !{!13, !14}
56+
!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
57+
!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64)
58+
!15 = !{!16}
59+
!16 = !DILocalVariable(name: "bar", arg: 1, scope: !10, file: !1, line: 1, type: !14)
60+
!17 = !DILocation(line: 0, scope: !10)
61+
!18 = !DILocation(line: 2, column: 8, scope: !10)
62+
!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)
63+
!25 = !{!26}
64+
!26 = !DILocalVariable(name: "bar", arg: 1, scope: !20, file: !1, line: 11, type: !14)
65+
!27 = !DILocation(line: 0, scope: !20)
66+
!28 = !DILocation(line: 12, column: 8, scope: !20)
67+

0 commit comments

Comments
 (0)