18bcb0991SDimitry Andric //===- llvm/Analysis/DependenceGraphBuilder.h -------------------*- C++ -*-===// 28bcb0991SDimitry Andric // 38bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 48bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 58bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 68bcb0991SDimitry Andric // 78bcb0991SDimitry Andric //===----------------------------------------------------------------------===// 88bcb0991SDimitry Andric // 98bcb0991SDimitry Andric // This file defines a builder interface that can be used to populate dependence 108bcb0991SDimitry Andric // graphs such as DDG and PDG. 118bcb0991SDimitry Andric // 128bcb0991SDimitry Andric //===----------------------------------------------------------------------===// 138bcb0991SDimitry Andric 14fe6060f1SDimitry Andric #ifndef LLVM_ANALYSIS_DEPENDENCEGRAPHBUILDER_H 15fe6060f1SDimitry Andric #define LLVM_ANALYSIS_DEPENDENCEGRAPHBUILDER_H 168bcb0991SDimitry Andric 175ffd83dbSDimitry Andric #include "llvm/ADT/DenseMap.h" 188bcb0991SDimitry Andric #include "llvm/ADT/EquivalenceClasses.h" 195ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h" 208bcb0991SDimitry Andric 218bcb0991SDimitry Andric namespace llvm { 228bcb0991SDimitry Andric 235ffd83dbSDimitry Andric class BasicBlock; 245ffd83dbSDimitry Andric class DependenceInfo; 255ffd83dbSDimitry Andric class Instruction; 265ffd83dbSDimitry Andric 278bcb0991SDimitry Andric /// This abstract builder class defines a set of high-level steps for creating 288bcb0991SDimitry Andric /// DDG-like graphs. The client code is expected to inherit from this class and 298bcb0991SDimitry Andric /// define concrete implementation for each of the pure virtual functions used 308bcb0991SDimitry Andric /// in the high-level algorithm. 318bcb0991SDimitry Andric template <class GraphType> class AbstractDependenceGraphBuilder { 328bcb0991SDimitry Andric protected: 338bcb0991SDimitry Andric using BasicBlockListType = SmallVectorImpl<BasicBlock *>; 348bcb0991SDimitry Andric 358bcb0991SDimitry Andric private: 368bcb0991SDimitry Andric using NodeType = typename GraphType::NodeType; 378bcb0991SDimitry Andric using EdgeType = typename GraphType::EdgeType; 388bcb0991SDimitry Andric 398bcb0991SDimitry Andric public: 408bcb0991SDimitry Andric using ClassesType = EquivalenceClasses<BasicBlock *>; 418bcb0991SDimitry Andric using NodeListType = SmallVector<NodeType *, 4>; 428bcb0991SDimitry Andric AbstractDependenceGraphBuilder(GraphType & G,DependenceInfo & D,const BasicBlockListType & BBs)438bcb0991SDimitry Andric AbstractDependenceGraphBuilder(GraphType &G, DependenceInfo &D, 448bcb0991SDimitry Andric const BasicBlockListType &BBs) 458bcb0991SDimitry Andric : Graph(G), DI(D), BBList(BBs) {} 461fd87a68SDimitry Andric virtual ~AbstractDependenceGraphBuilder() = default; 478bcb0991SDimitry Andric 488bcb0991SDimitry Andric /// The main entry to the graph construction algorithm. It starts by 498bcb0991SDimitry Andric /// creating nodes in increasing order of granularity and then 50480093f4SDimitry Andric /// adds def-use and memory edges. As one of the final stages, it 51480093f4SDimitry Andric /// also creates pi-block nodes to facilitate codegen in transformations 52480093f4SDimitry Andric /// that use dependence graphs. 538bcb0991SDimitry Andric /// 548bcb0991SDimitry Andric /// The algorithmic complexity of this implementation is O(V^2 * I^2), where V 558bcb0991SDimitry Andric /// is the number of vertecies (nodes) and I is the number of instructions in 568bcb0991SDimitry Andric /// each node. The total number of instructions, N, is equal to V * I, 578bcb0991SDimitry Andric /// therefore the worst-case time complexity is O(N^2). The average time 588bcb0991SDimitry Andric /// complexity is O((N^2)/2). populate()598bcb0991SDimitry Andric void populate() { 60480093f4SDimitry Andric computeInstructionOrdinals(); 618bcb0991SDimitry Andric createFineGrainedNodes(); 628bcb0991SDimitry Andric createDefUseEdges(); 638bcb0991SDimitry Andric createMemoryDependencyEdges(); 645ffd83dbSDimitry Andric simplify(); 658bcb0991SDimitry Andric createAndConnectRootNode(); 66480093f4SDimitry Andric createPiBlocks(); 67480093f4SDimitry Andric sortNodesTopologically(); 688bcb0991SDimitry Andric } 698bcb0991SDimitry Andric 70480093f4SDimitry Andric /// Compute ordinal numbers for each instruction and store them in a map for 71480093f4SDimitry Andric /// future look up. These ordinals are used to compute node ordinals which are 72480093f4SDimitry Andric /// in turn used to order nodes that are part of a cycle. 73480093f4SDimitry Andric /// Instruction ordinals are assigned based on lexical program order. 74480093f4SDimitry Andric void computeInstructionOrdinals(); 75480093f4SDimitry Andric 768bcb0991SDimitry Andric /// Create fine grained nodes. These are typically atomic nodes that 778bcb0991SDimitry Andric /// consist of a single instruction. 788bcb0991SDimitry Andric void createFineGrainedNodes(); 798bcb0991SDimitry Andric 808bcb0991SDimitry Andric /// Analyze the def-use chains and create edges from the nodes containing 818bcb0991SDimitry Andric /// definitions to the nodes containing the uses. 828bcb0991SDimitry Andric void createDefUseEdges(); 838bcb0991SDimitry Andric 848bcb0991SDimitry Andric /// Analyze data dependencies that exist between memory loads or stores, 858bcb0991SDimitry Andric /// in the graph nodes and create edges between them. 868bcb0991SDimitry Andric void createMemoryDependencyEdges(); 878bcb0991SDimitry Andric 888bcb0991SDimitry Andric /// Create a root node and add edges such that each node in the graph is 898bcb0991SDimitry Andric /// reachable from the root. 908bcb0991SDimitry Andric void createAndConnectRootNode(); 918bcb0991SDimitry Andric 92480093f4SDimitry Andric /// Apply graph abstraction to groups of nodes that belong to a strongly 93480093f4SDimitry Andric /// connected component of the graph to create larger compound nodes 94480093f4SDimitry Andric /// called pi-blocks. The purpose of this abstraction is to isolate sets of 95480093f4SDimitry Andric /// program elements that need to stay together during codegen and turn 96480093f4SDimitry Andric /// the dependence graph into an acyclic graph. 97480093f4SDimitry Andric void createPiBlocks(); 98480093f4SDimitry Andric 995ffd83dbSDimitry Andric /// Go through all the nodes in the graph and collapse any two nodes 1005ffd83dbSDimitry Andric /// 'a' and 'b' if all of the following are true: 1015ffd83dbSDimitry Andric /// - the only edge from 'a' is a def-use edge to 'b' and 1025ffd83dbSDimitry Andric /// - the only edge to 'b' is a def-use edge from 'a' and 1035ffd83dbSDimitry Andric /// - there is no cyclic edge from 'b' to 'a' and 1045ffd83dbSDimitry Andric /// - all instructions in 'a' and 'b' belong to the same basic block and 1055ffd83dbSDimitry Andric /// - both 'a' and 'b' are simple (single or multi instruction) nodes. 1065ffd83dbSDimitry Andric void simplify(); 1075ffd83dbSDimitry Andric 108480093f4SDimitry Andric /// Topologically sort the graph nodes. 109480093f4SDimitry Andric void sortNodesTopologically(); 110480093f4SDimitry Andric 1118bcb0991SDimitry Andric protected: 1128bcb0991SDimitry Andric /// Create the root node of the graph. 1138bcb0991SDimitry Andric virtual NodeType &createRootNode() = 0; 1148bcb0991SDimitry Andric 1158bcb0991SDimitry Andric /// Create an atomic node in the graph given a single instruction. 1168bcb0991SDimitry Andric virtual NodeType &createFineGrainedNode(Instruction &I) = 0; 1178bcb0991SDimitry Andric 118480093f4SDimitry Andric /// Create a pi-block node in the graph representing a group of nodes in an 119480093f4SDimitry Andric /// SCC of the graph. 120480093f4SDimitry Andric virtual NodeType &createPiBlock(const NodeListType &L) = 0; 121480093f4SDimitry Andric 1228bcb0991SDimitry Andric /// Create a def-use edge going from \p Src to \p Tgt. 1238bcb0991SDimitry Andric virtual EdgeType &createDefUseEdge(NodeType &Src, NodeType &Tgt) = 0; 1248bcb0991SDimitry Andric 1258bcb0991SDimitry Andric /// Create a memory dependence edge going from \p Src to \p Tgt. 1268bcb0991SDimitry Andric virtual EdgeType &createMemoryEdge(NodeType &Src, NodeType &Tgt) = 0; 1278bcb0991SDimitry Andric 1288bcb0991SDimitry Andric /// Create a rooted edge going from \p Src to \p Tgt . 1298bcb0991SDimitry Andric virtual EdgeType &createRootedEdge(NodeType &Src, NodeType &Tgt) = 0; 1308bcb0991SDimitry Andric 131480093f4SDimitry Andric /// Given a pi-block node, return a vector of all the nodes contained within 132480093f4SDimitry Andric /// it. 133480093f4SDimitry Andric virtual const NodeListType &getNodesInPiBlock(const NodeType &N) = 0; 134480093f4SDimitry Andric 1358bcb0991SDimitry Andric /// Deallocate memory of edge \p E. destroyEdge(EdgeType & E)1368bcb0991SDimitry Andric virtual void destroyEdge(EdgeType &E) { delete &E; } 1378bcb0991SDimitry Andric 1388bcb0991SDimitry Andric /// Deallocate memory of node \p N. destroyNode(NodeType & N)1398bcb0991SDimitry Andric virtual void destroyNode(NodeType &N) { delete &N; } 1408bcb0991SDimitry Andric 141480093f4SDimitry Andric /// Return true if creation of pi-blocks are supported and desired, 142480093f4SDimitry Andric /// and false otherwise. shouldCreatePiBlocks()143480093f4SDimitry Andric virtual bool shouldCreatePiBlocks() const { return true; } 144480093f4SDimitry Andric 1455ffd83dbSDimitry Andric /// Return true if graph simplification step is requested, and false 1465ffd83dbSDimitry Andric /// otherwise. shouldSimplify()1475ffd83dbSDimitry Andric virtual bool shouldSimplify() const { return true; } 1485ffd83dbSDimitry Andric 1495ffd83dbSDimitry Andric /// Return true if it's safe to merge the two nodes. 1505ffd83dbSDimitry Andric virtual bool areNodesMergeable(const NodeType &A, 1515ffd83dbSDimitry Andric const NodeType &B) const = 0; 1525ffd83dbSDimitry Andric 1535ffd83dbSDimitry Andric /// Append the content of node \p B into node \p A and remove \p B and 1545ffd83dbSDimitry Andric /// the edge between \p A and \p B from the graph. 1555ffd83dbSDimitry Andric virtual void mergeNodes(NodeType &A, NodeType &B) = 0; 1565ffd83dbSDimitry Andric 157480093f4SDimitry Andric /// Given an instruction \p I return its associated ordinal number. getOrdinal(Instruction & I)158480093f4SDimitry Andric size_t getOrdinal(Instruction &I) { 15906c3fb27SDimitry Andric assert(InstOrdinalMap.contains(&I) && 160480093f4SDimitry Andric "No ordinal computed for this instruction."); 161480093f4SDimitry Andric return InstOrdinalMap[&I]; 162480093f4SDimitry Andric } 163480093f4SDimitry Andric 164480093f4SDimitry Andric /// Given a node \p N return its associated ordinal number. getOrdinal(NodeType & N)165480093f4SDimitry Andric size_t getOrdinal(NodeType &N) { 166*5f757f3fSDimitry Andric assert(NodeOrdinalMap.contains(&N) && "No ordinal computed for this node."); 167480093f4SDimitry Andric return NodeOrdinalMap[&N]; 168480093f4SDimitry Andric } 169480093f4SDimitry Andric 1708bcb0991SDimitry Andric /// Map types to map instructions to nodes used when populating the graph. 1718bcb0991SDimitry Andric using InstToNodeMap = DenseMap<Instruction *, NodeType *>; 1728bcb0991SDimitry Andric 173480093f4SDimitry Andric /// Map Types to map instruction/nodes to an ordinal number. 174480093f4SDimitry Andric using InstToOrdinalMap = DenseMap<Instruction *, size_t>; 175480093f4SDimitry Andric using NodeToOrdinalMap = DenseMap<NodeType *, size_t>; 176480093f4SDimitry Andric 1778bcb0991SDimitry Andric /// Reference to the graph that gets built by a concrete implementation of 1788bcb0991SDimitry Andric /// this builder. 1798bcb0991SDimitry Andric GraphType &Graph; 1808bcb0991SDimitry Andric 1818bcb0991SDimitry Andric /// Dependence information used to create memory dependence edges in the 1828bcb0991SDimitry Andric /// graph. 1838bcb0991SDimitry Andric DependenceInfo &DI; 1848bcb0991SDimitry Andric 1858bcb0991SDimitry Andric /// The list of basic blocks to consider when building the graph. 1868bcb0991SDimitry Andric const BasicBlockListType &BBList; 1878bcb0991SDimitry Andric 1888bcb0991SDimitry Andric /// A mapping from instructions to the corresponding nodes in the graph. 1898bcb0991SDimitry Andric InstToNodeMap IMap; 190480093f4SDimitry Andric 191480093f4SDimitry Andric /// A mapping from each instruction to an ordinal number. This map is used to 192480093f4SDimitry Andric /// populate the \p NodeOrdinalMap. 193480093f4SDimitry Andric InstToOrdinalMap InstOrdinalMap; 194480093f4SDimitry Andric 195480093f4SDimitry Andric /// A mapping from nodes to an ordinal number. This map is used to sort nodes 196480093f4SDimitry Andric /// in a pi-block based on program order. 197480093f4SDimitry Andric NodeToOrdinalMap NodeOrdinalMap; 1988bcb0991SDimitry Andric }; 1998bcb0991SDimitry Andric 2008bcb0991SDimitry Andric } // namespace llvm 2018bcb0991SDimitry Andric 202fe6060f1SDimitry Andric #endif // LLVM_ANALYSIS_DEPENDENCEGRAPHBUILDER_H 203