1db800c26SBardia Mahjour //===- DependenceGraphBuilder.cpp ------------------------------------------==//
2db800c26SBardia Mahjour //
3db800c26SBardia Mahjour // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4db800c26SBardia Mahjour // See https://llvm.org/LICENSE.txt for license information.
5db800c26SBardia Mahjour // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6db800c26SBardia Mahjour //
7db800c26SBardia Mahjour //===----------------------------------------------------------------------===//
8db800c26SBardia Mahjour // This file implements common steps of the build algorithm for construction
9db800c26SBardia Mahjour // of dependence graphs such as DDG and PDG.
10db800c26SBardia Mahjour //===----------------------------------------------------------------------===//
11db800c26SBardia Mahjour
12db800c26SBardia Mahjour #include "llvm/Analysis/DependenceGraphBuilder.h"
135006e551SSimon Pilgrim #include "llvm/ADT/DepthFirstIterator.h"
14f0af11d8Sbmahjour #include "llvm/ADT/EnumeratedArray.h"
15*c6f0940dSBill Wendling #include "llvm/ADT/PostOrderIterator.h"
16db800c26SBardia Mahjour #include "llvm/ADT/SCCIterator.h"
17db800c26SBardia Mahjour #include "llvm/ADT/Statistic.h"
18db800c26SBardia Mahjour #include "llvm/Analysis/DDG.h"
19db800c26SBardia Mahjour
20db800c26SBardia Mahjour using namespace llvm;
21db800c26SBardia Mahjour
22db800c26SBardia Mahjour #define DEBUG_TYPE "dgb"
23db800c26SBardia Mahjour
24db800c26SBardia Mahjour STATISTIC(TotalGraphs, "Number of dependence graphs created.");
25db800c26SBardia Mahjour STATISTIC(TotalDefUseEdges, "Number of def-use edges created.");
26db800c26SBardia Mahjour STATISTIC(TotalMemoryEdges, "Number of memory dependence edges created.");
27db800c26SBardia Mahjour STATISTIC(TotalFineGrainedNodes, "Number of fine-grained nodes created.");
28f0af11d8Sbmahjour STATISTIC(TotalPiBlockNodes, "Number of pi-block nodes created.");
29db800c26SBardia Mahjour STATISTIC(TotalConfusedEdges,
30db800c26SBardia Mahjour "Number of confused memory dependencies between two nodes.");
31db800c26SBardia Mahjour STATISTIC(TotalEdgeReversals,
32db800c26SBardia Mahjour "Number of times the source and sink of dependence was reversed to "
33db800c26SBardia Mahjour "expose cycles in the graph.");
34db800c26SBardia Mahjour
35db800c26SBardia Mahjour using InstructionListType = SmallVector<Instruction *, 2>;
36db800c26SBardia Mahjour
37db800c26SBardia Mahjour //===--------------------------------------------------------------------===//
38db800c26SBardia Mahjour // AbstractDependenceGraphBuilder implementation
39db800c26SBardia Mahjour //===--------------------------------------------------------------------===//
40db800c26SBardia Mahjour
41db800c26SBardia Mahjour template <class G>
computeInstructionOrdinals()4286acaa94SBardia Mahjour void AbstractDependenceGraphBuilder<G>::computeInstructionOrdinals() {
4386acaa94SBardia Mahjour // The BBList is expected to be in program order.
4486acaa94SBardia Mahjour size_t NextOrdinal = 1;
4586acaa94SBardia Mahjour for (auto *BB : BBList)
4686acaa94SBardia Mahjour for (auto &I : *BB)
4786acaa94SBardia Mahjour InstOrdinalMap.insert(std::make_pair(&I, NextOrdinal++));
4886acaa94SBardia Mahjour }
4986acaa94SBardia Mahjour
5086acaa94SBardia Mahjour template <class G>
createFineGrainedNodes()51db800c26SBardia Mahjour void AbstractDependenceGraphBuilder<G>::createFineGrainedNodes() {
52db800c26SBardia Mahjour ++TotalGraphs;
53db800c26SBardia Mahjour assert(IMap.empty() && "Expected empty instruction map at start");
54db800c26SBardia Mahjour for (BasicBlock *BB : BBList)
55db800c26SBardia Mahjour for (Instruction &I : *BB) {
56db800c26SBardia Mahjour auto &NewNode = createFineGrainedNode(I);
57db800c26SBardia Mahjour IMap.insert(std::make_pair(&I, &NewNode));
5886acaa94SBardia Mahjour NodeOrdinalMap.insert(std::make_pair(&NewNode, getOrdinal(I)));
59db800c26SBardia Mahjour ++TotalFineGrainedNodes;
60db800c26SBardia Mahjour }
61db800c26SBardia Mahjour }
62db800c26SBardia Mahjour
6391b62d5cSBardia Mahjour template <class G>
createAndConnectRootNode()6491b62d5cSBardia Mahjour void AbstractDependenceGraphBuilder<G>::createAndConnectRootNode() {
6591b62d5cSBardia Mahjour // Create a root node that connects to every connected component of the graph.
6691b62d5cSBardia Mahjour // This is done to allow graph iterators to visit all the disjoint components
6791b62d5cSBardia Mahjour // of the graph, in a single walk.
6891b62d5cSBardia Mahjour //
6991b62d5cSBardia Mahjour // This algorithm works by going through each node of the graph and for each
7091b62d5cSBardia Mahjour // node N, do a DFS starting from N. A rooted edge is established between the
7191b62d5cSBardia Mahjour // root node and N (if N is not yet visited). All the nodes reachable from N
7291b62d5cSBardia Mahjour // are marked as visited and are skipped in the DFS of subsequent nodes.
7391b62d5cSBardia Mahjour //
7491b62d5cSBardia Mahjour // Note: This algorithm tries to limit the number of edges out of the root
7591b62d5cSBardia Mahjour // node to some extent, but there may be redundant edges created depending on
7691b62d5cSBardia Mahjour // the iteration order. For example for a graph {A -> B}, an edge from the
7791b62d5cSBardia Mahjour // root node is added to both nodes if B is visited before A. While it does
7891b62d5cSBardia Mahjour // not result in minimal number of edges, this approach saves compile-time
7991b62d5cSBardia Mahjour // while keeping the number of edges in check.
8091b62d5cSBardia Mahjour auto &RootNode = createRootNode();
8191b62d5cSBardia Mahjour df_iterator_default_set<const NodeType *, 4> Visited;
8291b62d5cSBardia Mahjour for (auto *N : Graph) {
8391b62d5cSBardia Mahjour if (*N == RootNode)
8491b62d5cSBardia Mahjour continue;
8591b62d5cSBardia Mahjour for (auto I : depth_first_ext(N, Visited))
8691b62d5cSBardia Mahjour if (I == N)
8791b62d5cSBardia Mahjour createRootedEdge(RootNode, *N);
8891b62d5cSBardia Mahjour }
8991b62d5cSBardia Mahjour }
9091b62d5cSBardia Mahjour
createPiBlocks()91f0af11d8Sbmahjour template <class G> void AbstractDependenceGraphBuilder<G>::createPiBlocks() {
92f0af11d8Sbmahjour if (!shouldCreatePiBlocks())
93f0af11d8Sbmahjour return;
94f0af11d8Sbmahjour
95f0af11d8Sbmahjour LLVM_DEBUG(dbgs() << "==== Start of Creation of Pi-Blocks ===\n");
96f0af11d8Sbmahjour
97f0af11d8Sbmahjour // The overall algorithm is as follows:
98f0af11d8Sbmahjour // 1. Identify SCCs and for each SCC create a pi-block node containing all
99f0af11d8Sbmahjour // the nodes in that SCC.
100f0af11d8Sbmahjour // 2. Identify incoming edges incident to the nodes inside of the SCC and
101f0af11d8Sbmahjour // reconnect them to the pi-block node.
102f0af11d8Sbmahjour // 3. Identify outgoing edges from the nodes inside of the SCC to nodes
103f0af11d8Sbmahjour // outside of it and reconnect them so that the edges are coming out of the
104f0af11d8Sbmahjour // SCC node instead.
105f0af11d8Sbmahjour
106f0af11d8Sbmahjour // Adding nodes as we iterate through the SCCs cause the SCC
107f0af11d8Sbmahjour // iterators to get invalidated. To prevent this invalidation, we first
108f0af11d8Sbmahjour // collect a list of nodes that are part of an SCC, and then iterate over
109f0af11d8Sbmahjour // those lists to create the pi-block nodes. Each element of the list is a
110f0af11d8Sbmahjour // list of nodes in an SCC. Note: trivial SCCs containing a single node are
111f0af11d8Sbmahjour // ignored.
112f0af11d8Sbmahjour SmallVector<NodeListType, 4> ListOfSCCs;
113f0af11d8Sbmahjour for (auto &SCC : make_range(scc_begin(&Graph), scc_end(&Graph))) {
114f0af11d8Sbmahjour if (SCC.size() > 1)
115f0af11d8Sbmahjour ListOfSCCs.emplace_back(SCC.begin(), SCC.end());
116f0af11d8Sbmahjour }
117f0af11d8Sbmahjour
118f0af11d8Sbmahjour for (NodeListType &NL : ListOfSCCs) {
119f0af11d8Sbmahjour LLVM_DEBUG(dbgs() << "Creating pi-block node with " << NL.size()
120f0af11d8Sbmahjour << " nodes in it.\n");
121f0af11d8Sbmahjour
12286acaa94SBardia Mahjour // SCC iterator may put the nodes in an order that's different from the
12386acaa94SBardia Mahjour // program order. To preserve original program order, we sort the list of
12486acaa94SBardia Mahjour // nodes based on ordinal numbers computed earlier.
12586acaa94SBardia Mahjour llvm::sort(NL, [&](NodeType *LHS, NodeType *RHS) {
12686acaa94SBardia Mahjour return getOrdinal(*LHS) < getOrdinal(*RHS);
12786acaa94SBardia Mahjour });
12886acaa94SBardia Mahjour
129f0af11d8Sbmahjour NodeType &PiNode = createPiBlock(NL);
130f0af11d8Sbmahjour ++TotalPiBlockNodes;
131f0af11d8Sbmahjour
132f0af11d8Sbmahjour // Build a set to speed up the lookup for edges whose targets
133f0af11d8Sbmahjour // are inside the SCC.
134f0af11d8Sbmahjour SmallPtrSet<NodeType *, 4> NodesInSCC(NL.begin(), NL.end());
135f0af11d8Sbmahjour
136f0af11d8Sbmahjour // We have the set of nodes in the SCC. We go through the set of nodes
137f0af11d8Sbmahjour // that are outside of the SCC and look for edges that cross the two sets.
138f0af11d8Sbmahjour for (NodeType *N : Graph) {
139f0af11d8Sbmahjour
140f0af11d8Sbmahjour // Skip the SCC node and all the nodes inside of it.
141f0af11d8Sbmahjour if (*N == PiNode || NodesInSCC.count(N))
142f0af11d8Sbmahjour continue;
143f0af11d8Sbmahjour
144f0af11d8Sbmahjour enum Direction {
145f0af11d8Sbmahjour Incoming, // Incoming edges to the SCC
146f0af11d8Sbmahjour Outgoing, // Edges going ot of the SCC
147f0af11d8Sbmahjour DirectionCount // To make the enum usable as an array index.
148f0af11d8Sbmahjour };
149f0af11d8Sbmahjour
150f0af11d8Sbmahjour // Use these flags to help us avoid creating redundant edges. If there
151f0af11d8Sbmahjour // are more than one edges from an outside node to inside nodes, we only
152f0af11d8Sbmahjour // keep one edge from that node to the pi-block node. Similarly, if
153f0af11d8Sbmahjour // there are more than one edges from inside nodes to an outside node,
154f0af11d8Sbmahjour // we only keep one edge from the pi-block node to the outside node.
155f0af11d8Sbmahjour // There is a flag defined for each direction (incoming vs outgoing) and
156f0af11d8Sbmahjour // for each type of edge supported, using a two-dimensional boolean
157f0af11d8Sbmahjour // array.
158f0af11d8Sbmahjour using EdgeKind = typename EdgeType::EdgeKind;
159ebfe4de2SBardia Mahjour EnumeratedArray<bool, EdgeKind> EdgeAlreadyCreated[DirectionCount]{false,
160ebfe4de2SBardia Mahjour false};
161f0af11d8Sbmahjour
162f0af11d8Sbmahjour auto createEdgeOfKind = [this](NodeType &Src, NodeType &Dst,
163f0af11d8Sbmahjour const EdgeKind K) {
164f0af11d8Sbmahjour switch (K) {
165f0af11d8Sbmahjour case EdgeKind::RegisterDefUse:
166f0af11d8Sbmahjour createDefUseEdge(Src, Dst);
167f0af11d8Sbmahjour break;
168f0af11d8Sbmahjour case EdgeKind::MemoryDependence:
169f0af11d8Sbmahjour createMemoryEdge(Src, Dst);
170f0af11d8Sbmahjour break;
171f0af11d8Sbmahjour case EdgeKind::Rooted:
172f0af11d8Sbmahjour createRootedEdge(Src, Dst);
173f0af11d8Sbmahjour break;
174f0af11d8Sbmahjour default:
175f0af11d8Sbmahjour llvm_unreachable("Unsupported type of edge.");
176f0af11d8Sbmahjour }
177f0af11d8Sbmahjour };
178f0af11d8Sbmahjour
179f0af11d8Sbmahjour auto reconnectEdges = [&](NodeType *Src, NodeType *Dst, NodeType *New,
180f0af11d8Sbmahjour const Direction Dir) {
181f0af11d8Sbmahjour if (!Src->hasEdgeTo(*Dst))
182f0af11d8Sbmahjour return;
183ebfe4de2SBardia Mahjour LLVM_DEBUG(
184ebfe4de2SBardia Mahjour dbgs() << "reconnecting("
185f0af11d8Sbmahjour << (Dir == Direction::Incoming ? "incoming)" : "outgoing)")
186ebfe4de2SBardia Mahjour << ":\nSrc:" << *Src << "\nDst:" << *Dst << "\nNew:" << *New
187ebfe4de2SBardia Mahjour << "\n");
188f0af11d8Sbmahjour assert((Dir == Direction::Incoming || Dir == Direction::Outgoing) &&
189f0af11d8Sbmahjour "Invalid direction.");
190f0af11d8Sbmahjour
191f0af11d8Sbmahjour SmallVector<EdgeType *, 10> EL;
192f0af11d8Sbmahjour Src->findEdgesTo(*Dst, EL);
193f0af11d8Sbmahjour for (EdgeType *OldEdge : EL) {
194f0af11d8Sbmahjour EdgeKind Kind = OldEdge->getKind();
195f0af11d8Sbmahjour if (!EdgeAlreadyCreated[Dir][Kind]) {
196f0af11d8Sbmahjour if (Dir == Direction::Incoming) {
197f0af11d8Sbmahjour createEdgeOfKind(*Src, *New, Kind);
198f0af11d8Sbmahjour LLVM_DEBUG(dbgs() << "created edge from Src to New.\n");
199f0af11d8Sbmahjour } else if (Dir == Direction::Outgoing) {
200f0af11d8Sbmahjour createEdgeOfKind(*New, *Dst, Kind);
201f0af11d8Sbmahjour LLVM_DEBUG(dbgs() << "created edge from New to Dst.\n");
202f0af11d8Sbmahjour }
203f0af11d8Sbmahjour EdgeAlreadyCreated[Dir][Kind] = true;
204f0af11d8Sbmahjour }
205f0af11d8Sbmahjour Src->removeEdge(*OldEdge);
206f0af11d8Sbmahjour destroyEdge(*OldEdge);
207f0af11d8Sbmahjour LLVM_DEBUG(dbgs() << "removed old edge between Src and Dst.\n\n");
208f0af11d8Sbmahjour }
209f0af11d8Sbmahjour };
210f0af11d8Sbmahjour
211ebfe4de2SBardia Mahjour for (NodeType *SCCNode : NL) {
212f0af11d8Sbmahjour // Process incoming edges incident to the pi-block node.
213f0af11d8Sbmahjour reconnectEdges(N, SCCNode, &PiNode, Direction::Incoming);
214f0af11d8Sbmahjour
215f0af11d8Sbmahjour // Process edges that are coming out of the pi-block node.
216f0af11d8Sbmahjour reconnectEdges(SCCNode, N, &PiNode, Direction::Outgoing);
217f0af11d8Sbmahjour }
218f0af11d8Sbmahjour }
219f0af11d8Sbmahjour }
220f0af11d8Sbmahjour
22186acaa94SBardia Mahjour // Ordinal maps are no longer needed.
22286acaa94SBardia Mahjour InstOrdinalMap.clear();
22386acaa94SBardia Mahjour NodeOrdinalMap.clear();
22486acaa94SBardia Mahjour
225f0af11d8Sbmahjour LLVM_DEBUG(dbgs() << "==== End of Creation of Pi-Blocks ===\n");
226f0af11d8Sbmahjour }
227f0af11d8Sbmahjour
createDefUseEdges()228db800c26SBardia Mahjour template <class G> void AbstractDependenceGraphBuilder<G>::createDefUseEdges() {
229db800c26SBardia Mahjour for (NodeType *N : Graph) {
230db800c26SBardia Mahjour InstructionListType SrcIList;
231db800c26SBardia Mahjour N->collectInstructions([](const Instruction *I) { return true; }, SrcIList);
232db800c26SBardia Mahjour
233db800c26SBardia Mahjour // Use a set to mark the targets that we link to N, so we don't add
234db800c26SBardia Mahjour // duplicate def-use edges when more than one instruction in a target node
235db800c26SBardia Mahjour // use results of instructions that are contained in N.
236db800c26SBardia Mahjour SmallPtrSet<NodeType *, 4> VisitedTargets;
237db800c26SBardia Mahjour
238db800c26SBardia Mahjour for (Instruction *II : SrcIList) {
239db800c26SBardia Mahjour for (User *U : II->users()) {
240db800c26SBardia Mahjour Instruction *UI = dyn_cast<Instruction>(U);
241db800c26SBardia Mahjour if (!UI)
242db800c26SBardia Mahjour continue;
243db800c26SBardia Mahjour NodeType *DstNode = nullptr;
244db800c26SBardia Mahjour if (IMap.find(UI) != IMap.end())
245db800c26SBardia Mahjour DstNode = IMap.find(UI)->second;
246db800c26SBardia Mahjour
247db800c26SBardia Mahjour // In the case of loops, the scope of the subgraph is all the
248db800c26SBardia Mahjour // basic blocks (and instructions within them) belonging to the loop. We
249db800c26SBardia Mahjour // simply ignore all the edges coming from (or going into) instructions
250db800c26SBardia Mahjour // or basic blocks outside of this range.
251db800c26SBardia Mahjour if (!DstNode) {
252db800c26SBardia Mahjour LLVM_DEBUG(
253db800c26SBardia Mahjour dbgs()
254db800c26SBardia Mahjour << "skipped def-use edge since the sink" << *UI
255db800c26SBardia Mahjour << " is outside the range of instructions being considered.\n");
256db800c26SBardia Mahjour continue;
257db800c26SBardia Mahjour }
258db800c26SBardia Mahjour
259db800c26SBardia Mahjour // Self dependencies are ignored because they are redundant and
260db800c26SBardia Mahjour // uninteresting.
261db800c26SBardia Mahjour if (DstNode == N) {
262db800c26SBardia Mahjour LLVM_DEBUG(dbgs()
263db800c26SBardia Mahjour << "skipped def-use edge since the sink and the source ("
264db800c26SBardia Mahjour << N << ") are the same.\n");
265db800c26SBardia Mahjour continue;
266db800c26SBardia Mahjour }
267db800c26SBardia Mahjour
268db800c26SBardia Mahjour if (VisitedTargets.insert(DstNode).second) {
269db800c26SBardia Mahjour createDefUseEdge(*N, *DstNode);
270db800c26SBardia Mahjour ++TotalDefUseEdges;
271db800c26SBardia Mahjour }
272db800c26SBardia Mahjour }
273db800c26SBardia Mahjour }
274db800c26SBardia Mahjour }
275db800c26SBardia Mahjour }
276db800c26SBardia Mahjour
277db800c26SBardia Mahjour template <class G>
createMemoryDependencyEdges()278db800c26SBardia Mahjour void AbstractDependenceGraphBuilder<G>::createMemoryDependencyEdges() {
279db800c26SBardia Mahjour using DGIterator = typename G::iterator;
280db800c26SBardia Mahjour auto isMemoryAccess = [](const Instruction *I) {
281db800c26SBardia Mahjour return I->mayReadOrWriteMemory();
282db800c26SBardia Mahjour };
283db800c26SBardia Mahjour for (DGIterator SrcIt = Graph.begin(), E = Graph.end(); SrcIt != E; ++SrcIt) {
284db800c26SBardia Mahjour InstructionListType SrcIList;
285db800c26SBardia Mahjour (*SrcIt)->collectInstructions(isMemoryAccess, SrcIList);
286db800c26SBardia Mahjour if (SrcIList.empty())
287db800c26SBardia Mahjour continue;
288db800c26SBardia Mahjour
289db800c26SBardia Mahjour for (DGIterator DstIt = SrcIt; DstIt != E; ++DstIt) {
290db800c26SBardia Mahjour if (**SrcIt == **DstIt)
291db800c26SBardia Mahjour continue;
292db800c26SBardia Mahjour InstructionListType DstIList;
293db800c26SBardia Mahjour (*DstIt)->collectInstructions(isMemoryAccess, DstIList);
294db800c26SBardia Mahjour if (DstIList.empty())
295db800c26SBardia Mahjour continue;
296db800c26SBardia Mahjour bool ForwardEdgeCreated = false;
297db800c26SBardia Mahjour bool BackwardEdgeCreated = false;
298db800c26SBardia Mahjour for (Instruction *ISrc : SrcIList) {
299db800c26SBardia Mahjour for (Instruction *IDst : DstIList) {
300db800c26SBardia Mahjour auto D = DI.depends(ISrc, IDst, true);
301db800c26SBardia Mahjour if (!D)
302db800c26SBardia Mahjour continue;
303db800c26SBardia Mahjour
304db800c26SBardia Mahjour // If we have a dependence with its left-most non-'=' direction
305db800c26SBardia Mahjour // being '>' we need to reverse the direction of the edge, because
306db800c26SBardia Mahjour // the source of the dependence cannot occur after the sink. For
307db800c26SBardia Mahjour // confused dependencies, we will create edges in both directions to
308db800c26SBardia Mahjour // represent the possibility of a cycle.
309db800c26SBardia Mahjour
310db800c26SBardia Mahjour auto createConfusedEdges = [&](NodeType &Src, NodeType &Dst) {
311db800c26SBardia Mahjour if (!ForwardEdgeCreated) {
312db800c26SBardia Mahjour createMemoryEdge(Src, Dst);
313db800c26SBardia Mahjour ++TotalMemoryEdges;
314db800c26SBardia Mahjour }
315db800c26SBardia Mahjour if (!BackwardEdgeCreated) {
316db800c26SBardia Mahjour createMemoryEdge(Dst, Src);
317db800c26SBardia Mahjour ++TotalMemoryEdges;
318db800c26SBardia Mahjour }
319db800c26SBardia Mahjour ForwardEdgeCreated = BackwardEdgeCreated = true;
320db800c26SBardia Mahjour ++TotalConfusedEdges;
321db800c26SBardia Mahjour };
322db800c26SBardia Mahjour
323db800c26SBardia Mahjour auto createForwardEdge = [&](NodeType &Src, NodeType &Dst) {
324db800c26SBardia Mahjour if (!ForwardEdgeCreated) {
325db800c26SBardia Mahjour createMemoryEdge(Src, Dst);
326db800c26SBardia Mahjour ++TotalMemoryEdges;
327db800c26SBardia Mahjour }
328db800c26SBardia Mahjour ForwardEdgeCreated = true;
329db800c26SBardia Mahjour };
330db800c26SBardia Mahjour
331db800c26SBardia Mahjour auto createBackwardEdge = [&](NodeType &Src, NodeType &Dst) {
332db800c26SBardia Mahjour if (!BackwardEdgeCreated) {
333db800c26SBardia Mahjour createMemoryEdge(Dst, Src);
334db800c26SBardia Mahjour ++TotalMemoryEdges;
335db800c26SBardia Mahjour }
336db800c26SBardia Mahjour BackwardEdgeCreated = true;
337db800c26SBardia Mahjour };
338db800c26SBardia Mahjour
339db800c26SBardia Mahjour if (D->isConfused())
340db800c26SBardia Mahjour createConfusedEdges(**SrcIt, **DstIt);
341db800c26SBardia Mahjour else if (D->isOrdered() && !D->isLoopIndependent()) {
342db800c26SBardia Mahjour bool ReversedEdge = false;
343db800c26SBardia Mahjour for (unsigned Level = 1; Level <= D->getLevels(); ++Level) {
344db800c26SBardia Mahjour if (D->getDirection(Level) == Dependence::DVEntry::EQ)
345db800c26SBardia Mahjour continue;
346db800c26SBardia Mahjour else if (D->getDirection(Level) == Dependence::DVEntry::GT) {
347db800c26SBardia Mahjour createBackwardEdge(**SrcIt, **DstIt);
348db800c26SBardia Mahjour ReversedEdge = true;
349db800c26SBardia Mahjour ++TotalEdgeReversals;
350db800c26SBardia Mahjour break;
351db800c26SBardia Mahjour } else if (D->getDirection(Level) == Dependence::DVEntry::LT)
352db800c26SBardia Mahjour break;
353db800c26SBardia Mahjour else {
354db800c26SBardia Mahjour createConfusedEdges(**SrcIt, **DstIt);
355db800c26SBardia Mahjour break;
356db800c26SBardia Mahjour }
357db800c26SBardia Mahjour }
358db800c26SBardia Mahjour if (!ReversedEdge)
359db800c26SBardia Mahjour createForwardEdge(**SrcIt, **DstIt);
360db800c26SBardia Mahjour } else
361db800c26SBardia Mahjour createForwardEdge(**SrcIt, **DstIt);
362db800c26SBardia Mahjour
363db800c26SBardia Mahjour // Avoid creating duplicate edges.
364db800c26SBardia Mahjour if (ForwardEdgeCreated && BackwardEdgeCreated)
365db800c26SBardia Mahjour break;
366db800c26SBardia Mahjour }
367db800c26SBardia Mahjour
368db800c26SBardia Mahjour // If we've created edges in both directions, there is no more
369db800c26SBardia Mahjour // unique edge that we can create between these two nodes, so we
370db800c26SBardia Mahjour // can exit early.
371db800c26SBardia Mahjour if (ForwardEdgeCreated && BackwardEdgeCreated)
372db800c26SBardia Mahjour break;
373db800c26SBardia Mahjour }
374db800c26SBardia Mahjour }
375db800c26SBardia Mahjour }
376db800c26SBardia Mahjour }
377db800c26SBardia Mahjour
simplify()3780a2626d0SBardia Mahjour template <class G> void AbstractDependenceGraphBuilder<G>::simplify() {
3790a2626d0SBardia Mahjour if (!shouldSimplify())
3800a2626d0SBardia Mahjour return;
3810a2626d0SBardia Mahjour LLVM_DEBUG(dbgs() << "==== Start of Graph Simplification ===\n");
3820a2626d0SBardia Mahjour
3830a2626d0SBardia Mahjour // This algorithm works by first collecting a set of candidate nodes that have
3840a2626d0SBardia Mahjour // an out-degree of one (in terms of def-use edges), and then ignoring those
3850a2626d0SBardia Mahjour // whose targets have an in-degree more than one. Each node in the resulting
3860a2626d0SBardia Mahjour // set can then be merged with its corresponding target and put back into the
3870a2626d0SBardia Mahjour // worklist until no further merge candidates are available.
3880a2626d0SBardia Mahjour SmallPtrSet<NodeType *, 32> CandidateSourceNodes;
3890a2626d0SBardia Mahjour
3900a2626d0SBardia Mahjour // A mapping between nodes and their in-degree. To save space, this map
3910a2626d0SBardia Mahjour // only contains nodes that are targets of nodes in the CandidateSourceNodes.
3920a2626d0SBardia Mahjour DenseMap<NodeType *, unsigned> TargetInDegreeMap;
3930a2626d0SBardia Mahjour
3940a2626d0SBardia Mahjour for (NodeType *N : Graph) {
3950a2626d0SBardia Mahjour if (N->getEdges().size() != 1)
3960a2626d0SBardia Mahjour continue;
3970a2626d0SBardia Mahjour EdgeType &Edge = N->back();
3980a2626d0SBardia Mahjour if (!Edge.isDefUse())
3990a2626d0SBardia Mahjour continue;
4000a2626d0SBardia Mahjour CandidateSourceNodes.insert(N);
4010a2626d0SBardia Mahjour
4020a2626d0SBardia Mahjour // Insert an element into the in-degree map and initialize to zero. The
4030a2626d0SBardia Mahjour // count will get updated in the next step.
4040a2626d0SBardia Mahjour TargetInDegreeMap.insert({&Edge.getTargetNode(), 0});
4050a2626d0SBardia Mahjour }
4060a2626d0SBardia Mahjour
4070a2626d0SBardia Mahjour LLVM_DEBUG({
4080a2626d0SBardia Mahjour dbgs() << "Size of candidate src node list:" << CandidateSourceNodes.size()
4090a2626d0SBardia Mahjour << "\nNode with single outgoing def-use edge:\n";
4100a2626d0SBardia Mahjour for (NodeType *N : CandidateSourceNodes) {
4110a2626d0SBardia Mahjour dbgs() << N << "\n";
4120a2626d0SBardia Mahjour }
4130a2626d0SBardia Mahjour });
4140a2626d0SBardia Mahjour
4150a2626d0SBardia Mahjour for (NodeType *N : Graph) {
4160a2626d0SBardia Mahjour for (EdgeType *E : *N) {
4170a2626d0SBardia Mahjour NodeType *Tgt = &E->getTargetNode();
4180a2626d0SBardia Mahjour auto TgtIT = TargetInDegreeMap.find(Tgt);
4190a2626d0SBardia Mahjour if (TgtIT != TargetInDegreeMap.end())
4200a2626d0SBardia Mahjour ++(TgtIT->second);
4210a2626d0SBardia Mahjour }
4220a2626d0SBardia Mahjour }
4230a2626d0SBardia Mahjour
4240a2626d0SBardia Mahjour LLVM_DEBUG({
4250a2626d0SBardia Mahjour dbgs() << "Size of target in-degree map:" << TargetInDegreeMap.size()
4260a2626d0SBardia Mahjour << "\nContent of in-degree map:\n";
4270a2626d0SBardia Mahjour for (auto &I : TargetInDegreeMap) {
4280a2626d0SBardia Mahjour dbgs() << I.first << " --> " << I.second << "\n";
4290a2626d0SBardia Mahjour }
4300a2626d0SBardia Mahjour });
4310a2626d0SBardia Mahjour
4320a2626d0SBardia Mahjour SmallVector<NodeType *, 32> Worklist(CandidateSourceNodes.begin(),
4330a2626d0SBardia Mahjour CandidateSourceNodes.end());
4340a2626d0SBardia Mahjour while (!Worklist.empty()) {
4350a2626d0SBardia Mahjour NodeType &Src = *Worklist.pop_back_val();
4360a2626d0SBardia Mahjour // As nodes get merged, we need to skip any node that has been removed from
4370a2626d0SBardia Mahjour // the candidate set (see below).
4383badd17bSBenjamin Kramer if (!CandidateSourceNodes.erase(&Src))
4390a2626d0SBardia Mahjour continue;
4400a2626d0SBardia Mahjour
4410a2626d0SBardia Mahjour assert(Src.getEdges().size() == 1 &&
4420a2626d0SBardia Mahjour "Expected a single edge from the candidate src node.");
4430a2626d0SBardia Mahjour NodeType &Tgt = Src.back().getTargetNode();
4440a2626d0SBardia Mahjour assert(TargetInDegreeMap.find(&Tgt) != TargetInDegreeMap.end() &&
4450a2626d0SBardia Mahjour "Expected target to be in the in-degree map.");
4460a2626d0SBardia Mahjour
4470a2626d0SBardia Mahjour if (TargetInDegreeMap[&Tgt] != 1)
4480a2626d0SBardia Mahjour continue;
4490a2626d0SBardia Mahjour
4500a2626d0SBardia Mahjour if (!areNodesMergeable(Src, Tgt))
4510a2626d0SBardia Mahjour continue;
4520a2626d0SBardia Mahjour
4530a2626d0SBardia Mahjour // Do not merge if there is also an edge from target to src (immediate
4540a2626d0SBardia Mahjour // cycle).
4550a2626d0SBardia Mahjour if (Tgt.hasEdgeTo(Src))
4560a2626d0SBardia Mahjour continue;
4570a2626d0SBardia Mahjour
4580a2626d0SBardia Mahjour LLVM_DEBUG(dbgs() << "Merging:" << Src << "\nWith:" << Tgt << "\n");
4590a2626d0SBardia Mahjour
4600a2626d0SBardia Mahjour mergeNodes(Src, Tgt);
4610a2626d0SBardia Mahjour
4620a2626d0SBardia Mahjour // If the target node is in the candidate set itself, we need to put the
4630a2626d0SBardia Mahjour // src node back into the worklist again so it gives the target a chance
4640a2626d0SBardia Mahjour // to get merged into it. For example if we have:
4650a2626d0SBardia Mahjour // {(a)->(b), (b)->(c), (c)->(d), ...} and the worklist is initially {b, a},
4660a2626d0SBardia Mahjour // then after merging (a) and (b) together, we need to put (a,b) back in
4670a2626d0SBardia Mahjour // the worklist so that (c) can get merged in as well resulting in
4680a2626d0SBardia Mahjour // {(a,b,c) -> d}
4690a2626d0SBardia Mahjour // We also need to remove the old target (b), from the worklist. We first
4700a2626d0SBardia Mahjour // remove it from the candidate set here, and skip any item from the
4710a2626d0SBardia Mahjour // worklist that is not in the set.
4723badd17bSBenjamin Kramer if (CandidateSourceNodes.erase(&Tgt)) {
4730a2626d0SBardia Mahjour Worklist.push_back(&Src);
4740a2626d0SBardia Mahjour CandidateSourceNodes.insert(&Src);
4750a2626d0SBardia Mahjour LLVM_DEBUG(dbgs() << "Putting " << &Src << " back in the worklist.\n");
4760a2626d0SBardia Mahjour }
4770a2626d0SBardia Mahjour }
4780a2626d0SBardia Mahjour LLVM_DEBUG(dbgs() << "=== End of Graph Simplification ===\n");
4790a2626d0SBardia Mahjour }
4800a2626d0SBardia Mahjour
4812dd82a1cSBardia Mahjour template <class G>
sortNodesTopologically()4822dd82a1cSBardia Mahjour void AbstractDependenceGraphBuilder<G>::sortNodesTopologically() {
4832dd82a1cSBardia Mahjour
4842dd82a1cSBardia Mahjour // If we don't create pi-blocks, then we may not have a DAG.
4852dd82a1cSBardia Mahjour if (!shouldCreatePiBlocks())
4862dd82a1cSBardia Mahjour return;
4872dd82a1cSBardia Mahjour
4882dd82a1cSBardia Mahjour SmallVector<NodeType *, 64> NodesInPO;
4892dd82a1cSBardia Mahjour using NodeKind = typename NodeType::NodeKind;
4902dd82a1cSBardia Mahjour for (NodeType *N : post_order(&Graph)) {
4912dd82a1cSBardia Mahjour if (N->getKind() == NodeKind::PiBlock) {
4922dd82a1cSBardia Mahjour // Put members of the pi-block right after the pi-block itself, for
4932dd82a1cSBardia Mahjour // convenience.
4942dd82a1cSBardia Mahjour const NodeListType &PiBlockMembers = getNodesInPiBlock(*N);
495f76e83bfSKazu Hirata llvm::append_range(NodesInPO, PiBlockMembers);
4962dd82a1cSBardia Mahjour }
4972dd82a1cSBardia Mahjour NodesInPO.push_back(N);
4982dd82a1cSBardia Mahjour }
4992dd82a1cSBardia Mahjour
5002dd82a1cSBardia Mahjour size_t OldSize = Graph.Nodes.size();
5012dd82a1cSBardia Mahjour Graph.Nodes.clear();
502a3254904SKazu Hirata append_range(Graph.Nodes, reverse(NodesInPO));
5032dd82a1cSBardia Mahjour if (Graph.Nodes.size() != OldSize)
5042dd82a1cSBardia Mahjour assert(false &&
5052dd82a1cSBardia Mahjour "Expected the number of nodes to stay the same after the sort");
5062dd82a1cSBardia Mahjour }
5072dd82a1cSBardia Mahjour
508db800c26SBardia Mahjour template class llvm::AbstractDependenceGraphBuilder<DataDependenceGraph>;
509db800c26SBardia Mahjour template class llvm::DependenceGraphInfo<DDGNode>;
510