//===- 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);
 
 
 
  /// 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