[llvm] [DebugInfo][DWARF] Emit Per-Function Line Table Offsets and End Sequences (PR #110192)

via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 12 18:03:37 PST 2024


https://github.com/alx32 updated https://github.com/llvm/llvm-project/pull/110192

>From bd3f96d30f1b2137c658a19ae1094afd6e85836c Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Thu, 26 Sep 2024 17:30:48 -0700
Subject: [PATCH 1/4] [DebugInfo][DWARF] Emit Per-Function Line Table Offsets
 and End Sequences

---
 llvm/include/llvm/BinaryFormat/Dwarf.def      |  1 +
 llvm/include/llvm/MC/MCDwarf.h                |  5 +-
 llvm/include/llvm/MC/MCStreamer.h             | 27 ++++++
 .../CodeGen/AsmPrinter/DwarfCompileUnit.cpp   |  8 ++
 llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp    | 30 ++++++-
 llvm/lib/MC/MCDwarf.cpp                       | 22 ++++-
 .../X86/DW_AT_LLVM_stmt_seq_sec_offset.ll     | 82 +++++++++++++++++++
 7 files changed, 169 insertions(+), 6 deletions(-)
 create mode 100644 llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll

diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def
index ca86474365355d..4aa6defdc3a41f 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -618,6 +618,7 @@ HANDLE_DW_AT(0x3e08, LLVM_ptrauth_isa_pointer, 0, LLVM)
 HANDLE_DW_AT(0x3e09, LLVM_ptrauth_authenticates_null_values, 0, LLVM)
 HANDLE_DW_AT(0x3e0a, LLVM_ptrauth_authentication_mode, 0, LLVM)
 HANDLE_DW_AT(0x3e0b, LLVM_num_extra_inhabitants, 0, LLVM)
+HANDLE_DW_AT(0x3e0c, LLVM_stmt_sequence, 0, LLVM)
 
 // Apple extensions.
 
diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h
index 1392336968e74a..3a39ff33a24782 100644
--- a/llvm/include/llvm/MC/MCDwarf.h
+++ b/llvm/include/llvm/MC/MCDwarf.h
@@ -123,6 +123,9 @@ class MCDwarfLoc {
   friend class MCContext;
   friend class MCDwarfLineEntry;
 
+  // DwarfDebug::endFunctionImpl needs to construct MCDwarfLoc(IsEndOfFunction)
+  friend class DwarfDebug;
+
   MCDwarfLoc(unsigned fileNum, unsigned line, unsigned column, unsigned flags,
              unsigned isa, unsigned discriminator)
       : FileNum(fileNum), Line(line), Column(column), Flags(flags), Isa(isa),
@@ -239,7 +242,7 @@ class MCLineSection {
 
   // Add an end entry by cloning the last entry, if exists, for the section
   // the given EndLabel belongs to. The label is replaced by the given EndLabel.
-  void addEndEntry(MCSymbol *EndLabel);
+  void addEndEntry(MCSymbol *EndLabel, bool generatingFuncLineTableOffsets);
 
   using MCDwarfLineEntryCollection = std::vector<MCDwarfLineEntry>;
   using iterator = MCDwarfLineEntryCollection::iterator;
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index df2eb9cf136bc9..5aabb0a61ac3d7 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -251,6 +251,15 @@ class MCStreamer {
   /// discussion for future inclusion.
   bool AllowAutoPadding = false;
 
+  // Flag specifying weather functions will have an offset into the line table
+  // where the line data for that function starts
+  bool GenerateFuncLineTableOffsets = false;
+
+  // Symbol that tracks the stream symbol for first line of the current function
+  // being generated. This symbol can be used to reference where the line
+  // entries for the function start in the generated line table.
+  MCSymbol *CurrentFuncFirstLineStreamSym;
+
 protected:
   MCFragment *CurFrag = nullptr;
 
@@ -313,6 +322,24 @@ class MCStreamer {
   void setAllowAutoPadding(bool v) { AllowAutoPadding = v; }
   bool getAllowAutoPadding() const { return AllowAutoPadding; }
 
+  void setGenerateFuncLineTableOffsets(bool v) {
+    GenerateFuncLineTableOffsets = v;
+  }
+  bool getGenerateFuncLineTableOffsets() const {
+    return GenerateFuncLineTableOffsets;
+  }
+
+  // Use the below functions to track the symbol that points to the current
+  // function's line info in the output stream.
+  void beginFunction() { CurrentFuncFirstLineStreamSym = nullptr; }
+  void emittedLineStreamSym(MCSymbol *StreamSym) {
+    if (!CurrentFuncFirstLineStreamSym)
+      CurrentFuncFirstLineStreamSym = StreamSym;
+  }
+  MCSymbol *getCurrentFuncFirstLineStreamSym() {
+    return CurrentFuncFirstLineStreamSym;
+  }
+
   /// When emitting an object file, create and emit a real label. When emitting
   /// textual assembly, this should do nothing to avoid polluting our output.
   virtual MCSymbol *emitCFILabel();
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index c4ce0f2ebc6b89..5e6fdc8486b6e5 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -526,6 +526,14 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) {
           *DD->getCurrentFunction()))
     addFlag(*SPDie, dwarf::DW_AT_APPLE_omit_frame_ptr);
 
+  if (Asm->OutStreamer->getGenerateFuncLineTableOffsets() &&
+      Asm->OutStreamer->getCurrentFuncFirstLineStreamSym()) {
+    addSectionLabel(
+        *SPDie, dwarf::DW_AT_LLVM_stmt_sequence,
+        Asm->OutStreamer->getCurrentFuncFirstLineStreamSym(),
+        Asm->getObjFileLowering().getDwarfLineSection()->getBeginSymbol());
+  }
+
   // Only include DW_AT_frame_base in full debug info
   if (!includeMinimalInlineScopes()) {
     const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 88ed3f5dc7b4b4..183c4f0a6ec366 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -170,6 +170,12 @@ static cl::opt<DwarfDebug::MinimizeAddrInV5> MinimizeAddrInV5Option(
                           "Stuff")),
     cl::init(DwarfDebug::MinimizeAddrInV5::Default));
 
+static cl::opt<bool> EmitFuncLineTableOffsetsOption(
+    "emit-func-debug-line-table-offsets", cl::Hidden,
+    cl::desc("Include line table offset in function's debug info and emit end "
+             "sequence after each function's line data."),
+    cl::init(false));
+
 static constexpr unsigned ULEB128PadSize = 4;
 
 void DebugLocDwarfExpression::emitOp(uint8_t Op, const char *Comment) {
@@ -441,6 +447,8 @@ DwarfDebug::DwarfDebug(AsmPrinter *A)
   Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion);
   Asm->OutStreamer->getContext().setDwarfFormat(Dwarf64 ? dwarf::DWARF64
                                                         : dwarf::DWARF32);
+  Asm->OutStreamer->setGenerateFuncLineTableOffsets(
+      EmitFuncLineTableOffsetsOption);
 }
 
 // Define out of line so we don't have to include DwarfUnit.h in DwarfDebug.h.
@@ -2222,6 +2230,10 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) {
   if (SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug)
     return;
 
+  // Notify the streamer that we are beginning a function - this will reset the
+  // label pointing to the currently generated function's first line entry
+  Asm->OutStreamer->beginFunction();
+
   DwarfCompileUnit &CU = getOrCreateDwarfCompileUnit(SP->getUnit());
 
   Asm->OutStreamer->getContext().setDwarfCompileUnitID(
@@ -2250,7 +2262,8 @@ void DwarfDebug::terminateLineTable(const DwarfCompileUnit *CU) {
       getDwarfCompileUnitIDForLineTable(*CU));
   // Add the last range label for the given CU.
   LineTable.getMCLineSections().addEndEntry(
-      const_cast<MCSymbol *>(CURanges.back().End));
+      const_cast<MCSymbol *>(CURanges.back().End),
+      EmitFuncLineTableOffsetsOption);
 }
 
 void DwarfDebug::skippedNonDebugFunction() {
@@ -2343,6 +2356,21 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
   // Construct call site entries.
   constructCallSiteEntryDIEs(*SP, TheCU, ScopeDIE, *MF);
 
+  // If we're emitting line table offsets, we also need to emit an end label
+  // after all function's line entries
+  if (EmitFuncLineTableOffsetsOption) {
+    MCSymbol *LineSym = Asm->OutStreamer->getContext().createTempSymbol();
+    Asm->OutStreamer->emitLabel(LineSym);
+    MCDwarfLoc DwarfLoc(
+        1, 1, 0, DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, 0, 0);
+    MCDwarfLineEntry LineEntry(LineSym, DwarfLoc);
+    Asm->OutStreamer->getContext()
+        .getMCDwarfLineTable(
+            Asm->OutStreamer->getContext().getDwarfCompileUnitID())
+        .getMCLineSections()
+        .addLineEntry(LineEntry, Asm->OutStreamer->getCurrentSectionOnly());
+  }
+
   // Clear debug info
   // Ownership of DbgVariables is a bit subtle - ScopeVariables owns all the
   // DbgVariables except those that are also in AbstractVariables (since they
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index e058358fb8ad4b..05ac3f860f962f 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -104,8 +104,17 @@ void MCDwarfLineEntry::make(MCStreamer *MCOS, MCSection *Section) {
   // Get the current .loc info saved in the context.
   const MCDwarfLoc &DwarfLoc = MCOS->getContext().getCurrentDwarfLoc();
 
+  MCSymbol *LineStreamLabel = nullptr;
+  // If functions need offsets into the generated line table, then we need to
+  // create a label referencing where the line was generated in the output
+  // stream
+  if (MCOS->getGenerateFuncLineTableOffsets()) {
+    LineStreamLabel = MCOS->getContext().createTempSymbol();
+    MCOS->emittedLineStreamSym(LineStreamLabel);
+  }
+
   // Create a (local) line entry with the symbol and the current .loc info.
-  MCDwarfLineEntry LineEntry(LineSym, DwarfLoc);
+  MCDwarfLineEntry LineEntry(LineSym, DwarfLoc, LineStreamLabel);
 
   // clear DwarfLocSeen saying the current .loc info is now used.
   MCOS->getContext().clearDwarfLocSeen();
@@ -145,7 +154,8 @@ makeStartPlusIntExpr(MCContext &Ctx, const MCSymbol &Start, int IntVal) {
   return Res;
 }
 
-void MCLineSection::addEndEntry(MCSymbol *EndLabel) {
+void MCLineSection::addEndEntry(MCSymbol *EndLabel,
+                                bool generatingFuncLineTableOffsets) {
   auto *Sec = &EndLabel->getSection();
   // The line table may be empty, which we should skip adding an end entry.
   // There are two cases:
@@ -158,8 +168,12 @@ void MCLineSection::addEndEntry(MCSymbol *EndLabel) {
   if (I != MCLineDivisions.end()) {
     auto &Entries = I->second;
     auto EndEntry = Entries.back();
-    EndEntry.setEndLabel(EndLabel);
-    Entries.push_back(EndEntry);
+    // If generatingFuncLineTableOffsets is set, then we already generated an
+    // end label at the end of the last function, so skip generating another one
+    if (!generatingFuncLineTableOffsets) {
+      EndEntry.setEndLabel(EndLabel);
+      Entries.push_back(EndEntry);
+    }
   }
 }
 
diff --git a/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll b/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll
new file mode 100644
index 00000000000000..ef8b0c817cfb67
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll
@@ -0,0 +1,82 @@
+; RUN: llc -mtriple=i686-w64-mingw32 -o %t -filetype=obj %s
+; RUN: llvm-dwarfdump -v -all %t | FileCheck %s -check-prefix=NO_STMT_SEQ
+
+; RUN: llc -mtriple=i686-w64-mingw32 -o %t -filetype=obj %s -emit-func-debug-line-table-offsets
+; RUN: llvm-dwarfdump -v -all %t | FileCheck %s -check-prefix=STMT_SEQ
+
+; NO_STMT_SEQ-NOT:      DW_AT_LLVM_stmt_sequence
+
+; STMT_SEQ:   [[[ABBREV_CODE:[0-9]+]]] DW_TAG_subprogram
+; STMT_SEQ:  	       DW_AT_LLVM_stmt_sequence    DW_FORM_sec_offset
+; STMT_SEQ:   DW_TAG_subprogram [[[ABBREV_CODE]]]
+; STMT_SEQ:       DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset]	(0x00000028)
+; STMT_SEQ:   DW_AT_name {{.*}}func01
+; STMT_SEQ:   DW_TAG_subprogram [[[ABBREV_CODE]]]
+; STMT_SEQ:       DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset]	(0x00000033)
+; STMT_SEQ:   DW_AT_name {{.*}}main
+
+;; Check that the line table starts at 0x00000028 (first function)
+; STMT_SEQ:            Address            Line   Column File   ISA Discriminator OpIndex Flags
+; STMT_SEQ-NEXT:       ------------------ ------ ------ ------ --- ------------- ------- -------------
+; STMT_SEQ-NEXT:  0x00000028: 00 DW_LNE_set_address (0x00000006)
+
+;; Check that we have an 'end_sequence' just before the next function (0x00000033)
+; STMT_SEQ:            0x0000000000000006      1      0      1   0             0       0  is_stmt end_sequence
+; STMT_SEQ-NEXT: 0x00000033: 00 DW_LNE_set_address (0x00000027)
+
+;; Check that the end of the line table still has an 'end_sequence'
+; STMT_SEQ       0x00000049: 00 DW_LNE_end_sequence
+; STMT_SEQ-NEXT        0x0000000000000027      6      3      1   0             0       0  end_sequence
+
+
+; generated from:
+; clang -g -S -emit-llvm test.c -o test.ll
+; ======= test.c ======
+; int func01() {
+;   return 1;
+; }
+; int main() {
+;   return 0;
+; }
+; =====================
+
+
+; ModuleID = 'test.c'
+source_filename = "test.c"
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+target triple = "arm64-apple-macosx14.0.0"
+
+; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
+define i32 @func01() #0 !dbg !9 {
+  ret i32 1, !dbg !13
+}
+
+; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
+define i32 @main() #0 !dbg !14 {
+  %1 = alloca i32, align 4
+  store i32 0, ptr %1, align 4
+  ret i32 0, !dbg !15
+}
+
+attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 17.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk")
+!1 = !DIFile(filename: "test.c", directory: "/tmp/clang_test")
+!2 = !{i32 7, !"Dwarf Version", i32 4}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"uwtable", i32 1}
+!7 = !{i32 7, !"frame-pointer", i32 1}
+!8 = !{!"Homebrew clang version 17.0.6"}
+!9 = distinct !DISubprogram(name: "func01", scope: !1, file: !1, line: 1, type: !10, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
+!10 = !DISubroutineType(types: !11)
+!11 = !{!12}
+!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!13 = !DILocation(line: 2, column: 3, scope: !9)
+!14 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !10, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !0)
+!15 = !DILocation(line: 6, column: 3, scope: !14)

