MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
dot.cpp
Go to the documentation of this file.
1#include <fstream>
2#include <ostream>
3#include <sstream>
4
5#include "mim/def.h"
6#include "mim/nest.h"
7#include "mim/world.h"
8
9#include "mim/util/print.h"
10
11using namespace std::string_literals;
12
13namespace mim {
14
15namespace {
16
17template<class T>
18std::string escape(const T& val) {
19 std::ostringstream oss;
20 oss << val;
21 auto str = oss.str();
22 find_and_replace(str, "<", "&lt;");
23 find_and_replace(str, ">", "&gt;");
24 return str;
25}
26
27class Dot {
28public:
29 Dot(std::ostream& ostream, bool types, const Def* root = nullptr)
30 : os_(ostream)
31 , types_(types)
32 , root_(root) {}
33
34 void prologue() {
35 (tab_++).println(os_, "digraph {{");
36 tab_.println(os_, "ordering=out;");
37 tab_.println(os_, "splines=ortho;");
38 tab_.println(os_, "newrank=true;");
39 tab_.println(os_, "nodesep=0.6;");
40 tab_.println(os_, "ranksep=1.2;");
41 tab_.println(os_, "node [shape=box,style=filled,fontname=\"monospace\"];");
42 }
43
44 void epilogue() { (--tab_).println(os_, "}}"); }
45
46 void run(const Def* root, uint32_t max) {
47 prologue();
48 recurse(root, max);
49 epilogue();
50 }
51
52 void recurse(const Def* def, uint32_t max) {
53 if (max == 0 || !done_.emplace(def).second) return;
54
55 tab_.print(os_, "_{}[", def->gid());
56
57 if (def->isa_mut())
58 if (def == root_)
59 os_ << "style=\"filled,diagonals,bold\"";
60 else
61 os_ << "style=\"filled,diagonals\",penwidth=2";
62 else if (def == root_)
63 os_ << "style=\"filled,bold\"";
64
65 label(def) << ',';
66 color(def) << ',';
67 if (def->is_closed()) os_ << "rank=min,";
68 tooltip(def) << "];\n";
69
70 if (def->is_set()) {
71 for (size_t i = 0, e = def->num_ops(); i != e; ++i) {
72 auto op = def->op(i);
73 recurse(op, max - 1);
74 if (op->isa<Lit>() || op->isa<Axm>() || def->isa<Var>() || def->isa<Nat>() || def->isa<Idx>())
75 tab_.println(os_, "_{}:{} -> _{}[color=\"#00000000\",constraint=false];", def->gid(), i, op->gid());
76 else
77 tab_.println(os_, "_{}:{} -> _{};", def->gid(), i, op->gid());
78 }
79 }
80
81 if (auto t = def->type(); t && types_) {
82 recurse(t, max - 1);
83 tab_.println(os_, "_{} -> _{}[color=\"#00000000\",constraint=false,style=dashed];", def->gid(), t->gid());
84 }
85 }
86
87 std::ostream& label(const Def* def) {
88 auto n = def->is_set() ? def->num_ops() : size_t(0);
89 if (n > 0) {
90 print(os_, "label=<<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr><td colspan=\"{}\">", n);
91 emit_name(def);
92 os_ << "</td></tr><tr>";
93 for (size_t i = 0; i < n; ++i)
94 print(os_, "<td port=\"{}\" cellpadding=\"0\" height=\"1\" width=\"8\"></td>", i);
95 os_ << "</tr></table>>";
96 } else {
97 os_ << "label=<";
98 emit_name(def);
99 os_ << ">";
100 }
101 return os_;
102 }
103
104 void emit_name(const Def* def) {
105 if (auto lit = def->isa<Lit>())
106 lit->stream(os_, 0);
107 else
108 os_ << def->node_name();
109 print(os_, "<br/><font point-size=\"9\">{}</font>", escape(def->unique_name()));
110 }
111
112 std::ostream& color(const Def* def) {
113 float hue;
114 // clang-format off
115 if (def->is_form()) hue = 0.60f; // blue - type formation
116 else if (def->is_intro()) hue = 0.35f; // green - introduction
117 else if (def->is_elim()) hue = 0.00f; // red - elimination
118 else if (def->is_meta()) hue = 0.15f; // yellow - universe/meta
119 else hue = 0.80f; // purple - Hole
120 // clang-format on
121 return print(os_, "fillcolor=\"{} 0.5 0.75\"", hue);
122 }
123
124 std::ostream& tooltip(const Def* def) {
125 static constexpr auto NL = "&#13;&#10;"; // newline
126
127 auto loc = escape(def->loc());
128 auto type = escape(def->type());
129 print(os_, "tooltip=\"");
130 print(os_, "<b>expr:</b> {}{}", def, NL);
131 print(os_, "<b>type:</b> {}{}", type, NL);
132 print(os_, "<b>name:</b> {}{}", def->sym(), NL);
133 print(os_, "<b>gid:</b> {}{}", def->gid(), NL);
134 print(os_, "<b>flags:</b> 0x{x}{}", def->flags(), NL);
135 print(os_, "<b>mark:</b> 0x{x}{}", def->mark(), NL);
136 print(os_, "<b>local_muts:</b> {, }{}", def->local_muts(), NL);
137 print(os_, "<b>local_vars:</b> {, }{}", def->local_vars(), NL);
138 print(os_, "<b>free_vars:</b> {, }{}", def->free_vars(), NL);
139 if (auto mut = def->isa_mut()) print(os_, "<b>users:</b> {{{, }}}{}", mut->users(), NL);
140 print(os_, "<b>loc:</b> {}", loc);
141 return print(os_, "\"");
142 }
143
144private:
145 std::ostream& os_;
146 bool types_;
147 const Def* root_;
148 Tab tab_;
149 DefSet done_;
150};
151
152} // namespace
153
154void Def::dot(std::ostream& ostream, uint32_t max, bool types) const { Dot(ostream, types, this).run(this, max); }
155
156void Def::dot(const char* file, uint32_t max, bool types) const {
157 if (!file) {
158 dot(std::cout, max, types);
159 } else {
160 auto of = std::ofstream(file);
161 dot(of, max, types);
162 }
163}
164
165void World::dot(const char* file, bool annexes, bool types) const {
166 if (!file) {
167 dot(std::cout, annexes, types);
168 } else {
169 auto of = std::ofstream(file);
170 dot(of, annexes, types);
171 }
172}
173
174void World::dot(std::ostream& os, bool anx, bool types) const {
175 Dot dot(os, types);
176 dot.prologue();
177 for (auto external : externals().muts())
178 dot.recurse(external, uint32_t(-1));
179 if (anx)
180 for (auto annex : annexes())
181 dot.recurse(annex, uint32_t(-1));
182 dot.epilogue();
183}
184
185/*
186 * Nest
187 */
188
189void Nest::dot(const char* file) const {
190 if (!file) {
191 dot(std::cout);
192 } else {
193 auto of = std::ofstream(file);
194 dot(of);
195 }
196}
197
198void Nest::dot(std::ostream& os) const {
199 Tab tab;
200 (tab++).println(os, "digraph {{");
201 tab.println(os, "ordering=out;");
202 tab.println(os, "node [shape=box,style=filled];");
203 root()->dot(tab, os);
204 (--tab).println(os, "}}");
205}
206
207void Nest::Node::dot(Tab tab, std::ostream& os) const {
208 std::string s;
209 for (const auto& scc : topo_) {
210 s += '[';
211 for (auto sep = ""s; auto n : *scc) {
212 s += sep + n->name();
213 sep = ", ";
214 }
215 s += "] ";
216 }
217
218 for (auto sibl : sibl_deps())
219 tab.println(os, "\"{}\":s -> \"{}\":s [style=dashed,constraint=false,splines=true]", name(), sibl->name());
220
221 auto rec = is_mutually_recursive() ? "rec*" : (is_directly_recursive() ? "rec" : "");
222 auto html = "<b>" + name() + "</b>";
223 if (*rec) html += "<br/><i>"s + rec + "</i>";
224 html += "<br/><font point-size=\"8\">depth " + std::to_string(loop_depth()) + "</font>";
225 tab.println(os, "\"{}\" [label=<{}>,tooltip=\"{}\"]", name(), html, s);
226 for (auto child : children().nodes()) {
227 tab.println(os, "\"{}\" -> \"{}\" [splines=false]", name(), child->name());
228 child->dot(tab, os);
229 }
230
231 // Overlay domination between siblings and their parent
232 if (idom()) tab.println(os, "\"{}\" -> \"{}\" [color=red,style=bold,constraint=false]", idom()->name(), name());
233}
234
235} // namespace mim
void dot(std::ostream &os, uint32_t max=0xFFFFFF, bool types=false) const
Definition dot.cpp:154
const Def * op(size_t i) const noexcept
Definition def.h:308
constexpr u32 gid() const noexcept
Global id - unique number for this Def.
Definition def.h:270
std::string name() const
Definition nest.h:18
auto & sibl_deps()
Definition nest.h:113
const Children & children() const
Definition nest.h:73
auto idom() const
Immediate Dominator for children in connected components.
Definition nest.h:24
bool is_directly_recursive() const
Definition nest.h:138
bool is_mutually_recursive() const
Definition nest.h:137
uint32_t loop_depth() const
Definition nest.h:32
void dot(std::ostream &os) const
Definition dot.cpp:198
auto nodes() const
Definition nest.h:213
const Node * root() const
Definition nest.h:202
Keeps track of indentation level.
Definition print.h:206
std::ostream & println(std::ostream &os, const char *s, Args &&... args)
Same as Tab::print but appends a std::endl to os.
Definition print.h:235
auto & muts()
Definition world.h:584
const Def * annex(Id id)
Lookup annex by Axm::id.
Definition world.h:184
const Externals & externals() const
Definition world.h:240
auto annexes() const
Definition world.h:180
void dot(std::ostream &os, bool annexes=false, bool types=false) const
Dumps DOT to os.
Definition dot.cpp:174
const Def * op(trait o, const Def *type)
Definition core.h:33
int run(std::string cmd, std::string args={})
Wraps sys::system and puts .exe at the back (Windows) and ./ at the front (otherwise) of cmd.
Definition sys.cpp:77
std::string escape(const std::filesystem::path &path)
Returns the path as std::string and escapes all whitespaces with backslash.
Definition sys.cpp:86
Definition ast.h:14
std::ostream & print(std::ostream &os, const char *s)
Base case.
Definition print.cpp:5
void find_and_replace(std::string &str, std::string_view what, std::string_view repl)
Replaces all occurrences of what with repl.
Definition util.h:74
GIDSet< const Def * > DefSet
Definition def.h:74
std::ostream & println(std::ostream &os, const char *fmt, Args &&... args)
As above but end with std::endl.
Definition print.h:157
@ Nat
Definition def.h:114
@ Idx
Definition def.h:114
@ Var
Definition def.h:114
@ Axm
Definition def.h:114
@ Lit
Definition def.h:114