<div dir="ltr">Any idea if there's work to add str_index support to the name tables?<br><br>I guess the idea is that it's more efficient to have one fewer indirections for strings, and worth the cost in duplicate relocations/bytes/etc? *shrug*<br><br>(also one question inline \/)<br><br><div class="gmail_quote"><div dir="ltr">On Tue, Aug 21, 2018 at 11:22 AM Pavel Labath via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: labath<br>
Date: Tue Aug  7 02:54:52 2018<br>
New Revision: 339122<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=339122&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=339122&view=rev</a><br>
Log:<br>
[DebugInfo] Reduce debug_str_offsets section size<br>
<br>
Summary:<br>
The accelerator tables use the debug_str section to store their strings.<br>
However, they do not support the indirect method of access that is<br>
available for the debug_info section (DW_FORM_strx et al.).<br>
<br>
Currently our code is assuming that all strings can/will be referenced<br>
indirectly, and puts all of them into the debug_str_offsets section.<br>
This is generally true for regular (unsplit) dwarf, but in the DWO case,<br>
most of the strings in the debug_str section will only be used from the<br>
accelerator tables. Therefore the contents of the debug_str_offsets<br>
section will be largely unused and bloating the main executable.<br>
<br>
This patch rectifies this by teaching the DwarfStringPool to<br>
differentiate between strings accessed directly and indirectly. When a<br>
user inserts a string into the pool it has to declare whether that<br>
string will be referenced directly or not. If at least one user requsts<br>
indirect access, that string will be assigned an index ID and put into<br>
debug_str_offsets table. Otherwise, the offset table is skipped.<br>
<br>
This approach reduces the overall binary size (when compiled with<br>
-gdwarf-5 -gsplit-dwarf) in my tests by about 2% (debug_str_offsets is<br>
shrunk by 99%).<br>
<br>
Reviewers: probinson, dblaikie, JDevlieghere<br>
<br>
Subscribers: aprantl, mgrang, llvm-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D49493" rel="noreferrer" target="_blank">https://reviews.llvm.org/D49493</a><br>
<br>
Added:<br>
    llvm/trunk/test/DebugInfo/X86/string-offsets-table-order.ll<br>
Modified:<br>
    llvm/trunk/include/llvm/CodeGen/DwarfStringPoolEntry.h<br>
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp<br>
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp<br>
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfStringPool.h<br>
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp<br>
    llvm/trunk/test/DebugInfo/X86/string-offsets-table.ll<br>
    llvm/trunk/tools/dsymutil/DwarfStreamer.cpp<br>
    llvm/trunk/tools/dsymutil/MachOUtils.cpp<br>
    llvm/trunk/tools/dsymutil/NonRelocatableStringpool.cpp<br>
    llvm/trunk/tools/dsymutil/NonRelocatableStringpool.h<br>
    llvm/trunk/unittests/CodeGen/DIEHashTest.cpp<br>
    llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp<br>
    llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/CodeGen/DwarfStringPoolEntry.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/DwarfStringPoolEntry.h?rev=339122&r1=339121&r2=339122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/DwarfStringPoolEntry.h?rev=339122&r1=339121&r2=339122&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/CodeGen/DwarfStringPoolEntry.h (original)<br>
+++ llvm/trunk/include/llvm/CodeGen/DwarfStringPoolEntry.h Tue Aug  7 02:54:52 2018<br>
@@ -10,6 +10,7 @@<br>
 #ifndef LLVM_CODEGEN_DWARFSTRINGPOOLENTRY_H<br>
 #define LLVM_CODEGEN_DWARFSTRINGPOOLENTRY_H<br>
<br>
+#include "llvm/ADT/PointerIntPair.h"<br>
 #include "llvm/ADT/StringMap.h"<br>
