#include #include #include #include #include "API/ExportDef.h" namespace Dna::API { inline bool alreadyOnStackQuick(std::set& StackSet, llvm::BasicBlock* Node) { if (StackSet.count(Node)) { return true; } else { return false; } } using Edge = std::pair; using Stack = std::vector>; // Helper function to find all nodes on paths between a source and a target // node DNA_EXPORT ImmutableManagedVector* FindReachableNodes(llvm::BasicBlock* Source, llvm::BasicBlock* Target) { // The node starting the exploration should always exist (the same does not // hold for the target node). assert(Source != nullptr); // Add to the Targets set the original target node, if we actually have a // target node as a parameter. std::set Targets; if (Target != nullptr) Targets.insert(Target); // Exploration stack initialization. Stack Stack; std::set StackSet; Stack.push_back(std::make_pair(Source, 0)); // Visited nodes to avoid entering in a loop. std::set VisitedEdges; // Additional data structure to keep nodes that need to be added only if a // certain node will be added to the set of reachable nodes. std::map> AdditionalNodes; // Exploration. while (!Stack.empty()) { auto StackElem = Stack.back(); Stack.pop_back(); llvm::BasicBlock* Vertex = StackElem.first; if (StackElem.second == 0) { // Stop condition for the exploration. If a `Target` is provided, then we // can only stop once we hit a node in `Targets`. If, instead, no `Target` // is provided, we must also stop at a node that has no successors (which, // usually, means that we invoked the helper function on a graph where we // computed a filtered post dominator tree, and the `nullptr` passed as // argument represents exactly the `VirtualRoot` node which acts as a sink // needed for the tree computation. if ((Targets.count(Vertex) != 0) || (Target == nullptr && Vertex->getTerminator()->getNumSuccessors() == 0)) { for (auto StackE : Stack) { Targets.insert(StackE.first); } continue; } else if (alreadyOnStackQuick(StackSet, Vertex)) { // Add all the nodes on the stack to the set of additional nodes. std::set& AdditionalSet = AdditionalNodes[Vertex]; for (auto StackE : Stack) { AdditionalSet.insert(StackE.first); } continue; } } StackSet.insert(Vertex); size_t Index = StackElem.second; if (Index < StackElem.first->getTerminator()->getNumSuccessors()) { llvm::BasicBlock* NextSuccessor = Vertex->getTerminator()->getSuccessor(Index); Index++; Stack.push_back(std::make_pair(Vertex, Index)); if (VisitedEdges.count(std::make_pair(Vertex, NextSuccessor)) == 0 && NextSuccessor != Source && !alreadyOnStackQuick(StackSet, NextSuccessor)) { Stack.push_back(std::make_pair(NextSuccessor, 0)); VisitedEdges.insert(std::make_pair(Vertex, NextSuccessor)); } } else { StackSet.erase(Vertex); } } // Add additional nodes. std::set OldTargets; do { // At each iteration obtain a copy of the old set, so that we are able to // exit from the loop as soon no change is made to the `Targets` set. OldTargets = Targets; // Temporary storage for the nodes to add at each iteration, to avoid // invalidation on the `Targets` set. std::set NodesToAdd; for (llvm::BasicBlock* Node : Targets) { std::set& AdditionalSet = AdditionalNodes[Node]; NodesToAdd.insert(AdditionalSet.begin(), AdditionalSet.end()); } // Add all the additional nodes found in this step. Targets.insert(NodesToAdd.begin(), NodesToAdd.end()); NodesToAdd.clear(); } while (Targets != OldTargets); auto vec = new std::vector(); for (auto tgt : Targets) vec->push_back(tgt); return ImmutableManagedVector::NonCopyingFrom(vec); } }