1 //===- DependenceGraphBuilder.cpp ------------------------------------------==//
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
7 //===----------------------------------------------------------------------===//
8 // This file implements common steps of the build algorithm for construction
9 // of dependence graphs such as DDG and PDG.
10 //===----------------------------------------------------------------------===//
12 #include "llvm/Analysis/DependenceGraphBuilder.h"
13 #include "llvm/ADT/SCCIterator.h"
14 #include "llvm/ADT/Statistic.h"
15 #include "llvm/Analysis/DDG.h"
19 #define DEBUG_TYPE "dgb"
21 STATISTIC(TotalGraphs
, "Number of dependence graphs created.");
22 STATISTIC(TotalDefUseEdges
, "Number of def-use edges created.");
23 STATISTIC(TotalMemoryEdges
, "Number of memory dependence edges created.");
24 STATISTIC(TotalFineGrainedNodes
, "Number of fine-grained nodes created.");
25 STATISTIC(TotalConfusedEdges
,
26 "Number of confused memory dependencies between two nodes.");
27 STATISTIC(TotalEdgeReversals
,
28 "Number of times the source and sink of dependence was reversed to "
29 "expose cycles in the graph.");
31 using InstructionListType
= SmallVector
<Instruction
*, 2>;
33 //===--------------------------------------------------------------------===//
34 // AbstractDependenceGraphBuilder implementation
35 //===--------------------------------------------------------------------===//
38 void AbstractDependenceGraphBuilder
<G
>::createFineGrainedNodes() {
40 assert(IMap
.empty() && "Expected empty instruction map at start");
41 for (BasicBlock
*BB
: BBList
)
42 for (Instruction
&I
: *BB
) {
43 auto &NewNode
= createFineGrainedNode(I
);
44 IMap
.insert(std::make_pair(&I
, &NewNode
));
45 ++TotalFineGrainedNodes
;
50 void AbstractDependenceGraphBuilder
<G
>::createAndConnectRootNode() {
51 // Create a root node that connects to every connected component of the graph.
52 // This is done to allow graph iterators to visit all the disjoint components
53 // of the graph, in a single walk.
55 // This algorithm works by going through each node of the graph and for each
56 // node N, do a DFS starting from N. A rooted edge is established between the
57 // root node and N (if N is not yet visited). All the nodes reachable from N
58 // are marked as visited and are skipped in the DFS of subsequent nodes.
60 // Note: This algorithm tries to limit the number of edges out of the root
61 // node to some extent, but there may be redundant edges created depending on
62 // the iteration order. For example for a graph {A -> B}, an edge from the
63 // root node is added to both nodes if B is visited before A. While it does
64 // not result in minimal number of edges, this approach saves compile-time
65 // while keeping the number of edges in check.
66 auto &RootNode
= createRootNode();
67 df_iterator_default_set
<const NodeType
*, 4> Visited
;
68 for (auto *N
: Graph
) {
71 for (auto I
: depth_first_ext(N
, Visited
))
73 createRootedEdge(RootNode
, *N
);
77 template <class G
> void AbstractDependenceGraphBuilder
<G
>::createDefUseEdges() {
78 for (NodeType
*N
: Graph
) {
79 InstructionListType SrcIList
;
80 N
->collectInstructions([](const Instruction
*I
) { return true; }, SrcIList
);
82 // Use a set to mark the targets that we link to N, so we don't add
83 // duplicate def-use edges when more than one instruction in a target node
84 // use results of instructions that are contained in N.
85 SmallPtrSet
<NodeType
*, 4> VisitedTargets
;
87 for (Instruction
*II
: SrcIList
) {
88 for (User
*U
: II
->users()) {
89 Instruction
*UI
= dyn_cast
<Instruction
>(U
);
92 NodeType
*DstNode
= nullptr;
93 if (IMap
.find(UI
) != IMap
.end())
94 DstNode
= IMap
.find(UI
)->second
;
96 // In the case of loops, the scope of the subgraph is all the
97 // basic blocks (and instructions within them) belonging to the loop. We
98 // simply ignore all the edges coming from (or going into) instructions
99 // or basic blocks outside of this range.
103 << "skipped def-use edge since the sink" << *UI
104 << " is outside the range of instructions being considered.\n");
108 // Self dependencies are ignored because they are redundant and
112 << "skipped def-use edge since the sink and the source ("
113 << N
<< ") are the same.\n");
117 if (VisitedTargets
.insert(DstNode
).second
) {
118 createDefUseEdge(*N
, *DstNode
);
127 void AbstractDependenceGraphBuilder
<G
>::createMemoryDependencyEdges() {
128 using DGIterator
= typename
G::iterator
;
129 auto isMemoryAccess
= [](const Instruction
*I
) {
130 return I
->mayReadOrWriteMemory();
132 for (DGIterator SrcIt
= Graph
.begin(), E
= Graph
.end(); SrcIt
!= E
; ++SrcIt
) {
133 InstructionListType SrcIList
;
134 (*SrcIt
)->collectInstructions(isMemoryAccess
, SrcIList
);
135 if (SrcIList
.empty())
138 for (DGIterator DstIt
= SrcIt
; DstIt
!= E
; ++DstIt
) {
139 if (**SrcIt
== **DstIt
)
141 InstructionListType DstIList
;
142 (*DstIt
)->collectInstructions(isMemoryAccess
, DstIList
);
143 if (DstIList
.empty())
145 bool ForwardEdgeCreated
= false;
146 bool BackwardEdgeCreated
= false;
147 for (Instruction
*ISrc
: SrcIList
) {
148 for (Instruction
*IDst
: DstIList
) {
149 auto D
= DI
.depends(ISrc
, IDst
, true);
153 // If we have a dependence with its left-most non-'=' direction
154 // being '>' we need to reverse the direction of the edge, because
155 // the source of the dependence cannot occur after the sink. For
156 // confused dependencies, we will create edges in both directions to
157 // represent the possibility of a cycle.
159 auto createConfusedEdges
= [&](NodeType
&Src
, NodeType
&Dst
) {
160 if (!ForwardEdgeCreated
) {
161 createMemoryEdge(Src
, Dst
);
164 if (!BackwardEdgeCreated
) {
165 createMemoryEdge(Dst
, Src
);
168 ForwardEdgeCreated
= BackwardEdgeCreated
= true;
169 ++TotalConfusedEdges
;
172 auto createForwardEdge
= [&](NodeType
&Src
, NodeType
&Dst
) {
173 if (!ForwardEdgeCreated
) {
174 createMemoryEdge(Src
, Dst
);
177 ForwardEdgeCreated
= true;
180 auto createBackwardEdge
= [&](NodeType
&Src
, NodeType
&Dst
) {
181 if (!BackwardEdgeCreated
) {
182 createMemoryEdge(Dst
, Src
);
185 BackwardEdgeCreated
= true;
189 createConfusedEdges(**SrcIt
, **DstIt
);
190 else if (D
->isOrdered() && !D
->isLoopIndependent()) {
191 bool ReversedEdge
= false;
192 for (unsigned Level
= 1; Level
<= D
->getLevels(); ++Level
) {
193 if (D
->getDirection(Level
) == Dependence::DVEntry::EQ
)
195 else if (D
->getDirection(Level
) == Dependence::DVEntry::GT
) {
196 createBackwardEdge(**SrcIt
, **DstIt
);
198 ++TotalEdgeReversals
;
200 } else if (D
->getDirection(Level
) == Dependence::DVEntry::LT
)
203 createConfusedEdges(**SrcIt
, **DstIt
);
208 createForwardEdge(**SrcIt
, **DstIt
);
210 createForwardEdge(**SrcIt
, **DstIt
);
212 // Avoid creating duplicate edges.
213 if (ForwardEdgeCreated
&& BackwardEdgeCreated
)
217 // If we've created edges in both directions, there is no more
218 // unique edge that we can create between these two nodes, so we
220 if (ForwardEdgeCreated
&& BackwardEdgeCreated
)
227 template class llvm::AbstractDependenceGraphBuilder
<DataDependenceGraph
>;
228 template class llvm::DependenceGraphInfo
<DDGNode
>;