Skip to content

Commit

Permalink
Remove recursion in schedule, hoist_enters and importer.
Browse files Browse the repository at this point in the history
Using recursion in these passes can lead to stack overflows if large
programs are being compiled.
  • Loading branch information
m-kurtenacker committed Oct 4, 2022
1 parent abe617c commit 2c0ce6c
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 20 deletions.
67 changes: 62 additions & 5 deletions src/thorin/analyses/schedule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "thorin/analyses/looptree.h"
#include "thorin/analyses/scope.h"

#include <stack>

namespace thorin {

Scheduler::Scheduler(const Scope& s)
Expand Down Expand Up @@ -44,37 +46,92 @@ Scheduler::Scheduler(const Scope& s)
}
}

Continuation* Scheduler::early(const Def* def) {
std::stack<const Def*> early_todo;

Continuation* Scheduler::early(const Def * def) {
if (auto cont = early_.lookup(def)) return *cont;
if (auto param = def->isa<Param>()) return early_[def] = param->continuation();

early_todo.push(def);
Continuation *return_cont = nullptr;
while (!early_todo.empty()) {
return_cont = early_intern();
}
assert(return_cont);
return return_cont;
}

Continuation* Scheduler::early_intern() {
const Def* def = early_todo.top();

if (auto cont = early_.lookup(def)) {
early_todo.pop();
return *cont;
}
if (auto param = def->isa<Param>()) {
early_todo.pop();
return early_[def] = param->continuation();
}

auto result = scope().entry();
for (auto op : def->as_structural()->ops()) {
if (!op->isa_nom<Continuation>() && def2uses_.find(op) != def2uses_.end()) {
auto cont = early(op);
Continuation *cont;
if (early_.lookup(op)) {
cont = *early_.lookup(op);
} else {
early_todo.push(op);
return nullptr;
}
if (domtree().depth(cfg(cont)) > domtree().depth(cfg(result)))
result = cont;
}
}

early_todo.pop();
return early_[def] = result;
}

Continuation* Scheduler::late(const Def* def) {
std::stack<const Def*> late_todo;

Continuation* Scheduler::late(const Def * def) {
if (auto cont = late_.lookup(def)) return *cont;

late_todo.push(def);
Continuation *return_cont = nullptr;
while (!late_todo.empty()) {
return_cont = late_intern();
}
assert(return_cont);
return return_cont;
}

Continuation* Scheduler::late_intern() {
const Def* def = late_todo.top();

if (auto cont = late_.lookup(def)) {
late_todo.pop();
return *cont;
}

Continuation* result = nullptr;
if (auto continuation = def->isa_nom<Continuation>()) {
result = continuation;
} else if (auto param = def->isa<Param>()) {
result = param->continuation();
} else {
for (auto use : uses(def)) {
auto cont = late(use);
Continuation* cont;
if (late_.lookup(use)) {
cont = *late_.lookup(use);
} else {
late_todo.push(use);
return nullptr;
}
result = result ? domtree().least_common_ancestor(cfg(result), cfg(cont))->continuation() : cont;
}
}

late_todo.pop();
return late_[def] = result;
}

Expand Down
3 changes: 3 additions & 0 deletions src/thorin/analyses/schedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class Scheduler {
DefMap<Continuation*> late_;
DefMap<Continuation*> smart_;
DefMap<Uses> def2uses_;

Continuation* early_intern();
Continuation* late_intern();
};

using Schedule = std::vector<Continuation*>;
Expand Down
17 changes: 14 additions & 3 deletions src/thorin/transform/hoist_enters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
#include "thorin/analyses/scope.h"
#include "thorin/analyses/verify.h"

#include <stack>

namespace thorin {

std::stack<const Def*> todo;

static void find_enters(std::deque<const Enter*>& enters, const Def* def) {
if (auto enter = def->isa<Enter>())
enters.push_back(enter);
Expand All @@ -15,13 +19,20 @@ static void find_enters(std::deque<const Enter*>& enters, const Def* def) {

for (auto use : def->uses()) {
if (auto memop = use->isa<MemOp>())
find_enters(enters, memop);
todo.push(memop);
}
}

static void find_enters(std::deque<const Enter*>& enters, Continuation* continuation) {
if (auto mem_param = continuation->mem_param())
find_enters(enters, mem_param);
if (auto mem_param = continuation->mem_param()) {
todo.push(mem_param);
while (!todo.empty()) {
auto next_item = todo.top();
todo.pop();

find_enters(enters, next_item);
}
}
}

static void hoist_enters(const Scope& scope) {
Expand Down
108 changes: 97 additions & 11 deletions src/thorin/transform/importer.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
#include "thorin/transform/importer.h"

#include <set>
#include <stack>
#include <utility>

namespace thorin {

const Type* Importer::import(const Type* otype) {
const Type* Importer::import_type(const Type* otype) {
if (auto ntype = type_old2new_.lookup(otype)) {
assert(&(*ntype)->table() == &world_);
return *ntype;
Expand All @@ -13,13 +17,13 @@ const Type* Importer::import(const Type* otype) {
auto ntype = nominal_type->stub(world_);
type_old2new_[otype] = ntype;
for (size_t i = 0; i != size; ++i)
ntype->set(i, import(otype->op(i)));
ntype->set(i, import_type(otype->op(i)));
return ntype;
}

Array<const Type*> nops(size);
for (size_t i = 0; i != size; ++i)
nops[i] = import(otype->op(i));
nops[i] = import_type(otype->op(i));

auto ntype = otype->rebuild(world_, nops);
type_old2new_[otype] = ntype;
Expand All @@ -28,38 +32,108 @@ const Type* Importer::import(const Type* otype) {
return ntype;
}

std::stack<std::pair<const Def*, bool>> required_defs;
std::set<const Def *> analyzed_conts;

void enqueue(const Def* elem) {
if (elem->isa_nom<Continuation>()) {
if (analyzed_conts.find(elem) != analyzed_conts.end()) {
required_defs.push(std::pair(elem, false));
} else {
analyzed_conts.insert(elem);
required_defs.push(std::pair(elem, true));
}
} else {
required_defs.push(std::pair(elem, false));
}
}

const Def* Importer::import(const Def* odef) {
if (auto ndef = def_old2new_.lookup(odef)) {
assert(&(*ndef)->world() == &world_);
return *ndef;
}

auto ntype = import(odef->type());
assert(required_defs.empty());
enqueue(odef);

const Def* return_def = nullptr;
while (!required_defs.empty()) {
return_def = import_nonrecursive();
}

assert(return_def);
assert (return_def == def_old2new_.lookup(odef));

analyzed_conts.clear();

return return_def;
}

const Def* Importer::import_nonrecursive() {
const Def* odef = required_defs.top().first;
bool jump_to_analyze = required_defs.top().second;

Continuation* ncontinuation = nullptr;

if (auto ndef = def_old2new_.lookup(odef)) {
assert(&(*ndef)->world() == &world_);
if (odef->isa_nom<Continuation>()) {
if (!jump_to_analyze) {
required_defs.pop();
return *ndef;
}
ncontinuation = (*ndef)->as_nom<Continuation>();
} else {
required_defs.pop();
return *ndef;
}
}

auto ntype = import_type(odef->type());

if (auto oparam = odef->isa<Param>()) {
if (!def_old2new_.lookup(oparam->continuation())) {
enqueue(oparam->continuation());
return nullptr;
}
import(oparam->continuation())->as_nom<Continuation>();
auto nparam = def_old2new_[oparam];
assert(nparam && &nparam->world() == &world_);
return nparam;
required_defs.pop();
return def_old2new_[oparam] = nparam;
}

if (auto ofilter = odef->isa<Filter>()) {
Array<const Def*> new_conditions(ofilter->num_ops());

bool unfinished_business = false;
for (size_t i = 0, e = ofilter->size(); i != e; ++i)
if (!def_old2new_.lookup(ofilter->condition(i))) {
enqueue(ofilter->condition(i));
unfinished_business = true;
}
if (unfinished_business)
return nullptr;

for (size_t i = 0, e = ofilter->size(); i != e; ++i)
new_conditions[i] = import(ofilter->condition(i));
auto nfilter = world().filter(new_conditions, ofilter->debug());
return nfilter;
required_defs.pop();
return def_old2new_[ofilter] = nfilter;
}

Continuation* ncontinuation = nullptr;
if (auto ocontinuation = odef->isa_nom<Continuation>()) { // create stub in new world
if (auto ocontinuation = odef->isa_nom<Continuation>(); ocontinuation && !ncontinuation) { // create stub in new world
assert(!ocontinuation->dead_);
// TODO maybe we want to deal with intrinsics in a more streamlined way
if (ocontinuation == ocontinuation->world().branch())
if (ocontinuation == ocontinuation->world().branch()) {
required_defs.pop();
return def_old2new_[ocontinuation] = world().branch();
if (ocontinuation == ocontinuation->world().end_scope())
} else if (ocontinuation == ocontinuation->world().end_scope()) {
required_defs.pop();
return def_old2new_[ocontinuation] = world().end_scope();
auto npi = import(ocontinuation->type())->as<FnType>();
}
auto npi = import_type(ocontinuation->type())->as<FnType>();
ncontinuation = world().continuation(npi, ocontinuation->attributes(), ocontinuation->debug_history());
assert(&ncontinuation->world() == &world());
assert(&npi->table() == &world());
Expand All @@ -76,6 +150,16 @@ const Def* Importer::import(const Def* odef) {

size_t size = odef->num_ops();
Array<const Def*> nops(size);

bool unfinished = false;
for (size_t i = 0; i != size; ++i)
if (!def_old2new_.lookup(odef->op(i))) {
enqueue(odef->op(i));
unfinished = true;
}
if (unfinished)
return nullptr;

for (size_t i = 0; i != size; ++i) {
assert(odef->op(i) != odef);
nops[i] = import(odef->op(i));
Expand All @@ -85,6 +169,7 @@ const Def* Importer::import(const Def* odef) {
if (odef->isa_structural()) {
auto ndef = odef->rebuild(world(), ntype, nops);
todo_ |= odef->tag() != ndef->tag();
required_defs.pop();
return def_old2new_[odef] = ndef;
}

Expand All @@ -94,6 +179,7 @@ const Def* Importer::import(const Def* odef) {
ncontinuation->set_body(napp);
ncontinuation->set_filter(nops[1]->as<Filter>());
ncontinuation->verify();
required_defs.pop();
return ncontinuation;
}

Expand Down
5 changes: 4 additions & 1 deletion src/thorin/transform/importer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ class Importer {
}

World& world() { return world_; }
const Type* import(const Type*);
const Type* import_type(const Type*);
const Def* import(const Def*);
bool todo() const { return todo_; }

private:
const Def* import_nonrecursive();

public:
Type2Type type_old2new_;
Def2Def def_old2new_;
Expand Down

0 comments on commit 2c0ce6c

Please sign in to comment.