109467b48Spatrick //===- DependenceGraphBuilder.cpp ------------------------------------------==// 209467b48Spatrick // 309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information. 509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 609467b48Spatrick // 709467b48Spatrick //===----------------------------------------------------------------------===// 809467b48Spatrick // This file implements common steps of the build algorithm for construction 909467b48Spatrick // of dependence graphs such as DDG and PDG. 1009467b48Spatrick //===----------------------------------------------------------------------===// 1109467b48Spatrick 1209467b48Spatrick #include "llvm/Analysis/DependenceGraphBuilder.h" 13*097a140dSpatrick #include "llvm/ADT/DepthFirstIterator.h" 1409467b48Spatrick #include "llvm/ADT/EnumeratedArray.h" 1509467b48Spatrick #include "llvm/ADT/SCCIterator.h" 1609467b48Spatrick #include "llvm/ADT/Statistic.h" 1709467b48Spatrick #include "llvm/Analysis/DDG.h" 1809467b48Spatrick 1909467b48Spatrick using namespace llvm; 2009467b48Spatrick 2109467b48Spatrick #define DEBUG_TYPE "dgb" 2209467b48Spatrick 2309467b48Spatrick STATISTIC(TotalGraphs, "Number of dependence graphs created."); 2409467b48Spatrick STATISTIC(TotalDefUseEdges, "Number of def-use edges created."); 2509467b48Spatrick STATISTIC(TotalMemoryEdges, "Number of memory dependence edges created."); 2609467b48Spatrick STATISTIC(TotalFineGrainedNodes, "Number of fine-grained nodes created."); 2709467b48Spatrick STATISTIC(TotalPiBlockNodes, "Number of pi-block nodes created."); 2809467b48Spatrick STATISTIC(TotalConfusedEdges, 2909467b48Spatrick "Number of confused memory dependencies between two nodes."); 3009467b48Spatrick STATISTIC(TotalEdgeReversals, 3109467b48Spatrick "Number of times the source and sink of dependence was reversed to " 3209467b48Spatrick "expose cycles in the graph."); 3309467b48Spatrick 3409467b48Spatrick using InstructionListType = SmallVector<Instruction *, 2>; 3509467b48Spatrick 3609467b48Spatrick //===--------------------------------------------------------------------===// 3709467b48Spatrick // AbstractDependenceGraphBuilder implementation 3809467b48Spatrick //===--------------------------------------------------------------------===// 3909467b48Spatrick 4009467b48Spatrick template <class G> 4109467b48Spatrick void AbstractDependenceGraphBuilder<G>::computeInstructionOrdinals() { 4209467b48Spatrick // The BBList is expected to be in program order. 4309467b48Spatrick size_t NextOrdinal = 1; 4409467b48Spatrick for (auto *BB : BBList) 4509467b48Spatrick for (auto &I : *BB) 4609467b48Spatrick InstOrdinalMap.insert(std::make_pair(&I, NextOrdinal++)); 4709467b48Spatrick } 4809467b48Spatrick 4909467b48Spatrick template <class G> 5009467b48Spatrick void AbstractDependenceGraphBuilder<G>::createFineGrainedNodes() { 5109467b48Spatrick ++TotalGraphs; 5209467b48Spatrick assert(IMap.empty() && "Expected empty instruction map at start"); 5309467b48Spatrick for (BasicBlock *BB : BBList) 5409467b48Spatrick for (Instruction &I : *BB) { 5509467b48Spatrick auto &NewNode = createFineGrainedNode(I); 5609467b48Spatrick IMap.insert(std::make_pair(&I, &NewNode)); 5709467b48Spatrick NodeOrdinalMap.insert(std::make_pair(&NewNode, getOrdinal(I))); 5809467b48Spatrick ++TotalFineGrainedNodes; 5909467b48Spatrick } 6009467b48Spatrick } 6109467b48Spatrick 6209467b48Spatrick template <class G> 6309467b48Spatrick void AbstractDependenceGraphBuilder<G>::createAndConnectRootNode() { 6409467b48Spatrick // Create a root node that connects to every connected component of the graph. 6509467b48Spatrick // This is done to allow graph iterators to visit all the disjoint components 6609467b48Spatrick // of the graph, in a single walk. 6709467b48Spatrick // 6809467b48Spatrick // This algorithm works by going through each node of the graph and for each 6909467b48Spatrick // node N, do a DFS starting from N. A rooted edge is established between the 7009467b48Spatrick // root node and N (if N is not yet visited). All the nodes reachable from N 7109467b48Spatrick // are marked as visited and are skipped in the DFS of subsequent nodes. 7209467b48Spatrick // 7309467b48Spatrick // Note: This algorithm tries to limit the number of edges out of the root 7409467b48Spatrick // node to some extent, but there may be redundant edges created depending on 7509467b48Spatrick // the iteration order. For example for a graph {A -> B}, an edge from the 7609467b48Spatrick // root node is added to both nodes if B is visited before A. While it does 7709467b48Spatrick // not result in minimal number of edges, this approach saves compile-time 7809467b48Spatrick // while keeping the number of edges in check. 7909467b48Spatrick auto &RootNode = createRootNode(); 8009467b48Spatrick df_iterator_default_set<const NodeType *, 4> Visited; 8109467b48Spatrick for (auto *N : Graph) { 8209467b48Spatrick if (*N == RootNode) 8309467b48Spatrick continue; 8409467b48Spatrick for (auto I : depth_first_ext(N, Visited)) 8509467b48Spatrick if (I == N) 8609467b48Spatrick createRootedEdge(RootNode, *N); 8709467b48Spatrick } 8809467b48Spatrick } 8909467b48Spatrick 9009467b48Spatrick template <class G> void AbstractDependenceGraphBuilder<G>::createPiBlocks() { 9109467b48Spatrick if (!shouldCreatePiBlocks()) 9209467b48Spatrick return; 9309467b48Spatrick 9409467b48Spatrick LLVM_DEBUG(dbgs() << "==== Start of Creation of Pi-Blocks ===\n"); 9509467b48Spatrick 9609467b48Spatrick // The overall algorithm is as follows: 9709467b48Spatrick // 1. Identify SCCs and for each SCC create a pi-block node containing all 9809467b48Spatrick // the nodes in that SCC. 9909467b48Spatrick // 2. Identify incoming edges incident to the nodes inside of the SCC and 10009467b48Spatrick // reconnect them to the pi-block node. 10109467b48Spatrick // 3. Identify outgoing edges from the nodes inside of the SCC to nodes 10209467b48Spatrick // outside of it and reconnect them so that the edges are coming out of the 10309467b48Spatrick // SCC node instead. 10409467b48Spatrick 10509467b48Spatrick // Adding nodes as we iterate through the SCCs cause the SCC 10609467b48Spatrick // iterators to get invalidated. To prevent this invalidation, we first 10709467b48Spatrick // collect a list of nodes that are part of an SCC, and then iterate over 10809467b48Spatrick // those lists to create the pi-block nodes. Each element of the list is a 10909467b48Spatrick // list of nodes in an SCC. Note: trivial SCCs containing a single node are 11009467b48Spatrick // ignored. 11109467b48Spatrick SmallVector<NodeListType, 4> ListOfSCCs; 11209467b48Spatrick for (auto &SCC : make_range(scc_begin(&Graph), scc_end(&Graph))) { 11309467b48Spatrick if (SCC.size() > 1) 11409467b48Spatrick ListOfSCCs.emplace_back(SCC.begin(), SCC.end()); 11509467b48Spatrick } 11609467b48Spatrick 11709467b48Spatrick for (NodeListType &NL : ListOfSCCs) { 11809467b48Spatrick LLVM_DEBUG(dbgs() << "Creating pi-block node with " << NL.size() 11909467b48Spatrick << " nodes in it.\n"); 12009467b48Spatrick 12109467b48Spatrick // SCC iterator may put the nodes in an order that's different from the 12209467b48Spatrick // program order. To preserve original program order, we sort the list of 12309467b48Spatrick // nodes based on ordinal numbers computed earlier. 12409467b48Spatrick llvm::sort(NL, [&](NodeType *LHS, NodeType *RHS) { 12509467b48Spatrick return getOrdinal(*LHS) < getOrdinal(*RHS); 12609467b48Spatrick }); 12709467b48Spatrick 12809467b48Spatrick NodeType &PiNode = createPiBlock(NL); 12909467b48Spatrick ++TotalPiBlockNodes; 13009467b48Spatrick 13109467b48Spatrick // Build a set to speed up the lookup for edges whose targets 13209467b48Spatrick // are inside the SCC. 13309467b48Spatrick SmallPtrSet<NodeType *, 4> NodesInSCC(NL.begin(), NL.end()); 13409467b48Spatrick 13509467b48Spatrick // We have the set of nodes in the SCC. We go through the set of nodes 13609467b48Spatrick // that are outside of the SCC and look for edges that cross the two sets. 13709467b48Spatrick for (NodeType *N : Graph) { 13809467b48Spatrick 13909467b48Spatrick // Skip the SCC node and all the nodes inside of it. 14009467b48Spatrick if (*N == PiNode || NodesInSCC.count(N)) 14109467b48Spatrick continue; 14209467b48Spatrick 14309467b48Spatrick for (NodeType *SCCNode : NL) { 14409467b48Spatrick 14509467b48Spatrick enum Direction { 14609467b48Spatrick Incoming, // Incoming edges to the SCC 14709467b48Spatrick Outgoing, // Edges going ot of the SCC 14809467b48Spatrick DirectionCount // To make the enum usable as an array index. 14909467b48Spatrick }; 15009467b48Spatrick 15109467b48Spatrick // Use these flags to help us avoid creating redundant edges. If there 15209467b48Spatrick // are more than one edges from an outside node to inside nodes, we only 15309467b48Spatrick // keep one edge from that node to the pi-block node. Similarly, if 15409467b48Spatrick // there are more than one edges from inside nodes to an outside node, 15509467b48Spatrick // we only keep one edge from the pi-block node to the outside node. 15609467b48Spatrick // There is a flag defined for each direction (incoming vs outgoing) and 15709467b48Spatrick // for each type of edge supported, using a two-dimensional boolean 15809467b48Spatrick // array. 15909467b48Spatrick using EdgeKind = typename EdgeType::EdgeKind; 16009467b48Spatrick EnumeratedArray<bool, EdgeKind> EdgeAlreadyCreated[DirectionCount]{ 16109467b48Spatrick false, false}; 16209467b48Spatrick 16309467b48Spatrick auto createEdgeOfKind = [this](NodeType &Src, NodeType &Dst, 16409467b48Spatrick const EdgeKind K) { 16509467b48Spatrick switch (K) { 16609467b48Spatrick case EdgeKind::RegisterDefUse: 16709467b48Spatrick createDefUseEdge(Src, Dst); 16809467b48Spatrick break; 16909467b48Spatrick case EdgeKind::MemoryDependence: 17009467b48Spatrick createMemoryEdge(Src, Dst); 17109467b48Spatrick break; 17209467b48Spatrick case EdgeKind::Rooted: 17309467b48Spatrick createRootedEdge(Src, Dst); 17409467b48Spatrick break; 17509467b48Spatrick default: 17609467b48Spatrick llvm_unreachable("Unsupported type of edge."); 17709467b48Spatrick } 17809467b48Spatrick }; 17909467b48Spatrick 18009467b48Spatrick auto reconnectEdges = [&](NodeType *Src, NodeType *Dst, NodeType *New, 18109467b48Spatrick const Direction Dir) { 18209467b48Spatrick if (!Src->hasEdgeTo(*Dst)) 18309467b48Spatrick return; 18409467b48Spatrick LLVM_DEBUG(dbgs() 18509467b48Spatrick << "reconnecting(" 18609467b48Spatrick << (Dir == Direction::Incoming ? "incoming)" : "outgoing)") 18709467b48Spatrick << ":\nSrc:" << *Src << "\nDst:" << *Dst 18809467b48Spatrick << "\nNew:" << *New << "\n"); 18909467b48Spatrick assert((Dir == Direction::Incoming || Dir == Direction::Outgoing) && 19009467b48Spatrick "Invalid direction."); 19109467b48Spatrick 19209467b48Spatrick SmallVector<EdgeType *, 10> EL; 19309467b48Spatrick Src->findEdgesTo(*Dst, EL); 19409467b48Spatrick for (EdgeType *OldEdge : EL) { 19509467b48Spatrick EdgeKind Kind = OldEdge->getKind(); 19609467b48Spatrick if (!EdgeAlreadyCreated[Dir][Kind]) { 19709467b48Spatrick if (Dir == Direction::Incoming) { 19809467b48Spatrick createEdgeOfKind(*Src, *New, Kind); 19909467b48Spatrick LLVM_DEBUG(dbgs() << "created edge from Src to New.\n"); 20009467b48Spatrick } else if (Dir == Direction::Outgoing) { 20109467b48Spatrick createEdgeOfKind(*New, *Dst, Kind); 20209467b48Spatrick LLVM_DEBUG(dbgs() << "created edge from New to Dst.\n"); 20309467b48Spatrick } 20409467b48Spatrick EdgeAlreadyCreated[Dir][Kind] = true; 20509467b48Spatrick } 20609467b48Spatrick Src->removeEdge(*OldEdge); 20709467b48Spatrick destroyEdge(*OldEdge); 20809467b48Spatrick LLVM_DEBUG(dbgs() << "removed old edge between Src and Dst.\n\n"); 20909467b48Spatrick } 21009467b48Spatrick }; 21109467b48Spatrick 21209467b48Spatrick // Process incoming edges incident to the pi-block node. 21309467b48Spatrick reconnectEdges(N, SCCNode, &PiNode, Direction::Incoming); 21409467b48Spatrick 21509467b48Spatrick // Process edges that are coming out of the pi-block node. 21609467b48Spatrick reconnectEdges(SCCNode, N, &PiNode, Direction::Outgoing); 21709467b48Spatrick } 21809467b48Spatrick } 21909467b48Spatrick } 22009467b48Spatrick 22109467b48Spatrick // Ordinal maps are no longer needed. 22209467b48Spatrick InstOrdinalMap.clear(); 22309467b48Spatrick NodeOrdinalMap.clear(); 22409467b48Spatrick 22509467b48Spatrick LLVM_DEBUG(dbgs() << "==== End of Creation of Pi-Blocks ===\n"); 22609467b48Spatrick } 22709467b48Spatrick 22809467b48Spatrick template <class G> void AbstractDependenceGraphBuilder<G>::createDefUseEdges() { 22909467b48Spatrick for (NodeType *N : Graph) { 23009467b48Spatrick InstructionListType SrcIList; 23109467b48Spatrick N->collectInstructions([](const Instruction *I) { return true; }, SrcIList); 23209467b48Spatrick 23309467b48Spatrick // Use a set to mark the targets that we link to N, so we don't add 23409467b48Spatrick // duplicate def-use edges when more than one instruction in a target node 23509467b48Spatrick // use results of instructions that are contained in N. 23609467b48Spatrick SmallPtrSet<NodeType *, 4> VisitedTargets; 23709467b48Spatrick 23809467b48Spatrick for (Instruction *II : SrcIList) { 23909467b48Spatrick for (User *U : II->users()) { 24009467b48Spatrick Instruction *UI = dyn_cast<Instruction>(U); 24109467b48Spatrick if (!UI) 24209467b48Spatrick continue; 24309467b48Spatrick NodeType *DstNode = nullptr; 24409467b48Spatrick if (IMap.find(UI) != IMap.end()) 24509467b48Spatrick DstNode = IMap.find(UI)->second; 24609467b48Spatrick 24709467b48Spatrick // In the case of loops, the scope of the subgraph is all the 24809467b48Spatrick // basic blocks (and instructions within them) belonging to the loop. We 24909467b48Spatrick // simply ignore all the edges coming from (or going into) instructions 25009467b48Spatrick // or basic blocks outside of this range. 25109467b48Spatrick if (!DstNode) { 25209467b48Spatrick LLVM_DEBUG( 25309467b48Spatrick dbgs() 25409467b48Spatrick << "skipped def-use edge since the sink" << *UI 25509467b48Spatrick << " is outside the range of instructions being considered.\n"); 25609467b48Spatrick continue; 25709467b48Spatrick } 25809467b48Spatrick 25909467b48Spatrick // Self dependencies are ignored because they are redundant and 26009467b48Spatrick // uninteresting. 26109467b48Spatrick if (DstNode == N) { 26209467b48Spatrick LLVM_DEBUG(dbgs() 26309467b48Spatrick << "skipped def-use edge since the sink and the source (" 26409467b48Spatrick << N << ") are the same.\n"); 26509467b48Spatrick continue; 26609467b48Spatrick } 26709467b48Spatrick 26809467b48Spatrick if (VisitedTargets.insert(DstNode).second) { 26909467b48Spatrick createDefUseEdge(*N, *DstNode); 27009467b48Spatrick ++TotalDefUseEdges; 27109467b48Spatrick } 27209467b48Spatrick } 27309467b48Spatrick } 27409467b48Spatrick } 27509467b48Spatrick } 27609467b48Spatrick 27709467b48Spatrick template <class G> 27809467b48Spatrick void AbstractDependenceGraphBuilder<G>::createMemoryDependencyEdges() { 27909467b48Spatrick using DGIterator = typename G::iterator; 28009467b48Spatrick auto isMemoryAccess = [](const Instruction *I) { 28109467b48Spatrick return I->mayReadOrWriteMemory(); 28209467b48Spatrick }; 28309467b48Spatrick for (DGIterator SrcIt = Graph.begin(), E = Graph.end(); SrcIt != E; ++SrcIt) { 28409467b48Spatrick InstructionListType SrcIList; 28509467b48Spatrick (*SrcIt)->collectInstructions(isMemoryAccess, SrcIList); 28609467b48Spatrick if (SrcIList.empty()) 28709467b48Spatrick continue; 28809467b48Spatrick 28909467b48Spatrick for (DGIterator DstIt = SrcIt; DstIt != E; ++DstIt) { 29009467b48Spatrick if (**SrcIt == **DstIt) 29109467b48Spatrick continue; 29209467b48Spatrick InstructionListType DstIList; 29309467b48Spatrick (*DstIt)->collectInstructions(isMemoryAccess, DstIList); 29409467b48Spatrick if (DstIList.empty()) 29509467b48Spatrick continue; 29609467b48Spatrick bool ForwardEdgeCreated = false; 29709467b48Spatrick bool BackwardEdgeCreated = false; 29809467b48Spatrick for (Instruction *ISrc : SrcIList) { 29909467b48Spatrick for (Instruction *IDst : DstIList) { 30009467b48Spatrick auto D = DI.depends(ISrc, IDst, true); 30109467b48Spatrick if (!D) 30209467b48Spatrick continue; 30309467b48Spatrick 30409467b48Spatrick // If we have a dependence with its left-most non-'=' direction 30509467b48Spatrick // being '>' we need to reverse the direction of the edge, because 30609467b48Spatrick // the source of the dependence cannot occur after the sink. For 30709467b48Spatrick // confused dependencies, we will create edges in both directions to 30809467b48Spatrick // represent the possibility of a cycle. 30909467b48Spatrick 31009467b48Spatrick auto createConfusedEdges = [&](NodeType &Src, NodeType &Dst) { 31109467b48Spatrick if (!ForwardEdgeCreated) { 31209467b48Spatrick createMemoryEdge(Src, Dst); 31309467b48Spatrick ++TotalMemoryEdges; 31409467b48Spatrick } 31509467b48Spatrick if (!BackwardEdgeCreated) { 31609467b48Spatrick createMemoryEdge(Dst, Src); 31709467b48Spatrick ++TotalMemoryEdges; 31809467b48Spatrick } 31909467b48Spatrick ForwardEdgeCreated = BackwardEdgeCreated = true; 32009467b48Spatrick ++TotalConfusedEdges; 32109467b48Spatrick }; 32209467b48Spatrick 32309467b48Spatrick auto createForwardEdge = [&](NodeType &Src, NodeType &Dst) { 32409467b48Spatrick if (!ForwardEdgeCreated) { 32509467b48Spatrick createMemoryEdge(Src, Dst); 32609467b48Spatrick ++TotalMemoryEdges; 32709467b48Spatrick } 32809467b48Spatrick ForwardEdgeCreated = true; 32909467b48Spatrick }; 33009467b48Spatrick 33109467b48Spatrick auto createBackwardEdge = [&](NodeType &Src, NodeType &Dst) { 33209467b48Spatrick if (!BackwardEdgeCreated) { 33309467b48Spatrick createMemoryEdge(Dst, Src); 33409467b48Spatrick ++TotalMemoryEdges; 33509467b48Spatrick } 33609467b48Spatrick BackwardEdgeCreated = true; 33709467b48Spatrick }; 33809467b48Spatrick 33909467b48Spatrick if (D->isConfused()) 34009467b48Spatrick createConfusedEdges(**SrcIt, **DstIt); 34109467b48Spatrick else if (D->isOrdered() && !D->isLoopIndependent()) { 34209467b48Spatrick bool ReversedEdge = false; 34309467b48Spatrick for (unsigned Level = 1; Level <= D->getLevels(); ++Level) { 34409467b48Spatrick if (D->getDirection(Level) == Dependence::DVEntry::EQ) 34509467b48Spatrick continue; 34609467b48Spatrick else if (D->getDirection(Level) == Dependence::DVEntry::GT) { 34709467b48Spatrick createBackwardEdge(**SrcIt, **DstIt); 34809467b48Spatrick ReversedEdge = true; 34909467b48Spatrick ++TotalEdgeReversals; 35009467b48Spatrick break; 35109467b48Spatrick } else if (D->getDirection(Level) == Dependence::DVEntry::LT) 35209467b48Spatrick break; 35309467b48Spatrick else { 35409467b48Spatrick createConfusedEdges(**SrcIt, **DstIt); 35509467b48Spatrick break; 35609467b48Spatrick } 35709467b48Spatrick } 35809467b48Spatrick if (!ReversedEdge) 35909467b48Spatrick createForwardEdge(**SrcIt, **DstIt); 36009467b48Spatrick } else 36109467b48Spatrick createForwardEdge(**SrcIt, **DstIt); 36209467b48Spatrick 36309467b48Spatrick // Avoid creating duplicate edges. 36409467b48Spatrick if (ForwardEdgeCreated && BackwardEdgeCreated) 36509467b48Spatrick break; 36609467b48Spatrick } 36709467b48Spatrick 36809467b48Spatrick // If we've created edges in both directions, there is no more 36909467b48Spatrick // unique edge that we can create between these two nodes, so we 37009467b48Spatrick // can exit early. 37109467b48Spatrick if (ForwardEdgeCreated && BackwardEdgeCreated) 37209467b48Spatrick break; 37309467b48Spatrick } 37409467b48Spatrick } 37509467b48Spatrick } 37609467b48Spatrick } 37709467b48Spatrick 378*097a140dSpatrick template <class G> void AbstractDependenceGraphBuilder<G>::simplify() { 379*097a140dSpatrick if (!shouldSimplify()) 380*097a140dSpatrick return; 381*097a140dSpatrick LLVM_DEBUG(dbgs() << "==== Start of Graph Simplification ===\n"); 382*097a140dSpatrick 383*097a140dSpatrick // This algorithm works by first collecting a set of candidate nodes that have 384*097a140dSpatrick // an out-degree of one (in terms of def-use edges), and then ignoring those 385*097a140dSpatrick // whose targets have an in-degree more than one. Each node in the resulting 386*097a140dSpatrick // set can then be merged with its corresponding target and put back into the 387*097a140dSpatrick // worklist until no further merge candidates are available. 388*097a140dSpatrick SmallPtrSet<NodeType *, 32> CandidateSourceNodes; 389*097a140dSpatrick 390*097a140dSpatrick // A mapping between nodes and their in-degree. To save space, this map 391*097a140dSpatrick // only contains nodes that are targets of nodes in the CandidateSourceNodes. 392*097a140dSpatrick DenseMap<NodeType *, unsigned> TargetInDegreeMap; 393*097a140dSpatrick 394*097a140dSpatrick for (NodeType *N : Graph) { 395*097a140dSpatrick if (N->getEdges().size() != 1) 396*097a140dSpatrick continue; 397*097a140dSpatrick EdgeType &Edge = N->back(); 398*097a140dSpatrick if (!Edge.isDefUse()) 399*097a140dSpatrick continue; 400*097a140dSpatrick CandidateSourceNodes.insert(N); 401*097a140dSpatrick 402*097a140dSpatrick // Insert an element into the in-degree map and initialize to zero. The 403*097a140dSpatrick // count will get updated in the next step. 404*097a140dSpatrick TargetInDegreeMap.insert({&Edge.getTargetNode(), 0}); 405*097a140dSpatrick } 406*097a140dSpatrick 407*097a140dSpatrick LLVM_DEBUG({ 408*097a140dSpatrick dbgs() << "Size of candidate src node list:" << CandidateSourceNodes.size() 409*097a140dSpatrick << "\nNode with single outgoing def-use edge:\n"; 410*097a140dSpatrick for (NodeType *N : CandidateSourceNodes) { 411*097a140dSpatrick dbgs() << N << "\n"; 412*097a140dSpatrick } 413*097a140dSpatrick }); 414*097a140dSpatrick 415*097a140dSpatrick for (NodeType *N : Graph) { 416*097a140dSpatrick for (EdgeType *E : *N) { 417*097a140dSpatrick NodeType *Tgt = &E->getTargetNode(); 418*097a140dSpatrick auto TgtIT = TargetInDegreeMap.find(Tgt); 419*097a140dSpatrick if (TgtIT != TargetInDegreeMap.end()) 420*097a140dSpatrick ++(TgtIT->second); 421*097a140dSpatrick } 422*097a140dSpatrick } 423*097a140dSpatrick 424*097a140dSpatrick LLVM_DEBUG({ 425*097a140dSpatrick dbgs() << "Size of target in-degree map:" << TargetInDegreeMap.size() 426*097a140dSpatrick << "\nContent of in-degree map:\n"; 427*097a140dSpatrick for (auto &I : TargetInDegreeMap) { 428*097a140dSpatrick dbgs() << I.first << " --> " << I.second << "\n"; 429*097a140dSpatrick } 430*097a140dSpatrick }); 431*097a140dSpatrick 432*097a140dSpatrick SmallVector<NodeType *, 32> Worklist(CandidateSourceNodes.begin(), 433*097a140dSpatrick CandidateSourceNodes.end()); 434*097a140dSpatrick while (!Worklist.empty()) { 435*097a140dSpatrick NodeType &Src = *Worklist.pop_back_val(); 436*097a140dSpatrick // As nodes get merged, we need to skip any node that has been removed from 437*097a140dSpatrick // the candidate set (see below). 438*097a140dSpatrick if (!CandidateSourceNodes.erase(&Src)) 439*097a140dSpatrick continue; 440*097a140dSpatrick 441*097a140dSpatrick assert(Src.getEdges().size() == 1 && 442*097a140dSpatrick "Expected a single edge from the candidate src node."); 443*097a140dSpatrick NodeType &Tgt = Src.back().getTargetNode(); 444*097a140dSpatrick assert(TargetInDegreeMap.find(&Tgt) != TargetInDegreeMap.end() && 445*097a140dSpatrick "Expected target to be in the in-degree map."); 446*097a140dSpatrick 447*097a140dSpatrick if (TargetInDegreeMap[&Tgt] != 1) 448*097a140dSpatrick continue; 449*097a140dSpatrick 450*097a140dSpatrick if (!areNodesMergeable(Src, Tgt)) 451*097a140dSpatrick continue; 452*097a140dSpatrick 453*097a140dSpatrick // Do not merge if there is also an edge from target to src (immediate 454*097a140dSpatrick // cycle). 455*097a140dSpatrick if (Tgt.hasEdgeTo(Src)) 456*097a140dSpatrick continue; 457*097a140dSpatrick 458*097a140dSpatrick LLVM_DEBUG(dbgs() << "Merging:" << Src << "\nWith:" << Tgt << "\n"); 459*097a140dSpatrick 460*097a140dSpatrick mergeNodes(Src, Tgt); 461*097a140dSpatrick 462*097a140dSpatrick // If the target node is in the candidate set itself, we need to put the 463*097a140dSpatrick // src node back into the worklist again so it gives the target a chance 464*097a140dSpatrick // to get merged into it. For example if we have: 465*097a140dSpatrick // {(a)->(b), (b)->(c), (c)->(d), ...} and the worklist is initially {b, a}, 466*097a140dSpatrick // then after merging (a) and (b) together, we need to put (a,b) back in 467*097a140dSpatrick // the worklist so that (c) can get merged in as well resulting in 468*097a140dSpatrick // {(a,b,c) -> d} 469*097a140dSpatrick // We also need to remove the old target (b), from the worklist. We first 470*097a140dSpatrick // remove it from the candidate set here, and skip any item from the 471*097a140dSpatrick // worklist that is not in the set. 472*097a140dSpatrick if (CandidateSourceNodes.erase(&Tgt)) { 473*097a140dSpatrick Worklist.push_back(&Src); 474*097a140dSpatrick CandidateSourceNodes.insert(&Src); 475*097a140dSpatrick LLVM_DEBUG(dbgs() << "Putting " << &Src << " back in the worklist.\n"); 476*097a140dSpatrick } 477*097a140dSpatrick } 478*097a140dSpatrick LLVM_DEBUG(dbgs() << "=== End of Graph Simplification ===\n"); 479*097a140dSpatrick } 480*097a140dSpatrick 48109467b48Spatrick template <class G> 48209467b48Spatrick void AbstractDependenceGraphBuilder<G>::sortNodesTopologically() { 48309467b48Spatrick 48409467b48Spatrick // If we don't create pi-blocks, then we may not have a DAG. 48509467b48Spatrick if (!shouldCreatePiBlocks()) 48609467b48Spatrick return; 48709467b48Spatrick 48809467b48Spatrick SmallVector<NodeType *, 64> NodesInPO; 48909467b48Spatrick using NodeKind = typename NodeType::NodeKind; 49009467b48Spatrick for (NodeType *N : post_order(&Graph)) { 49109467b48Spatrick if (N->getKind() == NodeKind::PiBlock) { 49209467b48Spatrick // Put members of the pi-block right after the pi-block itself, for 49309467b48Spatrick // convenience. 49409467b48Spatrick const NodeListType &PiBlockMembers = getNodesInPiBlock(*N); 49509467b48Spatrick NodesInPO.insert(NodesInPO.end(), PiBlockMembers.begin(), 49609467b48Spatrick PiBlockMembers.end()); 49709467b48Spatrick } 49809467b48Spatrick NodesInPO.push_back(N); 49909467b48Spatrick } 50009467b48Spatrick 50109467b48Spatrick size_t OldSize = Graph.Nodes.size(); 50209467b48Spatrick Graph.Nodes.clear(); 50309467b48Spatrick for (NodeType *N : reverse(NodesInPO)) 50409467b48Spatrick Graph.Nodes.push_back(N); 50509467b48Spatrick if (Graph.Nodes.size() != OldSize) 50609467b48Spatrick assert(false && 50709467b48Spatrick "Expected the number of nodes to stay the same after the sort"); 50809467b48Spatrick } 50909467b48Spatrick 51009467b48Spatrick template class llvm::AbstractDependenceGraphBuilder<DataDependenceGraph>; 51109467b48Spatrick template class llvm::DependenceGraphInfo<DDGNode>; 512