Skip to content

[DomTreeUpdater] Move critical edge splitting code to updater #115111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 11, 2024

Conversation

paperchalice
Copy link
Contributor

@paperchalice paperchalice commented Nov 6, 2024

@paperchalice
Copy link
Contributor Author

Tried to add a new kind in cfg::Update but I couldn't handle it in LegalizeUpdates, because this method is not based on graph diff, it uses dominance info and the critical edge.

@llvmbot
Copy link
Member

llvmbot commented Nov 6, 2024

@llvm/pr-subscribers-llvm-analysis
@llvm/pr-subscribers-backend-amdgpu
@llvm/pr-subscribers-debuginfo

@llvm/pr-subscribers-backend-webassembly

Author: None (paperchalice)

Changes

Support critical edge splitting in dominator tree updater. Continue the work in #100856.

Compile time check: https://llvm-compile-time-tracker.com/compare.php?from=87c35d782795b54911b3e3a91a5b738d4d870e55&to=42b3e5623a9ab4c3648564dc0926b36f3b438a3a&stat=instructions%3Au


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

29 Files Affected:

  • (modified) llvm/include/llvm/Analysis/DomTreeUpdater.h (+3-3)
  • (modified) llvm/include/llvm/Analysis/GenericDomTreeUpdater.h (+40-5)
  • (modified) llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h (+209-42)
  • (modified) llvm/include/llvm/CodeGen/MachineBasicBlock.h (+16-8)
  • (modified) llvm/include/llvm/CodeGen/MachineDominators.h (+2-167)
  • (modified) llvm/include/llvm/CodeGen/MachineSSAContext.h (-6)
  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+2-2)
  • (modified) llvm/lib/CodeGen/LazyMachineBlockFrequencyInfo.cpp (+2-2)
  • (modified) llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/LiveDebugValues/LiveDebugValues.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/MachineBasicBlock.cpp (+5-3)
  • (modified) llvm/lib/CodeGen/MachineDomTreeUpdater.cpp (+1)
  • (modified) llvm/lib/CodeGen/MachineDominanceFrontier.cpp (+1-2)
  • (modified) llvm/lib/CodeGen/MachineDominators.cpp (-74)
  • (modified) llvm/lib/CodeGen/MachineLICM.cpp (+10-7)
  • (modified) llvm/lib/CodeGen/MachineLoopInfo.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/MachineSink.cpp (+5-1)
  • (modified) llvm/lib/CodeGen/MachineUniformityAnalysis.cpp (+1-2)
  • (modified) llvm/lib/CodeGen/PHIElimination.cpp (+18-9)
  • (modified) llvm/lib/CodeGen/XRayInstrumentation.cpp (+2-2)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPURegBankSelect.cpp (+2-3)
  • (modified) llvm/lib/Target/AMDGPU/SILateBranchLowering.cpp (+3-3)
  • (modified) llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp (+1-1)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp (+1-1)
  • (modified) llvm/lib/Target/X86/X86FlagsCopyLowering.cpp (+1-2)
  • (modified) llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp (+1-1)
  • (modified) llvm/unittests/Analysis/DomTreeUpdaterTest.cpp (+43)
  • (modified) llvm/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp (+4-4)
diff --git a/llvm/include/llvm/Analysis/DomTreeUpdater.h b/llvm/include/llvm/Analysis/DomTreeUpdater.h
index c120a6cc6ce5ab..c54f5cc5c1759a 100644
--- a/llvm/include/llvm/Analysis/DomTreeUpdater.h
+++ b/llvm/include/llvm/Analysis/DomTreeUpdater.h
@@ -81,6 +81,9 @@ class DomTreeUpdater
 
   ///@}
 
+  /// Debug method to help view the internal state of this class.
+  LLVM_DUMP_METHOD void dump() const;
+
 private:
   class CallBackOnDeletion final : public CallbackVH {
   public:
@@ -109,9 +112,6 @@ class DomTreeUpdater
 
   /// Returns true if at least one BasicBlock is deleted.
   bool forceFlushDeletedBB();
-
-  /// Debug method to help view the internal state of this class.
-  LLVM_DUMP_METHOD void dump() const;
 };
 
 extern template class GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
index ca4ce68b85cbcf..6ec64de1b140ed 100644
--- a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
+++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
@@ -30,6 +30,7 @@ class GenericDomTreeUpdater {
 public:
   enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };
   using BasicBlockT = typename DomTreeT::NodeType;
+  using UpdateT = typename DomTreeT::UpdateType;
 
   explicit GenericDomTreeUpdater(UpdateStrategy Strategy_)
       : Strategy(Strategy_) {}
