llvm.org GIT mirror llvm / 11e505a
Data Dependence Graph Basics Summary: This is the first patch in a series of patches that will implement data dependence graph in LLVM. Many of the ideas used in this implementation are based on the following paper: D. J. Kuck, R. H. Kuhn, D. A. Padua, B. Leasure, and M. Wolfe (1981). DEPENDENCE GRAPHS AND COMPILER OPTIMIZATIONS. This patch contains support for a basic DDGs containing only atomic nodes (one node for each instruction). The edges are two fold: def-use edges and memory-dependence edges. The implementation takes a list of basic-blocks and only considers dependencies among instructions in those basic blocks. Any dependencies coming into or going out of instructions that do not belong to those basic blocks are ignored. The algorithm for building the graph involves the following steps in order: 1. For each instruction in the range of basic blocks to consider, create an atomic node in the resulting graph. 2. For each node in the graph establish def-use edges to/from other nodes in the graph. 3. For each pair of nodes containing memory instruction(s) create memory edges between them. This part of the algorithm goes through the instructions in lexicographical order and creates edges in reverse order if the sink of the dependence occurs before the source of it. Authored By: bmahjour Reviewer: Meinersbur, fhahn, myhsu, xtian, dmgreen, kbarton, jdoerfert Reviewed By: Meinersbur, fhahn, myhsu Subscribers: ychen, arphaman, simoll, a.elovikov, mgorny, hiraditya, jfb, wuzish, llvm-commits, jsji, Whitney, etiotto Tag: #llvm Differential Revision: https://reviews.llvm.org/D65350 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@372162 91177308-0d34-0410-b5e6-96231b3b80d8 Bardia Mahjour a month ago
16 changed file(s) with 1845 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
0 =========================
1 Dependence Graphs in LLVM
2 =========================
3
4 .. contents::
5 :local:
6
7 Dependence graphs are useful tools in compilers for analyzing relationships
8 between various program elements to help guide optimizations. The ideas
9 behind these graphs are described in the following two papers:
10
11 .. [1] "D. J. Kuck, R. H. Kuhn, D. A. Padua, B. Leasure, and M. Wolfe (1981). DEPENDENCE GRAPHS AND COMPILER OPTIMIZATIONS."
12 .. [2] "J. FERRANTE (IBM), K. J. OTTENSTEIN (Michigan Technological University) and JOE D. WARREN (Rice University), 1987. The Program Dependence Graph and Its Use in Optimization."
13
14 The implementation of these ideas in LLVM may be slightly different than
15 what is mentioned in the papers. These differences are documented in
16 the `implementation details `_.
17
18 .. _DataDependenceGraph:
19
20 Data Dependence Graph
21 =====================
22 In its simplest form the Data Dependence Graph (or DDG) represents data
23 dependencies between individual instructions. Each node in such a graph
24 represents a single instruction and is referred to as an "atomic" node.
25 It is also possible to combine some atomic nodes that have a simple
26 def-use dependency between them into larger nodes that contain multiple-
27 instructions.
28
29 As described in [1]_ the DDG uses graph abstraction to group nodes
30 that are part of a strongly connected component of the graph
31 into special nodes called pi-blocks. pi-blocks represent cycles of data
32 dependency that prevent reordering transformations. Since any strongly
33 connected component of the graph is a maximal subgraph of all the nodes
34 that form a cycle, pi-blocks are at most one level deep. In other words,
35 no pi-blocks are nested inside another pi-block, resulting in a
36 hierarchical representation that is at most one level deep.
37
38
39 For example, consider the following:
40
41 .. code-block:: c++
42
43 for (int i = 1; i < n; i++) {
44 b[i] = c[i] + b[i-1];
45 }
46
47 This code contains a statement that has a loop carried dependence on
48 itself creating a cycle in the DDG. The figure bellow illustrates
49 how the cycle of dependency is carried through multiple def-use relations
50 and a memory access dependency.
51
52 .. image:: cycle.png
53
54 The DDG corresponding to this example would have a pi-block that contains
55 all the nodes participating in the cycle, as shown bellow:
56
57 .. image:: cycle_pi.png
58
59 Program Dependence Graph
60 ========================
61
62 The Program Dependence Graph (or PDG) has a similar structure as the
63 DDG, but it is capable of representing both data dependencies and
64 control-flow dependencies between program elements such as
65 instructions, groups of instructions, basic blocks or groups of
66 basic blocks.
67
68 High-Level Design
69 =================
70
71 The DDG and the PDG are both directed graphs and they extend the
72 ``DirectedGraph`` class. Each implementation extends its corresponding
73 node and edge types resulting in the inheritance relationship depicted
74 in the UML diagram bellow:
75
76 .. image:: uml_nodes_and_edges.png
77
78 Graph Construction
79 ------------------
80
81 The graph build algorithm considers dependencies between elements of
82 a given set of instructions or basic blocks. Any dependencies coming
83 into or going out of instructions that do not belong to that range
84 are ignored. The steps in the build algorithm for the DDG are very
85 similar to the steps in the build algorithm for the PDG. As such,
86 one of the design goals is to reuse the build algorithm code to
87 allow creation of both DDG and PDG representations while allowing
88 the two implementations to define their own distinct and independent
89 node and edge types. This is achieved by using the well-known builder
90 design pattern to isolate the construction of the dependence graph
91 from its concrete representation.
92
93 The following UML diagram depicts the overall structure of the design
94 pattern as it applies to the dependence graph implementation.
95
96 .. image:: uml_builder_pattern.png
97
98 Notice that the common code for building the two types of graphs are
99 provided in the ``DependenceGraphBuilder`` class, while the ``DDGBuilder``
100 and ``PDGBuilder`` control some aspects of how the graph is constructed
101 by the way of overriding virtual methods defined in ``DependenceGraphBuilder``.
102
103 Note also that the steps and the names used in this diagram are for
104 illustrative purposes and may be different from those in the actual
105 implementation.
106
107 Design Trade-offs
108 -----------------
109
110 Advantages:
111 ^^^^^^^^^^^
112 - Builder allows graph construction code to be reused for DDG and PDG.
113 - Builder allows us to create DDG and PDG as separate graphs.
114 - DDG nodes and edges are completely disjoint from PDG nodes and edges allowing them to change easily and independently.
115
116 Disadvantages:
117 ^^^^^^^^^^^^^^
118 - Builder may be perceived as over-engineering at first.
119 - There are some similarities between DDG nodes and edges compared to PDG nodes and edges, but there is little reuse of the class definitions.
120
121 - This is tolerable given that the node and edge types are fairly simple and there is little code reuse opportunity anyway.
122
123
124 .. _implementation-details:
125
126 Implementation Details
127 ======================
128
129 The current implementation of DDG differs slightly from the dependence
130 graph described in [1]_ in the following ways:
131
132 1. The graph nodes in the paper represent three main program components, namely *assignment statements*, *for loop headers* and *while loop headers*. In this implementation, DDG nodes naturally represent LLVM IR instructions. An assignment statement in this implementation typically involves a node representing the ``store`` instruction along with a number of individual nodes computing the right-hand-side of the assignment that connect to the ``store`` node via a def-use edge. The loop header instructions are not represented as special nodes in this implementation because they have limited uses and can be easily identified, for example, through ``LoopAnalysis``.
133 2. The paper describes five types of dependency edges between nodes namely *loop dependency*, *flow-*, *anti-*, *output-*, and *input-* dependencies. In this implementation *memory* edges represent the *flow-*, *anti-*, *output-*, and *input-* dependencies. However, *loop dependencies* are not made explicit, because they mainly represent association between a loop structure and the program elements inside the loop and this association is fairly obvious in LLVM IR itself.
134 3. The paper describes two types of pi-blocks; *recurrences* whose bodies are SCCs and *IN* nodes whose bodies are not part of any SCC. In this impelmentation, pi-blocks are only created for *recurrences*. *IN* nodes remain as simple DDG nodes in the graph.
5454 SpeculativeLoadHardening
5555 StackSafetyAnalysis
5656 LoopTerminology
57 DataDependenceGraphs
5758
5859 :doc:`WritingAnLLVMPass`
5960 Information on how to write LLVM transformations and analyses.
206207 variables.
207208
208209 :doc:`LoopTerminology`
209 A document describing Loops and associated terms as used in LLVM.
210 A document describing Loops and associated terms as used in LLVM.
211
212 :doc:`DataDependenceGraphs`
213 A description of the design of the DDG (Data Dependence Graph).
0 //===- llvm/Analysis/DDG.h --------------------------------------*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file defines the Data-Dependence Graph (DDG).
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_ANALYSIS_DDG_H
13 #define LLVM_ANALYSIS_DDG_H
14
15 #include "llvm/ADT/DirectedGraph.h"
16 #include "llvm/Analysis/DependenceAnalysis.h"
17 #include "llvm/Analysis/DependenceGraphBuilder.h"
18 #include "llvm/Analysis/LoopPass.h"
19 #include "llvm/IR/Instructions.h"
20 #include "llvm/Transforms/Scalar/LoopPassManager.h"
21 #include
22
23 namespace llvm {
24 class DDGNode;
25 class DDGEdge;
26 using DDGNodeBase = DGNode;
27 using DDGEdgeBase = DGEdge;
28 using DDGBase = DirectedGraph;
29
30 /// Data Dependence Graph Node
31 /// The graph can represent the following types of nodes:
32 /// 1. Single instruction node containing just one instruction.
33 /// 2. Multiple instruction node where two or more instructions from
34 /// the same basic block are merged into one node.
35 class DDGNode : public DDGNodeBase {
36 public:
37 using InstructionListType = SmallVectorImpl;
38
39 enum class NodeKind {
40 Unknown,
41 SingleInstruction,
42 MultiInstruction,
43 };
44
45 DDGNode() = delete;
46 DDGNode(const NodeKind K) : DDGNodeBase(), Kind(K) {}
47 DDGNode(const DDGNode &N) : DDGNodeBase(N), Kind(N.Kind) {}
48 DDGNode(DDGNode &&N) : DDGNodeBase(std::move(N)), Kind(N.Kind) {}
49 virtual ~DDGNode() = 0;
50
51 DDGNode &operator=(const DDGNode &N) {
52 DGNode::operator=(N);
53 Kind = N.Kind;
54 return *this;
55 }
56
57 DDGNode &operator=(DDGNode &&N) {
58 DGNode::operator=(std::move(N));
59 Kind = N.Kind;
60 return *this;
61 }
62
63 /// Getter for the kind of this node.
64 NodeKind getKind() const { return Kind; }
65
66 /// Collect a list of instructions, in \p IList, for which predicate \p Pred
67 /// evaluates to true when iterating over instructions of this node. Return
68 /// true if at least one instruction was collected, and false otherwise.
69 bool collectInstructions(llvm::function_ref const &Pred,
70 InstructionListType &IList) const;
71
72 protected:
73 /// Setter for the kind of this node.
74 void setKind(NodeKind K) { Kind = K; }
75
76 private:
77 NodeKind Kind;
78 };
79
80 /// Subclass of DDGNode representing single or multi-instruction nodes.
81 class SimpleDDGNode : public DDGNode {
82 public:
83 SimpleDDGNode() = delete;
84 SimpleDDGNode(Instruction &I);
85 SimpleDDGNode(const SimpleDDGNode &N);
86 SimpleDDGNode(SimpleDDGNode &&N);
87 ~SimpleDDGNode();
88
89 SimpleDDGNode &operator=(const SimpleDDGNode &N) {
90 DDGNode::operator=(N);
91 InstList = N.InstList;
92 return *this;
93 }
94
95 SimpleDDGNode &operator=(SimpleDDGNode &&N) {
96 DDGNode::operator=(std::move(N));
97 InstList = std::move(N.InstList);
98 return *this;
99 }
100
101 /// Get the list of instructions in this node.
102 const InstructionListType &getInstructions() const {
103 assert(!InstList.empty() && "Instruction List is empty.");
104 return InstList;
105 }
106 InstructionListType &getInstructions() {
107 return const_cast(
108 static_cast(this)->getInstructions());
109 }
110
111 /// Get the first/last instruction in the node.
112 Instruction *getFirstInstruction() const { return getInstructions().front(); }
113 Instruction *getLastInstruction() const { return getInstructions().back(); }
114
115 /// Define classof to be able to use isa<>, cast<>, dyn_cast<>, etc.
116 static bool classof(const DDGNode *N) {
117 return N->getKind() == NodeKind::SingleInstruction ||
118 N->getKind() == NodeKind::MultiInstruction;
119 }
120 static bool classof(const SimpleDDGNode *N) { return true; }
121
122 private:
123 /// Append the list of instructions in \p Input to this node.
124 void appendInstructions(const InstructionListType &Input) {
125 setKind((InstList.size() == 0 && Input.size() == 1)
126 ? NodeKind::SingleInstruction
127 : NodeKind::MultiInstruction);
128 InstList.insert(InstList.end(), Input.begin(), Input.end());
129 }
130 void appendInstructions(const SimpleDDGNode &Input) {
131 appendInstructions(Input.getInstructions());
132 }
133
134 /// List of instructions associated with a single or multi-instruction node.
135 SmallVector InstList;
136 };
137
138 /// Data Dependency Graph Edge.
139 /// An edge in the DDG can represent a def-use relationship or
140 /// a memory dependence based on the result of DependenceAnalysis.
141 class DDGEdge : public DDGEdgeBase {
142 public:
143 /// The kind of edge in the DDG
144 enum class EdgeKind { Unknown, RegisterDefUse, MemoryDependence };
145
146 explicit DDGEdge(DDGNode &N) = delete;
147 DDGEdge(DDGNode &N, EdgeKind K) : DDGEdgeBase(N), Kind(K) {}
148 DDGEdge(const DDGEdge &E) : DDGEdgeBase(E), Kind(E.getKind()) {}
149 DDGEdge(DDGEdge &&E) : DDGEdgeBase(std::move(E)), Kind(E.Kind) {}
150 DDGEdge &operator=(const DDGEdge &E) {
151 DDGEdgeBase::operator=(E);
152 Kind = E.Kind;
153 return *this;
154 }
155
156 DDGEdge &operator=(DDGEdge &&E) {
157 DDGEdgeBase::operator=(std::move(E));
158 Kind = E.Kind;
159 return *this;
160 }
161
162 /// Get the edge kind
163 EdgeKind getKind() const { return Kind; };
164
165 /// Return true if this is a def-use edge, and false otherwise.
166 bool isDefUse() const { return Kind == EdgeKind::RegisterDefUse; }
167
168 /// Return true if this is a memory dependence edge, and false otherwise.
169 bool isMemoryDependence() const { return Kind == EdgeKind::MemoryDependence; }
170
171 private:
172 EdgeKind Kind;
173 };
174
175 /// Encapsulate some common data and functionality needed for different
176 /// variations of data dependence graphs.
177 template class DependenceGraphInfo {
178 public:
179 using DependenceList = SmallVector, 1>;
180
181 DependenceGraphInfo() = delete;
182 DependenceGraphInfo(const DependenceGraphInfo &G) = delete;
183 DependenceGraphInfo(const std::string &N, const DependenceInfo &DepInfo)
184 : Name(N), DI(DepInfo) {}
185 DependenceGraphInfo(DependenceGraphInfo &&G)
186 : Name(std::move(G.Name)), DI(std::move(G.DI)) {}
187 virtual ~DependenceGraphInfo() {}
188
189 /// Return the label that is used to name this graph.
190 const StringRef getName() const { return Name; }
191
192 protected:
193 // Name of the graph.
194 std::string Name;
195
196 // Store a copy of DependenceInfo in the graph, so that individual memory
197 // dependencies don't need to be stored. Instead when the dependence is
198 // queried it is recomputed using @DI.
199 const DependenceInfo DI;
200 };
201
202 using DDGInfo = DependenceGraphInfo;
203
204 /// Data Dependency Graph
205 class DataDependenceGraph : public DDGBase, public DDGInfo {
206 friend class DDGBuilder;
207
208 public:
209 using NodeType = DDGNode;
210 using EdgeType = DDGEdge;
211
212 DataDependenceGraph() = delete;
213 DataDependenceGraph(const DataDependenceGraph &G) = delete;
214 DataDependenceGraph(DataDependenceGraph &&G)
215 : DDGBase(std::move(G)), DDGInfo(std::move(G)) {}
216 DataDependenceGraph(Function &F, DependenceInfo &DI);
217 DataDependenceGraph(const Loop &L, DependenceInfo &DI);
218 ~DataDependenceGraph();
219 };
220
221 /// Concrete implementation of a pure data dependence graph builder. This class
222 /// provides custom implementation for the pure-virtual functions used in the
223 /// generic dependence graph build algorithm.
224 ///
225 /// For information about time complexity of the build algorithm see the
226 /// comments near the declaration of AbstractDependenceGraphBuilder.
227 class DDGBuilder : public AbstractDependenceGraphBuilder {
228 public:
229 DDGBuilder(DataDependenceGraph &G, DependenceInfo &D,
230 const BasicBlockListType &BBs)
231 : AbstractDependenceGraphBuilder(G, D, BBs) {}
232 DDGNode &createFineGrainedNode(Instruction &I) final override {
233 auto *SN = new SimpleDDGNode(I);
234 assert(SN && "Failed to allocate memory for simple DDG node.");
235 Graph.addNode(*SN);
236 return *SN;
237 }
238 DDGEdge &createDefUseEdge(DDGNode &Src, DDGNode &Tgt) final override {
239 auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::RegisterDefUse);
240 assert(E && "Failed to allocate memory for edge");
241 Graph.connect(Src, Tgt, *E);
242 return *E;
243 }
244 DDGEdge &createMemoryEdge(DDGNode &Src, DDGNode &Tgt) final override {
245 auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::MemoryDependence);
246 assert(E && "Failed to allocate memory for edge");
247 Graph.connect(Src, Tgt, *E);
248 return *E;
249 }
250 };
251
252 raw_ostream &operator<<(raw_ostream &OS, const DDGNode &N);
253 raw_ostream &operator<<(raw_ostream &OS, const DDGNode::NodeKind K);
254 raw_ostream &operator<<(raw_ostream &OS, const DDGEdge &E);
255 raw_ostream &operator<<(raw_ostream &OS, const DDGEdge::EdgeKind K);
256 raw_ostream &operator<<(raw_ostream &OS, const DataDependenceGraph &G);
257
258 //===--------------------------------------------------------------------===//
259 // DDG Analysis Passes
260 //===--------------------------------------------------------------------===//
261
262 /// Analysis pass that builds the DDG for a loop.
263 class DDGAnalysis : public AnalysisInfoMixin {
264 public:
265 using Result = std::unique_ptr;
266 Result run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR);
267
268 private:
269 friend AnalysisInfoMixin;
270 static AnalysisKey Key;
271 };
272
273 /// Textual printer pass for the DDG of a loop.
274 class DDGAnalysisPrinterPass : public PassInfoMixin {
275 public:
276 explicit DDGAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {}
277 PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM,
278 LoopStandardAnalysisResults &AR, LPMUpdater &U);
279
280 private:
281 raw_ostream &OS;
282 };
283
284 //===--------------------------------------------------------------------===//
285 // GraphTraits specializations for the DDG
286 //===--------------------------------------------------------------------===//
287
288 /// non-const versions of the grapth trait specializations for DDG
289 template <> struct GraphTraits {
290 using NodeRef = DDGNode *;
291
292 static DDGNode *DDGGetTargetNode(DGEdge *P) {
293 return &P->getTargetNode();
294 }
295
296 // Provide a mapped iterator so that the GraphTrait-based implementations can
297 // find the target nodes without having to explicitly go through the edges.
298 using ChildIteratorType =
299 mapped_iterator;
300 using ChildEdgeIteratorType = DDGNode::iterator;
301
302 static NodeRef getEntryNode(NodeRef N) { return N; }
303 static ChildIteratorType child_begin(NodeRef N) {
304 return ChildIteratorType(N->begin(), &DDGGetTargetNode);
305 }
306 static ChildIteratorType child_end(NodeRef N) {
307 return ChildIteratorType(N->end(), &DDGGetTargetNode);
308 }
309
310 static ChildEdgeIteratorType child_edge_begin(NodeRef N) {
311 return N->begin();
312 }
313 static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
314 };
315
316 template <>
317 struct GraphTraits : public GraphTraits {
318 using nodes_iterator = DataDependenceGraph::iterator;
319 static NodeRef getEntryNode(DataDependenceGraph *DG) { return *DG->begin(); }
320 static nodes_iterator nodes_begin(DataDependenceGraph *DG) {
321 return DG->begin();
322 }
323 static nodes_iterator nodes_end(DataDependenceGraph *DG) { return DG->end(); }
324 };
325
326 /// const versions of the grapth trait specializations for DDG
327 template <> struct GraphTraits {
328 using NodeRef = const DDGNode *;
329
330 static const DDGNode *DDGGetTargetNode(const DGEdge *P) {
331 return &P->getTargetNode();
332 }
333
334 // Provide a mapped iterator so that the GraphTrait-based implementations can
335 // find the target nodes without having to explicitly go through the edges.
336 using ChildIteratorType =
337 mapped_iterator;
338 using ChildEdgeIteratorType = DDGNode::const_iterator;
339
340 static NodeRef getEntryNode(NodeRef N) { return N; }
341 static ChildIteratorType child_begin(NodeRef N) {
342 return ChildIteratorType(N->begin(), &DDGGetTargetNode);
343 }
344 static ChildIteratorType child_end(NodeRef N) {
345 return ChildIteratorType(N->end(), &DDGGetTargetNode);
346 }
347
348 static ChildEdgeIteratorType child_edge_begin(NodeRef N) {
349 return N->begin();
350 }
351 static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
352 };
353
354 template <>
355 struct GraphTraits
356 : public GraphTraits {
357 using nodes_iterator = DataDependenceGraph::const_iterator;
358 static NodeRef getEntryNode(const DataDependenceGraph *DG) {
359 return *DG->begin();
360 }
361 static nodes_iterator nodes_begin(const DataDependenceGraph *DG) {
362 return DG->begin();
363 }
364 static nodes_iterator nodes_end(const DataDependenceGraph *DG) {
365 return DG->end();
366 }
367 };
368
369 } // namespace llvm
370
371 #endif // LLVM_ANALYSIS_DDG_H
0 //===- llvm/Analysis/DependenceGraphBuilder.h -------------------*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file defines a builder interface that can be used to populate dependence
9 // graphs such as DDG and PDG.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_ANALYSIS_DEPENDENCE_GRAPH_BUILDER_H
14 #define LLVM_ANALYSIS_DEPENDENCE_GRAPH_BUILDER_H
15
16 #include "llvm/ADT/EquivalenceClasses.h"
17 #include "llvm/Analysis/DependenceAnalysis.h"
18 #include "llvm/IR/BasicBlock.h"
19 #include "llvm/IR/Instructions.h"
20
21 namespace llvm {
22
23 /// This abstract builder class defines a set of high-level steps for creating
24 /// DDG-like graphs. The client code is expected to inherit from this class and
25 /// define concrete implementation for each of the pure virtual functions used
26 /// in the high-level algorithm.
27 template class AbstractDependenceGraphBuilder {
28 protected:
29 using BasicBlockListType = SmallVectorImpl;
30
31 private:
32 using NodeType = typename GraphType::NodeType;
33 using EdgeType = typename GraphType::EdgeType;
34
35 public:
36 using ClassesType = EquivalenceClasses;
37 using NodeListType = SmallVector;
38
39 AbstractDependenceGraphBuilder(GraphType &G, DependenceInfo &D,
40 const BasicBlockListType &BBs)
41 : Graph(G), DI(D), BBList(BBs) {}
42 virtual ~AbstractDependenceGraphBuilder() {}
43
44 /// The main entry to the graph construction algorithm. It starts by
45 /// creating nodes in increasing order of granularity and then
46 /// adds def-use and memory edges.
47 ///
48 /// The algorithmic complexity of this implementation is O(V^2 * I^2), where V
49 /// is the number of vertecies (nodes) and I is the number of instructions in
50 /// each node. The total number of instructions, N, is equal to V * I,
51 /// therefore the worst-case time complexity is O(N^2). The average time
52 /// complexity is O((N^2)/2).
53 void populate() {
54 createFineGrainedNodes();
55 createDefUseEdges();
56 createMemoryDependencyEdges();
57 }
58
59 /// Create fine grained nodes. These are typically atomic nodes that
60 /// consist of a single instruction.
61 void createFineGrainedNodes();
62
63 /// Analyze the def-use chains and create edges from the nodes containing
64 /// definitions to the nodes containing the uses.
65 void createDefUseEdges();
66
67 /// Analyze data dependencies that exist between memory loads or stores,
68 /// in the graph nodes and create edges between them.
69 void createMemoryDependencyEdges();
70
71 protected:
72 /// Create an atomic node in the graph given a single instruction.
73 virtual NodeType &createFineGrainedNode(Instruction &I) = 0;
74
75 /// Create a def-use edge going from \p Src to \p Tgt.
76 virtual EdgeType &createDefUseEdge(NodeType &Src, NodeType &Tgt) = 0;
77
78 /// Create a memory dependence edge going from \p Src to \p Tgt.
79 virtual EdgeType &createMemoryEdge(NodeType &Src, NodeType &Tgt) = 0;
80
81 /// Deallocate memory of edge \p E.
82 virtual void destroyEdge(EdgeType &E) { delete &E; }
83
84 /// Deallocate memory of node \p N.
85 virtual void destroyNode(NodeType &N) { delete &N; }
86
87 /// Map types to map instructions to nodes used when populating the graph.
88 using InstToNodeMap = DenseMap;
89
90 /// Reference to the graph that gets built by a concrete implementation of
91 /// this builder.
92 GraphType &Graph;
93
94 /// Dependence information used to create memory dependence edges in the
95 /// graph.
96 DependenceInfo &DI;
97
98 /// The list of basic blocks to consider when building the graph.
99 const BasicBlockListType &BBList;
100
101 /// A mapping from instructions to the corresponding nodes in the graph.
102 InstToNodeMap IMap;
103 };
104
105 } // namespace llvm
106
107 #endif // LLVM_ANALYSIS_DEPENDENCE_GRAPH_BUILDER_H
2121 CostModel.cpp
2222 CodeMetrics.cpp
2323 ConstantFolding.cpp
24 DDG.cpp
2425 Delinearization.cpp
2526 DemandedBits.cpp
2627 DependenceAnalysis.cpp
28 DependenceGraphBuilder.cpp
2729 DivergenceAnalysis.cpp
2830 DomPrinter.cpp
2931 DomTreeUpdater.cpp
0 //===- DDG.cpp - Data Dependence Graph -------------------------------------==//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // The implementation for the data dependence graph.
9 //===----------------------------------------------------------------------===//
10 #include "llvm/Analysis/DDG.h"
11 #include "llvm/Analysis/LoopInfo.h"
12
13 using namespace llvm;
14
15 #define DEBUG_TYPE "ddg"
16
17 template class llvm::DGEdge;
18 template class llvm::DGNode;
19 template class llvm::DirectedGraph;
20
21 //===--------------------------------------------------------------------===//
22 // DDGNode implementation
23 //===--------------------------------------------------------------------===//
24 DDGNode::~DDGNode() {}
25
26 bool DDGNode::collectInstructions(
27 llvm::function_ref const &Pred,
28 InstructionListType &IList) const {
29 assert(IList.empty() && "Expected the IList to be empty on entry.");
30 if (isa(this)) {
31 for (auto *I : cast(this)->getInstructions())
32 if (Pred(I))
33 IList.push_back(I);
34 } else
35 llvm_unreachable("unimplemented type of node");
36 return !IList.empty();
37 }
38
39 raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGNode::NodeKind K) {
40 const char *Out;
41 switch (K) {
42 case DDGNode::NodeKind::SingleInstruction:
43 Out = "single-instruction";
44 break;
45 case DDGNode::NodeKind::MultiInstruction:
46 Out = "multi-instruction";
47 break;
48 case DDGNode::NodeKind::Unknown:
49 Out = "??";
50 break;
51 }
52 OS << Out;
53 return OS;
54 }
55
56 raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGNode &N) {
57 OS << "Node Address:" << &N << ":" << N.getKind() << "\n";
58 if (isa(N)) {
59 OS << " Instructions:\n";
60 for (auto *I : cast(N).getInstructions())
61 OS.indent(2) << *I << "\n";
62 } else
63 llvm_unreachable("unimplemented type of node");
64
65 OS << (N.getEdges().empty() ? " Edges:none!\n" : " Edges:\n");
66 for (auto &E : N.getEdges())
67 OS.indent(2) << *E;
68 return OS;
69 }
70
71 //===--------------------------------------------------------------------===//
72 // SimpleDDGNode implementation
73 //===--------------------------------------------------------------------===//
74
75 SimpleDDGNode::SimpleDDGNode(Instruction &I)
76 : DDGNode(NodeKind::SingleInstruction), InstList() {
77 assert(InstList.empty() && "Expected empty list.");
78 InstList.push_back(&I);
79 }
80
81 SimpleDDGNode::SimpleDDGNode(const SimpleDDGNode &N)
82 : DDGNode(N), InstList(N.InstList) {
83 assert(((getKind() == NodeKind::SingleInstruction && InstList.size() == 1) ||
84 (getKind() == NodeKind::MultiInstruction && InstList.size() > 1)) &&
85 "constructing from invalid simple node.");
86 }
87
88 SimpleDDGNode::SimpleDDGNode(SimpleDDGNode &&N)
89 : DDGNode(std::move(N)), InstList(std::move(N.InstList)) {
90 assert(((getKind() == NodeKind::SingleInstruction && InstList.size() == 1) ||
91 (getKind() == NodeKind::MultiInstruction && InstList.size() > 1)) &&
92 "constructing from invalid simple node.");
93 }
94
95 SimpleDDGNode::~SimpleDDGNode() { InstList.clear(); }
96
97 //===--------------------------------------------------------------------===//
98 // DDGEdge implementation
99 //===--------------------------------------------------------------------===//
100
101 raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGEdge::EdgeKind K) {
102 const char *Out;
103 switch (K) {
104 case DDGEdge::EdgeKind::RegisterDefUse:
105 Out = "def-use";
106 break;
107 case DDGEdge::EdgeKind::MemoryDependence:
108 Out = "memory";
109 break;
110 case DDGEdge::EdgeKind::Unknown:
111 Out = "??";
112 break;
113 }
114 OS << Out;
115 return OS;
116 }
117
118 raw_ostream &llvm::operator<<(raw_ostream &OS, const DDGEdge &E) {
119 OS << "[" << E.getKind() << "] to " << &E.getTargetNode() << "\n";
120 return OS;
121 }
122
123 //===--------------------------------------------------------------------===//
124 // DataDependenceGraph implementation
125 //===--------------------------------------------------------------------===//
126 using BasicBlockListType = SmallVector;
127
128 DataDependenceGraph::DataDependenceGraph(Function &F, DependenceInfo &D)
129 : DependenceGraphInfo(F.getName().str(), D) {
130 BasicBlockListType BBList;
131 for (auto &BB : F.getBasicBlockList())
132 BBList.push_back(&BB);
133 DDGBuilder(*this, D, BBList).populate();
134 }
135
136 DataDependenceGraph::DataDependenceGraph(const Loop &L, DependenceInfo &D)
137 : DependenceGraphInfo(Twine(L.getHeader()->getParent()->getName() + "." +
138 L.getHeader()->getName())
139 .str(),
140 D) {
141 BasicBlockListType BBList;
142 for (BasicBlock *BB : L.blocks())
143 BBList.push_back(BB);
144 DDGBuilder(*this, D, BBList).populate();
145 }
146
147 DataDependenceGraph::~DataDependenceGraph() {
148 for (auto *N : Nodes) {
149 for (auto *E : *N)
150 delete E;
151 delete N;
152 }
153 }
154
155 raw_ostream &llvm::operator<<(raw_ostream &OS, const DataDependenceGraph &G) {
156 for (auto *Node : G)
157 OS << *Node << "\n";
158 return OS;
159 }
160
161 //===--------------------------------------------------------------------===//
162 // DDG Analysis Passes
163 //===--------------------------------------------------------------------===//
164
165 /// DDG as a loop pass.
166 DDGAnalysis::Result DDGAnalysis::run(Loop &L, LoopAnalysisManager &AM,
167 LoopStandardAnalysisResults &AR) {
168 Function *F = L.getHeader()->getParent();
169 DependenceInfo DI(F, &AR.AA, &AR.SE, &AR.LI);
170 return std::make_unique(L, DI);
171 }
172 AnalysisKey DDGAnalysis::Key;
173
174 PreservedAnalyses DDGAnalysisPrinterPass::run(Loop &L, LoopAnalysisManager &AM,
175 LoopStandardAnalysisResults &AR,
176 LPMUpdater &U) {
177 OS << "'DDG' for loop '" << L.getHeader()->getName() << "':\n";
178 OS << *AM.getResult(L, AR);
179 return PreservedAnalyses::all();
180 }
0 //===- DependenceGraphBuilder.cpp ------------------------------------------==//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 // This file implements common steps of the build algorithm for construction
8 // of dependence graphs such as DDG and PDG.
9 //===----------------------------------------------------------------------===//
10
11 #include "llvm/Analysis/DependenceGraphBuilder.h"
12 #include "llvm/ADT/SCCIterator.h"
13 #include "llvm/ADT/Statistic.h"
14 #include "llvm/Analysis/DDG.h"
15
16 using namespace llvm;
17
18 #define DEBUG_TYPE "dgb"
19
20 STATISTIC(TotalGraphs, "Number of dependence graphs created.");
21 STATISTIC(TotalDefUseEdges, "Number of def-use edges created.");
22 STATISTIC(TotalMemoryEdges, "Number of memory dependence edges created.");
23 STATISTIC(TotalFineGrainedNodes, "Number of fine-grained nodes created.");
24 STATISTIC(TotalConfusedEdges,
25 "Number of confused memory dependencies between two nodes.");
26 STATISTIC(TotalEdgeReversals,
27 "Number of times the source and sink of dependence was reversed to "
28 "expose cycles in the graph.");
29
30 using InstructionListType = SmallVector;
31
32 //===--------------------------------------------------------------------===//
33 // AbstractDependenceGraphBuilder implementation
34 //===--------------------------------------------------------------------===//
35
36 template
37 void AbstractDependenceGraphBuilder::createFineGrainedNodes() {
38 ++TotalGraphs;
39 assert(IMap.empty() && "Expected empty instruction map at start");
40 for (BasicBlock *BB : BBList)
41 for (Instruction &I : *BB) {
42 auto &NewNode = createFineGrainedNode(I);
43 IMap.insert(std::make_pair(&I, &NewNode));
44 ++TotalFineGrainedNodes;
45 }
46 }
47
48 template void AbstractDependenceGraphBuilder::createDefUseEdges() {
49 for (NodeType *N : Graph) {
50 InstructionListType SrcIList;
51 N->collectInstructions([](const Instruction *I) { return true; }, SrcIList);
52
53 // Use a set to mark the targets that we link to N, so we don't add
54 // duplicate def-use edges when more than one instruction in a target node
55 // use results of instructions that are contained in N.
56 SmallPtrSet VisitedTargets;
57
58 for (Instruction *II : SrcIList) {
59 for (User *U : II->users()) {
60 Instruction *UI = dyn_cast(U);
61 if (!UI)
62 continue;
63 NodeType *DstNode = nullptr;
64 if (IMap.find(UI) != IMap.end())
65 DstNode = IMap.find(UI)->second;
66
67 // In the case of loops, the scope of the subgraph is all the
68 // basic blocks (and instructions within them) belonging to the loop. We
69 // simply ignore all the edges coming from (or going into) instructions
70 // or basic blocks outside of this range.
71 if (!DstNode) {
72 LLVM_DEBUG(
73 dbgs()
74 << "skipped def-use edge since the sink" << *UI
75 << " is outside the range of instructions being considered.\n");
76 continue;
77 }
78
79 // Self dependencies are ignored because they are redundant and
80 // uninteresting.
81 if (DstNode == N) {
82 LLVM_DEBUG(dbgs()
83 << "skipped def-use edge since the sink and the source ("
84 << N << ") are the same.\n");
85 continue;
86 }
87
88 if (VisitedTargets.insert(DstNode).second) {
89 createDefUseEdge(*N, *DstNode);
90 ++TotalDefUseEdges;
91 }
92 }
93 }
94 }
95 }
96
97 template
98 void AbstractDependenceGraphBuilder::createMemoryDependencyEdges() {
99 using DGIterator = typename G::iterator;
100 auto isMemoryAccess = [](const Instruction *I) {
101 return I->mayReadOrWriteMemory();
102 };
103 for (DGIterator SrcIt = Graph.begin(), E = Graph.end(); SrcIt != E; ++SrcIt) {
104 InstructionListType SrcIList;
105 (*SrcIt)->collectInstructions(isMemoryAccess, SrcIList);
106 if (SrcIList.empty())
107 continue;
108
109 for (DGIterator DstIt = SrcIt; DstIt != E; ++DstIt) {
110 if (**SrcIt == **DstIt)
111 continue;
112 InstructionListType DstIList;
113 (*DstIt)->collectInstructions(isMemoryAccess, DstIList);
114 if (DstIList.empty())
115 continue;
116 bool ForwardEdgeCreated = false;
117 bool BackwardEdgeCreated = false;
118 for (Instruction *ISrc : SrcIList) {
119 for (Instruction *IDst : DstIList) {
120 auto D = DI.depends(ISrc, IDst, true);
121 if (!D)
122 continue;
123
124 // If we have a dependence with its left-most non-'=' direction
125 // being '>' we need to reverse the direction of the edge, because
126 // the source of the dependence cannot occur after the sink. For
127 // confused dependencies, we will create edges in both directions to
128 // represent the possibility of a cycle.
129
130 auto createConfusedEdges = [&](NodeType &Src, NodeType &Dst) {
131 if (!ForwardEdgeCreated) {
132 createMemoryEdge(Src, Dst);
133 ++TotalMemoryEdges;
134 }
135 if (!BackwardEdgeCreated) {
136 createMemoryEdge(Dst, Src);
137 ++TotalMemoryEdges;
138 }
139 ForwardEdgeCreated = BackwardEdgeCreated = true;
140 ++TotalConfusedEdges;
141 };
142
143 auto createForwardEdge = [&](NodeType &Src, NodeType &Dst) {
144 if (!ForwardEdgeCreated) {
145 createMemoryEdge(Src, Dst);
146 ++TotalMemoryEdges;
147 }
148 ForwardEdgeCreated = true;
149 };
150
151 auto createBackwardEdge = [&](NodeType &Src, NodeType &Dst) {
152 if (!BackwardEdgeCreated) {
153 createMemoryEdge(Dst, Src);
154 ++TotalMemoryEdges;
155 }
156 BackwardEdgeCreated = true;
157 };
158
159 if (D->isConfused())
160 createConfusedEdges(**SrcIt, **DstIt);
161 else if (D->isOrdered() && !D->isLoopIndependent()) {
162 bool ReversedEdge = false;
163 for (unsigned Level = 1; Level <= D->getLevels(); ++Level) {
164 if (D->getDirection(Level) == Dependence::DVEntry::EQ)
165 continue;
166 else if (D->getDirection(Level) == Dependence::DVEntry::GT) {
167 createBackwardEdge(**SrcIt, **DstIt);
168 ReversedEdge = true;
169 ++TotalEdgeReversals;
170 break;
171 } else if (D->getDirection(Level) == Dependence::DVEntry::LT)
172 break;
173 else {
174 createConfusedEdges(**SrcIt, **DstIt);
175 break;
176 }
177 }
178 if (!ReversedEdge)
179 createForwardEdge(**SrcIt, **DstIt);
180 } else
181 createForwardEdge(**SrcIt, **DstIt);
182
183 // Avoid creating duplicate edges.
184 if (ForwardEdgeCreated && BackwardEdgeCreated)
185 break;
186 }
187
188 // If we've created edges in both directions, there is no more
189 // unique edge that we can create between these two nodes, so we
190 // can exit early.
191 if (ForwardEdgeCreated && BackwardEdgeCreated)
192 break;
193 }
194 }
195 }
196 }
197
198 template class llvm::AbstractDependenceGraphBuilder;
199 template class llvm::DependenceGraphInfo;
2626 #include "llvm/Analysis/CFLSteensAliasAnalysis.h"
2727 #include "llvm/Analysis/CGSCCPassManager.h"
2828 #include "llvm/Analysis/CallGraph.h"
29 #include "llvm/Analysis/DDG.h"
2930 #include "llvm/Analysis/DemandedBits.h"
3031 #include "llvm/Analysis/DependenceAnalysis.h"
3132 #include "llvm/Analysis/DominanceFrontier.h"
280280 #endif
281281 LOOP_ANALYSIS("no-op-loop", NoOpLoopAnalysis())
282282 LOOP_ANALYSIS("access-info", LoopAccessAnalysis())
283 LOOP_ANALYSIS("ddg", DDGAnalysis())
283284 LOOP_ANALYSIS("ivusers", IVUsersAnalysis())
284285 LOOP_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis(PIC))
285286 #undef LOOP_ANALYSIS
302303 LOOP_PASS("unroll-and-jam", LoopUnrollAndJamPass())
303304 LOOP_PASS("unroll-full", LoopFullUnrollPass())
304305 LOOP_PASS("print-access-info", LoopAccessInfoPrinterPass(dbgs()))
306 LOOP_PASS("print", DDGAnalysisPrinterPass(dbgs()))
305307 LOOP_PASS("print", IVUsersPrinterPass(dbgs()))
306308 LOOP_PASS("print", LoopCachePrinterPass(dbgs()))
307309 LOOP_PASS("loop-predication", LoopPredicationPass())
0 ; RUN: opt < %s -disable-output "-passes=print" 2>&1 | FileCheck %s
1
2 ; CHECK-LABEL: 'DDG' for loop 'test1.for.body':
3 ; CHECK: Node Address:[[N1:0x[0-9a-f]*]]:single-instruction
4 ; CHECK-NEXT: Instructions:
5 ; CHECK-NEXT: %i.02 = phi i64 [ %inc, %test1.for.body ], [ 0, %test1.for.body.preheader ]
6 ; CHECK-NEXT: Edges:
7 ; CHECK-NEXT: [def-use] to [[N2:0x[0-9a-f]*]]
8 ; CHECK-NEXT: [def-use] to [[N3:0x[0-9a-f]*]]
9 ; CHECK-NEXT: [def-use] to [[N4:0x[0-9a-f]*]]
10
11 ; CHECK: Node Address:[[N4]]:single-instruction
12 ; CHECK-NEXT: Instructions:
13 ; CHECK-NEXT: %arrayidx = getelementptr inbounds float, float* %b, i64 %i.02
14 ; CHECK-NEXT: Edges:
15 ; CHECK-NEXT: [def-use] to [[N5:0x[0-9a-f]*]]
16
17 ; CHECK: Node Address:[[N5]]:single-instruction
18 ; CHECK-NEXT: Instructions:
19 ; CHECK-NEXT: %0 = load float, float* %arrayidx, align 4
20 ; CHECK-NEXT: Edges:
21 ; CHECK-NEXT: [def-use] to [[N6:0x[0-9a-f]*]]
22
23 ; CHECK: Node Address:[[N7:0x[0-9a-f]*]]:single-instruction
24 ; CHECK-NEXT: Instructions:
25 ; CHECK-NEXT: %conv = uitofp i64 %n to float
26 ; CHECK-NEXT: Edges:
27 ; CHECK-NEXT: [def-use] to [[N6]]
28
29 ; CHECK: Node Address:[[N6]]:single-instruction
30 ; CHECK-NEXT: Instructions:
31 ; CHECK-NEXT: %add = fadd float %0, %conv
32 ; CHECK-NEXT: Edges:
33 ; CHECK-NEXT: [def-use] to [[N8:0x[0-9a-f]*]]
34
35 ; CHECK: Node Address:[[N3]]:single-instruction
36 ; CHECK-NEXT: Instructions:
37 ; CHECK-NEXT: %arrayidx1 = getelementptr inbounds float, float* %a, i64 %i.02
38 ; CHECK-NEXT: Edges:
39 ; CHECK-NEXT: [def-use] to [[N8]]
40
41 ; CHECK: Node Address:[[N8]]:single-instruction
42 ; CHECK-NEXT: Instructions:
43 ; CHECK-NEXT: store float %add, float* %arrayidx1, align 4
44 ; CHECK-NEXT: Edges:none!
45
46 ; CHECK: Node Address:[[N2]]:single-instruction
47 ; CHECK-NEXT: Instructions:
48 ; CHECK-NEXT: %inc = add i64 %i.02, 1
49 ; CHECK-NEXT: Edges:
50 ; CHECK-NEXT: [def-use] to [[N9:0x[0-9a-f]*]]
51 ; CHECK-NEXT: [def-use] to [[N1]]
52
53 ; CHECK: Node Address:[[N9]]:single-instruction
54 ; CHECK-NEXT: Instructions:
55 ; CHECK-NEXT: %exitcond = icmp ne i64 %inc, %n
56 ; CHECK-NEXT: Edges:
57 ; CHECK-NEXT: [def-use] to [[N10:0x[0-9a-f]*]]
58
59 ; CHECK: Node Address:[[N10]]:single-instruction
60 ; CHECK-NEXT: Instructions:
61 ; CHECK-NEXT: br i1 %exitcond, label %test1.for.body, label %for.end.loopexit
62 ; CHECK-NEXT: Edges:none!
63
64 ;; No memory dependencies.
65 ;; void test1(unsigned long n, float * restrict a, float * restrict b) {
66 ;; for (unsigned long i = 0; i < n; i++)
67 ;; a[i] = b[i] + n;
68 ;; }
69
70 define void @test1(i64 %n, float* noalias %a, float* noalias %b) {
71 entry:
72 %exitcond1 = icmp ne i64 0, %n
73 br i1 %exitcond1, label %test1.for.body, label %for.end
74
75 test1.for.body: ; preds = %entry, %test1.for.body
76 %i.02 = phi i64 [ %inc, %test1.for.body ], [ 0, %entry ]
77 %arrayidx = getelementptr inbounds float, float* %b, i64 %i.02
78 %0 = load float, float* %arrayidx, align 4
79 %conv = uitofp i64 %n to float
80 %add = fadd float %0, %conv
81 %arrayidx1 = getelementptr inbounds float, float* %a, i64 %i.02
82 store float %add, float* %arrayidx1, align 4
83 %inc = add i64 %i.02, 1
84 %exitcond = icmp ne i64 %inc, %n
85 br i1 %exitcond, label %test1.for.body, label %for.end
86
87 for.end: ; preds = %test1.for.body, %entry
88 ret void
89 }
90
91
92 ; CHECK-LABEL: 'DDG' for loop 'test2.for.body':
93 ; CHECK: Node Address:[[N1:0x[0-9a-f]*]]:single-instruction
94 ; CHECK-NEXT: Instructions:
95 ; CHECK-NEXT: %i.02 = phi i64 [ %inc, %test2.for.body ], [ 0, %test2.for.body.preheader ]
96 ; CHECK-NEXT: Edges:
97 ; CHECK-NEXT: [def-use] to [[N2:0x[0-9a-f]*]]
98 ; CHECK-NEXT: [def-use] to [[N3:0x[0-9a-f]*]]
99 ; CHECK-NEXT: [def-use] to [[N4:0x[0-9a-f]*]]
100 ; CHECK-NEXT: [def-use] to [[N5:0x[0-9a-f]*]]
101
102 ; CHECK: Node Address:[[N5]]:single-instruction
103 ; CHECK-NEXT: Instructions:
104 ; CHECK-NEXT: %arrayidx = getelementptr inbounds float, float* %b, i64 %i.02
105 ; CHECK-NEXT: Edges:
106 ; CHECK-NEXT: [def-use] to [[N6:0x[0-9a-f]*]]
107
108 ; CHECK: Node Address:[[N6]]:single-instruction
109 ; CHECK-NEXT: Instructions:
110 ; CHECK-NEXT: %0 = load float, float* %arrayidx, align 4
111 ; CHECK-NEXT: Edges:
112 ; CHECK-NEXT: [def-use] to [[N7:0x[0-9a-f]*]]
113
114 ; CHECK: Node Address:[[N4]]:single-instruction
115 ; CHECK-NEXT: Instructions:
116 ; CHECK-NEXT: %arrayidx1 = getelementptr inbounds float, float* %a, i64 %i.02
117 ; CHECK-NEXT: Edges:
118 ; CHECK-NEXT: [def-use] to [[N8:0x[0-9a-f]*]]
119
120 ; CHECK: Node Address:[[N8]]:single-instruction
121 ; CHECK-NEXT: Instructions:
122 ; CHECK-NEXT: %1 = load float, float* %arrayidx1, align 4
123 ; CHECK-NEXT: Edges:
124 ; CHECK-NEXT: [def-use] to [[N7]]
125 ; CHECK-NEXT: [memory] to [[N9:0x[0-9a-f]*]]
126
127 ; CHECK: Node Address:[[N7]]:single-instruction
128 ; CHECK-NEXT: Instructions:
129 ; CHECK-NEXT: %add = fadd float %0, %1
130 ; CHECK-NEXT: Edges:
131 ; CHECK-NEXT: [def-use] to [[N9]]
132
133 ; CHECK: Node Address:[[N3]]:single-instruction
134 ; CHECK-NEXT: Instructions:
135 ; CHECK-NEXT: %arrayidx2 = getelementptr inbounds float, float* %a, i64 %i.02
136 ; CHECK-NEXT: Edges:
137 ; CHECK-NEXT: [def-use] to [[N9]]
138
139 ; CHECK: Node Address:[[N9]]:single-instruction
140 ; CHECK-NEXT: Instructions:
141 ; CHECK-NEXT: store float %add, float* %arrayidx2, align 4
142 ; CHECK-NEXT: Edges:none!
143
144 ; CHECK: Node Address:[[N2]]:single-instruction
145 ; CHECK-NEXT: Instructions:
146 ; CHECK-NEXT: %inc = add i64 %i.02, 1
147 ; CHECK-NEXT: Edges:
148 ; CHECK-NEXT: [def-use] to [[N10:0x[0-9a-f]*]]
149 ; CHECK-NEXT: [def-use] to [[N1]]
150
151 ; CHECK: Node Address:[[N10]]:single-instruction
152 ; CHECK-NEXT: Instructions:
153 ; CHECK-NEXT: %exitcond = icmp ne i64 %inc, %n
154 ; CHECK-NEXT: Edges:
155 ; CHECK-NEXT: [def-use] to [[N11:0x[0-9a-f]*]]
156
157 ; CHECK: Node Address:[[N11]]:single-instruction
158 ; CHECK-NEXT: Instructions:
159 ; CHECK-NEXT: br i1 %exitcond, label %test2.for.body, label %for.end.loopexit
160 ; CHECK-NEXT: Edges:none!
161
162 ;; Loop-independent memory dependencies.
163 ;; void test2(unsigned long n, float * restrict a, float * restrict b) {
164 ;; for (unsigned long i = 0; i < n; i++)
165 ;; a[i] = b[i] + a[i];
166 ;; }
167
168 define void @test2(i64 %n, float* noalias %a, float* noalias %b) {
169 entry:
170 %exitcond1 = icmp ne i64 0, %n
171 br i1 %exitcond1, label %test2.for.body, label %for.end
172
173 test2.for.body: ; preds = %entry, %test2.for.body
174 %i.02 = phi i64 [ %inc, %test2.for.body ], [ 0, %entry ]
175 %arrayidx = getelementptr inbounds float, float* %b, i64 %i.02
176 %0 = load float, float* %arrayidx, align 4
177 %arrayidx1 = getelementptr inbounds float, float* %a, i64 %i.02
178 %1 = load float, float* %arrayidx1, align 4
179 %add = fadd float %0, %1
180 %arrayidx2 = getelementptr inbounds float, float* %a, i64 %i.02
181 store float %add, float* %arrayidx2, align 4
182 %inc = add i64 %i.02, 1
183 %exitcond = icmp ne i64 %inc, %n
184 br i1 %exitcond, label %test2.for.body, label %for.end
185
186 for.end: ; preds = %test2.for.body, %entry
187 ret void
188 }
0 ; RUN: opt < %s -disable-output "-passes=print" 2>&1 | FileCheck %s
1
2 ; CHECK-LABEL: 'DDG' for loop 'test1.for.body':
3 ; CHECK: Node Address:[[N1:0x[0-9a-f]*]]:single-instruction
4 ; CHECK-NEXT: Instructions:
5 ; CHECK-NEXT: %i.02 = phi i64 [ %inc, %test1.for.body ], [ 1, %test1.for.body.preheader ]
6 ; CHECK-NEXT: Edges:
7 ; CHECK-NEXT: [def-use] to [[N2:0x[0-9a-f]*]]
8 ; CHECK-NEXT: [def-use] to [[N3:0x[0-9a-f]*]]
9 ; CHECK-NEXT: [def-use] to [[N4:0x[0-9a-f]*]]
10 ; CHECK-NEXT: [def-use] to [[N5:0x[0-9a-f]*]]
11
12 ; CHECK: Node Address:[[N5]]:single-instruction
13 ; CHECK-NEXT: Instructions:
14 ; CHECK-NEXT: %arrayidx = getelementptr inbounds float, float* %b, i64 %i.02
15 ; CHECK-NEXT: Edges:
16 ; CHECK-NEXT: [def-use] to [[N6:0x[0-9a-f]*]]
17
18 ; CHECK: Node Address:[[N6]]:single-instruction
19 ; CHECK-NEXT: Instructions:
20 ; CHECK-NEXT: %0 = load float, float* %arrayidx, align 4
21 ; CHECK-NEXT: Edges:
22 ; CHECK-NEXT: [def-use] to [[N7:0x[0-9a-f]*]]
23
24 ; CHECK: Node Address:[[N4]]:single-instruction
25 ; CHECK-NEXT: Instructions:
26 ; CHECK-NEXT: %sub1 = add i64 %i.02, -1
27 ; CHECK-NEXT: Edges:
28 ; CHECK-NEXT: [def-use] to [[N8:0x[0-9a-f]*]]
29
30 ; CHECK: Node Address:[[N8]]:single-instruction
31 ; CHECK-NEXT: Instructions:
32 ; CHECK-NEXT: %arrayidx2 = getelementptr inbounds float, float* %a, i64 %sub1
33 ; CHECK-NEXT: Edges:
34 ; CHECK-NEXT: [def-use] to [[N9:0x[0-9a-f]*]]
35
36 ; CHECK: Node Address:[[N9]]:single-instruction
37 ; CHECK-NEXT: Instructions:
38 ; CHECK-NEXT: %1 = load float, float* %arrayidx2, align 4
39 ; CHECK-NEXT: Edges:
40 ; CHECK-NEXT: [def-use] to [[N7]]
41
42 ; CHECK: Node Address:[[N7]]:single-instruction
43 ; CHECK-NEXT: Instructions:
44 ; CHECK-NEXT: %add = fadd float %0, %1
45 ; CHECK-NEXT: Edges:
46 ; CHECK-NEXT: [def-use] to [[N10:0x[0-9a-f]*]]
47
48 ; CHECK: Node Address:[[N3]]:single-instruction
49 ; CHECK-NEXT: Instructions:
50 ; CHECK-NEXT: %arrayidx3 = getelementptr inbounds float, float* %a, i64 %i.02
51 ; CHECK-NEXT: Edges:
52 ; CHECK-NEXT: [def-use] to [[N10]]
53
54 ; CHECK: Node Address:[[N10]]:single-instruction
55 ; CHECK-NEXT: Instructions:
56 ; CHECK-NEXT: store float %add, float* %arrayidx3, align 4
57 ; CHECK-NEXT: Edges:
58 ; CHECK-NEXT: [memory] to [[N9]]
59
60 ; CHECK: Node Address:[[N2]]:single-instruction
61 ; CHECK-NEXT: Instructions:
62 ; CHECK-NEXT: %inc = add i64 %i.02, 1
63 ; CHECK-NEXT: Edges:
64 ; CHECK-NEXT: [def-use] to [[N11:0x[0-9a-f]*]]
65 ; CHECK-NEXT: [def-use] to [[N1]]
66
67 ; CHECK: Node Address:[[N11]]:single-instruction
68 ; CHECK-NEXT: Instructions:
69 ; CHECK-NEXT: %cmp = icmp ult i64 %inc, %sub
70 ; CHECK-NEXT: Edges:
71 ; CHECK-NEXT: [def-use] to [[N12:0x[0-9a-f]*]]
72
73 ; CHECK: Node Address:[[N12]]:single-instruction
74 ; CHECK-NEXT: Instructions:
75 ; CHECK-NEXT: br i1 %cmp, label %test1.for.body, label %for.end.loopexit
76 ; CHECK-NEXT: Edges:none!
77
78 ;; Loop-carried dependence requiring edge-reversal to expose a cycle
79 ;; in the graph.
80 ;; void test(unsigned long n, float * restrict a, float * restrict b) {
81 ;; for (unsigned long i = 1; i < n-1; i++)
82 ;; a[i] = b[i] + a[i-1];
83 ;; }
84
85 define void @test1(i64 %n, float* noalias %a, float* noalias %b) {
86 entry:
87 %sub = add i64 %n, -1
88 %cmp1 = icmp ult i64 1, %sub
89 br i1 %cmp1, label %test1.for.body, label %for.end
90
91 test1.for.body: ; preds = %entry, %test1.for.body
92 %i.02 = phi i64 [ %inc, %test1.for.body ], [ 1, %entry ]
93 %arrayidx = getelementptr inbounds float, float* %b, i64 %i.02
94 %0 = load float, float* %arrayidx, align 4
95 %sub1 = add i64 %i.02, -1
96 %arrayidx2 = getelementptr inbounds float, float* %a, i64 %sub1
97 %1 = load float, float* %arrayidx2, align 4
98 %add = fadd float %0, %1
99 %arrayidx3 = getelementptr inbounds float, float* %a, i64 %i.02
100 store float %add, float* %arrayidx3, align 4
101 %inc = add i64 %i.02, 1
102 %cmp = icmp ult i64 %inc, %sub
103 br i1 %cmp, label %test1.for.body, label %for.end
104
105 for.end: ; preds = %test1.for.body, %entry
106 ret void
107 }
108
109
110 ; CHECK-LABEL: 'DDG' for loop 'test2.for.body':
111 ; CHECK: Node Address:[[N1:0x[0-9a-f]*]]:single-instruction
112 ; CHECK-NEXT: Instructions:
113 ; CHECK-NEXT: %i.02 = phi i64 [ %inc, %test2.for.body ], [ 1, %test2.for.body.preheader ]
114 ; CHECK-NEXT: Edges:
115 ; CHECK-NEXT: [def-use] to [[N2:0x[0-9a-f]*]]
116 ; CHECK-NEXT: [def-use] to [[N3:0x[0-9a-f]*]]
117 ; CHECK-NEXT: [def-use] to [[N4:0x[0-9a-f]*]]
118 ; CHECK-NEXT: [def-use] to [[N5:0x[0-9a-f]*]]
119
120 ; CHECK: Node Address:[[N5]]:single-instruction
121 ; CHECK-NEXT: Instructions:
122 ; CHECK-NEXT: %arrayidx = getelementptr inbounds float, float* %b, i64 %i.02
123 ; CHECK-NEXT: Edges:
124 ; CHECK-NEXT: [def-use] to [[N6:0x[0-9a-f]*]]
125
126 ; CHECK: Node Address:[[N6]]:single-instruction
127 ; CHECK-NEXT: Instructions:
128 ; CHECK-NEXT: %0 = load float, float* %arrayidx, align 4
129 ; CHECK-NEXT: Edges:
130 ; CHECK-NEXT: [def-use] to [[N7:0x[0-9a-f]*]]
131
132 ; CHECK: Node Address:[[N4]]:single-instruction
133 ; CHECK-NEXT: Instructions:
134 ; CHECK-NEXT: %add1 = add i64 %i.02, 1
135 ; CHECK-NEXT: Edges:
136 ; CHECK-NEXT: [def-use] to [[N8:0x[0-9a-f]*]]
137
138 ; CHECK: Node Address:[[N8]]:single-instruction
139 ; CHECK-NEXT: Instructions:
140 ; CHECK-NEXT: %arrayidx2 = getelementptr inbounds float, float* %a, i64 %add1
141 ; CHECK-NEXT: Edges:
142 ; CHECK-NEXT: [def-use] to [[N9:0x[0-9a-f]*]]
143
144 ; CHECK: Node Address:[[N9]]:single-instruction
145 ; CHECK-NEXT: Instructions:
146 ; CHECK-NEXT: %1 = load float, float* %arrayidx2, align 4
147 ; CHECK-NEXT: Edges:
148 ; CHECK-NEXT: [def-use] to [[N7]]
149 ; CHECK-NEXT: [memory] to [[N10:0x[0-9a-f]*]]
150
151 ; CHECK: Node Address:[[N7]]:single-instruction
152 ; CHECK-NEXT: Instructions:
153 ; CHECK-NEXT: %add = fadd float %0, %1
154 ; CHECK-NEXT: Edges:
155 ; CHECK-NEXT: [def-use] to [[N10]]
156
157 ; CHECK: Node Address:[[N3]]:single-instruction
158 ; CHECK-NEXT: Instructions:
159 ; CHECK-NEXT: %arrayidx3 = getelementptr inbounds float, float* %a, i64 %i.02
160 ; CHECK-NEXT: Edges:
161 ; CHECK-NEXT: [def-use] to [[N10]]
162
163 ; CHECK: Node Address:[[N10]]:single-instruction
164 ; CHECK-NEXT: Instructions:
165 ; CHECK-NEXT: store float %add, float* %arrayidx3, align 4
166 ; CHECK-NEXT: Edges:none!
167
168 ; CHECK: Node Address:[[N2]]:single-instruction
169 ; CHECK-NEXT: Instructions:
170 ; CHECK-NEXT: %inc = add i64 %i.02, 1
171 ; CHECK-NEXT: Edges:
172 ; CHECK-NEXT: [def-use] to [[N11:0x[0-9a-f]*]]
173 ; CHECK-NEXT: [def-use] to [[N1]]
174
175 ; CHECK: Node Address:[[N11]]:single-instruction
176 ; CHECK-NEXT: Instructions:
177 ; CHECK-NEXT: %cmp = icmp ult i64 %inc, %sub
178 ; CHECK-NEXT: Edges:
179 ; CHECK-NEXT: [def-use] to [[N12:0x[0-9a-f]*]]
180
181 ; CHECK: Node Address:[[N12]]:single-instruction
182 ; CHECK-NEXT: Instructions:
183 ; CHECK-NEXT: br i1 %cmp, label %test2.for.body, label %for.end.loopexit
184 ; CHECK-NEXT: Edges:none!
185
186
187 ;; Forward loop-carried dependence *not* causing a cycle.
188 ;; void test2(unsigned long n, float * restrict a, float * restrict b) {
189 ;; for (unsigned long i = 1; i < n-1; i++)
190 ;; a[i] = b[i] + a[i+1];
191 ;; }
192
193 define void @test2(i64 %n, float* noalias %a, float* noalias %b) {
194 entry:
195 %sub = add i64 %n, -1
196 %cmp1 = icmp ult i64 1, %sub
197 br i1 %cmp1, label %test2.for.body, label %for.end
198
199 test2.for.body: ; preds = %entry, %test2.for.body
200 %i.02 = phi i64 [ %inc, %test2.for.body ], [ 1, %entry ]
201 %arrayidx = getelementptr inbounds float, float* %b, i64 %i.02
202 %0 = load float, float* %arrayidx, align 4
203 %add1 = add i64 %i.02, 1
204 %arrayidx2 = getelementptr inbounds float, float* %a, i64 %add1
205 %1 = load float, float* %arrayidx2, align 4
206 %add = fadd float %0, %1
207 %arrayidx3 = getelementptr inbounds float, float* %a, i64 %i.02
208 store float %add, float* %arrayidx3, align 4
209 %inc = add i64 %i.02, 1
210 %cmp = icmp ult i64 %inc, %sub
211 br i1 %cmp, label %test2.for.body, label %for.end
212
213 for.end: ; preds = %test2.for.body, %entry
214 ret void
215 }
0 ; RUN: opt < %s -disable-output "-passes=print" 2>&1 | FileCheck %s
1
2
3 ; CHECK-LABEL: 'DDG' for loop 'test1.for.cond1.preheader':
4 ; CHECK: Node Address:[[N1:0x[0-9a-f]*]]:single-instruction
5 ; CHECK-NEXT: Instructions:
6 ; CHECK-NEXT: %i.04 = phi i64 [ %inc13, %for.inc12 ], [ 0, %test1.for.cond1.preheader.preheader ]
7 ; CHECK-NEXT: Edges:
8 ; CHECK-NEXT: [def-use] to [[N2:0x[0-9a-f]*]]
9 ; CHECK-NEXT: [def-use] to [[N3:0x[0-9a-f]*]]
10 ; CHECK-NEXT: [def-use] to [[N4:0x[0-9a-f]*]]
11 ; CHECK-NEXT: [def-use] to [[N5:0x[0-9a-f]*]]
12
13 ; CHECK: Node Address:[[N6:0x[0-9a-f]*]]:single-instruction
14 ; CHECK-NEXT: Instructions:
15 ; CHECK-NEXT: %sub = add i64 %n, -1
16 ; CHECK-NEXT: Edges:
17 ; CHECK-NEXT: [def-use] to [[N7:0x[0-9a-f]*]]
18 ; CHECK-NEXT: [def-use] to [[N8:0x[0-9a-f]*]]
19
20 ; CHECK: Node Address:[[N8]]:single-instruction
21 ; CHECK-NEXT: Instructions:
22 ; CHECK-NEXT: %cmp21 = icmp ult i64 1, %sub
23 ; CHECK-NEXT: Edges:
24 ; CHECK-NEXT: [def-use] to [[N9:0x[0-9a-f]*]]
25
26 ; CHECK: Node Address:[[N9]]:single-instruction
27 ; CHECK-NEXT: Instructions:
28 ; CHECK-NEXT: br i1 %cmp21, label %for.body4.preheader, label %for.inc12
29 ; CHECK-NEXT: Edges:none!
30
31 ; CHECK: Node Address:[[N10:0x[0-9a-f]*]]:single-instruction
32 ; CHECK-NEXT: Instructions:
33 ; CHECK-NEXT: %j.02 = phi i64 [ %inc, %for.body4 ], [ 1, %for.body4.preheader ]
34 ; CHECK-NEXT: Edges:
35 ; CHECK-NEXT: [def-use] to [[N11:0x[0-9a-f]*]]
36 ; CHECK-NEXT: [def-use] to [[N12:0x[0-9a-f]*]]
37 ; CHECK-NEXT: [def-use] to [[N13:0x[0-9a-f]*]]
38 ; CHECK-NEXT: [def-use] to [[N14:0x[0-9a-f]*]]
39
40 ; CHECK: Node Address:[[N5]]:single-instruction
41 ; CHECK-NEXT: Instructions:
42 ; CHECK-NEXT: %0 = mul nsw i64 %i.04, %n
43 ; CHECK-NEXT: Edges:
44 ; CHECK-NEXT: [def-use] to [[N15:0x[0-9a-f]*]]
45
46 ; CHECK: Node Address:[[N15]]:single-instruction
47 ; CHECK-NEXT: Instructions:
48 ; CHECK-NEXT: %arrayidx = getelementptr inbounds float, float* %b, i64 %0
49 ; CHECK-NEXT: Edges:
50 ; CHECK-NEXT: [def-use] to [[N14]]
51
52 ; CHECK: Node Address:[[N14]]:single-instruction
53 ; CHECK-NEXT: Instructions:
54 ; CHECK-NEXT: %arrayidx5 = getelementptr inbounds float, float* %arrayidx, i64 %j.02
55 ; CHECK-NEXT: Edges:
56 ; CHECK-NEXT: [def-use] to [[N16:0x[0-9a-f]*]]
57
58 ; CHECK: Node Address:[[N16]]:single-instruction
59 ; CHECK-NEXT: Instructions:
60 ; CHECK-NEXT: %1 = load float, float* %arrayidx5, align 4
61 ; CHECK-NEXT: Edges:
62 ; CHECK-NEXT: [def-use] to [[N17:0x[0-9a-f]*]]
63
64 ; CHECK: Node Address:[[N4]]:single-instruction
65 ; CHECK-NEXT: Instructions:
66 ; CHECK-NEXT: %2 = mul nsw i64 %i.04, %n
67 ; CHECK-NEXT: Edges:
68 ; CHECK-NEXT: [def-use] to [[N18:0x[0-9a-f]*]]
69
70 ; CHECK: Node Address:[[N18]]:single-instruction
71 ; CHECK-NEXT: Instructions:
72 ; CHECK-NEXT: %arrayidx6 = getelementptr inbounds float, float* %a, i64 %2
73 ; CHECK-NEXT: Edges:
74 ; CHECK-NEXT: [def-use] to [[N19:0x[0-9a-f]*]]
75
76 ; CHECK: Node Address:[[N13]]:single-instruction
77 ; CHECK-NEXT: Instructions:
78 ; CHECK-NEXT: %sub7 = add i64 %j.02, -1
79 ; CHECK-NEXT: Edges:
80 ; CHECK-NEXT: [def-use] to [[N19]]
81
82 ; CHECK: Node Address:[[N19]]:single-instruction
83 ; CHECK-NEXT: Instructions:
84 ; CHECK-NEXT: %arrayidx8 = getelementptr inbounds float, float* %arrayidx6, i64 %sub7
85 ; CHECK-NEXT: Edges:
86 ; CHECK-NEXT: [def-use] to [[N20:0x[0-9a-f]*]]
87
88 ; CHECK: Node Address:[[N20]]:single-instruction
89 ; CHECK-NEXT: Instructions:
90 ; CHECK-NEXT: %3 = load float, float* %arrayidx8, align 4
91 ; CHECK-NEXT: Edges:
92 ; CHECK-NEXT: [def-use] to [[N17]]
93
94 ; CHECK: Node Address:[[N17]]:single-instruction
95 ; CHECK-NEXT: Instructions:
96 ; CHECK-NEXT: %add = fadd float %1, %3
97 ; CHECK-NEXT: Edges:
98 ; CHECK-NEXT: [def-use] to [[N26:0x[0-9a-f]*]]
99
100 ; CHECK: Node Address:[[N3]]:single-instruction
101 ; CHECK-NEXT: Instructions:
102 ; CHECK-NEXT: %4 = mul nsw i64 %i.04, %n
103 ; CHECK-NEXT: Edges:
104 ; CHECK-NEXT: [def-use] to [[N27:0x[0-9a-f]*]]
105
106 ; CHECK: Node Address:[[N27]]:single-instruction
107 ; CHECK-NEXT: Instructions:
108 ; CHECK-NEXT: %arrayidx10 = getelementptr inbounds float, float* %a, i64 %4
109 ; CHECK-NEXT: Edges:
110 ; CHECK-NEXT: [def-use] to [[N12]]
111
112 ; CHECK: Node Address:[[N12]]:single-instruction
113 ; CHECK-NEXT: Instructions:
114 ; CHECK-NEXT: %arrayidx11 = getelementptr inbounds float, float* %arrayidx10, i64 %j.02
115 ; CHECK-NEXT: Edges:
116 ; CHECK-NEXT: [def-use] to [[N26]]
117
118 ; CHECK: Node Address:[[N26]]:single-instruction
119 ; CHECK-NEXT: Instructions:
120 ; CHECK-NEXT: store float %add, float* %arrayidx11, align 4
121 ; CHECK-NEXT: Edges:
122 ; CHECK-NEXT: [memory] to [[N20]]
123
124 ; CHECK: Node Address:[[N11]]:single-instruction
125 ; CHECK-NEXT: Instructions:
126 ; CHECK-NEXT: %inc = add i64 %j.02, 1
127 ; CHECK-NEXT: Edges:
128 ; CHECK-NEXT: [def-use] to [[N7]]
129 ; CHECK-NEXT: [def-use] to [[N10]]
130
131 ; CHECK: Node Address:[[N7]]:single-instruction
132 ; CHECK-NEXT: Instructions:
133 ; CHECK-NEXT: %cmp2 = icmp ult i64 %inc, %sub
134 ; CHECK-NEXT: Edges:
135 ; CHECK-NEXT: [def-use] to [[N21:0x[0-9a-f]*]]
136
137 ; CHECK: Node Address:[[N21]]:single-instruction
138 ; CHECK-NEXT: Instructions:
139 ; CHECK-NEXT: br i1 %cmp2, label %for.body4, label %for.inc12.loopexit
140 ; CHECK-NEXT: Edges:none!
141
142 ; CHECK: Node Address:[[N2]]:single-instruction
143 ; CHECK-NEXT: Instructions:
144 ; CHECK-NEXT: %inc13 = add i64 %i.04, 1
145 ; CHECK-NEXT: Edges:
146 ; CHECK-NEXT: [def-use] to [[N22:0x[0-9a-f]*]]
147 ; CHECK-NEXT: [def-use] to [[N1]]
148
149 ; CHECK: Node Address:[[N22]]:single-instruction
150 ; CHECK-NEXT: Instructions:
151 ; CHECK-NEXT: %exitcond = icmp ne i64 %inc13, %n
152 ; CHECK-NEXT: Edges:
153 ; CHECK-NEXT: [def-use] to [[N23:0x[0-9a-f]*]]
154
155 ; CHECK: Node Address:[[N23]]:single-instruction
156 ; CHECK-NEXT: Instructions:
157 ; CHECK-NEXT: br i1 %exitcond, label %test1.for.cond1.preheader, label %for.end14.loopexit
158 ; CHECK-NEXT: Edges:none!
159
160 ; CHECK: Node Address:[[N24:0x[0-9a-f]*]]:single-instruction
161 ; CHECK-NEXT: Instructions:
162 ; CHECK-NEXT: br label %for.body4
163 ; CHECK-NEXT: Edges:none!
164
165 ; CHECK: Node Address:[[N25:0x[0-9a-f]*]]:single-instruction
166 ; CHECK-NEXT: Instructions:
167 ; CHECK-NEXT: br label %for.inc12
168 ; CHECK-NEXT: Edges:none!
169
170
171
172 ;; This test has a cycle.
173 ;; void test1(unsigned long n, float a[][n], float b[][n]) {
174 ;; for (unsigned long i = 0; i < n; i++)
175 ;; for (unsigned long j = 1; j < n-1; j++)
176 ;; a[i][j] = b[i][j] + a[i][j-1];
177 ;; }
178
179 define void @test1(i64 %n, float* noalias %a, float* noalias %b) {
180 entry:
181 %exitcond3 = icmp ne i64 0, %n
182 br i1 %exitcond3, label %test1.for.cond1.preheader, label %for.end14
183
184 test1.for.cond1.preheader: ; preds = %entry, %for.inc12
185 %i.04 = phi i64 [ %inc13, %for.inc12 ], [ 0, %entry ]
186 %sub = add i64 %n, -1
187 %cmp21 = icmp ult i64 1, %sub
188 br i1 %cmp21, label %for.body4, label %for.inc12
189
190 for.body4: ; preds = %test1.for.cond1.preheader, %for.body4
191 %j.02 = phi i64 [ %inc, %for.body4 ], [ 1, %test1.for.cond1.preheader ]
192 %0 = mul nsw i64 %i.04, %n
193 %arrayidx = getelementptr inbounds float, float* %b, i64 %0
194 %arrayidx5 = getelementptr inbounds float, float* %arrayidx, i64 %j.02
195 %1 = load float, float* %arrayidx5, align 4
196 %2 = mul nsw i64 %i.04, %n
197 %arrayidx6 = getelementptr inbounds float, float* %a, i64 %2
198 %sub7 = add i64 %j.02, -1
199 %arrayidx8 = getelementptr inbounds float, float* %arrayidx6, i64 %sub7
200 %3 = load float, float* %arrayidx8, align 4
201 %add = fadd float %1, %3
202 %4 = mul nsw i64 %i.04, %n
203 %arrayidx10 = getelementptr inbounds float, float* %a, i64 %4
204 %arrayidx11 = getelementptr inbounds float, float* %arrayidx10, i64 %j.02
205 store float %add, float* %arrayidx11, align 4
206 %inc = add i64 %j.02, 1
207 %cmp2 = icmp ult i64 %inc, %sub
208 br i1 %cmp2, label %for.body4, label %for.inc12
209
210 for.inc12: ; preds = %for.body4, %test1.for.cond1.preheader
211 %inc13 = add i64 %i.04, 1
212 %exitcond = icmp ne i64 %inc13, %n
213 br i1 %exitcond, label %test1.for.cond1.preheader, label %for.end14
214
215 for.end14: ; preds = %for.inc12, %entry
216 ret void
217 }
218
219
220
221 ; CHECK-LABEL: 'DDG' for loop 'test2.for.cond1.preheader':
222 ; CHECK: Node Address:[[N1:0x[0-9a-f]*]]:single-instruction
223 ; CHECK-NEXT: Instructions:
224 ; CHECK-NEXT: %i.04 = phi i64 [ %inc13, %for.inc12 ], [ 0, %test2.for.cond1.preheader.preheader ]
225 ; CHECK-NEXT: Edges:
226 ; CHECK-NEXT: [def-use] to [[N2:0x[0-9a-f]*]]
227 ; CHECK-NEXT: [def-use] to [[N3:0x[0-9a-f]*]]
228 ; CHECK-NEXT: [def-use] to [[N4:0x[0-9a-f]*]]
229 ; CHECK-NEXT: [def-use] to [[N5:0x[0-9a-f]*]]
230
231 ; CHECK: Node Address:[[N6:0x[0-9a-f]*]]:single-instruction
232 ; CHECK-NEXT: Instructions:
233 ; CHECK-NEXT: %sub = add i64 %n, -1
234 ; CHECK-NEXT: Edges:
235 ; CHECK-NEXT: [def-use] to [[N7:0x[0-9a-f]*]]
236 ; CHECK-NEXT: [def-use] to [[N8:0x[0-9a-f]*]]
237
238 ; CHECK: Node Address:[[N8]]:single-instruction
239 ; CHECK-NEXT: Instructions:
240 ; CHECK-NEXT: %cmp21 = icmp ult i64 1, %sub
241 ; CHECK-NEXT: Edges:
242 ; CHECK-NEXT: [def-use] to [[N9:0x[0-9a-f]*]]
243
244 ; CHECK: Node Address:[[N9]]:single-instruction
245 ; CHECK-NEXT: Instructions:
246 ; CHECK-NEXT: br i1 %cmp21, label %for.body4.preheader, label %for.inc12
247 ; CHECK-NEXT: Edges:none!
248
249 ; CHECK: Node Address:[[N10:0x[0-9a-f]*]]:single-instruction
250 ; CHECK-NEXT: Instructions:
251 ; CHECK-NEXT: %j.02 = phi i64 [ %inc, %for.body4 ], [ 1, %for.body4.preheader ]
252 ; CHECK-NEXT: Edges:
253 ; CHECK-NEXT: [def-use] to [[N11:0x[0-9a-f]*]]
254 ; CHECK-NEXT: [def-use] to [[N12:0x[0-9a-f]*]]
255 ; CHECK-NEXT: [def-use] to [[N13:0x[0-9a-f]*]]
256 ; CHECK-NEXT: [def-use] to [[N14:0x[0-9a-f]*]]
257
258 ; CHECK: Node Address:[[N5]]:single-instruction
259 ; CHECK-NEXT: Instructions:
260 ; CHECK-NEXT: %0 = mul nsw i64 %i.04, %n
261 ; CHECK-NEXT: Edges:
262 ; CHECK-NEXT: [def-use] to [[N15:0x[0-9a-f]*]]
263
264 ; CHECK: Node Address:[[N15]]:single-instruction
265 ; CHECK-NEXT: Instructions:
266 ; CHECK-NEXT: %arrayidx = getelementptr inbounds float, float* %b, i64 %0
267 ; CHECK-NEXT: Edges:
268 ; CHECK-NEXT: [def-use] to [[N14]]
269
270 ; CHECK: Node Address:[[N14]]:single-instruction
271 ; CHECK-NEXT: Instructions:
272 ; CHECK-NEXT: %arrayidx5 = getelementptr inbounds float, float* %arrayidx, i64 %j.02
273 ; CHECK-NEXT: Edges:
274 ; CHECK-NEXT: [def-use] to [[N16:0x[0-9a-f]*]]
275
276 ; CHECK: Node Address:[[N16]]:single-instruction
277 ; CHECK-NEXT: Instructions:
278 ; CHECK-NEXT: %1 = load float, float* %arrayidx5, align 4
279 ; CHECK-NEXT: Edges:
280 ; CHECK-NEXT: [def-use] to [[N17:0x[0-9a-f]*]]
281
282 ; CHECK: Node Address:[[N4]]:single-instruction
283 ; CHECK-NEXT: Instructions:
284 ; CHECK-NEXT: %2 = mul nsw i64 %i.04, %n
285 ; CHECK-NEXT: Edges:
286 ; CHECK-NEXT: [def-use] to [[N18:0x[0-9a-f]*]]
287
288 ; CHECK: Node Address:[[N18]]:single-instruction
289 ; CHECK-NEXT: Instructions:
290 ; CHECK-NEXT: %arrayidx6 = getelementptr inbounds float, float* %a, i64 %2
291 ; CHECK-NEXT: Edges:
292 ; CHECK-NEXT: [def-use] to [[N19:0x[0-9a-f]*]]
293
294 ; CHECK: Node Address:[[N13]]:single-instruction
295 ; CHECK-NEXT: Instructions:
296 ; CHECK-NEXT: %add7 = add i64 %j.02, 1
297 ; CHECK-NEXT: Edges:
298 ; CHECK-NEXT: [def-use] to [[N19]]
299
300 ; CHECK: Node Address:[[N19]]:single-instruction
301 ; CHECK-NEXT: Instructions:
302 ; CHECK-NEXT: %arrayidx8 = getelementptr inbounds float, float* %arrayidx6, i64 %add7
303 ; CHECK-NEXT: Edges:
304 ; CHECK-NEXT: [def-use] to [[N20:0x[0-9a-f]*]]
305
306 ; CHECK: Node Address:[[N20]]:single-instruction
307 ; CHECK-NEXT: Instructions:
308 ; CHECK-NEXT: %3 = load float, float* %arrayidx8, align 4
309 ; CHECK-NEXT: Edges:
310 ; CHECK-NEXT: [def-use] to [[N17]]
311 ; CHECK-NEXT: [memory] to [[N26:0x[0-9a-f]*]]
312
313 ; CHECK: Node Address:[[N17]]:single-instruction
314 ; CHECK-NEXT: Instructions:
315 ; CHECK-NEXT: %add = fadd float %1, %3
316 ; CHECK-NEXT: Edges:
317 ; CHECK-NEXT: [def-use] to [[N26]]
318
319 ; CHECK: Node Address:[[N3]]:single-instruction
320 ; CHECK-NEXT: Instructions:
321 ; CHECK-NEXT: %4 = mul nsw i64 %i.04, %n
322 ; CHECK-NEXT: Edges:
323 ; CHECK-NEXT: [def-use] to [[N27:0x[0-9a-f]*]]
324
325 ; CHECK: Node Address:[[N27]]:single-instruction
326 ; CHECK-NEXT: Instructions:
327 ; CHECK-NEXT: %arrayidx10 = getelementptr inbounds float, float* %a, i64 %4
328 ; CHECK-NEXT: Edges:
329 ; CHECK-NEXT: [def-use] to [[N12]]
330
331 ; CHECK: Node Address:[[N12]]:single-instruction
332 ; CHECK-NEXT: Instructions:
333 ; CHECK-NEXT: %arrayidx11 = getelementptr inbounds float, float* %arrayidx10, i64 %j.02
334 ; CHECK-NEXT: Edges:
335 ; CHECK-NEXT: [def-use] to [[N26]]
336
337 ; CHECK: Node Address:[[N26]]:single-instruction
338 ; CHECK-NEXT: Instructions:
339 ; CHECK-NEXT: store float %add, float* %arrayidx11, align 4
340 ; CHECK-NEXT: Edges:none!
341
342 ; CHECK: Node Address:[[N11]]:single-instruction
343 ; CHECK-NEXT: Instructions:
344 ; CHECK-NEXT: %inc = add i64 %j.02, 1
345 ; CHECK-NEXT: Edges:
346 ; CHECK-NEXT: [def-use] to [[N7]]
347 ; CHECK-NEXT: [def-use] to [[N10]]
348
349 ; CHECK: Node Address:[[N7]]:single-instruction
350 ; CHECK-NEXT: Instructions:
351 ; CHECK-NEXT: %cmp2 = icmp ult i64 %inc, %sub
352 ; CHECK-NEXT: Edges:
353 ; CHECK-NEXT: [def-use] to [[N21:0x[0-9a-f]*]]
354
355 ; CHECK: Node Address:[[N21]]:single-instruction
356 ; CHECK-NEXT: Instructions:
357 ; CHECK-NEXT: br i1 %cmp2, label %for.body4, label %for.inc12.loopexit
358 ; CHECK-NEXT: Edges:none!
359
360 ; CHECK: Node Address:[[N2]]:single-instruction
361 ; CHECK-NEXT: Instructions:
362 ; CHECK-NEXT: %inc13 = add i64 %i.04, 1
363 ; CHECK-NEXT: Edges:
364 ; CHECK-NEXT: [def-use] to [[N22:0x[0-9a-f]*]]
365 ; CHECK-NEXT: [def-use] to [[N1]]
366
367 ; CHECK: Node Address:[[N22]]:single-instruction
368 ; CHECK-NEXT: Instructions:
369 ; CHECK-NEXT: %exitcond = icmp ne i64 %inc13, %n
370 ; CHECK-NEXT: Edges:
371 ; CHECK-NEXT: [def-use] to [[N23:0x[0-9a-f]*]]
372
373 ; CHECK: Node Address:[[N23]]:single-instruction
374 ; CHECK-NEXT: Instructions:
375 ; CHECK-NEXT: br i1 %exitcond, label %test2.for.cond1.preheader, label %for.end14.loopexit
376 ; CHECK-NEXT: Edges:none!
377
378 ; CHECK: Node Address:[[N24:0x[0-9a-f]*]]:single-instruction
379 ; CHECK-NEXT: Instructions:
380 ; CHECK-NEXT: br label %for.body4
381 ; CHECK-NEXT: Edges:none!
382
383 ; CHECK: Node Address:[[N25:0x[0-9a-f]*]]:single-instruction
384 ; CHECK-NEXT: Instructions:
385 ; CHECK-NEXT: br label %for.inc12
386 ; CHECK-NEXT: Edges:none!
387
388 ;; This test has no cycles.
389 ;; void test2(unsigned long n, float a[][n], float b[][n]) {
390 ;; for (unsigned long i = 0; i < n; i++)
391 ;; for (unsigned long j = 1; j < n-1; j++)
392 ;; a[i][j] = b[i][j] + a[i][j+1];
393 ;; }
394
395 define void @test2(i64 %n, float* noalias %a, float* noalias %b) {
396 entry:
397 %exitcond3 = icmp ne i64 0, %n
398 br i1 %exitcond3, label %test2.for.cond1.preheader, label %for.end14
399
400 test2.for.cond1.preheader: ; preds = %entry, %for.inc12
401 %i.04 = phi i64 [ %inc13, %for.inc12 ], [ 0, %entry ]
402 %sub = add i64 %n, -1
403 %cmp21 = icmp ult i64 1, %sub
404 br i1 %cmp21, label %for.body4, label %for.inc12
405
406 for.body4: ; preds = %test2.for.cond1.preheader, %for.body4
407 %j.02 = phi i64 [ %inc, %for.body4 ], [ 1, %test2.for.cond1.preheader ]
408 %0 = mul nsw i64 %i.04, %n
409 %arrayidx = getelementptr inbounds float, float* %b, i64 %0
410 %arrayidx5 = getelementptr inbounds float, float* %arrayidx, i64 %j.02
411 %1 = load float, float* %arrayidx5, align 4
412 %2 = mul nsw i64 %i.04, %n
413 %arrayidx6 = getelementptr inbounds float, float* %a, i64 %2
414 %add7 = add i64 %j.02, 1
415 %arrayidx8 = getelementptr inbounds float, float* %arrayidx6, i64 %add7
416 %3 = load float, float* %arrayidx8, align 4
417 %add = fadd float %1, %3
418 %4 = mul nsw i64 %i.04, %n
419 %arrayidx10 = getelementptr inbounds float, float* %a, i64 %4
420 %arrayidx11 = getelementptr inbounds float, float* %arrayidx10, i64 %j.02
421 store float %add, float* %arrayidx11, align 4
422 %inc = add i64 %j.02, 1
423 %cmp2 = icmp ult i64 %inc, %sub
424 br i1 %cmp2, label %for.body4, label %for.inc12
425
426 for.inc12: ; preds = %for.body4, %test2.for.cond1.preheader
427 %inc13 = add i64 %i.04, 1
428 %exitcond = icmp ne i64 %inc13, %n
429 br i1 %exitcond, label %test2.for.cond1.preheader, label %for.end14
430
431 for.end14: ; preds = %for.inc12, %entry
432 ret void
433 }