xref: /freebsd-src/contrib/llvm-project/llvm/lib/Analysis/DependenceGraphBuilder.cpp (revision 8bcb0991864975618c09697b1aca10683346d9f0)
1*8bcb0991SDimitry Andric //===- DependenceGraphBuilder.cpp ------------------------------------------==//
2*8bcb0991SDimitry Andric //
3*8bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*8bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*8bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*8bcb0991SDimitry Andric //
7*8bcb0991SDimitry Andric //===----------------------------------------------------------------------===//
8*8bcb0991SDimitry Andric // This file implements common steps of the build algorithm for construction
9*8bcb0991SDimitry Andric // of dependence graphs such as DDG and PDG.
10*8bcb0991SDimitry Andric //===----------------------------------------------------------------------===//
11*8bcb0991SDimitry Andric 
12*8bcb0991SDimitry Andric #include "llvm/Analysis/DependenceGraphBuilder.h"
13*8bcb0991SDimitry Andric #include "llvm/ADT/SCCIterator.h"
14*8bcb0991SDimitry Andric #include "llvm/ADT/Statistic.h"
15*8bcb0991SDimitry Andric #include "llvm/Analysis/DDG.h"
16*8bcb0991SDimitry Andric 
17*8bcb0991SDimitry Andric using namespace llvm;
18*8bcb0991SDimitry Andric 
19*8bcb0991SDimitry Andric #define DEBUG_TYPE "dgb"
20*8bcb0991SDimitry Andric 
21*8bcb0991SDimitry Andric STATISTIC(TotalGraphs, "Number of dependence graphs created.");
22*8bcb0991SDimitry Andric STATISTIC(TotalDefUseEdges, "Number of def-use edges created.");
23*8bcb0991SDimitry Andric STATISTIC(TotalMemoryEdges, "Number of memory dependence edges created.");
24*8bcb0991SDimitry Andric STATISTIC(TotalFineGrainedNodes, "Number of fine-grained nodes created.");
25*8bcb0991SDimitry Andric STATISTIC(TotalConfusedEdges,
26*8bcb0991SDimitry Andric           "Number of confused memory dependencies between two nodes.");
27*8bcb0991SDimitry Andric STATISTIC(TotalEdgeReversals,
28*8bcb0991SDimitry Andric           "Number of times the source and sink of dependence was reversed to "
29*8bcb0991SDimitry Andric           "expose cycles in the graph.");
30*8bcb0991SDimitry Andric 
31*8bcb0991SDimitry Andric using InstructionListType = SmallVector<Instruction *, 2>;
32*8bcb0991SDimitry Andric 
33*8bcb0991SDimitry Andric //===--------------------------------------------------------------------===//
34*8bcb0991SDimitry Andric // AbstractDependenceGraphBuilder implementation
35*8bcb0991SDimitry Andric //===--------------------------------------------------------------------===//
36*8bcb0991SDimitry Andric 
37*8bcb0991SDimitry Andric template <class G>
38*8bcb0991SDimitry Andric void AbstractDependenceGraphBuilder<G>::createFineGrainedNodes() {
39*8bcb0991SDimitry Andric   ++TotalGraphs;
40*8bcb0991SDimitry Andric   assert(IMap.empty() && "Expected empty instruction map at start");
41*8bcb0991SDimitry Andric   for (BasicBlock *BB : BBList)
42*8bcb0991SDimitry Andric     for (Instruction &I : *BB) {
43*8bcb0991SDimitry Andric       auto &NewNode = createFineGrainedNode(I);
44*8bcb0991SDimitry Andric       IMap.insert(std::make_pair(&I, &NewNode));
45*8bcb0991SDimitry Andric       ++TotalFineGrainedNodes;
46*8bcb0991SDimitry Andric     }
47*8bcb0991SDimitry Andric }
48*8bcb0991SDimitry Andric 
49*8bcb0991SDimitry Andric template <class G>
50*8bcb0991SDimitry Andric void AbstractDependenceGraphBuilder<G>::createAndConnectRootNode() {
51*8bcb0991SDimitry Andric   // Create a root node that connects to every connected component of the graph.
52*8bcb0991SDimitry Andric   // This is done to allow graph iterators to visit all the disjoint components
53*8bcb0991SDimitry Andric   // of the graph, in a single walk.
54*8bcb0991SDimitry Andric   //
55*8bcb0991SDimitry Andric   // This algorithm works by going through each node of the graph and for each
56*8bcb0991SDimitry Andric   // node N, do a DFS starting from N. A rooted edge is established between the
57*8bcb0991SDimitry Andric   // root node and N (if N is not yet visited). All the nodes reachable from N
58*8bcb0991SDimitry Andric   // are marked as visited and are skipped in the DFS of subsequent nodes.
59*8bcb0991SDimitry Andric   //
60*8bcb0991SDimitry Andric   // Note: This algorithm tries to limit the number of edges out of the root
61*8bcb0991SDimitry Andric   // node to some extent, but there may be redundant edges created depending on
62*8bcb0991SDimitry Andric   // the iteration order. For example for a graph {A -> B}, an edge from the
63*8bcb0991SDimitry Andric   // root node is added to both nodes if B is visited before A. While it does
64*8bcb0991SDimitry Andric   // not result in minimal number of edges, this approach saves compile-time
65*8bcb0991SDimitry Andric   // while keeping the number of edges in check.
66*8bcb0991SDimitry Andric   auto &RootNode = createRootNode();
67*8bcb0991SDimitry Andric   df_iterator_default_set<const NodeType *, 4> Visited;
68*8bcb0991SDimitry Andric   for (auto *N : Graph) {
69*8bcb0991SDimitry Andric     if (*N == RootNode)
70*8bcb0991SDimitry Andric       continue;
71*8bcb0991SDimitry Andric     for (auto I : depth_first_ext(N, Visited))
72*8bcb0991SDimitry Andric       if (I == N)
73*8bcb0991SDimitry Andric         createRootedEdge(RootNode, *N);
74*8bcb0991SDimitry Andric   }
75*8bcb0991SDimitry Andric }
76*8bcb0991SDimitry Andric 
77*8bcb0991SDimitry Andric template <class G> void AbstractDependenceGraphBuilder<G>::createDefUseEdges() {
78*8bcb0991SDimitry Andric   for (NodeType *N : Graph) {
79*8bcb0991SDimitry Andric     InstructionListType SrcIList;
80*8bcb0991SDimitry Andric     N->collectInstructions([](const Instruction *I) { return true; }, SrcIList);
81*8bcb0991SDimitry Andric 
82*8bcb0991SDimitry Andric     // Use a set to mark the targets that we link to N, so we don't add
83*8bcb0991SDimitry Andric     // duplicate def-use edges when more than one instruction in a target node
84*8bcb0991SDimitry Andric     // use results of instructions that are contained in N.
85*8bcb0991SDimitry Andric     SmallPtrSet<NodeType *, 4> VisitedTargets;
86*8bcb0991SDimitry Andric 
87*8bcb0991SDimitry Andric     for (Instruction *II : SrcIList) {
88*8bcb0991SDimitry Andric       for (User *U : II->users()) {
89*8bcb0991SDimitry Andric         Instruction *UI = dyn_cast<Instruction>(U);
90*8bcb0991SDimitry Andric         if (!UI)
91*8bcb0991SDimitry Andric           continue;
92*8bcb0991SDimitry Andric         NodeType *DstNode = nullptr;
93*8bcb0991SDimitry Andric         if (IMap.find(UI) != IMap.end())
94*8bcb0991SDimitry Andric           DstNode = IMap.find(UI)->second;
95*8bcb0991SDimitry Andric 
96*8bcb0991SDimitry Andric         // In the case of loops, the scope of the subgraph is all the
97*8bcb0991SDimitry Andric         // basic blocks (and instructions within them) belonging to the loop. We
98*8bcb0991SDimitry Andric         // simply ignore all the edges coming from (or going into) instructions
99*8bcb0991SDimitry Andric         // or basic blocks outside of this range.
100*8bcb0991SDimitry Andric         if (!DstNode) {
101*8bcb0991SDimitry Andric           LLVM_DEBUG(
102*8bcb0991SDimitry Andric               dbgs()
103*8bcb0991SDimitry Andric               << "skipped def-use edge since the sink" << *UI
104*8bcb0991SDimitry Andric               << " is outside the range of instructions being considered.\n");
105*8bcb0991SDimitry Andric           continue;
106*8bcb0991SDimitry Andric         }
107*8bcb0991SDimitry Andric 
108*8bcb0991SDimitry Andric         // Self dependencies are ignored because they are redundant and
109*8bcb0991SDimitry Andric         // uninteresting.
110*8bcb0991SDimitry Andric         if (DstNode == N) {
111*8bcb0991SDimitry Andric           LLVM_DEBUG(dbgs()
112*8bcb0991SDimitry Andric                      << "skipped def-use edge since the sink and the source ("
113*8bcb0991SDimitry Andric                      << N << ") are the same.\n");
114*8bcb0991SDimitry Andric           continue;
115*8bcb0991SDimitry Andric         }
116*8bcb0991SDimitry Andric 
117*8bcb0991SDimitry Andric         if (VisitedTargets.insert(DstNode).second) {
118*8bcb0991SDimitry Andric           createDefUseEdge(*N, *DstNode);
119*8bcb0991SDimitry Andric           ++TotalDefUseEdges;
120*8bcb0991SDimitry Andric         }
121*8bcb0991SDimitry Andric       }
122*8bcb0991SDimitry Andric     }
123*8bcb0991SDimitry Andric   }
124*8bcb0991SDimitry Andric }
125*8bcb0991SDimitry Andric 
126*8bcb0991SDimitry Andric template <class G>
127*8bcb0991SDimitry Andric void AbstractDependenceGraphBuilder<G>::createMemoryDependencyEdges() {
128*8bcb0991SDimitry Andric   using DGIterator = typename G::iterator;
129*8bcb0991SDimitry Andric   auto isMemoryAccess = [](const Instruction *I) {
130*8bcb0991SDimitry Andric     return I->mayReadOrWriteMemory();
131*8bcb0991SDimitry Andric   };
132*8bcb0991SDimitry Andric   for (DGIterator SrcIt = Graph.begin(), E = Graph.end(); SrcIt != E; ++SrcIt) {
133*8bcb0991SDimitry Andric     InstructionListType SrcIList;
134*8bcb0991SDimitry Andric     (*SrcIt)->collectInstructions(isMemoryAccess, SrcIList);
135*8bcb0991SDimitry Andric     if (SrcIList.empty())
136*8bcb0991SDimitry Andric       continue;
137*8bcb0991SDimitry Andric 
138*8bcb0991SDimitry Andric     for (DGIterator DstIt = SrcIt; DstIt != E; ++DstIt) {
139*8bcb0991SDimitry Andric       if (**SrcIt == **DstIt)
140*8bcb0991SDimitry Andric         continue;
141*8bcb0991SDimitry Andric       InstructionListType DstIList;
142*8bcb0991SDimitry Andric       (*DstIt)->collectInstructions(isMemoryAccess, DstIList);
143*8bcb0991SDimitry Andric       if (DstIList.empty())
144*8bcb0991SDimitry Andric         continue;
145*8bcb0991SDimitry Andric       bool ForwardEdgeCreated = false;
146*8bcb0991SDimitry Andric       bool BackwardEdgeCreated = false;
147*8bcb0991SDimitry Andric       for (Instruction *ISrc : SrcIList) {
148*8bcb0991SDimitry Andric         for (Instruction *IDst : DstIList) {
149*8bcb0991SDimitry Andric           auto D = DI.depends(ISrc, IDst, true);
150*8bcb0991SDimitry Andric           if (!D)
151*8bcb0991SDimitry Andric             continue;
152*8bcb0991SDimitry Andric 
153*8bcb0991SDimitry Andric           // If we have a dependence with its left-most non-'=' direction
154*8bcb0991SDimitry Andric           // being '>' we need to reverse the direction of the edge, because
155*8bcb0991SDimitry Andric           // the source of the dependence cannot occur after the sink. For
156*8bcb0991SDimitry Andric           // confused dependencies, we will create edges in both directions to
157*8bcb0991SDimitry Andric           // represent the possibility of a cycle.
158*8bcb0991SDimitry Andric 
159*8bcb0991SDimitry Andric           auto createConfusedEdges = [&](NodeType &Src, NodeType &Dst) {
160*8bcb0991SDimitry Andric             if (!ForwardEdgeCreated) {
161*8bcb0991SDimitry Andric               createMemoryEdge(Src, Dst);
162*8bcb0991SDimitry Andric               ++TotalMemoryEdges;
163*8bcb0991SDimitry Andric             }
164*8bcb0991SDimitry Andric             if (!BackwardEdgeCreated) {
165*8bcb0991SDimitry Andric               createMemoryEdge(Dst, Src);
166*8bcb0991SDimitry Andric               ++TotalMemoryEdges;
167*8bcb0991SDimitry Andric             }
168*8bcb0991SDimitry Andric             ForwardEdgeCreated = BackwardEdgeCreated = true;
169*8bcb0991SDimitry Andric             ++TotalConfusedEdges;
170*8bcb0991SDimitry Andric           };
171*8bcb0991SDimitry Andric 
172*8bcb0991SDimitry Andric           auto createForwardEdge = [&](NodeType &Src, NodeType &Dst) {
173*8bcb0991SDimitry Andric             if (!ForwardEdgeCreated) {
174*8bcb0991SDimitry Andric               createMemoryEdge(Src, Dst);
175*8bcb0991SDimitry Andric               ++TotalMemoryEdges;
176*8bcb0991SDimitry Andric             }
177*8bcb0991SDimitry Andric             ForwardEdgeCreated = true;
178*8bcb0991SDimitry Andric           };
179*8bcb0991SDimitry Andric 
180*8bcb0991SDimitry Andric           auto createBackwardEdge = [&](NodeType &Src, NodeType &Dst) {
181*8bcb0991SDimitry Andric             if (!BackwardEdgeCreated) {
182*8bcb0991SDimitry Andric               createMemoryEdge(Dst, Src);
183*8bcb0991SDimitry Andric               ++TotalMemoryEdges;
184*8bcb0991SDimitry Andric             }
185*8bcb0991SDimitry Andric             BackwardEdgeCreated = true;
186*8bcb0991SDimitry Andric           };
187*8bcb0991SDimitry Andric 
188*8bcb0991SDimitry Andric           if (D->isConfused())
189*8bcb0991SDimitry Andric             createConfusedEdges(**SrcIt, **DstIt);
190*8bcb0991SDimitry Andric           else if (D->isOrdered() && !D->isLoopIndependent()) {
191*8bcb0991SDimitry Andric             bool ReversedEdge = false;
192*8bcb0991SDimitry Andric             for (unsigned Level = 1; Level <= D->getLevels(); ++Level) {
193*8bcb0991SDimitry Andric               if (D->getDirection(Level) == Dependence::DVEntry::EQ)
194*8bcb0991SDimitry Andric                 continue;
195*8bcb0991SDimitry Andric               else if (D->getDirection(Level) == Dependence::DVEntry::GT) {
196*8bcb0991SDimitry Andric                 createBackwardEdge(**SrcIt, **DstIt);
197*8bcb0991SDimitry Andric                 ReversedEdge = true;
198*8bcb0991SDimitry Andric                 ++TotalEdgeReversals;
199*8bcb0991SDimitry Andric                 break;
200*8bcb0991SDimitry Andric               } else if (D->getDirection(Level) == Dependence::DVEntry::LT)
201*8bcb0991SDimitry Andric                 break;
202*8bcb0991SDimitry Andric               else {
203*8bcb0991SDimitry Andric                 createConfusedEdges(**SrcIt, **DstIt);
204*8bcb0991SDimitry Andric                 break;
205*8bcb0991SDimitry Andric               }
206*8bcb0991SDimitry Andric             }
207*8bcb0991SDimitry Andric             if (!ReversedEdge)
208*8bcb0991SDimitry Andric               createForwardEdge(**SrcIt, **DstIt);
209*8bcb0991SDimitry Andric           } else
210*8bcb0991SDimitry Andric             createForwardEdge(**SrcIt, **DstIt);
211*8bcb0991SDimitry Andric 
212*8bcb0991SDimitry Andric           // Avoid creating duplicate edges.
213*8bcb0991SDimitry Andric           if (ForwardEdgeCreated && BackwardEdgeCreated)
214*8bcb0991SDimitry Andric             break;
215*8bcb0991SDimitry Andric         }
216*8bcb0991SDimitry Andric 
217*8bcb0991SDimitry Andric         // If we've created edges in both directions, there is no more
218*8bcb0991SDimitry Andric         // unique edge that we can create between these two nodes, so we
219*8bcb0991SDimitry Andric         // can exit early.
220*8bcb0991SDimitry Andric         if (ForwardEdgeCreated && BackwardEdgeCreated)
221*8bcb0991SDimitry Andric           break;
222*8bcb0991SDimitry Andric       }
223*8bcb0991SDimitry Andric     }
224*8bcb0991SDimitry Andric   }
225*8bcb0991SDimitry Andric }
226*8bcb0991SDimitry Andric 
227*8bcb0991SDimitry Andric template class llvm::AbstractDependenceGraphBuilder<DataDependenceGraph>;
228*8bcb0991SDimitry Andric template class llvm::DependenceGraphInfo<DDGNode>;
229