Move the functionality of the old SereneContext to JIT itself
This commit is contained in:
parent
7a4e76fe08
commit
e9012b7583
|
@ -19,5 +19,4 @@ target_sources(serene PRIVATE
|
||||||
|
|
||||||
commands/commands.cpp
|
commands/commands.cpp
|
||||||
jit/jit.cpp
|
jit/jit.cpp
|
||||||
context.cpp
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
/* -*- C++ -*-
|
|
||||||
* Serene Programming Language
|
|
||||||
*
|
|
||||||
* Copyright (c) 2019-2023 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <context.h>
|
|
||||||
#include <cstdlib> // for exit
|
|
||||||
|
|
||||||
namespace serene {
|
|
||||||
|
|
||||||
int SereneContext::getOptimizatioLevel() {
|
|
||||||
if (targetPhase <= CompilationPhase::NoOptimization) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetPhase == CompilationPhase::O1) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (targetPhase == CompilationPhase::O2) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
void terminate(SereneContext &ctx, int exitCode) {
|
|
||||||
(void)ctx;
|
|
||||||
// TODO: Since we are running in a single thread for now using exit is fine
|
|
||||||
// but we need to adjust and change it to a thread safe termination
|
|
||||||
// process later on.
|
|
||||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
|
||||||
std::exit(exitCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<SereneContext> makeSereneContext(Options opts) {
|
|
||||||
return std::make_unique<SereneContext>(opts);
|
|
||||||
};
|
|
||||||
|
|
||||||
}; // namespace serene
|
|
|
@ -1,104 +0,0 @@
|
||||||
/* -*- C++ -*-
|
|
||||||
* Serene Programming Language
|
|
||||||
*
|
|
||||||
* Copyright (c) 2019-2023 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 CONTEXT_H
|
|
||||||
#define CONTEXT_H
|
|
||||||
|
|
||||||
#include "options.h" // for Options
|
|
||||||
#include <__fwd/string.h> // for string
|
|
||||||
#include <__memory/unique_ptr.h> // for make_unique, unique_ptr
|
|
||||||
|
|
||||||
#include <llvm/ADT/Twine.h> // for Twine
|
|
||||||
#include <llvm/IR/LLVMContext.h> // for LLVMContext
|
|
||||||
#include <llvm/TargetParser/Host.h> // for getDefaultTargetTriple
|
|
||||||
#include <llvm/TargetParser/Triple.h> // for Triple
|
|
||||||
|
|
||||||
#include <string> // for basic_string
|
|
||||||
#include <vector> // for vector
|
|
||||||
|
|
||||||
namespace serene {
|
|
||||||
class SereneContext;
|
|
||||||
|
|
||||||
/// This enum describes the different operational phases for the compiler
|
|
||||||
/// in order. Anything below `NoOptimization` is considered only for debugging
|
|
||||||
enum class CompilationPhase {
|
|
||||||
Parse,
|
|
||||||
Analysis,
|
|
||||||
SLIR,
|
|
||||||
MLIR, // Lowered slir to other dialects
|
|
||||||
LIR, // Lowered to the llvm ir dialect
|
|
||||||
IR, // Lowered to the LLVMIR itself
|
|
||||||
NoOptimization,
|
|
||||||
O1,
|
|
||||||
O2,
|
|
||||||
O3,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Terminates the serene compiler process in a thread safe manner
|
|
||||||
/// This function is only meant to be used in the compiler context
|
|
||||||
/// if you want to terminate the process in context of a serene program
|
|
||||||
/// via the JIT use an appropriate function in the `serene.core` ns.
|
|
||||||
void terminate(SereneContext &ctx, int exitCode);
|
|
||||||
|
|
||||||
// Why SereneContext and not Context? We will be using LLVMContext
|
|
||||||
// and MLIRContext through out Serene, so it's better to follow
|
|
||||||
// the same convention
|
|
||||||
class SereneContext {
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// The set of options to change the compilers behaviors
|
|
||||||
Options options;
|
|
||||||
|
|
||||||
const llvm::Triple triple;
|
|
||||||
|
|
||||||
explicit SereneContext(Options &options)
|
|
||||||
: options(options), triple(llvm::sys::getDefaultTargetTriple()),
|
|
||||||
targetPhase(CompilationPhase::NoOptimization){};
|
|
||||||
|
|
||||||
/// Set the target compilation phase of the compiler. The compilation
|
|
||||||
/// phase dictates the behavior and the output type of the compiler.
|
|
||||||
void setOperationPhase(CompilationPhase phase);
|
|
||||||
|
|
||||||
CompilationPhase getTargetPhase() { return targetPhase; };
|
|
||||||
int getOptimizatioLevel();
|
|
||||||
|
|
||||||
static std::unique_ptr<llvm::LLVMContext> genLLVMContext() {
|
|
||||||
return std::make_unique<llvm::LLVMContext>();
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Setup the load path for namespace lookups
|
|
||||||
void setLoadPaths(std::vector<std::string> &dirs) { loadPaths.swap(dirs); };
|
|
||||||
|
|
||||||
/// Return the load paths for namespaces
|
|
||||||
std::vector<std::string> &getLoadPaths() { return loadPaths; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
CompilationPhase targetPhase;
|
|
||||||
std::vector<std::string> loadPaths;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Creates a new context object. Contexts are used through out the compilation
|
|
||||||
/// process to store the state.
|
|
||||||
///
|
|
||||||
/// \p opts is an instance of \c Options that can be used to set options of
|
|
||||||
/// of the compiler.
|
|
||||||
std::unique_ptr<SereneContext> makeSereneContext(Options opts = Options());
|
|
||||||
|
|
||||||
} // namespace serene
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -16,21 +16,22 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "jit/jit.h"
|
#include <jit/jit.h>
|
||||||
|
|
||||||
#include "options.h" // for Options
|
|
||||||
#include <system_error> // for error_code
|
#include <system_error> // for error_code
|
||||||
|
|
||||||
#include <llvm/ADT/StringMapEntry.h> // for StringMapEntry
|
#include <llvm/ADT/StringMapEntry.h> // for StringMapEntry
|
||||||
#include <llvm/ADT/iterator.h> // for iterator_facade_base
|
#include <llvm/ADT/iterator.h> // for iterator_facade_base
|
||||||
#include <llvm/ExecutionEngine/JITEventListener.h> // for JITEventListener
|
#include <llvm/ExecutionEngine/JITEventListener.h> // for JITEventListener
|
||||||
#include <llvm/ExecutionEngine/Orc/LLJIT.h> // IWYU pragma: keep
|
#include <llvm/ExecutionEngine/Orc/LLJIT.h> // IWYU pragma: keep
|
||||||
#include <llvm/IR/Module.h> // for Module
|
#include <llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h>
|
||||||
#include <llvm/Support/FileSystem.h> // for OpenFlags
|
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
|
||||||
#include <llvm/Support/ToolOutputFile.h> // for ToolOutputFile
|
#include <llvm/IR/Module.h> // for Module
|
||||||
|
#include <llvm/Support/FileSystem.h> // for OpenFlags
|
||||||
|
#include <llvm/Support/ToolOutputFile.h> // for ToolOutputFile
|
||||||
|
|
||||||
#include <assert.h> // for assert
|
#include <assert.h> // for assert
|
||||||
#include <string> // for operator+, char_t...
|
#include <options.h> // for Options
|
||||||
|
#include <string> // for operator+, char_t...
|
||||||
|
|
||||||
namespace serene::jit {
|
namespace serene::jit {
|
||||||
|
|
||||||
|
@ -113,15 +114,168 @@ size_t JIT::getNumberOfJITDylibs(const llvm::StringRef &nsName) {
|
||||||
return jitDylibs[nsName].size();
|
return jitDylibs[nsName].size();
|
||||||
};
|
};
|
||||||
|
|
||||||
JIT::JIT(llvm::orc::JITTargetMachineBuilder &&jtmb, Options &opts)
|
JIT::JIT(llvm::orc::JITTargetMachineBuilder &&jtmb,
|
||||||
: isLazy(opts.JITLazy),
|
std::unique_ptr<Options> opts)
|
||||||
cache(opts.JITenableObjectCache ? new ObjectCache() : nullptr),
|
:
|
||||||
gdbListener(opts.JITenableGDBNotificationListener
|
|
||||||
|
options(std::move(opts)),
|
||||||
|
cache(options->JITenableObjectCache ? new ObjectCache() : nullptr),
|
||||||
|
gdbListener(options->JITenableGDBNotificationListener
|
||||||
? llvm::JITEventListener::createGDBRegistrationListener()
|
? llvm::JITEventListener::createGDBRegistrationListener()
|
||||||
: nullptr),
|
: nullptr),
|
||||||
perfListener(opts.JITenablePerfNotificationListener
|
perfListener(options->JITenablePerfNotificationListener
|
||||||
? llvm::JITEventListener::createPerfJITEventListener()
|
? llvm::JITEventListener::createPerfJITEventListener()
|
||||||
: nullptr),
|
: nullptr),
|
||||||
jtmb(jtmb){};
|
jtmb(jtmb){};
|
||||||
|
|
||||||
|
void JIT::dumpToObjectFile(const llvm::StringRef &filename) {
|
||||||
|
cache->dumpToObjectFile(filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
int JIT::getOptimizatioLevel() const {
|
||||||
|
if (options->compilationPhase <= CompilationPhase::NoOptimization) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options->compilationPhase == CompilationPhase::O1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (options->compilationPhase == CompilationPhase::O2) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Error JIT::createCurrentProcessJD() {
|
||||||
|
|
||||||
|
auto &es = WITH_ENGINE(auto &, getExecutionSession());
|
||||||
|
auto *processJDPtr = es.getJITDylibByName(MAIN_PROCESS_JD_NAME);
|
||||||
|
|
||||||
|
if (processJDPtr != nullptr) {
|
||||||
|
// We already created the JITDylib for the current process
|
||||||
|
return llvm::Error::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto processJD = es.createJITDylib(MAIN_PROCESS_JD_NAME);
|
||||||
|
|
||||||
|
if (!processJD) {
|
||||||
|
return processJD.takeError();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto generator =
|
||||||
|
llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
|
||||||
|
WITH_ENGINE(const auto &, getDataLayout()).getGlobalPrefix());
|
||||||
|
|
||||||
|
if (!generator) {
|
||||||
|
return generator.takeError();
|
||||||
|
}
|
||||||
|
|
||||||
|
processJD->addGenerator(std::move(*generator));
|
||||||
|
return llvm::Error::success();
|
||||||
|
};
|
||||||
|
|
||||||
|
MaybeJIT JIT::make(llvm::orc::JITTargetMachineBuilder &&jtmb,
|
||||||
|
std::unique_ptr<Options> opts) {
|
||||||
|
auto dl = jtmb.getDefaultDataLayoutForTarget();
|
||||||
|
if (!dl) {
|
||||||
|
return dl.takeError();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto jitEngine = std::make_unique<JIT>(std::move(jtmb), std::move(opts));
|
||||||
|
//
|
||||||
|
// 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<llvm::LLVMContext> ctx(new llvm::LLVMContext);
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
(void)tt;
|
||||||
|
|
||||||
|
auto objectLayer =
|
||||||
|
std::make_unique<llvm::orc::RTDyldObjectLinkingLayer>(session, []() {
|
||||||
|
return std::make_unique<llvm::SectionMemoryManager>();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Register JIT event listeners if they are enabled.
|
||||||
|
if (jitEngine->gdbListener != nullptr) {
|
||||||
|
objectLayer->registerJITEventListener(*jitEngine->gdbListener);
|
||||||
|
}
|
||||||
|
if (jitEngine->perfListener != nullptr) {
|
||||||
|
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
|
||||||
|
if (jitEngine->hostTriple.isOSBinFormatCOFF()) {
|
||||||
|
objectLayer->setOverrideObjectFlagsWithResponsibilityFlags(true);
|
||||||
|
objectLayer->setAutoClaimResponsibilityForObjectSymbols(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return objectLayer;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Callback to inspect the cache and recompile on demand.
|
||||||
|
auto compileFunctionCreator = [&](llvm::orc::JITTargetMachineBuilder JTMB)
|
||||||
|
-> llvm::Expected<
|
||||||
|
std::unique_ptr<llvm::orc::IRCompileLayer::IRCompiler>> {
|
||||||
|
llvm::CodeGenOpt::Level jitCodeGenOptLevel =
|
||||||
|
static_cast<llvm::CodeGenOpt::Level>(jitEngine->getOptimizatioLevel());
|
||||||
|
|
||||||
|
JTMB.setCodeGenOptLevel(jitCodeGenOptLevel);
|
||||||
|
|
||||||
|
auto targetMachine = JTMB.createTargetMachine();
|
||||||
|
if (!targetMachine) {
|
||||||
|
return targetMachine.takeError();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<llvm::orc::TMOwningSimpleCompiler>(
|
||||||
|
std::move(*targetMachine), jitEngine->cache.get());
|
||||||
|
};
|
||||||
|
|
||||||
|
auto compileNotifier = [&](llvm::orc::MaterializationResponsibility &r,
|
||||||
|
llvm::orc::ThreadSafeModule tsm) {
|
||||||
|
auto syms = r.getRequestedSymbols();
|
||||||
|
tsm.withModuleDo([&](llvm::Module &m) {
|
||||||
|
HALLEY_LOG("Compiled " << syms
|
||||||
|
<< " for the module: " << m.getModuleIdentifier());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (jitEngine->options->JITLazy) {
|
||||||
|
// Setup a LLLazyJIT instance to the times that latency is important
|
||||||
|
// for example in a REPL. This way
|
||||||
|
auto jit =
|
||||||
|
cantFail(llvm::orc::LLLazyJITBuilder()
|
||||||
|
.setCompileFunctionCreator(compileFunctionCreator)
|
||||||
|
.setObjectLinkingLayerCreator(objectLinkingLayerCreator)
|
||||||
|
.create());
|
||||||
|
jit->getIRCompileLayer().setNotifyCompiled(compileNotifier);
|
||||||
|
jitEngine->engine = std::move(jit);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Setup a LLJIT instance for the times that performance is important
|
||||||
|
// and we want to compile everything as soon as possible. For instance
|
||||||
|
// when we run the JIT in the compiler
|
||||||
|
auto jit =
|
||||||
|
cantFail(llvm::orc::LLJITBuilder()
|
||||||
|
.setCompileFunctionCreator(compileFunctionCreator)
|
||||||
|
.setObjectLinkingLayerCreator(objectLinkingLayerCreator)
|
||||||
|
.create());
|
||||||
|
jit->getIRCompileLayer().setNotifyCompiled(compileNotifier);
|
||||||
|
jitEngine->engine = std::move(jit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto err = jitEngine->createCurrentProcessJD()) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MaybeJIT(std::move(jitEngine));
|
||||||
|
};
|
||||||
} // namespace serene::jit
|
} // namespace serene::jit
|
||||||
|
|
|
@ -59,9 +59,19 @@ namespace serene {
|
||||||
struct Options;
|
struct Options;
|
||||||
} // namespace serene
|
} // namespace serene
|
||||||
|
|
||||||
|
#define MAIN_PROCESS_JD_NAME "*main*"
|
||||||
#define HALLEY_LOG(...) \
|
#define HALLEY_LOG(...) \
|
||||||
DEBUG_WITH_TYPE("JIT", llvm::dbgs() << "[JIT]: " << __VA_ARGS__ << "\n");
|
DEBUG_WITH_TYPE("JIT", llvm::dbgs() << "[JIT]: " << __VA_ARGS__ << "\n");
|
||||||
|
|
||||||
|
/// A simple macro that we need to use to call those member functions that are
|
||||||
|
/// shared between LLJIT and LLLAZYJIT. This macro supposed to be used
|
||||||
|
/// only within the JIT class itself. The first argument is the return type
|
||||||
|
/// of the member function and the second arg is the member function call.
|
||||||
|
/// The whole point of this macro is to unwrap the variant type and call
|
||||||
|
/// the shared member function on the unwraped value.
|
||||||
|
#define WITH_ENGINE(retType, fnCall) \
|
||||||
|
std::visit([](auto &e) -> retType { return e->fnCall; }, engine)
|
||||||
|
|
||||||
namespace orc = llvm::orc;
|
namespace orc = llvm::orc;
|
||||||
|
|
||||||
namespace serene::jit {
|
namespace serene::jit {
|
||||||
|
@ -91,7 +101,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class JIT {
|
class JIT {
|
||||||
const bool isLazy;
|
std::unique_ptr<const Options> options;
|
||||||
|
|
||||||
std::variant<std::unique_ptr<orc::LLJIT>, std::unique_ptr<orc::LLLazyJIT>>
|
std::variant<std::unique_ptr<orc::LLJIT>, std::unique_ptr<orc::LLLazyJIT>>
|
||||||
engine;
|
engine;
|
||||||
|
@ -103,6 +113,8 @@ class JIT {
|
||||||
|
|
||||||
llvm::orc::JITTargetMachineBuilder jtmb;
|
llvm::orc::JITTargetMachineBuilder jtmb;
|
||||||
|
|
||||||
|
std::vector<const char *> loadPaths;
|
||||||
|
|
||||||
// We keep the jibDylibs for each name space in a mapping from the ns
|
// We keep the jibDylibs for each name space in a mapping from the ns
|
||||||
// name to a vector of jitdylibs, the last element is always the newest
|
// name to a vector of jitdylibs, the last element is always the newest
|
||||||
// jitDylib
|
// jitDylib
|
||||||
|
@ -115,9 +127,30 @@ class JIT {
|
||||||
void pushJITDylib(const llvm::StringRef &nsName, llvm::orc::JITDylib *l);
|
void pushJITDylib(const llvm::StringRef &nsName, llvm::orc::JITDylib *l);
|
||||||
size_t getNumberOfJITDylibs(const llvm::StringRef &nsName);
|
size_t getNumberOfJITDylibs(const llvm::StringRef &nsName);
|
||||||
|
|
||||||
|
llvm::Error createCurrentProcessJD();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JIT(llvm::orc::JITTargetMachineBuilder &&jtmb, Options &opts);
|
// We will use this triple to generate code that will endup in the binary
|
||||||
static MaybeJIT make(llvm::orc::JITTargetMachineBuilder &&jtmb);
|
// for the target platform. If we're not cross compiling, `targetTriple`
|
||||||
|
// will be the same as `hostTriple`.
|
||||||
|
const llvm::Triple targetTriple;
|
||||||
|
|
||||||
|
// This triple will be used in code generation for the host platform in
|
||||||
|
// complie time. For example any function that will be called during
|
||||||
|
// the compile time has to run on the host. So we need to generate
|
||||||
|
// appropriate code for the host. If the same function has to be part
|
||||||
|
// of the runtime, then we use `targetTriple` again to generate the code
|
||||||
|
// for the target platform. So, we might end up with two version of the
|
||||||
|
// same function
|
||||||
|
const llvm::Triple hostTriple;
|
||||||
|
|
||||||
|
JIT(llvm::orc::JITTargetMachineBuilder &&jtmb, std::unique_ptr<Options> opts);
|
||||||
|
static MaybeJIT make(llvm::orc::JITTargetMachineBuilder &&jtmb,
|
||||||
|
std::unique_ptr<Options> opts);
|
||||||
|
|
||||||
|
// Return an integer indicating the level of optimization that is currently
|
||||||
|
// set. 0 == No optimizaion -> it includes compling to IR and AST
|
||||||
|
int getOptimizatioLevel() const;
|
||||||
|
|
||||||
/// Return a pointer to the most registered JITDylib of the given \p ns
|
/// Return a pointer to the most registered JITDylib of the given \p ns
|
||||||
////name
|
////name
|
||||||
|
@ -137,6 +170,11 @@ public:
|
||||||
llvm::Error loadModule(const llvm::StringRef &nsName,
|
llvm::Error loadModule(const llvm::StringRef &nsName,
|
||||||
const llvm::StringRef &file);
|
const llvm::StringRef &file);
|
||||||
void dumpToObjectFile(const llvm::StringRef &filename);
|
void dumpToObjectFile(const llvm::StringRef &filename);
|
||||||
|
|
||||||
|
/// Setup the load path for namespace lookups
|
||||||
|
void setLoadPaths(std::vector<const char *> &dirs) { loadPaths.swap(dirs); };
|
||||||
|
/// Return the load paths for namespaces
|
||||||
|
llvm::ArrayRef<const char *> getLoadPaths() { return loadPaths; };
|
||||||
};
|
};
|
||||||
|
|
||||||
MaybeJIT makeJIT();
|
MaybeJIT makeJIT();
|
||||||
|
|
|
@ -20,6 +20,21 @@
|
||||||
#define OPTIONS_H
|
#define OPTIONS_H
|
||||||
|
|
||||||
namespace serene {
|
namespace serene {
|
||||||
|
/// This enum describes the different operational phases for the compiler
|
||||||
|
/// in order. Anything below `NoOptimization` is considered only for debugging
|
||||||
|
enum class CompilationPhase {
|
||||||
|
Parse,
|
||||||
|
Analysis,
|
||||||
|
SLIR,
|
||||||
|
MLIR, // Lowered slir to other dialects
|
||||||
|
LIR, // Lowered to the llvm ir dialect
|
||||||
|
IR, // Lowered to the LLVMIR itself
|
||||||
|
NoOptimization,
|
||||||
|
O1,
|
||||||
|
O2,
|
||||||
|
O3,
|
||||||
|
};
|
||||||
|
|
||||||
/// Options describes the compiler options that can be passed to the
|
/// Options describes the compiler options that can be passed to the
|
||||||
/// compiler via command line. Anything that user should be able to
|
/// compiler via command line. Anything that user should be able to
|
||||||
/// tweak about the compiler has to end up here regardless of the
|
/// tweak about the compiler has to end up here regardless of the
|
||||||
|
@ -34,6 +49,8 @@ struct Options {
|
||||||
bool JITenableGDBNotificationListener = true;
|
bool JITenableGDBNotificationListener = true;
|
||||||
bool JITenablePerfNotificationListener = true;
|
bool JITenablePerfNotificationListener = true;
|
||||||
bool JITLazy = false;
|
bool JITLazy = false;
|
||||||
|
|
||||||
|
CompilationPhase compilationPhase = CompilationPhase::NoOptimization;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace serene
|
} // namespace serene
|
||||||
|
|
Loading…
Reference in New Issue