xref: /openbsd-src/gnu/llvm/llvm/lib/Analysis/DependenceGraphBuilder.cpp (revision 09467b48e8bc8b4905716062da846024139afbf2)
1*09467b48Spatrick //===- DependenceGraphBuilder.cpp ------------------------------------------==//
2*09467b48Spatrick //
3*09467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*09467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*09467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*09467b48Spatrick //
7*09467b48Spatrick //===----------------------------------------------------------------------===//
8*09467b48Spatrick // This file implements common steps of the build algorithm for construction
9*09467b48Spatrick // of dependence graphs such as DDG and PDG.
10*09467b48Spatrick //===----------------------------------------------------------------------===//
11*09467b48Spatrick 
12*09467b48Spatrick #include "llvm/Analysis/DependenceGraphBuilder.h"
13*09467b48Spatrick #include "llvm/ADT/EnumeratedArray.h"
14*09467b48Spatrick #include "llvm/ADT/SCCIterator.h"
15*09467b48Spatrick #include "llvm/ADT/Statistic.h"
16*09467b48Spatrick #include "llvm/Analysis/DDG.h"
17*09467b48Spatrick 
18*09467b48Spatrick using namespace llvm;
19*09467b48Spatrick 
20*09467b48Spatrick #define DEBUG_TYPE "dgb"
21*09467b48Spatrick 
22*09467b48Spatrick STATISTIC(TotalGraphs, "Number of dependence graphs created.");
23*09467b48Spatrick STATISTIC(TotalDefUseEdges, "Number of def-use edges created.");
24*09467b48Spatrick STATISTIC(TotalMemoryEdges, "Number of memory dependence edges created.");
25*09467b48Spatrick STATISTIC(TotalFineGrainedNodes, "Number of fine-grained nodes created.");
26*09467b48Spatrick STATISTIC(TotalPiBlockNodes, "Number of pi-block nodes created.");
27*09467b48Spatrick STATISTIC(TotalConfusedEdges,
28*09467b48Spatrick           "Number of confused memory dependencies between two nodes.");
29*09467b48Spatrick STATISTIC(TotalEdgeReversals,
30*09467b48Spatrick           "Number of times the source and sink of dependence was reversed to "
31*09467b48Spatrick           "expose cycles in the graph.");
32*09467b48Spatrick 
33*09467b48Spatrick using InstructionListType = SmallVector<Instruction *, 2>;
34*09467b48Spatrick 
35*09467b48Spatrick //===--------------------------------------------------------------------===//
36*09467b48Spatrick // AbstractDependenceGraphBuilder implementation
37*09467b48Spatrick //===--------------------------------------------------------------------===//
38*09467b48Spatrick 
39*09467b48Spatrick template <class G>
40*09467b48Spatrick void AbstractDependenceGraphBuilder<G>::computeInstructionOrdinals() {
41*09467b48Spatrick   // The BBList is expected to be in program order.
42*09467b48Spatrick   size_t NextOrdinal = 1;
43*09467b48Spatrick   for (auto *BB : BBList)
44*09467b48Spatrick     for (auto &I : *BB)
45*09467b48Spatrick       InstOrdinalMap.insert(std::make_pair(&I, NextOrdinal++));
46*09467b48Spatrick }
47*09467b48Spatrick 
48*09467b48Spatrick template <class G>
49*09467b48Spatrick void AbstractDependenceGraphBuilder<G>::createFineGrainedNodes() {
50*09467b48Spatrick   ++TotalGraphs;
51*09467b48Spatrick   assert(IMap.empty() && "Expected empty instruction map at start");
52*09467b48Spatrick   for (BasicBlock *BB : BBList)
53*09467b48Spatrick     for (Instruction &I : *BB) {
54*09467b48Spatrick       auto &NewNode = createFineGrainedNode(I);
55*09467b48Spatrick       IMap.insert(std::make_pair(&I, &NewNode));
56*09467b48Spatrick       NodeOrdinalMap.insert(std::make_pair(&NewNode, getOrdinal(I)));
57*09467b48Spatrick       ++TotalFineGrainedNodes;
58*09467b48Spatrick     }
59*09467b48Spatrick }
60*09467b48Spatrick 
61*09467b48Spatrick template <class G>
62*09467b48Spatrick void AbstractDependenceGraphBuilder<G>::createAndConnectRootNode() {
63*09467b48Spatrick   // Create a root node that connects to every connected component of the graph.
64*09467b48Spatrick   // This is done to allow graph iterators to visit all the disjoint components
65*09467b48Spatrick   // of the graph, in a single walk.
66*09467b48Spatrick   //
67*09467b48Spatrick   // This algorithm works by going through each node of the graph and for each
68*09467b48Spatrick   // node N, do a DFS starting from N. A rooted edge is established between the
69*09467b48Spatrick   // root node and N (if N is not yet visited). All the nodes reachable from N
70*09467b48Spatrick   // are marked as visited and are skipped in the DFS of subsequent nodes.
71*09467b48Spatrick   //
72*09467b48Spatrick   // Note: This algorithm tries to limit the number of edges out of the root
73*09467b48Spatrick   // node to some extent, but there may be redundant edges created depending on
74*09467b48Spatrick   // the iteration order. For example for a graph {A -> B}, an edge from the
75*09467b48Spatrick   // root node is added to both nodes if B is visited before A. While it does
76*09467b48Spatrick   // not result in minimal number of edges, this approach saves compile-time
77*09467b48Spatrick   // while keeping the number of edges in check.
78*09467b48Spatrick   auto &RootNode = createRootNode();
79*09467b48Spatrick   df_iterator_default_set<const NodeType *, 4> Visited;
80*09467b48Spatrick   for (auto *N : Graph) {
81*09467b48Spatrick     if (*N == RootNode)
82*09467b48Spatrick       continue;
83*09467b48Spatrick     for (auto I : depth_first_ext(N, Visited))
84*09467b48Spatrick       if (I == N)
85*09467b48Spatrick         createRootedEdge(RootNode, *N);
86*09467b48Spatrick   }
87*09467b48Spatrick }
88*09467b48Spatrick 
89*09467b48Spatrick template <class G> void AbstractDependenceGraphBuilder<G>::createPiBlocks() {
90*09467b48Spatrick   if (!shouldCreatePiBlocks())
91*09467b48Spatrick     return;
92*09467b48Spatrick 
93*09467b48Spatrick   LLVM_DEBUG(dbgs() << "==== Start of Creation of Pi-Blocks ===\n");
94*09467b48Spatrick 
95*09467b48Spatrick   // The overall algorithm is as follows:
96*09467b48Spatrick   // 1. Identify SCCs and for each SCC create a pi-block node containing all
97*09467b48Spatrick   //    the nodes in that SCC.
98*09467b48Spatrick   // 2. Identify incoming edges incident to the nodes inside of the SCC and
99*09467b48Spatrick   //    reconnect them to the pi-block node.
100*09467b48Spatrick   // 3. Identify outgoing edges from the nodes inside of the SCC to nodes
101*09467b48Spatrick   //    outside of it and reconnect them so that the edges are coming out of the
102*09467b48Spatrick   //    SCC node instead.
103*09467b48Spatrick 
104*09467b48Spatrick   // Adding nodes as we iterate through the SCCs cause the SCC
105*09467b48Spatrick   // iterators to get invalidated. To prevent this invalidation, we first
106*09467b48Spatrick   // collect a list of nodes that are part of an SCC, and then iterate over
107*09467b48Spatrick   // those lists to create the pi-block nodes. Each element of the list is a
108*09467b48Spatrick   // list of nodes in an SCC. Note: trivial SCCs containing a single node are
109*09467b48Spatrick   // ignored.
110*09467b48Spatrick   SmallVector<NodeListType, 4> ListOfSCCs;
111*09467b48Spatrick   for (auto &SCC : make_range(scc_begin(&Graph), scc_end(&Graph))) {
112*09467b48Spatrick     if (SCC.size() > 1)
113*09467b48Spatrick       ListOfSCCs.emplace_back(SCC.begin(), SCC.end());
114*09467b48Spatrick   }
115*09467b48Spatrick 
116*09467b48Spatrick   for (NodeListType &NL : ListOfSCCs) {
117*09467b48Spatrick     LLVM_DEBUG(dbgs() << "Creating pi-block node with " << NL.size()
118*09467b48Spatrick                       << " nodes in it.\n");
119*09467b48Spatrick 
120*09467b48Spatrick     // SCC iterator may put the nodes in an order that's different from the
121*09467b48Spatrick     // program order. To preserve original program order, we sort the list of
122*09467b48Spatrick     // nodes based on ordinal numbers computed earlier.
123*09467b48Spatrick     llvm::sort(NL, [&](NodeType *LHS, NodeType *RHS) {
124*09467b48Spatrick       return getOrdinal(*LHS) < getOrdinal(*RHS);
125*09467b48Spatrick     });
126*09467b48Spatrick 
127*09467b48Spatrick     NodeType &PiNode = createPiBlock(NL);
128*09467b48Spatrick     ++TotalPiBlockNodes;
129*09467b48Spatrick 
130*09467b48Spatrick     // Build a set to speed up the lookup for edges whose targets
131*09467b48Spatrick     // are inside the SCC.
132*09467b48Spatrick     SmallPtrSet<NodeType *, 4> NodesInSCC(NL.begin(), NL.end());
133*09467b48Spatrick 
134*09467b48Spatrick     // We have the set of nodes in the SCC. We go through the set of nodes
135*09467b48Spatrick     // that are outside of the SCC and look for edges that cross the two sets.
136*09467b48Spatrick     for (NodeType *N : Graph) {
137*09467b48Spatrick 
138*09467b48Spatrick       // Skip the SCC node and all the nodes inside of it.
139*09467b48Spatrick       if (*N == PiNode || NodesInSCC.count(N))
140*09467b48Spatrick         continue;
141*09467b48Spatrick 
142*09467b48Spatrick       for (NodeType *SCCNode : NL) {
143*09467b48Spatrick 
144*09467b48Spatrick         enum Direction {
145*09467b48Spatrick           Incoming,      // Incoming edges to the SCC
146*09467b48Spatrick           Outgoing,      // Edges going ot of the SCC
147*09467b48Spatrick           DirectionCount // To make the enum usable as an array index.
148*09467b48Spatrick         };
149*09467b48Spatrick 
150*09467b48Spatrick         // Use these flags to help us avoid creating redundant edges. If there
151*09467b48Spatrick         // are more than one edges from an outside node to inside nodes, we only
152*09467b48Spatrick         // keep one edge from that node to the pi-block node. Similarly, if
153*09467b48Spatrick         // there are more than one edges from inside nodes to an outside node,
154*09467b48Spatrick         // we only keep one edge from the pi-block node to the outside node.
155*09467b48Spatrick         // There is a flag defined for each direction (incoming vs outgoing) and
156*09467b48Spatrick         // for each type of edge supported, using a two-dimensional boolean
157*09467b48Spatrick         // array.
158*09467b48Spatrick         using EdgeKind = typename EdgeType::EdgeKind;
159*09467b48Spatrick         EnumeratedArray<bool, EdgeKind> EdgeAlreadyCreated[DirectionCount]{
160*09467b48Spatrick             false, false};
161*09467b48Spatrick 
162*09467b48Spatrick         auto createEdgeOfKind = [this](NodeType &Src, NodeType &Dst,
163*09467b48Spatrick                                        const EdgeKind K) {
164*09467b48Spatrick           switch (K) {
165*09467b48Spatrick           case EdgeKind::RegisterDefUse:
166*09467b48Spatrick             createDefUseEdge(Src, Dst);
167*09467b48Spatrick             break;
168*09467b48Spatrick           case EdgeKind::MemoryDependence:
169*09467b48Spatrick             createMemoryEdge(Src, Dst);
170*09467b48Spatrick             break;
171*09467b48Spatrick           case EdgeKind::Rooted:
172*09467b48Spatrick             createRootedEdge(Src, Dst);
173*09467b48Spatrick             break;
174*09467b48Spatrick           default:
175*09467b48Spatrick             llvm_unreachable("Unsupported type of edge.");
176*09467b48Spatrick           }
177*09467b48Spatrick         };
178*09467b48Spatrick 
179*09467b48Spatrick         auto reconnectEdges = [&](NodeType *Src, NodeType *Dst, NodeType *New,
180*09467b48Spatrick                                   const Direction Dir) {
181*09467b48Spatrick           if (!Src->hasEdgeTo(*Dst))
182*09467b48Spatrick             return;
183*09467b48Spatrick           LLVM_DEBUG(dbgs()
184*09467b48Spatrick                      << "reconnecting("
185*09467b48Spatrick                      << (Dir == Direction::Incoming ? "incoming)" : "outgoing)")
186*09467b48Spatrick                      << ":\nSrc:" << *Src << "\nDst:" << *Dst
187*09467b48Spatrick                      << "\nNew:" << *New << "\n");
188*09467b48Spatrick           assert((Dir == Direction::Incoming || Dir == Direction::Outgoing) &&
189*09467b48Spatrick                  "Invalid direction.");
190*09467b48Spatrick 
191*09467b48Spatrick           SmallVector<EdgeType *, 10> EL;
192*09467b48Spatrick           Src->findEdgesTo(*Dst, EL);
193*09467b48Spatrick           for (EdgeType *OldEdge : EL) {
194*09467b48Spatrick             EdgeKind Kind = OldEdge->getKind();
195*09467b48Spatrick             if (!EdgeAlreadyCreated[Dir][Kind]) {
196*09467b48Spatrick               if (Dir == Direction::Incoming) {
197*09467b48Spatrick                 createEdgeOfKind(*Src, *New, Kind);
198*09467b48Spatrick                 LLVM_DEBUG(dbgs() << "created edge from Src to New.\n");
199*09467b48Spatrick               } else if (Dir == Direction::Outgoing) {
200*09467b48Spatrick                 createEdgeOfKind(*New, *Dst, Kind);
201*09467b48Spatrick                 LLVM_DEBUG(dbgs() << "created edge from New to Dst.\n");
202*09467b48Spatrick               }
203*09467b48Spatrick               EdgeAlreadyCreated[Dir][Kind] = true;
204*09467b48Spatrick             }
205*09467b48Spatrick             Src->removeEdge(*OldEdge);
206*09467b48Spatrick             destroyEdge(*OldEdge);
207*09467b48Spatrick             LLVM_DEBUG(dbgs() << "removed old edge between Src and Dst.\n\n");
208*09467b48Spatrick           }
209*09467b48Spatrick         };
210*09467b48Spatrick 
211*09467b48Spatrick         // Process incoming edges incident to the pi-block node.
212*09467b48Spatrick         reconnectEdges(N, SCCNode, &PiNode, Direction::Incoming);
213*09467b48Spatrick 
214*09467b48Spatrick         // Process edges that are coming out of the pi-block node.
215*09467b48Spatrick         reconnectEdges(SCCNode, N, &PiNode, Direction::Outgoing);
216*09467b48Spatrick       }
217*09467b48Spatrick     }
218*09467b48Spatrick   }
219*09467b48Spatrick 
220*09467b48Spatrick   // Ordinal maps are no longer needed.
221*09467b48Spatrick   InstOrdinalMap.clear();
222*09467b48Spatrick   NodeOrdinalMap.clear();
223*09467b48Spatrick 
224*09467b48Spatrick   LLVM_DEBUG(dbgs() << "==== End of Creation of Pi-Blocks ===\n");
225*09467b48Spatrick }
226*09467b48Spatrick 
227*09467b48Spatrick template <class G> void AbstractDependenceGraphBuilder<G>::createDefUseEdges() {
228*09467b48Spatrick   for (NodeType *N : Graph) {
229*09467b48Spatrick     InstructionListType SrcIList;
230*09467b48Spatrick     N->collectInstructions([](const Instruction *I) { return true; }, SrcIList);
231*09467b48Spatrick 
232*09467b48Spatrick     // Use a set to mark the targets that we link to N, so we don't add
233*09467b48Spatrick     // duplicate def-use edges when more than one instruction in a target node
234*09467b48Spatrick     // use results of instructions that are contained in N.
235*09467b48Spatrick     SmallPtrSet<NodeType *, 4> VisitedTargets;
236*09467b48Spatrick 
237*09467b48Spatrick     for (Instruction *II : SrcIList) {
238*09467b48Spatrick       for (User *U : II->users()) {
239*09467b48Spatrick         Instruction *UI = dyn_cast<Instruction>(U);
240*09467b48Spatrick         if (!UI)
241*09467b48Spatrick           continue;
242*09467b48Spatrick         NodeType *DstNode = nullptr;
243*09467b48Spatrick         if (IMap.find(UI) != IMap.end())
244*09467b48Spatrick           DstNode = IMap.find(UI)->second;
245*09467b48Spatrick 
246*09467b48Spatrick         // In the case of loops, the scope of the subgraph is all the
247*09467b48Spatrick         // basic blocks (and instructions within them) belonging to the loop. We
248*09467b48Spatrick         // simply ignore all the edges coming from (or going into) instructions
249*09467b48Spatrick         // or basic blocks outside of this range.
250*09467b48Spatrick         if (!DstNode) {
251*09467b48Spatrick           LLVM_DEBUG(
252*09467b48Spatrick               dbgs()
253*09467b48Spatrick               << "skipped def-use edge since the sink" << *UI
254*09467b48Spatrick               << " is outside the range of instructions being considered.\n");
255*09467b48Spatrick           continue;
256*09467b48Spatrick         }
257*09467b48Spatrick 
258*09467b48Spatrick         // Self dependencies are ignored because they are redundant and
259*09467b48Spatrick         // uninteresting.
260*09467b48Spatrick         if (DstNode == N) {
261*09467b48Spatrick           LLVM_DEBUG(dbgs()
262*09467b48Spatrick                      << "skipped def-use edge since the sink and the source ("
263*09467b48Spatrick                      << N << ") are the same.\n");
264*09467b48Spatrick           continue;
265*09467b48Spatrick         }
266*09467b48Spatrick 
267*09467b48Spatrick         if (VisitedTargets.insert(DstNode).second) {
268*09467b48Spatrick           createDefUseEdge(*N, *DstNode);
269*09467b48Spatrick           ++TotalDefUseEdges;
270*09467b48Spatrick         }
271*09467b48Spatrick       }
272*09467b48Spatrick     }
273*09467b48Spatrick   }
274*09467b48Spatrick }
275*09467b48Spatrick 
276*09467b48Spatrick template <class G>
277*09467b48Spatrick void AbstractDependenceGraphBuilder<G>::createMemoryDependencyEdges() {
278*09467b48Spatrick   using DGIterator = typename G::iterator;
279*09467b48Spatrick   auto isMemoryAccess = [](const Instruction *I) {
280*09467b48Spatrick     return I->mayReadOrWriteMemory();
281*09467b48Spatrick   };
282*09467b48Spatrick   for (DGIterator SrcIt = Graph.begin(), E = Graph.end(); SrcIt != E; ++SrcIt) {
283*09467b48Spatrick     InstructionListType SrcIList;
284*09467b48Spatrick     (*SrcIt)->collectInstructions(isMemoryAccess, SrcIList);
285*09467b48Spatrick     if (SrcIList.empty())
286*09467b48Spatrick       continue;
287*09467b48Spatrick 
288*09467b48Spatrick     for (DGIterator DstIt = SrcIt; DstIt != E; ++DstIt) {
289*09467b48Spatrick       if (**SrcIt == **DstIt)
290*09467b48Spatrick         continue;
291*09467b48Spatrick       InstructionListType DstIList;
292*09467b48Spatrick       (*DstIt)->collectInstructions(isMemoryAccess, DstIList);
293*09467b48Spatrick       if (DstIList.empty())
294*09467b48Spatrick         continue;
295*09467b48Spatrick       bool ForwardEdgeCreated = false;
296*09467b48Spatrick       bool BackwardEdgeCreated = false;
297*09467b48Spatrick       for (Instruction *ISrc : SrcIList) {
298*09467b48Spatrick         for (Instruction *IDst : DstIList) {
299*09467b48Spatrick           auto D = DI.depends(ISrc, IDst, true);
300*09467b48Spatrick           if (!D)
301*09467b48Spatrick             continue;
302*09467b48Spatrick 
303*09467b48Spatrick           // If we have a dependence with its left-most non-'=' direction
304*09467b48Spatrick           // being '>' we need to reverse the direction of the edge, because
305*09467b48Spatrick           // the source of the dependence cannot occur after the sink. For
306*09467b48Spatrick           // confused dependencies, we will create edges in both directions to
307*09467b48Spatrick           // represent the possibility of a cycle.
308*09467b48Spatrick 
309*09467b48Spatrick           auto createConfusedEdges = [&](NodeType &Src, NodeType &Dst) {
310*09467b48Spatrick             if (!ForwardEdgeCreated) {
311*09467b48Spatrick               createMemoryEdge(Src, Dst);
312*09467b48Spatrick               ++TotalMemoryEdges;
313*09467b48Spatrick             }
314*09467b48Spatrick             if (!BackwardEdgeCreated) {
315*09467b48Spatrick               createMemoryEdge(Dst, Src);
316*09467b48Spatrick               ++TotalMemoryEdges;
317*09467b48Spatrick             }
318*09467b48Spatrick             ForwardEdgeCreated = BackwardEdgeCreated = true;
319*09467b48Spatrick             ++TotalConfusedEdges;
320*09467b48Spatrick           };
321*09467b48Spatrick 
322*09467b48Spatrick           auto createForwardEdge = [&](NodeType &Src, NodeType &Dst) {
323*09467b48Spatrick             if (!ForwardEdgeCreated) {
324*09467b48Spatrick               createMemoryEdge(Src, Dst);
325*09467b48Spatrick               ++TotalMemoryEdges;
326*09467b48Spatrick             }
327*09467b48Spatrick             ForwardEdgeCreated = true;
328*09467b48Spatrick           };
329*09467b48Spatrick 
330*09467b48Spatrick           auto createBackwardEdge = [&](NodeType &Src, NodeType &Dst) {
331*09467b48Spatrick             if (!BackwardEdgeCreated) {
332*09467b48Spatrick               createMemoryEdge(Dst, Src);
333*09467b48Spatrick               ++TotalMemoryEdges;
334*09467b48Spatrick             }
335*09467b48Spatrick             BackwardEdgeCreated = true;
336*09467b48Spatrick           };
337*09467b48Spatrick 
338*09467b48Spatrick           if (D->isConfused())
339*09467b48Spatrick             createConfusedEdges(**SrcIt, **DstIt);
340*09467b48Spatrick           else if (D->isOrdered() && !D->isLoopIndependent()) {
341*09467b48Spatrick             bool ReversedEdge = false;
342*09467b48Spatrick             for (unsigned Level = 1; Level <= D->getLevels(); ++Level) {
343*09467b48Spatrick               if (D->getDirection(Level) == Dependence::DVEntry::EQ)
344*09467b48Spatrick                 continue;
345*09467b48Spatrick               else if (D->getDirection(Level) == Dependence::DVEntry::GT) {
346*09467b48Spatrick                 createBackwardEdge(**SrcIt, **DstIt);
347*09467b48Spatrick                 ReversedEdge = true;
348*09467b48Spatrick                 ++TotalEdgeReversals;
349*09467b48Spatrick                 break;
350*09467b48Spatrick               } else if (D->getDirection(Level) == Dependence::DVEntry::LT)
351*09467b48Spatrick                 break;
352*09467b48Spatrick               else {
353*09467b48Spatrick                 createConfusedEdges(**SrcIt, **DstIt);
354*09467b48Spatrick                 break;
355*09467b48Spatrick               }
356*09467b48Spatrick             }
357*09467b48Spatrick             if (!ReversedEdge)
358*09467b48Spatrick               createForwardEdge(**SrcIt, **DstIt);
359*09467b48Spatrick           } else
360*09467b48Spatrick             createForwardEdge(**SrcIt, **DstIt);
361*09467b48Spatrick 
362*09467b48Spatrick           // Avoid creating duplicate edges.
363*09467b48Spatrick           if (ForwardEdgeCreated && BackwardEdgeCreated)
364*09467b48Spatrick             break;
365*09467b48Spatrick         }
366*09467b48Spatrick 
367*09467b48Spatrick         // If we've created edges in both directions, there is no more
368*09467b48Spatrick         // unique edge that we can create between these two nodes, so we
369*09467b48Spatrick         // can exit early.
370*09467b48Spatrick         if (ForwardEdgeCreated && BackwardEdgeCreated)
371*09467b48Spatrick           break;
372*09467b48Spatrick       }
373*09467b48Spatrick     }
374*09467b48Spatrick   }
375*09467b48Spatrick }
376*09467b48Spatrick 
377*09467b48Spatrick template <class G>
378*09467b48Spatrick void AbstractDependenceGraphBuilder<G>::sortNodesTopologically() {
379*09467b48Spatrick 
380*09467b48Spatrick   // If we don't create pi-blocks, then we may not have a DAG.
381*09467b48Spatrick   if (!shouldCreatePiBlocks())
382*09467b48Spatrick     return;
383*09467b48Spatrick 
384*09467b48Spatrick   SmallVector<NodeType *, 64> NodesInPO;
385*09467b48Spatrick   using NodeKind = typename NodeType::NodeKind;
386*09467b48Spatrick   for (NodeType *N : post_order(&Graph)) {
387*09467b48Spatrick     if (N->getKind() == NodeKind::PiBlock) {
388*09467b48Spatrick       // Put members of the pi-block right after the pi-block itself, for
389*09467b48Spatrick       // convenience.
390*09467b48Spatrick       const NodeListType &PiBlockMembers = getNodesInPiBlock(*N);
391*09467b48Spatrick       NodesInPO.insert(NodesInPO.end(), PiBlockMembers.begin(),
392*09467b48Spatrick                        PiBlockMembers.end());
393*09467b48Spatrick     }
394*09467b48Spatrick     NodesInPO.push_back(N);
395*09467b48Spatrick   }
396*09467b48Spatrick 
397*09467b48Spatrick   size_t OldSize = Graph.Nodes.size();
398*09467b48Spatrick   Graph.Nodes.clear();
399*09467b48Spatrick   for (NodeType *N : reverse(NodesInPO))
400*09467b48Spatrick     Graph.Nodes.push_back(N);
401*09467b48Spatrick   if (Graph.Nodes.size() != OldSize)
402*09467b48Spatrick     assert(false &&
403*09467b48Spatrick            "Expected the number of nodes to stay the same after the sort");
404*09467b48Spatrick }
405*09467b48Spatrick 
406*09467b48Spatrick template class llvm::AbstractDependenceGraphBuilder<DataDependenceGraph>;
407*09467b48Spatrick template class llvm::DependenceGraphInfo<DDGNode>;
408