40 std::vector<assoc::set<void *>> *color_groups =
nullptr;
44 std::stringstream out;
46 std::vector<std::string> colors = {
"brown",
"coral",
"crimson",
"deeppink",
"gold",
47 "red",
"blue",
"green",
"cyan",
"orchid"};
50 explicit DotDumper(std::string filename,
bool detail) : filename(filename), detail(detail) {}
53 : filename(filename), color_groups(&color_groups), detail(detail) {}
56 static std::string escape(std::string s) {
57 boost::replace_all(s,
"ingress::",
"");
58 boost::replace_all(s,
"egress::",
"");
59 boost::replace_all(s,
"$",
"\\$");
60 boost::replace_all(s,
".",
"\\.");
61 boost::replace_all(s,
"->",
"-~");
62 boost::replace_all(s,
"<",
"\\<");
63 boost::replace_all(s,
">",
"\\>");
64 boost::replace_all(s,
"-~",
"->");
68 std::string cluster_name;
70 std::string to_label(std::string label,
const void *what) {
72 ss << cluster_name << label << what;
76 std::string to_label(std::string label) {
78 ss << cluster_name << label;
82 std::string lookup_color(
void *obj) {
84 for (
auto it = color_groups->begin(); it != color_groups->end(); it++) {
85 if ((*it).count(obj)) {
86 auto cid = std::distance(color_groups->begin(), it) % colors.size();
87 return colors.at(cid);
94 void dump(
const IR::BFN::Transition *transition) {
95 auto c = lookup_color((
void *)transition);
96 if (c !=
"undef") out <<
"color=" << c <<
" ";
98 if (detail) out <<
"label=\"" << transition <<
"\"";
101 std::string get_color(
const IR::BFN::ParserState *state) {
102 auto c = lookup_color((
void *)state);
103 if (c !=
"undef")
return c;
108 void dump(
const IR::BFN::ParserState *state) {
109 out << to_label(
"State", state);
110 out <<
" [shape=record, style=\"filled,rounded\", ";
111 out <<
"fillcolor=" << get_color(state);
112 out <<
", label=\"{";
118 for (
auto stmt : state->statements) out <<
" " << stmt <<
"\\l";
120 if (state->statements.size()) out <<
"\\l";
122 for (
auto select : state->selects) out <<
" " << select <<
"\\l";
126 out <<
"];" << std::endl;
130 for (
auto s : graph.states()) dump(s);
132 for (
auto succ : graph.successors()) {
133 for (
auto dst : succ.second) {
134 for (
auto t : graph.transitions(succ.first, dst)) {
135 out << to_label(
"State", succ.first) <<
" -> " << to_label(
"State", dst)
140 out <<
" ]" << std::endl;
145 for (
auto &kv : graph.to_pipe()) {
146 for (
auto t : graph.to_pipe(kv.first)) {
147 out << to_label(
"State", kv.first) <<
" -> "
148 << to_label(::toString(gress) +
"_pipe") <<
" [ ";
152 out <<
" ]" << std::endl;
156 for (
auto &kv : graph.loopbacks()) {
157 auto next = graph.get_state(kv.first.second);
159 for (
auto t : kv.second) {
160 out << to_label(
"State", kv.first.first) <<
" -> " << to_label(
"State", next)
161 <<
" [ color=\"red\" ";
165 out <<
" ]" << std::endl;
170 void dump(
const IR::BFN::LoweredParserState *state) {
171 out << to_label(
"State", state) <<
" [style=filled, fillcolor=lightskyblue1, shape=record";
172 out <<
", label=\"{";
173 out << state->name <<
":\\l\\l";
176 if (!state->select->regs.empty()) out <<
" " << state->select <<
"\\l";
180 out <<
"];" << std::endl;
183 void dump(
const IR::BFN::LoweredParserMatch *match) {
184 out << to_label(
"Match", match) <<
" [style=filled, fillcolor=aliceblue, shape=record";
185 out <<
", label=\"{";
186 out <<
"match " << match->value <<
": \\l\\l";
189 for (
auto stmt : match->extracts) out <<
" " << stmt <<
"\\l";
191 if (match->extracts.size()) out <<
"\\l";
193 for (
auto save : match->saves) out <<
" " << save <<
"\\l";
195 if (match->saves.size()) out <<
"\\l";
197 for (
auto csum : match->checksums) out <<
" " << csum <<
"\\l";
199 if (match->checksums.size()) out <<
"\\l";
201 for (
auto cntr : match->counters) out <<
" " << cntr <<
"\\l";
203 if (match->counters.size()) out <<
"\\l";
205 out <<
"shift: " << match->shift;
209 out <<
"];" << std::endl;
214 for (
auto s : graph.states()) {
215 out <<
"subgraph cluster_" <<
id++ <<
" {";
216 out <<
"style=invis;" << std::endl;
220 for (
auto m : s->transitions) dump(m);
222 out <<
"}" << std::endl;
225 for (
auto s : graph.states()) {
226 for (
auto m : s->transitions) {
227 out << to_label(
"State", s) <<
" -> " << to_label(
"Match", m) << std::endl;
230 out << to_label(
"Match", m) <<
" -> " << to_label(
"State", m->next)
232 }
else if (m->loop) {
235 out << to_label(
"Match", m) <<
" -> " << to_label(::toString(gress) +
"_pipe")
242 for (
auto s : graph.states()) {
243 for (
auto m : s->transitions) {
245 auto next = graph.get_state(stripThreadPrefix(m->loop));
246 out << to_label(
"Match", m) <<
" -> " << to_label(
"State", next)
247 <<
" [color=\"red\"] " << std::endl;
253 template <
typename ParserGraphType>
254 void dump_graph(
const ParserGraphType &graph, gress_t gress,
int pipe_id) {
255 out.str(std::string());
257 out <<
"digraph parser {" << std::endl;
258 out <<
"size=\"8,5\"" << std::endl;
262 out <<
"}" << std::endl;
264 if (
auto fs = open_file(gress, pipe_id)) write_to_file(fs);
267 std::ofstream *open_file(gress_t gress,
int pipe_id,
cstring directory =
"graphs"_cs) {
269 if (!outdir)
return nullptr;
272 auto filepath = outdir +
"/" + std::to_string(fid++) +
"_" + filename +
"_" +
273 ::toString(gress) +
".dot";
275 return new std::ofstream(filepath);
278 void write_to_file(std::ofstream *fs) {
279 *fs << escape(out.str());
290 explicit DumpParser(std::string filename,
bool detail =
false,
bool to_log =
false)
291 :
DotDumper(filename, detail || LOGGING(4)), log(to_log) {}
294 bool detail =
false,
bool to_log =
false)
295 :
DotDumper(filename, color_groups, detail || LOGGING(4)), log(to_log) {}
298 const IR::Node *apply_visitor(
const IR::Node *n,
const char *)
override {
return n; }
301 auto rv = Visitor::init_apply(root);
309 if (!cg.graphs().empty() && !cgl.graphs().empty()) BUG(
"IR is in an incoherent state");
311 for (
auto g : cg.graphs())
312 dump_graph(*(g.second), (g.first)->gress, root->to<IR::BFN::Pipe>()->canon_id());
314 for (
auto g : cgl.graphs())
315 dump_graph(*(g.second), (g.first)->gress, root->to<IR::BFN::Pipe>()->canon_id());
320 for (
auto g : cg.graphs())
321 LOG1(
"Parser IR [" << filename <<
"] : " << std::endl
322 << dumpToString(g.first) << std::endl);
324 for (
auto g : cgl.graphs())
325 LOG1(
"Lowered Parser IR [" << filename <<
"] : " << std::endl
326 << dumpToString(g.first) << std::endl);
static BFNContext & get()
Definition bf-p4c-options.cpp:777
cstring getOutputDirectory(const cstring &suffix=cstring(), int pipe_id=-1)
Definition bf-p4c-options.cpp:795