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