#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #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 inline llvm::SmallPtrSet nodesBetweenImpl(NodeRef Source, NodeRef Destination, const llvm::SmallPtrSetImpl *IgnoreList) { using Iterator = typename GT::ChildIteratorType; using NodeSet = llvm::SmallPtrSet; 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 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 inline llvm::SmallPtrSet nodesBetween(G Source, G Destination, const llvm::SmallPtrSetImpl *IgnoreList = nullptr) { return nodesBetweenImpl>(Source, Destination, IgnoreList); } template inline llvm::SmallPtrSet nodesBetweenReverse(G Source, G Destination, const llvm::SmallPtrSetImpl *IgnoreList = nullptr) { using namespace llvm; return nodesBetweenImpl>>(Source, Destination, IgnoreList); } template struct scc_iterator_traits { using iterator = llvm::scc_iterator>; using iterator_category = std::forward_iterator_tag; using reference = decltype(*llvm::scc_begin((T) nullptr)); using value_type = std::remove_reference_t; using pointer = value_type *; using difference_type = size_t; }; template auto exitless_scc_range(NodeTy Entry) { using namespace llvm; auto Range = make_range(scc_begin(Entry), scc_end(Entry)); using NodesVector = std::vector; using GT = llvm::GraphTraits; auto Filter = [](const NodesVector &SCC) { std::set 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); }