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 @@ -196,11 +196,20 @@ // A collection of MCDwarfLineEntry for each section. MCLineDivisionMap MCLineDivisions; + // Points to the end label of the last function range. + MCSymbol *EndLabel = nullptr; + public: // Returns the collection of MCDwarfLineEntry for a given Compile Unit ID. const MCLineDivisionMap &getMCLineEntries() const { return MCLineDivisions; } + + // Set the end label from the last function range. + void setEndLabel(MCSymbol *FuncEndLabel) { EndLabel = FuncEndLabel; } + + // Get the end label for the CU. + MCSymbol *getEndLabel() const { return EndLabel; } }; struct MCDwarfLineTableParams { diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h --- a/llvm/include/llvm/MC/MCObjectStreamer.h +++ b/llvm/include/llvm/MC/MCObjectStreamer.h @@ -148,7 +148,8 @@ void emitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel, const MCSymbol *Label, unsigned PointerSize) override; - void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel) override; + void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel, + MCSymbol *EndLabel) override; void emitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, const MCSymbol *Label); void emitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -1106,7 +1106,8 @@ virtual void emitDwarfLineStartLabel(MCSymbol *StartSym); /// Emit the debug line end entry. - virtual void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel) {} + virtual void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel, + MCSymbol *EndLabel) {} /// If targets does not support representing debug line section by .loc/.file /// directives in assembly output, we need to populate debug line section with 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 @@ -2201,6 +2201,13 @@ for (const auto &R : Asm->MBBSectionRanges) TheCU.addRange({R.second.BeginLabel, R.second.EndLabel}); + // Set the end label from the last function range to the CU's line table. + assert(!Asm->MBBSectionRanges.empty()); + Asm->OutStreamer->getContext() + .getMCDwarfLineTable(getDwarfCompileUnitID(TheCU)) + .getMCLineSections() + .setEndLabel(Asm->MBBSectionRanges.back().second.EndLabel); + // Under -gmlt, skip building the subprogram if there are no inlined // subroutines inside it. But with -fdebug-info-for-profiling, the subprogram // is still needed as we need its source location. diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -393,7 +393,8 @@ void emitDwarfLineStartLabel(MCSymbol *StartSym) override; - void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel) override; + void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel, + MCSymbol *EndLabel = nullptr) override; void emitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel, const MCSymbol *Label, @@ -2403,7 +2404,8 @@ } void MCAsmStreamer::emitDwarfLineEndEntry(MCSection *Section, - MCSymbol *LastLabel) { + MCSymbol *LastLabel, + MCSymbol *EndLabel) { // If the targets write the raw debug line data for assembly output (We can // not switch to Section and add the end symbol there for assembly output) // we currently use the .text end label as any section end. This will not 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 @@ -162,9 +162,10 @@ // This emits the Dwarf line table for the specified section from the entries // in the LineSection. // -static inline void emitDwarfLineTable( - MCStreamer *MCOS, MCSection *Section, - const MCLineSection::MCDwarfLineEntryCollection &LineEntries) { +static inline void +emitDwarfLineTable(MCStreamer *MCOS, MCSection *Section, + const MCLineSection::MCDwarfLineEntryCollection &LineEntries, + MCSymbol *EndLabel) { unsigned FileNum = 1; unsigned LastLine = 1; unsigned Column = 0; @@ -227,7 +228,7 @@ } // Generate DWARF line end entry. - MCOS->emitDwarfLineEndEntry(Section, LastLabel); + MCOS->emitDwarfLineEndEntry(Section, LastLabel, EndLabel); } // @@ -522,7 +523,8 @@ // Put out the line tables. for (const auto &LineSec : MCLineSections.getMCLineEntries()) - emitDwarfLineTable(MCOS, LineSec.first, LineSec.second); + emitDwarfLineTable(MCOS, LineSec.first, LineSec.second, + MCLineSections.getEndLabel()); // This is the end of the section, so set the value of the symbol at the end // of this section (that was used in a previous expression). diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -503,12 +503,21 @@ } void MCObjectStreamer::emitDwarfLineEndEntry(MCSection *Section, - MCSymbol *LastLabel) { - // Emit a DW_LNE_end_sequence for the end of the section. - // Use the section end label to compute the address delta and use INT64_MAX + MCSymbol *LastLabel, + MCSymbol *EndLabel) { + // Emit a DW_LNE_end_sequence. When EndLabel is provided, check if + // the address delta can be fully resolved for the end sequence. Otherwise, + // use the section end label to compute the address delta and use INT64_MAX // as the line delta which is the signal that this is actually a // DW_LNE_end_sequence. - MCSymbol *SectionEnd = endSection(Section); + auto *EndSequence = endSection(Section); + if (EndLabel && LastLabel) { + auto &Assembler = getAssembler(); + auto &Writer = Assembler.getWriter(); + if (Writer.isSymbolRefDifferenceFullyResolvedImpl( + Assembler, *LastLabel, *EndLabel, /*InSet*/ false)) + EndSequence = EndLabel; + } // Switch back the dwarf line section, in case endSection had to switch the // section. @@ -516,7 +525,7 @@ SwitchSection(Ctx.getObjectFileInfo()->getDwarfLineSection()); const MCAsmInfo *AsmInfo = Ctx.getAsmInfo(); - emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd, + emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, EndSequence, 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,36 @@ +; RUN: %llc_dwarf %s -filetype=obj -o - | llvm-dwarfdump -all - | FileCheck %s + +; CHECK: DW_AT_name ("") +; CHECK: DW_AT_high_pc ([[EndSeq:.*]]) + +; Expect the line table ends with the highest address for each CU. +; CHECK: [[EndSeq]] [[T:.*]] end_sequence + +target triple = "x86_64-apple-macosx11.0.0" + +define void @f1() !dbg !10 { + ret void, !dbg !13 +} + +define void @f2() { + ret void +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "LLVM", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None, sysroot: "/") +!1 = !DIFile(filename: "", directory: "/") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{i32 7, !"PIC Level", i32 2} +!7 = !{i32 7, !"uwtable", i32 1} +!8 = !{i32 7, !"frame-pointer", i32 2} +!9 = !{!"clang"} +!10 = distinct !DISubprogram(name: "f1", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!11 = !DISubroutineType(types: !12) +!12 = !{null} +!13 = !DILocation(line: 1, column: 13, scope: !10)