Skip to content
This repository has been archived by the owner on Sep 27, 2019. It is now read-only.

Commit

Permalink
Bytecode Interpreter (#1244)
Browse files Browse the repository at this point in the history
* Introducing Bytecode Interpreter

  * interpreter deactivated if not requested by command line
  * no supprt for OrderBy yet

* Change Compile/Verify functions to void

  * throw an Exception in case of errors

* Small changes from review on #1244

* Add explicit function calls, small changes

  * add template system to generate handler for explicit function calls
  * refactor InsertBytecodeFunction
  * add missingFP truct/extend instructions
  • Loading branch information
tcm-marcel authored and tli2 committed Jun 26, 2018
1 parent 9cca1b7 commit a045cfc
Show file tree
Hide file tree
Showing 33 changed files with 5,889 additions and 116 deletions.
5 changes: 5 additions & 0 deletions cmake/Dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ llvm_map_components_to_libnames(LLVM_LIBRARIES core mcjit nativecodegen native)
include_directories(SYSTEM ${LLVM_INCLUDE_DIRS})
list(APPEND Peloton_LINKER_LIBS ${LLVM_LIBRARIES})

# --[ FFI
find_package(Libffi)
include_directories(SYSTEM ${LIBFFI_INCLUDE_DIRS})
list(APPEND Peloton_LINKER_LIBS ${LIBFFI_LIBRARIES})

# --[ IWYU

# Generate clang compilation database
Expand Down
39 changes: 39 additions & 0 deletions cmake/Modules/FindLibffi.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# - Try to find Libffi
#
# A Portable Foreign Function Interface Library (https://sourceware.org/libffi)
#
# Usage:
# LIBFFI_INCLUDE_DIRS, location of header files
# LIBFFI_LIBRARIES, location of library
# LIBFFI_FOUND, indicates if libffi was found

# Look for the header file.
execute_process(COMMAND brew --prefix libffi OUTPUT_VARIABLE LIBFFI_BREW_PREFIX)

find_library(LIBFFI_LIBRARY NAMES ffi libffi
PATHS /usr /usr/local /opt/local
PATH_SUFFIXES lib lib64 x86_64-linux-gnu lib/x86_64-linux-gnu
)

find_path(LIBFFI_INCLUDE_DIR ffi.h
PATHS /usr /usr/local /opt/local /usr/include/ffi
PATH_SUFFIXES include include/ffi include/x86_64-linux-gnu x86_64-linux-gnu
HINT LIBFFI_BREW_PREFIX
)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LIBFFI DEFAULT_MSG LIBFFI_LIBRARY LIBFFI_INCLUDE_DIR)


# Copy the results to the output variables.
IF(LIBFFI_FOUND)
SET(LIBFFI_LIBRARIES ${LIBFFI_LIBRARY})
SET(LIBFFI_INCLUDE_DIRS ${LIBFFI_INCLUDE_DIR})
ELSE(LIBFFI_FOUND)
SET(LIBFFI_LIBRARIES)
SET(LIBFFI_INCLUDE_DIRS)
ENDIF(LIBFFI_FOUND)

MARK_AS_ADVANCED(LIBFFI_INCLUDE_DIRS LIBFFI_LIBRARIES)

