1e8d8bef9SDimitry Andric //===- DDGPrinter.cpp - DOT printer for the data dependence graph ----------==// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric 9e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 10e8d8bef9SDimitry Andric // 11e8d8bef9SDimitry Andric // This file defines the `-dot-ddg` analysis pass, which emits DDG in DOT format 12e8d8bef9SDimitry Andric // in a file named `ddg.<graph-name>.dot` for each loop in a function. 13e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 14e8d8bef9SDimitry Andric 15e8d8bef9SDimitry Andric #include "llvm/Analysis/DDGPrinter.h" 16e8d8bef9SDimitry Andric #include "llvm/Support/CommandLine.h" 17e8d8bef9SDimitry Andric #include "llvm/Support/GraphWriter.h" 18e8d8bef9SDimitry Andric 19e8d8bef9SDimitry Andric using namespace llvm; 20e8d8bef9SDimitry Andric 21e8d8bef9SDimitry Andric static cl::opt<bool> DotOnly("dot-ddg-only", cl::init(false), cl::Hidden, 22e8d8bef9SDimitry Andric cl::ZeroOrMore, cl::desc("simple ddg dot graph")); 23e8d8bef9SDimitry Andric static cl::opt<std::string> DDGDotFilenamePrefix( 24e8d8bef9SDimitry Andric "dot-ddg-filename-prefix", cl::init("ddg"), cl::Hidden, 25e8d8bef9SDimitry Andric cl::desc("The prefix used for the DDG dot file names.")); 26e8d8bef9SDimitry Andric 27e8d8bef9SDimitry Andric static void writeDDGToDotFile(DataDependenceGraph &G, bool DOnly = false); 28e8d8bef9SDimitry Andric 29e8d8bef9SDimitry Andric //===--------------------------------------------------------------------===// 30e8d8bef9SDimitry Andric // Implementation of DDG DOT Printer for a loop 31e8d8bef9SDimitry Andric //===--------------------------------------------------------------------===// 32e8d8bef9SDimitry Andric PreservedAnalyses DDGDotPrinterPass::run(Loop &L, LoopAnalysisManager &AM, 33e8d8bef9SDimitry Andric LoopStandardAnalysisResults &AR, 34e8d8bef9SDimitry Andric LPMUpdater &U) { 35e8d8bef9SDimitry Andric writeDDGToDotFile(*AM.getResult<DDGAnalysis>(L, AR), DotOnly); 36e8d8bef9SDimitry Andric return PreservedAnalyses::all(); 37e8d8bef9SDimitry Andric } 38e8d8bef9SDimitry Andric 39e8d8bef9SDimitry Andric static void writeDDGToDotFile(DataDependenceGraph &G, bool DOnly) { 40e8d8bef9SDimitry Andric std::string Filename = 41e8d8bef9SDimitry Andric Twine(DDGDotFilenamePrefix + "." + G.getName() + ".dot").str(); 42e8d8bef9SDimitry Andric errs() << "Writing '" << Filename << "'..."; 43e8d8bef9SDimitry Andric 44e8d8bef9SDimitry Andric std::error_code EC; 45*fe6060f1SDimitry Andric raw_fd_ostream File(Filename, EC, sys::fs::OF_Text); 46e8d8bef9SDimitry Andric 47e8d8bef9SDimitry Andric if (!EC) 48e8d8bef9SDimitry Andric // We only provide the constant verson of the DOTGraphTrait specialization, 49e8d8bef9SDimitry Andric // hence the conversion to const pointer 50e8d8bef9SDimitry Andric WriteGraph(File, (const DataDependenceGraph *)&G, DOnly); 51e8d8bef9SDimitry Andric else 52e8d8bef9SDimitry Andric errs() << " error opening file for writing!"; 53e8d8bef9SDimitry Andric errs() << "\n"; 54e8d8bef9SDimitry Andric } 55e8d8bef9SDimitry Andric 56e8d8bef9SDimitry Andric //===--------------------------------------------------------------------===// 57e8d8bef9SDimitry Andric // DDG DOT Printer Implementation 58e8d8bef9SDimitry Andric //===--------------------------------------------------------------------===// 59e8d8bef9SDimitry Andric std::string DDGDotGraphTraits::getNodeLabel(const DDGNode *Node, 60e8d8bef9SDimitry Andric const DataDependenceGraph *Graph) { 61e8d8bef9SDimitry Andric if (isSimple()) 62e8d8bef9SDimitry Andric return getSimpleNodeLabel(Node, Graph); 63e8d8bef9SDimitry Andric else 64e8d8bef9SDimitry Andric return getVerboseNodeLabel(Node, Graph); 65e8d8bef9SDimitry Andric } 66e8d8bef9SDimitry Andric 67e8d8bef9SDimitry Andric std::string DDGDotGraphTraits::getEdgeAttributes( 68e8d8bef9SDimitry Andric const DDGNode *Node, GraphTraits<const DDGNode *>::ChildIteratorType I, 69e8d8bef9SDimitry Andric const DataDependenceGraph *G) { 70e8d8bef9SDimitry Andric const DDGEdge *E = static_cast<const DDGEdge *>(*I.getCurrent()); 71e8d8bef9SDimitry Andric if (isSimple()) 72e8d8bef9SDimitry Andric return getSimpleEdgeAttributes(Node, E, G); 73e8d8bef9SDimitry Andric else 74e8d8bef9SDimitry Andric return getVerboseEdgeAttributes(Node, E, G); 75e8d8bef9SDimitry Andric } 76e8d8bef9SDimitry Andric 77e8d8bef9SDimitry Andric bool DDGDotGraphTraits::isNodeHidden(const DDGNode *Node, 78e8d8bef9SDimitry Andric const DataDependenceGraph *Graph) { 79e8d8bef9SDimitry Andric if (isSimple() && isa<RootDDGNode>(Node)) 80e8d8bef9SDimitry Andric return true; 81e8d8bef9SDimitry Andric assert(Graph && "expected a valid graph pointer"); 82e8d8bef9SDimitry Andric return Graph->getPiBlock(*Node) != nullptr; 83e8d8bef9SDimitry Andric } 84e8d8bef9SDimitry Andric 85e8d8bef9SDimitry Andric std::string 86e8d8bef9SDimitry Andric DDGDotGraphTraits::getSimpleNodeLabel(const DDGNode *Node, 87e8d8bef9SDimitry Andric const DataDependenceGraph *G) { 88e8d8bef9SDimitry Andric std::string Str; 89e8d8bef9SDimitry Andric raw_string_ostream OS(Str); 90e8d8bef9SDimitry Andric if (isa<SimpleDDGNode>(Node)) 91e8d8bef9SDimitry Andric for (auto *II : static_cast<const SimpleDDGNode *>(Node)->getInstructions()) 92e8d8bef9SDimitry Andric OS << *II << "\n"; 93e8d8bef9SDimitry Andric else if (isa<PiBlockDDGNode>(Node)) 94e8d8bef9SDimitry Andric OS << "pi-block\nwith\n" 95e8d8bef9SDimitry Andric << cast<PiBlockDDGNode>(Node)->getNodes().size() << " nodes\n"; 96e8d8bef9SDimitry Andric else if (isa<RootDDGNode>(Node)) 97e8d8bef9SDimitry Andric OS << "root\n"; 98e8d8bef9SDimitry Andric else 99e8d8bef9SDimitry Andric llvm_unreachable("Unimplemented type of node"); 100e8d8bef9SDimitry Andric return OS.str(); 101e8d8bef9SDimitry Andric } 102e8d8bef9SDimitry Andric 103e8d8bef9SDimitry Andric std::string 104e8d8bef9SDimitry Andric DDGDotGraphTraits::getVerboseNodeLabel(const DDGNode *Node, 105e8d8bef9SDimitry Andric const DataDependenceGraph *G) { 106e8d8bef9SDimitry Andric std::string Str; 107e8d8bef9SDimitry Andric raw_string_ostream OS(Str); 108e8d8bef9SDimitry Andric OS << "<kind:" << Node->getKind() << ">\n"; 109e8d8bef9SDimitry Andric if (isa<SimpleDDGNode>(Node)) 110e8d8bef9SDimitry Andric for (auto *II : static_cast<const SimpleDDGNode *>(Node)->getInstructions()) 111e8d8bef9SDimitry Andric OS << *II << "\n"; 112e8d8bef9SDimitry Andric else if (isa<PiBlockDDGNode>(Node)) { 113e8d8bef9SDimitry Andric OS << "--- start of nodes in pi-block ---\n"; 114e8d8bef9SDimitry Andric unsigned Count = 0; 115e8d8bef9SDimitry Andric const auto &PNodes = cast<PiBlockDDGNode>(Node)->getNodes(); 116e8d8bef9SDimitry Andric for (auto *PN : PNodes) { 117e8d8bef9SDimitry Andric OS << getVerboseNodeLabel(PN, G); 118e8d8bef9SDimitry Andric if (++Count != PNodes.size()) 119e8d8bef9SDimitry Andric OS << "\n"; 120e8d8bef9SDimitry Andric } 121e8d8bef9SDimitry Andric OS << "--- end of nodes in pi-block ---\n"; 122e8d8bef9SDimitry Andric } else if (isa<RootDDGNode>(Node)) 123e8d8bef9SDimitry Andric OS << "root\n"; 124e8d8bef9SDimitry Andric else 125e8d8bef9SDimitry Andric llvm_unreachable("Unimplemented type of node"); 126e8d8bef9SDimitry Andric return OS.str(); 127e8d8bef9SDimitry Andric } 128e8d8bef9SDimitry Andric 129e8d8bef9SDimitry Andric std::string DDGDotGraphTraits::getSimpleEdgeAttributes( 130e8d8bef9SDimitry Andric const DDGNode *Src, const DDGEdge *Edge, const DataDependenceGraph *G) { 131e8d8bef9SDimitry Andric std::string Str; 132e8d8bef9SDimitry Andric raw_string_ostream OS(Str); 133e8d8bef9SDimitry Andric DDGEdge::EdgeKind Kind = Edge->getKind(); 134e8d8bef9SDimitry Andric OS << "label=\"[" << Kind << "]\""; 135e8d8bef9SDimitry Andric return OS.str(); 136e8d8bef9SDimitry Andric } 137e8d8bef9SDimitry Andric 138e8d8bef9SDimitry Andric std::string DDGDotGraphTraits::getVerboseEdgeAttributes( 139e8d8bef9SDimitry Andric const DDGNode *Src, const DDGEdge *Edge, const DataDependenceGraph *G) { 140e8d8bef9SDimitry Andric std::string Str; 141e8d8bef9SDimitry Andric raw_string_ostream OS(Str); 142e8d8bef9SDimitry Andric DDGEdge::EdgeKind Kind = Edge->getKind(); 143e8d8bef9SDimitry Andric OS << "label=\"["; 144e8d8bef9SDimitry Andric if (Kind == DDGEdge::EdgeKind::MemoryDependence) 145e8d8bef9SDimitry Andric OS << G->getDependenceString(*Src, Edge->getTargetNode()); 146e8d8bef9SDimitry Andric else 147e8d8bef9SDimitry Andric OS << Kind; 148e8d8bef9SDimitry Andric OS << "]\""; 149e8d8bef9SDimitry Andric return OS.str(); 150e8d8bef9SDimitry Andric } 151