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