diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h --- a/llvm/include/llvm/MC/MCDwarf.h +++ b/llvm/include/llvm/MC/MCDwarf.h @@ -188,6 +188,15 @@ MCSymbol *getLabel() const { return Label; } + // This indicates the line entry is synthesized for an end entry. + bool IsEndEntry = false; + + // Override the label with the given EndLabel. + void setEndLabel(MCSymbol *EndLabel) { + Label = EndLabel; + IsEndEntry = true; + } + // This is called when an instruction is assembled into the specified // section and if there is information from the last .loc directive that // has yet to have a line entry made for it is made. @@ -203,6 +212,17 @@ // Add an entry to this MCLineSection's line entries. void addLineEntry(const MCDwarfLineEntry &LineEntry, MCSection *Sec) { MCLineDivisions[Sec].push_back(LineEntry); + PrevSec = Sec; + } + + // Create an end entry by cloning the last entry for PrevSec and resetting the + // label with the given EndLabel. Append the end entry to the line table. + void addEndEntry(MCSymbol *EndLabel) { + assert(PrevSec); + auto *LastEntry = &MCLineDivisions[PrevSec].back(); + auto EndEntry = *LastEntry; + EndEntry.setEndLabel(EndLabel); + MCLineDivisions[PrevSec].push_back(EndEntry); } using MCDwarfLineEntryCollection = std::vector; @@ -214,6 +234,9 @@ // A collection of MCDwarfLineEntry for each section. MCLineDivisionMap MCLineDivisions; + // The previous section which a line entry was added for. + MCSection *PrevSec = nullptr; + public: // Returns the collection of MCDwarfLineEntry for a given Compile Unit ID. const MCLineDivisionMap &getMCLineEntries() const { diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -494,7 +494,7 @@ // FIXME: when writing dwo, we need to avoid relocations. Probably // the "right" solution is to treat globals the way func and data // symbols are (with entries in .debug_addr). - // For now, since we only ever use index 0, this should work as-is. + // For now, since we only ever use index 0, this should work as-is. addUInt(*Loc, dwarf::DW_FORM_data4, FrameBase.Location.WasmLoc.Index); } addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_stack_value); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -786,7 +786,19 @@ /// Returns the previous CU that was being updated const DwarfCompileUnit *getPrevCU() const { return PrevCU; } - void setPrevCU(const DwarfCompileUnit *PrevCU) { this->PrevCU = PrevCU; } + + /// Set PrevCU with the given NewCU. + void setPrevCU(const DwarfCompileUnit *NewCU) { + if (PrevCU != nullptr && PrevCU != NewCU) + terminateLineTableForPrevCU(); + PrevCU = NewCU; + } + + /// Reset PrevCU. + void resetPrevCU() { setPrevCU(nullptr); } + + /// Terminate the line table by adding an end entry for PrevCU. + void terminateLineTableForPrevCU(); /// Returns the entries for the .debug_loc section. const DebugLocStream &getDebugLocs() const { return DebugLocs; } 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 @@ -2178,11 +2178,19 @@ return CU.getUniqueID(); } +void DwarfDebug::terminateLineTableForPrevCU() { + const auto &CURanges = PrevCU->getRanges(); + auto &LineTable = Asm->OutStreamer->getContext().getMCDwarfLineTable( + getDwarfCompileUnitIDForLineTable(*PrevCU)); + LineTable.getMCLineSections().addEndEntry( + const_cast(CURanges.back().End)); +} + void DwarfDebug::skippedNonDebugFunction() { // If we don't have a subprogram for this function then there will be a hole // in the range information. Keep note of this by setting the previously used // section to nullptr. - PrevCU = nullptr; + resetPrevCU(); CurFn = nullptr; } diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp --- a/llvm/lib/MC/MCDwarf.cpp +++ b/llvm/lib/MC/MCDwarf.cpp @@ -158,6 +158,22 @@ // Loop through each MCDwarfLineEntry and encode the dwarf line number table. for (const MCDwarfLineEntry &LineEntry : LineEntries) { + MCSymbol *Label = LineEntry.getLabel(); + const MCAsmInfo *asmInfo = MCOS->getContext().getAsmInfo(); + + if (LineEntry.IsEndEntry) { + MCOS->emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, Label, + asmInfo->getCodePointerSize()); + Discriminator = 0; + LastLabel = nullptr; + LastLine = 1; + + // If it is the last entry, don't emit another end entry after the loop. + if (&LineEntries.back() == &LineEntry) + return; + continue; + } + int64_t LineDelta = static_cast(LineEntry.getLine()) - LastLine; if (FileNum != LineEntry.getFileNum()) { @@ -195,12 +211,9 @@ if (LineEntry.getFlags() & DWARF2_FLAG_EPILOGUE_BEGIN) MCOS->emitInt8(dwarf::DW_LNS_set_epilogue_begin); - MCSymbol *Label = LineEntry.getLabel(); - // At this point we want to emit/create the sequence to encode the delta in // line numbers and the increment of the address from the previous Label // and the current Label. - const MCAsmInfo *asmInfo = MCOS->getContext().getAsmInfo(); MCOS->emitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label, asmInfo->getCodePointerSize()); diff --git a/llvm/test/DebugInfo/debugline-endsequence.ll b/llvm/test/DebugInfo/debugline-endsequence.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/debugline-endsequence.ll @@ -0,0 +1,61 @@ +; RUN: llc %s -filetype=obj -o - | llvm-dwarfdump --debug-line - | FileCheck %s + +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx12.0.0" + +; Check if the end_sequences are emitted for each debug range. + +; CU1 Line table +; CHECK: 0x0000000000000004 [[T:.*]] end_sequence +; CHECK: 0x0000000000000010 [[T:.*]] end_sequence +; +; CU2 Line table +; CHECK: 0x0000000000000008 [[T:.*]] end_sequence + +; CU1 (0x0 ~ 0x4) +define void @f1() !dbg !15 { + ret void, !dbg !18 +} + +; CU2 (0x4 ~ 0x8) +define void @f2() !dbg !21 { + ret void, !dbg !22 +} + +; CU2 (nodebug) - (0x8 ~ 0xc) +define void @f3() { + ret void +} + +; CU1 (0xc ~ 0x10) +define void @f4() !dbg !19 { + ret void, !dbg !20 +} + +!llvm.dbg.cu = !{!0, !3} +!llvm.ident = !{!5, !5} +!llvm.module.flags = !{!6, !7, !8, !9, !10, !11, !12, !13, !14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "LLVM", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None, sysroot: "/") +!1 = !DIFile(filename: "", directory: "/") +!2 = !{} +!3 = distinct !DICompileUnit(language: DW_LANG_C99, file: !4, producer: "LLVM", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None, sysroot: "/") +!4 = !DIFile(filename: "", directory: "/") +!5 = !{!"Apple clang version 13.0.0 (clang-1300.0.29.3)"} +!6 = !{i32 2, !"SDK Version", [2 x i32] [i32 11, i32 3]} +!7 = !{i32 7, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{i32 1, !"branch-target-enforcement", i32 0} +!11 = !{i32 1, !"sign-return-address", i32 0} +!12 = !{i32 1, !"sign-return-address-all", i32 0} +!13 = !{i32 1, !"sign-return-address-with-bkey", i32 0} +!14 = !{i32 7, !"PIC Level", i32 2} +!15 = distinct !DISubprogram(name: "f1", scope: !1, file: !1, line: 1, type: !16, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!16 = !DISubroutineType(types: !17) +!17 = !{null} +!18 = !DILocation(line: 2, column: 1, scope: !15) +!19 = distinct !DISubprogram(name: "f4", scope: !1, file: !1, line: 4, type: !16, scopeLine: 4, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!20 = !DILocation(line: 5, column: 1, scope: !19) +!21 = distinct !DISubprogram(name: "f2", scope: !4, file: !4, line: 1, type: !16, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !3, retainedNodes: !2) +!22 = !DILocation(line: 2, column: 1, scope: !21)