diff --git a/example/ex_kaleidoscope4/CMakeLists.txt b/example/ex_kaleidoscope4/CMakeLists.txt new file mode 100644 index 00000000..4e9476c3 --- /dev/null +++ b/example/ex_kaleidoscope4/CMakeLists.txt @@ -0,0 +1,12 @@ +# xo-jit/example/ex1/CMakeLists.txt + +set(SELF_EXE xo_kaleidoscope4) +set(SELF_SRCS ex_kaleidoscope4.cpp) + +if (XO_ENABLE_EXAMPLES) + xo_add_executable(${SELF_EXE} ${SELF_SRCS}) + xo_self_dependency(${SELF_EXE} xo_jit) + #xo_dependency(${SELF_EXE} xo_expression) +endif() + +# end CMakeLists.txt diff --git a/example/ex_kaleidoscope4/ex_kaleidoscope4.cpp b/example/ex_kaleidoscope4/ex_kaleidoscope4.cpp new file mode 100644 index 00000000..63926aad --- /dev/null +++ b/example/ex_kaleidoscope4/ex_kaleidoscope4.cpp @@ -0,0 +1,16 @@ +/** ex_kaleidoscop4.cpp **/ + +#include "xo/jit/KaleidoscopeJit.hpp" +#include + +int +main() { + using std::cerr; + using std::endl; + + auto jit = xo::jit::KaleidoscopeJIT::Create(); + + cerr << "created kaleidoscope jit successfully" << endl; +} + +/** end ex_kaleidoscope4.cpp **/ diff --git a/include/xo/jit/Jit.hpp b/include/xo/jit/Jit.hpp index 044343b8..d66f86fe 100644 --- a/include/xo/jit/Jit.hpp +++ b/include/xo/jit/Jit.hpp @@ -14,6 +14,27 @@ #include "xo/expression/Apply.hpp" #include "xo/expression/Lambda.hpp" #include "xo/expression/Variable.hpp" + +#include "KaleidoscopeJit.hpp" +#ifdef NOT_USING +/* stuff from KaleidoscopeJIT.hpp */ +#include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" +#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" +#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/LLVMContext.h" +#include +#endif + +/* stuff from kaleidoscope.cpp */ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" #include "llvm/IR/BasicBlock.h" @@ -36,6 +57,7 @@ #include "llvm/Transforms/Scalar/Reassociate.h" #include "llvm/Transforms/Scalar/SimplifyCFG.h" + namespace xo { namespace jit { /** @class Jit @@ -49,7 +71,8 @@ namespace xo { //using ConstantInterface = xo::ast::ConstantInterface; public: - static ref::rp make() { return new Jit(); } + /* tracking KaleidoscopeJIT::Create() here.. */ + static llvm::Expected> make_aux(); llvm::Value * codegen_constant(ref::brw expr); llvm::Function * codegen_primitive(ref::brw expr); @@ -63,9 +86,32 @@ namespace xo { virtual std::string display_string() const; private: - Jit(); + Jit( + std::unique_ptr kal_jit +#ifdef NOT_USING + std::unique_ptr es, + llvm::orc::JITTargetMachineBuilder jtmb, + llvm::DataLayout dl +#endif + ); private: + // ----- this part adapted from LLVM 19.0 KaleidoscopeJIT.hpp [wip] ----- + + std::unique_ptr kal_jit_; + +#ifdef NOT_USING + std::unique_ptr jit_es_; + llvm::DataLayout jit_data_layout_; + llvm::orc::MangleAndInterner jit_mangle_; + llvm::orc::RTDyldObjectLinkingLayer jit_object_layer_; + llvm::orc::IRCompileLayer jit_compile_layer_; + /** reference here. looks like storage owned by .jit_es **/ + llvm::orc::JITDylib & jit_our_dynamic_lib_; +#endif + + // ----- this part adapted from kaleidoscope.cpp ----- + /** owns + manages core "global" llvm data, * including type- and constant- unique-ing tables. * diff --git a/include/xo/jit/KaleidoscopeJit.hpp b/include/xo/jit/KaleidoscopeJit.hpp new file mode 100644 index 00000000..3094c076 --- /dev/null +++ b/include/xo/jit/KaleidoscopeJit.hpp @@ -0,0 +1,126 @@ +//===- KaleidoscopeJIT.h - A simple JIT for Kaleidoscope --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Contains a simple JIT definition for use in the kaleidoscope tutorials. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H +#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" +#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" +#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/LLVMContext.h" +#include + +namespace xo { + namespace jit { + + class KaleidoscopeJIT { + private: + using StringRef = llvm::StringRef; + using SectionMemoryManager = llvm::SectionMemoryManager; + using DynamicLibrarySearchGenerator = llvm::orc::DynamicLibrarySearchGenerator; + using ConcurrentIRCompiler = llvm::orc::ConcurrentIRCompiler; + using ExecutionSession = llvm::orc::ExecutionSession; + using DataLayout = llvm::DataLayout; + using MangleAndInterner = llvm::orc::MangleAndInterner; + using RTDyldObjectLinkingLayer = llvm::orc::RTDyldObjectLinkingLayer; + using IRCompileLayer = llvm::orc::IRCompileLayer; + using JITDylib = llvm::orc::JITDylib; + using JITTargetMachineBuilder = llvm::orc::JITTargetMachineBuilder; + using ThreadSafeModule = llvm::orc::ThreadSafeModule; + using ResourceTrackerSP = llvm::orc::ResourceTrackerSP; + using ExecutorSymbolDef = llvm::orc::ExecutorSymbolDef; + using SelfExecutorProcessControl = llvm::orc::SelfExecutorProcessControl; + + private: + std::unique_ptr ES; + + DataLayout DL; + MangleAndInterner Mangle; + + RTDyldObjectLinkingLayer ObjectLayer; + IRCompileLayer CompileLayer; + + JITDylib &MainJD; + + public: + KaleidoscopeJIT(std::unique_ptr ES, + JITTargetMachineBuilder JTMB, + DataLayout DL) + : ES(std::move(ES)), + DL(std::move(DL)), + Mangle(*this->ES, this->DL), + ObjectLayer(*this->ES, + []() { return std::make_unique(); }), + CompileLayer(*this->ES, ObjectLayer, + std::make_unique(std::move(JTMB))), + MainJD(this->ES->createBareJITDylib("
")) + { + MainJD.addGenerator( + cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess( + DL.getGlobalPrefix()))); + if (JTMB.getTargetTriple().isOSBinFormatCOFF()) { + ObjectLayer.setOverrideObjectFlagsWithResponsibilityFlags(true); + ObjectLayer.setAutoClaimResponsibilityForObjectSymbols(true); + } + } + + ~KaleidoscopeJIT() { + if (auto Err = ES->endSession()) + ES->reportError(std::move(Err)); + } + + static llvm::Expected> Create() { + auto EPC = SelfExecutorProcessControl::Create(); + if (!EPC) + return EPC.takeError(); + + auto ES = std::make_unique(std::move(*EPC)); + + JITTargetMachineBuilder JTMB( + ES->getExecutorProcessControl().getTargetTriple()); + + auto DL = JTMB.getDefaultDataLayoutForTarget(); + if (!DL) + return DL.takeError(); + + return std::make_unique(std::move(ES), std::move(JTMB), + std::move(*DL)); + } + + const DataLayout &getDataLayout() const { return DL; } + + JITDylib &getMainJITDylib() { return MainJD; } + + llvm::Error addModule(ThreadSafeModule TSM, ResourceTrackerSP RT = nullptr) { + if (!RT) + RT = MainJD.getDefaultResourceTracker(); + return CompileLayer.add(RT, std::move(TSM)); + } + + llvm::Expected lookup(StringRef Name) { + return ES->lookup({&MainJD}, Mangle(Name.str())); + } + }; + + } // end namespace jit +} // end namespace xo + +#endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H diff --git a/src/jit/Jit.cpp b/src/jit/Jit.cpp index 872b949e..d5aa2901 100644 --- a/src/jit/Jit.cpp +++ b/src/jit/Jit.cpp @@ -15,11 +15,96 @@ namespace xo { using std::endl; namespace jit { - Jit::Jit() - : llvm_cx_{std::make_unique()}, + + /* tracking KaleidoscopeJIT::Create() here.. + * + * Verified: + * + 'execution session' as per Kaleidoscope JIT, + * can instantiate from python + * + 'jit object layer' + * (realtime dynamic library object linking layer) + * + 'jit_copmile_layer' + * + 'jit_our_dynamic_lib' + */ + llvm::Expected> + Jit::make_aux() + { +#ifdef NOT_USING + /* 'executor process control' */ + auto epc = llvm::orc::SelfExecutorProcessControl::Create(); + if (!epc) { + return epc.takeError(); + //throw std::runtime_error("Jit::make: failed to establish executor process control"); + } + + /* 'execution session' */ + auto es = std::make_unique(std::move(*epc)); + + /* 'jit target machine builder' */ + llvm::orc::JITTargetMachineBuilder jtmb(es + ->getExecutorProcessControl() + .getTargetTriple()); + + auto dl = jtmb.getDefaultDataLayoutForTarget(); + if (!dl) { + return dl.takeError(); + //throw std::runtime_error("Jit::make: failed to establish data layout object" + // " for target machine"); + } +#endif + + static llvm::ExitOnError llvm_exit_on_err; + + std::unique_ptr kal_jit = llvm_exit_on_err(KaleidoscopeJIT::Create()); + + return std::unique_ptr(new Jit(std::move(kal_jit) +#ifdef NOT_USING + std::move(es), + std::move(jtmb), + std::move(*dl) +#endif + )); + } /*make*/ + + Jit::Jit( + std::unique_ptr kal_jit +#ifdef NOT_USING + std::unique_ptr jit_es, + llvm::orc::JITTargetMachineBuilder jtmb, + llvm::DataLayout dl +#endif + ) + : kal_jit_{std::move(kal_jit)}, +#ifdef NOT_USING + jit_es_(std::move(jit_es)), + jit_data_layout_(std::move(dl)), + jit_mangle_(*this->jit_es_, this->jit_data_layout_), + jit_object_layer_(*this->jit_es_, + []() { return std::make_unique(); }), + jit_compile_layer_(*this->jit_es_, + jit_object_layer_, + std::make_unique(std::move(jtmb))), + /* note: string passed to createBareJITDyLib must be unique + * (within running process address space?) + */ + jit_our_dynamic_lib_(this->jit_es_->createBareJITDylib("")), /*was MainJD*/ +#endif + + llvm_cx_{std::make_unique()}, llvm_ir_builder_{std::make_unique>(*llvm_cx_)}, llvm_module_{std::make_unique("xojit", *llvm_cx_)} - {} + { +#ifdef NOT_USING + jit_our_dynamic_lib_.addGenerator + (cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess + (jit_data_layout_.getGlobalPrefix()))); + + if(jtmb.getTargetTriple().isOSBinFormatCOFF()) { + jit_object_layer_.setOverrideObjectFlagsWithResponsibilityFlags(true); + jit_object_layer_.setAutoClaimResponsibilityForObjectSymbols(true); + } +#endif + } llvm::Value * Jit::codegen_constant(ref::brw expr) @@ -40,9 +125,12 @@ namespace xo { llvm::Function * Jit::codegen_primitive(ref::brw expr) { + constexpr bool c_debug_flag = true; + using xo::scope; + /** note: documentation (such as it is) for llvm::Function here: * - * https://llvm.org/doxygen/classllvm_1_1Function.html + * https://llvm.org/doxygenL/classllvm_1_1Function.html **/ auto * fn = llvm_module_->getFunction(expr->name()); @@ -64,12 +152,19 @@ namespace xo { TypeDescr fn_td = expr->value_td(); int n_fn_arg = fn_td->n_fn_arg(); - std::vector llvm_argtype_v(n_fn_arg); + scope log(XO_DEBUG(c_debug_flag), + xtag("fn_td", fn_td->short_name()), + xtag("n_fn_arg", n_fn_arg)); + + std::vector llvm_argtype_v; + llvm_argtype_v.reserve(n_fn_arg); /** check function args are all doubles **/ for (int i = 0; i < n_fn_arg; ++i) { TypeDescr arg_td = fn_td->fn_arg(i); + 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_)); @@ -87,6 +182,9 @@ namespace xo { //std::vector double_v(n_fn_arg, llvm::Type::getDoubleTy(*llvm_cx_)); TypeDescr retval_td = fn_td->fn_retval(); + + log && log(xtag("retval_td", retval_td->short_name())); + llvm::Type * llvm_retval = nullptr; if (retval_td->is_native()) { @@ -108,12 +206,22 @@ namespace xo { expr->name(), llvm_module_.get()); - // set names for arguments (for diagonostics?). Money-see-kaleidoscope-monkey-do here #ifdef NOT_USING - for (auto & arg : fn->args()) - arg.setName(formalnameofthisarg); + // set names for arguments (for diagnostics?). Monkey-see-kaleidoscope-monkey-do here + { + int i_arg = 0; + for (auto & arg : fn->args()) { + std::stringstream ss; + ss << "x_" << i_arg; + + arg.setName(ss.str()); + ++i_arg; + } + } #endif + log && log("returning llvm function"); + return fn; } /*codegen_primitive*/ @@ -189,7 +297,7 @@ namespace xo { /* establish prototype for this function */ // PLACEHOLDER - // just make prototype for function :: double -> double + // just handle double arguments + return type for now std::vector double_v(1, llvm::Type::getDoubleTy(*llvm_cx_));