[llvm] 4f902d2 - [llvm-dwarfdump] Make --verify for .debug_names multithreaded. (#127281)

via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 3 14:02:31 PDT 2025


Author: Alexander Yermolovich
Date: 2025-04-03T14:02:27-07:00
New Revision: 4f902d2425e59bd182390702de23d5cec3467fc2

URL: https://github.com/llvm/llvm-project/commit/4f902d2425e59bd182390702de23d5cec3467fc2
DIFF: https://github.com/llvm/llvm-project/commit/4f902d2425e59bd182390702de23d5cec3467fc2.diff

LOG: [llvm-dwarfdump] Make --verify for .debug_names multithreaded. (#127281)

This PR makes verification of .debug_names acceleration table
multithreaded. In local testing it improves verification of clang
.debug_names from four minutes to under a minute.
This PR relies on a current mechanism of extracting DIEs into a vector. 
Future improvements can include creating API to extract one DIE at a
time, or grouping Entires into buckets by CUs and extracting before
parallel step.

Single Thread
4:12.37 real,   246.88 user,    3.54 sys,       0 amem,10232004 mmem
Multi Thread
0:49.40 real,   612.84 user,    515.73 sys,     0 amem, 11226292 mmem

Added: 
    

Modified: 
    llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
    llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
    llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
    llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-completeness.s
    llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
index 9d7ac12cefdc8..cef5fa1f2ee53 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
@@ -770,6 +770,7 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
     }
 
   public:
+    using size_type = size_t;
     using iterator_category = std::input_iterator_tag;
     using value_type = NameTableEntry;
     using 
diff erence_type = uint32_t;
@@ -793,6 +794,16 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
       next();
       return I;
     }
+    /// Accesses entry at specific index (1-based internally, 0-based
+    /// externally). For example how this is used in parallelForEach.
+    reference operator[](size_type idx) {
+      return CurrentIndex->getNameTableEntry(idx + 1);
+    }
+    /// Computes 
diff erence between iterators (used in parallelForEach).
+    
diff erence_type operator-(const NameIterator &other) const {
+      assert(CurrentIndex == other.CurrentIndex);
+      return this->CurrentName - other.CurrentName;
+    }
 
     friend bool operator==(const NameIterator &A, const NameIterator &B) {
       return A.CurrentIndex == B.CurrentIndex && A.CurrentName == B.CurrentName;

diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
index 595215ba35dd5..717f9cedc4ee3 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H
 #define LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H
 
+#include "llvm/ADT/StringMap.h"
 #include "llvm/DebugInfo/DIContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
 #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
@@ -16,6 +17,7 @@
 #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
 #include <cstdint>
 #include <map>
+#include <mutex>
 #include <set>
 
 namespace llvm {
@@ -37,7 +39,9 @@ struct AggregationData {
 
 class OutputCategoryAggregator {
 private:
+  std::mutex WriteMutex;
   std::map<std::string, AggregationData, std::less<>> Aggregation;
+  uint64_t NumErrors = 0;
   bool IncludeDetail;
 
 public:
@@ -52,6 +56,8 @@ class OutputCategoryAggregator {
   void EnumerateDetailedResultsFor(
       StringRef category,
       std::function<void(StringRef, unsigned)> handleCounts);
+  /// Return the number of errors that have been reported.
+  uint64_t GetNumErrors() const { return NumErrors; }
 };
 
 /// A class that verifies DWARF debug information given a DWARF Context.
@@ -114,6 +120,7 @@ class DWARFVerifier {
   bool IsObjectFile;
   bool IsMachOObject;
   using ReferenceMap = std::map<uint64_t, std::set<uint64_t>>;
+  std::mutex AccessMutex;
 
   raw_ostream &error() const;
   raw_ostream &warn() const;
@@ -274,21 +281,23 @@ class DWARFVerifier {
   /// \param SectionName the name of the table we're verifying
   ///
   /// \returns The number of errors occurred during verification
-  unsigned verifyAppleAccelTable(const DWARFSection *AccelSection,
-                                 DataExtractor *StrData,
-                                 const char *SectionName);
-
-  unsigned verifyDebugNamesCULists(const DWARFDebugNames &AccelTable);
-  unsigned verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
-                                  const DataExtractor &StrData);
-  unsigned verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI);
-  unsigned verifyNameIndexAttribute(const DWARFDebugNames::NameIndex &NI,
-                                    const DWARFDebugNames::Abbrev &Abbr,
-                                    DWARFDebugNames::AttributeEncoding AttrEnc);
-  unsigned verifyNameIndexEntries(const DWARFDebugNames::NameIndex &NI,
-                                  const DWARFDebugNames::NameTableEntry &NTE);
-  unsigned verifyNameIndexCompleteness(const DWARFDie &Die,
-                                       const DWARFDebugNames::NameIndex &NI);
+  void verifyAppleAccelTable(const DWARFSection *AccelSection,
+                             DataExtractor *StrData, const char *SectionName);
+
+  void verifyDebugNamesCULists(const DWARFDebugNames &AccelTable);
+  void verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
+                              const DataExtractor &StrData);
+  void verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI);
+  void verifyNameIndexAttribute(const DWARFDebugNames::NameIndex &NI,
+                                const DWARFDebugNames::Abbrev &Abbr,
+                                DWARFDebugNames::AttributeEncoding AttrEnc);
+  void verifyNameIndexEntries(
+      const DWARFDebugNames::NameIndex &NI,
+      const DWARFDebugNames::NameTableEntry &NTE,
+      const DenseMap<uint64_t, DWARFUnit *> &CUOffsetsToDUMap);
+  void verifyNameIndexCompleteness(
+      const DWARFDie &Die, const DWARFDebugNames::NameIndex &NI,
+      const StringMap<DenseSet<uint64_t>> &NamesToDieOffsets);
 
   /// Verify that the DWARF v5 accelerator table is valid.
   ///
@@ -307,8 +316,8 @@ class DWARFVerifier {
   /// \param StrData string section
   ///
   /// \returns The number of errors occurred during verification
-  unsigned verifyDebugNames(const DWARFSection &AccelSection,
-                            const DataExtractor &StrData);
+  void verifyDebugNames(const DWARFSection &AccelSection,
+                        const DataExtractor &StrData);
 
 public:
   DWARFVerifier(raw_ostream &S, DWARFContext &D,

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
index 69027500ab51d..690a2e5fee9de 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -33,6 +33,7 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/JSON.h"
+#include "llvm/Support/Parallel.h"
 #include "llvm/Support/WithColor.h"
 #include "llvm/Support/raw_ostream.h"
 #include <map>
@@ -1106,10 +1107,9 @@ bool DWARFVerifier::handleDebugLine() {
   return NumDebugLineErrors == 0;
 }
 
-unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
-                                              DataExtractor *StrData,
-                                              const char *SectionName) {
-  unsigned NumErrors = 0;
+void DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
+                                          DataExtractor *StrData,
+                                          const char *SectionName) {
   DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection,
                                       DCtx.isLittleEndian(), 0);
   AppleAcceleratorTable AccelTable(AccelSectionData, *StrData);
@@ -1121,7 +1121,7 @@ unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
     ErrorCategory.Report("Section is too small to fit a section header", [&]() {
       error() << "Section is too small to fit a section header.\n";
     });
-    return 1;
+    return;
   }
 
   // Verify that the section is not too short.
@@ -1129,7 +1129,7 @@ unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
     std::string Msg = toString(std::move(E));
     ErrorCategory.Report("Section is too small to fit a section header",
                          [&]() { error() << Msg << '\n'; });
-    return 1;
+    return;
   }
 
   // Verify that all buckets have a valid hash index or are empty.
@@ -1147,7 +1147,6 @@ unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
         error() << format("Bucket[%d] has invalid hash index: %u.\n", BucketIdx,
                           HashIdx);
       });
