Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:12

0001 //===- GenericDomTreeUpdater.h ----------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This file defines the GenericDomTreeUpdater class, which provides a uniform
0010 // way to update dominator tree related data structures.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
0015 #define LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
0016 
0017 #include "llvm/ADT/ArrayRef.h"
0018 #include "llvm/ADT/SmallSet.h"
0019 #include "llvm/Support/Compiler.h"
0020 
0021 namespace llvm {
0022 
0023 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
0024 class GenericDomTreeUpdater {
0025   DerivedT &derived() { return *static_cast<DerivedT *>(this); }
0026   const DerivedT &derived() const {
0027     return *static_cast<const DerivedT *>(this);
0028   }
0029 
0030 public:
0031   enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };
0032   using BasicBlockT = typename DomTreeT::NodeType;
0033   using UpdateT = typename DomTreeT::UpdateType;
0034 
0035   explicit GenericDomTreeUpdater(UpdateStrategy Strategy_)
0036       : Strategy(Strategy_) {}
0037   GenericDomTreeUpdater(DomTreeT &DT_, UpdateStrategy Strategy_)
0038       : DT(&DT_), Strategy(Strategy_) {}
0039   GenericDomTreeUpdater(DomTreeT *DT_, UpdateStrategy Strategy_)
0040       : DT(DT_), Strategy(Strategy_) {}
0041   GenericDomTreeUpdater(PostDomTreeT &PDT_, UpdateStrategy Strategy_)
0042       : PDT(&PDT_), Strategy(Strategy_) {}
0043   GenericDomTreeUpdater(PostDomTreeT *PDT_, UpdateStrategy Strategy_)
0044       : PDT(PDT_), Strategy(Strategy_) {}
0045   GenericDomTreeUpdater(DomTreeT &DT_, PostDomTreeT &PDT_,
0046                         UpdateStrategy Strategy_)
0047       : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {}
0048   GenericDomTreeUpdater(DomTreeT *DT_, PostDomTreeT *PDT_,
0049                         UpdateStrategy Strategy_)
0050       : DT(DT_), PDT(PDT_), Strategy(Strategy_) {}
0051 
0052   ~GenericDomTreeUpdater() {
0053     // We cannot call into derived() here as it will already be destroyed.
0054     assert(!hasPendingUpdates() &&
0055            "Pending updates were not flushed by derived class.");
0056   }
0057 
0058   /// Returns true if the current strategy is Lazy.
0059   bool isLazy() const { return Strategy == UpdateStrategy::Lazy; }
0060 
0061   /// Returns true if the current strategy is Eager.
0062   bool isEager() const { return Strategy == UpdateStrategy::Eager; }
0063 
0064   /// Returns true if it holds a DomTreeT.
0065   bool hasDomTree() const { return DT != nullptr; }
0066 
0067   /// Returns true if it holds a PostDomTreeT.
0068   bool hasPostDomTree() const { return PDT != nullptr; }
0069 
0070   /// Returns true if there is BasicBlockT awaiting deletion.
0071   /// The deletion will only happen until a flush event and
0072   /// all available trees are up-to-date.
0073   /// Returns false under Eager UpdateStrategy.
0074   bool hasPendingDeletedBB() const { return !DeletedBBs.empty(); }
0075 
0076   /// Returns true if DelBB is awaiting deletion.
0077   /// Returns false under Eager UpdateStrategy.
0078   bool isBBPendingDeletion(BasicBlockT *DelBB) const {
0079     if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty())
0080       return false;
0081     return DeletedBBs.contains(DelBB);
0082   }
0083 
0084   /// Returns true if either of DT or PDT is valid and the tree has at
0085   /// least one update pending. If DT or PDT is nullptr it is treated
0086   /// as having no pending updates. This function does not check
0087   /// whether there is MachineBasicBlock awaiting deletion.
0088   /// Returns false under Eager UpdateStrategy.
0089   bool hasPendingUpdates() const {
0090     return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates();
0091   }
0092 
0093   /// Returns true if there are DomTreeT updates queued.
0094   /// Returns false under Eager UpdateStrategy or DT is nullptr.
0095   bool hasPendingDomTreeUpdates() const {
0096     if (!DT)
0097       return false;
0098     return PendUpdates.size() != PendDTUpdateIndex;
0099   }
0100 
0101   /// Returns true if there are PostDomTreeT updates queued.
0102   /// Returns false under Eager UpdateStrategy or PDT is nullptr.
0103   bool hasPendingPostDomTreeUpdates() const {
0104     if (!PDT)
0105       return false;
0106     return PendUpdates.size() != PendPDTUpdateIndex;
0107   }
0108 
0109   ///@{
0110   /// \name Mutation APIs
0111   ///
0112   /// These methods provide APIs for submitting updates to the DomTreeT and
0113   /// the PostDominatorTree.
0114   ///
0115   /// Note: There are two strategies to update the DomTreeT and the
0116   /// PostDominatorTree:
0117   /// 1. Eager UpdateStrategy: Updates are submitted and then flushed
0118   /// immediately.
0119   /// 2. Lazy UpdateStrategy: Updates are submitted but only flushed when you
0120   /// explicitly call Flush APIs. It is recommended to use this update strategy
0121   /// when you submit a bunch of updates multiple times which can then
0122   /// add up to a large number of updates between two queries on the
0123   /// DomTreeT. The incremental updater can reschedule the updates or
0124   /// decide to recalculate the dominator tree in order to speedup the updating
0125   /// process depending on the number of updates.
0126   ///
0127   /// Although GenericDomTree provides several update primitives,
0128   /// it is not encouraged to use these APIs directly.
0129 
0130   /// Notify DTU that the entry block was replaced.
0131   /// Recalculate all available trees and flush all BasicBlocks
0132   /// awaiting deletion immediately.
0133   template <typename FuncT> void recalculate(FuncT &F);
0134 
0135   /// Submit updates to all available trees.
0136   /// The Eager Strategy flushes updates immediately while the Lazy Strategy
0137   /// queues the updates.
0138   ///
0139   /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
0140   /// in sync with + all updates before that single update.
0141   ///
0142   /// CAUTION!
0143   /// 1. It is required for the state of the LLVM IR to be updated
0144   /// *before* submitting the updates because the internal update routine will
0145   /// analyze the current state of the CFG to determine whether an update
0146   /// is valid.
0147   /// 2. It is illegal to submit any update that has already been submitted,
0148   /// i.e., you are supposed not to insert an existent edge or delete a
0149   /// nonexistent edge.
0150   void applyUpdates(ArrayRef<UpdateT> Updates);
0151 
0152   /// Apply updates that the critical edge (FromBB, ToBB) has been
0153   /// split with NewBB.
0154   void splitCriticalEdge(BasicBlockT *FromBB, BasicBlockT *ToBB,
0155                          BasicBlockT *NewBB);
0156 
0157   /// Submit updates to all available trees. It will also
0158   /// 1. discard duplicated updates,
0159   /// 2. remove invalid updates. (Invalid updates means deletion of an edge that
0160   /// still exists or insertion of an edge that does not exist.)
0161   /// The Eager Strategy flushes updates immediately while the Lazy Strategy
0162   /// queues the updates.
0163   ///
0164   /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
0165   /// in sync with + all updates before that single update.
0166   ///
0167   /// CAUTION!
0168   /// 1. It is required for the state of the LLVM IR to be updated
0169   /// *before* submitting the updates because the internal update routine will
0170   /// analyze the current state of the CFG to determine whether an update
0171   /// is valid.
0172   /// 2. It is illegal to submit any update that has already been submitted,
0173   /// i.e., you are supposed not to insert an existent edge or delete a
0174   /// nonexistent edge.
0175   /// 3. It is only legal to submit updates to an edge in the order CFG changes
0176   /// are made. The order you submit updates on different edges is not
0177   /// restricted.
0178   void applyUpdatesPermissive(ArrayRef<UpdateT> Updates);
0179 
0180   ///@}
0181 
0182   ///@{
0183   /// \name Flush APIs
0184   ///
0185   /// CAUTION! By the moment these flush APIs are called, the current CFG needs
0186   /// to be the same as the CFG which DTU is in sync with + all updates
0187   /// submitted.
0188 
0189   /// Flush DomTree updates and return DomTree.
0190   /// It flushes Deleted BBs if both trees are up-to-date.
0191   /// It must only be called when it has a DomTree.
0192   DomTreeT &getDomTree();
0193 
0194   /// Flush PostDomTree updates and return PostDomTree.
0195   /// It flushes Deleted BBs if both trees are up-to-date.
0196   /// It must only be called when it has a PostDomTree.
0197   PostDomTreeT &getPostDomTree();
0198 
0199   /// Apply all pending updates to available trees and flush all BasicBlocks
0200   /// awaiting deletion.
0201 
0202   void flush() {
0203     applyDomTreeUpdates();
0204     applyPostDomTreeUpdates();
0205     dropOutOfDateUpdates();
0206   }
0207 
0208   ///@}
0209 
0210   /// Debug method to help view the internal state of this class.
0211   LLVM_DUMP_METHOD void dump() const;
0212 
0213 protected:
0214   /// Helper structure used to hold all the basic blocks
0215   /// involved in the split of a critical edge.
0216   struct CriticalEdge {
0217     BasicBlockT *FromBB;
0218     BasicBlockT *ToBB;
0219     BasicBlockT *NewBB;
0220   };
0221 
0222   struct DomTreeUpdate {
0223     bool IsCriticalEdgeSplit = false;
0224     union {
0225       UpdateT Update;
0226       CriticalEdge EdgeSplit;
0227     };
0228     DomTreeUpdate(UpdateT Update) : Update(Update) {}
0229     DomTreeUpdate(CriticalEdge E) : IsCriticalEdgeSplit(true), EdgeSplit(E) {}
0230   };
0231 
0232   SmallVector<DomTreeUpdate, 16> PendUpdates;
0233   size_t PendDTUpdateIndex = 0;
0234   size_t PendPDTUpdateIndex = 0;
0235   DomTreeT *DT = nullptr;
0236   PostDomTreeT *PDT = nullptr;
0237   const UpdateStrategy Strategy;
0238   SmallPtrSet<BasicBlockT *, 8> DeletedBBs;
0239   bool IsRecalculatingDomTree = false;
0240   bool IsRecalculatingPostDomTree = false;
0241 
0242   /// Returns true if the update is self dominance.
0243   bool isSelfDominance(UpdateT Update) const {
0244     // Won't affect DomTree and PostDomTree.
0245     return Update.getFrom() == Update.getTo();
0246   }
0247 
0248   /// Helper function to apply all pending DomTree updates.
0249   void applyDomTreeUpdates() { applyUpdatesImpl<true>(); }
0250 
0251   /// Helper function to apply all pending PostDomTree updates.
0252   void applyPostDomTreeUpdates() { applyUpdatesImpl<false>(); }
0253 
0254   /// Returns true if the update appears in the LLVM IR.
0255   /// It is used to check whether an update is valid in
0256   /// insertEdge/deleteEdge or is unnecessary in the batch update.
0257   bool isUpdateValid(UpdateT Update) const;
0258 
0259   /// Erase Basic Block node before it is unlinked from Function
0260   /// in the DomTree and PostDomTree.
0261   void eraseDelBBNode(BasicBlockT *DelBB);
0262 
0263   /// Helper function to flush deleted BasicBlocks if all available
0264   /// trees are up-to-date.
0265   void tryFlushDeletedBB();
0266 
0267   /// Drop all updates applied by all available trees and delete BasicBlocks if
0268   /// all available trees are up-to-date.
0269   void dropOutOfDateUpdates();
0270 
0271 private:
0272   void splitDTCriticalEdges(ArrayRef<CriticalEdge> Updates);
0273   void splitPDTCriticalEdges(ArrayRef<CriticalEdge> Updates);
0274   template <bool IsForward> void applyUpdatesImpl();
0275 };
0276 
0277 } // namespace llvm
0278 
0279 #endif // LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H