Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor plugin system #141

Open
wants to merge 4 commits into
base: plugins
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/thorin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ set(THORIN_SOURCES
type.h
world.cpp
world.h
plugin.cpp
plugin.h
plugin_helpers.h
analyses/cfg.cpp
analyses/cfg.h
analyses/domfrontier.cpp
Expand Down
78 changes: 78 additions & 0 deletions src/thorin/plugin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include "thorin/world.h"

#ifdef _WIN32
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <execinfo.h>
#include <dlfcn.h>
#endif

namespace thorin {
[[nodiscard]] static void* load_plugin_module(const char* plugin_name) {
#ifdef _WIN32
return LoadLibraryA(plugin_name);
#else
return dlopen(plugin_name, RTLD_LAZY | RTLD_GLOBAL);
#endif
}

static bool unload_plugin_module(void* plugin_module) {
#ifdef _WIN32
return FreeLibrary(static_cast<HMODULE>(plugin_module)) == TRUE;
#else
return dlclose(plugin_module) == 0;
#endif
}

template <typename T>
[[nodiscard]] static T* lookup_plugin_function(void* plugin_module, const char* function_name) {
#ifdef _WIN32
return reinterpret_cast<T*>(GetProcAddress(static_cast<HMODULE>(plugin_module), function_name));
#else
return reinterpret_cast<T*>(dlsym(plugin_module, function_name));
#endif
}

bool World::load_plugin(const char* plugin_name) {
void* module = load_plugin_module(plugin_name);

if (!module) {
ELOG("failed to load plugin {}", plugin_name);
return false;
}

if (auto init = lookup_plugin_function<plugin_init_func_t>(module, "init")) {
if (!init()) {
ELOG("failed to initialize plugin {}", plugin_name);
unload_plugin_module(module);
return false;
}
} else {
ILOG("plugin {} did not supply an init function", plugin_name);
}

data_.plugin_modules_.push_back(module);
return true;
}

unique_plugin_intrinsic World::load_plugin_intrinsic(const char* function_name) const {
for (auto plugin_module : data_.plugin_modules_) {
if (auto create_intrinsic = lookup_plugin_function<plugin_intrinsic_create_func_t>(plugin_module, function_name))
return unique_plugin_intrinsic(create_intrinsic());
}

return nullptr;
}

void World::link_plugin_intrinsic(Continuation* cont) {
auto intrinsic = load_plugin_intrinsic(cont->name().c_str());

if (!intrinsic)
error(cont->loc(), "failed to link plugin intrinsic {}", cont->name());

cont->attributes().intrinsic = Intrinsic::Plugin;
data_.plugin_intrinsics_.push_back({ cont, std::move(intrinsic) });
}
}
39 changes: 39 additions & 0 deletions src/thorin/plugin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#ifndef THORIN_PLUGIN_H
#define THORIN_PLUGIN_H

#include <memory>

namespace thorin {
class Def;
class Continuation;
class App;
class World;

struct plugin_intrinsic {
virtual void transform(World* world, const Continuation* cont) = 0;
virtual void destroy() = 0;

protected:
plugin_intrinsic() = default;
plugin_intrinsic(const plugin_intrinsic&) = default;
plugin_intrinsic(plugin_intrinsic&&) = default;
plugin_intrinsic& operator =(const plugin_intrinsic&) = default;
plugin_intrinsic& operator =(plugin_intrinsic&&) = default;
~plugin_intrinsic() = default;
};

struct plugin_deleter {
void operator ()(plugin_intrinsic* ptr) const {
ptr->destroy();
}
};

using unique_plugin_intrinsic = std::unique_ptr<plugin_intrinsic, plugin_deleter>;

extern "C" {
using plugin_init_func_t = bool();
using plugin_intrinsic_create_func_t = plugin_intrinsic*();
}
}

#endif
42 changes: 42 additions & 0 deletions src/thorin/plugin_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef THORIN_PLUGIN_HELPERS_H
#define THORIN_PLUGIN_HELPERS_H

#include "plugin.h"
#include "continuation.h"
#include "world.h"

namespace thorin {
template <typename Plugin>
class plugin_intrinsic_app_wrapper : public virtual plugin_intrinsic {
virtual const Def* transform(World* world, const App* app) = 0;

void transform(World* world, const Continuation* cont) final override {
for (auto use : cont->copy_uses()) {
if (!use.def()->isa<App>())
continue;

auto app = use.def()->as<App>();

// transform plugin(mem, args, ret) to ret(mem, func(args))

auto output = static_cast<Plugin*>(this)->transform(world, app);

auto app_rebuild =
output ? app->rebuild(*world, world->bottom_type(), {app->arg(app->num_args() - 1), app->arg(0), output})
: app->rebuild(*world, world->bottom_type(), {app->arg(app->num_args() - 1), app->arg(0)});

app->replace_uses(app_rebuild);
}
}

protected:
plugin_intrinsic_app_wrapper() = default;
plugin_intrinsic_app_wrapper(const plugin_intrinsic_app_wrapper&) = default;
plugin_intrinsic_app_wrapper(plugin_intrinsic_app_wrapper&&) = default;
plugin_intrinsic_app_wrapper& operator =(const plugin_intrinsic_app_wrapper&) = default;
plugin_intrinsic_app_wrapper& operator =(plugin_intrinsic_app_wrapper&&) = default;
~plugin_intrinsic_app_wrapper() = default;
};
}

#endif
50 changes: 27 additions & 23 deletions src/thorin/transform/cleanup_world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ class Cleaner {
: world_(world)
{}

World& world() { return world_; }
void cleanup();
void eliminate_tail_rec();
void eta_conversion();
Expand Down Expand Up @@ -49,7 +48,7 @@ void Cleaner::eliminate_tail_rec() {
} else if (use->isa_nom<Param>())
continue; // ignore params

world().ELOG("non-recursive usage of {} index:{} use:{}", scope.entry()->name(), use.index(), use.def()->to_string());
world_.ELOG("non-recursive usage of {} index:{} use:{}", scope.entry()->name(), use.index(), use.def()->to_string());
only_tail_calls = false;
break;
}
Expand Down Expand Up @@ -88,7 +87,7 @@ void Cleaner::eliminate_tail_rec() {
}

if (new_args.size() != n) {
world().DLOG("tail recursive: {}", entry);
world_.DLOG("tail recursive: {}", entry);
auto dropped = drop(scope, args);

entry->jump(dropped, new_args);
Expand All @@ -102,7 +101,7 @@ void Cleaner::eliminate_tail_rec() {
void Cleaner::eta_conversion() {
for (bool todo = true; todo;) {
todo = false;
for (auto def : world().copy_defs()) {
for (auto def : world_.copy_defs()) {
auto continuation = def->isa_nom<Continuation>();
if (!continuation || !continuation->has_body()) continue;

Expand All @@ -111,7 +110,7 @@ void Cleaner::eta_conversion() {
auto body = continuation->body();
if (callee == continuation) break;

if (callee->has_body() && !world().is_external(callee) && callee->can_be_inlined()) {
if (callee->has_body() && !world_.is_external(callee) && callee->can_be_inlined()) {
auto callee_body = callee->body();
for (size_t i = 0, e = body->num_args(); i != e; ++i)
callee->param(i)->replace_uses(body->arg(i));
Expand All @@ -131,7 +130,7 @@ void Cleaner::eta_conversion() {
// try to subsume continuations which call a parameter
// (that is free within that continuation) with that parameter
if (auto param = body->callee()->isa<Param>()) {
if (param->continuation() == continuation || world().is_external(continuation))
if (param->continuation() == continuation || world_.is_external(continuation))
continue;

if (body->args() == continuation->params_as_defs()) {
Expand Down Expand Up @@ -181,11 +180,11 @@ void Cleaner::eta_conversion() {

void Cleaner::eliminate_params() {
// TODO
for (auto ocontinuation : world().copy_continuations()) {
for (auto ocontinuation : world_.copy_continuations()) {
std::vector<size_t> proxy_idx;
std::vector<size_t> param_idx;

if (ocontinuation->has_body() && !world().is_external(ocontinuation)) {
if (ocontinuation->has_body() && !world_.is_external(ocontinuation)) {
auto obody = ocontinuation->body();
for (auto use : ocontinuation->uses()) {
if (use.index() != 0 || !use->isa_nom<Continuation>())
Expand All @@ -201,8 +200,8 @@ void Cleaner::eliminate_params() {
}

if (!proxy_idx.empty()) {
auto ncontinuation = world().continuation(
world().fn_type(ocontinuation->type()->ops().cut(proxy_idx)),
auto ncontinuation = world_.continuation(
world_.fn_type(ocontinuation->type()->ops().cut(proxy_idx)),
ocontinuation->attributes(), ocontinuation->debug_history());
size_t j = 0;
for (auto i : param_idx) {
Expand Down Expand Up @@ -236,14 +235,19 @@ void Cleaner::rebuild() {
importer.type_old2new_.rehash(world_.types().capacity());
importer.def_old2new_.rehash(world_.defs().capacity());

for (auto&& [_, cont] : world().externals()) {
for (auto&& [_, cont] : world_.externals()) {
if (cont->is_exported())
importer.import(cont);
}

for (auto&& [cont, func] : world_.data_.plugin_intrinsics_) {
if (cont->num_uses() > 0)
importer.import_plugin_intrinsic(cont, std::move(func));
}

swap(importer.world(), world_);

// verify(world());
// verify(world_);

todo_ |= importer.todo();
}
Expand All @@ -262,20 +266,20 @@ void Cleaner::verify_closedness() {
}
};

for (auto def : world().defs())
for (auto def : world_.defs())
check(def);
}

void Cleaner::within(const Def* def) {
if (def->isa<Param>()) return; // TODO remove once Params are within World's sea of nodes
assert(world().types().contains(def->type()));
assert_unused(world().defs().contains(def));
assert(world_.types().contains(def->type()));
assert_unused(world_.defs().contains(def));
}

void Cleaner::clean_pe_info(std::queue<Continuation*> queue, Continuation* cur) {
assert(cur->has_body());
auto body = cur->body();
assert(body->arg(1)->type() == world().ptr_type(world().indefinite_array_type(world().type_pu8())));
assert(body->arg(1)->type() == world_.ptr_type(world_.indefinite_array_type(world_.type_pu8())));
auto next = body->arg(3);
auto msg = body->arg(1)->as<Bitcast>()->from()->as<Global>()->init()->as<DefiniteArray>();

Expand All @@ -296,7 +300,7 @@ void Cleaner::clean_pe_infos() {
queue.push(continuation);
};

for (auto&& [_, cont] : world().externals())
for (auto&& [_, cont] : world_.externals())
if (cont->has_body()) enqueue(cont);

while (!queue.empty()) {
Expand Down Expand Up @@ -326,9 +330,9 @@ void Cleaner::cleanup_fix_point() {
eta_conversion();
eliminate_params();
rebuild(); // resolve replaced defs before going to resolve_loads
todo_ |= resolve_loads(world());
todo_ |= resolve_loads(world_);
rebuild();
if (!world().is_pe_done())
if (!world_.is_pe_done())
todo_ |= partial_evaluation(world_);
else
clean_pe_infos();
Expand All @@ -339,9 +343,9 @@ void Cleaner::cleanup() {
world_.VLOG("start cleanup");
cleanup_fix_point();

if (!world().is_pe_done()) {
world().mark_pe_done();
for (auto def : world().defs()) {
if (!world_.is_pe_done()) {
world_.mark_pe_done();
for (auto def : world_.defs()) {
if (auto cont = def->isa_nom<Continuation>())
cont->destroy_filter();
}
Expand All @@ -353,7 +357,7 @@ void Cleaner::cleanup() {
world_.VLOG("end cleanup");
#if THORIN_ENABLE_CHECKS
verify_closedness();
debug_verify(world());
debug_verify(world_);
#endif
}

Expand Down
Loading