Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:12

0001 //===- llvm/Analysis/DDG.h --------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This file defines the Data-Dependence Graph (DDG).
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_ANALYSIS_DDG_H
0014 #define LLVM_ANALYSIS_DDG_H
0015 
0016 #include "llvm/ADT/DenseMap.h"
0017 #include "llvm/ADT/DirectedGraph.h"
0018 #include "llvm/Analysis/DependenceAnalysis.h"
0019 #include "llvm/Analysis/DependenceGraphBuilder.h"
0020 #include "llvm/Analysis/LoopAnalysisManager.h"
0021 
0022 namespace llvm {
0023 class Function;
0024 class Loop;
0025 class LoopInfo;
0026 class DDGNode;
0027 class DDGEdge;
0028 using DDGNodeBase = DGNode<DDGNode, DDGEdge>;
0029 using DDGEdgeBase = DGEdge<DDGNode, DDGEdge>;
0030 using DDGBase = DirectedGraph<DDGNode, DDGEdge>;
0031 class LPMUpdater;
0032 
0033 /// Data Dependence Graph Node
0034 /// The graph can represent the following types of nodes:
0035 /// 1. Single instruction node containing just one instruction.
0036 /// 2. Multiple instruction node where two or more instructions from
0037 ///    the same basic block are merged into one node.
0038 /// 3. Pi-block node which is a group of other DDG nodes that are part of a
0039 ///    strongly-connected component of the graph.
0040 ///    A pi-block node contains more than one single or multiple instruction
0041 ///    nodes. The root node cannot be part of a pi-block.
0042 /// 4. Root node is a special node that connects to all components such that
0043 ///    there is always a path from it to any node in the graph.
0044 class DDGNode : public DDGNodeBase {
0045 public:
0046   using InstructionListType = SmallVectorImpl<Instruction *>;
0047 
0048   enum class NodeKind {
0049     Unknown,
0050     SingleInstruction,
0051     MultiInstruction,
0052     PiBlock,
0053     Root,
0054   };
0055 
0056   DDGNode() = delete;
0057   DDGNode(const NodeKind K) : Kind(K) {}
0058   DDGNode(const DDGNode &N) = default;
0059   DDGNode(DDGNode &&N) : DDGNodeBase(std::move(N)), Kind(N.Kind) {}
0060   virtual ~DDGNode() = 0;
0061 
0062   DDGNode &operator=(const DDGNode &N) {
0063     DGNode::operator=(N);
0064     Kind = N.Kind;
0065     return *this;
0066   }
0067 
0068   DDGNode &operator=(DDGNode &&N) {
0069     DGNode::operator=(std::move(N));
0070     Kind = N.Kind;
0071     return *this;
0072   }
0073 
0074   /// Getter for the kind of this node.
0075   NodeKind getKind() const { return Kind; }
0076 
0077   /// Collect a list of instructions, in \p IList, for which predicate \p Pred
0078   /// evaluates to true when iterating over instructions of this node. Return
0079   /// true if at least one instruction was collected, and false otherwise.
0080   bool collectInstructions(llvm::function_ref<bool(Instruction *)> const &Pred,
0081                            InstructionListType &IList) const;
0082 
0083 protected:
0084   /// Setter for the kind of this node.
0085   void setKind(NodeKind K) { Kind = K; }
0086 
0087 private:
0088   NodeKind Kind;
0089 };
0090 
0091 /// Subclass of DDGNode representing the root node of the graph.
0092 /// There should only be one such node in a given graph.
0093 class RootDDGNode : public DDGNode {
0094 public:
0095   RootDDGNode() : DDGNode(NodeKind::Root) {}
0096   RootDDGNode(const RootDDGNode &N) = delete;
0097   RootDDGNode(RootDDGNode &&N) : DDGNode(std::move(N)) {}
0098   ~RootDDGNode() = default;
0099 
0100   /// Define classof to be able to use isa<>, cast<>, dyn_cast<>, etc.
0101   static bool classof(const DDGNode *N) {
0102     return N->getKind() == NodeKind::Root;
0103   }
0104   static bool classof(const RootDDGNode *N) { return true; }
0105 };
0106 
0107 /// Subclass of DDGNode representing single or multi-instruction nodes.
0108 class SimpleDDGNode : public DDGNode {
0109   friend class DDGBuilder;
0110 
0111 public:
0112   SimpleDDGNode() = delete;
0113   SimpleDDGNode(Instruction &I);
0114   SimpleDDGNode(const SimpleDDGNode &N);
0115   SimpleDDGNode(SimpleDDGNode &&N);
0116   ~SimpleDDGNode();
0117 
0118   SimpleDDGNode &operator=(const SimpleDDGNode &N) = default;
0119 
0120   SimpleDDGNode &operator=(SimpleDDGNode &&N) {
0121     DDGNode::operator=(std::move(N));
0122     InstList = std::move(N.InstList);
0123     return *this;
0124   }
0125 
0126   /// Get the list of instructions in this node.
0127   const InstructionListType &getInstructions() const {
0128     assert(!InstList.empty() && "Instruction List is empty.");
0129     return InstList;
0130   }
0131   InstructionListType &getInstructions() {
0132     return const_cast<InstructionListType &>(
0133         static_cast<const SimpleDDGNode *>(this)->getInstructions());
0134   }
0135 
0136   /// Get the first/last instruction in the node.
0137   Instruction *getFirstInstruction() const { return getInstructions().front(); }
0138   Instruction *getLastInstruction() const { return getInstructions().back(); }
0139 
0140   /// Define classof to be able to use isa<>, cast<>, dyn_cast<>, etc.
0141   static bool classof(const DDGNode *N) {
0142     return N->getKind() == NodeKind::SingleInstruction ||
0143            N->getKind() == NodeKind::MultiInstruction;
0144   }
0145   static bool classof(const SimpleDDGNode *N) { return true; }
0146 
0147 private:
0148   /// Append the list of instructions in \p Input to this node.
0149   void appendInstructions(const InstructionListType &Input) {
0150     setKind((InstList.size() == 0 && Input.size() == 1)
0151                 ? NodeKind::SingleInstruction
0152                 : NodeKind::MultiInstruction);
0153     llvm::append_range(InstList, Input);
0154   }
0155   void appendInstructions(const SimpleDDGNode &Input) {
0156     appendInstructions(Input.getInstructions());
0157   }
0158 
0159   /// List of instructions associated with a single or multi-instruction node.
0160   SmallVector<Instruction *, 2> InstList;
0161 };
0162 
0163 /// Subclass of DDGNode representing a pi-block. A pi-block represents a group
0164 /// of DDG nodes that are part of a strongly-connected component of the graph.
0165 /// Replacing all the SCCs with pi-blocks results in an acyclic representation
0166 /// of the DDG. For example if we have:
0167 /// {a -> b}, {b -> c, d}, {c -> a}
0168 /// the cycle a -> b -> c -> a is abstracted into a pi-block "p" as follows:
0169 /// {p -> d} with "p" containing: {a -> b}, {b -> c}, {c -> a}
0170 class PiBlockDDGNode : public DDGNode {
0171 public:
0172   using PiNodeList = SmallVector<DDGNode *, 4>;
0173 
0174   PiBlockDDGNode() = delete;
0175   PiBlockDDGNode(const PiNodeList &List);
0176   PiBlockDDGNode(const PiBlockDDGNode &N);
0177   PiBlockDDGNode(PiBlockDDGNode &&N);
0178   ~PiBlockDDGNode();
0179 
0180   PiBlockDDGNode &operator=(const PiBlockDDGNode &N) = default;
0181 
0182   PiBlockDDGNode &operator=(PiBlockDDGNode &&N) {
0183     DDGNode::operator=(std::move(N));
0184     NodeList = std::move(N.NodeList);
0185     return *this;
0186   }
0187 
0188   /// Get the list of nodes in this pi-block.
0189   const PiNodeList &getNodes() const {
0190     assert(!NodeList.empty() && "Node list is empty.");
0191     return NodeList;
0192   }
0193   PiNodeList &getNodes() {
0194     return const_cast<PiNodeList &>(
0195         static_cast<const PiBlockDDGNode *>(this)->getNodes());
0196   }
0197 
0198   /// Define classof to be able to use isa<>, cast<>, dyn_cast<>, etc.
0199   static bool classof(const DDGNode *N) {
0200     return N->getKind() == NodeKind::PiBlock;
0201   }
0202 
0203 private:
0204   /// List of nodes in this pi-block.
0205   PiNodeList NodeList;
0206 };
0207 
0208 /// Data Dependency Graph Edge.
0209 /// An edge in the DDG can represent a def-use relationship or
0210 /// a memory dependence based on the result of DependenceAnalysis.
0211 /// A rooted edge connects the root node to one of the components
0212 /// of the graph.
0213 class DDGEdge : public DDGEdgeBase {
0214 public:
0215   /// The kind of edge in the DDG
0216   enum class EdgeKind {
0217     Unknown,
0218     RegisterDefUse,
0219     MemoryDependence,
0220     Rooted,
0221     Last = Rooted // Must be equal to the largest enum value.
0222   };
0223 
0224   explicit DDGEdge(DDGNode &N) = delete;
0225   DDGEdge(DDGNode &N, EdgeKind K) : DDGEdgeBase(N), Kind(K) {}
0226   DDGEdge(const DDGEdge &E) : DDGEdgeBase(E), Kind(E.getKind()) {}
0227   DDGEdge(DDGEdge &&E) : DDGEdgeBase(std::move(E)), Kind(E.Kind) {}
0228   DDGEdge &operator=(const DDGEdge &E) = default;
0229 
0230   DDGEdge &operator=(DDGEdge &&E) {
0231     DDGEdgeBase::operator=(std::move(E));
0232     Kind = E.Kind;
0233     return *this;
0234   }
0235 
0236   /// Get the edge kind
0237   EdgeKind getKind() const { return Kind; };
0238 
0239   /// Return true if this is a def-use edge, and false otherwise.
0240   bool isDefUse() const { return Kind == EdgeKind::RegisterDefUse; }
0241 
0242   /// Return true if this is a memory dependence edge, and false otherwise.
0243   bool isMemoryDependence() const { return Kind == EdgeKind::MemoryDependence; }
0244 
0245   /// Return true if this is an edge stemming from the root node, and false
0246   /// otherwise.
0247   bool isRooted() const { return Kind == EdgeKind::Rooted; }
0248 
0249 private:
0250   EdgeKind Kind;
0251 };
0252 
0253 /// Encapsulate some common data and functionality needed for different
0254 /// variations of data dependence graphs.
0255 template <typename NodeType> class DependenceGraphInfo {
0256 public:
0257   using DependenceList = SmallVector<std::unique_ptr<Dependence>, 1>;
0258 
0259   DependenceGraphInfo() = delete;
0260   DependenceGraphInfo(const DependenceGraphInfo &G) = delete;
0261   DependenceGraphInfo(const std::string &N, const DependenceInfo &DepInfo)
0262       : Name(N), DI(DepInfo), Root(nullptr) {}
0263   DependenceGraphInfo(DependenceGraphInfo &&G)
0264       : Name(std::move(G.Name)), DI(std::move(G.DI)), Root(G.Root) {}
0265   virtual ~DependenceGraphInfo() = default;
0266 
0267   /// Return the label that is used to name this graph.
0268   StringRef getName() const { return Name; }
0269 
0270   /// Return the root node of the graph.
0271   NodeType &getRoot() const {
0272     assert(Root && "Root node is not available yet. Graph construction may "
0273                    "still be in progress\n");
0274     return *Root;
0275   }
0276 
0277   /// Collect all the data dependency infos coming from any pair of memory
0278   /// accesses from \p Src to \p Dst, and store them into \p Deps. Return true
0279   /// if a dependence exists, and false otherwise.
0280   bool getDependencies(const NodeType &Src, const NodeType &Dst,
0281                        DependenceList &Deps) const;
0282 
0283   /// Return a string representing the type of dependence that the dependence
0284   /// analysis identified between the two given nodes. This function assumes
0285   /// that there is a memory dependence between the given two nodes.
0286   std::string getDependenceString(const NodeType &Src,
0287                                   const NodeType &Dst) const;
0288 
0289 protected:
0290   // Name of the graph.
0291   std::string Name;
0292 
0293   // Store a copy of DependenceInfo in the graph, so that individual memory
0294   // dependencies don't need to be stored. Instead when the dependence is
0295   // queried it is recomputed using @DI.
0296   const DependenceInfo DI;
0297 
0298   // A special node in the graph that has an edge to every connected component of
0299   // the graph, to ensure all nodes are reachable in a graph walk.
0300   NodeType *Root = nullptr;
0301 };
0302 
0303 using DDGInfo = DependenceGraphInfo<DDGNode>;
0304 
0305 /// Data Dependency Graph
0306 class DataDependenceGraph : public DDGBase, public DDGInfo {
0307   friend AbstractDependenceGraphBuilder<DataDependenceGraph>;
0308   friend class DDGBuilder;
0309 
0310 public:
0311   using NodeType = DDGNode;
0312   using EdgeType = DDGEdge;
0313 
0314   DataDependenceGraph() = delete;
0315   DataDependenceGraph(const DataDependenceGraph &G) = delete;
0316   DataDependenceGraph(DataDependenceGraph &&G)
0317       : DDGBase(std::move(G)), DDGInfo(std::move(G)) {}
0318   DataDependenceGraph(Function &F, DependenceInfo &DI);
0319   DataDependenceGraph(Loop &L, LoopInfo &LI, DependenceInfo &DI);
0320   ~DataDependenceGraph();
0321 
0322   /// If node \p N belongs to a pi-block return a pointer to the pi-block,
0323   /// otherwise return null.
0324   const PiBlockDDGNode *getPiBlock(const NodeType &N) const;
0325 
0326 protected:
0327   /// Add node \p N to the graph, if it's not added yet, and keep track of the
0328   /// root node as well as pi-blocks and their members. Return true if node is
0329   /// successfully added.
0330   bool addNode(NodeType &N);
0331 
0332 private:
0333   using PiBlockMapType = DenseMap<const NodeType *, const PiBlockDDGNode *>;
0334 
0335   /// Mapping from graph nodes to their containing pi-blocks. If a node is not
0336   /// part of a pi-block, it will not appear in this map.
0337   PiBlockMapType PiBlockMap;
0338 };
0339 
0340 /// Concrete implementation of a pure data dependence graph builder. This class
0341 /// provides custom implementation for the pure-virtual functions used in the
0342 /// generic dependence graph build algorithm.
0343 ///
0344 /// For information about time complexity of the build algorithm see the
0345 /// comments near the declaration of AbstractDependenceGraphBuilder.
0346 class DDGBuilder : public AbstractDependenceGraphBuilder<DataDependenceGraph> {
0347 public:
0348   DDGBuilder(DataDependenceGraph &G, DependenceInfo &D,
0349              const BasicBlockListType &BBs)
0350       : AbstractDependenceGraphBuilder(G, D, BBs) {}
0351   DDGNode &createRootNode() final {
0352     auto *RN = new RootDDGNode();
0353     assert(RN && "Failed to allocate memory for DDG root node.");
0354     Graph.addNode(*RN);
0355     return *RN;
0356   }
0357   DDGNode &createFineGrainedNode(Instruction &I) final {
0358     auto *SN = new SimpleDDGNode(I);
0359     assert(SN && "Failed to allocate memory for simple DDG node.");
0360     Graph.addNode(*SN);
0361     return *SN;
0362   }
0363   DDGNode &createPiBlock(const NodeListType &L) final {
0364     auto *Pi = new PiBlockDDGNode(L);
0365     assert(Pi && "Failed to allocate memory for pi-block node.");
0366     Graph.addNode(*Pi);
0367     return *Pi;
0368   }
0369   DDGEdge &createDefUseEdge(DDGNode &Src, DDGNode &Tgt) final {
0370     auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::RegisterDefUse);
0371     assert(E && "Failed to allocate memory for edge");
0372     Graph.connect(Src, Tgt, *E);
0373     return *E;
0374   }
0375   DDGEdge &createMemoryEdge(DDGNode &Src, DDGNode &Tgt) final {
0376     auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::MemoryDependence);
0377     assert(E && "Failed to allocate memory for edge");
0378     Graph.connect(Src, Tgt, *E);
0379     return *E;
0380   }
0381   DDGEdge &createRootedEdge(DDGNode &Src, DDGNode &Tgt) final {
0382     auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::Rooted);
0383     assert(E && "Failed to allocate memory for edge");
0384     assert(isa<RootDDGNode>(Src) && "Expected root node");
0385     Graph.connect(Src, Tgt, *E);
0386     return *E;
0387   }
0388 
0389   const NodeListType &getNodesInPiBlock(const DDGNode &N) final {
0390     auto *PiNode = dyn_cast<const PiBlockDDGNode>(&N);
0391     assert(PiNode && "Expected a pi-block node.");
0392     return PiNode->getNodes();
0393   }
0394 
0395   /// Return true if the two nodes \pSrc and \pTgt are both simple nodes and
0396   /// the consecutive instructions after merging belong to the same basic block.
0397   bool areNodesMergeable(const DDGNode &Src, const DDGNode &Tgt) const final;
0398   void mergeNodes(DDGNode &Src, DDGNode &Tgt) final;
0399   bool shouldSimplify() const final;
0400   bool shouldCreatePiBlocks() const final;
0401 };
0402 
0403 raw_ostream &operator<<(raw_ostream &OS, const DDGNode &N);
0404 raw_ostream &operator<<(raw_ostream &OS, const DDGNode::NodeKind K);
0405 raw_ostream &operator<<(raw_ostream &OS, const DDGEdge &E);
0406 raw_ostream &operator<<(raw_ostream &OS, const DDGEdge::EdgeKind K);
0407 raw_ostream &operator<<(raw_ostream &OS, const DataDependenceGraph &G);
0408 
0409 //===--------------------------------------------------------------------===//
0410 // DDG Analysis Passes
0411 //===--------------------------------------------------------------------===//
0412 
0413 /// Analysis pass that builds the DDG for a loop.
0414 class DDGAnalysis : public AnalysisInfoMixin<DDGAnalysis> {
0415 public:
0416   using Result = std::unique_ptr<DataDependenceGraph>;
0417   Result run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR);
0418 
0419 private:
0420   friend AnalysisInfoMixin<DDGAnalysis>;
0421   static AnalysisKey Key;
0422 };
0423 
0424 /// Textual printer pass for the DDG of a loop.
0425 class DDGAnalysisPrinterPass : public PassInfoMixin<DDGAnalysisPrinterPass> {
0426 public:
0427   explicit DDGAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {}
0428   PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM,
0429                         LoopStandardAnalysisResults &AR, LPMUpdater &U);
0430   static bool isRequired() { return true; }
0431 
0432 private:
0433   raw_ostream &OS;
0434 };
0435 
0436 //===--------------------------------------------------------------------===//
0437 // DependenceGraphInfo Implementation
0438 //===--------------------------------------------------------------------===//
0439 
0440 template <typename NodeType>
0441 bool DependenceGraphInfo<NodeType>::getDependencies(
0442     const NodeType &Src, const NodeType &Dst, DependenceList &Deps) const {
0443   assert(Deps.empty() && "Expected empty output list at the start.");
0444 
0445   // List of memory access instructions from src and dst nodes.
0446   SmallVector<Instruction *, 8> SrcIList, DstIList;
0447   auto isMemoryAccess = [](const Instruction *I) {
0448     return I->mayReadOrWriteMemory();
0449   };
0450   Src.collectInstructions(isMemoryAccess, SrcIList);
0451   Dst.collectInstructions(isMemoryAccess, DstIList);
0452 
0453   for (auto *SrcI : SrcIList)
0454     for (auto *DstI : DstIList)
0455       if (auto Dep =
0456               const_cast<DependenceInfo *>(&DI)->depends(SrcI, DstI, true))
0457         Deps.push_back(std::move(Dep));
0458 
0459   return !Deps.empty();
0460 }
0461 
0462 template <typename NodeType>
0463 std::string
0464 DependenceGraphInfo<NodeType>::getDependenceString(const NodeType &Src,
0465                                                    const NodeType &Dst) const {
0466   std::string Str;
0467   raw_string_ostream OS(Str);
0468   DependenceList Deps;
0469   if (!getDependencies(Src, Dst, Deps))
0470     return Str;
0471   interleaveComma(Deps, OS, [&](const std::unique_ptr<Dependence> &D) {
0472     D->dump(OS);
0473     // Remove the extra new-line character printed by the dump
0474     // method
0475     if (Str.back() == '\n')
0476       Str.pop_back();
0477   });
0478 
0479   return Str;
0480 }
0481 
0482 //===--------------------------------------------------------------------===//
0483 // GraphTraits specializations for the DDG
0484 //===--------------------------------------------------------------------===//
0485 
0486 /// non-const versions of the grapth trait specializations for DDG
0487 template <> struct GraphTraits<DDGNode *> {
0488   using NodeRef = DDGNode *;
0489 
0490   static DDGNode *DDGGetTargetNode(DGEdge<DDGNode, DDGEdge> *P) {
0491     return &P->getTargetNode();
0492   }
0493 
0494   // Provide a mapped iterator so that the GraphTrait-based implementations can
0495   // find the target nodes without having to explicitly go through the edges.
0496   using ChildIteratorType =
0497       mapped_iterator<DDGNode::iterator, decltype(&DDGGetTargetNode)>;
0498   using ChildEdgeIteratorType = DDGNode::iterator;
0499 
0500   static NodeRef getEntryNode(NodeRef N) { return N; }
0501   static ChildIteratorType child_begin(NodeRef N) {
0502     return ChildIteratorType(N->begin(), &DDGGetTargetNode);
0503   }
0504   static ChildIteratorType child_end(NodeRef N) {
0505     return ChildIteratorType(N->end(), &DDGGetTargetNode);
0506   }
0507 
0508   static ChildEdgeIteratorType child_edge_begin(NodeRef N) {
0509     return N->begin();
0510   }
0511   static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
0512 };
0513 
0514 template <>
0515 struct GraphTraits<DataDependenceGraph *> : public GraphTraits<DDGNode *> {
0516   using nodes_iterator = DataDependenceGraph::iterator;
0517   static NodeRef getEntryNode(DataDependenceGraph *DG) {
0518     return &DG->getRoot();
0519   }
0520   static nodes_iterator nodes_begin(DataDependenceGraph *DG) {
0521     return DG->begin();
0522   }
0523   static nodes_iterator nodes_end(DataDependenceGraph *DG) { return DG->end(); }
0524 };
0525 
0526 /// const versions of the grapth trait specializations for DDG
0527 template <> struct GraphTraits<const DDGNode *> {
0528   using NodeRef = const DDGNode *;
0529 
0530   static const DDGNode *DDGGetTargetNode(const DGEdge<DDGNode, DDGEdge> *P) {
0531     return &P->getTargetNode();
0532   }
0533 
0534   // Provide a mapped iterator so that the GraphTrait-based implementations can
0535   // find the target nodes without having to explicitly go through the edges.
0536   using ChildIteratorType =
0537       mapped_iterator<DDGNode::const_iterator, decltype(&DDGGetTargetNode)>;
0538   using ChildEdgeIteratorType = DDGNode::const_iterator;
0539 
0540   static NodeRef getEntryNode(NodeRef N) { return N; }
0541   static ChildIteratorType child_begin(NodeRef N) {
0542     return ChildIteratorType(N->begin(), &DDGGetTargetNode);
0543   }
0544   static ChildIteratorType child_end(NodeRef N) {
0545     return ChildIteratorType(N->end(), &DDGGetTargetNode);
0546   }
0547 
0548   static ChildEdgeIteratorType child_edge_begin(NodeRef N) {
0549     return N->begin();
0550   }
0551   static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
0552 };
0553 
0554 template <>
0555 struct GraphTraits<const DataDependenceGraph *>
0556     : public GraphTraits<const DDGNode *> {
0557   using nodes_iterator = DataDependenceGraph::const_iterator;
0558   static NodeRef getEntryNode(const DataDependenceGraph *DG) {
0559     return &DG->getRoot();
0560   }
0561   static nodes_iterator nodes_begin(const DataDependenceGraph *DG) {
0562     return DG->begin();
0563   }
0564   static nodes_iterator nodes_end(const DataDependenceGraph *DG) {
0565     return DG->end();
0566   }
0567 };
0568 
0569 } // namespace llvm
0570 
0571 #endif // LLVM_ANALYSIS_DDG_H