message(STATUS "Found Libffi (include: ${LIBFFI_INCLUDE_DIRS}, library: ${LIBFFI_LIBRARIES})")
3 changes: 3 additions & 0 deletions script/installation/packages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ if [ "$DISTRO" = "UBUNTU" ]; then
libedit-dev \
libssl-dev \
postgresql-client \
libffi6 \
libffi-dev \
libtbb-dev \
python3-pip \
curl \
Expand Down Expand Up @@ -219,6 +221,7 @@ elif [ "$DISTRO" = "DARWIN" ]; then
brew install libedit
brew install llvm@3.7
brew install postgresql
brew install libffi
brew install tbb
brew install curl
brew install wget
Expand Down
99 changes: 67 additions & 32 deletions src/codegen/code_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ namespace {
class PelotonMemoryManager : public llvm::SectionMemoryManager {
public:
explicit PelotonMemoryManager(
const std::unordered_map<std::string, CodeContext::FuncPtr> &symbols)
: symbols_(symbols) {}
const std::unordered_map<std::string,
std::pair<llvm::Function *, CodeContext::FuncPtr>> &builtins)
: builtins_(builtins) {}

#if LLVM_VERSION_GE(4, 0)
#define RET_TYPE llvm::JITSymbol
Expand All @@ -56,8 +57,6 @@ class PelotonMemoryManager : public llvm::SectionMemoryManager {
#define BUILD_RET_TYPE(addr) \
(RET_TYPE{(uint64_t)addr, llvm::JITSymbolFlags::Exported})
#endif

/// Find the address of the function with the given name
RET_TYPE findSymbol(const std::string &name) override {
LOG_TRACE("Looking up symbol '%s' ...", name.c_str());
if (auto *builtin = LookupSymbol(name)) {
Expand All @@ -68,23 +67,22 @@ class PelotonMemoryManager : public llvm::SectionMemoryManager {
LOG_TRACE("--> Not builtin, use fallback resolution ...");
return llvm::SectionMemoryManager::findSymbol(name);
}

#undef RET_TYPE
#undef BUILD_RET_TYPE

private:
void *LookupSymbol(const std::string &name) const {
// Check for a builtin with the exact name
auto symbol_iter = symbols_.find(name);
if (symbol_iter != symbols_.end()) {
return symbol_iter->second;
auto symbol_iter = builtins_.find(name);
if (symbol_iter != builtins_.end()) {
return symbol_iter->second.second;
}

// Check for a builtin with the leading '_' removed
if (!name.empty() && name[0] == '_') {
symbol_iter = symbols_.find(name.substr(1));
if (symbol_iter != symbols_.end()) {
return symbol_iter->second;
symbol_iter = builtins_.find(name.substr(1));
if (symbol_iter != builtins_.end()) {
return symbol_iter->second.second;
}
}

Expand All @@ -94,7 +92,9 @@ class PelotonMemoryManager : public llvm::SectionMemoryManager {

private:
// The code context
const std::unordered_map<std::string, CodeContext::FuncPtr> &symbols_;
const std::unordered_map<std::string,
std::pair<llvm::Function *, CodeContext::FuncPtr>>
&builtins_;
};

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -177,7 +177,8 @@ CodeContext::CodeContext()
func_(nullptr),
udf_func_ptr_(nullptr),
pass_manager_(nullptr),
engine_(nullptr) {
engine_(nullptr),
is_verified_(false) {
// Initialize JIT stuff
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
Expand All @@ -200,8 +201,7 @@ CodeContext::CodeContext()
engine_.reset(
llvm::EngineBuilder(std::move(m))
.setEngineKind(llvm::EngineKind::JIT)
.setMCJITMemoryManager(
llvm::make_unique<PelotonMemoryManager>(function_symbols_))
.setMCJITMemoryManager(llvm::make_unique<PelotonMemoryManager>(builtins_))
.setMCPU(llvm::sys::getHostCPUName())
.setErrorStr(&err_str_)
.create());
Expand All @@ -223,6 +223,7 @@ CodeContext::CodeContext()
int32_type_ = llvm::Type::getInt32Ty(*context_);
int64_type_ = llvm::Type::getInt64Ty(*context_);
double_type_ = llvm::Type::getDoubleTy(*context_);
float_type_ = llvm::Type::getFloatTy(*context_);
void_type_ = llvm::Type::getVoidTy(*context_);
void_ptr_type_ = llvm::Type::getInt8PtrTy(*context_);
char_ptr_type_ = llvm::Type::getInt8PtrTy(*context_);
Expand Down Expand Up @@ -251,14 +252,13 @@ void CodeContext::RegisterExternalFunction(llvm::Function *func_decl,
PELOTON_ASSERT(func_impl != nullptr && "The function pointer cannot be NULL");
functions_.emplace_back(func_decl, func_impl);

// Register the builtin symbol by name
function_symbols_[func_decl->getName()] = func_impl;
builtins_[func_decl->getName()] = std::make_pair(func_decl, func_impl);
}

void CodeContext::RegisterBuiltin(llvm::Function *func_decl,
CodeContext::FuncPtr func_impl) {
const auto name = func_decl->getName();
if (LookupBuiltin(name) != nullptr) {
if (LookupBuiltin(name).first != nullptr) {
LOG_DEBUG("Builtin '%s' already registered, skipping ...", name.data());
return;
}
Expand All @@ -268,44 +268,58 @@ void CodeContext::RegisterBuiltin(llvm::Function *func_decl,
func_decl->isDeclaration() &&
"You cannot provide a function definition for a builtin function");

// Register the builtin function
builtins_[name] = func_decl;

// Register the builtin symbol by name
function_symbols_[name] = func_impl;
// Register the builtin function with type and implementation
builtins_[name] = std::make_pair(func_decl, func_impl);
}

llvm::Function *CodeContext::LookupBuiltin(const std::string &name) const {
std::pair<llvm::Function *, CodeContext::FuncPtr> CodeContext::LookupBuiltin(const std::string &name) const {
auto iter = builtins_.find(name);
return (iter == builtins_.end() ? nullptr : iter->second);
return (iter == builtins_.end() ? std::make_pair<llvm::Function *, CodeContext::FuncPtr>(nullptr, nullptr) : iter->second);
}

/// Optimize and JIT compile all the functions that were created in this context
bool CodeContext::Compile() {
/// Verify all the functions that were created in this context
void CodeContext::Verify() {
// Verify the module is okay
llvm::raw_ostream &errors = llvm::errs();
if (llvm::verifyModule(*module_, &errors)) {
// There is an error in the module that failed compilation.
// There is an error in the module.
// Dump the crappy IR to the log ...
LOG_ERROR("ERROR IN MODULE:\n%s\n", GetIR().c_str());
return false;

throw Exception("The generated LLVM code contains errors. ");
}

// All is well
is_verified_ = true;
}

/// Optimize all the functions that were created in this context
void CodeContext::Optimize() {
// make sure the code is verified
if (!is_verified_) Verify();

// Run the optimization passes over each function in this module
pass_manager_->doInitialization();
for (auto &func_iter : functions_) {
pass_manager_->run(*func_iter.first);
}
pass_manager_->doFinalization();
}

/// JIT compile all the functions that were created in this context
void CodeContext::Compile() {
// make sure the code is verified
if (!is_verified_) Verify();

// Print some IR stats
if (settings::SettingsManager::GetBool(settings::SettingId::print_ir_stats)) {
char name[] = "inst count";
InstructionCounts inst_count(*name);
inst_count.runOnModule(GetModule());
inst_count.DumpStats();
}

// Functions and module have been optimized, now JIT compile the module
// JIT compile the module
engine_->finalizeObject();

// Pull out the compiled function implementations
Expand All @@ -314,14 +328,34 @@ bool CodeContext::Compile() {
}

// Log the module
LOG_TRACE("%s\n", GetIR().c_str());
if (settings::SettingsManager::GetBool(settings::SettingId::dump_ir)) {
LOG_DEBUG("%s\n", GetIR().c_str());
}
}

// All is well
return true;
size_t CodeContext::GetTypeSize(llvm::Type *type) const {
auto size = GetDataLayout().getTypeSizeInBits(type) / 8;
return size != 0 ? size : 1;
}

size_t CodeContext::GetTypeSizeInBits(llvm::Type *type) const {
return GetDataLayout().getTypeSizeInBits(type);
}

size_t CodeContext::GetTypeAllocSize(llvm::Type *type) const {
return GetDataLayout().getTypeAllocSize(type);
}

size_t CodeContext::GetTypeAllocSizeInBits(llvm::Type *type) const {
return GetDataLayout().getTypeAllocSizeInBits(type);
}

size_t CodeContext::GetStructElementOffset(llvm::StructType *type, size_t index) const {
return GetDataLayout().getStructLayout(type)->getElementOffset(index);
}

// TODO(marcel) same as LookupBuiltin?
CodeContext::FuncPtr CodeContext::GetRawFunctionPointer(
llvm::Function *fn) const {
for (const auto &iter : functions_) {
Expand All @@ -334,6 +368,7 @@ CodeContext::FuncPtr CodeContext::GetRawFunctionPointer(
return nullptr;
}

/// Get the module's layout
const llvm::DataLayout &CodeContext::GetDataLayout() const {
return module_->getDataLayout();
}
Expand Down
24 changes: 21 additions & 3 deletions src/codegen/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ llvm::Value *CodeGen::CallFunc(llvm::Value *fn,

llvm::Value *CodeGen::Printf(const std::string &format,
const std::vector<llvm::Value *> &args) {
auto *printf_fn = LookupBuiltin("printf");
auto *printf_fn = LookupBuiltin("printf").first;
if (printf_fn == nullptr) {
#if GCC_AT_LEAST_6
// In newer GCC versions (i.e., GCC 6+), function attributes are part of the
Expand Down Expand Up @@ -183,7 +183,7 @@ llvm::Value *CodeGen::Printf(const std::string &format,
llvm::Value *CodeGen::Memcmp(llvm::Value *ptr1, llvm::Value *ptr2,
llvm::Value *len) {
static constexpr char kMemcmpFnName[] = "memcmp";
auto *memcmp_fn = LookupBuiltin(kMemcmpFnName);
auto *memcmp_fn = LookupBuiltin(kMemcmpFnName).first;
if (memcmp_fn == nullptr) {
#if GCC_AT_LEAST_6
// In newer GCC versions (i.e., GCC 6+), function attributes are part of the
Expand Down Expand Up @@ -311,7 +311,7 @@ llvm::Function *CodeGen::RegisterBuiltin(const std::string &fn_name,
llvm::FunctionType *fn_type,
void *func_impl) {
// Check if this is already registered as a built in, quit if to
auto *builtin = LookupBuiltin(fn_name);
auto *builtin = LookupBuiltin(fn_name).first;
if (builtin != nullptr) {
return builtin;
}
Expand All @@ -332,6 +332,10 @@ llvm::Type *CodeGen::LookupType(const std::string &name) const {
return GetModule().getTypeByName(name);
}

std::pair<llvm::Function *, CodeContext::FuncPtr> CodeGen::LookupBuiltin(const std::string &name) const {
return code_context_.LookupBuiltin(name);
};

llvm::Value *CodeGen::GetState() const {
auto *func_builder = code_context_.GetCurrentFunction();
PELOTON_ASSERT(func_builder != nullptr);
Expand All @@ -346,6 +350,20 @@ uint64_t CodeGen::SizeOf(llvm::Type *type) const {
return size != 0 ? size : 1;
}

std::string CodeGen::Dump(const llvm::Value *value) {
std::string string;
llvm::raw_string_ostream llvm_stream(string);
llvm_stream << *value;
return llvm_stream.str();
}

std::string CodeGen::Dump(llvm::Type *type) {
std::string string;
llvm::raw_string_ostream llvm_stream(string);
llvm_stream << *type;
return llvm_stream.str();
}

uint64_t CodeGen::ElementOffset(llvm::Type *type, uint32_t element_idx) const {
PELOTON_ASSERT(llvm::isa<llvm::StructType>(type));
auto &data_layout = code_context_.GetDataLayout();
Expand Down
10 changes: 3 additions & 7 deletions src/codegen/compilation_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,13 @@ void CompilationContext::GeneratePlan(Query &query,
}

// Next, we prepare the query statement with the functions we've generated
Query::QueryFunctions funcs = {
.init_func = init, .plan_func = plan, .tear_down_func = tear_down};
bool prepared = query.Prepare(funcs);
if (!prepared) {
throw Exception{"There was an error preparing the compiled query"};
}
Query::LLVMFunctions funcs = {init, plan, tear_down};
query.Prepare(funcs);

// We're done
if (stats != nullptr) {
timer.Stop();
stats->jit_ms = timer.GetDuration();
stats->optimize_ms = timer.GetDuration();
}
}

Expand Down
Loading

0 comments on commit a045cfc

Please sign in to comment.