Enhance codegen framework to support arbitrary expr tree

上级 ec626ce6
......@@ -167,6 +167,10 @@ set(GPCODEGEN_SRC
codegen_wrapper.cc
exec_variable_list_codegen.cc
exec_eval_expr_codegen.cc
expr_tree_generator.cc
op_expr_tree_generator.cc
var_expr_tree_generator.cc
const_expr_tree_generator.cc
)
# Integrate with GPDB build system.
......
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#include "codegen/expr_tree_generator.h"
#include "codegen/const_expr_tree_generator.h"
#include "llvm/IR/Value.h"
extern "C" {
#include "postgres.h"
#include "utils/elog.h"
#include "nodes/execnodes.h"
}
using gpcodegen::ConstExprTreeGenerator;
using gpcodegen::ExprTreeGenerator;
bool ConstExprTreeGenerator::VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
std::unique_ptr<ExprTreeGenerator>& expr_tree) {
assert(nullptr != expr_state && nullptr != expr_state->expr && T_Const == nodeTag(expr_state->expr));
expr_tree.reset(new ConstExprTreeGenerator(expr_state));
return true;
}
ConstExprTreeGenerator::ConstExprTreeGenerator(ExprState* expr_state) :
ExprTreeGenerator(expr_state, ExprTreeNodeType::kConst) {
}
bool ConstExprTreeGenerator::GenerateCode(CodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
llvm::Value* & value) {
Const* const_expr = (Const*)expr_state()->expr;
value = codegen_utils->GetConstant(const_expr->constvalue);
return true;
}
......@@ -14,6 +14,8 @@
#include <string>
#include "codegen/exec_eval_expr_codegen.h"
#include "codegen/expr_tree_generator.h"
#include "codegen/op_expr_tree_generator.h"
#include "codegen/utils/clang_compiler.h"
#include "codegen/utils/utility.h"
#include "codegen/utils/instance_method_wrappers.h"
......@@ -125,12 +127,18 @@ bool ExecEvalExprCodegen::GenerateExecEvalExpr(
gpcodegen::CodegenUtils* codegen_utils) {
assert(NULL != codegen_utils);
if (nullptr == exprstate_ ||
nullptr == exprstate_->expr ||
nullptr == econtext_) {
return false;
}
ElogWrapper elogwrapper(codegen_utils);
//TODO : krajaraman move to better place
OpExprTreeGenerator::InitializeSupportedFunction();
llvm::Function* exec_eval_expr_func = codegen_utils->
CreateFunction<ExecEvalExprFn>(
GetUniqueFuncName());
llvm::Function* exec_eval_expr_func = CreateFunction<ExecEvalExprFn>(
codegen_utils, GetUniqueFuncName());
// Function arguments to ExecVariableList
llvm::Value* llvm_expression_arg =
......@@ -144,134 +152,48 @@ bool ExecEvalExprCodegen::GenerateExecEvalExpr(
codegen_utils->RegisterExternalFunction(slot_getattr);
// BasicBlock of function entry.
llvm::BasicBlock* entry_block = codegen_utils->CreateBasicBlock(
llvm::BasicBlock* llvm_entry_block = codegen_utils->CreateBasicBlock(
"entry", exec_eval_expr_func);
llvm::BasicBlock* return_true_block = codegen_utils->CreateBasicBlock(
"return_true", exec_eval_expr_func);
llvm::BasicBlock* return_false_block = codegen_utils->CreateBasicBlock(
"return_false", exec_eval_expr_func);
llvm::BasicBlock* llvm_error_block = codegen_utils->CreateBasicBlock(
"error_block", exec_eval_expr_func);
auto irb = codegen_utils->ir_builder();
irb->SetInsertPoint(entry_block);
if (exprstate_ && exprstate_->expr && econtext_) {
// Codegen Operation expression
Expr *expr_ = exprstate_->expr;
if (nodeTag(expr_) != T_OpExpr) {
elog(DEBUG1, "Unsupported expression. Support only T_OpExpr");
return false;
}
// In ExecEvalOper
OpExpr *op = (OpExpr *) expr_;
if (op->opno != 523 /* "<=" */ && op->opno != 1096 /* date "<=" */) {
// Operators are stored in pg_proc table. See postgres.bki for more details.
elog(DEBUG1, "Unsupported operator %d.", op->opno);
return false;
}
// In ExecMakeFunctionResult
// retrieve operator's arguments
List *arguments = ((FuncExprState *)exprstate_)->args;
// In ExecEvalFuncArgs
if (list_length(arguments) != 2) {
elog(DEBUG1, "Wrong number of arguments (!= 2)");
return false;
}
ListCell *arg;
int arg_num = 0;
llvm::Value *llvm_arg_val[2];
foreach(arg, arguments)
{
// retrieve argument's ExprState
ExprState *argstate = (ExprState *) lfirst(arg);
// Currently we support only variable and constant arguments
if (nodeTag(argstate->expr) == T_Var) {
// In ExecEvalVar
Var *variable = (Var *) argstate->expr;
int attnum = variable->varattno;
// slot = econtext->ecxt_scantuple; {{{
// At code generation time, slot is NULL.
// For that reason, we keep a double pointer to slot and at execution time
// we load slot.
TupleTableSlot **ptr_to_slot_ptr = NULL;
switch (variable->varno)
{
case INNER: /* get the tuple from the inner node */
ptr_to_slot_ptr = &econtext_->ecxt_innertuple;
break;
case OUTER: /* get the tuple from the outer node */
ptr_to_slot_ptr = &econtext_->ecxt_outertuple;
break;
default: /* get the tuple from the relation being scanned */
ptr_to_slot_ptr = &econtext_->ecxt_scantuple;
break;
}
llvm::Value *llvm_slot = irb->CreateLoad(
codegen_utils->GetConstant(ptr_to_slot_ptr));
//}}}
llvm::Value *llvm_variable_varattno = codegen_utils->
GetConstant<int4>(variable->varattno);
// retrieve variable
llvm_arg_val[arg_num] = codegen_utils->ir_builder()->CreateCall(
llvm_slot_getattr, {
llvm_slot,
llvm_variable_varattno,
llvm_isnull_arg /* TODO: Fix isNull */
});
}
else if (nodeTag(argstate->expr) == T_Const) {
// In ExecEvalConst
Const *con = (Const *) argstate->expr;
llvm_arg_val[arg_num] = codegen_utils->GetConstant(con->constvalue);
}
else {
elog(DEBUG1, "Unsupported argument type.");
return false;
}
arg_num++;
}
if (op->opno == 523) {
// Execute **int4le**
irb->CreateCondBr(
irb->CreateICmpSLE(llvm_arg_val[0], llvm_arg_val[1]),
return_true_block /* true */,
return_false_block /* false */);
}
else { // op->opno == 1096
// Execute **date_le**
// Similar to int4le but we trunc the values to i32 from i64
irb->CreateCondBr(irb->CreateICmpSLE(
irb->CreateTrunc(llvm_arg_val[0], codegen_utils->GetType<int32>()),
irb->CreateTrunc(llvm_arg_val[1], codegen_utils->GetType<int32>())),
return_true_block /* true */,
return_false_block /* false */);
}
irb->SetInsertPoint(return_true_block);
irb->CreateRet(codegen_utils->GetConstant<int64>(1));
irb->SetInsertPoint(return_false_block);
irb->CreateRet(codegen_utils->GetConstant<int64>(0));
irb->SetInsertPoint(llvm_entry_block);
return true;
elogwrapper.CreateElog(
DEBUG1,
"Calling codegen'ed expression evaluation");
// Check if we can codegen. If so create ExprTreeGenerator
std::unique_ptr<ExprTreeGenerator> expr_tree_generator(nullptr);
bool can_generate = ExprTreeGenerator::VerifyAndCreateExprTree(
exprstate_, econtext_, expr_tree_generator);
if (!can_generate ||
expr_tree_generator.get() == nullptr) {
return false;
}
return false;
// Generate code from expression tree generator
llvm::Value* value = nullptr;
bool is_generated = expr_tree_generator->GenerateCode(codegen_utils,
econtext_,
exec_eval_expr_func,
llvm_error_block,
llvm_isnull_arg,
value);
if (!is_generated ||
nullptr == value) {
return false;
}
llvm::Value* llvm_ret_value = codegen_utils->CreateCast<int64_t>(value);
irb->CreateRet(llvm_ret_value);
irb->SetInsertPoint(llvm_error_block);
irb->CreateRet(codegen_utils->GetConstant<int64_t>(0));
exec_eval_expr_func->dump();
return true;
}
......
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#include <cassert>
#include "codegen/expr_tree_generator.h"
#include "codegen/op_expr_tree_generator.h"
#include "codegen/var_expr_tree_generator.h"
#include "codegen/const_expr_tree_generator.h"
#include "llvm/IR/Value.h"
extern "C" {
#include "postgres.h"
#include "utils/elog.h"
#include "nodes/execnodes.h"
}
using gpcodegen::ExprTreeGenerator;
bool ExprTreeGenerator::VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
std::unique_ptr<ExprTreeGenerator>& expr_tree) {
assert(nullptr != expr_state && nullptr != expr_state->expr);
expr_tree.reset(nullptr);
bool supported_expr_tree = false;
switch(nodeTag(expr_state->expr)) {
case T_OpExpr: {
supported_expr_tree = OpExprTreeGenerator::VerifyAndCreateExprTree(expr_state,
econtext,
expr_tree);
break;
}
case T_Var: {
supported_expr_tree = VarExprTreeGenerator::VerifyAndCreateExprTree(expr_state,
econtext,
expr_tree);
break;
}
case T_Const: {
supported_expr_tree = ConstExprTreeGenerator::VerifyAndCreateExprTree(expr_state,
econtext,
expr_tree);
break;
}
default : {
supported_expr_tree = false;
elog(DEBUG1, "Unsupported expression tree %d found", nodeTag(expr_state->expr));
}
}
assert((!supported_expr_tree && nullptr == expr_tree.get()) ||
(supported_expr_tree && nullptr != expr_tree.get()));
return supported_expr_tree;
}
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_CONST_EXPR_TREE_GENERATOR_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_CONST_EXPR_TREE_GENERATOR_H_
#include "codegen/expr_tree_generator.h"
#include "llvm/IR/Value.h"
namespace gpcodegen {
/** \addtogroup gpcodegen
* @{
*/
class ConstExprTreeGenerator : public ExprTreeGenerator {
public:
static bool VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
std::unique_ptr<ExprTreeGenerator>& expr_tree);
bool GenerateCode(gpcodegen::CodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
llvm::Value* & value) final;
protected:
ConstExprTreeGenerator(ExprState* expr_state);
};
/** @} */
} // namespace gpcodegen
#endif // GPCODEGEN_CONST_EXPR_TREE_GENERATOR_H_
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_EXPR_TREE_GENERATOR_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_EXPR_TREE_GENERATOR_H_
#include <string>
#include <vector>
#include <memory>
#include <utility>
#include <unordered_map>
#include "codegen/utils/codegen_utils.h"
#include "llvm/IR/Value.h"
typedef struct ExprContext ExprContext;
typedef struct ExprState ExprState;
typedef struct Expr Expr;
typedef struct OpExpr OpExpr;
typedef struct Var Var;
typedef struct Const Const;
namespace gpcodegen {
/** \addtogroup gpcodegen
* @{
*/
enum class ExprTreeNodeType {
kConst = 0,
kVar = 1,
kOperator = 2
};
class ExprTreeGenerator {
public:
static bool VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
std::unique_ptr<ExprTreeGenerator>& expr_tree);
virtual bool GenerateCode(gpcodegen::CodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
llvm::Value* & value) = 0;
ExprState* expr_state() { return expr_state_; }
protected:
ExprTreeGenerator(ExprState* expr_state,
ExprTreeNodeType node_type) :
expr_state_(expr_state), node_type_(node_type) {}
private:
ExprState* expr_state_;
ExprTreeNodeType node_type_;
DISALLOW_COPY_AND_ASSIGN(ExprTreeGenerator);
};
/** @} */
} // namespace gpcodegen
#endif // GPCODEGEN_EXPR_TREE_GENERATOR_H_
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_OP_EXPR_TREE_GENERATOR_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_OP_EXPR_TREE_GENERATOR_H_
#include "codegen/expr_tree_generator.h"
#include "codegen/pg_func_generator_interface.h"
#include "codegen/pg_func_generator.h"
#include "llvm/IR/Value.h"
namespace gpcodegen {
/** \addtogroup gpcodegen
* @{
*/
using CodeGenFuncMap = std::unordered_map<unsigned int,
std::unique_ptr<gpcodegen::PGFuncGeneratorInterface>>;
class OpExprTreeGenerator : public ExprTreeGenerator {
public:
static void InitializeSupportedFunction();
static bool VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
std::unique_ptr<ExprTreeGenerator>& expr_tree);
bool GenerateCode(gpcodegen::CodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
llvm::Value* & value) final;
protected:
OpExprTreeGenerator(ExprState* expr_state,
std::vector<std::unique_ptr<ExprTreeGenerator>>& arguments);
private:
std::vector<std::unique_ptr<ExprTreeGenerator>> arguments_;
static CodeGenFuncMap supported_function_;
};
/** @} */
} // namespace gpcodegen
#endif // GPCODEGEN_OP_EXPR_TREE_GENERATOR_H_
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_PG_ARITH_FUNC_GENERATOR_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_PG_ARITH_FUNC_GENERATOR_H_
#include <string>
#include <vector>
#include <memory>
#include "codegen/utils/codegen_utils.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Value.h"
namespace gpcodegen {
/** \addtogroup gpcodegen
* @{
*/
template <typename rtype, typename Arg0, typename Arg1>
class PGArithFuncGenerator {
public:
static bool MulWithOverflow(gpcodegen::CodegenUtils* codegen_utils,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
std::vector<llvm::Value*>& llvm_args,
llvm::Value* & llvm_out_value);
static bool AddWithOverflow(gpcodegen::CodegenUtils* codegen_utils,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
std::vector<llvm::Value*>& llvm_args,
llvm::Value* & llvm_out_value);
static bool SubWithOverflow(gpcodegen::CodegenUtils* codegen_utils,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
std::vector<llvm::Value*>& llvm_args,
llvm::Value* & llvm_out_value);
};
template <typename rtype, typename Arg0, typename Arg1>
bool PGArithFuncGenerator<rtype, Arg0, Arg1>::MulWithOverflow(gpcodegen::CodegenUtils* codegen_utils,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
std::vector<llvm::Value*>& llvm_args,
llvm::Value* & llvm_out_value) {
// Assumed caller checked vector size and nullptr for codegen_utils
llvm::BasicBlock* llvm_non_overflow_block = codegen_utils->CreateBasicBlock(
"mul_non_overflow_block", llvm_main_func);
llvm::BasicBlock* llvm_overflow_block = codegen_utils->CreateBasicBlock(
"mul_overflow_block", llvm_main_func);
llvm::Value* llvm_mul_output = codegen_utils->CreateMulOverflow<rtype>(
llvm_args[0], llvm_args[1]);
llvm::IRBuilder<>* irb = codegen_utils->ir_builder();
llvm_out_value = irb->CreateExtractValue(llvm_mul_output, 0);
llvm::Value* llvm_overflow_flag = irb->CreateExtractValue(llvm_mul_output, 1);
irb->CreateCondBr(
irb->CreateICmpEQ(llvm_overflow_flag,
codegen_utils->GetConstant<bool>(true)),
llvm_overflow_block,
llvm_non_overflow_block );
irb->SetInsertPoint(llvm_overflow_block);
// TODO : krajaraman Elog::ERROR after ElogWrapper integrad.
irb->CreateBr(llvm_error_block);
irb->SetInsertPoint(llvm_non_overflow_block);
return true;
}
template <typename rtype, typename Arg0, typename Arg1>
bool PGArithFuncGenerator<rtype, Arg0, Arg1>::AddWithOverflow(
gpcodegen::CodegenUtils* codegen_utils,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
std::vector<llvm::Value*>& llvm_args,
llvm::Value* & llvm_out_value) {
// Assumed caller checked vector size and nullptr for codegen_utils
llvm::BasicBlock* llvm_non_overflow_block = codegen_utils->CreateBasicBlock(
"add_non_overflow_block", llvm_main_func);
llvm::BasicBlock* llvm_overflow_block = codegen_utils->CreateBasicBlock(
"add_overflow_block", llvm_main_func);
llvm::Value* llvm_mul_output = codegen_utils->CreateAddOverflow<rtype>(
llvm_args[0], llvm_args[1]);
llvm::IRBuilder<>* irb = codegen_utils->ir_builder();
llvm_out_value = irb->CreateExtractValue(llvm_mul_output, 0);
llvm::Value* llvm_overflow_flag = irb->CreateExtractValue(llvm_mul_output, 1);
irb->CreateCondBr(
irb->CreateICmpEQ(llvm_overflow_flag,
codegen_utils->GetConstant<bool>(true)),
llvm_overflow_block,
llvm_non_overflow_block );
irb->SetInsertPoint(llvm_overflow_block);
// TODO : krajaraman Elog::ERROR after ElogWrapper integrad.
irb->CreateBr(llvm_error_block);
irb->SetInsertPoint(llvm_non_overflow_block);
return true;
}
template <typename rtype, typename Arg0, typename Arg1>
bool PGArithFuncGenerator<rtype, Arg0, Arg1>::SubWithOverflow(
gpcodegen::CodegenUtils* codegen_utils,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
std::vector<llvm::Value*>& llvm_args,
llvm::Value* & llvm_out_value) {
// Assumed caller checked vector size and nullptr for codegen_utils
llvm::BasicBlock* llvm_non_overflow_block = codegen_utils->CreateBasicBlock(
"sub_non_overflow_block", llvm_main_func);
llvm::BasicBlock* llvm_overflow_block = codegen_utils->CreateBasicBlock(
"sub_overflow_block", llvm_main_func);
llvm::Value* llvm_mul_output = codegen_utils->CreateSubOverflow<rtype>(
llvm_args[0], llvm_args[1]);
llvm::IRBuilder<>* irb = codegen_utils->ir_builder();
llvm_out_value = irb->CreateExtractValue(llvm_mul_output, 0);
llvm::Value* llvm_overflow_flag = irb->CreateExtractValue(llvm_mul_output, 1);
irb->CreateCondBr(
irb->CreateICmpEQ(llvm_overflow_flag,
codegen_utils->GetConstant<bool>(true)),
llvm_overflow_block,
llvm_non_overflow_block );
irb->SetInsertPoint(llvm_overflow_block);
// TODO : krajaraman Elog::ERROR after ElogWrapper integrad.
irb->CreateBr(llvm_error_block);
irb->SetInsertPoint(llvm_non_overflow_block);
return true;
}
/** @} */
} // namespace gpcodegen
#endif // GPCODEGEN_PG_ARITH_FUNC_GENERATOR_H_
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_PG_FUNC_GENERATOR_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_PG_FUNC_GENERATOR_H_
#include <string>
#include <vector>
#include <memory>
#include "codegen/pg_func_generator_interface.h"
#include "codegen/utils/codegen_utils.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Value.h"
namespace gpcodegen {
/** \addtogroup gpcodegen
* @{
*/
typedef bool (*ExprCodeGenerator)(gpcodegen::CodegenUtils* codegen_utils,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
std::vector<llvm::Value*>& llvm_args,
llvm::Value* & llvm_out_value);
template <typename FuncPtrType, typename Arg0, typename Arg1>
class PGFuncGenerator : public PGFuncGeneratorInterface {
public:
std::string GetName() final { return pg_func_name_; };
size_t GetTotalArgCount() final { return 2; }
protected:
// TODO : krajaraman
// For now treating all argument. Later make template to take
// variable length instead of two arguments
bool PreProcessArgs(gpcodegen::CodegenUtils* codegen_utils,
std::vector<llvm::Value*>& llvm_in_args,
std::vector<llvm::Value*>& llvm_out_args) {
assert(nullptr != codegen_utils);
if (llvm_in_args.size() != GetTotalArgCount()) {
return false;
}
llvm_out_args.push_back(codegen_utils->CreateCast<Arg0>(llvm_in_args[0]));
llvm_out_args.push_back(codegen_utils->CreateCast<Arg1>(llvm_in_args[1]));
return true;
}
FuncPtrType func_ptr() {
return func_ptr_;
}
PGFuncGenerator(int pg_func_oid,
const std::string& pg_func_name,
FuncPtrType mem_func_ptr) : pg_func_oid_(pg_func_oid),
pg_func_name_(pg_func_name),
func_ptr_(mem_func_ptr) {
}
private:
std::string pg_func_name_;
unsigned int pg_func_oid_;
FuncPtrType func_ptr_;
};
template <typename FuncPtrType, typename Arg0, typename Arg1>
class PGIRBuilderFuncGenerator : public PGFuncGenerator<FuncPtrType,
Arg0, Arg1> {
public:
PGIRBuilderFuncGenerator(int pg_func_oid,
const std::string& pg_func_name,
FuncPtrType func_ptr) :
PGFuncGenerator<FuncPtrType,
Arg0, Arg1>(pg_func_oid,
pg_func_name,
func_ptr) {
}
bool GenerateCode(gpcodegen::CodegenUtils* codegen_utils,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
std::vector<llvm::Value*>& llvm_args,
llvm::Value* & llvm_out_value) final {
std::vector<llvm::Value*> llvm_preproc_args;
if (!this->PreProcessArgs(codegen_utils, llvm_args, llvm_preproc_args)) {
return false;
}
llvm::IRBuilder<>* irb = codegen_utils->ir_builder();
llvm_out_value = (irb->*this->func_ptr())(llvm_preproc_args[0],
llvm_preproc_args[1], "");
return true;
}
};
template <typename Arg0, typename Arg1>
class PGGenericFuncGenerator : public PGFuncGenerator<ExprCodeGenerator,
Arg0, Arg1> {
public:
PGGenericFuncGenerator(int pg_func_oid,
const std::string& pg_func_name,
ExprCodeGenerator func_ptr) :
PGFuncGenerator<ExprCodeGenerator,
Arg0, Arg1>(pg_func_oid,
pg_func_name,
func_ptr) {
}
bool GenerateCode(gpcodegen::CodegenUtils* codegen_utils,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
std::vector<llvm::Value*>& llvm_args,
llvm::Value* & llvm_out_value) final {
assert(nullptr != codegen_utils);
if (llvm_args.size() != this->GetTotalArgCount()) {
return false;
}
this->func_ptr()(codegen_utils,
llvm_main_func,
llvm_error_block,
llvm_args,
llvm_out_value);
return true;
}
};
/** @} */
} // namespace gpcodegen
#endif // GPCODEGEN_PG_FUNC_GENERATOR_H_
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_PG_FUNC_GENERATOR_INTERFACE_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_PG_FUNC_GENERATOR_INTERFACE_H_
#include <string>
#include <vector>
#include <memory>
#include "llvm/IR/Value.h"
#include "codegen/utils/codegen_utils.h"
namespace gpcodegen {
/** \addtogroup gpcodegen
* @{
*/
class PGFuncGeneratorInterface {
public:
virtual std::string GetName() = 0;
virtual size_t GetTotalArgCount() = 0;
virtual bool GenerateCode(gpcodegen::CodegenUtils* codegen_utils,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
std::vector<llvm::Value*>& llvm_args,
llvm::Value* & llvm_out_value) = 0;
};
/** @} */
} // namespace gpcodegen
#endif // GPCODEGEN_PG_FUNC_GENERATOR_INTERFACE_H_
......@@ -41,6 +41,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Value.h"
namespace gpcodegen {
......@@ -49,6 +50,7 @@ namespace gpcodegen {
namespace codegen_utils_detail {
template <typename, typename> class ConstantMaker;
template <typename> class FunctionTypeUnpacker;
template <typename, typename> class ArithOpMaker;
} // namespace codegen_utils_detail
/** \addtogroup gpcodegen
......@@ -269,7 +271,36 @@ class CodegenUtils {
return llvm::BasicBlock::Create(context_, name, parent, nullptr);
}
/*
template <typename DestType>
llvm::Value* CreateCast(llvm::Value* value) {
assert(nullptr != value);
llvm::Type* llvm_dest_type = GetType<DestType>();
unsigned dest_size = llvm_dest_type->getScalarSizeInBits();
llvm::Type* llvm_src_type = value->getType();
unsigned src_size = llvm_src_type->getScalarSizeInBits();
if (src_size < dest_size) {
return ir_builder()->CreateZExt(value, llvm_dest_type);
}
else if (src_size > dest_size) {
return ir_builder()->CreateTrunc(value, llvm_dest_type);
}
else if (llvm_src_type->getTypeID() != llvm_dest_type->getTypeID()) {
return ir_builder()->CreateBitCast(value, llvm_dest_type);
}
return value;
}
template <typename CppType>
llvm::Value* CreateMulOverflow(llvm::Value* arg0, llvm::Value* arg1);
template <typename CppType>
llvm::Value* CreateAddOverflow(llvm::Value* arg0, llvm::Value* arg1);
template <typename CppType>
llvm::Value* CreateSubOverflow(llvm::Value* arg0, llvm::Value* arg1);
/**
* @brief Register an external function if previously unregistered. Otherwise
* return a pointer to the previously registered llvm::Function
*
......@@ -419,6 +450,9 @@ class CodegenUtils {
template <typename, typename>
friend class codegen_utils_detail::ConstantMaker;
template <typename, typename>
friend class codegen_utils_detail::ArithOpMaker;
template <typename>
friend class codegen_utils_detail::FunctionTypeUnpacker;
......@@ -482,6 +516,11 @@ class CodegenUtils {
llvm::Type* cast_type,
const std::size_t cumulative_offset);
llvm::Value* CreateArithOp(llvm::Intrinsic::ID Id,
llvm::ArrayRef<llvm::Type*> Tys,
llvm::Value* arg0,
llvm::Value* arg1);
// Helper method for GetPointerToMember(). This variadic template recursively
// consumes pointers-to-members, adding up 'cumulative_offset' and resolving
// 'MemberType' to '*cast_type' at the penultimate level of recursion before
......@@ -1111,6 +1150,192 @@ void CodegenUtils::CreateFallback(llvm::Function* regular_function,
}
}
// ----------------------------------------------------------------------------
// Implementation of CodegenUtils::CreateMulOverflow, CreateSubOverflow...
// Helper template classes are nested in this namespace and are not considered
// part of the public API.
namespace codegen_utils_detail {
// ArithOpMaker has various template specializations to handle
// different C++ types.
template <typename CppType, typename Enable = void>
class ArithOpMaker {
};
// Partial specialization for unsigned integer types (including bool).
template <typename UnsignedIntType>
class ArithOpMaker<
UnsignedIntType,
typename std::enable_if<
std::is_integral<UnsignedIntType>::value
&& std::is_unsigned<UnsignedIntType>::value>::type> {
public:
static llvm::Value* CreateAddOverflow(CodegenUtils* generator,
llvm::Value* arg0,
llvm::Value* arg1) {
Checker(arg0, arg1);
llvm::Value* casted_arg0 = generator->CreateCast<UnsignedIntType>(arg0);
llvm::Value* casted_arg1 = generator->CreateCast<UnsignedIntType>(arg1);
return generator->CreateArithOp(llvm::Intrinsic::uadd_with_overflow,
generator->GetType<UnsignedIntType>(),
casted_arg0,
casted_arg1);
}
static llvm::Value* CreateSubOverflow(CodegenUtils* generator,
llvm::Value* arg0,
llvm::Value* arg1) {
Checker(arg0, arg1);
llvm::Value* casted_arg0 = generator->CreateCast<UnsignedIntType>(arg0);
llvm::Value* casted_arg1 = generator->CreateCast<UnsignedIntType>(arg1);
return generator->CreateArithOp(llvm::Intrinsic::usub_with_overflow,
generator->GetType<UnsignedIntType>(),
casted_arg0,
casted_arg1);
}
static llvm::Value* CreateMulOverflow(CodegenUtils* generator,
llvm::Value* arg0,
llvm::Value* arg1) {
Checker(arg0, arg1);
llvm::Value* casted_arg0 = generator->CreateCast<UnsignedIntType>(arg0);
llvm::Value* casted_arg1 = generator->CreateCast<UnsignedIntType>(arg1);
return generator->CreateArithOp(llvm::Intrinsic::umul_with_overflow,
generator->GetType<UnsignedIntType>(),
casted_arg0,
casted_arg1);
}
private:
static void Checker(llvm::Value* arg0,
llvm::Value* arg1) {
assert(nullptr != arg0 && nullptr != arg0->getType());
assert(nullptr != arg1 && nullptr != arg1->getType());
assert(arg0->getType()->isIntegerTy());
assert(arg1->getType()->isIntegerTy());
}
};
// Partial specialization for signed integer types.
template <typename SignedIntType>
class ArithOpMaker<
SignedIntType,
typename std::enable_if<
std::is_integral<SignedIntType>::value
&& std::is_signed<SignedIntType>::value>::type> {
public:
static llvm::Value* CreateAddOverflow(CodegenUtils* generator,
llvm::Value* arg0,
llvm::Value* arg1) {
Checker(arg0, arg1);
llvm::Value* casted_arg0 = generator->CreateCast<SignedIntType>(arg0);
llvm::Value* casted_arg1 = generator->CreateCast<SignedIntType>(arg1);
return generator->CreateArithOp(llvm::Intrinsic::sadd_with_overflow,
generator->GetType<SignedIntType>(),
casted_arg0,
casted_arg1);
}
static llvm::Value* CreateSubOverflow(CodegenUtils* generator,
llvm::Value* arg0,
llvm::Value* arg1) {
Checker(arg0, arg1);
llvm::Value* casted_arg0 = generator->CreateCast<SignedIntType>(arg0);
llvm::Value* casted_arg1 = generator->CreateCast<SignedIntType>(arg1);
return generator->CreateArithOp(llvm::Intrinsic::ssub_with_overflow,
generator->GetType<SignedIntType>(),
casted_arg0,
casted_arg1);
}
static llvm::Value* CreateMulOverflow(CodegenUtils* generator,
llvm::Value* arg0,
llvm::Value* arg1) {
Checker(arg0, arg1);
llvm::Value* casted_arg0 = generator->CreateCast<SignedIntType>(arg0);
llvm::Value* casted_arg1 = generator->CreateCast<SignedIntType>(arg1);
return generator->CreateArithOp(llvm::Intrinsic::smul_with_overflow,
generator->GetType<SignedIntType>(),
casted_arg0,
casted_arg1);
}
private:
static void Checker(llvm::Value* arg0,
llvm::Value* arg1) {
assert(nullptr != arg0 && nullptr != arg0->getType());
assert(nullptr != arg1 && nullptr != arg1->getType());
assert(arg0->getType()->isIntegerTy());
assert(arg1->getType()->isIntegerTy());
}
};
// Partial specialization for enums (mapped to the underlying integer type).
template <typename EnumType>
class ArithOpMaker<
EnumType,
typename std::enable_if<std::is_enum<EnumType>::value>::type> {
public:
static llvm::Value* Get(CodegenUtils* generator,
llvm::Value* arg0,
llvm::Value* arg1) {
static_assert("Not support for enum");
}
};
// Explicit specialization for 32-bit float.
template <>
class ArithOpMaker<float> {
public:
static llvm::Value* Get(CodegenUtils* generator,
llvm::Value* arg0,
llvm::Value* arg1) {
static_assert("Not support for float");
}
};
// Explicit specialization for 64-bit double.
template <>
class ArithOpMaker<double> {
public:
static llvm::Value* Get(CodegenUtils* generator,
llvm::Value* arg0,
llvm::Value* arg1) {
static_assert("Not support for double");
}
};
} // namespace codegen_utils_detail
template <typename CppType>
llvm::Value* CodegenUtils::CreateAddOverflow(llvm::Value* arg0,
llvm::Value* arg1) {
return codegen_utils_detail::ArithOpMaker<CppType>::CreateAddOverflow(this,
arg0,
arg1);
}
template <typename CppType>
llvm::Value* CodegenUtils::CreateSubOverflow(llvm::Value* arg0,
llvm::Value* arg1) {
return codegen_utils_detail::ArithOpMaker<CppType>::CreateSubOverflow(this,
arg0,
arg1);
}
template <typename CppType>
llvm::Value* CodegenUtils::CreateMulOverflow(llvm::Value* arg0,
llvm::Value* arg1) {
return codegen_utils_detail::ArithOpMaker<CppType>::CreateMulOverflow(this,
arg0,
arg1);
}
} // namespace gpcodegen
#endif // GPCODEGEN_CODEGEN_UTILS_H_
......
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_VAR_EXPR_TREE_GENERATOR_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_VAR_EXPR_TREE_GENERATOR_H_
#include "codegen/expr_tree_generator.h"
#include "llvm/IR/Value.h"
namespace gpcodegen {
/** \addtogroup gpcodegen
* @{
*/
class VarExprTreeGenerator : public ExprTreeGenerator {
public:
static bool VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
std::unique_ptr<ExprTreeGenerator>& expr_tree);
bool GenerateCode(gpcodegen::CodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
llvm::Value* & value) final;
protected:
VarExprTreeGenerator(ExprState* expr_state);
};
/** @} */
} // namespace gpcodegen
#endif // GPCODEGEN_VAR_EXPR_TREE_GENERATOR_H_
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#include "codegen/expr_tree_generator.h"
#include "codegen/op_expr_tree_generator.h"
#include "include/codegen/pg_arith_func_generator.h"
#include "llvm/IR/Value.h"
extern "C" {
#include "postgres.h"
#include "utils/elog.h"
#include "nodes/execnodes.h"
}
using gpcodegen::OpExprTreeGenerator;
using gpcodegen::ExprTreeGenerator;
using gpcodegen::CodegenUtils;
using gpcodegen::PGFuncGeneratorInterface;
using gpcodegen::PGFuncGenerator;
using gpcodegen::CodeGenFuncMap;
using llvm::IRBuilder;
CodeGenFuncMap
OpExprTreeGenerator::supported_function_;
void OpExprTreeGenerator::InitializeSupportedFunction() {
if (!supported_function_.empty()) { return; }
supported_function_[149] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGIRBuilderFuncGenerator<decltype(&IRBuilder<>::CreateICmpSLE),
int32_t, int32_t>(149, "int4le", &IRBuilder<>::CreateICmpSLE));
supported_function_[1088] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGIRBuilderFuncGenerator<decltype(&IRBuilder<>::CreateICmpSLE),
int32_t, int32_t>(1088, "date_le", &IRBuilder<>::CreateICmpSLE));
supported_function_[177] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<int32_t, int32_t>(
141, "int4pl", &PGArithFuncGenerator<int32_t, int32_t, int32_t>::AddWithOverflow));
supported_function_[181] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<int32_t, int32_t>(
141, "int4mi", &PGArithFuncGenerator<int32_t, int32_t, int32_t>::SubWithOverflow));
supported_function_[141] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<int32_t, int32_t>(
141, "int4mul", &PGArithFuncGenerator<int32_t, int32_t, int32_t>::MulWithOverflow));
}
OpExprTreeGenerator::OpExprTreeGenerator(
ExprState* expr_state,
std::vector<std::unique_ptr<ExprTreeGenerator>>& arguments) :
arguments_(std::move(arguments)),
ExprTreeGenerator(expr_state, ExprTreeNodeType::kOperator) {
}
bool OpExprTreeGenerator::VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
std::unique_ptr<ExprTreeGenerator>& expr_tree) {
assert(nullptr != expr_state && nullptr != expr_state->expr && T_OpExpr == nodeTag(expr_state->expr));
OpExpr* op_expr = (OpExpr*)expr_state->expr;
expr_tree.reset(nullptr);
CodeGenFuncMap::iterator itr = supported_function_.find(op_expr->opfuncid);
if (itr == supported_function_.end()) {
// Operators are stored in pg_proc table. See postgres.bki for more details.
elog(DEBUG1, "Unsupported operator %d.", op_expr->opfuncid);
return false;
}
List *arguments = ((FuncExprState *)expr_state)->args;
if (nullptr == arguments) {
elog(DEBUG1, "No argument for the function");
return false;
}
// In ExecEvalFuncArgs
if (list_length(arguments) != itr->second->GetTotalArgCount()) {
elog(DEBUG1, "Wrong number of arguments (!= %d)", itr->second->GetTotalArgCount());
return false;
}
ListCell *arg = nullptr;
bool supported_tree = true;
std::vector<std::unique_ptr<ExprTreeGenerator>> expr_tree_arguments;
foreach(arg, arguments)
{
// retrieve argument's ExprState
ExprState *argstate = (ExprState *) lfirst(arg);
assert(nullptr != argstate);
std::unique_ptr<ExprTreeGenerator> arg(nullptr);
supported_tree &= ExprTreeGenerator::VerifyAndCreateExprTree(argstate,
econtext,
arg);
if (!supported_tree) {
break;
}
assert(nullptr != arg);
expr_tree_arguments.push_back(std::move(arg));
}
if (!supported_tree) {
return supported_tree;
}
expr_tree.reset(new OpExprTreeGenerator(expr_state, expr_tree_arguments));
return true;
}
bool OpExprTreeGenerator::GenerateCode(CodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
llvm::Value* & value) {
value = nullptr;
OpExpr* op_expr = (OpExpr*)expr_state()->expr;
CodeGenFuncMap::iterator itr = supported_function_.find(op_expr->opfuncid);
if (itr == supported_function_.end()) {
// Operators are stored in pg_proc table. See postgres.bki for more details.
elog(WARNING, "Unsupported operator %d.", op_expr->opfuncid);
return false;
}
if (arguments_.size() != itr->second->GetTotalArgCount()) {
elog(WARNING, "Expected argument size to be %d\n", itr->second->GetTotalArgCount());
return false;
}
bool arg_generated = true;
std::vector<llvm::Value*> llvm_arguments;
for(auto& arg : arguments_) {
llvm::Value* llvm_arg = nullptr;
arg_generated &= arg->GenerateCode(codegen_utils,
econtext,
llvm_main_func,
llvm_error_block,
llvm_isnull_arg,
llvm_arg);
if (!arg_generated) {
return false;
}
llvm_arguments.push_back(llvm_arg);
}
return itr->second->GenerateCode(codegen_utils,
llvm_main_func,
llvm_error_block,
llvm_arguments,
value);
}
......@@ -42,6 +42,7 @@
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/Casting.h"
extern "C" {
......@@ -62,6 +63,7 @@ namespace gpcodegen {
typedef int (*SumFunc) (int x, int y);
typedef void (*UncompilableFunc)(int x);
typedef int (*MulFunc) (int x, int y);
int SumFuncRegular(int x, int y) {
return x + y;
......@@ -71,9 +73,14 @@ void UncompilableFuncRegular(int x) {
return;
}
int MulFuncRegular(int x, int y) {
return x * y;
}
SumFunc sum_func_ptr = nullptr;
SumFunc failed_func_ptr = nullptr;
UncompilableFunc uncompilable_func_ptr = nullptr;
MulFunc mul_func_ptr = nullptr;
class SumCodeGenerator : public BaseCodegen<SumFunc> {
public:
......@@ -105,6 +112,57 @@ class SumCodeGenerator : public BaseCodegen<SumFunc> {
static constexpr char kAddFuncNamePrefix[] = "SumFunc";
};
class MulOverflowCodeGenerator : public BaseCodegen<MulFunc> {
public:
explicit MulOverflowCodeGenerator(MulFunc regular_func_ptr,
MulFunc* ptr_to_regular_func_ptr) :
BaseCodegen(kMulFuncNamePrefix,
regular_func_ptr,
ptr_to_regular_func_ptr) {
}
virtual ~MulOverflowCodeGenerator() = default;
protected:
bool GenerateCodeInternal(gpcodegen::CodegenUtils* codegen_utils) final {
llvm::Function* mul2_func
= CreateFunction<MulFunc>(codegen_utils, GetUniqueFuncName());
llvm::BasicBlock* mul2_body = codegen_utils->CreateBasicBlock("body",
mul2_func);
llvm::BasicBlock* result_result_block = codegen_utils->CreateBasicBlock(
"return_result", mul2_func);
llvm::BasicBlock* return_overflow_block = codegen_utils->CreateBasicBlock(
"return_overflow", mul2_func);
codegen_utils->ir_builder()->SetInsertPoint(mul2_body);
llvm::Value* arg0 = ArgumentByPosition(mul2_func, 0);
llvm::Value* arg1 = ArgumentByPosition(mul2_func, 1);
llvm::Function* llvm_mul_overflow = llvm::Intrinsic::getDeclaration(codegen_utils->module(),
llvm::Intrinsic::smul_with_overflow,
arg0->getType());
llvm::Value* llvm_umul_results = codegen_utils->ir_builder()->CreateCall(llvm_mul_overflow, {arg0, arg1});
llvm::Value* llvm_overflow_flag = codegen_utils->ir_builder()->CreateExtractValue(llvm_umul_results, 1);
llvm::Value* llvm_results = codegen_utils->ir_builder()->CreateExtractValue(llvm_umul_results, 0);
codegen_utils->ir_builder()->CreateCondBr(
codegen_utils->ir_builder()->CreateICmpSLE(llvm_overflow_flag, codegen_utils->GetConstant<bool>(true)),
return_overflow_block,
result_result_block );
codegen_utils->ir_builder()->SetInsertPoint(return_overflow_block);
codegen_utils->ir_builder()->CreateAdd(llvm_results, codegen_utils->GetConstant(1));
codegen_utils->ir_builder()->SetInsertPoint(result_result_block);
codegen_utils->ir_builder()->CreateRet(llvm_results);
mul2_func->dump();
return true;
}
public:
static constexpr char kMulFuncNamePrefix[] = "MulOverflowFunc";
};
class FailingCodeGenerator : public BaseCodegen<SumFunc> {
public:
explicit FailingCodeGenerator(SumFunc regular_func_ptr,
......@@ -157,6 +215,7 @@ class UncompilableCodeGenerator : public BaseCodegen<UncompilableFunc> {
constexpr char SumCodeGenerator::kAddFuncNamePrefix[];
constexpr char FailingCodeGenerator::kFailingFuncNamePrefix[];
constexpr char MulOverflowCodeGenerator::kMulFuncNamePrefix[];
template <bool GEN_SUCCESS>
constexpr char
UncompilableCodeGenerator<GEN_SUCCESS>::kUncompilableFuncNamePrefix[];
......@@ -367,6 +426,29 @@ TEST_F(CodegenManagerTest, UnCompilablePassedGenerationTest) {
ASSERT_TRUE(UncompilableFuncRegular == uncompilable_func_ptr);
}
TEST_F(CodegenManagerTest, MulOverFlowTest) {
// Test if generation happens successfully
mul_func_ptr = nullptr;
EnrollCodegen<MulOverflowCodeGenerator, MulFunc>(MulFuncRegular, &mul_func_ptr);
EXPECT_EQ(1, manager_->GenerateCode());
ASSERT_TRUE(MulFuncRegular == mul_func_ptr);
// This should cause program to exit because of
// broken function
EXPECT_EQ(1, manager_->PrepareGeneratedFunctions());
EXPECT_EQ(6, mul_func_ptr(2, 3));
EXPECT_EQ(1, mul_func_ptr(2147483647, 3));
EXPECT_EQ(-6, mul_func_ptr(-2, 3));
// Reset the manager, so that all the code generators go away
manager_.reset(nullptr);
}
TEST_F(CodegenManagerTest, ResetTest) {
sum_func_ptr = nullptr;
SumCodeGenerator* code_gen = new SumCodeGenerator(SumFuncRegular,
......
......@@ -358,6 +358,16 @@ llvm::Value* CodegenUtils::GetPointerToMemberImpl(
}
}
llvm::Value* CodegenUtils::CreateArithOp(llvm::Intrinsic::ID Id,
llvm::ArrayRef<llvm::Type*> Tys,
llvm::Value* arg0,
llvm::Value* arg1) {
llvm::Function* llvm_intr_func = llvm::Intrinsic::getDeclaration(module(),
Id,
Tys);
return ir_builder()->CreateCall(llvm_intr_func, {arg0, arg1});
}
} // namespace gpcodegen
// EOF
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#include "codegen/expr_tree_generator.h"
#include "codegen/var_expr_tree_generator.h"
#include "llvm/IR/Value.h"
extern "C" {
#include "postgres.h"
#include "utils/elog.h"
#include "nodes/execnodes.h"
}
using gpcodegen::VarExprTreeGenerator;
using gpcodegen::ExprTreeGenerator;
using gpcodegen::CodegenUtils;
bool VarExprTreeGenerator::VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
std::unique_ptr<ExprTreeGenerator>& expr_tree) {
assert(nullptr != expr_state && nullptr != expr_state->expr && T_Var == nodeTag(expr_state->expr));
expr_tree.reset(new VarExprTreeGenerator(expr_state));
return true;
}
VarExprTreeGenerator::VarExprTreeGenerator(ExprState* expr_state) :
ExprTreeGenerator(expr_state, ExprTreeNodeType::kVar) {
}
bool VarExprTreeGenerator::GenerateCode(CodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
llvm::Value* & value) {
value = nullptr;
Var* var_expr = (Var *)expr_state()->expr;
int attnum = var_expr->varattno;
auto irb = codegen_utils->ir_builder();
// slot = econtext->ecxt_scantuple; {{{
// At code generation time, slot is NULL.
// For that reason, we keep a double pointer to slot and at execution time
// we load slot.
TupleTableSlot **ptr_to_slot_ptr = NULL;
switch (var_expr->varno)
{
case INNER: /* get the tuple from the inner node */
ptr_to_slot_ptr = &econtext->ecxt_innertuple;
break;
case OUTER: /* get the tuple from the outer node */
ptr_to_slot_ptr = &econtext->ecxt_outertuple;
break;
default: /* get the tuple from the relation being scanned */
ptr_to_slot_ptr = &econtext->ecxt_scantuple;
break;
}
llvm::Value *llvm_slot = irb->CreateLoad(
codegen_utils->GetConstant(ptr_to_slot_ptr));
//}}}
llvm::Value *llvm_variable_varattno = codegen_utils->
GetConstant<int32_t>(attnum);
// External functions
llvm::Function* llvm_slot_getattr =
codegen_utils->RegisterExternalFunction(slot_getattr);
// retrieve variable
value = irb->CreateCall(
llvm_slot_getattr, {
llvm_slot,
llvm_variable_varattno,
llvm_isnull_arg /* TODO: Fix isNull */ });
return true;
}
......@@ -3357,7 +3357,7 @@ struct config_bool ConfigureNamesBool_gp[] =
{"codegen", PGC_USERSET, DEVELOPER_OPTIONS,
gettext_noop("Perform just-in-time code generation."),
NULL,
GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE
GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_GPDB_ADDOPT
},
&codegen,
false, NULL, NULL
......
......@@ -77,14 +77,14 @@ ExecVariableListCodegenEnroll(ExecVariableListFn regular_func_ptr,
return NULL;
}
// returns the pointer to the ExecQualGenerator
void*
ExecQualCodegenEnroll(ExecQualFn regular_func_ptr,
ExecQualFn* ptr_to_regular_func_ptr,
struct PlanState *planstate)
ExecEvalExprCodegenEnroll(ExecEvalExprFn regular_func_ptr,
ExecEvalExprFn* ptr_to_regular_func_ptr,
struct ExprState *exprstate,
struct ExprContext *econtext)
{
*ptr_to_regular_func_ptr = regular_func_ptr;
elog(ERROR, "mock implementation of ExecQualCodegenEnroll called");
return NULL;
elog(ERROR, "mock implementation of ExecEvalExprCodegenEnroll called");
return NULL;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册