xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/Analysis/DependenceGraphBuilder.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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