[llvm] [DWARFLinkerParallel] Add support for -odr mode. (PR #68721)

via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 10 09:14:43 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-debuginfo

Author: None (avl-llvm)

<details>
<summary>Changes</summary>

This patch is extracted from D96035, it adds support for the type deduplication mode. With this patch DWARFLinkerParallel handles --odr option. It also processes clang modules.

run-time performance and memory requirements for clang binary --num-threads 16 :
    
```
------------------------------------------------------------------------------
                                |  time, sec   |  mem, GB  | .debug_info, MB |
------------------------------------------------------------------------------
dsymutil --odr --linker llvm    |      45      |     13    |       192       |
------------------------------------------------------------------------------
dsymutil --odr --linker apple   |     115      |     11    |       561       |
------------------------------------------------------------------------------

```    
run-time performance and memory requirements for clang binary --num-threads 1 :
    
```
------------------------------------------------------------------------------
                                |  time, sec   |  mem, GB  | .debug_info, MB |
------------------------------------------------------------------------------
dsymutil --odr --linker llvm    |     236      |    12.6   |       192       |
------------------------------------------------------------------------------
dsymutil --odr --linker apple   |     187      |    10.0   |       561       |
------------------------------------------------------------------------------

```    
Note: Sometimes DWARFLinkerParallel may produce non-deterministic results.
The reason for that is ambiguous input DWARF. That problem is assumed
to be solved with separate patches(most probably not for DWARFLinkerParallel
but for generated DWARF).
    
Note: The dependency tracking algorithm handles DW_TAG_imported_module and
DW_TAG_imported_declaration differently than current DWARFLinker. Current
DWARFLinker keeps all content referenced by DW_AT_import attribute despite
the fact whether it references live code or not. This patch keeps only DIEs
referencing live addresses(and all their dependencies)

---

Patch is 469.13 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/68721.diff


77 Files Affected:

- (added) llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp (+295) 
- (added) llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h (+70) 
- (modified) llvm/lib/DWARFLinkerParallel/ArrayList.h (+24-2) 
- (modified) llvm/lib/DWARFLinkerParallel/CMakeLists.txt (+3) 
- (modified) llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp (+187-110) 
- (modified) llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h (+55-18) 
- (modified) llvm/lib/DWARFLinkerParallel/DIEGenerator.h (+18-3) 
- (modified) llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp (+1) 
- (modified) llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp (+542-303) 
- (modified) llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h (+210-59) 
- (modified) llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h (+1) 
- (modified) llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp (+336-104) 
- (modified) llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h (+18-40) 
- (added) llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp (+391) 
- (added) llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h (+138) 
- (modified) llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp (+46-4) 
- (modified) llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h (+41-67) 
- (modified) llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h (+1) 
- (modified) llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp (+632-198) 
- (modified) llvm/lib/DWARFLinkerParallel/DependencyTracker.h (+195-40) 
- (modified) llvm/lib/DWARFLinkerParallel/OutputSections.cpp (+138-26) 
- (modified) llvm/lib/DWARFLinkerParallel/OutputSections.h (+76-17) 
- (added) llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp (+767) 
- (added) llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h (+155) 
- (added) llvm/lib/DWARFLinkerParallel/TypePool.h (+177) 
- (added) llvm/lib/DWARFLinkerParallel/Utils.h (+40) 
- (added) llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test (+80) 
- (modified) llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test (+6-14) 
- (modified) llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test (+32-11) 
- (modified) llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test (+21-7) 
- (modified) llvm/test/tools/dsymutil/ARM/dwarf5-macho.test (+16-4) 
- (modified) llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test (+42-23) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp (+67) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test (+5) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp (+74) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test (+36) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp (+68) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test (+101) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test (+131) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test (+381) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp (+192) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test (+157) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test (+384) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test (+374) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test (+238) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test (+117) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test (+120) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test (+245) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test (+180) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test (+201) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test (+205) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test (+431) 
- (added) llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp (+475) 
- (added) llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o () 
- (added) llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o () 
- (added) llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o () 
- (added) llvm/test/tools/dsymutil/X86/Inputs/String/main.o () 
- (modified) llvm/test/tools/dsymutil/X86/dead-stripped.cpp (-5) 
- (modified) llvm/test/tools/dsymutil/X86/dummy-debug-map.map (+2-2) 
- (modified) llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test (+2-2) 
- (modified) llvm/test/tools/dsymutil/X86/empty-CU.test (-2) 
- (modified) llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp (+12-6) 
- (modified) llvm/test/tools/dsymutil/X86/keep-func.test (-5) 
- (added) llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test (+65) 
- (modified) llvm/test/tools/dsymutil/X86/location-expression.test (+3-3) 
- (modified) llvm/test/tools/dsymutil/X86/modules-empty.m (+3-3) 
- (modified) llvm/test/tools/dsymutil/X86/odr-uniquing.cpp (+2) 
- (modified) llvm/test/tools/dsymutil/X86/op-convert.test (+7-5) 
- (modified) llvm/test/tools/dsymutil/X86/union-fwd-decl.test (-3) 
- (modified) llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test (+1-1) 
- (modified) llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test (+12-12) 
- (modified) llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test (+9-9) 
- (modified) llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test (+2-2) 
- (modified) llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test (+4-4) 
- (modified) llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test (+2-2) 
- (modified) llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test (+2-2) 
- (modified) llvm/tools/dsymutil/DwarfLinkerForBinary.cpp (-1) 


``````````diff
diff --git a/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp
new file mode 100644
index 000000000000000..5ec25cfe5fd26e1
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp
@@ -0,0 +1,295 @@
+//=== AcceleratorRecordsSaver.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "AcceleratorRecordsSaver.h"
+#include "Utils.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/Support/DJB.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+static uint32_t hashFullyQualifiedName(CompileUnit &InputCU, DWARFDie &InputDIE,
+                                       int ChildRecurseDepth = 0) {
+  const char *Name = nullptr;
+  CompileUnit *CU = &InputCU;
+  std::optional<DWARFFormValue> RefVal;
+
+  if (Error Err = finiteLoop([&]() -> Expected<bool> {
+        if (const char *CurrentName = InputDIE.getName(DINameKind::ShortName))
+          Name = CurrentName;
+
+        if (!(RefVal = InputDIE.find(dwarf::DW_AT_specification)) &&
+            !(RefVal = InputDIE.find(dwarf::DW_AT_abstract_origin)))
+          return false;
+
+        if (!RefVal->isFormClass(DWARFFormValue::FC_Reference))
+          return false;
+
+        std::optional<UnitEntryPairTy> RefDie = CU->resolveDIEReference(
+            *RefVal, ResolveInterCUReferencesMode::Resolve);
+        if (!RefDie)
+          return false;
+
+        if (!RefDie->DieEntry)
+          return false;
+
+        CU = RefDie->CU;
+        InputDIE = RefDie->CU->getDIE(RefDie->DieEntry);
+        return true;
+      })) {
+    consumeError(std::move(Err));
+  }
+
+  if (!Name && InputDIE.getTag() == dwarf::DW_TAG_namespace)
+    Name = "(anonymous namespace)";
+
+  DWARFDie ParentDie = InputDIE.getParent();
+  if (!ParentDie.isValid() || ParentDie.getTag() == dwarf::DW_TAG_compile_unit)
+    return djbHash(Name ? Name : "", djbHash(ChildRecurseDepth ? "" : "::"));
+
+  return djbHash(
+      (Name ? Name : ""),
+      djbHash((Name ? "::" : ""),
+              hashFullyQualifiedName(*CU, ParentDie, ++ChildRecurseDepth)));
+}
+
+void AcceleratorRecordsSaver::save(const DWARFDebugInfoEntry *InputDieEntry,
+                                   DIE *OutDIE, AttributesInfo &AttrInfo,
+                                   TypeEntry *TypeEntry) {
+  if (GlobalData.getOptions().AccelTables.empty())
+    return;
+
+  DWARFDie InputDIE = InUnit.getDIE(InputDieEntry);
+
+  // Look for short name recursively if short name is not known yet.
+  if (AttrInfo.Name == nullptr)
+    if (const char *ShortName = InputDIE.getShortName())
+      AttrInfo.Name = GlobalData.getStringPool().insert(ShortName).first;
+
+  switch (InputDieEntry->getTag()) {
+  case dwarf::DW_TAG_array_type:
+  case dwarf::DW_TAG_class_type:
+  case dwarf::DW_TAG_enumeration_type:
+  case dwarf::DW_TAG_pointer_type:
+  case dwarf::DW_TAG_reference_type:
+  case dwarf::DW_TAG_string_type:
+  case dwarf::DW_TAG_structure_type:
+  case dwarf::DW_TAG_subroutine_type:
+  case dwarf::DW_TAG_typedef:
+  case dwarf::DW_TAG_union_type:
+  case dwarf::DW_TAG_ptr_to_member_type:
+  case dwarf::DW_TAG_set_type:
+  case dwarf::DW_TAG_subrange_type:
+  case dwarf::DW_TAG_base_type:
+  case dwarf::DW_TAG_const_type:
+  case dwarf::DW_TAG_constant:
+  case dwarf::DW_TAG_file_type:
+  case dwarf::DW_TAG_namelist:
+  case dwarf::DW_TAG_packed_type:
+  case dwarf::DW_TAG_volatile_type:
+  case dwarf::DW_TAG_restrict_type:
+  case dwarf::DW_TAG_atomic_type:
+  case dwarf::DW_TAG_interface_type:
+  case dwarf::DW_TAG_unspecified_type:
+  case dwarf::DW_TAG_shared_type:
+  case dwarf::DW_TAG_immutable_type:
+  case dwarf::DW_TAG_rvalue_reference_type: {
+    if (!AttrInfo.IsDeclaration && AttrInfo.Name != nullptr &&
+        !AttrInfo.Name->getKey().empty()) {
+      uint32_t Hash = hashFullyQualifiedName(InUnit, InputDIE);
+
+      uint64_t RuntimeLang =
+          dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class))
+              .value_or(0);
+
+      bool ObjCClassIsImplementation =
+          (RuntimeLang == dwarf::DW_LANG_ObjC ||
+           RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
+          dwarf::toUnsigned(
+              InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type))
+              .value_or(0);
+
+      saveTypeRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(), Hash,
+                     ObjCClassIsImplementation, TypeEntry);
+    }
+  } break;
+  case dwarf::DW_TAG_namespace: {
+    if (AttrInfo.Name == nullptr)
+      AttrInfo.Name =
+          GlobalData.getStringPool().insert("(anonymous namespace)").first;
+
+    saveNamespaceRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(),
+                        TypeEntry);
+  } break;
+  case dwarf::DW_TAG_imported_declaration: {
+    if (AttrInfo.Name != nullptr)
+      saveNamespaceRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(),
+                          TypeEntry);
+  } break;
+  case dwarf::DW_TAG_compile_unit:
+  case dwarf::DW_TAG_lexical_block: {
+    // Nothing to do.
+  } break;
+  default:
+    if (TypeEntry)
+      // Do not store this kind of accelerator entries for type entries.
+      return;
+
+    if (AttrInfo.HasLiveAddress || AttrInfo.HasRanges) {
+      if (AttrInfo.Name)
+        saveNameRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(),
+                       InputDieEntry->getTag() ==
+                           dwarf::DW_TAG_inlined_subroutine);
+
+      // Look for mangled name recursively if mangled name is not known yet.
+      if (!AttrInfo.MangledName)
+        if (const char *LinkageName = InputDIE.getLinkageName())
+          AttrInfo.MangledName =
+              GlobalData.getStringPool().insert(LinkageName).first;
+
+      if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
+        saveNameRecord(AttrInfo.MangledName, OutDIE, InputDieEntry->getTag(),
+                       InputDieEntry->getTag() ==
+                           dwarf::DW_TAG_inlined_subroutine);
+
+      // Strip template parameters from the short name.
+      if (AttrInfo.Name && AttrInfo.MangledName != AttrInfo.Name &&
+          (InputDieEntry->getTag() != dwarf::DW_TAG_inlined_subroutine)) {
+        if (std::optional<StringRef> Name =
+                StripTemplateParameters(AttrInfo.Name->getKey())) {
+          StringEntry *NameWithoutTemplateParams =
+              GlobalData.getStringPool().insert(*Name).first;
+
+          saveNameRecord(NameWithoutTemplateParams, OutDIE,
+                         InputDieEntry->getTag(), true);
+        }
+      }
+
+      if (AttrInfo.Name)
+        saveObjC(InputDieEntry, OutDIE, AttrInfo);
+    }
+    break;
+  }
+}
+
+void AcceleratorRecordsSaver::saveObjC(const DWARFDebugInfoEntry *InputDieEntry,
+                                       DIE *OutDIE, AttributesInfo &AttrInfo) {
+  std::optional<ObjCSelectorNames> Names =
+      getObjCNamesIfSelector(AttrInfo.Name->getKey());
+  if (!Names)
+    return;
+
+  StringEntry *Selector =
+      GlobalData.getStringPool().insert(Names->Selector).first;
+  saveNameRecord(Selector, OutDIE, InputDieEntry->getTag(), true);
+  StringEntry *ClassName =
+      GlobalData.getStringPool().insert(Names->ClassName).first;
+  saveObjCNameRecord(ClassName, OutDIE, InputDieEntry->getTag());
+  if (Names->ClassNameNoCategory) {
+    StringEntry *ClassNameNoCategory =
+        GlobalData.getStringPool().insert(*Names->ClassNameNoCategory).first;
+    saveObjCNameRecord(ClassNameNoCategory, OutDIE, InputDieEntry->getTag());
+  }
+  if (Names->MethodNameNoCategory) {
+    StringEntry *MethodNameNoCategory =
+        GlobalData.getStringPool().insert(*Names->MethodNameNoCategory).first;
+    saveNameRecord(MethodNameNoCategory, OutDIE, InputDieEntry->getTag(), true);
+  }
+}
+
+void AcceleratorRecordsSaver::saveNameRecord(StringEntry *Name, DIE *OutDIE,
+                                             dwarf::Tag Tag,
+                                             bool AvoidForPubSections) {
+  DwarfUnit::AccelInfo Info;
+
+  Info.Type = DwarfUnit::AccelType::Name;
+  Info.String = Name;
+  Info.OutOffset = OutDIE->getOffset();
+  Info.Tag = Tag;
+  Info.AvoidForPubSections = AvoidForPubSections;
+
+  OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
+}
+void AcceleratorRecordsSaver::saveNamespaceRecord(StringEntry *Name,
+                                                  DIE *OutDIE, dwarf::Tag Tag,
+                                                  TypeEntry *TypeEntry) {
+  if (OutUnit.isCompileUnit()) {
+    assert(TypeEntry == nullptr);
+    DwarfUnit::AccelInfo Info;
+
+    Info.Type = DwarfUnit::AccelType::Namespace;
+    Info.String = Name;
+    Info.OutOffset = OutDIE->getOffset();
+    Info.Tag = Tag;
+
+    OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
+    return;
+  }
+
+  assert(TypeEntry != nullptr);
+  TypeUnit::TypeUnitAccelInfo Info;
+  Info.Type = DwarfUnit::AccelType::Namespace;
+  Info.String = Name;
+  Info.OutOffset = 0xbaddef;
+  Info.Tag = Tag;
+  Info.OutDIE = OutDIE;
+  Info.TypeEntryBodyPtr = TypeEntry->getValue().load();
+
+  OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
+}
+
+void AcceleratorRecordsSaver::saveObjCNameRecord(StringEntry *Name, DIE *OutDIE,
+                                                 dwarf::Tag Tag) {
+  DwarfUnit::AccelInfo Info;
+
+  Info.Type = DwarfUnit::AccelType::ObjC;
+  Info.String = Name;
+  Info.OutOffset = OutDIE->getOffset();
+  Info.Tag = Tag;
+  Info.AvoidForPubSections = true;
+
+  OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
+}
+
+void AcceleratorRecordsSaver::saveTypeRecord(StringEntry *Name, DIE *OutDIE,
+                                             dwarf::Tag Tag,
+                                             uint32_t QualifiedNameHash,
+                                             bool ObjcClassImplementation,
+                                             TypeEntry *TypeEntry) {
+  if (OutUnit.isCompileUnit()) {
+    assert(TypeEntry == nullptr);
+    DwarfUnit::AccelInfo Info;
+
+    Info.Type = DwarfUnit::AccelType::Type;
+    Info.String = Name;
+    Info.OutOffset = OutDIE->getOffset();
+    Info.Tag = Tag;
+    Info.QualifiedNameHash = QualifiedNameHash;
+    Info.ObjcClassImplementation = ObjcClassImplementation;
+
+    OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
+    return;
+  }
+
+  assert(TypeEntry != nullptr);
+  TypeUnit::TypeUnitAccelInfo Info;
+
+  Info.Type = DwarfUnit::AccelType::Type;
+  Info.String = Name;
+  Info.OutOffset = 0xbaddef;
+  Info.Tag = Tag;
+  Info.QualifiedNameHash = QualifiedNameHash;
+  Info.ObjcClassImplementation = ObjcClassImplementation;
+  Info.OutDIE = OutDIE;
+  Info.TypeEntryBodyPtr = TypeEntry->getValue().load();
+  OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
+}
+
+} // end of namespace dwarflinker_parallel
+} // namespace llvm
diff --git a/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h
new file mode 100644
index 000000000000000..5e7f4d0c3166fd1
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h
@@ -0,0 +1,70 @@
+//===- AcceleratorRecordsSaver.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H
+#define LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H
+
+#include "DIEAttributeCloner.h"
+#include "DWARFLinkerCompileUnit.h"
+#include "DWARFLinkerGlobalData.h"
+#include "DWARFLinkerTypeUnit.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+/// This class helps to store information for accelerator entries.
+/// It prepares accelerator info for the certain DIE and store it inside
+/// OutUnit.
+class AcceleratorRecordsSaver {
+public:
+  AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit,
+                          CompileUnit *OutUnit)
+      : AcceleratorRecordsSaver(GlobalData, InUnit,
+                                CompileUnit::OutputUnitVariantPtr(OutUnit)) {}
+
+  AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit,
+                          TypeUnit *OutUnit)
+      : AcceleratorRecordsSaver(GlobalData, InUnit,
+                                CompileUnit::OutputUnitVariantPtr(OutUnit)) {}
+
+  /// Save accelerator info for the specified \p OutDIE inside OutUnit.
+  /// Side effects: set attributes in \p AttrInfo.
+  void save(const DWARFDebugInfoEntry *InputDieEntry, DIE *OutDIE,
+            AttributesInfo &AttrInfo, TypeEntry *TypeEntry);
+
+protected:
+  AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit,
+                          CompileUnit::OutputUnitVariantPtr OutUnit)
+      : GlobalData(GlobalData), InUnit(InUnit), OutUnit(OutUnit) {}
+
+  void saveObjC(const DWARFDebugInfoEntry *InputDieEntry, DIE *OutDIE,
+                AttributesInfo &AttrInfo);
+
+  void saveNameRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag,
+                      bool AvoidForPubSections);
+  void saveNamespaceRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag,
+                           TypeEntry *TypeEntry);
+  void saveObjCNameRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag);
+  void saveTypeRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag,
+                      uint32_t QualifiedNameHash, bool ObjcClassImplementation,
+                      TypeEntry *TypeEntry);
+
+  /// Global linking data.
+  LinkingGlobalData &GlobalData;
+
+  /// Comiple unit corresponding to input DWARF.
+  CompileUnit &InUnit;
+
+  /// Compile unit or Artificial type unit corresponding to the output DWARF.
+  CompileUnit::OutputUnitVariantPtr OutUnit;
+};
+
+} // end of namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H
diff --git a/llvm/lib/DWARFLinkerParallel/ArrayList.h b/llvm/lib/DWARFLinkerParallel/ArrayList.h
index 58d550982c8dfc0..def83f91bc6f319 100644
--- a/llvm/lib/DWARFLinkerParallel/ArrayList.h
+++ b/llvm/lib/DWARFLinkerParallel/ArrayList.h
@@ -21,6 +21,9 @@ namespace dwarflinker_parallel {
 /// Method add() can be called asynchronously.
 template <typename T, size_t ItemsGroupSize = 512> class ArrayList {
 public:
+  ArrayList(parallel::PerThreadBumpPtrAllocator *Allocator)
+      : Allocator(Allocator) {}
+
   /// Add specified \p Item to the list.
   T &add(const T &Item) {
     assert(Allocator);
@@ -73,8 +76,27 @@ template <typename T, size_t ItemsGroupSize = 512> class ArrayList {
     LastGroup = nullptr;
   }
 
-  void setAllocator(parallel::PerThreadBumpPtrAllocator *Allocator) {
-    this->Allocator = Allocator;
+  void sort(function_ref<bool(const T &LHS, const T &RHS)> Comparator) {
+    SmallVector<T> SortedItems;
+    forEach([&](T &Item) { SortedItems.push_back(Item); });
+
+    if (SortedItems.size()) {
+      std::sort(SortedItems.begin(), SortedItems.end(), Comparator);
+
+      size_t SortedItemIdx = 0;
+      forEach([&](T &Item) { Item = SortedItems[SortedItemIdx++]; });
+      assert(SortedItemIdx == SortedItems.size());
+    }
+  }
+
+  size_t size() {
+    size_t Result = 0;
+
+    for (ItemsGroup *CurGroup = GroupsHead; CurGroup != nullptr;
+         CurGroup = CurGroup->Next)
+      Result += CurGroup->getItemsCount();
+
+    return Result;
   }
 
 protected:
diff --git a/llvm/lib/DWARFLinkerParallel/CMakeLists.txt b/llvm/lib/DWARFLinkerParallel/CMakeLists.txt
index d321ecf8d5ce847..b0f0b3910e586ab 100644
--- a/llvm/lib/DWARFLinkerParallel/CMakeLists.txt
+++ b/llvm/lib/DWARFLinkerParallel/CMakeLists.txt
@@ -1,14 +1,17 @@
 add_llvm_component_library(LLVMDWARFLinkerParallel
+  AcceleratorRecordsSaver.cpp
   DependencyTracker.cpp
   DIEAttributeCloner.cpp
   DWARFEmitterImpl.cpp
   DWARFFile.cpp
   DWARFLinker.cpp
   DWARFLinkerCompileUnit.cpp
+  DWARFLinkerTypeUnit.cpp
   DWARFLinkerImpl.cpp
   DWARFLinkerUnit.cpp
   OutputSections.cpp
   StringPool.cpp
+  SyntheticTypeNameBuilder.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/DWARFLinkerParallel
diff --git a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp
index d05fd8d61b85743..81fc57f7cabbb79 100644
--- a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp
@@ -13,18 +13,16 @@ namespace llvm {
 namespace dwarflinker_parallel {
 
 void DIEAttributeCloner::clone() {
-  DWARFUnit &U = CU.getOrigUnit();
-
   // Extract and clone every attribute.
-  DWARFDataExtractor Data = U.getDebugInfoExtractor();
+  DWARFDataExtractor Data = InUnit.getOrigUnit().getDebugInfoExtractor();
 
   uint64_t Offset = InputDieEntry->getOffset();
   // Point to the next DIE (generally there is always at least a NULL
   // entry after the current one). If this is a lone
   // DW_TAG_compile_unit without any children, point to the next unit.
-  uint64_t NextOffset = (InputDIEIdx + 1 < U.getNumDIEs())
-                            ? U.getDIEAtIndex(InputDIEIdx + 1).getOffset()
-                            : U.getNextUnitOffset();
+  uint64_t NextOffset = (InputDIEIdx + 1 < InUnit.getOrigUnit().getNumDIEs())
+                            ? InUnit.getDIEAtIndex(InputDIEIdx + 1).getOffset()
+                            : InUnit.getOrigUnit().getNextUnitOffset();
 
   // We could copy the data only if we need to apply a relocation to it. After
   // testing, it seems there is no performance downside to doing the copy
@@ -34,8 +32,8 @@ void DIEAttributeCloner::clone() {
       DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());
 
   // Modify the copy with relocated addresses.
-  CU.getContaingFile().Addresses->applyValidRelocs(DIECopy, Offset,
-                                                   Data.isLittleEndian());
+  InUnit.getContaingFile().Addresses->applyValidRelocs(DIECopy, Offset,
+                                                       Data.isLittleEndian());
 
   // Reset the Offset to 0 as we will be working on the local copy of
   // the data.
@@ -45,17 +43,18 @@ void DIEAttributeCloner::clone() {
   Offset += getULEB128Size(Abbrev->getCode());
 
   // Set current output offset.
-  AttrOutOffset = OutDIE->getOffset();
+  AttrOutOffset = OutUnit.isCompileUnit() ? OutDIE->getOffset() : 0;
   for (const auto &AttrSpec : Abbrev->attributes()) {
     // Check whether current attribute should be skipped.
     if (shouldSkipAttribute(AttrSpec)) {
       DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
-                                U.getFormParams());
+                                InUnit.getFormParams());
       continue;
     }
 
     DWARFFormValue Val = AttrSpec.getFormValue();
-    Val.extractValue(Data, &Offset, U.getFormParams(), &U);
+    Val.extractValue(Data, &Offset, InUnit.getFormParams(),
+                     &InUnit.getOrigUnit());
 
     // Clone current attribute.
     switch (AttrSpec.Form) {
@@ -107,10 +106,10 @@ void DIEAttributeCloner::clone() {
       AttrOutOffset += cloneAddressAttr(Val, AttrSpec);
       break;
     default:
-      CU.warn("unsupported attribute form " +
-                  dwarf::FormEncodingString(AttrSpec.Form) +
-                  " in DieAttributeCloner::clone(). Dropping.",
-              InputDieEntry);
+      InUnit.warn("unsupported attribute form " +
+                      dwarf::FormEncodingString(AttrSpec.Form) +
+                      " in DieAttributeCloner::clone(). Dropping.",
+                  InputDieEntry);
     }
   }
 
@@ -118,19 +117,20 @@ void DIEAttributeCloner::clone() {
   // Check if original compile unit already has DW_AT_str_offsets_base
   // attribute.
   if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit &&
-      CU.getVersion() >= 5 && !AttrInfo.HasStringOffsetBaseAttr) {
+      InUnit.getVersion() >= 5 && !AttrInfo.HasStringOffsetBaseAttr) {
     DebugInfoOutput...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/68721


More information about the llvm-commits mailing list