GraphWriter.cpp revision 261991
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 14249423Sdim#include "llvm/Support/GraphWriter.h" 15249423Sdim#include "llvm/Config/config.h" 16234353Sdim#include "llvm/Support/CommandLine.h" 17261991Sdim#include "llvm/Support/FileSystem.h" 18218893Sdim#include "llvm/Support/Path.h" 19218893Sdim#include "llvm/Support/Program.h" 20193323Sedusing namespace llvm; 21193323Sed 22234353Sdimstatic cl::opt<bool> ViewBackground("view-background", cl::Hidden, 23234353Sdim cl::desc("Execute graph viewer in the background. Creates tmp file litter.")); 24234353Sdim 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 57249423Sdim/// \brief Get a color string for this node number. Simply round-robin selects 58249423Sdim/// from a reasonable number of colors. 59249423SdimStringRef llvm::DOT::getColorString(unsigned ColorNumber) { 60249423Sdim static const int NumColors = 20; 61249423Sdim static const char* Colors[NumColors] = { 62249423Sdim "aaaaaa", "aa0000", "00aa00", "aa5500", "0055ff", "aa00aa", "00aaaa", 63249423Sdim "555555", "ff5555", "55ff55", "ffff55", "5555ff", "ff55ff", "55ffff", 64249423Sdim "ffaaaa", "aaffaa", "ffffaa", "aaaaff", "ffaaff", "aaffff"}; 65249423Sdim return Colors[ColorNumber % NumColors]; 66249423Sdim} 67249423Sdim 68261991Sdimstd::string llvm::createGraphFilename(const Twine &Name, int &FD) { 69261991Sdim FD = -1; 70261991Sdim SmallString<128> Filename; 71261991Sdim error_code EC = sys::fs::createTemporaryFile(Name, "dot", FD, Filename); 72261991Sdim if (EC) { 73261991Sdim errs() << "Error: " << EC.message() << "\n"; 74261991Sdim return ""; 75261991Sdim } 76261991Sdim 77261991Sdim errs() << "Writing '" << Filename << "'... "; 78261991Sdim return Filename.str(); 79261991Sdim} 80261991Sdim 81234353Sdim// Execute the graph viewer. Return true if successful. 82234353Sdimstatic bool LLVM_ATTRIBUTE_UNUSED 83261991SdimExecGraphViewer(StringRef ExecPath, std::vector<const char*> &args, 84261991Sdim StringRef Filename, bool wait, std::string &ErrMsg) { 85234353Sdim if (wait) { 86261991Sdim if (sys::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) { 87234353Sdim errs() << "Error: " << ErrMsg << "\n"; 88234353Sdim return false; 89234353Sdim } 90261991Sdim bool Existed; 91261991Sdim sys::fs::remove(Filename, Existed); 92234353Sdim errs() << " done. \n"; 93234353Sdim } 94234353Sdim else { 95261991Sdim sys::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg); 96234353Sdim errs() << "Remember to erase graph file: " << Filename.str() << "\n"; 97234353Sdim } 98234353Sdim return true; 99234353Sdim} 100198090Srdivacky 101261991Sdimvoid llvm::DisplayGraph(StringRef FilenameRef, bool wait, 102198090Srdivacky GraphProgram::Name program) { 103261991Sdim std::string Filename = FilenameRef; 104234353Sdim wait &= !ViewBackground; 105193323Sed std::string ErrMsg; 106193323Sed#if HAVE_GRAPHVIZ 107261991Sdim 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); 113234353Sdim 114198090Srdivacky errs() << "Running 'Graphviz' program... "; 115234353Sdim if (!ExecGraphViewer(Graphviz, args, Filename, wait, ErrMsg)) 116218893Sdim return; 117198090Srdivacky 118261991Sdim#elif HAVE_XDOT 119218893Sdim std::vector<const char*> args; 120261991Sdim 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 } 130234353Sdim 131218893Sdim args.push_back(0); 132218893Sdim 133218893Sdim errs() << "Running 'xdot.py' program... "; 134261991Sdim 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)) 139261991Sdim std::string PSFilename = Filename + ".ps"; 140261991Sdim std::string prog; 141193323Sed 142198090Srdivacky // Set default grapher 143198090Srdivacky#if HAVE_CIRCO 144261991Sdim prog = LLVM_PATH_CIRCO; 145198090Srdivacky#endif 146198090Srdivacky#if HAVE_TWOPI 147261991Sdim prog = LLVM_PATH_TWOPI; 148198090Srdivacky#endif 149198090Srdivacky#if HAVE_NEATO 150261991Sdim prog = LLVM_PATH_NEATO; 151198090Srdivacky#endif 152198090Srdivacky#if HAVE_FDP 153261991Sdim prog = LLVM_PATH_FDP; 154198090Srdivacky#endif 155198090Srdivacky#if HAVE_DOT 156261991Sdim prog = LLVM_PATH_DOT; 157198090Srdivacky#endif 158198090Srdivacky 159198090Srdivacky // Find which program the user wants 160198090Srdivacky#if HAVE_DOT 161198090Srdivacky if (program == GraphProgram::DOT) 162261991Sdim prog = LLVM_PATH_DOT; 163198090Srdivacky#endif 164198090Srdivacky#if (HAVE_FDP) 165198090Srdivacky if (program == GraphProgram::FDP) 166261991Sdim prog = LLVM_PATH_FDP; 167198090Srdivacky#endif 168198090Srdivacky#if (HAVE_NEATO) 169198090Srdivacky if (program == GraphProgram::NEATO) 170261991Sdim prog = LLVM_PATH_NEATO; 171198090Srdivacky#endif 172198090Srdivacky#if (HAVE_TWOPI) 173198090Srdivacky if (program == GraphProgram::TWOPI) 174261991Sdim prog = LLVM_PATH_TWOPI; 175198090Srdivacky#endif 176198090Srdivacky#if (HAVE_CIRCO) 177198090Srdivacky if (program == GraphProgram::CIRCO) 178261991Sdim 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); 190234353Sdim 191261991Sdim errs() << "Running '" << prog << "' program... "; 192198090Srdivacky 193234353Sdim if (!ExecGraphViewer(prog, args, Filename, wait, ErrMsg)) 194207618Srdivacky return; 195193323Sed 196261991Sdim 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); 202234353Sdim 203207618Srdivacky ErrMsg.clear(); 204234353Sdim if (!ExecGraphViewer(gv, args, PSFilename, wait, ErrMsg)) 205234353Sdim return; 206234353Sdim 207193323Sed#elif HAVE_DOTTY 208261991Sdim 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); 214234353Sdim 215207618Srdivacky// Dotty spawns another app and doesn't wait until it returns 216207618Srdivacky#if defined (__MINGW32__) || defined (_WINDOWS) 217234353Sdim wait = false; 218234353Sdim#endif 219234353Sdim errs() << "Running 'dotty' program... "; 220234353Sdim if (!ExecGraphViewer(dotty, args, Filename, wait, ErrMsg)) 221193323Sed return; 222261991Sdim#else 223261991Sdim (void)Filename; 224261991Sdim (void)ErrMsg; 225193323Sed#endif 226193323Sed} 227