llvm.org GIT mirror llvm / 4c48a60
[DDG] Data Dependence Graph - Root Node Summary: This patch adds Root Node to the DDG. The purpose of the root node is to create a single entry node that allows graph walk iterators to iterate through all nodes of the graph, making sure that no node is left unvisited during a graph walk (eg. SCC or DFS). Once the DDG is fully constructed it will have exactly one root node. Every node in the graph is reachable from the root. The algorithm for connecting the root node is based on depth-first-search that keeps track of visited nodes to try to avoid creating unnecessary edges. Authored By: bmahjour Reviewer: Meinersbur, fhahn, myhsu, xtian, dmgreen, kbarton, jdoerfert Reviewed By: Meinersbur Subscribers: ychen, arphaman, simoll, a.elovikov, mgorny, hiraditya, jfb, wuzish, llvm-commits, jsji, Whitney, etiotto, ppc-slack Tag: #llvm Differential Revision: https://reviews.llvm.org/D67970 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@373386 91177308-0d34-0410-b5e6-96231b3b80d8 Bardia Mahjour 1 year, 19 days ago
5 changed file(s) with 177 addition(s) and 6 deletion(s). Raw diff Collapse all Expand all
3232 /// 1. Single instruction node containing just one instruction.
3333 /// 2. Multiple instruction node where two or more instructions from
3434 /// the same basic block are merged into one node.
35 /// 3. Root node is a special node that connects to all components such that
36 /// there is always a path from it to any node in the graph.
3537 class DDGNode : public DDGNodeBase {
3638 public:
3739 using InstructionListType = SmallVectorImpl;
4042 Unknown,
4143 SingleInstruction,
4244 MultiInstruction,
45 Root,
4346 };
4447
4548 DDGNode() = delete;
7578
7679 private:
7780 NodeKind Kind;
81 };
82
83 /// Subclass of DDGNode representing the root node of the graph.
84 /// There should only be one such node in a given graph.
85 class RootDDGNode : public DDGNode {
86 public:
87 RootDDGNode() : DDGNode(NodeKind::Root) {}
88 RootDDGNode(const RootDDGNode &N) = delete;
89 RootDDGNode(RootDDGNode &&N) : DDGNode(std::move(N)) {}
90 ~RootDDGNode() {}
91
92 /// Define classof to be able to use isa<>, cast<>, dyn_cast<>, etc.
93 static bool classof(const DDGNode *N) {
94 return N->getKind() == NodeKind::Root;
95 }
96 static bool classof(const RootDDGNode *N) { return true; }
7897 };
7998
8099 /// Subclass of DDGNode representing single or multi-instruction nodes.
138157 /// Data Dependency Graph Edge.
139158 /// An edge in the DDG can represent a def-use relationship or
140159 /// a memory dependence based on the result of DependenceAnalysis.
160 /// A rooted edge connects the root node to one of the components
161 /// of the graph.
141162 class DDGEdge : public DDGEdgeBase {
142163 public:
143164 /// The kind of edge in the DDG
144 enum class EdgeKind { Unknown, RegisterDefUse, MemoryDependence };
165 enum class EdgeKind { Unknown, RegisterDefUse, MemoryDependence, Rooted };
145166
146167 explicit DDGEdge(DDGNode &N) = delete;
147168 DDGEdge(DDGNode &N, EdgeKind K) : DDGEdgeBase(N), Kind(K) {}
168189 /// Return true if this is a memory dependence edge, and false otherwise.
169190 bool isMemoryDependence() const { return Kind == EdgeKind::MemoryDependence; }
170191
192 /// Return true if this is an edge stemming from the root node, and false
193 /// otherwise.
194 bool isRooted() const { return Kind == EdgeKind::Rooted; }
195
171196 private:
172197 EdgeKind Kind;
173198 };
181206 DependenceGraphInfo() = delete;
182207 DependenceGraphInfo(const DependenceGraphInfo &G) = delete;
183208 DependenceGraphInfo(const std::string &N, const DependenceInfo &DepInfo)
184 : Name(N), DI(DepInfo) {}
209 : Name(N), DI(DepInfo), Root(nullptr) {}
185210 DependenceGraphInfo(DependenceGraphInfo &&G)
186 : Name(std::move(G.Name)), DI(std::move(G.DI)) {}
211 : Name(std::move(G.Name)), DI(std::move(G.DI)), Root(G.Root) {}
187212 virtual ~DependenceGraphInfo() {}
188213
189214 /// Return the label that is used to name this graph.
190215 const StringRef getName() const { return Name; }
216
217 /// Return the root node of the graph.
218 NodeType &getRoot() const {
219 assert(Root && "Root node is not available yet. Graph construction may "
220 "still be in progress\n");
221 return *Root;
222 }
191223
192224 protected:
193225 // Name of the graph.
197229 // dependencies don't need to be stored. Instead when the dependence is
198230 // queried it is recomputed using @DI.
199231 const DependenceInfo DI;
232
233 // A special node in the graph that has an edge to every connected component of
234 // the graph, to ensure all nodes are reachable in a graph walk.
235 NodeType *Root = nullptr;
200236 };
201237
202238 using DDGInfo = DependenceGraphInfo;
216252 DataDependenceGraph(Function &F, DependenceInfo &DI);
217253 DataDependenceGraph(const Loop &L, DependenceInfo &DI);
218254 ~DataDependenceGraph();
255
256 protected:
257 /// Add node \p N to the graph, if it's not added yet, and keep track of
258 /// the root node. Return true if node is successfully added.
259 bool addNode(NodeType &N);
260
219261 };
220262
221263 /// Concrete implementation of a pure data dependence graph builder. This class
229271 DDGBuilder(DataDependenceGraph &G, DependenceInfo &D,
230272 const BasicBlockListType &BBs)
231273 : AbstractDependenceGraphBuilder(G, D, BBs) {}
274 DDGNode &createRootNode() final override {
275 auto *RN = new RootDDGNode();
276 assert(RN && "Failed to allocate memory for DDG root node.");
277 Graph.addNode(*RN);
278 return *RN;
279 }
232280 DDGNode &createFineGrainedNode(Instruction &I) final override {
233281 auto *SN = new SimpleDDGNode(I);
234282 assert(SN && "Failed to allocate memory for simple DDG node.");
247295 Graph.connect(Src, Tgt, *E);
248296 return *E;
249297 }
298 DDGEdge &createRootedEdge(DDGNode &Src, DDGNode &Tgt) final override {
299 auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::Rooted);
300 assert(E && "Failed to allocate memory for edge");
301 assert(isa(Src) && "Expected root node");
302 Graph.connect(Src, Tgt, *E);
303 return *E;
304 }
305
250306 };
251307
252308 raw_ostream &operator<<(raw_ostream &OS, const DDGNode &N);
316372 template <>
317373 struct GraphTraits : public GraphTraits {
318374 using nodes_iterator = DataDependenceGraph::iterator;
319 static NodeRef getEntryNode(DataDependenceGraph *DG) { return *DG->begin(); }
375 static NodeRef getEntryNode(DataDependenceGraph *DG) {
376 return &DG->getRoot();
377 }
320378 static nodes_iterator nodes_begin(DataDependenceGraph *DG) {
321379 return DG->begin();
322380 }
356414 : public GraphTraits {
357415 using nodes_iterator = DataDependenceGraph::const_iterator;
358416 static NodeRef getEntryNode(const DataDependenceGraph *DG) {
359 return *DG->begin();
417 return &DG->getRoot();
360418 }
361419 static nodes_iterator nodes_begin(const DataDependenceGraph *DG) {
362420 return DG->begin();
5454 createFineGrainedNodes();
5555 createDefUseEdges();
5656 createMemoryDependencyEdges();
57 createAndConnectRootNode();
5758 }
5859
5960 /// Create fine grained nodes. These are typically atomic nodes that
6869 /// in the graph nodes and create edges between them.
6970 void createMemoryDependencyEdges();
7071
72 /// Create a root node and add edges such that each node in the graph is
73 /// reachable from the root.
74 void createAndConnectRootNode();
75
7176 protected:
77 /// Create the root node of the graph.
78 virtual NodeType &createRootNode() = 0;
79
7280 /// Create an atomic node in the graph given a single instruction.
7381 virtual NodeType &createFineGrainedNode(Instruction &I) = 0;
7482
7785
7886 /// Create a memory dependence edge going from \p Src to \p Tgt.
7987 virtual EdgeType &createMemoryEdge(NodeType &Src, NodeType &Tgt) = 0;
88
89 /// Create a rooted edge going from \p Src to \p Tgt .
90 virtual EdgeType &createRootedEdge(NodeType &Src, NodeType &Tgt) = 0;
8091
8192 /// Deallocate memory of edge \p E.
8293 virtual void destroyEdge(EdgeType &E) { delete &E; }
4545 case DDGNode::NodeKind::MultiInstruction:
4646 Out = "multi-instruction";
4747 break;
48 case DDGNode::NodeKind::Root:
49 Out = "root";
50 break;
4851 case DDGNode::NodeKind::Unknown:
4952 Out = "??";
5053 break;
5962 OS << " Instructions:\n";
6063 for (auto *I : cast(N).getInstructions())
6164 OS.indent(2) << *I << "\n";
62 } else
65 } else if (!isa(N))
6366 llvm_unreachable("unimplemented type of node");
6467
6568 OS << (N.getEdges().empty() ? " Edges:none!\n" : " Edges:\n");
106109 break;
107110 case DDGEdge::EdgeKind::MemoryDependence:
108111 Out = "memory";
112 break;
113 case DDGEdge::EdgeKind::Rooted:
114 Out = "rooted";
109115 break;
110116 case DDGEdge::EdgeKind::Unknown:
111117 Out = "??";
152158 }
153159 }
154160
161 bool DataDependenceGraph::addNode(DDGNode &N) {
162 if (!DDGBase::addNode(N))
163 return false;
164
165 // In general, if the root node is already created and linked, it is not safe
166 // to add new nodes since they may be unreachable by the root.
167 // TODO: Allow adding Pi-block nodes after root is created. Pi-blocks are an
168 // exception because they represent components that are already reachable by
169 // root.
170 assert(!Root && "Root node is already added. No more nodes can be added.");
171 if (isa(N))
172 Root = &N;
173
174 return true;
175 }
176
155177 raw_ostream &llvm::operator<<(raw_ostream &OS, const DataDependenceGraph &G) {
156178 for (auto *Node : G)
157179 OS << *Node << "\n";
4343 IMap.insert(std::make_pair(&I, &NewNode));
4444 ++TotalFineGrainedNodes;
4545 }
46 }
47
48 template
49 void AbstractDependenceGraphBuilder::createAndConnectRootNode() {
50 // Create a root node that connects to every connected component of the graph.
51 // This is done to allow graph iterators to visit all the disjoint components
52 // of the graph, in a single walk.
53 //
54 // This algorithm works by going through each node of the graph and for each
55 // node N, do a DFS starting from N. A rooted edge is established between the
56 // root node and N (if N is not yet visited). All the nodes reachable from N
57 // are marked as visited and are skipped in the DFS of subsequent nodes.
58 //
59 // Note: This algorithm tries to limit the number of edges out of the root
60 // node to some extent, but there may be redundant edges created depending on
61 // the iteration order. For example for a graph {A -> B}, an edge from the
62 // root node is added to both nodes if B is visited before A. While it does
63 // not result in minimal number of edges, this approach saves compile-time
64 // while keeping the number of edges in check.
65 auto &RootNode = createRootNode();
66 df_iterator_default_set Visited;
67 for (auto *N : Graph) {
68 if (*N == RootNode)
69 continue;
70 for (auto I : depth_first_ext(N, Visited))
71 if (I == N)
72 createRootedEdge(RootNode, *N);
73 }
4674 }
4775
4876 template void AbstractDependenceGraphBuilder::createDefUseEdges() {
0 ; RUN: opt < %s -disable-output "-passes=print" 2>&1 | FileCheck %s
1
2 ; CHECK-LABEL: 'DDG' for loop 'test1.for.body':
3
4 ; CHECK: Node Address:[[N1:0x[0-9a-f]*]]:single-instruction
5 ; CHECK-NEXT: Instructions:
6 ; CHECK-NEXT: %i2.03 = phi i64 [ 0, %for.body.lr.ph ], [ %inc2, %test1.for.body ]
7
8 ; CHECK: Node Address:[[N2:0x[0-9a-f]*]]:single-instruction
9 ; CHECK-NEXT: Instructions:
10 ; CHECK-NEXT: %i1.02 = phi i64 [ 0, %for.body.lr.ph ], [ %inc, %test1.for.body ]
11
12 ; CHECK: Node Address:[[ROOT:0x[0-9a-f]*]]:root
13 ; CHECK-NEXT: Edges:
14 ; CHECK-NEXT: [rooted] to [[N1]]
15 ; CHECK-NEXT: [rooted] to [[N2]]
16
17
18 ;; // Two separate components in the graph. Root node must link to both.
19 ;; void test1(unsigned long n, float * restrict a, float * restrict b) {
20 ;; for (unsigned long i1 = 0, i2 = 0; i1 < n; i1++, i2++) {
21 ;; a[i1] = 1;
22 ;; b[i2] = -1;
23 ;; }
24 ;; }
25
26 define void @test1(i64 %n, float* noalias %a, float* noalias %b) {
27 entry:
28 %cmp1 = icmp ult i64 0, %n
29 br i1 %cmp1, label %for.body.lr.ph, label %for.end
30
31 for.body.lr.ph: ; preds = %entry
32 br label %test1.for.body
33
34 test1.for.body: ; preds = %for.body.lr.ph, %test1.for.body
35 %i2.03 = phi i64 [ 0, %for.body.lr.ph ], [ %inc2, %test1.for.body ]
36 %i1.02 = phi i64 [ 0, %for.body.lr.ph ], [ %inc, %test1.for.body ]
37 %arrayidx = getelementptr inbounds float, float* %a, i64 %i1.02
38 store float 1.000000e+00, float* %arrayidx, align 4
39 %arrayidx1 = getelementptr inbounds float, float* %b, i64 %i2.03
40 store float -1.000000e+00, float* %arrayidx1, align 4
41 %inc = add i64 %i1.02, 1
42 %inc2 = add i64 %i2.03, 1
43 %cmp = icmp ult i64 %inc, %n
44 br i1 %cmp, label %test1.for.body, label %for.cond.for.end_crit_edge
45
46 for.cond.for.end_crit_edge: ; preds = %test1.for.body
47 br label %for.end
48
49 for.end: ; preds = %for.cond.for.end_crit_edge, %entry
50 ret void
51 }