1//===- llvm/Support/GraphWriter.h - Write graph to a .dot file --*- C++ -*-===//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//===----------------------------------------------------------------------===//
9// This file defines a simple interface that can be used to print out generic
10// LLVM graphs to ".dot" files. "dot" is a tool that is part of the AT&T
11// graphviz package (http://www.research.att.com/sw/tools/graphviz/) which can
12// be used to turn the files output by this interface into a variety of
13// different graphics formats.
15// Graphs do not need to implement any interface past what is already required
16// by the GraphTraits template, but they can choose to implement specializations
17// of the DOTGraphTraits template if they want to customize the graphs output in
20//===----------------------------------------------------------------------===//
22#ifndef LLVM_SUPPORT_GRAPHWRITER_H
23#define LLVM_SUPPORT_GRAPHWRITER_H
39 namespace DOT {
// Private functions...
43/// Get a color string for this node number. Simply round-robin selects
44/// from a reasonable number of colors.
59}
// end namespace GraphProgram
77 static_assert(std::is_pointer_v<NodeRef>,
78 "FIXME: Currently GraphWriterBase requires the NodeRef type to "
79 "be a pointer.\nThe pointer usage should be moved to "
80 "DOTGraphTraits, and removed from GraphWriterBase itself.");
82 // Cast the 'this' pointer to the derived type and return a reference.
83 Derived &
getDerived() {
return *
static_cast<Derived *
>(
this); }
85 return *
static_cast<const Derived *
>(
this);
88 // Writes the edge labels of the node to O and returns true if there are any
89 // edge labels not equal to the empty string "".
93 bool hasEdgeSourceLabels =
false;
98 for (
unsigned i = 0; EI != EE && i != 64; ++EI, ++i) {
99 std::string label =
DTraits.getEdgeSourceLabel(
Node, EI);
104 hasEdgeSourceLabels =
true;
107 O <<
"<td colspan=\"1\" port=\"s" << i <<
"\">" << label <<
"</td>";
116 if (EI != EE && hasEdgeSourceLabels) {
118 O <<
"<td colspan=\"1\" port=\"s64\">truncated...</td>";
120 O <<
"|<s64>truncated...";
123 return hasEdgeSourceLabels;
134 // Output the header for the graph...
137 // Emit all of the nodes in the graph...
140 // Output any customizations on the graph
143 // Output the end of the graph
148 std::string GraphName(
DTraits.getGraphName(
G));
152 else if (!GraphName.empty())
155 O <<
"digraph unnamed {\n";
157 if (
DTraits.renderGraphFromBottomUp())
158 O <<
"\trankdir=\"BT\";\n";
162 else if (!GraphName.empty())
169 // Finish off the graph
174 // Loop over the graph, printing it out...
183 std::string NodeAttributes =
DTraits.getNodeAttributes(
Node,
G);
185 O <<
"\tNode" <<
static_cast<const void *
>(
Node) <<
" [shape=";
191 if (!NodeAttributes.empty())
O << NodeAttributes <<
",";
195 // Count the numbewr of edges out of the node to determine how
196 // many columns to span (max 64)
197 unsigned ColSpan = 0;
200 for (; EI != EE && ColSpan != 64; ++EI, ++ColSpan)
204 // Include truncated messages when counting.
207 O <<
"<<table border=\"0\" cellborder=\"1\" cellspacing=\"0\""
208 <<
" cellpadding=\"0\"><tr><td align=\"text\" colspan=\"" << ColSpan
214 if (!
DTraits.renderGraphFromBottomUp()) {
220 // If we should include the address of the node in the label, do so now.
221 std::string Id =
DTraits.getNodeIdentifierLabel(
Node,
G);
225 std::string NodeDesc =
DTraits.getNodeDescription(
Node,
G);
226 if (!NodeDesc.empty())
230 std::string edgeSourceLabels;
234 if (hasEdgeSourceLabels) {
235 if (!
DTraits.renderGraphFromBottomUp())
240 O << edgeSourceLabels;
242 O <<
"{" << edgeSourceLabels <<
"}";
244 if (
DTraits.renderGraphFromBottomUp())
249 if (
DTraits.renderGraphFromBottomUp()) {
255 // If we should include the address of the node in the label, do so now.
256 std::string Id =
DTraits.getNodeIdentifierLabel(
Node,
G);
260 std::string NodeDesc =
DTraits.getNodeDescription(
Node,
G);
261 if (!NodeDesc.empty())
265 if (
DTraits.hasEdgeDestLabels()) {
268 unsigned i = 0, e =
DTraits.numEdgeDestLabels(
Node);
269 for (; i != e && i != 64; ++i) {
271 O <<
"<d" << i <<
">"
276 O <<
"|<d64>truncated...";
281 O <<
"</tr></table>>";
284 O <<
"];\n";
// Finish printing the "node" line
286 // Output all of the edges now
289 for (
unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
292 for (; EI != EE; ++EI)
298 if (
NodeRef TargetNode = *EI) {
303 // Figure out which edge this targets...
305 (
unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt);
306 DestPort =
static_cast<int>(
Offset);
313 static_cast<const void *
>(TargetNode), DestPort,
318 /// emitSimpleNode - Outputs a simple (non-record) node
320 const std::string &Label,
unsigned NumEdgeSources = 0,
321 const std::vector<std::string> *EdgeSourceLabels =
nullptr) {
322 O <<
"\tNode" <<
ID <<
"[ ";
326 if (NumEdgeSources)
O <<
"{";
328 if (NumEdgeSources) {
331 for (
unsigned i = 0; i != NumEdgeSources; ++i) {
333 O <<
"<s" << i <<
">";
341 /// emitEdge - Output an edge from a simple node into the graph...
342 void emitEdge(
const void *SrcNodeID,
int SrcNodePort,
343 const void *DestNodeID,
int DestNodePort,
344 const std::string &Attrs) {
345 if (SrcNodePort > 64)
return;
// Eminating from truncated part?
346 DestNodePort = std::min(DestNodePort, 64);
// Targeting the truncated part?
348 O <<
"\tNode" << SrcNodeID;
349 if (SrcNodePort >= 0)
350 O <<
":s" << SrcNodePort;
351 O <<
" -> Node" << DestNodeID;
352 if (DestNodePort >= 0 &&
DTraits.hasEdgeDestLabels())
353 O <<
":d" << DestNodePort;
356 O <<
"[" << Attrs <<
"]";
360 /// getOStream - Get the raw output stream into the graph file. Useful to
361 /// write fancy things using addCustomGraphFeatures().
367template <
typename GraphType>
375template <
typename GraphType>
377 bool ShortNames =
false,
const Twine &Title =
"") {
378 // Start the graph emission process...
382 W.writeGraph(Title.str());
389/// Writes graph into a provided @c Filename.
390/// If @c Filename is empty, generates a random one.
391/// \return The resulting filename, or an empty string if writing
393template <
typename GraphType>
395 bool ShortNames =
false,
396 const Twine &Title =
"",
397 std::string Filename =
"") {
399 if (Filename.empty()) {
405 // Writing over an existing file is not considered an error.
406 if (EC == std::errc::file_exists) {
407 errs() <<
"file exists, overwriting" <<
"\n";
409 errs() <<
"error writing into file" <<
"\n";
412 errs() <<
"writing to the newly created file " << Filename <<
"\n";
418 errs() <<
"error opening file '" << Filename <<
"' for writing!\n";
423 errs() <<
" done. \n";
428/// DumpDotGraph - Just dump a dot graph to the user-provided file name.
429#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
430template <
typename GraphType>
433 const Twine &Title,
bool ShortNames =
false,
434 const Twine &Name =
"") {
439/// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
440/// then cleanup. For use from the debugger.
442template<
typename GraphType>
444 bool ShortNames =
false,
const Twine &Title =
"",
448 if (Filename.empty())
454}
// end namespace llvm
456#endif // LLVM_SUPPORT_GRAPHWRITER_H
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
This file defines the little GraphTraits<X> template class that should be specialized by classes that...
INLINE void g(uint32_t *state, size_t a, size_t b, size_t c, size_t d, uint32_t x, uint32_t y)
void writeEdge(NodeRef Node, unsigned edgeidx, child_iterator EI)
typename GTraits::ChildIteratorType child_iterator
bool getEdgeSourceLabels(raw_ostream &O, NodeRef Node)
const Derived & getDerived() const
bool isNodeHidden(NodeRef Node)
void writeHeader(const std::string &Title)
typename GTraits::NodeRef NodeRef
void writeGraph(const std::string &Title="")
void writeNode(NodeRef Node)
GraphWriterBase(raw_ostream &o, const GraphType &g, bool SN)
void emitSimpleNode(const void *ID, const std::string &Attr, const std::string &Label, unsigned NumEdgeSources=0, const std::vector< std::string > *EdgeSourceLabels=nullptr)
emitSimpleNode - Outputs a simple (non-record) node
void emitEdge(const void *SrcNodeID, int SrcNodePort, const void *DestNodeID, int DestNodePort, const std::string &Attrs)
emitEdge - Output an edge from a simple node into the graph...
raw_ostream & getOStream()
getOStream - Get the raw output stream into the graph file.
virtual ~GraphWriterBase()=default
GraphTraits< GraphType > GTraits
typename GTraits::nodes_iterator node_iterator
DOTGraphTraits< GraphType > DOTTraits
GraphWriter(raw_ostream &o, const GraphType &g, bool SN)
~GraphWriter() override=default
StringRef - Represent a constant reference to a string, i.e.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
LLVM_ABI std::string str() const
Return the twine contents as a std::string.
A raw_ostream that writes to a file descriptor.
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
LLVM_ABI std::string EscapeString(const std::string &Label)
LLVM_ABI StringRef getColorString(unsigned NodeNumber)
Get a color string for this node number.
@ OF_Text
The file should be opened in text mode on platforms like z/OS that make this distinction.
@ CD_CreateAlways
CD_CreateAlways - When opening a file:
std::error_code openFileForWrite(const Twine &Name, int &ResultFD, CreationDisposition Disp=CD_CreateAlways, OpenFlags Flags=OF_None, unsigned Mode=0666)
Opens the file with the given name in a write-only or read-write mode, returning its open file descri...
This is an optimization pass for GlobalISel generic memory operations.
iterator_range< typename GraphTraits< GraphType >::nodes_iterator > nodes(const GraphType &G)
LLVM_ABI bool DisplayGraph(StringRef Filename, bool wait=true, GraphProgram::Name program=GraphProgram::DOT)
LLVM_DUMP_METHOD void dumpDotGraphToFile(const GraphType &G, const Twine &FileName, const Twine &Title, bool ShortNames=false, const Twine &Name="")
DumpDotGraph - Just dump a dot graph to the user-provided file name.
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
LLVM_ABI std::string createGraphFilename(const Twine &Name, int &FD)
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
void ViewGraph(const GraphType &G, const Twine &Name, bool ShortNames=false, const Twine &Title="", GraphProgram::Name Program=GraphProgram::DOT)
ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file, then cleanup.
DOTGraphTraits - Template class that can be specialized to customize how graphs are converted to 'dot...
static void addCustomGraphFeatures(const GraphType &, GraphWriter &)
addCustomGraphFeatures - If a graph is made up of more than just straight-forward nodes and edges,...
typename GraphType::UnknownGraphTypeError NodeRef