123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- DomTreeUpdater.h - DomTree/Post DomTree Updater ----------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file defines the DomTreeUpdater class, which provides a uniform way to
- // update dominator tree related data structures.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_ANALYSIS_DOMTREEUPDATER_H
- #define LLVM_ANALYSIS_DOMTREEUPDATER_H
- #include "llvm/ADT/SmallPtrSet.h"
- #include "llvm/IR/Dominators.h"
- #include "llvm/IR/ValueHandle.h"
- #include "llvm/Support/Compiler.h"
- #include <cstddef>
- #include <functional>
- #include <vector>
- namespace llvm {
- class PostDominatorTree;
- class DomTreeUpdater {
- public:
- enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };
- explicit DomTreeUpdater(UpdateStrategy Strategy_) : Strategy(Strategy_) {}
- DomTreeUpdater(DominatorTree &DT_, UpdateStrategy Strategy_)
- : DT(&DT_), Strategy(Strategy_) {}
- DomTreeUpdater(DominatorTree *DT_, UpdateStrategy Strategy_)
- : DT(DT_), Strategy(Strategy_) {}
- DomTreeUpdater(PostDominatorTree &PDT_, UpdateStrategy Strategy_)
- : PDT(&PDT_), Strategy(Strategy_) {}
- DomTreeUpdater(PostDominatorTree *PDT_, UpdateStrategy Strategy_)
- : PDT(PDT_), Strategy(Strategy_) {}
- DomTreeUpdater(DominatorTree &DT_, PostDominatorTree &PDT_,
- UpdateStrategy Strategy_)
- : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {}
- DomTreeUpdater(DominatorTree *DT_, PostDominatorTree *PDT_,
- UpdateStrategy Strategy_)
- : DT(DT_), PDT(PDT_), Strategy(Strategy_) {}
- ~DomTreeUpdater() { flush(); }
- /// Returns true if the current strategy is Lazy.
- bool isLazy() const { return Strategy == UpdateStrategy::Lazy; };
- /// Returns true if the current strategy is Eager.
- bool isEager() const { return Strategy == UpdateStrategy::Eager; };
- /// Returns true if it holds a DominatorTree.
- bool hasDomTree() const { return DT != nullptr; }
- /// Returns true if it holds a PostDominatorTree.
- bool hasPostDomTree() const { return PDT != nullptr; }
- /// Returns true if there is BasicBlock awaiting deletion.
- /// The deletion will only happen until a flush event and
- /// all available trees are up-to-date.
- /// Returns false under Eager UpdateStrategy.
- bool hasPendingDeletedBB() const { return !DeletedBBs.empty(); }
- /// Returns true if DelBB is awaiting deletion.
- /// Returns false under Eager UpdateStrategy.
- bool isBBPendingDeletion(BasicBlock *DelBB) const;
- /// Returns true if either of DT or PDT is valid and the tree has at
- /// least one update pending. If DT or PDT is nullptr it is treated
- /// as having no pending updates. This function does not check
- /// whether there is BasicBlock awaiting deletion.
- /// Returns false under Eager UpdateStrategy.
- bool hasPendingUpdates() const;
- /// Returns true if there are DominatorTree updates queued.
- /// Returns false under Eager UpdateStrategy or DT is nullptr.
- bool hasPendingDomTreeUpdates() const;
- /// Returns true if there are PostDominatorTree updates queued.
- /// Returns false under Eager UpdateStrategy or PDT is nullptr.
- bool hasPendingPostDomTreeUpdates() const;
- ///@{
- /// \name Mutation APIs
- ///
- /// These methods provide APIs for submitting updates to the DominatorTree and
- /// the PostDominatorTree.
- ///
- /// Note: There are two strategies to update the DominatorTree and the
- /// PostDominatorTree:
- /// 1. Eager UpdateStrategy: Updates are submitted and then flushed
- /// immediately.
- /// 2. Lazy UpdateStrategy: Updates are submitted but only flushed when you
- /// explicitly call Flush APIs. It is recommended to use this update strategy
- /// when you submit a bunch of updates multiple times which can then
- /// add up to a large number of updates between two queries on the
- /// DominatorTree. The incremental updater can reschedule the updates or
- /// decide to recalculate the dominator tree in order to speedup the updating
- /// process depending on the number of updates.
- ///
- /// Although GenericDomTree provides several update primitives,
- /// it is not encouraged to use these APIs directly.
- /// Submit updates to all available trees.
- /// The Eager Strategy flushes updates immediately while the Lazy Strategy
- /// queues the updates.
- ///
- /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
- /// in sync with + all updates before that single update.
- ///
- /// CAUTION!
- /// 1. It is required for the state of the LLVM IR to be updated
- /// *before* submitting the updates because the internal update routine will
- /// analyze the current state of the CFG to determine whether an update
- /// is valid.
- /// 2. It is illegal to submit any update that has already been submitted,
- /// i.e., you are supposed not to insert an existent edge or delete a
- /// nonexistent edge.
- void applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates);
- /// Submit updates to all available trees. It will also
- /// 1. discard duplicated updates,
- /// 2. remove invalid updates. (Invalid updates means deletion of an edge that
- /// still exists or insertion of an edge that does not exist.)
- /// The Eager Strategy flushes updates immediately while the Lazy Strategy
- /// queues the updates.
- ///
- /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
- /// in sync with + all updates before that single update.
- ///
- /// CAUTION!
- /// 1. It is required for the state of the LLVM IR to be updated
- /// *before* submitting the updates because the internal update routine will
- /// analyze the current state of the CFG to determine whether an update
- /// is valid.
- /// 2. It is illegal to submit any update that has already been submitted,
- /// i.e., you are supposed not to insert an existent edge or delete a
- /// nonexistent edge.
- /// 3. It is only legal to submit updates to an edge in the order CFG changes
- /// are made. The order you submit updates on different edges is not
- /// restricted.
- void applyUpdatesPermissive(ArrayRef<DominatorTree::UpdateType> Updates);
- /// Notify DTU that the entry block was replaced.
- /// Recalculate all available trees and flush all BasicBlocks
- /// awaiting deletion immediately.
- void recalculate(Function &F);
- /// \deprecated { Submit an edge insertion to all available trees. The Eager
- /// Strategy flushes this update immediately while the Lazy Strategy queues
- /// the update. An internal function checks if the edge exists in the CFG in
- /// DEBUG mode. CAUTION! This function has to be called *after* making the
- /// update on the actual CFG. It is illegal to submit any update that has
- /// already been applied. }
- LLVM_ATTRIBUTE_DEPRECATED(void insertEdge(BasicBlock *From, BasicBlock *To),
- "Use applyUpdates() instead.");
- /// \deprecated {Submit an edge insertion to all available trees.
- /// Under either Strategy, an invalid update will be discard silently.
- /// Invalid update means inserting an edge that does not exist in the CFG.
- /// The Eager Strategy flushes this update immediately while the Lazy Strategy
- /// queues the update. It is only recommended to use this method when you
- /// want to discard an invalid update.
- /// CAUTION! It is illegal to submit any update that has already been
- /// submitted. }
- LLVM_ATTRIBUTE_DEPRECATED(void insertEdgeRelaxed(BasicBlock *From,
- BasicBlock *To),
- "Use applyUpdatesPermissive() instead.");
- /// \deprecated { Submit an edge deletion to all available trees. The Eager
- /// Strategy flushes this update immediately while the Lazy Strategy queues
- /// the update. An internal function checks if the edge doesn't exist in the
- /// CFG in DEBUG mode.
- /// CAUTION! This function has to be called *after* making the update on the
- /// actual CFG. It is illegal to submit any update that has already been
- /// submitted. }
- LLVM_ATTRIBUTE_DEPRECATED(void deleteEdge(BasicBlock *From, BasicBlock *To),
- "Use applyUpdates() instead.");
- /// \deprecated { Submit an edge deletion to all available trees.
- /// Under either Strategy, an invalid update will be discard silently.
- /// Invalid update means deleting an edge that exists in the CFG.
- /// The Eager Strategy flushes this update immediately while the Lazy Strategy
- /// queues the update. It is only recommended to use this method when you
- /// want to discard an invalid update.
- /// CAUTION! It is illegal to submit any update that has already been
- /// submitted. }
- LLVM_ATTRIBUTE_DEPRECATED(void deleteEdgeRelaxed(BasicBlock *From,
- BasicBlock *To),
- "Use applyUpdatesPermissive() instead.");
- /// Delete DelBB. DelBB will be removed from its Parent and
- /// erased from available trees if it exists and finally get deleted.
- /// Under Eager UpdateStrategy, DelBB will be processed immediately.
- /// Under Lazy UpdateStrategy, DelBB will be queued until a flush event and
- /// all available trees are up-to-date. Assert if any instruction of DelBB is
- /// modified while awaiting deletion. When both DT and PDT are nullptrs, DelBB
- /// will be queued until flush() is called.
- void deleteBB(BasicBlock *DelBB);
- /// Delete DelBB. DelBB will be removed from its Parent and
- /// erased from available trees if it exists. Then the callback will
- /// be called. Finally, DelBB will be deleted.
- /// Under Eager UpdateStrategy, DelBB will be processed immediately.
- /// Under Lazy UpdateStrategy, DelBB will be queued until a flush event and
- /// all available trees are up-to-date. Assert if any instruction of DelBB is
- /// modified while awaiting deletion. Multiple callbacks can be queued for one
- /// DelBB under Lazy UpdateStrategy.
- void callbackDeleteBB(BasicBlock *DelBB,
- std::function<void(BasicBlock *)> Callback);
- ///@}
- ///@{
- /// \name Flush APIs
- ///
- /// CAUTION! By the moment these flush APIs are called, the current CFG needs
- /// to be the same as the CFG which DTU is in sync with + all updates
- /// submitted.
- /// Flush DomTree updates and return DomTree.
- /// It flushes Deleted BBs if both trees are up-to-date.
- /// It must only be called when it has a DomTree.
- DominatorTree &getDomTree();
- /// Flush PostDomTree updates and return PostDomTree.
- /// It flushes Deleted BBs if both trees are up-to-date.
- /// It must only be called when it has a PostDomTree.
- PostDominatorTree &getPostDomTree();
- /// Apply all pending updates to available trees and flush all BasicBlocks
- /// awaiting deletion.
- void flush();
- ///@}
- /// Debug method to help view the internal state of this class.
- LLVM_DUMP_METHOD void dump() const;
- private:
- class CallBackOnDeletion final : public CallbackVH {
- public:
- CallBackOnDeletion(BasicBlock *V,
- std::function<void(BasicBlock *)> Callback)
- : CallbackVH(V), DelBB(V), Callback_(Callback) {}
- private:
- BasicBlock *DelBB = nullptr;
- std::function<void(BasicBlock *)> Callback_;
- void deleted() override {
- Callback_(DelBB);
- CallbackVH::deleted();
- }
- };
- SmallVector<DominatorTree::UpdateType, 16> PendUpdates;
- size_t PendDTUpdateIndex = 0;
- size_t PendPDTUpdateIndex = 0;
- DominatorTree *DT = nullptr;
- PostDominatorTree *PDT = nullptr;
- const UpdateStrategy Strategy;
- SmallPtrSet<BasicBlock *, 8> DeletedBBs;
- std::vector<CallBackOnDeletion> Callbacks;
- bool IsRecalculatingDomTree = false;
- bool IsRecalculatingPostDomTree = false;
- /// First remove all the instructions of DelBB and then make sure DelBB has a
- /// valid terminator instruction which is necessary to have when DelBB still
- /// has to be inside of its parent Function while awaiting deletion under Lazy
- /// UpdateStrategy to prevent other routines from asserting the state of the
- /// IR is inconsistent. Assert if DelBB is nullptr or has predecessors.
- void validateDeleteBB(BasicBlock *DelBB);
- /// Returns true if at least one BasicBlock is deleted.
- bool forceFlushDeletedBB();
- /// Helper function to apply all pending DomTree updates.
- void applyDomTreeUpdates();
- /// Helper function to apply all pending PostDomTree updates.
- void applyPostDomTreeUpdates();
- /// Helper function to flush deleted BasicBlocks if all available
- /// trees are up-to-date.
- void tryFlushDeletedBB();
- /// Drop all updates applied by all available trees and delete BasicBlocks if
- /// all available trees are up-to-date.
- void dropOutOfDateUpdates();
- /// Erase Basic Block node that has been unlinked from Function
- /// in the DomTree and PostDomTree.
- void eraseDelBBNode(BasicBlock *DelBB);
- /// Returns true if the update appears in the LLVM IR.
- /// It is used to check whether an update is valid in
- /// insertEdge/deleteEdge or is unnecessary in the batch update.
- bool isUpdateValid(DominatorTree::UpdateType Update) const;
- /// Returns true if the update is self dominance.
- bool isSelfDominance(DominatorTree::UpdateType Update) const;
- };
- } // namespace llvm
- #endif // LLVM_ANALYSIS_DOMTREEUPDATER_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|