• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- llvm/Analysis/DDG.h --------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the Data-Dependence Graph (DDG).
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_ANALYSIS_DDG_H
14 #define LLVM_ANALYSIS_DDG_H
15 
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/ADT/DirectedGraph.h"
18 #include "llvm/Analysis/DependenceAnalysis.h"
19 #include "llvm/Analysis/DependenceGraphBuilder.h"
20 #include "llvm/Analysis/LoopAnalysisManager.h"
21 #include "llvm/IR/Instructions.h"
22 
23 namespace llvm {
24 class DDGNode;
25 class DDGEdge;
26 using DDGNodeBase = DGNode<DDGNode, DDGEdge>;
27 using DDGEdgeBase = DGEdge<DDGNode, DDGEdge>;
28 using DDGBase = DirectedGraph<DDGNode, DDGEdge>;
29 class LPMUpdater;
30 
31 /// Data Dependence Graph Node
32 /// The graph can represent the following types of nodes:
33 /// 1. Single instruction node containing just one instruction.
34 /// 2. Multiple instruction node where two or more instructions from
35 ///    the same basic block are merged into one node.
36 /// 3. Pi-block node which is a group of other DDG nodes that are part of a
37 ///    strongly-connected component of the graph.
38 ///    A pi-block node contains more than one single or multiple instruction
39 ///    nodes. The root node cannot be part of a pi-block.
40 /// 4. Root node is a special node that connects to all components such that
41 ///    there is always a path from it to any node in the graph.
42 class DDGNode : public DDGNodeBase {
43 public:
44   using InstructionListType = SmallVectorImpl<Instruction *>;
45 
46   enum class NodeKind {
47     Unknown,
48     SingleInstruction,
49     MultiInstruction,
50     PiBlock,
51     Root,
52   };
53 
54   DDGNode() = delete;
DDGNode(const NodeKind K)55   DDGNode(const NodeKind K) : DDGNodeBase(), Kind(K) {}
DDGNode(const DDGNode & N)56   DDGNode(const DDGNode &N) : DDGNodeBase(N), Kind(N.Kind) {}
DDGNode(DDGNode && N)57   DDGNode(DDGNode &&N) : DDGNodeBase(std::move(N)), Kind(N.Kind) {}
58   virtual ~DDGNode() = 0;
59 
60   DDGNode &operator=(const DDGNode &N) {
61     DGNode::operator=(N);
62     Kind = N.Kind;
63     return *this;
64   }
65 
66   DDGNode &operator=(DDGNode &&N) {
67     DGNode::operator=(std::move(N));
68     Kind = N.Kind;
69     return *this;
70   }
71 
72   /// Getter for the kind of this node.
getKind()73   NodeKind getKind() const { return Kind; }
74 
75   /// Collect a list of instructions, in \p IList, for which predicate \p Pred
76   /// evaluates to true when iterating over instructions of this node. Return
77   /// true if at least one instruction was collected, and false otherwise.
78   bool collectInstructions(llvm::function_ref<bool(Instruction *)> const &Pred,
79                            InstructionListType &IList) const;
80 
81 protected:
82   /// Setter for the kind of this node.
setKind(NodeKind K)83   void setKind(NodeKind K) { Kind = K; }
84 
85 private:
86   NodeKind Kind;
87 };
88 
89 /// Subclass of DDGNode representing the root node of the graph.
90 /// There should only be one such node in a given graph.
91 class RootDDGNode : public DDGNode {
92 public:
RootDDGNode()93   RootDDGNode() : DDGNode(NodeKind::Root) {}
94   RootDDGNode(const RootDDGNode &N) = delete;
RootDDGNode(RootDDGNode && N)95   RootDDGNode(RootDDGNode &&N) : DDGNode(std::move(N)) {}
~RootDDGNode()96   ~RootDDGNode() {}
97 
98   /// Define classof to be able to use isa<>, cast<>, dyn_cast<>, etc.
classof(const DDGNode * N)99   static bool classof(const DDGNode *N) {
100     return N->getKind() == NodeKind::Root;
101   }
classof(const RootDDGNode * N)102   static bool classof(const RootDDGNode *N) { return true; }
103 };
104 
105 /// Subclass of DDGNode representing single or multi-instruction nodes.
106 class SimpleDDGNode : public DDGNode {
107 public:
108   SimpleDDGNode() = delete;
109   SimpleDDGNode(Instruction &I);
110   SimpleDDGNode(const SimpleDDGNode &N);
111   SimpleDDGNode(SimpleDDGNode &&N);
112   ~SimpleDDGNode();
113 
114   SimpleDDGNode &operator=(const SimpleDDGNode &N) {
115     DDGNode::operator=(N);
116     InstList = N.InstList;
117     return *this;
118   }
119 
120   SimpleDDGNode &operator=(SimpleDDGNode &&N) {
121     DDGNode::operator=(std::move(N));
122     InstList = std::move(N.InstList);
123     return *this;
124   }
125 
126   /// Get the list of instructions in this node.
getInstructions()127   const InstructionListType &getInstructions() const {
128     assert(!InstList.empty() && "Instruction List is empty.");
129     return InstList;
130   }
getInstructions()131   InstructionListType &getInstructions() {
132     return const_cast<InstructionListType &>(
133         static_cast<const SimpleDDGNode *>(this)->getInstructions());
134   }
135 
136   /// Get the first/last instruction in the node.
getFirstInstruction()137   Instruction *getFirstInstruction() const { return getInstructions().front(); }
getLastInstruction()138   Instruction *getLastInstruction() const { return getInstructions().back(); }
139 
140   /// Define classof to be able to use isa<>, cast<>, dyn_cast<>, etc.
classof(const DDGNode * N)141   static bool classof(const DDGNode *N) {
142     return N->getKind() == NodeKind::SingleInstruction ||
143            N->getKind() == NodeKind::MultiInstruction;
144   }
classof(const SimpleDDGNode * N)145   static bool classof(const SimpleDDGNode *N) { return true; }
146 
147 private:
148   /// Append the list of instructions in \p Input to this node.
appendInstructions(const InstructionListType & Input)149   void appendInstructions(const InstructionListType &Input) {
150     setKind((InstList.size() == 0 && Input.size() == 1)
151                 ? NodeKind::SingleInstruction
152                 : NodeKind::MultiInstruction);
153     InstList.insert(InstList.end(), Input.begin(), Input.end());
154   }
appendInstructions(const SimpleDDGNode & Input)155   void appendInstructions(const SimpleDDGNode &Input) {
156     appendInstructions(Input.getInstructions());
157   }
158 
159   /// List of instructions associated with a single or multi-instruction node.
160   SmallVector<Instruction *, 2> InstList;
161 };
162 
163 /// Subclass of DDGNode representing a pi-block. A pi-block represents a group
164 /// of DDG nodes that are part of a strongly-connected component of the graph.
165 /// Replacing all the SCCs with pi-blocks results in an acyclic representation
166 /// of the DDG. For example if we have:
167 /// {a -> b}, {b -> c, d}, {c -> a}
168 /// the cycle a -> b -> c -> a is abstracted into a pi-block "p" as follows:
169 /// {p -> d} with "p" containing: {a -> b}, {b -> c}, {c -> a}
170 class PiBlockDDGNode : public DDGNode {
171 public:
172   using PiNodeList = SmallVector<DDGNode *, 4>;
173 
174   PiBlockDDGNode() = delete;
175   PiBlockDDGNode(const PiNodeList &List);
176   PiBlockDDGNode(const PiBlockDDGNode &N);
177   PiBlockDDGNode(PiBlockDDGNode &&N);
178   ~PiBlockDDGNode();
179 
180   PiBlockDDGNode &operator=(const PiBlockDDGNode &N) {
181     DDGNode::operator=(N);
182     NodeList = N.NodeList;
183     return *this;
184   }
185 
186   PiBlockDDGNode &operator=(PiBlockDDGNode &&N) {
187     DDGNode::operator=(std::move(N));
188     NodeList = std::move(N.NodeList);
189     return *this;
190   }
191 
192   /// Get the list of nodes in this pi-block.
getNodes()193   const PiNodeList &getNodes() const {
194     assert(!NodeList.empty() && "Node list is empty.");
195     return NodeList;
196   }
getNodes()197   PiNodeList &getNodes() {
198     return const_cast<PiNodeList &>(
199         static_cast<const PiBlockDDGNode *>(this)->getNodes());
200   }
201 
202   /// Define classof to be able to use isa<>, cast<>, dyn_cast<>, etc.
classof(const DDGNode * N)203   static bool classof(const DDGNode *N) {
204     return N->getKind() == NodeKind::PiBlock;
205   }
206 
207 private:
208   /// List of nodes in this pi-block.
209   PiNodeList NodeList;
210 };
211 
212 /// Data Dependency Graph Edge.
213 /// An edge in the DDG can represent a def-use relationship or
214 /// a memory dependence based on the result of DependenceAnalysis.
215 /// A rooted edge connects the root node to one of the components
216 /// of the graph.
217 class DDGEdge : public DDGEdgeBase {
218 public:
219   /// The kind of edge in the DDG
220   enum class EdgeKind {
221     Unknown,
222     RegisterDefUse,
223     MemoryDependence,
224     Rooted,
225     Last = Rooted // Must be equal to the largest enum value.
226   };
227 
228   explicit DDGEdge(DDGNode &N) = delete;
DDGEdge(DDGNode & N,EdgeKind K)229   DDGEdge(DDGNode &N, EdgeKind K) : DDGEdgeBase(N), Kind(K) {}
DDGEdge(const DDGEdge & E)230   DDGEdge(const DDGEdge &E) : DDGEdgeBase(E), Kind(E.getKind()) {}
DDGEdge(DDGEdge && E)231   DDGEdge(DDGEdge &&E) : DDGEdgeBase(std::move(E)), Kind(E.Kind) {}
232   DDGEdge &operator=(const DDGEdge &E) {
233     DDGEdgeBase::operator=(E);
234     Kind = E.Kind;
235     return *this;
236   }
237 
238   DDGEdge &operator=(DDGEdge &&E) {
239     DDGEdgeBase::operator=(std::move(E));
240     Kind = E.Kind;
241     return *this;
242   }
243 
244   /// Get the edge kind
getKind()245   EdgeKind getKind() const { return Kind; };
246 
247   /// Return true if this is a def-use edge, and false otherwise.
isDefUse()248   bool isDefUse() const { return Kind == EdgeKind::RegisterDefUse; }
249 
250   /// Return true if this is a memory dependence edge, and false otherwise.
isMemoryDependence()251   bool isMemoryDependence() const { return Kind == EdgeKind::MemoryDependence; }
252 
253   /// Return true if this is an edge stemming from the root node, and false
254   /// otherwise.
isRooted()255   bool isRooted() const { return Kind == EdgeKind::Rooted; }
256 
257 private:
258   EdgeKind Kind;
259 };
260 
261 /// Encapsulate some common data and functionality needed for different
262 /// variations of data dependence graphs.
263 template <typename NodeType> class DependenceGraphInfo {
264 public:
265   using DependenceList = SmallVector<std::unique_ptr<Dependence>, 1>;
266 
267   DependenceGraphInfo() = delete;
268   DependenceGraphInfo(const DependenceGraphInfo &G) = delete;
DependenceGraphInfo(const std::string & N,const DependenceInfo & DepInfo)269   DependenceGraphInfo(const std::string &N, const DependenceInfo &DepInfo)
270       : Name(N), DI(DepInfo), Root(nullptr) {}
DependenceGraphInfo(DependenceGraphInfo && G)271   DependenceGraphInfo(DependenceGraphInfo &&G)
272       : Name(std::move(G.Name)), DI(std::move(G.DI)), Root(G.Root) {}
~DependenceGraphInfo()273   virtual ~DependenceGraphInfo() {}
274 
275   /// Return the label that is used to name this graph.
getName()276   const StringRef getName() const { return Name; }
277 
278   /// Return the root node of the graph.
getRoot()279   NodeType &getRoot() const {
280     assert(Root && "Root node is not available yet. Graph construction may "
281                    "still be in progress\n");
282     return *Root;
283   }
284 
285 protected:
286   // Name of the graph.
287   std::string Name;
288 
289   // Store a copy of DependenceInfo in the graph, so that individual memory
290   // dependencies don't need to be stored. Instead when the dependence is
291   // queried it is recomputed using @DI.
292   const DependenceInfo DI;
293 
294   // A special node in the graph that has an edge to every connected component of
295   // the graph, to ensure all nodes are reachable in a graph walk.
296   NodeType *Root = nullptr;
297 };
298 
299 using DDGInfo = DependenceGraphInfo<DDGNode>;
300 
301 /// Data Dependency Graph
302 class DataDependenceGraph : public DDGBase, public DDGInfo {
303   friend AbstractDependenceGraphBuilder<DataDependenceGraph>;
304   friend class DDGBuilder;
305 
306 public:
307   using NodeType = DDGNode;
308   using EdgeType = DDGEdge;
309 
310   DataDependenceGraph() = delete;
311   DataDependenceGraph(const DataDependenceGraph &G) = delete;
DataDependenceGraph(DataDependenceGraph && G)312   DataDependenceGraph(DataDependenceGraph &&G)
313       : DDGBase(std::move(G)), DDGInfo(std::move(G)) {}
314   DataDependenceGraph(Function &F, DependenceInfo &DI);
315   DataDependenceGraph(Loop &L, LoopInfo &LI, DependenceInfo &DI);
316   ~DataDependenceGraph();
317 
318   /// If node \p N belongs to a pi-block return a pointer to the pi-block,
319   /// otherwise return null.
320   const PiBlockDDGNode *getPiBlock(const NodeType &N) const;
321 
322 protected:
323   /// Add node \p N to the graph, if it's not added yet, and keep track of the
324   /// root node as well as pi-blocks and their members. Return true if node is
325   /// successfully added.
326   bool addNode(NodeType &N);
327 
328 private:
329   using PiBlockMapType = DenseMap<const NodeType *, const PiBlockDDGNode *>;
330 
331   /// Mapping from graph nodes to their containing pi-blocks. If a node is not
332   /// part of a pi-block, it will not appear in this map.
333   PiBlockMapType PiBlockMap;
334 };
335 
336 /// Concrete implementation of a pure data dependence graph builder. This class
337 /// provides custom implementation for the pure-virtual functions used in the
338 /// generic dependence graph build algorithm.
339 ///
340 /// For information about time complexity of the build algorithm see the
341 /// comments near the declaration of AbstractDependenceGraphBuilder.
342 class DDGBuilder : public AbstractDependenceGraphBuilder<DataDependenceGraph> {
343 public:
DDGBuilder(DataDependenceGraph & G,DependenceInfo & D,const BasicBlockListType & BBs)344   DDGBuilder(DataDependenceGraph &G, DependenceInfo &D,
345              const BasicBlockListType &BBs)
346       : AbstractDependenceGraphBuilder(G, D, BBs) {}
createRootNode()347   DDGNode &createRootNode() final override {
348     auto *RN = new RootDDGNode();
349     assert(RN && "Failed to allocate memory for DDG root node.");
350     Graph.addNode(*RN);
351     return *RN;
352   }
createFineGrainedNode(Instruction & I)353   DDGNode &createFineGrainedNode(Instruction &I) final override {
354     auto *SN = new SimpleDDGNode(I);
355     assert(SN && "Failed to allocate memory for simple DDG node.");
356     Graph.addNode(*SN);
357     return *SN;
358   }
createPiBlock(const NodeListType & L)359   DDGNode &createPiBlock(const NodeListType &L) final override {
360     auto *Pi = new PiBlockDDGNode(L);
361     assert(Pi && "Failed to allocate memory for pi-block node.");
362     Graph.addNode(*Pi);
363     return *Pi;
364   }
createDefUseEdge(DDGNode & Src,DDGNode & Tgt)365   DDGEdge &createDefUseEdge(DDGNode &Src, DDGNode &Tgt) final override {
366     auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::RegisterDefUse);
367     assert(E && "Failed to allocate memory for edge");
368     Graph.connect(Src, Tgt, *E);
369     return *E;
370   }
createMemoryEdge(DDGNode & Src,DDGNode & Tgt)371   DDGEdge &createMemoryEdge(DDGNode &Src, DDGNode &Tgt) final override {
372     auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::MemoryDependence);
373     assert(E && "Failed to allocate memory for edge");
374     Graph.connect(Src, Tgt, *E);
375     return *E;
376   }
createRootedEdge(DDGNode & Src,DDGNode & Tgt)377   DDGEdge &createRootedEdge(DDGNode &Src, DDGNode &Tgt) final override {
378     auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::Rooted);
379     assert(E && "Failed to allocate memory for edge");
380     assert(isa<RootDDGNode>(Src) && "Expected root node");
381     Graph.connect(Src, Tgt, *E);
382     return *E;
383   }
384 
getNodesInPiBlock(const DDGNode & N)385   const NodeListType &getNodesInPiBlock(const DDGNode &N) final override {
386     auto *PiNode = dyn_cast<const PiBlockDDGNode>(&N);
387     assert(PiNode && "Expected a pi-block node.");
388     return PiNode->getNodes();
389   }
390 
391   bool shouldCreatePiBlocks() const final override;
392 };
393 
394 raw_ostream &operator<<(raw_ostream &OS, const DDGNode &N);
395 raw_ostream &operator<<(raw_ostream &OS, const DDGNode::NodeKind K);
396 raw_ostream &operator<<(raw_ostream &OS, const DDGEdge &E);
397 raw_ostream &operator<<(raw_ostream &OS, const DDGEdge::EdgeKind K);
398 raw_ostream &operator<<(raw_ostream &OS, const DataDependenceGraph &G);
399 
400 //===--------------------------------------------------------------------===//
401 // DDG Analysis Passes
402 //===--------------------------------------------------------------------===//
403 
404 /// Analysis pass that builds the DDG for a loop.
405 class DDGAnalysis : public AnalysisInfoMixin<DDGAnalysis> {
406 public:
407   using Result = std::unique_ptr<DataDependenceGraph>;
408   Result run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR);
409 
410 private:
411   friend AnalysisInfoMixin<DDGAnalysis>;
412   static AnalysisKey Key;
413 };
414 
415 /// Textual printer pass for the DDG of a loop.
416 class DDGAnalysisPrinterPass : public PassInfoMixin<DDGAnalysisPrinterPass> {
417 public:
DDGAnalysisPrinterPass(raw_ostream & OS)418   explicit DDGAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {}
419   PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM,
420                         LoopStandardAnalysisResults &AR, LPMUpdater &U);
421 
422 private:
423   raw_ostream &OS;
424 };
425 
426 //===--------------------------------------------------------------------===//
427 // GraphTraits specializations for the DDG
428 //===--------------------------------------------------------------------===//
429 
430 /// non-const versions of the grapth trait specializations for DDG
431 template <> struct GraphTraits<DDGNode *> {
432   using NodeRef = DDGNode *;
433 
434   static DDGNode *DDGGetTargetNode(DGEdge<DDGNode, DDGEdge> *P) {
435     return &P->getTargetNode();
436   }
437 
438   // Provide a mapped iterator so that the GraphTrait-based implementations can
439   // find the target nodes without having to explicitly go through the edges.
440   using ChildIteratorType =
441       mapped_iterator<DDGNode::iterator, decltype(&DDGGetTargetNode)>;
442   using ChildEdgeIteratorType = DDGNode::iterator;
443 
444   static NodeRef getEntryNode(NodeRef N) { return N; }
445   static ChildIteratorType child_begin(NodeRef N) {
446     return ChildIteratorType(N->begin(), &DDGGetTargetNode);
447   }
448   static ChildIteratorType child_end(NodeRef N) {
449     return ChildIteratorType(N->end(), &DDGGetTargetNode);
450   }
451 
452   static ChildEdgeIteratorType child_edge_begin(NodeRef N) {
453     return N->begin();
454   }
455   static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
456 };
457 
458 template <>
459 struct GraphTraits<DataDependenceGraph *> : public GraphTraits<DDGNode *> {
460   using nodes_iterator = DataDependenceGraph::iterator;
461   static NodeRef getEntryNode(DataDependenceGraph *DG) {
462     return &DG->getRoot();
463   }
464   static nodes_iterator nodes_begin(DataDependenceGraph *DG) {
465     return DG->begin();
466   }
467   static nodes_iterator nodes_end(DataDependenceGraph *DG) { return DG->end(); }
468 };
469 
470 /// const versions of the grapth trait specializations for DDG
471 template <> struct GraphTraits<const DDGNode *> {
472   using NodeRef = const DDGNode *;
473 
474   static const DDGNode *DDGGetTargetNode(const DGEdge<DDGNode, DDGEdge> *P) {
475     return &P->getTargetNode();
476   }
477 
478   // Provide a mapped iterator so that the GraphTrait-based implementations can
479   // find the target nodes without having to explicitly go through the edges.
480   using ChildIteratorType =
481       mapped_iterator<DDGNode::const_iterator, decltype(&DDGGetTargetNode)>;
482   using ChildEdgeIteratorType = DDGNode::const_iterator;
483 
484   static NodeRef getEntryNode(NodeRef N) { return N; }
485   static ChildIteratorType child_begin(NodeRef N) {
486     return ChildIteratorType(N->begin(), &DDGGetTargetNode);
487   }
488   static ChildIteratorType child_end(NodeRef N) {
489     return ChildIteratorType(N->end(), &DDGGetTargetNode);
490   }
491 
492   static ChildEdgeIteratorType child_edge_begin(NodeRef N) {
493     return N->begin();
494   }
495   static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
496 };
497 
498 template <>
499 struct GraphTraits<const DataDependenceGraph *>
500     : public GraphTraits<const DDGNode *> {
501   using nodes_iterator = DataDependenceGraph::const_iterator;
502   static NodeRef getEntryNode(const DataDependenceGraph *DG) {
503     return &DG->getRoot();
504   }
505   static nodes_iterator nodes_begin(const DataDependenceGraph *DG) {
506     return DG->begin();
507   }
508   static nodes_iterator nodes_end(const DataDependenceGraph *DG) {
509     return DG->end();
510   }
511 };
512 
513 } // namespace llvm
514 
515 #endif // LLVM_ANALYSIS_DDG_H
516