From a927d44e0e757190ea1baa903c7ab91cd72300f8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 16 Jun 2024 11:00:37 -0400 Subject: [PATCH] xo-jit: + LlvmContext to keepalive native LLVMContext --- include/xo/jit/IrPipeline.hpp | 6 ++++- include/xo/jit/Jit.hpp | 5 +++-- include/xo/jit/LlvmContext.hpp | 40 ++++++++++++++++++++++++++++++++++ src/jit/CMakeLists.txt | 1 + src/jit/IrPipeline.cpp | 7 ++++-- src/jit/Jit.cpp | 32 +++++++++++++++++---------- src/jit/LlvmContext.cpp | 20 +++++++++++++++++ 7 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 include/xo/jit/LlvmContext.hpp create mode 100644 src/jit/LlvmContext.cpp diff --git a/include/xo/jit/IrPipeline.hpp b/include/xo/jit/IrPipeline.hpp index 8719fbe2..7efd5b4f 100644 --- a/include/xo/jit/IrPipeline.hpp +++ b/include/xo/jit/IrPipeline.hpp @@ -6,6 +6,7 @@ #pragma once #include "xo/refcnt/Refcounted.hpp" +#include "LlvmContext.hpp" /* stuff from kaleidoscope.cpp */ #include "llvm/ADT/APFloat.h" @@ -46,13 +47,16 @@ namespace xo { **/ class IrPipeline : public ref::Refcount { public: - explicit IrPipeline(llvm::LLVMContext & llvm_cx); + explicit IrPipeline(ref::rp llvm_cx); void run_pipeline(llvm::Function & fn); private: // ----- transforms (also adapted from kaleidescope.cpp) ------ + /** keepalive for contained llvm::LLVMContext **/ + ref::rp llvm_cx_; + /** manages all the passes+analaysis (?) **/ std::unique_ptr llvm_fpmgr_; /** loop analysis (?) **/ diff --git a/include/xo/jit/Jit.hpp b/include/xo/jit/Jit.hpp index f5eb65a4..0cfb423d 100644 --- a/include/xo/jit/Jit.hpp +++ b/include/xo/jit/Jit.hpp @@ -9,6 +9,7 @@ #include "xo/refcnt/Refcounted.hpp" #include "IrPipeline.hpp" +#include "LlvmContext.hpp" #include "xo/expression/Expression.hpp" #include "xo/expression/ConstantInterface.hpp" #include "xo/expression/PrimitiveInterface.hpp" @@ -31,7 +32,6 @@ #include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/DataLayout.h" -#include "llvm/IR/LLVMContext.h" #include #endif @@ -159,7 +159,8 @@ namespace xo { * Not threadsafe, but ok to have multiple threads, * each with its own LLVMContext **/ - std::unique_ptr llvm_cx_; + ref::rp llvm_cx_; + //std::unique_ptr llvm_cx_; /** builder for intermediate-representation objects **/ std::unique_ptr> llvm_ir_builder_; /** a module (1:1 with library) being prepared by llvm. diff --git a/include/xo/jit/LlvmContext.hpp b/include/xo/jit/LlvmContext.hpp new file mode 100644 index 00000000..38f1492a --- /dev/null +++ b/include/xo/jit/LlvmContext.hpp @@ -0,0 +1,40 @@ +/** @file LlvmContext.hpp + * + * Author: Roland Conybeare + **/ + +#pragma once + +#include "xo/refcnt/Refcounted.hpp" +#include "llvm/IR/LLVMContext.h" +//#include + +namespace xo { + namespace jit { + /** @class LlvmContext + * @brief Keepalive for a llvm::LLVMContext instance. + * + * For example IrPipeline holds an rp + * to help ensure validity of embedded llvm::LLVMContext reference + **/ + class LlvmContext : public ref::Refcount { + public: + static xo::ref::rp make(); + + llvm::LLVMContext & llvm_cx_ref() { return *llvm_cx_; } + std::unique_ptr & llvm_cx() { return llvm_cx_; } + + private: + LlvmContext(); + + private: + /** Llvm context. Ties together fragments of code generation + * for AST subtrees that go into the same module. + **/ + std::unique_ptr llvm_cx_; + }; /*LlvmContext*/ + } /*namespace jit*/ +} /*namespace xo*/ + + +/** end LlvmContext.hpp **/ diff --git a/src/jit/CMakeLists.txt b/src/jit/CMakeLists.txt index bbf5aa99..018ecb0e 100644 --- a/src/jit/CMakeLists.txt +++ b/src/jit/CMakeLists.txt @@ -2,6 +2,7 @@ set(SELF_LIB xo_jit) set(SELF_SRCS + LlvmContext.cpp IrPipeline.cpp Jit.cpp ) diff --git a/src/jit/IrPipeline.cpp b/src/jit/IrPipeline.cpp index 200d3a52..d08d9639 100644 --- a/src/jit/IrPipeline.cpp +++ b/src/jit/IrPipeline.cpp @@ -4,17 +4,20 @@ namespace xo { namespace jit { - IrPipeline::IrPipeline(llvm::LLVMContext & llvm_cx) + IrPipeline::IrPipeline(ref::rp llvm_cx) { using std::make_unique; + this->llvm_cx_ = std::move(llvm_cx); + this->llvm_fpmgr_ = make_unique(); this->llvm_lamgr_ = std::make_unique(); this->llvm_famgr_ = std::make_unique(); this->llvm_cgamgr_ = std::make_unique(); this->llvm_mamgr_ = std::make_unique(); this->llvm_pic_ = std::make_unique(); - this->llvm_si_ = std::make_unique(llvm_cx, + /* reference kept alive by @ref llvm_cx_ */ + this->llvm_si_ = std::make_unique(llvm_cx_->llvm_cx_ref(), /*DebugLogging*/ true); this->llvm_si_->registerCallbacks(*llvm_pic_, llvm_mamgr_.get()); diff --git a/src/jit/Jit.cpp b/src/jit/Jit.cpp index 67752b7b..0accdd65 100644 --- a/src/jit/Jit.cpp +++ b/src/jit/Jit.cpp @@ -132,9 +132,10 @@ namespace xo { void Jit::recreate_llvm_ir_pipeline() { - llvm_cx_ = std::make_unique(); - llvm_ir_builder_ = std::make_unique>(*llvm_cx_); - llvm_module_ = std::make_unique("xojit", *llvm_cx_); + //llvm_cx_ = std::make_unique(); + llvm_cx_ = LlvmContext::make(); + llvm_ir_builder_ = std::make_unique>(llvm_cx_->llvm_cx_ref()); + llvm_module_ = std::make_unique("xojit", llvm_cx_->llvm_cx_ref()); llvm_module_->setDataLayout(kal_jit_->getDataLayout()); @@ -148,7 +149,7 @@ namespace xo { throw std::runtime_error("Jit::ctor: expected non-empty llvm module"); } - ir_pipeline_ = new IrPipeline(*llvm_cx_); + ir_pipeline_ = new IrPipeline(llvm_cx_); } /*recreate_llvm_ir_pipeline*/ const std::string & @@ -176,10 +177,10 @@ namespace xo { TypeDescr td = expr->value_td(); if (td->is_native()) { - return llvm::ConstantFP::get(*llvm_cx_, + return llvm::ConstantFP::get(llvm_cx_->llvm_cx_ref(), llvm::APFloat(*(expr->value_tp().recover_native()))); } else if (td->is_native()) { - return llvm::ConstantFP::get(*llvm_cx_, + return llvm::ConstantFP::get(llvm_cx_->llvm_cx_ref(), llvm::APFloat(*(expr->value_tp().recover_native()))); } @@ -230,7 +231,7 @@ namespace xo { log && log(xtag("i_arg", i), xtag("arg_td", arg_td->short_name())); if (arg_td->is_native()) { - llvm_argtype_v.push_back(llvm::Type::getDoubleTy(*llvm_cx_)); + llvm_argtype_v.push_back(llvm::Type::getDoubleTy(llvm_cx_->llvm_cx_ref())); // TODO: extend with other native types here... } else { @@ -252,7 +253,7 @@ namespace xo { llvm::Type * llvm_retval = nullptr; if (retval_td->is_native()) { - llvm_retval = llvm::Type::getDoubleTy(*llvm_cx_); + llvm_retval = llvm::Type::getDoubleTy(llvm_cx_->llvm_cx_ref()); } else { cerr << "Jit::codegen_primitive: error: primitive f returning T where double expected" << xtag("f", expr->name()) @@ -363,9 +364,9 @@ namespace xo { // PLACEHOLDER // just handle double arguments + return type for now - std::vector double_v(1, llvm::Type::getDoubleTy(*llvm_cx_)); + std::vector double_v(1, llvm::Type::getDoubleTy(llvm_cx_->llvm_cx_ref())); - auto * llvm_fn_type = llvm::FunctionType::get(llvm::Type::getDoubleTy(*llvm_cx_), + auto * llvm_fn_type = llvm::FunctionType::get(llvm::Type::getDoubleTy(llvm_cx_->llvm_cx_ref()), double_v, false /*!varargs*/); @@ -381,7 +382,7 @@ namespace xo { /* generate function body */ - auto block = llvm::BasicBlock::Create(*llvm_cx_, "entry", fn); + auto block = llvm::BasicBlock::Create(llvm_cx_->llvm_cx_ref(), "entry", fn); llvm_ir_builder_->SetInsertPoint(block); @@ -459,8 +460,15 @@ namespace xo { auto tracker = kal_jit_->getMainJITDylib().createResourceTracker(); + /* invalidates llvm_cx_->llvm_cx_ref(); will discard and re-create + * + * Note that @ref ir_pipeline_ holds reference, which is invalidated here + */ auto ts_module = llvm::orc::ThreadSafeModule(std::move(llvm_module_), - std::move(llvm_cx_)); + std::move(llvm_cx_->llvm_cx())); + + /* note does not discard llvm_cx_->llvm_cx(), it's already been moved */ + this->llvm_cx_ = nullptr; llvm_exit_on_err(kal_jit_->addModule(std::move(ts_module), tracker)); diff --git a/src/jit/LlvmContext.cpp b/src/jit/LlvmContext.cpp new file mode 100644 index 00000000..19349aca --- /dev/null +++ b/src/jit/LlvmContext.cpp @@ -0,0 +1,20 @@ +/* @file LlvmContext.cpp */ + +#include "LlvmContext.hpp" + +namespace xo { + namespace jit { + xo::ref::rp + LlvmContext::make() { + return new LlvmContext(); + } + + LlvmContext::LlvmContext() + : llvm_cx_{std::make_unique()} + {} + + } /*namespace jit*/ +} /*namespace xo*/ + + +/* end LlvmContext.cpp */