Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 14 | pmbaty | 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 | |||
| 22 | namespace llvm { | ||
| 23 | class Function; | ||
| 24 | class Loop; | ||
| 25 | class LoopInfo; | ||
| 26 | class DDGNode; | ||
| 27 | class DDGEdge; | ||
| 28 | using DDGNodeBase = DGNode<DDGNode, DDGEdge>; | ||
| 29 | using DDGEdgeBase = DGEdge<DDGNode, DDGEdge>; | ||
| 30 | using DDGBase = DirectedGraph<DDGNode, DDGEdge>; | ||
| 31 | class LPMUpdater; | ||
| 32 | |||
| 33 | /// Data Dependence Graph Node | ||
| 34 | /// The graph can represent the following types of nodes: | ||
| 35 | /// 1. Single instruction node containing just one instruction. | ||
| 36 | /// 2. Multiple instruction node where two or more instructions from | ||
| 37 | ///    the same basic block are merged into one node. | ||
| 38 | /// 3. Pi-block node which is a group of other DDG nodes that are part of a | ||
| 39 | ///    strongly-connected component of the graph. | ||
| 40 | ///    A pi-block node contains more than one single or multiple instruction | ||
| 41 | ///    nodes. The root node cannot be part of a pi-block. | ||
| 42 | /// 4. Root node is a special node that connects to all components such that | ||
| 43 | ///    there is always a path from it to any node in the graph. | ||
| 44 | class DDGNode : public DDGNodeBase { | ||
| 45 | public: | ||
| 46 | using InstructionListType = SmallVectorImpl<Instruction *>; | ||
| 47 | |||
| 48 | enum class NodeKind { | ||
| 49 | Unknown, | ||
| 50 | SingleInstruction, | ||
| 51 | MultiInstruction, | ||
| 52 | PiBlock, | ||
| 53 | Root, | ||
| 54 | }; | ||
| 55 | |||
| 56 | DDGNode() = delete; | ||
| 57 | DDGNode(const NodeKind K) : Kind(K) {} | ||
| 58 | DDGNode(const DDGNode &N) = default; | ||
| 59 | DDGNode(DDGNode &&N) : DDGNodeBase(std::move(N)), Kind(N.Kind) {} | ||
| 60 | virtual ~DDGNode() = 0; | ||
| 61 | |||
| 62 | DDGNode &operator=(const DDGNode &N) { | ||
| 63 | DGNode::operator=(N); | ||
| 64 | Kind = N.Kind; | ||
| 65 | return *this; | ||
| 66 |   } | ||
| 67 | |||
| 68 | DDGNode &operator=(DDGNode &&N) { | ||
| 69 | DGNode::operator=(std::move(N)); | ||
| 70 | Kind = N.Kind; | ||
| 71 | return *this; | ||
| 72 |   } | ||
| 73 | |||
| 74 |   /// Getter for the kind of this node. | ||
| 75 | NodeKind getKind() const { return Kind; } | ||
| 76 | |||
| 77 |   /// Collect a list of instructions, in \p IList, for which predicate \p Pred | ||
| 78 |   /// evaluates to true when iterating over instructions of this node. Return | ||
| 79 |   /// true if at least one instruction was collected, and false otherwise. | ||
| 80 | bool collectInstructions(llvm::function_ref<bool(Instruction *)> const &Pred, | ||
| 81 | InstructionListType &IList) const; | ||
| 82 | |||
| 83 | protected: | ||
| 84 |   /// Setter for the kind of this node. | ||
| 85 | void setKind(NodeKind K) { Kind = K; } | ||
| 86 | |||
| 87 | private: | ||
| 88 |   NodeKind Kind; | ||
| 89 | }; | ||
| 90 | |||
| 91 | /// Subclass of DDGNode representing the root node of the graph. | ||
| 92 | /// There should only be one such node in a given graph. | ||
| 93 | class RootDDGNode : public DDGNode { | ||
| 94 | public: | ||
| 95 | RootDDGNode() : DDGNode(NodeKind::Root) {} | ||
| 96 | RootDDGNode(const RootDDGNode &N) = delete; | ||
| 97 | RootDDGNode(RootDDGNode &&N) : DDGNode(std::move(N)) {} | ||
| 98 | ~RootDDGNode() = default; | ||
| 99 | |||
| 100 |   /// Define classof to be able to use isa<>, cast<>, dyn_cast<>, etc. | ||
| 101 | static bool classof(const DDGNode *N) { | ||
| 102 | return N->getKind() == NodeKind::Root; | ||
| 103 |   } | ||
| 104 | static bool classof(const RootDDGNode *N) { return true; } | ||
| 105 | }; | ||
| 106 | |||
| 107 | /// Subclass of DDGNode representing single or multi-instruction nodes. | ||
| 108 | class SimpleDDGNode : public DDGNode { | ||
| 109 | friend class DDGBuilder; | ||
| 110 | |||
| 111 | public: | ||
| 112 | SimpleDDGNode() = delete; | ||
| 113 | SimpleDDGNode(Instruction &I); | ||
| 114 | SimpleDDGNode(const SimpleDDGNode &N); | ||
| 115 | SimpleDDGNode(SimpleDDGNode &&N); | ||
| 116 | ~SimpleDDGNode(); | ||
| 117 | |||
| 118 | SimpleDDGNode &operator=(const SimpleDDGNode &N) = default; | ||
| 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. | ||
| 127 | const InstructionListType &getInstructions() const { | ||
| 128 | assert(!InstList.empty() && "Instruction List is empty."); | ||
| 129 | return InstList; | ||
| 130 |   } | ||
| 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. | ||
| 137 | Instruction *getFirstInstruction() const { return getInstructions().front(); } | ||
| 138 | Instruction *getLastInstruction() const { return getInstructions().back(); } | ||
| 139 | |||
| 140 |   /// Define classof to be able to use isa<>, cast<>, dyn_cast<>, etc. | ||
| 141 | static bool classof(const DDGNode *N) { | ||
| 142 | return N->getKind() == NodeKind::SingleInstruction || | ||
| 143 | N->getKind() == NodeKind::MultiInstruction; | ||
| 144 |   } | ||
| 145 | static bool classof(const SimpleDDGNode *N) { return true; } | ||
| 146 | |||
| 147 | private: | ||
| 148 |   /// Append the list of instructions in \p Input to this node. | ||
| 149 | void appendInstructions(const InstructionListType &Input) { | ||
| 150 | setKind((InstList.size() == 0 && Input.size() == 1) | ||
| 151 | ? NodeKind::SingleInstruction | ||
| 152 | : NodeKind::MultiInstruction); | ||
| 153 | llvm::append_range(InstList, Input); | ||
| 154 |   } | ||
| 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) = default; | ||
| 181 | |||
| 182 | PiBlockDDGNode &operator=(PiBlockDDGNode &&N) { | ||
| 183 | DDGNode::operator=(std::move(N)); | ||
| 184 | NodeList = std::move(N.NodeList); | ||
| 185 | return *this; | ||
| 186 |   } | ||
| 187 | |||
| 188 |   /// Get the list of nodes in this pi-block. | ||
| 189 | const PiNodeList &getNodes() const { | ||
| 190 | assert(!NodeList.empty() && "Node list is empty."); | ||
| 191 | return NodeList; | ||
| 192 |   } | ||
| 193 | PiNodeList &getNodes() { | ||
| 194 | return const_cast<PiNodeList &>( | ||
| 195 | static_cast<const PiBlockDDGNode *>(this)->getNodes()); | ||
| 196 |   } | ||
| 197 | |||
| 198 |   /// Define classof to be able to use isa<>, cast<>, dyn_cast<>, etc. | ||
| 199 | static bool classof(const DDGNode *N) { | ||
| 200 | return N->getKind() == NodeKind::PiBlock; | ||
| 201 |   } | ||
| 202 | |||
| 203 | private: | ||
| 204 |   /// List of nodes in this pi-block. | ||
| 205 |   PiNodeList NodeList; | ||
| 206 | }; | ||
| 207 | |||
| 208 | /// Data Dependency Graph Edge. | ||
| 209 | /// An edge in the DDG can represent a def-use relationship or | ||
| 210 | /// a memory dependence based on the result of DependenceAnalysis. | ||
| 211 | /// A rooted edge connects the root node to one of the components | ||
| 212 | /// of the graph. | ||
| 213 | class DDGEdge : public DDGEdgeBase { | ||
| 214 | public: | ||
| 215 |   /// The kind of edge in the DDG | ||
| 216 | enum class EdgeKind { | ||
| 217 | Unknown, | ||
| 218 | RegisterDefUse, | ||
| 219 | MemoryDependence, | ||
| 220 | Rooted, | ||
| 221 | Last = Rooted // Must be equal to the largest enum value. | ||
| 222 | }; | ||
| 223 | |||
| 224 | explicit DDGEdge(DDGNode &N) = delete; | ||
| 225 | DDGEdge(DDGNode &N, EdgeKind K) : DDGEdgeBase(N), Kind(K) {} | ||
| 226 | DDGEdge(const DDGEdge &E) : DDGEdgeBase(E), Kind(E.getKind()) {} | ||
| 227 | DDGEdge(DDGEdge &&E) : DDGEdgeBase(std::move(E)), Kind(E.Kind) {} | ||
| 228 | DDGEdge &operator=(const DDGEdge &E) = default; | ||
| 229 | |||
| 230 | DDGEdge &operator=(DDGEdge &&E) { | ||
| 231 | DDGEdgeBase::operator=(std::move(E)); | ||
| 232 | Kind = E.Kind; | ||
| 233 | return *this; | ||
| 234 |   } | ||
| 235 | |||
| 236 |   /// Get the edge kind | ||
| 237 | EdgeKind getKind() const { return Kind; }; | ||
| 238 | |||
| 239 |   /// Return true if this is a def-use edge, and false otherwise. | ||
| 240 | bool isDefUse() const { return Kind == EdgeKind::RegisterDefUse; } | ||
| 241 | |||
| 242 |   /// Return true if this is a memory dependence edge, and false otherwise. | ||
| 243 | bool isMemoryDependence() const { return Kind == EdgeKind::MemoryDependence; } | ||
| 244 | |||
| 245 |   /// Return true if this is an edge stemming from the root node, and false | ||
| 246 |   /// otherwise. | ||
| 247 | bool isRooted() const { return Kind == EdgeKind::Rooted; } | ||
| 248 | |||
| 249 | private: | ||
| 250 |   EdgeKind Kind; | ||
| 251 | }; | ||
| 252 | |||
| 253 | /// Encapsulate some common data and functionality needed for different | ||
| 254 | /// variations of data dependence graphs. | ||
| 255 | template <typename NodeType> class DependenceGraphInfo { | ||
| 256 | public: | ||
| 257 | using DependenceList = SmallVector<std::unique_ptr<Dependence>, 1>; | ||
| 258 | |||
| 259 | DependenceGraphInfo() = delete; | ||
| 260 | DependenceGraphInfo(const DependenceGraphInfo &G) = delete; | ||
| 261 | DependenceGraphInfo(const std::string &N, const DependenceInfo &DepInfo) | ||
| 262 | : Name(N), DI(DepInfo), Root(nullptr) {} | ||
| 263 | DependenceGraphInfo(DependenceGraphInfo &&G) | ||
| 264 | : Name(std::move(G.Name)), DI(std::move(G.DI)), Root(G.Root) {} | ||
| 265 | virtual ~DependenceGraphInfo() = default; | ||
| 266 | |||
| 267 |   /// Return the label that is used to name this graph. | ||
| 268 | StringRef getName() const { return Name; } | ||
| 269 | |||
| 270 |   /// Return the root node of the graph. | ||
| 271 | NodeType &getRoot() const { | ||
| 272 | assert(Root && "Root node is not available yet. Graph construction may " | ||
| 273 | "still be in progress\n"); | ||
| 274 | return *Root; | ||
| 275 |   } | ||
| 276 | |||
| 277 |   /// Collect all the data dependency infos coming from any pair of memory | ||
| 278 |   /// accesses from \p Src to \p Dst, and store them into \p Deps. Return true | ||
| 279 |   /// if a dependence exists, and false otherwise. | ||
| 280 | bool getDependencies(const NodeType &Src, const NodeType &Dst, | ||
| 281 | DependenceList &Deps) const; | ||
| 282 | |||
| 283 |   /// Return a string representing the type of dependence that the dependence | ||
| 284 |   /// analysis identified between the two given nodes. This function assumes | ||
| 285 |   /// that there is a memory dependence between the given two nodes. | ||
| 286 | std::string getDependenceString(const NodeType &Src, | ||
| 287 | const NodeType &Dst) const; | ||
| 288 | |||
| 289 | protected: | ||
| 290 |   // Name of the graph. | ||
| 291 | std::string Name; | ||
| 292 | |||
| 293 |   // Store a copy of DependenceInfo in the graph, so that individual memory | ||
| 294 |   // dependencies don't need to be stored. Instead when the dependence is | ||
| 295 |   // queried it is recomputed using @DI. | ||
| 296 | const DependenceInfo DI; | ||
| 297 | |||
| 298 |   // A special node in the graph that has an edge to every connected component of | ||
| 299 |   // the graph, to ensure all nodes are reachable in a graph walk. | ||
| 300 | NodeType *Root = nullptr; | ||
| 301 | }; | ||
| 302 | |||
| 303 | using DDGInfo = DependenceGraphInfo<DDGNode>; | ||
| 304 | |||
| 305 | /// Data Dependency Graph | ||
| 306 | class DataDependenceGraph : public DDGBase, public DDGInfo { | ||
| 307 | friend AbstractDependenceGraphBuilder<DataDependenceGraph>; | ||
| 308 | friend class DDGBuilder; | ||
| 309 | |||
| 310 | public: | ||
| 311 | using NodeType = DDGNode; | ||
| 312 | using EdgeType = DDGEdge; | ||
| 313 | |||
| 314 | DataDependenceGraph() = delete; | ||
| 315 | DataDependenceGraph(const DataDependenceGraph &G) = delete; | ||
| 316 | DataDependenceGraph(DataDependenceGraph &&G) | ||
| 317 | : DDGBase(std::move(G)), DDGInfo(std::move(G)) {} | ||
| 318 | DataDependenceGraph(Function &F, DependenceInfo &DI); | ||
| 319 | DataDependenceGraph(Loop &L, LoopInfo &LI, DependenceInfo &DI); | ||
| 320 | ~DataDependenceGraph(); | ||
| 321 | |||
| 322 |   /// If node \p N belongs to a pi-block return a pointer to the pi-block, | ||
| 323 |   /// otherwise return null. | ||
| 324 | const PiBlockDDGNode *getPiBlock(const NodeType &N) const; | ||
| 325 | |||
| 326 | protected: | ||
| 327 |   /// Add node \p N to the graph, if it's not added yet, and keep track of the | ||
| 328 |   /// root node as well as pi-blocks and their members. Return true if node is | ||
| 329 |   /// successfully added. | ||
| 330 | bool addNode(NodeType &N); | ||
| 331 | |||
| 332 | private: | ||
| 333 | using PiBlockMapType = DenseMap<const NodeType *, const PiBlockDDGNode *>; | ||
| 334 | |||
| 335 |   /// Mapping from graph nodes to their containing pi-blocks. If a node is not | ||
| 336 |   /// part of a pi-block, it will not appear in this map. | ||
| 337 |   PiBlockMapType PiBlockMap; | ||
| 338 | }; | ||
| 339 | |||
| 340 | /// Concrete implementation of a pure data dependence graph builder. This class | ||
| 341 | /// provides custom implementation for the pure-virtual functions used in the | ||
| 342 | /// generic dependence graph build algorithm. | ||
| 343 | /// | ||
| 344 | /// For information about time complexity of the build algorithm see the | ||
| 345 | /// comments near the declaration of AbstractDependenceGraphBuilder. | ||
| 346 | class DDGBuilder : public AbstractDependenceGraphBuilder<DataDependenceGraph> { | ||
| 347 | public: | ||
| 348 | DDGBuilder(DataDependenceGraph &G, DependenceInfo &D, | ||
| 349 | const BasicBlockListType &BBs) | ||
| 350 | : AbstractDependenceGraphBuilder(G, D, BBs) {} | ||
| 351 | DDGNode &createRootNode() final { | ||
| 352 | auto *RN = new RootDDGNode(); | ||
| 353 | assert(RN && "Failed to allocate memory for DDG root node."); | ||
| 354 | Graph.addNode(*RN); | ||
| 355 | return *RN; | ||
| 356 |   } | ||
| 357 | DDGNode &createFineGrainedNode(Instruction &I) final { | ||
| 358 | auto *SN = new SimpleDDGNode(I); | ||
| 359 | assert(SN && "Failed to allocate memory for simple DDG node."); | ||
| 360 | Graph.addNode(*SN); | ||
| 361 | return *SN; | ||
| 362 |   } | ||
| 363 | DDGNode &createPiBlock(const NodeListType &L) final { | ||
| 364 | auto *Pi = new PiBlockDDGNode(L); | ||
| 365 | assert(Pi && "Failed to allocate memory for pi-block node."); | ||
| 366 | Graph.addNode(*Pi); | ||
| 367 | return *Pi; | ||
| 368 |   } | ||
| 369 | DDGEdge &createDefUseEdge(DDGNode &Src, DDGNode &Tgt) final { | ||
| 370 | auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::RegisterDefUse); | ||
| 371 | assert(E && "Failed to allocate memory for edge"); | ||
| 372 | Graph.connect(Src, Tgt, *E); | ||
| 373 | return *E; | ||
| 374 |   } | ||
| 375 | DDGEdge &createMemoryEdge(DDGNode &Src, DDGNode &Tgt) final { | ||
| 376 | auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::MemoryDependence); | ||
| 377 | assert(E && "Failed to allocate memory for edge"); | ||
| 378 | Graph.connect(Src, Tgt, *E); | ||
| 379 | return *E; | ||
| 380 |   } | ||
| 381 | DDGEdge &createRootedEdge(DDGNode &Src, DDGNode &Tgt) final { | ||
| 382 | auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::Rooted); | ||
| 383 | assert(E && "Failed to allocate memory for edge"); | ||
| 384 | assert(isa<RootDDGNode>(Src) && "Expected root node"); | ||
| 385 | Graph.connect(Src, Tgt, *E); | ||
| 386 | return *E; | ||
| 387 |   } | ||
| 388 | |||
| 389 | const NodeListType &getNodesInPiBlock(const DDGNode &N) final { | ||
| 390 | auto *PiNode = dyn_cast<const PiBlockDDGNode>(&N); | ||
| 391 | assert(PiNode && "Expected a pi-block node."); | ||
| 392 | return PiNode->getNodes(); | ||
| 393 |   } | ||
| 394 | |||
| 395 |   /// Return true if the two nodes \pSrc and \pTgt are both simple nodes and | ||
| 396 |   /// the consecutive instructions after merging belong to the same basic block. | ||
| 397 | bool areNodesMergeable(const DDGNode &Src, const DDGNode &Tgt) const final; | ||
| 398 | void mergeNodes(DDGNode &Src, DDGNode &Tgt) final; | ||
| 399 | bool shouldSimplify() const final; | ||
| 400 | bool shouldCreatePiBlocks() const final; | ||
| 401 | }; | ||
| 402 | |||
| 403 | raw_ostream &operator<<(raw_ostream &OS, const DDGNode &N); | ||
| 404 | raw_ostream &operator<<(raw_ostream &OS, const DDGNode::NodeKind K); | ||
| 405 | raw_ostream &operator<<(raw_ostream &OS, const DDGEdge &E); | ||
| 406 | raw_ostream &operator<<(raw_ostream &OS, const DDGEdge::EdgeKind K); | ||
| 407 | raw_ostream &operator<<(raw_ostream &OS, const DataDependenceGraph &G); | ||
| 408 | |||
| 409 | //===--------------------------------------------------------------------===// | ||
| 410 | // DDG Analysis Passes | ||
| 411 | //===--------------------------------------------------------------------===// | ||
| 412 | |||
| 413 | /// Analysis pass that builds the DDG for a loop. | ||
| 414 | class DDGAnalysis : public AnalysisInfoMixin<DDGAnalysis> { | ||
| 415 | public: | ||
| 416 | using Result = std::unique_ptr<DataDependenceGraph>; | ||
| 417 | Result run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR); | ||
| 418 | |||
| 419 | private: | ||
| 420 | friend AnalysisInfoMixin<DDGAnalysis>; | ||
| 421 | static AnalysisKey Key; | ||
| 422 | }; | ||
| 423 | |||
| 424 | /// Textual printer pass for the DDG of a loop. | ||
| 425 | class DDGAnalysisPrinterPass : public PassInfoMixin<DDGAnalysisPrinterPass> { | ||
| 426 | public: | ||
| 427 | explicit DDGAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {} | ||
| 428 | PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, | ||
| 429 | LoopStandardAnalysisResults &AR, LPMUpdater &U); | ||
| 430 | |||
| 431 | private: | ||
| 432 | raw_ostream &OS; | ||
| 433 | }; | ||
| 434 | |||
| 435 | //===--------------------------------------------------------------------===// | ||
| 436 | // DependenceGraphInfo Implementation | ||
| 437 | //===--------------------------------------------------------------------===// | ||
| 438 | |||
| 439 | template <typename NodeType> | ||
| 440 | bool DependenceGraphInfo<NodeType>::getDependencies( | ||
| 441 | const NodeType &Src, const NodeType &Dst, DependenceList &Deps) const { | ||
| 442 | assert(Deps.empty() && "Expected empty output list at the start."); | ||
| 443 | |||
| 444 |   // List of memory access instructions from src and dst nodes. | ||
| 445 | SmallVector<Instruction *, 8> SrcIList, DstIList; | ||
| 446 | auto isMemoryAccess = [](const Instruction *I) { | ||
| 447 | return I->mayReadOrWriteMemory(); | ||
| 448 | }; | ||
| 449 | Src.collectInstructions(isMemoryAccess, SrcIList); | ||
| 450 | Dst.collectInstructions(isMemoryAccess, DstIList); | ||
| 451 | |||
| 452 | for (auto *SrcI : SrcIList) | ||
| 453 | for (auto *DstI : DstIList) | ||
| 454 | if (auto Dep = | ||
| 455 | const_cast<DependenceInfo *>(&DI)->depends(SrcI, DstI, true)) | ||
| 456 | Deps.push_back(std::move(Dep)); | ||
| 457 | |||
| 458 | return !Deps.empty(); | ||
| 459 | } | ||
| 460 | |||
| 461 | template <typename NodeType> | ||
| 462 | std::string | ||
| 463 | DependenceGraphInfo<NodeType>::getDependenceString(const NodeType &Src, | ||
| 464 | const NodeType &Dst) const { | ||
| 465 | std::string Str; | ||
| 466 | raw_string_ostream OS(Str); | ||
| 467 |   DependenceList Deps; | ||
| 468 | if (!getDependencies(Src, Dst, Deps)) | ||
| 469 | return OS.str(); | ||
| 470 | interleaveComma(Deps, OS, [&](const std::unique_ptr<Dependence> &D) { | ||
| 471 | D->dump(OS); | ||
| 472 |     // Remove the extra new-line character printed by the dump | ||
| 473 |     // method | ||
| 474 | if (OS.str().back() == '\n') | ||
| 475 | OS.str().pop_back(); | ||
| 476 | }); | ||
| 477 | |||
| 478 | return OS.str(); | ||
| 479 | } | ||
| 480 | |||
| 481 | //===--------------------------------------------------------------------===// | ||
| 482 | // GraphTraits specializations for the DDG | ||
| 483 | //===--------------------------------------------------------------------===// | ||
| 484 | |||
| 485 | /// non-const versions of the grapth trait specializations for DDG | ||
| 486 | template <> struct GraphTraits<DDGNode *> { | ||
| 487 | using NodeRef = DDGNode *; | ||
| 488 | |||
| 489 | static DDGNode *DDGGetTargetNode(DGEdge<DDGNode, DDGEdge> *P) { | ||
| 490 | return &P->getTargetNode(); | ||
| 491 |   } | ||
| 492 | |||
| 493 |   // Provide a mapped iterator so that the GraphTrait-based implementations can | ||
| 494 |   // find the target nodes without having to explicitly go through the edges. | ||
| 495 | using ChildIteratorType = | ||
| 496 | mapped_iterator<DDGNode::iterator, decltype(&DDGGetTargetNode)>; | ||
| 497 | using ChildEdgeIteratorType = DDGNode::iterator; | ||
| 498 | |||
| 499 | static NodeRef getEntryNode(NodeRef N) { return N; } | ||
| 500 | static ChildIteratorType child_begin(NodeRef N) { | ||
| 501 | return ChildIteratorType(N->begin(), &DDGGetTargetNode); | ||
| 502 |   } | ||
| 503 | static ChildIteratorType child_end(NodeRef N) { | ||
| 504 | return ChildIteratorType(N->end(), &DDGGetTargetNode); | ||
| 505 |   } | ||
| 506 | |||
| 507 | static ChildEdgeIteratorType child_edge_begin(NodeRef N) { | ||
| 508 | return N->begin(); | ||
| 509 |   } | ||
| 510 | static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); } | ||
| 511 | }; | ||
| 512 | |||
| 513 | template <> | ||
| 514 | struct GraphTraits<DataDependenceGraph *> : public GraphTraits<DDGNode *> { | ||
| 515 | using nodes_iterator = DataDependenceGraph::iterator; | ||
| 516 | static NodeRef getEntryNode(DataDependenceGraph *DG) { | ||
| 517 | return &DG->getRoot(); | ||
| 518 |   } | ||
| 519 | static nodes_iterator nodes_begin(DataDependenceGraph *DG) { | ||
| 520 | return DG->begin(); | ||
| 521 |   } | ||
| 522 | static nodes_iterator nodes_end(DataDependenceGraph *DG) { return DG->end(); } | ||
| 523 | }; | ||
| 524 | |||
| 525 | /// const versions of the grapth trait specializations for DDG | ||
| 526 | template <> struct GraphTraits<const DDGNode *> { | ||
| 527 | using NodeRef = const DDGNode *; | ||
| 528 | |||
| 529 | static const DDGNode *DDGGetTargetNode(const DGEdge<DDGNode, DDGEdge> *P) { | ||
| 530 | return &P->getTargetNode(); | ||
| 531 |   } | ||
| 532 | |||
| 533 |   // Provide a mapped iterator so that the GraphTrait-based implementations can | ||
| 534 |   // find the target nodes without having to explicitly go through the edges. | ||
| 535 | using ChildIteratorType = | ||
| 536 | mapped_iterator<DDGNode::const_iterator, decltype(&DDGGetTargetNode)>; | ||
| 537 | using ChildEdgeIteratorType = DDGNode::const_iterator; | ||
| 538 | |||
| 539 | static NodeRef getEntryNode(NodeRef N) { return N; } | ||
| 540 | static ChildIteratorType child_begin(NodeRef N) { | ||
| 541 | return ChildIteratorType(N->begin(), &DDGGetTargetNode); | ||
| 542 |   } | ||
| 543 | static ChildIteratorType child_end(NodeRef N) { | ||
| 544 | return ChildIteratorType(N->end(), &DDGGetTargetNode); | ||
| 545 |   } | ||
| 546 | |||
| 547 | static ChildEdgeIteratorType child_edge_begin(NodeRef N) { | ||
| 548 | return N->begin(); | ||
| 549 |   } | ||
| 550 | static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); } | ||
| 551 | }; | ||
| 552 | |||
| 553 | template <> | ||
| 554 | struct GraphTraits<const DataDependenceGraph *> | ||
| 555 | : public GraphTraits<const DDGNode *> { | ||
| 556 | using nodes_iterator = DataDependenceGraph::const_iterator; | ||
| 557 | static NodeRef getEntryNode(const DataDependenceGraph *DG) { | ||
| 558 | return &DG->getRoot(); | ||
| 559 |   } | ||
| 560 | static nodes_iterator nodes_begin(const DataDependenceGraph *DG) { | ||
| 561 | return DG->begin(); | ||
| 562 |   } | ||
| 563 | static nodes_iterator nodes_end(const DataDependenceGraph *DG) { | ||
| 564 | return DG->end(); | ||
| 565 |   } | ||
| 566 | }; | ||
| 567 | |||
| 568 | } // namespace llvm | ||
| 569 | |||
| 570 | #endif // LLVM_ANALYSIS_DDG_H |