#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/BasicBlock.h" #include "revng/Support/Assert.h" #include "revng/Support/Debug.h" // Forward declarations template class RegionCFG; /// Graph Node, representing a basic block template class BasicBlockNode { protected: using BasicBlockNodeMap = std::map; public: enum class Type { Code, Empty, Break, Continue, EntrySet, ExitSet, Collapsed, EntryDispatcher, ExitDispatcher, Tile, }; using BasicBlockNodeT = BasicBlockNode; using BBNodeSet = std::set *>; using BBNodeMap = std::map; using RegionCFGT = RegionCFG; // EdgeDescriptor is a handy way to create and manipulate edges on the // RegionCFG. using EdgeDescriptor = std::pair; using edge_label_t = llvm::SmallSet; // The `EdgeInfo` struct is devoted to contain additional info for the edges, // that may come handy during the control flow processing. struct EdgeInfo { // In this field, the labels associated to an edge are stored. edge_label_t Labels; // This field of the struct represent the fact that on this edge, we have an // inlinable path. This means that, the edge dominates all nodes reachable // from the edge on all the possible paths going towards all the exit nodes // reachable from the edge. Therefore, this edges can be excluded from the // computation of the postdominator tree, since they can be emitted // completely as body of the `then`/`else` branches. bool Inlined = false; // Spaceship operator for struct comparison. auto operator<=>(const EdgeInfo &) const = default; }; using node_edgeinfo_pair = std::pair; using links_container = llvm::SmallVector; using links_iterator = typename links_container::iterator; using links_const_iterator = typename links_container::const_iterator; using links_range = llvm::iterator_range; using links_const_range = llvm::iterator_range; protected: static BasicBlockNodeT *&getChild(node_edgeinfo_pair &P) { return P.first; } static BasicBlockNodeT *const &getCChild(const node_edgeinfo_pair &P) { return P.first; } public: using child_iterator = llvm::mapped_iterator; using child_const_iterator = llvm::mapped_iterator; using child_range = llvm::iterator_range; using child_const_range = llvm::iterator_range; protected: /// Unique Node Id inside a RegionCFG, useful for printing to graphviz unsigned ID; /// Pointer to the parent RegionCFG RegionCFGT *Parent = nullptr; /// Reference to the corresponding collapsed region // // This is nullptr unless the BasicBlockNode represents a collapsed // RegionCFG RegionCFGT *CollapsedRegion = nullptr; /// Flag to identify the exit type of a block Type NodeType; /// Name of the basic block. llvm::SmallString<32> Name; unsigned StateVariableValue; /// List of successors links_container Successors; /// List of predecessors links_container Predecessors; // Original object pointer NodeT OriginalNode; // Flag for nodes that were created by weaving switches bool Weaved; explicit BasicBlockNode(RegionCFGT *Parent, NodeT OriginalNode, RegionCFGT *Collapsed, llvm::StringRef Name, Type T, unsigned StateVariableVal = 0); public: BasicBlockNode() = delete; BasicBlockNode(const BasicBlockNode &BBN) = delete; BasicBlockNode &operator=(const BasicBlockNode &BBN) = delete; BasicBlockNode(BasicBlockNode &&BBN) = delete; BasicBlockNode &operator=(BasicBlockNode &&BBN) = delete; /// Copy ctor: clone the node in the same Parent with new ID and without edges explicit BasicBlockNode(const BasicBlockNode &BBN, RegionCFGT *Parent) : BasicBlockNode(Parent, BBN.OriginalNode, BBN.CollapsedRegion, BBN.Name, BBN.NodeType, BBN.StateVariableValue) {} /// Constructor for nodes pointing to LLVM IR BasicBlock explicit BasicBlockNode(RegionCFGT *Parent, NodeT OriginalNode, llvm::StringRef Name = "") : BasicBlockNode(Parent, OriginalNode, nullptr, Name, Type::Code) {} /// Constructor for nodes representing collapsed subgraphs explicit BasicBlockNode(RegionCFGT *Parent, RegionCFGT *Collapsed) : BasicBlockNode(Parent, nullptr, Collapsed, "collapsed", Type::Collapsed) {} /// Constructor for empty dummy nodes and for entry/exit dispatcher explicit BasicBlockNode(RegionCFG *Parent, llvm::StringRef Name, Type T) : BasicBlockNode(Parent, nullptr, nullptr, Name, T) { revng_assert(T == Type::Empty or T == Type::Break or T == Type::Continue or T == Type::EntryDispatcher or T == Type::ExitDispatcher or T == Type::Tile); } /// Constructor for dummy nodes that handle the state variable explicit BasicBlockNode(RegionCFGT *Parent, llvm::StringRef Name, Type T, unsigned Value) : BasicBlockNode(Parent, nullptr, nullptr, Name, T, Value) { revng_assert(T == Type::EntrySet or T == Type::ExitSet); } public: bool isBreak() const { return NodeType == Type::Break; } bool isContinue() const { return NodeType == Type::Continue; } bool isSet() const { return NodeType == Type::EntrySet or NodeType == Type::ExitSet; } bool isCode() const { return NodeType == Type::Code; } bool isEmpty() const { return NodeType == Type::Empty; } bool isArtificial() const { return NodeType != Type::Code and NodeType != Type::Collapsed; } bool isDispatcher() const { return NodeType == Type::EntryDispatcher or NodeType == Type::ExitDispatcher; } bool isTile() const { return NodeType == Type::Tile; } Type getNodeType() const { return NodeType; } unsigned getStateVariableValue() const { revng_assert(isSet()); return StateVariableValue; } RegionCFGT *getParent() { return Parent; } void setParent(RegionCFGT *P) { Parent = P; } // TODO: Check why this implementation is really necessary. void printAsOperand(llvm::raw_ostream &O, bool /* PrintType */) const; void addLabeledSuccessor(const node_edgeinfo_pair &P) { revng_assert(not hasSuccessor(P.first)); Successors.push_back(P); } void addLabeledSuccessor(node_edgeinfo_pair &&P) { revng_assert(not hasSuccessor(P.first)); Successors.push_back(std::move(P)); } void addUnlabeledSuccessor(BasicBlockNode *Successor) { addLabeledSuccessor(std::make_pair(Successor, EdgeInfo())); } bool hasSuccessor(const BasicBlockNode *Candidate) const { const auto First = [](const auto &Pair) { return Pair.first; }; auto BBRange = llvm::map_range(Successors, First); const auto Find = [](const auto &Range, const auto *C) { return std::find(Range.begin(), Range.end(), C) != Range.end(); }; return Find(BBRange, Candidate); } void removeSuccessor(BasicBlockNode *Successor); node_edgeinfo_pair extractSuccessorEdge(BasicBlockNode *Successor); const node_edgeinfo_pair & getSuccessorEdge(const BasicBlockNode *Successor) const; node_edgeinfo_pair &getSuccessorEdge(BasicBlockNode *Successor); void addLabeledPredecessor(const node_edgeinfo_pair &P) { revng_assert(not hasPredecessor(P.first)); Predecessors.push_back(P); } void addUnlabeledPredecessor(BasicBlockNode *Predecessor) { addLabeledPredecessor(std::make_pair(Predecessor, EdgeInfo())); } bool hasPredecessor(BasicBlockNode *Candidate) const { const auto First = [](const auto &Pair) { return Pair.first; }; auto BBRange = llvm::map_range(Predecessors, First); const auto Find = [](const auto &Range, const auto *C) { return std::find(Range.begin(), Range.end(), C) != Range.end(); }; return Find(BBRange, Candidate); } void removePredecessor(BasicBlockNode *Successor); node_edgeinfo_pair extractPredecessorEdge(BasicBlockNode *Predecessor); const node_edgeinfo_pair & getPredecessorEdge(const BasicBlockNode *Predecessor) const; node_edgeinfo_pair &getPredecessorEdge(BasicBlockNode *Predecessor); void updatePointers(const BasicBlockNodeMap &SubstitutionMap); size_t successor_size() const { return Successors.size(); } links_const_range labeled_successors() const { return llvm::make_range(Successors.begin(), Successors.end()); } links_range labeled_successors() { return llvm::make_range(Successors.begin(), Successors.end()); } child_const_range successors() const { return llvm::map_range(labeled_successors(), &getCChild); } child_range successors() { return llvm::map_range(labeled_successors(), &getChild); } BasicBlockNode *getSuccessorI(size_t i) const { return Successors[i].first; } size_t predecessor_size() const { return Predecessors.size(); } links_const_range labeled_predecessors() const { return llvm::make_range(Predecessors.begin(), Predecessors.end()); } links_range labeled_predecessors() { return llvm::make_range(Predecessors.begin(), Predecessors.end()); } child_const_range predecessors() const { return llvm::map_range(labeled_predecessors(), &getCChild); } child_range predecessors() { return llvm::map_range(labeled_predecessors(), &getChild); } BasicBlockNode *getUniquePredecessor() const { revng_assert(Predecessors.size() == 1); return Predecessors[0].first; } unsigned getID() const { return ID; } bool isBasicBlock() const { return NodeType == Type::Code; } NodeT getOriginalNode() const { revng_assert(isCode() and nullptr != OriginalNode); return OriginalNode; } llvm::StringRef getName() const; std::string getNameStr() const { return "ID:" + std::to_string(getID()) + " " + getName().str(); } void setName(llvm::StringRef N) { Name = N; } bool isCollapsed() const { return NodeType == Type::Collapsed; } RegionCFGT *getCollapsedCFG() const { revng_assert(isCollapsed()); return CollapsedRegion; } std::string getCollapsedRegionName() const { revng_assert(isCollapsed()); return CollapsedRegion->getRegionName(); } bool isEquivalentTo(BasicBlockNode *) const; /// Obtain a estimate of the weight of a BasicBlockNode in terms of /// original instructions. size_t getWeight() const; bool isWeaved() const { return Weaved; } void setWeaved(bool Val) { Weaved = Val; } Type getDispatcherType() const { revng_assert(isDispatcher() or isSet()); return NodeType; } }; // Provide graph traits for usage with, e.g., llvm::ReversePostOrderTraversal namespace llvm { template struct GraphTraits *> { using BBNodeT = BasicBlockNode; using NodeRef = BBNodeT *; using EdgeRef = typename BBNodeT::node_edgeinfo_pair; using ChildIteratorType = typename BBNodeT::child_iterator; using ChildEdgeIteratorType = typename BBNodeT::links_iterator; static NodeRef getEntryNode(NodeRef N) { return N; } static inline ChildIteratorType child_begin(NodeRef N) { return N->successors().begin(); } static inline ChildIteratorType child_end(NodeRef N) { return N->successors().end(); } static inline ChildEdgeIteratorType child_edge_begin(NodeRef N) { return N->labeled_successors().begin(); } static inline ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->labeled_successors().end(); } static inline NodeRef edge_dest(EdgeRef E) { return E.first; }; }; template struct GraphTraits *>> { using BBNodeT = BasicBlockNode; using NodeRef = BBNodeT *; using EdgeRef = typename BBNodeT::node_edgeinfo_pair; using ChildIteratorType = typename BBNodeT::child_iterator; using ChildEdgeIteratorType = typename BBNodeT::links_iterator; static NodeRef getEntryNode(Inverse G) { return G.Graph; } static inline ChildIteratorType child_begin(NodeRef N) { return N->predecessors().begin(); } static inline ChildIteratorType child_end(NodeRef N) { return N->predecessors().end(); } static inline ChildEdgeIteratorType child_edge_begin(NodeRef N) { return N->labeled_predecessors().begin(); } static inline ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->labeled_predecessors().end(); } static inline NodeRef edge_dest(EdgeRef E) { return E.first; }; }; } // namespace llvm