From 3ace6ec260c7eb0be903326bfa09594ac7bb2834 Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Sun, 15 Aug 2021 12:06:56 +0100 Subject: [PATCH] Chaneg the namespace to generate modules instead of owning them --- bin/serene.cpp | 38 ++- include/serene/context.h | 3 +- include/serene/errors/constants.h | 11 +- include/serene/exprs/call.h | 2 +- include/serene/exprs/def.h | 2 +- include/serene/exprs/expression.h | 6 +- include/serene/exprs/fn.h | 2 +- include/serene/exprs/list.h | 2 +- include/serene/exprs/number.h | 2 +- include/serene/exprs/symbol.h | 2 +- include/serene/jit.h | 58 +++- include/serene/namespace.h | 23 +- include/serene/reader/reader.h | 5 +- include/serene/slir/generatable.h | 2 + include/serene/slir/slir.h | 11 +- include/serene/utils.h | 27 ++ resources/images/logo.svg | 87 ------ resources/images/logo_with_text.svg | 142 --------- resources/site/archetypes/default.md | 6 - resources/site/config.toml | 7 - resources/site/content/posts/my-first-post.md | 7 - resources/site/scripts/deploy.sh | 9 - resources/site/themes/anybodyhome/LICENSE.md | 20 -- resources/site/themes/anybodyhome/README.md | 36 --- .../themes/anybodyhome/archetypes/default.md | 2 - .../site/themes/anybodyhome/layouts/404.html | 0 .../layouts/_default/paginator.html | 10 - .../anybodyhome/layouts/_default/single.html | 15 - .../anybodyhome/layouts/_default/summary.html | 9 - .../themes/anybodyhome/layouts/index.html | 17 -- .../anybodyhome/layouts/partials/footer.html | 0 .../anybodyhome/layouts/partials/head.html | 43 --- .../anybodyhome/layouts/partials/header.html | 6 - .../layouts/partials/paginator.html | 12 - .../themes/anybodyhome/layouts/summary.html | 9 - .../themes/anybodyhome/static/css/styles.css | 162 ---------- resources/site/themes/anybodyhome/theme.toml | 12 - src/serene/CMakeLists.txt | 1 + src/serene/exprs/def.cpp | 7 +- src/serene/exprs/fn.cpp | 12 +- src/serene/exprs/number.cpp | 5 +- src/serene/jit.cpp | 281 ++++++++++++++++++ src/serene/namespace.cpp | 77 +++-- src/serene/slir/slir.cpp | 64 ++++ 44 files changed, 549 insertions(+), 705 deletions(-) delete mode 100644 resources/images/logo.svg delete mode 100644 resources/images/logo_with_text.svg delete mode 100644 resources/site/archetypes/default.md delete mode 100644 resources/site/config.toml delete mode 100644 resources/site/content/posts/my-first-post.md delete mode 100755 resources/site/scripts/deploy.sh delete mode 100644 resources/site/themes/anybodyhome/LICENSE.md delete mode 100644 resources/site/themes/anybodyhome/README.md delete mode 100644 resources/site/themes/anybodyhome/archetypes/default.md delete mode 100644 resources/site/themes/anybodyhome/layouts/404.html delete mode 100644 resources/site/themes/anybodyhome/layouts/_default/paginator.html delete mode 100644 resources/site/themes/anybodyhome/layouts/_default/single.html delete mode 100644 resources/site/themes/anybodyhome/layouts/_default/summary.html delete mode 100644 resources/site/themes/anybodyhome/layouts/index.html delete mode 100644 resources/site/themes/anybodyhome/layouts/partials/footer.html delete mode 100644 resources/site/themes/anybodyhome/layouts/partials/head.html delete mode 100644 resources/site/themes/anybodyhome/layouts/partials/header.html delete mode 100644 resources/site/themes/anybodyhome/layouts/partials/paginator.html delete mode 100644 resources/site/themes/anybodyhome/layouts/summary.html delete mode 100644 resources/site/themes/anybodyhome/static/css/styles.css delete mode 100644 resources/site/themes/anybodyhome/theme.toml create mode 100644 src/serene/jit.cpp create mode 100644 src/serene/slir/slir.cpp diff --git a/bin/serene.cpp b/bin/serene.cpp index 3ab6670..8b1b8a3 100644 --- a/bin/serene.cpp +++ b/bin/serene.cpp @@ -24,7 +24,6 @@ #include "serene/serene.h" -#include "mlir/ExecutionEngine/ExecutionEngine.h" #include "serene/context.h" #include "serene/namespace.h" #include "serene/reader/reader.h" @@ -32,14 +31,13 @@ #include "serene/slir/generatable.h" #include "serene/slir/slir.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringRef.h" - #include #include #include #include +#include +#include +#include #include #include #include @@ -129,9 +127,16 @@ exprs::Ast readAndAnalyze(SereneContext &ctx) { int dumpAsObject(Namespace &ns) { // TODO: Move the compilation process to the Namespace class - auto &module = ns.getLLVMModule(); + auto maybeModule = ns.compileToLLVM(); + // TODO: Fix this call to raise the wrapped error instead + auto module = std::move( + maybeModule.getValueOrFail("Faild to generato LLVM IR for namespace")); auto &ctx = ns.getContext(); - module.setTargetTriple(ctx.targetTriple); + + // TODO: We need to set the triple data layout and everything to that sort in + // one place. We want them for the JIT as well and also we're kinda + // duplicating what we're doing in `Namespace#compileToLLVM`. + module->setTargetTriple(ctx.targetTriple); std::string Error; auto target = llvm::TargetRegistry::lookupTarget(ctx.targetTriple, Error); @@ -153,7 +158,7 @@ int dumpAsObject(Namespace &ns) { target->createTargetMachine(ctx.targetTriple, cpu, features, opt, rm); auto targetMachine = std::unique_ptr(targetMachinePtr); - module.setDataLayout(targetMachine->createDataLayout()); + module->setDataLayout(targetMachine->createDataLayout()); auto filename = strcmp(outputFile.c_str(), "-") == 0 ? "output" : outputFile.c_str(); @@ -177,7 +182,7 @@ int dumpAsObject(Namespace &ns) { return 1; } - pass.run(module); + pass.run(*module); dest.flush(); if (emitAction == Action::Compile) { @@ -304,12 +309,17 @@ int main(int argc, char *argv[]) { if (isSet.succeeded()) { ctx->insertNS(ns); - if (mlir::failed(serene::slir::generate(*ns))) { - llvm::errs() << "IR generation faild\n"; - return 1; - } if (emitAction < CompileToObject) { - serene::slir::dump(*ns); + ns->dump(); + } else if (emitAction == Action::DumpIR) { + auto maybeModule = ns->compileToLLVM(); + + if (!maybeModule) { + llvm::errs() << "Failed to generate the IR.\n"; + return 1; + } + + maybeModule.getValue()->dump(); } else if (emitAction == Action::JIT) { } else { diff --git a/include/serene/context.h b/include/serene/context.h index fbdce11..19f5231 100644 --- a/include/serene/context.h +++ b/include/serene/context.h @@ -31,6 +31,7 @@ #include "serene/slir/dialect.h" #include +#include #include #include #include @@ -87,7 +88,7 @@ public: mlirContext.getOrLoadDialect(); mlirContext.getOrLoadDialect(); // TODO: Get the crash report path dynamically from the cli - pm.enableCrashReproducerGeneration("/home/lxsameer/mlir.mlir"); + // pm.enableCrashReproducerGeneration("/home/lxsameer/mlir.mlir"); targetTriple = llvm::sys::getDefaultTargetTriple(); }; diff --git a/include/serene/errors/constants.h b/include/serene/errors/constants.h index 77bedc2..d8052da 100644 --- a/include/serene/errors/constants.h +++ b/include/serene/errors/constants.h @@ -39,6 +39,7 @@ enum ErrID { E0004, E0005, E0006, + E0007, }; struct ErrorVariant { @@ -71,11 +72,13 @@ static ErrorVariant DontKnowHowToCallNode(E0006, "Don't know how to call the given expression.", ""); +static ErrorVariant PassFailureError(E0007, "Pass Failure.", ""); + static std::map ErrDesc = { - {E0000, &UnknownError}, {E0001, &DefExpectSymbol}, - {E0002, &DefWrongNumberOfArgs}, {E0003, &FnNoArgsList}, - {E0004, &FnArgsMustBeList}, {E0005, &CantResolveSymbol}, - {E0006, &DontKnowHowToCallNode}}; + {E0000, &UnknownError}, {E0001, &DefExpectSymbol}, + {E0002, &DefWrongNumberOfArgs}, {E0003, &FnNoArgsList}, + {E0004, &FnArgsMustBeList}, {E0005, &CantResolveSymbol}, + {E0006, &DontKnowHowToCallNode}, {E0007, &PassFailureError}}; } // namespace errors } // namespace serene diff --git a/include/serene/exprs/call.h b/include/serene/exprs/call.h index 4a83d94..13bddaa 100644 --- a/include/serene/exprs/call.h +++ b/include/serene/exprs/call.h @@ -57,7 +57,7 @@ public: ExprType getType() const; std::string toString() const; MaybeNode analyze(SereneContext &); - void generateIR(serene::Namespace &){}; + void generateIR(serene::Namespace &, mlir::ModuleOp &){}; static bool classof(const Expression *e); diff --git a/include/serene/exprs/def.h b/include/serene/exprs/def.h index dc14b9c..ebfb316 100644 --- a/include/serene/exprs/def.h +++ b/include/serene/exprs/def.h @@ -56,7 +56,7 @@ public: ExprType getType() const; std::string toString() const; MaybeNode analyze(SereneContext &); - void generateIR(serene::Namespace &); + void generateIR(serene::Namespace &, mlir::ModuleOp &); static bool classof(const Expression *e); diff --git a/include/serene/exprs/expression.h b/include/serene/exprs/expression.h index 1da3e19..847ecef 100644 --- a/include/serene/exprs/expression.h +++ b/include/serene/exprs/expression.h @@ -25,6 +25,7 @@ #ifndef EXPRS_EXPRESSION_H #define EXPRS_EXPRESSION_H +#include "mlir/IR/BuiltinOps.h" #include "serene/context.h" #include "serene/errors/error.h" #include "serene/exprs/traits.h" @@ -82,10 +83,11 @@ public: virtual MaybeNode analyze(SereneContext &ctx) = 0; /// Genenates the correspondig SLIR of the expressoin and attach it to the - /// module of the given namespace. + /// given module. /// /// \param ns The namespace that current expression is in it. - virtual void generateIR(serene::Namespace &ns) = 0; + /// \param m The target MLIR moduleOp to attach the operations to + virtual void generateIR(serene::Namespace &ns, mlir::ModuleOp &m) = 0; }; /// Create a new `node` of type `T` and forwards any given parameter diff --git a/include/serene/exprs/fn.h b/include/serene/exprs/fn.h index 4f9ac27..8b4b4c4 100644 --- a/include/serene/exprs/fn.h +++ b/include/serene/exprs/fn.h @@ -60,7 +60,7 @@ public: ExprType getType() const; std::string toString() const; MaybeNode analyze(SereneContext &); - void generateIR(serene::Namespace &); + void generateIR(serene::Namespace &, mlir::ModuleOp &); static bool classof(const Expression *e); diff --git a/include/serene/exprs/list.h b/include/serene/exprs/list.h index de90514..4151a95 100644 --- a/include/serene/exprs/list.h +++ b/include/serene/exprs/list.h @@ -78,7 +78,7 @@ public: std::vector::iterator end(); MaybeNode analyze(SereneContext &); - void generateIR(serene::Namespace &){}; + void generateIR(serene::Namespace &, mlir::ModuleOp &){}; ~List() = default; diff --git a/include/serene/exprs/number.h b/include/serene/exprs/number.h index bc6fb91..274eada 100644 --- a/include/serene/exprs/number.h +++ b/include/serene/exprs/number.h @@ -54,7 +54,7 @@ struct Number : public Expression { std::string toString() const; MaybeNode analyze(SereneContext &ctx); - void generateIR(serene::Namespace &); + void generateIR(serene::Namespace &, mlir::ModuleOp &); // TODO: This is horrible, we need to fix it after the mvp int toI64(); diff --git a/include/serene/exprs/symbol.h b/include/serene/exprs/symbol.h index 372556f..b6a0aeb 100644 --- a/include/serene/exprs/symbol.h +++ b/include/serene/exprs/symbol.h @@ -51,7 +51,7 @@ public: std::string toString() const; MaybeNode analyze(SereneContext &); - void generateIR(serene::Namespace &){}; + void generateIR(serene::Namespace &, mlir::ModuleOp &){}; ~Symbol() = default; diff --git a/include/serene/jit.h b/include/serene/jit.h index 427512c..ffbda4d 100644 --- a/include/serene/jit.h +++ b/include/serene/jit.h @@ -25,18 +25,70 @@ #ifndef SERENE_JIT_H #define SERENE_JIT_H +#include "serene/errors.h" #include "serene/slir/generatable.h" +#include "serene/utils.h" #include +#include +#include +#include +#include +#include #include -#include +#include + +#define JIT_LOG(...) \ + DEBUG_WITH_TYPE("JIT", llvm::dbgs() << "[JIT]: " << __VA_ARGS__ << "\n"); namespace serene { +class JIT; + +using MaybeJIT = Result, serene::errors::Error>; + +/// A simple object cache following Lang's LLJITWithObjectCache example and +/// MLIR's SimpelObjectCache. +class ObjectCache : public llvm::ObjectCache { +public: + /// Cache the given `objBuffer` for the given module `m`. The buffer contains + /// the combiled objects of the module + void notifyObjectCompiled(const llvm::Module *m, + llvm::MemoryBufferRef objBuffer) override; + + // Lookup the cache for the given module `m` or returen a nullptr. + std::unique_ptr getObject(const llvm::Module *m) override; + + /// Dump cached object to output file `filename`. + void dumpToObjectFile(llvm::StringRef filename); + +private: + llvm::StringMap> cachedObjects; +}; + class JIT { - std::unique_ptr engine; + // TODO: Should the JIT own the context ??? + Namespace &ns; + + std::unique_ptr engine; + + std::unique_ptr cache; + + /// GDB notification listener. + llvm::JITEventListener *gdbListener; + + /// Perf notification listener. + llvm::JITEventListener *perfListener; public: - JIT(SereneContext &c, Namespace &entryNS, llvm::StringRef fn = "main") {} + JIT(Namespace &ns, bool enableObjectCache = true, + bool enableGDBNotificationListener = true, + bool enablePerfNotificationListener = true); + + static MaybeJIT + make(Namespace &ns, mlir::ArrayRef sharedLibPaths = {}, + mlir::Optional jitCodeGenOptLevel = llvm::None, + bool enableObjectCache = true, bool enableGDBNotificationListener = true, + bool enablePerfNotificationListener = true); }; } // namespace serene diff --git a/include/serene/namespace.h b/include/serene/namespace.h index d72ce2b..058e6dd 100644 --- a/include/serene/namespace.h +++ b/include/serene/namespace.h @@ -53,18 +53,21 @@ class Expression; using Node = std::shared_ptr; using Ast = std::vector; } // namespace exprs + // TODO: replace the temporary `bool` by errors::Error +using MaybeModule = Result, bool>; + +// TODO: replace the temporary `bool` by errors::Error +using MaybeModuleOp = Result; /// Serene's namespaces are the unit of compilation. Any code that needs to be /// compiled has to be in a namespace. The official way to create a new /// namespace is to use the `makeNamespace` function. -class Namespace : public WithTrait { +class Namespace { private: SereneContext &ctx; bool initialized = false; std::atomic fn_counter = 0; exprs::Ast tree; - std::unique_ptr llvmModule; - mlir::ModuleOp module; public: mlir::StringRef name; @@ -82,16 +85,15 @@ public: mlir::LogicalResult setTree(exprs::Ast &); uint nextFnCounter(); - mlir::ModuleOp &getModule(); SereneContext &getContext(); - void setLLVMModule(std::unique_ptr); - llvm::Module &getLLVMModule(); - - // Generatable Trait /// Generate the IR of the namespace with respect to the compilation phase - mlir::LogicalResult generate(); - mlir::LogicalResult runPasses(); + MaybeModuleOp generate(); + /// Compile the given namespace to the llvm module. It will call the + /// `generate` method of the namespace to generate the IR. + MaybeModule compileToLLVM(); + + mlir::LogicalResult runPasses(mlir::ModuleOp &m); /// Dumps the namespace with respect to the compilation phase void dump(); @@ -102,6 +104,7 @@ public: std::shared_ptr makeNamespace(SereneContext &ctx, llvm::StringRef name, llvm::Optional filename, bool setCurrent = true); + } // namespace serene #endif diff --git a/include/serene/reader/reader.h b/include/serene/reader/reader.h index 15c70c8..68c1371 100644 --- a/include/serene/reader/reader.h +++ b/include/serene/reader/reader.h @@ -33,9 +33,8 @@ #include "serene/reader/location.h" #include "serene/serene.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" - +#include +#include #include #include #include diff --git a/include/serene/slir/generatable.h b/include/serene/slir/generatable.h index a4abf5e..1c4556a 100644 --- a/include/serene/slir/generatable.h +++ b/include/serene/slir/generatable.h @@ -100,6 +100,8 @@ std::unique_ptr toLLVMIR(Generatable &t) { // Initialize LLVM targets. llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); + + // TODO: replace this call with our own version of setupTargetTriple mlir::ExecutionEngine::setupTargetTriple(llvmModule.get()); /// Optionally run an optimization pipeline over the llvm module. diff --git a/include/serene/slir/slir.h b/include/serene/slir/slir.h index 76d1019..0e38de8 100644 --- a/include/serene/slir/slir.h +++ b/include/serene/slir/slir.h @@ -24,16 +24,17 @@ #ifndef SERENE_SLIR_H #define SERENE_SLIR_H -#include "mlir/IR/BuiltinOps.h" -#include "mlir/IR/MLIRContext.h" #include "serene/exprs/expression.h" -#include "serene/slir/generatable.h" #include +#include +#include namespace serene { -namespace slir {} // namespace slir - +namespace slir { +std::unique_ptr compileToLLVMIR(serene::SereneContext &ctx, + mlir::ModuleOp &module); +} // namespace slir } // namespace serene #endif diff --git a/include/serene/utils.h b/include/serene/utils.h index 80d3300..671392b 100644 --- a/include/serene/utils.h +++ b/include/serene/utils.h @@ -91,6 +91,33 @@ public: bool ok() const { return std::holds_alternative(contents); }; operator bool() const { return ok(); } + + const T &getValueOrFail(llvm::StringRef msg, int exitCode = 1) const & { + if (ok()) { + return getValue(); + } + + llvm::errs() << msg << "\n"; + exit(exitCode); + } + + T &getValueOrFail(llvm::StringRef msg, int exitCode = 1) & { + if (ok()) { + return getValue(); + } + + llvm::errs() << msg << "\n"; + exit(exitCode); + } + + T &&getValueOrFail(llvm::StringRef msg, int exitCode = 1) && { + if (ok()) { + return getValue(); + } + + llvm::errs() << msg << "\n"; + exit(exitCode); + } }; } // namespace serene diff --git a/resources/images/logo.svg b/resources/images/logo.svg deleted file mode 100644 index 0dba0d3..0000000 --- a/resources/images/logo.svg +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - diff --git a/resources/images/logo_with_text.svg b/resources/images/logo_with_text.svg deleted file mode 100644 index 3f188a9..0000000 --- a/resources/images/logo_with_text.svg +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/site/archetypes/default.md b/resources/site/archetypes/default.md deleted file mode 100644 index 00e77bd..0000000 --- a/resources/site/archetypes/default.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: "{{ replace .Name "-" " " | title }}" -date: {{ .Date }} -draft: true ---- - diff --git a/resources/site/config.toml b/resources/site/config.toml deleted file mode 100644 index b3940b3..0000000 --- a/resources/site/config.toml +++ /dev/null @@ -1,7 +0,0 @@ -theme = "anybodyhome" -baseURL = "https://serene-lang.org/" -languageCode = "en-us" -title = "Serene" - -[params] - subtitle = "A Simple programming language" diff --git a/resources/site/content/posts/my-first-post.md b/resources/site/content/posts/my-first-post.md deleted file mode 100644 index 8936aaf..0000000 --- a/resources/site/content/posts/my-first-post.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: "Welcome to Serene's website" -date: 2021-01-01T22:08:28Z -draft: false ---- - -We’ll have posts available here about important news and features. diff --git a/resources/site/scripts/deploy.sh b/resources/site/scripts/deploy.sh deleted file mode 100755 index 41e2b7d..0000000 --- a/resources/site/scripts/deploy.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -USER=www -HOST=core.lxsameer.com -DIR=/home/www/public/serene/ -SITEDIR=$(cd "$(dirname "$0")/.." >/dev/null 2>&1 ; pwd -P) - -hugo && rsync -avz --delete ${SITEDIR}/public/ ${USER}@${HOST}:${DIR} - -exit 0 diff --git a/resources/site/themes/anybodyhome/LICENSE.md b/resources/site/themes/anybodyhome/LICENSE.md deleted file mode 100644 index e1265aa..0000000 --- a/resources/site/themes/anybodyhome/LICENSE.md +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 YOUR_NAME_HERE - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/resources/site/themes/anybodyhome/README.md b/resources/site/themes/anybodyhome/README.md deleted file mode 100644 index 719016c..0000000 --- a/resources/site/themes/anybodyhome/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# Anybody Home? - -![anybodyhome](https://github.com/lasseborly/anybodyhome/blob/master/images/screenshot.png "Anybody Home?") - -A simple theme for simple people with simple needs. - -## Features -* __Blog only__ - Only a list of the 10 most recent posts and added pagination. There is no other pages than the main page and the post page. -* [__Highlight.js__](https://highlightjs.org/) - For all of you code needs. - -## Getting Started -From the root of you Hugo site clone the theme into `themes/anybodyhome` by running: - -`git clone https://github.com/lasseborly/anybodyhome.git themes/anybodyhome` - -## Usage -To use Anybody Home? you must first, from the root of your Hugo site, run either: - -`hugo -t anybodyhome` - -or set in you `config.toml`. - -`theme = "anybodyhome"` - -## Configuration -You can set the normal Hugo site variables in your `config.toml` but there is also some custom Anybody Home? variables you can set. This is an example of a full `config.toml`. - -```toml -theme = "anybodyhome" -baseurl = "https://hugosite.com" -languageCode = "en-us" -title = "Anybody Home?" - -[params] - subtitle = "A Simple Theme" -``` diff --git a/resources/site/themes/anybodyhome/archetypes/default.md b/resources/site/themes/anybodyhome/archetypes/default.md deleted file mode 100644 index ac36e06..0000000 --- a/resources/site/themes/anybodyhome/archetypes/default.md +++ /dev/null @@ -1,2 +0,0 @@ -+++ -+++ diff --git a/resources/site/themes/anybodyhome/layouts/404.html b/resources/site/themes/anybodyhome/layouts/404.html deleted file mode 100644 index e69de29..0000000 diff --git a/resources/site/themes/anybodyhome/layouts/_default/paginator.html b/resources/site/themes/anybodyhome/layouts/_default/paginator.html deleted file mode 100644 index b0483b7..0000000 --- a/resources/site/themes/anybodyhome/layouts/_default/paginator.html +++ /dev/null @@ -1,10 +0,0 @@ -{{ if .Paginator.HasPrev }} - - Previous Page - -{{ end }} -{{ if .Paginator.HasNext }} - - Next Page - -{{ end }} diff --git a/resources/site/themes/anybodyhome/layouts/_default/single.html b/resources/site/themes/anybodyhome/layouts/_default/single.html deleted file mode 100644 index af39af1..0000000 --- a/resources/site/themes/anybodyhome/layouts/_default/single.html +++ /dev/null @@ -1,15 +0,0 @@ -{{ partial "head.html" . }} -{{ partial "header.html" . }} -{{ $baseurl := .Site.BaseURL }} -
-
-

