Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Gpdb
提交
f38c9064
G
Gpdb
项目概览
Greenplum
/
Gpdb
通知
7
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
Gpdb
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
f38c9064
编写于
11月 28, 2016
作者:
S
Shreedhar Hardikar
提交者:
Nikos Armenatzoglou
12月 08, 2016
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Support avg aggregate function in codegen
Signed-off-by:
N
Nikos Armenatzoglou
<
nikos.armenatzoglou@gmail.com
>
上级
87dcae4c
变更
15
隐藏空白更改
内联
并排
Showing
15 changed file
with
716 addition
and
35 deletion
+716
-35
src/backend/codegen/CMakeLists.txt
src/backend/codegen/CMakeLists.txt
+4
-0
src/backend/codegen/advance_aggregates_codegen.cc
src/backend/codegen/advance_aggregates_codegen.cc
+55
-19
src/backend/codegen/codegen_wrapper.cc
src/backend/codegen/codegen_wrapper.cc
+10
-0
src/backend/codegen/include/codegen/pg_numeric_func_generator.h
...ckend/codegen/include/codegen/pg_numeric_func_generator.h
+162
-0
src/backend/codegen/include/codegen/utils/codegen_utils.h
src/backend/codegen/include/codegen/utils/codegen_utils.h
+58
-0
src/backend/codegen/include/codegen/utils/gp_codegen_utils.h
src/backend/codegen/include/codegen/utils/gp_codegen_utils.h
+21
-0
src/backend/codegen/op_expr_tree_generator.cc
src/backend/codegen/op_expr_tree_generator.cc
+33
-0
src/backend/codegen/pg_numeric_func_generator.cc
src/backend/codegen/pg_numeric_func_generator.cc
+160
-0
src/backend/codegen/tests/codegen_utils_unittest.cc
src/backend/codegen/tests/codegen_utils_unittest.cc
+46
-0
src/backend/codegen/tests/gp_codegen_utils_unittest.cc
src/backend/codegen/tests/gp_codegen_utils_unittest.cc
+115
-0
src/backend/codegen/utils/gp_assert.cc
src/backend/codegen/utils/gp_assert.cc
+1
-1
src/backend/codegen/utils/gp_codegen_utils.cc
src/backend/codegen/utils/gp_codegen_utils.cc
+20
-0
src/backend/utils/adt/numeric.c
src/backend/utils/adt/numeric.c
+2
-15
src/include/codegen/codegen_wrapper.h
src/include/codegen/codegen_wrapper.h
+12
-0
src/include/utils/numeric.h
src/include/utils/numeric.h
+17
-0
未找到文件。
src/backend/codegen/CMakeLists.txt
浏览文件 @
f38c9064
...
...
@@ -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
()
...
...
src/backend/codegen/advance_aggregates_codegen.cc
浏览文件 @
f38c9064
...
...
@@ -55,7 +55,7 @@ bool AdvanceAggregatesCodegen::GenerateAdvanceTransitionFunction(
auto
irb
=
codegen_utils
->
ir_builder
();
AggStatePerAgg
peraggstate
=
&
aggstate_
->
peragg
[
aggno
];
assert
(
nullptr
!=
peraggstate
);
llvm
::
Value
*
newV
al
=
nullptr
;
llvm
::
Value
*
llvm_newv
al
=
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
);
}
// }}
newV
al
=
irb
->
CreateCall
(
llvm_newv
al
=
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
(
newV
al
,
llvm_pergroupstate_transValue_ptr
);
irb
->
CreateStore
(
llvm_newv
al
,
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
,
&
newV
al
,
pg_func_gen
->
GenerateCode
(
codegen_utils
,
*
pg_func_info
,
&
llvm_newv
al
,
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
)
,
s
witch_memory_context
_block
/*true*/
,
s
et_noTransvalue
_block
/*false*/
);
irb
->
CreateCondBr
(
llvm_fcinfo_is_not_null
,
s
et_noTransvalue
_block
/*true*/
,
s
witch_memory_context
_block
/*false*/
);
// set_noTransvalue_block
// ----------------------
...
...
src/backend/codegen/codegen_wrapper.cc
浏览文件 @
f38c9064
...
...
@@ -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
,
...
...
src/backend/codegen/include/codegen/pg_numeric_func_generator.h
0 → 100644
浏览文件 @
f38c9064
//---------------------------------------------------------------------------
// 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_
src/backend/codegen/include/codegen/utils/codegen_utils.h
浏览文件 @
f38c9064
...
...
@@ -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
>
...
...
src/backend/codegen/include/codegen/utils/gp_codegen_utils.h
浏览文件 @
f38c9064
...
...
@@ -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
...
...
src/backend/codegen/op_expr_tree_generator.cc
浏览文件 @
f38c9064
...
...
@@ -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
(
...
...
src/backend/codegen/pg_numeric_func_generator.cc
0 → 100644
浏览文件 @
f38c9064
//---------------------------------------------------------------------------
// 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
;
}
src/backend/codegen/tests/codegen_utils_unittest.cc
浏览文件 @
f38c9064
...
...
@@ -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
)
{
...
...
src/backend/codegen/tests/gp_codegen_utils_unittest.cc
0 → 100644
浏览文件 @
f38c9064
//---------------------------------------------------------------------------
// 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
src/backend/codegen/utils/gp_assert.cc
浏览文件 @
f38c9064
...
...
@@ -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
...
...
src/backend/codegen/utils/gp_codegen_utils.cc
浏览文件 @
f38c9064
...
...
@@ -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
src/backend/utils/adt/numeric.c
浏览文件 @
f38c9064
...
...
@@ -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
))
{
...
...
src/include/codegen/codegen_wrapper.h
浏览文件 @
f38c9064
...
...
@@ -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
*/
...
...
src/include/utils/numeric.h
浏览文件 @
f38c9064
...
...
@@ -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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录