LLVM: lib/Support/GraphWriter.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

14

16

20#include "llvm/Config/config.h"

28

29#ifdef __APPLE__

32#endif

33

34#include

35#include <system_error>

36#include

37

38using namespace llvm;

39

40#ifdef __APPLE__

41namespace {

42struct CreateViewBackground {

43 static void *call() {

45 cl::desc("Execute graph viewer in the background. "

46 "Creates tmp file litter."));

47 }

48};

49}

52#else

54#endif

55

57 std::string Str(Label);

58 for (unsigned i = 0; i != Str.length(); ++i)

59 switch (Str[i]) {

60 case '\n':

61 Str.insert(Str.begin()+i, '\\');

62 ++i;

63 Str[i] = 'n';

64 break;

65 case '\t':

66 Str.insert(Str.begin()+i, ' ');

67 ++i;

68 Str[i] = ' ';

69 break;

70 case '\\':

71 if (i+1 != Str.length())

72 switch (Str[i+1]) {

73 case 'l': continue;

74 case '|': case '{': case '}':

75 Str.erase(Str.begin()+i); continue;

76 default: break;

77 }

78 [[fallthrough]];

79 case '{': case '}':

80 case '<': case '>':

81 case '|': case '"':

82 Str.insert(Str.begin()+i, '\\');

83 ++i;

84 break;

85 }

86 return Str;

87}

88

89

90

92 static const int NumColors = 20;

93 static const char* Colors[NumColors] = {

94 "aaaaaa", "aa0000", "00aa00", "aa5500", "0055ff", "aa00aa", "00aaaa",

95 "555555", "ff5555", "55ff55", "ffff55", "5555ff", "ff55ff", "55ffff",

96 "ffaaaa", "aaffaa", "ffffaa", "aaaaff", "ffaaff", "aaffff"};

97 return Colors[ColorNumber % NumColors];

98}

99

101 const char ReplacementChar) {

102 std::string IllegalChars =

104

105 for (char IllegalChar : IllegalChars)

106 llvm::replace(Filename, IllegalChar, ReplacementChar);

107

108 return Filename;

109}

110

112 FD = -1;

114

115

116 std::string N = Name.str();

117 if (N.size() > 140)

118 N.resize(140);

119

120

122

123 std::error_code EC =

125 if (EC) {

126 errs() << "Error: " << EC.message() << "\n";

127 return "";

128 }

129

130 errs() << "Writing '" << Filename << "'... ";

131 return std::string(Filename);

132}

133

134

137 std::string &ErrMsg) {

138 if (wait) {

140 errs() << "Error: " << ErrMsg << "\n";

141 return true;

142 }

144 errs() << " done. \n";

145 } else {

147 errs() << "Remember to erase graph file: " << Filename << "\n";

148 }

149 return false;

150}

151

152namespace {

153

154struct GraphSession {

155 std::string LogBuffer;

156

157 bool TryFindProgram(StringRef Names, std::string &ProgramPath) {

158 raw_string_ostream Log(LogBuffer);

160 Names.split(parts, '|');

161 for (auto Name : parts) {

163 ProgramPath = *P;

164 return true;

165 }

166 Log << " Tried '" << Name << "'\n";

167 }

168 return false;

169 }

170};

171

172}

173

175 switch (program) {

177 return "dot";

179 return "fdp";

181 return "neato";

183 return "twopi";

185 return "circo";

186 }

188}

189

192 std::string Filename = std::string(FilenameRef);

193 std::string ErrMsg;

194 std::string ViewerPath;

195 GraphSession S;

196

197#ifdef __APPLE__

198 wait &= !*ViewBackground;

199 if (S.TryFindProgram("open", ViewerPath)) {

200 std::vector args;

201 args.push_back(ViewerPath);

202 if (wait)

203 args.push_back("-W");

204 args.push_back(Filename);

205 errs() << "Trying 'open' program... ";

207 return false;

208 }

209#endif

210 if (S.TryFindProgram("xdg-open", ViewerPath)) {

211 std::vector args;

212 args.push_back(ViewerPath);

213 args.push_back(Filename);

214 errs() << "Trying 'xdg-open' program... ";

216 return false;

217 }

218

219

220 if (S.TryFindProgram("Graphviz", ViewerPath)) {

221 std::vector args;

222 args.push_back(ViewerPath);

223 args.push_back(Filename);

224

225 errs() << "Running 'Graphviz' program... ";

227 }

228

229

230 if (S.TryFindProgram("xdot|xdot.py", ViewerPath)) {

231 std::vector args;

232 args.push_back(ViewerPath);

233 args.push_back(Filename);

234

235 args.push_back("-f");

237

238 errs() << "Running 'xdot.py' program... ";

240 }

241

242 enum ViewerKind {

243 VK_None,

244 VK_OSXOpen,

245 VK_XDGOpen,

246 VK_Ghostview,

247 VK_CmdStart

248 };

249 ViewerKind Viewer = VK_None;

250#ifdef __APPLE__

251 if (!Viewer && S.TryFindProgram("open", ViewerPath))

252 Viewer = VK_OSXOpen;

253#endif

254 if (!Viewer && S.TryFindProgram("gv", ViewerPath))

255 Viewer = VK_Ghostview;

256 if (!Viewer && S.TryFindProgram("xdg-open", ViewerPath))

257 Viewer = VK_XDGOpen;

