xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Analysis/DependenceGraphBuilder.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- llvm/Analysis/DependenceGraphBuilder.h -------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines a builder interface that can be used to populate dependence
10 // graphs such as DDG and PDG.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_ANALYSIS_DEPENDENCEGRAPHBUILDER_H
15 #define LLVM_ANALYSIS_DEPENDENCEGRAPHBUILDER_H
16 
17 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/ADT/EquivalenceClasses.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/Support/Compiler.h"
21 
22 namespace llvm {
23 
24 class BasicBlock;
25 class DependenceInfo;
26 class Instruction;
27 
28 /// This abstract builder class defines a set of high-level steps for creating
29 /// DDG-like graphs. The client code is expected to inherit from this class and
30 /// define concrete implementation for each of the pure virtual functions used
31 /// in the high-level algorithm.
32 template <class GraphType> class LLVM_ABI AbstractDependenceGraphBuilder {
33 protected:
34   using BasicBlockListType = SmallVectorImpl<BasicBlock *>;
35 
36 private:
37   using NodeType = typename GraphType::NodeType;
38   using EdgeType = typename GraphType::EdgeType;
39 
40 public:
41   using ClassesType = EquivalenceClasses<BasicBlock *>;
42   using NodeListType = SmallVector<NodeType *, 4>;
43 
AbstractDependenceGraphBuilder(GraphType & G,DependenceInfo & D,const BasicBlockListType & BBs)44   AbstractDependenceGraphBuilder(GraphType &G, DependenceInfo &D,
45                                  const BasicBlockListType &BBs)
46       : Graph(G), DI(D), BBList(BBs) {}
47   virtual ~AbstractDependenceGraphBuilder() = default;
48 
49   /// The main entry to the graph construction algorithm. It starts by
50   /// creating nodes in increasing order of granularity and then
51   /// adds def-use and memory edges. As one of the final stages, it
52   /// also creates pi-block nodes to facilitate codegen in transformations
53   /// that use dependence graphs.
54   ///
55   /// The algorithmic complexity of this implementation is O(V^2 * I^2), where V
56   /// is the number of vertecies (nodes) and I is the number of instructions in
57   /// each node. The total number of instructions, N, is equal to V * I,
58   /// therefore the worst-case time complexity is O(N^2). The average time
59   /// complexity is O((N^2)/2).
populate()60   void populate() {
61     computeInstructionOrdinals();
62     createFineGrainedNodes();
63     createDefUseEdges();
64     createMemoryDependencyEdges();
65     simplify();
66     createAndConnectRootNode();
67     createPiBlocks();
68     sortNodesTopologically();
69   }
70 
71   /// Compute ordinal numbers for each instruction and store them in a map for
72   /// future look up. These ordinals are used to compute node ordinals which are
73   /// in turn used to order nodes that are part of a cycle.
74   /// Instruction ordinals are assigned based on lexical program order.
75   void computeInstructionOrdinals();
76 
77   /// Create fine grained nodes. These are typically atomic nodes that
78   /// consist of a single instruction.
79   void createFineGrainedNodes();
80 
81   /// Analyze the def-use chains and create edges from the nodes containing
82   /// definitions to the nodes containing the uses.
83   void createDefUseEdges();
84 
85   /// Analyze data dependencies that exist between memory loads or stores,
86   /// in the graph nodes and create edges between them.
87   void createMemoryDependencyEdges();
88 
89   /// Create a root node and add edges such that each node in the graph is
90   /// reachable from the root.
91   void createAndConnectRootNode();
92 
93   /// Apply graph abstraction to groups of nodes that belong to a strongly
94   /// connected component of the graph to create larger compound nodes
95   /// called pi-blocks. The purpose of this abstraction is to isolate sets of
96   /// program elements that need to stay together during codegen and turn
97   /// the dependence graph into an acyclic graph.
98   void createPiBlocks();
99 
100   /// Go through all the nodes in the graph and collapse any two nodes
101   /// 'a' and 'b' if all of the following are true:
102   ///   - the only edge from 'a' is a def-use edge to 'b' and
103   ///   - the only edge to 'b' is a def-use edge from 'a' and
104   ///   - there is no cyclic edge from 'b' to 'a' and
105   ///   - all instructions in 'a' and 'b' belong to the same basic block and
106   ///   - both 'a' and 'b' are simple (single or multi instruction) nodes.
107   void simplify();
108 
109   /// Topologically sort the graph nodes.
110   void sortNodesTopologically();
111 
112 protected:
113   /// Create the root node of the graph.
114   virtual NodeType &createRootNode() = 0;
115 
116   /// Create an atomic node in the graph given a single instruction.
117   virtual NodeType &createFineGrainedNode(Instruction &I) = 0;
118 
119   /// Create a pi-block node in the graph representing a group of nodes in an
120   /// SCC of the graph.
121   virtual NodeType &createPiBlock(const NodeListType &L) = 0;
122 
123   /// Create a def-use edge going from \p Src to \p Tgt.
124   virtual EdgeType &createDefUseEdge(NodeType &Src, NodeType &Tgt) = 0;
125 
126   /// Create a memory dependence edge going from \p Src to \p Tgt.
127   virtual EdgeType &createMemoryEdge(NodeType &Src, NodeType &Tgt) = 0;
128 
129   /// Create a rooted edge going from \p Src to \p Tgt .
130   virtual EdgeType &createRootedEdge(NodeType &Src, NodeType &Tgt) = 0;
131 
132   /// Given a pi-block node, return a vector of all the nodes contained within
133   /// it.
134   virtual const NodeListType &getNodesInPiBlock(const NodeType &N) = 0;
135 
136   /// Deallocate memory of edge \p E.
destroyEdge(EdgeType & E)137   virtual void destroyEdge(EdgeType &E) { delete &E; }
138 
139   /// Deallocate memory of node \p N.
destroyNode(NodeType & N)140   virtual void destroyNode(NodeType &N) { delete &N; }
141 
142   /// Return true if creation of pi-blocks are supported and desired,
143   /// and false otherwise.
shouldCreatePiBlocks()144   virtual bool shouldCreatePiBlocks() const { return true; }
145 
146   /// Return true if graph simplification step is requested, and false
147   /// otherwise.
shouldSimplify()148   virtual bool shouldSimplify() const { return true; }
149 
150   /// Return true if it's safe to merge the two nodes.
151   virtual bool areNodesMergeable(const NodeType &A,
152                                  const NodeType &B) const = 0;
153 
154   /// Append the content of node \p B into node \p A and remove \p B and
155   /// the edge between \p A and \p B from the graph.
156   virtual void mergeNodes(NodeType &A, NodeType &B) = 0;
157 
158   /// Given an instruction \p I return its associated ordinal number.
getOrdinal(Instruction & I)159   size_t getOrdinal(Instruction &I) {
160     assert(InstOrdinalMap.contains(&I) &&
161            "No ordinal computed for this instruction.");
162     return InstOrdinalMap[&I];
163   }
164 
165   /// Given a node \p N return its associated ordinal number.
getOrdinal(NodeType & N)166   size_t getOrdinal(NodeType &N) {
167     assert(NodeOrdinalMap.contains(&N) && "No ordinal computed for this node.");
168     return NodeOrdinalMap[&N];
169   }
170 
171   /// Map types to map instructions to nodes used when populating the graph.
172   using InstToNodeMap = DenseMap<Instruction *, NodeType *>;
173 
174   /// Map Types to map instruction/nodes to an ordinal number.
175   using InstToOrdinalMap = DenseMap<Instruction *, size_t>;
176   using NodeToOrdinalMap = DenseMap<NodeType *, size_t>;
177 
178   /// Reference to the graph that gets built by a concrete implementation of
179   /// this builder.
180   GraphType &Graph;
181 
182   /// Dependence information used to create memory dependence edges in the
183   /// graph.
184   DependenceInfo &DI;
185 
186   /// The list of basic blocks to consider when building the graph.
187   const BasicBlockListType &BBList;
188 
189   /// A mapping from instructions to the corresponding nodes in the graph.
190   InstToNodeMap IMap;
191 
192   /// A mapping from each instruction to an ordinal number. This map is used to
193   /// populate the \p NodeOrdinalMap.
194   InstToOrdinalMap InstOrdinalMap;
195 
196   /// A mapping from nodes to an ordinal number. This map is used to sort nodes
197   /// in a pi-block based on program order.
198   NodeToOrdinalMap NodeOrdinalMap;
199 };
200 
201 } // namespace llvm
202 
203 #endif // LLVM_ANALYSIS_DEPENDENCEGRAPHBUILDER_H
204