提交 020b71a5 编写于 作者: N Nikos Armenatzoglou

Generate code for COUNT aggregate function

Enhance GenerateAdvanceAggregates function and support int8inc built-in function to generate code for COUNT aggregate function.
Signed-off-by: NShreedhar Hardikar <shardikar@pivotal.io>
上级 4dfab11a
......@@ -11,7 +11,6 @@
//---------------------------------------------------------------------------
#include "codegen/advance_aggregates_codegen.h"
#include "codegen/op_expr_tree_generator.h"
#include "codegen/pg_func_generator_interface.h"
#include "codegen/utils/gp_codegen_utils.h"
#include "codegen/utils/utility.h"
......@@ -50,10 +49,7 @@ bool AdvanceAggregatesCodegen::GenerateAdvanceTransitionFunction(
gpcodegen::GpCodegenUtils* codegen_utils,
llvm::Value* llvm_pergroup_arg,
int aggno,
llvm::Function* advance_aggregates_func,
llvm::BasicBlock* error_block,
llvm::Value *llvm_in_arg_ptr) {
gpcodegen::PGFuncGeneratorInfo& pg_func_info) {
auto irb = codegen_utils->ir_builder();
AggStatePerAgg peraggstate = &aggstate_->peragg[aggno];
......@@ -88,19 +84,16 @@ bool AdvanceAggregatesCodegen::GenerateAdvanceTransitionFunction(
codegen_utils->GetPointerToMember(
llvm_pergroupstate, &AggStatePerGroupData::noTransValue);
assert(nullptr != peraggstate);
if (!peraggstate->transtypeByVal) {
elog(DEBUG1, "We do not support pass-by-ref datatypes.");
return false;
}
// FunctionCallInvoke(fcinfo); {{
// We do not need to use a FunctionCallInfoData struct, since the supported
// aggregate functions are simple enough.
gpcodegen::PGFuncGeneratorInfo pg_func_info(
advance_aggregates_func,
error_block,
{irb->CreateLoad(llvm_pergroupstate_transValue_ptr),
irb->CreateLoad(llvm_in_arg_ptr)});
assert(nullptr != peraggstate->aggref);
assert(pg_func_info.llvm_args.size() == 1 +
list_length(peraggstate->aggref->args));
pg_func_info.llvm_args[0] = irb->CreateLoad(llvm_pergroupstate_transValue_ptr);
gpcodegen::PGFuncGeneratorInterface* pg_func_gen =
gpcodegen::OpExprTreeGenerator::GetPGFuncGenerator(
......@@ -157,15 +150,15 @@ bool AdvanceAggregatesCodegen::GenerateAdvanceAggregates(
// BasicBlock of function entry.
llvm::BasicBlock* entry_block = codegen_utils->CreateBasicBlock(
"entry block", advance_aggregates_func);
"entry_block", advance_aggregates_func);
llvm::BasicBlock* implementation_block = codegen_utils->CreateBasicBlock(
"implementation block", advance_aggregates_func);
"implementation_block", advance_aggregates_func);
llvm::BasicBlock* error_aggstate_block = codegen_utils->CreateBasicBlock(
"error aggstate block", advance_aggregates_func);
"error_aggstate_block", advance_aggregates_func);
llvm::BasicBlock* overflow_block = codegen_utils->CreateBasicBlock(
"overflow block", advance_aggregates_func);
"overflow_block", advance_aggregates_func);
llvm::BasicBlock* null_attribute_block = codegen_utils->CreateBasicBlock(
"null attribute block", advance_aggregates_func);
"null_attribute_block", advance_aggregates_func);
// External functions
llvm::Function* llvm_ExecTargetList =
......@@ -203,14 +196,6 @@ bool AdvanceAggregatesCodegen::GenerateAdvanceAggregates(
// ----------
irb->SetInsertPoint(implementation_block);
// Since we do not support ordered functions, we do not need to store
// the value of the variables, which are used as input to the aggregate
// function, in a slot. Instead we simply store them in a stuck variable.
llvm::Value *llvm_in_arg_ptr = irb->CreateAlloca(
codegen_utils->GetType<Datum>());
llvm::Value *llvm_in_argnull_ptr = irb->CreateAlloca(
codegen_utils->GetType<bool>());
for (int aggno = 0; aggno < aggstate_->numaggs; aggno++) {
// Generate the code of each aggregate function in a different block.
llvm::BasicBlock* advance_aggregate_block = codegen_utils->
......@@ -237,43 +222,93 @@ bool AdvanceAggregatesCodegen::GenerateAdvanceAggregates(
return false;
}
int nargs = list_length(aggref->args);
assert(nargs == peraggstate->numArguments);
assert(peraggstate->evalproj);
if (peraggstate->evalproj->pi_isVarList) {
irb->CreateCall(llvm_ExecVariableList, {
codegen_utils->GetConstant<ProjectionInfo *>(peraggstate->evalproj),
llvm_in_arg_ptr,
llvm_in_argnull_ptr});
} else {
irb->CreateCall(llvm_ExecTargetList, {
codegen_utils->GetConstant(peraggstate->evalproj->pi_targetlist),
codegen_utils->GetConstant(peraggstate->evalproj->pi_exprContext),
llvm_in_arg_ptr,
llvm_in_argnull_ptr,
codegen_utils->GetConstant(peraggstate->evalproj->pi_itemIsDone),
codegen_utils->GetConstant<ExprDoneCond *>(nullptr)});
}
// Number of attributes to be retrieved. This is one less than
// number of arguments of the transition function, since the transition
// value is passed as the first argument to the transition function.
int nargs = peraggstate->transfn.fn_nargs - 1;
assert(nargs >= 0);
// Since we do not support ordered functions, we do not need to store
// the value of the variables, which are used as input to the aggregate
// function, in a slot.
llvm::Value* llvm_in_args_ptr = irb->CreateAlloca(
codegen_utils->GetType<Datum>(),
codegen_utils->GetConstant(nargs));
llvm::Value* llvm_in_isnulls_ptr = irb->CreateAlloca(
codegen_utils->GetType<bool>(),
codegen_utils->GetConstant(nargs));
llvm::BasicBlock* advance_transition_function_block = codegen_utils->
CreateBasicBlock("advance_transition_function_block_aggno_"
+ std::to_string(aggno), advance_aggregates_func);
// Error out if attribute is NULL.
// TODO(nikos): Support null attributes.
irb->CreateCondBr(irb->CreateLoad(llvm_in_argnull_ptr),
null_attribute_block /*true*/,
advance_transition_function_block /*false*/);
// Although the (nargs > 0) check does not exist in the regular
// advance_aggregates, the calls to ExecVariableList and
// ExecTargetList becomes a no-op when it is true.
// So we can avoid the call all together.
if (nargs > 0) {
if (peraggstate->evalproj->pi_isVarList) {
irb->CreateCall(llvm_ExecVariableList, {
codegen_utils->GetConstant<ProjectionInfo *>(peraggstate->evalproj),
llvm_in_args_ptr,
llvm_in_isnulls_ptr});
} else {
irb->CreateCall(llvm_ExecTargetList, {
codegen_utils->GetConstant(peraggstate->evalproj->pi_targetlist),
codegen_utils->GetConstant(peraggstate->evalproj->pi_exprContext),
llvm_in_args_ptr,
llvm_in_isnulls_ptr,
codegen_utils->GetConstant(peraggstate->evalproj->pi_itemIsDone),
codegen_utils->GetConstant<ExprDoneCond *>(nullptr)});
}
// Error out if there is a NULL attribute.
// TODO(nikos): Support null attributes.
llvm::BasicBlock* null_check_block_0 = codegen_utils->CreateBasicBlock(
"null_check_arg0", advance_aggregates_func);
irb->CreateBr(null_check_block_0);
irb->SetInsertPoint(null_check_block_0);
for (int i=0; i < nargs; ++i) {
llvm::BasicBlock* next_block = codegen_utils->CreateBasicBlock(
"null_check_arg" + std::to_string(i+1), advance_aggregates_func);
llvm::Value* llvm_in_isnull_ptr = irb->CreateInBoundsGEP(
codegen_utils->GetType<bool>(),
llvm_in_isnulls_ptr,
codegen_utils->GetConstant(i));
irb->CreateCondBr(irb->CreateLoad(llvm_in_isnull_ptr),
null_attribute_block /*true*/,
next_block /*false*/);
irb->SetInsertPoint(next_block);
}
}
irb->CreateBr(advance_transition_function_block);
// advance_transition_function block
// ----------
// We generate code for advance_transition_function.
irb->SetInsertPoint(advance_transition_function_block);
// Collect input arguments and the transition value in a vector.
// The transition value is stored at the first position.
std::vector<llvm::Value*> llvm_in_args(nargs+1);
for (int i=0; i < nargs; ++i) {
llvm_in_args[i+1] = irb->CreateLoad(
irb->CreateInBoundsGEP(
codegen_utils->GetType<Datum>(),
llvm_in_args_ptr,
codegen_utils->GetConstant(i)));
}
gpcodegen::PGFuncGeneratorInfo pg_func_info(
advance_aggregates_func,
overflow_block,
llvm_in_args);
bool isGenerated = GenerateAdvanceTransitionFunction(
codegen_utils, llvm_pergroup_arg, aggno, advance_aggregates_func,
overflow_block, llvm_in_arg_ptr);
codegen_utils, llvm_pergroup_arg, aggno, pg_func_info);
if (!isGenerated)
return false;
} // End of for loop
......
......@@ -68,7 +68,8 @@ ExecVariableListCodegen::ExecVariableListCodegen(
}
bool ExecVariableListCodegen::InitDependencies() {
assert(proj_info_ != nullptr);
assert(nullptr != proj_info_);
assert(nullptr != proj_info_->pi_targetlist);
// Find the largest attribute index in projInfo->pi_targetlist
max_attr_ = *std::max_element(
......
......@@ -15,6 +15,7 @@
#include "codegen/base_codegen.h"
#include "codegen/codegen_wrapper.h"
#include "codegen/pg_func_generator_interface.h"
namespace gpcodegen {
......@@ -93,9 +94,7 @@ class AdvanceAggregatesCodegen: public BaseCodegen<AdvanceAggregatesFn> {
gpcodegen::GpCodegenUtils* codegen_utils,
llvm::Value* llvm_pergroup_arg,
int aggno,
llvm::Function* advance_aggregates_func,
llvm::BasicBlock* error_block,
llvm::Value *llvm_arg);
gpcodegen::PGFuncGeneratorInfo& pg_func_info);
};
/** @} */
......
......@@ -62,6 +62,7 @@ double> {
using gpcodegen_ArithOp_detail::ArithOpOverFlowErrorMsg;
/**
* @brief Class with Static member function to generate code for +, - and *
* operator
......@@ -131,6 +132,7 @@ class PGArithFuncGenerator {
pg_func_info,
llvm_out_value);
}
/**
* @brief Create LLVM Sub instruction with check for overflow
*
......@@ -165,28 +167,81 @@ class PGArithFuncGenerator {
llvm::Value** llvm_out_value);
};
template <typename rtype, typename Arg0, typename Arg1>
bool PGArithFuncGenerator<rtype, Arg0, Arg1>::ArithOpWithOverflow(
/**
* @brief Class with Static member function to generate code for unary
* operator such as ++, -- etc.
*
* @tparam rtype Return type of function
* @tparam Arg Argument's type
**/
template <typename rtype, typename Arg>
class PGArithUnaryFuncGenerator {
template <typename CppType>
using CGArithOpTemplateFunc = llvm::Value* (GpCodegenUtils::*)(
llvm::Value* arg);
using CGArithOpFunc = CGArithOpTemplateFunc<rtype>;
public:
/**
* @brief Increase the value of a variable with check for overflow
*
* @param codegen_utils Utility for easy code generation.
* @param pg_func_info Details for pgfunc generation
* @param llvm_out_value Store location for the result
*
* @return true if generation was successful otherwise return false
*
* @note If there is overflow, it will do elog::ERROR and then jump to given
* error block.
**/
static bool IncWithOverflow(gpcodegen::GpCodegenUtils* codegen_utils,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value) {
llvm::Value* llvm_err_msg = codegen_utils->GetConstant(
ArithOpOverFlowErrorMsg<rtype>::OverFlowErrMsg());
return PGArithUnaryFuncGenerator<rtype, Arg>::ArithOpWithOverflow(
codegen_utils,
&gpcodegen::GpCodegenUtils::CreateIncOverflow<rtype>,
llvm_err_msg,
pg_func_info,
llvm_out_value);
}
static bool ArithOpWithOverflow(gpcodegen::GpCodegenUtils* codegen_utils,
CGArithOpFunc codegen_mem_funcptr,
llvm::Value* llvm_error_msg,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value);
};
/**
* @brief Utility function for generating code for overflow checking. This
* includes an overflow block and non-overflow block, check and conditional
* branch instructions.
*
* @param codegen_utils Utility for easy code generation.
* @param pg_func_info Details for pgfunc generation
* @param llvm_arith_output Result of the arithmetic operation
* @param llvm_error_msg Error message to use when overflow occurs
* @param llvm_out_value Store location for the result
*
* @return true if generation was successful otherwise return false
*
* @note Only integral types are currently supported.
**/
template<typename rtype>
static bool CreateOverflowCheckLogic(
gpcodegen::GpCodegenUtils* codegen_utils,
CGArithOpFunc codegen_mem_funcptr,
llvm::Value* llvm_error_msg,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value* llvm_arith_output,
llvm::Value* llvm_error_msg,
llvm::Value** llvm_out_value) {
assert(nullptr != llvm_out_value);
assert(nullptr != codegen_mem_funcptr);
assert(nullptr != codegen_utils);
assert(nullptr != llvm_arith_output);
assert(nullptr != llvm_error_msg);
// Assumed caller checked vector size and nullptr for codegen_utils
llvm::Value* casted_arg0 =
codegen_utils->CreateCast<rtype, Arg0>(pg_func_info.llvm_args[0]);
llvm::Value* casted_arg1 =
codegen_utils->CreateCast<rtype, Arg1>(pg_func_info.llvm_args[1]);
llvm::Value* llvm_arith_output = (codegen_utils->*codegen_mem_funcptr)(
casted_arg0, casted_arg1);
llvm::IRBuilder<>* irb = codegen_utils->ir_builder();
// Check if it is a Integer type
if (std::is_integral<rtype>::value) {
llvm::BasicBlock* llvm_non_overflow_block = codegen_utils->CreateBasicBlock(
......@@ -198,22 +253,78 @@ bool PGArithFuncGenerator<rtype, Arg0, Arg1>::ArithOpWithOverflow(
llvm::Value* llvm_overflow_flag =
irb->CreateExtractValue(llvm_arith_output, 1);
irb->CreateCondBr(llvm_overflow_flag,
llvm_overflow_block,
irb->CreateCondBr(llvm_overflow_flag, llvm_overflow_block,
llvm_non_overflow_block);
irb->SetInsertPoint(llvm_overflow_block);
codegen_utils->CreateElog(
ERROR, "%s", llvm_error_msg);
ERROR,
"%s", llvm_error_msg);
irb->CreateBr(pg_func_info.llvm_error_block);
irb->SetInsertPoint(llvm_non_overflow_block);
} else {
*llvm_out_value = llvm_arith_output;
}
return true;
}
template <typename rtype, typename Arg>
bool PGArithUnaryFuncGenerator<rtype, Arg>::ArithOpWithOverflow(
gpcodegen::GpCodegenUtils* codegen_utils,
CGArithOpFunc codegen_mem_funcptr,
llvm::Value* llvm_error_msg,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value) {
assert(nullptr != codegen_utils);
assert(nullptr != llvm_out_value);
assert(nullptr != codegen_mem_funcptr);
assert(nullptr != llvm_error_msg);
// Assumed caller checked vector size and nullptr for codegen_utils
llvm::Value* casted_arg =
codegen_utils->CreateCast<rtype, Arg>(pg_func_info.llvm_args[0]);
llvm::Value* llvm_arith_output = (codegen_utils->*codegen_mem_funcptr)(
casted_arg);
return CreateOverflowCheckLogic<rtype>(codegen_utils,
pg_func_info,
llvm_arith_output,
llvm_error_msg,
llvm_out_value);
}
template <typename rtype, typename Arg0, typename Arg1>
bool PGArithFuncGenerator<rtype, Arg0, Arg1>::ArithOpWithOverflow(
gpcodegen::GpCodegenUtils* codegen_utils,
CGArithOpFunc codegen_mem_funcptr,
llvm::Value* llvm_error_msg,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value) {
assert(nullptr != codegen_utils);
assert(nullptr != llvm_out_value);
assert(nullptr != codegen_mem_funcptr);
assert(nullptr != llvm_error_msg);
// Assumed caller checked vector size and nullptr for codegen_utils
llvm::Value* casted_arg0 =
codegen_utils->CreateCast<rtype, Arg0>(pg_func_info.llvm_args[0]);
llvm::Value* casted_arg1 =
codegen_utils->CreateCast<rtype, Arg1>(pg_func_info.llvm_args[1]);
llvm::Value* llvm_arith_output =
(codegen_utils->*codegen_mem_funcptr)(casted_arg0, casted_arg1);
return CreateOverflowCheckLogic<rtype>(codegen_utils,
pg_func_info,
llvm_arith_output,
llvm_error_msg,
llvm_out_value);
}
/** @} */
} // namespace gpcodegen
......
......@@ -308,6 +308,18 @@ class CodegenUtils {
template <typename CppType>
llvm::Value* CreateAddOverflow(llvm::Value* arg0, llvm::Value* arg1);
/**
* @brief Use LLVM intrinsic to increase the value of a variable by one
* with overflow instruction
*
* @tparam CppType CppType for add
* @param arg Input variable
*
* @return LLVM Value as a pair of results and overflow flag.
**/
template <typename CppType>
llvm::Value* CreateIncOverflow(llvm::Value* arg);
/**
* @brief Use LLVM intrinsic to create Subtract with overflow
* instruction
......@@ -1410,6 +1422,12 @@ llvm::Value* CodegenUtils::CreateAddOverflow(llvm::Value* arg0,
arg1);
}
template <typename CppType>
llvm::Value* CodegenUtils::CreateIncOverflow(llvm::Value* arg) {
return codegen_utils_detail::ArithOpMaker<CppType>::
CreateAddOverflow(this, arg, GetConstant<CppType>(1));
}
template <typename CppType>
llvm::Value* CodegenUtils::CreateSubOverflow(llvm::Value* arg0,
llvm::Value* arg1) {
......@@ -1468,6 +1486,7 @@ class CastMaker<
assert(nullptr != value);
assert(nullptr != value->getType());
assert(value->getType()->isIntegerTy());
assert(nullptr != llvm_dest_type);
assert(llvm_dest_type->isIntegerTy());
}
};
......@@ -1497,6 +1516,7 @@ class CastMaker<
assert(nullptr != value);
assert(nullptr != value->getType());
assert(value->getType()->isIntegerTy());
assert(nullptr != llvm_dest_type);
assert(llvm_dest_type->isIntegerTy());
}
};
......@@ -1525,6 +1545,7 @@ class CastMaker<
assert(nullptr != value->getType());
assert(value->getType()->isFloatTy() ||
value->getType()->isDoubleTy());
assert(nullptr != llvm_dest_type);
assert(llvm_dest_type->isFloatTy());
}
};
......@@ -1553,6 +1574,7 @@ class CastMaker<
assert(nullptr != value->getType());
assert(value->getType()->isFloatTy() ||
value->getType()->isDoubleTy());
assert(nullptr != llvm_dest_type);
assert(llvm_dest_type->isDoubleTy());
}
};
......
......@@ -93,6 +93,18 @@ void OpExprTreeGenerator::InitializeSupportedFunction() {
"int8pl",
&PGArithFuncGenerator<int64_t, int64_t, int64_t>::AddWithOverflow));
supported_function_[1219] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<int64_t, int64_t>(
1219,
"int8inc",
&PGArithUnaryFuncGenerator<int64_t, int64_t>::IncWithOverflow));
supported_function_[2803] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<int64_t, int64_t>(
2803,
"int8inc",
&PGArithUnaryFuncGenerator<int64_t, int64_t>::IncWithOverflow));
supported_function_[216] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<float8, float8, float8>(
216,
......
......@@ -298,7 +298,10 @@ InitScanStateRelationDetails(ScanState *scanState, Plan *plan, EState *estate)
ExecAssignScanProjectionInfo(scanState);
ProjectionInfo *projInfo = scanState->ps.ps_ProjInfo;
if (NULL != projInfo && projInfo->pi_isVarList){
if (NULL != projInfo &&
projInfo->pi_isVarList &&
NULL != projInfo->pi_targetlist)
{
enroll_ExecVariableList_codegen(ExecVariableList,
&projInfo->ExecVariableList_gen_info.ExecVariableList_fn, projInfo, scanState->ss_ScanTupleSlot);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册