1193323Sed//===-- GraphWriter.cpp - Implements GraphWriter support routines ---------===// 2193323Sed// 3193323Sed// The LLVM Compiler Infrastructure 4193323Sed// 5193323Sed// This file is distributed under the University of Illinois Open Source 6193323Sed// License. See LICENSE.TXT for details. 7193323Sed// 8193323Sed//===----------------------------------------------------------------------===// 9193323Sed// 10193323Sed// This file implements misc. GraphWriter support routines. 11193323Sed// 12193323Sed//===----------------------------------------------------------------------===// 13193323Sed 14252723Sdim#include "llvm/Support/GraphWriter.h" 15252723Sdim#include "llvm/Config/config.h" 16235633Sdim#include "llvm/Support/CommandLine.h" 17263509Sdim#include "llvm/Support/FileSystem.h" 18218893Sdim#include "llvm/Support/Path.h" 19218893Sdim#include "llvm/Support/Program.h" 20193323Sedusing namespace llvm; 21193323Sed 22235633Sdimstatic cl::opt<bool> ViewBackground("view-background", cl::Hidden, 23235633Sdim cl::desc("Execute graph viewer in the background. Creates tmp file litter.")); 24235633Sdim 25198090Srdivackystd::string llvm::DOT::EscapeString(const std::string &Label) { 26198090Srdivacky std::string Str(Label); 27198090Srdivacky for (unsigned i = 0; i != Str.length(); ++i) 28198090Srdivacky switch (Str[i]) { 29198090Srdivacky case '\n': 30198090Srdivacky Str.insert(Str.begin()+i, '\\'); // Escape character... 31198090Srdivacky ++i; 32198090Srdivacky Str[i] = 'n'; 33198090Srdivacky break; 34198090Srdivacky case '\t': 35198090Srdivacky Str.insert(Str.begin()+i, ' '); // Convert to two spaces 36198090Srdivacky ++i; 37198090Srdivacky Str[i] = ' '; 38198090Srdivacky break; 39198090Srdivacky case '\\': 40198090Srdivacky if (i+1 != Str.length()) 41198090Srdivacky switch (Str[i+1]) { 42198090Srdivacky case 'l': continue; // don't disturb \l 43198090Srdivacky case '|': case '{': case '}': 44198090Srdivacky Str.erase(Str.begin()+i); continue; 45198090Srdivacky default: break; 46198090Srdivacky } 47198090Srdivacky case '{': case '}': 48198090Srdivacky case '<': case '>': 49198090Srdivacky case '|': case '"': 50198090Srdivacky Str.insert(Str.begin()+i, '\\'); // Escape character... 51198090Srdivacky ++i; // don't infinite loop 52198090Srdivacky break; 53198090Srdivacky } 54198090Srdivacky return Str; 55198090Srdivacky} 56198090Srdivacky 57252723Sdim/// \brief Get a color string for this node number. Simply round-robin selects 58252723Sdim/// from a reasonable number of colors. 59252723SdimStringRef llvm::DOT::getColorString(unsigned ColorNumber) { 60252723Sdim static const int NumColors = 20; 61252723Sdim static const char* Colors[NumColors] = { 62252723Sdim "aaaaaa", "aa0000", "00aa00", "aa5500", "0055ff", "aa00aa", "00aaaa", 63252723Sdim "555555", "ff5555", "55ff55", "ffff55", "5555ff", "ff55ff", "55ffff", 64252723Sdim "ffaaaa", "aaffaa", "ffffaa", "aaaaff", "ffaaff", "aaffff"}; 65252723Sdim return Colors[ColorNumber % NumColors]; 66252723Sdim} 67252723Sdim 68263509Sdimstd::string llvm::createGraphFilename(const Twine &Name, int &FD) { 69263509Sdim FD = -1; 70263509Sdim SmallString<128> Filename; 71263509Sdim error_code EC = sys::fs::createTemporaryFile(Name, "dot", FD, Filename); 72263509Sdim if (EC) { 73263509Sdim errs() << "Error: " << EC.message() << "\n"; 74263509Sdim return ""; 75263509Sdim } 76263509Sdim 77263509Sdim errs() << "Writing '" << Filename << "'... "; 78263509Sdim return Filename.str(); 79263509Sdim} 80263509Sdim 81235633Sdim// Execute the graph viewer. Return true if successful. 82235633Sdimstatic bool LLVM_ATTRIBUTE_UNUSED 83263509SdimExecGraphViewer(StringRef ExecPath, std::vector<const char*> &args, 84263509Sdim StringRef Filename, bool wait, std::string &ErrMsg) { 85235633Sdim if (wait) { 86263509Sdim if (sys::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) { 87235633Sdim errs() << "Error: " << ErrMsg << "\n"; 88235633Sdim return false; 89235633Sdim } 90263509Sdim bool Existed; 91263509Sdim sys::fs::remove(Filename, Existed); 92235633Sdim errs() << " done. \n"; 93235633Sdim } 94235633Sdim else { 95263509Sdim sys::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg); 96235633Sdim errs() << "Remember to erase graph file: " << Filename.str() << "\n"; 97235633Sdim } 98235633Sdim return true; 99235633Sdim} 100198090Srdivacky 101263509Sdimvoid llvm::DisplayGraph(StringRef FilenameRef, bool wait, 102198090Srdivacky GraphProgram::Name program) { 103263509Sdim std::string Filename = FilenameRef; 104235633Sdim wait &= !ViewBackground; 105193323Sed std::string ErrMsg; 106193323Sed#if HAVE_GRAPHVIZ 107263509Sdim std::string Graphviz(LLVM_PATH_GRAPHVIZ); 108193323Sed 109193323Sed std::vector<const char*> args; 110193323Sed args.push_back(Graphviz.c_str()); 111193323Sed args.push_back(Filename.c_str()); 112193323Sed args.push_back(0); 113235633Sdim 114198090Srdivacky errs() << "Running 'Graphviz' program... "; 115235633Sdim if (!ExecGraphViewer(Graphviz, args, Filename, wait, ErrMsg)) 116218893Sdim return; 117198090Srdivacky 118263509Sdim#elif HAVE_XDOT 119218893Sdim std::vector<const char*> args; 120263509Sdim args.push_back(LLVM_PATH_XDOT); 121218893Sdim args.push_back(Filename.c_str()); 122218893Sdim 123218893Sdim switch (program) { 124218893Sdim case GraphProgram::DOT: args.push_back("-f"); args.push_back("dot"); break; 125218893Sdim case GraphProgram::FDP: args.push_back("-f"); args.push_back("fdp"); break; 126218893Sdim case GraphProgram::NEATO: args.push_back("-f"); args.push_back("neato");break; 127218893Sdim case GraphProgram::TWOPI: args.push_back("-f"); args.push_back("twopi");break; 128218893Sdim case GraphProgram::CIRCO: args.push_back("-f"); args.push_back("circo");break; 129218893Sdim } 130235633Sdim 131218893Sdim args.push_back(0); 132218893Sdim 133218893Sdim errs() << "Running 'xdot.py' program... "; 134263509Sdim if (!ExecGraphViewer(LLVM_PATH_XDOT, args, Filename, wait, ErrMsg)) 135218893Sdim return; 136218893Sdim 137198090Srdivacky#elif (HAVE_GV && (HAVE_DOT || HAVE_FDP || HAVE_NEATO || \ 138198090Srdivacky HAVE_TWOPI || HAVE_CIRCO)) 139263509Sdim std::string PSFilename = Filename + ".ps"; 140263509Sdim std::string prog; 141193323Sed 142198090Srdivacky // Set default grapher 143198090Srdivacky#if HAVE_CIRCO 144263509Sdim prog = LLVM_PATH_CIRCO; 145198090Srdivacky#endif 146198090Srdivacky#if HAVE_TWOPI 147263509Sdim prog = LLVM_PATH_TWOPI; 148198090Srdivacky#endif 149198090Srdivacky#if HAVE_NEATO 150263509Sdim prog = LLVM_PATH_NEATO; 151198090Srdivacky#endif 152198090Srdivacky#if HAVE_FDP 153263509Sdim prog = LLVM_PATH_FDP; 154198090Srdivacky#endif 155198090Srdivacky#if HAVE_DOT 156263509Sdim prog = LLVM_PATH_DOT; 157198090Srdivacky#endif 158198090Srdivacky 159198090Srdivacky // Find which program the user wants 160198090Srdivacky#if HAVE_DOT 161198090Srdivacky if (program == GraphProgram::DOT) 162263509Sdim prog = LLVM_PATH_DOT; 163198090Srdivacky#endif 164198090Srdivacky#if (HAVE_FDP) 165198090Srdivacky if (program == GraphProgram::FDP) 166263509Sdim prog = LLVM_PATH_FDP; 167198090Srdivacky#endif 168198090Srdivacky#if (HAVE_NEATO) 169198090Srdivacky if (program == GraphProgram::NEATO) 170263509Sdim prog = LLVM_PATH_NEATO; 171198090Srdivacky#endif 172198090Srdivacky#if (HAVE_TWOPI) 173198090Srdivacky if (program == GraphProgram::TWOPI) 174263509Sdim prog = LLVM_PATH_TWOPI; 175198090Srdivacky#endif 176198090Srdivacky#if (HAVE_CIRCO) 177198090Srdivacky if (program == GraphProgram::CIRCO) 178263509Sdim prog = LLVM_PATH_CIRCO; 179198090Srdivacky#endif 180198090Srdivacky 181193323Sed std::vector<const char*> args; 182198090Srdivacky args.push_back(prog.c_str()); 183193323Sed args.push_back("-Tps"); 184193323Sed args.push_back("-Nfontname=Courier"); 185193323Sed args.push_back("-Gsize=7.5,10"); 186193323Sed args.push_back(Filename.c_str()); 187193323Sed args.push_back("-o"); 188193323Sed args.push_back(PSFilename.c_str()); 189193323Sed args.push_back(0); 190235633Sdim 191263509Sdim errs() << "Running '" << prog << "' program... "; 192198090Srdivacky 193235633Sdim if (!ExecGraphViewer(prog, args, Filename, wait, ErrMsg)) 194207618Srdivacky return; 195193323Sed 196263509Sdim std::string gv(LLVM_PATH_GV); 197207618Srdivacky args.clear(); 198207618Srdivacky args.push_back(gv.c_str()); 199207618Srdivacky args.push_back(PSFilename.c_str()); 200207618Srdivacky args.push_back("--spartan"); 201207618Srdivacky args.push_back(0); 202235633Sdim 203207618Srdivacky ErrMsg.clear(); 204235633Sdim if (!ExecGraphViewer(gv, args, PSFilename, wait, ErrMsg)) 205235633Sdim return; 206235633Sdim 207193323Sed#elif HAVE_DOTTY 208263509Sdim std::string dotty(LLVM_PATH_DOTTY); 209193323Sed 210193323Sed std::vector<const char*> args; 211193323Sed args.push_back(dotty.c_str()); 212193323Sed args.push_back(Filename.c_str()); 213193323Sed args.push_back(0); 214235633Sdim 215207618Srdivacky// Dotty spawns another app and doesn't wait until it returns 216207618Srdivacky#if defined (__MINGW32__) || defined (_WINDOWS) 217235633Sdim wait = false; 218235633Sdim#endif 219235633Sdim errs() << "Running 'dotty' program... "; 220235633Sdim if (!ExecGraphViewer(dotty, args, Filename, wait, ErrMsg)) 221193323Sed return; 222263509Sdim#else 223263509Sdim (void)Filename; 224263509Sdim (void)ErrMsg; 225193323Sed#endif 226193323Sed} 227