xref: /openbsd-src/gnu/llvm/llvm/lib/Analysis/DependenceGraphBuilder.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
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"
13097a140dSpatrick #include "llvm/ADT/DepthFirstIterator.h"
1409467b48Spatrick #include "llvm/ADT/EnumeratedArray.h"
15*d415bd75Srobert #include "llvm/ADT/PostOrderIterator.h"
1609467b48Spatrick #include "llvm/ADT/SCCIterator.h"
1709467b48Spatrick #include "llvm/ADT/Statistic.h"
1809467b48Spatrick #include "llvm/Analysis/DDG.h"
1909467b48Spatrick 
2009467b48Spatrick using namespace llvm;
2109467b48Spatrick 
2209467b48Spatrick #define DEBUG_TYPE "dgb"
2309467b48Spatrick 
2409467b48Spatrick STATISTIC(TotalGraphs, "Number of dependence graphs created.");
2509467b48Spatrick STATISTIC(TotalDefUseEdges, "Number of def-use edges created.");
2609467b48Spatrick STATISTIC(TotalMemoryEdges, "Number of memory dependence edges created.");
2709467b48Spatrick STATISTIC(TotalFineGrainedNodes, "Number of fine-grained nodes created.");
2809467b48Spatrick STATISTIC(TotalPiBlockNodes, "Number of pi-block nodes created.");
2909467b48Spatrick STATISTIC(TotalConfusedEdges,
3009467b48Spatrick           "Number of confused memory dependencies between two nodes.");
3109467b48Spatrick STATISTIC(TotalEdgeReversals,
3209467b48Spatrick           "Number of times the source and sink of dependence was reversed to "
3309467b48Spatrick           "expose cycles in the graph.");
3409467b48Spatrick 
3509467b48Spatrick using InstructionListType = SmallVector<Instruction *, 2>;
3609467b48Spatrick 
3709467b48Spatrick //===--------------------------------------------------------------------===//
3809467b48Spatrick // AbstractDependenceGraphBuilder implementation
3909467b48Spatrick //===--------------------------------------------------------------------===//
4009467b48Spatrick 
4109467b48Spatrick template <class G>
computeInstructionOrdinals()4209467b48Spatrick void AbstractDependenceGraphBuilder<G>::computeInstructionOrdinals() {
4309467b48Spatrick   // The BBList is expected to be in program order.
4409467b48Spatrick   size_t NextOrdinal = 1;
4509467b48Spatrick   for (auto *BB : BBList)
4609467b48Spatrick     for (auto &I : *BB)
4709467b48Spatrick       InstOrdinalMap.insert(std::make_pair(&I, NextOrdinal++));
4809467b48Spatrick }
4909467b48Spatrick 
5009467b48Spatrick template <class G>
createFineGrainedNodes()5109467b48Spatrick void AbstractDependenceGraphBuilder<G>::createFineGrainedNodes() {
5209467b48Spatrick   ++TotalGraphs;
5309467b48Spatrick   assert(IMap.empty() && "Expected empty instruction map at start");
5409467b48Spatrick   for (BasicBlock *BB : BBList)
5509467b48Spatrick     for (Instruction &I : *BB) {
5609467b48Spatrick       auto &NewNode = createFineGrainedNode(I);
5709467b48Spatrick       IMap.insert(std::make_pair(&I, &NewNode));
5809467b48Spatrick       NodeOrdinalMap.insert(std::make_pair(&NewNode, getOrdinal(I)));
5909467b48Spatrick       ++TotalFineGrainedNodes;
6009467b48Spatrick     }
6109467b48Spatrick }
6209467b48Spatrick 
6309467b48Spatrick template <class G>
createAndConnectRootNode()6409467b48Spatrick void AbstractDependenceGraphBuilder<G>::createAndConnectRootNode() {
6509467b48Spatrick   // Create a root node that connects to every connected component of the graph.
6609467b48Spatrick   // This is done to allow graph iterators to visit all the disjoint components
6709467b48Spatrick   // of the graph, in a single walk.
6809467b48Spatrick   //
6909467b48Spatrick   // This algorithm works by going through each node of the graph and for each
7009467b48Spatrick   // node N, do a DFS starting from N. A rooted edge is established between the
7109467b48Spatrick   // root node and N (if N is not yet visited). All the nodes reachable from N
7209467b48Spatrick   // are marked as visited and are skipped in the DFS of subsequent nodes.
7309467b48Spatrick   //
7409467b48Spatrick   // Note: This algorithm tries to limit the number of edges out of the root
7509467b48Spatrick   // node to some extent, but there may be redundant edges created depending on
7609467b48Spatrick   // the iteration order. For example for a graph {A -> B}, an edge from the
7709467b48Spatrick   // root node is added to both nodes if B is visited before A. While it does
7809467b48Spatrick   // not result in minimal number of edges, this approach saves compile-time
7909467b48Spatrick   // while keeping the number of edges in check.
8009467b48Spatrick   auto &RootNode = createRootNode();
8109467b48Spatrick   df_iterator_default_set<const NodeType *, 4> Visited;
8209467b48Spatrick   for (auto *N : Graph) {
8309467b48Spatrick     if (*N == RootNode)
8409467b48Spatrick       continue;
8509467b48Spatrick     for (auto I : depth_first_ext(N, Visited))
8609467b48Spatrick       if (I == N)
8709467b48Spatrick         createRootedEdge(RootNode, *N);
8809467b48Spatrick   }
8909467b48Spatrick }
9009467b48Spatrick 
createPiBlocks()9109467b48Spatrick template <class G> void AbstractDependenceGraphBuilder<G>::createPiBlocks() {
9209467b48Spatrick   if (!shouldCreatePiBlocks())
9309467b48Spatrick     return;
9409467b48Spatrick 
9509467b48Spatrick   LLVM_DEBUG(dbgs() << "==== Start of Creation of Pi-Blocks ===\n");
9609467b48Spatrick 
9709467b48Spatrick   // The overall algorithm is as follows:
9809467b48Spatrick   // 1. Identify SCCs and for each SCC create a pi-block node containing all
9909467b48Spatrick   //    the nodes in that SCC.
10009467b48Spatrick   // 2. Identify incoming edges incident to the nodes inside of the SCC and
10109467b48Spatrick   //    reconnect them to the pi-block node.
10209467b48Spatrick   // 3. Identify outgoing edges from the nodes inside of the SCC to nodes
10309467b48Spatrick   //    outside of it and reconnect them so that the edges are coming out of the
10409467b48Spatrick   //    SCC node instead.
10509467b48Spatrick 
10609467b48Spatrick   // Adding nodes as we iterate through the SCCs cause the SCC
10709467b48Spatrick   // iterators to get invalidated. To prevent this invalidation, we first
10809467b48Spatrick   // collect a list of nodes that are part of an SCC, and then iterate over
10909467b48Spatrick   // those lists to create the pi-block nodes. Each element of the list is a
11009467b48Spatrick   // list of nodes in an SCC. Note: trivial SCCs containing a single node are
11109467b48Spatrick   // ignored.
11209467b48Spatrick   SmallVector<NodeListType, 4> ListOfSCCs;
11309467b48Spatrick   for (auto &SCC : make_range(scc_begin(&Graph), scc_end(&Graph))) {
11409467b48Spatrick     if (SCC.size() > 1)
11509467b48Spatrick       ListOfSCCs.emplace_back(SCC.begin(), SCC.end());
11609467b48Spatrick   }
11709467b48Spatrick 
11809467b48Spatrick   for (NodeListType &NL : ListOfSCCs) {
11909467b48Spatrick     LLVM_DEBUG(dbgs() << "Creating pi-block node with " << NL.size()
12009467b48Spatrick                       << " nodes in it.\n");
12109467b48Spatrick 
12209467b48Spatrick     // SCC iterator may put the nodes in an order that's different from the
12309467b48Spatrick     // program order. To preserve original program order, we sort the list of
12409467b48Spatrick     // nodes based on ordinal numbers computed earlier.
12509467b48Spatrick     llvm::sort(NL, [&](NodeType *LHS, NodeType *RHS) {
12609467b48Spatrick       return getOrdinal(*LHS) < getOrdinal(*RHS);
12709467b48Spatrick     });
12809467b48Spatrick 
12909467b48Spatrick     NodeType &PiNode = createPiBlock(NL);
13009467b48Spatrick     ++TotalPiBlockNodes;
13109467b48Spatrick 
13209467b48Spatrick     // Build a set to speed up the lookup for edges whose targets
13309467b48Spatrick     // are inside the SCC.
13409467b48Spatrick     SmallPtrSet<NodeType *, 4> NodesInSCC(NL.begin(), NL.end());
13509467b48Spatrick 
13609467b48Spatrick     // We have the set of nodes in the SCC. We go through the set of nodes
13709467b48Spatrick     // that are outside of the SCC and look for edges that cross the two sets.
13809467b48Spatrick     for (NodeType *N : Graph) {
13909467b48Spatrick 
14009467b48Spatrick       // Skip the SCC node and all the nodes inside of it.
14109467b48Spatrick       if (*N == PiNode || NodesInSCC.count(N))
14209467b48Spatrick         continue;
14309467b48Spatrick 
14409467b48Spatrick       enum Direction {
14509467b48Spatrick         Incoming,      // Incoming edges to the SCC
14609467b48Spatrick         Outgoing,      // Edges going ot of the SCC
14709467b48Spatrick         DirectionCount // To make the enum usable as an array index.
14809467b48Spatrick       };
14909467b48Spatrick 
15009467b48Spatrick       // Use these flags to help us avoid creating redundant edges. If there
15109467b48Spatrick       // are more than one edges from an outside node to inside nodes, we only
15209467b48Spatrick       // keep one edge from that node to the pi-block node. Similarly, if
15309467b48Spatrick       // there are more than one edges from inside nodes to an outside node,
15409467b48Spatrick       // we only keep one edge from the pi-block node to the outside node.
15509467b48Spatrick       // There is a flag defined for each direction (incoming vs outgoing) and
15609467b48Spatrick       // for each type of edge supported, using a two-dimensional boolean
15709467b48Spatrick       // array.
15809467b48Spatrick       using EdgeKind = typename EdgeType::EdgeKind;
15973471bf0Spatrick       EnumeratedArray<bool, EdgeKind> EdgeAlreadyCreated[DirectionCount]{false,
16073471bf0Spatrick                                                                          false};
16109467b48Spatrick 
16209467b48Spatrick       auto createEdgeOfKind = [this](NodeType &Src, NodeType &Dst,
16309467b48Spatrick                                      const EdgeKind K) {
16409467b48Spatrick         switch (K) {
16509467b48Spatrick         case EdgeKind::RegisterDefUse:
16609467b48Spatrick           createDefUseEdge(Src, Dst);
16709467b48Spatrick           break;
16809467b48Spatrick         case EdgeKind::MemoryDependence:
16909467b48Spatrick           createMemoryEdge(Src, Dst);
17009467b48Spatrick           break;
17109467b48Spatrick         case EdgeKind::Rooted:
17209467b48Spatrick           createRootedEdge(Src, Dst);
17309467b48Spatrick           break;
17409467b48Spatrick         default:
17509467b48Spatrick           llvm_unreachable("Unsupported type of edge.");
17609467b48Spatrick         }
17709467b48Spatrick       };
17809467b48Spatrick 
17909467b48Spatrick       auto reconnectEdges = [&](NodeType *Src, NodeType *Dst, NodeType *New,
18009467b48Spatrick                                 const Direction Dir) {
18109467b48Spatrick         if (!Src->hasEdgeTo(*Dst))
18209467b48Spatrick           return;
18373471bf0Spatrick         LLVM_DEBUG(
18473471bf0Spatrick             dbgs() << "reconnecting("
18509467b48Spatrick                    << (Dir == Direction::Incoming ? "incoming)" : "outgoing)")
18673471bf0Spatrick                    << ":\nSrc:" << *Src << "\nDst:" << *Dst << "\nNew:" << *New
18773471bf0Spatrick                    << "\n");
18809467b48Spatrick         assert((Dir == Direction::Incoming || Dir == Direction::Outgoing) &&
18909467b48Spatrick                "Invalid direction.");
19009467b48Spatrick 
19109467b48Spatrick         SmallVector<EdgeType *, 10> EL;
19209467b48Spatrick         Src->findEdgesTo(*Dst, EL);
19309467b48Spatrick         for (EdgeType *OldEdge : EL) {
19409467b48Spatrick           EdgeKind Kind = OldEdge->getKind();
19509467b48Spatrick           if (!EdgeAlreadyCreated[Dir][Kind]) {
19609467b48Spatrick             if (Dir == Direction::Incoming) {
19709467b48Spatrick               createEdgeOfKind(*Src, *New, Kind);
19809467b48Spatrick               LLVM_DEBUG(dbgs() << "created edge from Src to New.\n");
19909467b48Spatrick             } else if (Dir == Direction::Outgoing) {
20009467b48Spatrick               createEdgeOfKind(*New, *Dst, Kind);
20109467b48Spatrick               LLVM_DEBUG(dbgs() << "created edge from New to Dst.\n");
20209467b48Spatrick             }
20309467b48Spatrick             EdgeAlreadyCreated[Dir][Kind] = true;
20409467b48Spatrick           }
20509467b48Spatrick           Src->removeEdge(*OldEdge);
20609467b48Spatrick           destroyEdge(*OldEdge);
20709467b48Spatrick           LLVM_DEBUG(dbgs() << "removed old edge between Src and Dst.\n\n");
20809467b48Spatrick         }
20909467b48Spatrick       };
21009467b48Spatrick 
21173471bf0Spatrick       for (NodeType *SCCNode : NL) {
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 
createDefUseEdges()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>
createMemoryDependencyEdges()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 
simplify()378097a140dSpatrick template <class G> void AbstractDependenceGraphBuilder<G>::simplify() {
379097a140dSpatrick   if (!shouldSimplify())
380097a140dSpatrick     return;
381097a140dSpatrick   LLVM_DEBUG(dbgs() << "==== Start of Graph Simplification ===\n");
382097a140dSpatrick 
383097a140dSpatrick   // This algorithm works by first collecting a set of candidate nodes that have
384097a140dSpatrick   // an out-degree of one (in terms of def-use edges), and then ignoring those
385097a140dSpatrick   // whose targets have an in-degree more than one. Each node in the resulting
386097a140dSpatrick   // set can then be merged with its corresponding target and put back into the
387097a140dSpatrick   // worklist until no further merge candidates are available.
388097a140dSpatrick   SmallPtrSet<NodeType *, 32> CandidateSourceNodes;
389097a140dSpatrick 
390097a140dSpatrick   // A mapping between nodes and their in-degree. To save space, this map
391097a140dSpatrick   // only contains nodes that are targets of nodes in the CandidateSourceNodes.
392097a140dSpatrick   DenseMap<NodeType *, unsigned> TargetInDegreeMap;
393097a140dSpatrick 
394097a140dSpatrick   for (NodeType *N : Graph) {
395097a140dSpatrick     if (N->getEdges().size() != 1)
396097a140dSpatrick       continue;
397097a140dSpatrick     EdgeType &Edge = N->back();
398097a140dSpatrick     if (!Edge.isDefUse())
399097a140dSpatrick       continue;
400097a140dSpatrick     CandidateSourceNodes.insert(N);
401097a140dSpatrick 
402097a140dSpatrick     // Insert an element into the in-degree map and initialize to zero. The
403097a140dSpatrick     // count will get updated in the next step.
404097a140dSpatrick     TargetInDegreeMap.insert({&Edge.getTargetNode(), 0});
405097a140dSpatrick   }
406097a140dSpatrick 
407097a140dSpatrick   LLVM_DEBUG({
408097a140dSpatrick     dbgs() << "Size of candidate src node list:" << CandidateSourceNodes.size()
409097a140dSpatrick            << "\nNode with single outgoing def-use edge:\n";
410097a140dSpatrick     for (NodeType *N : CandidateSourceNodes) {
411097a140dSpatrick       dbgs() << N << "\n";
412097a140dSpatrick     }
413097a140dSpatrick   });
414097a140dSpatrick 
415097a140dSpatrick   for (NodeType *N : Graph) {
416097a140dSpatrick     for (EdgeType *E : *N) {
417097a140dSpatrick       NodeType *Tgt = &E->getTargetNode();
418097a140dSpatrick       auto TgtIT = TargetInDegreeMap.find(Tgt);
419097a140dSpatrick       if (TgtIT != TargetInDegreeMap.end())
420097a140dSpatrick         ++(TgtIT->second);
421097a140dSpatrick     }
422097a140dSpatrick   }
423097a140dSpatrick 
424097a140dSpatrick   LLVM_DEBUG({
425097a140dSpatrick     dbgs() << "Size of target in-degree map:" << TargetInDegreeMap.size()
426097a140dSpatrick            << "\nContent of in-degree map:\n";
427097a140dSpatrick     for (auto &I : TargetInDegreeMap) {
428097a140dSpatrick       dbgs() << I.first << " --> " << I.second << "\n";
429097a140dSpatrick     }
430097a140dSpatrick   });
431097a140dSpatrick 
432097a140dSpatrick   SmallVector<NodeType *, 32> Worklist(CandidateSourceNodes.begin(),
433097a140dSpatrick                                        CandidateSourceNodes.end());
434097a140dSpatrick   while (!Worklist.empty()) {
435097a140dSpatrick     NodeType &Src = *Worklist.pop_back_val();
436097a140dSpatrick     // As nodes get merged, we need to skip any node that has been removed from
437097a140dSpatrick     // the candidate set (see below).
438097a140dSpatrick     if (!CandidateSourceNodes.erase(&Src))
439097a140dSpatrick       continue;
440097a140dSpatrick 
441097a140dSpatrick     assert(Src.getEdges().size() == 1 &&
442097a140dSpatrick            "Expected a single edge from the candidate src node.");
443097a140dSpatrick     NodeType &Tgt = Src.back().getTargetNode();
444097a140dSpatrick     assert(TargetInDegreeMap.find(&Tgt) != TargetInDegreeMap.end() &&
445097a140dSpatrick            "Expected target to be in the in-degree map.");
446097a140dSpatrick 
447097a140dSpatrick     if (TargetInDegreeMap[&Tgt] != 1)
448097a140dSpatrick       continue;
449097a140dSpatrick 
450097a140dSpatrick     if (!areNodesMergeable(Src, Tgt))
451097a140dSpatrick       continue;
452097a140dSpatrick 
453097a140dSpatrick     // Do not merge if there is also an edge from target to src (immediate
454097a140dSpatrick     // cycle).
455097a140dSpatrick     if (Tgt.hasEdgeTo(Src))
456097a140dSpatrick       continue;
457097a140dSpatrick 
458097a140dSpatrick     LLVM_DEBUG(dbgs() << "Merging:" << Src << "\nWith:" << Tgt << "\n");
459097a140dSpatrick 
460097a140dSpatrick     mergeNodes(Src, Tgt);
461097a140dSpatrick 
462097a140dSpatrick     // If the target node is in the candidate set itself, we need to put the
463097a140dSpatrick     // src node back into the worklist again so it gives the target a chance
464097a140dSpatrick     // to get merged into it. For example if we have:
465097a140dSpatrick     // {(a)->(b), (b)->(c), (c)->(d), ...} and the worklist is initially {b, a},
466097a140dSpatrick     // then after merging (a) and (b) together, we need to put (a,b) back in
467097a140dSpatrick     // the worklist so that (c) can get merged in as well resulting in
468097a140dSpatrick     // {(a,b,c) -> d}
469097a140dSpatrick     // We also need to remove the old target (b), from the worklist. We first
470097a140dSpatrick     // remove it from the candidate set here, and skip any item from the
471097a140dSpatrick     // worklist that is not in the set.
472097a140dSpatrick     if (CandidateSourceNodes.erase(&Tgt)) {
473097a140dSpatrick       Worklist.push_back(&Src);
474097a140dSpatrick       CandidateSourceNodes.insert(&Src);
475097a140dSpatrick       LLVM_DEBUG(dbgs() << "Putting " << &Src << " back in the worklist.\n");
476097a140dSpatrick     }
477097a140dSpatrick   }
478097a140dSpatrick   LLVM_DEBUG(dbgs() << "=== End of Graph Simplification ===\n");
479097a140dSpatrick }
480097a140dSpatrick 
48109467b48Spatrick template <class G>
sortNodesTopologically()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);
49573471bf0Spatrick       llvm::append_range(NodesInPO, PiBlockMembers);
49609467b48Spatrick     }
49709467b48Spatrick     NodesInPO.push_back(N);
49809467b48Spatrick   }
49909467b48Spatrick 
50009467b48Spatrick   size_t OldSize = Graph.Nodes.size();
50109467b48Spatrick   Graph.Nodes.clear();
50273471bf0Spatrick   append_range(Graph.Nodes, reverse(NodesInPO));
50309467b48Spatrick   if (Graph.Nodes.size() != OldSize)
50409467b48Spatrick     assert(false &&
50509467b48Spatrick            "Expected the number of nodes to stay the same after the sort");
50609467b48Spatrick }
50709467b48Spatrick 
50809467b48Spatrick template class llvm::AbstractDependenceGraphBuilder<DataDependenceGraph>;
50909467b48Spatrick template class llvm::DependenceGraphInfo<DDGNode>;
510