{{ .Title }}

- -
-
-
- {{ .Content }} -
-
-
-{{ partial "footer.html" . }} diff --git a/resources/site/themes/anybodyhome/layouts/_default/summary.html b/resources/site/themes/anybodyhome/layouts/_default/summary.html deleted file mode 100644 index f9ec1db..0000000 --- a/resources/site/themes/anybodyhome/layouts/_default/summary.html +++ /dev/null @@ -1,9 +0,0 @@ -
-

- {{ .Title }} -

- -
-

{{ .Summary }}

-
-
diff --git a/resources/site/themes/anybodyhome/layouts/index.html b/resources/site/themes/anybodyhome/layouts/index.html deleted file mode 100644 index e646657..0000000 --- a/resources/site/themes/anybodyhome/layouts/index.html +++ /dev/null @@ -1,17 +0,0 @@ -{{ partial "head.html" . }} - - - -{{ partial "header.html" . }} - -
- {{ range (.Paginator 5).Pages }} - {{ .Render "summary" }} - {{ end }} -
- -{{ partial "paginator.html" . }} - -{{ partial "footer.html" . }} - - diff --git a/resources/site/themes/anybodyhome/layouts/partials/footer.html b/resources/site/themes/anybodyhome/layouts/partials/footer.html deleted file mode 100644 index e69de29..0000000 diff --git a/resources/site/themes/anybodyhome/layouts/partials/head.html b/resources/site/themes/anybodyhome/layouts/partials/head.html deleted file mode 100644 index 1b795d0..0000000 --- a/resources/site/themes/anybodyhome/layouts/partials/head.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - {{ .Site.Title }} - - - - - - - - - - - - - diff --git a/resources/site/themes/anybodyhome/layouts/partials/header.html b/resources/site/themes/anybodyhome/layouts/partials/header.html deleted file mode 100644 index 37fbaac..0000000 --- a/resources/site/themes/anybodyhome/layouts/partials/header.html +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/resources/site/themes/anybodyhome/layouts/partials/paginator.html b/resources/site/themes/anybodyhome/layouts/partials/paginator.html deleted file mode 100644 index 2fac42a..0000000 --- a/resources/site/themes/anybodyhome/layouts/partials/paginator.html +++ /dev/null @@ -1,12 +0,0 @@ -
-{{ if .Paginator.HasPrev }} - -{{ end }} -{{ if .Paginator.HasNext }} - -{{ end }} -
diff --git a/resources/site/themes/anybodyhome/layouts/summary.html b/resources/site/themes/anybodyhome/layouts/summary.html deleted file mode 100644 index 743b45a..0000000 --- a/resources/site/themes/anybodyhome/layouts/summary.html +++ /dev/null @@ -1,9 +0,0 @@ -
-

