Move over a modified version of MLIR jit. Add the pch

This commit is contained in:
Sameer Rahmani 2021-08-17 08:52:26 +01:00
parent 8af6452457
commit aba81bfcae
8 changed files with 254 additions and 24 deletions

View File

@ -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}")

View File

@ -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
View File

@ -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"

View File

@ -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

View File

@ -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";

View File

@ -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

View File

@ -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>
)

View File

@ -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