[llvm] [CodeGen] Introduce `MachineDomTreeUpdater` (PR #95369)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 24 05:42:35 PDT 2024


https://github.com/paperchalice updated https://github.com/llvm/llvm-project/pull/95369

>From 3bcdc3e8105de1c9a8500d73474fb2cb0ddb45bf Mon Sep 17 00:00:00 2001
From: PaperChalice <liujunchang97 at outlook.com>
Date: Thu, 13 Jun 2024 16:03:52 +0800
Subject: [PATCH 1/2] [CodeGen] Introduce `MachineDomTreeUpdater` This commit
 convert most of `DomTreeUpdater` into `GenericDomTreeUpdater` class template.
 There are some differences between the interfaces of `BasicBlock` and
 `MachineBasicBlock`, so there are some functions needed to implement by
 subclasses.

---
 llvm/include/llvm/Analysis/DomTreeUpdater.h   | 196 ++-----
 .../llvm/Analysis/GenericDomTreeUpdater.h     | 525 ++++++++++++++++++
 llvm/include/llvm/CodeGen/MachineBasicBlock.h |   3 +
 .../llvm/CodeGen/MachineDomTreeUpdater.h      |  72 +++
 .../llvm/CodeGen/MachinePostDominators.h      |   1 +
 llvm/lib/Analysis/DomTreeUpdater.cpp          | 348 +-----------
 llvm/lib/CodeGen/CMakeLists.txt               |   1 +
 llvm/lib/CodeGen/MachineBasicBlock.cpp        |   7 +
 llvm/lib/CodeGen/MachineDomTreeUpdater.cpp    |  62 +++
 llvm/unittests/CodeGen/CMakeLists.txt         |   1 +
 .../CodeGen/MachineDomTreeUpdaterTest.cpp     | 276 +++++++++
 11 files changed, 982 insertions(+), 510 deletions(-)
 create mode 100644 llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
 create mode 100644 llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h
 create mode 100644 llvm/lib/CodeGen/MachineDomTreeUpdater.cpp
 create mode 100644 llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp

diff --git a/llvm/include/llvm/Analysis/DomTreeUpdater.h b/llvm/include/llvm/Analysis/DomTreeUpdater.h
index ddb958455ccd7..2b838a311440e 100644
--- a/llvm/include/llvm/Analysis/DomTreeUpdater.h
+++ b/llvm/include/llvm/Analysis/DomTreeUpdater.h
@@ -15,6 +15,8 @@
 #define LLVM_ANALYSIS_DOMTREEUPDATER_H
 
 #include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Analysis/GenericDomTreeUpdater.h"
+#include "llvm/Analysis/PostDominators.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/ValueHandle.h"
 #include "llvm/Support/Compiler.h"
@@ -23,66 +25,17 @@
 #include <vector>
 
 namespace llvm {
-class PostDominatorTree;
 
-class DomTreeUpdater {
-public:
-  enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };
-
-  explicit DomTreeUpdater(UpdateStrategy Strategy_) : Strategy(Strategy_) {}
-  DomTreeUpdater(DominatorTree &DT_, UpdateStrategy Strategy_)
-      : DT(&DT_), Strategy(Strategy_) {}
-  DomTreeUpdater(DominatorTree *DT_, UpdateStrategy Strategy_)
-      : DT(DT_), Strategy(Strategy_) {}
-  DomTreeUpdater(PostDominatorTree &PDT_, UpdateStrategy Strategy_)
-      : PDT(&PDT_), Strategy(Strategy_) {}
-  DomTreeUpdater(PostDominatorTree *PDT_, UpdateStrategy Strategy_)
-      : PDT(PDT_), Strategy(Strategy_) {}
-  DomTreeUpdater(DominatorTree &DT_, PostDominatorTree &PDT_,
-                 UpdateStrategy Strategy_)
-      : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {}
-  DomTreeUpdater(DominatorTree *DT_, PostDominatorTree *PDT_,
-                 UpdateStrategy Strategy_)
-      : DT(DT_), PDT(PDT_), Strategy(Strategy_) {}
-
-  ~DomTreeUpdater() { flush(); }
-
-  /// Returns true if the current strategy is Lazy.
-  bool isLazy() const { return Strategy == UpdateStrategy::Lazy; };
-
-  /// Returns true if the current strategy is Eager.
-  bool isEager() const { return Strategy == UpdateStrategy::Eager; };
-
-  /// Returns true if it holds a DominatorTree.
-  bool hasDomTree() const { return DT != nullptr; }
-
-  /// Returns true if it holds a PostDominatorTree.
-  bool hasPostDomTree() const { return PDT != nullptr; }
-
-  /// Returns true if there is BasicBlock awaiting deletion.
-  /// The deletion will only happen until a flush event and
-  /// all available trees are up-to-date.
-  /// Returns false under Eager UpdateStrategy.
-  bool hasPendingDeletedBB() const { return !DeletedBBs.empty(); }
-
-  /// Returns true if DelBB is awaiting deletion.
-  /// Returns false under Eager UpdateStrategy.
-  bool isBBPendingDeletion(BasicBlock *DelBB) const;
-
-  /// Returns true if either of DT or PDT is valid and the tree has at
-  /// least one update pending. If DT or PDT is nullptr it is treated
-  /// as having no pending updates. This function does not check
-  /// whether there is BasicBlock awaiting deletion.
-  /// Returns false under Eager UpdateStrategy.
-  bool hasPendingUpdates() const;
+class DomTreeUpdater
+    : public GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
+                                   PostDominatorTree> {
+  friend GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
+                               PostDominatorTree>;
 
-  /// Returns true if there are DominatorTree updates queued.
-  /// Returns false under Eager UpdateStrategy or DT is nullptr.
-  bool hasPendingDomTreeUpdates() const;
-
-  /// Returns true if there are PostDominatorTree updates queued.
-  /// Returns false under Eager UpdateStrategy or PDT is nullptr.
-  bool hasPendingPostDomTreeUpdates() const;
+public:
+  using Base =
+      GenericDomTreeUpdater<DomTreeUpdater, DominatorTree, PostDominatorTree>;
+  using Base::Base;
 
   ///@{
   /// \name Mutation APIs
@@ -105,51 +58,6 @@ class DomTreeUpdater {
   /// Although GenericDomTree provides several update primitives,
   /// it is not encouraged to use these APIs directly.
 
-  /// Submit updates to all available trees.
-  /// The Eager Strategy flushes updates immediately while the Lazy Strategy
-  /// queues the updates.
-  ///
-  /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
-  /// in sync with + all updates before that single update.
-  ///
-  /// CAUTION!
-  /// 1. It is required for the state of the LLVM IR to be updated
-  /// *before* submitting the updates because the internal update routine will
-  /// analyze the current state of the CFG to determine whether an update
-  /// is valid.
-  /// 2. It is illegal to submit any update that has already been submitted,
-  /// i.e., you are supposed not to insert an existent edge or delete a
-  /// nonexistent edge.
-  void applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates);
-
-  /// Submit updates to all available trees. It will also
-  /// 1. discard duplicated updates,
-  /// 2. remove invalid updates. (Invalid updates means deletion of an edge that
-  /// still exists or insertion of an edge that does not exist.)
-  /// The Eager Strategy flushes updates immediately while the Lazy Strategy
-  /// queues the updates.
-  ///
-  /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
-  /// in sync with + all updates before that single update.
-  ///
-  /// CAUTION!
-  /// 1. It is required for the state of the LLVM IR to be updated
-  /// *before* submitting the updates because the internal update routine will
-  /// analyze the current state of the CFG to determine whether an update
-  /// is valid.
-  /// 2. It is illegal to submit any update that has already been submitted,
-  /// i.e., you are supposed not to insert an existent edge or delete a
-  /// nonexistent edge.
-  /// 3. It is only legal to submit updates to an edge in the order CFG changes
-  /// are made. The order you submit updates on different edges is not
-  /// restricted.
-  void applyUpdatesPermissive(ArrayRef<DominatorTree::UpdateType> Updates);
-
-  /// Notify DTU that the entry block was replaced.
-  /// Recalculate all available trees and flush all BasicBlocks
-  /// awaiting deletion immediately.
-  void recalculate(Function &F);
-
   /// Delete DelBB. DelBB will be removed from its Parent and
   /// erased from available trees if it exists and finally get deleted.
   /// Under Eager UpdateStrategy, DelBB will be processed immediately.
@@ -172,33 +80,6 @@ class DomTreeUpdater {
 
   ///@}
 
-  ///@{
-  /// \name Flush APIs
-  ///
-  /// CAUTION! By the moment these flush APIs are called, the current CFG needs
-  /// to be the same as the CFG which DTU is in sync with + all updates
-  /// submitted.
-
-  /// Flush DomTree updates and return DomTree.
-  /// It flushes Deleted BBs if both trees are up-to-date.
-  /// It must only be called when it has a DomTree.
-  DominatorTree &getDomTree();
-
-  /// Flush PostDomTree updates and return PostDomTree.
-  /// It flushes Deleted BBs if both trees are up-to-date.
-  /// It must only be called when it has a PostDomTree.
-  PostDominatorTree &getPostDomTree();
-
-  /// Apply all pending updates to available trees and flush all BasicBlocks
-  /// awaiting deletion.
-
-  void flush();
-
-  ///@}
-
-  /// Debug method to help view the internal state of this class.
-  LLVM_DUMP_METHOD void dump() const;
-
 private:
   class CallBackOnDeletion final : public CallbackVH {
   public:
@@ -216,16 +97,7 @@ class DomTreeUpdater {
     }
   };
 
-  SmallVector<DominatorTree::UpdateType, 16> PendUpdates;
-  size_t PendDTUpdateIndex = 0;
-  size_t PendPDTUpdateIndex = 0;
-  DominatorTree *DT = nullptr;
-  PostDominatorTree *PDT = nullptr;
-  const UpdateStrategy Strategy;
-  SmallPtrSet<BasicBlock *, 8> DeletedBBs;
   std::vector<CallBackOnDeletion> Callbacks;
-  bool IsRecalculatingDomTree = false;
-  bool IsRecalculatingPostDomTree = false;
 
   /// First remove all the instructions of DelBB and then make sure DelBB has a
   /// valid terminator instruction which is necessary to have when DelBB still
@@ -237,32 +109,28 @@ class DomTreeUpdater {
   /// Returns true if at least one BasicBlock is deleted.
   bool forceFlushDeletedBB();
 
-  /// Helper function to apply all pending DomTree updates.
-  void applyDomTreeUpdates();
-
-  /// Helper function to apply all pending PostDomTree updates.
-  void applyPostDomTreeUpdates();
-
-  /// Helper function to flush deleted BasicBlocks if all available
-  /// trees are up-to-date.
-  void tryFlushDeletedBB();
-
-  /// Drop all updates applied by all available trees and delete BasicBlocks if
-  /// all available trees are up-to-date.
-  void dropOutOfDateUpdates();
-
-  /// Erase Basic Block node that has been unlinked from Function
-  /// in the DomTree and PostDomTree.
-  void eraseDelBBNode(BasicBlock *DelBB);
-
-  /// Returns true if the update appears in the LLVM IR.
-  /// It is used to check whether an update is valid in
-  /// insertEdge/deleteEdge or is unnecessary in the batch update.
-  bool isUpdateValid(DominatorTree::UpdateType Update) const;
-
-  /// Returns true if the update is self dominance.
-  bool isSelfDominance(DominatorTree::UpdateType Update) const;
+  /// Debug method to help view the internal state of this class.
+  LLVM_DUMP_METHOD void dump() const {
+    Base::dump();
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+    raw_ostream &OS = dbgs();
+    OS << "Pending Callbacks:\n";
+    int Index = 0;
+    for (const auto &BB : Callbacks) {
+      OS << "  " << Index << " : ";
+      ++Index;
+      if (BB->hasName())
+        OS << BB->getName() << "(";
+      else
+        OS << "(no_name)(";
+      OS << BB << ")\n";
+    }
+#endif
+  }
 };
+
+extern template class GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
+                                            PostDominatorTree>;
 } // namespace llvm
 
 #endif // LLVM_ANALYSIS_DOMTREEUPDATER_H
diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
new file mode 100644
index 0000000000000..7092c67083a67
--- /dev/null
+++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
@@ -0,0 +1,525 @@
+//===- GenericDomTreeUpdater.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the GenericDomTreeUpdater class, which provides a uniform
+// way to update dominator tree related data structures.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
+#define LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+class GenericDomTreeUpdater {
+  DerivedT &derived() { return *static_cast<DerivedT *>(this); }
+  const DerivedT &derived() const {
+    return *static_cast<const DerivedT *>(this);
+  }
+
+public:
+  enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };
+  using BasicBlockT = typename DomTreeT::NodeType;
+
+  explicit GenericDomTreeUpdater(UpdateStrategy Strategy_)
+      : Strategy(Strategy_) {}
+  GenericDomTreeUpdater(DomTreeT &DT_, UpdateStrategy Strategy_)
+      : DT(&DT_), Strategy(Strategy_) {}
+  GenericDomTreeUpdater(DomTreeT *DT_, UpdateStrategy Strategy_)
+      : DT(DT_), Strategy(Strategy_) {}
+  GenericDomTreeUpdater(PostDomTreeT &PDT_, UpdateStrategy Strategy_)
+      : PDT(&PDT_), Strategy(Strategy_) {}
+  GenericDomTreeUpdater(PostDomTreeT *PDT_, UpdateStrategy Strategy_)
+      : PDT(PDT_), Strategy(Strategy_) {}
+  GenericDomTreeUpdater(DomTreeT &DT_, PostDomTreeT &PDT_,
+                        UpdateStrategy Strategy_)
+      : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {}
+  GenericDomTreeUpdater(DomTreeT *DT_, PostDomTreeT *PDT_,
+                        UpdateStrategy Strategy_)
+      : DT(DT_), PDT(PDT_), Strategy(Strategy_) {}
+
+  ~GenericDomTreeUpdater() { flush(); }
+
+  /// Returns true if the current strategy is Lazy.
+  bool isLazy() const { return Strategy == UpdateStrategy::Lazy; };
+
+  /// Returns true if the current strategy is Eager.
+  bool isEager() const { return Strategy == UpdateStrategy::Eager; };
+
+  /// Returns true if it holds a DomTreeT.
+  bool hasDomTree() const { return DT != nullptr; }
+
+  /// Returns true if it holds a PostDomTreeT.
+  bool hasPostDomTree() const { return PDT != nullptr; }
+
+  /// Returns true if there is BasicBlockT awaiting deletion.
+  /// The deletion will only happen until a flush event and
+  /// all available trees are up-to-date.
+  /// Returns false under Eager UpdateStrategy.
+  bool hasPendingDeletedBB() const { return !DeletedBBs.empty(); }
+
+  /// Returns true if DelBB is awaiting deletion.
+  /// Returns false under Eager UpdateStrategy.
+  bool isBBPendingDeletion(BasicBlockT *DelBB) const {
+    if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty())
+      return false;
+    return DeletedBBs.contains(DelBB);
+  }
+
+  /// Returns true if either of DT or PDT is valid and the tree has at
+  /// least one update pending. If DT or PDT is nullptr it is treated
+  /// as having no pending updates. This function does not check
+  /// whether there is MachineBasicBlock awaiting deletion.
+  /// Returns false under Eager UpdateStrategy.
+  bool hasPendingUpdates() const {
+    return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates();
+  }
+
+  /// Returns true if there are DomTreeT updates queued.
+  /// Returns false under Eager UpdateStrategy or DT is nullptr.
+  bool hasPendingDomTreeUpdates() const {
+    if (!DT)
+      return false;
+    return PendUpdates.size() != PendDTUpdateIndex;
+  }
+
+  /// Returns true if there are PostDomTreeT updates queued.
+  /// Returns false under Eager UpdateStrategy or PDT is nullptr.
+  bool hasPendingPostDomTreeUpdates() const {
+    if (!PDT)
+      return false;
+    return PendUpdates.size() != PendPDTUpdateIndex;
+  }
+
+  ///@{
+  /// \name Mutation APIs
+  ///
+  /// These methods provide APIs for submitting updates to the DomTreeT and
+  /// the PostDominatorTree.
+  ///
+  /// Note: There are two strategies to update the DomTreeT and the
+  /// PostDominatorTree:
+  /// 1. Eager UpdateStrategy: Updates are submitted and then flushed
+  /// immediately.
+  /// 2. Lazy UpdateStrategy: Updates are submitted but only flushed when you
+  /// explicitly call Flush APIs. It is recommended to use this update strategy
+  /// when you submit a bunch of updates multiple times which can then
+  /// add up to a large number of updates between two queries on the
+  /// DomTreeT. The incremental updater can reschedule the updates or
+  /// decide to recalculate the dominator tree in order to speedup the updating
+  /// process depending on the number of updates.
+  ///
+  /// Although GenericDomTree provides several update primitives,
+  /// it is not encouraged to use these APIs directly.
+
+  /// Notify DTU that the entry block was replaced.
+  /// Recalculate all available trees and flush all BasicBlocks
+  /// awaiting deletion immediately.
+  template <typename FuncT> void recalculate(FuncT &F) {
+    if (Strategy == UpdateStrategy::Eager) {
+      if (DT)
+        DT->recalculate(F);
+      if (PDT)
+        PDT->recalculate(F);
+      return;
+    }
+
+    // There is little performance gain if we pend the recalculation under
+    // Lazy UpdateStrategy so we recalculate available trees immediately.
+
+    // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes.
+    IsRecalculatingDomTree = IsRecalculatingPostDomTree = true;
+
+    // Because all trees are going to be up-to-date after recalculation,
+    // flush awaiting deleted BasicBlocks.
+    derived().forceFlushDeletedBB();
+    if (DT)
+      DT->recalculate(F);
+    if (PDT)
+      PDT->recalculate(F);
+
+    // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes.
+    IsRecalculatingDomTree = IsRecalculatingPostDomTree = false;
+    PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size();
+    dropOutOfDateUpdates();
+  }
+
+  /// Submit updates to all available trees.
+  /// The Eager Strategy flushes updates immediately while the Lazy Strategy
+  /// queues the updates.
+  ///
+  /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
+  /// in sync with + all updates before that single update.
+  ///
+  /// CAUTION!
+  /// 1. It is required for the state of the LLVM IR to be updated
+  /// *before* submitting the updates because the internal update routine will
+  /// analyze the current state of the CFG to determine whether an update
+  /// is valid.
+  /// 2. It is illegal to submit any update that has already been submitted,
+  /// i.e., you are supposed not to insert an existent edge or delete a
+  /// nonexistent edge.
+  void applyUpdates(ArrayRef<typename DomTreeT::UpdateType> Updates) {
+    if (!DT && !PDT)
+      return;
+
+    if (Strategy == UpdateStrategy::Lazy) {
+      PendUpdates.reserve(PendUpdates.size() + Updates.size());
+      for (const auto &U : Updates)
+        if (!isSelfDominance(U))
+          PendUpdates.push_back(U);
+
+      return;
+    }
+
+    if (DT)
+      DT->applyUpdates(Updates);
+    if (PDT)
+      PDT->applyUpdates(Updates);
+  }
+
+  /// Submit updates to all available trees. It will also
+  /// 1. discard duplicated updates,
+  /// 2. remove invalid updates. (Invalid updates means deletion of an edge that
+  /// still exists or insertion of an edge that does not exist.)
+  /// The Eager Strategy flushes updates immediately while the Lazy Strategy
+  /// queues the updates.
+  ///
+  /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
+  /// in sync with + all updates before that single update.
+  ///
+  /// CAUTION!
+  /// 1. It is required for the state of the LLVM IR to be updated
+  /// *before* submitting the updates because the internal update routine will
+  /// analyze the current state of the CFG to determine whether an update
+  /// is valid.
+  /// 2. It is illegal to submit any update that has already been submitted,
+  /// i.e., you are supposed not to insert an existent edge or delete a
+  /// nonexistent edge.
+  /// 3. It is only legal to submit updates to an edge in the order CFG changes
+  /// are made. The order you submit updates on different edges is not
+  /// restricted.
+  void applyUpdatesPermissive(ArrayRef<typename DomTreeT::UpdateType> Updates) {
+    if (!DT && !PDT)
+      return;
+
+    SmallSet<std::pair<BasicBlockT *, BasicBlockT *>, 8> Seen;
+    SmallVector<typename DomTreeT::UpdateType, 8> DeduplicatedUpdates;
+    for (const auto &U : Updates) {
+      auto Edge = std::make_pair(U.getFrom(), U.getTo());
+      // Because it is illegal to submit updates that have already been applied
+      // and updates to an edge need to be strictly ordered,
+      // it is safe to infer the existence of an edge from the first update
+      // to this edge.
+      // If the first update to an edge is "Delete", it means that the edge
+      // existed before. If the first update to an edge is "Insert", it means
+      // that the edge didn't exist before.
+      //
+      // For example, if the user submits {{Delete, A, B}, {Insert, A, B}},
+      // because
+      // 1. it is illegal to submit updates that have already been applied,
+      // i.e., user cannot delete an nonexistent edge,
+      // 2. updates to an edge need to be strictly ordered,
+      // So, initially edge A -> B existed.
+      // We can then safely ignore future updates to this edge and directly
+      // inspect the current CFG:
+      // a. If the edge still exists, because the user cannot insert an existent
+      // edge, so both {Delete, A, B}, {Insert, A, B} actually happened and
+      // resulted in a no-op. DTU won't submit any update in this case.
+      // b. If the edge doesn't exist, we can then infer that {Delete, A, B}
+      // actually happened but {Insert, A, B} was an invalid update which never
+      // happened. DTU will submit {Delete, A, B} in this case.
+      if (!isSelfDominance(U) && Seen.count(Edge) == 0) {
+        Seen.insert(Edge);
+        // If the update doesn't appear in the CFG, it means that
+        // either the change isn't made or relevant operations
+        // result in a no-op.
+        if (isUpdateValid(U)) {
+          if (isLazy())
+            PendUpdates.push_back(U);
+          else
+            DeduplicatedUpdates.push_back(U);
+        }
+      }
+    }
+
+    if (Strategy == UpdateStrategy::Lazy)
+      return;
+
+    if (DT)
+      DT->applyUpdates(DeduplicatedUpdates);
+    if (PDT)
+      PDT->applyUpdates(DeduplicatedUpdates);
+  }
+
+  ///@}
+
+  ///@{
+  /// \name Flush APIs
+  ///
+  /// CAUTION! By the moment these flush APIs are called, the current CFG needs
+  /// to be the same as the CFG which DTU is in sync with + all updates
+  /// submitted.
+
+  /// Flush DomTree updates and return DomTree.
+  /// It flushes Deleted BBs if both trees are up-to-date.
+  /// It must only be called when it has a DomTree.
+  DomTreeT &getDomTree() {
+    assert(DT && "Invalid acquisition of a null DomTree");
+    applyDomTreeUpdates();
+    dropOutOfDateUpdates();
+    return *DT;
+  }
+
+  /// Flush PostDomTree updates and return PostDomTree.
+  /// It flushes Deleted BBs if both trees are up-to-date.
+  /// It must only be called when it has a PostDomTree.
+  PostDomTreeT &getPostDomTree() {
+    assert(PDT && "Invalid acquisition of a null PostDomTree");
+    applyPostDomTreeUpdates();
+    dropOutOfDateUpdates();
+    return *PDT;
+  }
+
+  /// Apply all pending updates to available trees and flush all BasicBlocks
+  /// awaiting deletion.
+
+  void flush() {
+    applyDomTreeUpdates();
+    applyPostDomTreeUpdates();
+    dropOutOfDateUpdates();
+  }
+
+  ///@}
+
+  /// Debug method to help view the internal state of this class.
+  LLVM_DUMP_METHOD void dump() const {
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+    raw_ostream &OS = llvm::dbgs();
+
+    OS << "Available Trees: ";
+    if (DT || PDT) {
+      if (DT)
+        OS << "DomTree ";
+      if (PDT)
+        OS << "PostDomTree ";
+      OS << "\n";
+    } else
+      OS << "None\n";
+
+    OS << "UpdateStrategy: ";
+    if (Strategy == UpdateStrategy::Eager) {
+      OS << "Eager\n";
+      return;
+    } else
+      OS << "Lazy\n";
+    int Index = 0;
+
+    auto printUpdates =
+        [&](typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
+                begin,
+            typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
+                end) {
+          if (begin == end)
+            OS << "  None\n";
+          Index = 0;
+          for (auto It = begin, ItEnd = end; It != ItEnd; ++It) {
+            auto U = *It;
+            OS << "  " << Index << " : ";
+            ++Index;
+            if (U.getKind() == DomTreeT::Insert)
+              OS << "Insert, ";
+            else
+              OS << "Delete, ";
+            BasicBlockT *From = U.getFrom();
+            if (From) {
+              auto S = From->getName();
+              if (!From->hasName())
+                S = "(no name)";
+              OS << S << "(" << From << "), ";
+            } else {
+              OS << "(badref), ";
+            }
+            BasicBlockT *To = U.getTo();
+            if (To) {
+              auto S = To->getName();
+              if (!To->hasName())
+                S = "(no_name)";
+              OS << S << "(" << To << ")\n";
+            } else {
+              OS << "(badref)\n";
+            }
+          }
+        };
+
+    if (DT) {
+      const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+      assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
+             "Iterator out of range.");
+      OS << "Applied but not cleared DomTreeUpdates:\n";
+      printUpdates(PendUpdates.begin(), I);
+      OS << "Pending DomTreeUpdates:\n";
+      printUpdates(I, PendUpdates.end());
+    }
+
+    if (PDT) {
+      const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+      assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
+             "Iterator out of range.");
+      OS << "Applied but not cleared PostDomTreeUpdates:\n";
+      printUpdates(PendUpdates.begin(), I);
+      OS << "Pending PostDomTreeUpdates:\n";
+      printUpdates(I, PendUpdates.end());
+    }
+
+    OS << "Pending DeletedBBs:\n";
+    Index = 0;
+    for (const auto *BB : DeletedBBs) {
+      OS << "  " << Index << " : ";
+      ++Index;
+      if (BB->hasName())
+        OS << BB->getName() << "(";
+      else
+        OS << "(no_name)(";
+      OS << BB << ")\n";
+    }
+#endif
+  }
+
+protected:
+  SmallVector<typename DomTreeT::UpdateType, 16> PendUpdates;
+  size_t PendDTUpdateIndex = 0;
+  size_t PendPDTUpdateIndex = 0;
+  DomTreeT *DT = nullptr;
+  PostDomTreeT *PDT = nullptr;
+  const UpdateStrategy Strategy;
+  SmallPtrSet<BasicBlockT *, 8> DeletedBBs;
+  bool IsRecalculatingDomTree = false;
+  bool IsRecalculatingPostDomTree = false;
+
+  /// Returns true if the update is self dominance.
+  bool isSelfDominance(typename DomTreeT::UpdateType Update) const {
+    // Won't affect DomTree and PostDomTree.
+    return Update.getFrom() == Update.getTo();
+  }
+
+  /// Helper function to apply all pending DomTree updates.
+  void applyDomTreeUpdates() {
+    // No pending DomTreeUpdates.
+    if (Strategy != UpdateStrategy::Lazy || !DT)
+      return;
+
+    // Only apply updates not are applied by DomTree.
+    if (hasPendingDomTreeUpdates()) {
+      const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+      const auto E = PendUpdates.end();
+      assert(I < E &&
+             "Iterator range invalid; there should be DomTree updates.");
+      DT->applyUpdates(ArrayRef<typename DomTreeT::UpdateType>(I, E));
+      PendDTUpdateIndex = PendUpdates.size();
+    }
+  }
+
+  /// Helper function to apply all pending PostDomTree updates.
+  void applyPostDomTreeUpdates() {
+    // No pending PostDomTreeUpdates.
+    if (Strategy != UpdateStrategy::Lazy || !PDT)
+      return;
+
+    // Only apply updates not are applied by PostDomTree.
+    if (hasPendingPostDomTreeUpdates()) {
+      const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+      const auto E = PendUpdates.end();
+      assert(I < E &&
+             "Iterator range invalid; there should be PostDomTree updates.");
+      PDT->applyUpdates(ArrayRef<typename DomTreeT::UpdateType>(I, E));
+      PendPDTUpdateIndex = PendUpdates.size();
+    }
+  }
+
+  /// Returns true if the update appears in the LLVM IR.
+  /// It is used to check whether an update is valid in
+  /// insertEdge/deleteEdge or is unnecessary in the batch update.
+  bool isUpdateValid(typename DomTreeT::UpdateType Update) const {
+    const auto *From = Update.getFrom();
+    const auto *To = Update.getTo();
+    const auto Kind = Update.getKind();
+
+    // Discard updates by inspecting the current state of successors of From.
+    // Since isUpdateValid() must be called *after* the Terminator of From is
+    // altered we can determine if the update is unnecessary for batch updates
+    // or invalid for a single update.
+    const bool HasEdge = llvm::is_contained(successors(From), To);
+
+    // If the IR does not match the update,
+    // 1. In batch updates, this update is unnecessary.
+    // 2. When called by insertEdge*()/deleteEdge*(), this update is invalid.
+    // Edge does not exist in IR.
+    if (Kind == DomTreeT::Insert && !HasEdge)
+      return false;
+
+    // Edge exists in IR.
+    if (Kind == DomTreeT::Delete && HasEdge)
+      return false;
+
+    return true;
+  }
+
+  /// Erase Basic Block node that has been unlinked from Function
+  /// in the DomTree and PostDomTree.
+  void eraseDelBBNode(BasicBlockT *DelBB) {
+    if (DT && !IsRecalculatingDomTree)
+      if (DT->getNode(DelBB))
+        DT->eraseNode(DelBB);
+
+    if (PDT && !IsRecalculatingPostDomTree)
+      if (PDT->getNode(DelBB))
+        PDT->eraseNode(DelBB);
+  }
+
+  /// Helper function to flush deleted BasicBlocks if all available
+  /// trees are up-to-date.
+  void tryFlushDeletedBB() {
+    if (!hasPendingUpdates())
+      derived().forceFlushDeletedBB();
+  }
+
+  /// Drop all updates applied by all available trees and delete BasicBlocks if
+  /// all available trees are up-to-date.
+  void dropOutOfDateUpdates() {
+    if (Strategy == UpdateStrategy::Eager)
+      return;
+
+    tryFlushDeletedBB();
+
+    // Drop all updates applied by both trees.
+    if (!DT)
+      PendDTUpdateIndex = PendUpdates.size();
+    if (!PDT)
+      PendPDTUpdateIndex = PendUpdates.size();
+
+    const size_t dropIndex = std::min(PendDTUpdateIndex, PendPDTUpdateIndex);
+    const auto B = PendUpdates.begin();
+    const auto E = PendUpdates.begin() + dropIndex;
+    assert(B <= E && "Iterator out of range.");
+    PendUpdates.erase(B, E);
+    // Calculate current index.
+    PendDTUpdateIndex -= dropIndex;
+    PendPDTUpdateIndex -= dropIndex;
+  }
+};
+
+} // namespace llvm
+
+#endif // LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
diff --git a/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
index 5b6be3a96b2fb..e4919ecabd705 100644
--- a/llvm/include/llvm/CodeGen/MachineBasicBlock.h
+++ b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
@@ -238,6 +238,9 @@ class MachineBasicBlock
     BB = nullptr;
   }
 
