MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
schedule.cpp
Go to the documentation of this file.
1#include "mim/schedule.h"
2
3#include <fe/container.h>
4#include <fe/worklist.h>
5
6#include "mim/world.h"
7
8namespace mim {
9
11 : nest_(&nest) {
12 auto queue = fe::BFSWorklist<DefSet>();
13
14 auto enqueue = [&](const Def* def, size_t i, const Def* op) {
15 if (nest.contains(op)) {
16 fe::assert_emplace(def2uses_[op], def, i);
17 queue.push(op);
18 }
19 };
20
21 queue.push(nest.muts());
22
23 while (!queue.empty()) {
24 auto def = queue.pop();
25
26 if (!def->is_set()) continue;
27
28 for (size_t i = 0, e = def->num_ops(); i != e; ++i) {
29 // all reachable muts have already been registered above
30 // NOTE we might still see references to unreachable muts in the schedule
31 if (!def->op(i)->isa_mut()) enqueue(def, i, def->op(i));
32 }
33
34 if (!def->type()->isa_mut()) enqueue(def, -1, def->type());
35 }
36}
37
38const Nest::Node* Scheduler::early(const Def* def) {
39 if (auto i = early_.find(def); i != early_.end()) return i->second;
40 if (def->is_closed() || !nest().contains(def)) return early_[def] = nest().root();
41 if (auto var = def->isa<Var>()) return early_[def] = nest()[var->binder()];
42
43 auto result = nest().root();
44 for (auto op : def->deps()) {
45 if (!op->isa_mut() && nest().contains(op)) {
46 auto node = early(op);
47 if (node->level() > result->level()) result = node;
48 }
49 }
50
51 return early_[def] = result;
52}
53
54const Nest::Node* Scheduler::late(Def* curr_mut, const Def* def) {
55 if (auto i = late_.find(def); i != late_.end()) return i->second;
56 if (def->is_closed() || !nest().contains(def)) return late_[def] = nest().root();
57
58 const Nest::Node* result = nullptr;
59 if (auto mut = def->isa_mut()) {
60 result = nest()[mut];
61 } else if (auto var = def->isa<Var>()) {
62 result = nest()[var->binder()];
63 } else {
64 for (auto use : uses(def)) {
65 auto mut = late(curr_mut, use);
66 result = result ? Nest::lca(result, mut) : mut;
67 }
68 }
69
70 if (!result) result = nest()[curr_mut];
71
72 return late_[def] = result;
73}
74
75const Nest::Node* Scheduler::smart(Def* curr_mut, const Def* def) {
76 if (auto i = smart_.find(def); i != smart_.end()) return i->second;
77
78 auto e = early(def);
79 auto l = late(curr_mut, def);
80 auto s = l;
81
82 int depth = l->loop_depth();
83 for (auto i = l; i != e;) {
84 i = i->inest();
85
86 if (i == nullptr) {
87 world().log().e("no place found for {}", def);
88 s = l;
89 break;
90 }
91
92 if (int curr_depth = i->loop_depth(); curr_depth < depth) {
93 s = i;
94 depth = curr_depth;
95 }
96 }
97
98 return smart_[def] = s;
99}
100
101static void post_order(const Nest& nest, const Nest::Node* node, Scheduler::Schedule& res, MutSet& done) {
102 // The mut of a virtual root is a nullptr
103 if (!node->mut()) {
104 for (auto child : node->children().nodes())
105 post_order(nest, child, res, done);
106 return;
107 }
108
109 if (!node->mut()->isa<Lam>()) return;
110 if (auto [_, ins] = done.emplace(node->mut()); !ins) return;
111
112 for (auto op : node->mut()->deps()) {
113 for (auto mut : op->local_muts())
114 if (auto next = nest[mut]) post_order(nest, next, res, done);
115 }
116
117 res.emplace_back(node->mut());
118}
119
120// until we have sth better ...
123 MutSet done;
124 post_order(nest, nest.root(), schedule, done);
125 std::ranges::reverse(schedule); // post-order → reverse post-order
126 return schedule;
127}
128
129} // namespace mim
Base class for all Defs.
Definition def.h:273
bool is_set() const
Definition def.h:370
Defs deps() const noexcept
Definition def.cpp:468
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:580
const Def * op(size_t i) const noexcept
Definition def.h:351
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.h:1111
bool is_closed() const
Same as !has_free_vars().
Definition def.cpp:353
constexpr size_t num_ops() const noexcept
Definition def.h:352
A function.
Definition lam.h:113
Def * mut() const
The mutable capsulated in this Node or nullptr, if it's a virtual root comprising several Nodes.
Definition nest.h:46
const Children & children() const
Definition nest.h:95
Builds a nesting tree for all mutables/binders.
Definition nest.h:31
static const Node * lca(const Node *n, const Node *m)
Least common ancestor of n and m.
Definition nest.cpp:107
auto muts() const
Definition nest.h:234
const Node * root() const
Definition nest.h:224
bool contains(const Def *def) const
Definition nest.h:226
const Nest::Node * smart(Def *curr, const Def *)
Definition schedule.cpp:75
fe::Vector< Def * > Schedule
Definition schedule.h:79
const Nest::Node * late(Def *curr, const Def *)
Definition schedule.cpp:54
const Uses & uses(const Def *def) const
Definition schedule.h:63
static Schedule schedule(const Nest &)
Definition schedule.cpp:121
World & world()
Definition schedule.h:60
const Nest & nest() const
Definition schedule.h:61
const Nest::Node * early(const Def *)
Definition schedule.cpp:38
Scheduler()=default
A variable introduced by a binder (mutable).
Definition def.h:825
const fe::Log & log() const
Log via log().e("...", args) etc.; owned by the Driver.
Definition world.cpp:129
Definition ast.h:16
GIDSet< Def * > MutSet
Definition def.h:101
static void post_order(const Nest &nest, const Nest::Node *node, Scheduler::Schedule &res, MutSet &done)
Definition schedule.cpp:101
auto nodes() const
Definition nest.h:65