|
@@ -71,6 +71,7 @@ struct SemiNCAInfo {
|
|
|
DenseMap<NodePtr, InfoRec> NodeToInfo;
|
|
|
|
|
|
using UpdateT = typename DomTreeT::UpdateType;
|
|
|
+ using UpdateKind = typename DomTreeT::UpdateKind;
|
|
|
struct BatchUpdateInfo {
|
|
|
SmallVector<UpdateT, 4> Updates;
|
|
|
using NodePtrAndKind = PointerIntPair<NodePtr, 1, UpdateKind>;
|
|
@@ -1166,7 +1167,8 @@ struct SemiNCAInfo {
|
|
|
}
|
|
|
|
|
|
BatchUpdateInfo BUI;
|
|
|
- LegalizeUpdates(Updates, BUI.Updates);
|
|
|
+ LLVM_DEBUG(dbgs() << "Legalizing " << BUI.Updates.size() << " updates\n");
|
|
|
+ cfg::LegalizeUpdates<NodePtr>(Updates, BUI.Updates, IsPostDom);
|
|
|
|
|
|
const size_t NumLegalized = BUI.Updates.size();
|
|
|
BUI.FutureSuccessors.reserve(NumLegalized);
|
|
@@ -1182,8 +1184,11 @@ struct SemiNCAInfo {
|
|
|
|
|
|
LLVM_DEBUG(dbgs() << "About to apply " << NumLegalized << " updates\n");
|
|
|
LLVM_DEBUG(if (NumLegalized < 32) for (const auto &U
|
|
|
- : reverse(BUI.Updates)) dbgs()
|
|
|
- << '\t' << U << "\n");
|
|
|
+ : reverse(BUI.Updates)) {
|
|
|
+ dbgs() << "\t";
|
|
|
+ U.dump();
|
|
|
+ dbgs() << "\n";
|
|
|
+ });
|
|
|
LLVM_DEBUG(dbgs() << "\n");
|
|
|
|
|
|
// If the DominatorTree was recalculated at some point, stop the batch
|
|
@@ -1193,76 +1198,11 @@ struct SemiNCAInfo {
|
|
|
ApplyNextUpdate(DT, BUI);
|
|
|
}
|
|
|
|
|
|
- // This function serves double purpose:
|
|
|
- // a) It removes redundant updates, which makes it easier to reverse-apply
|
|
|
- // them when traversing CFG.
|
|
|
- // b) It optimizes away updates that cancel each other out, as the end result
|
|
|
- // is the same.
|
|
|
- //
|
|
|
- // It relies on the property of the incremental updates that says that the
|
|
|
- // order of updates doesn't matter. This allows us to reorder them and end up
|
|
|
- // with the exact same DomTree every time.
|
|
|
- //
|
|
|
- // Following the same logic, the function doesn't care about the order of
|
|
|
- // input updates, so it's OK to pass it an unordered sequence of updates, that
|
|
|
- // doesn't make sense when applied sequentially, eg. performing double
|
|
|
- // insertions or deletions and then doing an opposite update.
|
|
|
- //
|
|
|
- // In the future, it should be possible to schedule updates in way that
|
|
|
- // minimizes the amount of work needed done during incremental updates.
|
|
|
- static void LegalizeUpdates(ArrayRef<UpdateT> AllUpdates,
|
|
|
- SmallVectorImpl<UpdateT> &Result) {
|
|
|
- LLVM_DEBUG(dbgs() << "Legalizing " << AllUpdates.size() << " updates\n");
|
|
|
- // Count the total number of inserions of each edge.
|
|
|
- // Each insertion adds 1 and deletion subtracts 1. The end number should be
|
|
|
- // one of {-1 (deletion), 0 (NOP), +1 (insertion)}. Otherwise, the sequence
|
|
|
- // of updates contains multiple updates of the same kind and we assert for
|
|
|
- // that case.
|
|
|
- SmallDenseMap<std::pair<NodePtr, NodePtr>, int, 4> Operations;
|
|
|
- Operations.reserve(AllUpdates.size());
|
|
|
-
|
|
|
- for (const auto &U : AllUpdates) {
|
|
|
- NodePtr From = U.getFrom();
|
|
|
- NodePtr To = U.getTo();
|
|
|
- if (IsPostDom) std::swap(From, To); // Reverse edge for postdominators.
|
|
|
-
|
|
|
- Operations[{From, To}] += (U.getKind() == UpdateKind::Insert ? 1 : -1);
|
|
|
- }
|
|
|
-
|
|
|
- Result.clear();
|
|
|
- Result.reserve(Operations.size());
|
|
|
- for (auto &Op : Operations) {
|
|
|
- const int NumInsertions = Op.second;
|
|
|
- assert(std::abs(NumInsertions) <= 1 && "Unbalanced operations!");
|
|
|
- if (NumInsertions == 0) continue;
|
|
|
- const UpdateKind UK =
|
|
|
- NumInsertions > 0 ? UpdateKind::Insert : UpdateKind::Delete;
|
|
|
- Result.push_back({UK, Op.first.first, Op.first.second});
|
|
|
- }
|
|
|
-
|
|
|
- // Make the order consistent by not relying on pointer values within the
|
|
|
- // set. Reuse the old Operations map.
|
|
|
- // In the future, we should sort by something else to minimize the amount
|
|
|
- // of work needed to perform the series of updates.
|
|
|
- for (size_t i = 0, e = AllUpdates.size(); i != e; ++i) {
|
|
|
- const auto &U = AllUpdates[i];
|
|
|
- if (!IsPostDom)
|
|
|
- Operations[{U.getFrom(), U.getTo()}] = int(i);
|
|
|
- else
|
|
|
- Operations[{U.getTo(), U.getFrom()}] = int(i);
|
|
|
- }
|
|
|
-
|
|
|
- llvm::sort(Result.begin(), Result.end(),
|
|
|
- [&Operations](const UpdateT &A, const UpdateT &B) {
|
|
|
- return Operations[{A.getFrom(), A.getTo()}] >
|
|
|
- Operations[{B.getFrom(), B.getTo()}];
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
static void ApplyNextUpdate(DomTreeT &DT, BatchUpdateInfo &BUI) {
|
|
|
assert(!BUI.Updates.empty() && "No updates to apply!");
|
|
|
UpdateT CurrentUpdate = BUI.Updates.pop_back_val();
|
|
|
- LLVM_DEBUG(dbgs() << "Applying update: " << CurrentUpdate << "\n");
|
|
|
+ LLVM_DEBUG(dbgs() << "Applying update: ");
|
|
|
+ LLVM_DEBUG(CurrentUpdate.dump(); dbgs() << "\n");
|
|
|
|
|
|
// Move to the next snapshot of the CFG by removing the reverse-applied
|
|
|
// current update. Since updates are performed in the same order they are
|