19d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer//===-- GraphWriter.cpp - Implements GraphWriter support routines ---------===// 29d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer// 39d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer// The LLVM Compiler Infrastructure 49d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer// 54ee451de366474b9c228b4e5fa573795a715216dChris Lattner// This file is distributed under the University of Illinois Open Source 64ee451de366474b9c228b4e5fa573795a715216dChris Lattner// License. See LICENSE.TXT for details. 79d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer// 89d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer//===----------------------------------------------------------------------===// 99d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer// 109d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer// This file implements misc. GraphWriter support routines. 119d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer// 129d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer//===----------------------------------------------------------------------===// 139d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer 1465a392ebeae214ccb25f4d5ec856688e4e690e0dChris Lattner#include "llvm/Support/GraphWriter.h" 15d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/Config/config.h" 16d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/Support/CommandLine.h" 171f6efa3996dd1929fbc129203ce5009b620e6969Michael J. Spencer#include "llvm/Support/Path.h" 181f6efa3996dd1929fbc129203ce5009b620e6969Michael J. Spencer#include "llvm/Support/Program.h" 199d5b532de9bdca37810a59a93a69128441b02c55Reid Spencerusing namespace llvm; 209d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer 21255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trickstatic cl::opt<bool> ViewBackground("view-background", cl::Hidden, 22255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick cl::desc("Execute graph viewer in the background. Creates tmp file litter.")); 23255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick 24103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattnerstd::string llvm::DOT::EscapeString(const std::string &Label) { 25103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner std::string Str(Label); 26103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner for (unsigned i = 0; i != Str.length(); ++i) 27103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner switch (Str[i]) { 28103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner case '\n': 29103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner Str.insert(Str.begin()+i, '\\'); // Escape character... 30103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner ++i; 31103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner Str[i] = 'n'; 32103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner break; 33103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner case '\t': 34103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner Str.insert(Str.begin()+i, ' '); // Convert to two spaces 35103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner ++i; 36103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner Str[i] = ' '; 37103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner break; 38103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner case '\\': 39103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner if (i+1 != Str.length()) 40103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner switch (Str[i+1]) { 41103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner case 'l': continue; // don't disturb \l 42103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner case '|': case '{': case '}': 43103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner Str.erase(Str.begin()+i); continue; 44103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner default: break; 45103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner } 46103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner case '{': case '}': 47103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner case '<': case '>': 48103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner case '|': case '"': 49103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner Str.insert(Str.begin()+i, '\\'); // Escape character... 50103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner ++i; // don't infinite loop 51103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner break; 52103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner } 53103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner return Str; 54103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner} 55103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner 56c6ada8e5f38168f13830e448f2b9e2d8e3eac72bAndrew Trick/// \brief Get a color string for this node number. Simply round-robin selects 57c6ada8e5f38168f13830e448f2b9e2d8e3eac72bAndrew Trick/// from a reasonable number of colors. 58c6ada8e5f38168f13830e448f2b9e2d8e3eac72bAndrew TrickStringRef llvm::DOT::getColorString(unsigned ColorNumber) { 59c6ada8e5f38168f13830e448f2b9e2d8e3eac72bAndrew Trick static const int NumColors = 20; 60c6ada8e5f38168f13830e448f2b9e2d8e3eac72bAndrew Trick static const char* Colors[NumColors] = { 61c6ada8e5f38168f13830e448f2b9e2d8e3eac72bAndrew Trick "aaaaaa", "aa0000", "00aa00", "aa5500", "0055ff", "aa00aa", "00aaaa", 62c6ada8e5f38168f13830e448f2b9e2d8e3eac72bAndrew Trick "555555", "ff5555", "55ff55", "ffff55", "5555ff", "ff55ff", "55ffff", 63c6ada8e5f38168f13830e448f2b9e2d8e3eac72bAndrew Trick "ffaaaa", "aaffaa", "ffffaa", "aaaaff", "ffaaff", "aaffff"}; 64c6ada8e5f38168f13830e448f2b9e2d8e3eac72bAndrew Trick return Colors[ColorNumber % NumColors]; 65c6ada8e5f38168f13830e448f2b9e2d8e3eac72bAndrew Trick} 66c6ada8e5f38168f13830e448f2b9e2d8e3eac72bAndrew Trick 67255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick// Execute the graph viewer. Return true if successful. 68cdaedf9f4acc60f8a7a1042af4be04291465e213Benjamin Kramerstatic bool LLVM_ATTRIBUTE_UNUSED 69cdaedf9f4acc60f8a7a1042af4be04291465e213Benjamin KramerExecGraphViewer(const sys::Path &ExecPath, std::vector<const char*> &args, 70cdaedf9f4acc60f8a7a1042af4be04291465e213Benjamin Kramer const sys::Path &Filename, bool wait, std::string &ErrMsg) { 71255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick if (wait) { 72255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick if (sys::Program::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) { 73255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick errs() << "Error: " << ErrMsg << "\n"; 74255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick return false; 75255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick } 76255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick Filename.eraseFromDisk(); 77255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick errs() << " done. \n"; 78255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick } 79255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick else { 80255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick sys::Program::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg); 81255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick errs() << "Remember to erase graph file: " << Filename.str() << "\n"; 82255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick } 83255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick return true; 84255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick} 85103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner 8600ad26ff5760ff2d1b24acb18718e63541088923David Greenevoid llvm::DisplayGraph(const sys::Path &Filename, bool wait, 8700ad26ff5760ff2d1b24acb18718e63541088923David Greene GraphProgram::Name program) { 88255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick wait &= !ViewBackground; 898ea5ecb0564b8822c70ad84202471f03e2690da7Reid Spencer std::string ErrMsg; 909d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer#if HAVE_GRAPHVIZ 919d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer sys::Path Graphviz(LLVM_PATH_GRAPHVIZ); 929d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer 939d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer std::vector<const char*> args; 949d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer args.push_back(Graphviz.c_str()); 959d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer args.push_back(Filename.c_str()); 969d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer args.push_back(0); 97255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick 98103289e9383ad1eb66caf28c9b166aebce963a35Chris Lattner errs() << "Running 'Graphviz' program... "; 99255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick if (!ExecGraphViewer(Graphviz, args, Filename, wait, ErrMsg)) 100644801a199794a74bdc4655f6af5bc05f8153dc8Dan Gohman return; 10100ad26ff5760ff2d1b24acb18718e63541088923David Greene 10248fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman#elif HAVE_XDOT_PY 10348fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman std::vector<const char*> args; 10448fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman args.push_back(LLVM_PATH_XDOT_PY); 10548fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman args.push_back(Filename.c_str()); 10648fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman 10748fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman switch (program) { 10848fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman case GraphProgram::DOT: args.push_back("-f"); args.push_back("dot"); break; 10948fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman case GraphProgram::FDP: args.push_back("-f"); args.push_back("fdp"); break; 11048fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman case GraphProgram::NEATO: args.push_back("-f"); args.push_back("neato");break; 11148fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman case GraphProgram::TWOPI: args.push_back("-f"); args.push_back("twopi");break; 11248fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman case GraphProgram::CIRCO: args.push_back("-f"); args.push_back("circo");break; 11348fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman } 114255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick 11548fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman args.push_back(0); 11648fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman 11748fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman errs() << "Running 'xdot.py' program... "; 118255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick if (!ExecGraphViewer(sys::Path(LLVM_PATH_XDOT_PY), args, Filename, wait, ErrMsg)) 119644801a199794a74bdc4655f6af5bc05f8153dc8Dan Gohman return; 12048fd5a79e023bf6a647dfabb2bbb4c2f98617b81Dan Gohman 12100ad26ff5760ff2d1b24acb18718e63541088923David Greene#elif (HAVE_GV && (HAVE_DOT || HAVE_FDP || HAVE_NEATO || \ 12200ad26ff5760ff2d1b24acb18718e63541088923David Greene HAVE_TWOPI || HAVE_CIRCO)) 1239d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer sys::Path PSFilename = Filename; 1249d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer PSFilename.appendSuffix("ps"); 125229509a8bc2390c4c9c1bd20f777acf29911d452David Greene 12600ad26ff5760ff2d1b24acb18718e63541088923David Greene sys::Path prog; 12700ad26ff5760ff2d1b24acb18718e63541088923David Greene 12800ad26ff5760ff2d1b24acb18718e63541088923David Greene // Set default grapher 12900ad26ff5760ff2d1b24acb18718e63541088923David Greene#if HAVE_CIRCO 13000ad26ff5760ff2d1b24acb18718e63541088923David Greene prog = sys::Path(LLVM_PATH_CIRCO); 13100ad26ff5760ff2d1b24acb18718e63541088923David Greene#endif 13200ad26ff5760ff2d1b24acb18718e63541088923David Greene#if HAVE_TWOPI 13300ad26ff5760ff2d1b24acb18718e63541088923David Greene prog = sys::Path(LLVM_PATH_TWOPI); 13400ad26ff5760ff2d1b24acb18718e63541088923David Greene#endif 13500ad26ff5760ff2d1b24acb18718e63541088923David Greene#if HAVE_NEATO 13600ad26ff5760ff2d1b24acb18718e63541088923David Greene prog = sys::Path(LLVM_PATH_NEATO); 13700ad26ff5760ff2d1b24acb18718e63541088923David Greene#endif 138229509a8bc2390c4c9c1bd20f777acf29911d452David Greene#if HAVE_FDP 13900ad26ff5760ff2d1b24acb18718e63541088923David Greene prog = sys::Path(LLVM_PATH_FDP); 14000ad26ff5760ff2d1b24acb18718e63541088923David Greene#endif 14100ad26ff5760ff2d1b24acb18718e63541088923David Greene#if HAVE_DOT 14200ad26ff5760ff2d1b24acb18718e63541088923David Greene prog = sys::Path(LLVM_PATH_DOT); 14300ad26ff5760ff2d1b24acb18718e63541088923David Greene#endif 14400ad26ff5760ff2d1b24acb18718e63541088923David Greene 14500ad26ff5760ff2d1b24acb18718e63541088923David Greene // Find which program the user wants 14600ad26ff5760ff2d1b24acb18718e63541088923David Greene#if HAVE_DOT 14740ef79d5e24d0a66345b4c9a1b97952478850d42Chris Lattner if (program == GraphProgram::DOT) 14800ad26ff5760ff2d1b24acb18718e63541088923David Greene prog = sys::Path(LLVM_PATH_DOT); 14900ad26ff5760ff2d1b24acb18718e63541088923David Greene#endif 15000ad26ff5760ff2d1b24acb18718e63541088923David Greene#if (HAVE_FDP) 15140ef79d5e24d0a66345b4c9a1b97952478850d42Chris Lattner if (program == GraphProgram::FDP) 15200ad26ff5760ff2d1b24acb18718e63541088923David Greene prog = sys::Path(LLVM_PATH_FDP); 15300ad26ff5760ff2d1b24acb18718e63541088923David Greene#endif 15400ad26ff5760ff2d1b24acb18718e63541088923David Greene#if (HAVE_NEATO) 15540ef79d5e24d0a66345b4c9a1b97952478850d42Chris Lattner if (program == GraphProgram::NEATO) 15600ad26ff5760ff2d1b24acb18718e63541088923David Greene prog = sys::Path(LLVM_PATH_NEATO); 15700ad26ff5760ff2d1b24acb18718e63541088923David Greene#endif 15800ad26ff5760ff2d1b24acb18718e63541088923David Greene#if (HAVE_TWOPI) 15940ef79d5e24d0a66345b4c9a1b97952478850d42Chris Lattner if (program == GraphProgram::TWOPI) 16000ad26ff5760ff2d1b24acb18718e63541088923David Greene prog = sys::Path(LLVM_PATH_TWOPI); 16100ad26ff5760ff2d1b24acb18718e63541088923David Greene#endif 16200ad26ff5760ff2d1b24acb18718e63541088923David Greene#if (HAVE_CIRCO) 16340ef79d5e24d0a66345b4c9a1b97952478850d42Chris Lattner if (program == GraphProgram::CIRCO) 16400ad26ff5760ff2d1b24acb18718e63541088923David Greene prog = sys::Path(LLVM_PATH_CIRCO); 165229509a8bc2390c4c9c1bd20f777acf29911d452David Greene#endif 1669d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer 1679d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer std::vector<const char*> args; 168229509a8bc2390c4c9c1bd20f777acf29911d452David Greene args.push_back(prog.c_str()); 1699d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer args.push_back("-Tps"); 1709d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer args.push_back("-Nfontname=Courier"); 1719d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer args.push_back("-Gsize=7.5,10"); 1729d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer args.push_back(Filename.c_str()); 1739d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer args.push_back("-o"); 1749d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer args.push_back(PSFilename.c_str()); 1759d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer args.push_back(0); 176255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick 1772d5e3acd2a69070c4e3550e014a54626e18bf12cDan Gohman errs() << "Running '" << prog.str() << "' program... "; 178229509a8bc2390c4c9c1bd20f777acf29911d452David Greene 179255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick if (!ExecGraphViewer(prog, args, Filename, wait, ErrMsg)) 180459e13a9cef943c582f55d26ce03a0dc7409edffChris Lattner return; 1819d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer 182459e13a9cef943c582f55d26ce03a0dc7409edffChris Lattner sys::Path gv(LLVM_PATH_GV); 183459e13a9cef943c582f55d26ce03a0dc7409edffChris Lattner args.clear(); 184459e13a9cef943c582f55d26ce03a0dc7409edffChris Lattner args.push_back(gv.c_str()); 185459e13a9cef943c582f55d26ce03a0dc7409edffChris Lattner args.push_back(PSFilename.c_str()); 186459e13a9cef943c582f55d26ce03a0dc7409edffChris Lattner args.push_back("--spartan"); 187459e13a9cef943c582f55d26ce03a0dc7409edffChris Lattner args.push_back(0); 188255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick 189459e13a9cef943c582f55d26ce03a0dc7409edffChris Lattner ErrMsg.clear(); 190255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick if (!ExecGraphViewer(gv, args, PSFilename, wait, ErrMsg)) 191255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick return; 192255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick 1939d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer#elif HAVE_DOTTY 1949d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer sys::Path dotty(LLVM_PATH_DOTTY); 1959d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer 1969d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer std::vector<const char*> args; 19782493289e0234e0172313e845fb87306cf3687acChris Lattner args.push_back(dotty.c_str()); 1989d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer args.push_back(Filename.c_str()); 1999d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer args.push_back(0); 200255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick 2017c57b7b80838eb48db03f4cfc7839864822c0112Chris Lattner// Dotty spawns another app and doesn't wait until it returns 2027c57b7b80838eb48db03f4cfc7839864822c0112Chris Lattner#if defined (__MINGW32__) || defined (_WINDOWS) 203255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick wait = false; 2049d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer#endif 205255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick errs() << "Running 'dotty' program... "; 206255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick if (!ExecGraphViewer(dotty, args, Filename, wait, ErrMsg)) 207255cd51fbd771c0131a74eaf4385f1ea703a3c68Andrew Trick return; 2089d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer#endif 2099d5b532de9bdca37810a59a93a69128441b02c55Reid Spencer} 210