>From 662dcecd4626e47d5e5d622bc7d37f028ed26252 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Fri, 25 Oct 2024 10:36:19 -0700
Subject: [PATCH 2/4] Fix compatibility with current MCStreamer Line Label
 implementation

---
 llvm/include/llvm/MC/MCDwarf.h                |  5 +---
 llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp    | 18 +-------------
 llvm/lib/MC/MCDwarf.cpp                       | 24 +++++++++----------
 .../X86/DW_AT_LLVM_stmt_seq_sec_offset.ll     | 12 +++++-----
 4 files changed, 20 insertions(+), 39 deletions(-)

diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h
index 3a39ff33a24782..1392336968e74a 100644
--- a/llvm/include/llvm/MC/MCDwarf.h
+++ b/llvm/include/llvm/MC/MCDwarf.h
@@ -123,9 +123,6 @@ class MCDwarfLoc {
   friend class MCContext;
   friend class MCDwarfLineEntry;
 
-  // DwarfDebug::endFunctionImpl needs to construct MCDwarfLoc(IsEndOfFunction)
-  friend class DwarfDebug;
-
   MCDwarfLoc(unsigned fileNum, unsigned line, unsigned column, unsigned flags,
              unsigned isa, unsigned discriminator)
       : FileNum(fileNum), Line(line), Column(column), Flags(flags), Isa(isa),
@@ -242,7 +239,7 @@ class MCLineSection {
 
   // Add an end entry by cloning the last entry, if exists, for the section
   // the given EndLabel belongs to. The label is replaced by the given EndLabel.
-  void addEndEntry(MCSymbol *EndLabel, bool generatingFuncLineTableOffsets);
+  void addEndEntry(MCSymbol *EndLabel);
 
   using MCDwarfLineEntryCollection = std::vector<MCDwarfLineEntry>;
   using iterator = MCDwarfLineEntryCollection::iterator;
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 183c4f0a6ec366..54237309b7ec99 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -2262,8 +2262,7 @@ void DwarfDebug::terminateLineTable(const DwarfCompileUnit *CU) {
       getDwarfCompileUnitIDForLineTable(*CU));
   // Add the last range label for the given CU.
   LineTable.getMCLineSections().addEndEntry(
-      const_cast<MCSymbol *>(CURanges.back().End),
-      EmitFuncLineTableOffsetsOption);
+      const_cast<MCSymbol *>(CURanges.back().End));
 }
 
 void DwarfDebug::skippedNonDebugFunction() {
@@ -2356,21 +2355,6 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
   // Construct call site entries.
   constructCallSiteEntryDIEs(*SP, TheCU, ScopeDIE, *MF);
 
-  // If we're emitting line table offsets, we also need to emit an end label
-  // after all function's line entries
-  if (EmitFuncLineTableOffsetsOption) {
-    MCSymbol *LineSym = Asm->OutStreamer->getContext().createTempSymbol();
-    Asm->OutStreamer->emitLabel(LineSym);
-    MCDwarfLoc DwarfLoc(
-        1, 1, 0, DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, 0, 0);
-    MCDwarfLineEntry LineEntry(LineSym, DwarfLoc);
-    Asm->OutStreamer->getContext()
-        .getMCDwarfLineTable(
-            Asm->OutStreamer->getContext().getDwarfCompileUnitID())
-        .getMCLineSections()
-        .addLineEntry(LineEntry, Asm->OutStreamer->getCurrentSectionOnly());
-  }
-
   // Clear debug info
   // Ownership of DbgVariables is a bit subtle - ScopeVariables owns all the
   // DbgVariables except those that are also in AbstractVariables (since they
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index 05ac3f860f962f..0b078f7bb0c523 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -104,17 +104,22 @@ void MCDwarfLineEntry::make(MCStreamer *MCOS, MCSection *Section) {
   // Get the current .loc info saved in the context.
   const MCDwarfLoc &DwarfLoc = MCOS->getContext().getCurrentDwarfLoc();
 
-  MCSymbol *LineStreamLabel = nullptr;
   // If functions need offsets into the generated line table, then we need to
   // create a label referencing where the line was generated in the output
   // stream
-  if (MCOS->getGenerateFuncLineTableOffsets()) {
-    LineStreamLabel = MCOS->getContext().createTempSymbol();
+  if (MCOS->getGenerateFuncLineTableOffsets() &&
+      !MCOS->getCurrentFuncFirstLineStreamSym()) {
+    MCSymbol *LineStreamLabel = MCOS->getContext().createTempSymbol();
     MCOS->emittedLineStreamSym(LineStreamLabel);
+    MCDwarfLineEntry LabelLineEntry(LineSym, DwarfLoc, LineStreamLabel);
+    MCOS->getContext()
+        .getMCDwarfLineTable(MCOS->getContext().getDwarfCompileUnitID())
+        .getMCLineSections()
+        .addLineEntry(LabelLineEntry, Section);
   }
 
   // Create a (local) line entry with the symbol and the current .loc info.
-  MCDwarfLineEntry LineEntry(LineSym, DwarfLoc, LineStreamLabel);
+  MCDwarfLineEntry LineEntry(LineSym, DwarfLoc);
 
   // clear DwarfLocSeen saying the current .loc info is now used.
   MCOS->getContext().clearDwarfLocSeen();
@@ -154,8 +159,7 @@ makeStartPlusIntExpr(MCContext &Ctx, const MCSymbol &Start, int IntVal) {
   return Res;
 }
 
-void MCLineSection::addEndEntry(MCSymbol *EndLabel,
-                                bool generatingFuncLineTableOffsets) {
+void MCLineSection::addEndEntry(MCSymbol *EndLabel) {
   auto *Sec = &EndLabel->getSection();
   // The line table may be empty, which we should skip adding an end entry.
   // There are two cases:
@@ -168,12 +172,8 @@ void MCLineSection::addEndEntry(MCSymbol *EndLabel,
   if (I != MCLineDivisions.end()) {
     auto &Entries = I->second;
     auto EndEntry = Entries.back();
-    // If generatingFuncLineTableOffsets is set, then we already generated an
-    // end label at the end of the last function, so skip generating another one
-    if (!generatingFuncLineTableOffsets) {
-      EndEntry.setEndLabel(EndLabel);
-      Entries.push_back(EndEntry);
-    }
+    EndEntry.setEndLabel(EndLabel);
+    Entries.push_back(EndEntry);
   }
 }
 
diff --git a/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll b/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll
index ef8b0c817cfb67..d3bed46ab86be0 100644
--- a/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll
+++ b/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll
@@ -12,20 +12,20 @@
 ; STMT_SEQ:       DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset]	(0x00000028)
 ; STMT_SEQ:   DW_AT_name {{.*}}func01
 ; STMT_SEQ:   DW_TAG_subprogram [[[ABBREV_CODE]]]
-; STMT_SEQ:       DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset]	(0x00000033)
+; STMT_SEQ:       DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset]	(0x00000036)
 ; STMT_SEQ:   DW_AT_name {{.*}}main
 
 ;; Check that the line table starts at 0x00000028 (first function)
 ; STMT_SEQ:            Address            Line   Column File   ISA Discriminator OpIndex Flags
 ; STMT_SEQ-NEXT:       ------------------ ------ ------ ------ --- ------------- ------- -------------
-; STMT_SEQ-NEXT:  0x00000028: 00 DW_LNE_set_address (0x00000006)
+; STMT_SEQ-NEXT:  0x00000028: 05 DW_LNS_set_column (3)
 
-;; Check that we have an 'end_sequence' just before the next function (0x00000033)
-; STMT_SEQ:            0x0000000000000006      1      0      1   0             0       0  is_stmt end_sequence
-; STMT_SEQ-NEXT: 0x00000033: 00 DW_LNE_set_address (0x00000027)
+;; Check that we have an 'end_sequence' just before the next function (0x00000036)
+; STMT_SEQ:            0x0000000000000000      2      3      1   0             0       0  is_stmt end_sequence
+; STMT_SEQ-NEXT: 0x00000036: 00 DW_LNE_set_address (0x00000010)
 
 ;; Check that the end of the line table still has an 'end_sequence'
-; STMT_SEQ       0x00000049: 00 DW_LNE_end_sequence
+; STMT_SEQ       0x00000047: 00 DW_LNE_end_sequence
 ; STMT_SEQ-NEXT        0x0000000000000027      6      3      1   0             0       0  end_sequence
 
 

>From ab07e40dd701e874ba6bb7bfb5a719e5c68ffa9e Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Tue, 5 Nov 2024 14:31:53 -0800
Subject: [PATCH 3/4] More comprehensive test

---
 .../X86/DW_AT_LLVM_stmt_seq_sec_offset.ll     | 163 +++++++++++-------
 1 file changed, 102 insertions(+), 61 deletions(-)

diff --git a/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll b/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll
index d3bed46ab86be0..58f6495924b90c 100644
--- a/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll
+++ b/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll
@@ -1,82 +1,123 @@
-; RUN: llc -mtriple=i686-w64-mingw32 -o %t -filetype=obj %s
-; RUN: llvm-dwarfdump -v -all %t | FileCheck %s -check-prefix=NO_STMT_SEQ
+; RUN: llc -O3 -mtriple=i686-w64-mingw32 -o %t_no -filetype=obj %s
+; RUN: llvm-dwarfdump -v -all %t_no | FileCheck %s -check-prefix=NO_STMT_SEQ
 
-; RUN: llc -mtriple=i686-w64-mingw32 -o %t -filetype=obj %s -emit-func-debug-line-table-offsets
-; RUN: llvm-dwarfdump -v -all %t | FileCheck %s -check-prefix=STMT_SEQ
+; RUN: llc -O3 -mtriple=i686-w64-mingw32 -o %t_yes -filetype=obj %s -emit-func-debug-line-table-offsets
+; RUN: llvm-dwarfdump -v -all %t_yes | FileCheck %s -check-prefix=STMT_SEQ
 
 ; NO_STMT_SEQ-NOT:      DW_AT_LLVM_stmt_sequence
 
-; STMT_SEQ:   [[[ABBREV_CODE:[0-9]+]]] DW_TAG_subprogram
+; STMT_SEQ:   [[[ABBREV_CODE1:[0-9]+]]] DW_TAG_subprogram
 ; STMT_SEQ:  	       DW_AT_LLVM_stmt_sequence    DW_FORM_sec_offset
-; STMT_SEQ:   DW_TAG_subprogram [[[ABBREV_CODE]]]
-; STMT_SEQ:       DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset]	(0x00000028)
+; STMT_SEQ:   [[[ABBREV_CODE2:[0-9]+]]] DW_TAG_subprogram
+; STMT_SEQ:  	       DW_AT_LLVM_stmt_sequence    DW_FORM_sec_offset
+; STMT_SEQ:   DW_TAG_subprogram [[[ABBREV_CODE1]]]
+; STMT_SEQ:       DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset]	(0x00000043)
 ; STMT_SEQ:   DW_AT_name {{.*}}func01
