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 for (auto mut : nest.muts())
22 if (mut) queue.push(mut);
23
24 while (!queue.empty()) {
25 auto def = queue.pop();
26
27 if (!def->is_set()) continue;
28
29 for (size_t i = 0, e = def->num_ops(); i != e; ++i) {
30 // all reachable muts have already been registered above
31 // NOTE we might still see references to unreachable muts in the schedule
32 if (!def->op(i)->isa_mut()) enqueue(def, i, def->op(i));
33 }
34
35 if (!def->type()->isa_mut()) enqueue(def, -1, def->type());
36 }
37}
38
39const Nest::Node* Scheduler::early(const Def* def) {
40 if (auto n = fe::lookup(early_, def)) return n;
41 if (def->is_closed() || !nest().contains(def)) return early_[def] = nest().root();
42 if (auto var = def->isa<Var>()) return early_[def] = nest()[var->binder()];
43
44 auto result = nest().root();
45 for (auto op : def->deps()) {
46 if (!op->isa_mut() && nest().contains(op)) {
47 auto node = early(op);
48 if (node->level() > result->level()) result = node;
49 }
50 }
51
52 return early_[def] = result;
53}
54
55const Nest::Node* Scheduler::late(Def* curr_mut, const Def* def) {
56 if (auto n = fe::lookup(late_, def)) return n;
57 if (def->is_closed() || !nest().contains(def)) return late_[def] = nest().root();
58
59 const Nest::Node* result = nullptr;
60 if (auto mut = def->isa_mut()) {
61 result = nest()[mut];
62 } else if (auto var = def->isa<Var>()) {
63 result = nest()[var->binder()];
64 } else {
65 for (auto use : uses(def)) {
66 auto mut = late(curr_mut, use);
67 result = result ? Nest::lca(result, mut) : mut;
68 }
69 }
70
71 if (!result) result = nest()[curr_mut];
72
73 return late_[def] = result;
74}
75
76const Nest::Node* Scheduler::smart(Def* curr_mut, const Def* def) {
77 if (auto n = fe::lookup(smart_, def)) return n;
78
79 auto e = early(def);
80 auto l = late(curr_mut, def);
81 auto s = l;
82
83 int depth = l->loop_depth();
84 for (auto i = l; i != e;) {
85 i = i->inest();
86
87 if (i == nullptr) {
88 world().log().e("no place found for {}", def);
89 s = l;
90 break;
91 }
92
93 if (int curr_depth = i->loop_depth(); curr_depth < depth) {
94 s = i;
95 depth = curr_depth;
96 }
97 }
98
99 return smart_[def] = s;
100}
101
102// until we have sth better ...
104 auto in_nest = [&nest](Def* mut) { return nest[mut] != nullptr; };
105 auto done = MutSet();
106 auto schedule = Schedule();
107
108 // The mut of a virtual root is a nullptr.
109 if (auto root = nest.root()->mut())
110 post_order(root, done, schedule, in_nest, in_nest);
111 else
112 for (auto mut : nest.root()->children().muts())
113 post_order(mut, done, schedule, in_nest, in_nest);
114
115 std::ranges::reverse(schedule); // post-order → reverse post-order
116 return schedule;
117}
118
119} // namespace mim
Base class for all Defs.
Definition def.h:289
bool is_set() const
Definition def.h:396
Defs deps() const noexcept
Definition def.cpp:486
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:588
const Def * op(size_t i) const noexcept
Definition def.h:377
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.h:1119
bool is_closed() const
Same as !has_free_vars().
Definition def.cpp:357
constexpr size_t num_ops() const noexcept
Definition def.h:378
Def * mut() const
The mutable capsulated in this Node or nullptr, if it's a virtual root comprising several Nodes.
Definition nest.h:39
const Children & children() const
Definition nest.h:82
Builds a nesting tree for all mutables/binders.
Definition nest.h:25
static const Node * lca(const Node *n, const Node *m)
Least common ancestor of n and m.
Definition nest.cpp:174
auto muts() const
Definition nest.h:204
const Node * root() const
Definition nest.h:195
bool contains(const Def *def) const
Definition nest.h:197
Def * root() const
Definition schedule.h:61
const Nest::Node * smart(Def *curr, const Def *)
Definition schedule.cpp:76
fe::Vector< Def * > Schedule
Definition schedule.h:78
const Nest::Node * late(Def *curr, const Def *)
Definition schedule.cpp:55
const Uses & uses(const Def *def) const
Definition schedule.h:62
static Schedule schedule(const Nest &)
Definition schedule.cpp:103
World & world()
Definition schedule.h:59
const Nest & nest() const
Definition schedule.h:60
const Nest::Node * early(const Def *)
Definition schedule.cpp:39
Scheduler()=default
A variable introduced by a binder (mutable).
Definition def.h:857
const fe::Log & log() const
Log via log().e("...", args) etc.; owned by the Driver.
Definition world.cpp:224
Definition ast.h:16
void post_order(Def *mut, MutSet &done, fe::Vector< Def * > &res, MutPred auto descend, MutPred auto collect)
Appends the mutables reachable from mut via Def::deps / Def::local_muts to res in post-order: callees...
Definition def.h:1155
GIDSet< Def * > MutSet
Definition def.h:106
auto muts() const
Definition nest.h:56