From 70e97163e0809d74955bfa157d1c1eaefbd92ea2 Mon Sep 17 00:00:00 2001 From: Chijun Sima Date: Fri, 22 Feb 2019 13:48:38 +0000 Subject: [DTU] Refine the interface and logic of applyUpdates Summary: This patch separates two semantics of `applyUpdates`: 1. User provides an accurate CFG diff and the dominator tree is updated according to the difference of `the number of edge insertions` and `the number of edge deletions` to infer the status of an edge before and after the update. 2. User provides a sequence of hints. Updates mentioned in this sequence might never happened and even duplicated. Logic changes: Previously, removing invalid updates is considered a side-effect of deduplication and is not guaranteed to be reliable. To handle the second semantic, `applyUpdates` does validity checking before deduplication, which can cause updates that have already been applied to be submitted again. Then, different calls to `applyUpdates` might cause unintended consequences, for example, ``` DTU(Lazy) and Edge A->B exists. 1. DTU.applyUpdates({{Delete, A, B}, {Insert, A, B}}) // User expects these 2 updates result in a no-op, but {Insert, A, B} is queued 2. Remove A->B 3. DTU.applyUpdates({{Delete, A, B}}) // DTU cancels this update with {Insert, A, B} mentioned above together (Unintended) ``` But by restricting the precondition that updates of an edge need to be strictly ordered as how CFG changes were made, we can infer the initial status of this edge to resolve this issue. Interface changes: The second semantic of `applyUpdates` is separated to `applyUpdatesPermissive`. These changes enable DTU(Lazy) to use the first semantic if needed, which is quite useful in `transforms/utils`. Reviewers: kuhar, brzycki, dmgreen, grosser Reviewed By: brzycki Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D58170 llvm-svn: 354669 --- llvm/lib/Analysis/DomTreeUpdater.cpp | 123 ++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 59 deletions(-) (limited to 'llvm/lib/Analysis/DomTreeUpdater.cpp') diff --git a/llvm/lib/Analysis/DomTreeUpdater.cpp b/llvm/lib/Analysis/DomTreeUpdater.cpp index e4d505b8f1a..49215889cfd 100644 --- a/llvm/lib/Analysis/DomTreeUpdater.cpp +++ b/llvm/lib/Analysis/DomTreeUpdater.cpp @@ -12,11 +12,13 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/DomTreeUpdater.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/IR/Dominators.h" #include "llvm/Support/GenericDomTree.h" #include #include +#include namespace llvm { @@ -53,41 +55,6 @@ bool DomTreeUpdater::isSelfDominance( return Update.getFrom() == Update.getTo(); } -bool DomTreeUpdater::applyLazyUpdate(DominatorTree::UpdateKind Kind, - BasicBlock *From, BasicBlock *To) { - assert((DT || PDT) && - "Call applyLazyUpdate() when both DT and PDT are nullptrs."); - assert(Strategy == DomTreeUpdater::UpdateStrategy::Lazy && - "Call applyLazyUpdate() with Eager strategy error"); - // Analyze pending updates to determine if the update is unnecessary. - const DominatorTree::UpdateType Update = {Kind, From, To}; - const DominatorTree::UpdateType Invert = {Kind != DominatorTree::Insert - ? DominatorTree::Insert - : DominatorTree::Delete, - From, To}; - // Only check duplicates in updates that are not applied by both trees. - auto I = - PendUpdates.begin() + std::max(PendDTUpdateIndex, PendPDTUpdateIndex); - const auto E = PendUpdates.end(); - - assert(I <= E && "Iterator out of range."); - - for (; I != E; ++I) { - if (Update == *I) - return false; // Discard duplicate updates. - - if (Invert == *I) { - // Update and Invert are both valid (equivalent to a no-op). Remove - // Invert from PendUpdates and discard the Update. - PendUpdates.erase(I); - return false; - } - } - - PendUpdates.push_back(Update); // Save the valid update. - return true; -} - void DomTreeUpdater::applyDomTreeUpdates() { // No pending DomTreeUpdates. if (Strategy != UpdateStrategy::Lazy || !DT) @@ -261,31 +228,15 @@ void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) { new UnreachableInst(DelBB->getContext(), DelBB); } -void DomTreeUpdater::applyUpdates(ArrayRef Updates, - bool ForceRemoveDuplicates) { +void DomTreeUpdater::applyUpdates(ArrayRef Updates) { if (!DT && !PDT) return; - if (Strategy == UpdateStrategy::Lazy || ForceRemoveDuplicates) { - SmallVector Seen; + if (Strategy == UpdateStrategy::Lazy) { for (const auto U : Updates) - // For Lazy UpdateStrategy, avoid duplicates to applyLazyUpdate() to save - // on analysis. - if (llvm::none_of( - Seen, - [U](const DominatorTree::UpdateType S) { return S == U; }) && - isUpdateValid(U) && !isSelfDominance(U)) { - Seen.push_back(U); - if (Strategy == UpdateStrategy::Lazy) - applyLazyUpdate(U.getKind(), U.getFrom(), U.getTo()); - } - if (Strategy == UpdateStrategy::Lazy) - return; + if (!isSelfDominance(U)) + PendUpdates.push_back(U); - if (DT) - DT->applyUpdates(Seen); - if (PDT) - PDT->applyUpdates(Seen); return; } @@ -295,6 +246,60 @@ void DomTreeUpdater::applyUpdates(ArrayRef Updates, PDT->applyUpdates(Updates); } +void DomTreeUpdater::applyUpdatesPermissive( + ArrayRef Updates) { + if (!DT && !PDT) + return; + + SmallSet, 8> Seen; + SmallVector DeduplicatedUpdates; + for (const auto U : Updates) { + auto Edge = std::make_pair(U.getFrom(), U.getTo()); + // Because it is illegal to submit updates that have already been applied + // and updates to an edge need to be strictly ordered, + // it is safe to infer the existence of an edge from the first update + // to this edge. + // If the first update to an edge is "Delete", it means that the edge + // existed before. If the first update to an edge is "Insert", it means + // that the edge didn't exist before. + // + // For example, if the user submits {{Delete, A, B}, {Insert, A, B}}, + // because + // 1. it is illegal to submit updates that have already been applied, + // i.e., user cannot delete an nonexistent edge, + // 2. updates to an edge need to be strictly ordered, + // So, initially edge A -> B existed. + // We can then safely ignore future updates to this edge and directly + // inspect the current CFG: + // a. If the edge still exists, because the user cannot insert an existent + // edge, so both {Delete, A, B}, {Insert, A, B} actually happened and + // resulted in a no-op. DTU won't submit any update in this case. + // b. If the edge doesn't exist, we can then infer that {Delete, A, B} + // actually happened but {Insert, A, B} was an invalid update which never + // happened. DTU will submit {Delete, A, B} in this case. + if (!isSelfDominance(U) && Seen.count(Edge) == 0) { + Seen.insert(Edge); + // If the update doesn't appear in the CFG, it means that + // either the change isn't made or relevant operations + // result in a no-op. + if (isUpdateValid(U)) { + if (isLazy()) + PendUpdates.push_back(U); + else + DeduplicatedUpdates.push_back(U); + } + } + } + + if (Strategy == UpdateStrategy::Lazy) + return; + + if (DT) + DT->applyUpdates(DeduplicatedUpdates); + if (PDT) + PDT->applyUpdates(DeduplicatedUpdates); +} + DominatorTree &DomTreeUpdater::getDomTree() { assert(DT && "Invalid acquisition of a null DomTree"); applyDomTreeUpdates(); @@ -331,7 +336,7 @@ void DomTreeUpdater::insertEdge(BasicBlock *From, BasicBlock *To) { return; } - applyLazyUpdate(DominatorTree::Insert, From, To); + PendUpdates.push_back({DominatorTree::Insert, From, To}); } void DomTreeUpdater::insertEdgeRelaxed(BasicBlock *From, BasicBlock *To) { @@ -352,7 +357,7 @@ void DomTreeUpdater::insertEdgeRelaxed(BasicBlock *From, BasicBlock *To) { return; } - applyLazyUpdate(DominatorTree::Insert, From, To); + PendUpdates.push_back({DominatorTree::Insert, From, To}); } void DomTreeUpdater::deleteEdge(BasicBlock *From, BasicBlock *To) { @@ -377,7 +382,7 @@ void DomTreeUpdater::deleteEdge(BasicBlock *From, BasicBlock *To) { return; } - applyLazyUpdate(DominatorTree::Delete, From, To); + PendUpdates.push_back({DominatorTree::Delete, From, To}); } void DomTreeUpdater::deleteEdgeRelaxed(BasicBlock *From, BasicBlock *To) { @@ -398,7 +403,7 @@ void DomTreeUpdater::deleteEdgeRelaxed(BasicBlock *From, BasicBlock *To) { return; } - applyLazyUpdate(DominatorTree::Delete, From, To); + PendUpdates.push_back({DominatorTree::Delete, From, To}); } void DomTreeUpdater::dropOutOfDateUpdates() { -- cgit v1.2.3