+  /// Check if there is a name of corresponding LLVM basic block.
+  bool hasName() const;
+
   /// Return the name of the corresponding LLVM basic block, or an empty string.
   StringRef getName() const;
 
diff --git a/llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h b/llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h
new file mode 100644
index 0000000000000..8bc572e6e6af0
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h
@@ -0,0 +1,72 @@
+//===- llvm/CodeGen/MachineDomTreeUpdater.h -----------------------*- C++
+//-*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file exposes interfaces to post dominance information for
+// target-specific code.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_MACHINEDOMTREEUPDATER_H
+#define LLVM_CODEGEN_MACHINEDOMTREEUPDATER_H
+
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Analysis/GenericDomTreeUpdater.h"
+#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachinePostDominators.h"
+#include "llvm/IR/ValueHandle.h"
+#include "llvm/Support/Compiler.h"
+#include <cstddef>
+#include <functional>
+#include <vector>
+
+namespace llvm {
+
+class MachineDomTreeUpdater
+    : public GenericDomTreeUpdater<MachineDomTreeUpdater, MachineDominatorTree,
+                                   MachinePostDominatorTree> {
+  friend GenericDomTreeUpdater<MachineDomTreeUpdater, MachineDominatorTree,
+                               MachinePostDominatorTree>;
+
+public:
+  using Base =
+      GenericDomTreeUpdater<MachineDomTreeUpdater, MachineDominatorTree,
+                            MachinePostDominatorTree>;
+  using Base::Base;
+
+  ///@{
+  /// \name Mutation APIs
+  ///
+
+  /// Delete DelBB. DelBB will be removed from its Parent and
+  /// erased from available trees if it exists and finally get deleted.
+  /// Under Eager UpdateStrategy, DelBB will be processed immediately.
+  /// Under Lazy UpdateStrategy, DelBB will be queued until a flush event and
+  /// all available trees are up-to-date. Assert if any instruction of DelBB is
+  /// modified while awaiting deletion. When both DT and PDT are nullptrs, DelBB
+  /// will be queued until flush() is called.
+  void deleteBB(MachineBasicBlock *DelBB);
+
+  ///@}
+
+private:
+  /// First remove all the instructions of DelBB and then make sure DelBB has a
+  /// valid terminator instruction which is necessary to have when DelBB still
+  /// has to be inside of its parent Function while awaiting deletion under Lazy
+  /// UpdateStrategy to prevent other routines from asserting the state of the
+  /// IR is inconsistent. Assert if DelBB is nullptr or has predecessors.
+  void validateDeleteBB(MachineBasicBlock *DelBB);
+
+  /// Returns true if at least one MachineBasicBlock is deleted.
+  bool forceFlushDeletedBB();
+};
+
+extern template class GenericDomTreeUpdater<
+    MachineDomTreeUpdater, MachineDominatorTree, MachinePostDominatorTree>;
+} // namespace llvm
+#endif // LLVM_CODEGEN_MACHINEDOMTREEUPDATER_H
diff --git a/llvm/include/llvm/CodeGen/MachinePostDominators.h b/llvm/include/llvm/CodeGen/MachinePostDominators.h
index c047e08266292..8846121a3fb7c 100644
--- a/llvm/include/llvm/CodeGen/MachinePostDominators.h
+++ b/llvm/include/llvm/CodeGen/MachinePostDominators.h
@@ -48,6 +48,7 @@ class MachinePostDominatorTree : public PostDomTreeBase<MachineBasicBlock> {
 
 public:
   MachinePostDominatorTree() = default;
+  explicit MachinePostDominatorTree(MachineFunction &MF) { recalculate(MF); }
 
   /// Make findNearestCommonDominator(const NodeT *A, const NodeT *B) available.
   using Base::findNearestCommonDominator;
diff --git a/llvm/lib/Analysis/DomTreeUpdater.cpp b/llvm/lib/Analysis/DomTreeUpdater.cpp
index 0a16fc9a76d29..676cb87210176 100644
--- a/llvm/lib/Analysis/DomTreeUpdater.cpp
+++ b/llvm/lib/Analysis/DomTreeUpdater.cpp
@@ -23,79 +23,8 @@
 
 namespace llvm {
 
-bool DomTreeUpdater::isUpdateValid(
-    const DominatorTree::UpdateType Update) const {
-  const auto *From = Update.getFrom();
-  const auto *To = Update.getTo();
-  const auto Kind = Update.getKind();
-
-  // Discard updates by inspecting the current state of successors of From.
-  // Since isUpdateValid() must be called *after* the Terminator of From is
-  // altered we can determine if the update is unnecessary for batch updates
-  // or invalid for a single update.
-  const bool HasEdge = llvm::is_contained(successors(From), To);
-
-  // If the IR does not match the update,
-  // 1. In batch updates, this update is unnecessary.
-  // 2. When called by insertEdge*()/deleteEdge*(), this update is invalid.
-  // Edge does not exist in IR.
-  if (Kind == DominatorTree::Insert && !HasEdge)
-    return false;
-
-  // Edge exists in IR.
-  if (Kind == DominatorTree::Delete && HasEdge)
-    return false;
-
-  return true;
-}
-
-bool DomTreeUpdater::isSelfDominance(
-    const DominatorTree::UpdateType Update) const {
-  // Won't affect DomTree and PostDomTree.
-  return Update.getFrom() == Update.getTo();
-}
-
-void DomTreeUpdater::applyDomTreeUpdates() {
-  // No pending DomTreeUpdates.
-  if (Strategy != UpdateStrategy::Lazy || !DT)
-    return;
-
-  // Only apply updates not are applied by DomTree.
-  if (hasPendingDomTreeUpdates()) {
-    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
-    const auto E = PendUpdates.end();
-    assert(I < E && "Iterator range invalid; there should be DomTree updates.");
-    DT->applyUpdates(ArrayRef<DominatorTree::UpdateType>(I, E));
-    PendDTUpdateIndex = PendUpdates.size();
-  }
-}
-
-void DomTreeUpdater::flush() {
-  applyDomTreeUpdates();
-  applyPostDomTreeUpdates();
-  dropOutOfDateUpdates();
-}
-
-void DomTreeUpdater::applyPostDomTreeUpdates() {
-  // No pending PostDomTreeUpdates.
-  if (Strategy != UpdateStrategy::Lazy || !PDT)
-    return;
-
-  // Only apply updates not are applied by PostDomTree.
-  if (hasPendingPostDomTreeUpdates()) {
-    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
-    const auto E = PendUpdates.end();
-    assert(I < E &&
-           "Iterator range invalid; there should be PostDomTree updates.");
-    PDT->applyUpdates(ArrayRef<DominatorTree::UpdateType>(I, E));
-    PendPDTUpdateIndex = PendUpdates.size();
-  }
-}
-
-void DomTreeUpdater::tryFlushDeletedBB() {
-  if (!hasPendingUpdates())
-    forceFlushDeletedBB();
-}
+template class GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
+                                     PostDominatorTree>;
 
 bool DomTreeUpdater::forceFlushDeletedBB() {
   if (DeletedBBs.empty())
@@ -117,58 +46,6 @@ bool DomTreeUpdater::forceFlushDeletedBB() {
   return true;
 }
 
-void DomTreeUpdater::recalculate(Function &F) {
-
-  if (Strategy == UpdateStrategy::Eager) {
-    if (DT)
-      DT->recalculate(F);
-    if (PDT)
-      PDT->recalculate(F);
-    return;
-  }
-
-  // There is little performance gain if we pend the recalculation under
-  // Lazy UpdateStrategy so we recalculate available trees immediately.
-
-  // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes.
-  IsRecalculatingDomTree = IsRecalculatingPostDomTree = true;
-
-  // Because all trees are going to be up-to-date after recalculation,
-  // flush awaiting deleted BasicBlocks.
-  forceFlushDeletedBB();
-  if (DT)
-    DT->recalculate(F);
-  if (PDT)
-    PDT->recalculate(F);
-
-  // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes.
-  IsRecalculatingDomTree = IsRecalculatingPostDomTree = false;
-  PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size();
-  dropOutOfDateUpdates();
-}
-
-bool DomTreeUpdater::hasPendingUpdates() const {
-  return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates();
-}
-
-bool DomTreeUpdater::hasPendingDomTreeUpdates() const {
-  if (!DT)
-    return false;
-  return PendUpdates.size() != PendDTUpdateIndex;
-}
-
-bool DomTreeUpdater::hasPendingPostDomTreeUpdates() const {
-  if (!PDT)
-    return false;
-  return PendUpdates.size() != PendPDTUpdateIndex;
-}
-
-bool DomTreeUpdater::isBBPendingDeletion(llvm::BasicBlock *DelBB) const {
-  if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty())
-    return false;
-  return DeletedBBs.contains(DelBB);
-}
-
 // The DT and PDT require the nodes related to updates
 // are not deleted when update functions are called.
 // So BasicBlock deletions must be pended when the
@@ -201,16 +78,6 @@ void DomTreeUpdater::callbackDeleteBB(
   delete DelBB;
 }
 
-void DomTreeUpdater::eraseDelBBNode(BasicBlock *DelBB) {
-  if (DT && !IsRecalculatingDomTree)
-    if (DT->getNode(DelBB))
-      DT->eraseNode(DelBB);
-
-  if (PDT && !IsRecalculatingPostDomTree)
-    if (PDT->getNode(DelBB))
-      PDT->eraseNode(DelBB);
-}
-
 void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) {
   assert(DelBB && "Invalid push_back of nullptr DelBB.");
   assert(pred_empty(DelBB) && "DelBB has one or more predecessors.");
@@ -227,215 +94,4 @@ void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) {
   new UnreachableInst(DelBB->getContext(), DelBB);
 }
 
-void DomTreeUpdater::applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates) {
-  if (!DT && !PDT)
-    return;
-
-  if (Strategy == UpdateStrategy::Lazy) {
-    PendUpdates.reserve(PendUpdates.size() + Updates.size());
-    for (const auto &U : Updates)
-      if (!isSelfDominance(U))
-        PendUpdates.push_back(U);
-
-    return;
-  }
-
-  if (DT)
-    DT->applyUpdates(Updates);
-  if (PDT)
-    PDT->applyUpdates(Updates);
-}
-
-void DomTreeUpdater::applyUpdatesPermissive(
-    ArrayRef<DominatorTree::UpdateType> Updates) {
-  if (!DT && !PDT)
-    return;
-
-  SmallSet<std::pair<BasicBlock *, BasicBlock *>, 8> Seen;
-  SmallVector<DominatorTree::UpdateType, 8> DeduplicatedUpdates;
-  for (const auto &U : Updates) {
-    auto Edge = std::make_pair(U.getFrom(), U.getTo());
-    // Because it is illegal to submit updates that have already been applied
-    // and updates to an edge need to be strictly ordered,
-    // it is safe to infer the existence of an edge from the first update
-    // to this edge.
-    // If the first update to an edge is "Delete", it means that the edge
-    // existed before. If the first update to an edge is "Insert", it means
-    // that the edge didn't exist before.
-    //
-    // For example, if the user submits {{Delete, A, B}, {Insert, A, B}},
-    // because
-    // 1. it is illegal to submit updates that have already been applied,
-    // i.e., user cannot delete an nonexistent edge,
-    // 2. updates to an edge need to be strictly ordered,
-    // So, initially edge A -> B existed.
-    // We can then safely ignore future updates to this edge and directly
-    // inspect the current CFG:
-    // a. If the edge still exists, because the user cannot insert an existent
-    // edge, so both {Delete, A, B}, {Insert, A, B} actually happened and
-    // resulted in a no-op. DTU won't submit any update in this case.
-    // b. If the edge doesn't exist, we can then infer that {Delete, A, B}
-    // actually happened but {Insert, A, B} was an invalid update which never
-    // happened. DTU will submit {Delete, A, B} in this case.
-    if (!isSelfDominance(U) && Seen.count(Edge) == 0) {
-      Seen.insert(Edge);
-      // If the update doesn't appear in the CFG, it means that
-      // either the change isn't made or relevant operations
-      // result in a no-op.
-      if (isUpdateValid(U)) {
-        if (isLazy())
-          PendUpdates.push_back(U);
-        else
-          DeduplicatedUpdates.push_back(U);
-      }
-    }
-  }
-
-  if (Strategy == UpdateStrategy::Lazy)
-    return;
-
-  if (DT)
-    DT->applyUpdates(DeduplicatedUpdates);
-  if (PDT)
-    PDT->applyUpdates(DeduplicatedUpdates);
-}
-
-DominatorTree &DomTreeUpdater::getDomTree() {
-  assert(DT && "Invalid acquisition of a null DomTree");
-  applyDomTreeUpdates();
-  dropOutOfDateUpdates();
-  return *DT;
-}
-
-PostDominatorTree &DomTreeUpdater::getPostDomTree() {
-  assert(PDT && "Invalid acquisition of a null PostDomTree");
-  applyPostDomTreeUpdates();
-  dropOutOfDateUpdates();
-  return *PDT;
-}
-
-void DomTreeUpdater::dropOutOfDateUpdates() {
-  if (Strategy == DomTreeUpdater::UpdateStrategy::Eager)
-    return;
-
-  tryFlushDeletedBB();
-
-  // Drop all updates applied by both trees.
-  if (!DT)
-    PendDTUpdateIndex = PendUpdates.size();
-  if (!PDT)
-    PendPDTUpdateIndex = PendUpdates.size();
-
-  const size_t dropIndex = std::min(PendDTUpdateIndex, PendPDTUpdateIndex);
-  const auto B = PendUpdates.begin();
-  const auto E = PendUpdates.begin() + dropIndex;
-  assert(B <= E && "Iterator out of range.");
-  PendUpdates.erase(B, E);
-  // Calculate current index.
-  PendDTUpdateIndex -= dropIndex;
-  PendPDTUpdateIndex -= dropIndex;
-}
-
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-LLVM_DUMP_METHOD void DomTreeUpdater::dump() const {
-  raw_ostream &OS = llvm::dbgs();
-
-  OS << "Available Trees: ";
-  if (DT || PDT) {
-    if (DT)
-      OS << "DomTree ";
-    if (PDT)
-      OS << "PostDomTree ";
-    OS << "\n";
-  } else
-    OS << "None\n";
-
-  OS << "UpdateStrategy: ";
-  if (Strategy == UpdateStrategy::Eager) {
-    OS << "Eager\n";
-    return;
-  } else
-    OS << "Lazy\n";
-  int Index = 0;
-
-  auto printUpdates =
-      [&](ArrayRef<DominatorTree::UpdateType>::const_iterator begin,
-          ArrayRef<DominatorTree::UpdateType>::const_iterator end) {
-        if (begin == end)
-          OS << "  None\n";
-        Index = 0;
-        for (auto It = begin, ItEnd = end; It != ItEnd; ++It) {
-          auto U = *It;
-          OS << "  " << Index << " : ";
-          ++Index;
-          if (U.getKind() == DominatorTree::Insert)
-            OS << "Insert, ";
-          else
-            OS << "Delete, ";
-          BasicBlock *From = U.getFrom();
-          if (From) {
-            auto S = From->getName();
-            if (!From->hasName())
-              S = "(no name)";
-            OS << S << "(" << From << "), ";
-          } else {
-            OS << "(badref), ";
-          }
-          BasicBlock *To = U.getTo();
-          if (To) {
-            auto S = To->getName();
-            if (!To->hasName())
-              S = "(no_name)";
-            OS << S << "(" << To << ")\n";
-          } else {
-            OS << "(badref)\n";
-          }
-        }
-      };
-
-  if (DT) {
-    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
-    assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
-           "Iterator out of range.");
-    OS << "Applied but not cleared DomTreeUpdates:\n";
-    printUpdates(PendUpdates.begin(), I);
-    OS << "Pending DomTreeUpdates:\n";
-    printUpdates(I, PendUpdates.end());
-  }
-
-  if (PDT) {
-    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
-    assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
-           "Iterator out of range.");
-    OS << "Applied but not cleared PostDomTreeUpdates:\n";
-    printUpdates(PendUpdates.begin(), I);
-    OS << "Pending PostDomTreeUpdates:\n";
-    printUpdates(I, PendUpdates.end());
-  }
-
-  OS << "Pending DeletedBBs:\n";
-  Index = 0;
-  for (const auto *BB : DeletedBBs) {
-    OS << "  " << Index << " : ";
-    ++Index;
-    if (BB->hasName())
-      OS << BB->getName() << "(";
-    else
-      OS << "(no_name)(";
-    OS << BB << ")\n";
-  }
-
-  OS << "Pending Callbacks:\n";
-  Index = 0;
-  for (const auto &BB : Callbacks) {
-    OS << "  " << Index << " : ";
-    ++Index;
-    if (BB->hasName())
-      OS << BB->getName() << "(";
-    else
-      OS << "(no_name)(";
-    OS << BB << ")\n";
-  }
-}
-#endif
 } // namespace llvm
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index 77bf1b165d0cf..8728cb9e11504 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -116,6 +116,7 @@ add_llvm_component_library(LLVMCodeGen
   MachineCheckDebugify.cpp
   MachineCycleAnalysis.cpp
   MachineDebugify.cpp
+  MachineDomTreeUpdater.cpp
   MachineDominanceFrontier.cpp
   MachineDominators.cpp
   MachineFrameInfo.cpp
diff --git a/llvm/lib/CodeGen/MachineBasicBlock.cpp b/llvm/lib/CodeGen/MachineBasicBlock.cpp
index 16505f21f0aad..be8a9e5744ea0 100644
--- a/llvm/lib/CodeGen/MachineBasicBlock.cpp
+++ b/llvm/lib/CodeGen/MachineBasicBlock.cpp
@@ -315,6 +315,13 @@ bool MachineBasicBlock::isLegalToHoistInto() const {
   return true;
 }
 
+bool MachineBasicBlock::hasName() const {
+  if (const BasicBlock *LBB = getBasicBlock())
+    return LBB->hasName();
+  else
+    return false;
+}
+
 StringRef MachineBasicBlock::getName() const {
   if (const BasicBlock *LBB = getBasicBlock())
     return LBB->getName();
diff --git a/llvm/lib/CodeGen/MachineDomTreeUpdater.cpp b/llvm/lib/CodeGen/MachineDomTreeUpdater.cpp
new file mode 100644
index 0000000000000..86b3185ca90a3
--- /dev/null
+++ b/llvm/lib/CodeGen/MachineDomTreeUpdater.cpp
@@ -0,0 +1,62 @@
+//===- MachineDomTreeUpdater.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the MachineDomTreeUpdater class, which provides a
+// uniform way to update dominator tree related data structures.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/MachineDomTreeUpdater.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/CodeGen/MachinePostDominators.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/Support/GenericDomTree.h"
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+namespace llvm {
+
+template class GenericDomTreeUpdater<
+    MachineDomTreeUpdater, MachineDominatorTree, MachinePostDominatorTree>;
+
+bool MachineDomTreeUpdater::forceFlushDeletedBB() {
+  if (DeletedBBs.empty())
+    return false;
+
+  for (auto *BB : DeletedBBs) {
+    eraseDelBBNode(BB);
+    BB->eraseFromParent();
+  }
+  DeletedBBs.clear();
+  return true;
+}
+
+// The DT and PDT require the nodes related to updates
+// are not deleted when update functions are called.
+// So MachineBasicBlock deletions must be pended when the
+// UpdateStrategy is Lazy. When the UpdateStrategy is
+// Eager, the MachineBasicBlock will be deleted immediately.
+void MachineDomTreeUpdater::deleteBB(MachineBasicBlock *DelBB) {
+  validateDeleteBB(DelBB);
+  if (Strategy == UpdateStrategy::Lazy) {
+    DeletedBBs.insert(DelBB);
+    return;
+  }
+
+  eraseDelBBNode(DelBB);
+  DelBB->eraseFromParent();
+}
+
+void MachineDomTreeUpdater::validateDeleteBB(MachineBasicBlock *DelBB) {
+  assert(DelBB && "Invalid push_back of nullptr DelBB.");
+  assert(DelBB->pred_empty() && "DelBB has one or more predecessors.");
+}
+
+} // namespace llvm
diff --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt
index dbbacdd95ec9f..963cdcc0275e1 100644
--- a/llvm/unittests/CodeGen/CMakeLists.txt
+++ b/llvm/unittests/CodeGen/CMakeLists.txt
@@ -32,6 +32,7 @@ add_llvm_unittest(CodeGenTests
   LowLevelTypeTest.cpp
   LexicalScopesTest.cpp
   MachineBasicBlockTest.cpp
+  MachineDomTreeUpdaterTest.cpp
   MachineInstrBundleIteratorTest.cpp
   MachineInstrTest.cpp
   MachineOperandTest.cpp
diff --git a/llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp b/llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp
new file mode 100644
index 0000000000000..638a684f0cef6
--- /dev/null
+++ b/llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp
@@ -0,0 +1,276 @@
+//===- MachineDomTreeUpdaterTest.cpp - MachineDomTreeUpdater unit tests ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/MachineDomTreeUpdater.h"
+#include "llvm/Analysis/CGSCCPassManager.h"
+#include "llvm/Analysis/LoopAnalysisManager.h"
+#include "llvm/CodeGen/MIRParser/MIRParser.h"
+#include "llvm/CodeGen/MachineFunctionAnalysis.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachinePassManager.h"
+#include "llvm/CodeGen/MachinePostDominators.h"
+#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+class MachineDomTreeUpdaterTest : public testing::Test {
+public:
+  LLVMContext Context;
+  std::unique_ptr<TargetMachine> TM;
+  std::unique_ptr<Module> M;
+  std::unique_ptr<MachineModuleInfo> MMI;
+  std::unique_ptr<MIRParser> MIR;
+
+  LoopAnalysisManager LAM;
+  MachineFunctionAnalysisManager MFAM;
+  FunctionAnalysisManager FAM;
+  CGSCCAnalysisManager CGAM;
+  ModuleAnalysisManager MAM;
+
+  ModulePassManager MPM;
+  FunctionPassManager FPM;
+  MachineFunctionPassManager MFPM;
+
+  static void SetUpTestCase() {
+    InitializeAllTargets();
+    InitializeAllTargetMCs();
+  }
+
+  void SetUp() override {
+    Triple TargetTriple("x86_64-unknown-linux-gnu");
+    std::string Error;
+    const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
+    if (!T)
+      GTEST_SKIP();
+    TargetOptions Options;
+    TM = std::unique_ptr<TargetMachine>(
+        T->createTargetMachine("X86", "", "", Options, std::nullopt));
+    if (!TM)
+      GTEST_SKIP();
+    MMI = std::make_unique<MachineModuleInfo>(
+        static_cast<LLVMTargetMachine *>(TM.get()));
+
+    PassBuilder PB(TM.get());
+    PB.registerModuleAnalyses(MAM);
+    PB.registerCGSCCAnalyses(CGAM);
+    PB.registerFunctionAnalyses(FAM);
+    PB.registerLoopAnalyses(LAM);
+    PB.registerMachineFunctionAnalyses(MFAM);
+    PB.crossRegisterProxies(LAM, FAM, CGAM, MAM, &MFAM);
+    MAM.registerPass([&] { return MachineModuleAnalysis(*MMI); });
+  }
+
+  bool parseMIR(StringRef MIRCode, const char *FnName) {
+    SMDiagnostic Diagnostic;
+    std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRCode);
+    MIR = createMIRParser(std::move(MBuffer), Context);
+    if (!MIR)
+      return false;
+
+    M = MIR->parseIRModule();
+    M->setDataLayout(TM->createDataLayout());
+
+    if (MIR->parseMachineFunctions(*M, MAM)) {
+      M.reset();
+      return false;
+    }
+
+    return true;
+  }
+};
+
+TEST_F(MachineDomTreeUpdaterTest, EagerUpdateBasicOperations) {
+  StringRef MIRString = R"(
+--- |
+  define i64 @f0(i64 %i, ptr %p) {
+  bb0:
+    store i64 %i, ptr %p, align 4
+    switch i64 %i, label %bb1 [
+      i64 1, label %bb2
+      i64 2, label %bb3
+    ]
+  bb1:                                              ; preds = %bb0
+    ret i64 1
+  bb2:                                              ; preds = %bb0
+    ret i64 2
+  bb3:                                              ; preds = %bb0
+    ret i64 3
+  }
+...
+---
+name:            f0
+body:             |
+  bb.0.bb0:
+    successors: %bb.2, %bb.4
+    liveins: $rdi, $rsi
+
+    %1:gr32 = COPY $rsi
+    %0:gr64 = COPY $rdi
+    MOV64mr %1, 1, $noreg, 0, $noreg, %0 :: (store (s64) into %ir.p)
+    %2:gr64 = SUB64ri32 %0, 1, implicit-def $eflags
+    JCC_1 %bb.2, 4, implicit $eflags
+    JMP_1 %bb.4
+
+  bb.4.bb0:
+    successors: %bb.3, %bb.1
+
+    %3:gr64 = SUB64ri32 %0, 2, implicit-def $eflags
+    JCC_1 %bb.3, 4, implicit $eflags
+    JMP_1 %bb.1
+
+  bb.1.bb1:
+    %6:gr64 = MOV32ri64 1
+    $rax = COPY %6
+    RET 0, $rax
+
+  bb.2.bb2:
+    %5:gr64 = MOV32ri64 2
+    $rax = COPY %5
+    RET 0, $rax
+
+  bb.3.bb3:
+    %4:gr64 = MOV32ri64 3
+    $rax = COPY %4
+    RET 0, $rax
+
+...
+)";
+
+  ASSERT_TRUE(parseMIR(MIRString, "f0"));
+
+  auto &MF =
+      FAM.getResult<MachineFunctionAnalysis>(*M->getFunction("f0")).getMF();
+
+  MachineDominatorTree DT(MF);
+  MachinePostDominatorTree PDT(MF);
+  MachineDomTreeUpdater DTU(DT, PDT,
+                            MachineDomTreeUpdater::UpdateStrategy::Eager);
+
+  ASSERT_TRUE(DTU.hasDomTree());
+  ASSERT_TRUE(DTU.hasPostDomTree());
+  ASSERT_TRUE(DTU.isEager());
+  ASSERT_FALSE(DTU.isLazy());
+  ASSERT_TRUE(DTU.getDomTree().verify());
+  ASSERT_TRUE(DTU.getPostDomTree().verify());
+  ASSERT_FALSE(DTU.hasPendingUpdates());
+
+  auto B = MF.begin();
+  [[maybe_unused]] auto BB0 = B;
+  auto BB1 = ++B;
+  auto BB2 = ++B;
+  [[maybe_unused]] auto BB3 = ++B;
+  auto BB4 = ++B;
+  EXPECT_EQ(BB1->succ_size(), 2u);
+  ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
+  ASSERT_TRUE(DT.dominates(&*BB1, &*BB4));
+  BB1->removeSuccessor(&*BB4);
+  DTU.deleteBB(&*BB4);
+  EXPECT_EQ(BB1->succ_size(), 1u);
+  ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
+  ASSERT_TRUE(DT.getNode(&*BB4) == nullptr);
+}
+
+TEST_F(MachineDomTreeUpdaterTest, LazyUpdateBasicOperations) {
+  StringRef MIRString = R"(
+--- |
+  define i64 @f0(i64 %i, ptr %p) {
+  bb0:
+    store i64 %i, ptr %p, align 4
+    switch i64 %i, label %bb1 [
+      i64 1, label %bb2
+      i64 2, label %bb3
+    ]
+  bb1:                                              ; preds = %bb0
+    ret i64 1
+  bb2:                                              ; preds = %bb0
+    ret i64 2
+  bb3:                                              ; preds = %bb0
+    ret i64 3
+  }
+...
+---
+name:            f0
+body:             |
+  bb.0.bb0:
+    successors: %bb.2, %bb.4
+    liveins: $rdi, $rsi
+
+    %1:gr32 = COPY $rsi
+    %0:gr64 = COPY $rdi
+    MOV64mr %1, 1, $noreg, 0, $noreg, %0 :: (store (s64) into %ir.p)
+    %2:gr64 = SUB64ri32 %0, 1, implicit-def $eflags
+    JCC_1 %bb.2, 4, implicit $eflags
+    JMP_1 %bb.4
+
+  bb.4.bb0:
+    successors: %bb.3, %bb.1
+
+    %3:gr64 = SUB64ri32 %0, 2, implicit-def $eflags
+    JCC_1 %bb.3, 4, implicit $eflags
+    JMP_1 %bb.1
+
+  bb.1.bb1:
+    %6:gr64 = MOV32ri64 1
+    $rax = COPY %6
+    RET 0, $rax
+
+  bb.2.bb2:
+    %5:gr64 = MOV32ri64 2
+    $rax = COPY %5
+    RET 0, $rax
+
+  bb.3.bb3:
+    %4:gr64 = MOV32ri64 3
+    $rax = COPY %4
+    RET 0, $rax
+
+...
+)";
+
+  ASSERT_TRUE(parseMIR(MIRString, "f0"));
+
+  auto &MF =
+      FAM.getResult<MachineFunctionAnalysis>(*M->getFunction("f0")).getMF();
+
+  MachineDominatorTree DT(MF);
+  MachinePostDominatorTree PDT(MF);
+  MachineDomTreeUpdater DTU(DT, PDT,
+                            MachineDomTreeUpdater::UpdateStrategy::Lazy);
+
+  ASSERT_TRUE(DTU.hasDomTree());
+  ASSERT_TRUE(DTU.hasPostDomTree());
+  ASSERT_FALSE(DTU.isEager());
+  ASSERT_TRUE(DTU.isLazy());
+  ASSERT_TRUE(DTU.getDomTree().verify());
+  ASSERT_TRUE(DTU.getPostDomTree().verify());
+  ASSERT_FALSE(DTU.hasPendingUpdates());
+
+  auto B = MF.begin();
+  [[maybe_unused]] auto BB0 = B;
+  auto BB1 = ++B;
+  auto BB2 = ++B;
+  [[maybe_unused]] auto BB3 = ++B;
+  auto BB4 = ++B;
+  EXPECT_EQ(BB1->succ_size(), 2u);
+  ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
+  ASSERT_TRUE(DT.dominates(&*BB1, &*BB4));
+  BB1->removeSuccessor(&*BB4);
+  DTU.deleteBB(&*BB4);
+  EXPECT_EQ(BB1->succ_size(), 1u);
+  ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
+  ASSERT_FALSE(DT.getNode(&*BB4) == nullptr);
+  DTU.flush();
+  ASSERT_TRUE(DT.getNode(&*BB4) == nullptr);
+}

