Move over a modified version of MLIR jit. Add the pch
This commit is contained in:
parent
8af6452457
commit
aba81bfcae
|
@ -35,7 +35,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
|
|||
# Let's ensure -std=c++xx instead of -std=g++xx
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG
|
||||
"${CMAKE_CXX_FLAGS_DEBUG} -g -fno-omit-frame-pointer $ENV{ASAN_FLAG} -fno-builtin-strlen -ggdb -fno-inline ")
|
||||
"${CMAKE_CXX_FLAGS_DEBUG} -g -fno-omit-frame-pointer $ENV{ASAN_FLAG} -fno-builtin-strlen -ggdb -fno-inline -fdebug-prefix-map=$PWD=.")
|
||||
set(CMAKE_LINKER_FLAGS_DEBUG
|
||||
"${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer $ENV{ASAN_FLAG}")
|
||||
|
||||
|
|
|
@ -37,4 +37,3 @@ target_include_directories(serene PRIVATE ${INCLUDE_DIR})
|
|||
|
||||
install(TARGETS serenec DESTINATION bin)
|
||||
install(FILES "${PROJECT_BINARY_DIR}/config.h" DESTINATION include)
|
||||
cotire(serenec)
|
||||
|
|
40
builder
40
builder
|
@ -5,15 +5,18 @@ command=$1
|
|||
# Utilize `ccache` if available
|
||||
if type "ccache" > /dev/null
|
||||
then
|
||||
CC="$(which ccache) $(which clang)"
|
||||
CXX="$(which ccache) $(which clang++)"
|
||||
else
|
||||
CC=$(which clang)
|
||||
CXX=$(which clang++)
|
||||
fi
|
||||
echo "CCache detected."
|
||||
CMAKE_CCACHE="-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
|
||||
|
||||
else
|
||||
echo "CCache not detected."
|
||||
CMAKE_CCACHE=""
|
||||
fi
|
||||
export CMAKE_CCACHE
|
||||
|
||||
export CC=$(which clang)
|
||||
export CXX=$(which clang++)
|
||||
|
||||
export CC
|
||||
export CXX
|
||||
export CCACHE_SLOPPINESS="pch_defines,time_macros"
|
||||
# Meke sure to use `lld` linker it faster and has a better UX
|
||||
export LDFLAGS="-fuse-ld=lld"
|
||||
|
@ -29,6 +32,16 @@ BUILD_DIR=$ROOT_DIR/build
|
|||
|
||||
scanbuild=scan-build
|
||||
|
||||
|
||||
function gen_precompile_header_index() {
|
||||
echo "// DO NOT EDIT THIS FILE: It is aute generated by './builder gen_precompile_index'" > ./include/serene_precompiles.h
|
||||
echo "#ifndef SERENE_PRECOMPIL_H" >> ./include/serene_precompiles.h
|
||||
echo "#define SERENE_PRECOMPIL_H" >> ./include/serene_precompiles.h
|
||||
grep -oP "#include .llvm/.*" . -R|cut -d':' -f2|tail +2 >> ./include/serene_precompiles.h
|
||||
grep -oP "#include .mlir/.*" . -R|cut -d':' -f2|tail +2 >> ./include/serene_precompiles.h
|
||||
echo "#endif" >> ./include/serene_precompiles.h
|
||||
}
|
||||
|
||||
function pushed_build() {
|
||||
pushd "$BUILD_DIR" > /dev/null || return
|
||||
}
|
||||
|
@ -45,14 +58,16 @@ function compile() {
|
|||
|
||||
function build() {
|
||||
pushed_build
|
||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug "$@" "$ROOT_DIR"
|
||||
echo "Running: "
|
||||
echo "cmake -G Ninja $CMAKE_CCACHE -DCMAKE_BUILD_TYPE=Debug \"$@\" \"$ROOT_DIR\""
|
||||
cmake -G Ninja $CMAKE_CCACHE -DCMAKE_BUILD_TYPE=Debug "$@" "$ROOT_DIR"
|
||||
ninja -j "$(nproc)"
|
||||
popd_build
|
||||
}
|
||||
|
||||
function build-20() {
|
||||
pushed_build
|
||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCPP_20_SUPPORT=ON "$@" "$ROOT_DIR"
|
||||
cmake -G Ninja $CMAKE_CCACHE -DCMAKE_BUILD_TYPE=Debug -DCPP_20_SUPPORT=ON "$@" "$ROOT_DIR"
|
||||
ninja -j "$(nproc)"
|
||||
popd_build
|
||||
}
|
||||
|
@ -66,7 +81,7 @@ function build-release() {
|
|||
|
||||
function build-docs() {
|
||||
pushed_build
|
||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Docs "$ROOT_DIR"
|
||||
cmake -G Ninja $CMAKE_CCACHE -DCMAKE_BUILD_TYPE=Docs "$ROOT_DIR"
|
||||
ninja -j "$(nproc)"
|
||||
popd_build
|
||||
}
|
||||
|
@ -166,6 +181,9 @@ case "$command" in
|
|||
"clean")
|
||||
rm -rf "$BUILD_DIR"
|
||||
;;
|
||||
"gen_precompile_index")
|
||||
gen_precompile_header_index
|
||||
;;
|
||||
"full-build")
|
||||
clean
|
||||
mkdir -p "$BUILD_DIR"
|
||||
|
|
|
@ -89,6 +89,78 @@ public:
|
|||
mlir::Optional<llvm::CodeGenOpt::Level> jitCodeGenOptLevel = llvm::None,
|
||||
bool enableObjectCache = true, bool enableGDBNotificationListener = true,
|
||||
bool enablePerfNotificationListener = true);
|
||||
|
||||
/// Looks up a packed-argument function with the given name and returns a
|
||||
/// pointer to it. Propagates errors in case of failure.
|
||||
llvm::Expected<void (*)(void **)> lookup(llvm::StringRef name) const;
|
||||
|
||||
/// Invokes the function with the given name passing it the list of opaque
|
||||
/// pointers to the actual arguments.
|
||||
llvm::Error invokePacked(llvm::StringRef name,
|
||||
llvm::MutableArrayRef<void *> args = llvm::None);
|
||||
|
||||
/// Trait that defines how a given type is passed to the JIT code. This
|
||||
/// defaults to passing the address but can be specialized.
|
||||
template <typename T>
|
||||
struct Argument {
|
||||
static void pack(llvm::SmallVectorImpl<void *> &args, T &val) {
|
||||
args.push_back(&val);
|
||||
}
|
||||
};
|
||||
|
||||
/// Tag to wrap an output parameter when invoking a jitted function.
|
||||
template <typename T>
|
||||
struct FnResult {
|
||||
FnResult(T &result) : value(result) {}
|
||||
T &value;
|
||||
};
|
||||
|
||||
/// Helper function to wrap an output operand when using
|
||||
/// ExecutionEngine::invoke.
|
||||
template <typename T>
|
||||
static FnResult<T> result(T &t) {
|
||||
return FnResult<T>(t);
|
||||
}
|
||||
|
||||
// Specialization for output parameter: their address is forwarded directly to
|
||||
// the native code.
|
||||
template <typename T>
|
||||
struct Argument<Result<T>> {
|
||||
static void pack(llvm::SmallVectorImpl<void *> &args, FnResult<T> &result) {
|
||||
args.push_back(&result.value);
|
||||
}
|
||||
};
|
||||
|
||||
/// Invokes the function with the given name passing it the list of arguments
|
||||
/// by value. Function result can be obtain through output parameter using the
|
||||
/// `FnResult` wrapper defined above. For example:
|
||||
///
|
||||
/// func @foo(%arg0 : i32) -> i32 attributes { llvm.emit_c_interface }
|
||||
///
|
||||
/// can be invoked:
|
||||
///
|
||||
/// int32_t result = 0;
|
||||
/// llvm::Error error = jit->invoke("foo", 42,
|
||||
/// result(result));
|
||||
template <typename... Args>
|
||||
llvm::Error invoke(llvm::StringRef funcName, Args... args) {
|
||||
const std::string adapterName =
|
||||
std::string("_mlir_ciface_") + funcName.str();
|
||||
llvm::SmallVector<void *> argsArray;
|
||||
// Pack every arguments in an array of pointers. Delegate the packing to a
|
||||
// trait so that it can be overridden per argument type.
|
||||
// TODO: replace with a fold expression when migrating to C++17.
|
||||
int dummy[] = {0, ((void)Argument<Args>::pack(argsArray, args), 0)...};
|
||||
(void)dummy;
|
||||
return invokePacked(adapterName, argsArray);
|
||||
};
|
||||
/// Dump object code to output file `filename`.
|
||||
void dumpToObjectFile(llvm::StringRef filename);
|
||||
|
||||
/// Register symbols with this ExecutionEngine.
|
||||
void registerSymbols(
|
||||
llvm::function_ref<llvm::orc::SymbolMap(llvm::orc::MangleAndInterner)>
|
||||
symbolMap);
|
||||
};
|
||||
} // namespace serene
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ public:
|
|||
|
||||
T &&getValueOrFail(llvm::StringRef msg, int exitCode = 1) && {
|
||||
if (ok()) {
|
||||
return getValue();
|
||||
return std::move(getValue());
|
||||
}
|
||||
|
||||
llvm::errs() << msg << "\n";
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
// DO NOT EDIT THIS FILE: It is aute generated by './builder
|
||||
// gen_precompile_index'
|
||||
#ifndef SERENE_PRECOMPIL_H
|
||||
#define SERENE_PRECOMPIL_H
|
||||
#include "mlir/Dialect/StandardOps/IR/Ops.h"
|
||||
#include "mlir/IR/Attributes.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/BuiltinAttributes.h"
|
||||
#include "mlir/IR/BuiltinOps.h"
|
||||
#include "mlir/IR/BuiltinTypes.h"
|
||||
#include "mlir/IR/Dialect.h"
|
||||
#include "mlir/IR/Identifier.h"
|
||||
#include "mlir/IR/Location.h"
|
||||
#include "mlir/IR/MLIRContext.h"
|
||||
#include "mlir/IR/OpDefinition.h"
|
||||
#include "mlir/IR/OpImplementation.h"
|
||||
#include "mlir/IR/Value.h"
|
||||
#include "mlir/Interfaces/SideEffectInterfaces.h"
|
||||
#include "mlir/Support/LogicalResult.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
|
||||
#include <llvm/ADT/ArrayRef.h>
|
||||
#include <llvm/ADT/Optional.h>
|
||||
#include <llvm/ADT/STLExtras.h>
|
||||
#include <llvm/ADT/SmallString.h>
|
||||
#include <llvm/ADT/StringRef.h>
|
||||
#include <llvm/ExecutionEngine/JITEventListener.h>
|
||||
#include <llvm/ExecutionEngine/ObjectCache.h>
|
||||
#include <llvm/ExecutionEngine/Orc/CompileUtils.h>
|
||||
#include <llvm/ExecutionEngine/Orc/ExecutionUtils.h>
|
||||
#include <llvm/ExecutionEngine/Orc/IRCompileLayer.h>
|
||||
#include <llvm/ExecutionEngine/Orc/IRTransformLayer.h>
|
||||
#include <llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h>
|
||||
#include <llvm/ExecutionEngine/Orc/LLJIT.h>
|
||||
#include <llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h>
|
||||
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/LegacyPassManager.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Value.h>
|
||||
#include <llvm/Support/Casting.h>
|
||||
#include <llvm/Support/CodeGen.h>
|
||||
#include <llvm/Support/CommandLine.h>
|
||||
#include <llvm/Support/Debug.h>
|
||||
#include <llvm/Support/ErrorHandling.h>
|
||||
#include <llvm/Support/FileSystem.h>
|
||||
#include <llvm/Support/FormatVariadic.h>
|
||||
#include <llvm/Support/Host.h>
|
||||
#include <llvm/Support/Path.h>
|
||||
#include <llvm/Support/TargetRegistry.h>
|
||||
#include <llvm/Support/TargetSelect.h>
|
||||
#include <llvm/Support/ToolOutputFile.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <llvm/Target/TargetMachine.h>
|
||||
#include <llvm/Target/TargetOptions.h>
|
||||
#include <mlir/Conversion/AffineToStandard/AffineToStandard.h>
|
||||
#include <mlir/Conversion/SCFToStandard/SCFToStandard.h>
|
||||
#include <mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h>
|
||||
#include <mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h>
|
||||
#include <mlir/Dialect/Affine/IR/AffineOps.h>
|
||||
#include <mlir/Dialect/LLVMIR/LLVMDialect.h>
|
||||
#include <mlir/Dialect/MemRef/IR/MemRef.h>
|
||||
#include <mlir/Dialect/SCF/SCF.h>
|
||||
#include <mlir/Dialect/StandardOps/IR/Ops.h>
|
||||
#include <mlir/ExecutionEngine/ExecutionEngine.h>
|
||||
#include <mlir/ExecutionEngine/OptUtils.h>
|
||||
#include <mlir/IR/Block.h>
|
||||
#include <mlir/IR/Builders.h>
|
||||
#include <mlir/IR/BuiltinOps.h>
|
||||
#include <mlir/IR/MLIRContext.h>
|
||||
#include <mlir/IR/OperationSupport.h>
|
||||
#include <mlir/IR/OwningOpRef.h>
|
||||
#include <mlir/IR/Value.h>
|
||||
#include <mlir/Pass/Pass.h>
|
||||
#include <mlir/Pass/PassManager.h>
|
||||
#include <mlir/Support/FileUtilities.h>
|
||||
#include <mlir/Support/LLVM.h>
|
||||
#include <mlir/Support/LogicalResult.h>
|
||||
#include <mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h>
|
||||
#include <mlir/Target/LLVMIR/ModuleTranslation.h>
|
||||
#include <mlir/Transforms/DialectConversion.h>
|
||||
#endif
|
|
@ -33,6 +33,7 @@ set(HEADER_LIST
|
|||
"${INCLUDE_DIR}/serene/slir/generatable.h"
|
||||
"${INCLUDE_DIR}/serene/slir/utils.h"
|
||||
"${INCLUDE_DIR}/serene/namespace.h"
|
||||
"${INCLUDE_DIR}/serene/jit.h"
|
||||
|
||||
"${INCLUDE_DIR}/serene/passes.h")
|
||||
|
||||
|
@ -50,6 +51,7 @@ add_library(serene
|
|||
context.cpp
|
||||
serene.cpp
|
||||
namespace.cpp
|
||||
jit.cpp
|
||||
|
||||
# Reader
|
||||
reader/reader.cpp
|
||||
|
@ -108,5 +110,9 @@ target_link_libraries(serene
|
|||
MLIRSideEffectInterfaces
|
||||
MLIRTargetLLVMIRExport
|
||||
MLIRTransforms
|
||||
${llvm_libs}
|
||||
)
|
||||
${llvm_libs})
|
||||
|
||||
target_precompile_headers(serene
|
||||
PRIVATE
|
||||
<serene_precompiles.h>
|
||||
)
|
||||
|
|
|
@ -44,6 +44,14 @@
|
|||
|
||||
namespace serene {
|
||||
|
||||
// TODO: Remove this function and replace it by our own version of
|
||||
// error handler
|
||||
/// Wrap a string into an llvm::StringError.
|
||||
static llvm::Error make_string_error(const llvm::Twine &message) {
|
||||
return llvm::make_error<llvm::StringError>(message.str(),
|
||||
llvm::inconvertibleErrorCode());
|
||||
}
|
||||
|
||||
static std::string makePackedFunctionName(llvm::StringRef name) {
|
||||
return "_serene_" + name.str();
|
||||
}
|
||||
|
@ -183,15 +191,13 @@ MaybeJIT JIT::make(Namespace &ns,
|
|||
// run it.
|
||||
std::unique_ptr<llvm::LLVMContext> 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 maybeModule = jitEngine->ns.compileToLLVM();
|
||||
|
||||
auto &llvmModule = ns.getLLVMModule();
|
||||
packFunctionArguments(&llvmModule);
|
||||
auto llvmModule =
|
||||
std::move(maybeModule.getValueOrFail("Compilation Failed!"));
|
||||
packFunctionArguments(llvmModule.get());
|
||||
|
||||
auto dataLayout = llvmModule.getDataLayout();
|
||||
auto dataLayout = llvmModule->getDataLayout();
|
||||
|
||||
// Callback to create the object layer with symbol resolution to current
|
||||
// process and dynamically linked libraries.
|
||||
|
@ -211,7 +217,7 @@ MaybeJIT JIT::make(Namespace &ns,
|
|||
// 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()));
|
||||
llvm::Triple targetTriple(llvm::Twine(llvmModule->getTargetTriple()));
|
||||
if (targetTriple.isOSBinFormatCOFF()) {
|
||||
objectLayer->setOverrideObjectFlagsWithResponsibilityFlags(true);
|
||||
objectLayer->setAutoClaimResponsibilityForObjectSymbols(true);
|
||||
|
@ -278,4 +284,41 @@ MaybeJIT JIT::make(Namespace &ns,
|
|||
|
||||
return MaybeJIT::success(std::move(jitEngine));
|
||||
};
|
||||
|
||||
llvm::Expected<void (*)(void **)> JIT::lookup(llvm::StringRef name) const {
|
||||
auto expectedSymbol = engine->lookup(makePackedFunctionName(name));
|
||||
|
||||
// JIT lookup may return an Error referring to strings stored internally by
|
||||
// the JIT. If the Error outlives the ExecutionEngine, it would want have a
|
||||
// dangling reference, which is currently caught by an assertion inside JIT
|
||||
// thanks to hand-rolled reference counting. Rewrap the error message into a
|
||||
// string before returning. Alternatively, ORC JIT should consider copying
|
||||
// the string into the error message.
|
||||
if (!expectedSymbol) {
|
||||
std::string errorMessage;
|
||||
llvm::raw_string_ostream os(errorMessage);
|
||||
llvm::handleAllErrors(expectedSymbol.takeError(),
|
||||
[&os](llvm::ErrorInfoBase &ei) { ei.log(os); });
|
||||
return make_string_error(os.str());
|
||||
}
|
||||
|
||||
auto rawFPtr = expectedSymbol->getAddress();
|
||||
auto fptr = reinterpret_cast<void (*)(void **)>(rawFPtr);
|
||||
if (!fptr)
|
||||
return make_string_error("looked up function is null");
|
||||
return fptr;
|
||||
}
|
||||
|
||||
llvm::Error JIT::invokePacked(llvm::StringRef name,
|
||||
llvm::MutableArrayRef<void *> args) {
|
||||
auto expectedFPtr = lookup(name);
|
||||
if (!expectedFPtr)
|
||||
return expectedFPtr.takeError();
|
||||
auto fptr = *expectedFPtr;
|
||||
|
||||
(*fptr)(args.data());
|
||||
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
} // namespace serene
|
||||
|
|
Loading…
Reference in New Issue