<br>
 namespace llvm {<br>
@@ -18,34 +19,52 @@ class MCSymbol;<br>
<br>
 /// Data for a string pool entry.<br>
 struct DwarfStringPoolEntry {<br>
+  static constexpr unsigned NotIndexed = -1;<br>
+<br>
   MCSymbol *Symbol;<br>
   unsigned Offset;<br>
   unsigned Index;<br>
+<br>
+  bool isIndexed() const { return Index != NotIndexed; }<br>
 };<br>
<br>
 /// String pool entry reference.<br>
-struct DwarfStringPoolEntryRef {<br>
-  const StringMapEntry<DwarfStringPoolEntry> *I = nullptr;<br>
+class DwarfStringPoolEntryRef {<br>
+  PointerIntPair<const StringMapEntry<DwarfStringPoolEntry> *, 1, bool><br>
+      MapEntryAndIndexed;<br>
+<br>
+  const StringMapEntry<DwarfStringPoolEntry> *getMapEntry() const {<br>
+    return MapEntryAndIndexed.getPointer();<br>
+  }<br>
<br>
 public:<br>
   DwarfStringPoolEntryRef() = default;<br>
-  explicit DwarfStringPoolEntryRef(<br>
-      const StringMapEntry<DwarfStringPoolEntry> &I)<br>
-      : I(&I) {}<br>
+  DwarfStringPoolEntryRef(const StringMapEntry<DwarfStringPoolEntry> &Entry,<br>
+                          bool Indexed)<br>
+      : MapEntryAndIndexed(&Entry, Indexed) {}<br>
<br>
-  explicit operator bool() const { return I; }<br>
+  explicit operator bool() const { return getMapEntry(); }<br>
   MCSymbol *getSymbol() const {<br>
-    assert(I->second.Symbol && "No symbol available!");<br>
-    return I->second.Symbol;<br>
+    assert(getMapEntry()->second.Symbol && "No symbol available!");<br>
+    return getMapEntry()->second.Symbol;<br>
   }<br>
-  unsigned getOffset() const { return I->second.Offset; }<br>
-  unsigned getIndex() const { return I->second.Index; }<br>
-  StringRef getString() const { return I->first(); }<br>
+  unsigned getOffset() const { return getMapEntry()->second.Offset; }<br>
+  bool isIndexed() const { return MapEntryAndIndexed.getInt(); }<br>
+  unsigned getIndex() const {<br>
+    assert(isIndexed());<br>
+    assert(getMapEntry()->getValue().isIndexed());<br>
+    return getMapEntry()->second.Index;<br>
+  }<br>
+  StringRef getString() const { return getMapEntry()->first(); }<br>
   /// Return the entire string pool entry for convenience.<br>
-  DwarfStringPoolEntry getEntry() const { return I->getValue(); }<br>
+  DwarfStringPoolEntry getEntry() const { return getMapEntry()->getValue(); }<br>
<br>
-  bool operator==(const DwarfStringPoolEntryRef &X) const { return I == X.I; }<br>
-  bool operator!=(const DwarfStringPoolEntryRef &X) const { return I != X.I; }<br>
+  bool operator==(const DwarfStringPoolEntryRef &X) const {<br>
+    return getMapEntry() == X.getMapEntry();<br>
+  }<br>
+  bool operator!=(const DwarfStringPoolEntryRef &X) const {<br>
+    return getMapEntry() != X.getMapEntry();<br>
+  }<br>
 };<br>
<br>
 } // end namespace llvm<br>
<br>
Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp?rev=339122&r1=339121&r2=339122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp?rev=339122&r1=339121&r2=339122&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (original)<br>
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp Tue Aug  7 02:54:52 2018<br>
@@ -2437,8 +2437,7 @@ void DwarfDebug::addAccelNameImpl(AccelT<br>
     return;<br>
<br>
   DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder;<br>
-  DwarfStringPoolEntryRef Ref =<br>
-      Holder.getStringPool().getEntry(*Asm, Name);<br>
+  DwarfStringPoolEntryRef Ref = Holder.getStringPool().getEntry(*Asm, Name);<br>
<br>
   switch (getAccelTableKind()) {<br>
   case AccelTableKind::Apple:<br>
<br>
Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp?rev=339122&r1=339121&r2=339122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp?rev=339122&r1=339121&r2=339122&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp (original)<br>
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp Tue Aug  7 02:54:52 2018<br>
@@ -24,25 +24,39 @@ DwarfStringPool::DwarfStringPool(BumpPtr<br>
     : Pool(A), Prefix(Prefix),<br>
       ShouldCreateSymbols(Asm.MAI->doesDwarfUseRelocationsAcrossSections()) {}<br>
<br>
-DwarfStringPool::EntryRef DwarfStringPool::getEntry(AsmPrinter &Asm,<br>
-                                                    StringRef Str) {<br>
+StringMapEntry<DwarfStringPool::EntryTy> &<br>
+DwarfStringPool::getEntryImpl(AsmPrinter &Asm, StringRef Str) {<br>
   auto I = Pool.insert(std::make_pair(Str, EntryTy()));<br>
+  auto &Entry = I.first->second;<br>
   if (I.second) {<br>
-    auto &Entry = I.first->second;<br>
-    Entry.Index = Pool.size() - 1;<br>
+    Entry.Index = EntryTy::NotIndexed;<br>
     Entry.Offset = NumBytes;<br>
     Entry.Symbol = ShouldCreateSymbols ? Asm.createTempSymbol(Prefix) : nullptr;<br>
<br>
     NumBytes += Str.size() + 1;<br>
     assert(NumBytes > Entry.Offset && "Unexpected overflow");<br>
   }<br>
-  return EntryRef(*I.first);<br>
+  return *I.first;<br>
+}<br>
+<br>
+DwarfStringPool::EntryRef DwarfStringPool::getEntry(AsmPrinter &Asm,<br>
+                                                    StringRef Str) {<br>
+  auto &MapEntry = getEntryImpl(Asm, Str);<br>
+  return EntryRef(MapEntry, false);<br>
+}<br>
+<br>
+DwarfStringPool::EntryRef DwarfStringPool::getIndexedEntry(AsmPrinter &Asm,<br>
+                                                           StringRef Str) {<br>
+  auto &MapEntry = getEntryImpl(Asm, Str);<br>
+  if (!MapEntry.getValue().isIndexed())<br>
+    MapEntry.getValue().Index = NumIndexedStrings++;<br>
+  return EntryRef(MapEntry, true);<br>
 }<br>
<br>
 void DwarfStringPool::emitStringOffsetsTableHeader(AsmPrinter &Asm,<br>
                                                    MCSection *Section,<br>
                                                    MCSymbol *StartSym) {<br>
-  if (empty())<br>
+  if (getNumIndexedStrings() == 0)<br>
     return;<br>
   Asm.OutStreamer->SwitchSection(Section);<br>
   unsigned EntrySize = 4;<br>
@@ -51,7 +65,7 @@ void DwarfStringPool::emitStringOffsetsT<br>
   // table. The header consists of an entry with the contribution's<br>
   // size (not including the size of the length field), the DWARF version and<br>
   // 2 bytes of padding.<br>
-  Asm.emitInt32(size() * EntrySize + 4);<br>
+  Asm.emitInt32(getNumIndexedStrings() * EntrySize + 4);<br>
   Asm.emitInt16(Asm.getDwarfVersion());<br>
   Asm.emitInt16(0);<br>
   // Define the symbol that marks the start of the contribution. It is<br>
@@ -69,12 +83,18 @@ void DwarfStringPool::emit(AsmPrinter &A<br>
   // Start the dwarf str section.<br>
   Asm.OutStreamer->SwitchSection(StrSection);<br>
<br>
-  // Get all of the string pool entries and put them in an array by their ID so<br>
-  // we can sort them.<br>
-  SmallVector<const StringMapEntry<EntryTy> *, 64> Entries(Pool.size());<br>
+  // Get all of the string pool entries and sort them by their offset.<br>
+  SmallVector<const StringMapEntry<EntryTy> *, 64> Entries;<br>
+  Entries.reserve(Pool.size());<br>
<br>
   for (const auto &E : Pool)<br>
-    Entries[E.getValue().Index] = &E;<br>
+    Entries.push_back(&E);<br>
+<br>
+  llvm::sort(<br>
+      Entries.begin(), Entries.end(),<br>
+      [](const StringMapEntry<EntryTy> *A, const StringMapEntry<EntryTy> *B) {<br>
+        return A->getValue().Offset < B->getValue().Offset;<br>
+      });<br>
<br>
   for (const auto &Entry : Entries) {<br>
     assert(ShouldCreateSymbols == static_cast<bool>(Entry->getValue().Symbol) &&<br>
@@ -93,6 +113,14 @@ void DwarfStringPool::emit(AsmPrinter &A<br>
<br>
   // If we've got an offset section go ahead and emit that now as well.<br>
   if (OffsetSection) {<br>
+    // Now only take the indexed entries and put them in an array by their ID so<br>
+    // we can emit them in order.<br>
+    Entries.resize(NumIndexedStrings);<br>
+    for (const auto &Entry : Pool) {<br>
+      if (Entry.getValue().isIndexed())<br>
+        Entries[Entry.getValue().Index] = &Entry;<br>
+    }<br>
+<br>
     Asm.OutStreamer->SwitchSection(OffsetSection);<br>
     unsigned size = 4; // FIXME: DWARF64 is 8.<br>
     for (const auto &Entry : Entries)<br>
<br>
Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfStringPool.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfStringPool.h?rev=339122&r1=339121&r2=339122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfStringPool.h?rev=339122&r1=339121&r2=339122&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfStringPool.h (original)<br>
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfStringPool.h Tue Aug  7 02:54:52 2018<br>
@@ -30,8 +30,11 @@ class DwarfStringPool {<br>
   StringMap<EntryTy, BumpPtrAllocator &> Pool;<br>
   StringRef Prefix;<br>
   unsigned NumBytes = 0;<br>
+  unsigned NumIndexedStrings = 0;<br>
   bool ShouldCreateSymbols;<br>
<br>
+  StringMapEntry<EntryTy> &getEntryImpl(AsmPrinter &Asm, StringRef Str);<br>
+<br>
 public:<br>
   using EntryRef = DwarfStringPoolEntryRef;<br>
<br>
@@ -48,8 +51,15 @@ public:<br>
<br>
   unsigned size() const { return Pool.size(); }<br>
<br>
+  unsigned getNumIndexedStrings() const { return NumIndexedStrings; }<br>
+<br>
   /// Get a reference to an entry in the string pool.<br>
   EntryRef getEntry(AsmPrinter &Asm, StringRef Str);<br>
+<br>
+  /// Same as getEntry, except that you can use EntryRef::getIndex to obtain a<br>
+  /// unique ID of this entry (e.g., for use in indexed forms like<br>
+  /// DW_FORM_strx).<br>
+  EntryRef getIndexedEntry(AsmPrinter &Asm, StringRef Str);<br>
 };<br>
<br>
 } // end namespace llvm<br>
<br>
Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp?rev=339122&r1=339121&r2=339122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp?rev=339122&r1=339121&r2=339122&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp (original)<br>
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp Tue Aug  7 02:54:52 2018<br>
@@ -243,9 +243,14 @@ void DwarfUnit::addString(DIE &Die, dwar<br>
                      DIEInlineString(String, DIEValueAllocator));<br>
     return;<br>
   }<br>
-  auto StringPoolEntry = DU->getStringPool().getEntry(*Asm, String);<br>
   dwarf::Form IxForm =<br>
       isDwoUnit() ? dwarf::DW_FORM_GNU_str_index : dwarf::DW_FORM_strp;<br>
+<br>
+  auto StringPoolEntry =<br>
+      useSegmentedStringOffsetsTable() || IxForm == dwarf::DW_FORM_GNU_str_index<br>
+          ? DU->getStringPool().getIndexedEntry(*Asm, String)<br>
+          : DU->getStringPool().getEntry(*Asm, String);<br>
+<br>
   // For DWARF v5 and beyond, use the smallest strx? form possible.<br>
   if (useSegmentedStringOffsetsTable()) {<br>
     IxForm = dwarf::DW_FORM_strx1;<br>
<br>
Added: llvm/trunk/test/DebugInfo/X86/string-offsets-table-order.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/string-offsets-table-order.ll?rev=339122&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/string-offsets-table-order.ll?rev=339122&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/DebugInfo/X86/string-offsets-table-order.ll (added)<br>
+++ llvm/trunk/test/DebugInfo/X86/string-offsets-table-order.ll Tue Aug  7 02:54:52 2018<br>
@@ -0,0 +1,79 @@<br>
+; REQUIRES: object-emission<br>
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu -split-dwarf-file=foo.dwo -filetype=obj < %s \<br>
+; RUN:   | llvm-dwarfdump -v - | FileCheck %s<br>
+<br>
+; This triggers a situation where the order of entries in the .debug_str and<br>
+; .debug_str_offsets sections does not match and makes sure that all entries are<br>
+; still wired up correctly.<br>
+<br>
+; Produced with "clang -S -emit-llvm -gdwarf-5" from source "int X;", copied<br>
+; three times and modified by hand.<br></blockquote><div><br>Could you describe in the comment what modifications were necessary?<br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+; CHECK: .debug_info contents:<br>
+; CHECK:   DW_TAG_compile_unit<br>
+; CHECK:     DW_AT_comp_dir [DW_FORM_strx1] ( indexed (00000001) string = "X3")<br>
+; CHECK:   DW_TAG_compile_unit<br>
+; CHECK:     DW_AT_comp_dir [DW_FORM_strx1] ( indexed (00000002) string = "X2")<br>
+; CHECK:   DW_TAG_compile_unit<br>
+; CHECK:     DW_AT_comp_dir [DW_FORM_strx1] ( indexed (00000003) string = "X1")<br>
+; CHECK: .debug_info.dwo contents:<br>
+<br>
+; CHECK: .debug_str contents:<br>
+; CHECK: 0x[[X3:[0-9a-f]*]]: "X3"<br>
+; CHECK: 0x[[X1:[0-9a-f]*]]: "X1"<br>
+; CHECK: 0x[[X2:[0-9a-f]*]]: "X2"<br>
+<br>
+; CHECK: .debug_str_offsets contents:<br>
+; CHECK: Format = DWARF32, Version = 5<br>
+; CHECK-NEXT: 00000000 "foo.dwo"<br>
+; CHECK-NEXT: [[X3]] "X3"<br>
+; CHECK-NEXT: [[X2]] "X2"<br>
+; CHECK-NEXT: [[X1]] "X1"<br>
+; CHECK-EMPTY:<br>
+<br>
+<br>
+<br>
+!<a href="http://llvm.dbg.cu" rel="noreferrer" target="_blank">llvm.dbg.cu</a> = !{!10, !20, !30}<br>
+!llvm.module.flags = !{!0, !1, !2}<br>
+!llvm.ident = !{!3}<br>
+<br>
+!0 = !{i32 2, !"Dwarf Version", i32 5}<br>
+!1 = !{i32 2, !"Debug Info Version", i32 3}<br>
+!2 = !{i32 1, !"wchar_size", i32 4}<br>
+!3 = !{!"clang version 7.0.0 (trunk 337353) (llvm/trunk 337361)"}<br>
+<br>
+<br>
+@X1 = dso_local global i32 0, align 4, !dbg !11<br>
+<br>
+!10 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !13, producer: "clang version 7.0.0 (trunk 337353) (llvm/trunk 337361)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !14, globals: !15)<br>
+!11 = !DIGlobalVariableExpression(var: !12, expr: !DIExpression())<br>
+!12 = distinct !DIGlobalVariable(name: "X1", scope: !10, file: !16, line: 1, type: !17, isLocal: false, isDefinition: true)<br>
+!13 = !DIFile(filename: "-", directory: "X3", checksumkind: CSK_MD5, checksum: "f2e6e10e303927a308f1645fbf6f710e")<br>
+!14 = !{}<br>
+!15 = !{!11}<br>
+!16 = !DIFile(filename: "<stdin>", directory: "X3", checksumkind: CSK_MD5, checksum: "f2e6e10e303927a308f1645fbf6f710e")<br>
+!17 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)<br>
+<br>
+<br>
+@X2 = dso_local global i32 0, align 4, !dbg !21<br>
+<br>
+!20 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !23, producer: "clang version 7.0.0 (trunk 337353) (llvm/trunk 337361)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !24, globals: !25)<br>
+!21 = !DIGlobalVariableExpression(var: !22, expr: !DIExpression())<br>
+!22 = distinct !DIGlobalVariable(name: "X2", scope: !20, file: !26, line: 1, type: !27, isLocal: false, isDefinition: true)<br>
+!23 = !DIFile(filename: "-", directory: "X2", checksumkind: CSK_MD5, checksum: "f2e6e10e303927a308f1645fbf6f710e")<br>
+!24 = !{}<br>
+!25 = !{!21}<br>
+!26 = !DIFile(filename: "<stdin>", directory: "X2", checksumkind: CSK_MD5, checksum: "f2e6e10e303927a308f1645fbf6f710e")<br>
+!27 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)<br>
+<br>
+<br>
+@X3 = dso_local global i32 0, align 4, !dbg !31<br>
+<br>
+!30 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !33, producer: "clang version 7.0.0 (trunk 337353) (llvm/trunk 337361)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !34, globals: !35)<br>
+!31 = !DIGlobalVariableExpression(var: !32, expr: !DIExpression())<br>
+!32 = distinct !DIGlobalVariable(name: "X3", scope: !30, file: !36, line: 1, type: !37, isLocal: false, isDefinition: true)<br>
+!33 = !DIFile(filename: "-", directory: "X1", checksumkind: CSK_MD5, checksum: "f2e6e10e303927a308f1645fbf6f710e")<br>
+!34 = !{}<br>
+!35 = !{!31}<br>
+!36 = !DIFile(filename: "<stdin>", directory: "X1", checksumkind: CSK_MD5, checksum: "f2e6e10e303927a308f1645fbf6f710e")<br>
+!37 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)<br>
<br>
Modified: llvm/trunk/test/DebugInfo/X86/string-offsets-table.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/string-offsets-table.ll?rev=339122&r1=339121&r2=339122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/string-offsets-table.ll?rev=339122&r1=339121&r2=339122&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/DebugInfo/X86/string-offsets-table.ll (original)<br>
+++ llvm/trunk/test/DebugInfo/X86/string-offsets-table.ll Tue Aug  7 02:54:52 2018<br>
@@ -1,7 +1,7 @@<br>
 ; REQUIRES: object-emission<br>
 ; RUN: llc -mtriple=x86_64-unknown-linux-gnu -filetype=obj < %s | llvm-dwarfdump -v - \<br>
 ; RUN:   | FileCheck --check-prefix=MONOLITHIC %s<br>
-; RUN: llc -mtriple=x86_64-unknown-linux-gnu -split-dwarf-file=%t.dwo -filetype=obj < %s \<br>
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu -split-dwarf-file=foo.dwo -filetype=obj < %s \<br>
 ; RUN:   | llvm-dwarfdump -v - | FileCheck --check-prefix=SPLIT %s<br>
<br>
 ; This basic test checks the emission of a DWARF v5 string offsets table in<br>
@@ -59,6 +59,8 @@<br>
 ; SPLIT:      DW_TAG_compile_unit<br>
 ; SPLIT-NOT:  {{DW_TAG|contents:}}<br>
 ; SPLIT:      DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008)<br>
+; SPLIT:      DW_AT_GNU_dwo_name [DW_FORM_strx1] ( indexed (00000000) string = "foo.dwo")<br>
+; SPLIT:      DW_AT_comp_dir [DW_FORM_strx1] ( indexed (00000001) string = "/home/test")<br>
<br>
 ; Check for the split CU in .debug_info.dwo.<br>
 ; SPLIT:      .debug_info.dwo contents:<br>
@@ -79,10 +81,10 @@<br>
 ;<br>
 ; Extract the string offsets referenced in the main file by the skeleton unit.<br>
 ; SPLIT:      .debug_str contents:<br>
-; SPLIT-NEXT: 0x00000000:{{.*}}<br>
-; SPLIT-NEXT: 0x[[STRING2SPLIT:[0-9a-f]*]]{{.*}}<br>
-; SPLIT-NEXT: 0x[[STRING3SPLIT:[0-9a-f]*]]{{.*}}<br>
-; SPLIT-NEXT: 0x[[STRING4SPLIT:[0-9a-f]*]]{{.*}}<br>
+; SPLIT-NEXT: 0x00000000: "foo.dwo"<br>
+; SPLIT-NEXT: 0x[[STRING2SPLIT:[0-9a-f]*]]: "/home/test"<br>
+; SPLIT-NEXT: 0x[[STRING3SPLIT:[0-9a-f]*]]: "E"<br>
+; SPLIT-NEXT: 0x[[STRING4SPLIT:[0-9a-f]*]]: "glob"<br>
 ;<br>
 ; Extract the string offsets referenced in the .dwo file by the split unit.<br>
 ; SPLIT:      .debug_str.dwo contents:<br>
@@ -91,13 +93,15 @@<br>
 ; SPLIT-NEXT: 0x[[STRING3DWO:[0-9a-f]*]]{{.*}}<br>
 ;<br>
 ; Check the string offsets sections in both the main and the .dwo files and<br>
-; verify that the extracted string offsets are referenced correctly.<br>
+; verify that the extracted string offsets are referenced correctly. The<br>
+; sections should contain only the offsets of strings that are actually<br>
+; referenced by the debug info.<br>
 ; SPLIT:      .debug_str_offsets contents:<br>
-; SPLIT-NEXT: 0x00000000: Contribution size = 20, Format = DWARF32, Version = 5<br>
-; SPLIT-NEXT: 0x00000008: 00000000{{.*}}<br>
-; SPLIT-NEXT: 0x0000000c: [[STRING2SPLIT]]<br>
-; SPLIT-NEXT: 0x00000010: [[STRING3SPLIT]]<br>
-; SPLIT-NEXT: 0x00000014: [[STRING4SPLIT]]<br>
+; SPLIT-NEXT: 0x00000000: Contribution size = 12, Format = DWARF32, Version = 5<br>
+; SPLIT-NEXT: 0x00000008: 00000000 "foo.dwo"<br>
+; SPLIT-NEXT: 0x0000000c: [[STRING2SPLIT]] "/home/test"<br>
+; SPLIT-EMPTY:<br>
+<br>
 ; SPLIT:      .debug_str_offsets.dwo contents:<br>
 ; SPLIT-NEXT: 0x00000000: Contribution size = 36, Format = DWARF32, Version = 5<br>
 ; SPLIT-NEXT: 0x00000008: 00000000{{.*}}<br>
<br>
Modified: llvm/trunk/tools/dsymutil/DwarfStreamer.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DwarfStreamer.cpp?rev=339122&r1=339121&r2=339122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DwarfStreamer.cpp?rev=339122&r1=339121&r2=339122&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/dsymutil/DwarfStreamer.cpp (original)<br>
+++ llvm/trunk/tools/dsymutil/DwarfStreamer.cpp Tue Aug  7 02:54:52 2018<br>
@@ -190,10 +190,8 @@ void DwarfStreamer::emitDIE(DIE &Die) {<br>
 /// Emit the debug_str section stored in \p Pool.<br>
 void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) {<br>
   Asm->OutStreamer->SwitchSection(MOFI->getDwarfStrSection());<br>
-  std::vector<DwarfStringPoolEntryRef> Entries = Pool.getEntries();<br>
+  std::vector<DwarfStringPoolEntryRef> Entries = Pool.getEntriesForEmission();<br>
   for (auto Entry : Entries) {<br>
-    if (Entry.getIndex() == -1U)<br>
-      break;<br>
     // Emit the string itself.<br>
     Asm->OutStreamer->EmitBytes(Entry.getString());<br>
     // Emit a null terminator.<br>
<br>
Modified: llvm/trunk/tools/dsymutil/MachOUtils.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/MachOUtils.cpp?rev=339122&r1=339121&r2=339122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/MachOUtils.cpp?rev=339122&r1=339121&r2=339122&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/dsymutil/MachOUtils.cpp (original)<br>
+++ llvm/trunk/tools/dsymutil/MachOUtils.cpp Tue Aug  7 02:54:52 2018<br>
@@ -514,10 +514,9 @@ bool generateDsymCompanion(const DebugMa<br>
     // Reproduce that behavior for now (there is corresponding code in<br>
     // transferSymbol).<br>
     OutFile << '\0';<br>
-    std::vector<DwarfStringPoolEntryRef> Strings = NewStrings.getEntries();<br>
+    std::vector<DwarfStringPoolEntryRef> Strings =<br>
+        NewStrings.getEntriesForEmission();<br>
     for (auto EntryRef : Strings) {<br>
-      if (EntryRef.getIndex() == -1U)<br>
-        break;<br>
       OutFile.write(EntryRef.getString().data(),<br>
                     EntryRef.getString().size() + 1);<br>
     }<br>
<br>
Modified: llvm/trunk/tools/dsymutil/NonRelocatableStringpool.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/NonRelocatableStringpool.cpp?rev=339122&r1=339121&r2=339122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/NonRelocatableStringpool.cpp?rev=339122&r1=339121&r2=339122&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/dsymutil/NonRelocatableStringpool.cpp (original)<br>
+++ llvm/trunk/tools/dsymutil/NonRelocatableStringpool.cpp Tue Aug  7 02:54:52 2018<br>
@@ -18,27 +18,28 @@ DwarfStringPoolEntryRef NonRelocatableSt<br>
<br>
   auto I = Strings.insert({S, DwarfStringPoolEntry()});<br>
   auto &Entry = I.first->second;<br>
-  if (I.second || Entry.Index == -1U) {<br>
+  if (I.second || !Entry.isIndexed()) {<br>
     Entry.Index = NumEntries++;<br>
     Entry.Offset = CurrentEndOffset;<br>
     Entry.Symbol = nullptr;<br>
     CurrentEndOffset += S.size() + 1;<br>
   }<br>
-  return DwarfStringPoolEntryRef(*I.first);<br>
+  return DwarfStringPoolEntryRef(*I.first, true);<br>
 }<br>
<br>
 StringRef NonRelocatableStringpool::internString(StringRef S) {<br>
-  DwarfStringPoolEntry Entry{nullptr, 0, -1U};<br>
+  DwarfStringPoolEntry Entry{nullptr, 0, DwarfStringPoolEntry::NotIndexed};<br>
   auto InsertResult = Strings.insert({S, Entry});<br>
   return InsertResult.first->getKey();<br>
 }<br>
<br>
 std::vector<DwarfStringPoolEntryRef><br>
-NonRelocatableStringpool::getEntries() const {<br>
+NonRelocatableStringpool::getEntriesForEmission() const {<br>
   std::vector<DwarfStringPoolEntryRef> Result;<br>
   Result.reserve(Strings.size());<br>
   for (const auto &E : Strings)<br>
-    Result.emplace_back(E);<br>
+    if (E.getValue().isIndexed())<br>
+      Result.emplace_back(E, true);<br>
   llvm::sort(<br>
       Result.begin(), Result.end(),<br>
       [](const DwarfStringPoolEntryRef A, const DwarfStringPoolEntryRef B) {<br>
<br>
Modified: llvm/trunk/tools/dsymutil/NonRelocatableStringpool.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/NonRelocatableStringpool.h?rev=339122&r1=339121&r2=339122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/NonRelocatableStringpool.h?rev=339122&r1=339121&r2=339122&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/dsymutil/NonRelocatableStringpool.h (original)<br>
+++ llvm/trunk/tools/dsymutil/NonRelocatableStringpool.h Tue Aug  7 02:54:52 2018<br>
@@ -53,7 +53,9 @@ public:<br>
<br>
   uint64_t getSize() { return CurrentEndOffset; }<br>
<br>
-  std::vector<DwarfStringPoolEntryRef> getEntries() const;<br>
+  /// Return the list of strings to be emitted. This does not contain the<br>
+  /// strings which were added via internString only.<br>
+  std::vector<DwarfStringPoolEntryRef> getEntriesForEmission() const;<br>
<br>
 private:<br>
   MapTy Strings;<br>
<br>
Modified: llvm/trunk/unittests/CodeGen/DIEHashTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/CodeGen/DIEHashTest.cpp?rev=339122&r1=339121&r2=339122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/CodeGen/DIEHashTest.cpp?rev=339122&r1=339121&r2=339122&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/CodeGen/DIEHashTest.cpp (original)<br>
+++ llvm/trunk/unittests/CodeGen/DIEHashTest.cpp Tue Aug  7 02:54:52 2018<br>
@@ -31,8 +31,8 @@ private:<br>
 public:<br>
   DIEString getString(StringRef S) {<br>
     DwarfStringPoolEntry Entry = {nullptr, 1, 1};<br>
-    return DIEString(<br>
-        DwarfStringPoolEntryRef(*Pool.insert(std::make_pair(S, Entry)).first));<br>
+    return DIEString(DwarfStringPoolEntryRef(<br>
+        *Pool.insert(std::make_pair(S, Entry)).first, Entry.isIndexed()));<br>
   }<br>
 };<br>
<br>
<br>
Modified: llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp?rev=339122&r1=339121&r2=339122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp?rev=339122&r1=339121&r2=339122&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp (original)<br>
+++ llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp Tue Aug  7 02:54:52 2018<br>
@@ -1007,6 +1007,99 @@ TEST(DWARFDebugInfo, TestDWARF32Version4<br>
   TestAddresses<4, AddrType>();<br>
 }<br>
<br>
+TEST(DWARFDebugInfo, TestStringOffsets) {<br>
+  Triple Triple = getHostTripleForAddrSize(sizeof(void *));<br>
+  if (!isConfigurationSupported(Triple))<br>
+    return;<br>
+<br>
+  const char *String1 = "Hello";<br>
+  const char *String2 = "World";<br>
+<br>
+  auto ExpectedDG = dwarfgen::Generator::create(Triple, 5);<br>
+  ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());<br>
+  dwarfgen::Generator *DG = ExpectedDG.get().get();<br>
+  dwarfgen::CompileUnit &CU = DG->addCompileUnit();<br>
+  dwarfgen::DIE CUDie = CU.getUnitDIE();<br>
+<br>
+  CUDie.addStrOffsetsBaseAttribute();<br>
+<br>
+  uint16_t Attr = DW_AT_lo_user;<br>
+<br>
+  // Create our strings. First we create a non-indexed reference to String1,<br>
+  // followed by an indexed String2. Finally, we add an indexed reference to<br>
+  // String1.<br>
+  const auto Attr1 = static_cast<dwarf::Attribute>(Attr++);<br>
+  CUDie.addAttribute(Attr1, DW_FORM_strp, String1);<br>
+<br>
+  const auto Attr2 = static_cast<dwarf::Attribute>(Attr++);<br>
+  CUDie.addAttribute(Attr2, DW_FORM_strx, String2);<br>
+<br>
+  const auto Attr3 = static_cast<dwarf::Attribute>(Attr++);<br>
+  CUDie.addAttribute(Attr3, DW_FORM_strx, String1);<br>
+<br>
+  // Generate the DWARF<br>
+  StringRef FileBytes = DG->generate();<br>
+  MemoryBufferRef FileBuffer(FileBytes, "dwarf");<br>
+  auto Obj = object::ObjectFile::createObjectFile(FileBuffer);<br>
+  ASSERT_TRUE((bool)Obj);<br>
+  std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);<br>
+  uint32_t NumCUs = DwarfContext->getNumCompileUnits();<br>
+  ASSERT_EQ(NumCUs, 1u);<br>
+  DWARFUnit *U = DwarfContext->getUnitAtIndex(0);<br>
+  auto DieDG = U->getUnitDIE(false);<br>
+  ASSERT_TRUE(DieDG.isValid());<br>
+<br>
+  // Now make sure the string offsets came out properly. Attr2 should have index<br>
+  // 0 (because it was the first indexed string) even though the string itself<br>
+  // was added eariler.<br>
+  auto Extracted1 = toString(DieDG.find(Attr1));<br>
+  ASSERT_TRUE((bool)Extracted1);<br>
+  EXPECT_STREQ(String1, *Extracted1);<br>
+<br>
+  Optional<DWARFFormValue> Form2 = DieDG.find(Attr2);<br>
+  ASSERT_TRUE((bool)Form2);<br>
+  EXPECT_EQ(0u, Form2->getRawUValue());<br>
+  auto Extracted2 = toString(Form2);<br>
+  ASSERT_TRUE((bool)Extracted2);<br>
+  EXPECT_STREQ(String2, *Extracted2);<br>
+<br>
+  Optional<DWARFFormValue> Form3 = DieDG.find(Attr3);<br>
+  ASSERT_TRUE((bool)Form3);<br>
+  EXPECT_EQ(1u, Form3->getRawUValue());<br>
+  auto Extracted3 = toString(Form3);<br>
+  ASSERT_TRUE((bool)Extracted3);<br>
+  EXPECT_STREQ(String1, *Extracted3);<br>
+}<br>
+<br>
+TEST(DWARFDebugInfo, TestEmptyStringOffsets) {<br>
+  Triple Triple = getHostTripleForAddrSize(sizeof(void *));<br>
+  if (!isConfigurationSupported(Triple))<br>
+    return;<br>
+<br>
+  const char *String1 = "Hello";<br>
+<br>
+  auto ExpectedDG = dwarfgen::Generator::create(Triple, 5);<br>
+  ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());<br>
+  dwarfgen::Generator *DG = ExpectedDG.get().get();<br>
+  dwarfgen::CompileUnit &CU = DG->addCompileUnit();<br>
+  dwarfgen::DIE CUDie = CU.getUnitDIE();<br>
+<br>
+  uint16_t Attr = DW_AT_lo_user;<br>
+<br>
+  // We shall insert only one string. It will be referenced directly.<br>
+  const auto Attr1 = static_cast<dwarf::Attribute>(Attr++);<br>
+  CUDie.addAttribute(Attr1, DW_FORM_strp, String1);<br>
+<br>
+  // Generate the DWARF<br>
+  StringRef FileBytes = DG->generate();<br>
+  MemoryBufferRef FileBuffer(FileBytes, "dwarf");<br>
+  auto Obj = object::ObjectFile::createObjectFile(FileBuffer);<br>
+  ASSERT_TRUE((bool)Obj);<br>
+  std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);<br>
+  EXPECT_TRUE(<br>
+      DwarfContext->getDWARFObj().getStringOffsetSection().Data.empty());<br>
+}<br>
+<br>
 TEST(DWARFDebugInfo, TestRelations) {<br>
   Triple Triple = getHostTripleForAddrSize(sizeof(void *));<br>
   if (!isConfigurationSupported(Triple))<br>
<br>
Modified: llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.cpp?rev=339122&r1=339121&r2=339122&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.cpp?rev=339122&r1=339121&r2=339122&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.cpp (original)<br>
+++ llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.cpp Tue Aug  7 02:54:52 2018<br>
@@ -71,15 +71,20 @@ void dwarfgen::DIE::addAttribute(uint16_<br>
     break;<br>
<br>
   case DW_FORM_strp:<br>
+    Die->addValue(<br>
+        DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,<br>
+        DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String)));<br>
+    break;<br>
+<br>
   case DW_FORM_GNU_str_index:<br>
   case DW_FORM_strx:<br>
   case DW_FORM_strx1:<br>
   case DW_FORM_strx2:<br>
   case DW_FORM_strx3:<br>
   case DW_FORM_strx4:<br>
-    Die->addValue(<br>
-        DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,<br>
-        DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String)));<br>
+    Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,<br>
+                  DIEString(DG.getStringPool().getIndexedEntry(<br>
+                      *DG.getAsmPrinter(), String)));<br>
     break;<br>
<br>
   default:<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div></div>