mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
199 lines
5.2 KiB
C++
199 lines
5.2 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
#include "llvm/ADT/GraphTraits.h"
|
|
#include "llvm/ADT/SCCIterator.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
#include "revng/Support/Debug.h"
|
|
|
|
template<typename GT, typename NodeRef = typename GT::NodeRef>
|
|
inline llvm::SmallPtrSet<NodeRef, 4>
|
|
nodesBetweenImpl(NodeRef Source,
|
|
NodeRef Destination,
|
|
const llvm::SmallPtrSetImpl<NodeRef> *IgnoreList) {
|
|
|
|
using Iterator = typename GT::ChildIteratorType;
|
|
using NodeSet = llvm::SmallPtrSet<NodeRef, 4>;
|
|
|
|
auto HasSuccessors = [](const NodeRef Node) {
|
|
return GT::child_begin(Node) != GT::child_end(Node);
|
|
};
|
|
|
|
// Ensure Source has at least one successor
|
|
if (not HasSuccessors(Source)) {
|
|
if (Source == Destination)
|
|
return { Source };
|
|
else
|
|
return {};
|
|
}
|
|
|
|
NodeSet Selected = { Destination };
|
|
NodeSet VisitedNodes;
|
|
|
|
struct StackEntry {
|
|
StackEntry(NodeRef Node) :
|
|
Node(Node),
|
|
Set({ Node }),
|
|
NextSuccessorIt(GT::child_begin(Node)),
|
|
EndSuccessorIt(GT::child_end(Node)) {}
|
|
|
|
NodeRef Node;
|
|
NodeSet Set;
|
|
Iterator NextSuccessorIt;
|
|
Iterator EndSuccessorIt;
|
|
};
|
|
std::vector<StackEntry> Stack;
|
|
|
|
Stack.emplace_back(Source);
|
|
|
|
while (not Stack.empty()) {
|
|
StackEntry *Entry = &Stack.back();
|
|
|
|
NodeRef CurrentSuccessor = *Entry->NextSuccessorIt;
|
|
|
|
bool Visited = (VisitedNodes.count(CurrentSuccessor) != 0);
|
|
VisitedNodes.insert(CurrentSuccessor);
|
|
|
|
if (Selected.count(CurrentSuccessor) != 0) {
|
|
|
|
// We reached a selected node, select all the nodes on the stack
|
|
for (const StackEntry &E : Stack) {
|
|
Selected.insert(E.Set.begin(), E.Set.end());
|
|
}
|
|
|
|
} else if (Visited) {
|
|
// We already visited this node, do not proceed in this direction
|
|
|
|
auto End = Stack.end();
|
|
auto IsCurrent = [CurrentSuccessor](const StackEntry &E) {
|
|
return E.Set.count(CurrentSuccessor) != 0;
|
|
};
|
|
auto It = std::find_if(Stack.begin(), End, IsCurrent);
|
|
bool IsAlreadyOnStack = It != End;
|
|
|
|
if (IsAlreadyOnStack) {
|
|
// It's already on the stack, insert all those on stack until the top
|
|
StackEntry &Target = *It;
|
|
Target.Set.insert(CurrentSuccessor);
|
|
++It;
|
|
for (const StackEntry &E : llvm::make_range(It, End)) {
|
|
Target.Set.insert(E.Set.begin(), E.Set.end());
|
|
}
|
|
}
|
|
|
|
} else if (IgnoreList != nullptr
|
|
and IgnoreList->count(CurrentSuccessor) != 0) {
|
|
// Ignore
|
|
} else {
|
|
|
|
// We never visited this node, proceed to its successors, if any
|
|
if (HasSuccessors(CurrentSuccessor)) {
|
|
revng_assert(CurrentSuccessor != nullptr);
|
|
Stack.emplace_back(CurrentSuccessor);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
bool TryNext = false;
|
|
do {
|
|
// Move to the next successor
|
|
++Entry->NextSuccessorIt;
|
|
|
|
// Are we done with this entry?
|
|
TryNext = (Entry->NextSuccessorIt == Entry->EndSuccessorIt);
|
|
|
|
if (TryNext) {
|
|
// Pop from the stack
|
|
Stack.pop_back();
|
|
|
|
// If there's another element process it
|
|
if (Stack.size() == 0) {
|
|
TryNext = false;
|
|
} else {
|
|
Entry = &Stack.back();
|
|
}
|
|
}
|
|
|
|
} while (TryNext);
|
|
}
|
|
|
|
return Selected;
|
|
}
|
|
|
|
template<class G>
|
|
inline llvm::SmallPtrSet<G, 4>
|
|
nodesBetween(G Source,
|
|
G Destination,
|
|
const llvm::SmallPtrSetImpl<G> *IgnoreList = nullptr) {
|
|
return nodesBetweenImpl<llvm::GraphTraits<G>>(Source,
|
|
Destination,
|
|
IgnoreList);
|
|
}
|
|
|
|
template<class G>
|
|
inline llvm::SmallPtrSet<G, 4>
|
|
nodesBetweenReverse(G Source,
|
|
G Destination,
|
|
const llvm::SmallPtrSetImpl<G> *IgnoreList = nullptr) {
|
|
using namespace llvm;
|
|
return nodesBetweenImpl<GraphTraits<Inverse<G>>>(Source,
|
|
Destination,
|
|
IgnoreList);
|
|
}
|
|
|
|
template<typename T>
|
|
struct scc_iterator_traits {
|
|
using iterator = llvm::scc_iterator<T, llvm::GraphTraits<T>>;
|
|
using iterator_category = std::forward_iterator_tag;
|
|
using reference = decltype(*llvm::scc_begin((T) nullptr));
|
|
using value_type = std::remove_reference_t<reference>;
|
|
using pointer = value_type *;
|
|
using difference_type = size_t;
|
|
};
|
|
|
|
template<typename NodeTy>
|
|
auto exitless_scc_range(NodeTy Entry) {
|
|
using namespace llvm;
|
|
|
|
auto Range = make_range(scc_begin(Entry), scc_end(Entry));
|
|
|
|
using NodesVector = std::vector<NodeTy>;
|
|
using GT = llvm::GraphTraits<NodeTy>;
|
|
|
|
auto Filter = [](const NodesVector &SCC) {
|
|
std::set<NodeTy> SCCNodes;
|
|
SCCNodes.clear();
|
|
for (NodeTy BB : SCC)
|
|
SCCNodes.insert(BB);
|
|
|
|
bool HasExit = false;
|
|
bool AtLeastOneEdge = false;
|
|
for (NodeTy BB : SCC) {
|
|
auto Successors = make_range(GT::child_begin(BB), GT::child_end(BB));
|
|
for (NodeTy Successor : Successors) {
|
|
AtLeastOneEdge = true;
|
|
if (SCCNodes.count(Successor) == 0) {
|
|
HasExit = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (HasExit)
|
|
break;
|
|
}
|
|
|
|
return (not HasExit) and AtLeastOneEdge;
|
|
};
|
|
|
|
return make_filter_range(Range, Filter);
|
|
}
|