MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
emitter.h
Go to the documentation of this file.
1#pragma once
2
3#include "mim/def.h"
4#include "mim/phase.h"
5#include "mim/schedule.h"
6#include "mim/world.h"
7
8namespace mim {
9
10template<class Value, class Type, class BB, class Child>
11class Emitter : public NestPhase<Lam> {
12private:
13 constexpr const Child& child() const { return *static_cast<const Child*>(this); }
14 constexpr Child& child() { return *static_cast<Child*>(this); }
15
16 /// Internal wrapper for Emitter::emit that schedules @p def and invokes `child().emit_bb`.
17 Value emit_(const Def* def) {
18 auto place = scheduler_.smart(curr_lam_, def);
19 auto& bb = lam2bb_[place->mut()->template as<Lam>()];
20 return child().emit_bb(bb, def);
21 }
22
23public:
25
26protected:
27 Emitter(World& world, std::string name, std::ostream& ostream)
28 : NestPhase(world, std::move(name), false)
29 , ostream_(ostream) {}
30
31 std::ostream& ostream() const { return ostream_; }
32
33 /// Recursively emits code.
34 /// `mem`-typed @p def%s return sth that is `!child().is_valid(value)`.
35 /// This variant asserts in this case.
36 Value emit(const Def* def) {
37 auto res = emit_unsafe(def);
38 assert(child().is_valid(res));
39 return res;
40 }
41
42 /// As above but returning `!child().is_valid(value)` is permitted.
43 Value emit_unsafe(const Def* def) {
44 if (auto i = globals_.find(def); i != globals_.end()) return i->second;
45 if (auto i = locals_.find(def); i != locals_.end()) return i->second;
46
47 auto val = emit_(def);
48 return locals_[def] = val;
49 }
50
51 void visit(const Nest& nest) override {
52 if (!root()->is_set()) {
53 child().emit_imported(root());
54 return;
55 }
56
57 auto muts = Scheduler::schedule(nest); // TODO make sure to not compute twice
58
59 // make sure that we don't need to rehash later on
60 for (auto mut : muts)
61 if (auto lam = mut->isa<Lam>()) lam2bb_.try_emplace(lam, BB());
62 auto old_size = lam2bb_.size();
63
64 assert(root()->ret_var());
65
66 auto fct = child().prepare();
67
68 Scheduler new_scheduler(nest);
69 swap(scheduler_, new_scheduler);
70
71 for (auto mut : muts) {
72 if (auto lam = mut->isa<Lam>()) {
73 curr_lam_ = lam;
74 assert(lam == root() || Lam::isa_basicblock(lam));
75 child().emit_epilogue(lam);
76 }
77 }
78
79 child().finalize();
80 locals_.clear();
81 assert_unused(lam2bb_.size() == old_size && "really make sure we didn't trigger a rehash");
82 }
83
84 Lam* curr_lam_ = nullptr;
85 std::ostream& ostream_;
91};
92
93} // namespace mim
Lam * root() const
Definition phase.h:304
Base class for all Defs.
Definition def.h:251
Emitter(World &world, std::string name, std::ostream &ostream)
Definition emitter.h:27
Value emit(const Def *def)
Recursively emits code.
Definition emitter.h:36
Scheduler scheduler_
Definition emitter.h:86
Value emit_unsafe(const Def *def)
As above but returning !child().is_valid(value) is permitted.
Definition emitter.h:43
Lam * curr_lam_
Definition emitter.h:84
LamMap< BB > lam2bb_
Definition emitter.h:90
void visit(const Nest &nest) override
Definition emitter.h:51
A function.
Definition lam.h:110
static const Lam * isa_basicblock(const Def *d)
Definition lam.h:142
const Nest & nest() const
Definition phase.h:320
NestPhase(World &world, std::string name, bool elide_empty)
Definition phase.h:315
Builds a nesting tree of all mutables‍/binders.
Definition nest.h:12
static Schedule schedule(const Nest &)
Definition schedule.cpp:118
World & world()
Definition pass.h:64
std::string_view name() const
Definition pass.h:67
Keeps track of indentation level.
Definition print.h:206
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:31
Definition ast.h:14
GIDMap< const Def *, To > DefMap
Definition def.h:73
GIDMap< Lam *, To > LamMap
Definition lam.h:219
Definition span.h:122