Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Gpdb
提交
ebd1d014
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,体验更适合开发者的 AI 搜索 >>
提交
ebd1d014
编写于
6月 13, 2016
作者:
K
Karthikeyan Jambu Rajaraman
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Enhance codegen framework to support arbitrary expr tree
上级
ec626ce6
变更
18
隐藏空白更改
内联
并排
Showing
18 changed file
with
1307 addition
and
132 deletion
+1307
-132
src/backend/codegen/CMakeLists.txt
src/backend/codegen/CMakeLists.txt
+4
-0
src/backend/codegen/const_expr_tree_generator.cc
src/backend/codegen/const_expr_tree_generator.cc
+50
-0
src/backend/codegen/exec_eval_expr_codegen.cc
src/backend/codegen/exec_eval_expr_codegen.cc
+46
-124
src/backend/codegen/expr_tree_generator.cc
src/backend/codegen/expr_tree_generator.cc
+62
-0
src/backend/codegen/include/codegen/const_expr_tree_generator.h
...ckend/codegen/include/codegen/const_expr_tree_generator.h
+46
-0
src/backend/codegen/include/codegen/expr_tree_generator.h
src/backend/codegen/include/codegen/expr_tree_generator.h
+73
-0
src/backend/codegen/include/codegen/op_expr_tree_generator.h
src/backend/codegen/include/codegen/op_expr_tree_generator.h
+57
-0
src/backend/codegen/include/codegen/pg_arith_func_generator.h
...backend/codegen/include/codegen/pg_arith_func_generator.h
+163
-0
src/backend/codegen/include/codegen/pg_func_generator.h
src/backend/codegen/include/codegen/pg_func_generator.h
+145
-0
src/backend/codegen/include/codegen/pg_func_generator_interface.h
...end/codegen/include/codegen/pg_func_generator_interface.h
+43
-0
src/backend/codegen/include/codegen/utils/codegen_utils.h
src/backend/codegen/include/codegen/utils/codegen_utils.h
+226
-1
src/backend/codegen/include/codegen/var_expr_tree_generator.h
...backend/codegen/include/codegen/var_expr_tree_generator.h
+45
-0
src/backend/codegen/op_expr_tree_generator.cc
src/backend/codegen/op_expr_tree_generator.cc
+158
-0
src/backend/codegen/tests/codegen_framework_unittest.cc
src/backend/codegen/tests/codegen_framework_unittest.cc
+82
-0
src/backend/codegen/utils/codegen_utils.cc
src/backend/codegen/utils/codegen_utils.cc
+10
-0
src/backend/codegen/var_expr_tree_generator.cc
src/backend/codegen/var_expr_tree_generator.cc
+90
-0
src/backend/utils/misc/guc_gp.c
src/backend/utils/misc/guc_gp.c
+1
-1
src/test/unit/mock/gpcodegen_mock.c
src/test/unit/mock/gpcodegen_mock.c
+6
-6
未找到文件。
src/backend/codegen/CMakeLists.txt
浏览文件 @
ebd1d014
...
...
@@ -167,6 +167,10 @@ set(GPCODEGEN_SRC
codegen_wrapper.cc
exec_variable_list_codegen.cc
exec_eval_expr_codegen.cc
expr_tree_generator.cc
op_expr_tree_generator.cc
var_expr_tree_generator.cc
const_expr_tree_generator.cc
)
# Integrate with GPDB build system.
...
...
src/backend/codegen/const_expr_tree_generator.cc
0 → 100644
浏览文件 @
ebd1d014
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#include "codegen/expr_tree_generator.h"
#include "codegen/const_expr_tree_generator.h"
#include "llvm/IR/Value.h"
extern
"C"
{
#include "postgres.h"
#include "utils/elog.h"
#include "nodes/execnodes.h"
}
using
gpcodegen
::
ConstExprTreeGenerator
;
using
gpcodegen
::
ExprTreeGenerator
;
bool
ConstExprTreeGenerator
::
VerifyAndCreateExprTree
(
ExprState
*
expr_state
,
ExprContext
*
econtext
,
std
::
unique_ptr
<
ExprTreeGenerator
>&
expr_tree
)
{
assert
(
nullptr
!=
expr_state
&&
nullptr
!=
expr_state
->
expr
&&
T_Const
==
nodeTag
(
expr_state
->
expr
));
expr_tree
.
reset
(
new
ConstExprTreeGenerator
(
expr_state
));
return
true
;
}
ConstExprTreeGenerator
::
ConstExprTreeGenerator
(
ExprState
*
expr_state
)
:
ExprTreeGenerator
(
expr_state
,
ExprTreeNodeType
::
kConst
)
{
}
bool
ConstExprTreeGenerator
::
GenerateCode
(
CodegenUtils
*
codegen_utils
,
ExprContext
*
econtext
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
llvm
::
Value
*
llvm_isnull_arg
,
llvm
::
Value
*
&
value
)
{
Const
*
const_expr
=
(
Const
*
)
expr_state
()
->
expr
;
value
=
codegen_utils
->
GetConstant
(
const_expr
->
constvalue
);
return
true
;
}
src/backend/codegen/exec_eval_expr_codegen.cc
浏览文件 @
ebd1d014
...
...
@@ -14,6 +14,8 @@
#include <string>
#include "codegen/exec_eval_expr_codegen.h"
#include "codegen/expr_tree_generator.h"
#include "codegen/op_expr_tree_generator.h"
#include "codegen/utils/clang_compiler.h"
#include "codegen/utils/utility.h"
#include "codegen/utils/instance_method_wrappers.h"
...
...
@@ -125,12 +127,18 @@ bool ExecEvalExprCodegen::GenerateExecEvalExpr(
gpcodegen
::
CodegenUtils
*
codegen_utils
)
{
assert
(
NULL
!=
codegen_utils
);
if
(
nullptr
==
exprstate_
||
nullptr
==
exprstate_
->
expr
||
nullptr
==
econtext_
)
{
return
false
;
}
ElogWrapper
elogwrapper
(
codegen_utils
);
//TODO : krajaraman move to better place
OpExprTreeGenerator
::
InitializeSupportedFunction
();
llvm
::
Function
*
exec_eval_expr_func
=
codegen_utils
->
CreateFunction
<
ExecEvalExprFn
>
(
GetUniqueFuncName
());
llvm
::
Function
*
exec_eval_expr_func
=
CreateFunction
<
ExecEvalExprFn
>
(
codegen_utils
,
GetUniqueFuncName
());
// Function arguments to ExecVariableList
llvm
::
Value
*
llvm_expression_arg
=
...
...
@@ -144,134 +152,48 @@ bool ExecEvalExprCodegen::GenerateExecEvalExpr(
codegen_utils
->
RegisterExternalFunction
(
slot_getattr
);
// BasicBlock of function entry.
llvm
::
BasicBlock
*
entry_block
=
codegen_utils
->
CreateBasicBlock
(
llvm
::
BasicBlock
*
llvm_
entry_block
=
codegen_utils
->
CreateBasicBlock
(
"entry"
,
exec_eval_expr_func
);
llvm
::
BasicBlock
*
return_true_block
=
codegen_utils
->
CreateBasicBlock
(
"return_true"
,
exec_eval_expr_func
);
llvm
::
BasicBlock
*
return_false_block
=
codegen_utils
->
CreateBasicBlock
(
"return_false"
,
exec_eval_expr_func
);
llvm
::
BasicBlock
*
llvm_error_block
=
codegen_utils
->
CreateBasicBlock
(
"error_block"
,
exec_eval_expr_func
);
auto
irb
=
codegen_utils
->
ir_builder
();
irb
->
SetInsertPoint
(
entry_block
);
if
(
exprstate_
&&
exprstate_
->
expr
&&
econtext_
)
{
// Codegen Operation expression
Expr
*
expr_
=
exprstate_
->
expr
;
if
(
nodeTag
(
expr_
)
!=
T_OpExpr
)
{
elog
(
DEBUG1
,
"Unsupported expression. Support only T_OpExpr"
);
return
false
;
}
// In ExecEvalOper
OpExpr
*
op
=
(
OpExpr
*
)
expr_
;
if
(
op
->
opno
!=
523
/* "<=" */
&&
op
->
opno
!=
1096
/* date "<=" */
)
{
// Operators are stored in pg_proc table. See postgres.bki for more details.
elog
(
DEBUG1
,
"Unsupported operator %d."
,
op
->
opno
);
return
false
;
}
// In ExecMakeFunctionResult
// retrieve operator's arguments
List
*
arguments
=
((
FuncExprState
*
)
exprstate_
)
->
args
;
// In ExecEvalFuncArgs
if
(
list_length
(
arguments
)
!=
2
)
{
elog
(
DEBUG1
,
"Wrong number of arguments (!= 2)"
);
return
false
;
}
ListCell
*
arg
;
int
arg_num
=
0
;
llvm
::
Value
*
llvm_arg_val
[
2
];
foreach
(
arg
,
arguments
)
{
// retrieve argument's ExprState
ExprState
*
argstate
=
(
ExprState
*
)
lfirst
(
arg
);
// Currently we support only variable and constant arguments
if
(
nodeTag
(
argstate
->
expr
)
==
T_Var
)
{
// In ExecEvalVar
Var
*
variable
=
(
Var
*
)
argstate
->
expr
;
int
attnum
=
variable
->
varattno
;
// slot = econtext->ecxt_scantuple; {{{
// At code generation time, slot is NULL.
// For that reason, we keep a double pointer to slot and at execution time
// we load slot.
TupleTableSlot
**
ptr_to_slot_ptr
=
NULL
;
switch
(
variable
->
varno
)
{
case
INNER
:
/* get the tuple from the inner node */
ptr_to_slot_ptr
=
&
econtext_
->
ecxt_innertuple
;
break
;
case
OUTER
:
/* get the tuple from the outer node */
ptr_to_slot_ptr
=
&
econtext_
->
ecxt_outertuple
;
break
;
default:
/* get the tuple from the relation being scanned */
ptr_to_slot_ptr
=
&
econtext_
->
ecxt_scantuple
;
break
;
}
llvm
::
Value
*
llvm_slot
=
irb
->
CreateLoad
(
codegen_utils
->
GetConstant
(
ptr_to_slot_ptr
));
//}}}
llvm
::
Value
*
llvm_variable_varattno
=
codegen_utils
->
GetConstant
<
int4
>
(
variable
->
varattno
);
// retrieve variable
llvm_arg_val
[
arg_num
]
=
codegen_utils
->
ir_builder
()
->
CreateCall
(
llvm_slot_getattr
,
{
llvm_slot
,
llvm_variable_varattno
,
llvm_isnull_arg
/* TODO: Fix isNull */
});
}
else
if
(
nodeTag
(
argstate
->
expr
)
==
T_Const
)
{
// In ExecEvalConst
Const
*
con
=
(
Const
*
)
argstate
->
expr
;
llvm_arg_val
[
arg_num
]
=
codegen_utils
->
GetConstant
(
con
->
constvalue
);
}
else
{
elog
(
DEBUG1
,
"Unsupported argument type."
);
return
false
;
}
arg_num
++
;
}
if
(
op
->
opno
==
523
)
{
// Execute **int4le**
irb
->
CreateCondBr
(
irb
->
CreateICmpSLE
(
llvm_arg_val
[
0
],
llvm_arg_val
[
1
]),
return_true_block
/* true */
,
return_false_block
/* false */
);
}
else
{
// op->opno == 1096
// Execute **date_le**
// Similar to int4le but we trunc the values to i32 from i64
irb
->
CreateCondBr
(
irb
->
CreateICmpSLE
(
irb
->
CreateTrunc
(
llvm_arg_val
[
0
],
codegen_utils
->
GetType
<
int32
>
()),
irb
->
CreateTrunc
(
llvm_arg_val
[
1
],
codegen_utils
->
GetType
<
int32
>
())),
return_true_block
/* true */
,
return_false_block
/* false */
);
}
irb
->
SetInsertPoint
(
return_true_block
);
irb
->
CreateRet
(
codegen_utils
->
GetConstant
<
int64
>
(
1
));
irb
->
SetInsertPoint
(
return_false_block
);
irb
->
CreateRet
(
codegen_utils
->
GetConstant
<
int64
>
(
0
));
irb
->
SetInsertPoint
(
llvm_entry_block
);
return
true
;
elogwrapper
.
CreateElog
(
DEBUG1
,
"Calling codegen'ed expression evaluation"
);
// Check if we can codegen. If so create ExprTreeGenerator
std
::
unique_ptr
<
ExprTreeGenerator
>
expr_tree_generator
(
nullptr
);
bool
can_generate
=
ExprTreeGenerator
::
VerifyAndCreateExprTree
(
exprstate_
,
econtext_
,
expr_tree_generator
);
if
(
!
can_generate
||
expr_tree_generator
.
get
()
==
nullptr
)
{
return
false
;
}
return
false
;
// Generate code from expression tree generator
llvm
::
Value
*
value
=
nullptr
;
bool
is_generated
=
expr_tree_generator
->
GenerateCode
(
codegen_utils
,
econtext_
,
exec_eval_expr_func
,
llvm_error_block
,
llvm_isnull_arg
,
value
);
if
(
!
is_generated
||
nullptr
==
value
)
{
return
false
;
}
llvm
::
Value
*
llvm_ret_value
=
codegen_utils
->
CreateCast
<
int64_t
>
(
value
);
irb
->
CreateRet
(
llvm_ret_value
);
irb
->
SetInsertPoint
(
llvm_error_block
);
irb
->
CreateRet
(
codegen_utils
->
GetConstant
<
int64_t
>
(
0
));
exec_eval_expr_func
->
dump
();
return
true
;
}
...
...
src/backend/codegen/expr_tree_generator.cc
0 → 100644
浏览文件 @
ebd1d014
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#include <cassert>
#include "codegen/expr_tree_generator.h"
#include "codegen/op_expr_tree_generator.h"
#include "codegen/var_expr_tree_generator.h"
#include "codegen/const_expr_tree_generator.h"
#include "llvm/IR/Value.h"
extern
"C"
{
#include "postgres.h"
#include "utils/elog.h"
#include "nodes/execnodes.h"
}
using
gpcodegen
::
ExprTreeGenerator
;
bool
ExprTreeGenerator
::
VerifyAndCreateExprTree
(
ExprState
*
expr_state
,
ExprContext
*
econtext
,
std
::
unique_ptr
<
ExprTreeGenerator
>&
expr_tree
)
{
assert
(
nullptr
!=
expr_state
&&
nullptr
!=
expr_state
->
expr
);
expr_tree
.
reset
(
nullptr
);
bool
supported_expr_tree
=
false
;
switch
(
nodeTag
(
expr_state
->
expr
))
{
case
T_OpExpr
:
{
supported_expr_tree
=
OpExprTreeGenerator
::
VerifyAndCreateExprTree
(
expr_state
,
econtext
,
expr_tree
);
break
;
}
case
T_Var
:
{
supported_expr_tree
=
VarExprTreeGenerator
::
VerifyAndCreateExprTree
(
expr_state
,
econtext
,
expr_tree
);
break
;
}
case
T_Const
:
{
supported_expr_tree
=
ConstExprTreeGenerator
::
VerifyAndCreateExprTree
(
expr_state
,
econtext
,
expr_tree
);
break
;
}
default
:
{
supported_expr_tree
=
false
;
elog
(
DEBUG1
,
"Unsupported expression tree %d found"
,
nodeTag
(
expr_state
->
expr
));
}
}
assert
((
!
supported_expr_tree
&&
nullptr
==
expr_tree
.
get
())
||
(
supported_expr_tree
&&
nullptr
!=
expr_tree
.
get
()));
return
supported_expr_tree
;
}
src/backend/codegen/include/codegen/const_expr_tree_generator.h
0 → 100644
浏览文件 @
ebd1d014
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_CONST_EXPR_TREE_GENERATOR_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_CONST_EXPR_TREE_GENERATOR_H_
#include "codegen/expr_tree_generator.h"
#include "llvm/IR/Value.h"
namespace
gpcodegen
{
/** \addtogroup gpcodegen
* @{
*/
class
ConstExprTreeGenerator
:
public
ExprTreeGenerator
{
public:
static
bool
VerifyAndCreateExprTree
(
ExprState
*
expr_state
,
ExprContext
*
econtext
,
std
::
unique_ptr
<
ExprTreeGenerator
>&
expr_tree
);
bool
GenerateCode
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
ExprContext
*
econtext
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
llvm
::
Value
*
llvm_isnull_arg
,
llvm
::
Value
*
&
value
)
final
;
protected:
ConstExprTreeGenerator
(
ExprState
*
expr_state
);
};
/** @} */
}
// namespace gpcodegen
#endif // GPCODEGEN_CONST_EXPR_TREE_GENERATOR_H_
src/backend/codegen/include/codegen/expr_tree_generator.h
0 → 100644
浏览文件 @
ebd1d014
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_EXPR_TREE_GENERATOR_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_EXPR_TREE_GENERATOR_H_
#include <string>
#include <vector>
#include <memory>
#include <utility>
#include <unordered_map>
#include "codegen/utils/codegen_utils.h"
#include "llvm/IR/Value.h"
typedef
struct
ExprContext
ExprContext
;
typedef
struct
ExprState
ExprState
;
typedef
struct
Expr
Expr
;
typedef
struct
OpExpr
OpExpr
;
typedef
struct
Var
Var
;
typedef
struct
Const
Const
;
namespace
gpcodegen
{
/** \addtogroup gpcodegen
* @{
*/
enum
class
ExprTreeNodeType
{
kConst
=
0
,
kVar
=
1
,
kOperator
=
2
};
class
ExprTreeGenerator
{
public:
static
bool
VerifyAndCreateExprTree
(
ExprState
*
expr_state
,
ExprContext
*
econtext
,
std
::
unique_ptr
<
ExprTreeGenerator
>&
expr_tree
);
virtual
bool
GenerateCode
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
ExprContext
*
econtext
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
llvm
::
Value
*
llvm_isnull_arg
,
llvm
::
Value
*
&
value
)
=
0
;
ExprState
*
expr_state
()
{
return
expr_state_
;
}
protected:
ExprTreeGenerator
(
ExprState
*
expr_state
,
ExprTreeNodeType
node_type
)
:
expr_state_
(
expr_state
),
node_type_
(
node_type
)
{}
private:
ExprState
*
expr_state_
;
ExprTreeNodeType
node_type_
;
DISALLOW_COPY_AND_ASSIGN
(
ExprTreeGenerator
);
};
/** @} */
}
// namespace gpcodegen
#endif // GPCODEGEN_EXPR_TREE_GENERATOR_H_
src/backend/codegen/include/codegen/op_expr_tree_generator.h
0 → 100644
浏览文件 @
ebd1d014
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_OP_EXPR_TREE_GENERATOR_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_OP_EXPR_TREE_GENERATOR_H_
#include "codegen/expr_tree_generator.h"
#include "codegen/pg_func_generator_interface.h"
#include "codegen/pg_func_generator.h"
#include "llvm/IR/Value.h"
namespace
gpcodegen
{
/** \addtogroup gpcodegen
* @{
*/
using
CodeGenFuncMap
=
std
::
unordered_map
<
unsigned
int
,
std
::
unique_ptr
<
gpcodegen
::
PGFuncGeneratorInterface
>>
;
class
OpExprTreeGenerator
:
public
ExprTreeGenerator
{
public:
static
void
InitializeSupportedFunction
();
static
bool
VerifyAndCreateExprTree
(
ExprState
*
expr_state
,
ExprContext
*
econtext
,
std
::
unique_ptr
<
ExprTreeGenerator
>&
expr_tree
);
bool
GenerateCode
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
ExprContext
*
econtext
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
llvm
::
Value
*
llvm_isnull_arg
,
llvm
::
Value
*
&
value
)
final
;
protected:
OpExprTreeGenerator
(
ExprState
*
expr_state
,
std
::
vector
<
std
::
unique_ptr
<
ExprTreeGenerator
>>&
arguments
);
private:
std
::
vector
<
std
::
unique_ptr
<
ExprTreeGenerator
>>
arguments_
;
static
CodeGenFuncMap
supported_function_
;
};
/** @} */
}
// namespace gpcodegen
#endif // GPCODEGEN_OP_EXPR_TREE_GENERATOR_H_
src/backend/codegen/include/codegen/pg_arith_func_generator.h
0 → 100644
浏览文件 @
ebd1d014
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_PG_ARITH_FUNC_GENERATOR_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_PG_ARITH_FUNC_GENERATOR_H_
#include <string>
#include <vector>
#include <memory>
#include "codegen/utils/codegen_utils.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Value.h"
namespace
gpcodegen
{
/** \addtogroup gpcodegen
* @{
*/
template
<
typename
rtype
,
typename
Arg0
,
typename
Arg1
>
class
PGArithFuncGenerator
{
public:
static
bool
MulWithOverflow
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
std
::
vector
<
llvm
::
Value
*>&
llvm_args
,
llvm
::
Value
*
&
llvm_out_value
);
static
bool
AddWithOverflow
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
std
::
vector
<
llvm
::
Value
*>&
llvm_args
,
llvm
::
Value
*
&
llvm_out_value
);
static
bool
SubWithOverflow
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
std
::
vector
<
llvm
::
Value
*>&
llvm_args
,
llvm
::
Value
*
&
llvm_out_value
);
};
template
<
typename
rtype
,
typename
Arg0
,
typename
Arg1
>
bool
PGArithFuncGenerator
<
rtype
,
Arg0
,
Arg1
>::
MulWithOverflow
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
std
::
vector
<
llvm
::
Value
*>&
llvm_args
,
llvm
::
Value
*
&
llvm_out_value
)
{
// Assumed caller checked vector size and nullptr for codegen_utils
llvm
::
BasicBlock
*
llvm_non_overflow_block
=
codegen_utils
->
CreateBasicBlock
(
"mul_non_overflow_block"
,
llvm_main_func
);
llvm
::
BasicBlock
*
llvm_overflow_block
=
codegen_utils
->
CreateBasicBlock
(
"mul_overflow_block"
,
llvm_main_func
);
llvm
::
Value
*
llvm_mul_output
=
codegen_utils
->
CreateMulOverflow
<
rtype
>
(
llvm_args
[
0
],
llvm_args
[
1
]);
llvm
::
IRBuilder
<>*
irb
=
codegen_utils
->
ir_builder
();
llvm_out_value
=
irb
->
CreateExtractValue
(
llvm_mul_output
,
0
);
llvm
::
Value
*
llvm_overflow_flag
=
irb
->
CreateExtractValue
(
llvm_mul_output
,
1
);
irb
->
CreateCondBr
(
irb
->
CreateICmpEQ
(
llvm_overflow_flag
,
codegen_utils
->
GetConstant
<
bool
>
(
true
)),
llvm_overflow_block
,
llvm_non_overflow_block
);
irb
->
SetInsertPoint
(
llvm_overflow_block
);
// TODO : krajaraman Elog::ERROR after ElogWrapper integrad.
irb
->
CreateBr
(
llvm_error_block
);
irb
->
SetInsertPoint
(
llvm_non_overflow_block
);
return
true
;
}
template
<
typename
rtype
,
typename
Arg0
,
typename
Arg1
>
bool
PGArithFuncGenerator
<
rtype
,
Arg0
,
Arg1
>::
AddWithOverflow
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
std
::
vector
<
llvm
::
Value
*>&
llvm_args
,
llvm
::
Value
*
&
llvm_out_value
)
{
// Assumed caller checked vector size and nullptr for codegen_utils
llvm
::
BasicBlock
*
llvm_non_overflow_block
=
codegen_utils
->
CreateBasicBlock
(
"add_non_overflow_block"
,
llvm_main_func
);
llvm
::
BasicBlock
*
llvm_overflow_block
=
codegen_utils
->
CreateBasicBlock
(
"add_overflow_block"
,
llvm_main_func
);
llvm
::
Value
*
llvm_mul_output
=
codegen_utils
->
CreateAddOverflow
<
rtype
>
(
llvm_args
[
0
],
llvm_args
[
1
]);
llvm
::
IRBuilder
<>*
irb
=
codegen_utils
->
ir_builder
();
llvm_out_value
=
irb
->
CreateExtractValue
(
llvm_mul_output
,
0
);
llvm
::
Value
*
llvm_overflow_flag
=
irb
->
CreateExtractValue
(
llvm_mul_output
,
1
);
irb
->
CreateCondBr
(
irb
->
CreateICmpEQ
(
llvm_overflow_flag
,
codegen_utils
->
GetConstant
<
bool
>
(
true
)),
llvm_overflow_block
,
llvm_non_overflow_block
);
irb
->
SetInsertPoint
(
llvm_overflow_block
);
// TODO : krajaraman Elog::ERROR after ElogWrapper integrad.
irb
->
CreateBr
(
llvm_error_block
);
irb
->
SetInsertPoint
(
llvm_non_overflow_block
);
return
true
;
}
template
<
typename
rtype
,
typename
Arg0
,
typename
Arg1
>
bool
PGArithFuncGenerator
<
rtype
,
Arg0
,
Arg1
>::
SubWithOverflow
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
std
::
vector
<
llvm
::
Value
*>&
llvm_args
,
llvm
::
Value
*
&
llvm_out_value
)
{
// Assumed caller checked vector size and nullptr for codegen_utils
llvm
::
BasicBlock
*
llvm_non_overflow_block
=
codegen_utils
->
CreateBasicBlock
(
"sub_non_overflow_block"
,
llvm_main_func
);
llvm
::
BasicBlock
*
llvm_overflow_block
=
codegen_utils
->
CreateBasicBlock
(
"sub_overflow_block"
,
llvm_main_func
);
llvm
::
Value
*
llvm_mul_output
=
codegen_utils
->
CreateSubOverflow
<
rtype
>
(
llvm_args
[
0
],
llvm_args
[
1
]);
llvm
::
IRBuilder
<>*
irb
=
codegen_utils
->
ir_builder
();
llvm_out_value
=
irb
->
CreateExtractValue
(
llvm_mul_output
,
0
);
llvm
::
Value
*
llvm_overflow_flag
=
irb
->
CreateExtractValue
(
llvm_mul_output
,
1
);
irb
->
CreateCondBr
(
irb
->
CreateICmpEQ
(
llvm_overflow_flag
,
codegen_utils
->
GetConstant
<
bool
>
(
true
)),
llvm_overflow_block
,
llvm_non_overflow_block
);
irb
->
SetInsertPoint
(
llvm_overflow_block
);
// TODO : krajaraman Elog::ERROR after ElogWrapper integrad.
irb
->
CreateBr
(
llvm_error_block
);
irb
->
SetInsertPoint
(
llvm_non_overflow_block
);
return
true
;
}
/** @} */
}
// namespace gpcodegen
#endif // GPCODEGEN_PG_ARITH_FUNC_GENERATOR_H_
src/backend/codegen/include/codegen/pg_func_generator.h
0 → 100644
浏览文件 @
ebd1d014
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_PG_FUNC_GENERATOR_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_PG_FUNC_GENERATOR_H_
#include <string>
#include <vector>
#include <memory>
#include "codegen/pg_func_generator_interface.h"
#include "codegen/utils/codegen_utils.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Value.h"
namespace
gpcodegen
{
/** \addtogroup gpcodegen
* @{
*/
typedef
bool
(
*
ExprCodeGenerator
)(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
std
::
vector
<
llvm
::
Value
*>&
llvm_args
,
llvm
::
Value
*
&
llvm_out_value
);
template
<
typename
FuncPtrType
,
typename
Arg0
,
typename
Arg1
>
class
PGFuncGenerator
:
public
PGFuncGeneratorInterface
{
public:
std
::
string
GetName
()
final
{
return
pg_func_name_
;
};
size_t
GetTotalArgCount
()
final
{
return
2
;
}
protected:
// TODO : krajaraman
// For now treating all argument. Later make template to take
// variable length instead of two arguments
bool
PreProcessArgs
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
std
::
vector
<
llvm
::
Value
*>&
llvm_in_args
,
std
::
vector
<
llvm
::
Value
*>&
llvm_out_args
)
{
assert
(
nullptr
!=
codegen_utils
);
if
(
llvm_in_args
.
size
()
!=
GetTotalArgCount
())
{
return
false
;
}
llvm_out_args
.
push_back
(
codegen_utils
->
CreateCast
<
Arg0
>
(
llvm_in_args
[
0
]));
llvm_out_args
.
push_back
(
codegen_utils
->
CreateCast
<
Arg1
>
(
llvm_in_args
[
1
]));
return
true
;
}
FuncPtrType
func_ptr
()
{
return
func_ptr_
;
}
PGFuncGenerator
(
int
pg_func_oid
,
const
std
::
string
&
pg_func_name
,
FuncPtrType
mem_func_ptr
)
:
pg_func_oid_
(
pg_func_oid
),
pg_func_name_
(
pg_func_name
),
func_ptr_
(
mem_func_ptr
)
{
}
private:
std
::
string
pg_func_name_
;
unsigned
int
pg_func_oid_
;
FuncPtrType
func_ptr_
;
};
template
<
typename
FuncPtrType
,
typename
Arg0
,
typename
Arg1
>
class
PGIRBuilderFuncGenerator
:
public
PGFuncGenerator
<
FuncPtrType
,
Arg0
,
Arg1
>
{
public:
PGIRBuilderFuncGenerator
(
int
pg_func_oid
,
const
std
::
string
&
pg_func_name
,
FuncPtrType
func_ptr
)
:
PGFuncGenerator
<
FuncPtrType
,
Arg0
,
Arg1
>
(
pg_func_oid
,
pg_func_name
,
func_ptr
)
{
}
bool
GenerateCode
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
std
::
vector
<
llvm
::
Value
*>&
llvm_args
,
llvm
::
Value
*
&
llvm_out_value
)
final
{
std
::
vector
<
llvm
::
Value
*>
llvm_preproc_args
;
if
(
!
this
->
PreProcessArgs
(
codegen_utils
,
llvm_args
,
llvm_preproc_args
))
{
return
false
;
}
llvm
::
IRBuilder
<>*
irb
=
codegen_utils
->
ir_builder
();
llvm_out_value
=
(
irb
->*
this
->
func_ptr
())(
llvm_preproc_args
[
0
],
llvm_preproc_args
[
1
],
""
);
return
true
;
}
};
template
<
typename
Arg0
,
typename
Arg1
>
class
PGGenericFuncGenerator
:
public
PGFuncGenerator
<
ExprCodeGenerator
,
Arg0
,
Arg1
>
{
public:
PGGenericFuncGenerator
(
int
pg_func_oid
,
const
std
::
string
&
pg_func_name
,
ExprCodeGenerator
func_ptr
)
:
PGFuncGenerator
<
ExprCodeGenerator
,
Arg0
,
Arg1
>
(
pg_func_oid
,
pg_func_name
,
func_ptr
)
{
}
bool
GenerateCode
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
std
::
vector
<
llvm
::
Value
*>&
llvm_args
,
llvm
::
Value
*
&
llvm_out_value
)
final
{
assert
(
nullptr
!=
codegen_utils
);
if
(
llvm_args
.
size
()
!=
this
->
GetTotalArgCount
())
{
return
false
;
}
this
->
func_ptr
()(
codegen_utils
,
llvm_main_func
,
llvm_error_block
,
llvm_args
,
llvm_out_value
);
return
true
;
}
};
/** @} */
}
// namespace gpcodegen
#endif // GPCODEGEN_PG_FUNC_GENERATOR_H_
src/backend/codegen/include/codegen/pg_func_generator_interface.h
0 → 100644
浏览文件 @
ebd1d014
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_PG_FUNC_GENERATOR_INTERFACE_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_PG_FUNC_GENERATOR_INTERFACE_H_
#include <string>
#include <vector>
#include <memory>
#include "llvm/IR/Value.h"
#include "codegen/utils/codegen_utils.h"
namespace
gpcodegen
{
/** \addtogroup gpcodegen
* @{
*/
class
PGFuncGeneratorInterface
{
public:
virtual
std
::
string
GetName
()
=
0
;
virtual
size_t
GetTotalArgCount
()
=
0
;
virtual
bool
GenerateCode
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
std
::
vector
<
llvm
::
Value
*>&
llvm_args
,
llvm
::
Value
*
&
llvm_out_value
)
=
0
;
};
/** @} */
}
// namespace gpcodegen
#endif // GPCODEGEN_PG_FUNC_GENERATOR_INTERFACE_H_
src/backend/codegen/include/codegen/utils/codegen_utils.h
浏览文件 @
ebd1d014
...
...
@@ -41,6 +41,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Value.h"
namespace
gpcodegen
{
...
...
@@ -49,6 +50,7 @@ namespace gpcodegen {
namespace
codegen_utils_detail
{
template
<
typename
,
typename
>
class
ConstantMaker
;
template
<
typename
>
class
FunctionTypeUnpacker
;
template
<
typename
,
typename
>
class
ArithOpMaker
;
}
// namespace codegen_utils_detail
/** \addtogroup gpcodegen
...
...
@@ -269,7 +271,36 @@ class CodegenUtils {
return
llvm
::
BasicBlock
::
Create
(
context_
,
name
,
parent
,
nullptr
);
}
/*
template
<
typename
DestType
>
llvm
::
Value
*
CreateCast
(
llvm
::
Value
*
value
)
{
assert
(
nullptr
!=
value
);
llvm
::
Type
*
llvm_dest_type
=
GetType
<
DestType
>
();
unsigned
dest_size
=
llvm_dest_type
->
getScalarSizeInBits
();
llvm
::
Type
*
llvm_src_type
=
value
->
getType
();
unsigned
src_size
=
llvm_src_type
->
getScalarSizeInBits
();
if
(
src_size
<
dest_size
)
{
return
ir_builder
()
->
CreateZExt
(
value
,
llvm_dest_type
);
}
else
if
(
src_size
>
dest_size
)
{
return
ir_builder
()
->
CreateTrunc
(
value
,
llvm_dest_type
);
}
else
if
(
llvm_src_type
->
getTypeID
()
!=
llvm_dest_type
->
getTypeID
())
{
return
ir_builder
()
->
CreateBitCast
(
value
,
llvm_dest_type
);
}
return
value
;
}
template
<
typename
CppType
>
llvm
::
Value
*
CreateMulOverflow
(
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
);
template
<
typename
CppType
>
llvm
::
Value
*
CreateAddOverflow
(
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
);
template
<
typename
CppType
>
llvm
::
Value
*
CreateSubOverflow
(
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
);
/**
* @brief Register an external function if previously unregistered. Otherwise
* return a pointer to the previously registered llvm::Function
*
...
...
@@ -419,6 +450,9 @@ class CodegenUtils {
template
<
typename
,
typename
>
friend
class
codegen_utils_detail
::
ConstantMaker
;
template
<
typename
,
typename
>
friend
class
codegen_utils_detail
::
ArithOpMaker
;
template
<
typename
>
friend
class
codegen_utils_detail
::
FunctionTypeUnpacker
;
...
...
@@ -482,6 +516,11 @@ class CodegenUtils {
llvm
::
Type
*
cast_type
,
const
std
::
size_t
cumulative_offset
);
llvm
::
Value
*
CreateArithOp
(
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
...
...
@@ -1111,6 +1150,192 @@ void CodegenUtils::CreateFallback(llvm::Function* regular_function,
}
}
// ----------------------------------------------------------------------------
// Implementation of CodegenUtils::CreateMulOverflow, CreateSubOverflow...
// Helper template classes are nested in this namespace and are not considered
// part of the public API.
namespace
codegen_utils_detail
{
// ArithOpMaker has various template specializations to handle
// different C++ types.
template
<
typename
CppType
,
typename
Enable
=
void
>
class
ArithOpMaker
{
};
// Partial specialization for unsigned integer types (including bool).
template
<
typename
UnsignedIntType
>
class
ArithOpMaker
<
UnsignedIntType
,
typename
std
::
enable_if
<
std
::
is_integral
<
UnsignedIntType
>::
value
&&
std
::
is_unsigned
<
UnsignedIntType
>::
value
>::
type
>
{
public:
static
llvm
::
Value
*
CreateAddOverflow
(
CodegenUtils
*
generator
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
Checker
(
arg0
,
arg1
);
llvm
::
Value
*
casted_arg0
=
generator
->
CreateCast
<
UnsignedIntType
>
(
arg0
);
llvm
::
Value
*
casted_arg1
=
generator
->
CreateCast
<
UnsignedIntType
>
(
arg1
);
return
generator
->
CreateArithOp
(
llvm
::
Intrinsic
::
uadd_with_overflow
,
generator
->
GetType
<
UnsignedIntType
>
(),
casted_arg0
,
casted_arg1
);
}
static
llvm
::
Value
*
CreateSubOverflow
(
CodegenUtils
*
generator
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
Checker
(
arg0
,
arg1
);
llvm
::
Value
*
casted_arg0
=
generator
->
CreateCast
<
UnsignedIntType
>
(
arg0
);
llvm
::
Value
*
casted_arg1
=
generator
->
CreateCast
<
UnsignedIntType
>
(
arg1
);
return
generator
->
CreateArithOp
(
llvm
::
Intrinsic
::
usub_with_overflow
,
generator
->
GetType
<
UnsignedIntType
>
(),
casted_arg0
,
casted_arg1
);
}
static
llvm
::
Value
*
CreateMulOverflow
(
CodegenUtils
*
generator
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
Checker
(
arg0
,
arg1
);
llvm
::
Value
*
casted_arg0
=
generator
->
CreateCast
<
UnsignedIntType
>
(
arg0
);
llvm
::
Value
*
casted_arg1
=
generator
->
CreateCast
<
UnsignedIntType
>
(
arg1
);
return
generator
->
CreateArithOp
(
llvm
::
Intrinsic
::
umul_with_overflow
,
generator
->
GetType
<
UnsignedIntType
>
(),
casted_arg0
,
casted_arg1
);
}
private:
static
void
Checker
(
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
assert
(
nullptr
!=
arg0
&&
nullptr
!=
arg0
->
getType
());
assert
(
nullptr
!=
arg1
&&
nullptr
!=
arg1
->
getType
());
assert
(
arg0
->
getType
()
->
isIntegerTy
());
assert
(
arg1
->
getType
()
->
isIntegerTy
());
}
};
// Partial specialization for signed integer types.
template
<
typename
SignedIntType
>
class
ArithOpMaker
<
SignedIntType
,
typename
std
::
enable_if
<
std
::
is_integral
<
SignedIntType
>::
value
&&
std
::
is_signed
<
SignedIntType
>::
value
>::
type
>
{
public:
static
llvm
::
Value
*
CreateAddOverflow
(
CodegenUtils
*
generator
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
Checker
(
arg0
,
arg1
);
llvm
::
Value
*
casted_arg0
=
generator
->
CreateCast
<
SignedIntType
>
(
arg0
);
llvm
::
Value
*
casted_arg1
=
generator
->
CreateCast
<
SignedIntType
>
(
arg1
);
return
generator
->
CreateArithOp
(
llvm
::
Intrinsic
::
sadd_with_overflow
,
generator
->
GetType
<
SignedIntType
>
(),
casted_arg0
,
casted_arg1
);
}
static
llvm
::
Value
*
CreateSubOverflow
(
CodegenUtils
*
generator
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
Checker
(
arg0
,
arg1
);
llvm
::
Value
*
casted_arg0
=
generator
->
CreateCast
<
SignedIntType
>
(
arg0
);
llvm
::
Value
*
casted_arg1
=
generator
->
CreateCast
<
SignedIntType
>
(
arg1
);
return
generator
->
CreateArithOp
(
llvm
::
Intrinsic
::
ssub_with_overflow
,
generator
->
GetType
<
SignedIntType
>
(),
casted_arg0
,
casted_arg1
);
}
static
llvm
::
Value
*
CreateMulOverflow
(
CodegenUtils
*
generator
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
Checker
(
arg0
,
arg1
);
llvm
::
Value
*
casted_arg0
=
generator
->
CreateCast
<
SignedIntType
>
(
arg0
);
llvm
::
Value
*
casted_arg1
=
generator
->
CreateCast
<
SignedIntType
>
(
arg1
);
return
generator
->
CreateArithOp
(
llvm
::
Intrinsic
::
smul_with_overflow
,
generator
->
GetType
<
SignedIntType
>
(),
casted_arg0
,
casted_arg1
);
}
private:
static
void
Checker
(
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
assert
(
nullptr
!=
arg0
&&
nullptr
!=
arg0
->
getType
());
assert
(
nullptr
!=
arg1
&&
nullptr
!=
arg1
->
getType
());
assert
(
arg0
->
getType
()
->
isIntegerTy
());
assert
(
arg1
->
getType
()
->
isIntegerTy
());
}
};
// Partial specialization for enums (mapped to the underlying integer type).
template
<
typename
EnumType
>
class
ArithOpMaker
<
EnumType
,
typename
std
::
enable_if
<
std
::
is_enum
<
EnumType
>::
value
>::
type
>
{
public:
static
llvm
::
Value
*
Get
(
CodegenUtils
*
generator
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
static_assert
(
"Not support for enum"
);
}
};
// Explicit specialization for 32-bit float.
template
<
>
class
ArithOpMaker
<
float
>
{
public:
static
llvm
::
Value
*
Get
(
CodegenUtils
*
generator
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
static_assert
(
"Not support for float"
);
}
};
// Explicit specialization for 64-bit double.
template
<
>
class
ArithOpMaker
<
double
>
{
public:
static
llvm
::
Value
*
Get
(
CodegenUtils
*
generator
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
static_assert
(
"Not support for double"
);
}
};
}
// namespace codegen_utils_detail
template
<
typename
CppType
>
llvm
::
Value
*
CodegenUtils
::
CreateAddOverflow
(
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
return
codegen_utils_detail
::
ArithOpMaker
<
CppType
>::
CreateAddOverflow
(
this
,
arg0
,
arg1
);
}
template
<
typename
CppType
>
llvm
::
Value
*
CodegenUtils
::
CreateSubOverflow
(
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
return
codegen_utils_detail
::
ArithOpMaker
<
CppType
>::
CreateSubOverflow
(
this
,
arg0
,
arg1
);
}
template
<
typename
CppType
>
llvm
::
Value
*
CodegenUtils
::
CreateMulOverflow
(
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
return
codegen_utils_detail
::
ArithOpMaker
<
CppType
>::
CreateMulOverflow
(
this
,
arg0
,
arg1
);
}
}
// namespace gpcodegen
#endif // GPCODEGEN_CODEGEN_UTILS_H_
...
...
src/backend/codegen/include/codegen/var_expr_tree_generator.h
0 → 100644
浏览文件 @
ebd1d014
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_VAR_EXPR_TREE_GENERATOR_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_VAR_EXPR_TREE_GENERATOR_H_
#include "codegen/expr_tree_generator.h"
#include "llvm/IR/Value.h"
namespace
gpcodegen
{
/** \addtogroup gpcodegen
* @{
*/
class
VarExprTreeGenerator
:
public
ExprTreeGenerator
{
public:
static
bool
VerifyAndCreateExprTree
(
ExprState
*
expr_state
,
ExprContext
*
econtext
,
std
::
unique_ptr
<
ExprTreeGenerator
>&
expr_tree
);
bool
GenerateCode
(
gpcodegen
::
CodegenUtils
*
codegen_utils
,
ExprContext
*
econtext
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
llvm
::
Value
*
llvm_isnull_arg
,
llvm
::
Value
*
&
value
)
final
;
protected:
VarExprTreeGenerator
(
ExprState
*
expr_state
);
};
/** @} */
}
// namespace gpcodegen
#endif // GPCODEGEN_VAR_EXPR_TREE_GENERATOR_H_
src/backend/codegen/op_expr_tree_generator.cc
0 → 100644
浏览文件 @
ebd1d014
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#include "codegen/expr_tree_generator.h"
#include "codegen/op_expr_tree_generator.h"
#include "include/codegen/pg_arith_func_generator.h"
#include "llvm/IR/Value.h"
extern
"C"
{
#include "postgres.h"
#include "utils/elog.h"
#include "nodes/execnodes.h"
}
using
gpcodegen
::
OpExprTreeGenerator
;
using
gpcodegen
::
ExprTreeGenerator
;
using
gpcodegen
::
CodegenUtils
;
using
gpcodegen
::
PGFuncGeneratorInterface
;
using
gpcodegen
::
PGFuncGenerator
;
using
gpcodegen
::
CodeGenFuncMap
;
using
llvm
::
IRBuilder
;
CodeGenFuncMap
OpExprTreeGenerator
::
supported_function_
;
void
OpExprTreeGenerator
::
InitializeSupportedFunction
()
{
if
(
!
supported_function_
.
empty
())
{
return
;
}
supported_function_
[
149
]
=
std
::
unique_ptr
<
PGFuncGeneratorInterface
>
(
new
PGIRBuilderFuncGenerator
<
decltype
(
&
IRBuilder
<>::
CreateICmpSLE
),
int32_t
,
int32_t
>
(
149
,
"int4le"
,
&
IRBuilder
<>::
CreateICmpSLE
));
supported_function_
[
1088
]
=
std
::
unique_ptr
<
PGFuncGeneratorInterface
>
(
new
PGIRBuilderFuncGenerator
<
decltype
(
&
IRBuilder
<>::
CreateICmpSLE
),
int32_t
,
int32_t
>
(
1088
,
"date_le"
,
&
IRBuilder
<>::
CreateICmpSLE
));
supported_function_
[
177
]
=
std
::
unique_ptr
<
PGFuncGeneratorInterface
>
(
new
PGGenericFuncGenerator
<
int32_t
,
int32_t
>
(
141
,
"int4pl"
,
&
PGArithFuncGenerator
<
int32_t
,
int32_t
,
int32_t
>::
AddWithOverflow
));
supported_function_
[
181
]
=
std
::
unique_ptr
<
PGFuncGeneratorInterface
>
(
new
PGGenericFuncGenerator
<
int32_t
,
int32_t
>
(
141
,
"int4mi"
,
&
PGArithFuncGenerator
<
int32_t
,
int32_t
,
int32_t
>::
SubWithOverflow
));
supported_function_
[
141
]
=
std
::
unique_ptr
<
PGFuncGeneratorInterface
>
(
new
PGGenericFuncGenerator
<
int32_t
,
int32_t
>
(
141
,
"int4mul"
,
&
PGArithFuncGenerator
<
int32_t
,
int32_t
,
int32_t
>::
MulWithOverflow
));
}
OpExprTreeGenerator
::
OpExprTreeGenerator
(
ExprState
*
expr_state
,
std
::
vector
<
std
::
unique_ptr
<
ExprTreeGenerator
>>&
arguments
)
:
arguments_
(
std
::
move
(
arguments
)),
ExprTreeGenerator
(
expr_state
,
ExprTreeNodeType
::
kOperator
)
{
}
bool
OpExprTreeGenerator
::
VerifyAndCreateExprTree
(
ExprState
*
expr_state
,
ExprContext
*
econtext
,
std
::
unique_ptr
<
ExprTreeGenerator
>&
expr_tree
)
{
assert
(
nullptr
!=
expr_state
&&
nullptr
!=
expr_state
->
expr
&&
T_OpExpr
==
nodeTag
(
expr_state
->
expr
));
OpExpr
*
op_expr
=
(
OpExpr
*
)
expr_state
->
expr
;
expr_tree
.
reset
(
nullptr
);
CodeGenFuncMap
::
iterator
itr
=
supported_function_
.
find
(
op_expr
->
opfuncid
);
if
(
itr
==
supported_function_
.
end
())
{
// Operators are stored in pg_proc table. See postgres.bki for more details.
elog
(
DEBUG1
,
"Unsupported operator %d."
,
op_expr
->
opfuncid
);
return
false
;
}
List
*
arguments
=
((
FuncExprState
*
)
expr_state
)
->
args
;
if
(
nullptr
==
arguments
)
{
elog
(
DEBUG1
,
"No argument for the function"
);
return
false
;
}
// In ExecEvalFuncArgs
if
(
list_length
(
arguments
)
!=
itr
->
second
->
GetTotalArgCount
())
{
elog
(
DEBUG1
,
"Wrong number of arguments (!= %d)"
,
itr
->
second
->
GetTotalArgCount
());
return
false
;
}
ListCell
*
arg
=
nullptr
;
bool
supported_tree
=
true
;
std
::
vector
<
std
::
unique_ptr
<
ExprTreeGenerator
>>
expr_tree_arguments
;
foreach
(
arg
,
arguments
)
{
// retrieve argument's ExprState
ExprState
*
argstate
=
(
ExprState
*
)
lfirst
(
arg
);
assert
(
nullptr
!=
argstate
);
std
::
unique_ptr
<
ExprTreeGenerator
>
arg
(
nullptr
);
supported_tree
&=
ExprTreeGenerator
::
VerifyAndCreateExprTree
(
argstate
,
econtext
,
arg
);
if
(
!
supported_tree
)
{
break
;
}
assert
(
nullptr
!=
arg
);
expr_tree_arguments
.
push_back
(
std
::
move
(
arg
));
}
if
(
!
supported_tree
)
{
return
supported_tree
;
}
expr_tree
.
reset
(
new
OpExprTreeGenerator
(
expr_state
,
expr_tree_arguments
));
return
true
;
}
bool
OpExprTreeGenerator
::
GenerateCode
(
CodegenUtils
*
codegen_utils
,
ExprContext
*
econtext
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
llvm
::
Value
*
llvm_isnull_arg
,
llvm
::
Value
*
&
value
)
{
value
=
nullptr
;
OpExpr
*
op_expr
=
(
OpExpr
*
)
expr_state
()
->
expr
;
CodeGenFuncMap
::
iterator
itr
=
supported_function_
.
find
(
op_expr
->
opfuncid
);
if
(
itr
==
supported_function_
.
end
())
{
// Operators are stored in pg_proc table. See postgres.bki for more details.
elog
(
WARNING
,
"Unsupported operator %d."
,
op_expr
->
opfuncid
);
return
false
;
}
if
(
arguments_
.
size
()
!=
itr
->
second
->
GetTotalArgCount
())
{
elog
(
WARNING
,
"Expected argument size to be %d
\n
"
,
itr
->
second
->
GetTotalArgCount
());
return
false
;
}
bool
arg_generated
=
true
;
std
::
vector
<
llvm
::
Value
*>
llvm_arguments
;
for
(
auto
&
arg
:
arguments_
)
{
llvm
::
Value
*
llvm_arg
=
nullptr
;
arg_generated
&=
arg
->
GenerateCode
(
codegen_utils
,
econtext
,
llvm_main_func
,
llvm_error_block
,
llvm_isnull_arg
,
llvm_arg
);
if
(
!
arg_generated
)
{
return
false
;
}
llvm_arguments
.
push_back
(
llvm_arg
);
}
return
itr
->
second
->
GenerateCode
(
codegen_utils
,
llvm_main_func
,
llvm_error_block
,
llvm_arguments
,
value
);
}
src/backend/codegen/tests/codegen_framework_unittest.cc
浏览文件 @
ebd1d014
...
...
@@ -42,6 +42,7 @@
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/Casting.h"
extern
"C"
{
...
...
@@ -62,6 +63,7 @@ namespace gpcodegen {
typedef
int
(
*
SumFunc
)
(
int
x
,
int
y
);
typedef
void
(
*
UncompilableFunc
)(
int
x
);
typedef
int
(
*
MulFunc
)
(
int
x
,
int
y
);
int
SumFuncRegular
(
int
x
,
int
y
)
{
return
x
+
y
;
...
...
@@ -71,9 +73,14 @@ void UncompilableFuncRegular(int x) {
return
;
}
int
MulFuncRegular
(
int
x
,
int
y
)
{
return
x
*
y
;
}
SumFunc
sum_func_ptr
=
nullptr
;
SumFunc
failed_func_ptr
=
nullptr
;
UncompilableFunc
uncompilable_func_ptr
=
nullptr
;
MulFunc
mul_func_ptr
=
nullptr
;
class
SumCodeGenerator
:
public
BaseCodegen
<
SumFunc
>
{
public:
...
...
@@ -105,6 +112,57 @@ class SumCodeGenerator : public BaseCodegen<SumFunc> {
static
constexpr
char
kAddFuncNamePrefix
[]
=
"SumFunc"
;
};
class
MulOverflowCodeGenerator
:
public
BaseCodegen
<
MulFunc
>
{
public:
explicit
MulOverflowCodeGenerator
(
MulFunc
regular_func_ptr
,
MulFunc
*
ptr_to_regular_func_ptr
)
:
BaseCodegen
(
kMulFuncNamePrefix
,
regular_func_ptr
,
ptr_to_regular_func_ptr
)
{
}
virtual
~
MulOverflowCodeGenerator
()
=
default
;
protected:
bool
GenerateCodeInternal
(
gpcodegen
::
CodegenUtils
*
codegen_utils
)
final
{
llvm
::
Function
*
mul2_func
=
CreateFunction
<
MulFunc
>
(
codegen_utils
,
GetUniqueFuncName
());
llvm
::
BasicBlock
*
mul2_body
=
codegen_utils
->
CreateBasicBlock
(
"body"
,
mul2_func
);
llvm
::
BasicBlock
*
result_result_block
=
codegen_utils
->
CreateBasicBlock
(
"return_result"
,
mul2_func
);
llvm
::
BasicBlock
*
return_overflow_block
=
codegen_utils
->
CreateBasicBlock
(
"return_overflow"
,
mul2_func
);
codegen_utils
->
ir_builder
()
->
SetInsertPoint
(
mul2_body
);
llvm
::
Value
*
arg0
=
ArgumentByPosition
(
mul2_func
,
0
);
llvm
::
Value
*
arg1
=
ArgumentByPosition
(
mul2_func
,
1
);
llvm
::
Function
*
llvm_mul_overflow
=
llvm
::
Intrinsic
::
getDeclaration
(
codegen_utils
->
module
(),
llvm
::
Intrinsic
::
smul_with_overflow
,
arg0
->
getType
());
llvm
::
Value
*
llvm_umul_results
=
codegen_utils
->
ir_builder
()
->
CreateCall
(
llvm_mul_overflow
,
{
arg0
,
arg1
});
llvm
::
Value
*
llvm_overflow_flag
=
codegen_utils
->
ir_builder
()
->
CreateExtractValue
(
llvm_umul_results
,
1
);
llvm
::
Value
*
llvm_results
=
codegen_utils
->
ir_builder
()
->
CreateExtractValue
(
llvm_umul_results
,
0
);
codegen_utils
->
ir_builder
()
->
CreateCondBr
(
codegen_utils
->
ir_builder
()
->
CreateICmpSLE
(
llvm_overflow_flag
,
codegen_utils
->
GetConstant
<
bool
>
(
true
)),
return_overflow_block
,
result_result_block
);
codegen_utils
->
ir_builder
()
->
SetInsertPoint
(
return_overflow_block
);
codegen_utils
->
ir_builder
()
->
CreateAdd
(
llvm_results
,
codegen_utils
->
GetConstant
(
1
));
codegen_utils
->
ir_builder
()
->
SetInsertPoint
(
result_result_block
);
codegen_utils
->
ir_builder
()
->
CreateRet
(
llvm_results
);
mul2_func
->
dump
();
return
true
;
}
public:
static
constexpr
char
kMulFuncNamePrefix
[]
=
"MulOverflowFunc"
;
};
class
FailingCodeGenerator
:
public
BaseCodegen
<
SumFunc
>
{
public:
explicit
FailingCodeGenerator
(
SumFunc
regular_func_ptr
,
...
...
@@ -157,6 +215,7 @@ class UncompilableCodeGenerator : public BaseCodegen<UncompilableFunc> {
constexpr
char
SumCodeGenerator
::
kAddFuncNamePrefix
[];
constexpr
char
FailingCodeGenerator
::
kFailingFuncNamePrefix
[];
constexpr
char
MulOverflowCodeGenerator
::
kMulFuncNamePrefix
[];
template
<
bool
GEN_SUCCESS
>
constexpr
char
UncompilableCodeGenerator
<
GEN_SUCCESS
>::
kUncompilableFuncNamePrefix
[];
...
...
@@ -367,6 +426,29 @@ TEST_F(CodegenManagerTest, UnCompilablePassedGenerationTest) {
ASSERT_TRUE
(
UncompilableFuncRegular
==
uncompilable_func_ptr
);
}
TEST_F
(
CodegenManagerTest
,
MulOverFlowTest
)
{
// Test if generation happens successfully
mul_func_ptr
=
nullptr
;
EnrollCodegen
<
MulOverflowCodeGenerator
,
MulFunc
>
(
MulFuncRegular
,
&
mul_func_ptr
);
EXPECT_EQ
(
1
,
manager_
->
GenerateCode
());
ASSERT_TRUE
(
MulFuncRegular
==
mul_func_ptr
);
// This should cause program to exit because of
// broken function
EXPECT_EQ
(
1
,
manager_
->
PrepareGeneratedFunctions
());
EXPECT_EQ
(
6
,
mul_func_ptr
(
2
,
3
));
EXPECT_EQ
(
1
,
mul_func_ptr
(
2147483647
,
3
));
EXPECT_EQ
(
-
6
,
mul_func_ptr
(
-
2
,
3
));
// Reset the manager, so that all the code generators go away
manager_
.
reset
(
nullptr
);
}
TEST_F
(
CodegenManagerTest
,
ResetTest
)
{
sum_func_ptr
=
nullptr
;
SumCodeGenerator
*
code_gen
=
new
SumCodeGenerator
(
SumFuncRegular
,
...
...
src/backend/codegen/utils/codegen_utils.cc
浏览文件 @
ebd1d014
...
...
@@ -358,6 +358,16 @@ llvm::Value* CodegenUtils::GetPointerToMemberImpl(
}
}
llvm
::
Value
*
CodegenUtils
::
CreateArithOp
(
llvm
::
Intrinsic
::
ID
Id
,
llvm
::
ArrayRef
<
llvm
::
Type
*>
Tys
,
llvm
::
Value
*
arg0
,
llvm
::
Value
*
arg1
)
{
llvm
::
Function
*
llvm_intr_func
=
llvm
::
Intrinsic
::
getDeclaration
(
module
(),
Id
,
Tys
);
return
ir_builder
()
->
CreateCall
(
llvm_intr_func
,
{
arg0
,
arg1
});
}
}
// namespace gpcodegen
// EOF
src/backend/codegen/var_expr_tree_generator.cc
0 → 100644
浏览文件 @
ebd1d014
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// base_codegen.h
//
// @doc:
// Base class for expression tree to generate code
//
//---------------------------------------------------------------------------
#include "codegen/expr_tree_generator.h"
#include "codegen/var_expr_tree_generator.h"
#include "llvm/IR/Value.h"
extern
"C"
{
#include "postgres.h"
#include "utils/elog.h"
#include "nodes/execnodes.h"
}
using
gpcodegen
::
VarExprTreeGenerator
;
using
gpcodegen
::
ExprTreeGenerator
;
using
gpcodegen
::
CodegenUtils
;
bool
VarExprTreeGenerator
::
VerifyAndCreateExprTree
(
ExprState
*
expr_state
,
ExprContext
*
econtext
,
std
::
unique_ptr
<
ExprTreeGenerator
>&
expr_tree
)
{
assert
(
nullptr
!=
expr_state
&&
nullptr
!=
expr_state
->
expr
&&
T_Var
==
nodeTag
(
expr_state
->
expr
));
expr_tree
.
reset
(
new
VarExprTreeGenerator
(
expr_state
));
return
true
;
}
VarExprTreeGenerator
::
VarExprTreeGenerator
(
ExprState
*
expr_state
)
:
ExprTreeGenerator
(
expr_state
,
ExprTreeNodeType
::
kVar
)
{
}
bool
VarExprTreeGenerator
::
GenerateCode
(
CodegenUtils
*
codegen_utils
,
ExprContext
*
econtext
,
llvm
::
Function
*
llvm_main_func
,
llvm
::
BasicBlock
*
llvm_error_block
,
llvm
::
Value
*
llvm_isnull_arg
,
llvm
::
Value
*
&
value
)
{
value
=
nullptr
;
Var
*
var_expr
=
(
Var
*
)
expr_state
()
->
expr
;
int
attnum
=
var_expr
->
varattno
;
auto
irb
=
codegen_utils
->
ir_builder
();
// slot = econtext->ecxt_scantuple; {{{
// At code generation time, slot is NULL.
// For that reason, we keep a double pointer to slot and at execution time
// we load slot.
TupleTableSlot
**
ptr_to_slot_ptr
=
NULL
;
switch
(
var_expr
->
varno
)
{
case
INNER
:
/* get the tuple from the inner node */
ptr_to_slot_ptr
=
&
econtext
->
ecxt_innertuple
;
break
;
case
OUTER
:
/* get the tuple from the outer node */
ptr_to_slot_ptr
=
&
econtext
->
ecxt_outertuple
;
break
;
default:
/* get the tuple from the relation being scanned */
ptr_to_slot_ptr
=
&
econtext
->
ecxt_scantuple
;
break
;
}
llvm
::
Value
*
llvm_slot
=
irb
->
CreateLoad
(
codegen_utils
->
GetConstant
(
ptr_to_slot_ptr
));
//}}}
llvm
::
Value
*
llvm_variable_varattno
=
codegen_utils
->
GetConstant
<
int32_t
>
(
attnum
);
// External functions
llvm
::
Function
*
llvm_slot_getattr
=
codegen_utils
->
RegisterExternalFunction
(
slot_getattr
);
// retrieve variable
value
=
irb
->
CreateCall
(
llvm_slot_getattr
,
{
llvm_slot
,
llvm_variable_varattno
,
llvm_isnull_arg
/* TODO: Fix isNull */
});
return
true
;
}
src/backend/utils/misc/guc_gp.c
浏览文件 @
ebd1d014
...
...
@@ -3357,7 +3357,7 @@ struct config_bool ConfigureNamesBool_gp[] =
{
"codegen"
,
PGC_USERSET
,
DEVELOPER_OPTIONS
,
gettext_noop
(
"Perform just-in-time code generation."
),
NULL
,
GUC_NO_SHOW_ALL
|
GUC_NOT_IN_SAMPLE
GUC_NO_SHOW_ALL
|
GUC_NOT_IN_SAMPLE
|
GUC_GPDB_ADDOPT
},
&
codegen
,
false
,
NULL
,
NULL
...
...
src/test/unit/mock/gpcodegen_mock.c
浏览文件 @
ebd1d014
...
...
@@ -77,14 +77,14 @@ ExecVariableListCodegenEnroll(ExecVariableListFn regular_func_ptr,
return
NULL
;
}
// returns the pointer to the ExecQualGenerator
void
*
ExecQualCodegenEnroll
(
ExecQualFn
regular_func_ptr
,
ExecQualFn
*
ptr_to_regular_func_ptr
,
struct
PlanState
*
planstate
)
ExecEvalExprCodegenEnroll
(
ExecEvalExprFn
regular_func_ptr
,
ExecEvalExprFn
*
ptr_to_regular_func_ptr
,
struct
ExprState
*
exprstate
,
struct
ExprContext
*
econtext
)
{
*
ptr_to_regular_func_ptr
=
regular_func_ptr
;
elog
(
ERROR
,
"mock implementation of ExecQual
CodegenEnroll called"
);
return
NULL
;
elog
(
ERROR
,
"mock implementation of ExecEvalExpr
CodegenEnroll called"
);
return
NULL
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录