Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Gpdb
提交
79517271
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,发现更多精彩内容 >>
提交
79517271
编写于
11月 08, 2016
作者:
K
Karthikeyan Jambu Rajaraman
提交者:
Nikos Armenatzoglou
11月 11, 2016
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Support overflow checks for doubles.
Signed-off-by:
N
Nikos Armenatzoglou
<
nikos.armenatzoglou@gmail.com
>
上级
ae48ae8f
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
228 addition
and
39 deletion
+228
-39
src/backend/codegen/include/codegen/pg_arith_func_generator.h
...backend/codegen/include/codegen/pg_arith_func_generator.h
+21
-25
src/backend/codegen/include/codegen/utils/codegen_utils.h
src/backend/codegen/include/codegen/utils/codegen_utils.h
+94
-14
src/backend/codegen/tests/codegen_utils_unittest.cc
src/backend/codegen/tests/codegen_utils_unittest.cc
+88
-0
src/backend/codegen/utils/codegen_utils.cc
src/backend/codegen/utils/codegen_utils.cc
+25
-0
未找到文件。
src/backend/codegen/include/codegen/pg_arith_func_generator.h
浏览文件 @
79517271
...
...
@@ -56,7 +56,7 @@ template <>
class
ArithOpOverFlowErrorMsg
<
double
>
{
public:
static
const
char
*
OverFlowErrMsg
()
{
return
"
float8 out of range
"
;
}
static
const
char
*
OverFlowErrMsg
()
{
return
"
value out of range: overflow
"
;
}
};
}
// namespace gpcodegen_ArithOp_detail
...
...
@@ -385,30 +385,26 @@ static bool CreateOverflowCheckLogic(
assert
(
nullptr
!=
llvm_error_msg
);
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
(
"arith_non_overflow_block"
,
pg_func_info
.
llvm_main_func
);
llvm
::
BasicBlock
*
llvm_overflow_block
=
codegen_utils
->
CreateBasicBlock
(
"arith_overflow_block"
,
pg_func_info
.
llvm_main_func
);
*
llvm_out_value
=
irb
->
CreateExtractValue
(
llvm_arith_output
,
0
);
llvm
::
Value
*
llvm_overflow_flag
=
irb
->
CreateExtractValue
(
llvm_arith_output
,
1
);
irb
->
CreateCondBr
(
llvm_overflow_flag
,
llvm_overflow_block
,
llvm_non_overflow_block
);
irb
->
SetInsertPoint
(
llvm_overflow_block
);
EXPAND_CREATE_ELOG
(
codegen_utils
,
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
;
}
llvm
::
BasicBlock
*
llvm_non_overflow_block
=
codegen_utils
->
CreateBasicBlock
(
"arith_non_overflow_block"
,
pg_func_info
.
llvm_main_func
);
llvm
::
BasicBlock
*
llvm_overflow_block
=
codegen_utils
->
CreateBasicBlock
(
"arith_overflow_block"
,
pg_func_info
.
llvm_main_func
);
*
llvm_out_value
=
irb
->
CreateExtractValue
(
llvm_arith_output
,
0
);
llvm
::
Value
*
llvm_overflow_flag
=
irb
->
CreateExtractValue
(
llvm_arith_output
,
1
);
irb
->
CreateCondBr
(
llvm_overflow_flag
,
llvm_overflow_block
,
llvm_non_overflow_block
);
irb
->
SetInsertPoint
(
llvm_overflow_block
);
EXPAND_CREATE_ELOG
(
codegen_utils
,
ERROR
,
"%s"
,
llvm_error_msg
);
irb
->
CreateBr
(
pg_func_info
.
llvm_error_block
);
irb
->
SetInsertPoint
(
llvm_non_overflow_block
);
return
true
;
}
...
...
src/backend/codegen/include/codegen/utils/codegen_utils.h
浏览文件 @
79517271
...
...
@@ -346,6 +346,20 @@ class CodegenUtils {
template
<
typename
DestType
,
typename
SrcType
>
llvm
::
Value
*
CreateCast
(
llvm
::
Value
*
value
);
/**
* @brief Similar to tuple in C++, this helps to create fixed-size collection
* of hetrogeneous values.
*
* @param members Different types of values that needs to be in the
* collection
* @param name Optional arguments to specify the name of the returned
* variable in IR
*
* @return Struct object allocated in stack, that contains all members.
**/
llvm
::
AllocaInst
*
CreateMakeTuple
(
const
std
::
vector
<
llvm
::
Value
*>&
members
,
const
std
::
string
&
name
=
""
);
/**
* @brief Register an external function if previously unregistered. Otherwise
* return a pointer to the previously registered llvm::Function
...
...
@@ -593,13 +607,6 @@ class CodegenUtils {
llvm
::
Type
*
cast_type
,
const
std
::
size_t
cumulative_offset
);
// Helper method to call any llvm intrinsic feature. E.g. CreateMulOverflow.
// TODO(krajaramn) : Support any number of arguments
llvm
::
Value
*
CreateIntrinsicInstrCall
(
llvm
::
Intrinsic
::
ID
Id
,
llvm
::
ArrayRef
<
llvm
::
Type
*>
Tys
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
);
// Helper method for GetPointerToMember(). This variadic template recursively
// consumes pointers-to-members, adding up 'cumulative_offset' and resolving
// 'MemberType' to '*cast_type' at the penultimate level of recursion before
...
...
@@ -614,6 +621,13 @@ class CodegenUtils {
MemberType
StructType
::*
pointer_to_member
,
TailPointerToMemberTypes
&&
...
tail_pointers_to_members
);
// Helper method to call any llvm intrinsic feature. E.g. CreateMulOverflow.
// TODO(krajaramn) : Support any number of arguments
llvm
::
Value
*
CreateIntrinsicInstrCall
(
llvm
::
Intrinsic
::
ID
Id
,
llvm
::
ArrayRef
<
llvm
::
Type
*>
Tys
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
);
// Helper method for RegisterExternalFunction() that appends an entry for an
// external function to 'named_external_functions_'.
template
<
typename
ReturnType
,
typename
...
ArgumentTypes
>
...
...
@@ -1378,26 +1392,55 @@ class ArithOpMaker<double> {
llvm
::
Value
*
arg1
)
{
Checker
(
arg0
,
arg1
);
// TODO(armenatzoglou) Support overflow
return
generator
->
ir_builder
()
->
CreateFAdd
(
arg0
,
arg1
);
auto
irb
=
generator
->
ir_builder
();
llvm
::
Value
*
llvm_result
=
irb
->
CreateFAdd
(
arg0
,
arg1
);
llvm
::
AllocaInst
*
llvm_tuple_ptr
=
CreateResultWithOverflow
(
generator
,
llvm_result
,
arg0
,
arg1
,
generator
->
GetConstant
<
bool
>
(
true
));
return
irb
->
CreateLoad
(
llvm_tuple_ptr
);
}
static
llvm
::
Value
*
CreateSubOverflow
(
CodegenUtils
*
generator
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
Checker
(
arg0
,
arg1
);
auto
irb
=
generator
->
ir_builder
();
llvm
::
Value
*
llvm_result
=
irb
->
CreateFSub
(
arg0
,
arg1
);
// TODO(armenatzoglou) Support overflow
return
generator
->
ir_builder
()
->
CreateFSub
(
arg0
,
arg1
);
llvm
::
AllocaInst
*
llvm_tuple_ptr
=
CreateResultWithOverflow
(
generator
,
llvm_result
,
arg0
,
arg1
,
generator
->
GetConstant
<
bool
>
(
true
));
return
irb
->
CreateLoad
(
llvm_tuple_ptr
);
}
static
llvm
::
Value
*
CreateMulOverflow
(
CodegenUtils
*
generator
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
Checker
(
arg0
,
arg1
);
// TODO(armenatzoglou) Support overflow
return
generator
->
ir_builder
()
->
CreateFMul
(
arg0
,
arg1
);
auto
irb
=
generator
->
ir_builder
();
llvm
::
Value
*
llvm_result
=
irb
->
CreateFMul
(
arg0
,
arg1
);
llvm
::
Value
*
llvm_arg0_zero
=
irb
->
CreateFCmpOEQ
(
arg0
,
generator
->
GetConstant
<
double
>
(
0
),
"is_arg0_zero"
);
llvm
::
Value
*
llvm_arg1_zero
=
irb
->
CreateFCmpOEQ
(
arg1
,
generator
->
GetConstant
<
double
>
(
0
),
"is_arg1_zero"
);
llvm
::
Value
*
llvm_zero_valid
=
irb
->
CreateOr
(
llvm_arg0_zero
,
llvm_arg1_zero
,
"llvm_zero_valid"
);
llvm
::
AllocaInst
*
llvm_tuple_ptr
=
CreateResultWithOverflow
(
generator
,
llvm_result
,
arg0
,
arg1
,
llvm_zero_valid
);
return
irb
->
CreateLoad
(
llvm_tuple_ptr
);
}
...
...
@@ -1409,6 +1452,43 @@ class ArithOpMaker<double> {
assert
(
arg0
->
getType
()
->
isDoubleTy
());
assert
(
arg1
->
getType
()
->
isDoubleTy
());
}
// Implements CHECKFLOATVAL(float_utils.h), but instead of error out,
// it returns true when an overflow occurs.
static
bool
CheckDoubleVal
(
double
val
,
double
arg0
,
double
arg1
,
bool
zero_is_valid
)
{
bool
inf_is_valid
=
isinf
(
arg0
)
||
isinf
(
arg1
);
if
(
isinf
(
val
)
&&
!
(
inf_is_valid
))
{
return
true
;
}
if
((
val
)
==
0.0
&&
!
(
zero_is_valid
))
{
return
true
;
}
return
false
;
}
// Returns a struct that contains the result value and the overflow flag of
// the operation. It mimics llvm integer intrinsics.
static
llvm
::
AllocaInst
*
CreateResultWithOverflow
(
CodegenUtils
*
generator
,
llvm
::
Value
*
llvm_result
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
,
llvm
::
Value
*
zero_is_valid
)
{
auto
irb
=
generator
->
ir_builder
();
llvm
::
Function
*
llvm_float_overflow_func
=
generator
->
GetOrRegisterExternalFunction
(
CheckDoubleVal
,
"CheckDoubleVal"
);
llvm
::
Value
*
llvm_overflow
=
irb
->
CreateCall
(
llvm_float_overflow_func
,
{
llvm_result
,
arg0
,
arg1
,
zero_is_valid
});
llvm
::
AllocaInst
*
llvm_tuple_ptr
=
generator
->
CreateMakeTuple
(
{
llvm_result
,
llvm_overflow
},
"float_result"
);
return
llvm_tuple_ptr
;
}
};
}
// namespace codegen_utils_detail
...
...
src/backend/codegen/tests/codegen_utils_unittest.cc
浏览文件 @
79517271
...
...
@@ -1255,6 +1255,64 @@ class CodegenUtilsTest : public ::testing::Test {
delete
[]
output_array
;
}
// Helper method for CreateMakeTupleTest. This method creates LLVM function of
// type int(*)(MemberType... args). This LLVM function will create tuple using
// passed arguments. Then it checks if the value of the member in the tuple
// matches with arguments passed in functions. If the check fails, it will
// return the argument index.
template
<
typename
...
MemberTypes
>
void
MakeTupleFunc
(
const
std
::
string
&
func_name
)
{
auto
irb
=
codegen_utils_
->
ir_builder
();
using
LLVMFuncType
=
int
(
*
)(
MemberTypes
...
args
);
llvm
::
Function
*
check_tuple_fn
=
codegen_utils_
->
CreateFunction
<
LLVMFuncType
>
(
func_name
);
irb
->
SetInsertPoint
(
codegen_utils_
->
CreateBasicBlock
(
"main"
,
check_tuple_fn
));
llvm
::
BasicBlock
*
return_block
=
codegen_utils_
->
CreateBasicBlock
(
"return_block"
,
check_tuple_fn
);
llvm
::
Value
*
llvm_ret_ptr
=
irb
->
CreateAlloca
(
codegen_utils_
->
GetType
<
int
>
(),
nullptr
,
"ret_ptr"
);
irb
->
CreateStore
(
codegen_utils_
->
GetConstant
<
int
>
(
200
),
llvm_ret_ptr
);
std
::
vector
<
llvm
::
Value
*>
members
;
llvm
::
Function
::
arg_iterator
itr
=
check_tuple_fn
->
arg_begin
();
for
(;
itr
!=
check_tuple_fn
->
arg_end
();
++
itr
)
{
members
.
push_back
(
&
(
*
itr
));
}
llvm
::
Value
*
llvm_struct_ptr
=
codegen_utils_
->
CreateMakeTuple
(
members
,
"tuple_struct"
);
llvm
::
Value
*
llvm_struct_a
=
irb
->
CreateLoad
(
llvm_struct_ptr
);
for
(
size_t
idx
=
0
;
idx
<
members
.
size
();
++
idx
)
{
llvm
::
BasicBlock
*
next_block
=
codegen_utils_
->
CreateBasicBlock
(
"member_"
+
std
::
to_string
(
idx
),
check_tuple_fn
);
llvm
::
Value
*
llvm_mem_val
=
irb
->
CreateExtractValue
(
llvm_struct_a
,
idx
);
irb
->
CreateStore
(
codegen_utils_
->
GetConstant
<
int
>
(
idx
),
llvm_ret_ptr
);
llvm
::
Type
*
arg_type
=
members
[
idx
]
->
getType
();
ASSERT_TRUE
(
arg_type
->
isIntegerTy
()
||
arg_type
->
isFloatingPointTy
());
llvm
::
Value
*
llvm_comp_res
=
nullptr
;
if
(
arg_type
->
isIntegerTy
())
{
llvm_comp_res
=
irb
->
CreateICmpEQ
(
members
[
idx
],
llvm_mem_val
);
}
else
{
llvm_comp_res
=
irb
->
CreateFCmpOEQ
(
members
[
idx
],
llvm_mem_val
);
}
irb
->
CreateCondBr
(
llvm_comp_res
,
next_block
/* true */
,
return_block
/* false */
);
irb
->
SetInsertPoint
(
next_block
);
}
irb
->
CreateStore
(
codegen_utils_
->
GetConstant
<
int
>
(
members
.
size
()),
llvm_ret_ptr
);
irb
->
CreateBr
(
return_block
);
irb
->
SetInsertPoint
(
return_block
);
irb
->
CreateRet
(
irb
->
CreateLoad
(
llvm_ret_ptr
));
}
std
::
unique_ptr
<
CodegenUtils
>
codegen_utils_
;
};
...
...
@@ -2930,6 +2988,36 @@ TEST_F(CodegenUtilsTest, InlineFunctionTest) {
EXPECT_EQ
(
compiled_add_two_fn
(
-
5
),
-
3
);
}
// Test CreateMakeTuple in CodegenUtils.
TEST_F
(
CodegenUtilsTest
,
CreateMakeTupleTest
)
{
MakeTupleFunc
<
int64_t
,
bool
,
int32_t
,
float
,
int16_t
,
double
>
(
"MakeTupleFunc"
);
using
MakeTupleFuncType
=
int
(
*
)(
int64_t
,
bool
,
int32_t
,
float
,
int16_t
,
double
);
int
total_arg
=
6
;
// Compiled module
EXPECT_TRUE
(
codegen_utils_
->
PrepareForExecution
(
CodegenUtils
::
OptimizationLevel
::
kNone
,
false
));
MakeTupleFuncType
compiled_tuple_fn
=
codegen_utils_
->
GetFunctionPointer
<
MakeTupleFuncType
>
(
"MakeTupleFunc"
);
EXPECT_EQ
(
total_arg
,
compiled_tuple_fn
(
42
,
false
,
23
,
36.23
,
12
,
25.23
));
EXPECT_EQ
(
total_arg
,
compiled_tuple_fn
(
std
::
numeric_limits
<
int64_t
>::
max
(),
true
,
std
::
numeric_limits
<
int32_t
>::
max
(),
std
::
numeric_limits
<
float
>::
max
(),
std
::
numeric_limits
<
int16_t
>::
max
(),
std
::
numeric_limits
<
double
>::
max
()));
EXPECT_EQ
(
total_arg
,
compiled_tuple_fn
(
std
::
numeric_limits
<
int64_t
>::
min
(),
true
,
std
::
numeric_limits
<
int32_t
>::
min
(),
std
::
numeric_limits
<
float
>::
min
(),
std
::
numeric_limits
<
int16_t
>::
min
(),
std
::
numeric_limits
<
double
>::
min
()));
}
#ifdef CODEGEN_DEBUG
...
...
src/backend/codegen/utils/codegen_utils.cc
浏览文件 @
79517271
...
...
@@ -97,6 +97,31 @@ bool CodegenUtils::InitializeGlobal() {
&&
!
llvm
::
InitializeNativeTargetAsmParser
();
}
llvm
::
AllocaInst
*
CodegenUtils
::
CreateMakeTuple
(
const
std
::
vector
<
llvm
::
Value
*>&
members
,
const
std
::
string
&
name
)
{
std
::
vector
<
llvm
::
Type
*>
argument_types
(
members
.
size
(),
nullptr
);
std
::
transform
(
members
.
begin
(),
members
.
end
(),
argument_types
.
begin
(),
[](
llvm
::
Value
*
arg
)
{
assert
(
nullptr
!=
arg
);
return
arg
->
getType
();});
llvm
::
StructType
*
llvm_struct_type
=
llvm
::
StructType
::
create
(
context_
,
argument_types
,
name
.
empty
()
?
""
:
name
+
"_type"
);
llvm
::
AllocaInst
*
llvm_struct_ptr
=
ir_builder
()
->
CreateAlloca
(
llvm_struct_type
,
nullptr
,
name
);
for
(
size_t
member_idx
=
0
;
member_idx
<
members
.
size
();
++
member_idx
)
{
llvm
::
Value
*
llvm_mem_ptr
=
ir_builder
()
->
CreateInBoundsGEP
(
llvm_struct_type
,
llvm_struct_ptr
,
// This doesn't work if type is not int32_t.
{
GetConstant
<
int32_t
>
(
0
),
GetConstant
<
int32_t
>
(
member_idx
)});
ir_builder
()
->
CreateStore
(
members
[
member_idx
],
llvm_mem_ptr
);
}
return
llvm_struct_ptr
;
}
bool
CodegenUtils
::
Optimize
(
const
OptimizationLevel
generic_opt_level
,
const
SizeLevel
size_level
,
const
bool
optimize_for_host_cpu
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录