diff --git a/llvm/include/llvm/CodeGen/LexicalScopes.h b/llvm/include/llvm/CodeGen/LexicalScopes.h --- a/llvm/include/llvm/CodeGen/LexicalScopes.h +++ b/llvm/include/llvm/CodeGen/LexicalScopes.h @@ -32,6 +32,7 @@ class MachineInstr; class MDNode; +enum DefaultOnOff { Default, Enable, Disable }; //===----------------------------------------------------------------------===// /// InsnRange - This is used to track range of instructions with identical /// lexical scope. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -65,6 +65,8 @@ STATISTIC(NumCSParams, "Number of dbg call site params created"); +extern cl::opt UnknownLocations; + static cl::opt UseDwarfRangesBaseAddressSpecifier( "use-dwarf-ranges-base-address-specifier", cl::Hidden, cl::desc("Use base address specifiers in debug_ranges"), cl::init(false)); @@ -83,15 +85,6 @@ "split-dwarf-cross-cu-references", cl::Hidden, cl::desc("Enable cross-cu references in DWO files"), cl::init(false)); -enum DefaultOnOff { Default, Enable, Disable }; - -static cl::opt UnknownLocations( - "use-unknown-locations", cl::Hidden, - cl::desc("Make an absence of debug location information explicit."), - cl::values(clEnumVal(Default, "At top of block or after label"), - clEnumVal(Enable, "In all cases"), clEnumVal(Disable, "Never")), - cl::init(Default)); - static cl::opt AccelTables( "accel-tables", cl::Hidden, cl::desc("Output dwarf accelerator tables."), cl::values(clEnumValN(AccelTableKind::Default, "Default", diff --git a/llvm/lib/CodeGen/LexicalScopes.cpp b/llvm/lib/CodeGen/LexicalScopes.cpp --- a/llvm/lib/CodeGen/LexicalScopes.cpp +++ b/llvm/lib/CodeGen/LexicalScopes.cpp @@ -36,6 +36,13 @@ #define DEBUG_TYPE "lexicalscopes" +cl::opt UnknownLocations( + "use-unknown-locations", cl::Hidden, + cl::desc("Make an absence of debug location information explicit."), + cl::values(clEnumVal(Default, "At top of block or after label"), + clEnumVal(Enable, "In all cases"), clEnumVal(Disable, "Never")), + cl::init(Default)); + /// reset - Reset the instance so that it's prepared for another function. void LexicalScopes::reset() { MF = nullptr; @@ -93,7 +100,8 @@ continue; } - if (RangeBeginMI) { + if (RangeBeginMI && + (MIDL->getLine() != 0 || UnknownLocations == Enable)) { // If we have already seen a beginning of an instruction range and // current instruction scope does not match scope of first instruction // in this range then create a new instruction range. diff --git a/llvm/test/DebugInfo/X86/contiguous-lexical-block.ll b/llvm/test/DebugInfo/X86/contiguous-lexical-block.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/X86/contiguous-lexical-block.ll @@ -0,0 +1,73 @@ +; This test verifies that the lexical block remains contiguous and is not split by runtime instructions with a line number of 0. + +; RUN: llc -filetype=obj --use-unknown-locations=Default %s -o - \ +; RUN: | llvm-dwarfdump --debug-info - \ +; RUN: | FileCheck %s --check-prefixes=CHECK,DISABLE +; RUN: llc -filetype=obj --use-unknown-locations=Enable %s -o - \ +; RUN: | llvm-dwarfdump --debug-info - \ +; RUN: | FileCheck %s --check-prefixes=CHECK,ENABLE +; RUN: llc -filetype=obj --use-unknown-locations=Disable %s -o - \ +; RUN: | llvm-dwarfdump --debug-info - \ +; RUN: | FileCheck %s --check-prefixes=CHECK,DISABLE + +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("test") +; CHECK-NOT: NULL + +; CHECK: DW_TAG_lexical_block +; ENABLE: DW_AT_ranges (0x{{[0-9a-f]+}} +; ENABLE: [0x{{[0-9a-f]+}}, 0x{{[0-9a-f]+}}) +; ENABLE: [0x{{[0-9a-f]+}}, 0x{{[0-9a-f]+}}) +; ENABLE: [0x{{[0-9a-f]+}}, 0x{{[0-9a-f]+}}) +; ENABLE: [0x{{[0-9a-f]+}}, 0x{{[0-9a-f]+}})) + +; DISABLE-NOT: DW_AT_ranges +; DISABLE: DW_AT_low_pc (0x{{[0-9a-f]+}}) +; DISABLE: DW_AT_high_pc (0x{{[0-9a-f]+}}) + +; ModuleID = 'contiguous-lexical-block.ll' +source_filename = "test.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-linux" + +; Function Attrs: convergent noinline nounwind optnone +define i32 @test(i32 %0) #0 !dbg !5 { +entry: + %1 = add nsw i32 %0, 1, !dbg !14 + %2 = add nsw i32 %1, 1, !dbg !15 + %3 = add nsw i32 %2, 1, !dbg !17 + %4 = add nsw i32 %3, 1, !dbg !15 + %5 = add nsw i32 %4, 1, !dbg !21 + %6 = add nsw i32 %5, 1, !dbg !15 + %7 = add nsw i32 %6, 1, !dbg !22 + ret i32 %7 +} + +attributes #0 = { convergent noinline nounwind optnone } + +!llvm.module.flags = !{!0, !1} +!llvm.dbg.cu = !{!2} + +!0 = !{i32 7, !"Dwarf Version", i32 4} +!1 = !{i32 2, !"Debug Info Version", i32 3} +!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4) +!3 = !DIFile(filename: "test.c", directory: "/path/to") +!4 = !{} +!5 = distinct !DISubprogram(name: "test", scope: null, file: !3, line: 34, type: !6, scopeLine: 34, flags: DIFlagArtificial, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagMainSubprogram, unit: !2, templateParams: !4, retainedNodes: !8) +!6 = !DISubroutineType(types: !7) +!7 = !{null} +!8 = !{!9} +!9 = !DILocalVariable(name: "i", scope: !10, file: !3, line: 17, type: !13) +!10 = distinct !DILexicalBlock(scope: !11, file: !3, line: 34, column: 1) +!11 = distinct !DILexicalBlock(scope: !12, file: !3, line: 30, column: 3) +!12 = distinct !DILexicalBlock(scope: !5, file: !3, line: 29, column: 1) +!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!14 = !DILocation(line: 34, column: 1, scope: !10) +!15 = !DILocation(line: 0, scope: !16) +!16 = !DILexicalBlockFile(scope: !5, file: !3, discriminator: 0) +!17 = !DILocation(line: 36, column: 21, scope: !18) +!18 = distinct !DILexicalBlock(scope: !19, file: !3, line: 36, column: 7) +!19 = distinct !DILexicalBlock(scope: !20, file: !3, line: 36, column: 7) +!20 = distinct !DILexicalBlock(scope: !10, file: !3, line: 35, column: 5) +!21 = !DILocation(line: 37, column: 23, scope: !18) +!22 = !DILocation(line: 36, column: 27, scope: !18)