{{ .Title }}

-

{{ .Date.Format "2. January, 2006"}}

-
-
- {{ .Summary }} -
-
-
diff --git a/resources/site/themes/anybodyhome/static/css/styles.css b/resources/site/themes/anybodyhome/static/css/styles.css deleted file mode 100644 index c145e67..0000000 --- a/resources/site/themes/anybodyhome/static/css/styles.css +++ /dev/null @@ -1,162 +0,0 @@ -@import 'https://fonts.googleapis.com/css?family=Lobster|Quicksand|Cutive+Mono'; - -body { - width: 600px; - margin: 0 auto; - font-size: 18px; - font-weight: 400; - font-family: 'Quicksand', sans-serif; - min-height: 100vh; - display: flex; - flex-direction: column; - color: #000; -} - -main { - flex: 1; -} - -@media(max-device-width: 667px) { - body { - width: 100%; - box-sizing: border-box; - padding: 0 80px; - } -} - -a { - text-decoration: none; - color: #336699; -} - -a:visited { - color: #333; -} - -a:hover { - color: #C0C0C0; -} - -p { - line-height: 1.4; - text-align: justify; -} - -@media(max-device-width: 667px) { - p { - font-size: 3em; - } -} - - -img { - max-width: 100%; -} - -section#header { - margin: 40px 0; -} - -section#header h1 { - font-size: 2em; - text-align: center; - font-family: 'Lobster', cursive; - margin: 0 0 9px 0; -} - -@media(max-device-width: 667px) { - section#header h1 { - font-size: 6em; - margin: 0 0 30px 0; - } -} - -section#header h2 { - font-family: 'Cutive Mono', monospace; - font-size: 0.8em; - text-align: center; -} - -@media(max-device-width: 667px) { - section#header h2 { - font-size: 1.5em; - } -} - -section.summary { - padding: 0 0 0 10px; - border-left: 1px solid black; - margin: 0 0 60px 0; -} - -@media(max-device-width: 667px) { - section.summary { - padding: 0 0 0 0; - border-left: 0px solid black; - } -} - -section.summary article { - margin: 15px 0 0 0; -} - -section h2 { - font-size: 1.3em; - font-family: 'Lobster', cursive; -} - -@media(max-device-width: 667px) { - section h2 { - font-size: 4em; - padding-bottom: 5px; - } -} - -section h2 a { - color: #000; -} - -section time { - font-family: 'Cutive Mono', monospace; - margin: 0 0 0 2px; - font-size: 0.8em; -} - -section article { - margin: 15px 0 0 0; -} - -section#paginator { - margin: 0 0 140px 0; - font-family: 'Lobster', cursive; -} - -@media(max-device-width: 667px) { - section#paginator { - font-size: 5em; - padding-bottom: 60px; - } -} - -section#paginator #next { - float: right; -} - -#post { - margin: 0 0 100px 0; -} - -.videoWrapper { - position: relative; - padding-bottom: 56.25%; /* 16:9 */ - padding-top: 25px; - height: 0; - margin: 10px; -} -.videoWrapper iframe { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} diff --git a/resources/site/themes/anybodyhome/theme.toml b/resources/site/themes/anybodyhome/theme.toml deleted file mode 100644 index 40e53ee..0000000 --- a/resources/site/themes/anybodyhome/theme.toml +++ /dev/null @@ -1,12 +0,0 @@ -name = "Anybody Home" -license = "MIT" -licenselink = "https://github.com/lasseborly/anybodyhome/blob/master/LICENSE.md" -description = "A simple theme for simple people with simple needs" -homepage = "https://github.com/lasseborly/anybodyhome/" -tags = ["clean", "simple"] -features = ["highlightjs", "Blog only"] -min_version = 0.16 - -[author] - name = "Lasse Borly" - homepage = "https://lasseborly.com/" diff --git a/src/serene/CMakeLists.txt b/src/serene/CMakeLists.txt index fe6b367..a92821a 100644 --- a/src/serene/CMakeLists.txt +++ b/src/serene/CMakeLists.txt @@ -61,6 +61,7 @@ add_library(serene errors/error.cpp # IR + slir/slir.cpp slir/dialect.cpp slir/value_op.cpp slir/generatable.cpp diff --git a/src/serene/exprs/def.cpp b/src/serene/exprs/def.cpp index 1af59a3..857b30b 100644 --- a/src/serene/exprs/def.cpp +++ b/src/serene/exprs/def.cpp @@ -115,14 +115,13 @@ MaybeNode Def::make(SereneContext &ctx, List *list) { } }; -void Def::generateIR(serene::Namespace &ns) { - auto &module = ns.getModule(); +void Def::generateIR(serene::Namespace &ns, mlir::ModuleOp &m) { if (value->getType() == ExprType::Fn) { - value->generateIR(ns); + value->generateIR(ns, m); return; } - module.emitError("Def: not implemented!"); + m.emitError("Def: not implemented!"); }; } // namespace exprs } // namespace serene diff --git a/src/serene/exprs/fn.cpp b/src/serene/exprs/fn.cpp index 38fbd3a..9d5fc7c 100644 --- a/src/serene/exprs/fn.cpp +++ b/src/serene/exprs/fn.cpp @@ -105,10 +105,10 @@ MaybeNode Fn::make(SereneContext &ctx, List *list) { return makeSuccessfulNode(ctx, list->location, *args, body); }; -void Fn::generateIR(serene::Namespace &ns) { +void Fn::generateIR(serene::Namespace &ns, mlir::ModuleOp &m) { auto loc = slir::toMLIRLocation(ns, location.start); auto &ctx = ns.getContext(); - auto &module = ns.getModule(); + mlir::OpBuilder builder(&ctx.mlirContext); // llvm::SmallVector arg_types; @@ -118,7 +118,7 @@ void Fn::generateIR(serene::Namespace &ns) { auto *argSym = llvm::dyn_cast(arg.get()); if (!argSym) { - module->emitError(llvm::formatv( + m->emitError(llvm::formatv( "Arguments of a function have to be symbols. Fn: '{0}'", name)); return; } @@ -134,7 +134,7 @@ void Fn::generateIR(serene::Namespace &ns) { builder.getStringAttr("public")); if (!fn) { - module.emitError(llvm::formatv("Can't create the function '{0}'", name)); + m.emitError(llvm::formatv("Can't create the function '{0}'", name)); } auto *entryBlock = new mlir::Block(); @@ -146,11 +146,11 @@ void Fn::generateIR(serene::Namespace &ns) { mlir::ReturnOp returnOp = builder.create(loc, retVal); if (!returnOp) { - module.emitError( + m.emitError( llvm::formatv("Can't create the return value of function '{0}'", name)); return; } - module.push_back(fn); + m.push_back(fn); }; } // namespace exprs } // namespace serene diff --git a/src/serene/exprs/number.cpp b/src/serene/exprs/number.cpp index 22c8287..46b9ab9 100644 --- a/src/serene/exprs/number.cpp +++ b/src/serene/exprs/number.cpp @@ -46,15 +46,14 @@ bool Number::classof(const Expression *e) { int Number::toI64() { return std::stoi(this->value); }; -void Number::generateIR(serene::Namespace &ns) { +void Number::generateIR(serene::Namespace &ns, mlir::ModuleOp &m) { mlir::OpBuilder builder(&ns.getContext().mlirContext); - mlir::ModuleOp &module = ns.getModule(); auto op = builder.create( serene::slir::toMLIRLocation(ns, location.start), toI64()); if (op) { - module.push_back(op); + m.push_back(op); } // TODO: in case of failure attach the error to the NS }; diff --git a/src/serene/jit.cpp b/src/serene/jit.cpp new file mode 100644 index 0000000..79fde35 --- /dev/null +++ b/src/serene/jit.cpp @@ -0,0 +1,281 @@ +/* + * Serene programming language. + * + * Copyright (c) 2020 Sameer Rahmani + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Most of the codes in this file is borrowed from the LLVM project so the LLVM + * license applies here + */ + +#include "serene/jit.h" + +#include "serene/context.h" +#include "serene/namespace.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace serene { + +static std::string makePackedFunctionName(llvm::StringRef name) { + return "_serene_" + name.str(); +} + +static void packFunctionArguments(llvm::Module *module) { + auto &ctx = module->getContext(); + llvm::IRBuilder<> builder(ctx); + llvm::DenseSet interfaceFunctions; + for (auto &func : module->getFunctionList()) { + if (func.isDeclaration()) { + continue; + } + if (interfaceFunctions.count(&func)) { + continue; + } + + // Given a function `foo(<...>)`, define the interface function + // `mlir_foo(i8**)`. + auto newType = llvm::FunctionType::get( + builder.getVoidTy(), builder.getInt8PtrTy()->getPointerTo(), + /*isVarArg=*/false); + auto newName = makePackedFunctionName(func.getName()); + auto funcCst = module->getOrInsertFunction(newName, newType); + llvm::Function *interfaceFunc = + llvm::cast(funcCst.getCallee()); + interfaceFunctions.insert(interfaceFunc); + + // Extract the arguments from the type-erased argument list and cast them to + // the proper types. + auto bb = llvm::BasicBlock::Create(ctx); + bb->insertInto(interfaceFunc); + builder.SetInsertPoint(bb); + llvm::Value *argList = interfaceFunc->arg_begin(); + llvm::SmallVector args; + args.reserve(llvm::size(func.args())); + for (auto &indexedArg : llvm::enumerate(func.args())) { + llvm::Value *argIndex = llvm::Constant::getIntegerValue( + builder.getInt64Ty(), llvm::APInt(64, indexedArg.index())); + llvm::Value *argPtrPtr = + builder.CreateGEP(builder.getInt8PtrTy(), argList, argIndex); + llvm::Value *argPtr = + builder.CreateLoad(builder.getInt8PtrTy(), argPtrPtr); + llvm::Type *argTy = indexedArg.value().getType(); + argPtr = builder.CreateBitCast(argPtr, argTy->getPointerTo()); + llvm::Value *arg = builder.CreateLoad(argTy, argPtr); + args.push_back(arg); + } + + // Call the implementation function with the extracted arguments. + llvm::Value *result = builder.CreateCall(&func, args); + + // Assuming the result is one value, potentially of type `void`. + if (!result->getType()->isVoidTy()) { + llvm::Value *retIndex = llvm::Constant::getIntegerValue( + builder.getInt64Ty(), llvm::APInt(64, llvm::size(func.args()))); + llvm::Value *retPtrPtr = + builder.CreateGEP(builder.getInt8PtrTy(), argList, retIndex); + llvm::Value *retPtr = + builder.CreateLoad(builder.getInt8PtrTy(), retPtrPtr); + retPtr = builder.CreateBitCast(retPtr, result->getType()->getPointerTo()); + builder.CreateStore(result, retPtr); + } + + // The interface function returns void. + builder.CreateRetVoid(); + } +}; + +void ObjectCache::notifyObjectCompiled(const llvm::Module *m, + llvm::MemoryBufferRef objBuffer) { + cachedObjects[m->getModuleIdentifier()] = + llvm::MemoryBuffer::getMemBufferCopy(objBuffer.getBuffer(), + objBuffer.getBufferIdentifier()); +} + +std::unique_ptr +ObjectCache::getObject(const llvm::Module *m) { + auto i = cachedObjects.find(m->getModuleIdentifier()); + + if (i == cachedObjects.end()) { + JIT_LOG("No object for " << m->getModuleIdentifier() + << " in cache. Compiling.\n"); + return nullptr; + } + JIT_LOG("Object for " << m->getModuleIdentifier() << " loaded from cache.\n"); + return llvm::MemoryBuffer::getMemBuffer(i->second->getMemBufferRef()); +} + +void ObjectCache::dumpToObjectFile(llvm::StringRef outputFilename) { + // Set up the output file. + std::string errorMessage; + auto file = mlir::openOutputFile(outputFilename, &errorMessage); + if (!file) { + llvm::errs() << errorMessage << "\n"; + return; + } + + // Dump the object generated for a single module to the output file. + // TODO: Replace this with a runtime check + assert(cachedObjects.size() == 1 && "Expected only one object entry."); + + auto &cachedObject = cachedObjects.begin()->second; + file->os() << cachedObject->getBuffer(); + file->keep(); +} + +JIT::JIT(Namespace &ns, bool enableObjectCache, + bool enableGDBNotificationListener, + bool enablePerfNotificationListener) + : ns(ns), cache(enableObjectCache ? new ObjectCache() : nullptr), + gdbListener(enableGDBNotificationListener + ? llvm::JITEventListener::createGDBRegistrationListener() + : nullptr), + perfListener(enablePerfNotificationListener + ? llvm::JITEventListener::createPerfJITEventListener() + : nullptr){}; + +MaybeJIT JIT::make(Namespace &ns, + mlir::ArrayRef sharedLibPaths, + mlir::Optional jitCodeGenOptLevel, + bool enableObjectCache, bool enableGDBNotificationListener, + bool enablePerfNotificationListener) { + + auto jitEngine = std::make_unique(ns, enableObjectCache, + enableGDBNotificationListener, + enablePerfNotificationListener); + + // Why not the llvmcontext from the SereneContext?? + // Sice we're going to pass the ownership of this context to a thread + // safe module later on and we will only create the jit function wrappers + // with it, then it is fine to use a new context. + // + // What might go wrong? + // in a repl env when we have to create new modules on top of each other + // having two different contex might be a problem, but i think since we + // use the first context to generate the IR and the second one to just + // run it. + std::unique_ptr ctx(new llvm::LLVMContext); + + if (ns.generate().failed()) { + // TODO: Return a MaybeJIT::error() with a proper error + throw std::runtime_error("Can't compile the slir module"); + } + + auto &llvmModule = ns.getLLVMModule(); + packFunctionArguments(&llvmModule); + + auto dataLayout = llvmModule.getDataLayout(); + + // Callback to create the object layer with symbol resolution to current + // process and dynamically linked libraries. + auto objectLinkingLayerCreator = [&](llvm::orc::ExecutionSession &session, + const llvm::Triple &tt) { + auto objectLayer = + std::make_unique(session, []() { + return std::make_unique(); + }); + + // Register JIT event listeners if they are enabled. + if (jitEngine->gdbListener) + objectLayer->registerJITEventListener(*jitEngine->gdbListener); + if (jitEngine->perfListener) + objectLayer->registerJITEventListener(*jitEngine->perfListener); + + // COFF format binaries (Windows) need special handling to deal with + // exported symbol visibility. + // cf llvm/lib/ExecutionEngine/Orc/LLJIT.cpp LLJIT::createObjectLinkingLayer + llvm::Triple targetTriple(llvm::Twine(llvmModule.getTargetTriple())); + if (targetTriple.isOSBinFormatCOFF()) { + objectLayer->setOverrideObjectFlagsWithResponsibilityFlags(true); + objectLayer->setAutoClaimResponsibilityForObjectSymbols(true); + } + + // Resolve symbols from shared libraries. + for (auto libPath : sharedLibPaths) { + auto mb = llvm::MemoryBuffer::getFile(libPath); + if (!mb) { + llvm::errs() << "Failed to create MemoryBuffer for: " << libPath + << "\nError: " << mb.getError().message() << "\n"; + continue; + } + auto &JD = session.createBareJITDylib(std::string(libPath)); + auto loaded = llvm::orc::DynamicLibrarySearchGenerator::Load( + libPath.data(), dataLayout.getGlobalPrefix()); + if (!loaded) { + llvm::errs() << "Could not load " << libPath << ":\n " + << loaded.takeError() << "\n"; + continue; + } + + JD.addGenerator(std::move(*loaded)); + cantFail(objectLayer->add(JD, std::move(mb.get()))); + } + + return objectLayer; + }; + + // Callback to inspect the cache and recompile on demand. This follows Lang's + // LLJITWithObjectCache example. + auto compileFunctionCreator = [&](llvm::orc::JITTargetMachineBuilder JTMB) + -> llvm::Expected< + std::unique_ptr> { + if (jitCodeGenOptLevel) + JTMB.setCodeGenOptLevel(jitCodeGenOptLevel.getValue()); + auto TM = JTMB.createTargetMachine(); + if (!TM) + return TM.takeError(); + return std::make_unique( + std::move(*TM), jitEngine->cache.get()); + }; + + // Create the LLJIT by calling the LLJITBuilder with 2 callbacks. + auto jit = + cantFail(llvm::orc::LLJITBuilder() + .setCompileFunctionCreator(compileFunctionCreator) + .setObjectLinkingLayerCreator(objectLinkingLayerCreator) + .create()); + + // Add a ThreadSafemodule to the engine and return. + llvm::orc::ThreadSafeModule tsm(std::move(llvmModule), std::move(ctx)); + + // TODO: Do we need a module transformer here??? + + cantFail(jit->addIRModule(std::move(tsm))); + jitEngine->engine = std::move(jit); + + // Resolve symbols that are statically linked in the current process. + llvm::orc::JITDylib &mainJD = jitEngine->engine->getMainJITDylib(); + mainJD.addGenerator( + cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( + dataLayout.getGlobalPrefix()))); + + return MaybeJIT::success(std::move(jitEngine)); +}; +} // namespace serene diff --git a/src/serene/namespace.cpp b/src/serene/namespace.cpp index ae78604..8e51732 100644 --- a/src/serene/namespace.cpp +++ b/src/serene/namespace.cpp @@ -1,4 +1,4 @@ -/** +/* * Serene programming language. * * Copyright (c) 2020 Sameer Rahmani @@ -24,15 +24,18 @@ #include "serene/namespace.h" -#include "mlir/IR/Builders.h" -#include "mlir/IR/BuiltinOps.h" #include "serene/context.h" +#include "serene/errors/constants.h" #include "serene/exprs/expression.h" #include "serene/llvm/IR/Value.h" +#include "serene/slir/slir.h" #include #include #include +#include +#include +#include #include #include @@ -46,9 +49,6 @@ Namespace::Namespace(SereneContext &ctx, llvm::StringRef ns_name, : ctx(ctx), name(ns_name) { - mlir::OpBuilder builder(&ctx.mlirContext); - // TODO: Fix the unknown location by pointing to the `ns` form - module = mlir::ModuleOp::create(builder.getUnknownLoc(), ns_name); if (filename.hasValue()) { this->filename.emplace(filename.getValue().str()); } @@ -80,49 +80,60 @@ makeNamespace(SereneContext &ctx, llvm::StringRef name, uint Namespace::nextFnCounter() { return fn_counter++; }; -mlir::ModuleOp &Namespace::getModule() { return this->module; }; SereneContext &Namespace::getContext() { return this->ctx; }; -void Namespace::setLLVMModule(std::unique_ptr m) { - this->llvmModule = std::move(m); -}; -llvm::Module &Namespace::getLLVMModule() { - // TODO: check the llvm module to make sure it is initialized - return *llvmModule; -}; +MaybeModuleOp Namespace::generate() { + mlir::OpBuilder builder(&ctx.mlirContext); + // TODO: Fix the unknown location by pointing to the `ns` form + // TODO: We need to call `erase` method of module somewhere to clean it up + // maybe use a unique ptr? + auto module = mlir::ModuleOp::create(builder.getUnknownLoc(), name); -mlir::LogicalResult Namespace::generate() { for (auto &x : getTree()) { - x->generateIR(*this); + x->generateIR(*this, module); } - if (mlir::failed(runPasses())) { + if (mlir::failed(runPasses(module))) { // TODO: throw a proper errer module.emitError("Failure in passes!"); - return mlir::failure(); + return MaybeModuleOp::error(true); } - if (ctx.getTargetPhase() >= CompilationPhase::IR) { - auto llvmTmpModule = slir::toLLVMIR(*this); - this->llvmModule = std::move(llvmTmpModule); - } - - return mlir::success(); + return MaybeModuleOp::success(module); } -mlir::LogicalResult Namespace::runPasses() { return ctx.pm.run(module); }; +mlir::LogicalResult Namespace::runPasses(mlir::ModuleOp &m) { + return ctx.pm.run(m); +}; void Namespace::dump() { llvm::outs() << "\nMLIR: \n"; - module->dump(); - if (llvmModule) { - llvm::outs() << "\nLLVM IR: \n"; - llvmModule->dump(); + auto maybeModuleOp = generate(); + + if (!maybeModuleOp) { + llvm::outs() << "Failed to generate the IR.\n"; + return; } + + maybeModuleOp.getValue().dump(); }; -Namespace::~Namespace() { this->module.erase(); } -namespace slir { -template class Generatable; -} +MaybeModule Namespace::compileToLLVM() { + auto m = generate(); + + if (!m) { + NAMESPACE_LOG("IR generation failed for '" << name << "'"); + return MaybeModule::error(true); + } + + if (ctx.getTargetPhase() >= CompilationPhase::IR) { + return MaybeModule::success( + ::serene::slir::compileToLLVMIR(ctx, m.getValue())); + } + + return MaybeModule::error(true); +}; + +Namespace::~Namespace(){}; + } // namespace serene diff --git a/src/serene/slir/slir.cpp b/src/serene/slir/slir.cpp new file mode 100644 index 0000000..91b64db --- /dev/null +++ b/src/serene/slir/slir.cpp @@ -0,0 +1,64 @@ +/* -*- C++ -*- + * Serene programming language. + * + * Copyright (c) 2019-2021 Sameer Rahmani + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "serene/slir/slir.h" + +namespace serene { +namespace slir { + +std::unique_ptr compileToLLVMIR(serene::SereneContext &ctx, + mlir::ModuleOp &module) { + // Register the translation to LLVM IR with the MLIR context. + mlir::registerLLVMDialectTranslation(ctx.mlirContext); + + // Convert the module to LLVM IR in a new LLVM IR context. + auto llvmModule = mlir::translateModuleToLLVMIR(module, ctx.llvmContext); + if (!llvmModule) { + // TODO: Return a Result type instead + llvm::errs() << "Failed to emit LLVM IR\n"; + throw std::runtime_error("Failed to emit LLVM IR\n"); + } + + // Initialize LLVM targets. + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + // TODO: replace this call with our own version of setupTargetTriple + mlir::ExecutionEngine::setupTargetTriple(llvmModule.get()); + + /// Optionally run an optimization pipeline over the llvm module. + auto optPipeline = mlir::makeOptimizingTransformer( + /*optLevel=*/ctx.getOptimizatioLevel(), /*sizeLevel=*/0, + /*targetMachine=*/nullptr); + if (auto err = optPipeline(llvmModule.get())) { + llvm::errs() << "Failed to optimize LLVM IR " << err << "\n"; + throw std::runtime_error("Failed to optimize LLVM IR"); + } + + return llvmModule; +}; + +} // namespace slir + +} // namespace serene