Index: lib/CodeGen/AsmPrinter/CodeViewDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -177,6 +177,9 @@ void maybeRecordLocation(const DebugLoc &DL, const MachineFunction *MF); + /// Mark this instruction as having no true source location. + void recordNoLocation(); + void clear(); void setCurrentSubprogram(const DISubprogram *SP) { Index: lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -361,6 +361,23 @@ /*IsStmt=*/false, DL->getFilename()); } +void CodeViewDebug::recordNoLocation() { + // This depends on having previous info to work from. + assert(CurFn->HaveLineInfo); + + // Work out the correct FuncId, depends on inlining info. + unsigned FuncId = CurFn->FuncId; + if (const DILocation *SiteLoc = CurFn->LastLoc->getInlinedAt()) { + const DILocation *Loc = CurFn->LastLoc.get(); + FuncId = + getInlineSite(SiteLoc, Loc->getScope()->getSubprogram()).SiteFuncId; + } + OS.EmitCVLocDirective(FuncId, CurFn->LastFileId, + LineInfo::NeverStepIntoLineNumber, + CurFn->LastLoc.getCol(), /*PrologueEnd=*/false, + /*IsStmt=*/false, CurFn->LastLoc->getFilename()); +} + void CodeViewDebug::emitCodeViewMagicVersion() { OS.EmitValueToAlignment(4); OS.AddComment("Debug section magic"); @@ -1932,12 +1949,14 @@ // Don't emit anything if we don't have any line tables. if (!CurFn->HaveLineInfo) { FnDebugInfo.erase(GV); + PrevLabel = nullptr; CurFn = nullptr; return; } CurFn->End = Asm->getFunctionEnd(); + PrevLabel = nullptr; CurFn = nullptr; } @@ -1949,9 +1968,15 @@ MI->getFlag(MachineInstr::FrameSetup)) return; DebugLoc DL = MI->getDebugLoc(); - if (DL == PrevInstLoc || !DL) + if (DL == PrevInstLoc) return; - maybeRecordLocation(DL, Asm->MF); + if (DL) { + maybeRecordLocation(DL, Asm->MF); + PrevInstLoc = DL; + } else if (PrevLabel || PrevInstBB != MI->getParent()) { + recordNoLocation(); + PrevInstLoc = DL; + } } MCSymbol *CodeViewDebug::beginCVSubsection(ModuleSubstreamKind Kind) { Index: lib/CodeGen/AsmPrinter/DebugHandlerBase.h =================================================================== --- lib/CodeGen/AsmPrinter/DebugHandlerBase.h +++ lib/CodeGen/AsmPrinter/DebugHandlerBase.h @@ -42,6 +42,7 @@ /// debug info. 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 @@ -1014,9 +1014,18 @@ const MDNode *Scope = DL.getScope(); recordSourceLine(DL.getLine(), DL.getCol(), Scope, Flags); - } else if (UnknownLocations) { + } else if (UnknownLocations || PrevLabel || + PrevInstBB != MI->getParent()) { + // 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; PrevInstLoc = DL; - recordSourceLine(0, 0, nullptr, 0); + recordSourceLine(0, 0, Scope, 0); } } } 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/COFF/cv-no-source-loc.ll =================================================================== --- test/DebugInfo/COFF/cv-no-source-loc.ll +++ test/DebugInfo/COFF/cv-no-source-loc.ll @@ -0,0 +1,90 @@ +; Verify "no source location" directives appear in appropriate places. +; RUN: llc %s -o - | FileCheck %s + +; Generated from this .cpp targeting Windows with -g -gcodeview +; 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:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc18.0.0" + +; Function Attrs: uwtable +define void @"\01?foo@@YAXH@Z"(i32 %x) !dbg !7 { +entry: + %x.addr = alloca i32, align 4 + %z = alloca i32, align 4 + store i32 %x, i32* %x.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %x.addr, metadata !12, metadata !13), !dbg !14 + call void @llvm.dbg.declare(metadata i32* %z, metadata !15, metadata !13), !dbg !16 + %0 = load i32, i32* %x.addr, align 4, !dbg !17 + %tobool = icmp ne i32 %0, 0, !dbg !17 + br i1 %tobool, label %if.then, label %if.end, !dbg !19 + +if.then: ; preds = %entry + call void @"\01?bar@@YAXPEAH@Z"(i32* %z), !dbg !20 + br label %if.end, !dbg !20 + +if.end: ; preds = %if.then, %entry + call void @"\01?baz@@YAXPEAH@Z"(i32* %z), !dbg !23 + ret void, !dbg !24 +} + +; CHECK: .cv_loc 0 1 7 7 +; CHECK-NOT: .cv_loc +; CHECK: .cv_loc 0 1 15732480 7 +; CHECK-NOT: .cv_loc +; CHECK: .cv_loc 0 2 20 5 +; CHECK: .LBB0_2: +; CHECK-NEXT: .cv_loc 0 2 15732480 5 +; CHECK-NOT: .cv_loc +; CHECK: .cv_loc 0 1 10 3 + + + +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +declare void @"\01?bar@@YAXPEAH@Z"(i32*) + +declare void @"\01?baz@@YAXPEAH@Z"(i32*) + + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 4.0.0 (trunk 280200)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "no-source-loc.cpp", directory: "/tests") +!2 = !{} +!3 = !{i32 2, !"CodeView", i32 1} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"PIC Level", i32 2} +!6 = !{!"clang version 4.0.0 (trunk 280200)"} +!7 = distinct !DISubprogram(name: "foo", linkageName: "\01?foo@@YAXH@Z", scope: !8, file: !8, line: 5, type: !9, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!8 = !DIFile(filename: "no-source-loc.cpp", directory: "/tests") +!9 = !DISubroutineType(types: !10) +!10 = !{null, !11} +!11 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!12 = !DILocalVariable(name: "x", arg: 1, scope: !7, file: !8, line: 5, type: !11) +!13 = !DIExpression() +!14 = !DILocation(line: 5, column: 14, scope: !7) +!15 = !DILocalVariable(name: "z", scope: !7, file: !8, line: 6, type: !11) +!16 = !DILocation(line: 6, column: 7, scope: !7) +!17 = !DILocation(line: 7, column: 7, scope: !18) +!18 = distinct !DILexicalBlock(scope: !7, file: !8, line: 7, column: 7) +!19 = !DILocation(line: 7, column: 7, scope: !7) +!20 = !DILocation(line: 20, column: 5, scope: !21) +!21 = !DILexicalBlockFile(scope: !18, file: !22, discriminator: 0) +!22 = !DIFile(filename: "include.h", directory: "/tests") +!23 = !DILocation(line: 10, column: 3, scope: !7) +!24 = !DILocation(line: 11, column: 1, scope: !7) Index: test/DebugInfo/COFF/local-variables.ll =================================================================== --- test/DebugInfo/COFF/local-variables.ll +++ test/DebugInfo/COFF/local-variables.ll @@ -45,6 +45,7 @@ ; ASM: leaq 44(%rsp), %rcx ; ASM: .cv_loc 1 1 5 3 # t.cpp:5:3 ; ASM: callq capture +; ASM: .cv_loc 1 1 15732480 3 ; ASM: leaq 40(%rsp), %rcx ; ASM: jmp .LBB0_3 ; ASM: [[else_start:\.Ltmp.*]]: @@ -59,6 +60,7 @@ ; ASM: leaq 48(%rsp), %rcx ; ASM: .cv_loc 2 1 5 3 # t.cpp:5:3 ; ASM: callq capture +; ASM: .cv_loc 2 1 15732480 3 ; ASM: leaq 36(%rsp), %rcx ; ASM: [[inline_site2_end:\.Ltmp.*]]: ; ASM: .LBB0_3: # %if.end @@ -167,7 +169,9 @@ ; OBJ: ChangeLineOffset: 1 ; OBJ: ChangeCodeOffset: 0x14 ; OBJ: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xD, LineOffset: 1} -; OBJ: ChangeCodeLength: 0xC +; OBJ: ChangeLineOffset: 15732475 +; OBJ: ChangeCodeOffset: 0x5 +; OBJ: ChangeCodeLength: 0x7 ; OBJ: ] ; OBJ: } ; OBJ: Local { @@ -197,7 +201,9 @@ ; OBJ: ChangeLineOffset: 1 ; OBJ: ChangeCodeOffset: 0x35 ; OBJ: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xD, LineOffset: 1} -; OBJ: ChangeCodeLength: 0xA +; OBJ: ChangeLineOffset: 15732475 +; OBJ: ChangeCodeOffset: 0x5 +; OBJ: ChangeCodeLength: 0x5 ; OBJ: ] ; OBJ: } ; OBJ: Local { 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)