-      ++NumErrors;
     }
   }
   uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
@@ -1155,13 +1154,13 @@ unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
     ErrorCategory.Report("No atoms", [&]() {
       error() << "No atoms: failed to read HashData.\n";
     });
-    return 1;
+    return;
   }
   if (!AccelTable.validateForms()) {
     ErrorCategory.Report("Unsupported form", [&]() {
       error() << "Unsupported form: failed to read HashData.\n";
     });
-    return 1;
+    return;
   }
 
   for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
@@ -1176,7 +1175,6 @@ unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
                           "0x%08" PRIx64 ".\n",
                           HashIdx, HashDataOffset);
       });
-      ++NumErrors;
     }
 
     uint64_t StrpOffset;
@@ -1207,8 +1205,6 @@ unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
                 SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,
                 HashDataIdx, Offset, Name);
           });
-
-          ++NumErrors;
           continue;
         }
         if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) {
@@ -1218,74 +1214,70 @@ unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
                     << dwarf::TagString(Die.getTag()) << " of DIE["
                     << HashDataIdx << "].\n";
           });
-          ++NumErrors;
         }
       }
-      ++StringCount;
     }
   }
-  return NumErrors;
 }
 
-unsigned
-DWARFVerifier::verifyDebugNamesCULists(const DWARFDebugNames &AccelTable) {
+void DWARFVerifier::verifyDebugNamesCULists(const DWARFDebugNames &AccelTable) {
   // A map from CU offset to the (first) Name Index offset which claims to index
   // this CU.
   DenseMap<uint64_t, uint64_t> CUMap;
-  const uint64_t NotIndexed = std::numeric_limits<uint64_t>::max();
-
   CUMap.reserve(DCtx.getNumCompileUnits());
+
+  DenseSet<uint64_t> CUOffsets;
   for (const auto &CU : DCtx.compile_units())
-    CUMap[CU->getOffset()] = NotIndexed;
+    CUOffsets.insert(CU->getOffset());
 
-  unsigned NumErrors = 0;
-  for (const DWARFDebugNames::NameIndex &NI : AccelTable) {
+  parallelForEach(AccelTable, [&](const DWARFDebugNames::NameIndex &NI) {
     if (NI.getCUCount() == 0) {
       ErrorCategory.Report("Name Index doesn't index any CU", [&]() {
         error() << formatv("Name Index @ {0:x} does not index any CU\n",
                            NI.getUnitOffset());
       });
-      ++NumErrors;
-      continue;
+      return;
     }
     for (uint32_t CU = 0, End = NI.getCUCount(); CU < End; ++CU) {
       uint64_t Offset = NI.getCUOffset(CU);
-      auto Iter = CUMap.find(Offset);
-
-      if (Iter == CUMap.end()) {
+      if (!CUOffsets.count(Offset)) {
         ErrorCategory.Report("Name Index references non-existing CU", [&]() {
           error() << formatv(
               "Name Index @ {0:x} references a non-existing CU @ {1:x}\n",
               NI.getUnitOffset(), Offset);
         });
-        ++NumErrors;
         continue;
       }
-
-      if (Iter->second != NotIndexed) {
+      uint64_t DuplicateCUOffset = 0;
+      {
+        std::lock_guard<std::mutex> Lock(AccessMutex);
+        auto Iter = CUMap.find(Offset);
+        if (Iter != CUMap.end())
+          DuplicateCUOffset = Iter->second;
+        else
+          CUMap[Offset] = NI.getUnitOffset();
+      }
+      if (DuplicateCUOffset) {
         ErrorCategory.Report("Duplicate Name Index", [&]() {
           error() << formatv(
               "Name Index @ {0:x} references a CU @ {1:x}, but "
               "this CU is already indexed by Name Index @ {2:x}\n",
-              NI.getUnitOffset(), Offset, Iter->second);
+              NI.getUnitOffset(), Offset, DuplicateCUOffset);
         });
         continue;
       }
-      Iter->second = NI.getUnitOffset();
     }
-  }
+  });
 
-  for (const auto &KV : CUMap) {
-    if (KV.second == NotIndexed)
-      warn() << formatv("CU @ {0:x} not covered by any Name Index\n", KV.first);
+  for (const auto &CU : DCtx.compile_units()) {
+    if (CUMap.count(CU->getOffset()) == 0)
+      warn() << formatv("CU @ {0:x} not covered by any Name Index\n",
+                        CU->getOffset());
   }
-
-  return NumErrors;
 }
 
-unsigned
-DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
-                                      const DataExtractor &StrData) {
+void DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
+                                           const DataExtractor &StrData) {
   struct BucketInfo {
     uint32_t Bucket;
     uint32_t Index;
@@ -1295,17 +1287,17 @@ DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
     bool operator<(const BucketInfo &RHS) const { return Index < RHS.Index; }
   };
 
-  uint32_t NumErrors = 0;
   if (NI.getBucketCount() == 0) {
     warn() << formatv("Name Index @ {0:x} does not contain a hash table.\n",
                       NI.getUnitOffset());
-    return NumErrors;
+    return;
   }
 
   // Build up a list of (Bucket, Index) pairs. We use this later to verify that
   // each Name is reachable from the appropriate bucket.
   std::vector<BucketInfo> BucketStarts;
   BucketStarts.reserve(NI.getBucketCount() + 1);
+  const uint64_t OrigNumberOfErrors = ErrorCategory.GetNumErrors();
   for (uint32_t Bucket = 0, End = NI.getBucketCount(); Bucket < End; ++Bucket) {
     uint32_t Index = NI.getBucketArrayEntry(Bucket);
     if (Index > NI.getNameCount()) {
@@ -1315,7 +1307,6 @@ DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
                            Bucket, NI.getUnitOffset(), Index,
                            NI.getNameCount());
       });
-      ++NumErrors;
       continue;
     }
     if (Index > 0)
@@ -1325,8 +1316,8 @@ DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
   // If there were any buckets with invalid values, skip further checks as they
   // will likely produce many errors which will only confuse the actual root
   // problem.
-  if (NumErrors > 0)
-    return NumErrors;
+  if (OrigNumberOfErrors != ErrorCategory.GetNumErrors())
+    return;
 
   // Sort the list in the order of increasing "Index" entries.
   array_pod_sort(BucketStarts.begin(), BucketStarts.end());
@@ -1352,7 +1343,6 @@ DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
                            "are not covered by the hash table.\n",
                            NI.getUnitOffset(), NextUncovered, B.Index - 1);
       });
