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

Commit

Permalink
llvm function support
Browse files Browse the repository at this point in the history
  • Loading branch information
Xupeng Li authored and apavlo committed Oct 12, 2017
1 parent 5d27bf9 commit 8666f36
Show file tree
Hide file tree
Showing 12 changed files with 334 additions and 16 deletions.
15 changes: 15 additions & 0 deletions src/codegen/codegen.cpp
Expand Up @@ -106,6 +106,21 @@ llvm::Value *CodeGen::CallPrintf(const std::string &format,
return CallFunc(printf_fn, printf_args);
}

llvm::Value *CodeGen::CallStrlen(llvm::Value *str) {
auto *strlen_fn = LookupBuiltin("strlen");
if (strlen_fn == nullptr) {
strlen_fn = RegisterBuiltin(
"strlen", llvm::TypeBuilder<int(const char *), false>::get(GetContext()),
reinterpret_cast<void *>(strlen));
}

// Collect all the arguments into a vector
std::vector<llvm::Value *> strlen_args{str};

// Call the function
return CallFunc(strlen_fn, strlen_args);
}

llvm::Value *CodeGen::CallAddWithOverflow(llvm::Value *left, llvm::Value *right,
llvm::Value *&overflow_bit) {
PL_ASSERT(left->getType() == right->getType());
Expand Down
74 changes: 72 additions & 2 deletions src/codegen/expression/function_translator.cpp
@@ -1,6 +1,7 @@
#include "codegen/expression/function_translator.h"

#include "codegen/type/sql_type.h"
#include "expression/function_expression.h"
#include "codegen/proxy/function_wrapper_proxy.h"

namespace peloton {
namespace codegen {
Expand All @@ -13,7 +14,76 @@ FunctionTranslator::FunctionTranslator(
codegen::Value FunctionTranslator::DeriveValue(
CodeGen &codegen, RowBatch::Row &row) const {
const auto &func_expr = GetExpressionAs<expression::FunctionExpression>();
func_expr->

// get the number of arguments
size_t child_num = func_expr.GetChildrenSize();
std::vector<llvm::Value*> args;

// store function pointer
args.push_back(codegen.Const64((int64_t)func_expr.func_ptr_));
// store argument number
args.push_back(codegen.Const32((int32_t) child_num));

// store arguments
for (size_t i = 0; i < child_num; ++i) {
args.push_back(codegen.Const32(
static_cast<int32_t>(func_expr.func_arg_types_[i])));
args.push_back(row.DeriveValue(codegen, *func_expr.GetChild(i))
.GetValue());
}

return CallWrapperFunction(func_expr.GetValueType(), args, codegen);
}

codegen::Value FunctionTranslator::CallWrapperFunction(
peloton::type::TypeId ret_type,
std::vector<llvm::Value*> &args,
CodeGen &codegen) const {
llvm::Function *wrapper = nullptr;
std::vector<llvm::Type *> arg_types{codegen.Int32Type()};

// get the wrapper function with certain return type
switch (ret_type) {
case peloton::type::TypeId::TINYINT:
wrapper = FunctionWrapperProxy::TinyIntWrapper.GetFunction(codegen);
break;
case peloton::type::TypeId::SMALLINT:
wrapper = FunctionWrapperProxy::SmallIntWrapper.GetFunction(codegen);
break;
case peloton::type::TypeId::INTEGER:
wrapper = FunctionWrapperProxy::IntegerWrapper.GetFunction(codegen);
break;
case peloton::type::TypeId::BIGINT:
wrapper = FunctionWrapperProxy::BigIntWrapper.GetFunction(codegen);
break;
case peloton::type::TypeId::DECIMAL:
wrapper = FunctionWrapperProxy::DecimalWrapper.GetFunction(codegen);
break;
case peloton::type::TypeId::DATE:
wrapper = FunctionWrapperProxy::DateWrapper.GetFunction(codegen);
break;
case peloton::type::TypeId::TIMESTAMP:
wrapper = FunctionWrapperProxy::TimestampWrapper.GetFunction(codegen);
break;
case peloton::type::TypeId::VARCHAR:
wrapper = FunctionWrapperProxy::VarcharWrapper.GetFunction(codegen);
break;
default:
break;
}
if (wrapper != nullptr) {
// call the function
llvm::Value *ret_val = codegen.CallFunc(wrapper, args);
// call strlen to get the length of a varchar
llvm::Value *ret_len = nullptr;
if (ret_type == peloton::type::TypeId::VARCHAR) {
ret_len = codegen.CallStrlen(ret_val);
}
return codegen::Value(type::SqlType::LookupType(ret_type), ret_val, ret_len);
}
else {
return codegen::Value(type::SqlType::LookupType(ret_type));
}
}

} // namespace codegen
Expand Down
132 changes: 132 additions & 0 deletions src/codegen/function_wrapper.cpp
@@ -0,0 +1,132 @@
#include <stdarg.h>
#include "codegen/function_wrapper.h"
#include "type/value_factory.h"
#include "type/ephemeral_pool.h"

namespace peloton {
namespace codegen {

inline std::vector<peloton::type::Value> GetArguments(
int n_args, va_list &ap) {
std::vector<peloton::type::Value> args;
for (int i = 0; i < n_args; ++i) {
peloton::type::TypeId type_id = peloton::type::TypeId(va_arg(ap, int32_t));
switch (type_id) {
case peloton::type::TypeId::TINYINT:
args.push_back(peloton::type::ValueFactory::GetTinyIntValue(
va_arg(ap, int32_t)
));
break;
case peloton::type::TypeId::SMALLINT:
args.push_back(peloton::type::ValueFactory::GetSmallIntValue(
va_arg(ap, int32_t)
));
break;
case peloton::type::TypeId::INTEGER:
args.push_back(peloton::type::ValueFactory::GetIntegerValue(
va_arg(ap, int32_t)
));
break;
case peloton::type::TypeId::BIGINT:
args.push_back(peloton::type::ValueFactory::GetBigIntValue(
va_arg(ap, int64_t)
));
break;
case peloton::type::TypeId::DECIMAL:
args.push_back(peloton::type::ValueFactory::GetDecimalValue(
va_arg(ap, double)
));
break;
case peloton::type::TypeId::DATE:
args.push_back(peloton::type::ValueFactory::GetDateValue(
va_arg(ap, int32_t)
));
break;
case peloton::type::TypeId::TIMESTAMP:
args.push_back(peloton::type::ValueFactory::GetTimestampValue(
va_arg(ap, int64_t)
));
break;
case peloton::type::TypeId::VARCHAR:
args.push_back(peloton::type::ValueFactory::GetVarcharValue(
va_arg(ap, const char*)
));
break;
default:
args.push_back(peloton::type::ValueFactory::GetNullValueByType(type_id));
break;
}
}
return args;
}

int8_t FunctionWrapper::TinyIntWrapper(int64_t func, int n_args, ...) {
va_list ap;
va_start(ap, n_args);
std::vector<peloton::type::Value> args = GetArguments(n_args, ap);
peloton::type::Value ret = ((BuiltInFuncType)func)(args);
return ret.GetAs<int8_t>();
}

int16_t FunctionWrapper::SmallIntWrapper(int64_t func, int n_args, ...) {
va_list ap;
va_start(ap, n_args);
std::vector<peloton::type::Value> args = GetArguments(n_args, ap);
peloton::type::Value ret = ((BuiltInFuncType)func)(args);
return ret.GetAs<int16_t>();
}

int32_t FunctionWrapper::IntegerWrapper(int64_t func, int n_args, ...) {
va_list ap;
va_start(ap, n_args);
std::vector<peloton::type::Value> args = GetArguments(n_args, ap);
peloton::type::Value ret = ((BuiltInFuncType)func)(args);
return ret.GetAs<int32_t>();
}

int64_t FunctionWrapper::BigIntWrapper(int64_t func, int n_args, ...) {
va_list ap;
va_start(ap, n_args);
std::vector<peloton::type::Value> args = GetArguments(n_args, ap);
peloton::type::Value ret = ((BuiltInFuncType)func)(args);
return ret.GetAs<int64_t>();
}

double FunctionWrapper::DecimalWrapper(int64_t func, int n_args, ...) {
va_list ap;
va_start(ap, n_args);
std::vector<peloton::type::Value> args = GetArguments(n_args, ap);
peloton::type::Value ret = ((BuiltInFuncType)func)(args);
return ret.GetAs<double>();
}

int32_t FunctionWrapper::DateWrapper(int64_t func, int n_args, ...) {
va_list ap;
va_start(ap, n_args);
std::vector<peloton::type::Value> args = GetArguments(n_args, ap);
peloton::type::Value ret = ((BuiltInFuncType)func)(args);
return ret.GetAs<int32_t>();
}

int64_t FunctionWrapper::TimestampWrapper(int64_t func, int n_args, ...) {
va_list ap;
va_start(ap, n_args);
std::vector<peloton::type::Value> args = GetArguments(n_args, ap);
peloton::type::Value ret = ((BuiltInFuncType)func)(args);
return ret.GetAs<int64_t>();
}

const char* FunctionWrapper::VarcharWrapper(int64_t func, int n_args, ...) {
// TODO: put this pool to a proper place
static type::EphemeralPool pool;
va_list ap;
va_start(ap, n_args);
std::vector<peloton::type::Value> args = GetArguments(n_args, ap);
peloton::type::Value ret = ((BuiltInFuncType)func)(args);
char* str = static_cast<char*>(pool.Allocate(ret.GetLength()));
strcpy(str, ret.GetData());
return str;
}

}
}
16 changes: 16 additions & 0 deletions src/codegen/proxy/function_wrapper_proxy.cpp
@@ -0,0 +1,16 @@
#include "codegen/proxy/function_wrapper_proxy.h"

namespace peloton {
namespace codegen {

DEFINE_METHOD(peloton::codegen, FunctionWrapper, TinyIntWrapper);
DEFINE_METHOD(peloton::codegen, FunctionWrapper, SmallIntWrapper);
DEFINE_METHOD(peloton::codegen, FunctionWrapper, IntegerWrapper);
DEFINE_METHOD(peloton::codegen, FunctionWrapper, BigIntWrapper);
DEFINE_METHOD(peloton::codegen, FunctionWrapper, DecimalWrapper);
DEFINE_METHOD(peloton::codegen, FunctionWrapper, DateWrapper);
DEFINE_METHOD(peloton::codegen, FunctionWrapper, TimestampWrapper);
DEFINE_METHOD(peloton::codegen, FunctionWrapper, VarcharWrapper);

} // namespace codegen
} // namespace peloton
3 changes: 1 addition & 2 deletions src/codegen/translator_factory.cpp
Expand Up @@ -28,13 +28,12 @@
#include "codegen/expression/tuple_value_translator.h"
#include "codegen/expression/function_translator.h"
#include "expression/case_expression.h"
#include "expression/comparison_expression.h"
#include "expression/conjunction_expression.h"
#include "expression/constant_value_expression.h"
#include "expression/operator_expression.h"
#include "expression/tuple_value_expression.h"
#include "expression/aggregate_expression.h"
#include "planner/aggregate_plan.h"
#include "expression/function_expression.h"
#include "planner/delete_plan.h"
#include "planner/hash_join_plan.h"
#include "planner/order_by_plan.h"
Expand Down
2 changes: 2 additions & 0 deletions src/include/codegen/codegen.h
Expand Up @@ -98,6 +98,8 @@ class CodeGen {
llvm::Value *CallPrintf(const std::string &format,
const std::vector<llvm::Value *> &args);

llvm::Value *CallStrlen(llvm::Value *str);

//===--------------------------------------------------------------------===//
// Arithmetic with overflow logic - These methods perform the desired math op,
// on the provided left and right argument and return the result of the op
Expand Down
7 changes: 7 additions & 0 deletions src/include/codegen/expression/function_translator.h
@@ -1,6 +1,8 @@
#pragma once

#include "codegen/expression/expression_translator.h"
#include "codegen/function_wrapper.h"
#include <unordered_set>

namespace peloton {

Expand All @@ -22,6 +24,11 @@ class FunctionTranslator : public ExpressionTranslator {
// Return the result of the function call
codegen::Value DeriveValue(CodeGen &codegen,
RowBatch::Row &row) const override;
private:
codegen::Value CallWrapperFunction(
peloton::type::TypeId ret_type,
std::vector<llvm::Value*> &args,
CodeGen &codegen) const;
};

} // namespace codegen
Expand Down
23 changes: 23 additions & 0 deletions src/include/codegen/function_wrapper.h
@@ -0,0 +1,23 @@
#pragma once

#include "type/types.h"
#include "type/value.h"

namespace peloton {
namespace codegen {

class FunctionWrapper {
typedef peloton::type::Value (*BuiltInFuncType)(const std::vector<peloton::type::Value> &);
public:
static int8_t TinyIntWrapper(int64_t func, int n_args, ...);
static int16_t SmallIntWrapper(int64_t func, int n_args, ...);
static int32_t IntegerWrapper(int64_t func, int n_args, ...);
static int64_t BigIntWrapper(int64_t func, int n_args, ...);
static double DecimalWrapper(int64_t func, int n_args, ...);
static int32_t DateWrapper(int64_t func, int n_args, ...);
static int64_t TimestampWrapper(int64_t func, int n_args, ...);
static const char *VarcharWrapper(int64_t func, int n_args, ...);
};

}
}
22 changes: 22 additions & 0 deletions src/include/codegen/proxy/function_wrapper_proxy.h
@@ -0,0 +1,22 @@
#pragma once

#include "codegen/function_wrapper.h"
#include "codegen/proxy/proxy.h"
#include "codegen/proxy/type_builder.h"

namespace peloton {
namespace codegen {

PROXY(FunctionWrapper) {
DECLARE_METHOD(TinyIntWrapper);
DECLARE_METHOD(SmallIntWrapper);
DECLARE_METHOD(IntegerWrapper);
DECLARE_METHOD(BigIntWrapper);
DECLARE_METHOD(DecimalWrapper);
DECLARE_METHOD(DateWrapper);
DECLARE_METHOD(TimestampWrapper);
DECLARE_METHOD(VarcharWrapper);
};

} // namespace codegen
} // namespace peloton
5 changes: 5 additions & 0 deletions src/include/codegen/proxy/proxy.h
Expand Up @@ -182,6 +182,11 @@ struct MemFn<R (*)(Args...), T, F> {
static void *Get() { return reinterpret_cast<void *>(F); }
};

template <typename R, typename... Args, typename T, T F>
struct MemFn<R (*)(Args..., ...), T, F> {
static void *Get() { return reinterpret_cast<void *>(F); }
};

} // namespace detail
} // namespace proxy

Expand Down
22 changes: 22 additions & 0 deletions src/include/codegen/proxy/type_builder.h
Expand Up @@ -103,6 +103,28 @@ struct TypeBuilder<Ret (*)(Args...)> {
}
};

/// Regular C-style functions with variable arguments
template <typename Ret, typename... Args>
struct TypeBuilder<Ret(Args..., ...)> {
static llvm::Type *GetType(CodeGen &codegen) ALWAYS_INLINE {
llvm::Type *ret_type = TypeBuilder<Ret>::GetType(codegen);
std::vector<llvm::Type *> arg_types = {
TypeBuilder<Args>::GetType(codegen)...};
return llvm::FunctionType::get(ret_type, arg_types, true);
}
};

/// C-style function pointer with variable arguments
template <typename Ret, typename... Args>
struct TypeBuilder<Ret (*)(Args..., ...)> {
static llvm::Type *GetType(CodeGen &codegen) ALWAYS_INLINE {
llvm::Type *ret_type = TypeBuilder<Ret>::GetType(codegen);
std::vector<llvm::Type *> arg_types = {
TypeBuilder<Args>::GetType(codegen)...};
return llvm::FunctionType::get(ret_type, arg_types, true)->getPointerTo();
}
};

/// Member functions
template <typename R, typename T, typename... Args>
struct TypeBuilder<R (T::*)(Args...)> {
Expand Down

0 comments on commit 8666f36

Please sign in to comment.