提交 f38c9064 编写于 作者: S Shreedhar Hardikar 提交者: Nikos Armenatzoglou

Support avg aggregate function in codegen

Signed-off-by: NNikos Armenatzoglou <nikos.armenatzoglou@gmail.com>
上级 87dcae4c
......@@ -152,6 +152,7 @@ add_library(gpcodegen SHARED
expr_tree_generator.cc
op_expr_tree_generator.cc
pg_date_func_generator.cc
pg_numeric_func_generator.cc
var_expr_tree_generator.cc
advance_aggregates_codegen.cc
......@@ -379,6 +380,9 @@ if(EXISTS ${TXT_OBJFILE})
add_cmockery_gtest(codegen_utils_unittest.t
tests/codegen_utils_unittest.cc
)
add_cmockery_gtest(gp_codegen_utils_unittest.t
tests/gp_codegen_utils_unittest.cc
)
endif()
......
......@@ -55,7 +55,7 @@ bool AdvanceAggregatesCodegen::GenerateAdvanceTransitionFunction(
auto irb = codegen_utils->ir_builder();
AggStatePerAgg peraggstate = &aggstate_->peragg[aggno];
assert(nullptr != peraggstate);
llvm::Value *newVal = nullptr;
llvm::Value *llvm_newval = nullptr;
// External functions
llvm::Function* llvm_MemoryContextSwitchTo =
......@@ -83,11 +83,6 @@ bool AdvanceAggregatesCodegen::GenerateAdvanceTransitionFunction(
codegen_utils->GetPointerToMember(
llvm_pergroupstate, &AggStatePerGroupData::noTransValue);
if (!peraggstate->transtypeByVal) {
elog(DEBUG1, "We do not support pass-by-ref datatypes.");
return false;
}
assert(nullptr != peraggstate->aggref);
assert(pg_func_info->llvm_args.size() == 1 +
list_length(peraggstate->aggref->args));
......@@ -171,7 +166,7 @@ bool AdvanceAggregatesCodegen::GenerateAdvanceTransitionFunction(
irb->CreateStore(codegen_utils->GetConstant<Datum>(0), llvm_arg1_ptr);
}
// }}
newVal = irb->CreateCall(
llvm_newval = irb->CreateCall(
llvm_datumCopyWithMemManager,
{irb->CreateLoad(llvm_pergroupstate_transValue_ptr),
irb->CreateLoad(llvm_arg1_ptr),
......@@ -179,7 +174,7 @@ bool AdvanceAggregatesCodegen::GenerateAdvanceTransitionFunction(
codegen_utils->GetConstant<int>(
static_cast<int>(peraggstate->transtypeLen)),
llvm_mem_manager_arg});
irb->CreateStore(newVal, llvm_pergroupstate_transValue_ptr);
irb->CreateStore(llvm_newval, llvm_pergroupstate_transValue_ptr);
// }}} newVal = datumCopyWithMemManager(...)
// *transValueIsNull = false;
irb->CreateStore(codegen_utils->GetConstant<bool>(false),
......@@ -217,23 +212,64 @@ bool AdvanceAggregatesCodegen::GenerateAdvanceTransitionFunction(
return false;
}
bool isGenerated =
pg_func_gen->GenerateCode(codegen_utils, *pg_func_info, &newVal,
pg_func_gen->GenerateCode(codegen_utils, *pg_func_info, &llvm_newval,
llvm_pergroupstate_transValueIsNull_ptr);
if (!isGenerated) {
elog(DEBUG1, "Function with oid = %d was not generated successfully!",
peraggstate->transfn.fn_oid);
return false;
}
// pergroupstate->transValue = newval
irb->CreateStore(codegen_utils->CreateCppTypeToDatumCast(newVal),
llvm_pergroupstate_transValue_ptr);
// We do not need to set *transValueIsNull = fcinfo->isnull, since
// transValueIsNull is passed as argument to pg_func_gen->GenerateCode
// We do not implement the code below, because we do not support
// pass-by-ref datatypes
// if (!transtypeByVal &&
// DatumGetPointer(newVal) != DatumGetPointer(transValue))
// !fcinfo->isnull
llvm::Value* llvm_fcinfo_is_not_null = irb->CreateNot(
irb->CreateLoad(llvm_pergroupstate_transValueIsNull_ptr));
if (!peraggstate->transtypeByVal) {
llvm::Value* llvm_newval_by_ref =
codegen_utils->CreateCppTypeToDatumCast(llvm_newval);
// if (DatumGetPointer(newVal) != DatumGetPointer(transValue) &&
// !fcinfo->isnull) {{
llvm::Value* llvm_val_changed = irb->CreateICmpNE(
codegen_utils->CreateDatumToCppTypeCast<void*>(llvm_newval),
codegen_utils->CreateDatumToCppTypeCast<void*>(
irb->CreateLoad(llvm_pergroupstate_transValue_ptr)));
llvm::BasicBlock* transtypebyref_block = codegen_utils->CreateBasicBlock(
"transtypebyref_block", pg_func_info->llvm_main_func);
llvm::BasicBlock* end_transtypebyref_block =
codegen_utils->CreateBasicBlock("end_transtypebyref_block",
pg_func_info->llvm_main_func);
irb->CreateCondBr(irb->CreateAnd(llvm_val_changed, llvm_fcinfo_is_not_null),
transtypebyref_block /* true */,
end_transtypebyref_block /* false */);
// }} if (DatumGetPointer ...
irb->SetInsertPoint(transtypebyref_block);
// newVal = datumCopyWithMemManager(transValue, newVal, transtypeByVal,
// transtypeLen, mem_manager); {{
llvm_newval_by_ref = irb->CreateCall(
llvm_datumCopyWithMemManager, {
irb->CreateLoad(llvm_pergroupstate_transValue_ptr),
llvm_newval_by_ref,
codegen_utils->GetConstant<bool>(peraggstate->transtypeByVal),
codegen_utils->GetConstant<int>(
static_cast<int>(peraggstate->transtypeLen)),
llvm_mem_manager_arg});
// pergroupstate->transValue = newval
irb->CreateStore(llvm_newval_by_ref,
llvm_pergroupstate_transValue_ptr);
// }} newVal = datumCopyWithMemManager ...
irb->CreateBr(end_transtypebyref_block);
irb->SetInsertPoint(end_transtypebyref_block);
} else {
// pergroupstate->transValue = newval
irb->CreateStore(codegen_utils->CreateCppTypeToDatumCast(llvm_newval),
llvm_pergroupstate_transValue_ptr);
}
// if (!fcinfo->isnull)
// *noTransvalue = false;
......@@ -244,9 +280,9 @@ bool AdvanceAggregatesCodegen::GenerateAdvanceTransitionFunction(
llvm::BasicBlock* switch_memory_context_block = codegen_utils->
CreateBasicBlock("switch_memory_context_block",
pg_func_info->llvm_main_func);
irb->CreateCondBr(irb->CreateLoad(llvm_pergroupstate_transValueIsNull_ptr),
switch_memory_context_block /*true*/,
set_noTransvalue_block /*false*/);
irb->CreateCondBr(llvm_fcinfo_is_not_null,
set_noTransvalue_block /*true*/,
switch_memory_context_block /*false*/);
// set_noTransvalue_block
// ----------------------
......
......@@ -27,6 +27,7 @@
extern "C" {
#include "lib/stringinfo.h"
#include "postgres.h" // NOLINT(build/include)
}
using gpcodegen::CodegenManager;
......@@ -112,6 +113,15 @@ att_align_nominal_regular(int cur_offset, char attalign) {
return att_align_nominal(cur_offset, attalign);
}
void SET_VARSIZE_regular(void* ptr, size_t len) {
SET_VARSIZE(ptr, len);
}
uint32
VARSIZE_regular(void* ptr) {
return VARSIZE(ptr);
}
void* ExecVariableListCodegenEnroll(
ExecVariableListFn regular_func_ptr,
ExecVariableListFn* ptr_to_chosen_func_ptr,
......
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// pg_numeric_func_generator.h
//
// @doc:
// Base class for numeric functions to generate code
//
//---------------------------------------------------------------------------
#ifndef GPDB_PG_NUMERIC_FUNC_GENERATOR_H_ // NOLINT(build/header_guard)
#define GPDB_PG_NUMERIC_FUNC_GENERATOR_H_
#include "codegen/utils/gp_codegen_utils.h"
#include "codegen/pg_func_generator.h"
#include "codegen/pg_func_generator_interface.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Value.h"
extern "C" {
#include "postgres.h" // NOLINT(build/include)
#include "c.h" // NOLINT(build/include)
#include "utils/numeric.h"
}
namespace llvm {
class Value;
}
namespace gpcodegen {
/** \addtogroup gpcodegen
* @{
*/
class GpCodegenUtils;
struct PGFuncGeneratorInfo;
/**
* @brief Class with Static member function to generate code for numeric
* operators.
**/
class PGNumericFuncGenerator {
public:
/**
* @brief Create LLVM instructions for intfloat_avg_accum_decum function,
* which is called by int8_avg_accum and float8_avg_accum
* built-in functions. Only accum case has been implemented.
*
* @tparam CType Data type of input argument.
* @param codegen_utils Utility for easy code generation.
* @param pg_func_info Details for pgfunc generation
* @param llvm_out_value Variable to keep the result
*
* @return true if generation was successful otherwise return false.
**/
template<typename CType>
static bool GenerateIntFloatAvgAccum(
gpcodegen::GpCodegenUtils* codegen_utils,
const gpcodegen::PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value);
/**
* @brief Create LLVM instructions for intfloat_avg_amalg_demalg function,
* which is called by int8_avg_amalg and float8_avg_amalg
* built-in functions. Only amalg case has been implemented.
*
* @param codegen_utils Utility for easy code generation.
* @param pg_func_info Details for pgfunc generation
* @param llvm_out_value Variable to keep the result
*
* @return true if generation was successful otherwise return false.
**/
static bool GenerateIntFloatAvgAmalg(
gpcodegen::GpCodegenUtils* codegen_utils,
const gpcodegen::PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value);
private:
/**
* @brief A helper function that creates LLVM instructions that check if a
* pointer points to a memory chunk that has a given size.
*
* @param codegen_utils Utility for easy code generation.
* @param llvm_ptr Pointer to the memory chunk
* @param llvm_size Expected size
* @param llvm_out_cond Will contain the result of the condition.
*
* @return true if generation was successful otherwise return false.
**/
static bool GenerateVarlenSizeCheck(gpcodegen::GpCodegenUtils* codegen_utils,
llvm::Value* llvm_ptr,
llvm::Value* llvm_size,
llvm::Value** llvm_out_cond);
/**
* @brief A helper function that creates LLVM instructions which implement
* the logic of the first `if` statement in intfloat_avg_accum_decum
* and intfloat_avg_amalg_demalg.
*
* @param codegen_utils Utility for easy code generation.
* @param llvm_in_transdata_ptr Pointer to transdata llvm value
* @param llvm_out_trandata_ptr If llvm_in_transdata_ptr is not valid,
* then llvm_out_trandata_ptr will point to
* a valid transdata llvm value.
*
* @return true if generation was successful otherwise return false.
**/
static bool GeneratePallocTransdata(gpcodegen::GpCodegenUtils* codegen_utils,
llvm::Value* llvm_in_transdata_ptr,
llvm::Value** llvm_out_trandata_ptr);
};
template<typename CType>
bool PGNumericFuncGenerator::GenerateIntFloatAvgAccum(
gpcodegen::GpCodegenUtils* codegen_utils,
const gpcodegen::PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value) {
// TODO(nikos): Can we figure if we need to detoast during generation?
llvm::Function* llvm_pg_detoast_datum = codegen_utils->
GetOrRegisterExternalFunction(pg_detoast_datum, "pg_detoast_datum");
auto irb = codegen_utils->ir_builder();
llvm::Value* llvm_in_transdata_ptr =
irb->CreateCall(llvm_pg_detoast_datum, {pg_func_info.llvm_args[0]});
llvm::Value* llvm_newval = codegen_utils->CreateCast<float8, CType>(
pg_func_info.llvm_args[1]);
// if(transdata == NULL ||
// VARSIZE(transdata) != sizeof(IntFloatAvgTransdata)) { ... } {{
llvm::Value* llvm_transdata_ptr = nullptr;
GeneratePallocTransdata(codegen_utils,
llvm_in_transdata_ptr,
&llvm_transdata_ptr);
// }}
// ++transdata->count;
// transdata->sum += newval; {{
llvm::Value* llvm_transdata_sum_ptr = codegen_utils->GetPointerToMember(
llvm_transdata_ptr, &IntFloatAvgTransdata::sum);
llvm::Value* llvm_transdata_count_ptr = codegen_utils->GetPointerToMember(
llvm_transdata_ptr, &IntFloatAvgTransdata::count);
irb->CreateStore(
irb->CreateFAdd(irb->CreateLoad(llvm_transdata_sum_ptr), llvm_newval),
llvm_transdata_sum_ptr);
irb->CreateStore(irb->CreateAdd(irb->CreateLoad(llvm_transdata_count_ptr),
codegen_utils->GetConstant<int64>(1)),
llvm_transdata_count_ptr);
// }}
*llvm_out_value = llvm_transdata_ptr;
return true;
}
/** @} */
} // namespace gpcodegen
#endif // GPDB_PG_NUMERIC_FUNC_GENERATOR_H_
......@@ -1659,6 +1659,64 @@ class CastMaker<
}
};
// Partial specialization for any signed integer to 64-bit float
template <typename SignedIntType>
class CastMaker<
double,
SignedIntType,
typename std::enable_if<
std::is_integral<SignedIntType>::value &&
std::is_signed<SignedIntType>::value>::type> {
public:
static llvm::Value* CreateCast(llvm::Value* value,
CodegenUtils* codegen_utils) {
assert(nullptr != codegen_utils);
llvm::Type* llvm_dest_type = codegen_utils->GetType<double>();
Checker(value, llvm_dest_type);
return codegen_utils->ir_builder()->CreateSIToFP(
value, llvm_dest_type);
}
private:
static void Checker(llvm::Value* value,
llvm::Type* llvm_dest_type) {
assert(nullptr != value);
assert(nullptr != value->getType());
assert(value->getType()->isIntegerTy());
assert(nullptr != llvm_dest_type);
assert(llvm_dest_type->isDoubleTy());
}
};
// Partial specialization for any unsigned integer to 64-bit float
template <typename UnsignedIntType>
class CastMaker<
double,
UnsignedIntType,
typename std::enable_if<
std::is_integral<UnsignedIntType>::value &&
std::is_unsigned<UnsignedIntType>::value>::type> {
public:
static llvm::Value* CreateCast(llvm::Value* value,
CodegenUtils* codegen_utils) {
assert(nullptr != codegen_utils);
llvm::Type* llvm_dest_type = codegen_utils->GetType<double>();
Checker(value, llvm_dest_type);
return codegen_utils->ir_builder()->CreateUIToFP(
value, llvm_dest_type);
}
private:
static void Checker(llvm::Value* value,
llvm::Type* llvm_dest_type) {
assert(nullptr != value);
assert(nullptr != value->getType());
assert(value->getType()->isIntegerTy());
assert(nullptr != llvm_dest_type);
assert(llvm_dest_type->isDoubleTy());
}
};
} // namespace codegen_utils_detail
template <typename DestType, typename SrcType>
......
......@@ -23,6 +23,8 @@
extern "C" {
#include "utils/elog.h"
#include "utils/palloc.h"
#include "nodes/memnodes.h"
}
#define EXPAND_CREATE_ELOG(codegen_utils, elevel, ...) \
......@@ -34,6 +36,9 @@ extern "C" {
TEXTDOMAIN, elevel, ecode, errmsg_fmt, \
##__VA_ARGS__)
#define EXPAND_CREATE_PALLOC(codegen_utils, sz) \
codegen_utils->CreatePalloc(sz, __FILE__, PG_FUNCNAME_MACRO, __LINE__)
namespace gpcodegen {
class GpCodegenUtils : public CodegenUtils {
......@@ -303,6 +308,22 @@ class GpCodegenUtils : public CodegenUtils {
return llvm_casted_value;
}
/**
* @brief Create instructions to call MemoryContextAllocImpl in the
* CurrentMemoryContext. Use the macro EXPAND_CREATE_PALLOC to get the
* line number, function name and file name.
*
* @param size Size to allocate in the CurrentMemoryContext
* @param file File name
* @param func Function name
* @param line Line number
* @return LLVM::Value pointer to the allocated memory
*/
llvm::Value* CreatePalloc(Size size,
const char* file,
const char *func,
int line);
/**
* @brief Create a Cast instruction to convert given llvm::Value of any type
* to Datum
......
......@@ -25,6 +25,7 @@
#include "codegen/utils/gp_codegen_utils.h"
#include "codegen/pg_arith_func_generator.h"
#include "codegen/pg_date_func_generator.h"
#include "codegen/pg_numeric_func_generator.h"
#include "llvm/IR/IRBuilder.h"
......@@ -160,6 +161,38 @@ void OpExprTreeGenerator::InitializeSupportedFunction() {
&PGDateFuncGenerator::DateLETimestamp,
nullptr,
true));
supported_function_[1963] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<void*, void*, int32>(
1963,
"int4_avg_accum",
&PGNumericFuncGenerator::GenerateIntFloatAvgAccum<int32>,
nullptr,
true));
supported_function_[3108] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<void*, void*, float8>(
3108,
"float8_avg_accum",
&PGNumericFuncGenerator::GenerateIntFloatAvgAccum<float8>,
nullptr,
true));
supported_function_[6009] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<void*, void*, void*>(
6009,
"int8_avg_amalg",
&PGNumericFuncGenerator::GenerateIntFloatAvgAmalg,
nullptr,
true));
supported_function_[3111] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<void*, void*, void*>(
3111,
"float8_avg_amalg",
&PGNumericFuncGenerator::GenerateIntFloatAvgAmalg,
nullptr,
true));
}
PGFuncGeneratorInterface* OpExprTreeGenerator::GetPGFuncGenerator(
......
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// pg_numeric_func_generator.cc
//
// @doc:
// Base class for numeric functions to generate code
//
//---------------------------------------------------------------------------
#include "codegen/pg_numeric_func_generator.h"
using gpcodegen::GpCodegenUtils;
using gpcodegen::PGNumericFuncGenerator;
using gpcodegen::PGFuncGeneratorInfo;
bool PGNumericFuncGenerator::GenerateIntFloatAvgAmalg(
gpcodegen::GpCodegenUtils* codegen_utils,
const gpcodegen::PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value) {
// TODO(nikos): Can we figure if we need to detoast during generation?
llvm::Function* llvm_pg_detoast_datum = codegen_utils->
GetOrRegisterExternalFunction(pg_detoast_datum, "pg_detoast_datum");
auto irb = codegen_utils->ir_builder();
llvm::Function* current_function = irb->GetInsertBlock()->getParent();
llvm::Value* llvm_in_tr0 =
irb->CreateCall(llvm_pg_detoast_datum, {pg_func_info.llvm_args[0]});
llvm::Value* llvm_in_tr1 =
irb->CreateCall(llvm_pg_detoast_datum, {pg_func_info.llvm_args[1]});
// if(transdata == NULL ||
// VARSIZE(transdata) != sizeof(IntFloatAvgTransdata)) { ... }
llvm::Value* llvm_tr0 = nullptr;
GeneratePallocTransdata(codegen_utils, llvm_in_tr0, &llvm_tr0);
// if(tr1 == NULL || VARSIZE(tr1) != sizeof(IntFloatAvgTransdata))
llvm::Value* llvm_varlena_null_size_cond = nullptr;
GenerateVarlenSizeCheck(codegen_utils,
llvm_in_tr1,
codegen_utils->
GetConstant<uint32>(sizeof(IntFloatAvgTransdata)),
&llvm_varlena_null_size_cond);
llvm::BasicBlock* update_block = codegen_utils->CreateBasicBlock(
"update_block", current_function);
llvm::BasicBlock* end_update_block = codegen_utils->CreateBasicBlock(
"end_update_block", current_function);
irb->CreateCondBr(llvm_varlena_null_size_cond,
end_update_block,
update_block);
irb->SetInsertPoint(update_block);
// tr0->count += tr1->count;
// tr0->sum += tr1->sum; {{
llvm::Value* llvm_tr0_sum_ptr =
codegen_utils->GetPointerToMember(llvm_tr0, &IntFloatAvgTransdata::sum);
llvm::Value* llvm_tr0_count_ptr =
codegen_utils->GetPointerToMember(llvm_tr0, &IntFloatAvgTransdata::count);
llvm::Value* llvm_tr1_sum_ptr = codegen_utils->
GetPointerToMember(llvm_in_tr1, &IntFloatAvgTransdata::sum);
llvm::Value* llvm_tr1_count_ptr = codegen_utils->
GetPointerToMember(llvm_in_tr1, &IntFloatAvgTransdata::count);
irb->CreateStore(irb->CreateFAdd(
irb->CreateLoad(llvm_tr0_sum_ptr),
irb->CreateLoad(llvm_tr1_sum_ptr)),
llvm_tr0_sum_ptr);
irb->CreateStore(irb->CreateAdd(
irb->CreateLoad(llvm_tr0_count_ptr),
irb->CreateLoad(llvm_tr1_count_ptr)),
llvm_tr0_count_ptr);
// }}
irb->CreateBr(end_update_block);
irb->SetInsertPoint(end_update_block);
*llvm_out_value = llvm_tr0;
return true;
}
bool PGNumericFuncGenerator::GenerateVarlenSizeCheck(
gpcodegen::GpCodegenUtils* codegen_utils,
llvm::Value* llvm_ptr,
llvm::Value* llvm_size,
llvm::Value** llvm_out_cond) {
llvm::Function* llvm_varsize = codegen_utils->
GetOrRegisterExternalFunction(VARSIZE_regular, "VARSIZE_regular");
auto irb = codegen_utils->ir_builder();
*llvm_out_cond = irb->CreateOr(
irb->CreateICmpEQ(llvm_ptr, codegen_utils->GetConstant<void*>(nullptr)),
irb->CreateICmpNE(
irb->CreateCall(llvm_varsize, {llvm_ptr}),
llvm_size));
return true;
}
bool PGNumericFuncGenerator::GeneratePallocTransdata(
gpcodegen::GpCodegenUtils* codegen_utils,
llvm::Value* llvm_in_transdata_ptr,
llvm::Value** llvm_out_trandata_ptr) {
llvm::Function* llvm_set_varsize = codegen_utils->
GetOrRegisterExternalFunction(SET_VARSIZE_regular, "SET_VARSIZE_regular");
auto irb = codegen_utils->ir_builder();
llvm::BasicBlock* entry_block = irb->GetInsertBlock();
llvm::Function* current_function = entry_block->getParent();
llvm::BasicBlock* transdata_palloc_block = codegen_utils->
CreateBasicBlock("transdata_palloc_block", current_function);
llvm::BasicBlock* end_transdata_palloc_block = codegen_utils->
CreateBasicBlock("end_transdata_palloc_block", current_function);
// if(tr0 == NULL || VARSIZE(tr0) != sizeof(IntFloatAvgTransdata)) {{
llvm::Value* palloc_cond = nullptr;
GenerateVarlenSizeCheck(codegen_utils,
llvm_in_transdata_ptr,
codegen_utils->GetConstant<uint32>(
sizeof(IntFloatAvgTransdata)),
&palloc_cond);
irb->CreateCondBr(palloc_cond,
transdata_palloc_block,
end_transdata_palloc_block);
// }}
irb->SetInsertPoint(transdata_palloc_block);
// tr0 = (IntFloatAvgTransdata *) palloc(sizeof(IntFloatAvgTransdata));
llvm::Value* llvm_palloc_transdata_ptr =
EXPAND_CREATE_PALLOC(codegen_utils, sizeof(IntFloatAvgTransdata));
// SET_VARSIZE(tr0, sizeof(IntFloatAvgTransdata));
irb->CreateCall(llvm_set_varsize, {
llvm_palloc_transdata_ptr,
codegen_utils->GetConstant(sizeof(IntFloatAvgTransdata))});
// tr0->sum = 0;
irb->CreateStore(codegen_utils->GetConstant<float8>(0),
codegen_utils->GetPointerToMember(
llvm_palloc_transdata_ptr, &IntFloatAvgTransdata::sum));
// tr0->count = 0;
irb->CreateStore(codegen_utils->GetConstant<int64>(0),
codegen_utils->GetPointerToMember(
llvm_palloc_transdata_ptr,
&IntFloatAvgTransdata::count));
irb->CreateBr(end_transdata_palloc_block);
irb->SetInsertPoint(end_transdata_palloc_block);
assert(llvm_in_transdata_ptr->getType() ==
llvm_palloc_transdata_ptr->getType());
llvm::PHINode* llvm_transdata_ptr = irb->
CreatePHI(llvm_in_transdata_ptr->getType(), 2);
llvm_transdata_ptr->addIncoming(llvm_in_transdata_ptr, entry_block);
llvm_transdata_ptr->addIncoming(llvm_palloc_transdata_ptr,
transdata_palloc_block);
*llvm_out_trandata_ptr = llvm_transdata_ptr;
return true;
}
......@@ -832,6 +832,44 @@ class CodegenUtilsTest : public ::testing::Test {
}
}
// Helper method for CreateCastTest. Tests
// CodegenUtils::CreateCast() from an 'IntegerType' to 64-bit float
template <typename IntegerSrcType>
void CheckIntegerTo64FloatCast(const double double_constant) {
llvm::Constant* constant = codegen_utils_->GetConstant<IntegerSrcType>(
static_cast<IntegerSrcType>(double_constant));
llvm::Constant* casted_constant =
llvm::dyn_cast<llvm::Constant>(
codegen_utils_->CreateCast<double, IntegerSrcType>(
constant));
CheckGetSingleFloatingPointConstant(double_constant, casted_constant);
}
// Helper method for CreateCastTest. Tests
// CodegenUtils::CreateCast() for an 'IntegerType' with several values
// of the specified integer type (0, 1, 123, the maximum, and if signed,
// -1, -123, and the minimum) to 64-bit float.
template <typename IntegerSrcType>
void CheckIntegerTo64FloatCast() {
CheckIntegerTo64FloatCast<IntegerSrcType>(static_cast<double>(0));
CheckIntegerTo64FloatCast<IntegerSrcType>(static_cast<double>(1));
CheckIntegerTo64FloatCast<IntegerSrcType>(static_cast<double>(123));
CheckIntegerTo64FloatCast<IntegerSrcType>(
static_cast<double>(
std::numeric_limits<IntegerSrcType>::max()));
if (std::is_signed<IntegerSrcType>::value) {
IntegerSrcType src_value = -1;
CheckIntegerTo64FloatCast<IntegerSrcType>(
static_cast<double>(src_value));
src_value = -123;
CheckIntegerTo64FloatCast<IntegerSrcType>(
static_cast<double>(src_value));
src_value = std::numeric_limits<IntegerSrcType>::min();
CheckIntegerTo64FloatCast<IntegerSrcType>(
static_cast<double>(src_value));
}
}
// Helper method for GetScalarConstantTest. Tests
// CodegenUtils::GetConstant() for a single 'enum_constant'.
template <typename EnumType>
......@@ -1944,6 +1982,14 @@ TEST_F(CodegenUtilsTest, CreateCastTest) {
// Floating type of same size
CheckFloatingPointCast<float, float>();
CheckFloatingPointCast<double, double>();
// signed integer to 64-bit float
CheckIntegerTo64FloatCast<std::int8_t>();
CheckIntegerTo64FloatCast<std::int16_t>();
// unsigned integer to 64-bit float
CheckIntegerTo64FloatCast<std::uint8_t>();
CheckIntegerTo64FloatCast<std::uint16_t>();
}
TEST_F(CodegenUtilsTest, GetPointerConstantTest) {
......
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright 2016 Pivotal Software, Inc.
//
// @filename:
// gp_codegen_utils_unittest.cc
//
// @doc:
// Unit tests for utils/codegen_utils.cc
//
// @test:
//
//---------------------------------------------------------------------------
#include "gtest/gtest.h"
extern "C" {
#include "postgres.h" // NOLINT(build/include)
#undef newNode // undef newNode so it doesn't have name collision with llvm
#include "utils/palloc.h"
#include "utils/memutils.h"
}
#include "codegen/utils/gp_codegen_utils.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
namespace gpcodegen {
// Test environment to handle global per-process initialization tasks for all
// tests.
class GpCodegenUtilsTestEnvironment : public ::testing::Environment {
public:
virtual void SetUp() {
ASSERT_TRUE(GpCodegenUtils::InitializeGlobal());
}
};
class GpCodegenUtilsTest : public ::testing::Test {
protected:
virtual void SetUp() {
codegen_utils_.reset(new GpCodegenUtils("test_module"));
}
// Helper method to test memory allocation.
void CheckCreatePalloc() {
// Test scenario: i) Create a memory context and set it as the current.
// ii) Create and call a function that allocates memory in the current
// memory context, and iii) check if the size of the current memory
// context has been increased.
typedef void (*AllocateMemoryFn) ();
llvm::Function* allocate_memory_fn
= codegen_utils_->CreateFunction<AllocateMemoryFn>("AllocateMemory");
llvm::BasicBlock* allocate_memory_fn_body
= codegen_utils_->CreateBasicBlock("body", allocate_memory_fn);
codegen_utils_->ir_builder()->SetInsertPoint(allocate_memory_fn_body);
EXPAND_CREATE_PALLOC(codegen_utils_, 10000);
codegen_utils_->ir_builder()->CreateRetVoid();
// Verify function is well-formed.
EXPECT_FALSE(llvm::verifyFunction(*allocate_memory_fn));
EXPECT_FALSE(llvm::verifyModule(*codegen_utils_->module()));
// Prepare generated code for execution.
EXPECT_TRUE(codegen_utils_->PrepareForExecution(
CodegenUtils::OptimizationLevel::kNone,
true));
// Cast to the actual function type.
void (*function_ptr)() = codegen_utils_->
GetFunctionPointer<AllocateMemoryFn>("AllocateMemory");
ASSERT_NE(function_ptr, nullptr);
// Create a memory context and set it as the current memory context.
MemoryContext memCtx =
AllocSetContextCreate(nullptr,
"memContext",
ALLOCSET_SMALL_MINSIZE,
ALLOCSET_SMALL_INITSIZE,
ALLOCSET_SMALL_MAXSIZE);
MemoryContextSwitchTo(memCtx);
EXPECT_EQ(0, MemoryContextGetCurrentSpace(memCtx));
(*function_ptr)();
EXPECT_LT(10000, MemoryContextGetCurrentSpace(memCtx));
}
std::unique_ptr<GpCodegenUtils> codegen_utils_;
};
TEST_F(GpCodegenUtilsTest, InitializationTest) {
EXPECT_NE(codegen_utils_->ir_builder(), nullptr);
ASSERT_NE(codegen_utils_->module(), nullptr);
EXPECT_EQ(std::string("test_module"),
codegen_utils_->module()->getModuleIdentifier());
}
TEST_F(GpCodegenUtilsTest, MemoryAllocationTest) {
CheckCreatePalloc();
}
} // namespace gpcodegen
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
AddGlobalTestEnvironment(new gpcodegen::GpCodegenUtilsTestEnvironment);
return RUN_ALL_TESTS();
}
// EOF
......@@ -13,7 +13,7 @@
#ifdef CODEGEN_GPDB_ASSERT_HANDLING
extern "C" {
#include "postgres.h"
#include "postgres.h" // NOLINT(build/include)
// Overload assert handling from LLVM, and pass any error messages to GPDB.
// LLVM has a custom implementation of __assert_rtn, only compiled
......
......@@ -67,6 +67,26 @@ llvm::Value* GpCodegenUtils::CreateCppTypeToDatumCast(
return llvm_casted_value;
}
llvm::Value* GpCodegenUtils::CreatePalloc(Size size,
const char* file,
const char *func,
int line) {
llvm::Function* llvm_memory_context_alloc_impl =
GetOrRegisterExternalFunction(MemoryContextAllocImpl,
"MemoryContextAllocImpl");
// Define llvm_memory_context_alloc_impl as a system memory allocation
// function that returns a pointer to allocated storage.
llvm_memory_context_alloc_impl->setDoesNotAlias(0 /* return value */);
llvm::Value* llvm_current_memory_context =
ir_builder()->CreateLoad(GetConstant(&CurrentMemoryContext));
return ir_builder()->CreateCall(llvm_memory_context_alloc_impl, {
llvm_current_memory_context,
GetConstant<Size>(size),
GetConstant(file),
GetConstant(func),
GetConstant(line)});
}
} // namespace gpcodegen
// EOF
......@@ -2933,21 +2933,8 @@ int8_invsum(PG_FUNCTION_ARGS)
NumericGetDatum(oldsum), newval));
}
/*
* Routines for avg int type. The transition datatype is a int64 for count, and a float8 for sum.
*/
typedef struct IntFloatAvgTransdata
{
int32 _len; /* len for varattrib, do not touch directly */
#if 1
int32 pad; /* pad so int64 and float64 will be 8 bytes aligned */
#endif
int64 count;
float8 sum;
} IntFloatAvgTransdata;
static inline Datum intfloat_avg_accum_decum(IntFloatAvgTransdata *transdata, float8 newval, bool acc)
inline
Datum intfloat_avg_accum_decum(IntFloatAvgTransdata *transdata, float8 newval, bool acc)
{
if(transdata == NULL || VARSIZE(transdata) != sizeof(IntFloatAvgTransdata))
{
......
......@@ -173,6 +173,18 @@ slot_getattr_regular(struct TupleTableSlot *slot, int attnum, bool *isnull);
int
att_align_nominal_regular(int cur_offset, char attalign);
/*
* Wrapper function for SET_VARSIZE.
*/
void
SET_VARSIZE_regular(void* ptr, size_t len);
/*
* Wrapper function for VARSIZE.
*/
uint32
VARSIZE_regular(void* ptr);
/*
* returns the pointer to the ExecVariableList
*/
......
......@@ -90,4 +90,21 @@ extern float8 numeric_li_fraction(Numeric x, Numeric x0, Numeric x1,
bool *eq_bounds, bool *eq_abscissas);
extern Numeric numeric_li_value(float8 f, Numeric y0, Numeric y1);
/*
* Routines for avg int type. The transition datatype is a int64 for count, and a float8 for sum.
*/
typedef struct IntFloatAvgTransdata
{
int32 _len; /* len for varattrib, do not touch directly */
#if 1
int32 pad; /* pad so int64 and float64 will be 8 bytes aligned */
#endif
int64 count;
float8 sum;
} IntFloatAvgTransdata;
extern Datum intfloat_avg_accum_decum(IntFloatAvgTransdata *transdata, float8 newval, bool acc);
#endif /* _PG_NUMERIC_H_ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册