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