提交 ec626ce6 编写于 作者: N Nikos Armenatzoglou 提交者: Karthikeyan Jambu Rajaraman

Generate and enroll naive ExecEvalExpr in Scan's quals

Verify that input expression is of type VAR <= CONST
Codegen expression evaluation
Fix wrong return value type
Support constants and variables of Date type
Add comments and fix code style
上级 1186001e
......@@ -166,6 +166,7 @@ set(GPCODEGEN_SRC
codegen_manager.cc
codegen_wrapper.cc
exec_variable_list_codegen.cc
exec_eval_expr_codegen.cc
)
# Integrate with GPDB build system.
......
......@@ -3,7 +3,7 @@
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// init_codegen.cpp
// codegen_wrapper.cc
//
// @doc:
// C wrappers for initialization of code generator.
......@@ -13,12 +13,14 @@
#include "codegen/codegen_wrapper.h"
#include "codegen/codegen_manager.h"
#include "codegen/exec_variable_list_codegen.h"
#include "codegen/exec_eval_expr_codegen.h"
#include "codegen/utils/gp_codegen_utils.h"
using gpcodegen::CodegenManager;
using gpcodegen::BaseCodegen;
using gpcodegen::ExecVariableListCodegen;
using gpcodegen::ExecEvalExprCodegen;
// Current code generator manager that oversees all code generators
static void* ActiveCodeGeneratorManager = nullptr;
......@@ -116,3 +118,14 @@ void* ExecVariableListCodegenEnroll(
regular_func_ptr, ptr_to_chosen_func_ptr, proj_info, slot);
return generator;
}
void* ExecEvalExprCodegenEnroll(
ExecEvalExprFn regular_func_ptr,
ExecEvalExprFn* ptr_to_chosen_func_ptr,
ExprState *exprstate,
ExprContext *econtext) {
ExecEvalExprCodegen* generator = CodegenEnroll<ExecEvalExprCodegen>(
regular_func_ptr, ptr_to_chosen_func_ptr, exprstate, econtext);
return generator;
}
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// exec_eval_expr_codegen.cc
//
// @doc:
// Generates code for ExecEvalExpr function.
//
//---------------------------------------------------------------------------
#include <algorithm>
#include <cstdint>
#include <string>
#include "codegen/exec_eval_expr_codegen.h"
#include "codegen/utils/clang_compiler.h"
#include "codegen/utils/utility.h"
#include "codegen/utils/instance_method_wrappers.h"
#include "codegen/utils/codegen_utils.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/Casting.h"
extern "C" {
#include "postgres.h"
#include "utils/elog.h"
#include "nodes/execnodes.h"
}
using gpcodegen::ExecEvalExprCodegen;
constexpr char ExecEvalExprCodegen::kExecEvalExprPrefix[];
class ElogWrapper {
public:
ElogWrapper(gpcodegen::CodegenUtils* codegen_utils) :
codegen_utils_(codegen_utils) {
SetupElog();
}
~ElogWrapper() {
TearDownElog();
}
template<typename... V>
void CreateElog(
llvm::Value* llvm_elevel,
llvm::Value* llvm_fmt,
V ... args ) {
assert(NULL != llvm_elevel);
assert(NULL != llvm_fmt);
codegen_utils_->ir_builder()->CreateCall(
llvm_elog_start_, {
codegen_utils_->GetConstant(""), // Filename
codegen_utils_->GetConstant(0), // line number
codegen_utils_->GetConstant("") // function name
});
codegen_utils_->ir_builder()->CreateCall(
llvm_elog_finish_, {
llvm_elevel,
llvm_fmt,
args...
});
}
template<typename... V>
void CreateElog(
int elevel,
const char* fmt,
V ... args ) {
CreateElog(codegen_utils_->GetConstant(elevel),
codegen_utils_->GetConstant(fmt),
args...);
}
private:
llvm::Function* llvm_elog_start_;
llvm::Function* llvm_elog_finish_;
gpcodegen::CodegenUtils* codegen_utils_;
void SetupElog(){
assert(codegen_utils_ != nullptr);
llvm_elog_start_ = codegen_utils_->RegisterExternalFunction(elog_start);
assert(llvm_elog_start_ != nullptr);
llvm_elog_finish_ = codegen_utils_->RegisterExternalFunction(elog_finish);
assert(llvm_elog_finish_ != nullptr);
}
void TearDownElog(){
llvm_elog_start_ = nullptr;
llvm_elog_finish_ = nullptr;
}
};
ExecEvalExprCodegen::ExecEvalExprCodegen
(
ExecEvalExprFn regular_func_ptr,
ExecEvalExprFn* ptr_to_regular_func_ptr,
ExprState *exprstate,
ExprContext *econtext) :
BaseCodegen(kExecEvalExprPrefix,
regular_func_ptr, ptr_to_regular_func_ptr),
exprstate_(exprstate),
econtext_(econtext){
}
bool ExecEvalExprCodegen::GenerateExecEvalExpr(
gpcodegen::CodegenUtils* codegen_utils) {
assert(NULL != codegen_utils);
ElogWrapper elogwrapper(codegen_utils);
llvm::Function* exec_eval_expr_func = codegen_utils->
CreateFunction<ExecEvalExprFn>(
GetUniqueFuncName());
// Function arguments to ExecVariableList
llvm::Value* llvm_expression_arg =
ArgumentByPosition(exec_eval_expr_func, 0);
llvm::Value* llvm_econtext_arg = ArgumentByPosition(exec_eval_expr_func, 1);
llvm::Value* llvm_isnull_arg = ArgumentByPosition(exec_eval_expr_func, 2);
llvm::Value* llvm_isDone_arg = ArgumentByPosition(exec_eval_expr_func, 3);
// External functions
llvm::Function* llvm_slot_getattr =
codegen_utils->RegisterExternalFunction(slot_getattr);
// BasicBlock of function entry.
llvm::BasicBlock* 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);
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));
return true;
}
return false;
}
bool ExecEvalExprCodegen::GenerateCodeInternal(CodegenUtils* codegen_utils) {
bool isGenerated = GenerateExecEvalExpr(codegen_utils);
if (isGenerated) {
elog(DEBUG1, "ExecEvalExpr was generated successfully!");
return true;
}
else {
elog(DEBUG1, "ExecEvalExpr generation failed!");
return false;
}
}
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// ExecQual_codegen.cc
//
// @doc:
// Generates code for ExecQual function.
//
//---------------------------------------------------------------------------
#include <algorithm>
#include <cstdint>
#include <string>
#include "codegen/exec_qual_codegen.h"
#include "codegen/utils/clang_compiler.h"
#include "codegen/utils/utility.h"
#include "codegen/utils/instance_method_wrappers.h"
#include "codegen/utils/gp_codegen_utils.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/Casting.h"
extern "C" {
#include "postgres.h"
#include "utils/elog.h"
}
using gpcodegen::ExecQualCodegen;
constexpr char ExecQualCodegen::kExecQualPrefix[];
ExecQualCodegen::ExecQualCodegen
(
ExecQualFn regular_func_ptr,
ExecQualFn* ptr_to_regular_func_ptr,
PlanState *planstate) :
BaseCodegen(kExecQualPrefix, regular_func_ptr, ptr_to_regular_func_ptr),
planstate_(planstate) {
}
bool ExecQualCodegen::GenerateExecQual(
gpcodegen::GpCodegenUtils* codegen_utils) {
assert(NULL != codegen_utils);
llvm::Function* exec_qual_func = codegen_utils->
CreateFunction<ExecQualFn>(
GetUniqueFuncName());
// BasicBlock of function entry.
llvm::BasicBlock* entry_block = codegen_utils->CreateBasicBlock(
"entry", exec_qual_func);
auto irb = codegen_utils->ir_builder();
irb->SetInsertPoint(entry_block);
codegen_utils->CreateElog(DEBUG1, "Falling back to regular ExecQual.");
codegen_utils->CreateFallback<ExecQualFn>(
codegen_utils->GetOrRegisterExternalFunction(GetRegularFuncPointer()),
exec_qual_func);
return true;
}
bool ExecQualCodegen::GenerateCodeInternal(GpCodegenUtils* codegen_utils) {
bool isGenerated = GenerateExecQual(codegen_utils);
if (isGenerated) {
elog(DEBUG1, "ExecQual was generated successfully!");
return true;
}
else {
elog(DEBUG1, "ExecQual generation failed!");
return false;
}
}
......@@ -3,15 +3,15 @@
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// ExecQual_codegen.h
// exec_eval_expr_codegen.h
//
// @doc:
// Headers for ExecQual codegen.
// Headers for ExecEvalExpr codegen.
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_EXECQUAL_CODEGEN_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_EXECQUAL_CODEGEN_H_
#ifndef GPCODEGEN_EXECEVALEXPR_CODEGEN_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_EXECEVALEXPR_CODEGEN_H_
#include "codegen/codegen_wrapper.h"
#include "codegen/base_codegen.h"
......@@ -22,53 +22,54 @@ namespace gpcodegen {
* @{
*/
class ExecQualCodegen: public BaseCodegen<ExecQualFn> {
class ExecEvalExprCodegen: public BaseCodegen<ExecEvalExprFn> {
public:
/**
* @brief Constructor
*
* @param regular_func_ptr Regular version of the target function.
* @param ptr_to_chosen_func_ptr Reference to the function pointer that the caller will call.
* @param slot The slot to use for generating code.
* @param exprstate The ExprState to use for generating code.
*
* @note The ptr_to_chosen_func_ptr can refer to either the generated function or the
* corresponding regular version.
*
**/
explicit ExecQualCodegen(ExecQualFn regular_func_ptr,
ExecQualFn* ptr_to_regular_func_ptr,
PlanState *planstate);
explicit ExecEvalExprCodegen(ExecEvalExprFn regular_func_ptr,
ExecEvalExprFn* ptr_to_regular_func_ptr,
ExprState *exprstate,
ExprContext *econtext);
virtual ~ExecQualCodegen() = default;
virtual ~ExecEvalExprCodegen() = default;
protected:
/**
* @brief Generate code for ExecQual.
* @brief Generate code for expression evaluation.
*
* @param codegen_utils
*
* @return true on successful generation; false otherwise.
*
* @note Currently, it simply falls back to regular ExecQual.
* @note Currently, it simply falls back to regular function for expression evaluation.
*/
bool GenerateCodeInternal(gpcodegen::GpCodegenUtils* codegen_utils) final;
bool GenerateCodeInternal(gpcodegen::CodegenUtils* codegen_utils) final;
private:
PlanState *planstate_;
ExprState *exprstate_;
ExprContext *econtext_;
static constexpr char kExecQualPrefix[] = "ExecQual";
static constexpr char kExecEvalExprPrefix[] = "ExecEvalExpr";
/**
* @brief Generates runtime code that implements ExecQual.
* @brief Generates runtime code that implements expression evaluation.
*
* @param codegen_utils Utility to ease the code generation process.
* @return true on successful generation.
**/
bool GenerateExecQual(gpcodegen::GpCodegenUtils* codegen_utils);
bool GenerateExecEvalExpr(gpcodegen::CodegenUtils* codegen_utils);
};
/** @} */
} // namespace gpcodegen
#endif // GPCODEGEN_EXECQUAL_CODEGEN_H_
#endif // GPCODEGEN_EXECEVALEXPR_CODEGEN_H_
......@@ -338,6 +338,18 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
estate, eflags);
}
END_MEMORY_ACCOUNT();
#ifdef USE_CODEGEN
/* Enroll quals' expression evaluation functions in codegen_manager */
if (result && NULL != result->qual)
{
ListCell *l;
foreach(l, result->qual)
{
ExprState *exprstate = (ExprState *) lfirst(l);
enroll_ExecEvalExpr_codegen(exprstate->evalfunc, &exprstate->evalfunc, exprstate, result->ps_ExprContext);
}
}
#endif
break;
case T_DynamicTableScan:
......
......@@ -26,8 +26,16 @@ typedef int64 Datum;
*/
struct TupleTableSlot;
struct ProjectionInfo;
struct ExprContext;
struct ExprState;
/* Enum used to mimic ExprDoneCond in ExecEvalExpr function pointer. */
typedef enum tmp_enum{
TmpResult
};
typedef void (*ExecVariableListFn) (struct ProjectionInfo *projInfo, Datum *values, bool *isnull);
typedef Datum (*ExecEvalExprFn) (struct ExprState *expression, struct ExprContext *econtext, bool *isNull, /*ExprDoneCond*/ enum tmp_enum *isDone);
#ifndef USE_CODEGEN
......@@ -137,6 +145,12 @@ ExecVariableListCodegenEnroll(ExecVariableListFn regular_func_ptr,
struct ProjectionInfo* proj_info,
struct TupleTableSlot* slot);
void*
ExecEvalExprCodegenEnroll(ExecEvalExprFn regular_func_ptr,
ExecEvalExprFn* ptr_to_regular_func_ptr,
struct ExprState *exprstate,
struct ExprContext *econtext);
#ifdef __cplusplus
} // extern "C"
#endif
......@@ -196,6 +210,11 @@ ExecVariableListCodegenEnroll(ExecVariableListFn regular_func_ptr,
regular_func, ptr_to_regular_func_ptr, proj_info, slot); \
Assert(proj_info->ExecVariableList_gen_info.ExecVariableList_fn == regular_func); \
#define enroll_ExecEvalExpr_codegen(regular_func, ptr_to_regular_func_ptr, exprstate, econtext) \
exprstate->ExecEvalExpr_code_generator = ExecEvalExprCodegenEnroll( \
(ExecEvalExprFn)regular_func, (ExecEvalExprFn*)ptr_to_regular_func_ptr, exprstate, econtext); \
Assert(exprstate->evalfunc == regular_func); \
#endif //USE_CODEGEN
#endif // CODEGEN_WRAPPER_H_
......@@ -23,7 +23,6 @@
#include "utils/hsearch.h"
#include "gpmon/gpmon.h" /* gpmon_packet_t */
#include "utils/tuplestore.h"
#include "codegen/codegen_wrapper.h"
/*
* partition selector ids start from 1. Sometimes we use 0 to initialize variables
......@@ -828,6 +827,11 @@ struct ExprState
NodeTag type;
Expr *expr; /* associated Expr node */
ExprStateEvalFunc evalfunc; /* routine to run to execute node */
#ifdef USE_CODEGEN
void *ExecEvalExpr_code_generator;
#endif
};
/* ----------------
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册