From 9d5b532de9bdca37810a59a93a69128441b02c55 Mon Sep 17 00:00:00 2001 From: Reid Spencer Date: Tue, 27 Jun 2006 16:49:46 +0000 Subject: [PATCH] For PR801: Refactor the Graph writing code to use a common implementation which is now in lib/Support/GraphWriter.cpp. This completes the PR. Patch by Anton Korobeynikov. Thanks, Anton! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@28925 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Support/GraphWriter.h | 58 +++++++++++ lib/Analysis/CFGPrinter.cpp | 96 +------------------ lib/Analysis/DataStructure/Printer.cpp | 87 +---------------- lib/CodeGen/MachineFunction.cpp | 96 +------------------ .../SelectionDAG/SelectionDAGPrinter.cpp | 94 +----------------- lib/Support/GraphWriter.cpp | 89 +++++++++++++++++ 6 files changed, 156 insertions(+), 364 deletions(-) create mode 100644 lib/Support/GraphWriter.cpp diff --git a/include/llvm/Support/GraphWriter.h b/include/llvm/Support/GraphWriter.h index ac0d52379f0..9f96a772380 100644 --- a/include/llvm/Support/GraphWriter.h +++ b/include/llvm/Support/GraphWriter.h @@ -25,8 +25,10 @@ #include "llvm/Support/DOTGraphTraits.h" #include "llvm/ADT/GraphTraits.h" +#include "llvm/System/Path.h" #include #include +#include namespace llvm { @@ -59,6 +61,8 @@ namespace DOT { // Private functions... } } +void DisplayGraph(const sys::Path& Filename); + template class GraphWriter { std::ostream &O; @@ -236,6 +240,60 @@ std::ostream &WriteGraph(std::ostream &O, const GraphType &G, return O; } +template +sys::Path WriteGraph(const GraphType &G, + const std::string& Name, + const std::string& Title = "") { + sys::Path Filename = sys::Path::GetTemporaryDirectory();; + Filename.appendComponent(Name + ".dot"); + Filename.makeUnique(); + std::cerr << "Writing '" << Filename << "'... "; + + std::ofstream O(Filename.c_str()); + + if (O.good()) { + // Start the graph emission process... + GraphWriter W(O, G); + + // Output the header for the graph... + W.writeHeader(Title); + + // Emit all of the nodes in the graph... + W.writeNodes(); + + // Output any customizations on the graph + DOTGraphTraits::addCustomGraphFeatures(G, W); + + // Output the end of the graph + W.writeFooter(); + std::cerr << " done. \n"; + + O.close(); + + } else { + std::cerr << "error opening file for writing!\n"; + Filename.clear(); + } + + return Filename; +} + +/// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file, +/// then cleanup. For use from the debugger. +/// +template +void ViewGraph(const GraphType& G, + const std::string& Name, + const std::string& Title = "") { + sys::Path Filename = WriteGraph(G, Name, Title); + + if (Filename.isEmpty()) { + return; + } + + DisplayGraph(Filename); +} + } // End llvm namespace #endif diff --git a/lib/Analysis/CFGPrinter.cpp b/lib/Analysis/CFGPrinter.cpp index 578889bade9..693c1f6d8c6 100644 --- a/lib/Analysis/CFGPrinter.cpp +++ b/lib/Analysis/CFGPrinter.cpp @@ -24,8 +24,6 @@ #include "llvm/Assembly/Writer.h" #include "llvm/Support/CFG.h" #include "llvm/Support/GraphWriter.h" -#include "llvm/System/Path.h" -#include "llvm/System/Program.h" #include "llvm/Config/config.h" #include #include @@ -140,99 +138,7 @@ namespace { /// being a 'dot' and 'gv' program in your path. /// void Function::viewCFG() const { -#ifndef NDEBUG - char pathsuff[9]; - - sprintf(pathsuff, "%06u", unsigned(rand())); - - sys::Path TempDir = sys::Path::GetTemporaryDirectory(); - sys::Path Filename = TempDir; - - Filename.appendComponent("cfg" + getName() + "." + pathsuff + ".dot"); - std::cerr << "Writing '" << Filename << "'... "; - std::ofstream F(Filename.c_str()); - - if (!F.good()) { - std::cerr << " error opening file for writing!\n"; - return; - } - - WriteGraph(F, this); - F.close(); - std::cerr << "\n"; - -#if HAVE_GRAPHVIZ - sys::Path Graphviz(LLVM_PATH_GRAPHVIZ); - std::vector args; - args.push_back(Graphviz.c_str()); - args.push_back(Filename.c_str()); - args.push_back(0); - - std::cerr << "Running 'Graphviz' program... " << std::flush; - if (sys::Program::ExecuteAndWait(Graphviz, &args[0])) { - std::cerr << "Error viewing graph: 'Graphviz' not in path?\n"; - } else { - Filename.eraseFromDisk(); - return; - } -#elif (HAVE_GV && HAVE_DOT) - sys::Path PSFilename = TempDir; - PSFilename.appendComponent(std::string("cfg.tempgraph") + "." + pathsuff + ".ps"); - - sys::Path dot(LLVM_PATH_DOT); - std::vector args; - args.push_back(dot.c_str()); - args.push_back("-Tps"); - args.push_back("-Nfontname=Courier"); - args.push_back("-Gsize=7.5,10"); - args.push_back(Filename.c_str()); - args.push_back("-o"); - args.push_back(PSFilename.c_str()); - args.push_back(0); - - std::cerr << "Running 'dot' program... " << std::flush; - if (sys::Program::ExecuteAndWait(dot, &args[0])) { - std::cerr << "Error viewing graph: 'dot' not in path?\n"; - } else { - std::cerr << "\n"; - - sys::Path gv(LLVM_PATH_GV); - args.clear(); - args.push_back(gv.c_str()); - args.push_back(PSFilename.c_str()); - args.push_back(0); - - sys::Program::ExecuteAndWait(gv, &args[0]); - } - Filename.eraseFromDisk(); - PSFilename.eraseFromDisk(); - return; -#elif HAVE_DOTTY - sys::Path dotty(LLVM_PATH_DOTTY); - std::vector args; - args.push_back(dotty.c_str()); - args.push_back(Filename.c_str()); - args.push_back(0); - - std::cerr << "Running 'dotty' program... " << std::flush; - if (sys::Program::ExecuteAndWait(dotty, &args[0])) { - std::cerr << "Error viewing graph: 'dotty' not in path?\n"; - } else { -#ifndef __MINGW32__ // Dotty spawns another app and doesn't wait until it returns - Filename.eraseFromDisk(); -#endif - return; - } -#endif - -#endif // NDEBUG - std::cerr << "Function::viewCFG is only available in debug builds on " - << "systems with Graphviz or gv or dotty!\n"; - -#ifndef NDEBUG - Filename.eraseFromDisk(); - TempDir.eraseFromDisk(true); -#endif + ViewGraph(this, "cfg" + getName()); } /// viewCFGOnly - This function is meant for use from the debugger. It works diff --git a/lib/Analysis/DataStructure/Printer.cpp b/lib/Analysis/DataStructure/Printer.cpp index 71a5071ae46..7cb79247e4b 100644 --- a/lib/Analysis/DataStructure/Printer.cpp +++ b/lib/Analysis/DataStructure/Printer.cpp @@ -19,8 +19,6 @@ #include "llvm/Assembly/Writer.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/GraphWriter.h" -#include "llvm/System/Path.h" -#include "llvm/System/Program.h" #include "llvm/ADT/Statistic.h" #include "llvm/Config/config.h" #include @@ -259,90 +257,7 @@ void DSGraph::writeGraphToFile(std::ostream &O, /// then cleanup. For use from the debugger. /// void DSGraph::viewGraph() const { - char pathsuff[9]; - - sprintf(pathsuff, "%06u", unsigned(rand())); - - sys::Path TempDir = sys::Path::GetTemporaryDirectory(); - sys::Path Filename = TempDir; - Filename.appendComponent("ds.tempgraph." + std::string(pathsuff) + ".dot"); - std::cerr << "Writing '" << Filename << "'... "; - std::ofstream F(Filename.c_str()); - - if (!F.good()) { - std::cerr << " error opening file for writing!\n"; - return; - } - - print(F); - F.close(); - std::cerr << "\n"; - -#if HAVE_GRAPHVIZ - sys::Path Graphviz(LLVM_PATH_GRAPHVIZ); - std::vector args; - args.push_back(Graphviz.c_str()); - args.push_back(Filename.c_str()); - args.push_back(0); - - std::cerr << "Running 'Graphviz' program... " << std::flush; - if (sys::Program::ExecuteAndWait(Graphviz, &args[0])) { - std::cerr << "Error viewing graph: 'Graphviz' not in path?\n"; - } else { - Filename.eraseFromDisk(); - return; - } -#elif (HAVE_GV && HAVE_DOT) - sys::Path PSFilename = TempDir; - PSFilename.appendComponent(std::string("ds.tempgraph") + "." + pathsuff + ".ps"); - - sys::Path dot(LLVM_PATH_DOT); - std::vector args; - args.push_back(dot.c_str()); - args.push_back("-Tps"); - args.push_back("-Nfontname=Courier"); - args.push_back("-Gsize=7.5,10"); - args.push_back(Filename.c_str()); - args.push_back("-o"); - args.push_back(PSFilename.c_str()); - args.push_back(0); - - std::cerr << "Running 'dot' program... " << std::flush; - if (sys::Program::ExecuteAndWait(dot, &args[0])) { - std::cerr << "Error viewing graph: 'dot' not in path?\n"; - } else { - std::cerr << "\n"; - - sys::Path gv(LLVM_PATH_GV); - args.clear(); - args.push_back(gv.c_str()); - args.push_back(PSFilename.c_str()); - args.push_back(0); - - sys::Program::ExecuteAndWait(gv, &args[0]); - } - Filename.eraseFromDisk(); - PSFilename.eraseFromDisk(); - return; -#elif HAVE_DOTTY - sys::Path dotty(LLVM_PATH_DOTTY); - std::vector args; - args.push_back(Filename.c_str()); - args.push_back(0); - - std::cerr << "Running 'dotty' program... " << std::flush; - if (sys::Program::ExecuteAndWait(dotty, &args[0])) { - std::cerr << "Error viewing graph: 'dotty' not in path?\n"; - } else { -#ifndef __MINGW32__ // Dotty spawns another app and doesn't wait until it returns - Filename.eraseFromDisk(); -#endif - return; - } -#endif - - Filename.eraseFromDisk(); - TempDir.eraseFromDisk(true); + ViewGraph(this, "ds.tempgraph", "DataStructures"); } diff --git a/lib/CodeGen/MachineFunction.cpp b/lib/CodeGen/MachineFunction.cpp index 18ea25f3c36..4c597d9b5ef 100644 --- a/lib/CodeGen/MachineFunction.cpp +++ b/lib/CodeGen/MachineFunction.cpp @@ -27,8 +27,6 @@ #include "llvm/Instructions.h" #include "llvm/Support/LeakDetector.h" #include "llvm/Support/GraphWriter.h" -#include "llvm/System/Path.h" -#include "llvm/System/Program.h" #include "llvm/Config/config.h" #include #include @@ -220,97 +218,11 @@ namespace llvm { void MachineFunction::viewCFG() const { #ifndef NDEBUG - char pathsuff[9]; - - sprintf(pathsuff, "%06u", unsigned(rand())); - - sys::Path TempDir = sys::Path::GetTemporaryDirectory(); - sys::Path Filename = TempDir; - Filename.appendComponent("mf" + getFunction()->getName() + "." + pathsuff + ".dot"); - std::cerr << "Writing '" << Filename << "'... "; - std::ofstream F(Filename.c_str()); - - if (!F) { - std::cerr << " error opening file for writing!\n"; - return; - } - - WriteGraph(F, this); - F.close(); - std::cerr << "\n"; - -#if HAVE_GRAPHVIZ - sys::Path Graphviz(LLVM_PATH_GRAPHVIZ); - std::vector args; - args.push_back(Graphviz.c_str()); - args.push_back(Filename.c_str()); - args.push_back(0); - - std::cerr << "Running 'Graphviz' program... " << std::flush; - if (sys::Program::ExecuteAndWait(Graphviz, &args[0])) { - std::cerr << "Error viewing graph: 'Graphviz' not in path?\n"; - } else { - Filename.eraseFromDisk(); - return; - } -#elif (HAVE_GV && HAVE_DOT) - sys::Path PSFilename = TempDir; - PSFilename.appendComponent(std::string("mf.tempgraph") + "." + pathsuff + ".ps"); - - sys::Path dot(LLVM_PATH_DOT); - std::vector args; - args.push_back(dot.c_str()); - args.push_back("-Tps"); - args.push_back("-Nfontname=Courier"); - args.push_back("-Gsize=7.5,10"); - args.push_back(Filename.c_str()); - args.push_back("-o"); - args.push_back(PSFilename.c_str()); - args.push_back(0); - - std::cerr << "Running 'dot' program... " << std::flush; - if (sys::Program::ExecuteAndWait(dot, &args[0])) { - std::cerr << "Error viewing graph: 'dot' not in path?\n"; - } else { - std::cerr << "\n"; - - sys::Path gv(LLVM_PATH_GV); - args.clear(); - args.push_back(gv.c_str()); - args.push_back(PSFilename.c_str()); - args.push_back(0); - - sys::Program::ExecuteAndWait(gv, &args[0]); - } - Filename.eraseFromDisk(); - PSFilename.eraseFromDisk(); - return; -#elif HAVE_DOTTY - sys::Path dotty(LLVM_PATH_DOTTY); - std::vector args; - args.push_back(dotty.c_str()); - args.push_back(Filename.c_str()); - args.push_back(0); - - std::cerr << "Running 'dotty' program... " << std::flush; - if (sys::Program::ExecuteAndWait(dotty, &args[0])) { - std::cerr << "Error viewing graph: 'dotty' not in path?\n"; - } else { -#ifndef __MINGW32__ // Dotty spawns another app and doesn't wait until it returns - Filename.eraseFromDisk(); -#endif - return; - } -#endif - -#endif // NDEBUG - std::cerr << "MachineFunction::viewCFG is only available in debug builds on " + ViewGraph(this, "mf" + getFunction()->getName()); +#else + std::cerr << "SelectionDAG::viewGraph is only available in debug builds on " << "systems with Graphviz or gv!\n"; - -#ifndef NDEBUG - Filename.eraseFromDisk(); - TempDir.eraseFromDisk(true); -#endif +#endif // NDEBUG } void MachineFunction::viewCFGOnly() const diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp index bc6d1b67bf1..28baa324491 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp @@ -19,8 +19,6 @@ #include "llvm/Target/MRegisterInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Support/GraphWriter.h" -#include "llvm/System/Path.h" -#include "llvm/System/Program.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" #include @@ -127,95 +125,9 @@ std::string DOTGraphTraits::getNodeLabel(const SDNode *Node, void SelectionDAG::viewGraph() { // This code is only for debugging! #ifndef NDEBUG - char pathsuff[9]; - - sprintf(pathsuff, "%06u", unsigned(rand())); - - sys::Path TempDir = sys::Path::GetTemporaryDirectory(); - sys::Path Filename = TempDir; - Filename.appendComponent("dag." + getMachineFunction().getFunction()->getName() + "." + pathsuff + ".dot"); - std::cerr << "Writing '" << Filename.toString() << "'... "; - std::ofstream F(Filename.toString().c_str()); - - if (!F) { - std::cerr << " error opening file for writing!\n"; - return; - } - - WriteGraph(F, this); - F.close(); - std::cerr << "\n"; - -#if HAVE_GRAPHVIZ - sys::Path Graphviz(LLVM_PATH_GRAPHVIZ); - std::vector args; - args.push_back(Graphviz.c_str()); - args.push_back(Filename.c_str()); - args.push_back(0); - - std::cerr << "Running 'Graphviz' program... " << std::flush; - if (sys::Program::ExecuteAndWait(Graphviz, &args[0])) { - std::cerr << "Error viewing graph: 'Graphviz' not in path?\n"; - } else { - Filename.eraseFromDisk(); - return; - } -#elif (HAVE_GV && HAVE_DOT) - sys::Path PSFilename = TempDir; - PSFilename.appendComponent(std::string("dag.tempgraph") + "." + pathsuff + ".ps"); - - sys::Path dot(LLVM_PATH_DOT); - std::vector args; - args.push_back(dot.c_str()); - args.push_back("-Tps"); - args.push_back("-Nfontname=Courier"); - args.push_back("-Gsize=7.5,10"); - args.push_back(Filename.c_str()); - args.push_back("-o"); - args.push_back(PSFilename.c_str()); - args.push_back(0); - - std::cerr << "Running 'dot' program... " << std::flush; - if (sys::Program::ExecuteAndWait(dot, &args[0])) { - std::cerr << "Error viewing graph: 'dot' not in path?\n"; - } else { - std::cerr << "\n"; - - sys::Path gv(LLVM_PATH_GV); - args.clear(); - args.push_back(gv.c_str()); - args.push_back(PSFilename.c_str()); - args.push_back(0); - - sys::Program::ExecuteAndWait(gv, &args[0]); - } - Filename.eraseFromDisk(); - PSFilename.eraseFromDisk(); - return; -#elif HAVE_DOTTY - sys::Path dotty(LLVM_PATH_DOTTY); - std::vector args; - args.push_back(dotty.c_str()); - args.push_back(Filename.c_str()); - args.push_back(0); - - std::cerr << "Running 'dotty' program... " << std::flush; - if (sys::Program::ExecuteAndWait(dotty, &args[0])) { - std::cerr << "Error viewing graph: 'dotty' not in path?\n"; - } else { -#ifndef __MINGW32__ // Dotty spawns another app and doesn't wait until it returns - Filename.eraseFromDisk(); -#endif - return; - } -#endif - -#endif // NDEBUG + ViewGraph(this, "dag." + getMachineFunction().getFunction()->getName()); +#else std::cerr << "SelectionDAG::viewGraph is only available in debug builds on " << "systems with Graphviz or gv!\n"; - -#ifndef NDEBUG - Filename.eraseFromDisk(); - TempDir.eraseFromDisk(true); -#endif +#endif // NDEBUG } diff --git a/lib/Support/GraphWriter.cpp b/lib/Support/GraphWriter.cpp new file mode 100644 index 00000000000..73126e29258 --- /dev/null +++ b/lib/Support/GraphWriter.cpp @@ -0,0 +1,89 @@ +//===-- GraphWriter.cpp - Implements GraphWriter support routines ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by the LLVM research group and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements misc. GraphWriter support routines. +// +//===----------------------------------------------------------------------===// + +#include "llvm/System/Path.h" +#include "llvm/System/Program.h" +#include "llvm/Config/config.h" + +#include + +using namespace llvm; + +namespace llvm { + +void DisplayGraph(const sys::Path& Filename) +{ +#if HAVE_GRAPHVIZ + sys::Path Graphviz(LLVM_PATH_GRAPHVIZ); + + std::vector args; + args.push_back(Graphviz.c_str()); + args.push_back(Filename.c_str()); + args.push_back(0); + + std::cerr << "Running 'Graphviz' program... " << std::flush; + if (sys::Program::ExecuteAndWait(Graphviz, &args[0])) { + std::cerr << "Error viewing graph: 'Graphviz' not in path?\n"; + } +#elif (HAVE_GV && HAVE_DOT) + sys::Path PSFilename = Filename; + PSFilename.appendSuffix("ps"); + + sys::Path dot(LLVM_PATH_DOT); + + std::vector args; + args.push_back(dot.c_str()); + args.push_back("-Tps"); + args.push_back("-Nfontname=Courier"); + args.push_back("-Gsize=7.5,10"); + args.push_back(Filename.c_str()); + args.push_back("-o"); + args.push_back(PSFilename.c_str()); + args.push_back(0); + + std::cerr << "Running 'dot' program... " << std::flush; + if (sys::Program::ExecuteAndWait(dot, &args[0])) { + std::cerr << "Error viewing graph: 'dot' not in path?\n"; + } else { + std::cerr << " done. \n"; + + sys::Path gv(LLVM_PATH_GV); + args.clear(); + args.push_back(gv.c_str()); + args.push_back(PSFilename.c_str()); + args.push_back(0); + + sys::Program::ExecuteAndWait(gv, &args[0]); + } + PSFilename.eraseFromDisk(); +#elif HAVE_DOTTY + sys::Path dotty(LLVM_PATH_DOTTY); + + std::vector args; + args.push_back(Filename.c_str()); + args.push_back(0); + + std::cerr << "Running 'dotty' program... " << std::flush; + if (sys::Program::ExecuteAndWait(dotty, &args[0])) { + std::cerr << "Error viewing graph: 'dotty' not in path?\n"; + } else { +#ifdef __MINGW32__ // Dotty spawns another app and doesn't wait until it returns. + return; +#endif + } +#endif + + Filename.eraseFromDisk(); +} + +} // End llvm namespace