Skip to content

Commit

Permalink
[CodeGen] Introduce MachineDomTreeUpdater (#95369)
Browse files Browse the repository at this point in the history
This commit converts most of `DomTreeUpdater` into
`GenericDomTreeUpdater` class template, so IR and MIR can reuse some
codes.
There are some differences between interfaces of `BasicBlock` and
`MachineBasicBlock`, so subclasses still need to implement some
functions, like `forceFlushDeletedBB`.
  • Loading branch information
paperchalice committed Jun 27, 2024
1 parent c791d86 commit 6ca387c
Show file tree
Hide file tree
Showing 11 changed files with 981 additions and 510 deletions.
196 changes: 32 additions & 164 deletions llvm/include/llvm/Analysis/DomTreeUpdater.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#define LLVM_ANALYSIS_DOMTREEUPDATER_H

#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Analysis/GenericDomTreeUpdater.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Compiler.h"
Expand All @@ -23,66 +25,17 @@
#include <vector>

namespace llvm {
class PostDominatorTree;

class DomTreeUpdater {
public:
enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };

explicit DomTreeUpdater(UpdateStrategy Strategy_) : Strategy(Strategy_) {}
DomTreeUpdater(DominatorTree &DT_, UpdateStrategy Strategy_)
: DT(&DT_), Strategy(Strategy_) {}
DomTreeUpdater(DominatorTree *DT_, UpdateStrategy Strategy_)
: DT(DT_), Strategy(Strategy_) {}
DomTreeUpdater(PostDominatorTree &PDT_, UpdateStrategy Strategy_)
: PDT(&PDT_), Strategy(Strategy_) {}
DomTreeUpdater(PostDominatorTree *PDT_, UpdateStrategy Strategy_)
: PDT(PDT_), Strategy(Strategy_) {}
DomTreeUpdater(DominatorTree &DT_, PostDominatorTree &PDT_,
UpdateStrategy Strategy_)
: DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {}
DomTreeUpdater(DominatorTree *DT_, PostDominatorTree *PDT_,
UpdateStrategy Strategy_)
: DT(DT_), PDT(PDT_), Strategy(Strategy_) {}

~DomTreeUpdater() { flush(); }

/// Returns true if the current strategy is Lazy.
bool isLazy() const { return Strategy == UpdateStrategy::Lazy; };

/// Returns true if the current strategy is Eager.
bool isEager() const { return Strategy == UpdateStrategy::Eager; };

/// Returns true if it holds a DominatorTree.
bool hasDomTree() const { return DT != nullptr; }

/// Returns true if it holds a PostDominatorTree.
bool hasPostDomTree() const { return PDT != nullptr; }

/// Returns true if there is BasicBlock awaiting deletion.
/// The deletion will only happen until a flush event and
/// all available trees are up-to-date.
/// Returns false under Eager UpdateStrategy.
bool hasPendingDeletedBB() const { return !DeletedBBs.empty(); }

/// Returns true if DelBB is awaiting deletion.
/// Returns false under Eager UpdateStrategy.
bool isBBPendingDeletion(BasicBlock *DelBB) const;

/// Returns true if either of DT or PDT is valid and the tree has at
/// least one update pending. If DT or PDT is nullptr it is treated
/// as having no pending updates. This function does not check
/// whether there is BasicBlock awaiting deletion.
/// Returns false under Eager UpdateStrategy.
bool hasPendingUpdates() const;
class DomTreeUpdater
: public GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
PostDominatorTree> {
friend GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
PostDominatorTree>;

/// Returns true if there are DominatorTree updates queued.
/// Returns false under Eager UpdateStrategy or DT is nullptr.
bool hasPendingDomTreeUpdates() const;

/// Returns true if there are PostDominatorTree updates queued.
/// Returns false under Eager UpdateStrategy or PDT is nullptr.
bool hasPendingPostDomTreeUpdates() const;
public:
using Base =
GenericDomTreeUpdater<DomTreeUpdater, DominatorTree, PostDominatorTree>;
using Base::Base;

///@{
/// \name Mutation APIs
Expand All @@ -105,51 +58,6 @@ class DomTreeUpdater {
/// Although GenericDomTree provides several update primitives,
/// it is not encouraged to use these APIs directly.

/// Submit updates to all available trees.
/// The Eager Strategy flushes updates immediately while the Lazy Strategy
/// queues the updates.
///
/// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
/// in sync with + all updates before that single update.
///
/// CAUTION!
/// 1. It is required for the state of the LLVM IR to be updated
/// *before* submitting the updates because the internal update routine will
/// analyze the current state of the CFG to determine whether an update
/// is valid.
/// 2. It is illegal to submit any update that has already been submitted,
/// i.e., you are supposed not to insert an existent edge or delete a
/// nonexistent edge.
void applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates);

/// Submit updates to all available trees. It will also
/// 1. discard duplicated updates,
/// 2. remove invalid updates. (Invalid updates means deletion of an edge that
/// still exists or insertion of an edge that does not exist.)
/// The Eager Strategy flushes updates immediately while the Lazy Strategy
/// queues the updates.
///
/// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
/// in sync with + all updates before that single update.
///
/// CAUTION!
/// 1. It is required for the state of the LLVM IR to be updated
/// *before* submitting the updates because the internal update routine will
/// analyze the current state of the CFG to determine whether an update
/// is valid.
/// 2. It is illegal to submit any update that has already been submitted,
/// i.e., you are supposed not to insert an existent edge or delete a
/// nonexistent edge.
/// 3. It is only legal to submit updates to an edge in the order CFG changes
/// are made. The order you submit updates on different edges is not
/// restricted.
void applyUpdatesPermissive(ArrayRef<DominatorTree::UpdateType> Updates);

/// Notify DTU that the entry block was replaced.
/// Recalculate all available trees and flush all BasicBlocks
/// awaiting deletion immediately.
void recalculate(Function &F);

/// Delete DelBB. DelBB will be removed from its Parent and
/// erased from available trees if it exists and finally get deleted.
/// Under Eager UpdateStrategy, DelBB will be processed immediately.
Expand All @@ -172,33 +80,6 @@ class DomTreeUpdater {

///@}

///@{
/// \name Flush APIs
///
/// CAUTION! By the moment these flush APIs are called, the current CFG needs
/// to be the same as the CFG which DTU is in sync with + all updates
/// submitted.

/// Flush DomTree updates and return DomTree.
/// It flushes Deleted BBs if both trees are up-to-date.
/// It must only be called when it has a DomTree.
DominatorTree &getDomTree();

/// Flush PostDomTree updates and return PostDomTree.
/// It flushes Deleted BBs if both trees are up-to-date.
/// It must only be called when it has a PostDomTree.
PostDominatorTree &getPostDomTree();

/// Apply all pending updates to available trees and flush all BasicBlocks
/// awaiting deletion.

void flush();

///@}

/// Debug method to help view the internal state of this class.
LLVM_DUMP_METHOD void dump() const;

private:
class CallBackOnDeletion final : public CallbackVH {
public:
Expand All @@ -216,16 +97,7 @@ class DomTreeUpdater {
}
};

SmallVector<DominatorTree::UpdateType, 16> PendUpdates;
size_t PendDTUpdateIndex = 0;
size_t PendPDTUpdateIndex = 0;
DominatorTree *DT = nullptr;
PostDominatorTree *PDT = nullptr;
const UpdateStrategy Strategy;
SmallPtrSet<BasicBlock *, 8> DeletedBBs;
std::vector<CallBackOnDeletion> Callbacks;
bool IsRecalculatingDomTree = false;
bool IsRecalculatingPostDomTree = false;

/// First remove all the instructions of DelBB and then make sure DelBB has a
/// valid terminator instruction which is necessary to have when DelBB still
Expand All @@ -237,32 +109,28 @@ class DomTreeUpdater {
/// Returns true if at least one BasicBlock is deleted.
bool forceFlushDeletedBB();

/// Helper function to apply all pending DomTree updates.
void applyDomTreeUpdates();

/// Helper function to apply all pending PostDomTree updates.
void applyPostDomTreeUpdates();

/// Helper function to flush deleted BasicBlocks if all available
/// trees are up-to-date.
void tryFlushDeletedBB();

/// Drop all updates applied by all available trees and delete BasicBlocks if
/// all available trees are up-to-date.
void dropOutOfDateUpdates();

/// Erase Basic Block node that has been unlinked from Function
/// in the DomTree and PostDomTree.
void eraseDelBBNode(BasicBlock *DelBB);

/// Returns true if the update appears in the LLVM IR.
/// It is used to check whether an update is valid in
/// insertEdge/deleteEdge or is unnecessary in the batch update.
bool isUpdateValid(DominatorTree::UpdateType Update) const;

/// Returns true if the update is self dominance.
bool isSelfDominance(DominatorTree::UpdateType Update) const;
/// Debug method to help view the internal state of this class.
LLVM_DUMP_METHOD void dump() const {
Base::dump();
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
raw_ostream &OS = dbgs();
OS << "Pending Callbacks:\n";
int Index = 0;
for (const auto &BB : Callbacks) {
OS << " " << Index << " : ";
++Index;
if (BB->hasName())
OS << BB->getName() << "(";
else
OS << "(no_name)(";
OS << BB << ")\n";
}
#endif
}
};

extern template class GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
PostDominatorTree>;
} // namespace llvm

#endif // LLVM_ANALYSIS_DOMTREEUPDATER_H
Loading

0 comments on commit 6ca387c

Please sign in to comment.