Thorin 1.9.0
The Higher ORder INtermediate representation
Loading...
Searching...
No Matches
schedule.cpp
Go to the documentation of this file.
2
3#include <queue>
4
5#include "thorin/world.h"
6
11
12namespace thorin {
13
15 : scope_(&s)
16 , cfg_(&scope().f_cfg())
17 , domtree_(&cfg().domtree()) {
18 std::queue<const Def*> queue;
19 DefSet done;
20
21 auto enqueue = [&](const Def* def, size_t i, const Def* op) {
22 if (scope().bound(op)) {
23 assert_emplace(def2uses_[op], def, i);
24 if (auto [_, ins] = done.emplace(op); ins) queue.push(op);
25 }
26 };
27
28 for (auto n : cfg().reverse_post_order()) {
29 queue.push(n->mut());
30 assert_emplace(done, n->mut());
31 }
32
33 while (!queue.empty()) {
34 auto def = queue.front();
35 queue.pop();
36
37 if (!def->is_set()) continue;
38
39 for (size_t i = 0, e = def->num_ops(); i != e; ++i) {
40 // all reachable muts have already been registered above
41 // NOTE we might still see references to unreachable muts in the schedule
42 if (!def->op(i)->isa_mut()) enqueue(def, i, def->op(i));
43 }
44
45 if (!def->type()->isa_mut()) enqueue(def, -1, def->type());
46 }
47}
48
49Def* Scheduler::early(const Def* def) {
50 if (auto i = early_.find(def); i != early_.end()) return i->second;
51 if (def->dep_const() || !scope().bound(def)) return early_[def] = scope().entry();
52 if (auto var = def->isa<Var>()) return early_[def] = var->mut();
53
54 auto result = scope().entry();
55 for (auto op : def->extended_ops()) {
56 if (!op->isa_mut() && def2uses_.find(op) != def2uses_.end()) {
57 auto mut = early(op);
58 if (domtree().depth(cfg(mut)) > domtree().depth(cfg(result))) result = mut;
59 }
60 }
61
62 return early_[def] = result;
63}
64
65Def* Scheduler::late(const Def* def) {
66 if (auto i = late_.find(def); i != late_.end()) return i->second;
67 if (def->dep_const() || !scope().bound(def)) return early_[def] = scope().entry();
68
69 Def* result = nullptr;
70 if (auto mut = def->isa_mut()) {
71 result = mut;
72 } else if (auto var = def->isa<Var>()) {
73 result = var->mut();
74 } else {
75 for (auto use : uses(def)) {
76 auto mut = late(use);
77 result = result ? domtree().least_common_ancestor(cfg(result), cfg(mut))->mut() : mut;
78 }
79 }
80
81 return late_[def] = result;
82}
83
84Def* Scheduler::smart(const Def* def) {
85 if (auto i = smart_.find(def); i != smart_.end()) return i->second;
86
87 auto e = cfg(early(def));
88 auto l = cfg(late(def));
89 auto s = l;
90
91 int depth = cfg().looptree()[l]->depth();
92 for (auto i = l; i != e;) {
93 auto idom = domtree().idom(i);
94 assert(i != idom);
95 i = idom;
96
97 if (i == nullptr) {
98 scope_->world().WLOG("this should never occur - don't know where to put {}", def);
99 s = l;
100 break;
101 }
102
103 if (int cur_depth = cfg().looptree()[i]->depth(); cur_depth < depth) {
104 s = i;
105 depth = cur_depth;
106 }
107 }
108
109 return smart_[def] = s->mut();
110}
111
113 // until we have sth better simply use the RPO of the CFG
114 Schedule result;
115 for (auto n : scope.f_cfg().reverse_post_order()) result.emplace_back(n->mut());
116
117 return result;
118}
119
120} // namespace thorin
const LoopTree< forward > & looptree() const
Definition cfg.cpp:181
auto reverse_post_order() const
Definition cfg.h:139
Def * mut() const
Definition cfg.h:34
Base class for all Defs.
Definition def.h:222
Defs extended_ops() const
Definition def.cpp:447
bool is_set() const
Yields true if empty or the last op is set.
Definition def.cpp:315
const Def * op(size_t i) const
Definition def.h:269
size_t num_ops() const
Definition def.h:270
const Def * type() const
Yields the raw type of this Def, i.e. maybe nullptr.
Definition def.h:248
T * isa_mut() const
If this is *mut*able, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:449
bool dep_const() const
Definition def.h:338
const CFNode * idom(const CFNode *n) const
Definition domtree.h:29
const CFNode * least_common_ancestor(const CFNode *i, const CFNode *j) const
Returns the least common ancestor of i and j.
Definition domtree.cpp:45
const Uses & uses(const Def *def) const
Definition schedule.h:30
const Scope & scope() const
Definition schedule.h:26
Def * smart(const Def *)
Definition schedule.cpp:84
Def * late(const Def *)
Definition schedule.cpp:65
std::vector< Def * > Schedule
Definition schedule.h:47
const F_CFG & cfg() const
Definition schedule.h:27
const DomTree & domtree() const
Definition schedule.h:29
Def * early(const Def *)
Definition schedule.cpp:49
static Schedule schedule(const Scope &)
Definition schedule.cpp:112
Scheduler()=default
A Scope represents a region of Defs that are live from the view of an entry's Var.
Definition scope.h:22
const F_CFG & f_cfg() const
Definition scope.cpp:87
World & world() const
Definition scope.h:32
Def * entry() const
Definition scope.h:33
bool bound(const Def *def) const
Definition scope.h:40
Definition cfg.h:11
GIDSet< const Def * > DefSet
Definition def.h:60
auto assert_emplace(C &container, Args &&... args)
Invokes emplace on container, asserts that insertion actually happened, and returns the iterator.
Definition util.h:102