[llvm] [Analysis][NFC] Store CallbackVH in vector, not in map (PR #184323)

Alexis Engelke via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 3 03:15:41 PST 2026


https://github.com/aengelke created https://github.com/llvm/llvm-project/pull/184323

This avoid non-trivial move operations whenever the map grows.

-0.09% perf improvement: https://llvm-compile-time-tracker.com/compare.php?from=7b6751916cf74692df9c331ecdc731c42addafdf&to=4448dbb3626ba122434057b0c7c96690e5bd97d7&stat=instructions:u

>From 35366ec3425fd78f2b6ed8b921d250e5f5d49e39 Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Sun, 18 Jan 2026 12:15:50 +0000
Subject: [PATCH] [Analysis][NFC] Store CallbackVH in vector, not in map

This avoid non-trivial move operations whenever the map grows.

-0.09% perf improvement: https://llvm-compile-time-tracker.com/compare.php?from=7b6751916cf74692df9c331ecdc731c42addafdf&to=4448dbb3626ba122434057b0c7c96690e5bd97d7&stat=instructions:u
---
 .../llvm/Analysis/BlockFrequencyInfoImpl.h    | 60 ++++++++++---------
 1 file changed, 31 insertions(+), 29 deletions(-)

diff --git a/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h b/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h
index 3d0942aa2d9f3..b3c48ee02d01a 100644
--- a/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h
+++ b/llvm/include/llvm/Analysis/BlockFrequencyInfoImpl.h
@@ -857,21 +857,10 @@ template <class BT> class BlockFrequencyInfoImpl : BlockFrequencyInfoImplBase {
   const FunctionT *F = nullptr;
 
   // All blocks in reverse postorder.
-  std::vector<const BlockT *> RPOT;
-  DenseMap<BlockKeyT, std::pair<BlockNode, BFICallbackVH>> Nodes;
+  std::vector<BFICallbackVH> RPOT;
+  DenseMap<const BlockT *, BlockNode> Nodes;
 
-  using rpot_iterator = typename std::vector<const BlockT *>::const_iterator;
-
-  rpot_iterator rpot_begin() const { return RPOT.begin(); }
-  rpot_iterator rpot_end() const { return RPOT.end(); }
-
-  size_t getIndex(const rpot_iterator &I) const { return I - rpot_begin(); }
-
-  BlockNode getNode(const rpot_iterator &I) const {
-    return BlockNode(getIndex(I));
-  }
-
-  BlockNode getNode(const BlockT *BB) const { return Nodes.lookup(BB).first; }
+  BlockNode getNode(const BlockT *BB) const { return Nodes.lookup(BB); }
 
   const BlockT *getBlock(const BlockNode &Node) const {
     assert(Node.Index < RPOT.size());
@@ -1035,7 +1024,10 @@ template <class BT> class BlockFrequencyInfoImpl : BlockFrequencyInfoImplBase {
     // We don't erase corresponding items from `Freqs`, `RPOT` and other to
     // avoid invalidating indices. Doing so would have saved some memory, but
     // it's not worth it.
-    Nodes.erase(BB);
+    auto It = Nodes.find(BB);
+    assert(It != Nodes.end() && "cannot forget block that was never seen");
+    RPOT[It->second.Index] = {}; // Clear value handle.
+    Nodes.erase(It);
   }
 
   Scaled64 getFloatingBlockFreq(const BlockT *BB) const {
@@ -1079,15 +1071,24 @@ class BFICallbackVH<BasicBlock, BFIImplT> : public CallbackVH {
   void deleted() override {
     BFIImpl->forgetBlock(cast<BasicBlock>(getValPtr()));
   }
+
+  operator const BasicBlock *() const {
+    Value *V = *static_cast<const CallbackVH *>(this);
+    return cast<BasicBlock>(V);
+  }
 };
 
 /// Dummy implementation since MachineBasicBlocks aren't Values, so ValueHandles
 /// don't apply to them.
 template <class BFIImplT>
 class BFICallbackVH<MachineBasicBlock, BFIImplT> {
+  const MachineBasicBlock *MBB;
+
 public:
   BFICallbackVH() = default;
-  BFICallbackVH(const MachineBasicBlock *, BFIImplT *) {}
+  BFICallbackVH(const MachineBasicBlock *MBB, BFIImplT *) : MBB(MBB) {}
+
+  operator const MachineBasicBlock *() const { return MBB; }
 };
 
 } // end namespace bfi_detail
@@ -1139,14 +1140,15 @@ void BlockFrequencyInfoImpl<BT>::setBlockFreq(const BlockT *BB,
                                               BlockFrequency Freq) {
   auto [It, Inserted] = Nodes.try_emplace(BB);
   if (!Inserted)
-    BlockFrequencyInfoImplBase::setBlockFreq(It->second.first, Freq);
+    BlockFrequencyInfoImplBase::setBlockFreq(It->second, Freq);
   else {
     // If BB is a newly added block after BFI is done, we need to create a new
     // BlockNode for it assigned with a new index. The index can be determined
     // by the size of Freqs.
     BlockNode NewNode(Freqs.size());
-    It->second = {NewNode, BFICallbackVH(BB, this)};
+    It->second = NewNode;
     Freqs.emplace_back();
+    RPOT.emplace_back(BB, this);
     BlockFrequencyInfoImplBase::setBlockFreq(NewNode, Freq);
   }
 }
@@ -1154,18 +1156,19 @@ void BlockFrequencyInfoImpl<BT>::setBlockFreq(const BlockT *BB,
 template <class BT> void BlockFrequencyInfoImpl<BT>::initializeRPOT() {
   const BlockT *Entry = &F->front();
   RPOT.reserve(F->size());
-  std::copy(po_begin(Entry), po_end(Entry), std::back_inserter(RPOT));
+  for (const BlockT *BB : post_order(Entry))
+    RPOT.emplace_back(BB, this);
   std::reverse(RPOT.begin(), RPOT.end());
 
   assert(RPOT.size() - 1 <= BlockNode::getMaxIndex() &&
          "More nodes in function than Block Frequency Info supports");
 
   LLVM_DEBUG(dbgs() << "reverse-post-order-traversal\n");
-  for (rpot_iterator I = rpot_begin(), E = rpot_end(); I != E; ++I) {
-    BlockNode Node = getNode(I);
-    LLVM_DEBUG(dbgs() << " - " << getIndex(I) << ": " << getBlockName(Node)
+  for (auto [Idx, Block] : enumerate(RPOT)) {
+    BlockNode Node = BlockNode(Idx);
+    LLVM_DEBUG(dbgs() << " - " << Idx << ": " << getBlockName(Node)
                       << "\n");
-    Nodes[*I] = {Node, BFICallbackVH(*I, this)};
+    Nodes[Block] = Node;
   }
 
   Working.reserve(RPOT.size());
@@ -1323,13 +1326,12 @@ bool BlockFrequencyInfoImpl<BT>::tryToComputeMassInFunction() {
   assert(!Working[0].isLoopHeader() && "entry block is a loop header");
 
   Working[0].getMass() = BlockMass::getFull();
-  for (rpot_iterator I = rpot_begin(), IE = rpot_end(); I != IE; ++I) {
+  for (size_t i = 0, n = RPOT.size(); i != n; ++i) {
     // Check for nodes that have been packaged.
-    BlockNode Node = getNode(I);
-    if (Working[Node.Index].isPackaged())
+    if (Working[i].isPackaged())
       continue;
 
-    if (!propagateMassToSuccessors(nullptr, Node))
+    if (!propagateMassToSuccessors(nullptr, BlockNode(i)))
       return false;
   }
   return true;
@@ -1720,13 +1722,13 @@ void BlockFrequencyInfoImpl<BT>::verifyMatch(
   for (auto &Entry : Nodes) {
     const BlockT *BB = Entry.first;
     if (BB) {
-      ValidNodes[BB] = Entry.second.first;
+      ValidNodes[BB] = Entry.second;
     }
   }
   for (auto &Entry : Other.Nodes) {
     const BlockT *BB = Entry.first;
     if (BB) {
-      OtherValidNodes[BB] = Entry.second.first;
+      OtherValidNodes[BB] = Entry.second;
     }
   }
   unsigned NumValidNodes = ValidNodes.size();



More information about the llvm-commits mailing list