Setup the CLI options around the JIT and make it the context owner

This commit is contained in:
Sameer Rahmani 2022-06-14 18:03:11 +01:00
parent c2fb6bf8cb
commit b71701a640
9 changed files with 202 additions and 71 deletions

View File

@ -247,13 +247,13 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
# Create the tools we use to compile Serene
add_subdirectory(serene-tblgen)
# Binary tools of the compiler
# add_subdirectory(serenec)
# add_subdirectory(serene-repl)
# The compiled library code is here
add_subdirectory(libserene)
# The static library containing builtin special forms and functions
add_subdirectory(core)
# Binary tools of the compiler
add_subdirectory(serenec)
# add_subdirectory(serene-repl)
# add_subdirectory(devtools)

View File

@ -20,6 +20,7 @@
#define SERENE_CONTEXT_H
#include "serene/export.h" // for SERENE_EXPORT
#include "serene/options.h"
#include <llvm/ADT/Triple.h> // for Triple
#include <llvm/ADT/Twine.h> // for Twine
@ -56,24 +57,6 @@ enum class CompilationPhase {
/// via the JIT use an appropriate function in the `serene.core` ns.
SERENE_EXPORT void terminate(SereneContext &ctx, int exitCode);
/// Options describes the compiler options that can be passed to the
/// compiler via command line. Anything that user should be able to
/// tweak about the compiler has to end up here regardless of the
/// different subsystem that might use it.
struct SERENE_EXPORT Options {
/// Whether to use colors for the output or not
bool withColors = true;
// JIT related flags
bool JITenableObjectCache = true;
bool JITenableGDBNotificationListener = true;
bool JITenablePerfNotificationListener = true;
bool JITLazy = false;
Options() = default;
};
class SERENE_EXPORT SereneContext {
public:
@ -100,6 +83,9 @@ public:
return std::make_unique<llvm::LLVMContext>();
};
/// Setup the load path for namespace lookups
void setLoadPaths(std::vector<std::string> &dirs) { loadPaths.swap(dirs); };
// JIT JITDylib related functions ---
// TODO: For Dylib related functions, make sure that the namespace in questoin
@ -117,7 +103,7 @@ public:
private:
CompilationPhase targetPhase;
std::vector<std::string> loadPaths;
/// A vector of pointers to all the jitDylibs for namespaces. Usually
/// There will be only one pre NS but in case of forceful reloads of a
/// namespace there will be more.

View File

@ -32,7 +32,8 @@
#ifndef SERENE_JIT_HALLEY_H
#define SERENE_JIT_HALLEY_H
#include "serene/export.h" // for SERENE...
#include "serene/context.h" // for Serene...
#include "serene/export.h" // for SERENE...
#include <llvm/ADT/SmallVector.h> // for SmallV...
#include <llvm/ADT/StringMap.h> // for StringMap
@ -59,12 +60,15 @@ class Module;
} // namespace llvm
namespace serene {
class SereneContext;
namespace jit {
class Halley;
using MaybeEngine = llvm::Expected<std::unique_ptr<Halley>>;
// Why? This is the lazy man's way to make it easier to replace
// the class under the hood later on to test different implementaion
// with the same interface
using Engine = Halley;
using EnginePtr = std::unique_ptr<Engine>;
using MaybeEngine = llvm::Expected<EnginePtr>;
using MaybeEnginePtr = llvm::Expected<void (*)(void **)>;
/// A simple object cache following Lang's LLJITWithObjectCache example and
@ -99,17 +103,20 @@ class SERENE_EXPORT Halley {
llvm::orc::JITTargetMachineBuilder jtmb;
llvm::DataLayout &dl;
SereneContext &ctx;
std::unique_ptr<SereneContext> ctx;
bool isLazy = false;
public:
Halley(serene::SereneContext &ctx, llvm::orc::JITTargetMachineBuilder &&jtmb,
llvm::DataLayout &&dl);
Halley(std::unique_ptr<SereneContext> ctx,
llvm::orc::JITTargetMachineBuilder &&jtmb, llvm::DataLayout &&dl);
static MaybeEngine make(serene::SereneContext &ctx,
static MaybeEngine make(std::unique_ptr<SereneContext> sereneCtxPtr,
llvm::orc::JITTargetMachineBuilder &&jtmb);
SereneContext &getContext() { return *ctx; };
void setEngine(std::unique_ptr<llvm::orc::LLJIT> e, bool isLazy);
/// Looks up a packed-argument function with the given sym name and returns a
/// pointer to it. Propagates errors in case of failure.
@ -156,7 +163,7 @@ public:
void dumpToObjectFile(llvm::StringRef filename);
};
MaybeEngine makeHalleyJIT(SereneContext &ctx);
MaybeEngine makeHalleyJIT(std::unique_ptr<SereneContext> ctx);
} // namespace jit
} // namespace serene

View File

@ -0,0 +1,44 @@
/* -*- C++ -*-
* Serene Programming Language
*
* Copyright (c) 2019-2022 Sameer Rahmani <lxsameer@gnu.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SERENE_OPTIONS_H
#define SERENE_OPTIONS_H
#include "serene/export.h"
namespace serene {
/// Options describes the compiler options that can be passed to the
/// compiler via command line. Anything that user should be able to
/// tweak about the compiler has to end up here regardless of the
/// different subsystem that might use it.
struct SERENE_EXPORT Options {
/// Whether to use colors for the output or not
bool withColors = true;
// JIT related flags
bool JITenableObjectCache = true;
bool JITenableGDBNotificationListener = true;
bool JITenablePerfNotificationListener = true;
bool JITLazy = false;
// namespace serene Options() = default;
};
} // namespace serene
#endif

View File

@ -20,11 +20,25 @@
#define SERENE_SERENE_H
#include "serene/export.h" // for SERENE_EXPORT
#include "serene/jit/halley.h" // for MaybeEngine
#include "serene/jit/halley.h" // for Engine, MaybeEngine
#include "serene/options.h" // for Options
namespace serene {
serene::jit::MaybeEngine SERENE_EXPORT makeEngine();
/// Clinet applications have to call this function before any interaction
/// with the Serene's compiler API.
void SERENE_EXPORT initSerene();
/// Register the global CLI options of the serene compiler. If the client
/// application needs to setup the compilers options automatically use this
/// function in conjunction with `applySereneCLOptions`.
void SERENE_EXPORT registerSereneCLOptions();
/// Applies the global compiler options on the give \p SereneContext. This
/// function has to be called after `llvm::cl::ParseCommandLineOptions`.
void SERENE_EXPORT applySereneCLOptions(serene::jit::Engine &engine);
serene::jit::MaybeEngine SERENE_EXPORT makeEngine(Options opts = Options());
} // namespace serene
#endif

View File

@ -89,4 +89,7 @@ target_compile_definitions(
target_link_libraries(serene PRIVATE
LLVMOrcJIT
LLVMX86CodeGen
LLVMX86AsmParser
${llvm_libs})

View File

@ -15,9 +15,11 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "serene/jit/halley.h"
#include "serene/context.h" // for Seren...
#include "serene/options.h" // for Options
#include <system_error> // for error...
@ -97,17 +99,17 @@ void ObjectCache::dumpToObjectFile(llvm::StringRef outputFilename) {
file->keep();
}
Halley::Halley(serene::SereneContext &ctx,
Halley::Halley(std::unique_ptr<SereneContext> ctx,
llvm::orc::JITTargetMachineBuilder &&jtmb, llvm::DataLayout &&dl)
: cache(ctx.opts.JITenableObjectCache ? new ObjectCache() : nullptr),
gdbListener(ctx.opts.JITenableGDBNotificationListener
: cache(ctx->opts.JITenableObjectCache ? new ObjectCache() : nullptr),
gdbListener(ctx->opts.JITenableGDBNotificationListener
? llvm::JITEventListener::createGDBRegistrationListener()
: nullptr),
perfListener(ctx.opts.JITenablePerfNotificationListener
perfListener(ctx->opts.JITenablePerfNotificationListener
? llvm::JITEventListener::createPerfJITEventListener()
: nullptr),
jtmb(jtmb), dl(dl), ctx(ctx){};
jtmb(jtmb), dl(dl), ctx(std::move(ctx)){};
// MaybeJITPtr Halley::lookup(exprs::Symbol &sym) const {
// HALLEY_LOG("Looking up: " << sym.toString());
@ -170,16 +172,15 @@ void Halley::dumpToObjectFile(llvm::StringRef filename) {
cache->dumpToObjectFile(filename);
};
MaybeEngine Halley::make(SereneContext &serene_ctx,
MaybeEngine Halley::make(std::unique_ptr<SereneContext> sereneCtxPtr,
llvm::orc::JITTargetMachineBuilder &&jtmb) {
auto dl = jtmb.getDefaultDataLayoutForTarget();
if (!dl) {
return dl.takeError();
}
auto jitEngine =
std::make_unique<Halley>(serene_ctx, std::move(jtmb), std::move(*dl));
auto jitEngine = std::make_unique<Halley>(std::move(sereneCtxPtr),
std::move(jtmb), std::move(*dl));
// Why not the llvmcontext from the SereneContext??
// Sice we're going to pass the ownership of this context to a thread
@ -193,6 +194,9 @@ MaybeEngine Halley::make(SereneContext &serene_ctx,
// run it.
std::unique_ptr<llvm::LLVMContext> ctx(new llvm::LLVMContext);
// Since we moved the original sereneCtxPtr into the engine.
auto &sereneCtx = jitEngine->getContext();
// Callback to create the object layer with symbol resolution to current
// process and dynamically linked libraries.
auto objectLinkingLayerCreator = [&](llvm::orc::ExecutionSession &session,
@ -217,7 +221,7 @@ MaybeEngine Halley::make(SereneContext &serene_ctx,
// cf llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
// LLJIT::createObjectLinkingLayer
if (serene_ctx.triple.isOSBinFormatCOFF()) {
if (sereneCtx.triple.isOSBinFormatCOFF()) {
objectLayer->setOverrideObjectFlagsWithResponsibilityFlags(true);
objectLayer->setAutoClaimResponsibilityForObjectSymbols(true);
}
@ -252,7 +256,7 @@ MaybeEngine Halley::make(SereneContext &serene_ctx,
-> llvm::Expected<
std::unique_ptr<llvm::orc::IRCompileLayer::IRCompiler>> {
llvm::CodeGenOpt::Level jitCodeGenOptLevel =
static_cast<llvm::CodeGenOpt::Level>(serene_ctx.getOptimizatioLevel());
static_cast<llvm::CodeGenOpt::Level>(sereneCtx.getOptimizatioLevel());
JTMB.setCodeGenOptLevel(jitCodeGenOptLevel);
@ -265,7 +269,7 @@ MaybeEngine Halley::make(SereneContext &serene_ctx,
std::move(*targetMachine), jitEngine->cache.get());
};
if (serene_ctx.opts.JITLazy) {
if (sereneCtx.opts.JITLazy) {
// Setup a LLLazyJIT instance to the times that latency is important
// for example in a REPL. This way
@ -308,10 +312,10 @@ MaybeEngine Halley::make(SereneContext &serene_ctx,
return MaybeEngine(std::move(jitEngine));
};
MaybeEngine makeHalleyJIT(SereneContext &ctx) {
MaybeEngine makeHalleyJIT(std::unique_ptr<SereneContext> ctx) {
llvm::orc::JITTargetMachineBuilder jtmb(ctx.triple);
auto maybeJIT = Halley::make(ctx, std::move(jtmb));
llvm::orc::JITTargetMachineBuilder jtmb(ctx->triple);
auto maybeJIT = Halley::make(std::move(ctx), std::move(jtmb));
if (!maybeJIT) {
return maybeJIT.takeError();
}

View File

@ -18,13 +18,75 @@
#include "serene/serene.h"
#include "serene/jit/halley.h" // for makeHalleyJIT, MaybeEngine
#include "serene/context.h" // for SereneContext, makeSereneCon...
#include "serene/jit/halley.h" // for makeHalleyJIT, Engine, Maybe...
#include <llvm/ADT/StringRef.h> // for StringRef
#include <llvm/Support/CommandLine.h> // for list, cat, desc, MiscFlags
#include <llvm/Support/ManagedStatic.h> // for ManagedStatic
#include <llvm/Support/TargetSelect.h> // for InitializeAllAsmParsers, Ini...
#include <string> // for string
#include <utility> // for move
namespace serene {
class SereneContext;
// CLI Option ----------------
serene::jit::MaybeEngine makeEngine(SereneContext &ctx) {
return serene::jit::makeHalleyJIT(ctx);
/// All the global CLI option ar defined here. If you need to add a new global
/// option
/// make sure that you are handling it in `applySereneCLOptions` too.
struct SereneOptions {
llvm::cl::OptionCategory clOptionsCategory{"Discovery options"};
llvm::cl::list<std::string> loadPaths{
"l", llvm::cl::desc("The load path to use for compilation."),
llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::PositionalEatsArgs,
llvm::cl::cat(clOptionsCategory)};
llvm::cl::list<std::string> sharedLibraryPaths{
"sl", llvm::cl::desc("Where to find shared libraries"),
llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::PositionalEatsArgs,
llvm::cl::cat(clOptionsCategory)};
};
static llvm::ManagedStatic<SereneOptions> options;
void registerSereneCLOptions() {
// Make sure that the options struct has been constructed.
*options;
// #ifdef SERENE_WITH_MLIR_CL_OPTION
// // mlir::registerAsmPrinterCLOptions();
// mlir::registerMLIRContextCLOptions();
// mlir::registerPassManagerCLOptions();
// #endif
}
void applySereneCLOptions(serene::jit::Engine &engine) {
if (!options.isConstructed()) {
return;
}
auto &ctx = engine.getContext();
ctx.setLoadPaths(options->loadPaths);
// #ifdef SERENE_WITH_MLIR_CL_OPTION
// mlir::applyPassManagerCLOptions(ctx.pm);
// #endif
}
void initSerene() {
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllAsmPrinters();
};
serene::jit::MaybeEngine makeEngine(Options opts) {
auto ctx = makeSereneContext(opts);
return serene::jit::makeHalleyJIT(std::move(ctx));
};
} // namespace serene

View File

@ -16,6 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "serene/config.h"
#include "serene/context.h"
#include "serene/serene.h"
// #include "serene/jit/halley.h"
// #include "serene/namespace.h"
// #include "serene/reader/location.h"
@ -36,9 +39,11 @@
// #include <llvm/ADT/StringRef.h>
// #include <llvm/IR/LegacyPassManager.h>
// //#include <llvm/MC/TargetRegistry.h>
// #include <llvm/Support/CommandLine.h>
#include <llvm/Support/CommandLine.h>
// #include <llvm/Support/FileSystem.h>
// #include <llvm/Support/FormatVariadic.h>
#include <llvm/Support/FormatVariadic.h>
#include <iostream>
// #include <llvm/Support/Host.h>
// #include <llvm/Support/Path.h>
// #include <llvm/Support/raw_ostream.h>
@ -48,9 +53,9 @@
// #include <memory>
// using namespace std;
// using namespace serene;
using namespace serene;
// namespace cl = llvm::cl;
namespace cl = llvm::cl;
// namespace {
// enum Action {
@ -68,15 +73,15 @@
// };
// } // namespace
// static std::string banner =
// llvm::formatv("\n\nSerene Compiler Version {0}"
// "\nCopyright (C) 2019-2022 "
// "Sameer Rahmani <lxsameer@gnu.org>\n"
// "Serene comes with ABSOLUTELY NO WARRANTY;\n"
// "This is free software, and you are welcome\n"
// "to redistribute it under certain conditions; \n"
// "for details take a look at the LICENSE file.\n",
// SERENE_VERSION);
static std::string banner =
llvm::formatv("\n\nSerene Compiler Version {0}"
"\nCopyright (C) 2019-2022 "
"Sameer Rahmani <lxsameer@gnu.org>\n"
"Serene comes with ABSOLUTELY NO WARRANTY;\n"
"This is free software, and you are welcome\n"
"to redistribute it under certain conditions; \n"
"for details take a look at the LICENSE file.\n",
SERENE_VERSION);
// static cl::opt<std::string> inputNS(cl::Positional, cl::desc("<namespace>"),
// cl::Required);
@ -256,15 +261,21 @@
// return 0;
// };
int main() {
// initCompiler();
// registerSereneCLOptions();
int main(int argc, char *argv[]) {
initSerene();
registerSereneCLOptions();
// cl::ParseCommandLineOptions(argc, argv, banner);
cl::ParseCommandLineOptions(argc, argv, banner);
// auto ctx = makeSereneContext();
auto engine = makeEngine();
// applySereneCLOptions(*ctx);
if (!engine) {
llvm::errs() << "Error: Couldn't create the engine due to '"
<< engine.takeError() << "'\n";
return 1;
}
applySereneCLOptions(*(*engine));
// // TODO: handle the outputDir by not forcing it. it should be
// // default to the current working dir