[llvm] [llvm] Replace unordered_{map,set} with Dense{Map,Set}/SmallPtrSet (PR #202222)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 12 10:59:30 PDT 2026


https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/202222

>From 182374eaca55fa641e9d1f54e4d598f24dc67ac4 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 6 Jun 2026 22:17:20 -0700
Subject: [PATCH 1/4] [llvm] Replace unordered_{map,set} with Dense{Map,Set}

std::unordered_map is slow. The remaining uses are pointer stability,
key spanning the full value range, or huge pair<key,value>. After
PR #201281 DenseMap no longer reserves sentinel keys, so more of these maps
can switch.
---
 .../LogicalView/Readers/LVDWARFReader.h       |  7 +-
 llvm/include/llvm/IR/ModuleSummaryIndex.h     |  3 +-
 .../llvm/Support/ELFAttrParserCompact.h       |  8 +--
 llvm/include/llvm/XRay/InstrumentationMap.h   |  6 +-
 llvm/lib/CodeGen/MLRegAllocEvictAdvisor.cpp   |  3 +-
 llvm/lib/CodeGen/RDFLiveness.cpp              |  3 +-
 llvm/lib/ObjCopy/ELF/ELFObject.cpp            |  4 +-
 llvm/lib/Passes/StandardInstrumentations.cpp  | 14 ++--
 llvm/lib/Target/BPF/BTFDebug.cpp              | 12 ++--
 llvm/lib/Target/BPF/BTFDebug.h                | 15 ++---
 .../Target/Hexagon/HexagonISelDAGToDAGHVX.cpp |  3 +-
 llvm/lib/Target/PowerPC/PPCInstrInfo.cpp      |  2 +-
 .../SPIRVConvergenceRegionAnalysis.cpp        |  6 +-
 llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 66 +++++++++----------
 llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h   |  2 +-
 .../SPIRV/SPIRVMergeRegionExitTargets.cpp     |  3 +-
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp |  2 +-
 llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp   | 12 ++--
 llvm/lib/Target/SPIRV/SPIRVUtils.cpp          |  8 +--
 llvm/lib/Target/SPIRV/SPIRVUtils.h            |  9 +--
 .../IPO/MemProfContextDisambiguation.cpp      |  5 +-
 .../Instrumentation/IndirectCallPromotion.cpp |  3 +-
 .../Utils/SampleProfileInference.cpp          |  4 +-
 llvm/tools/llvm-xray/func-id-helper.h         |  3 +-
 24 files changed, 98 insertions(+), 105 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h
index 1cf29147fe2a1..b6d514edab6e4 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h
@@ -14,10 +14,11 @@
 #ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVDWARFREADER_H
 #define LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVDWARFREADER_H
 
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h"
-#include <unordered_set>
 
 namespace llvm {
 namespace logicalview {
@@ -62,14 +63,14 @@ class LVDWARFReader final : public LVBinaryReader {
   std::optional<LVAddress> TombstoneAddress;
 
   // Cross references (Elements).
-  using LVElementSet = std::unordered_set<LVElement *>;
+  using LVElementSet = DenseSet<LVElement *>;
   struct LVElementEntry {
     LVElement *Element;
     LVElementSet References;
     LVElementSet Types;
     LVElementEntry(LVElement *Element = nullptr) : Element(Element) {}
   };
-  using LVElementReference = std::unordered_map<LVOffset, LVElementEntry>;
+  using LVElementReference = DenseMap<LVOffset, LVElementEntry>;
   LVElementReference ElementTable;
 
   Error loadTargetInfo(const object::ObjectFile &Obj);
diff --git a/llvm/include/llvm/IR/ModuleSummaryIndex.h b/llvm/include/llvm/IR/ModuleSummaryIndex.h
index 359026cfc85a0..de487d0429e7e 100644
--- a/llvm/include/llvm/IR/ModuleSummaryIndex.h
+++ b/llvm/include/llvm/IR/ModuleSummaryIndex.h
@@ -45,7 +45,6 @@
 #include <optional>
 #include <set>
 #include <string>
-#include <unordered_set>
 #include <utility>
 #include <vector>
 
@@ -1401,7 +1400,7 @@ using ModuleToSummariesForIndexTy =
     std::map<std::string, GVSummaryMapTy, std::less<>>;
 
 /// A set of global value summary pointers.
-using GVSummaryPtrSet = std::unordered_set<GlobalValueSummary *>;
+using GVSummaryPtrSet = DenseSet<GlobalValueSummary *>;
 
 /// Map of a type GUID to type id string and summary (multimap used
 /// in case of GUID conflicts).
diff --git a/llvm/include/llvm/Support/ELFAttrParserCompact.h b/llvm/include/llvm/Support/ELFAttrParserCompact.h
index d7e415331d1c3..f55c21d42de3d 100644
--- a/llvm/include/llvm/Support/ELFAttrParserCompact.h
+++ b/llvm/include/llvm/Support/ELFAttrParserCompact.h
@@ -10,6 +10,7 @@
 #define LLVM_SUPPORT_ELFCOMPACTATTRPARSER_H
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/DataExtractor.h"
 #include "llvm/Support/ELFAttributeParser.h"
@@ -17,7 +18,6 @@
 #include "llvm/Support/Error.h"
 
 #include <optional>
-#include <unordered_map>
 
 namespace llvm {
 class StringRef;
@@ -25,8 +25,8 @@ class ScopedPrinter;
 
 class LLVM_ABI ELFCompactAttrParser : public ELFAttributeParser {
   StringRef vendor;
-  std::unordered_map<unsigned, unsigned> attributes;
-  std::unordered_map<unsigned, StringRef> attributesStr;
+  DenseMap<unsigned, unsigned> attributes;
+  DenseMap<unsigned, StringRef> attributesStr;
 
   virtual Error handler(uint64_t tag, bool &handled) = 0;
 
@@ -45,7 +45,7 @@ class LLVM_ABI ELFCompactAttrParser : public ELFAttributeParser {
   Error parseSubsection(uint32_t length);
 
   void setAttributeString(unsigned tag, StringRef value) {
-    attributesStr.emplace(tag, value);
+    attributesStr.try_emplace(tag, value);
   }
 
 public:
diff --git a/llvm/include/llvm/XRay/InstrumentationMap.h b/llvm/include/llvm/XRay/InstrumentationMap.h
index c5e7ebff0e2c1..9305b2e3ad36c 100644
--- a/llvm/include/llvm/XRay/InstrumentationMap.h
+++ b/llvm/include/llvm/XRay/InstrumentationMap.h
@@ -14,13 +14,13 @@
 #ifndef LLVM_XRAY_INSTRUMENTATIONMAP_H
 #define LLVM_XRAY_INSTRUMENTATIONMAP_H
 
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/YAMLTraits.h"
 #include <cstdint>
 #include <optional>
-#include <unordered_map>
 #include <vector>
 
 namespace llvm::xray {
@@ -74,8 +74,8 @@ struct YAMLXRaySledEntry {
 ///
 class InstrumentationMap {
 public:
-  using FunctionAddressMap = std::unordered_map<int32_t, uint64_t>;
-  using FunctionAddressReverseMap = std::unordered_map<uint64_t, int32_t>;
+  using FunctionAddressMap = DenseMap<int32_t, uint64_t>;
+  using FunctionAddressReverseMap = DenseMap<uint64_t, int32_t>;
   using SledContainer = std::vector<SledEntry>;
 
 private:
diff --git a/llvm/lib/CodeGen/MLRegAllocEvictAdvisor.cpp b/llvm/lib/CodeGen/MLRegAllocEvictAdvisor.cpp
index 2f2ee6f535f40..23dc6fbd6e500 100644
--- a/llvm/lib/CodeGen/MLRegAllocEvictAdvisor.cpp
+++ b/llvm/lib/CodeGen/MLRegAllocEvictAdvisor.cpp
@@ -42,7 +42,6 @@
 #include <array>
 #include <bitset>
 #include <memory>
-#include <unordered_map>
 
 using namespace llvm;
 
@@ -329,7 +328,7 @@ class MLEvictAdvisor : public RegAllocEvictionAdvisor {
   using RegID = unsigned;
   mutable DenseMap<RegID, LIFeatureComponents> CachedFeatures;
 
-  mutable std::unordered_map<unsigned, unsigned> VirtRegEvictionCounts;
+  mutable DenseMap<unsigned, unsigned> VirtRegEvictionCounts;
 
   void onEviction(Register RegBeingEvicted) const {
     // If we cannot find the virtual register in the map, we just assume it has
diff --git a/llvm/lib/CodeGen/RDFLiveness.cpp b/llvm/lib/CodeGen/RDFLiveness.cpp
index 195446e61076e..10ab9b88a05e1 100644
--- a/llvm/lib/CodeGen/RDFLiveness.cpp
+++ b/llvm/lib/CodeGen/RDFLiveness.cpp
@@ -471,8 +471,7 @@ void Liveness::computePhiInfo() {
   // phi use -> (map: reaching phi -> set of registers defined in between)
   std::map<NodeId, std::map<NodeId, RegisterAggr>> PhiUp;
   std::vector<NodeId> PhiUQ; // Work list of phis for upward propagation.
-  std::unordered_map<NodeId, RegisterAggr>
-      PhiDRs; // Phi -> registers defined by it.
+  DenseMap<NodeId, RegisterAggr> PhiDRs; // Phi -> registers defined by it.
 
   // Go over all phis.
   for (NodeAddr<PhiNode *> PhiA : Phis) {
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 3c6f9a966694a..0982e3c02de08 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -8,6 +8,7 @@
 
 #include "ELFObject.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
@@ -23,7 +24,6 @@
 #include <cstddef>
 #include <cstdint>
 #include <iterator>
-#include <unordered_set>
 #include <utility>
 #include <vector>
 
@@ -2235,7 +2235,7 @@ Error Object::removeSections(
   // Now make sure there are no remaining references to the sections that will
   // be removed. Sometimes it is impossible to remove a reference so we emit
   // an error here instead.
-  std::unordered_set<const SectionBase *> RemoveSections;
+  DenseSet<const SectionBase *> RemoveSections;
   RemoveSections.reserve(std::distance(Iter, std::end(Sections)));
   for (auto &RemoveSec : make_range(Iter, std::end(Sections))) {
     for (auto &Segment : Segments)
diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index 19e72a8612c4a..3f00a15dbc617 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/llvm/lib/Passes/StandardInstrumentations.cpp
@@ -14,6 +14,8 @@
 
 #include "llvm/Passes/StandardInstrumentations.h"
 #include "llvm/ADT/Any.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Analysis/LazyCallGraph.h"
 #include "llvm/Analysis/LoopInfo.h"
@@ -40,8 +42,6 @@
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/xxhash.h"
-#include <unordered_map>
-#include <unordered_set>
 #include <utility>
 #include <vector>
 
@@ -1635,9 +1635,9 @@ class DisplayNode : public DisplayElement {
       : DisplayElement(Colour), Content(Content) {}
 
   // Iterator to the child nodes.  Required by GraphWriter.
-  using ChildIterator = std::unordered_set<DisplayNode *>::const_iterator;
-  ChildIterator children_begin() const { return Children.cbegin(); }
-  ChildIterator children_end() const { return Children.cend(); }
+  using ChildIterator = DenseSet<DisplayNode *>::const_iterator;
+  ChildIterator children_begin() const { return Children.begin(); }
+  ChildIterator children_end() const { return Children.end(); }
 
   // Iterator for the edges.  Required by GraphWriter.
   using EdgeIterator = std::vector<DisplayEdge *>::const_iterator;
@@ -1673,8 +1673,8 @@ class DisplayNode : public DisplayElement {
   std::vector<DisplayEdge> Edges;
 
   std::vector<DisplayEdge *> EdgePtrs;
-  std::unordered_set<DisplayNode *> Children;
-  std::unordered_map<const DisplayNode *, const DisplayEdge *> EdgeMap;
+  DenseSet<DisplayNode *> Children;
+  DenseMap<const DisplayNode *, const DisplayEdge *> EdgeMap;
 
   // Safeguard adding of edges.
   bool AllEdgesCreated = false;
diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp
index c847c1cb4b65c..227a9db86b62d 100644
--- a/llvm/lib/Target/BPF/BTFDebug.cpp
+++ b/llvm/lib/Target/BPF/BTFDebug.cpp
@@ -398,7 +398,7 @@ std::string BTFTypeStruct::getName() { return std::string(STy->getName()); }
 /// for subprogram.
 BTFTypeFuncProto::BTFTypeFuncProto(
     const DISubroutineType *STy, uint32_t VLen,
-    const std::unordered_map<uint32_t, StringRef> &FuncArgNames)
+    const DenseMap<uint32_t, StringRef> &FuncArgNames)
     : STy(STy), FuncArgNames(FuncArgNames) {
   Kind = BTF::BTF_KIND_FUNC_PROTO;
   BTFType.Info = (Kind << 24) | VLen;
@@ -626,8 +626,7 @@ void BTFDebug::visitBasicType(const DIBasicType *BTy, uint32_t &TypeId) {
 /// Handle subprogram or subroutine types.
 void BTFDebug::visitSubroutineType(
     const DISubroutineType *STy, bool ForSubprog,
-    const std::unordered_map<uint32_t, StringRef> &FuncArgNames,
-    uint32_t &TypeId) {
+    const DenseMap<uint32_t, StringRef> &FuncArgNames, uint32_t &TypeId) {
   DITypeArray Elements = STy->getTypeArray();
   uint32_t VLen = Elements.size() - 1;
   if (VLen > BTF::MAX_VLEN)
@@ -1036,8 +1035,7 @@ void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId,
   if (const auto *BTy = dyn_cast<DIBasicType>(Ty))
     visitBasicType(BTy, TypeId);
   else if (const auto *STy = dyn_cast<DISubroutineType>(Ty))
-    visitSubroutineType(STy, false, std::unordered_map<uint32_t, StringRef>(),
-                        TypeId);
+    visitSubroutineType(STy, false, DenseMap<uint32_t, StringRef>(), TypeId);
   else if (const auto *CTy = dyn_cast<DICompositeType>(Ty))
     visitCompositeType(CTy, TypeId);
   else if (const auto *DTy = dyn_cast<DIDerivedType>(Ty))
@@ -1331,7 +1329,7 @@ void BTFDebug::beginFunctionImpl(const MachineFunction *MF) {
   // Collect all types locally referenced in this function.
   // Use RetainedNodes so we can collect all argument names
   // even if the argument is not used.
-  std::unordered_map<uint32_t, StringRef> FuncArgNames;
+  DenseMap<uint32_t, StringRef> FuncArgNames;
   for (const DINode *DN : SP->getRetainedNodes()) {
     if (const auto *DV = dyn_cast<DILocalVariable>(DN)) {
       // Collect function arguments for subprogram func type.
@@ -1713,7 +1711,7 @@ void BTFDebug::processFuncPrototypes(const Function *F) {
     return;
 
   uint32_t ProtoTypeId;
-  const std::unordered_map<uint32_t, StringRef> FuncArgNames;
+  const DenseMap<uint32_t, StringRef> FuncArgNames;
   visitSubroutineType(SP->getType(), false, FuncArgNames, ProtoTypeId);
   uint32_t FuncId = processDISubprogram(SP, ProtoTypeId, BTF::FUNC_EXTERN);
 
diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h
index 75858fcc8bfde..7d2b7032f1faf 100644
--- a/llvm/lib/Target/BPF/BTFDebug.h
+++ b/llvm/lib/Target/BPF/BTFDebug.h
@@ -14,13 +14,13 @@
 #ifndef LLVM_LIB_TARGET_BPF_BTFDEBUG_H
 #define LLVM_LIB_TARGET_BPF_BTFDEBUG_H
 
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/CodeGen/DebugHandlerBase.h"
 #include "llvm/DebugInfo/BTF/BTF.h"
 #include <cstdint>
 #include <map>
 #include <set>
-#include <unordered_map>
 
 namespace llvm {
 
@@ -142,12 +142,12 @@ class BTFTypeStruct : public BTFTypeBase {
 /// Handle function pointer.
 class BTFTypeFuncProto : public BTFTypeBase {
   const DISubroutineType *STy;
-  std::unordered_map<uint32_t, StringRef> FuncArgNames;
+  DenseMap<uint32_t, StringRef> FuncArgNames;
   std::vector<struct BTF::BTFParam> Parameters;
 
 public:
   BTFTypeFuncProto(const DISubroutineType *STy, uint32_t NumParams,
-                   const std::unordered_map<uint32_t, StringRef> &FuncArgNames);
+                   const DenseMap<uint32_t, StringRef> &FuncArgNames);
   uint32_t getSize() override {
     return BTFTypeBase::getSize() + Parameters.size() * BTF::BTFParamSize;
   }
@@ -295,7 +295,7 @@ class BTFDebug : public DebugHandlerBase {
   bool MapDefNotCollected;
   BTFStringTable StringTable;
   std::vector<std::unique_ptr<BTFTypeBase>> TypeEntries;
-  std::unordered_map<const DIType *, uint32_t> DIToIdMap;
+  DenseMap<const DIType *, uint32_t> DIToIdMap;
   std::map<uint32_t, std::vector<BTFFuncInfo>> FuncInfoTable;
   std::map<uint32_t, std::vector<BTFLineInfo>> LineInfoTable;
   std::map<uint32_t, std::vector<BTFFieldReloc>> FieldRelocTable;
@@ -323,10 +323,9 @@ class BTFDebug : public DebugHandlerBase {
   void visitTypeEntry(const DIType *Ty, uint32_t &TypeId, bool CheckPointer,
                       bool SeenPointer);
   void visitBasicType(const DIBasicType *BTy, uint32_t &TypeId);
-  void visitSubroutineType(
-      const DISubroutineType *STy, bool ForSubprog,
-      const std::unordered_map<uint32_t, StringRef> &FuncArgNames,
-      uint32_t &TypeId);
+  void visitSubroutineType(const DISubroutineType *STy, bool ForSubprog,
+                           const DenseMap<uint32_t, StringRef> &FuncArgNames,
+                           uint32_t &TypeId);
   void visitFwdDeclType(const DICompositeType *CTy, bool IsUnion,
                         uint32_t &TypeId);
   void visitCompositeType(const DICompositeType *CTy, uint32_t &TypeId);
diff --git a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp
index ae369fe7ce901..a59ec1820a092 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp
@@ -23,7 +23,6 @@
 #include <map>
 #include <optional>
 #include <set>
-#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -2747,7 +2746,7 @@ void HexagonDAGToDAGISel::ppHvxShuffleOfShuffle(std::vector<SDNode *> &&Nodes) {
     unsigned HalfIdx;
   };
 
-  using MapType = std::unordered_map<SDValue, unsigned>;
+  using MapType = DenseMap<SDValue, unsigned>;
 
   auto getMaskElt = [&](unsigned Idx, ShuffleVectorSDNode *Shuff0,
                         ShuffleVectorSDNode *Shuff1,
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
index 59d18de06b2e0..925c679450ded 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
@@ -5448,7 +5448,7 @@ void PPCInstrInfo::promoteInstr32To64ForElimEXTSW(const Register &Reg,
   // Map the 32bit to 64bit opcodes for instructions that are not signed or zero
   // extended themselves, but may have operands who's destination registers of
   // signed or zero extended instructions.
-  std::unordered_map<unsigned, unsigned> OpcodeMap = {
+  DenseMap<unsigned, unsigned> OpcodeMap = {
       {PPC::OR, PPC::OR8},     {PPC::ISEL, PPC::ISEL8},
       {PPC::ORI, PPC::ORI8},   {PPC::XORI, PPC::XORI8},
       {PPC::ORIS, PPC::ORIS8}, {PPC::XORIS, PPC::XORIS8},
diff --git a/llvm/lib/Target/SPIRV/Analysis/SPIRVConvergenceRegionAnalysis.cpp b/llvm/lib/Target/SPIRV/Analysis/SPIRVConvergenceRegionAnalysis.cpp
index 0798483462e18..1cb32cce32cbd 100644
--- a/llvm/lib/Target/SPIRV/Analysis/SPIRVConvergenceRegionAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/Analysis/SPIRVConvergenceRegionAnalysis.cpp
@@ -14,6 +14,7 @@
 
 #include "SPIRVConvergenceRegionAnalysis.h"
 #include "SPIRV.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/IntrinsicInst.h"
@@ -21,7 +22,6 @@
 #include "llvm/Transforms/Utils/LoopSimplify.h"
 #include <optional>
 #include <queue>
-#include <unordered_set>
 
 #define DEBUG_TYPE "spirv-convergence-region-analysis"
 
@@ -210,10 +210,10 @@ class ConvergenceRegionAnalyzer {
     return false;
   }
 
-  std::unordered_set<BasicBlock *>
+  DenseSet<BasicBlock *>
   findPathsToMatch(LoopInfo &LI, BasicBlock *From,
                    std::function<bool(const BasicBlock *)> isMatch) const {
-    std::unordered_set<BasicBlock *> Output;
+    DenseSet<BasicBlock *> Output;
 
     if (isMatch(From))
       Output.insert(From);
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 97fa49d8836fb..1e1b0080be5ac 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -17,6 +17,7 @@
 #include "SPIRVSubtarget.h"
 #include "SPIRVTargetMachine.h"
 #include "SPIRVUtils.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Analysis/LoopInfo.h"
@@ -35,7 +36,6 @@
 #include <cassert>
 #include <optional>
 #include <queue>
-#include <unordered_set>
 
 // This pass performs the following transformation on LLVM IR level required
 // for the following translation to SPIR-V:
@@ -192,7 +192,7 @@ class SPIRVEmitIntrinsics
   DenseSet<Instruction *> AggrStores;
   SmallPtrSet<Instruction *, 8> DeletedInstrs;
   GlobalVariableUsers GVUsers;
-  std::unordered_set<Value *> Named;
+  DenseSet<Value *> Named;
 
   // map of function declarations to <pointer arg index => element type>
   DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
@@ -224,7 +224,7 @@ class SPIRVEmitIntrinsics
   }
   // a register of Instructions that were visited by deduceOperandElementType()
   // to validate operand types with an instruction
-  std::unordered_set<Instruction *> TypeValidated;
+  DenseSet<Instruction *> TypeValidated;
 
   // well known result types of builtins
   enum WellKnownTypes { Event };
@@ -232,24 +232,22 @@ class SPIRVEmitIntrinsics
   // deduce element type of untyped pointers
   Type *deduceElementType(Value *I, bool UnknownElemTypeI8);
   Type *deduceElementTypeHelper(Value *I, bool UnknownElemTypeI8);
-  Type *deduceElementTypeHelper(Value *I, std::unordered_set<Value *> &Visited,
+  Type *deduceElementTypeHelper(Value *I, DenseSet<Value *> &Visited,
                                 bool UnknownElemTypeI8,
                                 bool IgnoreKnownType = false);
   Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
                                      bool UnknownElemTypeI8);
   Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
-                                     std::unordered_set<Value *> &Visited,
+                                     DenseSet<Value *> &Visited,
                                      bool UnknownElemTypeI8);
-  Type *deduceElementTypeByUsersDeep(Value *Op,
-                                     std::unordered_set<Value *> &Visited,
+  Type *deduceElementTypeByUsersDeep(Value *Op, DenseSet<Value *> &Visited,
                                      bool UnknownElemTypeI8);
   void maybeAssignPtrType(Type *&Ty, Value *I, Type *RefTy,
                           bool UnknownElemTypeI8);
 
   // deduce nested types of composites
   Type *deduceNestedTypeHelper(User *U, bool UnknownElemTypeI8);
-  Type *deduceNestedTypeHelper(User *U, Type *Ty,
-                               std::unordered_set<Value *> &Visited,
+  Type *deduceNestedTypeHelper(User *U, Type *Ty, DenseSet<Value *> &Visited,
                                bool UnknownElemTypeI8);
 
   // deduce Types of operands of the Instruction if possible
@@ -287,7 +285,7 @@ class SPIRVEmitIntrinsics
   void processParamTypesByFunHeader(Function *F, IRBuilder<> &B);
   Type *deduceFunParamElementType(Function *F, unsigned OpIdx);
   Type *deduceFunParamElementType(Function *F, unsigned OpIdx,
-                                  std::unordered_set<Function *> &FVisited);
+                                  DenseSet<Function *> &FVisited);
 
   bool deduceOperandElementTypeCalledFunction(
       CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
@@ -310,7 +308,7 @@ class SPIRVEmitIntrinsics
                        DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
   void propagateElemTypeRec(Value *Op, Type *PtrElemTy, Type *CastElemTy,
                             DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
-                            std::unordered_set<Value *> &Visited,
+                            DenseSet<Value *> &Visited,
                             DenseMap<Function *, CallInst *> Ptrcasts);
 
   void replaceAllUsesWith(Value *Src, Value *Dest, bool DeleteOld = true);
@@ -647,7 +645,7 @@ void SPIRVEmitIntrinsics::propagateElemType(
 void SPIRVEmitIntrinsics::propagateElemTypeRec(
     Value *Op, Type *PtrElemTy, Type *CastElemTy,
     DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
-  std::unordered_set<Value *> Visited;
+  DenseSet<Value *> Visited;
   DenseMap<Function *, CallInst *> Ptrcasts;
   propagateElemTypeRec(Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
                        std::move(Ptrcasts));
@@ -656,8 +654,7 @@ void SPIRVEmitIntrinsics::propagateElemTypeRec(
 void SPIRVEmitIntrinsics::propagateElemTypeRec(
     Value *Op, Type *PtrElemTy, Type *CastElemTy,
     DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
-    std::unordered_set<Value *> &Visited,
-    DenseMap<Function *, CallInst *> Ptrcasts) {
+    DenseSet<Value *> &Visited, DenseMap<Function *, CallInst *> Ptrcasts) {
   if (!Visited.insert(Op).second)
     return;
   SmallVector<User *> Users(Op->users());
@@ -680,14 +677,15 @@ void SPIRVEmitIntrinsics::propagateElemTypeRec(
 Type *
 SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
                                                   bool UnknownElemTypeI8) {
-  std::unordered_set<Value *> Visited;
+  DenseSet<Value *> Visited;
   return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
                                       UnknownElemTypeI8);
 }
 
-Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
-    Type *ValueTy, Value *Operand, std::unordered_set<Value *> &Visited,
-    bool UnknownElemTypeI8) {
+Type *
+SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
+                                                  DenseSet<Value *> &Visited,
+                                                  bool UnknownElemTypeI8) {
   Type *Ty = ValueTy;
   if (Operand) {
     if (auto *PtrTy = dyn_cast<PointerType>(Ty)) {
@@ -704,7 +702,7 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
 
 // Traverse User instructions to deduce an element pointer type of the operand.
 Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
-    Value *Op, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8) {
+    Value *Op, DenseSet<Value *> &Visited, bool UnknownElemTypeI8) {
   if (!Op || !isPointerTy(Op->getType()) || isa<ConstantPointerNull>(Op) ||
       isa<UndefValue>(Op))
     return nullptr;
@@ -742,7 +740,7 @@ static Type *getPointeeTypeByCallInst(StringRef DemangledName,
 // or nullptr otherwise.
 Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(Value *I,
                                                    bool UnknownElemTypeI8) {
-  std::unordered_set<Value *> Visited;
+  DenseSet<Value *> Visited;
   return deduceElementTypeHelper(I, Visited, UnknownElemTypeI8);
 }
 
@@ -929,9 +927,10 @@ Type *SPIRVEmitIntrinsics::getGEPType(GetElementPtrInst *Ref) {
   return Ty;
 }
 
-Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
-    Value *I, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8,
-    bool IgnoreKnownType) {
+Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(Value *I,
+                                                   DenseSet<Value *> &Visited,
+                                                   bool UnknownElemTypeI8,
+                                                   bool IgnoreKnownType) {
   // allow to pass nullptr as an argument
   if (!I)
     return nullptr;
@@ -1089,13 +1088,13 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
 // information is found or needed.
 Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
                                                   bool UnknownElemTypeI8) {
-  std::unordered_set<Value *> Visited;
+  DenseSet<Value *> Visited;
   return deduceNestedTypeHelper(U, U->getType(), Visited, UnknownElemTypeI8);
 }
 
-Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(
-    User *U, Type *OrigTy, std::unordered_set<Value *> &Visited,
-    bool UnknownElemTypeI8) {
+Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U, Type *OrigTy,
+                                                  DenseSet<Value *> &Visited,
+                                                  bool UnknownElemTypeI8) {
   if (!U)
     return OrigTy;
 
@@ -2931,7 +2930,7 @@ void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(Module &M) {
     }
   }
 
-  std::unordered_map<unsigned, GlobalVariable *> GlobalVars;
+  DenseMap<unsigned, GlobalVariable *> GlobalVars;
   for (auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) {
     if (FPFastMathDefaultInfoVec.empty())
       continue;
@@ -3051,17 +3050,18 @@ void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
 
 Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *F,
                                                      unsigned OpIdx) {
-  std::unordered_set<Function *> FVisited;
+  DenseSet<Function *> FVisited;
   return deduceFunParamElementType(F, OpIdx, FVisited);
 }
 
-Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
-    Function *F, unsigned OpIdx, std::unordered_set<Function *> &FVisited) {
+Type *
+SPIRVEmitIntrinsics::deduceFunParamElementType(Function *F, unsigned OpIdx,
+                                               DenseSet<Function *> &FVisited) {
   // maybe a cycle
   if (!FVisited.insert(F).second)
     return nullptr;
 
-  std::unordered_set<Value *> Visited;
+  DenseSet<Value *> Visited;
   SmallVector<std::pair<Function *, unsigned>> Lookup;
   // search in function's call sites
   for (User *U : F->users()) {
@@ -3546,7 +3546,7 @@ bool SPIRVEmitIntrinsics::postprocessTypes(Module &M) {
     // Try to improve the type deduced after all Functions are processed.
     if (auto *CI = dyn_cast<Instruction>(Op)) {
       CurrF = CI->getParent()->getParent();
-      std::unordered_set<Value *> Visited;
+      DenseSet<Value *> Visited;
       if (Type *ElemTy = deduceElementTypeHelper(Op, Visited, false, true)) {
         if (ElemTy != KnownTy) {
           DenseSet<std::pair<Value *, Value *>> VisitedSubst;
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
index f05bdc2cc9861..fcb8b3fd66f91 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
@@ -87,7 +87,7 @@ class SPIRVGlobalRegistry : public SPIRVIRMapping {
   DenseMap<std::pair<const MachineFunction *, Register>, const Value *> Reg2GO;
 
   // map of aliasing decorations to aliasing metadata
-  std::unordered_map<const MDNode *, MachineInstr *> AliasInstMDMap;
+  DenseMap<const MDNode *, MachineInstr *> AliasInstMDMap;
 
   // Add a new OpTypeXXX instruction without checking for duplicates.
   SPIRVTypeInst createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder,
diff --git a/llvm/lib/Target/SPIRV/SPIRVMergeRegionExitTargets.cpp b/llvm/lib/Target/SPIRV/SPIRVMergeRegionExitTargets.cpp
index 959e7eb1e9e04..899026fd95ef4 100644
--- a/llvm/lib/Target/SPIRV/SPIRVMergeRegionExitTargets.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVMergeRegionExitTargets.cpp
@@ -18,6 +18,7 @@
 #include "SPIRVSubtarget.h"
 #include "SPIRVUtils.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/IR/Dominators.h"
@@ -166,7 +167,7 @@ static void validateRegionExits(const SPIRV::ConvergenceRegion *CR) {
   for (auto *Child : CR->Children)
     validateRegionExits(Child);
 
-  std::unordered_set<BasicBlock *> ExitTargets;
+  DenseSet<BasicBlock *> ExitTargets;
   for (auto *Exit : CR->Exits) {
     for (auto *BB : successors(Exit)) {
       if (CR->Blocks.count(BB) == 0)
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 49d9dc95603ca..ea0635dfdf89d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -2152,7 +2152,7 @@ void addInstrRequirements(const MachineInstr &MI,
 
     // Check Layout operand in case if it's not a standard one and add the
     // appropriate capability.
-    std::unordered_map<unsigned, unsigned> LayoutToInstMap = {
+    DenseMap<unsigned, unsigned> LayoutToInstMap = {
         {SPIRV::OpCooperativeMatrixLoadKHR, 3},
         {SPIRV::OpCooperativeMatrixStoreKHR, 2},
         {SPIRV::OpCooperativeMatrixLoadCheckedINTEL, 5},
diff --git a/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp b/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
index d2befa50789fa..b9d3095c36a8e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
@@ -14,6 +14,7 @@
 #include "SPIRVSubtarget.h"
 #include "SPIRVUtils.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/IR/CFG.h"
@@ -29,12 +30,11 @@
 #include "llvm/Transforms/Utils/LoopSimplify.h"
 #include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
 #include <stack>
-#include <unordered_set>
 
 using namespace llvm;
 using namespace SPIRV;
 
-using BlockSet = std::unordered_set<BasicBlock *>;
+using BlockSet = DenseSet<BasicBlock *>;
 using Edge = std::pair<BasicBlock *, BasicBlock *>;
 
 // Helper function to do a partial order visit from the block |Start|, calling
@@ -63,7 +63,7 @@ getRegionForHeader(const ConvergenceRegion *Node, BasicBlock *BB) {
 // Returns the single BasicBlock exiting the convergence region `CR`,
 // nullptr if no such exit exists.
 static BasicBlock *getExitFor(const ConvergenceRegion *CR) {
-  std::unordered_set<BasicBlock *> ExitTargets;
+  DenseSet<BasicBlock *> ExitTargets;
   for (BasicBlock *Exit : CR->Exits) {
     for (BasicBlock *Successor : successors(Exit)) {
       if (CR->Blocks.count(Successor) == 0)
@@ -427,7 +427,7 @@ class SPIRVStructurizer : public FunctionPass {
     // clang-format on
     std::vector<Edge>
     createAliasBlocksForComplexEdges(std::vector<Edge> Edges) {
-      std::unordered_set<BasicBlock *> Seen;
+      DenseSet<BasicBlock *> Seen;
       std::vector<Edge> Output;
       Output.reserve(Edges.size());
 
@@ -465,14 +465,14 @@ class SPIRVStructurizer : public FunctionPass {
       std::vector<Edge> FixedEdges = createAliasBlocksForComplexEdges(Edges);
 
       std::vector<BasicBlock *> Dsts;
-      std::unordered_map<BasicBlock *, ConstantInt *> DstToIndex;
+      DenseMap<BasicBlock *, ConstantInt *> DstToIndex;
       auto NewExit = BasicBlock::Create(F.getContext(),
                                         Header->getName() + ".new.exit", &F);
       IRBuilder<> ExitBuilder(NewExit);
       for (auto &[Src, Dst] : FixedEdges) {
         if (DstToIndex.count(Dst) != 0)
           continue;
-        DstToIndex.emplace(Dst, ExitBuilder.getInt32(DstToIndex.size()));
+        DstToIndex.try_emplace(Dst, ExitBuilder.getInt32(DstToIndex.size()));
         Dsts.push_back(Dst);
       }
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 6c5619c4585ef..6abdffe743f74 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -678,12 +678,12 @@ Type *parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx) {
   return nullptr;
 }
 
-std::unordered_set<BasicBlock *>
+DenseSet<BasicBlock *>
 PartialOrderingVisitor::getReachableFrom(BasicBlock *Start) {
   std::queue<BasicBlock *> ToVisit;
   ToVisit.push(Start);
 
-  std::unordered_set<BasicBlock *> Output;
+  DenseSet<BasicBlock *> Output;
   while (ToVisit.size() != 0) {
     BasicBlock *BB = ToVisit.front();
     ToVisit.pop();
@@ -792,7 +792,7 @@ size_t PartialOrderingVisitor::visit(BasicBlock *BB, size_t Unused) {
     QueueIndex = 0;
     size_t Rank = GetNodeRank(BB);
     OrderInfo Info = {Rank, BlockToOrder.size()};
-    BlockToOrder.emplace(BB, Info);
+    BlockToOrder.try_emplace(BB, Info);
 
     for (BasicBlock *S : successors(BB)) {
       if (Queued.count(S) != 0)
@@ -831,7 +831,7 @@ bool PartialOrderingVisitor::compare(const BasicBlock *LHS,
 
 void PartialOrderingVisitor::partialOrderVisit(
     BasicBlock &Start, std::function<bool(BasicBlock *)> Op) {
-  std::unordered_set<BasicBlock *> Reachable = getReachableFrom(&Start);
+  DenseSet<BasicBlock *> Reachable = getReachableFrom(&Start);
   assert(BlockToOrder.count(&Start) != 0);
 
   // Skipping blocks with a rank inferior to |Start|'s rank.
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index 27b196cb8dad3..78346abeeafd8 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -14,6 +14,8 @@
 #define LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
 
 #include "MCTargetDesc/SPIRVBaseInfo.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/IR/Dominators.h"
@@ -24,7 +26,6 @@
 #include <set>
 #include <string>
 #include <unordered_map>
-#include <unordered_set>
 
 #include "SPIRVTypeInst.h"
 
@@ -72,7 +73,7 @@ class PartialOrderingVisitor {
   DomTreeBuilder::BBDomTree DT;
   LoopInfo LI;
 
-  std::unordered_set<BasicBlock *> Queued = {};
+  DenseSet<BasicBlock *> Queued = {};
   std::queue<BasicBlock *> ToVisit = {};
 
   struct OrderInfo {
@@ -80,12 +81,12 @@ class PartialOrderingVisitor {
     size_t TraversalIndex;
   };
 
-  using BlockToOrderInfoMap = std::unordered_map<BasicBlock *, OrderInfo>;
+  using BlockToOrderInfoMap = DenseMap<BasicBlock *, OrderInfo>;
   BlockToOrderInfoMap BlockToOrder;
   std::vector<BasicBlock *> Order = {};
 
   // Get all basic-blocks reachable from Start.
-  std::unordered_set<BasicBlock *> getReachableFrom(BasicBlock *Start);
+  DenseSet<BasicBlock *> getReachableFrom(BasicBlock *Start);
 
   // Internal function used to determine the partial ordering.
   // Visits |BB| with the current rank being |Rank|.
diff --git a/llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp b/llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp
index ac93576391aff..73583981df31b 100644
--- a/llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp
+++ b/llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp
@@ -49,7 +49,6 @@
 #include "llvm/Transforms/Utils/Instrumentation.h"
 #include <deque>
 #include <sstream>
-#include <unordered_map>
 #include <vector>
 using namespace llvm;
 using namespace llvm::memprof;
@@ -1103,8 +1102,8 @@ class IndexCallsiteContextGraph
   // frames that we discover while building the graph.
   // It maps from the summary of the function making the tail call, to a map
   // of callee ValueInfo to corresponding synthesized callsite info.
-  std::unordered_map<FunctionSummary *,
-                     std::map<ValueInfo, std::unique_ptr<CallsiteInfo>>>
+  DenseMap<FunctionSummary *,
+           std::map<ValueInfo, std::unique_ptr<CallsiteInfo>>>
       FunctionCalleesToSynthesizedCallsiteInfos;
 };
 } // namespace
diff --git a/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp b/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp
index 9fe751a56df64..cc6361f03d89b 100644
--- a/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp
+++ b/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp
@@ -44,7 +44,6 @@
 #include <cstdint>
 #include <set>
 #include <string>
-#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -167,7 +166,7 @@ namespace {
 // In the inner map, the key represents address point offsets and the value is a
 // constant for this address point.
 using VTableAddressPointOffsetValMap =
-    SmallDenseMap<const GlobalVariable *, std::unordered_map<int, Constant *>>;
+    SmallDenseMap<const GlobalVariable *, DenseMap<int, Constant *>>;
 
 // A struct to collect type information for a virtual call site.
 struct VirtualCallSiteInfo {
diff --git a/llvm/lib/Transforms/Utils/SampleProfileInference.cpp b/llvm/lib/Transforms/Utils/SampleProfileInference.cpp
index 3e40cced8771c..69a6f18baef10 100644
--- a/llvm/lib/Transforms/Utils/SampleProfileInference.cpp
+++ b/llvm/lib/Transforms/Utils/SampleProfileInference.cpp
@@ -15,12 +15,12 @@
 
 #include "llvm/Transforms/Utils/SampleProfileInference.h"
 #include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include <queue>
 #include <set>
 #include <stack>
-#include <unordered_set>
 
 using namespace llvm;
 #define DEBUG_TYPE "sample-profile-inference"
@@ -1229,7 +1229,7 @@ void verifyInput(const FlowFunction &Func) {
 
   // Verify that there are no parallel edges
   for (auto &Block : Func.Blocks) {
-    std::unordered_set<uint64_t> UniqueSuccs;
+    DenseSet<uint64_t> UniqueSuccs;
     for (auto &Jump : Block.SuccJumps) {
       auto It = UniqueSuccs.insert(Jump->Target);
       assert(It.second && "input CFG contains parallel edges");
diff --git a/llvm/tools/llvm-xray/func-id-helper.h b/llvm/tools/llvm-xray/func-id-helper.h
index d1a66282bab0b..389415fa038fb 100644
--- a/llvm/tools/llvm-xray/func-id-helper.h
+++ b/llvm/tools/llvm-xray/func-id-helper.h
@@ -15,14 +15,13 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
-#include <unordered_map>
 
 namespace llvm::xray {
 
 // This class consolidates common operations related to Function IDs.
 class FuncIdConversionHelper {
 public:
-  using FunctionAddressMap = std::unordered_map<int32_t, uint64_t>;
+  using FunctionAddressMap = DenseMap<int32_t, uint64_t>;
 
 private:
   std::string BinaryInstrMap;

>From 2837ed2ae7f4d4928012803427ed38c0b0bd6760 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 7 Jun 2026 14:11:08 -0700
Subject: [PATCH 2/4] use SmallPtrSet<T *, 0>

---
 .../LogicalView/Readers/LVDWARFReader.h       |  4 +-
 llvm/include/llvm/IR/ModuleSummaryIndex.h     |  3 +-
 llvm/lib/ObjCopy/ELF/ELFObject.cpp            |  4 +-
 llvm/lib/Passes/StandardInstrumentations.cpp  |  6 +-
 .../SPIRVConvergenceRegionAnalysis.cpp        |  6 +-
 llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 66 ++++++++++---------
 .../SPIRV/SPIRVMergeRegionExitTargets.cpp     |  3 +-
 llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp   |  7 +-
 llvm/lib/Target/SPIRV/SPIRVUtils.cpp          |  6 +-
 llvm/lib/Target/SPIRV/SPIRVUtils.h            |  6 +-
 10 files changed, 56 insertions(+), 55 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h
index b6d514edab6e4..930eeac5f400e 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h
@@ -15,7 +15,7 @@
 #define LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVDWARFREADER_H
 
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h"
@@ -63,7 +63,7 @@ class LVDWARFReader final : public LVBinaryReader {
   std::optional<LVAddress> TombstoneAddress;
 
   // Cross references (Elements).
-  using LVElementSet = DenseSet<LVElement *>;
+  using LVElementSet = SmallPtrSet<LVElement *, 0>;
   struct LVElementEntry {
     LVElement *Element;
     LVElementSet References;
diff --git a/llvm/include/llvm/IR/ModuleSummaryIndex.h b/llvm/include/llvm/IR/ModuleSummaryIndex.h
index de487d0429e7e..7858bd1f015d9 100644
--- a/llvm/include/llvm/IR/ModuleSummaryIndex.h
+++ b/llvm/include/llvm/IR/ModuleSummaryIndex.h
@@ -19,6 +19,7 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
@@ -1400,7 +1401,7 @@ using ModuleToSummariesForIndexTy =
     std::map<std::string, GVSummaryMapTy, std::less<>>;
 
 /// A set of global value summary pointers.
-using GVSummaryPtrSet = DenseSet<GlobalValueSummary *>;
+using GVSummaryPtrSet = SmallPtrSet<GlobalValueSummary *, 0>;
 
 /// Map of a type GUID to type id string and summary (multimap used
 /// in case of GUID conflicts).
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 0982e3c02de08..ac818343f3f8f 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -8,8 +8,8 @@
 
 #include "ELFObject.h"
 #include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/ADT/iterator_range.h"
@@ -2235,7 +2235,7 @@ Error Object::removeSections(
   // Now make sure there are no remaining references to the sections that will
   // be removed. Sometimes it is impossible to remove a reference so we emit
   // an error here instead.
-  DenseSet<const SectionBase *> RemoveSections;
+  SmallPtrSet<const SectionBase *, 0> RemoveSections;
   RemoveSections.reserve(std::distance(Iter, std::end(Sections)));
   for (auto &RemoveSec : make_range(Iter, std::end(Sections))) {
     for (auto &Segment : Segments)
diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index 3f00a15dbc617..ef02299445391 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/llvm/lib/Passes/StandardInstrumentations.cpp
@@ -15,7 +15,7 @@
 #include "llvm/Passes/StandardInstrumentations.h"
 #include "llvm/ADT/Any.h"
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Analysis/LazyCallGraph.h"
 #include "llvm/Analysis/LoopInfo.h"
@@ -1635,7 +1635,7 @@ class DisplayNode : public DisplayElement {
       : DisplayElement(Colour), Content(Content) {}
 
   // Iterator to the child nodes.  Required by GraphWriter.
-  using ChildIterator = DenseSet<DisplayNode *>::const_iterator;
+  using ChildIterator = SmallPtrSet<DisplayNode *, 0>::const_iterator;
   ChildIterator children_begin() const { return Children.begin(); }
   ChildIterator children_end() const { return Children.end(); }
 
@@ -1673,7 +1673,7 @@ class DisplayNode : public DisplayElement {
   std::vector<DisplayEdge> Edges;
 
   std::vector<DisplayEdge *> EdgePtrs;
-  DenseSet<DisplayNode *> Children;
+  SmallPtrSet<DisplayNode *, 0> Children;
   DenseMap<const DisplayNode *, const DisplayEdge *> EdgeMap;
 
   // Safeguard adding of edges.
diff --git a/llvm/lib/Target/SPIRV/Analysis/SPIRVConvergenceRegionAnalysis.cpp b/llvm/lib/Target/SPIRV/Analysis/SPIRVConvergenceRegionAnalysis.cpp
index 1cb32cce32cbd..f24877611f077 100644
--- a/llvm/lib/Target/SPIRV/Analysis/SPIRVConvergenceRegionAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/Analysis/SPIRVConvergenceRegionAnalysis.cpp
@@ -14,7 +14,7 @@
 
 #include "SPIRVConvergenceRegionAnalysis.h"
 #include "SPIRV.h"
-#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/IntrinsicInst.h"
@@ -210,10 +210,10 @@ class ConvergenceRegionAnalyzer {
     return false;
   }
 
-  DenseSet<BasicBlock *>
+  SmallPtrSet<BasicBlock *, 0>
   findPathsToMatch(LoopInfo &LI, BasicBlock *From,
                    std::function<bool(const BasicBlock *)> isMatch) const {
-    DenseSet<BasicBlock *> Output;
+    SmallPtrSet<BasicBlock *, 0> Output;
 
     if (isMatch(From))
       Output.insert(From);
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 1e1b0080be5ac..e94b17d420b32 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -19,6 +19,7 @@
 #include "SPIRVUtils.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/IR/Dominators.h"
@@ -189,10 +190,10 @@ class SPIRVEmitIntrinsics
   bool HaveFunPtrs = false;
   DenseMap<Instruction *, Constant *> AggrConsts;
   DenseMap<Instruction *, Type *> AggrConstTypes;
-  DenseSet<Instruction *> AggrStores;
+  SmallPtrSet<Instruction *, 0> AggrStores;
   SmallPtrSet<Instruction *, 8> DeletedInstrs;
   GlobalVariableUsers GVUsers;
-  DenseSet<Value *> Named;
+  SmallPtrSet<Value *, 0> Named;
 
   // map of function declarations to <pointer arg index => element type>
   DenseMap<Function *, SmallVector<std::pair<unsigned, Type *>>> FDeclPtrTys;
@@ -224,7 +225,7 @@ class SPIRVEmitIntrinsics
   }
   // a register of Instructions that were visited by deduceOperandElementType()
   // to validate operand types with an instruction
-  DenseSet<Instruction *> TypeValidated;
+  SmallPtrSet<Instruction *, 0> TypeValidated;
 
   // well known result types of builtins
   enum WellKnownTypes { Event };
@@ -232,22 +233,24 @@ class SPIRVEmitIntrinsics
   // deduce element type of untyped pointers
   Type *deduceElementType(Value *I, bool UnknownElemTypeI8);
   Type *deduceElementTypeHelper(Value *I, bool UnknownElemTypeI8);
-  Type *deduceElementTypeHelper(Value *I, DenseSet<Value *> &Visited,
+  Type *deduceElementTypeHelper(Value *I, SmallPtrSet<Value *, 0> &Visited,
                                 bool UnknownElemTypeI8,
                                 bool IgnoreKnownType = false);
   Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
                                      bool UnknownElemTypeI8);
   Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
-                                     DenseSet<Value *> &Visited,
+                                     SmallPtrSet<Value *, 0> &Visited,
                                      bool UnknownElemTypeI8);
-  Type *deduceElementTypeByUsersDeep(Value *Op, DenseSet<Value *> &Visited,
+  Type *deduceElementTypeByUsersDeep(Value *Op,
+                                     SmallPtrSet<Value *, 0> &Visited,
                                      bool UnknownElemTypeI8);
   void maybeAssignPtrType(Type *&Ty, Value *I, Type *RefTy,
                           bool UnknownElemTypeI8);
 
   // deduce nested types of composites
   Type *deduceNestedTypeHelper(User *U, bool UnknownElemTypeI8);
-  Type *deduceNestedTypeHelper(User *U, Type *Ty, DenseSet<Value *> &Visited,
+  Type *deduceNestedTypeHelper(User *U, Type *Ty,
+                               SmallPtrSet<Value *, 0> &Visited,
                                bool UnknownElemTypeI8);
 
   // deduce Types of operands of the Instruction if possible
@@ -285,7 +288,7 @@ class SPIRVEmitIntrinsics
   void processParamTypesByFunHeader(Function *F, IRBuilder<> &B);
   Type *deduceFunParamElementType(Function *F, unsigned OpIdx);
   Type *deduceFunParamElementType(Function *F, unsigned OpIdx,
-                                  DenseSet<Function *> &FVisited);
+                                  SmallPtrSet<Function *, 0> &FVisited);
 
   bool deduceOperandElementTypeCalledFunction(
       CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
@@ -308,7 +311,7 @@ class SPIRVEmitIntrinsics
                        DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
   void propagateElemTypeRec(Value *Op, Type *PtrElemTy, Type *CastElemTy,
                             DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
-                            DenseSet<Value *> &Visited,
+                            SmallPtrSet<Value *, 0> &Visited,
                             DenseMap<Function *, CallInst *> Ptrcasts);
 
   void replaceAllUsesWith(Value *Src, Value *Dest, bool DeleteOld = true);
@@ -645,7 +648,7 @@ void SPIRVEmitIntrinsics::propagateElemType(
 void SPIRVEmitIntrinsics::propagateElemTypeRec(
     Value *Op, Type *PtrElemTy, Type *CastElemTy,
     DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
-  DenseSet<Value *> Visited;
+  SmallPtrSet<Value *, 0> Visited;
   DenseMap<Function *, CallInst *> Ptrcasts;
   propagateElemTypeRec(Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
                        std::move(Ptrcasts));
@@ -654,7 +657,8 @@ void SPIRVEmitIntrinsics::propagateElemTypeRec(
 void SPIRVEmitIntrinsics::propagateElemTypeRec(
     Value *Op, Type *PtrElemTy, Type *CastElemTy,
     DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
-    DenseSet<Value *> &Visited, DenseMap<Function *, CallInst *> Ptrcasts) {
+    SmallPtrSet<Value *, 0> &Visited,
+    DenseMap<Function *, CallInst *> Ptrcasts) {
   if (!Visited.insert(Op).second)
     return;
   SmallVector<User *> Users(Op->users());
@@ -677,15 +681,14 @@ void SPIRVEmitIntrinsics::propagateElemTypeRec(
 Type *
 SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
                                                   bool UnknownElemTypeI8) {
-  DenseSet<Value *> Visited;
+  SmallPtrSet<Value *, 0> Visited;
   return deduceElementTypeByValueDeep(ValueTy, Operand, Visited,
                                       UnknownElemTypeI8);
 }
 
-Type *
-SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
-                                                  DenseSet<Value *> &Visited,
-                                                  bool UnknownElemTypeI8) {
+Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
+    Type *ValueTy, Value *Operand, SmallPtrSet<Value *, 0> &Visited,
+    bool UnknownElemTypeI8) {
   Type *Ty = ValueTy;
   if (Operand) {
     if (auto *PtrTy = dyn_cast<PointerType>(Ty)) {
@@ -702,7 +705,7 @@ SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand,
 
 // Traverse User instructions to deduce an element pointer type of the operand.
 Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
-    Value *Op, DenseSet<Value *> &Visited, bool UnknownElemTypeI8) {
+    Value *Op, SmallPtrSet<Value *, 0> &Visited, bool UnknownElemTypeI8) {
   if (!Op || !isPointerTy(Op->getType()) || isa<ConstantPointerNull>(Op) ||
       isa<UndefValue>(Op))
     return nullptr;
@@ -740,7 +743,7 @@ static Type *getPointeeTypeByCallInst(StringRef DemangledName,
 // or nullptr otherwise.
 Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(Value *I,
                                                    bool UnknownElemTypeI8) {
-  DenseSet<Value *> Visited;
+  SmallPtrSet<Value *, 0> Visited;
   return deduceElementTypeHelper(I, Visited, UnknownElemTypeI8);
 }
 
@@ -927,10 +930,9 @@ Type *SPIRVEmitIntrinsics::getGEPType(GetElementPtrInst *Ref) {
   return Ty;
 }
 
-Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(Value *I,
-                                                   DenseSet<Value *> &Visited,
-                                                   bool UnknownElemTypeI8,
-                                                   bool IgnoreKnownType) {
+Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
+    Value *I, SmallPtrSet<Value *, 0> &Visited, bool UnknownElemTypeI8,
+    bool IgnoreKnownType) {
   // allow to pass nullptr as an argument
   if (!I)
     return nullptr;
@@ -1088,13 +1090,14 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(Value *I,
 // information is found or needed.
 Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U,
                                                   bool UnknownElemTypeI8) {
-  DenseSet<Value *> Visited;
+  SmallPtrSet<Value *, 0> Visited;
   return deduceNestedTypeHelper(U, U->getType(), Visited, UnknownElemTypeI8);
 }
 
-Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U, Type *OrigTy,
-                                                  DenseSet<Value *> &Visited,
-                                                  bool UnknownElemTypeI8) {
+Type *
+SPIRVEmitIntrinsics::deduceNestedTypeHelper(User *U, Type *OrigTy,
+                                            SmallPtrSet<Value *, 0> &Visited,
+                                            bool UnknownElemTypeI8) {
   if (!U)
     return OrigTy;
 
@@ -3050,18 +3053,17 @@ void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
 
 Type *SPIRVEmitIntrinsics::deduceFunParamElementType(Function *F,
                                                      unsigned OpIdx) {
-  DenseSet<Function *> FVisited;
+  SmallPtrSet<Function *, 0> FVisited;
   return deduceFunParamElementType(F, OpIdx, FVisited);
 }
 
-Type *
-SPIRVEmitIntrinsics::deduceFunParamElementType(Function *F, unsigned OpIdx,
-                                               DenseSet<Function *> &FVisited) {
+Type *SPIRVEmitIntrinsics::deduceFunParamElementType(
+    Function *F, unsigned OpIdx, SmallPtrSet<Function *, 0> &FVisited) {
   // maybe a cycle
   if (!FVisited.insert(F).second)
     return nullptr;
 
-  DenseSet<Value *> Visited;
+  SmallPtrSet<Value *, 0> Visited;
   SmallVector<std::pair<Function *, unsigned>> Lookup;
   // search in function's call sites
   for (User *U : F->users()) {
@@ -3546,7 +3548,7 @@ bool SPIRVEmitIntrinsics::postprocessTypes(Module &M) {
     // Try to improve the type deduced after all Functions are processed.
     if (auto *CI = dyn_cast<Instruction>(Op)) {
       CurrF = CI->getParent()->getParent();
-      DenseSet<Value *> Visited;
+      SmallPtrSet<Value *, 0> Visited;
       if (Type *ElemTy = deduceElementTypeHelper(Op, Visited, false, true)) {
         if (ElemTy != KnownTy) {
           DenseSet<std::pair<Value *, Value *>> VisitedSubst;
diff --git a/llvm/lib/Target/SPIRV/SPIRVMergeRegionExitTargets.cpp b/llvm/lib/Target/SPIRV/SPIRVMergeRegionExitTargets.cpp
index 899026fd95ef4..d1d40d0d899a5 100644
--- a/llvm/lib/Target/SPIRV/SPIRVMergeRegionExitTargets.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVMergeRegionExitTargets.cpp
@@ -18,7 +18,6 @@
 #include "SPIRVSubtarget.h"
 #include "SPIRVUtils.h"
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/IR/Dominators.h"
@@ -167,7 +166,7 @@ static void validateRegionExits(const SPIRV::ConvergenceRegion *CR) {
   for (auto *Child : CR->Children)
     validateRegionExits(Child);
 
-  DenseSet<BasicBlock *> ExitTargets;
+  SmallPtrSet<BasicBlock *, 0> ExitTargets;
   for (auto *Exit : CR->Exits) {
     for (auto *BB : successors(Exit)) {
       if (CR->Blocks.count(BB) == 0)
diff --git a/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp b/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
index b9d3095c36a8e..2b13a8da1f5e1 100644
--- a/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
@@ -14,7 +14,6 @@
 #include "SPIRVSubtarget.h"
 #include "SPIRVUtils.h"
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/IR/CFG.h"
@@ -34,7 +33,7 @@
 using namespace llvm;
 using namespace SPIRV;
 
-using BlockSet = DenseSet<BasicBlock *>;
+using BlockSet = SmallPtrSet<BasicBlock *, 0>;
 using Edge = std::pair<BasicBlock *, BasicBlock *>;
 
 // Helper function to do a partial order visit from the block |Start|, calling
@@ -63,7 +62,7 @@ getRegionForHeader(const ConvergenceRegion *Node, BasicBlock *BB) {
 // Returns the single BasicBlock exiting the convergence region `CR`,
 // nullptr if no such exit exists.
 static BasicBlock *getExitFor(const ConvergenceRegion *CR) {
-  DenseSet<BasicBlock *> ExitTargets;
+  SmallPtrSet<BasicBlock *, 0> ExitTargets;
   for (BasicBlock *Exit : CR->Exits) {
     for (BasicBlock *Successor : successors(Exit)) {
       if (CR->Blocks.count(Successor) == 0)
@@ -427,7 +426,7 @@ class SPIRVStructurizer : public FunctionPass {
     // clang-format on
     std::vector<Edge>
     createAliasBlocksForComplexEdges(std::vector<Edge> Edges) {
-      DenseSet<BasicBlock *> Seen;
+      SmallPtrSet<BasicBlock *, 0> Seen;
       std::vector<Edge> Output;
       Output.reserve(Edges.size());
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 6abdffe743f74..7246a968aabac 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -678,12 +678,12 @@ Type *parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx) {
   return nullptr;
 }
 
-DenseSet<BasicBlock *>
+SmallPtrSet<BasicBlock *, 0>
 PartialOrderingVisitor::getReachableFrom(BasicBlock *Start) {
   std::queue<BasicBlock *> ToVisit;
   ToVisit.push(Start);
 
-  DenseSet<BasicBlock *> Output;
+  SmallPtrSet<BasicBlock *, 0> Output;
   while (ToVisit.size() != 0) {
     BasicBlock *BB = ToVisit.front();
     ToVisit.pop();
@@ -831,7 +831,7 @@ bool PartialOrderingVisitor::compare(const BasicBlock *LHS,
 
 void PartialOrderingVisitor::partialOrderVisit(
     BasicBlock &Start, std::function<bool(BasicBlock *)> Op) {
-  DenseSet<BasicBlock *> Reachable = getReachableFrom(&Start);
+  SmallPtrSet<BasicBlock *, 0> Reachable = getReachableFrom(&Start);
   assert(BlockToOrder.count(&Start) != 0);
 
   // Skipping blocks with a rank inferior to |Start|'s rank.
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index 78346abeeafd8..a52012deff403 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -15,7 +15,7 @@
 
 #include "MCTargetDesc/SPIRVBaseInfo.h"
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/IR/Dominators.h"
@@ -73,7 +73,7 @@ class PartialOrderingVisitor {
   DomTreeBuilder::BBDomTree DT;
   LoopInfo LI;
 
-  DenseSet<BasicBlock *> Queued = {};
+  SmallPtrSet<BasicBlock *, 0> Queued = {};
   std::queue<BasicBlock *> ToVisit = {};
 
   struct OrderInfo {
@@ -86,7 +86,7 @@ class PartialOrderingVisitor {
   std::vector<BasicBlock *> Order = {};
 
   // Get all basic-blocks reachable from Start.
-  DenseSet<BasicBlock *> getReachableFrom(BasicBlock *Start);
+  SmallPtrSet<BasicBlock *, 0> getReachableFrom(BasicBlock *Start);
 
   // Internal function used to determine the partial ordering.
   // Visits |BB| with the current rank being |Rank|.

>From b05f92f1bc1377e4ce50a44bfed902b36a666fe1 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Fri, 12 Jun 2026 10:27:09 -0700
Subject: [PATCH 3/4] migrate more

---
 llvm/include/llvm/ADT/SCCIterator.h           | 18 +++++--
 .../llvm/Analysis/DOTGraphTraitsPass.h        |  4 +-
 llvm/include/llvm/CGData/OutlinedHashTree.h   |  5 +-
 llvm/include/llvm/CGData/StableFunctionMap.h  |  6 +--
 .../CodeGen/GlobalISel/LegacyLegalizerInfo.h  |  5 +-
 llvm/include/llvm/CodeGen/LexicalScopes.h     | 22 ++++----
 llvm/include/llvm/CodeGen/LiveStacks.h        | 13 +++--
 llvm/include/llvm/CodeGen/RDFGraph.h          |  5 +-
 llvm/include/llvm/CodeGen/RDFLiveness.h       |  3 +-
 llvm/include/llvm/DebugInfo/PDB/PDBExtras.h   |  4 +-
 .../llvm/ExecutionEngine/Orc/ELFNixPlatform.h | 23 ++-------
 llvm/include/llvm/MC/MCPseudoProbe.h          | 36 +++++++------
 llvm/include/llvm/ObjectYAML/DWARFYAML.h      |  3 +-
 llvm/include/llvm/ProfileData/MemProf.h       | 12 +++++
 llvm/include/llvm/ProfileData/SampleProf.h    | 51 +++++++++++--------
 .../llvm/ProfileData/SampleProfReader.h       |  8 +--
 llvm/include/llvm/Transforms/IPO/GlobalDCE.h  |  3 +-
 .../Transforms/IPO/SampleContextTracker.h     |  3 +-
 .../Transforms/IPO/SampleProfileMatcher.h     | 37 +++++---------
 .../llvm/Transforms/IPO/SampleProfileProbe.h  |  8 ++-
 .../Transforms/Instrumentation/MemProfUse.h   | 11 +---
 llvm/lib/CGData/OutlinedHashTree.cpp          |  4 +-
 llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 18 +++++--
 llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h   |  7 +--
 llvm/lib/CodeGen/LexicalScopes.cpp            | 38 +++++++-------
 llvm/lib/CodeGen/LiveStacks.cpp               | 23 +++++----
 llvm/lib/CodeGen/RDFGraph.cpp                 | 15 +++---
 llvm/lib/CodeGen/RDFLiveness.cpp              | 21 +++++---
 llvm/lib/CodeGen/StackSlotColoring.cpp        |  2 +-
 llvm/lib/DebugInfo/PDB/PDBSymbolFunc.cpp      |  4 +-
 .../RuntimeDyld/RuntimeDyldImpl.h             |  4 +-
 llvm/lib/IR/PrintPasses.cpp                   | 13 ++---
 llvm/lib/MC/MCPseudoProbe.cpp                 |  2 +-
 llvm/lib/ProfileData/SampleProf.cpp           |  8 +--
 llvm/lib/Support/Z3Solver.cpp                 | 14 ++---
 llvm/lib/Target/AArch64/AArch64.h             |  4 +-
 .../Target/AArch64/AArch64SIMDInstrOpt.cpp    |  4 +-
 .../AMDGPU/AMDGPUMarkLastScratchLoad.cpp      |  4 +-
 .../AMDGPU/AMDGPURewriteAGPRCopyMFMA.cpp      |  2 +-
 .../MCTargetDesc/HexagonMCTargetDesc.cpp      |  9 ++--
 llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp     |  2 +-
 llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 21 ++++----
 llvm/lib/Target/SPIRV/SPIRVUtils.h            |  4 +-
 llvm/lib/Transforms/IPO/GlobalDCE.cpp         | 12 +++--
 llvm/lib/Transforms/IPO/SampleProfile.cpp     |  4 +-
 .../Transforms/IPO/SampleProfileMatcher.cpp   |  9 ++--
 .../lib/Transforms/IPO/SampleProfileProbe.cpp |  8 +--
 .../tools/llvm-exegesis/lib/BenchmarkResult.h |  4 +-
 llvm/tools/llvm-exegesis/lib/SnippetFile.cpp  |  4 +-
 .../llvm-exegesis/lib/SubprocessMemory.cpp    | 20 ++++----
 .../llvm-exegesis/lib/SubprocessMemory.h      | 14 ++---
 llvm/tools/llvm-objdump/SourcePrinter.h       |  5 +-
 llvm/tools/llvm-profgen/ProfiledBinary.cpp    | 12 ++---
 llvm/tools/llvm-profgen/ProfiledBinary.h      |  7 ++-
 .../llvm-exegesis/X86/SnippetFileTest.cpp     |  4 +-
 .../X86/SubprocessMemoryTest.cpp              |  6 +--
 llvm/utils/TableGen/DFAPacketizerEmitter.cpp  |  9 ++--
 57 files changed, 309 insertions(+), 312 deletions(-)

diff --git a/llvm/include/llvm/ADT/SCCIterator.h b/llvm/include/llvm/ADT/SCCIterator.h
index 5e0ca2eb949a0..742a1ff5aabeb 100644
--- a/llvm/include/llvm/ADT/SCCIterator.h
+++ b/llvm/include/llvm/ADT/SCCIterator.h
@@ -25,14 +25,13 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/iterator.h"
 #include <cassert>
 #include <cstddef>
 #include <iterator>
 #include <queue>
 #include <set>
-#include <unordered_map>
-#include <unordered_set>
 #include <vector>
 
 namespace llvm {
@@ -292,7 +291,10 @@ class scc_member_iterator {
     return true;
   }
 
-  std::unordered_map<NodeType *, NodeInfo> NodeInfoMap;
+  // NodeInfo::Group is self-referential and unionGroups follows pointers into
+  // the map values, so the map must never relocate elements after the initial
+  // population: reserve() upfront and do not insert afterwards.
+  DenseMap<NodeType *, NodeInfo> NodeInfoMap;
   NodesType Nodes;
 
 public:
@@ -311,6 +313,7 @@ scc_member_iterator<GraphT, GT>::scc_member_iterator(
 
   // Initialize auxilary node information.
   NodeInfoMap.clear();
+  NodeInfoMap.reserve(InputNodes.size());
   for (auto *Node : InputNodes) {
     // Construct a `NodeInfo` object in place.  `insert()` would involve a copy
     // construction, invalidating the initial value of the `Group` field, which
@@ -335,7 +338,7 @@ scc_member_iterator<GraphT, GT>::scc_member_iterator(
 
   // Traverse all the edges and compute the Maximum Weight Spanning Tree
   // using Kruskal's algorithm.
-  std::unordered_set<const EdgeType *> MSTEdges;
+  SmallPtrSet<const EdgeType *, 0> MSTEdges;
   for (auto *Edge : SortedEdges) {
     if (unionGroups(Edge))
       MSTEdges.insert(Edge);
@@ -365,7 +368,12 @@ scc_member_iterator<GraphT, GT>::scc_member_iterator(
     Queue.pop();
     Nodes.push_back(Node);
     for (auto &Edge : Node->Edges) {
-      NodeInfo &Info = NodeInfoMap[Edge.Target];
+      // Edges to nodes outside the SCC carry no MST state; skip them instead
+      // of inserting a fresh entry (the map must not grow at this point).
+      auto It = NodeInfoMap.find(Edge.Target);
+      if (It == NodeInfoMap.end())
+        continue;
+      NodeInfo &Info = It->second;
       Info.IncomingMSTEdges.erase(&Edge);
       if (MSTEdges.count(&Edge) && Info.IncomingMSTEdges.empty()) {
         Queue.push(Edge.Target);
diff --git a/llvm/include/llvm/Analysis/DOTGraphTraitsPass.h b/llvm/include/llvm/Analysis/DOTGraphTraitsPass.h
index fe48f9910acae..4c9538d8a2cda 100644
--- a/llvm/include/llvm/Analysis/DOTGraphTraitsPass.h
+++ b/llvm/include/llvm/Analysis/DOTGraphTraitsPass.h
@@ -13,12 +13,12 @@
 #ifndef LLVM_ANALYSIS_DOTGRAPHTRAITSPASS_H
 #define LLVM_ANALYSIS_DOTGRAPHTRAITSPASS_H
 
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Analysis/CFGPrinter.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/GraphWriter.h"
-#include <unordered_set>
 
-static std::unordered_set<std::string> nameObj;
+static llvm::StringSet<> nameObj;
 
 namespace llvm {
 
diff --git a/llvm/include/llvm/CGData/OutlinedHashTree.h b/llvm/include/llvm/CGData/OutlinedHashTree.h
index 8cbc50bc1b9ee..af0a392e38a84 100644
--- a/llvm/include/llvm/CGData/OutlinedHashTree.h
+++ b/llvm/include/llvm/CGData/OutlinedHashTree.h
@@ -21,8 +21,6 @@
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 
-#include <unordered_map>
-
 namespace llvm {
 
 /// A HashNode is an entry in an OutlinedHashTree, holding a hash value
@@ -35,8 +33,7 @@ struct HashNode {
   /// The number of terminals in the sequence ending at this node.
   std::optional<unsigned> Terminals;
   /// The successors of this node.
-  /// We don't use DenseMap as a stable_hash value can be tombstone.
-  std::unordered_map<stable_hash, std::unique_ptr<HashNode>> Successors;
+  DenseMap<stable_hash, std::unique_ptr<HashNode>> Successors;
 };
 
 class OutlinedHashTree {
diff --git a/llvm/include/llvm/CGData/StableFunctionMap.h b/llvm/include/llvm/CGData/StableFunctionMap.h
index 50db26d31df37..94585e958485e 100644
--- a/llvm/include/llvm/CGData/StableFunctionMap.h
+++ b/llvm/include/llvm/CGData/StableFunctionMap.h
@@ -99,9 +99,9 @@ struct StableFunctionMap {
     friend struct StableFunctionMapRecord;
   };
 
-  // Note: DenseMap requires value type to be copyable even if only using
-  // in-place insertion. Use STL instead. This also affects the
-  // deletion-while-iteration in finalize().
+  // Note: EntryStorage contains a std::once_flag, which is neither copyable
+  // nor movable, and the lazy-loading design relies on value addresses being
+  // stable. DenseMap relocates values on rehash, so use std::unordered_map.
   using HashFuncsMapType = std::unordered_map<stable_hash, EntryStorage>;
 
   /// Get the HashToFuncs map for serialization.
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h
index e6d593e4f6d49..c4ceb99588906 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h
@@ -19,7 +19,6 @@
 #include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/CodeGenTypes/LowLevelType.h"
 #include "llvm/Support/Compiler.h"
-#include <unordered_map>
 #include <vector>
 
 namespace llvm {
@@ -456,9 +455,9 @@ class LegacyLegalizerInfo {
   // Data structures used by getAction:
   SmallVector<SizeAndActionsVec, 1> ScalarActions[LastOp - FirstOp + 1];
   SmallVector<SizeAndActionsVec, 1> ScalarInVectorActions[LastOp - FirstOp + 1];
-  std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
+  DenseMap<uint16_t, SmallVector<SizeAndActionsVec, 1>>
       AddrSpace2PointerActions[LastOp - FirstOp + 1];
-  std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
+  DenseMap<uint16_t, SmallVector<SizeAndActionsVec, 1>>
       NumElements2Actions[LastOp - FirstOp + 1];
 };
 
diff --git a/llvm/include/llvm/CodeGen/LexicalScopes.h b/llvm/include/llvm/CodeGen/LexicalScopes.h
index 6a52bdfb2f48c..1faa37cb3dc68 100644
--- a/llvm/include/llvm/CodeGen/LexicalScopes.h
+++ b/llvm/include/llvm/CodeGen/LexicalScopes.h
@@ -23,7 +23,7 @@
 #include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/Support/Compiler.h"
 #include <cassert>
-#include <unordered_map>
+#include <memory>
 #include <utility>
 
 namespace llvm {
@@ -190,19 +190,19 @@ class LexicalScopes {
   /// Find an abstract scope or return null.
   LexicalScope *findAbstractScope(const DILocalScope *N) {
     auto I = AbstractScopeMap.find(N);
-    return I != AbstractScopeMap.end() ? &I->second : nullptr;
+    return I != AbstractScopeMap.end() ? I->second.get() : nullptr;
   }
 
   /// Find an inlined scope for the given scope/inlined-at.
   LexicalScope *findInlinedScope(const DILocalScope *N, const DILocation *IA) {
     auto I = InlinedLexicalScopeMap.find(std::make_pair(N, IA));
-    return I != InlinedLexicalScopeMap.end() ? &I->second : nullptr;
+    return I != InlinedLexicalScopeMap.end() ? I->second.get() : nullptr;
   }
 
   /// Find regular lexical scope or return null.
   LexicalScope *findLexicalScope(const DILocalScope *N) {
     auto I = LexicalScopeMap.find(N);
-    return I != LexicalScopeMap.end() ? &I->second : nullptr;
+    return I != LexicalScopeMap.end() ? I->second.get() : nullptr;
   }
 
   /// Find or create an abstract lexical scope.
@@ -246,18 +246,18 @@ class LexicalScopes {
   DenseMap<const DISubprogram *, const Function *> FunctionMap;
 
   /// Tracks the scopes in the current function.
-  // Use an unordered_map to ensure value pointer validity over insertion.
-  std::unordered_map<const DILocalScope *, LexicalScope> LexicalScopeMap;
+  // The scopes are heap-allocated to ensure LexicalScope pointer validity
+  // over insertion.
+  DenseMap<const DILocalScope *, std::unique_ptr<LexicalScope>> LexicalScopeMap;
 
   /// Tracks inlined function scopes in current function.
-  std::unordered_map<std::pair<const DILocalScope *, const DILocation *>,
-                     LexicalScope,
-                     pair_hash<const DILocalScope *, const DILocation *>>
+  DenseMap<std::pair<const DILocalScope *, const DILocation *>,
+           std::unique_ptr<LexicalScope>>
       InlinedLexicalScopeMap;
 
   /// These scopes are  not included LexicalScopeMap.
-  // Use an unordered_map to ensure value pointer validity over insertion.
-  std::unordered_map<const DILocalScope *, LexicalScope> AbstractScopeMap;
+  DenseMap<const DILocalScope *, std::unique_ptr<LexicalScope>>
+      AbstractScopeMap;
 
   /// Tracks abstract scopes constructed while processing a function.
   SmallVector<LexicalScope *, 4> AbstractScopesList;
diff --git a/llvm/include/llvm/CodeGen/LiveStacks.h b/llvm/include/llvm/CodeGen/LiveStacks.h
index f2ecdca257bb1..c31ef0b05c36b 100644
--- a/llvm/include/llvm/CodeGen/LiveStacks.h
+++ b/llvm/include/llvm/CodeGen/LiveStacks.h
@@ -15,6 +15,7 @@
 #ifndef LLVM_CODEGEN_LIVESTACKS_H
 #define LLVM_CODEGEN_LIVESTACKS_H
 
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/CodeGen/LiveInterval.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/IR/PassManager.h"
@@ -22,7 +23,7 @@
 #include "llvm/PassRegistry.h"
 #include <cassert>
 #include <map>
-#include <unordered_map>
+#include <memory>
 
 namespace llvm {
 
@@ -40,8 +41,10 @@ class LiveStacks {
   ///
   VNInfo::Allocator VNInfoAllocator;
 
-  /// S2IMap - Stack slot indices to live interval mapping.
-  using SS2IntervalMap = std::unordered_map<int, LiveInterval>;
+  /// S2IMap - Stack slot indices to live interval mapping. The intervals are
+  /// heap-allocated so that references remain valid while new slots are
+  /// created.
+  using SS2IntervalMap = DenseMap<int, std::unique_ptr<LiveInterval>>;
   SS2IntervalMap S2IMap;
 
   /// S2RCMap - Stack slot indices to register class mapping.
@@ -65,14 +68,14 @@ class LiveStacks {
     assert(Slot >= 0 && "Spill slot indice must be >= 0");
     SS2IntervalMap::iterator I = S2IMap.find(Slot);
     assert(I != S2IMap.end() && "Interval does not exist for stack slot");
-    return I->second;
+    return *I->second;
   }
 
   const LiveInterval &getInterval(int Slot) const {
     assert(Slot >= 0 && "Spill slot indice must be >= 0");
     SS2IntervalMap::const_iterator I = S2IMap.find(Slot);
     assert(I != S2IMap.end() && "Interval does not exist for stack slot");
-    return I->second;
+    return *I->second;
   }
 
   bool hasInterval(int Slot) const { return S2IMap.count(Slot); }
diff --git a/llvm/include/llvm/CodeGen/RDFGraph.h b/llvm/include/llvm/CodeGen/RDFGraph.h
index c1ec2ddff14a3..27b5795b8ed2d 100644
--- a/llvm/include/llvm/CodeGen/RDFGraph.h
+++ b/llvm/include/llvm/CodeGen/RDFGraph.h
@@ -226,6 +226,7 @@
 
 #include "RDFRegisters.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/MC/LaneBitmask.h"
 #include "llvm/Support/Allocator.h"
@@ -236,7 +237,6 @@
 #include <map>
 #include <memory>
 #include <set>
-#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -770,9 +770,8 @@ struct DataFlowGraph {
     StorageType Stack;
   };
 
-  // Make this std::unordered_map for speed of accessing elements.
   // Map: Register (physical or virtual) -> DefStack
-  using DefStackMap = std::unordered_map<RegisterId, DefStack>;
+  using DefStackMap = DenseMap<RegisterId, DefStack>;
 
   LLVM_ABI void build(const Config &config);
   void build() { build(Config()); }
diff --git a/llvm/include/llvm/CodeGen/RDFLiveness.h b/llvm/include/llvm/CodeGen/RDFLiveness.h
index da88fb2bbeb3e..0ff4bb1e3b5a0 100644
--- a/llvm/include/llvm/CodeGen/RDFLiveness.h
+++ b/llvm/include/llvm/CodeGen/RDFLiveness.h
@@ -18,7 +18,6 @@
 #include "llvm/MC/LaneBitmask.h"
 #include <map>
 #include <set>
-#include <unordered_map>
 #include <unordered_set>
 #include <utility>
 
@@ -57,7 +56,7 @@ struct Liveness {
   using LiveMapType = RegisterAggrMap<MachineBasicBlock *>;
   using NodeRef = detail::NodeRef;
   using NodeRefSet = std::unordered_set<NodeRef>;
-  using RefMap = std::unordered_map<RegisterId, NodeRefSet>;
+  using RefMap = DenseMap<RegisterId, NodeRefSet>;
 
   Liveness(MachineRegisterInfo &mri, const DataFlowGraph &g)
       : DFG(g), TRI(g.getTRI()), PRI(g.getPRI()), MDT(g.getDT()),
diff --git a/llvm/include/llvm/DebugInfo/PDB/PDBExtras.h b/llvm/include/llvm/DebugInfo/PDB/PDBExtras.h
index d35b162d56a6b..0a5eca5cf66ef 100644
--- a/llvm/include/llvm/DebugInfo/PDB/PDBExtras.h
+++ b/llvm/include/llvm/DebugInfo/PDB/PDBExtras.h
@@ -9,19 +9,19 @@
 #ifndef LLVM_DEBUGINFO_PDB_PDBEXTRAS_H
 #define LLVM_DEBUGINFO_PDB_PDBEXTRAS_H
 
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/DebugInfo/PDB/PDBTypes.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cstdint>
-#include <unordered_map>
 
 namespace llvm {
 
 namespace pdb {
 
-using TagStats = std::unordered_map<PDB_SymType, int>;
+using TagStats = DenseMap<PDB_SymType, int>;
 
 LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const PDB_VariantType &Value);
 LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const PDB_CallingConv &Conv);
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h b/llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h
index 1d1c51d40be69..e601bca181483 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H
 #define LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H
 
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ExecutionEngine/Orc/Core.h"
 #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
@@ -22,7 +23,6 @@
 
 #include <future>
 #include <thread>
-#include <unordered_map>
 #include <vector>
 
 namespace llvm {
@@ -43,27 +43,10 @@ struct RuntimeFunction {
   ExecutorAddr Addr;
 };
 
-struct FunctionPairKeyHash {
-  std::size_t
-  operator()(const std::pair<RuntimeFunction *, RuntimeFunction *> &key) const {
-    return std::hash<void *>()(key.first->Addr.toPtr<void *>()) ^
-           std::hash<void *>()(key.second->Addr.toPtr<void *>());
-  }
-};
-
-struct FunctionPairKeyEqual {
-  std::size_t
-  operator()(const std::pair<RuntimeFunction *, RuntimeFunction *> &lhs,
-             const std::pair<RuntimeFunction *, RuntimeFunction *> &rhs) const {
-    return lhs.first == rhs.first && lhs.second == rhs.second;
-  }
-};
-
-using DeferredRuntimeFnMap = std::unordered_map<
+using DeferredRuntimeFnMap = DenseMap<
     std::pair<RuntimeFunction *, RuntimeFunction *>,
     SmallVector<std::pair<shared::WrapperFunctionCall::ArgDataBufferType,
-                          shared::WrapperFunctionCall::ArgDataBufferType>>,
-    FunctionPairKeyHash, FunctionPairKeyEqual>;
+                          shared::WrapperFunctionCall::ArgDataBufferType>>>;
 
 /// Mediates between ELFNix initialization and ExecutionSession state.
 class LLVM_ABI ELFNixPlatform : public Platform {
diff --git a/llvm/include/llvm/MC/MCPseudoProbe.h b/llvm/include/llvm/MC/MCPseudoProbe.h
index 2079e41e319f0..e5f581a1758a2 100644
--- a/llvm/include/llvm/MC/MCPseudoProbe.h
+++ b/llvm/include/llvm/MC/MCPseudoProbe.h
@@ -69,7 +69,6 @@
 #include <string>
 #include <tuple>
 #include <type_traits>
-#include <unordered_map>
 #include <vector>
 
 namespace llvm {
@@ -273,10 +272,12 @@ class MCPseudoProbeInlineTreeBase {
   MCPseudoProbeInlineTreeBase<ProbesType, DerivedProbeInlineTreeType,
                               InlinedProbeTreeMap> *Parent = nullptr;
   DerivedProbeInlineTreeType *getOrAddNode(const InlineSite &Site) {
-    auto Ret = Children.emplace(
-        Site, std::make_unique<DerivedProbeInlineTreeType>(Site));
-    Ret.first->second->Parent = this;
-    return Ret.first->second.get();
+    auto [It, Inserted] = Children.try_emplace(Site);
+    if (Inserted) {
+      It->second = std::make_unique<DerivedProbeInlineTreeType>(Site);
+      It->second->Parent = this;
+    }
+    return It->second.get();
   };
 };
 
@@ -285,17 +286,10 @@ class MCPseudoProbeInlineTreeBase {
 // instance is created as the root of a tree.
 // A real instance of this class is created for each function, either a
 // not inlined function that has code in .text section or an inlined function.
-struct InlineSiteHash {
-  uint64_t operator()(const InlineSite &Site) const {
-    return std::get<0>(Site) ^ std::get<1>(Site);
-  }
-};
 class MCPseudoProbeInlineTree
     : public MCPseudoProbeInlineTreeBase<
           std::vector<MCPseudoProbe>, MCPseudoProbeInlineTree,
-          std::unordered_map<InlineSite,
-                             std::unique_ptr<MCPseudoProbeInlineTree>,
-                             InlineSiteHash>> {
+          DenseMap<InlineSite, std::unique_ptr<MCPseudoProbeInlineTree>>> {
 public:
   MCPseudoProbeInlineTree() = default;
   MCPseudoProbeInlineTree(uint64_t Guid) { this->Guid = Guid; }
@@ -345,12 +339,16 @@ class MCPseudoProbeSections {
 public:
   void addPseudoProbe(MCSymbol *FuncSym, const MCPseudoProbe &Probe,
                       const MCPseudoProbeInlineStack &InlineStack) {
-    MCProbeDivisions[FuncSym].addPseudoProbe(Probe, InlineStack);
+    auto &Tree = MCProbeDivisions[FuncSym];
+    if (!Tree)
+      Tree = std::make_unique<MCPseudoProbeInlineTree>();
+    Tree->addPseudoProbe(Probe, InlineStack);
   }
 
-  // The addresses of MCPseudoProbeInlineTree are used by the tree structure and
-  // need to be stable.
-  using MCProbeDivisionMap = std::unordered_map<MCSymbol *, MCPseudoProbeInlineTree>;
+  // The addresses of MCPseudoProbeInlineTree are used by the tree structure
+  // and need to be stable, so the trees are heap-allocated.
+  using MCProbeDivisionMap =
+      DenseMap<MCSymbol *, std::unique_ptr<MCPseudoProbeInlineTree>>;
 
 private:
   // A collection of MCPseudoProbe for each function. The MCPseudoProbes are
@@ -394,8 +392,8 @@ class MCPseudoProbeDecoder {
   //    reallocation so that pointers to its elements will become invalid.
   // 2) Probes belonging to function record must be contiguous in PseudoProbeVec
   //    as owning InlineTree references them with an ArrayRef to save space.
-  std::unordered_map<const MCDecodedPseudoProbeInlineTree *,
-                     std::vector<MCDecodedPseudoProbe>>
+  DenseMap<const MCDecodedPseudoProbeInlineTree *,
+           std::vector<MCDecodedPseudoProbe>>
       InjectedProbeMap;
   // Decoded inline records vector.
   std::vector<MCDecodedPseudoProbeInlineTree> InlineTreeVec;
diff --git a/llvm/include/llvm/ObjectYAML/DWARFYAML.h b/llvm/include/llvm/ObjectYAML/DWARFYAML.h
index 46ec59feef40f..363f2631c172e 100644
--- a/llvm/include/llvm/ObjectYAML/DWARFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/DWARFYAML.h
@@ -15,6 +15,7 @@
 #ifndef LLVM_OBJECTYAML_DWARFYAML_H
 #define LLVM_OBJECTYAML_DWARFYAML_H
 
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/BinaryFormat/Dwarf.h"
@@ -288,7 +289,7 @@ struct Data {
   LLVM_ABI StringRef getAbbrevTableContentByIndex(uint64_t Index) const;
 
 private:
-  mutable std::unordered_map<uint64_t, AbbrevTableInfo> AbbrevTableInfoMap;
+  mutable DenseMap<uint64_t, AbbrevTableInfo> AbbrevTableInfoMap;
   mutable std::unordered_map<uint64_t, std::string> AbbrevTableContents;
 };
 
diff --git a/llvm/include/llvm/ProfileData/MemProf.h b/llvm/include/llvm/ProfileData/MemProf.h
index e4bc9ee6f6ad1..391ac0f339f67 100644
--- a/llvm/include/llvm/ProfileData/MemProf.h
+++ b/llvm/include/llvm/ProfileData/MemProf.h
@@ -853,5 +853,17 @@ struct LineLocation {
 // A pair of a call site location and its corresponding callee GUID.
 using CallEdgeTy = std::pair<LineLocation, uint64_t>;
 } // namespace memprof
+
+template <> struct DenseMapInfo<memprof::LineLocation> {
+  static unsigned getHashValue(const memprof::LineLocation &Val) {
+    return DenseMapInfo<uint64_t>::getHashValue(Val.getHashCode());
+  }
+
+  static bool isEqual(const memprof::LineLocation &LHS,
+                      const memprof::LineLocation &RHS) {
+    return LHS == RHS;
+  }
+};
+
 } // namespace llvm
 #endif // LLVM_PROFILEDATA_MEMPROF_H
diff --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h
index a3f25e5402ff9..cb0344e848c34 100644
--- a/llvm/include/llvm/ProfileData/SampleProf.h
+++ b/llvm/include/llvm/ProfileData/SampleProf.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_PROFILEDATA_SAMPLEPROF_H
 #define LLVM_PROFILEDATA_SAMPLEPROF_H
 
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/SmallVector.h"
@@ -315,13 +316,22 @@ struct LineLocation {
   uint32_t Discriminator;
 };
 
-struct LineLocationHash {
-  uint64_t operator()(const LineLocation &Loc) const {
-    return Loc.getHashCode();
+LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const LineLocation &Loc);
+
+} // end namespace sampleprof
+
+template <> struct DenseMapInfo<sampleprof::LineLocation> {
+  static unsigned getHashValue(const sampleprof::LineLocation &Val) {
+    return DenseMapInfo<uint64_t>::getHashValue(Val.getHashCode());
+  }
+
+  static bool isEqual(const sampleprof::LineLocation &LHS,
+                      const sampleprof::LineLocation &RHS) {
+    return LHS == RHS;
   }
 };
 
-LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const LineLocation &Loc);
+namespace sampleprof {
 
 /// Key represents type of a C++ polymorphic class type by its vtable and value
 /// represents its counter.
@@ -360,7 +370,7 @@ class SampleRecord {
   };
 
   using SortedCallTargetSet = std::set<CallTarget, CallTargetComparator>;
-  using CallTargetMap = std::unordered_map<FunctionId, uint64_t>;
+  using CallTargetMap = DenseMap<FunctionId, uint64_t>;
   SampleRecord() = default;
 
   /// Increment the number of samples for this record by \p S.
@@ -772,8 +782,7 @@ using BodySampleMap = std::map<LineLocation, SampleRecord>;
 using FunctionSamplesMap = std::map<FunctionId, FunctionSamples>;
 using CallsiteSampleMap = std::map<LineLocation, FunctionSamplesMap>;
 using CallsiteTypeMap = std::map<LineLocation, TypeCountMap>;
-using LocToLocMap =
-    std::unordered_map<LineLocation, LineLocation, LineLocationHash>;
+using LocToLocMap = DenseMap<LineLocation, LineLocation>;
 
 /// Representation of the samples collected for a function.
 ///
@@ -979,11 +988,11 @@ class FunctionSamples {
   /// \p Loc with the maximum total sample count. If \p Remapper or \p
   /// FuncNameToProfNameMap is not nullptr, use them to find FunctionSamples
   /// with equivalent name as \p CalleeName.
-  LLVM_ABI const FunctionSamples *findFunctionSamplesAt(
-      const LineLocation &Loc, StringRef CalleeName,
-      SampleProfileReaderItaniumRemapper *Remapper,
-      const HashKeyMap<std::unordered_map, FunctionId, FunctionId>
-          *FuncNameToProfNameMap = nullptr) const;
+  LLVM_ABI const FunctionSamples *
+  findFunctionSamplesAt(const LineLocation &Loc, StringRef CalleeName,
+                        SampleProfileReaderItaniumRemapper *Remapper,
+                        const HashKeyMap<DenseMap, FunctionId, FunctionId>
+                            *FuncNameToProfNameMap = nullptr) const;
 
   bool empty() const { return TotalSamples == 0; }
 
@@ -1154,10 +1163,10 @@ class FunctionSamples {
   /// corresponding function is no less than \p Threshold, add its corresponding
   /// GUID to \p S. Also traverse the BodySamples to add hot CallTarget's GUID
   /// to \p S.
-  void findInlinedFunctions(DenseSet<GlobalValue::GUID> &S,
-                            const HashKeyMap<std::unordered_map, FunctionId,
-                                             Function *>  &SymbolMap,
-                            uint64_t Threshold) const {
+  void findInlinedFunctions(
+      DenseSet<GlobalValue::GUID> &S,
+      const HashKeyMap<DenseMap, FunctionId, Function *> &SymbolMap,
+      uint64_t Threshold) const {
     if (TotalSamples <= Threshold)
       return;
     auto IsDeclaration = [](const Function *F) {
@@ -1310,11 +1319,11 @@ class FunctionSamples {
   /// If \p Remapper or \p FuncNameToProfNameMap is not nullptr, it will be used
   /// to find matching FunctionSamples with not exactly the same but equivalent
   /// name.
-  LLVM_ABI const FunctionSamples *findFunctionSamples(
-      const DILocation *DIL,
-      SampleProfileReaderItaniumRemapper *Remapper = nullptr,
-      const HashKeyMap<std::unordered_map, FunctionId, FunctionId>
-          *FuncNameToProfNameMap = nullptr) const;
+  LLVM_ABI const FunctionSamples *
+  findFunctionSamples(const DILocation *DIL,
+                      SampleProfileReaderItaniumRemapper *Remapper = nullptr,
+                      const HashKeyMap<DenseMap, FunctionId, FunctionId>
+                          *FuncNameToProfNameMap = nullptr) const;
 
   LLVM_ABI static bool ProfileIsProbeBased;
 
diff --git a/llvm/include/llvm/ProfileData/SampleProfReader.h b/llvm/include/llvm/ProfileData/SampleProfReader.h
index 71140af3b25e3..9854e90e6ffe7 100644
--- a/llvm/include/llvm/ProfileData/SampleProfReader.h
+++ b/llvm/include/llvm/ProfileData/SampleProfReader.h
@@ -543,7 +543,7 @@ class SampleProfileReader {
   void setModule(const Module *Mod) { M = Mod; }
 
   void setFuncNameToProfNameMap(
-      const HashKeyMap<std::unordered_map, FunctionId, FunctionId> &FPMap) {
+      const HashKeyMap<DenseMap, FunctionId, FunctionId> &FPMap) {
     FuncNameToProfNameMap = &FPMap;
   }
 
@@ -586,12 +586,12 @@ class SampleProfileReader {
   // A map pointer to the FuncNameToProfNameMap in SampleProfileLoader,
   // which maps the function name to the matched profile name. This is used
   // for sample loader to look up profile using the new name.
-  const HashKeyMap<std::unordered_map, FunctionId, FunctionId>
-      *FuncNameToProfNameMap = nullptr;
+  const HashKeyMap<DenseMap, FunctionId, FunctionId> *FuncNameToProfNameMap =
+      nullptr;
 
   // A map from a function's context hash to its meta data section range, used
   // for on-demand read function profile metadata.
-  std::unordered_map<uint64_t, std::pair<const uint8_t *, const uint8_t *>>
+  DenseMap<uint64_t, std::pair<const uint8_t *, const uint8_t *>>
       FuncMetadataIndex;
 
   std::pair<const uint8_t *, const uint8_t *> ProfileSecRange;
diff --git a/llvm/include/llvm/Transforms/IPO/GlobalDCE.h b/llvm/include/llvm/Transforms/IPO/GlobalDCE.h
index 9a0c8c20c13d1..ca38650075530 100644
--- a/llvm/include/llvm/Transforms/IPO/GlobalDCE.h
+++ b/llvm/include/llvm/Transforms/IPO/GlobalDCE.h
@@ -54,8 +54,7 @@ class GlobalDCEPass : public OptionalPassInfoMixin<GlobalDCEPass> {
   DenseMap<GlobalValue *, SmallPtrSet<GlobalValue *, 4>> GVDependencies;
 
   /// Constant -> Globals that use this global cache.
-  std::unordered_map<Constant *, SmallPtrSet<GlobalValue *, 8>>
-      ConstantDependenciesCache;
+  DenseMap<Constant *, SmallPtrSet<GlobalValue *, 8>> ConstantDependenciesCache;
 
   /// Comdat -> Globals in that Comdat section.
   std::unordered_multimap<Comdat *, GlobalValue *> ComdatMembers;
diff --git a/llvm/include/llvm/Transforms/IPO/SampleContextTracker.h b/llvm/include/llvm/Transforms/IPO/SampleContextTracker.h
index 1efe3ea127fd0..f8890899fedfb 100644
--- a/llvm/include/llvm/Transforms/IPO/SampleContextTracker.h
+++ b/llvm/include/llvm/Transforms/IPO/SampleContextTracker.h
@@ -215,8 +215,7 @@ class SampleContextTracker {
       FuncToCtxtProfiles;
 
   // Map from current FunctionSample to the belonged context trie.
-  std::unordered_map<const FunctionSamples *, ContextTrieNode *>
-      ProfileToNodeMap;
+  DenseMap<const FunctionSamples *, ContextTrieNode *> ProfileToNodeMap;
 
   // Map from function guid to real function names. Only used in md5 mode.
   const DenseMap<uint64_t, StringRef> *GUIDToFuncNameMap;
diff --git a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
index fa69177a822f4..22767cd058e21 100644
--- a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
+++ b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
@@ -14,12 +14,12 @@
 #ifndef LLVM_TRANSFORMS_IPO_SAMPLEPROFILEMATCHER_H
 #define LLVM_TRANSFORMS_IPO_SAMPLEPROFILEMATCHER_H
 
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h"
 
-#include <unordered_set>
-
 namespace llvm {
 
 using AnchorList = std::vector<std::pair<LineLocation, FunctionId>>;
@@ -59,21 +59,12 @@ class SampleProfileMatcher {
   // For each function, store every callsite and its matching state into this
   // map, of which each entry is a pair of callsite location and MatchState.
   // This is used for profile staleness computation and report.
-  StringMap<std::unordered_map<LineLocation, MatchState, LineLocationHash>>
-      FuncCallsiteMatchStates;
-
-  struct FuncToProfileNameMapHash {
-    uint64_t
-    operator()(const std::pair<const Function *, FunctionId> &P) const {
-      return hash_combine(P.first, P.second);
-    }
-  };
+  StringMap<DenseMap<LineLocation, MatchState>> FuncCallsiteMatchStates;
+
   // A map from a pair of function and profile name to a boolean value
   // indicating whether they are matched. This is used as a cache for the
   // matching result.
-  std::unordered_map<std::pair<const Function *, FunctionId>, bool,
-                     FuncToProfileNameMapHash>
-      FuncProfileMatchCache;
+  DenseMap<std::pair<const Function *, FunctionId>, bool> FuncProfileMatchCache;
   // The new functions found by the call graph matching. The map's key is the
   // the new(renamed) function pointer and the value is old(unused) profile
   // name.
@@ -82,16 +73,15 @@ class SampleProfileMatcher {
   // A map pointer to the FuncNameToProfNameMap in SampleProfileLoader,
   // which maps the function name to the matched profile name. This is used
   // for sample loader to look up profile using the new name.
-  HashKeyMap<std::unordered_map, FunctionId, FunctionId> *FuncNameToProfNameMap;
+  HashKeyMap<DenseMap, FunctionId, FunctionId> *FuncNameToProfNameMap;
 
   // A map pointer to the SymbolMap in SampleProfileLoader, which stores all
   // the original matched symbols before the matching. this is to determine if
   // the profile is unused(to be matched) or not.
-  HashKeyMap<std::unordered_map, FunctionId, Function *> *SymbolMap;
+  HashKeyMap<DenseMap, FunctionId, Function *> *SymbolMap;
 
   // The new functions from IR.
-  HashKeyMap<std::unordered_map, FunctionId, Function *>
-      FunctionsWithoutProfile;
+  HashKeyMap<DenseMap, FunctionId, Function *> FunctionsWithoutProfile;
 
   // Pointer to the Profile Symbol List in the reader.
   std::shared_ptr<ProfileSymbolList> PSL;
@@ -123,10 +113,9 @@ class SampleProfileMatcher {
   SampleProfileMatcher(
       Module &M, SampleProfileReader &Reader, LazyCallGraph &CG,
       const PseudoProbeManager *ProbeManager, ThinOrFullLTOPhase LTOPhase,
-      HashKeyMap<std::unordered_map, FunctionId, Function *> &SymMap,
+      HashKeyMap<DenseMap, FunctionId, Function *> &SymMap,
       std::shared_ptr<ProfileSymbolList> PSL,
-      HashKeyMap<std::unordered_map, FunctionId, FunctionId>
-          &FuncNameToProfNameMap)
+      HashKeyMap<DenseMap, FunctionId, FunctionId> &FuncNameToProfNameMap)
       : M(M), Reader(Reader), CG(CG), ProbeManager(ProbeManager),
         LTOPhase(LTOPhase), FuncNameToProfNameMap(&FuncNameToProfNameMap),
         SymbolMap(&SymMap), PSL(PSL) {};
@@ -189,9 +178,9 @@ class SampleProfileMatcher {
            State == MatchState::RemovedMatch;
   };
 
-  void countCallGraphRecoveredSamples(
-      const FunctionSamples &FS,
-      std::unordered_set<FunctionId> &MatchedUnusedProfile);
+  void
+  countCallGraphRecoveredSamples(const FunctionSamples &FS,
+                                 DenseSet<FunctionId> &MatchedUnusedProfile);
   // Count the samples of checksum mismatched function for the top-level
   // function and all inlinees.
   void countMismatchedFuncSamples(const FunctionSamples &FS, bool IsTopLevel);
diff --git a/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h b/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h
index bdb01ab353a84..1f6234f6778b0 100644
--- a/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h
+++ b/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h
@@ -20,7 +20,6 @@
 #include "llvm/IR/PassManager.h"
 #include "llvm/ProfileData/SampleProf.h"
 #include "llvm/Support/Compiler.h"
-#include <unordered_map>
 
 namespace llvm {
 class BasicBlock;
@@ -33,12 +32,11 @@ class TargetMachine;
 class Module;
 
 using namespace sampleprof;
-using BlockIdMap = std::unordered_map<BasicBlock *, uint32_t>;
-using InstructionIdMap = std::unordered_map<Instruction *, uint32_t>;
+using BlockIdMap = DenseMap<BasicBlock *, uint32_t>;
+using InstructionIdMap = DenseMap<Instruction *, uint32_t>;
 // Map from tuples of Probe id and inline stack hash code to distribution
 // factors.
-using ProbeFactorMap = std::unordered_map<std::pair<uint64_t, uint64_t>, float,
-                                          pair_hash<uint64_t, uint64_t>>;
+using ProbeFactorMap = DenseMap<std::pair<uint64_t, uint64_t>, float>;
 using FuncProbeFactorMap = StringMap<ProbeFactorMap>;
 
 
diff --git a/llvm/include/llvm/Transforms/Instrumentation/MemProfUse.h b/llvm/include/llvm/Transforms/Instrumentation/MemProfUse.h
index 5402ee25fc35c..01104097180e4 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/MemProfUse.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/MemProfUse.h
@@ -18,8 +18,6 @@
 #include "llvm/ProfileData/MemProf.h"
 #include "llvm/Support/Compiler.h"
 
-#include <unordered_map>
-
 namespace llvm {
 class IndexedInstrProfReader;
 class Module;
@@ -56,14 +54,7 @@ LLVM_ABI DenseMap<uint64_t, SmallVector<CallEdgeTy, 0>> extractCallsFromIR(
       return true;
     });
 
-struct LineLocationHash {
-  uint64_t operator()(const LineLocation &Loc) const {
-    return Loc.getHashCode();
-  }
-};
-
-using LocToLocMap =
-    std::unordered_map<LineLocation, LineLocation, LineLocationHash>;
+using LocToLocMap = DenseMap<LineLocation, LineLocation>;
 
 // Compute an undrifting map.  The result is a map from caller GUIDs to an inner
 // map that maps source locations in the profile to those in the current IR.
diff --git a/llvm/lib/CGData/OutlinedHashTree.cpp b/llvm/lib/CGData/OutlinedHashTree.cpp
index 7ddab66ae41f3..cc30feb30f67f 100644
--- a/llvm/lib/CGData/OutlinedHashTree.cpp
+++ b/llvm/lib/CGData/OutlinedHashTree.cpp
@@ -78,7 +78,7 @@ void OutlinedHashTree::insert(const HashSequencePair &SequencePair) {
       std::unique_ptr<HashNode> Next = std::make_unique<HashNode>();
       HashNode *NextPtr = Next.get();
       NextPtr->Hash = StableHash;
-      Current->Successors.emplace(StableHash, std::move(Next));
+      Current->Successors.try_emplace(StableHash, std::move(Next));
       Current = NextPtr;
     } else
       Current = I->second.get();
@@ -106,7 +106,7 @@ void OutlinedHashTree::merge(const OutlinedHashTree *Tree) {
         auto NextDst = std::make_unique<HashNode>();
         NextDstNode = NextDst.get();
         NextDstNode->Hash = Hash;
-        DstNode->Successors.emplace(Hash, std::move(NextDst));
+        DstNode->Successors.try_emplace(Hash, std::move(NextDst));
       } else
         NextDstNode = I->second.get();
 
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index ccec0b5910658..205bb193d32b6 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -237,8 +237,13 @@ CodeViewDebug::InlineSite &
 CodeViewDebug::getInlineSite(const DILocation *InlinedAt,
                              const DISubprogram *Inlinee) {
   auto SiteInsertion = CurFn->InlineSites.try_emplace(InlinedAt);
-  InlineSite *Site = &SiteInsertion.first->second;
-  if (SiteInsertion.second) {
+  bool Inserted = SiteInsertion.second;
+  if (Inserted)
+    SiteInsertion.first->second = std::make_unique<InlineSite>();
+  // The InlineSite is heap-allocated, so Site stays valid while the recursive
+  // getInlineSite call below grows InlineSites.
+  InlineSite *Site = SiteInsertion.first->second.get();
+  if (Inserted) {
     unsigned ParentFuncId = CurFn->FuncId;
     if (const DILocation *OuterIA = InlinedAt->getInlinedAt())
       ParentFuncId =
@@ -1046,7 +1051,7 @@ void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI,
     auto I = FI.InlineSites.find(ChildSite);
     assert(I != FI.InlineSites.end() &&
            "child site not in function inline site map");
-    emitInlinedCallSite(FI, ChildSite, I->second);
+    emitInlinedCallSite(FI, ChildSite, *I->second);
   }
 
   // Close the scope.
@@ -1222,7 +1227,7 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
       auto I = FI.InlineSites.find(InlinedAt);
       assert(I != FI.InlineSites.end() &&
              "child site not in function inline site map");
-      emitInlinedCallSite(FI, InlinedAt, I->second);
+      emitInlinedCallSite(FI, InlinedAt, *I->second);
     }
 
     for (auto Annot : FI.Annotations) {
@@ -3052,12 +3057,15 @@ void CodeViewDebug::collectLexicalBlockInfo(
   auto BlockInsertion = CurFn->LexicalBlocks.try_emplace(DILB);
   if (!BlockInsertion.second)
     return;
+  BlockInsertion.first->second = std::make_unique<LexicalBlock>();
 
   // Create a lexical block containing the variables and collect the
   // lexical block information for the children.
   const InsnRange &Range = Ranges.front();
   assert(Range.first && Range.second);
-  LexicalBlock &Block = BlockInsertion.first->second;
+  // The LexicalBlock is heap-allocated, so Block stays valid while the
+  // recursive collectLexicalBlockInfo call below grows LexicalBlocks.
+  LexicalBlock &Block = *BlockInsertion.first->second;
   Block.Begin = getLabelBeforeInsn(Range.first);
   Block.End = getLabelAfterInsn(Range.second);
   assert(Block.Begin && "missing label for scope begin");
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
index 04a75a21d7679..148e980c737e8 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
@@ -33,9 +33,9 @@
 #include "llvm/Support/Compiler.h"
 #include <cstdint>
 #include <map>
+#include <memory>
 #include <string>
 #include <tuple>
-#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -176,7 +176,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
 
     /// Map from inlined call site to inlined instructions and child inlined
     /// call sites. Listed in program order.
-    std::unordered_map<const DILocation *, InlineSite> InlineSites;
+    DenseMap<const DILocation *, std::unique_ptr<InlineSite>> InlineSites;
 
     /// Ordered list of top-level inlined call sites.
     SmallVector<const DILocation *, 1> ChildSites;
@@ -187,7 +187,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
     SmallVector<LocalVariable, 1> Locals;
     SmallVector<CVGlobalVariable, 1> Globals;
 
-    std::unordered_map<const DILexicalBlockBase*, LexicalBlock> LexicalBlocks;
+    DenseMap<const DILexicalBlockBase *, std::unique_ptr<LexicalBlock>>
+        LexicalBlocks;
 
     // Lexical blocks containing local variables.
     SmallVector<LexicalBlock *, 1> ChildBlocks;
diff --git a/llvm/lib/CodeGen/LexicalScopes.cpp b/llvm/lib/CodeGen/LexicalScopes.cpp
index 9fc9ac9a66d41..3966ca8f23be8 100644
--- a/llvm/lib/CodeGen/LexicalScopes.cpp
+++ b/llvm/lib/CodeGen/LexicalScopes.cpp
@@ -148,7 +148,7 @@ LexicalScope *LexicalScopes::findLexicalScope(const DILocation *DL) {
 
   if (auto *IA = DL->getInlinedAt()) {
     auto I = InlinedLexicalScopeMap.find(std::make_pair(Scope, IA));
-    return I != InlinedLexicalScopeMap.end() ? &I->second : nullptr;
+    return I != InlinedLexicalScopeMap.end() ? I->second.get() : nullptr;
   }
   return findLexicalScope(Scope);
 }
@@ -178,24 +178,24 @@ LexicalScopes::getOrCreateRegularScope(const DILocalScope *Scope) {
 
   auto I = LexicalScopeMap.find(Scope);
   if (I != LexicalScopeMap.end())
-    return &I->second;
+    return I->second.get();
 
   // FIXME: Should the following dyn_cast be DILexicalBlock?
   LexicalScope *Parent = nullptr;
   if (auto *Block = dyn_cast<DILexicalBlockBase>(Scope))
     Parent = getOrCreateLexicalScope(Block->getScope());
-  I = LexicalScopeMap.emplace(std::piecewise_construct,
-                              std::forward_as_tuple(Scope),
-                              std::forward_as_tuple(Parent, Scope, nullptr,
-                                                    false)).first;
+  I = LexicalScopeMap
+          .try_emplace(Scope, std::make_unique<LexicalScope>(Parent, Scope,
+                                                             nullptr, false))
+          .first;
 
   if (!Parent) {
     assert(cast<DISubprogram>(Scope)->describes(&MF->getFunction()));
     assert(!CurrentFnLexicalScope);
-    CurrentFnLexicalScope = &I->second;
+    CurrentFnLexicalScope = I->second.get();
   }
 
-  return &I->second;
+  return I->second.get();
 }
 
 /// getOrCreateInlinedScope - Find or create an inlined lexical scope.
@@ -207,7 +207,7 @@ LexicalScopes::getOrCreateInlinedScope(const DILocalScope *Scope,
   std::pair<const DILocalScope *, const DILocation *> P(Scope, InlinedAt);
   auto I = InlinedLexicalScopeMap.find(P);
   if (I != InlinedLexicalScopeMap.end())
-    return &I->second;
+    return I->second.get();
 
   LexicalScope *Parent;
   if (auto *Block = dyn_cast<DILexicalBlockBase>(Scope))
@@ -216,10 +216,10 @@ LexicalScopes::getOrCreateInlinedScope(const DILocalScope *Scope,
     Parent = getOrCreateLexicalScope(InlinedAt);
 
   I = InlinedLexicalScopeMap
-          .emplace(std::piecewise_construct, std::forward_as_tuple(P),
-                   std::forward_as_tuple(Parent, Scope, InlinedAt, false))
+          .try_emplace(P, std::make_unique<LexicalScope>(Parent, Scope,
+                                                         InlinedAt, false))
           .first;
-  return &I->second;
+  return I->second.get();
 }
 
 /// getOrCreateAbstractScope - Find or create an abstract lexical scope.
@@ -229,20 +229,20 @@ LexicalScopes::getOrCreateAbstractScope(const DILocalScope *Scope) {
   Scope = Scope->getNonLexicalBlockFileScope();
   auto I = AbstractScopeMap.find(Scope);
   if (I != AbstractScopeMap.end())
-    return &I->second;
+    return I->second.get();
 
   // FIXME: Should the following isa be DILexicalBlock?
   LexicalScope *Parent = nullptr;
   if (auto *Block = dyn_cast<DILexicalBlockBase>(Scope))
     Parent = getOrCreateAbstractScope(Block->getScope());
 
-  I = AbstractScopeMap.emplace(std::piecewise_construct,
-                               std::forward_as_tuple(Scope),
-                               std::forward_as_tuple(Parent, Scope,
-                                                     nullptr, true)).first;
+  I = AbstractScopeMap
+          .try_emplace(Scope, std::make_unique<LexicalScope>(Parent, Scope,
+                                                             nullptr, true))
+          .first;
   if (isa<DISubprogram>(Scope))
-    AbstractScopesList.push_back(&I->second);
-  return &I->second;
+    AbstractScopesList.push_back(I->second.get());
+  return I->second.get();
 }
 
 /// constructScopeNest - Traverse the Scope tree depth-first, storing
diff --git a/llvm/lib/CodeGen/LiveStacks.cpp b/llvm/lib/CodeGen/LiveStacks.cpp
index c07d985a09d1f..b76ec1195dc73 100644
--- a/llvm/lib/CodeGen/LiveStacks.cpp
+++ b/llvm/lib/CodeGen/LiveStacks.cpp
@@ -52,20 +52,17 @@ void LiveStacks::init(MachineFunction &MF) {
 LiveInterval &
 LiveStacks::getOrCreateInterval(int Slot, const TargetRegisterClass *RC) {
   assert(Slot >= 0 && "Spill slot indice must be >= 0");
-  SS2IntervalMap::iterator I = S2IMap.find(Slot);
-  if (I == S2IMap.end()) {
-    I = S2IMap
-            .emplace(
-                std::piecewise_construct, std::forward_as_tuple(Slot),
-                std::forward_as_tuple(Register::index2StackSlot(Slot), 0.0F))
-            .first;
+  auto [I, Inserted] = S2IMap.try_emplace(Slot);
+  if (Inserted) {
+    I->second =
+        std::make_unique<LiveInterval>(Register::index2StackSlot(Slot), 0.0F);
     S2RCMap.insert(std::make_pair(Slot, RC));
   } else {
     // Use the largest common subclass register class.
     const TargetRegisterClass *&OldRC = S2RCMap[Slot];
     OldRC = TRI->getCommonSubClass(OldRC, RC);
   }
-  return I->second;
+  return *I->second;
 }
 
 AnalysisKey LiveStacksAnalysis::Key;
@@ -99,9 +96,13 @@ void LiveStacksWrapperLegacy::print(raw_ostream &OS, const Module *) const {
 void LiveStacks::print(raw_ostream &OS, const Module*) const {
 
   OS << "********** INTERVALS **********\n";
-  for (const_iterator I = begin(), E = end(); I != E; ++I) {
-    I->second.print(OS);
-    int Slot = I->first;
+  // Print in slot order for deterministic output.
+  SmallVector<int, 8> Slots;
+  for (const_iterator I = begin(), E = end(); I != E; ++I)
+    Slots.push_back(I->first);
+  llvm::sort(Slots);
+  for (int Slot : Slots) {
+    getInterval(Slot).print(OS);
     const TargetRegisterClass *RC = getIntervalRegClass(Slot);
     if (RC)
       OS << " [" << TRI->getRegClassName(RC) << "]\n";
diff --git a/llvm/lib/CodeGen/RDFGraph.cpp b/llvm/lib/CodeGen/RDFGraph.cpp
index 7e7407e117dee..b172e70288986 100644
--- a/llvm/lib/CodeGen/RDFGraph.cpp
+++ b/llvm/lib/CodeGen/RDFGraph.cpp
@@ -1015,13 +1015,14 @@ void DataFlowGraph::releaseBlock(NodeId B, DefStackMap &DefM) {
   for (auto &P : DefM)
     P.second.clear_block(B);
 
-  // Finally, remove empty stacks from the map.
-  for (auto I = DefM.begin(), E = DefM.end(), NextI = I; I != E; I = NextI) {
-    NextI = std::next(I);
-    // This preserves the validity of iterators other than I.
-    if (I->second.empty())
-      DefM.erase(I);
-  }
+  // Finally, remove empty stacks from the map. DenseMap's erase relocates
+  // other elements, so collect the keys first.
+  SmallVector<RegisterId, 8> EmptyRegs;
+  for (auto &P : DefM)
+    if (P.second.empty())
+      EmptyRegs.push_back(P.first);
+  for (RegisterId R : EmptyRegs)
+    DefM.erase(R);
 }
 
 // Push all definitions from the instruction node IA to an appropriate
diff --git a/llvm/lib/CodeGen/RDFLiveness.cpp b/llvm/lib/CodeGen/RDFLiveness.cpp
index 10ab9b88a05e1..f0aa434bc3a53 100644
--- a/llvm/lib/CodeGen/RDFLiveness.cpp
+++ b/llvm/lib/CodeGen/RDFLiveness.cpp
@@ -573,8 +573,10 @@ void Liveness::computePhiInfo() {
           UI->second.insert({I.first, S.Mask});
         }
       }
-      UI = UI->second.empty() ? RealUses.erase(UI) : std::next(UI);
+      ++UI;
     }
+    // Drop the entries whose use sets ended up empty.
+    emptify(RealUses);
 
     // If this phi reaches some "real" uses, add it to the queue for upward
     // propagation.
@@ -696,7 +698,7 @@ void Liveness::computePhiInfo() {
         //     if MidDefs does not cover (R,U)
         //       then add (R-MidDefs,U) to RealUseMap[P]
         //
-        for (const std::pair<const RegisterId, NodeRefSet> &T : RUM) {
+        for (const auto &T : RUM) {
           RegisterRef R(T.first);
           // The current phi (PA) could be a phi for a regmask. It could
           // reach a whole variety of uses that are not related to the
@@ -829,7 +831,7 @@ void Liveness::computeLiveIns() {
         auto PrA = DFG.addr<BlockNode *>(PUA.Addr->getPredecessor());
         RefMap &LOX = PhiLOX[PrA.Addr->getCode()];
 
-        for (const std::pair<const RegisterId, NodeRefSet> &RS : RUs) {
+        for (const auto &RS : RUs) {
           // We need to visit each individual use.
           for (std::pair<NodeId, LaneBitmask> P : RS.second) {
             // Create a register ref corresponding to the use, and find
@@ -1047,7 +1049,7 @@ void Liveness::traverse(MachineBasicBlock *B, RefMap &LiveIn) {
   RefMap LiveInCopy = LiveIn;
   LiveIn.clear();
 
-  for (const std::pair<const RegisterId, NodeRefSet> &LE : LiveInCopy) {
+  for (const auto &LE : LiveInCopy) {
     RegisterRef LRef(LE.first);
     NodeRefSet &NewDefs = LiveIn[LRef.Id]; // To be filled.
     const NodeRefSet &OldDefs = LE.second;
@@ -1161,7 +1163,7 @@ void Liveness::traverse(MachineBasicBlock *B, RefMap &LiveIn) {
 
   for (auto *C : IIDF[B]) {
     RegisterAggr &LiveC = LiveMap[C];
-    for (const std::pair<const RegisterId, NodeRefSet> &S : LiveIn)
+    for (const auto &S : LiveIn)
       for (auto R : S.second)
         if (MDT.properlyDominates(getBlockWithRef(R.first), C))
           LiveC.insert(RegisterRef(S.first, R.second));
@@ -1169,8 +1171,13 @@ void Liveness::traverse(MachineBasicBlock *B, RefMap &LiveIn) {
 }
 
 void Liveness::emptify(RefMap &M) {
-  for (auto I = M.begin(), E = M.end(); I != E;)
-    I = I->second.empty() ? M.erase(I) : std::next(I);
+  // DenseMap's erase relocates other elements, so collect the keys first.
+  SmallVector<RegisterId, 8> Empty;
+  for (auto &P : M)
+    if (P.second.empty())
+      Empty.push_back(P.first);
+  for (RegisterId R : Empty)
+    M.erase(R);
 }
 
 } // namespace llvm::rdf
diff --git a/llvm/lib/CodeGen/StackSlotColoring.cpp b/llvm/lib/CodeGen/StackSlotColoring.cpp
index 105f9e93c7fbb..fad2e03baa6f5 100644
--- a/llvm/lib/CodeGen/StackSlotColoring.cpp
+++ b/llvm/lib/CodeGen/StackSlotColoring.cpp
@@ -273,7 +273,7 @@ void StackSlotColoring::InitializeSlots() {
   // Gather all spill slots into a list.
   LLVM_DEBUG(dbgs() << "Spill slot intervals:\n");
   for (auto *I : Intervals) {
-    LiveInterval &li = I->second;
+    LiveInterval &li = *I->second;
     LLVM_DEBUG(li.dump());
     int FI = li.reg().stackSlotIndex();
     if (MFI->isDeadObjectIndex(FI))
diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolFunc.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolFunc.cpp
index beb9197fe055d..25ce8c5e3d63f 100644
--- a/llvm/lib/DebugInfo/PDB/PDBSymbolFunc.cpp
+++ b/llvm/lib/DebugInfo/PDB/PDBSymbolFunc.cpp
@@ -8,6 +8,7 @@
 
 #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
 
+#include "llvm/ADT/StringSet.h"
 #include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h"
 #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
 #include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
@@ -17,7 +18,6 @@
 #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
 #include "llvm/DebugInfo/PDB/PDBTypes.h"
 
-#include <unordered_set>
 #include <utility>
 #include <vector>
 
@@ -34,7 +34,7 @@ class FunctionArgEnumerator : public IPDBEnumChildren<PDBSymbolData> {
       : Session(PDBSession), Func(PDBFunc) {
     // Arguments can appear multiple times if they have live range
     // information, so we only take the first occurrence.
-    std::unordered_set<std::string> SeenNames;
+    StringSet<> SeenNames;
     auto DataChildren = Func.findAllChildren<PDBSymbolData>();
     while (auto Child = DataChildren->getNext()) {
       if (Child->getDataKind() == PDB_DataKind::Param) {
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
index 89b20978c40e6..ee2163558f61f 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H
 #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H
 
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
@@ -30,7 +31,6 @@
 #include <deque>
 #include <map>
 #include <system_error>
-#include <unordered_map>
 
 using namespace llvm;
 using namespace llvm::object;
@@ -270,7 +270,7 @@ class RuntimeDyldImpl {
   // Relocations to sections already loaded. Indexed by SectionID which is the
   // source of the address. The target where the address will be written is
   // SectionID/Offset in the relocation itself.
-  std::unordered_map<unsigned, RelocationList> Relocations;
+  DenseMap<unsigned, RelocationList> Relocations;
 
   // Relocations to external symbols that are not yet resolved.  Symbols are
   // external when they aren't found in the global symbol table of all loaded
diff --git a/llvm/lib/IR/PrintPasses.cpp b/llvm/lib/IR/PrintPasses.cpp
index 5c14e3bc2a1e6..643aa69741d13 100644
--- a/llvm/lib/IR/PrintPasses.cpp
+++ b/llvm/lib/IR/PrintPasses.cpp
@@ -8,6 +8,7 @@
 
 #include "llvm/IR/PrintPasses.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Errc.h"
@@ -17,7 +18,6 @@
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Program.h"
 #include "llvm/Support/raw_ostream.h"
-#include <unordered_set>
 
 using namespace llvm;
 
@@ -155,18 +155,15 @@ bool llvm::forcePrintModuleIR() { return PrintModuleScope; }
 bool llvm::forcePrintFuncIR() { return LoopPrintFuncScope; }
 
 bool llvm::isPassInPrintList(StringRef PassName) {
-  static std::unordered_set<std::string> Set(FilterPasses.begin(),
-                                             FilterPasses.end());
-  return Set.empty() || Set.count(std::string(PassName));
+  static const StringSet<> Set(llvm::from_range, FilterPasses);
+  return Set.empty() || Set.contains(PassName);
 }
 
 bool llvm::isFilterPassesEmpty() { return FilterPasses.empty(); }
 
 bool llvm::isFunctionInPrintList(StringRef FunctionName) {
-  static std::unordered_set<std::string> PrintFuncNames(PrintFuncsList.begin(),
-                                                        PrintFuncsList.end());
-  return PrintFuncNames.empty() ||
-         PrintFuncNames.count(std::string(FunctionName));
+  static const StringSet<> PrintFuncNames(llvm::from_range, PrintFuncsList);
+  return PrintFuncNames.empty() || PrintFuncNames.contains(FunctionName);
 }
 
 std::error_code cleanUpTempFilesImpl(ArrayRef<std::string> FileName,
diff --git a/llvm/lib/MC/MCPseudoProbe.cpp b/llvm/lib/MC/MCPseudoProbe.cpp
index 99cba8e3d8375..8dea1908154ec 100644
--- a/llvm/lib/MC/MCPseudoProbe.cpp
+++ b/llvm/lib/MC/MCPseudoProbe.cpp
@@ -213,7 +213,7 @@ void MCPseudoProbeSections::emit(MCObjectStreamer *MCOS) {
   SmallVector<std::pair<MCSymbol *, MCPseudoProbeInlineTree *>> Vec;
   Vec.reserve(MCProbeDivisions.size());
   for (auto &ProbeSec : MCProbeDivisions)
-    Vec.emplace_back(ProbeSec.first, &ProbeSec.second);
+    Vec.emplace_back(ProbeSec.first, ProbeSec.second.get());
   for (auto I : llvm::enumerate(MCOS->getAssembler()))
     I.value().setOrdinal(I.index());
   llvm::sort(Vec, [](auto A, auto B) {
diff --git a/llvm/lib/ProfileData/SampleProf.cpp b/llvm/lib/ProfileData/SampleProf.cpp
index a7d784a72e380..8b81cfeecc9fe 100644
--- a/llvm/lib/ProfileData/SampleProf.cpp
+++ b/llvm/lib/ProfileData/SampleProf.cpp
@@ -308,8 +308,8 @@ LineLocation FunctionSamples::getCallSiteIdentifier(const DILocation *DIL,
 
 const FunctionSamples *FunctionSamples::findFunctionSamples(
     const DILocation *DIL, SampleProfileReaderItaniumRemapper *Remapper,
-    const HashKeyMap<std::unordered_map, FunctionId, FunctionId>
-        *FuncNameToProfNameMap) const {
+    const HashKeyMap<DenseMap, FunctionId, FunctionId> *FuncNameToProfNameMap)
+    const {
   assert(DIL);
   SmallVector<std::pair<LineLocation, StringRef>, 10> S;
 
@@ -351,8 +351,8 @@ void FunctionSamples::findAllNames(DenseSet<FunctionId> &NameSet) const {
 const FunctionSamples *FunctionSamples::findFunctionSamplesAt(
     const LineLocation &Loc, StringRef CalleeName,
     SampleProfileReaderItaniumRemapper *Remapper,
-    const HashKeyMap<std::unordered_map, FunctionId, FunctionId>
-        *FuncNameToProfNameMap) const {
+    const HashKeyMap<DenseMap, FunctionId, FunctionId> *FuncNameToProfNameMap)
+    const {
   CalleeName = getCanonicalFnName(CalleeName);
 
   auto I = CallsiteSamples.find(mapIRLocToProfileLoc(Loc));
diff --git a/llvm/lib/Support/Z3Solver.cpp b/llvm/lib/Support/Z3Solver.cpp
index 88851d2a24ce7..6715e43cf9c49 100644
--- a/llvm/lib/Support/Z3Solver.cpp
+++ b/llvm/lib/Support/Z3Solver.cpp
@@ -16,10 +16,10 @@ using namespace llvm;
 #if LLVM_WITH_Z3
 
 #include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/Twine.h"
 
 #include <set>
-#include <unordered_map>
 
 #include <z3.h>
 
@@ -938,19 +938,19 @@ class Z3Statistics final : public SMTSolverStatistics {
   };
 
   void print(raw_ostream &OS) const override {
-    for (auto const &[K, V] : UnsignedValues) {
-      OS << K << ": " << V << '\n';
+    for (const auto &E : UnsignedValues) {
+      OS << E.first() << ": " << E.second << '\n';
     }
-    for (auto const &[K, V] : DoubleValues) {
-      write_double(OS << K << ": ", V, FloatStyle::Fixed);
+    for (const auto &E : DoubleValues) {
+      write_double(OS << E.first() << ": ", E.second, FloatStyle::Fixed);
       OS << '\n';
     }
   }
 
 private:
   friend class Z3Solver;
-  std::unordered_map<std::string, unsigned> UnsignedValues;
-  std::unordered_map<std::string, double> DoubleValues;
+  StringMap<unsigned> UnsignedValues;
+  StringMap<double> DoubleValues;
 };
 
 std::unique_ptr<SMTSolverStatistics> Z3Solver::getStatistics() const {
diff --git a/llvm/lib/Target/AArch64/AArch64.h b/llvm/lib/Target/AArch64/AArch64.h
index a3660256ff4f9..e84c2bab20207 100644
--- a/llvm/lib/Target/AArch64/AArch64.h
+++ b/llvm/lib/Target/AArch64/AArch64.h
@@ -16,6 +16,7 @@
 
 #include "MCTargetDesc/AArch64MCTargetDesc.h"
 #include "Utils/AArch64BaseInfo.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineFunctionAnalysisManager.h"
 #include "llvm/CodeGen/SelectionDAGISel.h"
@@ -25,7 +26,6 @@
 #include "llvm/Target/TargetMachine.h"
 #include <map>
 #include <memory>
-#include <unordered_map>
 
 struct AArch64O0PreLegalizerCombinerImplRuleConfig;
 struct AArch64PreLegalizerCombinerImplRuleConfig;
@@ -302,7 +302,7 @@ class AArch64ConditionOptimizerPass
 class AArch64SIMDInstrOptPass
     : public OptionalPassInfoMixin<AArch64SIMDInstrOptPass> {
   std::map<std::pair<unsigned, std::string>, bool> SIMDInstrTable;
-  std::unordered_map<std::string, bool> InterlEarlyExit;
+  StringMap<bool> InterlEarlyExit;
 
 public:
   PreservedAnalyses run(MachineFunction &MF,
diff --git a/llvm/lib/Target/AArch64/AArch64SIMDInstrOpt.cpp b/llvm/lib/Target/AArch64/AArch64SIMDInstrOpt.cpp
index 4b27b77735284..1336b9f7af3c7 100644
--- a/llvm/lib/Target/AArch64/AArch64SIMDInstrOpt.cpp
+++ b/llvm/lib/Target/AArch64/AArch64SIMDInstrOpt.cpp
@@ -36,6 +36,7 @@
 #include "AArch64Subtarget.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFunction.h"
@@ -52,7 +53,6 @@
 #include "llvm/MC/MCSchedule.h"
 #include "llvm/Pass.h"
 #include <map>
-#include <unordered_map>
 
 using namespace llvm;
 
@@ -78,7 +78,7 @@ class AArch64SIMDInstrOptImpl {
 
   using SIMDInstrTableMap = std::map<std::pair<unsigned, std::string>, bool>;
 
-  using InterlEarlyExitMap = std::unordered_map<std::string, bool>;
+  using InterlEarlyExitMap = StringMap<bool>;
 
   // The two maps below are used to cache decisions instead of recomputing. Note
   // that we're only storing references, the data is scoped at the Pass level to
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUMarkLastScratchLoad.cpp b/llvm/lib/Target/AMDGPU/AMDGPUMarkLastScratchLoad.cpp
index 9b6bb56c85d24..639a875909851 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUMarkLastScratchLoad.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUMarkLastScratchLoad.cpp
@@ -103,14 +103,14 @@ bool AMDGPUMarkLastScratchLoad::run(MachineFunction &MF) {
   bool Changed = false;
 
   for (auto &[SS, LI] : *LS) {
-    for (const LiveRange::Segment &Segment : LI.segments) {
+    for (const LiveRange::Segment &Segment : LI->segments) {
 
       // Ignore segments that run to the end of basic block because in this case
       // slot is still live at the end of it.
       if (Segment.end.isBlock())
         continue;
 
-      const int FrameIndex = LI.reg().stackSlotIndex();
+      const int FrameIndex = LI->reg().stackSlotIndex();
       MachineInstr *LastLoad = nullptr;
 
       MachineInstr *MISegmentEnd = SI->getInstructionFromIndex(Segment.end);
diff --git a/llvm/lib/Target/AMDGPU/AMDGPURewriteAGPRCopyMFMA.cpp b/llvm/lib/Target/AMDGPU/AMDGPURewriteAGPRCopyMFMA.cpp
index 1d39b4f1bc52d..aebc9865d39e8 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURewriteAGPRCopyMFMA.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURewriteAGPRCopyMFMA.cpp
@@ -492,7 +492,7 @@ void AMDGPURewriteAGPRCopyMFMAImpl::eliminateSpillsOfReassignedVGPRs() const {
 
     const TargetRegisterClass *RC = LSS.getIntervalRegClass(Slot);
     if (TRI.hasVGPRs(RC))
-      StackIntervals.push_back(&LI);
+      StackIntervals.push_back(LI.get());
   }
 
   sort(StackIntervals, [](const LiveInterval *A, const LiveInterval *B) {
diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
index f4a7b4e78245f..fafb4e737ac4c 100644
--- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
+++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
@@ -19,6 +19,7 @@
 #include "MCTargetDesc/HexagonMCInstrInfo.h"
 #include "TargetInfo/HexagonTargetInfo.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/MC/MCAsmBackend.h"
@@ -43,7 +44,6 @@
 #include <mutex>
 #include <new>
 #include <string>
-#include <unordered_map>
 
 using namespace llvm;
 
@@ -527,14 +527,13 @@ std::pair<std::string, std::string> selectCPUAndFS(StringRef CPU,
   return Result;
 }
 std::mutex ArchSubtargetMutex;
-std::unordered_map<std::string, std::unique_ptr<MCSubtargetInfo const>>
-    ArchSubtarget;
+StringMap<std::unique_ptr<MCSubtargetInfo const>> ArchSubtarget;
 } // namespace
 
 MCSubtargetInfo const *
 Hexagon_MC::getArchSubtarget(MCSubtargetInfo const *STI) {
   std::lock_guard<std::mutex> Lock(ArchSubtargetMutex);
-  auto Existing = ArchSubtarget.find(std::string(STI->getCPU()));
+  auto Existing = ArchSubtarget.find(STI->getCPU());
   if (Existing == ArchSubtarget.end())
     return nullptr;
   return Existing->second.get();
@@ -673,7 +672,7 @@ void Hexagon_MC::addArchSubtarget(MCSubtargetInfo const *STI, StringRef FS) {
     auto ArchSTI = createHexagonMCSubtargetInfo(STI->getTargetTriple(),
                                                 STI->getCPU().drop_back(), FS);
     std::lock_guard<std::mutex> Lock(ArchSubtargetMutex);
-    ArchSubtarget[std::string(STI->getCPU())] =
+    ArchSubtarget[STI->getCPU()] =
         std::unique_ptr<MCSubtargetInfo const>(ArchSTI);
   }
 }
diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
index befe8e3fda4f2..f0296184dde49 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
@@ -775,7 +775,7 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() {
   // int32, that might be used as FP Fast Math Mode.
   std::vector<const MachineInstr *> SPIRVFloatTypes;
   // Hashtable to associate immediate values with the constant holding them.
-  std::unordered_map<int, const MachineInstr *> ConstMap;
+  DenseMap<int, const MachineInstr *> ConstMap;
   for (const MachineInstr *MI : MAI->getMSInstrs(SPIRV::MB_TypeConstVars)) {
     // Skip if the instruction is not OpTypeFloat or OpConstant.
     unsigned OpCode = MI->getOpcode();
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 7192664f2c75c..e25aa005da527 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -253,10 +253,11 @@ class SPIRVEmitIntrinsics
                                bool UnknownElemTypeI8);
 
   // deduce Types of operands of the Instruction if possible
-  void deduceOperandElementType(Instruction *I,
-                                SmallPtrSet<Instruction *, 4> *IncompleteRets,
-                                const SmallPtrSet<Value *, 4> *AskOps = nullptr,
-                                bool IsPostprocessing = false);
+  void
+  deduceOperandElementType(Instruction *I,
+                           SmallPtrSetImpl<Instruction *> *IncompleteRets,
+                           const SmallPtrSetImpl<Value *> *AskOps = nullptr,
+                           bool IsPostprocessing = false);
 
   void preprocessCompositeConstants(IRBuilder<> &B);
   void preprocessUndefs(IRBuilder<> &B);
@@ -296,8 +297,8 @@ class SPIRVEmitIntrinsics
       CallInst *CI, SmallVector<std::pair<Value *, unsigned>> &Ops,
       Type *&KnownElemTy, bool IsPostprocessing);
   bool deduceOperandElementTypeFunctionRet(
-      Instruction *I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
-      const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing,
+      Instruction *I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
+      const SmallPtrSetImpl<Value *> *AskOps, bool IsPostprocessing,
       Type *&KnownElemTy, Value *Op, Function *F);
 
   CallInst *buildSpvPtrcast(Function *F, Value *Op, Type *ElemTy);
@@ -1313,8 +1314,8 @@ void SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionPointer(
 }
 
 bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
-    Instruction *I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
-    const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing,
+    Instruction *I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
+    const SmallPtrSetImpl<Value *> *AskOps, bool IsPostprocessing,
     Type *&KnownElemTy, Value *Op, Function *F) {
   KnownElemTy = GR->findDeducedElementType(F);
   if (KnownElemTy)
@@ -1360,8 +1361,8 @@ bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
 // types which differ from expected, this function tries to insert a bitcast to
 // resolve the issue.
 void SPIRVEmitIntrinsics::deduceOperandElementType(
-    Instruction *I, SmallPtrSet<Instruction *, 4> *IncompleteRets,
-    const SmallPtrSet<Value *, 4> *AskOps, bool IsPostprocessing) {
+    Instruction *I, SmallPtrSetImpl<Instruction *> *IncompleteRets,
+    const SmallPtrSetImpl<Value *> *AskOps, bool IsPostprocessing) {
   SmallVector<std::pair<Value *, unsigned>> Ops;
   Type *KnownElemTy = nullptr;
   bool Incomplete = false;
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index 277360270db4f..ae897d35a6277 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -16,6 +16,7 @@
 #include "MCTargetDesc/SPIRVBaseInfo.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/IR/Dominators.h"
@@ -25,7 +26,6 @@
 #include <queue>
 #include <set>
 #include <string>
-#include <unordered_map>
 
 #include "SPIRVTypeInst.h"
 
@@ -568,7 +568,7 @@ bool isNestedPointer(const Type *Ty);
 enum FPDecorationId { NONE, RTE, RTZ, RTP, RTN, SAT };
 
 inline FPDecorationId demangledPostfixToDecorationId(const std::string &S) {
-  static std::unordered_map<std::string, FPDecorationId> Mapping = {
+  static const StringMap<FPDecorationId> Mapping = {
       {"rte", FPDecorationId::RTE},
       {"rtz", FPDecorationId::RTZ},
       {"rtp", FPDecorationId::RTP},
diff --git a/llvm/lib/Transforms/IPO/GlobalDCE.cpp b/llvm/lib/Transforms/IPO/GlobalDCE.cpp
index ad794a9f04111..0db05c9bfcdff 100644
--- a/llvm/lib/Transforms/IPO/GlobalDCE.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalDCE.cpp
@@ -96,13 +96,17 @@ void GlobalDCEPass::ComputeDependencies(Value *V,
     Deps.insert(GV);
   } else if (auto *CE = dyn_cast<Constant>(V)) {
     // Avoid walking the whole tree of a big ConstantExprs multiple times.
-    auto [Where, Inserted] = ConstantDependenciesCache.try_emplace(CE);
-    SmallPtrSetImpl<GlobalValue *> &LocalDeps = Where->second;
-    if (Inserted) {
+    auto Where = ConstantDependenciesCache.find(CE);
+    if (Where == ConstantDependenciesCache.end()) {
+      // Compute into a local set first: the recursion can insert into the
+      // cache, which would invalidate references into it.
+      SmallPtrSet<GlobalValue *, 8> LocalDeps;
       for (User *CEUser : CE->users())
         ComputeDependencies(CEUser, LocalDeps);
+      Where =
+          ConstantDependenciesCache.try_emplace(CE, std::move(LocalDeps)).first;
     }
-    Deps.insert_range(LocalDeps);
+    Deps.insert_range(Where->second);
   }
 }
 
diff --git a/llvm/lib/Transforms/IPO/SampleProfile.cpp b/llvm/lib/Transforms/IPO/SampleProfile.cpp
index 964c79c1e68d1..ab324ec76baa5 100644
--- a/llvm/lib/Transforms/IPO/SampleProfile.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfile.cpp
@@ -536,11 +536,11 @@ class SampleProfileLoader final : public SampleProfileLoaderBaseImpl<Function> {
   /// the function name. If the function name contains suffix, additional
   /// entry is added to map from the stripped name to the function if there
   /// is one-to-one mapping.
-  HashKeyMap<std::unordered_map, FunctionId, Function *> SymbolMap;
+  HashKeyMap<DenseMap, FunctionId, Function *> SymbolMap;
 
   /// Map from function name to profile name generated by call-graph based
   /// profile fuzzy matching(--salvage-unused-profile).
-  HashKeyMap<std::unordered_map, FunctionId, FunctionId> FuncNameToProfNameMap;
+  HashKeyMap<DenseMap, FunctionId, FunctionId> FuncNameToProfNameMap;
 
   std::function<AssumptionCache &(Function &)> GetAC;
   std::function<TargetTransformInfo &(Function &)> GetTTI;
diff --git a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
index 73eda1b9cd48a..de89a8a1676a1 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
@@ -19,7 +19,6 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Transforms/Utils/LongestCommonSequence.h"
 
-#include <unordered_set>
 
 using namespace llvm;
 using namespace sampleprof;
@@ -467,7 +466,7 @@ void SampleProfileMatcher::recordCallsiteMatchStates(
     if (IRCalleeId == ProfCalleeId) {
       auto It = CallsiteMatchStates.find(ProfileLoc);
       if (It == CallsiteMatchStates.end())
-        CallsiteMatchStates.emplace(ProfileLoc, MatchState::InitialMatch);
+        CallsiteMatchStates.try_emplace(ProfileLoc, MatchState::InitialMatch);
       else if (IsPostMatch) {
         if (It->second == MatchState::InitialMatch)
           It->second = MatchState::UnchangedMatch;
@@ -484,7 +483,7 @@ void SampleProfileMatcher::recordCallsiteMatchStates(
     assert(!I.second.stringRef().empty() && "Callees should not be empty");
     auto It = CallsiteMatchStates.find(Loc);
     if (It == CallsiteMatchStates.end())
-      CallsiteMatchStates.emplace(Loc, MatchState::InitialMismatch);
+      CallsiteMatchStates.try_emplace(Loc, MatchState::InitialMismatch);
     else if (IsPostMatch) {
       // Update the state if it's not matched(UnchangedMatch or
       // RecoveredMismatch).
@@ -594,7 +593,7 @@ void SampleProfileMatcher::countMismatchCallsites(const FunctionSamples &FS) {
 
 void SampleProfileMatcher::countCallGraphRecoveredSamples(
     const FunctionSamples &FS,
-    std::unordered_set<FunctionId> &CallGraphRecoveredProfiles) {
+    DenseSet<FunctionId> &CallGraphRecoveredProfiles) {
   if (CallGraphRecoveredProfiles.count(FS.getFunction())) {
     NumCallGraphRecoveredFuncSamples += FS.getTotalSamples();
     return;
@@ -611,7 +610,7 @@ void SampleProfileMatcher::computeAndReportProfileStaleness() {
   if (!ReportProfileStaleness && !PersistProfileStaleness)
     return;
 
-  std::unordered_set<FunctionId> CallGraphRecoveredProfiles;
+  DenseSet<FunctionId> CallGraphRecoveredProfiles;
   if (SalvageUnusedProfile) {
     for (const auto &I : FuncToProfileNameMap) {
       CallGraphRecoveredProfiles.insert(I.second);
diff --git a/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp b/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
index 7fd7d4d4f750b..b6de00de07756 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
@@ -12,6 +12,7 @@
 
 #include "llvm/Transforms/IPO/SampleProfileProbe.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Analysis/BlockFrequencyInfo.h"
 #include "llvm/Analysis/EHUtils.h"
 #include "llvm/Analysis/LoopInfo.h"
@@ -30,7 +31,6 @@
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Transforms/Utils/Instrumentation.h"
 #include "llvm/Transforms/Utils/ModuleUtils.h"
-#include <unordered_set>
 #include <vector>
 
 using namespace llvm;
@@ -77,9 +77,9 @@ bool PseudoProbeVerifier::shouldVerifyFunction(const Function *F) {
   if (F->hasAvailableExternallyLinkage())
     return false;
   // Do a name matching.
-  static std::unordered_set<std::string> VerifyFuncNames(
-      VerifyPseudoProbeFuncList.begin(), VerifyPseudoProbeFuncList.end());
-  return VerifyFuncNames.empty() || VerifyFuncNames.count(F->getName().str());
+  static const StringSet<> VerifyFuncNames(llvm::from_range,
+                                           VerifyPseudoProbeFuncList);
+  return VerifyFuncNames.empty() || VerifyFuncNames.contains(F->getName());
 }
 
 void PseudoProbeVerifier::registerCallbacks(PassInstrumentationCallbacks &PIC) {
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
index 6f3bbdfc7e17f..885f4cd2f9df5 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
@@ -18,6 +18,7 @@
 #include "LlvmState.h"
 #include "RegisterValue.h"
 #include "ValidationEvent.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstBuilder.h"
@@ -25,7 +26,6 @@
 #include <limits>
 #include <set>
 #include <string>
-#include <unordered_map>
 #include <vector>
 
 namespace llvm {
@@ -65,7 +65,7 @@ struct BenchmarkKey {
   std::vector<RegisterValue> RegisterInitialValues;
   // The memory values that can be mapped into the execution context of the
   // snippet.
-  std::unordered_map<std::string, MemoryValue> MemoryValues;
+  StringMap<MemoryValue> MemoryValues;
   // The memory mappings that the snippet can access.
   std::vector<MemoryMapping> MemoryMappings;
   // An opaque configuration, that can be used to separate several benchmarks of
diff --git a/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp b/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
index 7919d75ed0c56..250b6c7429266 100644
--- a/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
@@ -108,7 +108,7 @@ class BenchmarkCodeStreamer : public MCStreamer, public AsmCommentConsumer {
       }
       MemVal.Value = APInt(HexValue.size() * 4, HexValue, 16);
       MemVal.Index = Result->Key.MemoryValues.size();
-      Result->Key.MemoryValues[Parts[0].trim().str()] = MemVal;
+      Result->Key.MemoryValues[Parts[0].trim()] = MemVal;
       return;
     }
     if (CommentText.consume_front("MEM-MAP")) {
@@ -139,7 +139,7 @@ class BenchmarkCodeStreamer : public MCStreamer, public AsmCommentConsumer {
 
       // validate that the annotation refers to an already existing memory
       // definition
-      auto MemValIT = Result->Key.MemoryValues.find(Parts[0].trim().str());
+      auto MemValIT = Result->Key.MemoryValues.find(Parts[0].trim());
       if (MemValIT == Result->Key.MemoryValues.end()) {
         errs() << "invalid comment 'LLVM-EXEGESIS-MEM-MAP " << CommentText
                << "', expected <VALUE NAME> to contain the name of an already "
diff --git a/llvm/tools/llvm-exegesis/lib/SubprocessMemory.cpp b/llvm/tools/llvm-exegesis/lib/SubprocessMemory.cpp
index 849e055cf7a8a..4411ecc8a296c 100644
--- a/llvm/tools/llvm-exegesis/lib/SubprocessMemory.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SubprocessMemory.cpp
@@ -68,10 +68,10 @@ Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessID) {
 }
 
 Error SubprocessMemory::addMemoryDefinition(
-    std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
-    pid_t ProcessPID) {
+    StringMap<MemoryValue> MemoryDefinitions, pid_t ProcessPID) {
   SharedMemoryNames.reserve(MemoryDefinitions.size());
-  for (auto &[Name, MemVal] : MemoryDefinitions) {
+  for (const auto &E : MemoryDefinitions) {
+    const MemoryValue &MemVal = E.second;
     std::string SharedMemoryName =
         formatv("/{0}t{1}memdef{2}", ProcessPID, getCurrentTID(), MemVal.Index);
     SharedMemoryNames.push_back(SharedMemoryName);
@@ -112,8 +112,8 @@ Error SubprocessMemory::addMemoryDefinition(
 }
 
 Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess(
-    std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
-    pid_t ParentPID, long ParentTID, int CounterFileDescriptor) {
+    StringMap<MemoryValue> MemoryDefinitions, pid_t ParentPID, long ParentTID,
+    int CounterFileDescriptor) {
   std::string AuxiliaryMemoryName =
       formatv("/{0}auxmem{1}", ParentTID, ParentPID);
   int AuxiliaryMemoryFileDescriptor =
@@ -129,7 +129,8 @@ Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess(
   if (reinterpret_cast<intptr_t>(AuxiliaryMemoryMapping) == -1)
     return make_error<Failure>("Mapping auxiliary memory failed");
   AuxiliaryMemoryMapping[0] = CounterFileDescriptor;
-  for (auto &[Name, MemVal] : MemoryDefinitions) {
+  for (const auto &E : MemoryDefinitions) {
+    const MemoryValue &MemVal = E.second;
     std::string MemoryValueName =
         formatv("/{0}t{1}memdef{2}", ParentPID, ParentTID, MemVal.Index);
     AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] =
@@ -159,14 +160,13 @@ Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessPID) {
 }
 
 Error SubprocessMemory::addMemoryDefinition(
-    std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
-    pid_t ProcessPID) {
+    StringMap<MemoryValue> MemoryDefinitions, pid_t ProcessPID) {
   return make_error<Failure>("addMemoryDefinitions is only supported on Linux");
 }
 
 Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess(
-    std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
-    pid_t ParentPID, long ParentTID, int CounterFileDescriptor) {
+    StringMap<MemoryValue> MemoryDefinitions, pid_t ParentPID, long ParentTID,
+    int CounterFileDescriptor) {
   return make_error<Failure>(
       "setupAuxiliaryMemoryInSubprocess is only supported on Linux");
 }
diff --git a/llvm/tools/llvm-exegesis/lib/SubprocessMemory.h b/llvm/tools/llvm-exegesis/lib/SubprocessMemory.h
index 52ee980b6defd..5f2a522c21c2e 100644
--- a/llvm/tools/llvm-exegesis/lib/SubprocessMemory.h
+++ b/llvm/tools/llvm-exegesis/lib/SubprocessMemory.h
@@ -16,8 +16,8 @@
 #define LLVM_TOOLS_LLVM_EXEGESIS_SUBPROCESSMEMORY_H
 
 #include "BenchmarkResult.h"
+#include "llvm/ADT/StringMap.h"
 #include <string>
-#include <unordered_map>
 #include <vector>
 
 #ifdef _MSC_VER
@@ -44,9 +44,8 @@ class SubprocessMemory {
   // memory objects for the definitions and fills them with the specified
   // values. Arguments: MemoryDefinitions - A map from memory value names to
   // MemoryValues, ProcessID - The ID of the current process.
-  Error addMemoryDefinition(
-      std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
-      pid_t ProcessID);
+  Error addMemoryDefinition(StringMap<MemoryValue> MemoryDefinitions,
+                            pid_t ProcessID);
 
   // The following function sets up the auxiliary memory by opening shared
   // memory objects backing memory definitions and putting file descriptors
@@ -55,9 +54,10 @@ class SubprocessMemory {
   // setup the memory definitions, CounterFileDescriptor - The file descriptor
   // for the performance counter that will be placed in the auxiliary memory
   // section.
-  static Expected<int> setupAuxiliaryMemoryInSubprocess(
-      std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
-      pid_t ParentPID, long ParentTID, int CounterFileDescriptor);
+  static Expected<int>
+  setupAuxiliaryMemoryInSubprocess(StringMap<MemoryValue> MemoryDefinitions,
+                                   pid_t ParentPID, long ParentTID,
+                                   int CounterFileDescriptor);
 
   ~SubprocessMemory();
 
diff --git a/llvm/tools/llvm-objdump/SourcePrinter.h b/llvm/tools/llvm-objdump/SourcePrinter.h
index ad3ea122b4346..aac81fdc1bfab 100644
--- a/llvm/tools/llvm-objdump/SourcePrinter.h
+++ b/llvm/tools/llvm-objdump/SourcePrinter.h
@@ -19,7 +19,6 @@
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/Support/FormattedStream.h"
 #include <set>
-#include <unordered_map>
 #include <vector>
 
 namespace llvm {
@@ -215,9 +214,9 @@ class SourcePrinter {
   const object::ObjectFile *Obj = nullptr;
   std::unique_ptr<symbolize::LLVMSymbolizer> Symbolizer;
   // File name to file contents of source.
-  std::unordered_map<std::string, std::unique_ptr<MemoryBuffer>> SourceCache;
+  StringMap<std::unique_ptr<MemoryBuffer>> SourceCache;
   // Mark the line endings of the cached source.
-  std::unordered_map<std::string, std::vector<StringRef>> LineCache;
+  StringMap<std::vector<StringRef>> LineCache;
   // Keep track of missing sources.
   StringSet<> MissingSources;
   // Only emit 'invalid debug info' warning once.
diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.cpp b/llvm/tools/llvm-profgen/ProfiledBinary.cpp
index 3b9f1f46140cb..3b1e00093fb9e 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.cpp
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.cpp
@@ -218,7 +218,7 @@ void ProfiledBinary::warnNoFuncEntry() {
       NoFuncEntryNum++;
       if (ShowDetailedWarning)
         WithColor::warning()
-            << "Failed to determine function entry for " << F.first
+            << "Failed to determine function entry for " << F.first()
             << " due to inconsistent name from symbol table and dwarf info.\n";
     }
   }
@@ -953,10 +953,10 @@ void ProfiledBinary::loadSymbolsFromSymtab(const ObjectFile *Obj) {
       assert(findFuncRange(EndAddr - 1) == nullptr &&
              "Function range overlaps with existing functions.");
       // Function from symbol table not found previously in DWARF, store ranges.
-      auto Ret = BinaryFunctions.emplace(SymName, BinaryFunction());
+      auto Ret = BinaryFunctions.try_emplace(SymName);
       auto &Func = Ret.first->second;
       if (Ret.second) {
-        Func.FuncName = Ret.first->first;
+        Func.FuncName = Ret.first->first();
         HashBinaryFunctions[Function::getGUIDAssumingExternalLinkage(SymName)] =
             &Func;
       }
@@ -1030,10 +1030,10 @@ void ProfiledBinary::loadSymbolsFromDWARFUnit(DWARFUnit &CompilationUnit) {
 
     // Different DWARF symbols can have same function name, search or create
     // BinaryFunction indexed by the name.
-    auto Ret = BinaryFunctions.emplace(Name, BinaryFunction());
+    auto Ret = BinaryFunctions.try_emplace(Name);
     auto &Func = Ret.first->second;
     if (Ret.second)
-      Func.FuncName = Ret.first->first;
+      Func.FuncName = Ret.first->first();
 
     for (const auto &Range : Ranges) {
       uint64_t StartAddress = Range.LowPC;
@@ -1106,7 +1106,7 @@ void ProfiledBinary::loadSymbolsFromDWARF(ObjectFile &Obj) {
   // Populate the hash binary function map for MD5 function name lookup. This
   // is done after BinaryFunctions are finalized.
   for (auto &BinaryFunction : BinaryFunctions) {
-    HashBinaryFunctions[MD5Hash(StringRef(BinaryFunction.first))] =
+    HashBinaryFunctions[MD5Hash(BinaryFunction.first())] =
         &BinaryFunction.second;
   }
 
diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.h b/llvm/tools/llvm-profgen/ProfiledBinary.h
index 4a2c4cec8b49f..a407adb978091 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.h
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.h
@@ -236,7 +236,7 @@ class ProfiledBinary {
   std::set<std::pair<uint64_t, uint64_t>> TextSections;
 
   // A map of mapping function name to BinaryFunction info.
-  std::unordered_map<std::string, BinaryFunction> BinaryFunctions;
+  StringMap<BinaryFunction> BinaryFunctions;
 
   // Lookup BinaryFunctions using the function name's MD5 hash. Needed if the
   // profile is using MD5.
@@ -571,8 +571,7 @@ class ProfiledBinary {
     return FRange->Func->Ranges;
   }
 
-  const std::unordered_map<std::string, BinaryFunction> &
-  getAllBinaryFunctions() {
+  const StringMap<BinaryFunction> &getAllBinaryFunctions() {
     return BinaryFunctions;
   }
 
@@ -586,7 +585,7 @@ class ProfiledBinary {
 
   BinaryFunction *getBinaryFunction(FunctionId FName) {
     if (FName.isStringRef()) {
-      auto I = BinaryFunctions.find(FName.str());
+      auto I = BinaryFunctions.find(FName.stringRef());
       if (I == BinaryFunctions.end())
         return nullptr;
       return &I->second;
diff --git a/llvm/unittests/tools/llvm-exegesis/X86/SnippetFileTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/SnippetFileTest.cpp
index 755a74811eb69..a5493d327ac7d 100644
--- a/llvm/unittests/tools/llvm-exegesis/X86/SnippetFileTest.cpp
+++ b/llvm/unittests/tools/llvm-exegesis/X86/SnippetFileTest.cpp
@@ -67,11 +67,11 @@ MATCHER_P2(RegisterInitialValueIs, Reg, Val, "") {
 
 MATCHER_P3(MemoryDefinitionIs, Name, Value, Size, "") {
   if (arg.second.Value.getLimitedValue() == static_cast<uint64_t>(Value) &&
-      arg.second.SizeBytes == static_cast<size_t>(Size) && arg.first == Name)
+      arg.second.SizeBytes == static_cast<size_t>(Size) && arg.first() == Name)
     return true;
   *result_listener << "expected: {" << Name << ", " << Value << ", " << Size
                    << "} ";
-  *result_listener << "actual: {" << arg.first << ", "
+  *result_listener << "actual: {" << arg.first().str() << ", "
                    << arg.second.Value.getLimitedValue() << ", "
                    << arg.second.SizeBytes << "}";
   return false;
diff --git a/llvm/unittests/tools/llvm-exegesis/X86/SubprocessMemoryTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/SubprocessMemoryTest.cpp
index 08c18e4ed11e2..3a35e2e02e6be 100644
--- a/llvm/unittests/tools/llvm-exegesis/X86/SubprocessMemoryTest.cpp
+++ b/llvm/unittests/tools/llvm-exegesis/X86/SubprocessMemoryTest.cpp
@@ -11,7 +11,6 @@
 #include "X86/TestBase.h"
 #include "gtest/gtest.h"
 #include <string>
-#include <unordered_map>
 
 #ifdef __linux__
 #include <endian.h>
@@ -40,9 +39,8 @@ class SubprocessMemoryTest : public X86TestBase {
     return getpid() * TestCount + TestNumber;
   }
 
-  void
-  testCommon(std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
-             const unsigned TestNumber) {
+  void testCommon(StringMap<MemoryValue> MemoryDefinitions,
+                  const unsigned TestNumber) {
     EXPECT_FALSE(
         SM.initializeSubprocessMemory(getSharedMemoryNumber(TestNumber)));
     EXPECT_FALSE(SM.addMemoryDefinition(MemoryDefinitions,
diff --git a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp
index dfc92711d9e85..334aeef70ff51 100644
--- a/llvm/utils/TableGen/DFAPacketizerEmitter.cpp
+++ b/llvm/utils/TableGen/DFAPacketizerEmitter.cpp
@@ -18,6 +18,7 @@
 #include "Common/CodeGenTarget.h"
 #include "DFAEmitter.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TableGen/Record.h"
@@ -28,7 +29,6 @@
 #include <map>
 #include <set>
 #include <string>
-#include <unordered_map>
 #include <vector>
 
 #define DEBUG_TYPE "dfa-emitter"
@@ -217,17 +217,16 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) {
   CodeGenTarget CGT(Records);
   CodeGenSchedModels CGS(Records, CGT);
 
-  std::unordered_map<std::string, std::vector<const CodeGenProcModel *>>
-      ItinsByNamespace;
+  StringMap<std::vector<const CodeGenProcModel *>> ItinsByNamespace;
   for (const CodeGenProcModel &ProcModel : CGS.procModels()) {
     if (ProcModel.hasItineraries()) {
       auto NS = ProcModel.ItinsDef->getValueAsString("PacketizerNamespace");
-      ItinsByNamespace[NS.str()].push_back(&ProcModel);
+      ItinsByNamespace[NS].push_back(&ProcModel);
     }
   }
 
   for (auto &KV : ItinsByNamespace)
-    emitForItineraries(OS, KV.second, KV.first);
+    emitForItineraries(OS, KV.second, KV.first().str());
   OS << "} // end namespace llvm\n";
 }
 

>From e85c985c470cf58c66866e0b3d6da0a59959fc3a Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Fri, 12 Jun 2026 10:59:17 -0700
Subject: [PATCH 4/4] rebase

---
 llvm/tools/llvm-config/llvm-config.cpp        |  4 +-
 llvm/tools/llvm-exegesis/lib/Analysis.cpp     |  4 +-
 .../tools/llvm-exegesis/lib/MCInstrDescView.h |  5 +-
 .../llvm-exegesis/lib/RegisterAliasing.h      |  6 +-
 llvm/tools/llvm-objdump/llvm-objdump.cpp      | 27 ++++-----
 llvm/tools/llvm-profdata/llvm-profdata.cpp    | 16 +++--
 .../llvm-profgen/MissingFrameInferrer.cpp     | 11 ++--
 .../tools/llvm-profgen/MissingFrameInferrer.h | 28 +++------
 llvm/tools/llvm-profgen/PerfReader.cpp        | 21 +++----
 llvm/tools/llvm-profgen/PerfReader.h          | 58 ++++++++++---------
 llvm/tools/llvm-profgen/ProfileGenerator.cpp  | 11 ++--
 llvm/tools/llvm-profgen/ProfileGenerator.h    | 17 +++---
 llvm/tools/llvm-profgen/ProfiledBinary.cpp    | 10 ++--
 llvm/tools/llvm-profgen/ProfiledBinary.h      | 38 +++++++-----
 llvm/tools/llvm-readobj/ObjDumper.h           |  5 +-
 .../llvm-remarkutil/RemarkUtilRegistry.cpp    |  6 +-
 llvm/tools/llvm-xray/xray-registry.cpp        |  6 +-
 17 files changed, 131 insertions(+), 142 deletions(-)

diff --git a/llvm/tools/llvm-config/llvm-config.cpp b/llvm/tools/llvm-config/llvm-config.cpp
index 24ea264419af4..76aa9f82eb0a7 100644
--- a/llvm/tools/llvm-config/llvm-config.cpp
+++ b/llvm/tools/llvm-config/llvm-config.cpp
@@ -21,6 +21,7 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Config/config.h"
 #include "llvm/Support/FileSystem.h"
@@ -31,7 +32,6 @@
 #include "llvm/TargetParser/Triple.h"
 #include <cstdlib>
 #include <set>
-#include <unordered_set>
 #include <vector>
 
 using namespace llvm;
@@ -695,7 +695,7 @@ int main(int argc, char **argv) {
     }
 
     if (PrintSharedMode) {
-      std::unordered_set<std::string> FullDyLibComponents;
+      StringSet<> FullDyLibComponents;
       std::vector<std::string> DyLibComponents =
           getAllDyLibComponents(IsInDevelopmentTree, false, DirSep);
 
diff --git a/llvm/tools/llvm-exegesis/lib/Analysis.cpp b/llvm/tools/llvm-exegesis/lib/Analysis.cpp
index 559add2916896..c35ae0399c91b 100644
--- a/llvm/tools/llvm-exegesis/lib/Analysis.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Analysis.cpp
@@ -196,7 +196,7 @@ std::vector<Analysis::ResolvedSchedClassAndPoints>
 Analysis::makePointsPerSchedClass() const {
   std::vector<ResolvedSchedClassAndPoints> Entries;
   // Maps SchedClassIds to index in result.
-  std::unordered_map<unsigned, size_t> SchedClassIdToIndex;
+  DenseMap<unsigned, size_t> SchedClassIdToIndex;
   const auto &Points = Clustering_.getPoints();
   for (size_t PointId = 0, E = Points.size(); PointId < E; ++PointId) {
     const Benchmark &Point = Points[PointId];
@@ -214,7 +214,7 @@ Analysis::makePointsPerSchedClass() const {
     const auto IndexIt = SchedClassIdToIndex.find(SchedClassId);
     if (IndexIt == SchedClassIdToIndex.end()) {
       // Create a new entry.
-      SchedClassIdToIndex.emplace(SchedClassId, Entries.size());
+      SchedClassIdToIndex.try_emplace(SchedClassId, Entries.size());
       ResolvedSchedClassAndPoints Entry(ResolvedSchedClass(
           State_.getSubtargetInfo(), SchedClassId, WasVariant));
       Entry.PointIds.push_back(PointId);
diff --git a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
index 5c97fdac6916a..c0f28d7d168da 100644
--- a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
+++ b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
@@ -20,10 +20,10 @@
 
 #include <memory>
 #include <random>
-#include <unordered_map>
 
 #include "RegisterAliasing.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstrDesc.h"
 #include "llvm/MC/MCInstrInfo.h"
@@ -197,8 +197,7 @@ struct InstructionsCache {
   const MCInstrInfo &InstrInfo;
   const RegisterAliasingTrackerCache &RATC;
   const MCSubtargetInfo *STI;
-  mutable std::unordered_map<unsigned, std::unique_ptr<Instruction>>
-      Instructions;
+  mutable DenseMap<unsigned, std::unique_ptr<Instruction>> Instructions;
   const BitVectorCache BVC;
 };
 
diff --git a/llvm/tools/llvm-exegesis/lib/RegisterAliasing.h b/llvm/tools/llvm-exegesis/lib/RegisterAliasing.h
index 00e699d4c69b9..ebb7e1ba6d608 100644
--- a/llvm/tools/llvm-exegesis/lib/RegisterAliasing.h
+++ b/llvm/tools/llvm-exegesis/lib/RegisterAliasing.h
@@ -15,9 +15,9 @@
 #define LLVM_TOOLS_LLVM_EXEGESIS_ALIASINGTRACKER_H
 
 #include <memory>
-#include <unordered_map>
 
 #include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/PackedVector.h"
 #include "llvm/MC/MCRegisterInfo.h"
 
@@ -97,9 +97,9 @@ struct RegisterAliasingTrackerCache {
   const MCRegisterInfo &RegInfo;
   const BitVector ReservedReg;
   const BitVector EmptyRegisters;
-  mutable std::unordered_map<unsigned, std::unique_ptr<RegisterAliasingTracker>>
+  mutable DenseMap<unsigned, std::unique_ptr<RegisterAliasingTracker>>
       Registers;
-  mutable std::unordered_map<unsigned, std::unique_ptr<RegisterAliasingTracker>>
+  mutable DenseMap<unsigned, std::unique_ptr<RegisterAliasingTracker>>
       RegisterClasses;
 };
 
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 1da9b5771fd3f..13232d232c669 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -24,6 +24,7 @@
 #include "SourcePrinter.h"
 #include "WasmDump.h"
 #include "XCOFFDump.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetOperations.h"
 #include "llvm/ADT/StringExtras.h"
@@ -83,7 +84,6 @@
 #include <optional>
 #include <set>
 #include <system_error>
-#include <unordered_map>
 #include <utility>
 
 using namespace llvm;
@@ -262,8 +262,8 @@ class BBAddrMapInfo {
   void AddFunctionEntry(BBAddrMap AddrMap, PGOAnalysisMap PGOMap) {
     uint64_t FunctionAddr = AddrMap.getFunctionAddress();
     for (size_t I = 1; I < AddrMap.BBRanges.size(); ++I)
-      RangeBaseAddrToFunctionAddr.emplace(AddrMap.BBRanges[I].BaseAddress,
-                                          FunctionAddr);
+      RangeBaseAddrToFunctionAddr.try_emplace(AddrMap.BBRanges[I].BaseAddress,
+                                              FunctionAddr);
     [[maybe_unused]] auto R = FunctionAddrToMap.try_emplace(
         FunctionAddr, std::move(AddrMap), std::move(PGOMap));
     assert(R.second && "duplicate function address");
@@ -285,8 +285,8 @@ class BBAddrMapInfo {
   }
 
 private:
-  std::unordered_map<uint64_t, BBAddrMapFunctionEntry> FunctionAddrToMap;
-  std::unordered_map<uint64_t, uint64_t> RangeBaseAddrToFunctionAddr;
+  DenseMap<uint64_t, BBAddrMapFunctionEntry> FunctionAddrToMap;
+  DenseMap<uint64_t, uint64_t> RangeBaseAddrToFunctionAddr;
 };
 
 } // namespace
@@ -1659,8 +1659,7 @@ static SymbolInfoTy createDummySymbolInfo(const ObjectFile &Obj,
 
 static void collectBBAddrMapLabels(
     const BBAddrMapInfo &FullAddrMap, uint64_t SectionAddr, uint64_t Start,
-    uint64_t End,
-    std::unordered_map<uint64_t, std::vector<BBAddrMapLabel>> &Labels) {
+    uint64_t End, DenseMap<uint64_t, std::vector<BBAddrMapLabel>> &Labels) {
   if (FullAddrMap.empty())
     return;
   Labels.clear();
@@ -1692,12 +1691,10 @@ static void collectBBAddrMapLabels(
   }
 }
 
-static void
-collectLocalBranchTargets(ArrayRef<uint8_t> Bytes, MCInstrAnalysis *MIA,
-                          MCDisassembler *DisAsm, MCInstPrinter *IP,
-                          const MCSubtargetInfo *STI, uint64_t SectionAddr,
-                          uint64_t Start, uint64_t End,
-                          std::unordered_map<uint64_t, std::string> &Labels) {
+static void collectLocalBranchTargets(
+    ArrayRef<uint8_t> Bytes, MCInstrAnalysis *MIA, MCDisassembler *DisAsm,
+    MCInstPrinter *IP, const MCSubtargetInfo *STI, uint64_t SectionAddr,
+    uint64_t Start, uint64_t End, DenseMap<uint64_t, std::string> &Labels) {
   // Supported by certain targets.
   const bool isPPC = STI->getTargetTriple().isPPC();
   const bool isX86 = STI->getTargetTriple().isX86();
@@ -2422,8 +2419,8 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj,
           Symbols[SI - 1].XCOFFSymInfo.StorageMappingClass &&
           (*Symbols[SI - 1].XCOFFSymInfo.StorageMappingClass == XCOFF::XMC_PR);
 
-      std::unordered_map<uint64_t, std::string> AllLabels;
-      std::unordered_map<uint64_t, std::vector<BBAddrMapLabel>> BBAddrMapLabels;
+      DenseMap<uint64_t, std::string> AllLabels;
+      DenseMap<uint64_t, std::vector<BBAddrMapLabel>> BBAddrMapLabels;
       if (SymbolizeOperands) {
         collectLocalBranchTargets(Bytes, DT->InstrAnalysis.get(),
                                   DT->DisAsm.get(), DT->InstPrinter.get(),
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 08a1ea51af8e5..5a3be5f21c7ff 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -10,6 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallVector.h"
@@ -2045,8 +2046,7 @@ class SampleOverlapAggregator {
   /// Load profiles specified by BaseFilename and TestFilename.
   std::error_code loadProfiles();
 
-  using FuncSampleStatsMap =
-      std::unordered_map<SampleContext, FuncSampleStats, SampleContext::Hash>;
+  using FuncSampleStatsMap = DenseMap<SampleContext, FuncSampleStats>;
 
 private:
   SampleOverlapStats ProfOverlap;
@@ -2207,7 +2207,7 @@ void SampleOverlapAggregator::getHotFunctions(
     uint64_t HotThreshold) const {
   for (const auto &F : ProfStats) {
     if (isFunctionHot(F.second, HotThreshold))
-      HotFunc.emplace(F.first, F.second);
+      HotFunc.try_emplace(F.first, F.second);
   }
 }
 
@@ -2434,12 +2434,10 @@ double SampleOverlapAggregator::computeSampleFunctionOverlap(
 void SampleOverlapAggregator::computeSampleProfileOverlap(raw_fd_ostream &OS) {
   using namespace sampleprof;
 
-  std::unordered_map<SampleContext, const FunctionSamples *,
-                     SampleContext::Hash>
-      BaseFuncProf;
+  DenseMap<SampleContext, const FunctionSamples *> BaseFuncProf;
   const auto &BaseProfiles = BaseReader->getProfiles();
   for (const auto &BaseFunc : BaseProfiles) {
-    BaseFuncProf.emplace(BaseFunc.second.getContext(), &(BaseFunc.second));
+    BaseFuncProf.try_emplace(BaseFunc.second.getContext(), &(BaseFunc.second));
   }
   ProfOverlap.UnionCount = BaseFuncProf.size();
 
@@ -2557,7 +2555,7 @@ void SampleOverlapAggregator::initializeSampleProfileOverlap() {
     FuncSampleStats FuncStats;
     getFuncSampleStats(I.second, FuncStats, BaseHotThreshold);
     ProfOverlap.BaseSample += FuncStats.SampleSum;
-    BaseStats.emplace(I.second.getContext(), FuncStats);
+    BaseStats.try_emplace(I.second.getContext(), FuncStats);
   }
 
   const auto &TestProf = TestReader->getProfiles();
@@ -2566,7 +2564,7 @@ void SampleOverlapAggregator::initializeSampleProfileOverlap() {
     FuncSampleStats FuncStats;
     getFuncSampleStats(I.second, FuncStats, TestHotThreshold);
     ProfOverlap.TestSample += FuncStats.SampleSum;
-    TestStats.emplace(I.second.getContext(), FuncStats);
+    TestStats.try_emplace(I.second.getContext(), FuncStats);
   }
 
   ProfOverlap.BaseName = StringRef(BaseFilename);
diff --git a/llvm/tools/llvm-profgen/MissingFrameInferrer.cpp b/llvm/tools/llvm-profgen/MissingFrameInferrer.cpp
index 1141c41978428..de0eb3681cd3f 100644
--- a/llvm/tools/llvm-profgen/MissingFrameInferrer.cpp
+++ b/llvm/tools/llvm-profgen/MissingFrameInferrer.cpp
@@ -44,8 +44,8 @@ void MissingFrameInferrer::initialize(
     const ContextSampleCounterMap *SampleCounters) {
   // Refine call edges based on LBR samples.
   if (SampleCounters) {
-    std::unordered_map<uint64_t, std::unordered_set<uint64_t>> SampledCalls;
-    std::unordered_map<uint64_t, std::unordered_set<uint64_t>> SampledTailCalls;
+    DenseMap<uint64_t, DenseSet<uint64_t>> SampledCalls;
+    DenseMap<uint64_t, DenseSet<uint64_t>> SampledTailCalls;
 
     // Populate SampledCalls based on static call sites. Similarly to
     // SampledTailCalls.
@@ -72,8 +72,8 @@ void MissingFrameInferrer::initialize(
     }
 
     // Replace static edges with dynamic edges.
-    CallEdges = SampledCalls;
-    TailCallEdges = SampledTailCalls;
+    CallEdges = std::move(SampledCalls);
+    TailCallEdges = std::move(SampledTailCalls);
   }
 
   // Populate function-based edges. This is to speed up address to function
@@ -106,8 +106,7 @@ void MissingFrameInferrer::initialize(
 
 #ifndef NDEBUG
   auto PrintCallTargets =
-      [&](const std::unordered_map<uint64_t, std::unordered_set<uint64_t>>
-              &CallTargets,
+      [&](const DenseMap<uint64_t, DenseSet<uint64_t>> &CallTargets,
           bool IsTailCall) {
         for (const auto &Targets : CallTargets) {
           for (const auto &Target : Targets.second) {
diff --git a/llvm/tools/llvm-profgen/MissingFrameInferrer.h b/llvm/tools/llvm-profgen/MissingFrameInferrer.h
index 4680a9a979ffa..4ed9d3a9d5905 100644
--- a/llvm/tools/llvm-profgen/MissingFrameInferrer.h
+++ b/llvm/tools/llvm-profgen/MissingFrameInferrer.h
@@ -10,11 +10,11 @@
 #define LLVM_TOOLS_LLVM_PROFGEN_MISSINGFRAMEINFERRER_H
 
 #include "PerfReader.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
-#include <unordered_map>
-#include <unordered_set>
 
 namespace llvm {
 namespace sampleprof {
@@ -66,39 +66,29 @@ class MissingFrameInferrer {
   // A map of call instructions to their target addresses. This is first
   // populated with static call edges but then trimmed down to dynamic call
   // edges based on LBR samples.
-  std::unordered_map<uint64_t, std::unordered_set<uint64_t>> CallEdges;
+  DenseMap<uint64_t, DenseSet<uint64_t>> CallEdges;
 
   // A map of tail call instructions to their target addresses. This is first
   // populated with static call edges but then trimmed down to dynamic call
   // edges based on LBR samples.
-  std::unordered_map<uint64_t, std::unordered_set<uint64_t>> TailCallEdges;
+  DenseMap<uint64_t, DenseSet<uint64_t>> TailCallEdges;
 
   // Dynamic call targets in terms of BinaryFunction for any calls.
-  std::unordered_map<uint64_t, std::unordered_set<BinaryFunction *>> CallEdgesF;
+  DenseMap<uint64_t, SmallPtrSet<BinaryFunction *, 0>> CallEdgesF;
 
   // Dynamic call targets in terms of BinaryFunction  for tail calls.
-  std::unordered_map<uint64_t, std::unordered_set<BinaryFunction *>>
-      TailCallEdgesF;
+  DenseMap<uint64_t, SmallPtrSet<BinaryFunction *, 0>> TailCallEdgesF;
 
   // Dynamic tail call targets of caller functions.
-  std::unordered_map<BinaryFunction *, std::vector<uint64_t>> FuncToTailCallMap;
+  DenseMap<BinaryFunction *, std::vector<uint64_t>> FuncToTailCallMap;
 
   // Functions that are reachable via tail calls.
   DenseSet<const BinaryFunction *> TailCallTargetFuncs;
 
-  struct PairHash {
-    std::size_t operator()(
-        const std::pair<BinaryFunction *, BinaryFunction *> &Pair) const {
-      return std::hash<BinaryFunction *>()(Pair.first) ^
-             std::hash<BinaryFunction *>()(Pair.second);
-    }
-  };
-
   // Cached results from a CallerCalleePair to a unique call path between them.
-  std::unordered_map<CallerCalleePair, std::vector<uint64_t>, PairHash>
-      UniquePaths;
+  DenseMap<CallerCalleePair, std::vector<uint64_t>> UniquePaths;
   // Cached results from CallerCalleePair to the number of available call paths.
-  std::unordered_map<CallerCalleePair, uint64_t, PairHash> NonUniquePaths;
+  DenseMap<CallerCalleePair, uint64_t> NonUniquePaths;
 
   DenseSet<BinaryFunction *> Visiting;
 
diff --git a/llvm/tools/llvm-profgen/PerfReader.cpp b/llvm/tools/llvm-profgen/PerfReader.cpp
index 733bfc5c250ac..62b24a288dfc4 100644
--- a/llvm/tools/llvm-profgen/PerfReader.cpp
+++ b/llvm/tools/llvm-profgen/PerfReader.cpp
@@ -218,7 +218,7 @@ void VirtualUnwinder::collectSamplesFromFrame(UnwindState::ProfiledFrame *Cur,
   std::shared_ptr<ContextKey> Key = Stack.getContextKey();
   if (Key == nullptr)
     return;
-  auto Ret = CtxCounterMap->emplace(Hashable<ContextKey>(Key), SampleCounter());
+  auto Ret = CtxCounterMap->try_emplace(Hashable<ContextKey>(Key));
   SampleCounter &SCounter = Ret.first->second;
   for (auto &I : Cur->RangeSamples)
     SCounter.recordRangeCount(std::get<0>(I), std::get<1>(I), std::get<2>(I));
@@ -486,12 +486,12 @@ PerfScriptReader::convertPerfDataToTrace(ProfiledBinary *Binary, bool SkipPID,
 
     // Collect the PIDs
     TraceStream TraceIt(PerfTraceFile);
-    std::unordered_set<int32_t> PIDSet;
+    DenseSet<int32_t> PIDSet;
     while (!TraceIt.isAtEoF()) {
       MMapEvent MMap;
       if (isMMapEvent(TraceIt.getCurrentLine()) &&
           extractMMapEventForBinary(Binary, TraceIt.getCurrentLine(), MMap)) {
-        auto It = PIDSet.emplace(MMap.PID);
+        auto It = PIDSet.insert(MMap.PID);
         if (It.second && (!PIDFilter || MMap.PID == *PIDFilter)) {
           if (!PIDs.empty()) {
             PIDs.append(",");
@@ -996,12 +996,11 @@ void UnsymbolizedProfileReader::readUnsymbolizedProfile(StringRef FileName) {
     // Read context stack for CS profile.
     if (Line.starts_with("[")) {
       ProfileIsCS = true;
-      auto I = ContextStrSet.insert(Line.str());
-      SampleContext::createCtxVectorFromStr(*I.first, Key->Context);
+      auto I = ContextStrSet.insert(Line);
+      SampleContext::createCtxVectorFromStr(I.first->getKey(), Key->Context);
       TraceIt.advance();
     }
-    auto Ret =
-        SampleCounters.emplace(Hashable<ContextKey>(Key), SampleCounter());
+    auto Ret = SampleCounters.try_emplace(Hashable<ContextKey>(Key));
     readSampleCounters(TraceIt, Ret.first->second);
   }
 }
@@ -1053,7 +1052,7 @@ void PerfScriptReader::generateUnsymbolizedProfile() {
          "Sample counter map should be empty before raw profile generation");
   std::shared_ptr<StringBasedCtxKey> Key =
       std::make_shared<StringBasedCtxKey>();
-  SampleCounters.emplace(Hashable<ContextKey>(Key), SampleCounter());
+  SampleCounters.try_emplace(Hashable<ContextKey>(Key));
   for (const auto &Item : AggregatedSamples) {
     const PerfSample *Sample = Item.first.getPtr();
     computeCounterFromLBR(Sample, Item.second);
@@ -1265,9 +1264,7 @@ void PerfScriptReader::warnTruncatedStack() {
 }
 
 void PerfScriptReader::warnInvalidRange() {
-  std::unordered_map<std::pair<uint64_t, uint64_t>, uint64_t,
-                     pair_hash<uint64_t, uint64_t>>
-      Ranges;
+  DenseMap<std::pair<uint64_t, uint64_t>, uint64_t> Ranges;
 
   for (const auto &Item : AggregatedSamples) {
     const PerfSample *Sample = Item.first.getPtr();
@@ -1466,7 +1463,7 @@ void ETMReader::parseETMTraces() {
   // Initialize the SampleCounters map with a single empty context key
   // to aggregate all instruction hits into a global bucket.
   auto Key = std::make_shared<StringBasedCtxKey>();
-  Counters.emplace(Hashable<ContextKey>(Key), SampleCounter());
+  Counters.try_emplace(Hashable<ContextKey>(Key));
 
   // The protocol utilizes a 0x80 byte as an initial synchronization header.
   // Perform a manual search for this sync point to discard any leading
diff --git a/llvm/tools/llvm-profgen/PerfReader.h b/llvm/tools/llvm-profgen/PerfReader.h
index 4d912fa87d511..3e39ec3d0cdc8 100644
--- a/llvm/tools/llvm-profgen/PerfReader.h
+++ b/llvm/tools/llvm-profgen/PerfReader.h
@@ -10,6 +10,8 @@
 #define LLVM_TOOLS_LLVM_PROFGEN_PERFREADER_H
 #include "ErrorHandling.h"
 #include "ProfiledBinary.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Error.h"
@@ -124,27 +126,28 @@ template <class T> class Hashable {
   std::shared_ptr<T> Data;
   Hashable(const std::shared_ptr<T> &D) : Data(D) {}
 
-  // Hash code generation
-  struct Hash {
-    uint64_t operator()(const Hashable<T> &Key) const {
-      // Don't make it virtual for getHashCode
-      uint64_t Hash = Key.Data->getHashCode();
-      assert(Hash && "Should generate HashCode for it!");
-      return Hash;
-    }
-  };
+  T *getPtr() const { return Data.get(); }
+};
 
-  // Hash equal
-  struct Equal {
-    bool operator()(const Hashable<T> &LHS, const Hashable<T> &RHS) const {
-      // Precisely compare the data, vtable will have overhead.
-      return LHS.Data->isEqual(RHS.Data.get());
-    }
-  };
+} // end namespace sampleprof
 
-  T *getPtr() const { return Data.get(); }
+template <typename T> struct DenseMapInfo<sampleprof::Hashable<T>> {
+  static unsigned getHashValue(const sampleprof::Hashable<T> &Key) {
+    // Don't make it virtual for getHashCode
+    uint64_t Hash = Key.Data->getHashCode();
+    assert(Hash && "Should generate HashCode for it!");
+    return DenseMapInfo<uint64_t>::getHashValue(Hash);
+  }
+
+  static bool isEqual(const sampleprof::Hashable<T> &LHS,
+                      const sampleprof::Hashable<T> &RHS) {
+    // Precisely compare the data, vtable will have overhead.
+    return LHS.Data->isEqual(RHS.Data.get());
+  }
 };
 
+namespace sampleprof {
+
 struct PerfSample {
   // LBR stack recorded in FIFO order.
   SmallVector<LBREntry, 16> LBRStack;
@@ -203,9 +206,7 @@ struct PerfSample {
 // After parsing the sample, we record the samples by aggregating them
 // into this counter. The key stores the sample data and the value is
 // the sample repeat times.
-using AggregatedCounter =
-    std::unordered_map<Hashable<PerfSample>, uint64_t,
-                       Hashable<PerfSample>::Hash, Hashable<PerfSample>::Equal>;
+using AggregatedCounter = DenseMap<Hashable<PerfSample>, uint64_t>;
 
 using SampleVector = SmallVector<std::tuple<uint64_t, uint64_t, uint64_t>, 16>;
 
@@ -232,15 +233,16 @@ struct UnwindState {
     ProfiledFrame *Parent;
     SampleVector RangeSamples;
     SampleVector BranchSamples;
-    std::unordered_map<uint64_t, std::unique_ptr<ProfiledFrame>> Children;
+    DenseMap<uint64_t, std::unique_ptr<ProfiledFrame>> Children;
 
     ProfiledFrame(uint64_t Addr = 0, ProfiledFrame *P = nullptr)
         : Address(Addr), Parent(P) {}
     ProfiledFrame *getOrCreateChildFrame(uint64_t Address) {
       assert(Address && "Address can't be zero!");
-      auto Ret = Children.emplace(
-          Address, std::make_unique<ProfiledFrame>(Address, this));
-      return Ret.first->second.get();
+      auto [It, Inserted] = Children.try_emplace(Address);
+      if (Inserted)
+        It->second = std::make_unique<ProfiledFrame>(Address, this);
+      return It->second.get();
     }
     void recordRangeCount(uint64_t Start, uint64_t End, uint64_t Count) {
       RangeSamples.emplace_back(std::make_tuple(Start, End, Count));
@@ -416,9 +418,7 @@ struct SampleCounter {
 };
 
 // Sample counter with context to support context-sensitive profile
-using ContextSampleCounterMap =
-    std::unordered_map<Hashable<ContextKey>, SampleCounter,
-                       Hashable<ContextKey>::Hash, Hashable<ContextKey>::Equal>;
+using ContextSampleCounterMap = DenseMap<Hashable<ContextKey>, SampleCounter>;
 
 struct FrameStack {
   SmallVector<uint64_t, 16> Stack;
@@ -747,7 +747,9 @@ class UnsymbolizedProfileReader : public PerfReaderBase {
   void readSampleCounters(TraceStream &TraceIt, SampleCounter &SCounters);
   void readUnsymbolizedProfile(StringRef Filename);
 
-  std::unordered_set<std::string> ContextStrSet;
+  // Owns the context strings; context frames hold StringRefs into them, which
+  // is fine: StringSet entry storage is stable.
+  StringSet<> ContextStrSet;
 };
 
 class ETMReader {
diff --git a/llvm/tools/llvm-profgen/ProfileGenerator.cpp b/llvm/tools/llvm-profgen/ProfileGenerator.cpp
index 10b5e9ad3def5..97643c1aa1708 100644
--- a/llvm/tools/llvm-profgen/ProfileGenerator.cpp
+++ b/llvm/tools/llvm-profgen/ProfileGenerator.cpp
@@ -434,7 +434,7 @@ void ProfileGeneratorBase::updateFunctionSamples() {
 }
 
 void ProfileGeneratorBase::collectProfiledFunctions() {
-  std::unordered_set<const BinaryFunction *> ProfiledFunctions;
+  SmallPtrSet<const BinaryFunction *, 0> ProfiledFunctions;
   if (collectFunctionsFromRawProfile(ProfiledFunctions))
     Binary->setProfiledFunctions(ProfiledFunctions);
   else if (collectFunctionsFromLLVMProfile(ProfiledFunctions))
@@ -444,7 +444,7 @@ void ProfileGeneratorBase::collectProfiledFunctions() {
 }
 
 bool ProfileGeneratorBase::collectFunctionsFromRawProfile(
-    std::unordered_set<const BinaryFunction *> &ProfiledFunctions) {
+    SmallPtrSetImpl<const BinaryFunction *> &ProfiledFunctions) {
   if (!SampleCounters)
     return false;
   // Go through all the stacks, ranges and branches in sample counters, use
@@ -477,7 +477,7 @@ bool ProfileGeneratorBase::collectFunctionsFromRawProfile(
 }
 
 bool ProfileGenerator::collectFunctionsFromLLVMProfile(
-    std::unordered_set<const BinaryFunction *> &ProfiledFunctions) {
+    SmallPtrSetImpl<const BinaryFunction *> &ProfiledFunctions) {
   for (const auto &FS : ProfileMap) {
     if (auto *Func = Binary->getBinaryFunction(FS.second.getFunction()))
       ProfiledFunctions.insert(Func);
@@ -486,7 +486,7 @@ bool ProfileGenerator::collectFunctionsFromLLVMProfile(
 }
 
 bool CSProfileGenerator::collectFunctionsFromLLVMProfile(
-    std::unordered_set<const BinaryFunction *> &ProfiledFunctions) {
+    SmallPtrSetImpl<const BinaryFunction *> &ProfiledFunctions) {
   for (auto *Node : ContextTracker) {
     if (!Node->getFuncName().empty())
       if (auto *Func = Binary->getBinaryFunction(Node->getFuncName()))
@@ -1296,8 +1296,7 @@ void CSProfileGenerator::populateBodySamplesWithProbes(
   // Extract the top frame probes by looking up each address among the range in
   // the Address2ProbeMap
   extractProbesFromRange(RangeCounter, ProbeCounter);
-  std::unordered_map<MCDecodedPseudoProbeInlineTree *,
-                     std::unordered_set<FunctionSamples *>>
+  DenseMap<MCDecodedPseudoProbeInlineTree *, SmallPtrSet<FunctionSamples *, 0>>
       FrameSamples;
   for (const auto &PI : ProbeCounter) {
     const MCDecodedPseudoProbe *Probe = PI.first;
diff --git a/llvm/tools/llvm-profgen/ProfileGenerator.h b/llvm/tools/llvm-profgen/ProfileGenerator.h
index 2c512779319d4..274dec5d4cf24 100644
--- a/llvm/tools/llvm-profgen/ProfileGenerator.h
+++ b/llvm/tools/llvm-profgen/ProfileGenerator.h
@@ -12,6 +12,8 @@
 #include "ErrorHandling.h"
 #include "PerfReader.h"
 #include "ProfiledBinary.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/ProfileData/SampleProfWriter.h"
 #include <memory>
@@ -20,8 +22,7 @@
 namespace llvm {
 namespace sampleprof {
 
-using ProbeCounterMap =
-    std::unordered_map<const MCDecodedPseudoProbe *, uint64_t>;
+using ProbeCounterMap = DenseMap<const MCDecodedPseudoProbe *, uint64_t>;
 
 // This base class for profile generation of sample-based PGO. We reuse all
 // structures relating to function profiles and profile writers as seen in
@@ -128,11 +129,11 @@ class ProfileGeneratorBase {
   void collectProfiledFunctions();
 
   bool collectFunctionsFromRawProfile(
-      std::unordered_set<const BinaryFunction *> &ProfiledFunctions);
+      SmallPtrSetImpl<const BinaryFunction *> &ProfiledFunctions);
 
   // Collect profiled Functions for llvm sample profile input.
   virtual bool collectFunctionsFromLLVMProfile(
-      std::unordered_set<const BinaryFunction *> &ProfiledFunctions) = 0;
+      SmallPtrSetImpl<const BinaryFunction *> &ProfiledFunctions) = 0;
 
   // List of function prefix to filter out.
   static constexpr const char *FuncPrefixsToFilter[] = {"__cxx_global_var_init",
@@ -186,7 +187,7 @@ class ProfileGenerator : public ProfileGeneratorBase {
   void postProcessProfiles();
   void trimColdProfiles(uint64_t ColdCntThreshold);
   bool collectFunctionsFromLLVMProfile(
-      std::unordered_set<const BinaryFunction *> &ProfiledFunctions) override;
+      SmallPtrSetImpl<const BinaryFunction *> &ProfiledFunctions) override;
 };
 
 class CSProfileGenerator : public ProfileGeneratorBase {
@@ -367,7 +368,7 @@ class CSProfileGenerator : public ProfileGeneratorBase {
   void computeSummaryAndThreshold();
 
   bool collectFunctionsFromLLVMProfile(
-      std::unordered_set<const BinaryFunction *> &ProfiledFunctions) override;
+      SmallPtrSetImpl<const BinaryFunction *> &ProfiledFunctions) override;
 
   void initializeMissingFrameInferrer();
 
@@ -381,7 +382,9 @@ class CSProfileGenerator : public ProfileGeneratorBase {
   // The container for holding the FunctionSamples used by context trie.
   std::list<FunctionSamples> FSamplesList;
 
-  // Underlying context table serves for sample profile writer.
+  // Underlying context table serves for sample profile writer. SampleContexts
+  // in the output profile hold ArrayRefs into the stored vectors, so the
+  // elements' addresses must be stable: keep std::unordered_set.
   std::unordered_set<SampleContextFrameVector, SampleContextFrameHash> Contexts;
 
   SampleContextTracker ContextTracker;
diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.cpp b/llvm/tools/llvm-profgen/ProfiledBinary.cpp
index 3b1e00093fb9e..ab452d78062e6 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.cpp
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.cpp
@@ -1165,8 +1165,8 @@ SampleContextFrameVector ProfiledBinary::symbolize(const InstructionPointer &IP,
     }
 
     LineLocation Line(LineOffset, Discriminator);
-    auto It = NameStrings.insert(FunctionName.str());
-    CallStack.emplace_back(FunctionId(StringRef(*It.first)), Line);
+    auto It = NameStrings.insert(FunctionName);
+    CallStack.emplace_back(FunctionId(It.first->getKey()), Line);
   }
 
   return CallStack;
@@ -1177,9 +1177,7 @@ StringRef ProfiledBinary::symbolizeDataAddress(uint64_t Address) {
       unwrapOrError(Symbolizer->symbolizeData(SymbolizerPath.str(),
                                               getSectionedAddress(Address)),
                     SymbolizerPath);
-  decltype(NameStrings)::iterator Iter;
-  std::tie(Iter, std::ignore) = NameStrings.insert(DataDIGlobal.Name);
-  return StringRef(*Iter);
+  return NameStrings.insert(DataDIGlobal.Name).first->getKey();
 }
 
 void ProfiledBinary::computeInlinedContextSizeForRange(uint64_t RangeBegin,
@@ -1250,7 +1248,7 @@ void ProfiledBinary::loadSymbolsFromPseudoProbe() {
                "Top level pseudo probe does not match function range");
 
         const auto *ProbeDesc = getFuncDescForGUID(InlineTreeNode->Guid);
-        auto Ret = PseudoProbeNames.emplace(Func, ProbeDesc->FuncName);
+        auto Ret = PseudoProbeNames.try_emplace(Func, ProbeDesc->FuncName);
         if (!Ret.second && Ret.first->second != ProbeDesc->FuncName &&
             ShowDetailedWarning)
           WithColor::warning()
diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.h b/llvm/tools/llvm-profgen/ProfiledBinary.h
index a407adb978091..cb15fb14a4680 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.h
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.h
@@ -12,6 +12,8 @@
 #include "CallContext.h"
 #include "ErrorHandling.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
@@ -119,7 +121,7 @@ struct FuncRange {
 // we will switch to Dwarf CFI based tracker
 struct PrologEpilogTracker {
   // A set of prolog and epilog addresses. Used by virtual unwinding.
-  std::unordered_set<uint64_t> PrologEpilogSet;
+  DenseSet<uint64_t> PrologEpilogSet;
   ProfiledBinary *Binary;
   PrologEpilogTracker(ProfiledBinary *Bin) : Binary(Bin){};
 
@@ -136,7 +138,7 @@ struct PrologEpilogTracker {
   }
 
   // Take the last two addresses before the return address as epilog
-  void inferEpilogAddresses(std::unordered_set<uint64_t> &RetAddrs) {
+  void inferEpilogAddresses(DenseSet<uint64_t> &RetAddrs) {
     for (auto Addr : RetAddrs) {
       PrologEpilogSet.insert(Addr);
       InstructionPointer IP(Binary, Addr);
@@ -240,10 +242,10 @@ class ProfiledBinary {
 
   // Lookup BinaryFunctions using the function name's MD5 hash. Needed if the
   // profile is using MD5.
-  std::unordered_map<uint64_t, BinaryFunction *> HashBinaryFunctions;
+  DenseMap<uint64_t, BinaryFunction *> HashBinaryFunctions;
 
   // A list of binary functions that have samples.
-  std::unordered_set<const BinaryFunction *> ProfiledFunctions;
+  SmallPtrSet<const BinaryFunction *, 0> ProfiledFunctions;
 
   // GUID to symbol start address map
   DenseMap<uint64_t, uint64_t> SymbolStartAddrs;
@@ -254,7 +256,7 @@ class ProfiledBinary {
       AlternativeFunctionGUIDs;
 
   // Mapping of profiled binary function to its pseudo probe name
-  std::unordered_map<const BinaryFunction *, StringRef> PseudoProbeNames;
+  DenseMap<const BinaryFunction *, StringRef> PseudoProbeNames;
 
   // These maps are for temporary use of warning diagnosis.
   DenseSet<int64_t> AddrsWithMultipleSymbols;
@@ -269,26 +271,29 @@ class ProfiledBinary {
   std::map<uint64_t, FuncRange> StartAddrToFuncRangeMap;
 
   // Address to context location map. Used to expand the context.
+  // getCachedFrameLocationStack returns references to the mapped values while
+  // later queries insert, so the values' addresses must be stable: keep
+  // std::unordered_map.
   std::unordered_map<uint64_t, SampleContextFrameVector> AddressToLocStackMap;
 
   // Address to instruction size map. Also used for quick Address lookup.
-  std::unordered_map<uint64_t, uint64_t> AddressToInstSizeMap;
+  DenseMap<uint64_t, uint64_t> AddressToInstSizeMap;
 
   // An array of Addresses of all instructions sorted in increasing order. The
   // sorting is needed to fast advance to the next forward/backward instruction.
   std::vector<uint64_t> CodeAddressVec;
   // A set of call instruction addresses. Used by virtual unwinding.
-  std::unordered_set<uint64_t> CallAddressSet;
+  DenseSet<uint64_t> CallAddressSet;
   // A set of return instruction addresses. Used by virtual unwinding.
-  std::unordered_set<uint64_t> RetAddressSet;
+  DenseSet<uint64_t> RetAddressSet;
   // An ordered set of unconditional branch instruction addresses.
   std::set<uint64_t> UncondBranchAddrSet;
   // A set of branch instruction addresses.
-  std::unordered_set<uint64_t> BranchAddressSet;
+  DenseSet<uint64_t> BranchAddressSet;
   // A set of indirect branch instruction addresses.
-  std::unordered_set<uint64_t> IndirectBranchAddressSet;
+  DenseSet<uint64_t> IndirectBranchAddressSet;
   // A set of branch target addresses (destinations of branches/calls).
-  std::unordered_set<uint64_t> BranchTargetAddressSet;
+  DenseSet<uint64_t> BranchTargetAddressSet;
 
   // Estimate and track function prolog and epilog ranges.
   PrologEpilogTracker ProEpilogTracker;
@@ -304,7 +309,9 @@ class ProfiledBinary {
   std::unique_ptr<symbolize::LLVMSymbolizer> Symbolizer;
 
   // String table owning function name strings created from the symbolizer.
-  std::unordered_set<std::string> NameStrings;
+  // StringRefs into the stored names are retained by symbolization results,
+  // which is fine: StringSet entry storage is stable.
+  StringSet<> NameStrings;
 
   // MMap events for PT_LOAD segments without 'x' memory protection flag.
   std::map<uint64_t, MMapEvent, std::greater<uint64_t>> NonTextMMapEvents;
@@ -575,12 +582,13 @@ class ProfiledBinary {
     return BinaryFunctions;
   }
 
-  std::unordered_set<const BinaryFunction *> &getProfiledFunctions() {
+  SmallPtrSetImpl<const BinaryFunction *> &getProfiledFunctions() {
     return ProfiledFunctions;
   }
 
-  void setProfiledFunctions(std::unordered_set<const BinaryFunction *> &Funcs) {
-    ProfiledFunctions = Funcs;
+  void setProfiledFunctions(SmallPtrSetImpl<const BinaryFunction *> &Funcs) {
+    ProfiledFunctions.clear();
+    ProfiledFunctions.insert_range(Funcs);
   }
 
   BinaryFunction *getBinaryFunction(FunctionId FName) {
diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index 0dba8252fd466..f019ceee112d9 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -15,12 +15,11 @@
 
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Object/OffloadBinary.h"
 #include "llvm/Support/CommandLine.h"
 
-#include <unordered_set>
-
 namespace llvm {
 namespace object {
 class Archive;
@@ -207,7 +206,7 @@ class ObjDumper {
   virtual void printProgramHeaders() {}
   virtual void printSectionMapping() {}
 
-  std::unordered_set<std::string> Warnings;
+  StringSet<> Warnings;
 };
 
 std::unique_ptr<ObjDumper> createCOFFDumper(const object::COFFObjectFile &Obj,
diff --git a/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.cpp b/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.cpp
index 244a16d51805b..8ff8ac3d79ce0 100644
--- a/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.cpp
+++ b/llvm/tools/llvm-remarkutil/RemarkUtilRegistry.cpp
@@ -10,15 +10,15 @@
 //
 //===----------------------------------------------------------------------===//
 #include "RemarkUtilRegistry.h"
-#include <unordered_map>
+#include "llvm/ADT/DenseMap.h"
 
 namespace llvm {
 namespace remarkutil {
 
 using HandlerType = std::function<Error()>;
 
-static std::unordered_map<cl::SubCommand *, HandlerType> &getCommands() {
-  static std::unordered_map<cl::SubCommand *, HandlerType> Commands;
+static DenseMap<cl::SubCommand *, HandlerType> &getCommands() {
+  static DenseMap<cl::SubCommand *, HandlerType> Commands;
   return Commands;
 }
 
diff --git a/llvm/tools/llvm-xray/xray-registry.cpp b/llvm/tools/llvm-xray/xray-registry.cpp
index ae18f8d6f57c1..d5149a20c58ea 100644
--- a/llvm/tools/llvm-xray/xray-registry.cpp
+++ b/llvm/tools/llvm-xray/xray-registry.cpp
@@ -11,15 +11,15 @@
 //===----------------------------------------------------------------------===//
 #include "xray-registry.h"
 
-#include <unordered_map>
+#include "llvm/ADT/DenseMap.h"
 
 using namespace llvm;
 using namespace xray;
 
 using HandlerType = std::function<Error()>;
 
-static std::unordered_map<cl::SubCommand *, HandlerType> &getCommands() {
-  static std::unordered_map<cl::SubCommand *, HandlerType> Commands;
+static DenseMap<cl::SubCommand *, HandlerType> &getCommands() {
+  static DenseMap<cl::SubCommand *, HandlerType> Commands;
   return Commands;
 }
 



More information about the llvm-commits mailing list