From 7050e7d53d81e733e64f1020acac6d68b258be97 Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Tue, 29 Mar 2022 19:55:42 +0100 Subject: [PATCH] Clean up the halley files --- docs/videos.org | 10 ++++- libserene/include/serene/jit/halley.h | 24 ++++++------ libserene/lib/jit/halley.cpp | 44 ++++------------------ libserene/tests/errors/error_tests.cpp.inc | 3 +- libserene/tests/exprs/list_tests.cpp.inc | 12 +++--- libserene/tests/serenetests.cpp | 2 +- libserene/tests/test_helpers.cpp.inc | 9 ++++- 7 files changed, 46 insertions(+), 58 deletions(-) diff --git a/docs/videos.org b/docs/videos.org index 6840d55..b587c7d 100644 --- a/docs/videos.org +++ b/docs/videos.org @@ -925,7 +925,8 @@ CLOSED: [2022-02-26 Sat 12:50] #+RESULTS: ep-16-jit-3 [[file:/tmp/ep16-3.svg]] -* Episode 17 - Custom ORC Layers +* DONE Episode 17 - Custom ORC Layers +CLOSED: [2022-03-28 Mon 14:00] ** Updates: - Finished the basic compiler wiring - Restructured the source tree @@ -952,3 +953,10 @@ Let's have a look at the =MaterializationUnit= class. *** And the layer class itself The layer classes are not special but conventionally the come with few functions like: =add=, =emit= and =getInterface=. + +* Episode 18 - JIT Engine Part 1 +** =Halley= JIT Engine +- It's not the final implementation +- Wraps LLJIT and LLLazyJIT +- Uses object cache layer +- Supports ASTs and Namespaces diff --git a/libserene/include/serene/jit/halley.h b/libserene/include/serene/jit/halley.h index ea217ee..5ac17b0 100644 --- a/libserene/include/serene/jit/halley.h +++ b/libserene/include/serene/jit/halley.h @@ -18,7 +18,15 @@ /** * Commentary: - * The code is based on the MLIR's JIT and named after Edmond Halley. + This is the first working attempt on building a JIT engine for Serene + and named after Edmond Halley. + + - It supports both ASTs and Namespaces + - Every Namespace might have one or more JITDylibs. Depends on the method + of the compilation. + - It operates in lazy (for REPL) and non-lazy mode and wraps LLJIT + and LLLazyJIT + - It uses an object cache layer to cache module (not NSs) objects. */ #ifndef SERENE_JIT_HALLEY_H @@ -51,13 +59,14 @@ class Namespace; namespace exprs { class Symbol; -} +} // namespace exprs namespace jit { class Halley; using MaybeJIT = llvm::Expected>; using MaybeJITPtr = llvm::Expected; + /// A simple object cache following Lang's LLJITWithObjectCache example and /// MLIR's SimpelObjectCache. class ObjectCache : public llvm::ObjectCache { @@ -100,14 +109,12 @@ public: Halley(serene::SereneContext &ctx, llvm::orc::JITTargetMachineBuilder &&jtmb, llvm::DataLayout &&dl); - // TODO: Read the sharedLibPaths via context static MaybeJIT make(serene::SereneContext &ctx, llvm::orc::JITTargetMachineBuilder &&jtmb); void setEngine(std::unique_ptr e, bool isLazy); - /// Looks up a packed-argument function with the given name and returns a - /// pointer to it. Propagates errors in case of failure. - // llvm::Expected lookup(llvm::StringRef name) const; + /// Looks up a packed-argument function with the given sym name and returns a + /// pointer to it. Propagates errors in case of failure. MaybeJITPtr lookup(exprs::Symbol &sym) const; /// Invokes the function with the given name passing it the list of opaque @@ -174,11 +181,6 @@ public: void dumpToObjectFile(llvm::StringRef filename); - /// Register symbols with this ExecutionEngine. - void registerSymbols( - llvm::function_ref - symbolMap); - llvm::Error addNS(Namespace &ns, reader::LocationRange &loc); llvm::Error addAST(exprs::Ast &ast); diff --git a/libserene/lib/jit/halley.cpp b/libserene/lib/jit/halley.cpp index 6fcd138..1c81d7b 100644 --- a/libserene/lib/jit/halley.cpp +++ b/libserene/lib/jit/halley.cpp @@ -57,15 +57,9 @@ namespace serene { namespace jit { -// TODO: Remove this function and replace it by our own version of -// error handler -/// Wrap a string into an llvm::StringError. -// static llvm::Error make_string_error(const llvm::Twine &message) { -// return llvm::make_error(message.str(), -// llvm::inconvertibleErrorCode()); -// } static std::string makePackedFunctionName(llvm::StringRef name) { + // TODO: move the "_serene_" constant to a macro or something return "_serene_" + name.str(); } @@ -207,13 +201,13 @@ MaybeJITPtr Halley::lookup(exprs::Symbol &sym) const { auto expectedSymbol = engine->lookup(*dylib, makePackedFunctionName(sym.name)); - // auto expectedSymbol = engine->lookup(name); - // JIT lookup may return an Error referring to strings stored internally by - // the JIT. If the Error outlives the ExecutionEngine, it would want have a - // dangling reference, which is currently caught by an assertion inside JIT - // thanks to hand-rolled reference counting. Rewrap the error message into a - // string before returning. Alternatively, ORC JIT should consider copying - // the string into the error message. + + // JIT lookup may return an Error referring to strings stored internally by + // the JIT. If the Error outlives the ExecutionEngine, it would want have a + // dangling reference, which is currently caught by an assertion inside JIT + // thanks to hand-rolled reference counting. Rewrap the error message into a + // string before returning. Alternatively, ORC JIT should consider copying + // the string into the error message. if (!expectedSymbol) { std::string errorMessage; llvm::raw_string_ostream os(errorMessage); @@ -235,19 +229,6 @@ MaybeJITPtr Halley::lookup(exprs::Symbol &sym) const { return fptr; }; -void createObjectFile(SereneContext &ctx, llvm::StringRef name, - llvm::MemoryBufferRef objBuffer) { - std::string errorMessage; - auto file = mlir::openOutputFile(name, &errorMessage); - if (!file) { - - panic(ctx, errorMessage); - } - - file->os() << objBuffer.getBuffer(); - file->keep(); -} - // llvm::Error Halley::invokePacked(llvm::StringRef name, // llvm::MutableArrayRef args) const { // auto expectedFPtr = lookup(name); @@ -261,15 +242,6 @@ void createObjectFile(SereneContext &ctx, llvm::StringRef name, // return llvm::Error::success(); // } -void Halley::registerSymbols( - llvm::function_ref - symbolMap) { - auto &mainJitDylib = engine->getMainJITDylib(); - cantFail(mainJitDylib.define( - absoluteSymbols(symbolMap(llvm::orc::MangleAndInterner( - mainJitDylib.getExecutionSession(), engine->getDataLayout()))))); -}; - llvm::Error Halley::addNS(Namespace &ns, reader::LocationRange &loc) { HALLEY_LOG(llvm::formatv("Creating Dylib {0}#{1}", ns.name, diff --git a/libserene/tests/errors/error_tests.cpp.inc b/libserene/tests/errors/error_tests.cpp.inc index 2ce1b4a..67d8655 100644 --- a/libserene/tests/errors/error_tests.cpp.inc +++ b/libserene/tests/errors/error_tests.cpp.inc @@ -57,8 +57,7 @@ TEST_CASE("getMessage function", "[errors]") { llvm::Error err = makeError(*ctx, PassFailureError, *range, "test error"); CHECK(getMessage(err) == "test error"); - - CHECK_ERR(PassFailureError, std::move(err)); + CHECK_SERENE_ERR(PassFailureError, std::move(err)); } }; // namespace errors diff --git a/libserene/tests/exprs/list_tests.cpp.inc b/libserene/tests/exprs/list_tests.cpp.inc index 0fbcf50..030d5ee 100644 --- a/libserene/tests/exprs/list_tests.cpp.inc +++ b/libserene/tests/exprs/list_tests.cpp.inc @@ -88,19 +88,19 @@ TEST_CASE("List semantic analysis of 'def'", "[semantic,expression,list]") { auto afterAst = semantics::analyze(state, ast); REQUIRE_FALSE(afterAst); - CHECK_ERR(llvm::ErrorList, afterAst.takeError()); - + { + auto err = afterAst.takeError(); + CHECK(err.isA()); + } ast = llvm::cantFail(READ("(def a)")); afterAst = semantics::analyze(state, ast); REQUIRE_FALSE(afterAst); - CHECK(errors::getMessage(afterAst.takeError()) == - ""); + CHECK(errors::getMessage(afterAst.takeError()) == "Expected 3 got 2"); ast = llvm::cantFail(READ("(def a b c)")); afterAst = semantics::analyze(state, ast); REQUIRE_FALSE(afterAst); - CHECK(errors::getMessage(afterAst.takeError()) == - ""); + CHECK(errors::getMessage(afterAst.takeError()) == "Expected 3 got 4"); ast = llvm::cantFail(READ("(def a b)")); afterAst = semantics::analyze(state, ast); diff --git a/libserene/tests/serenetests.cpp b/libserene/tests/serenetests.cpp index 914a526..b8e1abf 100644 --- a/libserene/tests/serenetests.cpp +++ b/libserene/tests/serenetests.cpp @@ -21,7 +21,7 @@ #include "./environment_tests.cpp.inc" #include "./errors/error_tests.cpp.inc" #include "./exprs/expression_tests.cpp.inc" -//#include "./exprs/list_tests.cpp.inc" +#include "./exprs/list_tests.cpp.inc" #include "./exprs/number_tests.cpp.inc" #include "./exprs/symbol_tests.cpp.inc" #include "./setup.cpp.inc" diff --git a/libserene/tests/test_helpers.cpp.inc b/libserene/tests/test_helpers.cpp.inc index 63ed325..559e3e3 100644 --- a/libserene/tests/test_helpers.cpp.inc +++ b/libserene/tests/test_helpers.cpp.inc @@ -30,11 +30,18 @@ // `llvm::Error`s has to be checked in the same scope. This macro makes // the check easy while were testing the other aspects of the error. // `t` is the concrete error type and `e` is the error instance. -#define CHECK_ERR(t, e) \ +#define CHECK_SERENE_ERR(t, e) \ auto unhandled = llvm::handleErrors( \ e, [&](const SereneError &x) { CHECK(x.errorType == t); }); \ CHECK(!unhandled); +#define CHECK_ERR(t, e) \ + auto unhandled = llvm::handleErrors(e, [&](const t &x) { \ + (void)x; \ + CHECK(true); \ + }); \ + CHECK(!unhandled); + namespace serene { reader::LocationRange *dummyLocation() {