-      ++NumErrors;
     }
     uint32_t Idx = B.Index;
 
@@ -1374,7 +1364,6 @@ DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
             NI.getUnitOffset(), B.Bucket, FirstHash,
             FirstHash % NI.getBucketCount());
       });
-      ++NumErrors;
     }
 
     // This find the end of this bucket and also verifies that all the hashes in
@@ -1395,17 +1384,15 @@ DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
                   "the Name Index hash is {4:x}\n",
                   NI.getUnitOffset(), Str, Idx, caseFoldingDjbHash(Str), Hash);
             });
-        ++NumErrors;
       }
-
       ++Idx;
     }
     NextUncovered = std::max(NextUncovered, Idx);
   }
-  return NumErrors;
+  return;
 }
 
-unsigned DWARFVerifier::verifyNameIndexAttribute(
+void DWARFVerifier::verifyNameIndexAttribute(
     const DWARFDebugNames::NameIndex &NI, const DWARFDebugNames::Abbrev &Abbr,
     DWARFDebugNames::AttributeEncoding AttrEnc) {
   StringRef FormName = dwarf::FormEncodingString(AttrEnc.Form);
@@ -1416,7 +1403,7 @@ unsigned DWARFVerifier::verifyNameIndexAttribute(
                          NI.getUnitOffset(), Abbr.Code, AttrEnc.Index,
                          AttrEnc.Form);
     });
-    return 1;
+    return;
   }
 
   if (AttrEnc.Index == DW_IDX_type_hash) {
@@ -1427,9 +1414,9 @@ unsigned DWARFVerifier::verifyNameIndexAttribute(
             "uses an unexpected form {2} (should be {3}).\n",
             NI.getUnitOffset(), Abbr.Code, AttrEnc.Form, dwarf::DW_FORM_data8);
       });
-      return 1;
+      return;
     }
-    return 0;
+    return;
   }
 
   if (AttrEnc.Index == dwarf::DW_IDX_parent) {
@@ -1443,9 +1430,9 @@ unsigned DWARFVerifier::verifyNameIndexAttribute(
             "DW_FORM_ref4 or DW_FORM_flag_present).\n",
             NI.getUnitOffset(), Abbr.Code, AttrEnc.Form);
       });
-      return 1;
+      return;
     }
