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