[llvm] 77cfcd7 - DebugInfo: Use loclistx for DWARFv5 location lists to reduce the number of relocations

David Blaikie via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 15 18:51:21 PST 2019


Author: David Blaikie
Date: 2019-11-15T18:51:13-08:00
New Revision: 77cfcd75092b57693d40123a013e59295634a945

URL: https://github.com/llvm/llvm-project/commit/77cfcd75092b57693d40123a013e59295634a945
DIFF: https://github.com/llvm/llvm-project/commit/77cfcd75092b57693d40123a013e59295634a945.diff

LOG: DebugInfo: Use loclistx for DWARFv5 location lists to reduce the number of relocations

This only implements the non-dwo part, but loclistx is necessary to use
location lists in DWARFv5, so it's a precursor to that work - and
generally reduces relocations (only using one reloc, then
indexes/relative offsets for all location list references) in non-split
DWARF.

Added: 
    

Modified: 
    llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
    llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
    llvm/lib/CodeGen/AsmPrinter/DIE.cpp
    llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
    llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
    llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
    llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
    llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
    llvm/test/CodeGen/X86/debug-loclists.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
index f7f08b4a499d..52a0247b3e42 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
@@ -188,6 +188,7 @@ class DWARFDie {
   ///
   /// \returns anm optional absolute section offset value for the attribute.
   Optional<uint64_t> getRangesBaseAttribute() const;
+  Optional<uint64_t> getLocBaseAttribute() const;
 
   /// Get the DW_AT_high_pc attribute value as an address.
   ///

diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
index b518900811ca..d0a8533d1e34 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -200,6 +200,8 @@ class DWARFUnit {
   const DWARFDebugAbbrev *Abbrev;
   const DWARFSection *RangeSection;
   uint64_t RangeSectionBase;
+  const DWARFSection *LocSection;
+  uint64_t LocSectionBase;
 
   /// Location table of this unit.
   std::unique_ptr<DWARFLocationTable> LocTable;
@@ -219,6 +221,7 @@ class DWARFUnit {
 
   /// A table of range lists (DWARF v5 and later).
   Optional<DWARFDebugRnglistTable> RngListTable;
+  Optional<DWARFListTableHeader> LoclistTableHeader;
 
   mutable const DWARFAbbreviationDeclarationSet *Abbrevs;
   llvm::Optional<object::SectionedAddress> BaseAddr;
@@ -305,6 +308,14 @@ class DWARFUnit {
     RangeSection = RS;
     RangeSectionBase = Base;
   }
+  void setLocSection(const DWARFSection *LS, uint64_t Base) {
+    LocSection = LS;
+    LocSectionBase = Base;
+  }
+
+  uint64_t getLocSectionBase() const {
+    return LocSectionBase;
+  }
 
   Optional<object::SectionedAddress>
   getAddrOffsetSectionItem(uint32_t Index) const;
@@ -421,6 +432,11 @@ class DWARFUnit {
     return None;
   }
 
+  Optional<uint64_t> getLoclistOffset(uint32_t Index) {
+    if (LoclistTableHeader)
+      return LoclistTableHeader->getOffsetEntry(Index);
+    return None;
+  }
   Expected<DWARFAddressRangesVector> collectAddressRanges();
 
   /// Returns subprogram DIE with address range encompassing the provided

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DIE.cpp b/llvm/lib/CodeGen/AsmPrinter/DIE.cpp
index f4134da48caa..c4d5b717b25d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DIE.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DIE.cpp
@@ -798,6 +798,8 @@ void DIEBlock::print(raw_ostream &O) const {
 //===----------------------------------------------------------------------===//
 
 unsigned DIELocList::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
+  if (Form == dwarf::DW_FORM_loclistx)
+    return getULEB128Size(Index);
   if (Form == dwarf::DW_FORM_data4)
     return 4;
   if (Form == dwarf::DW_FORM_sec_offset)
@@ -808,6 +810,10 @@ unsigned DIELocList::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
 /// EmitValue - Emit label value.
 ///
 void DIELocList::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const {
+  if (Form == dwarf::DW_FORM_loclistx) {
+    AP->EmitULEB128(Index);
+    return;
+  }
   DwarfDebug *DD = AP->getDwarfDebug();
   MCSymbol *Label = DD->getDebugLocs().getList(Index).Label;
   AP->emitDwarfSymbolReference(Label, /*ForceOffset*/ DD->useSplitDwarf());

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index a61c98ec1c18..9578e01abdd4 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -1220,8 +1220,11 @@ void DwarfCompileUnit::addComplexAddress(const DbgVariable &DV, DIE &Die,
 /// Add a Dwarf loclistptr attribute data and value.
 void DwarfCompileUnit::addLocationList(DIE &Die, dwarf::Attribute Attribute,
                                        unsigned Index) {
-  dwarf::Form Form = DD->getDwarfVersion() >= 4 ? dwarf::DW_FORM_sec_offset
-                                                : dwarf::DW_FORM_data4;
+  dwarf::Form Form = dwarf::DW_FORM_data4;
+  if (DD->getDwarfVersion() == 4)
+    Form =dwarf::DW_FORM_sec_offset;
+  if (DD->getDwarfVersion() >= 5)
+    Form =dwarf::DW_FORM_loclistx;
   Die.addValue(DIEValueAllocator, Attribute, Form, DIELocList(Index));
 }
 

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index c240099910ec..d9b5eb1d6d08 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -2323,9 +2323,12 @@ static MCSymbol *emitLoclistsTableHeader(AsmPrinter *Asm,
   // FIXME: Generate the offsets table and use DW_FORM_loclistx with the
   // DW_AT_loclists_base attribute. Until then set the number of offsets to 0.
   Asm->OutStreamer->AddComment("Offset entry count");
-  Asm->emitInt32(0);
+  Asm->emitInt32(DebugLocs.getLists().size());
   Asm->OutStreamer->EmitLabel(DebugLocs.getSym());
 
+  for (const auto &List : DebugLocs.getLists())
+    Asm->EmitLabelDifference(List.Label, DebugLocs.getSym(), 4);
+
   return TableEnd;
 }
 

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index 49a7f7dc2a5d..7fa72b1bb576 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -96,6 +96,13 @@ static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue,
 
     uint64_t Offset = *FormValue.getAsSectionOffset();
 
+    if (FormValue.getForm() == DW_FORM_loclistx) {
+      FormValue.dump(OS, DumpOpts);
+      if (auto LoclistOffset = U->getLoclistOffset(Offset))
+        Offset = *LoclistOffset + U->getLocSectionBase();
+      else
+        return;
+    }
     U->getLocationTable().dumpLocationList(&Offset, OS, U->getBaseAddress(),
                                            MRI, U, LLDumpOpts, Indent);
     return;
@@ -409,6 +416,10 @@ Optional<uint64_t> DWARFDie::getRangesBaseAttribute() const {
   return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base}));
 }
 
+Optional<uint64_t> DWARFDie::getLocBaseAttribute() const {
+  return toSectionOffset(find(DW_AT_loclists_base));
+}
+
 Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const {
   if (auto FormValue = find(DW_AT_high_pc)) {
     if (auto Address = FormValue->getAsAddress()) {

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
index 26090638b34c..820f530a3e3e 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
@@ -312,6 +312,7 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
     case DW_FORM_udata:
     case DW_FORM_ref_udata:
     case DW_FORM_rnglistx:
+    case DW_FORM_loclistx:
       Value.uval = Data.getULEB128(OffsetPtr);
       break;
     case DW_FORM_string:
@@ -551,6 +552,10 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
     OS << format("indexed (0x%x) rangelist = ", (uint32_t)UValue);
     break;
 
+  case DW_FORM_loclistx:
+    OS << format("indexed (0x%x) loclist = ", (uint32_t)UValue);
+    break;
+
   // Should be formatted to 64-bit for DWARF64.
   case DW_FORM_sec_offset:
     AddrOS << format("0x%08x", (uint32_t)UValue);

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index e5cba5e50b31..2eb7d2f945a3 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -352,6 +352,7 @@ void DWARFUnit::clear() {
   Abbrevs = nullptr;
   BaseAddr.reset();
   RangeSectionBase = 0;
+  LocSectionBase = 0;
   AddrOffsetSectionBase = 0;
   clearDIEs(false);
   DWO.reset();
@@ -442,11 +443,13 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
   if (!IsDWO) {
     assert(AddrOffsetSectionBase == 0);
     assert(RangeSectionBase == 0);
+    assert(LocSectionBase == 0);
     AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_addr_base), 0);
     if (!AddrOffsetSectionBase)
       AddrOffsetSectionBase =
           toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0);
     RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0);
+    LocSectionBase = toSectionOffset(UnitDie.find(DW_AT_loclists_base), 0);
   }
 
   // In general, in DWARF v5 and beyond we derive the start of the unit's
@@ -498,6 +501,28 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
       if (IsDWO && RngListTable)
         RangeSectionBase = RngListTable->getHeaderSize();
     }
+
+    // FIXME: add loclists.dwo support
+    setLocSection(&Context.getDWARFObj().getLoclistsSection(),
+                  toSectionOffset(UnitDie.find(DW_AT_loclists_base), 0));
+
+    if (LocSection->Data.size()) {
+      LoclistTableHeader.emplace(".debug_loclists", "locations");
+      uint64_t Offset = LocSectionBase;
+      uint64_t HeaderSize = DWARFListTableHeader::getHeaderSize(Header.getFormat());
+      DWARFDataExtractor Data(Context.getDWARFObj(), *LocSection,
+                              isLittleEndian, getAddressByteSize());
+      if (Offset < HeaderSize)
+        return createStringError(errc::invalid_argument,
+                                 "did not detect a valid"
+                                 " list table with base = 0x%" PRIx64 "\n",
+                                 Offset);
+      Offset -= HeaderSize;
+      if (Error E = LoclistTableHeader->extract(Data, &Offset))
+        return createStringError(errc::invalid_argument,
+                                 "parsing a loclist table: " +
+                                     toString(std::move(E)));
+    }
   }
 
   // Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for

diff  --git a/llvm/test/CodeGen/X86/debug-loclists.ll b/llvm/test/CodeGen/X86/debug-loclists.ll
index ba6eb6a988cf..f22e9e1a5c47 100644
--- a/llvm/test/CodeGen/X86/debug-loclists.ll
+++ b/llvm/test/CodeGen/X86/debug-loclists.ll
@@ -2,32 +2,36 @@
 ; RUN: llvm-dwarfdump -v -debug-info -debug-loclists %t | FileCheck %s
 
 ; CHECK:      DW_TAG_variable
-; FIXME: Use DW_FORM_loclistx to reduce relocations
-; CHECK-NEXT:   DW_AT_location [DW_FORM_sec_offset]   (0x0000000c
+; CHECK-NEXT:   DW_AT_location [DW_FORM_loclistx]   (indexed (0x0) loclist = 0x00000018:
 ; CHECK-NEXT:     [0x0000000000000000, 0x0000000000000003): DW_OP_consts +3, DW_OP_stack_value
 ; CHECK-NEXT:     [0x0000000000000003, 0x0000000000000004): DW_OP_consts +4, DW_OP_stack_value)
 ; CHECK-NEXT:   DW_AT_name {{.*}} "y"
 
 ; CHECK:      DW_TAG_variable
-; FIXME: Use DW_FORM_loclistx to reduce relocations
-; CHECK-NEXT:   DW_AT_location [DW_FORM_sec_offset]   (0x0000001d
+; CHECK-NEXT:   DW_AT_location [DW_FORM_loclistx]   (indexed (0x1) loclist = 0x00000029:
 ; CHECK-NEXT:     [0x0000000000000000, 0x0000000000000003): DW_OP_consts +5, DW_OP_stack_value)
 ; CHECK-NEXT:   DW_AT_name {{.*}} "x"
 
 ; CHECK:      DW_TAG_variable
 ; FIXME: Use DW_FORM_loclistx to reduce relocations
-; CHECK-NEXT:   DW_AT_location [DW_FORM_sec_offset]   (0x00000025
+; CHECK-NEXT:   DW_AT_location [DW_FORM_loclistx]   (indexed (0x2) loclist = 0x00000031:
 ; CHECK-NEXT:     [0x0000000000000003, 0x0000000000000004): DW_OP_reg0 RAX)
 ; CHECK-NEXT:   DW_AT_name {{.*}} "r"
 
 ; CHECK:      .debug_loclists contents:
-; CHECK-NEXT: 0x00000000: locations list header: length = 0x00000029, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000
+; CHECK-NEXT: 0x00000000: locations list header: length = 0x00000035, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000003
+
+; CHECK-NEXT: offsets: [
+; CHECK-NEXT: 0x0000000c => 0x00000018
+; CHECK-NEXT: 0x0000001d => 0x00000029
+; CHECK-NEXT: 0x00000025 => 0x00000031
+; CHECK-NEXT: ]
 
 ; Don't use startx_length if there's more than one entry, because the shared
 ; base address will be useful for both the range that does start at the start of
 ; the function, and the one that doesn't.
 
-; CHECK-NEXT: 0x0000000c:
+; CHECK-NEXT: 0x00000018:
 ; CHECK-NEXT:             DW_LLE_base_addressx (0x0000000000000000)
 ; CHECK-NEXT:             DW_LLE_offset_pair   (0x0000000000000000, 0x0000000000000003): DW_OP_consts +3, DW_OP_stack_value
 ; CHECK-NEXT:             DW_LLE_offset_pair   (0x0000000000000003, 0x0000000000000004): DW_OP_consts +4, DW_OP_stack_value
@@ -35,14 +39,14 @@
 
 ; Show that startx_length can be used when the address range starts at the start of the function.
 
-; CHECK:      0x0000001d:
+; CHECK:      0x00000029:
 ; CHECK-NEXT:             DW_LLE_startx_length (0x0000000000000000, 0x0000000000000003): DW_OP_consts +5, DW_OP_stack_value
 ; CHECK-NEXT:             DW_LLE_end_of_list   ()
 
 ; And use a base address when the range doesn't start at an existing/useful
 ; address in the pool.
 
-; CHECK:      0x00000025:
+; CHECK:      0x00000031:
 ; CHECK-NEXT:             DW_LLE_base_addressx (0x0000000000000000)
 ; CHECK-NEXT:             DW_LLE_offset_pair   (0x0000000000000003, 0x0000000000000004): DW_OP_reg0 RAX
 ; CHECK-NEXT:             DW_LLE_end_of_list   ()


        


More information about the llvm-commits mailing list