-; STMT_SEQ:   DW_TAG_subprogram [[[ABBREV_CODE]]]
-; STMT_SEQ:       DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset]	(0x00000036)
+; STMT_SEQ:   DW_TAG_subprogram [[[ABBREV_CODE2]]]
+; STMT_SEQ:       DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset]	(0x00000056)
 ; STMT_SEQ:   DW_AT_name {{.*}}main
 
-;; Check that the line table starts at 0x00000028 (first function)
-; STMT_SEQ:            Address            Line   Column File   ISA Discriminator OpIndex Flags
-; STMT_SEQ-NEXT:       ------------------ ------ ------ ------ --- ------------- ------- -------------
-; STMT_SEQ-NEXT:  0x00000028: 05 DW_LNS_set_column (3)
-
-;; Check that we have an 'end_sequence' just before the next function (0x00000036)
-; STMT_SEQ:            0x0000000000000000      2      3      1   0             0       0  is_stmt end_sequence
-; STMT_SEQ-NEXT: 0x00000036: 00 DW_LNE_set_address (0x00000010)
-
-;; Check that the end of the line table still has an 'end_sequence'
-; STMT_SEQ       0x00000047: 00 DW_LNE_end_sequence
-; STMT_SEQ-NEXT        0x0000000000000027      6      3      1   0             0       0  end_sequence
-
+;; Check the entire line sequence to see that it's correct
+; STMT_SEQ:                   Address            Line   Column File   ISA Discriminator OpIndex Flags
+; STMT_SEQ-NEXT:              ------------------ ------ ------ ------ --- ------------- ------- -------------
+; STMT_SEQ-NEXT:  0x00000043: 04 DW_LNS_set_file (0)
+; STMT_SEQ-NEXT:  0x00000045: 05 DW_LNS_set_column (9)
+; STMT_SEQ-NEXT:  0x00000047: 0a DW_LNS_set_prologue_end
+; STMT_SEQ-NEXT:  0x00000048: 00 DW_LNE_set_address (0x00000000)
+; STMT_SEQ-NEXT:  0x0000004f: 16 address += 0,  line += 4,  op-index += 0
+; STMT_SEQ-NEXT:              0x0000000000000000      5      9      0   0             0       0  is_stmt prologue_end
+; STMT_SEQ-NEXT:  0x00000050: 05 DW_LNS_set_column (3)
+; STMT_SEQ-NEXT:  0x00000052: 67 address += 6,  line += 1,  op-index += 0
+; STMT_SEQ-NEXT:              0x0000000000000006      6      3      0   0             0       0  is_stmt
+; STMT_SEQ-NEXT:  0x00000053: 00 DW_LNE_end_sequence
+; STMT_SEQ-NEXT:              0x0000000000000006      6      3      0   0             0       0  is_stmt end_sequence
+; STMT_SEQ-NEXT:  0x00000056: 04 DW_LNS_set_file (0)
+; STMT_SEQ-NEXT:  0x00000058: 00 DW_LNE_set_address (0x00000008)
+; STMT_SEQ-NEXT:  0x0000005f: 03 DW_LNS_advance_line (10)
+; STMT_SEQ-NEXT:  0x00000061: 01 DW_LNS_copy
+; STMT_SEQ-NEXT:              0x0000000000000008     10      0      0   0             0       0  is_stmt
+; STMT_SEQ-NEXT:  0x00000062: 05 DW_LNS_set_column (10)
+; STMT_SEQ-NEXT:  0x00000064: 0a DW_LNS_set_prologue_end
+; STMT_SEQ-NEXT:  0x00000065: 83 address += 8,  line += 1,  op-index += 0
+; STMT_SEQ-NEXT:              0x0000000000000010     11     10      0   0             0       0  is_stmt prologue_end
+; STMT_SEQ-NEXT:  0x00000066: 05 DW_LNS_set_column (3)
+; STMT_SEQ-NEXT:  0x00000068: 9f address += 10,  line += 1,  op-index += 0
+; STMT_SEQ-NEXT:              0x000000000000001a     12      3      0   0             0       0  is_stmt
+; STMT_SEQ-NEXT:  0x00000069: 02 DW_LNS_advance_pc (addr += 5, op-index += 0)
+; STMT_SEQ-NEXT:  0x0000006b: 00 DW_LNE_end_sequence
+; STMT_SEQ-NEXT:              0x000000000000001f     12      3      0   0             0       0  is_stmt end_sequence
 
 ; generated from:
-; clang -g -S -emit-llvm test.c -o test.ll
+; clang -Oz -g -S -emit-llvm test.c -o test.ll
 ; ======= test.c ======
-; int func01() {
+; volatile int g_var1 = 1;
+; #define ATTR __attribute__((noinline))
+; ATTR int func01()  {
+;   g_var1++;
+;   func01();
 ;   return 1;
 ; }
-; int main() {
-;   return 0;
+; ATTR int main() {
+;   g_var1 = 100;
+;   func01();
+;   g_var1--;
+;   return g_var1;
 ; }
 ; =====================
 
 
 ; ModuleID = 'test.c'
 source_filename = "test.c"
-target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
-target triple = "arm64-apple-macosx14.0.0"
-
-; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
-define i32 @func01() #0 !dbg !9 {
-  ret i32 1, !dbg !13
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+ at g_var1 = dso_local global i32 1, align 4, !dbg !0
+; Function Attrs: minsize nofree noinline norecurse noreturn nounwind optsize memory(readwrite, argmem: none) uwtable
+define dso_local noundef i32 @func01() local_unnamed_addr #0 !dbg !14 {
+entry:
+  br label %tailrecurse
+tailrecurse:                                      ; preds = %tailrecurse, %entry
+  %0 = load volatile i32, ptr @g_var1, align 4, !dbg !17, !tbaa !18
+  %inc = add nsw i32 %0, 1, !dbg !17
+  store volatile i32 %inc, ptr @g_var1, align 4, !dbg !17, !tbaa !18
+  br label %tailrecurse, !dbg !22
 }
-
-; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
-define i32 @main() #0 !dbg !14 {
-  %1 = alloca i32, align 4
-  store i32 0, ptr %1, align 4
-  ret i32 0, !dbg !15
+; Function Attrs: minsize nofree noinline norecurse noreturn nounwind optsize uwtable
+define dso_local noundef i32 @main() local_unnamed_addr #1 !dbg !23 {
+entry:
+  store volatile i32 100, ptr @g_var1, align 4, !dbg !24, !tbaa !18
+  %call = tail call i32 @func01() #2, !dbg !25
+  unreachable, !dbg !26
 }