-    return 0;
+    return;
   }
 
   // A list of known index attributes and their expected form classes.
@@ -1470,7 +1457,7 @@ unsigned DWARFVerifier::verifyNameIndexAttribute(
     warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains an "
                       "unknown index attribute: {2}.\n",
                       NI.getUnitOffset(), Abbr.Code, AttrEnc.Index);
-    return 0;
+    return;
   }
 
   if (!DWARFFormValue(AttrEnc.Form).isFormClass(Iter->Class)) {
@@ -1480,14 +1467,13 @@ unsigned DWARFVerifier::verifyNameIndexAttribute(
                          NI.getUnitOffset(), Abbr.Code, AttrEnc.Index,
                          AttrEnc.Form, Iter->ClassName);
     });
-    return 1;
+    return;
   }
-  return 0;
+  return;
 }
 
-unsigned
-DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) {
-  unsigned NumErrors = 0;
+void DWARFVerifier::verifyNameIndexAbbrevs(
+    const DWARFDebugNames::NameIndex &NI) {
   for (const auto &Abbrev : NI.getAbbrevs()) {
     StringRef TagName = dwarf::TagString(Abbrev.Tag);
     if (TagName.empty()) {
@@ -1505,10 +1491,9 @@ DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) {
                   "multiple {2} attributes.\n",
                   NI.getUnitOffset(), Abbrev.Code, AttrEnc.Index);
             });
-        ++NumErrors;
         continue;
       }
-      NumErrors += verifyNameIndexAttribute(NI, Abbrev, AttrEnc);
+      verifyNameIndexAttribute(NI, Abbrev, AttrEnc);
     }
 
     if (NI.getCUCount() > 1 && !Attributes.count(dwarf::DW_IDX_compile_unit) &&
@@ -1519,7 +1504,6 @@ DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) {
                            "or DW_IDX_type_unit attribute.\n",
                            NI.getUnitOffset(), Abbrev.Code);
       });
-      ++NumErrors;
     }
     if (!Attributes.count(dwarf::DW_IDX_die_offset)) {
       ErrorCategory.Report("Abbreviate in NameIndex missing attribute", [&]() {
@@ -1527,12 +1511,12 @@ DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) {
             "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n",
             NI.getUnitOffset(), Abbrev.Code, dwarf::DW_IDX_die_offset);
       });
-      ++NumErrors;
     }
   }
-  return NumErrors;
 }
 
+/// Constructs a full name for a DIE. Potentially it does recursive lookup on
+/// DIEs. This can lead to extraction of DIEs in a 
diff erent CU or TU.
 static SmallVector<std::string, 3> getNames(const DWARFDie &DIE,
                                             bool IncludeStrippedTemplateNames,
                                             bool IncludeObjCNames = true,
@@ -1571,9 +1555,10 @@ static SmallVector<std::string, 3> getNames(const DWARFDie &DIE,
   return Result;
 }
 
-unsigned DWARFVerifier::verifyNameIndexEntries(
+void DWARFVerifier::verifyNameIndexEntries(
     const DWARFDebugNames::NameIndex &NI,
-    const DWARFDebugNames::NameTableEntry &NTE) {
+    const DWARFDebugNames::NameTableEntry &NTE,
+    const DenseMap<uint64_t, DWARFUnit *> &CUOffsetsToDUMap) {
   const char *CStr = NTE.getString();
   if (!CStr) {
     ErrorCategory.Report("Unable to get string associated with name", [&]() {
@@ -1581,11 +1566,9 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
                          "with name {1}.\n",
                          NI.getUnitOffset(), NTE.getIndex());
     });
-    return 1;
+    return;
   }
   StringRef Str(CStr);
-
-  unsigned NumErrors = 0;
   unsigned NumEntries = 0;
   uint64_t EntryID = NTE.getEntryOffset();
   uint64_t NextEntryID = EntryID;
@@ -1601,7 +1584,6 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
                            "invalid CU index ({2}).\n",
                            NI.getUnitOffset(), EntryID, *CUIndex);
       });
-      ++NumErrors;
       continue;
     }
     const uint32_t NumLocalTUs = NI.getLocalTUCount();
@@ -1612,7 +1594,6 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
                            "invalid TU index ({2}).\n",
                            NI.getUnitOffset(), EntryID, *TUIndex);
       });
-      ++NumErrors;
       continue;
     }
     std::optional<uint64_t> UnitOffset;
@@ -1640,7 +1621,6 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
                     "foreign TU index ({2}) with no CU index.\n",
                     NI.getUnitOffset(), EntryID, *TUIndex);
               });
-          ++NumErrors;
           continue;
         }
       } else {
@@ -1668,7 +1648,6 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
                                "invalid CU or TU offset {2:x}.\n",
                                NI.getUnitOffset(), EntryID, *UnitOffset);
           });
-      ++NumErrors;
       continue;
     }
     // This function will try to get the non skeleton unit DIE, but if it is
@@ -1682,9 +1661,15 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
     // call to properly deal with it. It isn't clear that getNonSkeletonUnitDIE
     // will return the unit DIE of DU if we aren't able to get the .dwo file,
     // but that is what the function currently does.
+    DWARFUnit *NonSkeletonUnit = nullptr;
+    if (DU->getDWOId()) {
+      auto Iter = CUOffsetsToDUMap.find(DU->getOffset());
+      NonSkeletonUnit = Iter->second;
+    } else {
+      NonSkeletonUnit = DU;
+    }
     DWARFDie UnitDie = DU->getUnitDIE();