>From 1a1dc2bcd45e27d0bec171521aaff74162813fa8 Mon Sep 17 00:00:00 2001
From: PaperChalice <liujunchang97 at outlook.com>
Date: Mon, 24 Jun 2024 20:41:26 +0800
Subject: [PATCH 2/2] address comments

---
 llvm/lib/CodeGen/MachineBasicBlock.cpp               | 3 +--
 llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp | 6 +++---
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/CodeGen/MachineBasicBlock.cpp b/llvm/lib/CodeGen/MachineBasicBlock.cpp
index be8a9e5744ea0..4e9f9d4b58232 100644
--- a/llvm/lib/CodeGen/MachineBasicBlock.cpp
+++ b/llvm/lib/CodeGen/MachineBasicBlock.cpp
@@ -318,8 +318,7 @@ bool MachineBasicBlock::isLegalToHoistInto() const {
 bool MachineBasicBlock::hasName() const {
   if (const BasicBlock *LBB = getBasicBlock())
     return LBB->hasName();
-  else
-    return false;
+  return false;
 }
 
 StringRef MachineBasicBlock::getName() const {
diff --git a/llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp b/llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp
index 638a684f0cef6..e123ba847e622 100644
--- a/llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp
+++ b/llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp
@@ -179,7 +179,7 @@ body:             |
   DTU.deleteBB(&*BB4);
   EXPECT_EQ(BB1->succ_size(), 1u);
   ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
-  ASSERT_TRUE(DT.getNode(&*BB4) == nullptr);
+  ASSERT_EQ(DT.getNode(&*BB4), nullptr);
 }
 
 TEST_F(MachineDomTreeUpdaterTest, LazyUpdateBasicOperations) {
@@ -270,7 +270,7 @@ body:             |
   DTU.deleteBB(&*BB4);
   EXPECT_EQ(BB1->succ_size(), 1u);
   ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
-  ASSERT_FALSE(DT.getNode(&*BB4) == nullptr);
+  ASSERT_NE(DT.getNode(&*BB4), nullptr);
   DTU.flush();
-  ASSERT_TRUE(DT.getNode(&*BB4) == nullptr);
+  ASSERT_EQ(DT.getNode(&*BB4), nullptr);
 }



More information about the llvm-commits mailing list