Compare commits
3 Commits
7a4e76fe08
...
48e97095c7
Author | SHA1 | Date |
---|---|---|
Sameer Rahmani | 48e97095c7 | |
Sameer Rahmani | 7fb2125c4b | |
Sameer Rahmani | e9012b7583 |
|
@ -16,7 +16,7 @@ AlignEscapedNewlines: Left
|
|||
AlwaysBreakTemplateDeclarations: Yes
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^"(serene)/'
|
||||
- Regex: '^"'
|
||||
Priority: 1
|
||||
SortPriority: 1
|
||||
CaseSensitive: true
|
||||
|
|
|
@ -20,10 +20,10 @@ repos:
|
|||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: include-fixer
|
||||
name: Fixing 'serene' includes
|
||||
language: script
|
||||
entry: ./scripts/include-fixer.sh
|
||||
- id: include-fixer py
|
||||
name: Fixing local includes
|
||||
language: python
|
||||
entry: ./scripts/include-fixer.py
|
||||
files: ".*.(h|cpp)"
|
||||
|
||||
- repo: https://github.com/pocc/pre-commit-hooks
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
import sys
|
||||
import re
|
||||
import fileinput
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
target_header_pattern = re.compile(r"\#include [<\"](.+)[\">](.*)$", re.M)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# In the `.pre-commit-config.yaml` configuration we have set:
|
||||
# files: ".*.(h|cpp)"
|
||||
# for this file. So it will only receive cpp and h files. No need to
|
||||
# fiter.
|
||||
files = sys.argv[1:]
|
||||
|
||||
src_dir = Path(__file__).parent.parent / "serene" / "src"
|
||||
headers_files = (src_dir).rglob("*.h")
|
||||
|
||||
headers = []
|
||||
for h in headers_files:
|
||||
headers.append(str(h.relative_to(src_dir)))
|
||||
|
||||
# Loop over every line in every input file and write lines
|
||||
# one by one and modify any file that needs to be rewritten
|
||||
for line in fileinput.input(files=files, inplace=True):
|
||||
m = re.match(target_header_pattern, line)
|
||||
if m:
|
||||
header = m.group(1)
|
||||
rest = m.group(2)
|
||||
if header in headers or header.startswith("serene/"):
|
||||
print(f"#include \"{header}\"{rest}")
|
||||
else:
|
||||
print(f"#include <{header}>{rest}")
|
||||
else:
|
||||
print(line, end='')
|
||||
|
||||
# # For debugging purposes I leave this here.
|
||||
# for f in files:
|
||||
# with open(f, "r") as fd:
|
||||
# lines = fd.readlines()
|
||||
# for line in lines:
|
||||
# m = re.match(target_header_pattern, line)
|
||||
# if m:
|
||||
# header = m.group(1)
|
||||
# print("header: ", header)
|
||||
# rest = m.group(2)
|
||||
# if header in headers or header == "serene/config.h":
|
||||
# print(f"#include \"{header}\"{rest}")
|
||||
# else:
|
||||
# print(f"#include <{header}>{rest}")
|
||||
# else:
|
||||
# print(line, end='')
|
||||
# raise TypeError()
|
|
@ -1,47 +0,0 @@
|
|||
#! /bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# function get_changed_files() {
|
||||
# local add_modified
|
||||
# local renamed
|
||||
# add_modified=$(git diff --cached --name-status |egrep '*\.(cpp|h|hpp|cpp.inc|h.inc)'|awk '($1 != "D" && $1 !~ /R.+/) { print $2 }')
|
||||
# renamed=$(git diff --cached --name-status |egrep '*\.(cpp|h|hpp|cpp.inc|h.inc)'|awk '$1 ~ /^R.+/ { print $3 }')
|
||||
|
||||
# echo $add_modified | sed '/^[[:space:]]*$/d'
|
||||
# echo $renamed | sed '/^[[:space:]]*$/d'
|
||||
# }
|
||||
|
||||
function fix_includes(){
|
||||
#local files=$(get_changed_files)
|
||||
|
||||
echo "Fixing '#include' syntax in '$1'"
|
||||
sed -i -E '/^#include "(serene|\.)/!s/^.include \"(.*)\"/#include <\1>/g' "$1"
|
||||
}
|
||||
|
||||
# function clang_format_staged() {
|
||||
# local files=$(get_changed_files)
|
||||
|
||||
# if [[ "$files" ]];
|
||||
# then
|
||||
# for file in $(get_changed_files)
|
||||
# do
|
||||
# echo "Reformatting $file..."
|
||||
# clang-format -i $file
|
||||
# done
|
||||
# fi
|
||||
|
||||
# }
|
||||
|
||||
# function git_add_changes() {
|
||||
# local files=$(get_changed_files)
|
||||
|
||||
# if [[ "$files" ]];
|
||||
# then
|
||||
# git add $files
|
||||
# fi
|
||||
# }
|
||||
|
||||
fix_includes "$1"
|
||||
# clang_format_staged
|
||||
# git_add_changes
|
|
@ -19,5 +19,4 @@ target_sources(serene PRIVATE
|
|||
|
||||
commands/commands.cpp
|
||||
jit/jit.cpp
|
||||
context.cpp
|
||||
)
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <commands/commands.h>
|
||||
#include "commands/commands.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
|
|
@ -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
|
|
@ -18,16 +18,31 @@
|
|||
|
||||
#include "jit/jit.h"
|
||||
|
||||
#include "options.h" // for Options
|
||||
#include <system_error> // for error_code
|
||||
#include "options.h" // for Options
|
||||
|
||||
#include <llvm/ADT/StringMapEntry.h> // for StringMapEntry
|
||||
#include <llvm/ADT/iterator.h> // for iterator_facade_base
|
||||
#include <llvm/ExecutionEngine/JITEventListener.h> // for JITEventListener
|
||||
#include <llvm/ExecutionEngine/Orc/LLJIT.h> // IWYU pragma: keep
|
||||
#include <llvm/IR/Module.h> // for Module
|
||||
#include <llvm/Support/FileSystem.h> // for OpenFlags
|
||||
#include <llvm/Support/ToolOutputFile.h> // for ToolOutputFile
|
||||
#include <__type_traits/remove_reference.h> // for remov...
|
||||
#include <__utility/move.h> // for move
|
||||
#include <system_error> // for error_code
|
||||
|
||||
#include <llvm/ADT/StringMapEntry.h> // for StringMapEntry
|
||||
#include <llvm/ADT/iterator.h> // for iterator_facade_base
|
||||
#include <llvm/ExecutionEngine/JITEventListener.h> // for JITEventListener
|
||||
#include <llvm/ExecutionEngine/Orc/CompileUtils.h> // for TMOwn...
|
||||
#include <llvm/ExecutionEngine/Orc/Core.h> // for JITDy...
|
||||
#include <llvm/ExecutionEngine/Orc/DebugUtils.h> // for opera...
|
||||
#include <llvm/ExecutionEngine/Orc/ExecutionUtils.h> // for Dynam...
|
||||
#include <llvm/ExecutionEngine/Orc/IRCompileLayer.h> // for IRCom...
|
||||
#include <llvm/ExecutionEngine/Orc/LLJIT.h> // IWYU pragma: keep
|
||||
#include <llvm/ExecutionEngine/Orc/Layer.h> // for Objec...
|
||||
#include <llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h>
|
||||
#include <llvm/ExecutionEngine/Orc/ThreadSafeModule.h> // for Threa...
|
||||
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
|
||||
#include <llvm/IR/DataLayout.h> // for DataL...
|
||||
#include <llvm/IR/LLVMContext.h> // for LLVMC...
|
||||
#include <llvm/IR/Module.h> // for Module
|
||||
#include <llvm/Support/FileSystem.h> // for OpenFlags
|
||||
#include <llvm/Support/ToolOutputFile.h> // for ToolOutputFile
|
||||
#include <llvm/TargetParser/Triple.h> // for Triple
|
||||
|
||||
#include <assert.h> // for assert
|
||||
#include <string> // for operator+, char_t...
|
||||
|
@ -113,15 +128,179 @@ size_t JIT::getNumberOfJITDylibs(const llvm::StringRef &nsName) {
|
|||
return jitDylibs[nsName].size();
|
||||
};
|
||||
|
||||
JIT::JIT(llvm::orc::JITTargetMachineBuilder &&jtmb, Options &opts)
|
||||
: isLazy(opts.JITLazy),
|
||||
cache(opts.JITenableObjectCache ? new ObjectCache() : nullptr),
|
||||
gdbListener(opts.JITenableGDBNotificationListener
|
||||
JIT::JIT(llvm::orc::JITTargetMachineBuilder &&jtmb,
|
||||
std::unique_ptr<Options> opts)
|
||||
:
|
||||
|
||||
options(std::move(opts)),
|
||||
cache(options->JITenableObjectCache ? new ObjectCache() : nullptr),
|
||||
gdbListener(options->JITenableGDBNotificationListener
|
||||
? llvm::JITEventListener::createGDBRegistrationListener()
|
||||
: nullptr),
|
||||
perfListener(opts.JITenablePerfNotificationListener
|
||||
perfListener(options->JITenablePerfNotificationListener
|
||||
? llvm::JITEventListener::createPerfJITEventListener()
|
||||
: nullptr),
|
||||
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->options->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));
|
||||
};
|
||||
|
||||
MaybeJIT makeJIT(std::unique_ptr<Options> opts) {
|
||||
llvm::orc::JITTargetMachineBuilder jtmb(opts->hostTriple);
|
||||
auto maybeJIT = JIT::make(std::move(jtmb), std::move(opts));
|
||||
|
||||
if (!maybeJIT) {
|
||||
return maybeJIT.takeError();
|
||||
}
|
||||
|
||||
return maybeJIT;
|
||||
};
|
||||
} // namespace serene::jit
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#ifndef JIT_JIT_H
|
||||
#define JIT_JIT_H
|
||||
|
||||
#include "options.h"
|
||||
|
||||
#include <__memory/unique_ptr.h>
|
||||
|
||||
#include <llvm/ADT/ArrayRef.h>
|
||||
|
@ -43,6 +45,7 @@
|
|||
#include <optional>
|
||||
#include <stddef.h>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class JITEventListener;
|
||||
|
@ -55,13 +58,20 @@ class JITDylib;
|
|||
class LLJIT;
|
||||
class LLLazyJIT;
|
||||
} // namespace llvm::orc
|
||||
namespace serene {
|
||||
struct Options;
|
||||
} // namespace serene
|
||||
|
||||
#define MAIN_PROCESS_JD_NAME "*main*"
|
||||
#define HALLEY_LOG(...) \
|
||||
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 serene::jit {
|
||||
|
@ -91,7 +101,7 @@ private:
|
|||
};
|
||||
|
||||
class JIT {
|
||||
const bool isLazy;
|
||||
std::unique_ptr<const Options> options;
|
||||
|
||||
std::variant<std::unique_ptr<orc::LLJIT>, std::unique_ptr<orc::LLLazyJIT>>
|
||||
engine;
|
||||
|
@ -103,6 +113,8 @@ class JIT {
|
|||
|
||||
llvm::orc::JITTargetMachineBuilder jtmb;
|
||||
|
||||
std::vector<const char *> loadPaths;
|
||||
|
||||
// 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
|
||||
// jitDylib
|
||||
|
@ -115,9 +127,16 @@ class JIT {
|
|||
void pushJITDylib(const llvm::StringRef &nsName, llvm::orc::JITDylib *l);
|
||||
size_t getNumberOfJITDylibs(const llvm::StringRef &nsName);
|
||||
|
||||
llvm::Error createCurrentProcessJD();
|
||||
|
||||
public:
|
||||
JIT(llvm::orc::JITTargetMachineBuilder &&jtmb, Options &opts);
|
||||
static MaybeJIT make(llvm::orc::JITTargetMachineBuilder &&jtmb);
|
||||
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
|
||||
////name
|
||||
|
@ -137,8 +156,13 @@ public:
|
|||
llvm::Error loadModule(const llvm::StringRef &nsName,
|
||||
const llvm::StringRef &file);
|
||||
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(std::unique_ptr<Options> opts);
|
||||
} // namespace serene::jit
|
||||
#endif
|
||||
|
|
|
@ -19,7 +19,24 @@
|
|||
#ifndef OPTIONS_H
|
||||
#define OPTIONS_H
|
||||
|
||||
#include <llvm/TargetParser/Triple.h> // for Triple
|
||||
|
||||
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
|
||||
/// compiler via command line. Anything that user should be able to
|
||||
/// tweak about the compiler has to end up here regardless of the
|
||||
|
@ -34,6 +51,22 @@ struct Options {
|
|||
bool JITenableGDBNotificationListener = true;
|
||||
bool JITenablePerfNotificationListener = true;
|
||||
bool JITLazy = false;
|
||||
|
||||
// We will use this triple to generate code that will endup in the binary
|
||||
// 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;
|
||||
|
||||
CompilationPhase compilationPhase = CompilationPhase::NoOptimization;
|
||||
};
|
||||
|
||||
} // namespace serene
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "serene/config.h" // for SERENE_VERSION
|
||||
|
||||
#include "commands/commands.h" // for cc, run
|
||||
#include "serene/config.h" // for SERENE_VERSION
|
||||
//
|
||||
#include <__fwd/string.h> // for string
|
||||
|
||||
#include <llvm/ADT/StringRef.h> // for StringRef
|
||||
|
|
Loading…
Reference in New Issue