-    DWARFDie NonSkeletonUnitDie = DU->getNonSkeletonUnitDIE();
-    if (DU->getDWOId() && UnitDie == NonSkeletonUnitDie) {
+    if (DU->getDWOId() && !NonSkeletonUnit->isDWOUnit()) {
       ErrorCategory.Report("Unable to get load .dwo file", [&]() {
         error() << formatv(
             "Name Index @ {0:x}: Entry @ {1:x} unable to load "
@@ -1693,10 +1678,9 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
             dwarf::toString(UnitDie.find({DW_AT_dwo_name, DW_AT_GNU_dwo_name})),
             *UnitOffset);
       });
-      ++NumErrors;
       continue;
     }
-    DWARFUnit *NonSkeletonUnit = nullptr;
+
     if (TUIndex && *TUIndex >= NumLocalTUs) {
       // We have a foreign TU index, which either means we have a .dwo file
       // that has one or more type units, or we have a .dwp file with one or
@@ -1707,17 +1691,16 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
       // above, so we know we have the right file.
       const uint32_t ForeignTUIdx = *TUIndex - NumLocalTUs;
       const uint64_t TypeSig = NI.getForeignTUSignature(ForeignTUIdx);
-      llvm::DWARFContext &SkeletonDCtx =
-          NonSkeletonUnitDie.getDwarfUnit()->getContext();
+      llvm::DWARFContext &NonSkeletonDCtx = NonSkeletonUnit->getContext();
       // Now find the type unit from the type signature and then update the
       // NonSkeletonUnitDie to point to the actual type unit in the .dwo/.dwp.
       NonSkeletonUnit =
-          SkeletonDCtx.getTypeUnitForHash(TypeSig, /*IsDWO=*/true);
-      NonSkeletonUnitDie = NonSkeletonUnit->getUnitDIE(true);
+          NonSkeletonDCtx.getTypeUnitForHash(TypeSig, /*IsDWO=*/true);
       // If we have foreign type unit in a DWP file, then we need to ignore
       // any entries from type units that don't match the one that made it into
       // the .dwp file.
-      if (SkeletonDCtx.isDWP()) {
+      if (NonSkeletonDCtx.isDWP()) {
+        DWARFDie NonSkeletonUnitDie = NonSkeletonUnit->getUnitDIE(true);
         StringRef DUDwoName = dwarf::toStringRef(
             UnitDie.find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
         StringRef TUDwoName = dwarf::toStringRef(
@@ -1725,8 +1708,6 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
         if (DUDwoName != TUDwoName)
           continue; // Skip this TU, it isn't the one in the .dwp file.
       }
-    } else {
-      NonSkeletonUnit = NonSkeletonUnitDie.getDwarfUnit();
     }
     uint64_t DIEOffset =
         NonSkeletonUnit->getOffset() + *EntryOr->getDIEUnitOffset();
@@ -1743,14 +1724,12 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
       continue;
     }
     DWARFDie DIE = NonSkeletonUnit->getDIEForOffset(DIEOffset);
-
     if (!DIE) {
       ErrorCategory.Report("NameIndex references nonexistent DIE", [&]() {
         error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a "
                            "non-existing DIE @ {2:x}.\n",
                            NI.getUnitOffset(), EntryID, DIEOffset);
       });
-      ++NumErrors;
       continue;
     }
     // Only compare the DIE we found's DWARFUnit offset if the DIE lives in
@@ -1766,7 +1745,6 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
             NI.getUnitOffset(), EntryID, DIEOffset, *UnitOffset,
             DIE.getDwarfUnit()->getOffset());
       });
-      ++NumErrors;
     }
     if (DIE.getTag() != EntryOr->tag()) {
       ErrorCategory.Report("Name Index contains mismatched Tag of DIE", [&]() {
@@ -1776,7 +1754,6 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
             NI.getUnitOffset(), EntryID, DIEOffset, EntryOr->tag(),
             DIE.getTag());
       });
-      ++NumErrors;
     }
 
     // We allow an extra name for functions: their name without any template
@@ -1792,7 +1769,6 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
                            NI.getUnitOffset(), EntryID, DIEOffset, Str,
                            make_range(EntryNames.begin(), EntryNames.end()));
       });
-      ++NumErrors;
     }
   }
   handleAllErrors(
@@ -1806,7 +1782,6 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
                                  "not associated with any entries.\n",
                                  NI.getUnitOffset(), NTE.getIndex(), Str);
             });
-        ++NumErrors;
       },
       [&](const ErrorInfoBase &Info) {
         ErrorCategory.Report("Uncategorized NameIndex error", [&]() {
@@ -1814,9 +1789,7 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
                              NI.getUnitOffset(), NTE.getIndex(), Str,
                              Info.message());
         });
-        ++NumErrors;
       });
-  return NumErrors;
 }
 
 static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) {
@@ -1844,8 +1817,9 @@ static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) {
   return false;
 }
 