-
-attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" }
-
-!llvm.dbg.cu = !{!0}
-!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
-!llvm.ident = !{!8}
-
-!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 17.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk")
-!1 = !DIFile(filename: "test.c", directory: "/tmp/clang_test")
-!2 = !{i32 7, !"Dwarf Version", i32 4}
-!3 = !{i32 2, !"Debug Info Version", i32 3}
-!4 = !{i32 1, !"wchar_size", i32 4}
-!5 = !{i32 8, !"PIC Level", i32 2}
-!6 = !{i32 7, !"uwtable", i32 1}
-!7 = !{i32 7, !"frame-pointer", i32 1}
-!8 = !{!"Homebrew clang version 17.0.6"}
-!9 = distinct !DISubprogram(name: "func01", scope: !1, file: !1, line: 1, type: !10, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
-!10 = !DISubroutineType(types: !11)
-!11 = !{!12}
-!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!13 = !DILocation(line: 2, column: 3, scope: !9)
-!14 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !10, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !0)
-!15 = !DILocation(line: 6, column: 3, scope: !14)
+attributes #0 = { minsize nofree noinline norecurse noreturn nounwind optsize memory(readwrite, argmem: none) uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { minsize nofree noinline norecurse noreturn nounwind optsize uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #2 = { minsize optsize }
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!7, !8, !9, !10, !11, !12}
+!llvm.ident = !{!13}
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "g_var1", scope: !2, file: !3, line: 1, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang version 20.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "test.c", directory: "/tmp/tst", checksumkind: CSK_MD5, checksum: "eee003eb3c4fd0a1ff078d3148679e06")
+!4 = !{!0}
+!5 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !6)
+!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!7 = !{i32 7, !"Dwarf Version", i32 5}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{i32 8, !"PIC Level", i32 2}
+!11 = !{i32 7, !"PIE Level", i32 2}
+!12 = !{i32 7, !"uwtable", i32 2}
+!13 = !{!"clang version 20.0.0"}
+!14 = distinct !DISubprogram(name: "func01", scope: !3, file: !3, line: 4, type: !15, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!15 = !DISubroutineType(types: !16)
+!16 = !{!6}
+!17 = !DILocation(line: 5, column: 9, scope: !14)
+!18 = !{!19, !19, i64 0}
+!19 = !{!"int", !20, i64 0}
+!20 = !{!"omnipotent char", !21, i64 0}
+!21 = !{!"Simple C/C++ TBAA"}
+!22 = !DILocation(line: 6, column: 3, scope: !14)
+!23 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 10, type: !15, scopeLine: 10, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!24 = !DILocation(line: 11, column: 10, scope: !23)
+!25 = !DILocation(line: 12, column: 3, scope: !23)
+!26 = !DILocation(line: 13, column: 9, scope: !23)

>From 9d8003d9174426549d8732f64b5c77cd1e51fbe6 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Tue, 12 Nov 2024 18:03:22 -0800
Subject: [PATCH 4/4] Reimplement with better encapsulation

---
 llvm/include/llvm/MC/MCStreamer.h             | 27 +------------------
 .../CodeGen/AsmPrinter/DwarfCompileUnit.cpp   | 24 ++++++++++++-----
 .../lib/CodeGen/AsmPrinter/DwarfCompileUnit.h | 14 +++++-----
 llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp    | 22 ++++++---------
 llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h      |  3 +++
 llvm/lib/MC/MCDwarf.cpp                       | 14 ----------
 llvm/lib/MC/MCStreamer.cpp                    | 14 ++++++++++
 7 files changed, 51 insertions(+), 67 deletions(-)

diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index 5aabb0a61ac3d7..ee23751527d650 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -251,15 +251,6 @@ class MCStreamer {
   /// discussion for future inclusion.
   bool AllowAutoPadding = false;
 
-  // Flag specifying weather functions will have an offset into the line table
-  // where the line data for that function starts
-  bool GenerateFuncLineTableOffsets = false;
-
-  // Symbol that tracks the stream symbol for first line of the current function
-  // being generated. This symbol can be used to reference where the line
-  // entries for the function start in the generated line table.
-  MCSymbol *CurrentFuncFirstLineStreamSym;
-
 protected:
   MCFragment *CurFrag = nullptr;
 
@@ -322,23 +313,7 @@ class MCStreamer {
   void setAllowAutoPadding(bool v) { AllowAutoPadding = v; }
   bool getAllowAutoPadding() const { return AllowAutoPadding; }
 
-  void setGenerateFuncLineTableOffsets(bool v) {
-    GenerateFuncLineTableOffsets = v;
-  }
-  bool getGenerateFuncLineTableOffsets() const {
-    return GenerateFuncLineTableOffsets;
-  }
-
-  // Use the below functions to track the symbol that points to the current
-  // function's line info in the output stream.
-  void beginFunction() { CurrentFuncFirstLineStreamSym = nullptr; }
-  void emittedLineStreamSym(MCSymbol *StreamSym) {
-    if (!CurrentFuncFirstLineStreamSym)
-      CurrentFuncFirstLineStreamSym = StreamSym;
-  }
-  MCSymbol *getCurrentFuncFirstLineStreamSym() {
-    return CurrentFuncFirstLineStreamSym;
-  }
+  MCSymbol *emitLineTableLabel();
 
   /// When emitting an object file, create and emit a real label. When emitting
   /// textual assembly, this should do nothing to avoid polluting our output.
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index 5e6fdc8486b6e5..2f96366b78e97d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -49,6 +49,12 @@ cl::opt<cl::boolOrDefault> AddLinkageNamesToDeclCallOrigins(
              "referenced by DW_AT_call_origin attributes. Enabled by default "
              "for -gsce debugger tuning."));
 
+static cl::opt<bool> EmitFuncLineTableOffsetsOption(
+    "emit-func-debug-line-table-offsets", cl::Hidden,
+    cl::desc("Include line table offset in function's debug info and emit end "
+             "sequence after each function's line data."),
+    cl::init(false));
+
 static bool AddLinkageNamesToDeclCallOriginsForTuning(const DwarfDebug *DD) {
   bool EnabledByDefault = DD->tuneForSCE();
   if (EnabledByDefault)
@@ -511,7 +517,8 @@ void DwarfCompileUnit::addWasmRelocBaseGlobal(DIELoc *Loc, StringRef GlobalName,
 // Find DIE for the given subprogram and attach appropriate DW_AT_low_pc
 // and DW_AT_high_pc attributes. If there are global variables in this
 // scope then create and insert DIEs for these variables.
-DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) {
+DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP,
+                                                MCSymbol *LineTableSym) {
   DIE *SPDie = getOrCreateSubprogramDIE(SP, includeMinimalInlineScopes());
   SmallVector<RangeSpan, 2> BB_List;
   // If basic block sections are on, ranges for each basic block section has
@@ -526,11 +533,9 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) {
           *DD->getCurrentFunction()))
     addFlag(*SPDie, dwarf::DW_AT_APPLE_omit_frame_ptr);
 
-  if (Asm->OutStreamer->getGenerateFuncLineTableOffsets() &&
-      Asm->OutStreamer->getCurrentFuncFirstLineStreamSym()) {
+  if (emitFuncLineTableOffsets() && LineTableSym) {
     addSectionLabel(
-        *SPDie, dwarf::DW_AT_LLVM_stmt_sequence,
-        Asm->OutStreamer->getCurrentFuncFirstLineStreamSym(),
+        *SPDie, dwarf::DW_AT_LLVM_stmt_sequence, LineTableSym,
         Asm->getObjFileLowering().getDwarfLineSection()->getBeginSymbol());
   }
 
@@ -1104,8 +1109,9 @@ sortLocalVars(SmallVectorImpl<DbgVariable *> &Input) {
 }
 
 DIE &DwarfCompileUnit::constructSubprogramScopeDIE(const DISubprogram *Sub,
-                                                   LexicalScope *Scope) {
-  DIE &ScopeDIE = updateSubprogramScopeDIE(Sub);
+                                                   LexicalScope *Scope,
+                                                   MCSymbol *LineTableSym) {
+  DIE &ScopeDIE = updateSubprogramScopeDIE(Sub, LineTableSym);
 
   if (Scope) {
     assert(!Scope->getInlinedAt());
@@ -1699,6 +1705,10 @@ bool DwarfCompileUnit::includeMinimalInlineScopes() const {
          (DD->useSplitDwarf() && !Skeleton);
 }
 
+bool DwarfCompileUnit::emitFuncLineTableOffsets() const {
+  return EmitFuncLineTableOffsetsOption;
+}
+
 void DwarfCompileUnit::addAddrTableBase() {
   const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
   MCSymbol *Label = DD->getAddressPool().getLabel();
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
index 76584b3eb8e78d..104039db03c7ca 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
@@ -152,6 +152,8 @@ class DwarfCompileUnit final : public DwarfUnit {
 
   bool includeMinimalInlineScopes() const;
 
+  bool emitFuncLineTableOffsets() const;
+
   void initStmtList();
 
   /// Apply the DW_AT_stmt_list from this compile unit to the specified DIE.
@@ -207,10 +209,10 @@ class DwarfCompileUnit final : public DwarfUnit {
   void attachLowHighPC(DIE &D, const MCSymbol *Begin, const MCSymbol *End);
 
   /// Find DIE for the given subprogram and attach appropriate
-  /// DW_AT_low_pc and DW_AT_high_pc attributes. If there are global
-  /// variables in this scope then create and insert DIEs for these
-  /// variables.
-  DIE &updateSubprogramScopeDIE(const DISubprogram *SP);
+  /// DW_AT_low_pc, DW_AT_high_pc and DW_AT_LLVM_stmt_sequence attributes.
+  /// If there are global variables in this scope then create and insert DIEs
+  /// for these variables.
+  DIE &updateSubprogramScopeDIE(const DISubprogram *SP, MCSymbol *LineTableSym);
 
   void constructScopeDIE(LexicalScope *Scope, DIE &ParentScopeDIE);
 
@@ -254,8 +256,8 @@ class DwarfCompileUnit final : public DwarfUnit {
   DIE *getOrCreateContextDIE(const DIScope *Ty) override;
 
   /// Construct a DIE for this subprogram scope.
-  DIE &constructSubprogramScopeDIE(const DISubprogram *Sub,
-                                   LexicalScope *Scope);
+  DIE &constructSubprogramScopeDIE(const DISubprogram *Sub, LexicalScope *Scope,
+                                   MCSymbol *LineTableSym);
 
   DIE *createAndAddScopeChildren(LexicalScope *Scope, DIE &ScopeDIE);
 
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 54237309b7ec99..b347fe09d48ee7 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -170,12 +170,6 @@ static cl::opt<DwarfDebug::MinimizeAddrInV5> MinimizeAddrInV5Option(
                           "Stuff")),
     cl::init(DwarfDebug::MinimizeAddrInV5::Default));
 
-static cl::opt<bool> EmitFuncLineTableOffsetsOption(
-    "emit-func-debug-line-table-offsets", cl::Hidden,
-    cl::desc("Include line table offset in function's debug info and emit end "
-             "sequence after each function's line data."),
-    cl::init(false));
-
 static constexpr unsigned ULEB128PadSize = 4;
 
 void DebugLocDwarfExpression::emitOp(uint8_t Op, const char *Comment) {
@@ -447,8 +441,6 @@ DwarfDebug::DwarfDebug(AsmPrinter *A)
   Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion);
   Asm->OutStreamer->getContext().setDwarfFormat(Dwarf64 ? dwarf::DWARF64
                                                         : dwarf::DWARF32);
-  Asm->OutStreamer->setGenerateFuncLineTableOffsets(
-      EmitFuncLineTableOffsetsOption);
 }
 
 // Define out of line so we don't have to include DwarfUnit.h in DwarfDebug.h.
@@ -2230,11 +2222,10 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) {
   if (SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug)
     return;
 
-  // Notify the streamer that we are beginning a function - this will reset the
-  // label pointing to the currently generated function's first line entry
-  Asm->OutStreamer->beginFunction();
-
   DwarfCompileUnit &CU = getOrCreateDwarfCompileUnit(SP->getUnit());
+  FunctionLineTableLabel = CU.emitFuncLineTableOffsets()
+                               ? Asm->OutStreamer->emitLineTableLabel()
+                               : nullptr;
 
   Asm->OutStreamer->getContext().setDwarfCompileUnitID(
       getDwarfCompileUnitIDForLineTable(CU));
@@ -2346,11 +2337,14 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
   }
 
   ProcessedSPNodes.insert(SP);
-  DIE &ScopeDIE = TheCU.constructSubprogramScopeDIE(SP, FnScope);
+  DIE &ScopeDIE =
+      TheCU.constructSubprogramScopeDIE(SP, FnScope, FunctionLineTableLabel);
   if (auto *SkelCU = TheCU.getSkeleton())
     if (!LScopes.getAbstractScopesList().empty() &&
         TheCU.getCUNode()->getSplitDebugInlining())
-      SkelCU->constructSubprogramScopeDIE(SP, FnScope);
+      SkelCU->constructSubprogramScopeDIE(SP, FnScope, FunctionLineTableLabel);
+
+  FunctionLineTableLabel = nullptr;
 
   // Construct call site entries.
   constructCallSiteEntryDIEs(*SP, TheCU, ScopeDIE, *MF);
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 6ed03124a2626f..61d7049ffb0a11 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -408,6 +408,9 @@ class DwarfDebug : public DebugHandlerBase {
       std::pair<std::unique_ptr<DwarfTypeUnit>, const DICompositeType *>, 1>
       TypeUnitsUnderConstruction;
 
+  /// Symbol pointing to the current function's DWARF line table entries.
+  MCSymbol *FunctionLineTableLabel;
+
   /// Used to set a uniqe ID for a Type Unit.
   /// This counter represents number of DwarfTypeUnits created, not necessarily
   /// number of type units that will be emitted.
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index 0b078f7bb0c523..e058358fb8ad4b 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -104,20 +104,6 @@ void MCDwarfLineEntry::make(MCStreamer *MCOS, MCSection *Section) {
   // Get the current .loc info saved in the context.
   const MCDwarfLoc &DwarfLoc = MCOS->getContext().getCurrentDwarfLoc();
 
-  // If functions need offsets into the generated line table, then we need to
-  // create a label referencing where the line was generated in the output
-  // stream
-  if (MCOS->getGenerateFuncLineTableOffsets() &&
-      !MCOS->getCurrentFuncFirstLineStreamSym()) {
-    MCSymbol *LineStreamLabel = MCOS->getContext().createTempSymbol();
-    MCOS->emittedLineStreamSym(LineStreamLabel);
-    MCDwarfLineEntry LabelLineEntry(LineSym, DwarfLoc, LineStreamLabel);
-    MCOS->getContext()
-        .getMCDwarfLineTable(MCOS->getContext().getDwarfCompileUnitID())
-        .getMCLineSections()
-        .addLineEntry(LabelLineEntry, Section);
-  }
-
   // Create a (local) line entry with the symbol and the current .loc info.
   MCDwarfLineEntry LineEntry(LineSym, DwarfLoc);
 
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index 5474db1315f141..9c7d5658a7a34f 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -483,6 +483,20 @@ void MCStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) {
   Frame.End = (MCSymbol *)1;
 }
 
+MCSymbol *MCStreamer::emitLineTableLabel() {
+  // Create a label and insert it into the line table and return this label
+  const MCDwarfLoc &DwarfLoc = getContext().getCurrentDwarfLoc();
+
+  MCSymbol *LineStreamLabel = getContext().createTempSymbol();
+  MCDwarfLineEntry LabelLineEntry(nullptr, DwarfLoc, LineStreamLabel);
+  getContext()
+      .getMCDwarfLineTable(getContext().getDwarfCompileUnitID())
+      .getMCLineSections()
+      .addLineEntry(LabelLineEntry, getCurrentSectionOnly() /*Section*/);
+
+  return LineStreamLabel;
+}
+
 MCSymbol *MCStreamer::emitCFILabel() {
   // Return a dummy non-null value so that label fields appear filled in when
   // generating textual assembly.



More information about the llvm-commits mailing list