#pragma once // // Copyright rev.ng Labs Srl. See LICENSE.md for details. // #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/GraphTraits.h" #include "revng/ADT/GeneratorIterator.h" #include "revng/RestructureCFG/ScopeGraphUtils.h" // We use a template here in order to instantiate `BlockType` both as // `BasicBlock *` and `const BasicBlock *` template inline cppcoro::generator getNextScopeGraphSuccessor(BlockType BB) { // First of all, we return all the standard successors of `BB`, but only if // the current block does not contain the `goto_block` marker. If that is the // case, since we have the constraint that a `goto_block` can only exists in // a block with a single successor (which is the `goto` target). if (not isGotoBlock(BB)) { for (auto *Successor : successors(BB)) { co_yield Successor; } } // We then move to returning the additional successor represented by the // `ScopeCloser` edge, if present at all BlockType ScopeCloserTarget = getScopeCloserTarget(BB); if (ScopeCloserTarget) { co_yield ScopeCloserTarget; } co_return; } /// This class is used as a marker class to tell the graph iterator to treat the /// underlying graph as a scope graph, i.e., considering also the scope closer /// edges as actual edges, and ignoring the goto edges template struct Scope { const GraphType &Graph; inline Scope(const GraphType &G) : Graph(G) {} }; /// Specializes `GraphTraits>` template<> struct llvm::GraphTraits> { public: using NodeRef = llvm::BasicBlock *; using ChildIteratorType = GeneratorIterator; public: static ChildIteratorType child_begin(NodeRef N) { return GeneratorIterator(getNextScopeGraphSuccessor(N)); } static ChildIteratorType child_end(NodeRef N) { return GeneratorIterator(); } // In the implementation for `llvm::BasicBlock *` trait we simply return // `this` static NodeRef getEntryNode(Scope N) { return N.Graph; } // Add a verify method to the trait which checks that we have at maximum one // occurrence of the marker call in each `BasicBlock`, in the correct position static void verify(NodeRef N) { verifyScopeGraphAnnotations(N); } }; template<> struct llvm::GraphTraits> { public: using NodeRef = const llvm::BasicBlock *; using ChildIteratorType = GeneratorIterator; public: static ChildIteratorType child_begin(NodeRef N) { return GeneratorIterator< const llvm::BasicBlock *>(getNextScopeGraphSuccessor(N)); } static ChildIteratorType child_end(NodeRef N) { return GeneratorIterator(); } // In the implementation for `llvm::BasicBlock *` trait we simply return // `this` static NodeRef getEntryNode(Scope N) { return N.Graph; } // Add a verify method to the trait which checks that we have at maximum one // occurrence of the marker call in each `BasicBlock`, in the correct position static void verify(NodeRef N) { verifyScopeGraphAnnotations(N); } }; template<> struct llvm::GraphTraits> : public llvm::GraphTraits> { using NodeRef = llvm::BasicBlock *; using nodes_iterator = pointer_iterator; static NodeRef getEntryNode(Scope G) { return &G.Graph->getEntryBlock(); } static nodes_iterator nodes_begin(Scope G) { return nodes_iterator(G.Graph->begin()); } static nodes_iterator nodes_end(Scope G) { return nodes_iterator(G.Graph->end()); } static size_t size(Scope G) { return G.Graph->size(); } // Add a verify method to the trait which invokes the `verify` of the // `BasicBlock *` trait for each node in the graph static void verify(Scope G) { for (auto &N : *G.Graph) { llvm::GraphTraits>::verify(&N); } } }; template<> struct llvm::GraphTraits> : public llvm::GraphTraits> { using NodeRef = const llvm::BasicBlock *; using nodes_iterator = pointer_iterator; static NodeRef getEntryNode(Scope G) { return &G.Graph->getEntryBlock(); } static nodes_iterator nodes_begin(Scope G) { return nodes_iterator(G.Graph->begin()); } static nodes_iterator nodes_end(Scope G) { return nodes_iterator(G.Graph->end()); } static size_t size(Scope G) { return G.Graph->size(); } // Add a verify method to the trait which invokes the `verify` of the // `BasicBlock *` trait for each node in the graph static void verify(Scope G) { for (auto &N : *G.Graph) { llvm::GraphTraits>::verify(&N); } } }; // Debug function used dump a serialized representation of the `ScopeGraph` on a // stream debug_function inline void dumpScopeGraph(llvm::Function &F) { llvm::dbgs() << "ScopeGraph of function: " << F.getName().str() << "\n"; for (llvm::BasicBlock &BB : F) { llvm::dbgs() << "Block " << BB.getName().str() << " successors:\n"; for (auto *Succ : llvm::children>(&BB)) { llvm::dbgs() << " " << Succ->getName().str() << "\n"; } } // Iteration on the whole graph using a `llvm::depth_first` visit llvm::dbgs() << "Depth first order:\n"; for (auto *DFSNode : llvm::depth_first(Scope(&F))) { llvm::dbgs() << DFSNode->getName().str() << "\n"; } }