29 auto isAlpha = [](
char c)
31 return (c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z');
33 auto isDigit = [](
char c)
35 return (c >=
'0' && c <=
'9');
38 char firstChar =
string[0];
39 if (!isAlpha(firstChar) && firstChar !=
'_')
43 if (!isAlpha(c) && !isDigit(c) && c !=
'_')
70 else if (c < ' ' || c >= 127)
74 snprintf(tmpStr,
sizeof(tmpStr),
"%02X", c);
75 out <<
"\\x" << tmpStr;
102 else if (c ==
'\n' && replaceNewlines)
116 for (
char c :
string)
118 if (c <= ' ' || c >= 127 || c ==
'<' || c ==
'>' || c ==
'"' || c ==
'\'' || c ==
'/'
132 [[nodiscard]]
static const char *
135 static constexpr
size_t SPACE_PER_INDENT = 2;
136 static constexpr
size_t MAX_SPACES = 128;
137 static thread_local
char indentation[MAX_SPACES + 1];
139 size_t spaces =
indent * SPACE_PER_INDENT;
140 if (spaces > MAX_SPACES)
143 for (
size_t i = 0; i < spaces; i++)
144 indentation[i] =
' ';
145 indentation[spaces] =
'\0';
151 UniqueIdSuffix_(std::nullopt),
160 std::ostringstream ss;
174 Label_ = std::move(label);
182 Label_.append(sep).append(text);
272 std::optional<std::string_view>
277 if (
auto stringValue = std::get_if<std::string>(&it->second))
285 std::optional<uintptr_t>
290 if (
auto uintptrValue = std::get_if<uintptr_t>(&it->second))
292 return *uintptrValue;
303 if (
auto graphElementValue = std::get_if<const GraphElement *>(&it->second))
305 return *graphElementValue;
310 if (
auto ptr = std::get_if<uintptr_t>(&it->second))
312 if (
auto gElement =
GetGraph().GetElementFromProgramObject(*ptr))
316 if (
auto gwElement =
GetGraph().GetWriter().GetElementFromProgramObject(*ptr))
350 auto FormatAttribute = [&](std::string_view name, std::string_view value)
373 auto OutputAttribute = [&](
const std::string & name)
377 FormatAttribute(name, *
string);
381 FormatAttribute(name, graphElement->GetFullId());
395 OutputAttribute(name);
425 const std::vector<Edge *> &
436 else if (
this == &edge.
GetTo())
449 if (&edge->GetFrom() ==
this || !edge->IsDirected())
460 if (&edge->GetTo() ==
this || !edge->IsDirected())
469 std::ostringstream text;
470 size_t numIncomingEdges = 0;
474 if (&edge->GetTo() !=
this && edge->IsDirected())
477 Port & otherEnd = edge->GetOtherEnd(*
this);
478 if (numIncomingEdges == 0)
486 if (numIncomingEdges == 1)
489 out <<
"[" << text.str() <<
"]";
582 out <<
"];" << std::endl;
668 for (
size_t i = 0; i < inputPorts; i++)
671 for (
size_t i = 0; i < outputPorts; i++)
680 throw Error(
"InOutNodes can not have custom shapes set");
764 inputPort->Finalize();
766 outputPort->Finalize();
775 graph->Output(out, format,
indent);
823 out <<
"label=<" << std::endl;
826 out <<
"<TABLE BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">" << std::endl;
829 auto PrintPortList = [&out](
auto & ports)
834 out <<
"\t<TR><TD>" << std::endl;
835 out <<
"\t\t<TABLE BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\"><TR>" << std::endl;
836 out <<
"\t\t\t<TD WIDTH=\"20\"></TD>" << std::endl;
837 for (
size_t i = 0; i < ports.size(); i++)
841 out <<
"\t\t\t<TD WIDTH=\"10\"></TD>" << std::endl;
843 auto & port = *ports[i];
844 out <<
"\t\t\t<TD BORDER=\"1\" CELLPADDING=\"1\" ";
845 out <<
"PORT=\"" << port.GetFullId() <<
"\" ";
849 out <<
"><FONT POINT-SIZE=\"10\">";
856 out <<
" WIDTH=\"8\" HEIGHT=\"5\" FIXEDSIZE=\"true\">";
858 out <<
"</TD>" << std::endl;
860 out <<
"\t\t\t<TD WIDTH=\"20\"></TD>" << std::endl;
861 out <<
"\t\t</TR></TABLE>" << std::endl;
862 out <<
"\t</TD></TR>" << std::endl;
869 out <<
"\t<TR><TD>" << std::endl;
870 out <<
"\t\t<TABLE BORDER=\"1\" STYLE=\"ROUNDED\" CELLBORDER=\"0\" ";
871 out <<
"CELLSPACING=\"0\" CELLPADDING=\"0\" ";
879 out <<
">" << std::endl;
880 out <<
"\t\t\t<TR><TD CELLPADDING=\"1\">";
882 out <<
"</TD></TR>" << std::endl;
887 out <<
"\t\t\t<TR><TD>" << std::endl;
888 out <<
"\t\t\t\t<TABLE BORDER=\"0\" CELLSPACING=\"4\" CELLPADDING=\"2\"><TR>" << std::endl;
891 out <<
"\t\t\t\t\t<TD BORDER=\"1\" STYLE=\"ROUNDED\" WIDTH=\"40\" BGCOLOR=\"white\" ";
892 out <<
"_SUBGRAPH=\"" << graph->GetFullId() <<
"\">";
894 out <<
"</TD>" << std::endl;
896 out <<
"\t\t\t\t</TR></TABLE>" << std::endl;
897 out <<
"\t\t\t</TD></TR>" << std::endl;
901 out <<
"\t\t</TABLE>" << std::endl;
902 out <<
"\t</TD></TR>" << std::endl;
906 out <<
"</TABLE>" << std::endl;
909 out <<
"];" << std::endl;
914 OutsideSource_(nullptr)
955 OutsideDestination_(nullptr)
1036 else if (&end == &
To_)
1072 if (hasHeadArrow && hasTailArrow)
1074 else if (hasHeadArrow)
1078 else if (hasTailArrow)
1099 out <<
"];" << std::endl;
1105 ParentNode_(nullptr)
1111 ParentNode_(&parentNode)
1147 auto node =
new Node(*
this);
1148 Nodes_.emplace_back(node);
1155 auto node =
new InOutNode(*
this, inputPorts, outputPorts);
1156 Nodes_.emplace_back(node);
1223 auto edge =
new Edge(from, to, directed);
1224 Edges_.emplace_back(edge);
1246 if (edge->IsDirected() && &edge->GetFrom() != &a)
1248 if (&edge->GetOtherEnd(a) == &b)
1271 JLM_ASSERT(slot ==
nullptr &&
"Trying to map a GraphElement to an already mapped program object");
1290 for (
auto & node :
Nodes_)
1294 for (
auto & edge :
Edges_)
1305 bool anyArguments =
false;
1312 anyArguments =
true;
1313 arg->OutputASCII(out,
indent);
1319 for (
auto & node :
Nodes_)
1322 node->OutputASCII(out,
indent);
1326 bool anyResults =
false;
1334 res->OutputASCII(out,
indent);
1351 <<
"node[shape=box style=filled fillcolor=white width=0.1 height=0.1 margin=0.05];"
1365 auto PrintOrderedSubgraph = [&out](
auto & nodes,
const char * rank,
size_t indent)
1370 out <<
Indent(
indent) <<
"rank=" << rank <<
";" << std::endl;
1371 for (
size_t i = 0; i < nodes.size(); i++)
1373 nodes[i]->OutputDot(out,
indent);
1377 out <<
Indent(
indent) << nodes[i - 1]->GetFullId() <<
" -> " << nodes[i]->GetFullId()
1378 <<
"[style=invis];" << std::endl;
1385 for (
auto & node :
Nodes_)
1387 node->OutputDot(out,
indent);
1392 for (
auto & edge :
Edges_)
1394 edge->OutputDot(out,
indent);
1401 for (
auto & node :
Nodes_)
1428 auto graph =
new Graph(*
this);
1449 auto graph =
new Graph(*
this, parentNode);
1458 if (
auto found = graph->GetElementFromProgramObject(
object))
1475 if (!graph->IsSubgraph())
1485 if (!graph->IsSubgraph())
1486 graph->Output(out, format);
bool CanBeEdgeHead() const override
void SetOutsideSource(const Port &outsideSource)
const char * GetIdPrefix() const override
const Port * OutsideSource_
ArgumentNode(Graph &graph)
void OutputASCII(std::ostream &out, size_t indent) const override
void SetStyle(std::string style)
void SetArrowTail(std::string arrow)
Port & GetOtherEnd(const Port &end)
const char * GetIdPrefix() const override
Graph & GetGraph() override
Edge(Port &from, Port &to, bool directed)
void OutputDot(std::ostream &out, size_t indent) const
void SetArrowHead(std::string arrow)
size_t GetUniqueIdSuffix() const
virtual Graph & GetGraph()=0
void SetLabel(std::string label)
uintptr_t GetProgramObject() const noexcept
std::string GetFullId() const
void SetAttributeObject(const std::string &attribute, uintptr_t object)
void RemoveProgramObject()
void AppendToLabel(std::string_view text, std::string_view sep="\n")
void SetAttribute(const std::string &attribute, std::string value)
virtual const char * GetIdPrefix() const =0
std::string_view GetLabelOr(std::string_view otherwise) const
const std::string & GetLabel() const
bool RemoveAttribute(const std::string &attribute)
std::optional< uintptr_t > GetAttributeObject(const std::string &attribute) const
std::unordered_map< std::string, AttributeValue > AttributeMap_
void OutputAttributes(std::ostream &out, AttributeOutputFormat format) const
bool HasAttribute(const std::string &attribute) const
const GraphElement * GetAttributeGraphElement(const std::string &attribute) const
std::optional< size_t > UniqueIdSuffix_
std::optional< std::string_view > GetAttributeString(const std::string &attribute) const
void SetProgramObjectUintptr(uintptr_t object)
void SetAttributeGraphElement(const std::string &attribute, const GraphElement &element)
bool HasProgramObject() const noexcept
std::vector< std::unique_ptr< ArgumentNode > > ArgumentNodes_
ArgumentNode & CreateArgumentNode()
Node & GetNode(size_t index)
GraphElement * GetElementFromProgramObject(uintptr_t object) const
std::unordered_map< uintptr_t, GraphElement * > ProgramObjectMapping_
Node & GetResultNode(size_t index)
Edge & GetEdge(size_t index)
Edge * GetEdgeBetween(Port &a, Port &b)
void OutputASCII(std::ostream &out, size_t indent) const
const char * GetIdPrefix() const override
void RemoveProgramObjectMapping(uintptr_t object)
std::vector< std::unique_ptr< Edge > > Edges_
Graph & GetGraph() override
ResultNode & CreateResultNode()
size_t NumResultNodes() const noexcept
void Output(std::ostream &out, OutputFormat format, size_t indent=0) const
std::vector< std::unique_ptr< ResultNode > > ResultNodes_
void OutputDot(std::ostream &out, size_t indent) const
size_t NumEdges() const noexcept
size_t NumNodes() const noexcept
Node & GetArgumentNode(size_t index)
InOutNode & CreateInOutNode(size_t inputPorts, size_t outputPorts)
size_t NumArgumentNodes() const noexcept
std::vector< std::unique_ptr< Node > > Nodes_
Edge & CreateEdge(Port &from, Port &to, bool directed)
void MapProgramObjectToElement(GraphElement &element)
size_t NumInputPorts() const
void OutputSubgraphs(std::ostream &out, OutputFormat format, size_t indent) const override
std::unordered_map< std::string, std::string > HtmlTableAttributes_
std::vector< std::unique_ptr< OutputPort > > OutputPorts_
void OutputDot(std::ostream &out, size_t indent) const override
InOutNode(Graph &graph, size_t inputPorts, size_t outputPorts)
void SetFillColor(std::string color) override
size_t NumOutputPorts() const
OutputPort & GetOutputPort(size_t index)
std::vector< Graph * > SubGraphs_
std::vector< std::unique_ptr< InputPort > > InputPorts_
void SetShape(std::string) override
InputPort & GetInputPort(size_t index)
size_t NumSubgraphs() const
Graph & GetSubgraph(size_t index)
InputPort & CreateInputPort()
void OutputASCII(std::ostream &out, size_t indent) const override
void SetHtmlTableAttribute(std::string name, std::string value)
OutputPort & CreateOutputPort()
Node & GetNode() override
const char * GetIdPrefix() const override
Graph & GetGraph() override
virtual void OutputDot(std::ostream &out, size_t indent) const
virtual void OutputSubgraphs(std::ostream &out, OutputFormat format, size_t indent) const
void OutputDotPortId(std::ostream &out) const override
void Output(std::ostream &out, OutputFormat format, size_t indent) const
virtual void OutputASCII(std::ostream &out, size_t indent) const
virtual void SetShape(std::string shape)
void SetFillColor(std::string color) override
Node & GetNode() override
void SetFillColor(std::string color) override
OutputPort(InOutNode &node)
bool CanBeEdgeHead() const override
void OutputDotPortId(std::ostream &out) const override
const char * GetIdPrefix() const override
const std::vector< Edge * > & GetConnections() const
virtual bool CanBeEdgeTail() const
virtual bool CanBeEdgeHead() const
std::vector< Edge * > Connections_
bool HasIncomingEdges() const
void OutputIncomingEdgesASCII(std::ostream &out) const
Graph & GetGraph() override
void OnEdgeAdded(Edge &edge)
bool HasOutgoingEdges() const
virtual void OutputDotPortId(std::ostream &out) const =0
virtual Node & GetNode()=0
const Port * OutsideDestination_
void SetOutsideDestination(const Port &outsideSource)
void OutputASCII(std::ostream &out, size_t indent) const override
const char * GetIdPrefix() const override
bool CanBeEdgeTail() const override
GraphElement * GetElementFromProgramObject(uintptr_t object) const
size_t GetNextUniqueIdStubSuffix(const char *idStub)
std::unordered_map< std::string, size_t > NextUniqueIdStubSuffix_
size_t NumGraphs() const noexcept
Graph & CreateSubGraph(Node &parentNode)
std::vector< std::unique_ptr< Graph > > Graphs_
void outputAllGraphs(std::ostream &out, OutputFormat format)
Graph & GetGraph(size_t index)
#define JLM_UNREACHABLE(msg)
std::string Edge(jlm::rvsdg::Output *output, jlm::rvsdg::Input *input, std::unordered_map< rvsdg::Output *, ViewColors > &tailLabel, bool back_edge=false)
static std::string hex(size_t i)
static bool empty(const rvsdg::GammaNode *gamma)
static std::string indent(size_t depth)
static const char *const EDGE_ID_ATTRIBUTE
static bool LooksLikeIdentifier(std::string_view string)
static const char * Indent(size_t indent)
static void PrintStringAsHtmlAttributeName(std::ostream &out, std::string_view string)
static const char *const TOOLTIP_ATTRIBUTE
static void PrintStringAsHtmlText(std::ostream &out, std::string_view string, bool replaceNewlines)
static void PrintIdentifierSafe(std::ostream &out, std::string_view string)
static std::string strfmt(Args... args)