258#ifdef _WIN32

259 if (!Viewer && S.TryFindProgram("cmd", ViewerPath)) {

260 Viewer = VK_CmdStart;

261 }

262#endif

263

264

265 std::string GeneratorPath;

266 if (Viewer &&

267 (S.TryFindProgram(getProgramName(program), GeneratorPath) ||

268 S.TryFindProgram("dot|fdp|neato|twopi|circo", GeneratorPath))) {

270 Filename + (Viewer == VK_CmdStart ? ".pdf" : ".ps");

271

272 std::vector args;

273 args.push_back(GeneratorPath);

274 if (Viewer == VK_CmdStart)

275 args.push_back("-Tpdf");

276 else

277 args.push_back("-Tps");

278 args.push_back("-Nfontname=Courier");

279 args.push_back("-Gsize=7.5,10");

280 args.push_back(Filename);

281 args.push_back("-o");

283

284 errs() << "Running '" << GeneratorPath << "' program... ";

285

287 return true;

288

289

290

291 std::string StartArg;

292

293 args.clear();

294 args.push_back(ViewerPath);

295 switch (Viewer) {

296 case VK_OSXOpen:

297 args.push_back("-W");

299 break;

300 case VK_XDGOpen:

301 wait = false;

303 break;

304 case VK_Ghostview:

305 args.push_back("--spartan");

307 break;

308 case VK_CmdStart:

309 args.push_back("/S");

310 args.push_back("/C");

311 StartArg =

313 args.push_back(StartArg);

314 break;

315 case VK_None:

317 }

318

319 ErrMsg.clear();

321 }

322

323

324 if (S.TryFindProgram("dotty", ViewerPath)) {

325 std::vector args;

326 args.push_back(ViewerPath);

327 args.push_back(Filename);

328

329

330#ifdef _WIN32

331 wait = false;

332#endif

333 errs() << "Running 'dotty' program... ";

335 }

336

337 errs() << "Error: Couldn't find a usable graph viewer program:\n";

338 errs() << S.LogBuffer << "\n";

339 return true;

340}

Provides ErrorOr smart pointer.

static std::string replaceIllegalFilenameChars(std::string Filename, const char ReplacementChar)

Definition GraphWriter.cpp:100

static bool ExecGraphViewer(StringRef ExecPath, std::vector< StringRef > &args, StringRef Filename, bool wait, std::string &ErrMsg)

Definition GraphWriter.cpp:135

static const char * getProgramName(GraphProgram::Name program)

Definition GraphWriter.cpp:174

static cl::opt< std::string > OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"), cl::init("-"))

This file defines the SmallString class.

This file defines the SmallVector class.

ManagedStatic - This transparently changes the behavior of global statics to be lazily constructed on...

SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...

StringRef - Represent a constant reference to a string, i.e.

std::pair< StringRef, StringRef > split(char Separator) const

Split into two substrings around the first occurrence of a separator character.

Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

LLVM_ABI std::string EscapeString(const std::string &Label)

Definition GraphWriter.cpp:56

LLVM_ABI StringRef getColorString(unsigned NodeNumber)

Get a color string for this node number.

Definition GraphWriter.cpp:91

template class LLVM_TEMPLATE_ABI opt< bool >

LLVM_ABI std::error_code remove(const Twine &path, bool IgnoreNonExisting=true)

Remove path.

LLVM_ABI std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD, SmallVectorImpl< char > &ResultPath, OpenFlags Flags=OF_None)

Create a file in the system temporary directory.

LLVM_ABI ProcessInfo ExecuteNoWait(StringRef Program, ArrayRef< StringRef > Args, std::optional< ArrayRef< StringRef > > Env, ArrayRef< std::optional< StringRef > > Redirects={}, unsigned MemoryLimit=0, std::string *ErrMsg=nullptr, bool *ExecutionFailed=nullptr, BitVector *AffinityMask=nullptr, bool DetachProcess=false)

Similar to ExecuteAndWait, but returns immediately.

LLVM_ABI ErrorOr< std::string > findProgramByName(StringRef Name, ArrayRef< StringRef > Paths={})

Find the first executable file Name in Paths.

LLVM_ABI int ExecuteAndWait(StringRef Program, ArrayRef< StringRef > Args, std::optional< ArrayRef< StringRef > > Env=std::nullopt, ArrayRef< std::optional< StringRef > > Redirects={}, unsigned SecondsToWait=0, unsigned MemoryLimit=0, std::string *ErrMsg=nullptr, bool *ExecutionFailed=nullptr, std::optional< ProcessStatistics > *ProcStat=nullptr, BitVector *AffinityMask=nullptr)

This function executes the program using the arguments provided.

This is an optimization pass for GlobalISel generic memory operations.

LLVM_ABI bool DisplayGraph(StringRef Filename, bool wait=true, GraphProgram::Name program=GraphProgram::DOT)

Definition GraphWriter.cpp:190

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

LLVM_ABI std::string createGraphFilename(const Twine &Name, int &FD)

Definition GraphWriter.cpp:111

LLVM_ABI raw_fd_ostream & errs()

This returns a reference to a raw_ostream for standard error.

void replace(R &&Range, const T &OldValue, const T &NewValue)

Provide wrappers to std::replace which take ranges instead of having to pass begin/end explicitly.

void initGraphWriterOptions()

Definition GraphWriter.cpp:53