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