Index: lib/CodeGen/AsmPrinter/DebugHandlerBase.h =================================================================== --- lib/CodeGen/AsmPrinter/DebugHandlerBase.h +++ lib/CodeGen/AsmPrinter/DebugHandlerBase.h @@ -38,10 +38,12 @@ MachineModuleInfo *MMI; /// Previous instruction's location information. This is used to - /// determine label location to indicate scope boundries in dwarf - /// debug info. + /// determine label location to indicate scope boundaries in debug info. + /// We track the previous instruction's source location (if not line 0), + /// whether it was a label, and its parent BB. DebugLoc PrevInstLoc; MCSymbol *PrevLabel = nullptr; + const MachineBasicBlock *PrevInstBB; /// This location indicates end of function prologue and beginning of /// function body. Index: lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp +++ lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp @@ -166,6 +166,7 @@ PrevInstLoc = DebugLoc(); PrevLabel = Asm->getFunctionBegin(); + PrevInstBB = nullptr; } void DebugHandlerBase::beginInstruction(const MachineInstr *MI) { @@ -201,8 +202,10 @@ assert(CurMI != nullptr); // Don't create a new label after DBG_VALUE instructions. // They don't generate code. - if (!CurMI->isDebugValue()) + if (!CurMI->isDebugValue()) { PrevLabel = nullptr; + PrevInstBB = CurMI->getParent(); + } DenseMap::iterator I = LabelsAfterInsn.find(CurMI); Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1006,24 +1006,56 @@ // Check if source location changes, but ignore DBG_VALUE locations. if (!MI->isDebugValue()) { const DebugLoc &DL = MI->getDebugLoc(); + // When we emit a line-0 record, we don't update PrevInstLoc; so look at + // the last line number actually emitted, to see if it was line 0. + unsigned LastAsmLine = + Asm->OutStreamer->getContext().getCurrentDwarfLoc().getLine(); if (DL != PrevInstLoc) { if (DL) { - unsigned Flags = 0; - PrevInstLoc = DL; - if (DL == PrologEndLoc) { - Flags |= DWARF2_FLAG_PROLOGUE_END; - PrologEndLoc = DebugLoc(); - Flags |= DWARF2_FLAG_IS_STMT; - } - if (DL.getLine() != - Asm->OutStreamer->getContext().getCurrentDwarfLoc().getLine()) - Flags |= DWARF2_FLAG_IS_STMT; + // We have an explicit location, different from the previous location. + // Don't repeat a line-0 record but otherwise emit the new location. + // (The new location might be an explicit line 0, which we do emit.) + if (DL.getLine() != 0 || LastAsmLine != 0) { + unsigned Flags = 0; + if (DL == PrologEndLoc) { + Flags |= DWARF2_FLAG_PROLOGUE_END | DWARF2_FLAG_IS_STMT; + PrologEndLoc = DebugLoc(); + } + // 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. + unsigned OldLine = PrevInstLoc ? PrevInstLoc.getLine() : LastAsmLine; + if (DL.getLine() != OldLine) + Flags |= DWARF2_FLAG_IS_STMT; + const MDNode *Scope = DL.getScope(); + recordSourceLine(DL.getLine(), DL.getCol(), Scope, Flags); + } + // If we're not at line 0, this is now the previous location. + if (DL.getLine()) + PrevInstLoc = DL; + } else if (LastAsmLine != 0 && + (UnknownLocations || PrevLabel || + (PrevInstBB && PrevInstBB != MI->getParent()))) { + // We have an unspecified location, and had a previous location + // that was not line 0. + // We want to ensure that any instruction starting a block or + // referenced from somewhere else (e.g. debug information) has + // a source location. Instead of making up a location from the + // surrounding instructions, just use a line-0 location that the + // debugger will ignore. Preserve the file number, if we can, + // which saves space in the encoded line table. + // FIXME: Also preserve the column number, for the same reason? + const MDNode *Scope = PrevInstLoc ? PrevInstLoc.getScope() : nullptr; + recordSourceLine(0, 0, Scope, 0); + } + } else if (DL) { + // We have an explicit location, same as the previous location. + // But it might not match the last emitted location. + if (DL.getLine() != LastAsmLine) { + // We emitted a line 0, and then reverted to the previous real line. + // Reinstate the source location but not as a statement. const MDNode *Scope = DL.getScope(); - recordSourceLine(DL.getLine(), DL.getCol(), Scope, Flags); - } else if (UnknownLocations) { - PrevInstLoc = DL; - recordSourceLine(0, 0, nullptr, 0); + recordSourceLine(DL.getLine(), DL.getCol(), Scope, 0); } } } Index: test/CodeGen/X86/stack-protector.ll =================================================================== --- test/CodeGen/X86/stack-protector.ll +++ test/CodeGen/X86/stack-protector.ll @@ -3888,23 +3888,27 @@ define void @test32() #1 !dbg !7 { entry: ; LINUX-I386-LABEL: test32: -; LINUX-I386: .loc 1 0 0 prologue_end +; LINUX-I386: .loc 1 4 2 prologue_end +; LINUX-I386: .loc 1 0 0 ; LINUX-I386-NEXT: calll __stack_chk_fail ; LINUX-X64-LABEL: test32: -; LINUX-X64: .loc 1 0 0 prologue_end +; LINUX-X64: .loc 1 4 2 prologue_end +; LINUX-X64: .loc 1 0 0 ; LINUX-X64-NEXT: callq __stack_chk_fail ; LINUX-KERNEL-X64-LABEL: test32: -; LINUX-KERNEL-X64: .loc 1 0 0 prologue_end +; LINUX-KERNEL-X64: .loc 1 4 2 prologue_end +; LINUX-KERNEL-X64: .loc 1 0 0 ; LINUX-KERNEL-X64-NEXT: callq __stack_chk_fail ; OPENBSD-AMD64-LABEL: test32: -; OPENBSD-AMD64: .loc 1 0 0 prologue_end +; OPENBSD-AMD64: .loc 1 4 2 prologue_end +; OPENBSD-AMD64: .loc 1 0 0 ; OPENBSD-AMD64-NEXT: movl ; OPENBSD-AMD64-NEXT: callq __stack_smash_handler %0 = alloca [5 x i8], align 1 - ret void + ret void, !dbg !9 } declare double @testi_aux() @@ -3940,3 +3944,4 @@ !6 = distinct !DISubprogram(name: "__stack_chk_fail", scope: !1, type: !8, unit: !0) !7 = distinct !DISubprogram(name: "test32", scope: !1, type: !8, unit: !0) !8 = !DISubroutineType(types: !2) +!9 = !DILocation(line: 4, column: 2, scope: !7) Index: test/DebugInfo/AArch64/line-header.ll =================================================================== --- test/DebugInfo/AArch64/line-header.ll +++ test/DebugInfo/AArch64/line-header.ll @@ -3,4 +3,4 @@ ; check line table length is correctly calculated for both big and little endian CHECK-LABEL: .debug_line contents: -CHECK: total_length: 0x0000003c +CHECK: total_length: 0x0000003e Index: test/DebugInfo/X86/dwarf-no-source-loc.ll =================================================================== --- test/DebugInfo/X86/dwarf-no-source-loc.ll +++ test/DebugInfo/X86/dwarf-no-source-loc.ll @@ -0,0 +1,74 @@ +; Verify "no source location" directives appear in appropriate places. +; RUN: llc %s -o - | FileCheck %s + +; Generated from this .cpp targeting linux using -g +; and then removed function attributes as clutter. +; +; void bar(int *); +; void baz(int *); +; # 5 "no-source-loc.cpp" +; void foo(int x) { +; int z; +; if (x) +; # 20 "include.h" +; bar(&z); +; # 10 "no-source-loc.cpp" +; baz(&z); +; } + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: uwtable +define void @_Z3fooi(i32 %x) !dbg !6 { +entry: + %x.addr = alloca i32, align 4 + %z = alloca i32, align 4 + store i32 %x, i32* %x.addr, align 4 + %0 = load i32, i32* %x.addr, align 4, !dbg !8 + %tobool = icmp ne i32 %0, 0, !dbg !8 + br i1 %tobool, label %if.then, label %if.end, !dbg !8 + +if.then: ; preds = %entry + call void @_Z3barPi(i32* %z), !dbg !9 + br label %if.end, !dbg !9 + +if.end: ; preds = %if.then, %entry + call void @_Z3bazPi(i32* %z), !dbg !12 + ret void, !dbg !14 +} + +; CHECK: .loc 1 7 7 +; CHECK-NOT: .loc +; CHECK: .loc 1 0 0 is_stmt 0 +; CHECK-NOT: .loc +; CHECK: .loc 2 20 5 is_stmt 1 +; CHECK: .LBB0_2: +; CHECK-NEXT: .loc 2 0 0 is_stmt 0 +; CHECK-NOT: .loc +; CHECK: .loc 1 10 3 is_stmt 1 + + +declare void @_Z3barPi(i32*) + +declare void @_Z3bazPi(i32*) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 4.0.0 (trunk 278782)", isOptimized: false, runtimeVersion: 0, emissionKind: LineTablesOnly, enums: !2) +!1 = !DIFile(filename: "no-source-loc.cpp", directory: "/tests") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{!"clang version 4.0.0 (trunk 278782)"} +!6 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 5, type: !7, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!7 = !DISubroutineType(types: !2) +!8 = !DILocation(line: 7, column: 7, scope: !6) +!9 = !DILocation(line: 20, column: 5, scope: !10) +!10 = !DILexicalBlockFile(scope: !6, file: !11, discriminator: 0) +!11 = !DIFile(filename: "include.h", directory: "/tests") +!12 = !DILocation(line: 10, column: 3, scope: !13) +!13 = !DILexicalBlockFile(scope: !6, file: !1, discriminator: 0) +!14 = !DILocation(line: 11, column: 1, scope: !13)