From 82ae27ea970c81c059c8d814368b6c8dbab667c6 Mon Sep 17 00:00:00 2001 From: Michael Kenzel Date: Wed, 5 Jul 2023 22:32:35 +0200 Subject: [PATCH 1/4] cleanup cleanup --- src/thorin/transform/cleanup_world.cpp | 45 +++++++++++++------------- src/thorin/transform/importer.cpp | 20 ++++++------ 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/thorin/transform/cleanup_world.cpp b/src/thorin/transform/cleanup_world.cpp index 2748d25d9..00173c5e7 100644 --- a/src/thorin/transform/cleanup_world.cpp +++ b/src/thorin/transform/cleanup_world.cpp @@ -18,7 +18,6 @@ class Cleaner { : world_(world) {} - World& world() { return world_; } void cleanup(); void eliminate_tail_rec(); void eta_conversion(); @@ -49,7 +48,7 @@ void Cleaner::eliminate_tail_rec() { } else if (use->isa_nom()) 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; } @@ -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); @@ -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(); if (!continuation || !continuation->has_body()) continue; @@ -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)); @@ -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()) { - if (param->continuation() == continuation || world().is_external(continuation)) + if (param->continuation() == continuation || world_.is_external(continuation)) continue; if (body->args() == continuation->params_as_defs()) { @@ -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 proxy_idx; std::vector 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()) @@ -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) { @@ -236,14 +235,14 @@ 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); } swap(importer.world(), world_); - // verify(world()); + // verify(world_); todo_ |= importer.todo(); } @@ -262,20 +261,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()) 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 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()->from()->as()->init()->as(); @@ -296,7 +295,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()) { @@ -326,9 +325,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(); @@ -339,9 +338,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()) cont->destroy_filter(); } @@ -353,7 +352,7 @@ void Cleaner::cleanup() { world_.VLOG("end cleanup"); #if THORIN_ENABLE_CHECKS verify_closedness(); - debug_verify(world()); + debug_verify(world_); #endif } diff --git a/src/thorin/transform/importer.cpp b/src/thorin/transform/importer.cpp index af7f5c1c8..4455b2656 100644 --- a/src/thorin/transform/importer.cpp +++ b/src/thorin/transform/importer.cpp @@ -47,7 +47,7 @@ const Def* Importer::import(const Def* odef) { Array new_conditions(ofilter->num_ops()); 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()); + auto nfilter = world_.filter(new_conditions, ofilter->debug()); return nfilter; } @@ -56,13 +56,13 @@ const Def* Importer::import(const Def* odef) { assert(!ocontinuation->dead_); // TODO maybe we want to deal with intrinsics in a more streamlined way if (ocontinuation == ocontinuation->world().branch()) - return def_old2new_[ocontinuation] = world().branch(); + return def_old2new_[ocontinuation] = world_.branch(); if (ocontinuation == ocontinuation->world().end_scope()) - return def_old2new_[ocontinuation] = world().end_scope(); + return def_old2new_[ocontinuation] = world_.end_scope(); auto npi = import(ocontinuation->type())->as(); - ncontinuation = world().continuation(npi, ocontinuation->attributes(), ocontinuation->debug_history()); - assert(&ncontinuation->world() == &world()); - assert(&npi->table() == &world()); + ncontinuation = world_.continuation(npi, ocontinuation->attributes(), ocontinuation->debug_history()); + assert(&ncontinuation->world() == &world_); + assert(&npi->table() == &world_); for (size_t i = 0, e = ocontinuation->num_params(); i != e; ++i) { ncontinuation->param(i)->set_name(ocontinuation->param(i)->debug_history().name); def_old2new_[ocontinuation->param(i)] = ncontinuation->param(i); @@ -74,7 +74,7 @@ const Def* Importer::import(const Def* odef) { def_old2new_[ocontinuation] = ncontinuation; if (ocontinuation->is_external()) - world().make_external(ncontinuation); + world_.make_external(ncontinuation); } size_t size = odef->num_ops(); @@ -82,16 +82,16 @@ const Def* Importer::import(const Def* odef) { for (size_t i = 0; i != size; ++i) { assert(odef->op(i) != odef); nops[i] = import(odef->op(i)); - assert(&nops[i]->world() == &world()); + assert(&nops[i]->world() == &world_); } if (odef->isa_structural()) { - auto ndef = odef->rebuild(world(), ntype, nops); + auto ndef = odef->rebuild(world_, ntype, nops); todo_ |= odef->tag() != ndef->tag(); return def_old2new_[odef] = ndef; } - assert(ncontinuation && &ncontinuation->world() == &world()); + assert(ncontinuation && &ncontinuation->world() == &world_); auto napp = nops[0]->isa(); if (napp) ncontinuation->set_body(napp); From cc9f8a9dc92316d28ec9b1b118c6c7c3b8adc257 Mon Sep 17 00:00:00 2001 From: Michael Kenzel Date: Wed, 5 Jul 2023 22:41:28 +0200 Subject: [PATCH 2/4] refactor plugin system --- src/thorin/CMakeLists.txt | 2 + src/thorin/plugin.h | 39 ++++++++++++++ src/thorin/plugin_helpers.h | 42 +++++++++++++++ src/thorin/transform/cleanup_world.cpp | 5 ++ src/thorin/transform/importer.cpp | 8 +++ src/thorin/transform/importer.h | 1 + src/thorin/transform/plugin_execute.cpp | 72 ++----------------------- src/thorin/transform/plugin_execute.h | 4 +- src/thorin/world.cpp | 41 ++++++++++---- src/thorin/world.h | 19 ++++--- 10 files changed, 147 insertions(+), 86 deletions(-) create mode 100644 src/thorin/plugin.h create mode 100644 src/thorin/plugin_helpers.h diff --git a/src/thorin/CMakeLists.txt b/src/thorin/CMakeLists.txt index 16dbcb97f..7209d9cda 100644 --- a/src/thorin/CMakeLists.txt +++ b/src/thorin/CMakeLists.txt @@ -14,6 +14,8 @@ set(THORIN_SOURCES type.h world.cpp world.h + plugin.h + plugin_helpers.h analyses/cfg.cpp analyses/cfg.h analyses/domfrontier.cpp diff --git a/src/thorin/plugin.h b/src/thorin/plugin.h new file mode 100644 index 000000000..a4d8e0487 --- /dev/null +++ b/src/thorin/plugin.h @@ -0,0 +1,39 @@ +#ifndef THORIN_PLUGIN_H +#define THORIN_PLUGIN_H + +#include + +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; + + extern "C" { + using plugin_init_func_t = void(); + using plugin_intrinsic_create_func_t = plugin_intrinsic*(); + } +} + +#endif diff --git a/src/thorin/plugin_helpers.h b/src/thorin/plugin_helpers.h new file mode 100644 index 000000000..fa4e8fcd7 --- /dev/null +++ b/src/thorin/plugin_helpers.h @@ -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 + 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()) + continue; + + auto app = use.def()->as(); + + // transform plugin(mem, args, ret) to ret(mem, func(args)) + + auto output = static_cast(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 diff --git a/src/thorin/transform/cleanup_world.cpp b/src/thorin/transform/cleanup_world.cpp index 00173c5e7..46974e67a 100644 --- a/src/thorin/transform/cleanup_world.cpp +++ b/src/thorin/transform/cleanup_world.cpp @@ -240,6 +240,11 @@ void Cleaner::rebuild() { 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_); diff --git a/src/thorin/transform/importer.cpp b/src/thorin/transform/importer.cpp index 4455b2656..b956f58ce 100644 --- a/src/thorin/transform/importer.cpp +++ b/src/thorin/transform/importer.cpp @@ -100,4 +100,12 @@ const Def* Importer::import(const Def* odef) { return ncontinuation; } +void Importer::import_plugin_intrinsic(const Continuation* cont, unique_plugin_intrinsic func) { + if (auto ncont = def_old2new_.lookup(cont)) { + assert(&(*ncont)->world() == &world_); + assert((*ncont)->isa()); + world_.data_.plugin_intrinsics_.push_back({ (*ncont)->as(), std::move(func) }); + } +} + } diff --git a/src/thorin/transform/importer.h b/src/thorin/transform/importer.h index c34db9ef3..3861fba0e 100644 --- a/src/thorin/transform/importer.h +++ b/src/thorin/transform/importer.h @@ -22,6 +22,7 @@ class Importer { World& world() { return world_; } const Type* import(const Type*); const Def* import(const Def*); + void import_plugin_intrinsic(const Continuation* cont, unique_plugin_intrinsic impl); bool todo() const { return todo_; } public: diff --git a/src/thorin/transform/plugin_execute.cpp b/src/thorin/transform/plugin_execute.cpp index 054a7c41f..91a536bf4 100644 --- a/src/thorin/transform/plugin_execute.cpp +++ b/src/thorin/transform/plugin_execute.cpp @@ -3,77 +3,15 @@ #include "thorin/transform/partial_evaluation.h" #include "thorin/analyses/scope.h" -#include - namespace thorin { -void plugin_execute(World& world) { +void plugin_execute(World& world, std::vector intrinsics) { world.VLOG("start plugin_execute"); - std::vector plugin_intrinsics; - - while (true) { - plugin_intrinsics.clear(); - - for (auto def : world.defs()) { - auto cont = def->isa_nom(); - if (!cont) continue; - - if (cont->is_intrinsic() && cont->intrinsic() == Intrinsic::Plugin) { - plugin_intrinsics.push_back(cont); - } - } - - if (plugin_intrinsics.empty()) - break; - - sort(plugin_intrinsics.begin(), plugin_intrinsics.end(), [&](const Continuation* a, const Continuation* b) { - const Continuation* depends = b; - while (depends) { - depends = depends->attributes().depends; - if (a == depends) return true; - } - return false; - }); - - for (auto cont : plugin_intrinsics) { - auto plugin_function = world.search_plugin_function(cont->name().c_str()); - if (!plugin_function) { - world.ELOG("Plugin function not found for: {}", cont->name()); - continue; - } - - bool evaluated = false; - for (auto use : cont->copy_uses()) { - if (!use.def()->isa()) { - continue; - } - - auto app = use.def()->as(); - assert(app->callee() == cont); - - if (app->num_uses() == 0) { - continue; - } - - const Def* output = plugin_function(&world, app); - const Def* app_rebuild = nullptr; - if (output) { - app_rebuild = app->rebuild(world, world.bottom_type(), {app->arg(app->num_args() - 1), app->arg(0), output}); - } else { - app_rebuild = app->rebuild(world, world.bottom_type(), {app->arg(app->num_args() - 1), app->arg(0)}); - } - app->replace_uses(app_rebuild); - - //partial_evaluation(world); //TODO: Some form of cleanup would be advisable here. - evaluated = true; - } - - if (evaluated) - break; - } - - world.cleanup(); + // assume that dependents precede dependencies + while (!intrinsics.empty()) { + intrinsics.back().impl->transform(&world, intrinsics.back().cont); + intrinsics.pop_back(); } world.mark_pe_done(false); diff --git a/src/thorin/transform/plugin_execute.h b/src/thorin/transform/plugin_execute.h index 49cd9dec3..ea2c0e1af 100644 --- a/src/thorin/transform/plugin_execute.h +++ b/src/thorin/transform/plugin_execute.h @@ -1,9 +1,11 @@ #ifndef THORIN_TRANSFORM_PLUGIN_EXECUTE_H #define THORIN_TRANSFORM_PLUGIN_EXECUTE_H +#include "thorin/world.h" + namespace thorin { -void plugin_execute(World&); +void plugin_execute(World&, std::vector intrinsics); } diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index 62af0d519..da3ba4825 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -10,6 +10,7 @@ #endif #include +#include #ifdef _MSC_VER #include #else @@ -1302,9 +1303,9 @@ void World::opt() { RUN_PASS(flatten_tuples(*this)) RUN_PASS(clone_bodies(*this)) RUN_PASS(split_slots(*this)) - if (plugin_handles.size() > 0) { - RUN_PASS(plugin_execute(*this)); - RUN_PASS(cleanup()); + if (!data_.plugin_intrinsics_.empty()) { + RUN_PASS(plugin_execute(*this, std::move(data_.plugin_intrinsics_))); + // RUN_PASS(cleanup()); } RUN_PASS(closure_conversion(*this)) RUN_PASS(lift_builtins(*this)) @@ -1315,7 +1316,7 @@ void World::opt() { RUN_PASS(codegen_prepare(*this)) } -bool World::register_plugin(const char* plugin_name) { +bool World::load_plugin(const char* plugin_name) { #ifdef _MSC_VER return false; #else // _MSC_VER @@ -1332,23 +1333,41 @@ bool World::register_plugin(const char* plugin_name) { if ((error = dlerror()) != NULL) { ILOG("Plugin {} did not supply an init function", plugin_name); } else { - initfunc(this); + initfunc(); } - plugin_handles.push_back(handle); + data_.plugin_modules_.push_back(handle); return true; #endif // _MSC_VER } -World::plugin_func_t* World::search_plugin_function(const char* function_name) const { +template +static T* lookup_plugin_function(void* plugin_module, const char* function_name) { #ifdef _MSC_VER #else // _MSC_VER - for (auto plugin : plugin_handles) { - if (void* plugin_function = dlsym(plugin, function_name)) { - return reinterpret_cast(plugin_function); - } + if (void* func = dlsym(plugin_module, function_name)) { + return reinterpret_cast(func); } #endif // _MSC_VER return nullptr; } + +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_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) }); +} } diff --git a/src/thorin/world.h b/src/thorin/world.h index ef27e0c67..0293901cf 100644 --- a/src/thorin/world.h +++ b/src/thorin/world.h @@ -6,12 +6,14 @@ #include #include #include +#include #include "thorin/enums.h" #include "thorin/continuation.h" #include "thorin/primop.h" #include "thorin/util/hash.h" #include "thorin/util/stream.h" +#include "thorin/plugin.h" #include "thorin/config.h" namespace thorin { @@ -321,11 +323,13 @@ class World : public TypeTable, public Streamable { // plugins - using plugin_init_func_t = void(World*); - using plugin_func_t = const Def*(World*, const App*); + struct PluginIntrinsic { + const Continuation* cont; + unique_plugin_intrinsic impl; + }; - bool register_plugin(const char* plugin_name); - plugin_func_t* search_plugin_function(const char* function_name) const; + bool load_plugin(const char* plugin_name); + void link_plugin_intrinsic(Continuation* cont); private: const Param* param(const Type* type, Continuation* continuation, size_t index, Debug dbg); @@ -334,9 +338,6 @@ class World : public TypeTable, public Streamable { template const Def* transcendental(MathOpTag, const Def*, Debug, F&&); template const Def* transcendental(MathOpTag, const Def*, const Def*, Debug, F&&); - std::unique_ptr world_; - std::vector plugin_handles; - /// @name put into see of nodes //@{ template const T* cse(const T* primop) { return cse_base(primop)->template as(); } @@ -371,10 +372,14 @@ class World : public TypeTable, public Streamable { Sea defs_; Continuation* branch_; Continuation* end_scope_; + std::vector plugin_modules_; + std::vector plugin_intrinsics_; } data_; std::shared_ptr stream_; + unique_plugin_intrinsic load_plugin_intrinsic(const char* function_name) const; + friend class Mangler; friend class Cleaner; friend class Continuation; From a9b4d86bbff8e59057a45e8e8b606eec111fdb71 Mon Sep 17 00:00:00 2001 From: Michael Kenzel Date: Thu, 27 Jul 2023 18:06:13 +0200 Subject: [PATCH 3/4] move plugin loading code to plugin.cpp --- src/thorin/CMakeLists.txt | 1 + src/thorin/plugin.cpp | 67 +++++++++++++++++++++++++++++++++++++++ src/thorin/world.cpp | 61 ----------------------------------- 3 files changed, 68 insertions(+), 61 deletions(-) create mode 100644 src/thorin/plugin.cpp diff --git a/src/thorin/CMakeLists.txt b/src/thorin/CMakeLists.txt index 7209d9cda..4055c72b1 100644 --- a/src/thorin/CMakeLists.txt +++ b/src/thorin/CMakeLists.txt @@ -14,6 +14,7 @@ set(THORIN_SOURCES type.h world.cpp world.h + plugin.cpp plugin.h plugin_helpers.h analyses/cfg.cpp diff --git a/src/thorin/plugin.cpp b/src/thorin/plugin.cpp new file mode 100644 index 000000000..0746f7e71 --- /dev/null +++ b/src/thorin/plugin.cpp @@ -0,0 +1,67 @@ +#include "thorin/world.h" + +#ifdef _WIN32 +#define NOMINMAX +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#include +#endif + +namespace thorin { +bool World::load_plugin(const char* plugin_name) { +#ifdef _WIN32 + return false; +#else + void *handle = dlopen(plugin_name, RTLD_LAZY | RTLD_GLOBAL); + if (!handle) { + ELOG("Error loading plugin {}: {}", plugin_name, dlerror()); + ELOG("Is plugin contained in LD_LIBRARY_PATH?"); + return false; + } + dlerror(); + + char *error; + auto initfunc = reinterpret_cast(dlsym(handle, "init")); + if ((error = dlerror()) != NULL) { + ILOG("Plugin {} did not supply an init function", plugin_name); + } else { + initfunc(); + } + + data_.plugin_modules_.push_back(handle); + return true; +#endif +} + +template +static T* lookup_plugin_function(void* plugin_module, const char* function_name) { +#ifdef _WIN32 +#else + if (void* func = dlsym(plugin_module, function_name)) { + return reinterpret_cast(func); + } +#endif + return nullptr; +} + +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_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) }); +} +} diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index da3ba4825..c8096f9a4 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -11,12 +11,6 @@ #include #include -#ifdef _MSC_VER -#include -#else -#include -#include -#endif #include "thorin/def.h" #include "thorin/primop.h" @@ -1315,59 +1309,4 @@ void World::opt() { RUN_PASS(cleanup()) RUN_PASS(codegen_prepare(*this)) } - -bool World::load_plugin(const char* plugin_name) { -#ifdef _MSC_VER - return false; -#else // _MSC_VER - void *handle = dlopen(plugin_name, RTLD_LAZY | RTLD_GLOBAL); - if (!handle) { - ELOG("Error loading plugin {}: {}", plugin_name, dlerror()); - ELOG("Is plugin contained in LD_LIBRARY_PATH?"); - return false; - } - dlerror(); - - char *error; - auto initfunc = reinterpret_cast(dlsym(handle, "init")); - if ((error = dlerror()) != NULL) { - ILOG("Plugin {} did not supply an init function", plugin_name); - } else { - initfunc(); - } - - data_.plugin_modules_.push_back(handle); - return true; -#endif // _MSC_VER -} - -template -static T* lookup_plugin_function(void* plugin_module, const char* function_name) { -#ifdef _MSC_VER -#else // _MSC_VER - if (void* func = dlsym(plugin_module, function_name)) { - return reinterpret_cast(func); - } -#endif // _MSC_VER - return nullptr; -} - -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_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) }); -} } From bc6cd74089bfcc56e09c7f52b8f2bb7509915516 Mon Sep 17 00:00:00 2001 From: Michael Kenzel Date: Fri, 28 Jul 2023 00:53:50 +0200 Subject: [PATCH 4/4] implement plugin loading for Windows --- src/thorin/plugin.cpp | 59 +++++++++++++++++++++++++------------------ src/thorin/plugin.h | 2 +- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/thorin/plugin.cpp b/src/thorin/plugin.cpp index 0746f7e71..fa154f153 100644 --- a/src/thorin/plugin.cpp +++ b/src/thorin/plugin.cpp @@ -10,40 +10,51 @@ #endif namespace thorin { -bool World::load_plugin(const char* plugin_name) { +[[nodiscard]] static void* load_plugin_module(const char* plugin_name) { #ifdef _WIN32 - return false; + return LoadLibraryA(plugin_name); #else - void *handle = dlopen(plugin_name, RTLD_LAZY | RTLD_GLOBAL); - if (!handle) { - ELOG("Error loading plugin {}: {}", plugin_name, dlerror()); - ELOG("Is plugin contained in LD_LIBRARY_PATH?"); - return false; - } - dlerror(); - - char *error; - auto initfunc = reinterpret_cast(dlsym(handle, "init")); - if ((error = dlerror()) != NULL) { - ILOG("Plugin {} did not supply an init function", plugin_name); - } else { - initfunc(); - } + return dlopen(plugin_name, RTLD_LAZY | RTLD_GLOBAL); +#endif +} - data_.plugin_modules_.push_back(handle); - return true; +static bool unload_plugin_module(void* plugin_module) { +#ifdef _WIN32 + return FreeLibrary(static_cast(plugin_module)) == TRUE; +#else + return dlclose(plugin_module) == 0; #endif } template -static T* lookup_plugin_function(void* plugin_module, const char* function_name) { +[[nodiscard]] static T* lookup_plugin_function(void* plugin_module, const char* function_name) { #ifdef _WIN32 + return reinterpret_cast(GetProcAddress(static_cast(plugin_module), function_name)); #else - if (void* func = dlsym(plugin_module, function_name)) { - return reinterpret_cast(func); - } + return reinterpret_cast(dlsym(plugin_module, function_name)); #endif - return nullptr; +} + +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(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 { diff --git a/src/thorin/plugin.h b/src/thorin/plugin.h index a4d8e0487..bc2b5c268 100644 --- a/src/thorin/plugin.h +++ b/src/thorin/plugin.h @@ -31,7 +31,7 @@ namespace thorin { using unique_plugin_intrinsic = std::unique_ptr; extern "C" { - using plugin_init_func_t = void(); + using plugin_init_func_t = bool(); using plugin_intrinsic_create_func_t = plugin_intrinsic*(); } }