mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-14 23:48:56 +00:00
[Dominators] Use a custom DFS implementation
Summary: Custom DFS implementation allows us to skip over certain nodes without adding them to the visited map, which is not easily doable with llvm's dfs iterators. What's more, caching predecessors becomes easy. This patch implements a single DFS function (template) for both forward and reverse DFS, which should be easier to maintain then separate two ones. Skipping over nodes based on a predicate will be necessary later to implement incremental updates. There also seems to be a very slight performance improved when bootstrapping clang with this patch on my machine (3:28s -> 3:26s) . Reviewers: dberlin, sanjoy, davide, grosser Reviewed By: dberlin Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D34651 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@307727 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c80f62248b
commit
3f91c64c16
@ -32,6 +32,20 @@
|
||||
namespace llvm {
|
||||
namespace DomTreeBuilder {
|
||||
|
||||
template <typename NodePtr, bool Inverse>
|
||||
struct ChildrenGetter {
|
||||
static auto Get(NodePtr N) -> decltype(reverse(children<NodePtr>(N))) {
|
||||
return reverse(children<NodePtr>(N));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename NodePtr>
|
||||
struct ChildrenGetter<NodePtr, true> {
|
||||
static auto Get(NodePtr N) -> decltype(inverse_children<NodePtr>(N)) {
|
||||
return inverse_children<NodePtr>(N);
|
||||
}
|
||||
};
|
||||
|
||||
// Information record used by Semi-NCA during tree construction.
|
||||
template <typename NodeT>
|
||||
struct SemiNCAInfo {
|
||||
@ -45,6 +59,7 @@ struct SemiNCAInfo {
|
||||
unsigned Semi = 0;
|
||||
NodePtr Label = nullptr;
|
||||
NodePtr IDom = nullptr;
|
||||
SmallVector<NodePtr, 2> ReverseChildren;
|
||||
};
|
||||
|
||||
std::vector<NodePtr> NumToNode;
|
||||
@ -79,68 +94,51 @@ struct SemiNCAInfo {
|
||||
.get();
|
||||
}
|
||||
|
||||
// External storage for depth first iterator that reuses the info lookup map
|
||||
// SemiNCAInfo already has. We don't have a set, but a map instead, so we are
|
||||
// converting the one argument insert calls.
|
||||
struct df_iterator_dom_storage {
|
||||
public:
|
||||
using BaseSet = decltype(NodeToInfo);
|
||||
df_iterator_dom_storage(BaseSet &Storage) : Storage(Storage) {}
|
||||
static bool AlwaysDescend(NodePtr, NodePtr) { return true; }
|
||||
|
||||
using iterator = typename BaseSet::iterator;
|
||||
std::pair<iterator, bool> insert(NodePtr N) {
|
||||
return Storage.insert({N, InfoRec()});
|
||||
// Custom DFS implementation which can skip nodes based on a provided
|
||||
// predicate. It also collects ReverseChildren so that we don't have to spend
|
||||
// time getting predecessors in SemiNCA.
|
||||
template <bool Inverse, typename DescendCondition>
|
||||
unsigned runDFS(NodePtr V, unsigned LastNum, DescendCondition Condition,
|
||||
unsigned AttachToNum) {
|
||||
assert(V);
|
||||
SmallVector<NodePtr, 64> WorkList = {V};
|
||||
if (NodeToInfo.count(V) != 0) NodeToInfo[V].Parent = AttachToNum;
|
||||
|
||||
while (!WorkList.empty()) {
|
||||
const NodePtr BB = WorkList.pop_back_val();
|
||||
auto &BBInfo = NodeToInfo[BB];
|
||||
|
||||
// Visited nodes always have positive DFS numbers.
|
||||
if (BBInfo.DFSNum != 0) continue;
|
||||
BBInfo.DFSNum = BBInfo.Semi = ++LastNum;
|
||||
BBInfo.Label = BB;
|
||||
NumToNode.push_back(BB);
|
||||
|
||||
for (const NodePtr Succ : ChildrenGetter<NodePtr, Inverse>::Get(BB)) {
|
||||
const auto SIT = NodeToInfo.find(Succ);
|
||||
// Don't visit nodes more than once but remember to collect
|
||||
// RerverseChildren.
|
||||
if (SIT != NodeToInfo.end() && SIT->second.DFSNum != 0) {
|
||||
if (Succ != BB) SIT->second.ReverseChildren.push_back(BB);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Condition(BB, Succ)) continue;
|
||||
|
||||
// It's fine to add Succ to the map, because we know that it will be
|
||||
// visited later.
|
||||
auto &SuccInfo = NodeToInfo[Succ];
|
||||
WorkList.push_back(Succ);
|
||||
SuccInfo.Parent = LastNum;
|
||||
SuccInfo.ReverseChildren.push_back(BB);
|
||||
}
|
||||
}
|
||||
void completed(NodePtr) {}
|
||||
|
||||
private:
|
||||
BaseSet &Storage;
|
||||
return LastNum;
|
||||
};
|
||||
|
||||
df_iterator_dom_storage getStorage() { return {NodeToInfo}; }
|
||||
|
||||
unsigned runReverseDFS(NodePtr V, unsigned N) {
|
||||
auto DFStorage = getStorage();
|
||||
|
||||
bool IsChildOfArtificialExit = (N != 0);
|
||||
for (auto I = idf_ext_begin(V, DFStorage), E = idf_ext_end(V, DFStorage);
|
||||
I != E; ++I) {
|
||||
NodePtr BB = *I;
|
||||
auto &BBInfo = NodeToInfo[BB];
|
||||
BBInfo.DFSNum = BBInfo.Semi = ++N;
|
||||
BBInfo.Label = BB;
|
||||
// Set the parent to the top of the visited stack. The stack includes us,
|
||||
// and is 1 based, so we subtract to account for both of these.
|
||||
if (I.getPathLength() > 1)
|
||||
BBInfo.Parent = NodeToInfo[I.getPath(I.getPathLength() - 2)].DFSNum;
|
||||
NumToNode.push_back(BB); // NumToNode[n] = V;
|
||||
|
||||
if (IsChildOfArtificialExit)
|
||||
BBInfo.Parent = 1;
|
||||
|
||||
IsChildOfArtificialExit = false;
|
||||
}
|
||||
return N;
|
||||
}
|
||||
|
||||
unsigned runForwardDFS(NodePtr V, unsigned N) {
|
||||
auto DFStorage = getStorage();
|
||||
|
||||
for (auto I = df_ext_begin(V, DFStorage), E = df_ext_end(V, DFStorage);
|
||||
I != E; ++I) {
|
||||
NodePtr BB = *I;
|
||||
auto &BBInfo = NodeToInfo[BB];
|
||||
BBInfo.DFSNum = BBInfo.Semi = ++N;
|
||||
BBInfo.Label = BB;
|
||||
// Set the parent to the top of the visited stack. The stack includes us,
|
||||
// and is 1 based, so we subtract to account for both of these.
|
||||
if (I.getPathLength() > 1)
|
||||
BBInfo.Parent = NodeToInfo[I.getPath(I.getPathLength() - 2)].DFSNum;
|
||||
NumToNode.push_back(BB); // NumToNode[n] = V;
|
||||
}
|
||||
return N;
|
||||
}
|
||||
|
||||
NodePtr eval(NodePtr VIn, unsigned LastLinked) {
|
||||
auto &VInInfo = NodeToInfo[VIn];
|
||||
if (VInInfo.DFSNum < LastLinked)
|
||||
@ -181,31 +179,14 @@ struct SemiNCAInfo {
|
||||
|
||||
template <typename NodeType>
|
||||
void runSemiNCA(DomTreeT &DT, unsigned NumBlocks) {
|
||||
unsigned N = 0;
|
||||
NumToNode.push_back(nullptr);
|
||||
|
||||
bool MultipleRoots = (DT.Roots.size() > 1);
|
||||
if (MultipleRoots) {
|
||||
auto &BBInfo = NodeToInfo[nullptr];
|
||||
BBInfo.DFSNum = BBInfo.Semi = ++N;
|
||||
BBInfo.Label = nullptr;
|
||||
|
||||
NumToNode.push_back(nullptr); // NumToNode[n] = V;
|
||||
}
|
||||
|
||||
// Step #1: Number blocks in depth-first order and initialize variables used
|
||||
// in later stages of the algorithm.
|
||||
if (DT.isPostDominator()){
|
||||
for (unsigned i = 0, e = static_cast<unsigned>(DT.Roots.size());
|
||||
i != e; ++i)
|
||||
N = runReverseDFS(DT.Roots[i], N);
|
||||
} else {
|
||||
N = runForwardDFS(DT.Roots[0], N);
|
||||
}
|
||||
const unsigned N = doFullDFSWalk(DT, AlwaysDescend);
|
||||
|
||||
// It might be that some blocks did not get a DFS number (e.g., blocks of
|
||||
// infinite loops). In these cases an artificial exit node is required.
|
||||
MultipleRoots |= (DT.isPostDominator() && N != NumBlocks);
|
||||
const bool MultipleRoots =
|
||||
DT.Roots.size() > 1 || (DT.isPostDominator() && N != NumBlocks);
|
||||
|
||||
// Initialize IDoms to spanning tree parents.
|
||||
for (unsigned i = 1; i <= N; ++i) {
|
||||
@ -221,7 +202,7 @@ struct SemiNCAInfo {
|
||||
|
||||
// Initialize the semi dominator to point to the parent node.
|
||||
WInfo.Semi = WInfo.Parent;
|
||||
for (const auto &N : inverse_children<NodeType>(W))
|
||||
for (const auto &N : WInfo.ReverseChildren)
|
||||
if (NodeToInfo.count(N)) { // Only if this predecessor is reachable!
|
||||
unsigned SemiU = NodeToInfo[eval(N, i + 1)].Semi;
|
||||
if (SemiU < WInfo.Semi)
|
||||
@ -279,14 +260,27 @@ struct SemiNCAInfo {
|
||||
}
|
||||
}
|
||||
|
||||
void doFullDFSWalk(const DomTreeT &DT) {
|
||||
NumToNode.push_back(nullptr);
|
||||
template <typename DescendCondition>
|
||||
unsigned doFullDFSWalk(const DomTreeT &DT, DescendCondition DC) {
|
||||
unsigned Num = 0;
|
||||
for (auto *Root : DT.Roots)
|
||||
if (!DT.isPostDominator())
|
||||
Num = runForwardDFS(Root, Num);
|
||||
else
|
||||
Num = runReverseDFS(Root, Num);
|
||||
NumToNode.push_back(nullptr);
|
||||
|
||||
if (DT.Roots.size() > 1) {
|
||||
auto &BBInfo = NodeToInfo[nullptr];
|
||||
BBInfo.DFSNum = BBInfo.Semi = ++Num;
|
||||
BBInfo.Label = nullptr;
|
||||
|
||||
NumToNode.push_back(nullptr); // NumToNode[n] = V;
|
||||
}
|
||||
|
||||
if (DT.isPostDominator()) {
|
||||
for (auto *Root : DT.Roots) Num = runDFS<true>(Root, Num, DC, 1);
|
||||
} else {
|
||||
assert(DT.Roots.size() == 1);
|
||||
Num = runDFS<false>(DT.Roots[0], Num, DC, Num);
|
||||
}
|
||||
|
||||
return Num;
|
||||
}
|
||||
|
||||
static void PrintBlockOrNullptr(raw_ostream &O, NodePtr Obj) {
|
||||
@ -299,7 +293,7 @@ struct SemiNCAInfo {
|
||||
// Checks if the tree contains all reachable nodes in the input graph.
|
||||
bool verifyReachability(const DomTreeT &DT) {
|
||||
clear();
|
||||
doFullDFSWalk(DT);
|
||||
doFullDFSWalk(DT, AlwaysDescend);
|
||||
|
||||
for (auto &NodeToTN : DT.DomTreeNodes) {
|
||||
const TreeNodePtr TN = NodeToTN.second.get();
|
||||
@ -356,7 +350,7 @@ struct SemiNCAInfo {
|
||||
// NCD(From, To) == IDom(To) or To.
|
||||
bool verifyNCD(const DomTreeT &DT) {
|
||||
clear();
|
||||
doFullDFSWalk(DT);
|
||||
doFullDFSWalk(DT, AlwaysDescend);
|
||||
|
||||
for (auto &BlockToInfo : NodeToInfo) {
|
||||
auto &Info = BlockToInfo.second;
|
||||
@ -440,8 +434,9 @@ struct SemiNCAInfo {
|
||||
if (!BB || TN->getChildren().empty()) continue;
|
||||
|
||||
clear();
|
||||
NodeToInfo.insert({BB, {}});
|
||||
doFullDFSWalk(DT);
|
||||
doFullDFSWalk(DT, [BB](NodePtr From, NodePtr To) {
|
||||
return From != BB && To != BB;
|
||||
});
|
||||
|
||||
for (TreeNodePtr Child : TN->getChildren())
|
||||
if (NodeToInfo.count(Child->getBlock()) != 0) {
|
||||
@ -473,8 +468,10 @@ struct SemiNCAInfo {
|
||||
const auto &Siblings = TN->getChildren();
|
||||
for (const TreeNodePtr N : Siblings) {
|
||||
clear();
|
||||
NodeToInfo.insert({N->getBlock(), {}});
|
||||
doFullDFSWalk(DT);
|
||||
NodePtr BBN = N->getBlock();
|
||||
doFullDFSWalk(DT, [BBN](NodePtr From, NodePtr To) {
|
||||
return From != BBN && To != BBN;
|
||||
});
|
||||
|
||||
for (const TreeNodePtr S : Siblings) {
|
||||
if (S == N) continue;
|
||||
|
Loading…
Reference in New Issue
Block a user