-unsigned DWARFVerifier::verifyNameIndexCompleteness(
-    const DWARFDie &Die, const DWARFDebugNames::NameIndex &NI) {
+void DWARFVerifier::verifyNameIndexCompleteness(
+    const DWARFDie &Die, const DWARFDebugNames::NameIndex &NI,
+    const StringMap<DenseSet<uint64_t>> &NamesToDieOffsets) {
 
   // First check, if the Die should be indexed. The code follows the DWARF v5
   // wording as closely as possible.
@@ -1853,7 +1827,7 @@ unsigned DWARFVerifier::verifyNameIndexCompleteness(
   // "All non-defining declarations (that is, debugging information entries
   // with a DW_AT_declaration attribute) are excluded."
   if (Die.find(DW_AT_declaration))
-    return 0;
+    return;
 
   // "DW_TAG_namespace debugging information entries without a DW_AT_name
   // attribute are included with the name “(anonymous namespace)”.
@@ -1871,7 +1845,7 @@ unsigned DWARFVerifier::verifyNameIndexCompleteness(
   auto EntryNames = getNames(Die, IncludeStrippedTemplateNames,
                              IncludeObjCNames, IncludeLinkageName);
   if (EntryNames.empty())
-    return 0;
+    return;
 
   // We deviate from the specification here, which says:
   // "The name index must contain an entry for each debugging information entry
@@ -1882,7 +1856,7 @@ unsigned DWARFVerifier::verifyNameIndexCompleteness(
   // Compile units and modules have names but shouldn't be indexed.
   case DW_TAG_compile_unit:
   case DW_TAG_module:
-    return 0;
+    return;
 
   // Function and template parameters are not globally visible, so we shouldn't
   // index them.
@@ -1891,22 +1865,22 @@ unsigned DWARFVerifier::verifyNameIndexCompleteness(
   case DW_TAG_template_type_parameter:
   case DW_TAG_GNU_template_parameter_pack:
   case DW_TAG_GNU_template_template_param:
-    return 0;
+    return;
 
   // Object members aren't globally visible.
   case DW_TAG_member:
-    return 0;
+    return;
 
   // According to a strict reading of the specification, enumerators should not
   // be indexed (and LLVM currently does not do that). However, this causes
   // problems for the debuggers, so we may need to reconsider this.
   case DW_TAG_enumerator:
-    return 0;
+    return;
 
   // Imported declarations should not be indexed according to the specification
   // and LLVM currently does not do that.
   case DW_TAG_imported_declaration:
-    return 0;
+    return;
 
   // "DW_TAG_subprogram, DW_TAG_inlined_subroutine, and DW_TAG_label debugging
   // information entries without an address attribute (DW_AT_low_pc,
@@ -1917,7 +1891,7 @@ unsigned DWARFVerifier::verifyNameIndexCompleteness(
     if (Die.findRecursively(
             {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc}))
       break;
-    return 0;
+    return;
 
   // "DW_TAG_variable debugging information entries with a DW_AT_location
   // attribute that includes a DW_OP_addr or DW_OP_form_tls_address operator are
@@ -1927,7 +1901,7 @@ unsigned DWARFVerifier::verifyNameIndexCompleteness(
   case DW_TAG_variable:
     if (isVariableIndexable(Die, DCtx))
       break;
-    return 0;
+    return;
 
   default:
     break;
@@ -1935,12 +1909,10 @@ unsigned DWARFVerifier::verifyNameIndexCompleteness(
 
   // Now we know that our Die should be present in the Index. Let's check if
   // that's the case.
-  unsigned NumErrors = 0;
   uint64_t DieUnitOffset = Die.getOffset() - Die.getDwarfUnit()->getOffset();
   for (StringRef Name : EntryNames) {
-    if (none_of(NI.equal_range(Name), [&](const DWARFDebugNames::Entry &E) {
-          return E.getDIEUnitOffset() == DieUnitOffset;
-        })) {
+    auto iter = NamesToDieOffsets.find(Name);
+    if (iter == NamesToDieOffsets.end() || !iter->second.count(DieUnitOffset)) {
       ErrorCategory.Report(
           "Name Index DIE entry missing name",
           llvm::dwarf::TagString(Die.getTag()), [&]() {
@@ -1949,15 +1921,47 @@ unsigned DWARFVerifier::verifyNameIndexCompleteness(
                 "name {3} missing.\n",
                 NI.getUnitOffset(), Die.getOffset(), Die.getTag(), Name);
           });
-      ++NumErrors;
     }
   }
-  return NumErrors;
 }
 
-unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection,
-                                         const DataExtractor &StrData) {
-  unsigned NumErrors = 0;
+/// Extracts all the data for CU/TUs so we can access it in parallel without
+/// locks.
+static void extractCUsTus(DWARFContext &DCtx) {
+  // Abbrev DeclSet is shared beween the units.
+  for (auto &CUTU : DCtx.normal_units()) {
+    CUTU->getUnitDIE();
+    CUTU->getBaseAddress();
+  }
+  parallelForEach(DCtx.normal_units(), [&](const auto &CUTU) {
+    if (Error E = CUTU->tryExtractDIEsIfNeeded(false))
+      DCtx.getRecoverableErrorHandler()(std::move(E));
+  });
+
+  // Invoking getNonSkeletonUnitDIE() sets up all the base pointers for DWO
+  // Units. This is needed for getBaseAddress().
+  for (const auto &CU : DCtx.compile_units()) {
+    if (!CU->getDWOId())
+      continue;
+    DWARFContext &NonSkeletonContext =
+        CU->getNonSkeletonUnitDIE().getDwarfUnit()->getContext();
+    // Iterates over CUs and TUs.
+    for (auto &CUTU : NonSkeletonContext.dwo_units()) {
+      CUTU->getUnitDIE();
+      CUTU->getBaseAddress();
+    }
+    parallelForEach(NonSkeletonContext.dwo_units(), [&](const auto &CUTU) {
+      if (Error E = CUTU->tryExtractDIEsIfNeeded(false))
+        DCtx.getRecoverableErrorHandler()(std::move(E));
+    });
+    // If context is for DWP we only need to extract once.
+    if (NonSkeletonContext.isDWP())
+      break;
+  }
+}
+
+void DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection,
+                                     const DataExtractor &StrData) {
   DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection,
                                       DCtx.isLittleEndian(), 0);
   DWARFDebugNames AccelTable(AccelSectionData, StrData);
@@ -1970,67 +1974,119 @@ unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection,
     std::string Msg = toString(std::move(E));
     ErrorCategory.Report("Accelerator Table Error",
                          [&]() { error() << Msg << '\n'; });
-    return 1;
+    return;
   }
-
-  NumErrors += verifyDebugNamesCULists(AccelTable);
-  for (const auto &NI : AccelTable)
-    NumErrors += verifyNameIndexBuckets(NI, StrData);
+  const uint64_t OriginalNumErrors = ErrorCategory.GetNumErrors();
+  verifyDebugNamesCULists(AccelTable);
   for (const auto &NI : AccelTable)
-    NumErrors += verifyNameIndexAbbrevs(NI);
+    verifyNameIndexBuckets(NI, StrData);
+  parallelForEach(AccelTable, [&](const DWARFDebugNames::NameIndex &NI) {
+    verifyNameIndexAbbrevs(NI);
+  });
 
   // Don't attempt Entry validation if any of the previous checks found errors
-  if (NumErrors > 0)
-    return NumErrors;
-  for (const auto &NI : AccelTable)
-    for (const DWARFDebugNames::NameTableEntry &NTE : NI)
-      NumErrors += verifyNameIndexEntries(NI, NTE);
+  if (OriginalNumErrors != ErrorCategory.GetNumErrors())
+    return;
+  DenseMap<uint64_t, DWARFUnit *> CUOffsetsToDUMap;
+  for (const auto &CU : DCtx.compile_units()) {
+    if (!(CU->getVersion() >= 5 && CU->getDWOId()))
+      continue;
+    CUOffsetsToDUMap[CU->getOffset()] =
+        CU->getNonSkeletonUnitDIE().getDwarfUnit();
+  }
+  extractCUsTus(DCtx);
+  for (const DWARFDebugNames::NameIndex &NI : AccelTable) {
+    parallelForEach(NI, [&](DWARFDebugNames::NameTableEntry NTE) {
+      verifyNameIndexEntries(NI, NTE, CUOffsetsToDUMap);
+    });
+  }
 
-  for (const std::unique_ptr<DWARFUnit> &U : DCtx.info_section_units()) {
-    if (const DWARFDebugNames::NameIndex *NI =
-            AccelTable.getCUOrTUNameIndex(U->getOffset())) {
-      DWARFCompileUnit *CU = dyn_cast<DWARFCompileUnit>(U.get());
+  auto populateNameToOffset =
+      [&](const DWARFDebugNames::NameIndex &NI,
+          StringMap<DenseSet<uint64_t>> &NamesToDieOffsets) {
+        for (const DWARFDebugNames::NameTableEntry &NTE : NI) {
+          const char *tName = NTE.getString();
+          const std::string Name = tName ? std::string(tName) : "";
+          uint64_t EntryID = NTE.getEntryOffset();
+          Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&EntryID);
+          auto Iter = NamesToDieOffsets.insert({Name, DenseSet<uint64_t>(3)});
+          for (; EntryOr; EntryOr = NI.getEntry(&EntryID)) {
+            if (std::optional<uint64_t> DieOffset = EntryOr->getDIEUnitOffset())
+              Iter.first->second.insert(*DieOffset);
+          }
+          handleAllErrors(
+              EntryOr.takeError(),
+              [&](const DWARFDebugNames::SentinelError &) {
+                if (!NamesToDieOffsets.empty())
+                  return;
+                ErrorCategory.Report(
+                    "NameIndex Name is not associated with any entries", [&]() {
+                      error()
+                          << formatv("Name Index @ {0:x}: Name {1} ({2}) is "
+                                     "not associated with any entries.\n",
+                                     NI.getUnitOffset(), NTE.getIndex(), Name);
+                    });
+              },
+              [&](const ErrorInfoBase &Info) {
+                ErrorCategory.Report("Uncategorized NameIndex error", [&]() {
+                  error() << formatv(
+                      "Name Index @ {0:x}: Name {1} ({2}): {3}\n",
+                      NI.getUnitOffset(), NTE.getIndex(), Name, Info.message());
+                });
+              });
+        }
+      };
+  // NameIndex can have multiple CUs. For example if it was created by BOLT.
+  // So better to iterate over NI, and then over CUs in it.
+  for (const DWARFDebugNames::NameIndex &NI : AccelTable) {
+    StringMap<DenseSet<uint64_t>> NamesToDieOffsets(NI.getNameCount());
+    populateNameToOffset(NI, NamesToDieOffsets);
+    for (uint32_t i = 0, iEnd = NI.getCUCount(); i < iEnd; ++i) {
+      const uint64_t CUOffset = NI.getCUOffset(i);
+      DWARFUnit *U = DCtx.getUnitForOffset(CUOffset);
+      DWARFCompileUnit *CU = dyn_cast<DWARFCompileUnit>(U);
       if (CU) {
         if (CU->getDWOId()) {
           DWARFDie CUDie = CU->getUnitDIE(true);
           DWARFDie NonSkeletonUnitDie =
               CUDie.getDwarfUnit()->getNonSkeletonUnitDIE(false);
           if (CUDie != NonSkeletonUnitDie) {
-            for (const DWARFDebugInfoEntry &Die :
-                 NonSkeletonUnitDie.getDwarfUnit()->dies())
-              NumErrors += verifyNameIndexCompleteness(
-                  DWARFDie(NonSkeletonUnitDie.getDwarfUnit(), &Die), *NI);
+            parallelForEach(
+                NonSkeletonUnitDie.getDwarfUnit()->dies(),
+                [&](const DWARFDebugInfoEntry &Die) {
+                  verifyNameIndexCompleteness(
+                      DWARFDie(NonSkeletonUnitDie.getDwarfUnit(), &Die), NI,
+                      NamesToDieOffsets);
+                });
           }
         } else {
-          for (const DWARFDebugInfoEntry &Die : CU->dies())
-            NumErrors += verifyNameIndexCompleteness(DWARFDie(CU, &Die), *NI);
+          parallelForEach(CU->dies(), [&](const DWARFDebugInfoEntry &Die) {
+            verifyNameIndexCompleteness(DWARFDie(CU, &Die), NI,
+                                        NamesToDieOffsets);
+          });
         }
       }
     }
   }
-  return NumErrors;
+  return;
 }
 
 bool DWARFVerifier::handleAccelTables() {
   const DWARFObject &D = DCtx.getDWARFObj();
   DataExtractor StrData(D.getStrSection(), DCtx.isLittleEndian(), 0);
-  unsigned NumErrors = 0;
   if (!D.getAppleNamesSection().Data.empty())
-    NumErrors += verifyAppleAccelTable(&D.getAppleNamesSection(), &StrData,
-                                       ".apple_names");
+    verifyAppleAccelTable(&D.getAppleNamesSection(), &StrData, ".apple_names");
   if (!D.getAppleTypesSection().Data.empty())
-    NumErrors += verifyAppleAccelTable(&D.getAppleTypesSection(), &StrData,
-                                       ".apple_types");
+    verifyAppleAccelTable(&D.getAppleTypesSection(), &StrData, ".apple_types");
   if (!D.getAppleNamespacesSection().Data.empty())
-    NumErrors += verifyAppleAccelTable(&D.getAppleNamespacesSection(), &StrData,
-                                       ".apple_namespaces");
+    verifyAppleAccelTable(&D.getAppleNamespacesSection(), &StrData,
+                          ".apple_namespaces");
   if (!D.getAppleObjCSection().Data.empty())
-    NumErrors += verifyAppleAccelTable(&D.getAppleObjCSection(), &StrData,
-                                       ".apple_objc");
+    verifyAppleAccelTable(&D.getAppleObjCSection(), &StrData, ".apple_objc");
 
   if (!D.getNamesSection().Data.empty())
-    NumErrors += verifyDebugNames(D.getNamesSection(), StrData);
-  return NumErrors == 0;
+    verifyDebugNames(D.getNamesSection(), StrData);
+  return ErrorCategory.GetNumErrors() == 0;
 }
 
 bool DWARFVerifier::handleDebugStrOffsets() {
@@ -2176,6 +2232,8 @@ void OutputCategoryAggregator::Report(
 void OutputCategoryAggregator::Report(
     StringRef category, StringRef sub_category,
     std::function<void(void)> detailCallback) {
+  std::lock_guard<std::mutex> Lock(WriteMutex);
+  ++NumErrors;
   std::string category_str = std::string(category);
   AggregationData &Agg = Aggregation[category_str];
   Agg.OverallCount++;

diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-completeness.s b/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-completeness.s
index b16f8658f87ec..9886968fdab99 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-completeness.s
+++ b/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-completeness.s
@@ -177,4 +177,3 @@
 .Lnames_abbrev_end0:
 .Lnames_entries0:
 .Lnames_end0:
-

diff  --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index 82dda93b7f1ab..5749b19d7ad49 100644
--- a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -30,9 +30,11 @@
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/InitLLVM.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Parallel.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Regex.h"
 #include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/Threading.h"
 #include "llvm/Support/ToolOutputFile.h"
 #include "llvm/Support/WithColor.h"
 #include "llvm/Support/raw_ostream.h"
@@ -284,6 +286,14 @@ static cl::opt<bool>
                 cat(DwarfDumpCategory));
 static opt<bool> Verify("verify", desc("Verify the DWARF debug info."),
                         cat(DwarfDumpCategory));
+static opt<unsigned> VerifyNumThreads(
+    "verify-num-threads", init(1),
+    desc("Number of threads to use for --verify. Single threaded verification "
+         "is the default unless this option is specified. If 0 is specified, "
+         "maximum hardware threads will be used. This can cause the "
+         "output to be non determinisitic, but can speed up verification and "
+         "is useful when running with the summary only or JSON summary modes."),
+    cat(DwarfDumpCategory));
 static opt<ErrorDetailLevel> ErrorDetails(
     "error-display", init(Unspecified),
     desc("Set the level of detail and summary to display when verifying "
@@ -778,7 +788,8 @@ static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
     if (filterArch(*Obj)) {
       std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(
           *Obj, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",
-          RecoverableErrorHandler);
+          RecoverableErrorHandler, WithColor::defaultWarningHandler,
+          /*ThreadSafe=*/true);
       DICtx->setParseCUTUIndexManually(ManuallyGenerateUnitIndex);
       if (!HandleObj(*Obj, *DICtx, Filename, OS))
         Result = false;
@@ -906,6 +917,11 @@ int main(int argc, char **argv) {
 
   bool Success = true;
   if (Verify) {
+    if (!VerifyNumThreads)
+      parallel::strategy =
+          hardware_concurrency(hardware_concurrency().compute_thread_count());
+    else
+      parallel::strategy = hardware_concurrency(VerifyNumThreads);
     for (StringRef Object : Objects)
       Success &= handleFile(Object, verifyObjectFile, OutputFile.os());
   } else if (Statistics) {


        


More information about the llvm-commits mailing list