@@ -146,7 +147,19 @@ class GenericDomTreeUpdater {
   /// 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);
+  void applyUpdates(ArrayRef<UpdateT> Updates);
+
+  /// Apply updates that the critical edge (FromBB, ToBB) has been
+  /// split with NewBB.
+  ///
+  /// \note Do not use this method with regular edges.
+  ///
+  /// \note This kind updates are incompatible with generic updates,
+  /// call this method will submit all generic updates in lazy mode.
+  /// It is not recommended to interleave applyUpdates and
+  /// applyUpdatesForCriticalEdgeSplitting.
+  void splitCriticalEdge(BasicBlockT *FromBB, BasicBlockT *ToBB,
+                         BasicBlockT *NewBB);
 
   /// Submit updates to all available trees. It will also
   /// 1. discard duplicated updates,
@@ -169,7 +182,7 @@ class GenericDomTreeUpdater {
   /// 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);
+  void applyUpdatesPermissive(ArrayRef<UpdateT> Updates);
 
   ///@}
 
@@ -205,7 +218,25 @@ class GenericDomTreeUpdater {
   LLVM_DUMP_METHOD void dump() const;
 
 protected:
-  SmallVector<typename DomTreeT::UpdateType, 16> PendUpdates;
+  /// Helper structure used to hold all the basic blocks
+  /// involved in the split of a critical edge.
+  struct CriticalEdge {
+    BasicBlockT *FromBB;
+    BasicBlockT *ToBB;
+    BasicBlockT *NewBB;
+  };
+
+  struct DomTreeUpdate {
+    bool IsCriticalEdgeSplit = false;
+    union {
+      UpdateT Update;
+      CriticalEdge EdgeSplit;
+    };
+    DomTreeUpdate(UpdateT Update) : Update(Update) {}
+    DomTreeUpdate(CriticalEdge E) : IsCriticalEdgeSplit(true), EdgeSplit(E) {}
+  };
+
+  SmallVector<DomTreeUpdate, 16> PendUpdates;
   size_t PendDTUpdateIndex = 0;
   size_t PendPDTUpdateIndex = 0;
   DomTreeT *DT = nullptr;
@@ -216,7 +247,7 @@ class GenericDomTreeUpdater {
   bool IsRecalculatingPostDomTree = false;
 
   /// Returns true if the update is self dominance.
-  bool isSelfDominance(typename DomTreeT::UpdateType Update) const {
+  bool isSelfDominance(UpdateT Update) const {
     // Won't affect DomTree and PostDomTree.
     return Update.getFrom() == Update.getTo();
   }
@@ -230,7 +261,7 @@ class GenericDomTreeUpdater {
   /// 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;
+  bool isUpdateValid(UpdateT Update) const;
 
   /// Erase Basic Block node before it is unlinked from Function
   /// in the DomTree and PostDomTree.
@@ -243,6 +274,10 @@ class GenericDomTreeUpdater {
   /// Drop all updates applied by all available trees and delete BasicBlocks if
   /// all available trees are up-to-date.
   void dropOutOfDateUpdates();
+
+private:
+  void splitDTCriticalEdges(ArrayRef<CriticalEdge> Updates);
+  void splitPDTCriticalEdges(ArrayRef<CriticalEdge> Updates);
 };
 
 } // namespace llvm
diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h
index b79eaef57710fa..a5698f4a777057 100644
--- a/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h
+++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h
@@ -16,6 +16,7 @@
 #ifndef LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
 #define LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
 
+#include "llvm/ADT/SmallBitVector.h"
 #include "llvm/Analysis/GenericDomTreeUpdater.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
@@ -56,7 +57,7 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::recalculate(
 
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::applyUpdates(
-    ArrayRef<typename DomTreeT::UpdateType> Updates) {
+    ArrayRef<UpdateT> Updates) {
   if (!DT && !PDT)
     return;
 
@@ -77,12 +78,12 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::applyUpdates(
 
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
-    applyUpdatesPermissive(ArrayRef<typename DomTreeT::UpdateType> Updates) {
+    applyUpdatesPermissive(ArrayRef<UpdateT> Updates) {
   if (!DT && !PDT)
     return;
 
   SmallSet<std::pair<BasicBlockT *, BasicBlockT *>, 8> Seen;
-  SmallVector<typename DomTreeT::UpdateType, 8> DeduplicatedUpdates;
+  SmallVector<UpdateT, 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
@@ -129,6 +130,24 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
     PDT->applyUpdates(DeduplicatedUpdates);
 }
 
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::splitCriticalEdge(
+    BasicBlockT *FromBB, BasicBlockT *ToBB, BasicBlockT *NewBB) {
+  if (!DT && !PDT)
+    return;
+
+  CriticalEdge E = {FromBB, ToBB, NewBB};
+  if (Strategy == UpdateStrategy::Lazy) {
+    PendUpdates.push_back(E);
+    return;
+  }
+
+  if (DT)
+    splitDTCriticalEdges(E);
+  if (PDT)
+    splitPDTCriticalEdges(E);
+}
+
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 DomTreeT &
 GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::getDomTree() {
@@ -171,45 +190,46 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
     OS << "Lazy\n";
   int Index = 0;
 
+  auto printBlockInfo = [&](BasicBlockT *BB, StringRef Ending) {
+    if (BB) {
+      auto S = BB->getName();
+      if (!BB->hasName())
+        S = "(no name)";
+      OS << S << "(" << BB << ")" << Ending;
+    } else {
+      OS << "(badref)" << Ending;
+    }
+  };
+
   auto printUpdates =
-      [&](typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
-              begin,
-          typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
-              end) {
+      [&](typename ArrayRef<DomTreeUpdate>::const_iterator begin,
+          typename ArrayRef<DomTreeUpdate>::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";
+          if (!It->IsCriticalEdgeSplit) {
+            auto U = It->Update;
+            OS << "  " << Index << " : ";
+            ++Index;
+            if (U.getKind() == DomTreeT::Insert)
+              OS << "Insert, ";
+            else
+              OS << "Delete, ";
+            printBlockInfo(U.getFrom(), ", ");
+            printBlockInfo(U.getTo(), "\n");
           } else {
-            OS << "(badref)\n";
+            const auto &Edge = It->EdgeSplit;
+            OS << "  " << Index++ << " : Split critical edge, ";
+            printBlockInfo(Edge.FromBB, ", ");
+            printBlockInfo(Edge.ToBB, ", ");
+            printBlockInfo(Edge.NewBB, "\n");
           }
         }
       };
 
   if (DT) {
-    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+    auto I = PendUpdates.begin() + PendDTUpdateIndex;
     assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
            "Iterator out of range.");
     OS << "Applied but not cleared DomTreeUpdates:\n";
@@ -219,7 +239,7 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
   }
 
   if (PDT) {
-    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+    auto I = PendUpdates.begin() + PendPDTUpdateIndex;
     assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
            "Iterator out of range.");
     OS << "Applied but not cleared PostDomTreeUpdates:\n";
@@ -236,7 +256,7 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
     if (BB->hasName())
       OS << BB->getName() << "(";
     else
-      OS << "(no_name)(";
+      OS << "(no name)(";
     OS << BB << ")\n";
   }
 #endif
@@ -250,12 +270,23 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT,
     return;
 
   // Only apply updates not are applied by DomTree.
-  if (hasPendingDomTreeUpdates()) {
-    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+  while (hasPendingDomTreeUpdates()) {
+    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();
+    if (!I->IsCriticalEdgeSplit) {
+      SmallVector<UpdateT, 32> NormalUpdates;
+      while (I != E && !I->IsCriticalEdgeSplit)
+        NormalUpdates.push_back((I++)->Update);
+      DT->applyUpdates(NormalUpdates);
+      PendDTUpdateIndex += NormalUpdates.size();
+    } else {
+      SmallVector<CriticalEdge, 32> CriticalEdges;
+      while (I != E && I->IsCriticalEdgeSplit)
+        CriticalEdges.push_back((I++)->EdgeSplit);
+      splitDTCriticalEdges(CriticalEdges);
+      PendDTUpdateIndex += CriticalEdges.size();
+    }
   }
 }
 
@@ -267,19 +298,30 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT,
     return;
 
   // Only apply updates not are applied by PostDomTree.
-  if (hasPendingPostDomTreeUpdates()) {
-    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+  while (hasPendingPostDomTreeUpdates()) {
+    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();
+    if (!I->IsCriticalEdgeSplit) {
+      SmallVector<UpdateT, 32> NormalUpdates;
+      while (I != E && !I->IsCriticalEdgeSplit)
+        NormalUpdates.push_back((I++)->Update);
+      PDT->applyUpdates(NormalUpdates);
+      PendPDTUpdateIndex += NormalUpdates.size();
+    } else {
+      SmallVector<CriticalEdge, 32> CriticalEdges;
+      while (I != E && I->IsCriticalEdgeSplit)
+        CriticalEdges.push_back((I++)->EdgeSplit);
+      splitPDTCriticalEdges(CriticalEdges);
+      PendPDTUpdateIndex += CriticalEdges.size();
+    }
   }
 }
 
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 bool GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::isUpdateValid(
-    typename DomTreeT::UpdateType Update) const {
+    UpdateT Update) const {
   const auto *From = Update.getFrom();
   const auto *To = Update.getTo();
   const auto Kind = Update.getKind();
@@ -347,6 +389,131 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT,
   PendPDTUpdateIndex -= dropIndex;
 }
 
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
+    splitDTCriticalEdges(ArrayRef<CriticalEdge> Edges) {
+  // Bail out early if there is nothing to do.
+  if (Edges.empty())
+    return;
+
+  // Remember all the basic blocks that are inserted during
+  // edge splitting.
+  // Invariant: NewBBs == all the basic blocks contained in the NewBB
+  // field of all the elements of Edges.
+  // I.e., forall elt in Edges, it exists BB in NewBBs
+  // such as BB == elt.NewBB.
+  SmallSet<BasicBlockT *, 32> NewBBs;
+  for (auto &Edge : Edges)
+    NewBBs.insert(Edge.NewBB);
+  // For each element in Edges, remember whether or not element
+  // is the new immediate domminator of its successor. The mapping is done by
+  // index, i.e., the information for the ith element of Edges is
+  // the ith element of IsNewIDom.
+  SmallBitVector IsNewIDom(Edges.size(), true);
+  size_t Idx = 0;
+
+  // Collect all the dominance properties info, before invalidating
+  // the underlying DT.
+  for (const auto &Edge : Edges) {
+    // Update dominator information.
+    if (DT) {
+      BasicBlockT *Succ = Edge.ToBB;
+      auto *SuccDTNode = DT->getNode(Succ);
+
+      for (BasicBlockT *PredBB : predecessors(Succ)) {
+        if (PredBB == Edge.NewBB)
+          continue;
+        // If we are in this situation:
+        // FromBB1        FromBB2
+        //    +              +
+        //   + +            + +
+        //  +   +          +   +
+        // ...  Split1  Split2 ...
+        //           +   +
+        //            + +
+        //             +
+        //            Succ
+        // Instead of checking the domiance property with Split2, we check it
+        // with FromBB2 since Split2 is still unknown of the underlying DT
+        // structure.
+        if (NewBBs.count(PredBB)) {
+          assert(pred_size(PredBB) == 1 && "A basic block resulting from a "
+                                           "critical edge split has more "
+                                           "than one predecessor!");
+          PredBB = *pred_begin(PredBB);
+        }
+        if (!DT->dominates(SuccDTNode, DT->getNode(PredBB))) {
+          IsNewIDom[Idx] = false;
+          break;
+        }
+      }
+    }
+    ++Idx;
+  }
+
+  // Now, update DT with the collected dominance properties info.
+  Idx = 0;
+  for (const auto &Edge : Edges) {
+    if (DT) {
+      // We know FromBB dominates NewBB.
+      auto *NewDTNode = DT->addNewBlock(Edge.NewBB, Edge.FromBB);
+
+      // If all the other predecessors of "Succ" are dominated by "Succ" itself
+      // then the new block is the new immediate dominator of "Succ". Otherwise,
+      // the new block doesn't dominate anything.
+      if (IsNewIDom[Idx])
+        DT->changeImmediateDominator(DT->getNode(Edge.ToBB), NewDTNode);
+    }
+    ++Idx;
+  }
+}
+
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
+    splitPDTCriticalEdges(ArrayRef<CriticalEdge> Edges) {
+  // Bail out early if there is nothing to do.
+  if (Edges.empty())
+    return;
+
+  SmallBitVector IsNewIPDom(Edges.size(), true);
+  SmallSet<BasicBlockT *, 32> NewBBs;
+  for (const auto &Edge : Edges)
+    NewBBs.insert(Edge.NewBB);
+  size_t Idx = 0;
+  for (const auto &Edge : Edges) {
+    // Same as DT version but from another direction.
+    if (PDT) {
+      BasicBlockT *Pred = Edge.FromBB;
+      auto *PredDTNode = PDT->getNode(Pred);
+      for (BasicBlockT *SuccBB : successors(Pred)) {
+        if (SuccBB == Edge.NewBB)
+          continue;
+        if (NewBBs.count(SuccBB)) {
+          assert(succ_size(SuccBB) == 1 && "A basic block resulting from a "
+                                           "critical edge split has more "
+                                           "than one predecessor!");
+          SuccBB = *succ_begin(SuccBB);
+        }
+        if (!PDT->dominates(PredDTNode, PDT->getNode(SuccBB))) {
+          IsNewIPDom[Idx] = false;
+          break;
+        }
+      }
+    }
+    ++Idx;
+  }
+
+  Idx = 0;
+  for (const auto &Edge : Edges) {
+    if (PDT) {
+      auto *NewPDTNode = PDT->addNewBlock(Edge.NewBB, Edge.ToBB);
+      if (IsNewIPDom[Idx])
+        PDT->changeImmediateDominator(PDT->getNode(Edge.FromBB), NewPDTNode);
+    }
+    ++Idx;
+  }
+}
+
 } // namespace llvm
 
 #endif // LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
diff --git a/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
index 6cf151c951b19f..7fe33c3913f2dd 100644
--- a/llvm/include/llvm/CodeGen/MachineBasicBlock.h
+++ b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
@@ -32,6 +32,7 @@
 namespace llvm {
 
 class BasicBlock;
+class MachineDomTreeUpdater;
 class MachineFunction;
 class MCSymbol;
 class ModuleSlotTracker;
@@ -972,22 +973,23 @@ class MachineBasicBlock
   /// MachineLoopInfo, as applicable.
   MachineBasicBlock *
   SplitCriticalEdge(MachineBasicBlock *Succ, Pass &P,
-                    std::vector<SparseBitVector<>> *LiveInSets = nullptr) {
-    return SplitCriticalEdge(Succ, &P, nullptr, LiveInSets);
+                    std::vector<SparseBitVector<>> *LiveInSets = nullptr,
+                    MachineDomTreeUpdater *MDTU = nullptr) {
+    return SplitCriticalEdge(Succ, &P, nullptr, LiveInSets, MDTU);
   }
 
   MachineBasicBlock *
   SplitCriticalEdge(MachineBasicBlock *Succ,
                     MachineFunctionAnalysisManager &MFAM,
-                    std::vector<SparseBitVector<>> *LiveInSets = nullptr) {
-    return SplitCriticalEdge(Succ, nullptr, &MFAM, LiveInSets);
+                    std::vector<SparseBitVector<>> *LiveInSets = nullptr,
+                    MachineDomTreeUpdater *MDTU = nullptr) {
+    return SplitCriticalEdge(Succ, nullptr, &MFAM, LiveInSets, MDTU);
   }
 
   // Helper method for new pass manager migration.
-  MachineBasicBlock *
-  SplitCriticalEdge(MachineBasicBlock *Succ, Pass *P,
-                    MachineFunctionAnalysisManager *MFAM,
-                    std::vector<SparseBitVector<>> *LiveInSets);
+  MachineBasicBlock *SplitCriticalEdge(
+      MachineBasicBlock *Succ, Pass *P, MachineFunctionAnalysisManager *MFAM,
+      std::vector<SparseBitVector<>> *LiveInSets, MachineDomTreeUpdater *MDTU);
 
   /// Check if the edge between this block and the given successor \p
   /// Succ, can be split. If this returns true a subsequent call to
@@ -1375,6 +1377,12 @@ inline auto successors(const MachineBasicBlock *BB) { return BB->successors(); }
 inline auto predecessors(const MachineBasicBlock *BB) {
   return BB->predecessors();
 }
+inline auto succ_size(const MachineBasicBlock *BB) { return BB->succ_size(); }
+inline auto pred_size(const MachineBasicBlock *BB) { return BB->pred_size(); }
+inline auto succ_begin(const MachineBasicBlock *BB) { return BB->succ_begin(); }
+inline auto pred_begin(const MachineBasicBlock *BB) { return BB->pred_begin(); }
+inline auto succ_end(const MachineBasicBlock *BB) { return BB->succ_end(); }
+inline auto pred_end(const MachineBasicBlock *BB) { return BB->pred_end(); }
 
 /// MachineInstrSpan provides an interface to get an iteration range
 /// containing the instruction it was ...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Nov 6, 2024

@llvm/pr-subscribers-backend-hexagon

Author: None (paperchalice)

Changes

Support critical edge splitting in dominator tree updater. Continue the work in #100856.

Compile time check: https://llvm-compile-time-tracker.com/compare.php?from=87c35d782795b54911b3e3a91a5b738d4d870e55&amp;to=42b3e5623a9ab4c3648564dc0926b36f3b438a3a&amp;stat=instructions%3Au


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

29 Files Affected:

  • (modified) llvm/include/llvm/Analysis/DomTreeUpdater.h (+3-3)
  • (modified) llvm/include/llvm/Analysis/GenericDomTreeUpdater.h (+40-5)
  • (modified) llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h (+209-42)
  • (modified) llvm/include/llvm/CodeGen/MachineBasicBlock.h (+16-8)
  • (modified) llvm/include/llvm/CodeGen/MachineDominators.h (+2-167)
  • (modified) llvm/include/llvm/CodeGen/MachineSSAContext.h (-6)
  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+2-2)
  • (modified) llvm/lib/CodeGen/LazyMachineBlockFrequencyInfo.cpp (+2-2)
  • (modified) llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/LiveDebugValues/LiveDebugValues.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/MachineBasicBlock.cpp (+5-3)
  • (modified) llvm/lib/CodeGen/MachineDomTreeUpdater.cpp (+1)
  • (modified) llvm/lib/CodeGen/MachineDominanceFrontier.cpp (+1-2)
  • (modified) llvm/lib/CodeGen/MachineDominators.cpp (-74)
  • (modified) llvm/lib/CodeGen/MachineLICM.cpp (+10-7)
  • (modified) llvm/lib/CodeGen/MachineLoopInfo.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/MachineSink.cpp (+5-1)
  • (modified) llvm/lib/CodeGen/MachineUniformityAnalysis.cpp (+1-2)
  • (modified) llvm/lib/CodeGen/PHIElimination.cpp (+18-9)
  • (modified) llvm/lib/CodeGen/XRayInstrumentation.cpp (+2-2)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPURegBankSelect.cpp (+2-3)
  • (modified) llvm/lib/Target/AMDGPU/SILateBranchLowering.cpp (+3-3)
  • (modified) llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp (+1-1)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp (+1-1)
  • (modified) llvm/lib/Target/X86/X86FlagsCopyLowering.cpp (+1-2)
  • (modified) llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp (+1-1)
  • (modified) llvm/unittests/Analysis/DomTreeUpdaterTest.cpp (+43)
  • (modified) llvm/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp (+4-4)
diff --git a/llvm/include/llvm/Analysis/DomTreeUpdater.h b/llvm/include/llvm/Analysis/DomTreeUpdater.h
index c120a6cc6ce5ab..c54f5cc5c1759a 100644
--- a/llvm/include/llvm/Analysis/DomTreeUpdater.h
+++ b/llvm/include/llvm/Analysis/DomTreeUpdater.h
@@ -81,6 +81,9 @@ class DomTreeUpdater
 
   ///@}
 
+  /// Debug method to help view the internal state of this class.
+  LLVM_DUMP_METHOD void dump() const;
+
 private:
   class CallBackOnDeletion final : public CallbackVH {
   public:
@@ -109,9 +112,6 @@ class DomTreeUpdater
 
   /// Returns true if at least one BasicBlock is deleted.
   bool forceFlushDeletedBB();
-
-  /// Debug method to help view the internal state of this class.
-  LLVM_DUMP_METHOD void dump() const;
 };
 
 extern template class GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
index ca4ce68b85cbcf..6ec64de1b140ed 100644
--- a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
+++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
@@ -30,6 +30,7 @@ class GenericDomTreeUpdater {
 public:
   enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };
   using BasicBlockT = typename DomTreeT::NodeType;
+  using UpdateT = typename DomTreeT::UpdateType;
 
   explicit GenericDomTreeUpdater(UpdateStrategy Strategy_)
       : Strategy(Strategy_) {}
@@ -146,7 +147,19 @@ class GenericDomTreeUpdater {
   /// 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);
+  void applyUpdates(ArrayRef<UpdateT> Updates);
+
+  /// Apply updates that the critical edge (FromBB, ToBB) has been
+  /// split with NewBB.
+  ///
+  /// \note Do not use this method with regular edges.
+  ///
+  /// \note This kind updates are incompatible with generic updates,
+  /// call this method will submit all generic updates in lazy mode.
+  /// It is not recommended to interleave applyUpdates and
+  /// applyUpdatesForCriticalEdgeSplitting.
+  void splitCriticalEdge(BasicBlockT *FromBB, BasicBlockT *ToBB,
+                         BasicBlockT *NewBB);
 
   /// Submit updates to all available trees. It will also
   /// 1. discard duplicated updates,
@@ -169,7 +182,7 @@ class GenericDomTreeUpdater {
   /// 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);
+  void applyUpdatesPermissive(ArrayRef<UpdateT> Updates);
 
   ///@}
 
@@ -205,7 +218,25 @@ class GenericDomTreeUpdater {
   LLVM_DUMP_METHOD void dump() const;
 
 protected:
-  SmallVector<typename DomTreeT::UpdateType, 16> PendUpdates;
+  /// Helper structure used to hold all the basic blocks
+  /// involved in the split of a critical edge.
+  struct CriticalEdge {
+    BasicBlockT *FromBB;
+    BasicBlockT *ToBB;
+    BasicBlockT *NewBB;
+  };
+
+  struct DomTreeUpdate {
+    bool IsCriticalEdgeSplit = false;
+    union {
+      UpdateT Update;
+      CriticalEdge EdgeSplit;
+    };
+    DomTreeUpdate(UpdateT Update) : Update(Update) {}
+    DomTreeUpdate(CriticalEdge E) : IsCriticalEdgeSplit(true), EdgeSplit(E) {}
+  };
+
+  SmallVector<DomTreeUpdate, 16> PendUpdates;
   size_t PendDTUpdateIndex = 0;
   size_t PendPDTUpdateIndex = 0;
   DomTreeT *DT = nullptr;
@@ -216,7 +247,7 @@ class GenericDomTreeUpdater {
   bool IsRecalculatingPostDomTree = false;
 
   /// Returns true if the update is self dominance.
-  bool isSelfDominance(typename DomTreeT::UpdateType Update) const {
+  bool isSelfDominance(UpdateT Update) const {
     // Won't affect DomTree and PostDomTree.
     return Update.getFrom() == Update.getTo();
   }
@@ -230,7 +261,7 @@ class GenericDomTreeUpdater {
   /// 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;
+  bool isUpdateValid(UpdateT Update) const;
 
   /// Erase Basic Block node before it is unlinked from Function
   /// in the DomTree and PostDomTree.
@@ -243,6 +274,10 @@ class GenericDomTreeUpdater {
   /// Drop all updates applied by all available trees and delete BasicBlocks if
   /// all available trees are up-to-date.
   void dropOutOfDateUpdates();
+
+private:
+  void splitDTCriticalEdges(ArrayRef<CriticalEdge> Updates);
+  void splitPDTCriticalEdges(ArrayRef<CriticalEdge> Updates);
 };
 
 } // namespace llvm
diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h
index b79eaef57710fa..a5698f4a777057 100644
--- a/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h
+++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h
@@ -16,6 +16,7 @@
 #ifndef LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
 #define LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
 
+#include "llvm/ADT/SmallBitVector.h"
 #include "llvm/Analysis/GenericDomTreeUpdater.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
@@ -56,7 +57,7 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::recalculate(
 
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::applyUpdates(
-    ArrayRef<typename DomTreeT::UpdateType> Updates) {
+    ArrayRef<UpdateT> Updates) {
   if (!DT && !PDT)
     return;
 
@@ -77,12 +78,12 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::applyUpdates(
 
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
-    applyUpdatesPermissive(ArrayRef<typename DomTreeT::UpdateType> Updates) {
+    applyUpdatesPermissive(ArrayRef<UpdateT> Updates) {
   if (!DT && !PDT)
     return;
 
   SmallSet<std::pair<BasicBlockT *, BasicBlockT *>, 8> Seen;
-  SmallVector<typename DomTreeT::UpdateType, 8> DeduplicatedUpdates;
+  SmallVector<UpdateT, 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
@@ -129,6 +130,24 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
     PDT->applyUpdates(DeduplicatedUpdates);
 }
 
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::splitCriticalEdge(
+    BasicBlockT *FromBB, BasicBlockT *ToBB, BasicBlockT *NewBB) {
+  if (!DT && !PDT)
+    return;
+
+  CriticalEdge E = {FromBB, ToBB, NewBB};
+  if (Strategy == UpdateStrategy::Lazy) {
+    PendUpdates.push_back(E);
+    return;
+  }
+
+  if (DT)
+    splitDTCriticalEdges(E);
+  if (PDT)
+    splitPDTCriticalEdges(E);
+}
+
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 DomTreeT &
 GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::getDomTree() {
@@ -171,45 +190,46 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
     OS << "Lazy\n";
   int Index = 0;
 
+  auto printBlockInfo = [&](BasicBlockT *BB, StringRef Ending) {
+    if (BB) {
+      auto S = BB->getName();
+      if (!BB->hasName())
+        S = "(no name)";
+      OS << S << "(" << BB << ")" << Ending;
+    } else {
+      OS << "(badref)" << Ending;
+    }
+  };
+
   auto printUpdates =
-      [&](typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
-              begin,
-          typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
-              end) {
+      [&](typename ArrayRef<DomTreeUpdate>::const_iterator begin,
+          typename ArrayRef<DomTreeUpdate>::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";
+          if (!It->IsCriticalEdgeSplit) {
+            auto U = It->Update;
+            OS << "  " << Index << " : ";
+            ++Index;
+            if (U.getKind() == DomTreeT::Insert)
+              OS << "Insert, ";
+            else
+              OS << "Delete, ";
+            printBlockInfo(U.getFrom(), ", ");
+            printBlockInfo(U.getTo(), "\n");
           } else {
-            OS << "(badref)\n";
+            const auto &Edge = It->EdgeSplit;
+            OS << "  " << Index++ << " : Split critical edge, ";
+            printBlockInfo(Edge.FromBB, ", ");
+            printBlockInfo(Edge.ToBB, ", ");
+            printBlockInfo(Edge.NewBB, "\n");
           }
         }
       };
 
   if (DT) {
-    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+    auto I = PendUpdates.begin() + PendDTUpdateIndex;
     assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
            "Iterator out of range.");
     OS << "Applied but not cleared DomTreeUpdates:\n";
@@ -219,7 +239,7 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
   }
 
   if (PDT) {
-    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+    auto I = PendUpdates.begin() + PendPDTUpdateIndex;
     assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
            "Iterator out of range.");
     OS << "Applied but not cleared PostDomTreeUpdates:\n";
@@ -236,7 +256,7 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
     if (BB->hasName())
       OS << BB->getName() << "(";
     else
-      OS << "(no_name)(";
+      OS << "(no name)(";
     OS << BB << ")\n";
   }
 #endif
@@ -250,12 +270,23 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT,
     return;
 
   // Only apply updates not are applied by DomTree.
-  if (hasPendingDomTreeUpdates()) {
-    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+  while (hasPendingDomTreeUpdates()) {
+    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();
+    if (!I->IsCriticalEdgeSplit) {
+      SmallVector<UpdateT, 32> NormalUpdates;
+      while (I != E && !I->IsCriticalEdgeSplit)
+        NormalUpdates.push_back((I++)->Update);
+      DT->applyUpdates(NormalUpdates);
+      PendDTUpdateIndex += NormalUpdates.size();
+    } else {
+      SmallVector<CriticalEdge, 32> CriticalEdges;
+      while (I != E && I->IsCriticalEdgeSplit)
+        CriticalEdges.push_back((I++)->EdgeSplit);
+      splitDTCriticalEdges(CriticalEdges);
+      PendDTUpdateIndex += CriticalEdges.size();
+    }
   }
 }
 
@@ -267,19 +298,30 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT,
     return;
 
   // Only apply updates not are applied by PostDomTree.
-  if (hasPendingPostDomTreeUpdates()) {
-    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+  while (hasPendingPostDomTreeUpdates()) {
+    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();
+    if (!I->IsCriticalEdgeSplit) {
+      SmallVector<UpdateT, 32> NormalUpdates;
+      while (I != E && !I->IsCriticalEdgeSplit)
+        NormalUpdates.push_back((I++)->Update);
+      PDT->applyUpdates(NormalUpdates);
+      PendPDTUpdateIndex += NormalUpdates.size();
+    } else {
+      SmallVector<CriticalEdge, 32> CriticalEdges;
+      while (I != E && I->IsCriticalEdgeSplit)
+        CriticalEdges.push_back((I++)->EdgeSplit);
+      splitPDTCriticalEdges(CriticalEdges);
+      PendPDTUpdateIndex += CriticalEdges.size();
+    }
   }
 }
 
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 bool GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::isUpdateValid(
-    typename DomTreeT::UpdateType Update) const {
+    UpdateT Update) const {
   const auto *From = Update.getFrom();
   const auto *To = Update.getTo();
   const auto Kind = Update.getKind();
@@ -347,6 +389,131 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT,
   PendPDTUpdateIndex -= dropIndex;
 }
 
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
+    splitDTCriticalEdges(ArrayRef<CriticalEdge> Edges) {
+  // Bail out early if there is nothing to do.
+  if (Edges.empty())
+    return;
+
+  // Remember all the basic blocks that are inserted during
+  // edge splitting.
+  // Invariant: NewBBs == all the basic blocks contained in the NewBB
+  // field of all the elements of Edges.
+  // I.e., forall elt in Edges, it exists BB in NewBBs
+  // such as BB == elt.NewBB.
+  SmallSet<BasicBlockT *, 32> NewBBs;
+  for (auto &Edge : Edges)
+    NewBBs.insert(Edge.NewBB);
+  // For each element in Edges, remember whether or not element
+  // is the new immediate domminator of its successor. The mapping is done by
+  // index, i.e., the information for the ith element of Edges is
+  // the ith element of IsNewIDom.
+  SmallBitVector IsNewIDom(Edges.size(), true);
+  size_t Idx = 0;
+
+  // Collect all the dominance properties info, before invalidating
+  // the underlying DT.
+  for (const auto &Edge : Edges) {
+    // Update dominator information.
+    if (DT) {
+      BasicBlockT *Succ = Edge.ToBB;
+      auto *SuccDTNode = DT->getNode(Succ);
+
+      for (BasicBlockT *PredBB : predecessors(Succ)) {
+        if (PredBB == Edge.NewBB)
+          continue;
+        // If we are in this situation:
+        // FromBB1        FromBB2
+        //    +              +
+        //   + +            + +
+        //  +   +          +   +
+        // ...  Split1  Split2 ...
+        //           +   +
+        //            + +
+        //             +
+        //            Succ
+        // Instead of checking the domiance property with Split2, we check it
+        // with FromBB2 since Split2 is still unknown of the underlying DT
+        // structure.
+        if (NewBBs.count(PredBB)) {
+          assert(pred_size(PredBB) == 1 && "A basic block resulting from a "
+                                           "critical edge split has more "
+                                           "than one predecessor!");
+          PredBB = *pred_begin(PredBB);
+        }
+        if (!DT->dominates(SuccDTNode, DT->getNode(PredBB))) {
+          IsNewIDom[Idx] = false;
+          break;
+        }
+      }
+    }
+    ++Idx;
+  }
+
+  // Now, update DT with the collected dominance properties info.
+  Idx = 0;
+  for (const auto &Edge : Edges) {
+    if (DT) {
+      // We know FromBB dominates NewBB.
+      auto *NewDTNode = DT->addNewBlock(Edge.NewBB, Edge.FromBB);
+
+      // If all the other predecessors of "Succ" are dominated by "Succ" itself
+      // then the new block is the new immediate dominator of "Succ". Otherwise,
+      // the new block doesn't dominate anything.
+      if (IsNewIDom[Idx])
+        DT->changeImmediateDominator(DT->getNode(Edge.ToBB), NewDTNode);
+    }
+    ++Idx;
+  }
+}
+
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
+    splitPDTCriticalEdges(ArrayRef<CriticalEdge> Edges) {
+  // Bail out early if there is nothing to do.
+  if (Edges.empty())
+    return;
+
+  SmallBitVector IsNewIPDom(Edges.size(), true);
+  SmallSet<BasicBlockT *, 32> NewBBs;
+  for (const auto &Edge : Edges)
+    NewBBs.insert(Edge.NewBB);
+  size_t Idx = 0;
+  for (const auto &Edge : Edges) {
+    // Same as DT version but from another direction.
+    if (PDT) {
+      BasicBlockT *Pred = Edge.FromBB;
+      auto *PredDTNode = PDT->getNode(Pred);
+      for (BasicBlockT *SuccBB : successors(Pred)) {
+        if (SuccBB == Edge.NewBB)
+          continue;
+        if (NewBBs.count(SuccBB)) {
+          assert(succ_size(SuccBB) == 1 && "A basic block resulting from a "
+                                           "critical edge split has more "
+                                           "than one predecessor!");
+          SuccBB = *succ_begin(SuccBB);
+        }
+        if (!PDT->dominates(PredDTNode, PDT->getNode(SuccBB))) {
+          IsNewIPDom[Idx] = false;
+          break;
+        }
+      }
+    }
+    ++Idx;
+  }
+
+  Idx = 0;
+  for (const auto &Edge : Edges) {
+    if (PDT) {
+      auto *NewPDTNode = PDT->addNewBlock(Edge.NewBB, Edge.ToBB);
+      if (IsNewIPDom[Idx])
+        PDT->changeImmediateDominator(PDT->getNode(Edge.FromBB), NewPDTNode);
+    }
+    ++Idx;
+  }
+}
+
 } // namespace llvm
 
 #endif // LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
diff --git a/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
index 6cf151c951b19f..7fe33c3913f2dd 100644
--- a/llvm/include/llvm/CodeGen/MachineBasicBlock.h
+++ b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
@@ -32,6 +32,7 @@
 namespace llvm {
 
 class BasicBlock;
+class MachineDomTreeUpdater;
 class MachineFunction;
 class MCSymbol;
 class ModuleSlotTracker;
@@ -972,22 +973,23 @@ class MachineBasicBlock
   /// MachineLoopInfo, as applicable.
   MachineBasicBlock *
   SplitCriticalEdge(MachineBasicBlock *Succ, Pass &P,
-                    std::vector<SparseBitVector<>> *LiveInSets = nullptr) {
-    return SplitCriticalEdge(Succ, &P, nullptr, LiveInSets);
+                    std::vector<SparseBitVector<>> *LiveInSets = nullptr,
+                    MachineDomTreeUpdater *MDTU = nullptr) {
+    return SplitCriticalEdge(Succ, &P, nullptr, LiveInSets, MDTU);
   }
 
   MachineBasicBlock *
   SplitCriticalEdge(MachineBasicBlock *Succ,
                     MachineFunctionAnalysisManager &MFAM,
-                    std::vector<SparseBitVector<>> *LiveInSets = nullptr) {
-    return SplitCriticalEdge(Succ, nullptr, &MFAM, LiveInSets);
+                    std::vector<SparseBitVector<>> *LiveInSets = nullptr,
+                    MachineDomTreeUpdater *MDTU = nullptr) {
+    return SplitCriticalEdge(Succ, nullptr, &MFAM, LiveInSets, MDTU);
   }
 
   // Helper method for new pass manager migration.
-  MachineBasicBlock *
-  SplitCriticalEdge(MachineBasicBlock *Succ, Pass *P,
-                    MachineFunctionAnalysisManager *MFAM,
-                    std::vector<SparseBitVector<>> *LiveInSets);
+  MachineBasicBlock *SplitCriticalEdge(
+      MachineBasicBlock *Succ, Pass *P, MachineFunctionAnalysisManager *MFAM,
+      std::vector<SparseBitVector<>> *LiveInSets, MachineDomTreeUpdater *MDTU);
 
   /// Check if the edge between this block and the given successor \p
   /// Succ, can be split. If this returns true a subsequent call to
@@ -1375,6 +1377,12 @@ inline auto successors(const MachineBasicBlock *BB) { return BB->successors(); }
 inline auto predecessors(const MachineBasicBlock *BB) {
   return BB->predecessors();
 }
+inline auto succ_size(const MachineBasicBlock *BB) { return BB->succ_size(); }
+inline auto pred_size(const MachineBasicBlock *BB) { return BB->pred_size(); }
+inline auto succ_begin(const MachineBasicBlock *BB) { return BB->succ_begin(); }
+inline auto pred_begin(const MachineBasicBlock *BB) { return BB->pred_begin(); }
+inline auto succ_end(const MachineBasicBlock *BB) { return BB->succ_end(); }
+inline auto pred_end(const MachineBasicBlock *BB) { return BB->pred_end(); }
 
 /// MachineInstrSpan provides an interface to get an iteration range
 /// containing the instruction it was ...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Nov 6, 2024

@llvm/pr-subscribers-llvm-regalloc

Author: None (paperchalice)

Changes

Support critical edge splitting in dominator tree updater. Continue the work in #100856.

Compile time check: https://llvm-compile-time-tracker.com/compare.php?from=87c35d782795b54911b3e3a91a5b738d4d870e55&amp;to=42b3e5623a9ab4c3648564dc0926b36f3b438a3a&amp;stat=instructions%3Au


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

29 Files Affected:

  • (modified) llvm/include/llvm/Analysis/DomTreeUpdater.h (+3-3)
  • (modified) llvm/include/llvm/Analysis/GenericDomTreeUpdater.h (+40-5)
  • (modified) llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h (+209-42)
  • (modified) llvm/include/llvm/CodeGen/MachineBasicBlock.h (+16-8)
  • (modified) llvm/include/llvm/CodeGen/MachineDominators.h (+2-167)
  • (modified) llvm/include/llvm/CodeGen/MachineSSAContext.h (-6)
  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+2-2)
  • (modified) llvm/lib/CodeGen/LazyMachineBlockFrequencyInfo.cpp (+2-2)
  • (modified) llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/LiveDebugValues/LiveDebugValues.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/MachineBasicBlock.cpp (+5-3)
  • (modified) llvm/lib/CodeGen/MachineDomTreeUpdater.cpp (+1)
  • (modified) llvm/lib/CodeGen/MachineDominanceFrontier.cpp (+1-2)
  • (modified) llvm/lib/CodeGen/MachineDominators.cpp (-74)
  • (modified) llvm/lib/CodeGen/MachineLICM.cpp (+10-7)
  • (modified) llvm/lib/CodeGen/MachineLoopInfo.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/MachineSink.cpp (+5-1)
  • (modified) llvm/lib/CodeGen/MachineUniformityAnalysis.cpp (+1-2)
  • (modified) llvm/lib/CodeGen/PHIElimination.cpp (+18-9)
  • (modified) llvm/lib/CodeGen/XRayInstrumentation.cpp (+2-2)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPURegBankSelect.cpp (+2-3)
  • (modified) llvm/lib/Target/AMDGPU/SILateBranchLowering.cpp (+3-3)
  • (modified) llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp (+1-1)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp (+1-1)
  • (modified) llvm/lib/Target/X86/X86FlagsCopyLowering.cpp (+1-2)
  • (modified) llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp (+1-1)
  • (modified) llvm/unittests/Analysis/DomTreeUpdaterTest.cpp (+43)
  • (modified) llvm/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp (+4-4)
diff --git a/llvm/include/llvm/Analysis/DomTreeUpdater.h b/llvm/include/llvm/Analysis/DomTreeUpdater.h
index c120a6cc6ce5ab..c54f5cc5c1759a 100644
--- a/llvm/include/llvm/Analysis/DomTreeUpdater.h
+++ b/llvm/include/llvm/Analysis/DomTreeUpdater.h
@@ -81,6 +81,9 @@ class DomTreeUpdater
 
   ///@}
 
+  /// Debug method to help view the internal state of this class.
+  LLVM_DUMP_METHOD void dump() const;
+
 private:
   class CallBackOnDeletion final : public CallbackVH {
   public:
@@ -109,9 +112,6 @@ class DomTreeUpdater
 
   /// Returns true if at least one BasicBlock is deleted.
   bool forceFlushDeletedBB();
-
-  /// Debug method to help view the internal state of this class.
-  LLVM_DUMP_METHOD void dump() const;
 };
 
 extern template class GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
index ca4ce68b85cbcf..6ec64de1b140ed 100644
--- a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
+++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
@@ -30,6 +30,7 @@ class GenericDomTreeUpdater {
 public:
   enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };
   using BasicBlockT = typename DomTreeT::NodeType;
+  using UpdateT = typename DomTreeT::UpdateType;
 
   explicit GenericDomTreeUpdater(UpdateStrategy Strategy_)
       : Strategy(Strategy_) {}
@@ -146,7 +147,19 @@ class GenericDomTreeUpdater {
   /// 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);
+  void applyUpdates(ArrayRef<UpdateT> Updates);
+
+  /// Apply updates that the critical edge (FromBB, ToBB) has been
+  /// split with NewBB.
+  ///
+  /// \note Do not use this method with regular edges.
+  ///
+  /// \note This kind updates are incompatible with generic updates,
+  /// call this method will submit all generic updates in lazy mode.
+  /// It is not recommended to interleave applyUpdates and
+  /// applyUpdatesForCriticalEdgeSplitting.
+  void splitCriticalEdge(BasicBlockT *FromBB, BasicBlockT *ToBB,
+                         BasicBlockT *NewBB);
 
   /// Submit updates to all available trees. It will also
   /// 1. discard duplicated updates,
@@ -169,7 +182,7 @@ class GenericDomTreeUpdater {
   /// 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);
+  void applyUpdatesPermissive(ArrayRef<UpdateT> Updates);
 
   ///@}
 
@@ -205,7 +218,25 @@ class GenericDomTreeUpdater {
   LLVM_DUMP_METHOD void dump() const;
 
 protected:
-  SmallVector<typename DomTreeT::UpdateType, 16> PendUpdates;
+  /// Helper structure used to hold all the basic blocks
+  /// involved in the split of a critical edge.
+  struct CriticalEdge {
+    BasicBlockT *FromBB;
+    BasicBlockT *ToBB;
+    BasicBlockT *NewBB;
+  };
+
+  struct DomTreeUpdate {
+    bool IsCriticalEdgeSplit = false;
+    union {
+      UpdateT Update;
+      CriticalEdge EdgeSplit;
+    };
+    DomTreeUpdate(UpdateT Update) : Update(Update) {}
+    DomTreeUpdate(CriticalEdge E) : IsCriticalEdgeSplit(true), EdgeSplit(E) {}
+  };
+
+  SmallVector<DomTreeUpdate, 16> PendUpdates;
   size_t PendDTUpdateIndex = 0;
   size_t PendPDTUpdateIndex = 0;
   DomTreeT *DT = nullptr;
@@ -216,7 +247,7 @@ class GenericDomTreeUpdater {
   bool IsRecalculatingPostDomTree = false;
 
   /// Returns true if the update is self dominance.
-  bool isSelfDominance(typename DomTreeT::UpdateType Update) const {
+  bool isSelfDominance(UpdateT Update) const {
     // Won't affect DomTree and PostDomTree.
     return Update.getFrom() == Update.getTo();
   }
@@ -230,7 +261,7 @@ class GenericDomTreeUpdater {
   /// 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;
+  bool isUpdateValid(UpdateT Update) const;
 
   /// Erase Basic Block node before it is unlinked from Function
   /// in the DomTree and PostDomTree.
@@ -243,6 +274,10 @@ class GenericDomTreeUpdater {
   /// Drop all updates applied by all available trees and delete BasicBlocks if
   /// all available trees are up-to-date.
   void dropOutOfDateUpdates();
+
+private:
+  void splitDTCriticalEdges(ArrayRef<CriticalEdge> Updates);
+  void splitPDTCriticalEdges(ArrayRef<CriticalEdge> Updates);
 };
 
 } // namespace llvm
diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h
index b79eaef57710fa..a5698f4a777057 100644
--- a/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h
+++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h
@@ -16,6 +16,7 @@
 #ifndef LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
 #define LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
 
+#include "llvm/ADT/SmallBitVector.h"
 #include "llvm/Analysis/GenericDomTreeUpdater.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
@@ -56,7 +57,7 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::recalculate(
 
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::applyUpdates(
-    ArrayRef<typename DomTreeT::UpdateType> Updates) {
+    ArrayRef<UpdateT> Updates) {
   if (!DT && !PDT)
     return;
 
@@ -77,12 +78,12 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::applyUpdates(
 
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
-    applyUpdatesPermissive(ArrayRef<typename DomTreeT::UpdateType> Updates) {
+    applyUpdatesPermissive(ArrayRef<UpdateT> Updates) {
   if (!DT && !PDT)
     return;
 
   SmallSet<std::pair<BasicBlockT *, BasicBlockT *>, 8> Seen;
-  SmallVector<typename DomTreeT::UpdateType, 8> DeduplicatedUpdates;
+  SmallVector<UpdateT, 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
@@ -129,6 +130,24 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
     PDT->applyUpdates(DeduplicatedUpdates);
 }
 
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::splitCriticalEdge(
+    BasicBlockT *FromBB, BasicBlockT *ToBB, BasicBlockT *NewBB) {
+  if (!DT && !PDT)
+    return;
+
+  CriticalEdge E = {FromBB, ToBB, NewBB};
+  if (Strategy == UpdateStrategy::Lazy) {
+    PendUpdates.push_back(E);
+    return;
+  }
+
+  if (DT)
+    splitDTCriticalEdges(E);
+  if (PDT)
+    splitPDTCriticalEdges(E);
+}
+
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 DomTreeT &
 GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::getDomTree() {
@@ -171,45 +190,46 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
     OS << "Lazy\n";
   int Index = 0;
 
+  auto printBlockInfo = [&](BasicBlockT *BB, StringRef Ending) {
+    if (BB) {
+      auto S = BB->getName();
+      if (!BB->hasName())
+        S = "(no name)";
+      OS << S << "(" << BB << ")" << Ending;
+    } else {
+      OS << "(badref)" << Ending;
+    }
+  };
+
   auto printUpdates =
-      [&](typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
-              begin,
-          typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
-              end) {
+      [&](typename ArrayRef<DomTreeUpdate>::const_iterator begin,
+          typename ArrayRef<DomTreeUpdate>::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";
+          if (!It->IsCriticalEdgeSplit) {
+            auto U = It->Update;
+            OS << "  " << Index << " : ";
+            ++Index;
+            if (U.getKind() == DomTreeT::Insert)
+              OS << "Insert, ";
+            else
+              OS << "Delete, ";
+            printBlockInfo(U.getFrom(), ", ");
+            printBlockInfo(U.getTo(), "\n");
           } else {
-            OS << "(badref)\n";
+            const auto &Edge = It->EdgeSplit;
+            OS << "  " << Index++ << " : Split critical edge, ";
+            printBlockInfo(Edge.FromBB, ", ");
+            printBlockInfo(Edge.ToBB, ", ");
+            printBlockInfo(Edge.NewBB, "\n");
           }
         }
       };
 
   if (DT) {
-    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+    auto I = PendUpdates.begin() + PendDTUpdateIndex;
     assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
            "Iterator out of range.");
     OS << "Applied but not cleared DomTreeUpdates:\n";
@@ -219,7 +239,7 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
   }
 
   if (PDT) {
-    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+    auto I = PendUpdates.begin() + PendPDTUpdateIndex;
     assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
            "Iterator out of range.");
     OS << "Applied but not cleared PostDomTreeUpdates:\n";
@@ -236,7 +256,7 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
     if (BB->hasName())
       OS << BB->getName() << "(";
     else
-      OS << "(no_name)(";
+      OS << "(no name)(";
     OS << BB << ")\n";
   }
 #endif
@@ -250,12 +270,23 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT,
     return;
 
   // Only apply updates not are applied by DomTree.
-  if (hasPendingDomTreeUpdates()) {
-    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+  while (hasPendingDomTreeUpdates()) {
+    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();
+    if (!I->IsCriticalEdgeSplit) {
+      SmallVector<UpdateT, 32> NormalUpdates;
+      while (I != E && !I->IsCriticalEdgeSplit)
+        NormalUpdates.push_back((I++)->Update);
+      DT->applyUpdates(NormalUpdates);
+      PendDTUpdateIndex += NormalUpdates.size();
+    } else {
+      SmallVector<CriticalEdge, 32> CriticalEdges;
+      while (I != E && I->IsCriticalEdgeSplit)
+        CriticalEdges.push_back((I++)->EdgeSplit);
+      splitDTCriticalEdges(CriticalEdges);
+      PendDTUpdateIndex += CriticalEdges.size();
+    }
   }
 }
 
@@ -267,19 +298,30 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT,
     return;
 
   // Only apply updates not are applied by PostDomTree.
-  if (hasPendingPostDomTreeUpdates()) {
-    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+  while (hasPendingPostDomTreeUpdates()) {
+    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();
+    if (!I->IsCriticalEdgeSplit) {
+      SmallVector<UpdateT, 32> NormalUpdates;
+      while (I != E && !I->IsCriticalEdgeSplit)
+        NormalUpdates.push_back((I++)->Update);
+      PDT->applyUpdates(NormalUpdates);
+      PendPDTUpdateIndex += NormalUpdates.size();
+    } else {
+      SmallVector<CriticalEdge, 32> CriticalEdges;
+      while (I != E && I->IsCriticalEdgeSplit)
+        CriticalEdges.push_back((I++)->EdgeSplit);
+      splitPDTCriticalEdges(CriticalEdges);
+      PendPDTUpdateIndex += CriticalEdges.size();
+    }
   }
 }
 
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 bool GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::isUpdateValid(
-    typename DomTreeT::UpdateType Update) const {
+    UpdateT Update) const {
   const auto *From = Update.getFrom();
   const auto *To = Update.getTo();
   const auto Kind = Update.getKind();
@@ -347,6 +389,131 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT,
   PendPDTUpdateIndex -= dropIndex;
 }
 
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
+    splitDTCriticalEdges(ArrayRef<CriticalEdge> Edges) {
+  // Bail out early if there is nothing to do.
+  if (Edges.empty())
+    return;
+
+  // Remember all the basic blocks that are inserted during
+  // edge splitting.
+  // Invariant: NewBBs == all the basic blocks contained in the NewBB
+  // field of all the elements of Edges.
+  // I.e., forall elt in Edges, it exists BB in NewBBs
+  // such as BB == elt.NewBB.
+  SmallSet<BasicBlockT *, 32> NewBBs;
+  for (auto &Edge : Edges)
+    NewBBs.insert(Edge.NewBB);
+  // For each element in Edges, remember whether or not element
+  // is the new immediate domminator of its successor. The mapping is done by
+  // index, i.e., the information for the ith element of Edges is
+  // the ith element of IsNewIDom.
+  SmallBitVector IsNewIDom(Edges.size(), true);
+  size_t Idx = 0;
+
+  // Collect all the dominance properties info, before invalidating
+  // the underlying DT.
+  for (const auto &Edge : Edges) {
+    // Update dominator information.
+    if (DT) {
+      BasicBlockT *Succ = Edge.ToBB;
+      auto *SuccDTNode = DT->getNode(Succ);
+
+      for (BasicBlockT *PredBB : predecessors(Succ)) {
+        if (PredBB == Edge.NewBB)
+          continue;
+        // If we are in this situation:
+        // FromBB1        FromBB2
+        //    +              +
+        //   + +            + +
+        //  +   +          +   +
+        // ...  Split1  Split2 ...
+        //           +   +
+        //            + +
+        //             +
+        //            Succ
+        // Instead of checking the domiance property with Split2, we check it
+        // with FromBB2 since Split2 is still unknown of the underlying DT
+        // structure.
+        if (NewBBs.count(PredBB)) {
+          assert(pred_size(PredBB) == 1 && "A basic block resulting from a "
+                                           "critical edge split has more "
+                                           "than one predecessor!");
+          PredBB = *pred_begin(PredBB);
+        }
+        if (!DT->dominates(SuccDTNode, DT->getNode(PredBB))) {
+          IsNewIDom[Idx] = false;
+          break;
+        }
+      }
+    }
+    ++Idx;
+  }
+
+  // Now, update DT with the collected dominance properties info.
+  Idx = 0;
+  for (const auto &Edge : Edges) {
+    if (DT) {
+      // We know FromBB dominates NewBB.
+      auto *NewDTNode = DT->addNewBlock(Edge.NewBB, Edge.FromBB);
+
+      // If all the other predecessors of "Succ" are dominated by "Succ" itself
+      // then the new block is the new immediate dominator of "Succ". Otherwise,
+      // the new block doesn't dominate anything.
+      if (IsNewIDom[Idx])
+        DT->changeImmediateDominator(DT->getNode(Edge.ToBB), NewDTNode);
+    }
+    ++Idx;
+  }
+}
+
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
+    splitPDTCriticalEdges(ArrayRef<CriticalEdge> Edges) {
+  // Bail out early if there is nothing to do.
+  if (Edges.empty())
+    return;
+
+  SmallBitVector IsNewIPDom(Edges.size(), true);
+  SmallSet<BasicBlockT *, 32> NewBBs;
+  for (const auto &Edge : Edges)
+    NewBBs.insert(Edge.NewBB);
+  size_t Idx = 0;
+  for (const auto &Edge : Edges) {
+    // Same as DT version but from another direction.
+    if (PDT) {
+      BasicBlockT *Pred = Edge.FromBB;
+      auto *PredDTNode = PDT->getNode(Pred);
+      for (BasicBlockT *SuccBB : successors(Pred)) {
+        if (SuccBB == Edge.NewBB)
+          continue;
+        if (NewBBs.count(SuccBB)) {
+          assert(succ_size(SuccBB) == 1 && "A basic block resulting from a "
+                                           "critical edge split has more "
+                                           "than one predecessor!");
+          SuccBB = *succ_begin(SuccBB);
+        }
+        if (!PDT->dominates(PredDTNode, PDT->getNode(SuccBB))) {
+          IsNewIPDom[Idx] = false;
+          break;
+        }
+      }
+    }
+    ++Idx;
+  }
+
+  Idx = 0;
+  for (const auto &Edge : Edges) {
+    if (PDT) {
+      auto *NewPDTNode = PDT->addNewBlock(Edge.NewBB, Edge.ToBB);
+      if (IsNewIPDom[Idx])
+        PDT->changeImmediateDominator(PDT->getNode(Edge.FromBB), NewPDTNode);
+    }
+    ++Idx;
+  }
+}
+
 } // namespace llvm
 
 #endif // LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
diff --git a/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
index 6cf151c951b19f..7fe33c3913f2dd 100644
--- a/llvm/include/llvm/CodeGen/MachineBasicBlock.h
+++ b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
@@ -32,6 +32,7 @@
 namespace llvm {
 
 class BasicBlock;
+class MachineDomTreeUpdater;
 class MachineFunction;
 class MCSymbol;
 class ModuleSlotTracker;
@@ -972,22 +973,23 @@ class MachineBasicBlock
   /// MachineLoopInfo, as applicable.
   MachineBasicBlock *
   SplitCriticalEdge(MachineBasicBlock *Succ, Pass &P,
-                    std::vector<SparseBitVector<>> *LiveInSets = nullptr) {
-    return SplitCriticalEdge(Succ, &P, nullptr, LiveInSets);
+                    std::vector<SparseBitVector<>> *LiveInSets = nullptr,
+                    MachineDomTreeUpdater *MDTU = nullptr) {
+    return SplitCriticalEdge(Succ, &P, nullptr, LiveInSets, MDTU);
   }
 
   MachineBasicBlock *
   SplitCriticalEdge(MachineBasicBlock *Succ,
                     MachineFunctionAnalysisManager &MFAM,
-                    std::vector<SparseBitVector<>> *LiveInSets = nullptr) {
-    return SplitCriticalEdge(Succ, nullptr, &MFAM, LiveInSets);
+                    std::vector<SparseBitVector<>> *LiveInSets = nullptr,
+                    MachineDomTreeUpdater *MDTU = nullptr) {
+    return SplitCriticalEdge(Succ, nullptr, &MFAM, LiveInSets, MDTU);
   }
 
   // Helper method for new pass manager migration.
-  MachineBasicBlock *
-  SplitCriticalEdge(MachineBasicBlock *Succ, Pass *P,
-                    MachineFunctionAnalysisManager *MFAM,
-                    std::vector<SparseBitVector<>> *LiveInSets);
+  MachineBasicBlock *SplitCriticalEdge(
+      MachineBasicBlock *Succ, Pass *P, MachineFunctionAnalysisManager *MFAM,
+      std::vector<SparseBitVector<>> *LiveInSets, MachineDomTreeUpdater *MDTU);
 
   /// Check if the edge between this block and the given successor \p
   /// Succ, can be split. If this returns true a subsequent call to
@@ -1375,6 +1377,12 @@ inline auto successors(const MachineBasicBlock *BB) { return BB->successors(); }
 inline auto predecessors(const MachineBasicBlock *BB) {
   return BB->predecessors();
 }
+inline auto succ_size(const MachineBasicBlock *BB) { return BB->succ_size(); }
+inline auto pred_size(const MachineBasicBlock *BB) { return BB->pred_size(); }
+inline auto succ_begin(const MachineBasicBlock *BB) { return BB->succ_begin(); }
+inline auto pred_begin(const MachineBasicBlock *BB) { return BB->pred_begin(); }
+inline auto succ_end(const MachineBasicBlock *BB) { return BB->succ_end(); }
+inline auto pred_end(const MachineBasicBlock *BB) { return BB->pred_end(); }
 
 /// MachineInstrSpan provides an interface to get an iteration range
 /// containing the instruction it was ...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Nov 6, 2024

@llvm/pr-subscribers-backend-x86

Author: None (paperchalice)

Changes

Support critical edge splitting in dominator tree updater. Continue the work in #100856.

Compile time check: https://llvm-compile-time-tracker.com/compare.php?from=87c35d782795b54911b3e3a91a5b738d4d870e55&amp;to=42b3e5623a9ab4c3648564dc0926b36f3b438a3a&amp;stat=instructions%3Au


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

29 Files Affected:

  • (modified) llvm/include/llvm/Analysis/DomTreeUpdater.h (+3-3)
  • (modified) llvm/include/llvm/Analysis/GenericDomTreeUpdater.h (+40-5)
  • (modified) llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h (+209-42)
  • (modified) llvm/include/llvm/CodeGen/MachineBasicBlock.h (+16-8)
  • (modified) llvm/include/llvm/CodeGen/MachineDominators.h (+2-167)
  • (modified) llvm/include/llvm/CodeGen/MachineSSAContext.h (-6)
  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+2-2)
  • (modified) llvm/lib/CodeGen/LazyMachineBlockFrequencyInfo.cpp (+2-2)
  • (modified) llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/LiveDebugValues/LiveDebugValues.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/MachineBasicBlock.cpp (+5-3)
  • (modified) llvm/lib/CodeGen/MachineDomTreeUpdater.cpp (+1)
  • (modified) llvm/lib/CodeGen/MachineDominanceFrontier.cpp (+1-2)
  • (modified) llvm/lib/CodeGen/MachineDominators.cpp (-74)
  • (modified) llvm/lib/CodeGen/MachineLICM.cpp (+10-7)
  • (modified) llvm/lib/CodeGen/MachineLoopInfo.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/MachineSink.cpp (+5-1)
  • (modified) llvm/lib/CodeGen/MachineUniformityAnalysis.cpp (+1-2)
  • (modified) llvm/lib/CodeGen/PHIElimination.cpp (+18-9)
  • (modified) llvm/lib/CodeGen/XRayInstrumentation.cpp (+2-2)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPURegBankSelect.cpp (+2-3)
  • (modified) llvm/lib/Target/AMDGPU/SILateBranchLowering.cpp (+3-3)
  • (modified) llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp (+1-1)
  • (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp (+1-1)
  • (modified) llvm/lib/Target/X86/X86FlagsCopyLowering.cpp (+1-2)
  • (modified) llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp (+1-1)
  • (modified) llvm/unittests/Analysis/DomTreeUpdaterTest.cpp (+43)
  • (modified) llvm/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp (+4-4)
diff --git a/llvm/include/llvm/Analysis/DomTreeUpdater.h b/llvm/include/llvm/Analysis/DomTreeUpdater.h
index c120a6cc6ce5ab..c54f5cc5c1759a 100644
--- a/llvm/include/llvm/Analysis/DomTreeUpdater.h
+++ b/llvm/include/llvm/Analysis/DomTreeUpdater.h
@@ -81,6 +81,9 @@ class DomTreeUpdater
 
   ///@}
 
+  /// Debug method to help view the internal state of this class.
+  LLVM_DUMP_METHOD void dump() const;
+
 private:
   class CallBackOnDeletion final : public CallbackVH {
   public:
@@ -109,9 +112,6 @@ class DomTreeUpdater
 
   /// Returns true if at least one BasicBlock is deleted.
   bool forceFlushDeletedBB();
-
-  /// Debug method to help view the internal state of this class.
-  LLVM_DUMP_METHOD void dump() const;
 };
 
 extern template class GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
index ca4ce68b85cbcf..6ec64de1b140ed 100644
--- a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
+++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
@@ -30,6 +30,7 @@ class GenericDomTreeUpdater {
 public:
   enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };
   using BasicBlockT = typename DomTreeT::NodeType;
+  using UpdateT = typename DomTreeT::UpdateType;
 
   explicit GenericDomTreeUpdater(UpdateStrategy Strategy_)
       : Strategy(Strategy_) {}
@@ -146,7 +147,19 @@ class GenericDomTreeUpdater {
   /// 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);
+  void applyUpdates(ArrayRef<UpdateT> Updates);
+
+  /// Apply updates that the critical edge (FromBB, ToBB) has been
+  /// split with NewBB.
+  ///
+  /// \note Do not use this method with regular edges.
+  ///
+  /// \note This kind updates are incompatible with generic updates,
+  /// call this method will submit all generic updates in lazy mode.
+  /// It is not recommended to interleave applyUpdates and
+  /// applyUpdatesForCriticalEdgeSplitting.
+  void splitCriticalEdge(BasicBlockT *FromBB, BasicBlockT *ToBB,
+                         BasicBlockT *NewBB);
 
   /// Submit updates to all available trees. It will also
   /// 1. discard duplicated updates,
@@ -169,7 +182,7 @@ class GenericDomTreeUpdater {
   /// 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);
+  void applyUpdatesPermissive(ArrayRef<UpdateT> Updates);
 
   ///@}
 
@@ -205,7 +218,25 @@ class GenericDomTreeUpdater {
   LLVM_DUMP_METHOD void dump() const;
 
 protected:
-  SmallVector<typename DomTreeT::UpdateType, 16> PendUpdates;
+  /// Helper structure used to hold all the basic blocks
+  /// involved in the split of a critical edge.
+  struct CriticalEdge {
+    BasicBlockT *FromBB;
+    BasicBlockT *ToBB;
+    BasicBlockT *NewBB;
+  };
+
+  struct DomTreeUpdate {
+    bool IsCriticalEdgeSplit = false;
+    union {
+      UpdateT Update;
+      CriticalEdge EdgeSplit;
+    };
+    DomTreeUpdate(UpdateT Update) : Update(Update) {}
+    DomTreeUpdate(CriticalEdge E) : IsCriticalEdgeSplit(true), EdgeSplit(E) {}
+  };
+
+  SmallVector<DomTreeUpdate, 16> PendUpdates;
   size_t PendDTUpdateIndex = 0;
   size_t PendPDTUpdateIndex = 0;
   DomTreeT *DT = nullptr;
@@ -216,7 +247,7 @@ class GenericDomTreeUpdater {
   bool IsRecalculatingPostDomTree = false;
 
   /// Returns true if the update is self dominance.
-  bool isSelfDominance(typename DomTreeT::UpdateType Update) const {
+  bool isSelfDominance(UpdateT Update) const {
     // Won't affect DomTree and PostDomTree.
     return Update.getFrom() == Update.getTo();
   }
@@ -230,7 +261,7 @@ class GenericDomTreeUpdater {
   /// 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;
+  bool isUpdateValid(UpdateT Update) const;
 
   /// Erase Basic Block node before it is unlinked from Function
   /// in the DomTree and PostDomTree.
@@ -243,6 +274,10 @@ class GenericDomTreeUpdater {
   /// Drop all updates applied by all available trees and delete BasicBlocks if
   /// all available trees are up-to-date.
   void dropOutOfDateUpdates();
+
+private:
+  void splitDTCriticalEdges(ArrayRef<CriticalEdge> Updates);
+  void splitPDTCriticalEdges(ArrayRef<CriticalEdge> Updates);
 };
 
 } // namespace llvm
diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h
index b79eaef57710fa..a5698f4a777057 100644
--- a/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h
+++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h
@@ -16,6 +16,7 @@
 #ifndef LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
 #define LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
 
+#include "llvm/ADT/SmallBitVector.h"
 #include "llvm/Analysis/GenericDomTreeUpdater.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
@@ -56,7 +57,7 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::recalculate(
 
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::applyUpdates(
-    ArrayRef<typename DomTreeT::UpdateType> Updates) {
+    ArrayRef<UpdateT> Updates) {
   if (!DT && !PDT)
     return;
 
@@ -77,12 +78,12 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::applyUpdates(
 
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
-    applyUpdatesPermissive(ArrayRef<typename DomTreeT::UpdateType> Updates) {
+    applyUpdatesPermissive(ArrayRef<UpdateT> Updates) {
   if (!DT && !PDT)
     return;
 
   SmallSet<std::pair<BasicBlockT *, BasicBlockT *>, 8> Seen;
-  SmallVector<typename DomTreeT::UpdateType, 8> DeduplicatedUpdates;
+  SmallVector<UpdateT, 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
@@ -129,6 +130,24 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
     PDT->applyUpdates(DeduplicatedUpdates);
 }
 
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::splitCriticalEdge(
+    BasicBlockT *FromBB, BasicBlockT *ToBB, BasicBlockT *NewBB) {
+  if (!DT && !PDT)
+    return;
+
+  CriticalEdge E = {FromBB, ToBB, NewBB};
+  if (Strategy == UpdateStrategy::Lazy) {
+    PendUpdates.push_back(E);
+    return;
+  }
+
+  if (DT)
+    splitDTCriticalEdges(E);
+  if (PDT)
+    splitPDTCriticalEdges(E);
+}
+
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 DomTreeT &
 GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::getDomTree() {
@@ -171,45 +190,46 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
     OS << "Lazy\n";
   int Index = 0;
 
+  auto printBlockInfo = [&](BasicBlockT *BB, StringRef Ending) {
+    if (BB) {
+      auto S = BB->getName();
+      if (!BB->hasName())
+        S = "(no name)";
+      OS << S << "(" << BB << ")" << Ending;
+    } else {
+      OS << "(badref)" << Ending;
+    }
+  };
+
   auto printUpdates =
-      [&](typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
-              begin,
-          typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
-              end) {
+      [&](typename ArrayRef<DomTreeUpdate>::const_iterator begin,
+          typename ArrayRef<DomTreeUpdate>::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";
+          if (!It->IsCriticalEdgeSplit) {
+            auto U = It->Update;
+            OS << "  " << Index << " : ";
+            ++Index;
+            if (U.getKind() == DomTreeT::Insert)
+              OS << "Insert, ";
+            else
+              OS << "Delete, ";
+            printBlockInfo(U.getFrom(), ", ");
+            printBlockInfo(U.getTo(), "\n");
           } else {
-            OS << "(badref)\n";
+            const auto &Edge = It->EdgeSplit;
+            OS << "  " << Index++ << " : Split critical edge, ";
+            printBlockInfo(Edge.FromBB, ", ");
+            printBlockInfo(Edge.ToBB, ", ");
+            printBlockInfo(Edge.NewBB, "\n");
           }
         }
       };
 
   if (DT) {
-    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+    auto I = PendUpdates.begin() + PendDTUpdateIndex;
     assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
            "Iterator out of range.");
     OS << "Applied but not cleared DomTreeUpdates:\n";
@@ -219,7 +239,7 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
   }
 
   if (PDT) {
-    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+    auto I = PendUpdates.begin() + PendPDTUpdateIndex;
     assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
            "Iterator out of range.");
     OS << "Applied but not cleared PostDomTreeUpdates:\n";
@@ -236,7 +256,7 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
     if (BB->hasName())
       OS << BB->getName() << "(";
     else
-      OS << "(no_name)(";
+      OS << "(no name)(";
     OS << BB << ")\n";
   }
 #endif
@@ -250,12 +270,23 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT,
     return;
 
   // Only apply updates not are applied by DomTree.
-  if (hasPendingDomTreeUpdates()) {
-    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+  while (hasPendingDomTreeUpdates()) {
+    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();
+    if (!I->IsCriticalEdgeSplit) {
+      SmallVector<UpdateT, 32> NormalUpdates;
+      while (I != E && !I->IsCriticalEdgeSplit)
+        NormalUpdates.push_back((I++)->Update);
+      DT->applyUpdates(NormalUpdates);
+      PendDTUpdateIndex += NormalUpdates.size();
+    } else {
+      SmallVector<CriticalEdge, 32> CriticalEdges;
+      while (I != E && I->IsCriticalEdgeSplit)
+        CriticalEdges.push_back((I++)->EdgeSplit);
+      splitDTCriticalEdges(CriticalEdges);
+      PendDTUpdateIndex += CriticalEdges.size();
+    }
   }
 }
 
@@ -267,19 +298,30 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT,
     return;
 
   // Only apply updates not are applied by PostDomTree.
-  if (hasPendingPostDomTreeUpdates()) {
-    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+  while (hasPendingPostDomTreeUpdates()) {
+    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();
+    if (!I->IsCriticalEdgeSplit) {
+      SmallVector<UpdateT, 32> NormalUpdates;
+      while (I != E && !I->IsCriticalEdgeSplit)
+        NormalUpdates.push_back((I++)->Update);
+      PDT->applyUpdates(NormalUpdates);
+      PendPDTUpdateIndex += NormalUpdates.size();
+    } else {
+      SmallVector<CriticalEdge, 32> CriticalEdges;
+      while (I != E && I->IsCriticalEdgeSplit)
+        CriticalEdges.push_back((I++)->EdgeSplit);
+      splitPDTCriticalEdges(CriticalEdges);
+      PendPDTUpdateIndex += CriticalEdges.size();
+    }
   }
 }
 
 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
 bool GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::isUpdateValid(
-    typename DomTreeT::UpdateType Update) const {
+    UpdateT Update) const {
   const auto *From = Update.getFrom();
   const auto *To = Update.getTo();
   const auto Kind = Update.getKind();
@@ -347,6 +389,131 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT,
   PendPDTUpdateIndex -= dropIndex;
 }
 
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
+    splitDTCriticalEdges(ArrayRef<CriticalEdge> Edges) {
+  // Bail out early if there is nothing to do.
+  if (Edges.empty())
+    return;
+
+  // Remember all the basic blocks that are inserted during
+  // edge splitting.
+  // Invariant: NewBBs == all the basic blocks contained in the NewBB
+  // field of all the elements of Edges.
+  // I.e., forall elt in Edges, it exists BB in NewBBs
+  // such as BB == elt.NewBB.
+  SmallSet<BasicBlockT *, 32> NewBBs;
+  for (auto &Edge : Edges)
+    NewBBs.insert(Edge.NewBB);
+  // For each element in Edges, remember whether or not element
+  // is the new immediate domminator of its successor. The mapping is done by
+  // index, i.e., the information for the ith element of Edges is
+  // the ith element of IsNewIDom.
+  SmallBitVector IsNewIDom(Edges.size(), true);
+  size_t Idx = 0;
+
+  // Collect all the dominance properties info, before invalidating
+  // the underlying DT.
+  for (const auto &Edge : Edges) {
+    // Update dominator information.
+    if (DT) {
+      BasicBlockT *Succ = Edge.ToBB;
+      auto *SuccDTNode = DT->getNode(Succ);
+
+      for (BasicBlockT *PredBB : predecessors(Succ)) {
+        if (PredBB == Edge.NewBB)
+          continue;
+        // If we are in this situation:
+        // FromBB1        FromBB2
+        //    +              +
+        //   + +            + +
+        //  +   +          +   +
+        // ...  Split1  Split2 ...
+        //           +   +
+        //            + +
+        //             +
+        //            Succ
+        // Instead of checking the domiance property with Split2, we check it
+        // with FromBB2 since Split2 is still unknown of the underlying DT
+        // structure.
+        if (NewBBs.count(PredBB)) {
+          assert(pred_size(PredBB) == 1 && "A basic block resulting from a "
+                                           "critical edge split has more "
+                                           "than one predecessor!");
+          PredBB = *pred_begin(PredBB);
+        }
+        if (!DT->dominates(SuccDTNode, DT->getNode(PredBB))) {
+          IsNewIDom[Idx] = false;
+          break;
+        }
+      }
+    }
+    ++Idx;
+  }
+
+  // Now, update DT with the collected dominance properties info.
+  Idx = 0;
+  for (const auto &Edge : Edges) {
+    if (DT) {
+      // We know FromBB dominates NewBB.
+      auto *NewDTNode = DT->addNewBlock(Edge.NewBB, Edge.FromBB);
+
+      // If all the other predecessors of "Succ" are dominated by "Succ" itself
+      // then the new block is the new immediate dominator of "Succ". Otherwise,
+      // the new block doesn't dominate anything.
+      if (IsNewIDom[Idx])
+        DT->changeImmediateDominator(DT->getNode(Edge.ToBB), NewDTNode);
+    }
+    ++Idx;
+  }
+}
+
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
+    splitPDTCriticalEdges(ArrayRef<CriticalEdge> Edges) {
+  // Bail out early if there is nothing to do.
+  if (Edges.empty())
+    return;
+
+  SmallBitVector IsNewIPDom(Edges.size(), true);
+  SmallSet<BasicBlockT *, 32> NewBBs;
+  for (const auto &Edge : Edges)
+    NewBBs.insert(Edge.NewBB);
+  size_t Idx = 0;
+  for (const auto &Edge : Edges) {
+    // Same as DT version but from another direction.
+    if (PDT) {
+      BasicBlockT *Pred = Edge.FromBB;
+      auto *PredDTNode = PDT->getNode(Pred);
+      for (BasicBlockT *SuccBB : successors(Pred)) {
+        if (SuccBB == Edge.NewBB)
+          continue;
+        if (NewBBs.count(SuccBB)) {
+          assert(succ_size(SuccBB) == 1 && "A basic block resulting from a "
+                                           "critical edge split has more "
+                                           "than one predecessor!");
+          SuccBB = *succ_begin(SuccBB);
+        }
+        if (!PDT->dominates(PredDTNode, PDT->getNode(SuccBB))) {
+          IsNewIPDom[Idx] = false;
+          break;
+        }
+      }
+    }
+    ++Idx;
+  }
+
+  Idx = 0;
+  for (const auto &Edge : Edges) {
+    if (PDT) {
+      auto *NewPDTNode = PDT->addNewBlock(Edge.NewBB, Edge.ToBB);
+      if (IsNewIPDom[Idx])
+        PDT->changeImmediateDominator(PDT->getNode(Edge.FromBB), NewPDTNode);
+    }
+    ++Idx;
+  }
+}
+
 } // namespace llvm
 
 #endif // LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
diff --git a/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
index 6cf151c951b19f..7fe33c3913f2dd 100644
--- a/llvm/include/llvm/CodeGen/MachineBasicBlock.h
+++ b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
@@ -32,6 +32,7 @@
 namespace llvm {
 
 class BasicBlock;
+class MachineDomTreeUpdater;
 class MachineFunction;
 class MCSymbol;
 class ModuleSlotTracker;
@@ -972,22 +973,23 @@ class MachineBasicBlock
   /// MachineLoopInfo, as applicable.
   MachineBasicBlock *
   SplitCriticalEdge(MachineBasicBlock *Succ, Pass &P,
-                    std::vector<SparseBitVector<>> *LiveInSets = nullptr) {
-    return SplitCriticalEdge(Succ, &P, nullptr, LiveInSets);
+                    std::vector<SparseBitVector<>> *LiveInSets = nullptr,
+                    MachineDomTreeUpdater *MDTU = nullptr) {
+    return SplitCriticalEdge(Succ, &P, nullptr, LiveInSets, MDTU);
   }
 
   MachineBasicBlock *
   SplitCriticalEdge(MachineBasicBlock *Succ,
                     MachineFunctionAnalysisManager &MFAM,
-                    std::vector<SparseBitVector<>> *LiveInSets = nullptr) {
-    return SplitCriticalEdge(Succ, nullptr, &MFAM, LiveInSets);
+                    std::vector<SparseBitVector<>> *LiveInSets = nullptr,
+                    MachineDomTreeUpdater *MDTU = nullptr) {
+    return SplitCriticalEdge(Succ, nullptr, &MFAM, LiveInSets, MDTU);
   }
 
   // Helper method for new pass manager migration.
-  MachineBasicBlock *
-  SplitCriticalEdge(MachineBasicBlock *Succ, Pass *P,
-                    MachineFunctionAnalysisManager *MFAM,
-                    std::vector<SparseBitVector<>> *LiveInSets);
+  MachineBasicBlock *SplitCriticalEdge(
+      MachineBasicBlock *Succ, Pass *P, MachineFunctionAnalysisManager *MFAM,
+      std::vector<SparseBitVector<>> *LiveInSets, MachineDomTreeUpdater *MDTU);
 
   /// Check if the edge between this block and the given successor \p
   /// Succ, can be split. If this returns true a subsequent call to
@@ -1375,6 +1377,12 @@ inline auto successors(const MachineBasicBlock *BB) { return BB->successors(); }
 inline auto predecessors(const MachineBasicBlock *BB) {
   return BB->predecessors();
 }
+inline auto succ_size(const MachineBasicBlock *BB) { return BB->succ_size(); }
+inline auto pred_size(const MachineBasicBlock *BB) { return BB->pred_size(); }
+inline auto succ_begin(const MachineBasicBlock *BB) { return BB->succ_begin(); }
+inline auto pred_begin(const MachineBasicBlock *BB) { return BB->pred_begin(); }
+inline auto succ_end(const MachineBasicBlock *BB) { return BB->succ_end(); }
+inline auto pred_end(const MachineBasicBlock *BB) { return BB->pred_end(); }
 
 /// MachineInstrSpan provides an interface to get an iteration range
 /// containing the instruction it was ...
[truncated]

@paperchalice paperchalice force-pushed the dt-critical-edge branch 2 times, most recently from 7cf5713 to 3ee69c8 Compare November 18, 2024 05:42
@paperchalice
Copy link
Contributor Author

Ping @kuhar @nikic

Copy link
Member

@kuhar kuhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly cosmetic issues, I'm unlikely to have enough time in near future to carefully review the logic

@paperchalice paperchalice force-pushed the dt-critical-edge branch 3 times, most recently from 1bcb07c to 5b9d04f Compare November 19, 2024 07:32
@paperchalice
Copy link
Contributor Author

Ping? @kuhar

@kuhar
Copy link
Member

kuhar commented Dec 9, 2024

Could you click the Resolve conversation button on comments that have been addressed? Overall, the patch seems OK to me, but this requires someone to review the logic. I, unfortunately, don't have the time to do this. Would you be able to find a secondary reviewer?

@paperchalice paperchalice requested review from alinas and removed request for kuhar December 10, 2024 08:15
Copy link
Collaborator

@qcolombet qcolombet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

}
}
};

if (DT) {
const auto I = PendUpdates.begin() + PendDTUpdateIndex;
auto I = PendUpdates.begin() + PendDTUpdateIndex;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we drop const here and below?

CriticalEdges.push_back(I->EdgeSplit);
splitDTCriticalEdges(CriticalEdges);
PendDTUpdateIndex += CriticalEdges.size();
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: We should be able to factor this logic into a lambda to reuse it for DT and PDT and pass splitDTCriticalEdges or splitPDTCriticalEdges

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Reuse logic by adding a new template member function.

Copy link
Collaborator

@qcolombet qcolombet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates.
LGTM

auto *DomTree = [&]() {
if constexpr (IsForward)
return DT;
else
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: no else after return

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the type of dominator tree and post dominator tree are different, this ensures compiler can deduce correct type.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it

@paperchalice paperchalice merged commit 79047fa into llvm:main Dec 11, 2024
8 checks passed
@chapuni
Copy link
Contributor

chapuni commented Dec 11, 2024

Seems failing to build tools/llvm-readtapi/CMakeFiles/llvm-readtapi.dir/llvm-readtapi.cpp.o

fatal error: error in backend: SmallVector unable to grow. Requested capacity (4294967296) is larger than maximum value for size type (4294967295)

See "stage3" in https://lab.llvm.org/buildbot/#/builders/164/builds/5423

In my private builder, I saw memory exhaust after a few minutes.

paperchalice added a commit that referenced this pull request Dec 13, 2024
…r" (#119547)

This relands commit #115111.
Use traditional way to update post dominator tree, i.e. break critical
edge splitting into insert, insert, delete sequence.
When splitting critical edges, the post dominator tree may change its
root node, and `setNewRoot` only works in normal dominator tree...
See

https://github.com/llvm/llvm-project/blob/6c7e5827eda26990e872eb7c3f0d7866ee3c3171/llvm/include/llvm/Support/GenericDomTree.h#L684-L687
@paperchalice paperchalice deleted the dt-critical-edge branch December 14, 2024 07:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants