22 #ifndef LLVM_SUPPORT_GRAPHWRITER_H
23 #define LLVM_SUPPORT_GRAPHWRITER_H
33 #include <type_traits>
48 namespace GraphProgram {
63 template<
typename GraphType>
67 bool RenderUsingHTML =
false;
69 using DOTTraits = DOTGraphTraits<GraphType>;
70 using GTraits = GraphTraits<GraphType>;
72 using node_iterator =
typename GTraits::nodes_iterator;
73 using child_iterator =
typename GTraits::ChildIteratorType;
76 static_assert(std::is_pointer<NodeRef>::value,
77 "FIXME: Currently GraphWriter requires the NodeRef type to be "
78 "a pointer.\nThe pointer usage should be moved to "
79 "DOTGraphTraits, and removed from GraphWriter itself.");
83 bool getEdgeSourceLabels(raw_ostream &O, NodeRef
Node) {
84 child_iterator EI = GTraits::child_begin(
Node);
85 child_iterator EE = GTraits::child_end(
Node);
86 bool hasEdgeSourceLabels =
false;
91 for (
unsigned i = 0; EI != EE &&
i != 64; ++EI, ++
i) {
92 std::string label = DTraits.getEdgeSourceLabel(
Node, EI);
97 hasEdgeSourceLabels =
true;
100 O <<
"<td colspan=\"1\" port=\"s" <<
i <<
"\">" << label <<
"</td>";
109 if (EI != EE && hasEdgeSourceLabels) {
111 O <<
"<td colspan=\"1\" port=\"s64\">truncated...</td>";
113 O <<
"|<s64>truncated...";
116 return hasEdgeSourceLabels;
122 RenderUsingHTML = DTraits.renderNodesUsingHTML();
140 std::string GraphName(DTraits.getGraphName(
G));
144 else if (!GraphName.empty())
147 O <<
"digraph unnamed {\n";
149 if (DTraits.renderGraphFromBottomUp())
150 O <<
"\trankdir=\"BT\";\n";
154 else if (!GraphName.empty())
156 O << DTraits.getGraphProperties(
G);
167 for (
const auto Node : nodes<GraphType>(
G))
175 std::string NodeAttributes = DTraits.getNodeAttributes(
Node,
G);
177 O <<
"\tNode" <<
static_cast<const void *
>(
Node) <<
" [shape=";
183 if (!NodeAttributes.empty()) O << NodeAttributes <<
",";
186 if (RenderUsingHTML) {
189 unsigned ColSpan = 0;
190 child_iterator EI = GTraits::child_begin(
Node);
191 child_iterator EE = GTraits::child_end(
Node);
192 for (; EI != EE && ColSpan != 64; ++EI, ++ColSpan)
199 O <<
"<<table border=\"0\" cellborder=\"1\" cellspacing=\"0\""
200 <<
" cellpadding=\"0\"><tr><td align=\"text\" colspan=\"" << ColSpan
205 if (!DTraits.renderGraphFromBottomUp()) {
207 O << DTraits.getNodeLabel(
Node,
G) <<
"</td>";
212 std::string
Id = DTraits.getNodeIdentifierLabel(
Node,
G);
216 std::string NodeDesc = DTraits.getNodeDescription(
Node,
G);
217 if (!NodeDesc.empty())
221 std::string edgeSourceLabels;
223 bool hasEdgeSourceLabels = getEdgeSourceLabels(EdgeSourceLabels,
Node);
225 if (hasEdgeSourceLabels) {
226 if (!DTraits.renderGraphFromBottomUp())
227 if (!RenderUsingHTML)
231 O << EdgeSourceLabels.
str();
233 O <<
"{" << EdgeSourceLabels.
str() <<
"}";
235 if (DTraits.renderGraphFromBottomUp())
236 if (!RenderUsingHTML)
240 if (DTraits.renderGraphFromBottomUp()) {
242 O << DTraits.getNodeLabel(
Node,
G);
247 std::string
Id = DTraits.getNodeIdentifierLabel(
Node,
G);
251 std::string NodeDesc = DTraits.getNodeDescription(
Node,
G);
252 if (!NodeDesc.empty())
256 if (DTraits.hasEdgeDestLabels()) {
259 unsigned i = 0,
e = DTraits.numEdgeDestLabels(
Node);
260 for (;
i !=
e &&
i != 64; ++
i) {
262 O <<
"<d" <<
i <<
">"
267 O <<
"|<d64>truncated...";
272 O <<
"</tr></table>>";
278 child_iterator EI = GTraits::child_begin(
Node);
279 child_iterator EE = GTraits::child_end(
Node);
280 for (
unsigned i = 0; EI != EE &&
i != 64; ++EI, ++
i)
281 if (!DTraits.isNodeHidden(*EI,
G))
283 for (; EI != EE; ++EI)
284 if (!DTraits.isNodeHidden(*EI,
G))
289 if (NodeRef TargetNode = *EI) {
291 if (DTraits.edgeTargetsEdgeSource(
Node, EI)) {
292 child_iterator TargetIt = DTraits.getEdgeTarget(
Node, EI);
296 (unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt);
297 DestPort =
static_cast<int>(
Offset);
300 if (DTraits.getEdgeSourceLabel(
Node, EI).empty())
304 static_cast<const void*
>(TargetNode), DestPort,
305 DTraits.getEdgeAttributes(
Node, EI,
G));
311 const std::string &Label,
unsigned NumEdgeSources = 0,
312 const std::vector<std::string> *EdgeSourceLabels =
nullptr) {
313 O <<
"\tNode" <<
ID <<
"[ ";
317 if (NumEdgeSources) O <<
"{";
319 if (NumEdgeSources) {
322 for (
unsigned i = 0;
i != NumEdgeSources; ++
i) {
324 O <<
"<s" <<
i <<
">";
333 void emitEdge(
const void *SrcNodeID,
int SrcNodePort,
334 const void *DestNodeID,
int DestNodePort,
335 const std::string &
Attrs) {
336 if (SrcNodePort > 64)
return;
337 if (DestNodePort > 64) DestNodePort = 64;
339 O <<
"\tNode" << SrcNodeID;
340 if (SrcNodePort >= 0)
341 O <<
":s" << SrcNodePort;
342 O <<
" -> Node" << DestNodeID;
343 if (DestNodePort >= 0 && DTraits.hasEdgeDestLabels())
344 O <<
":d" << DestNodePort;
347 O <<
"[" <<
Attrs <<
"]";
358 template<
typename GraphType>
360 bool ShortNames =
false,
361 const Twine &Title =
"") {
366 W.writeGraph(Title.str());
377 template <
typename GraphType>
379 bool ShortNames =
false,
380 const Twine &Title =
"",
381 std::string Filename =
"") {
383 if (Filename.empty()) {
390 if (EC == std::errc::file_exists) {
391 errs() <<
"file exists, overwriting" <<
"\n";
393 errs() <<
"error writing into file" <<
"\n";
396 errs() <<
"writing to the newly created file " << Filename <<
"\n";
402 errs() <<
"error opening file '" << Filename <<
"' for writing!\n";
407 errs() <<
" done. \n";
413 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
414 template <
typename GraphType>
417 const Twine &Title,
bool ShortNames =
false,
418 const Twine &Name =
"") {
426 template<
typename GraphType>
428 bool ShortNames =
false,
const Twine &Title =
"",
432 if (Filename.empty())
440 #endif // LLVM_SUPPORT_GRAPHWRITER_H