* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
* Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*
* ---------------------------------------------------------------------------------------
*
* vecexprcodegen.cpp
*
* IDENTIFICATION
* src/gausskernel/runtime/codegen/vecexecutor/vecexprcodegen.cpp
*
* ---------------------------------------------------------------------------------------
*/
#include "codegen/gscodegen.h"
#include "codegen/builtinscodegen.h"
#include "codegen/codegendebuger.h"
#include "codegen/datecodegen.h"
#include "codegen/timestampcodegen.h"
#include "codegen/vecexprcodegen.h"
#include "funcapi.h"
#include "access/htup.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_language.h"
#include "optimizer/planmain.h"
#include "pgxc/pgxc.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "vecexecutor/vecfunc.h"
#include "vecexecutor/vecnodes.h"
#define MAX_ARGS_NUM 3
#define MAX_OID_LENGTH 11
#define ARRAY_LIMIT_SIZE 10
#define STR_PER '%'
#define STR_UNL '_'
#define STR_SLA '\\'
* extern all the functions needed by WarpChooExtFunCodeGen.
*/
extern Datum ExtractVarType(Datum* data);
extern Datum ExtractAddrType(Datum* data);
extern Datum ExtractPlainType(Datum* data);
extern Datum ExtractFixedType(Datum* data);
extern Datum ExtractCstringType(Datum* data);
extern void initVectorFcache(Oid foid, Oid input_collation, FuncExprState* fcache, MemoryContext fcacheCxt);
extern TypeFuncClass get_expr_result_type(Node* expr, Oid* resultTypeId, TupleDesc* resultTupleDesc,
int4* resultTypeId_orig);
namespace dorado {
* Define C Functions : all there functions are used to deal with different
* datum types.
*/
static Datum WrapVecStrictOperFunc(FunctionCallInfo fcinfo, Datum* arg, bool* isNull);
static Datum WrapVecNonStrictOperFunc(FunctionCallInfo fcinfo, Datum* arg, const bool* argnull, bool* isNull);
static Datum WrapDatumCstringToScalar(Datum data);
static Datum WrapDatumFixLenToScalar(Datum data, Size len);
static VectorBatch* WrapGetVectorBatch(ExprContext* econtext);
static MemoryContext WrapMemoryContextSwitchTo(MemoryContext context);
#define DEFINE_FUNCTION_WITH_3_ARGS(jitted_funptr, name, arg1, arg1Type, arg2, arg2Type, arg3, arg3Type) \
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, name, int64Type); \
fn_prototype.addArgument(GsCodeGen::NamedVariable(arg1, arg1Type)); \
fn_prototype.addArgument(GsCodeGen::NamedVariable(arg2, arg2Type)); \
fn_prototype.addArgument(GsCodeGen::NamedVariable(arg3, arg3Type)); \
llvm::Function* jitted_funptr = fn_prototype.generatePrototype(&inner_builder, &llvmargs[0]);
bool VecExprCodeGen::QualJittable(List* qual)
{
ListCell* cell = NULL;
if (!u_sess->attr.attr_sql.enable_codegen || IS_PGXC_COORDINATOR || qual == NULL)
return false;
* Iterate over all the lists, if one of them can not be llvm optimized,
* then, the whole qual can not be llvm optimized.
*/
foreach (cell, qual) {
ExprState* qexpr = (ExprState*)lfirst(cell);
if (!ExprJittable(qexpr))
return false;
}
return true;
}
bool VecExprCodeGen::ExprJittable(ExprState* state)
{
Expr* node = state->expr;
if (!u_sess->attr.attr_sql.enable_codegen || IS_PGXC_COORDINATOR || (node == NULL))
return false;
switch (nodeTag(node)) {
case T_ScalarArrayOpExpr: {
return ScalarArrayJittable(state);
}
case T_CaseExpr: {
return CaseJittable(state);
}
case T_CaseTestExpr: {
* when case_arg is not null, we have CaseTestExpr Node.
* for each case when clause, we only need to eval the second arg.
*/
return true;
}
case T_BoolExpr: {
return BoolJittable(state);
}
case T_BooleanTest: {
return BooleanTestJittable(state);
}
case T_RelabelType: {
return RelabelJittable(state);
}
case T_FuncExpr: {
return FuncJittable(state);
}
case T_OpExpr: {
return OpJittable(state);
}
case T_NullIfExpr: {
return NullIfJittable(state);
}
case T_Var: {
return VarJittable(state);
}
case T_Const: {
return ConstJittable(state);
}
case T_NullTest: {
return NullTestJittable(state);
}
default:
return false;
}
}
bool VecExprCodeGen::ScalarArrayJittable(ExprState* state)
{
ScalarArrayOpExprState* arrayestate = (ScalarArrayOpExprState*)state;
ScalarArrayOpExpr* arrayexpr = (ScalarArrayOpExpr*)state->expr;
if (!arrayexpr->useOr)
return false;
switch (arrayexpr->opno) {
case INT2EQOID:
case INT4EQOID:
case INT8EQOID:
case INT48EQOID:
case INT84EQOID:
case TEXTEQOID:
case BPCHAREQOID:
case DATEEQOID:
case FLOAT4EQOID:
case FLOAT8EQOID:
case TIMESTAMPEQOID:
case TIMETZEQOID:
case INTERVALEQOID:
break;
default:
return false;
}
* Make sure the left operand and the right operand
* support codegen, or return false.
*/
List* args = arrayestate->fxprstate.args;
ExprState* lestate = (ExprState*)linitial(args);
if (!ExprJittable(lestate))
return false;
ExprState* restate = (ExprState*)lsecond(args);
if (!IsA(restate->expr, Const))
return false;
Const* cst = (Const*)restate->expr;
if (cst->constisnull)
return false;
* Avoid codegeneration when const lists is too long, since
* it may take a long time to compile it.
*/
if (BPCHAREQOID == arrayexpr->opno || TEXTEQOID == arrayexpr->opno) {
ArrayType* arrtyp = DatumGetArrayTypeP(cst->constvalue);
int nitems = ArrayGetNItems(ARR_NDIM(arrtyp), ARR_DIMS(arrtyp));
if (nitems > ARRAY_LIMIT_SIZE)
return false;
}
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::ScalarArrayCodeGen;
return true;
}
bool VecExprCodeGen::BooleanTestJittable(ExprState* state)
{
GenericExprState* bstate = (GenericExprState*)state;
ExprState* arg = bstate->arg;
if (!ExprJittable(arg))
return false;
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::BooleanTestCodeGen;
return true;
}
bool VecExprCodeGen::NullTestJittable(ExprState* state)
{
NullTestState* nullteststate = (NullTestState*)state;
NullTest* ntexpr = (NullTest*)state->expr;
ExprState* arg = nullteststate->arg;
if (!ExprJittable(arg))
return false;
if (ntexpr->nulltesttype != IS_NULL && ntexpr->nulltesttype != IS_NOT_NULL) {
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmodule(MOD_LLVM),
errmsg("unrecognized nulltesttype: %d", (int)ntexpr->nulltesttype)));
return false;
}
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::NullTestCodeGen;
return true;
}
bool VecExprCodeGen::CaseJittable(ExprState* state)
{
CaseExprState* casestate = (CaseExprState*)state;
CaseExpr* caseexpr = (CaseExpr*)state->expr;
ListCell* cell = NULL;
switch (caseexpr->casetype) {
case BOOLOID:
case INT1OID:
case INT4OID:
case INT8OID:
case FLOAT4OID:
case FLOAT8OID:
case TEXTOID:
case NUMERICOID:
case BPCHAROID:
case VARCHAROID:
case DATEOID:
case TIMEOID:
case TIMESTAMPOID:
case TIMESTAMPTZOID:
case INTERVALOID:
case OIDOID:
break;
default:
return false;
}
if (casestate->arg != NULL) {
if (!ExprJittable(casestate->arg))
return false;
}
foreach (cell, casestate->args) {
CaseWhenState* wclause = (CaseWhenState*)lfirst(cell);
if (!ExprJittable(wclause->expr) || !ExprJittable(wclause->result))
return false;
}
ExprState* case_default = casestate->defresult;
if (case_default != NULL) {
if (!ExprJittable(case_default))
return false;
}
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::CaseCodeGen;
return true;
}
bool VecExprCodeGen::NullIfJittable(ExprState* state)
{
NullIfExpr* opexpr = (NullIfExpr*)state->expr;
FuncExprState* fstate = (FuncExprState*)state;
List* args = fstate->args;
ExprState* lestate = NULL;
ExprState* restate = NULL;
if (fstate->func.fn_oid != InvalidOid)
return false;
switch (opexpr->opresulttype) {
case BOOLOID:
case INT1OID:
case INT2OID:
case INT4OID:
case INT8OID:
case FLOAT4OID:
case FLOAT8OID:
case NUMERICOID:
case DATEOID:
case TIMEOID:
case TIMETZOID:
case TIMESTAMPOID:
case TIMESTAMPTZOID:
case INTERVALOID:
case BPCHAROID:
case VARCHAROID:
case TEXTOID:
case OIDOID:
break;
default:
return false;
}
if (list_length(args) != 2)
return false;
lestate = (ExprState*)linitial(args);
restate = (ExprState*)lsecond(args);
if (!ExprJittable(lestate) || !ExprJittable(restate))
return false;
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::NullIfCodeGen;
return true;
}
bool VecExprCodeGen::BoolJittable(ExprState* state)
{
BoolExprState* bstate = (BoolExprState*)state;
BoolExpr* bexpr = (BoolExpr*)state->expr;
List* boolargs = bstate->args;
ListCell* cell = NULL;
* And/Or/Not Exprs are belong to Bool Expr. While we make a differentce
* between And/Or and Not Expr.
*/
switch (bexpr->boolop) {
case AND_EXPR:
case OR_EXPR: {
foreach (cell, boolargs) {
ExprState* cstate = (ExprState*)lfirst(cell);
if (!ExprJittable(cstate))
return false;
}
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::AndOrLogicCodeGen;
} break;
case NOT_EXPR: {
ExprState* nexpr = (ExprState*)linitial(boolargs);
if (!ExprJittable(nexpr))
return false;
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::NotCodeGen;
} break;
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmodule(MOD_LLVM),
errmsg("unrecognized boolop: %d", (int)bexpr->boolop)));
break;
}
return true;
}
bool VecExprCodeGen::RelabelJittable(ExprState* state)
{
* Only support the cast from varchar to text
*/
GenericExprState* gstate = (GenericExprState*)state;
RelabelType* RT = (RelabelType*)state->expr;
if (IsA(gstate->arg->expr, Var)) {
Var* var = (Var*)gstate->arg->expr;
if (var->vartype != VARCHAROID || RT->resulttype != TEXTOID)
return false;
ExprState* varg = (ExprState*)(gstate->arg);
varg->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::VarCodeGen;
} else if (IsA(gstate->arg->expr, CaseTestExpr)) {
* When exist CaseTestExpr, we only need to get the second argument
* (Const). Usualy, we have the Relabel Node for string type Const
* Node.
*/
CaseTestExpr* ctexpr = (CaseTestExpr*)gstate->arg->expr;
if (ctexpr->typeId != TEXTOID && ctexpr->typeId != VARCHAROID)
return false;
} else
return false;
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::RelabelCodeGen;
return true;
}
bool VecExprCodeGen::FuncJittable(ExprState* state)
{
FuncExprState* fstate = (FuncExprState*)state;
FuncExpr* funcexpr = (FuncExpr*)state->expr;
const FmgrBuiltin* fbp = NULL;
bool isnull = false;
if (funcexpr->funcretset)
return false;
* Return false if function takes no args
* Handle function like random().
*/
if (!fstate->args)
return false;
int num_args = fstate->args->length;
if (num_args > 3)
return false;
Oid funcid = funcexpr->funcid;
* Without doing codegeneration when UDF is defined in fencedMode.
*/
if ((fbp = fmgr_isbuiltin(funcid)) == NULL) {
HeapTuple procedureTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(procedureTuple))
ereport(ERROR,
(errcode(ERRCODE_CACHE_LOOKUP_FAILED),
errmodule(MOD_LLVM),
errmsg("cache lookup failed for function %u", funcid)));
Datum procFenced = SysCacheGetAttr(PROCOID, procedureTuple, Anum_pg_proc_fenced, &isnull);
bool fencedMode = DatumGetBool(procFenced) && !isnull;
if (fencedMode)
return false;
ReleaseSysCache(procedureTuple);
}
switch (funcid) {
case SUBSTRFUNCOID: {
int current_encoding = GetDatabaseEncoding();
if (current_encoding != PG_SQL_ASCII && current_encoding != PG_UTF8)
return false;
List* func_args = fstate->args;
ExprState* astate1 = (ExprState*)linitial(func_args);
ExprState* astate2 = (ExprState*)lsecond(func_args);
ExprState* astate3 = (ExprState*)lthird(func_args);
if (IsA(astate1->expr, FuncExpr) || IsA(astate1->expr, RelabelType) || IsA(astate1->expr, Var)) {
if (!ExprJittable(astate1))
return false;
} else
return false;
if (!IsA(astate2->expr, Const) || !IsA(astate3->expr, Const))
return false;
else {
* For lpad, if the length is less than zero, no need to do codegen,
* and for substr, if either start position or length is less than zero, no need to do codegen
*/
Const* cst2 = (Const*)astate2->expr;
Const* cst3 = (Const*)astate3->expr;
if (cst2 != NULL) {
int cst_val2 = DatumGetInt32(cst2->constvalue);
if (cst_val2 < 0)
return false;
}
if (cst3 != NULL && funcexpr->funcid == SUBSTRFUNCOID) {
int cst_val3 = DatumGetInt32(cst3->constvalue);
if (cst_val3 < 0)
return false;
}
astate2->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::ConstCodeGen;
astate3->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::ConstCodeGen;
}
} break;
* For btrim1/rtrim1, only consider one argument with set fixed as ' '
*/
case RTRIMPARAFUNCOID:
case RTRIM1FUNCOID:
case BTRIMFUNCOID:
case BPLENFUNCOID: {
int current_encoding = GetDatabaseEncoding();
if (current_encoding != PG_SQL_ASCII && current_encoding != PG_UTF8)
return false;
List* args = fstate->args;
ExprState* istate = (ExprState*)linitial(args);
if (!ExprJittable(istate))
return false;
} break;
default: {
* Call original C-Function without codegen
*/
List* func_args = fstate->args;
ListCell* func_cell = NULL;
ExprState* estate_arg = NULL;
foreach (func_cell, func_args) {
estate_arg = (ExprState*)lfirst(func_cell);
if (!ExprJittable(estate_arg))
return false;
}
} break;
}
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::FuncCodeGen;
return true;
}
bool VecExprCodeGen::NumericOpFastJittable(ExprState* state)
{
OpExpr* opexpr = (OpExpr*)state->expr;
FuncExprState* fstate = (FuncExprState*)state;
List* args = fstate->args;
ExprState* lestate = NULL;
ExprState* restate = NULL;
Const* cst = NULL;
switch (opexpr->opno) {
case NUMERICEQOID:
case NUMERICNEOID:
case NUMERICLTOID:
case NUMERICLEOID:
case NUMERICGTOID:
case NUMERICGEOID:
break;
default:
return false;
}
lestate = (ExprState*)linitial(args);
restate = (ExprState*)lsecond(args);
if (!((IsA(lestate->expr, Var) && IsA(restate->expr, Const)) ||
(IsA(lestate->expr, Const) && IsA(restate->expr, Var))))
return false;
if (IsA(lestate->expr, Var)) {
Var* var = (Var*)(lestate->expr);
bool isNumericOid = (var->vartype != NUMERICOID || var->vartypmod == -1);
if (isNumericOid)
return false;
int prec = (var->vartypmod >> 16) & 0xFFFF;
if (prec > 18)
return false;
cst = (Const*)(restate->expr);
if (cst->consttype != NUMERICOID || cst->constisnull)
return false;
ScalarValue val = ScalarVector::DatumToScalar(cst->constvalue, cst->consttype, cst->constisnull);
if ((((NumericData*)val)->choice.n_header & NUMERIC_BI_MASK) != NUMERIC_64)
return false;
}
if (IsA(lestate->expr, Const)) {
Var* var = (Var*)(restate->expr);
if (var->vartype != NUMERICOID || var->vartypmod == -1)
return false;
int prec = (var->vartypmod >> 16) & 0xFFFF;
if (prec > 18)
return false;
cst = (Const*)(lestate->expr);
if (cst->consttype != NUMERICOID || cst->constisnull)
return false;
ScalarValue val = ScalarVector::DatumToScalar(cst->constvalue, cst->consttype, cst->constisnull);
if ((((NumericData*)val)->choice.n_header & NUMERIC_BI_MASK) != NUMERIC_64)
return false;
}
return true;
}
bool VecExprCodeGen::OpJittable(ExprState* state)
{
OpExpr* opexpr = (OpExpr*)state->expr;
FuncExprState* fstate = (FuncExprState*)state;
List* args = fstate->args;
ExprState* lestate = NULL;
ExprState* restate = NULL;
switch (opexpr->opresulttype) {
case INT1OID:
case INT2OID:
case INT4OID:
case INT8OID:
case FLOAT4OID:
case FLOAT8OID:
case BOOLOID:
case DATEOID:
case TIMEOID:
case TIMETZOID:
case TIMESTAMPOID:
case TIMESTAMPTZOID:
case NUMERICOID:
case INTERVALOID:
case BPCHAROID:
case VARCHAROID:
case TEXTOID:
case OIDOID:
break;
default:
return false;
}
if (list_length(args) != 2)
return false;
lestate = (ExprState*)linitial(args);
restate = (ExprState*)lsecond(args);
if (!ExprJittable(lestate) || !ExprJittable(restate))
return false;
switch (opexpr->opno) {
case TEXTEQOID:
case TEXTNEOID:
case TEXTLEOID:
case TEXTGEOID:
case TEXTLTOID:
case TEXTGTOID: {
if (DB_IS_CMPT(A_FORMAT) && CHAR_COERCE_COMPAT) {
return false;
}
int current_encoding = GetDatabaseEncoding();
if (current_encoding != PG_SQL_ASCII && current_encoding != PG_UTF8)
return false;
if (!IsA(restate->expr, Const))
return false;
Const* cst = (Const*)restate->expr;
if (cst != NULL) {
text* cst_val = (text*)(cst->constvalue);
char* data = VARDATA_ANY(cst_val);
int len = VARSIZE_ANY_EXHDR(cst_val);
for (int i = 0; i < len; i++) {
if (data[i] < '0' || data[i] > '9')
return false;
}
} else {
ereport(ERROR,
(errcode(ERRCODE_UNEXPECTED_NULL_VALUE),
errmodule(MOD_LLVM),
errmsg("Failed to get the const node of the operation!\n")));
}
} break;
case OID_TEXT_LIKE_OP: {
int current_encoding = GetDatabaseEncoding();
if (current_encoding != PG_SQL_ASCII && current_encoding != PG_UTF8)
return false;
if (!IsA(restate->expr, Const))
return false;
* we only consider pattern string like 'pattern%' or '%pattern',
* or 'pattarn' and there is no wild char in 'pattern'.
*/
Const* cst = (Const*)restate->expr;
text* cst_val = (text*)(cst->constvalue);
char* data = VARDATA_ANY(cst_val);
int len = VARSIZE_ANY_EXHDR(cst_val);
if (len <= 1)
return false;
if (data[0] == STR_PER) {
* check whether there is a wild char '%', '\\', or ' ' in
* 'pattern' part in case of '%pattern' */
for (int i = 1; i < len; i++) {
if (data[i] == STR_UNL || data[i] == STR_PER || data[i] == STR_SLA)
return false;
}
} else if (data[len - 1] == STR_PER) {
for (int i = 0; i < len - 1; i++) {
if (data[i] == STR_UNL || data[i] == STR_PER || data[i] == STR_SLA)
return false;
}
} else {
for (int i = 0; i < len; i++) {
if (data[i] == STR_UNL || data[i] == STR_PER || data[i] == STR_SLA)
return false;
}
}
} break;
case TEXTNOTLIKEOID: {
int current_encoding = GetDatabaseEncoding();
if (current_encoding != PG_SQL_ASCII && current_encoding != PG_UTF8)
return false;
if (!IsA(restate->expr, Const))
return false;
* we only consider pattern string contain special character '%', without
* considering '_' and '\\' .
*/
Const* cst = (Const*)restate->expr;
text* cst_val = (text*)(cst->constvalue);
char* data = VARDATA_ANY(cst_val);
int len = VARSIZE_ANY_EXHDR(cst_val);
if (len <= 1)
return false;
for (int i = 0; i < len; i++) {
if (data[i] == STR_UNL || data[i] == STR_SLA)
return false;
}
} break;
case TIMESTAMPEQOID:
case TIMESTAMPNEOID:
case TIMESTAMPLTOID:
case TIMESTAMPLEOID:
case TIMESTAMPGTOID:
case TIMESTAMPGEOID: {
#ifdef HAVE_INT64_TIMESTAMP
#else
return false;
#endif
} break;
default:
break;
}
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::OpCodeGen;
return true;
}
bool VecExprCodeGen::VarJittable(ExprState* state)
{
Var* var = (Var*)state->expr;
if (var->varattno < 0)
return false;
switch (var->vartype) {
case BOOLOID:
case INT1OID:
case INT2OID:
case INT4OID:
case INT8OID:
case FLOAT4OID:
case FLOAT8OID:
case NUMERICOID:
case DATEOID:
case TIMEOID:
case TIMETZOID:
case TIMESTAMPOID:
case TIMESTAMPTZOID:
case INTERVALOID:
case BPCHAROID:
case VARCHAROID:
case TEXTOID:
case OIDOID:
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::VarCodeGen;
return true;
default:
return false;
}
}
bool VecExprCodeGen::ConstJittable(ExprState* state)
{
Const* con = (Const*)state->expr;
switch (con->consttype) {
case BOOLOID:
case INT1OID:
case INT2OID:
case INT4OID:
case INT8OID:
case FLOAT4OID:
case FLOAT8OID:
case NUMERICOID:
case DATEOID:
case TIMEOID:
case TIMETZOID:
case TIMESTAMPOID:
case TIMESTAMPTZOID:
case INTERVALOID:
case BPCHAROID:
case VARCHAROID:
case TEXTOID:
case OIDOID:
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::ConstCodeGen;
return true;
default:
return false;
}
}
bool VecExprCodeGen::TargetListJittable(List* targetlist)
{
ListCell* cell = NULL;
if (!u_sess->attr.attr_sql.enable_codegen || IS_PGXC_COORDINATOR || targetlist == NULL)
return false;
* Iterator over all the targetlists, if one of them can not be llvm
* optimized, the whole qual can not be llvm optimized.
*/
foreach (cell, targetlist) {
GenericExprState* gstate = (GenericExprState*)lfirst(cell);
ExprState* tstate = gstate->arg;
if (!ExprJittable(tstate))
return false;
}
return true;
}
* To fully use the 'data centric' thought, we exchange the position of qual
* and batch, which means we use the following
* for(i = 0; i < batch->m_rows; i++){
* foreach(cell, qual){
* expr = lfirst(cell)
* ExecEvalQual(expr, batch->m_arr[attno]->m_vals[i])
* }
* }
* instead of
* foreach(cell, qual){
* expr = lfirst(cell)
* for(i = 0; i < batch->m_rows; i++){
* ExecEvalQual(expr, batch->m_arr[attno]->m_vals[i])
* }
* }
*
* We show here an example to interpret the generated IR function with the following
* IR API Builder Code. If we have the query:
* select * from test where where (a + 1) * 2 > 4;
* then we arrived at the following IR function:
*
* define %class.ScalarVector* @JittedVecQual(%struct.ExprContext* %econtext) {
* entry:
* %0 = alloca i8
* %1 = getelementptr inbounds %struct.ExprContext* %econtext, i64 0, i32 17
* %scanbatch = load %class.VectorBatch** %1, align 8
* %2 = getelementptr inbounds %class.VectorBatch* %scanbatch, i64 0, i32 3
* %m_sel = load i8** %2, align 8
* call void @llvm.memset.p0i8.i64(i8* %m_sel, i8 0, i64 1000, i32 1, i1 false)
* %3 = getelementptr inbounds %class.VectorBatch* %scanbatch, i64 0, i32 0
* %m_rows = load i32* %3, align 4
* %4 = icmp sgt i32 %m_rows, 0
* br i1 %4, label %for_body, label %ret_bb
*
* for_body: ; preds = %bb_end, %entry
* %5 = phi i64 [ 0, %entry ], [ %7, %bb_end ]
* %6 = phi i1 [ false, %entry ], [ %11, %bb_end ]
* %7 = add i64 %5, 1
* %EvalVecOp = call i64 @JittedVecOper(%struct.ExprContext* %econtext, i8* %0, i64 %5)
* %8 = trunc i64 %EvalVecOp to i1
* br label %bb_end
*
* bb_end: ; preds = %for_body
* %9 = getelementptr inbounds i8* %m_sel, i64 %5
* %10 = zext i1 %8 to i8
* store i8 %10, i8* %9, align 1
* %11 = or i1 %8, %6
* %12 = trunc i64 %7 to i32
* %13 = icmp eq i32 %12, %m_rows
* br i1 %13, label %for_end, label %for_body
*
* for_end: ; preds = %bb_end
* %14 = icmp eq i1 %11, false
* br i1 %14, label %ret_bb, label %for2_begin
*
* for2_begin: ; preds = %for_end
* %15 = icmp slt i64 %7, 1000
* br i1 %15, label %for2_body, label %ret_bb
*
* for2_body: ; preds = %for2_body, %for2_begin
* %16 = phi i64 [ %7, %for2_begin ], [ %17, %for2_body ]
* %17 = add i64 %16, 1
* %18 = getelementptr inbounds i8* %m_sel, i64 %16
* store i8 0, i8* %18, align 1
* %19 = icmp eq i64 %17, 1000
* br i1 %19, label %ret_bb, label %for2_body
*
* ret_bb: ; preds = %for2_body, %for2_begin, %for_end, %entry
* %20 = phi i64 [ 0, %entry ], [ 0, %for_end ], [ 1, %for2_begin ], [ 1, %for2_body ]
* %21 = inttoptr i64 %20 to %class.ScalarVector*
* ret %class.ScalarVector* %21
* }
*/
llvm::Function* VecExprCodeGen::QualCodeGen(List* qual, PlanState* parent, bool isReset)
{
Assert(NULL != (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj);
dorado::GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
if (!QualJittable(qual))
return NULL;
llvmCodeGen->loadIRFile();
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
DEFINE_CG_TYPE(int1Type, BITOID);
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int32Type, INT4OID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(scalarVectorPtrType, "class.ScalarVector");
DEFINE_CGVAR_INT1(int1_0, 0);
DEFINE_CGVAR_INT8(int8_0, 0);
DEFINE_CGVAR_INT8(int8_1, 1);
DEFINE_CGVAR_INT32(int32_0, 0);
DEFINE_CGVAR_INT32(m_seloffset, 3);
DEFINE_CGVAR_INT32(ecxt_scanbatch_offset, 17);
DEFINE_CGVAR_INT32(ecxt_tupmem_offset, 5);
DEFINE_CGVAR_INT64(Datum_0, 0);
DEFINE_CGVAR_INT64(Datum_1, 1);
DEFINE_CGVAR_INT64(m_BatchMaxSize, BatchMaxSize);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
DEFINE_CG_PTRTYPE(VecBatchPtrType, "class.VectorBatch");
DEFINE_CG_PTRTYPE(MemContextPtrType, "struct.MemoryContextData");
llvm::BasicBlock* bb_next = NULL;
llvm::BasicBlock** bb_list = NULL;
llvm::PHINode* Phi_idx = NULL;
llvm::PHINode* Phi_idx2 = NULL;
llvm::PHINode* Phi_res = NULL;
llvm::PHINode* Phi_ret = NULL;
llvm::Value* idx_next = NULL;
llvm::Value* idx_next2 = NULL;
llvm::Value* nValues = NULL;
llvm::Value* econtext = NULL;
llvm::Value* pSelection = NULL;
llvm::Value* Val = NULL;
llvm::Value* pVal = NULL;
llvm::Value* ecxt_batch = NULL;
llvm::Value* Vals[] = {Datum_0, int32_0};
llvm::Value* isNull = NULL;
llvm::Value* result = NULL;
llvm::Value* cg_oldContext = NULL;
llvm::Value* curr_Context = NULL;
llvm::Value* llvmargs[3];
llvm::Function* jitted_vecqual = NULL;
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "JittedVecQual", scalarVectorPtrType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("econtext", ExprContextPtrType));
jitted_vecqual = fn_prototype.generatePrototype(&builder, &llvmargs[0]);
econtext = llvmargs[0];
* To avoid load values from memory continually, we keep tuple in memory
* as loog as possible. So the ourter loop is designed for each tuple, the
* inner loop is designed for each qual. First codegen the loop for
* for(i = 0; i < nValus, i++)
*/
llvm::BasicBlock* entry = &jitted_vecqual->getEntryBlock();
DEFINE_BLOCK(for_body, jitted_vecqual);
DEFINE_BLOCK(bb_end, jitted_vecqual);
DEFINE_BLOCK(for_end, jitted_vecqual);
DEFINE_BLOCK(for2_begin, jitted_vecqual);
DEFINE_BLOCK(for2_body, jitted_vecqual);
DEFINE_BLOCK(ret_bb, jitted_vecqual);
builder.SetInsertPoint(entry);
isNull = builder.CreateAlloca(int8Type);
* Run in short-lived per-tuple context while computing expressions
* First get the ecxt_per_tuple_memory, since we need to switch to this
* memory context.
*/
Vals[0] = Datum_0;
Vals[1] = ecxt_tupmem_offset;
curr_Context = builder.CreateInBoundsGEP(econtext, Vals);
curr_Context = builder.CreateLoad(MemContextPtrType, curr_Context, "per_tuple_memory");
cg_oldContext = MemCxtSwitToCodeGen(&builder, curr_Context);
* Start code generation on the entry of basic block.
* With CreateLoad we could get the element of the structure
* according to the offset.
*/
Vals[1] = ecxt_scanbatch_offset;
ecxt_batch = builder.CreateInBoundsGEP(econtext, Vals);
ecxt_batch = builder.CreateLoad(VecBatchPtrType, ecxt_batch, "scanbatch");
Vals[1] = m_seloffset;
pSelection = builder.CreateInBoundsGEP(ecxt_batch, Vals);
pSelection = builder.CreateLoad(int8PtrType, pSelection, "m_sel");
* Reset selection vector to be fully loaded
* Corresponding to 'econtext->ecxt_scanbatch->ResetSelection (true)'
*/
if (isReset) {
(void)builder.CreateMemSet(pSelection, int8_1, BatchMaxSize, (llvm::MaybeAlign)1);
}
Vals[1] = int32_0;
Val = builder.CreateInBoundsGEP(ecxt_batch, Vals);
nValues = builder.CreateLoad(int32Type, Val, "m_rows");
Val = builder.CreateICmpSGT(nValues, int32_0);
builder.CreateCondBr(Val, for_body, ret_bb);
builder.SetInsertPoint(for_body);
Phi_idx = builder.CreatePHI(int64Type, 2);
Phi_res = builder.CreatePHI(int1Type, 2);
idx_next = builder.CreateAdd(Phi_idx, Datum_1);
Phi_idx->addIncoming(Datum_0, entry);
Phi_idx->addIncoming(idx_next, bb_end);
Phi_res->addIncoming(int1_0, entry);
* For each time, we deal with one tuple. Phi_idx should be passed as
* 'loop index' in 'for' structure, these arguments will be used in
* function llvmCodeGenExpr. Each tuple passes through the whole quallist.
*/
llvmargs[1] = isNull;
llvmargs[2] = (llvm::Value*)Phi_idx;
int qual_len = list_length(qual);
int qual_index = 0;
int i;
ListCell* cell = NULL;
ExprState* node = NULL;
if (qual_len > 1) {
bb_list = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * qual_len);
bb_list[0] = for_body;
}
ExprCodeGenArgs args;
args.parent = parent;
args.builder = &builder;
args.llvm_args = &llvmargs[0];
foreach (cell, qual) {
node = (ExprState*)lfirst(cell);
* code generation the evaluation of each qual expression,
* one item at a time, which corresponds to
* qual_result = VectorExprEngine(clause, econtext,
* econtext->ecxt_scanbatch->m_sel, pVector);
*/
args.exprstate = node;
result = CodeGen(&args);
if (result == NULL) {
jitted_vecqual->eraseFromParent();
ereport(ERROR,
(errcode(ERRCODE_CODEGEN_ERROR),
errmodule(MOD_LLVM),
errmsg("Codegen failed on the procedure of ExecVecQual!")));
}
result = builder.CreateTrunc(result, int1Type);
* Since in LLVM we deal with one block at a time, we should check
* if there exists more predicates.
*/
if (cell->next == NULL) {
builder.CreateBr(bb_end);
} else {
bb_next = llvm::BasicBlock::Create(context, "bb", jitted_vecqual);
builder.CreateCondBr(result, bb_next, bb_end);
builder.SetInsertPoint(bb_next);
bb_list[++qual_index] = bb_next;
}
}
builder.SetInsertPoint(bb_end);
if (qual_len > 1) {
llvm::PHINode* Phi = builder.CreatePHI(int1Type, qual_len);
for (i = 0; i < qual_len - 1; i++)
Phi->addIncoming(int1_0, bb_list[i]);
Phi->addIncoming(result, bb_list[qual_len - 1]);
result = (llvm::Value*)Phi;
}
pVal = builder.CreateInBoundsGEP(pSelection, Phi_idx);
llvm::Value* res_i8 = builder.CreateZExt(result, int8Type);
builder.CreateStore(res_i8, pVal);
llvm::Value* bool_res = builder.CreateOr(result, Phi_res);
llvm::Value* v1 = builder.CreateTrunc(idx_next, int32Type);
v1 = builder.CreateICmpEQ(v1, nValues);
builder.CreateCondBr(v1, for_end, for_body);
Phi_res->addIncoming(bool_res, bb_end);
* when codegen is done for the loop, Codegen the following code:
*/
builder.SetInsertPoint(for_end);
Val = builder.CreateICmpEQ(bool_res, int1_0);
builder.CreateCondBr(Val, ret_bb, for2_begin);
builder.SetInsertPoint(for2_begin);
Val = builder.CreateICmpSLT(idx_next, m_BatchMaxSize);
builder.CreateCondBr(Val, for2_body, ret_bb);
builder.SetInsertPoint(for2_body);
Phi_idx2 = builder.CreatePHI(int64Type, 2);
idx_next2 = builder.CreateAdd(Phi_idx2, Datum_1);
Phi_idx2->addIncoming(idx_next, for2_begin);
Phi_idx2->addIncoming(idx_next2, for2_body);
pVal = builder.CreateInBoundsGEP(pSelection, Phi_idx2);
builder.CreateStore(int8_0, pVal);
v1 = builder.CreateICmpEQ(idx_next2, m_BatchMaxSize);
builder.CreateCondBr(v1, ret_bb, for2_body);
* for(i = 0; i < nValues; i++){ foreach(cell, qual){...} }
* return NULL or return econtext->qual_results
*/
builder.SetInsertPoint(ret_bb);
Phi_ret = builder.CreatePHI(int64Type, 4);
Phi_ret->addIncoming(Datum_0, entry);
Phi_ret->addIncoming(Datum_0, for_end);
Phi_ret->addIncoming(Datum_1, for2_begin);
Phi_ret->addIncoming(Datum_1, for2_body);
* Phi_ret has the type int64, need to convert it to a pointer type and
* return back to the old memory context.
*/
llvm::Value* ret_val = builder.CreateIntToPtr(Phi_ret, scalarVectorPtrType);
(void)MemCxtSwitToCodeGen(&builder, cg_oldContext);
builder.CreateRet(ret_val);
if (qual_len > 1)
pfree_ext(bb_list);
int plan_node_id = parent->plan->plan_node_id;
llvmCodeGen->FinalizeFunction(jitted_vecqual, plan_node_id);
llvmCodeGen->dumpCFunctionCalls("Filter", plan_node_id);
* If coden_strategy is CODEGEN_PURE and having C-function call in codegen,
* we need to discard the generated IR function.
*/
if (llvmCodeGen->hasCFunctionCalls()) {
llvmCodeGen->clearCFunctionCalls();
if (u_sess->attr.attr_sql.codegen_strategy == CODEGEN_PURE)
return NULL;
}
return jitted_vecqual;
}
llvm::Value* VecExprCodeGen::ScalarArrayCodeGen(ExprCodeGenArgs* args)
{
dorado::GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder* outer_builder = args->builder;
GsCodeGen::LlvmBuilder inner_builder(context);
DEFINE_CG_TYPE(int1Type, BITOID);
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int16Type, INT2OID);
DEFINE_CG_TYPE(int32Type, INT4OID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
DEFINE_CGVAR_INT8(null_true, 1);
DEFINE_CGVAR_INT64(Datum_0, 0);
DEFINE_CGVAR_INT64(Datum_1, 1);
ScalarArrayOpExprState* arrayexprstate = (ScalarArrayOpExprState*)args->exprstate;
ScalarArrayOpExpr* arrayexpr = (ScalarArrayOpExpr*)args->exprstate->expr;
List* arr_args = arrayexprstate->fxprstate.args;
ExprState* cststate = (ExprState*)lsecond(arr_args);
Const* cst = (Const*)cststate->expr;
ArrayType* arr = DatumGetArrayTypeP(cst->constvalue);
llvm::Value* isNull = NULL;
llvm::Value* result = NULL;
llvm::Value* lhs_value = NULL;
llvm::Value* llvmargs[3];
llvm::Value* cmp = NULL;
llvm::Value* tmpNull = NULL;
DEFINE_FUNCTION_WITH_3_ARGS(jitted_arrayop,
"JittedVecScalarArrayOp",
"econtext",
ExprContextPtrType,
"isNull",
int8PtrType,
"loop_index",
int64Type);
isNull = llvmargs[1];
llvm::BasicBlock* entry = &jitted_arrayop->getEntryBlock();
DEFINE_BLOCK(if_then, jitted_arrayop);
DEFINE_BLOCK(if_else, jitted_arrayop);
DEFINE_BLOCK(ret_bb, jitted_arrayop);
llvm::BasicBlock* current_bb = NULL;
llvm::BasicBlock* next_bb = NULL;
inner_builder.SetInsertPoint(entry);
ExprCodeGenArgs largs;
ExprState* leftstate = (ExprState*)linitial(arr_args);
largs = *args;
largs.exprstate = leftstate;
largs.builder = &inner_builder;
largs.llvm_args = &llvmargs[0];
lhs_value = CodeGen(&largs);
tmpNull = inner_builder.CreateLoad(int8Type, isNull, "tmpNull");
cmp = inner_builder.CreateICmpEQ(tmpNull, null_true);
inner_builder.CreateCondBr(cmp, if_then, if_else);
inner_builder.SetInsertPoint(if_then);
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(if_else);
* Since everything is already 'known' here, we could decode the data from
* the Const node without checking vecfunexpr:
* look over the arryelements, and get each arry element.
*/
int16 typlen;
bool typbyval = false;
char typalign;
bits8* bitmap = NULL;
uint32 bitmask;
int i = 0;
int j = 0;
get_typlenbyvalalign(ARR_ELEMTYPE(arr), &typlen, &typbyval, &typalign);
int nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
char* s = (char*)ARR_DATA_PTR(arr);
bitmap = ARR_NULLBITMAP(arr);
bitmask = 1;
Datum* Args = (Datum*)palloc(sizeof(Datum) * nitems);
bool* elemNull = (bool*)palloc(sizeof(bool) * nitems);
bool resultNull = false;
for (i = 0; i < nitems; i++) {
if (bitmap && (*bitmap & bitmask) == 0) {
elemNull[i] = true;
Args[i] = (Datum)0;
resultNull = true;
} else {
elemNull[i] = false;
Datum elt = fetch_att(s, typbyval, typlen);
Args[i] = ScalarVector::DatumToScalar(elt, ARR_ELEMTYPE(arr), false);
s = att_addlength_pointer(s, typlen, s);
s = (char*)att_align_nominal(s, typalign);
}
if (bitmap != NULL) {
bitmask <<= 1;
if (bitmask == 0x100) {
bitmap++;
bitmask = 1;
}
}
}
*/
for (i = 0; i < nitems; i++) {
if (elemNull[i]) {
for (j = i; j < nitems - 1; j++) {
Args[j] = Args[j + 1];
elemNull[j] = elemNull[j + 1];
}
i--;
nitems--;
}
}
* remove duplicate constants in 'switch instruction(with the definition
* in LLVM)'
*/
for (i = 0; i < nitems; i++) {
for (j = i + 1; j < nitems; j++) {
if (Args[i] == Args[j]) {
if (j == nitems - 1) {
nitems--;
break;
}
Args[j] = Args[nitems - 1];
j--;
nitems--;
}
}
}
* Do code generation according to data type
*/
if (nitems > 0) {
* When the number of items is large than zero, we should compare
* the elements one by one.
*/
DEFINE_BLOCK(in_bb, jitted_arrayop);
DEFINE_BLOCK(default_bb, jitted_arrayop);
switch (arrayexpr->opno) {
* For varchar, text and bpchar type, we should deal with elements
* one by one, and each element is considered in one basic block.
*/
case TEXTEQOID: {
current_bb = llvm::BasicBlock::Create(context, "current_bb", jitted_arrayop);
llvm::Function* func_varlena = llvmCodeGen->module()->getFunction("JittedEvalVarlena");
if (func_varlena == NULL) {
func_varlena = VarlenaCvtCodeGen();
}
llvm::Value* lhs_val = inner_builder.CreateCall(func_varlena, lhs_value, "lval");
llvm::Value* var_len = inner_builder.CreateExtractValue(lhs_val, 0);
llvm::Value* var_data = inner_builder.CreateExtractValue(lhs_val, 1);
inner_builder.CreateBr(current_bb);
for (i = 0; i < nitems; i++) {
inner_builder.SetInsertPoint(current_bb);
if (i == nitems - 1) {
next_bb = default_bb;
} else {
next_bb = llvm::BasicBlock::Create(context, "next_bb", jitted_arrayop);
}
text* cst_text = DatumGetTextPP(Args[i]);
int val_len = VARSIZE_ANY_EXHDR(cst_text);
char* val_data = VARDATA_ANY(cst_text);
llvm::Value* cst_len = llvmCodeGen->getIntConstant(INT4OID, val_len);
llvm::Value* cst_data = llvmCodeGen->CastPtrToLlvmPtr(int8PtrType, (void*)val_data);
llvm::Function* func_texteq_cc = llvmCodeGen->module()->getFunction("LLVMIRtexteq");
if (func_texteq_cc == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_IR_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Failed on getting IR function : LLVMIRtexteq!\n")));
}
llvm::Value* tmp =
inner_builder.CreateCall(func_texteq_cc, {var_len, var_data, cst_len, cst_data}, "texteq");
tmp = inner_builder.CreateTrunc(tmp, int1Type);
inner_builder.CreateCondBr(tmp, in_bb, next_bb);
current_bb = next_bb;
}
} break;
case BPCHAREQOID: {
current_bb = llvm::BasicBlock::Create(context, "current_bb", jitted_arrayop);
llvm::Function* func_varlena = llvmCodeGen->module()->getFunction("JittedEvalVarlena");
if (func_varlena == NULL) {
func_varlena = VarlenaCvtCodeGen();
}
llvm::Value* lhs_val = inner_builder.CreateCall(func_varlena, lhs_value, "lval");
llvm::Value* var_len = inner_builder.CreateExtractValue(lhs_val, 0);
llvm::Value* var_data = inner_builder.CreateExtractValue(lhs_val, 1);
inner_builder.CreateBr(current_bb);
for (i = 0; i < nitems; i++) {
inner_builder.SetInsertPoint(current_bb);
if (i == nitems - 1) {
next_bb = default_bb;
} else {
next_bb = llvm::BasicBlock::Create(context, "next_bb", jitted_arrayop);
}
BpChar* cst_bpchar = DatumGetBpCharPP(Args[i]);
int val_len = VARSIZE_ANY_EXHDR(cst_bpchar);
char* cst_char = VARDATA_ANY(cst_bpchar);
llvm::Value* cst_len = llvmCodeGen->getIntConstant(INT4OID, val_len);
llvm::Value* cst_data = llvmCodeGen->CastPtrToLlvmPtr(int8PtrType, (void*)cst_char);
llvm::Function* func_bpchareq_cc = llvmCodeGen->module()->getFunction("LLVMIRbpchareq");
if (func_bpchareq_cc == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_IR_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Failed on getting IR function : LLVMIRbpchareq!")));
}
llvm::Value* tmp =
inner_builder.CreateCall(func_bpchareq_cc, {var_len, var_data, cst_len, cst_data}, "bpchareq");
tmp = inner_builder.CreateTrunc(tmp, int1Type);
inner_builder.CreateCondBr(tmp, in_bb, next_bb);
current_bb = next_bb;
}
} break;
* Turn array operation to switch instruction operation defined in LLVM.
* Create a switch instruction with the specified value, default dest, and
* with a hint for the number of cases that will be added. We should also
* pay attention to different data type, since the values stored in llvm
* and pg may diffrent because of sign.
*/
case INT2EQOID: {
lhs_value = inner_builder.CreateTrunc(lhs_value, int16Type);
llvm::SwitchInst* switchInst = inner_builder.CreateSwitch(lhs_value, default_bb, nitems);
for (i = 0; i < nitems; i++) {
switchInst->addCase(llvm::ConstantInt::get(context, llvm::APInt(16, Args[i], true)), in_bb);
}
} break;
case INT4EQOID:
case FLOAT4EQOID: {
lhs_value = inner_builder.CreateTrunc(lhs_value, int32Type);
llvm::SwitchInst* switchInst = inner_builder.CreateSwitch(lhs_value, default_bb, nitems);
for (i = 0; i < nitems; i++) {
switchInst->addCase(llvm::ConstantInt::get(context, llvm::APInt(32, Args[i], true)), in_bb);
}
} break;
case INT8EQOID:
case FLOAT8EQOID:
case DATEEQOID:
case TIMESTAMPEQOID: {
llvm::SwitchInst* switchInst = inner_builder.CreateSwitch(lhs_value, default_bb, nitems);
for (i = 0; i < nitems; i++) {
switchInst->addCase(llvm::ConstantInt::get(context, llvm::APInt(64, Args[i], true)), in_bb);
}
} break;
case INT48EQOID: {
lhs_value = inner_builder.CreateTrunc(lhs_value, int32Type);
lhs_value = inner_builder.CreateSExt(lhs_value, int64Type);
llvm::SwitchInst* switchInst = inner_builder.CreateSwitch(lhs_value, default_bb, nitems);
for (i = 0; i < nitems; i++) {
switchInst->addCase(llvm::ConstantInt::get(context, llvm::APInt(64, Args[i], true)), in_bb);
}
} break;
case INT84EQOID: {
llvm::SwitchInst* switchInst = inner_builder.CreateSwitch(lhs_value, default_bb, nitems);
for (i = 0; i < nitems; i++) {
switchInst->addCase(llvm::ConstantInt::get(context, llvm::APInt(64, (int)Args[i], true)), in_bb);
}
} break;
default: {
current_bb = llvm::BasicBlock::Create(context, "current_bb", jitted_arrayop);
inner_builder.CreateBr(current_bb);
* By using EvalFuncResult function, we could evaluate different
* kind of operations defined here, say <, >, >=, <= and so on.
*/
FuncExprState* fcache = (FuncExprState*)args->exprstate;
for (i = 0; i < nitems; i++) {
inner_builder.SetInsertPoint(current_bb);
if (i == nitems - 1)
next_bb = default_bb;
else
next_bb = llvm::BasicBlock::Create(context, "next_bb", jitted_arrayop);
llvm::Value* rhs_value = llvmCodeGen->getIntConstant(INT8OID, Args[i]);
* Prepare the parameters usde by original c-function. For
* other cases, we have already remove null values and duplicate
* values.
*/
LLVMFuncCallInfo lfcinfo;
llvm::Value* inargs[MAX_ARGS_NUM];
inargs[0] = lhs_value;
inargs[1] = rhs_value;
lfcinfo.nargs = list_length(fcache->args);
lfcinfo.args = &inargs[0];
llvm::Value* tmp = EvalFuncResultCodeGen(&inner_builder, fcache, isNull, &lfcinfo);
tmp = inner_builder.CreateTrunc(tmp, int1Type);
inner_builder.CreateCondBr(tmp, in_bb, next_bb);
current_bb = next_bb;
}
} break;
}
inner_builder.SetInsertPoint(in_bb);
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(default_bb);
* If current value does not match any value in array, when resultNull
* is NULL, return NULL.
*/
if (resultNull)
inner_builder.CreateStore(null_true, isNull);
inner_builder.CreateBr(ret_bb);
* When the element is in 'in_bb' block, rerun true, else return false.
*/
inner_builder.SetInsertPoint(ret_bb);
llvm::PHINode* Phi = inner_builder.CreatePHI(int64Type, 3);
Phi->addIncoming(Datum_0, if_then);
Phi->addIncoming(Datum_1, in_bb);
Phi->addIncoming(Datum_0, default_bb);
inner_builder.CreateRet(Phi);
} else {
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(ret_bb);
llvm::PHINode* Phi = inner_builder.CreatePHI(int64Type, 3);
Phi->addIncoming(Datum_0, if_then);
Phi->addIncoming(Datum_0, if_else);
inner_builder.CreateRet(Phi);
}
pfree_ext(Args);
pfree_ext(elemNull);
llvmCodeGen->FinalizeFunction(jitted_arrayop);
result = outer_builder->CreateCall(
jitted_arrayop, {args->llvm_args[0], args->llvm_args[1], args->llvm_args[2]}, "VecScalarArrayOp");
return result;
}
llvm::Value* VecExprCodeGen::BooleanTestCodeGen(ExprCodeGenArgs* args)
{
GenericExprState* bstate = (GenericExprState*)(args->exprstate);
BooleanTest* btestexpr = (BooleanTest*)args->exprstate->expr;
ExprState* lestate = bstate->arg;
dorado::GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder* outer_builder = args->builder;
GsCodeGen::LlvmBuilder inner_builder(context);
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
DEFINE_CGVAR_INT64(Datum_0, 0);
DEFINE_CGVAR_INT64(Datum_1, 1);
DEFINE_CGVAR_INT8(null_true, 1);
DEFINE_CGVAR_INT8(null_false, 0);
llvm::Value* isNull = NULL;
llvm::Value* llvmargs[3];
llvm::Value* lhs_value = NULL;
llvm::Value* lhs_flag = NULL;
llvm::Value* cmp = NULL;
llvm::Value* res0 = NULL;
llvm::Value* res1 = NULL;
llvm::Value* res2 = NULL;
llvm::Value* result = NULL;
DEFINE_FUNCTION_WITH_3_ARGS(jitted_booleantest,
"JittedBooleanTest",
"econtext",
ExprContextPtrType,
"isNull",
int8PtrType,
"loop_index",
int64Type);
isNull = llvmargs[1];
llvm::BasicBlock* entry = &jitted_booleantest->getEntryBlock();
* Since IS_UNKNOWN and IS_NOT_UNKNOWN do not have any conditional
* branch, we enter into ret_bb block directly.
*/
DEFINE_BLOCK(ret_bb, jitted_booleantest);
inner_builder.SetInsertPoint(entry);
ExprCodeGenArgs largs;
largs = *args;
largs.exprstate = lestate;
largs.builder = &inner_builder;
largs.llvm_args = &llvmargs[0];
lhs_value = CodeGen(&largs);
lhs_flag = llvmargs[1];
lhs_flag = inner_builder.CreateLoad(int8Type, lhs_flag, "lflag");
inner_builder.CreateStore(null_false, isNull);
cmp = inner_builder.CreateICmpEQ(lhs_flag, null_true);
if (btestexpr->booltesttype == IS_UNKNOWN || btestexpr->booltesttype == IS_NOT_UNKNOWN) {
if (btestexpr->booltesttype == IS_UNKNOWN) {
res0 = lhs_flag;
} else {
cmp = inner_builder.CreateICmpEQ(lhs_flag, null_true);
res0 = inner_builder.CreateSelect(cmp, Datum_0, Datum_1);
}
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(ret_bb);
res0 = inner_builder.CreateZExt(res0, int64Type);
inner_builder.CreateRet(res0);
} else {
DEFINE_BLOCK(be_null, jitted_booleantest);
DEFINE_BLOCK(bnot_null, jitted_booleantest);
inner_builder.CreateCondBr(cmp, be_null, bnot_null);
switch (btestexpr->booltesttype) {
case IS_TRUE:
inner_builder.SetInsertPoint(be_null);
res1 = Datum_0;
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(bnot_null);
res2 = lhs_value;
inner_builder.CreateBr(ret_bb);
break;
case IS_NOT_TRUE:
inner_builder.SetInsertPoint(be_null);
res1 = Datum_1;
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(bnot_null);
cmp = inner_builder.CreateICmpEQ(lhs_value, Datum_1);
res2 = inner_builder.CreateSelect(cmp, Datum_0, Datum_1);
inner_builder.CreateBr(ret_bb);
break;
case IS_FALSE:
inner_builder.SetInsertPoint(be_null);
res1 = Datum_0;
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(bnot_null);
cmp = inner_builder.CreateICmpEQ(lhs_value, Datum_1);
res2 = inner_builder.CreateSelect(cmp, Datum_0, Datum_1);
inner_builder.CreateBr(ret_bb);
break;
case IS_NOT_FALSE:
inner_builder.SetInsertPoint(be_null);
res1 = Datum_1;
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(bnot_null);
res2 = lhs_value;
inner_builder.CreateBr(ret_bb);
break;
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmodule(MOD_LLVM),
errmsg("unrecognized booltexttype: %d", (int)btestexpr->booltesttype)));
break;
}
inner_builder.SetInsertPoint(ret_bb);
llvm::PHINode* Phi_ret = inner_builder.CreatePHI(int64Type, 2);
Phi_ret->addIncoming(res1, be_null);
Phi_ret->addIncoming(res2, bnot_null);
inner_builder.CreateRet(Phi_ret);
}
llvmCodeGen->FinalizeFunction(jitted_booleantest);
result = outer_builder->CreateCall(
jitted_booleantest, {args->llvm_args[0], args->llvm_args[1], args->llvm_args[2]}, "EvalVecBoolenTest");
return result;
}
llvm::Value* VecExprCodeGen::NullTestCodeGen(ExprCodeGenArgs* args)
{
NullTestState* nteststate = (NullTestState*)(args->exprstate);
NullTest* ntestexpr = (NullTest*)(args->exprstate->expr);
ExprState* lestate = nteststate->arg;
dorado::GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder* outer_builder = args->builder;
GsCodeGen::LlvmBuilder inner_builder(context);
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
DEFINE_CGVAR_INT64(Datum_0, 0);
DEFINE_CGVAR_INT64(Datum_1, 1);
DEFINE_CGVAR_INT8(null_false, 0);
llvm::Value* isNull = NULL;
llvm::Value* llvmargs[3];
llvm::Value* arg_flag = NULL;
llvm::Value* cmp = NULL;
llvm::Value* res0 = NULL;
llvm::Value* result = NULL;
DEFINE_FUNCTION_WITH_3_ARGS(jitted_nulltest,
"JittedNullTest",
"econtext",
ExprContextPtrType,
"isNull",
int8PtrType,
"loop_index",
int64Type);
isNull = llvmargs[1];
llvm::BasicBlock* entry = &jitted_nulltest->getEntryBlock();
inner_builder.SetInsertPoint(entry);
ExprCodeGenArgs largs;
largs = *args;
largs.exprstate = lestate;
largs.builder = &inner_builder;
largs.llvm_args = &llvmargs[0];
(void)CodeGen(&largs);
arg_flag = llvmargs[1];
arg_flag = inner_builder.CreateLoad(int8Type, arg_flag, "argflag");
inner_builder.CreateStore(null_false, isNull);
if (ntestexpr->nulltesttype == IS_NULL) {
res0 = inner_builder.CreateZExt(arg_flag, int64Type);
inner_builder.CreateRet(res0);
} else {
arg_flag = inner_builder.CreateZExt(arg_flag, int64Type);
cmp = inner_builder.CreateICmpEQ(arg_flag, Datum_1);
res0 = inner_builder.CreateSelect(cmp, Datum_0, Datum_1);
inner_builder.CreateRet(res0);
}
llvmCodeGen->FinalizeFunction(jitted_nulltest);
result = outer_builder->CreateCall(
jitted_nulltest, {args->llvm_args[0], args->llvm_args[1], args->llvm_args[2]}, "EvalVecNullTest");
return result;
}
llvm::Value* VecExprCodeGen::CaseCodeGen(ExprCodeGenArgs* args)
{
dorado::GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder* outer_builder = args->builder;
GsCodeGen::LlvmBuilder inner_builder(context);
DEFINE_CG_TYPE(int1Type, BITOID);
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
DEFINE_CGVAR_INT1(null_true, 1);
DEFINE_CGVAR_INT1(int1_0, 0);
DEFINE_CGVAR_INT64(Datum_0, 0);
llvm::Value* llvmargs[3];
llvm::Value* case_arg_value = NULL;
llvm::Value* case_arg_null = NULL;
llvm::Value* case_value = NULL;
llvm::Value* case_null = NULL;
llvm::Value* case_cond = NULL;
llvm::Value* case_cond1 = NULL;
llvm::Value* case_cond2 = NULL;
llvm::Value* result = NULL;
llvm::Value* tmp = NULL;
int i = 0;
int clause_index = 0;
DEFINE_FUNCTION_WITH_3_ARGS(jitted_caseexpr,
"JittedVecCase",
"econtext",
ExprContextPtrType,
"isNull",
int8PtrType,
"loop_index",
int64Type);
llvm::Value* isNull = llvmargs[1];
llvm::BasicBlock* entry = &jitted_caseexpr->getEntryBlock();
DEFINE_BLOCK(ret_bb, jitted_caseexpr);
llvm::BasicBlock* current_bb = NULL;
llvm::BasicBlock* next_bb = NULL;
* Extract caseexpr information from node, case_arg decides different
* forms of case expr.
*/
CaseExprState* cstate = (CaseExprState*)(args->exprstate);
ExprState* case_arg = cstate->arg;
ExprCodeGenArgs case_expr_arg;
case_expr_arg = *args;
case_expr_arg.builder = &inner_builder;
case_expr_arg.llvm_args = &llvmargs[0];
List* clauses = cstate->args;
ExprCodeGenArgs case_when_arg;
case_when_arg = *args;
case_when_arg.builder = &inner_builder;
case_when_arg.llvm_args = &llvmargs[0];
ExprState* case_default = cstate->defresult;
ExprCodeGenArgs case_default_arg;
case_default_arg = *args;
case_default_arg.builder = &inner_builder;
case_default_arg.llvm_args = &llvmargs[0];
ExprCodeGenArgs case_result_arg;
case_result_arg = *args;
case_result_arg.builder = &inner_builder;
case_result_arg.llvm_args = &llvmargs[0];
ExprState* case_arg_expr = NULL;
ListCell* cell = NULL;
* If there's a test expression, we have to evaluate it and save the value
* where the CaseTestExpr placeholders can find it. We must save and
* restore prior setting of econtext's caseValue fields, in case this node
* is itself within a larger CASE.
*/
if (case_arg != NULL) {
inner_builder.SetInsertPoint(entry);
case_expr_arg.exprstate = case_arg;
case_arg_value = CodeGen(&case_expr_arg);
case_arg_null = llvmargs[1];
case_arg_null = inner_builder.CreateLoad(int8Type, case_arg_null, "case_arg_flag");
if (case_arg_value == NULL)
return NULL;
}
* we evaluate each of the WHEN clauses in turn, as soon as one is true we
* return the corresponding result. If none are true then we return the
* value of the default clause, or NULL if there is none.
*
* the following code is designed to cover foreach(clause, clauses){...}
* Since each case... is a basicblock, we need a basicblock array
*/
int casewhen_len = list_length(clauses);
llvm::BasicBlock** clause_bb = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * (casewhen_len + 1));
llvm::BasicBlock** if_then = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * (casewhen_len + 1));
llvm::BasicBlock** if_else = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * (casewhen_len + 1));
llvm::BasicBlock** check_bb = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * (casewhen_len + 1));
llvm::Value** clause_result = (llvm::Value**)palloc(sizeof(llvm::Value*) * (casewhen_len + 1));
current_bb = entry;
foreach (cell, clauses) {
CaseWhenState* wclause = (CaseWhenState*)lfirst(cell);
clause_bb[clause_index] = llvm::BasicBlock::Create(context, "clause_bb", jitted_caseexpr);
check_bb[clause_index] = llvm::BasicBlock::Create(context, "check_bb", jitted_caseexpr);
next_bb = llvm::BasicBlock::Create(context, "next_bb", jitted_caseexpr);
* Since we could not call every function through ExecStrictVecOpExpr, so
* we should list all the cases we supported here, it should be
* changed later.
*/
inner_builder.SetInsertPoint(current_bb);
if (case_arg == NULL) {
case_when_arg.exprstate = (ExprState*)wclause->expr;
case_value = CodeGen(&case_when_arg);
if (case_value == NULL) {
next_bb->eraseFromParent();
return NULL;
}
case_cond = inner_builder.CreateTrunc(case_value, int1Type);
inner_builder.CreateBr(check_bb[clause_index]);
inner_builder.SetInsertPoint(check_bb[clause_index]);
} else {
if_then[clause_index] = llvm::BasicBlock::Create(context, "if_then", jitted_caseexpr);
if_else[clause_index] = llvm::BasicBlock::Create(context, "if_else", jitted_caseexpr);
if (IsA(wclause->expr->expr, CaseTestExpr)) {
* When there is only a CaseTextExpr here, the typeId is
* Boolean and we could get the result according to
* case_arg_value. (with 'when true' syntax)
*/
tmp = inner_builder.CreateTrunc(case_arg_null, int1Type);
inner_builder.CreateCondBr(tmp, if_else[clause_index], if_then[clause_index]);
inner_builder.SetInsertPoint(if_then[clause_index]);
case_cond1 = case_arg_value;
} else if (IsA(wclause->expr->expr, BoolExpr)) {
* When there is only a BoolExpr node with 'not' type, its
* argument is CastTestExpr. We could get the result accoding
* to not case_arg_value. (with 'when false' syntax)
*/
tmp = inner_builder.CreateTrunc(case_arg_null, int1Type);
inner_builder.CreateCondBr(tmp, if_else[clause_index], if_then[clause_index]);
inner_builder.SetInsertPoint(if_then[clause_index]);
case_cond1 = inner_builder.CreateNot(case_arg_value);
} else {
* the wclause->expr's first arg is CASETESTEXPR, its second
* arg is case_value different from 'case_arg==NULL',
* case_value should be compared with case_arg_value to see
* if this branch is satisfied or not.
*/
FuncExprState* arg_expr = (FuncExprState*)wclause->expr;
case_arg_expr = (ExprState*)(lsecond(arg_expr->args));
case_when_arg.exprstate = case_arg_expr;
case_value = CodeGen(&case_when_arg);
case_null = llvmargs[1];
case_null = inner_builder.CreateLoad(int8Type, case_null, "case_flag");
tmp = inner_builder.CreateOr(case_arg_null, case_null);
tmp = inner_builder.CreateTrunc(tmp, int1Type);
inner_builder.CreateCondBr(tmp, if_else[clause_index], if_then[clause_index]);
inner_builder.SetInsertPoint(if_then[clause_index]);
OpExpr* aexpr = (OpExpr*)arg_expr->xprstate.expr;
switch (aexpr->opno) {
case BooleanEqualOperator: {
llvm::Function* func_booleq = llvmCodeGen->module()->getFunction("Jitted_booleq");
if (func_booleq == NULL) {
func_booleq = booleq_codegen();
}
case_cond1 = inner_builder.CreateCall(func_booleq, {case_arg_value, case_value});
} break;
case INT4EQOID: {
llvm::Function* func_int4eq = llvmCodeGen->module()->getFunction("Jitted_int4eq");
if (func_int4eq == NULL) {
func_int4eq = int4_sop_codegen<SOP_EQ>();
}
case_cond1 = inner_builder.CreateCall(func_int4eq, {case_arg_value, case_value});
} break;
case INT8EQOID: {
llvm::Function* func_int8eq = llvmCodeGen->module()->getFunction("Jitted_int8eq");
if (func_int8eq == NULL) {
func_int8eq = int8_sop_codegen<SOP_EQ>();
}
case_cond1 = inner_builder.CreateCall(func_int8eq, {case_arg_value, case_value});
} break;
case INT24EQOID: {
llvm::Function* func_int24eq = llvmCodeGen->module()->getFunction("Jitted_int24eq");
if (func_int24eq == NULL) {
func_int24eq = int2_int4_sop_codegen<SOP_EQ, INT2OID>();
}
case_cond1 = inner_builder.CreateCall(func_int24eq, {case_arg_value, case_value});
} break;
case INT42EQOID: {
llvm::Function* func_int42eq = llvmCodeGen->module()->getFunction("Jitted_int42eq");
if (func_int42eq == NULL) {
func_int42eq = int2_int4_sop_codegen<SOP_EQ, INT4OID>();
}
case_cond1 = inner_builder.CreateCall(func_int42eq, {case_arg_value, case_value});
} break;
case INT48EQOID: {
llvm::Function* func_int48eq = llvmCodeGen->module()->getFunction("Jitted_int48eq");
if (func_int48eq == NULL) {
func_int48eq = int4_int8_sop_codegen<SOP_EQ, INT4OID>();
}
case_cond1 = inner_builder.CreateCall(func_int48eq, {case_arg_value, case_value});
} break;
case INT84EQOID: {
llvm::Function* func_int84eq = llvmCodeGen->module()->getFunction("Jitted_int84eq");
if (func_int84eq == NULL) {
func_int84eq = int4_int8_sop_codegen<SOP_EQ, INT8OID>();
}
case_cond1 = inner_builder.CreateCall(func_int84eq, {case_arg_value, case_value});
} break;
case DATEEQOID: {
llvm::Function* func_dateeq = llvmCodeGen->module()->getFunction("Jitted_dateeq");
if (func_dateeq == NULL) {
func_dateeq = date_eq_codegen();
}
case_cond1 = inner_builder.CreateCall(func_dateeq, {case_arg_value, case_value});
} break;
case FLOAT8EQOID: {
llvm::Function* func_float8eq = llvmCodeGen->module()->getFunction("Jitted_float8eq");
if (func_float8eq == NULL) {
func_float8eq = float8eq_codegen();
}
case_cond1 = inner_builder.CreateCall(func_float8eq, {case_arg_value, case_value});
} break;
case TIMESTAMPEQOID: {
llvm::Function* func_timestampeq = llvmCodeGen->module()->getFunction("Jitted_timestampeq");
if (func_timestampeq == NULL) {
func_timestampeq = timestamp_eq_codegen();
}
case_cond1 = inner_builder.CreateCall(func_timestampeq, {case_arg_value, case_value});
} break;
case TEXTEQOID: {
llvm::Function* func_texteq = llvmCodeGen->module()->getFunction("Jitted_texteq");
if (func_texteq == NULL) {
func_texteq = texteq_codegen();
}
case_cond1 = inner_builder.CreateCall(func_texteq, {case_arg_value, case_value});
} break;
case BPCHAREQOID: {
llvm::Function* func_bpchareq = llvmCodeGen->module()->getFunction("Jitted_bpchareq");
if (func_bpchareq == NULL) {
func_bpchareq = bpchareq_codegen();
}
case_cond1 = inner_builder.CreateCall(func_bpchareq, {case_arg_value, case_value});
} break;
case NUMERICEQOID: {
llvm::Function* func_numericeq = llvmCodeGen->module()->getFunction("Jitted_numericeq");
if (func_numericeq == NULL) {
func_numericeq = numeric_sop_codegen<BIEQ>();
}
case_cond1 =
inner_builder.CreateCall(func_numericeq, {case_arg_value, case_value}, "numericeq");
} break;
default: {
* first prepare the parameters used by EvalFuncResult,
* then invoke the origial c-function by WrapVecStrictOperFunc,
* since eq-func are all strict funcs.
*/
LLVMFuncCallInfo lfcinfo;
llvm::Value* inargs[MAX_ARGS_NUM];
inargs[0] = case_arg_value;
inargs[1] = case_value;
lfcinfo.nargs = list_length(arg_expr->args);
lfcinfo.args = &inargs[0];
case_cond1 = EvalFuncResultCodeGen(&inner_builder, arg_expr, isNull, &lfcinfo);
} break;
}
}
case_cond1 = inner_builder.CreateTrunc(case_cond1, int1Type);
inner_builder.CreateBr(check_bb[clause_index]);
inner_builder.SetInsertPoint(if_else[clause_index]);
case_cond2 = int1_0;
inner_builder.CreateBr(check_bb[clause_index]);
inner_builder.SetInsertPoint(check_bb[clause_index]);
llvm::PHINode* Phi_case = inner_builder.CreatePHI(int1Type, 2);
Phi_case->addIncoming(case_cond1, if_then[clause_index]);
Phi_case->addIncoming(case_cond2, if_else[clause_index]);
case_cond = (llvm::Value*)Phi_case;
}
* if we have a true test, then we return the result, since the case
* statement is satisfied. A NULL result from the test is not
* considered true.
*/
inner_builder.CreateCondBr(case_cond, clause_bb[clause_index], next_bb);
inner_builder.SetInsertPoint(clause_bb[clause_index]);
case_result_arg.exprstate = wclause->result;
clause_result[clause_index] = CodeGen(&case_result_arg);
if (clause_result[clause_index] == NULL) {
ret_bb->eraseFromParent();
return NULL;
}
inner_builder.CreateBr(ret_bb);
clause_index++;
current_bb = next_bb;
}
inner_builder.SetInsertPoint(next_bb);
clause_bb[clause_index] = next_bb;
if (case_default == NULL) {
clause_result[clause_index] = Datum_0;
inner_builder.CreateStore(null_true, isNull);
} else {
case_default_arg.exprstate = case_default;
clause_result[clause_index] = CodeGen(&case_default_arg);
if (clause_result[clause_index] == NULL)
return NULL;
}
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(ret_bb);
llvm::PHINode* Phi_ret = inner_builder.CreatePHI(int64Type, clause_index + 1);
for (i = 0; i < clause_index + 1; i++) {
Phi_ret->addIncoming(clause_result[i], clause_bb[i]);
}
inner_builder.CreateRet(Phi_ret);
pfree_ext(clause_bb);
pfree_ext(clause_result);
llvmCodeGen->FinalizeFunction(jitted_caseexpr);
result = outer_builder->CreateCall(
jitted_caseexpr, {args->llvm_args[0], args->llvm_args[1], args->llvm_args[2]}, "VecCase");
return result;
}
llvm::Value* VecExprCodeGen::AndOrLogicCodeGen(ExprCodeGenArgs* args)
{
BoolExprState* boolstate = (BoolExprState*)args->exprstate;
BoolExpr* boolexpr = (BoolExpr*)args->exprstate->expr;
List* boolargs = boolstate->args;
dorado::GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
GsCodeGen::LlvmBuilder* outer_builder = args->builder;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder inner_builder(context);
llvm::Value* isNull = NULL;
llvm::Value* result = NULL;
llvm::Value* cvalue = NULL;
llvm::Value* cflag = NULL;
llvm::Value* AnyNull = NULL;
llvm::Value* tmp = NULL;
llvm::Value* cmp = NULL;
llvm::Value* llvmargs[3];
DEFINE_CG_TYPE(int1Type, BITOID);
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
DEFINE_CGVAR_INT8(null_false, 0);
DEFINE_CGVAR_INT8(null_true, 1);
DEFINE_CGVAR_INT64(Datum_0, 0);
DEFINE_CGVAR_INT64(Datum_1, 1);
DEFINE_FUNCTION_WITH_3_ARGS(
jitted_vbool, "JittedVecBool", "econtext", ExprContextPtrType, "isNull", int8PtrType, "loop_index", int64Type);
isNull = llvmargs[1];
llvm::BasicBlock* entry = &jitted_vbool->getEntryBlock();
DEFINE_BLOCK(ret_bb, jitted_vbool);
llvm::BasicBlock* current_bb = NULL;
llvm::BasicBlock* next_bb = NULL;
ListCell* cell = NULL;
int clause_index = 0;
ExprCodeGenArgs bargs;
bargs = *args;
bargs.builder = &inner_builder;
bargs.llvm_args = &llvmargs[0];
AnyNull = inner_builder.CreateAlloca(int8Type);
inner_builder.CreateStore(null_false, AnyNull);
int bool_nargs = list_length(boolargs);
llvm::BasicBlock** clause_bb = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * (bool_nargs + 1));
llvm::BasicBlock** if_then = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * (bool_nargs + 1));
llvm::BasicBlock** if_else = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * (bool_nargs + 1));
llvm::Value** clause_result = (llvm::Value**)palloc(sizeof(llvm::Value*) * (bool_nargs + 1));
current_bb = entry;
switch (boolexpr->boolop) {
* And Expr:
* If any of the clauses is FALSE, the AND result if FALSE regardless
* of the states of teh rest of the caluses, so we can stop evaluating
* and return FALSE immediately.
*/
case AND_EXPR: {
foreach (cell, boolargs) {
ExprState* cexpr = (ExprState*)lfirst(cell);
clause_bb[clause_index] = llvm::BasicBlock::Create(context, "clause_bb", jitted_vbool);
if_then[clause_index] = llvm::BasicBlock::Create(context, "if_then", jitted_vbool);
if_else[clause_index] = llvm::BasicBlock::Create(context, "if_else", jitted_vbool);
next_bb = llvm::BasicBlock::Create(context, "next_bb", jitted_vbool);
inner_builder.SetInsertPoint(current_bb);
bargs.exprstate = cexpr;
cvalue = CodeGen(&bargs);
cflag = llvmargs[1];
cflag = inner_builder.CreateLoad(int8Type, cflag, "cflag");
tmp = inner_builder.CreateTrunc(cflag, int1Type);
inner_builder.CreateCondBr(tmp, if_then[clause_index], if_else[clause_index]);
inner_builder.SetInsertPoint(if_then[clause_index]);
inner_builder.CreateStore(null_true, AnyNull);
inner_builder.CreateBr(next_bb);
inner_builder.SetInsertPoint(if_else[clause_index]);
cmp = inner_builder.CreateICmpNE(cvalue, Datum_0);
cmp = inner_builder.CreateTrunc(cmp, int1Type);
inner_builder.CreateCondBr(cmp, next_bb, clause_bb[clause_index]);
inner_builder.SetInsertPoint(clause_bb[clause_index]);
clause_result[clause_index] = cvalue;
inner_builder.CreateStore(null_false, isNull);
inner_builder.CreateBr(ret_bb);
clause_index++;
current_bb = next_bb;
}
* AnyNull is true if at least one cluase evaluated to NULL.
* And the result is not AnyNull.
*/
inner_builder.SetInsertPoint(next_bb);
clause_bb[clause_index] = next_bb;
AnyNull = inner_builder.CreateLoad(int8Type, AnyNull);
cmp = inner_builder.CreateTrunc(AnyNull, int1Type);
clause_result[clause_index] = inner_builder.CreateSelect(cmp, Datum_0, Datum_1);
inner_builder.CreateStore(AnyNull, isNull);
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(ret_bb);
llvm::PHINode* Phi_ret = inner_builder.CreatePHI(int64Type, clause_index + 1);
for (int i = 0; i < clause_index + 1; i++) {
Phi_ret->addIncoming(clause_result[i], clause_bb[i]);
}
inner_builder.CreateRet(Phi_ret);
} break;
case OR_EXPR: {
* Or Expr:
* If any of the clauses is TRUE, the OR result is TRUE regardless of the
* states of the rest of the clauses, so we can stop evaluating and return
* TRUE immediately.
*/
foreach (cell, boolargs) {
ExprState* cexpr = (ExprState*)lfirst(cell);
clause_bb[clause_index] = llvm::BasicBlock::Create(context, "clause_bb", jitted_vbool);
if_then[clause_index] = llvm::BasicBlock::Create(context, "if_then", jitted_vbool);
if_else[clause_index] = llvm::BasicBlock::Create(context, "if_else", jitted_vbool);
next_bb = llvm::BasicBlock::Create(context, "next_bb", jitted_vbool);
inner_builder.SetInsertPoint(current_bb);
bargs.exprstate = cexpr;
cvalue = CodeGen(&bargs);
cflag = llvmargs[1];
cflag = inner_builder.CreateLoad(int8Type, cflag, "cflag");
tmp = inner_builder.CreateTrunc(cflag, int1Type);
inner_builder.CreateCondBr(tmp, if_then[clause_index], if_else[clause_index]);
inner_builder.SetInsertPoint(if_then[clause_index]);
inner_builder.CreateStore(null_true, AnyNull);
inner_builder.CreateBr(next_bb);
inner_builder.SetInsertPoint(if_else[clause_index]);
cmp = inner_builder.CreateICmpNE(cvalue, Datum_0);
cmp = inner_builder.CreateTrunc(cmp, int1Type);
inner_builder.CreateCondBr(cmp, clause_bb[clause_index], next_bb);
inner_builder.SetInsertPoint(clause_bb[clause_index]);
clause_result[clause_index] = cvalue;
inner_builder.CreateStore(null_false, isNull);
inner_builder.CreateBr(ret_bb);
clause_index++;
current_bb = next_bb;
}
inner_builder.SetInsertPoint(next_bb);
clause_bb[clause_index] = next_bb;
clause_result[clause_index] = Datum_0;
AnyNull = inner_builder.CreateLoad(int8Type, AnyNull);
inner_builder.CreateStore(AnyNull, isNull);
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(ret_bb);
llvm::PHINode* Phi_ret = inner_builder.CreatePHI(int64Type, clause_index + 1);
for (int i = 0; i < clause_index + 1; i++) {
Phi_ret->addIncoming(clause_result[i], clause_bb[i]);
}
inner_builder.CreateRet(Phi_ret);
} break;
default:
Assert(false);
break;
}
pfree_ext(clause_bb);
pfree_ext(clause_result);
pfree_ext(if_then);
pfree_ext(if_else);
llvmCodeGen->FinalizeFunction(jitted_vbool);
result = outer_builder->CreateCall(jitted_vbool, {args->llvm_args[0], args->llvm_args[1], args->llvm_args[2]});
return result;
}
llvm::Value* VecExprCodeGen::NotCodeGen(ExprCodeGenArgs* args)
{
BoolExprState* notclause = (BoolExprState*)args->exprstate;
ExprState* notexpr = (ExprState*)linitial(notclause->args);
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder* outer_builder = args->builder;
GsCodeGen::LlvmBuilder inner_builder(context);
DEFINE_CG_TYPE(int1Type, BITOID);
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
DEFINE_CGVAR_INT8(null_false, 0);
DEFINE_CGVAR_INT8(null_true, 1);
DEFINE_CGVAR_INT64(Datum_0, 0);
llvm::Value* isNull = NULL;
llvm::Value* expr_value = NULL;
llvm::Value* vflag = NULL;
llvm::Value* cmp = NULL;
llvm::Value* res1 = NULL;
llvm::Value* res2 = NULL;
llvm::Value* result = NULL;
llvm::Value* llvmargs[3];
DEFINE_FUNCTION_WITH_3_ARGS(
jitted_vnot, "JittedVecNot", "econtext", ExprContextPtrType, "isNull", int8PtrType, "loop_index", int64Type);
isNull = llvmargs[1];
ExprCodeGenArgs nargs;
nargs = *args;
nargs.builder = &inner_builder;
nargs.llvm_args = &llvmargs[0];
nargs.exprstate = notexpr;
expr_value = CodeGen(&nargs);
vflag = llvmargs[1];
llvm::BasicBlock* entry = &jitted_vnot->getEntryBlock();
DEFINE_BLOCK(be_null, jitted_vnot);
DEFINE_BLOCK(be_not_null, jitted_vnot);
DEFINE_BLOCK(ret_bb, jitted_vnot);
inner_builder.SetInsertPoint(entry);
vflag = inner_builder.CreateLoad(int8Type, vflag, "not_flag");
vflag = inner_builder.CreateTrunc(vflag, int1Type);
inner_builder.CreateCondBr(vflag, be_null, be_not_null);
* If the expression evaluates to null, just cascade the null back to
* whoever called us.
*/
inner_builder.SetInsertPoint(be_null);
res1 = expr_value;
inner_builder.CreateStore(null_true, isNull);
inner_builder.CreateBr(ret_bb);
* Evaluation of 'not' is simple..expr is false, then return 'true'
* and vice versa.
*/
inner_builder.SetInsertPoint(be_not_null);
cmp = inner_builder.CreateICmpNE(expr_value, Datum_0);
res2 = inner_builder.CreateNot(cmp);
res2 = inner_builder.CreateZExt(res2, int64Type);
inner_builder.CreateStore(null_false, isNull);
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(ret_bb);
llvm::PHINode* Phi_ret = inner_builder.CreatePHI(int64Type, 2);
Phi_ret->addIncoming(res1, be_null);
Phi_ret->addIncoming(res2, be_not_null);
inner_builder.CreateRet(Phi_ret);
llvmCodeGen->FinalizeFunction(jitted_vnot);
result = outer_builder->CreateCall(jitted_vnot, {args->llvm_args[0], args->llvm_args[1], args->llvm_args[2]});
return result;
}
llvm::Value* VecExprCodeGen::NullIfCodeGen(ExprCodeGenArgs* args)
{
FuncExprState* fcache = (FuncExprState*)args->exprstate;
NullIfExpr* nullifexpr = (NullIfExpr*)(args->exprstate->expr);
List* nullif_args = fcache->args;
ExprState* lestate = NULL;
ExprState* restate = NULL;
if (list_length(nullif_args) != 2)
return NULL;
dorado::GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
GsCodeGen::LlvmBuilder* outer_builder = args->builder;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder inner_builder(context);
llvm::Value* isNull = NULL;
llvm::Value* result = NULL;
llvm::Value* inargs[MAX_ARGS_NUM];
llvm::Value* inargnulls[MAX_ARGS_NUM];
llvm::Value* res1 = NULL;
llvm::Value* ret1 = NULL;
llvm::Value* ret2 = NULL;
llvm::Value* cmp = NULL;
llvm::Value* llvmargs[3];
DEFINE_CG_TYPE(int1Type, BITOID);
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
DEFINE_CGVAR_INT8(null_false, 0);
DEFINE_CGVAR_INT8(null_true, 1);
DEFINE_CGVAR_INT64(Datum_0, 0);
DEFINE_CGVAR_INT64(Datum_1, 1);
DEFINE_FUNCTION_WITH_3_ARGS(jitted_vnullif,
"JittedVecNullif",
"econtext",
ExprContextPtrType,
"isNull",
int8PtrType,
"loop_index",
int64Type);
isNull = llvmargs[1];
llvm::BasicBlock* entry = &jitted_vnullif->getEntryBlock();
DEFINE_BLOCK(bnot_null, jitted_vnullif);
DEFINE_BLOCK(be_null, jitted_vnullif);
DEFINE_BLOCK(ret_bb, jitted_vnullif);
DEFINE_BLOCK(if_then, jitted_vnullif);
DEFINE_BLOCK(if_else, jitted_vnullif);
lestate = (ExprState*)linitial(nullif_args);
restate = (ExprState*)lsecond(nullif_args);
inner_builder.SetInsertPoint(entry);
ExprCodeGenArgs largs;
largs = *args;
largs.exprstate = lestate;
largs.builder = &inner_builder;
largs.llvm_args = &llvmargs[0];
inargs[0] = CodeGen(&largs);
inargnulls[0] = llvmargs[1];
inargnulls[0] = inner_builder.CreateLoad(int8Type, inargnulls[0], "lflag");
ExprCodeGenArgs rargs;
rargs = *args;
rargs.exprstate = restate;
rargs.builder = &inner_builder;
rargs.llvm_args = &llvmargs[0];
inargs[1] = CodeGen(&rargs);
inargnulls[1] = llvmargs[1];
inargnulls[1] = inner_builder.CreateLoad(int8Type, inargnulls[1], "rflag");
cmp = inner_builder.CreateOr(inargnulls[0], inargnulls[1]);
cmp = inner_builder.CreateTrunc(cmp, int1Type);
inner_builder.CreateCondBr(cmp, be_null, bnot_null);
inner_builder.SetInsertPoint(bnot_null);
inner_builder.CreateStore(null_false, isNull);
* For NullIfExpr, there is no need to consider strict attribute.
* Only call the IR function when both the operands are not NULL.
* Once we have generated the IR function, we will not generate
* it again at the next time.
*/
switch (nullifexpr->opno) {
case INT2EQOID: {
llvm::Function* func_int2eq = llvmCodeGen->module()->getFunction("Jitted_int2eq");
if (func_int2eq == NULL) {
func_int2eq = int2_sop_codegen<SOP_EQ>();
}
res1 = inner_builder.CreateCall(func_int2eq, {inargs[0], inargs[1]}, "int2_eq");
} break;
case INT24EQOID: {
llvm::Function* func_int24eq = llvmCodeGen->module()->getFunction("Jitted_int24eq");
if (func_int24eq == NULL) {
func_int24eq = int2_int4_sop_codegen<SOP_EQ, INT2OID>();
}
res1 = inner_builder.CreateCall(func_int24eq, {inargs[0], inargs[1]}, "int24_eq");
} break;
case INT42EQOID: {
llvm::Function* func_int42eq = llvmCodeGen->module()->getFunction("Jitted_int42eq");
if (func_int42eq == NULL) {
func_int42eq = int2_int4_sop_codegen<SOP_EQ, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int42eq, {inargs[0], inargs[1]}, "int42_eq");
} break;
case INT4EQOID: {
llvm::Function* func_int4eq = llvmCodeGen->module()->getFunction("Jitted_int4eq");
if (func_int4eq == NULL) {
func_int4eq = int4_sop_codegen<SOP_EQ>();
}
res1 = inner_builder.CreateCall(func_int4eq, {inargs[0], inargs[1]}, "int4_eq");
} break;
case INT48EQOID: {
llvm::Function* func_int48eq = llvmCodeGen->module()->getFunction("Jitted_int48eq");
if (func_int48eq == NULL) {
func_int48eq = int4_int8_sop_codegen<SOP_EQ, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int48eq, {inargs[0], inargs[1]}, "int48_eq");
} break;
case INT84EQOID: {
llvm::Function* func_int84eq = llvmCodeGen->module()->getFunction("Jitted_int84eq");
if (func_int84eq == NULL) {
func_int84eq = int4_int8_sop_codegen<SOP_EQ, INT8OID>();
}
res1 = inner_builder.CreateCall(func_int84eq, {inargs[0], inargs[1]}, "int84_eq");
} break;
case INT8EQOID: {
llvm::Function* func_int8eq = llvmCodeGen->module()->getFunction("Jitted_int8eq");
if (func_int8eq == NULL) {
func_int8eq = int8_sop_codegen<SOP_EQ>();
}
res1 = inner_builder.CreateCall(func_int8eq, {inargs[0], inargs[1]}, "int8_eq");
} break;
case FLOAT8EQOID: {
llvm::Function* func_float8eq = llvmCodeGen->module()->getFunction("Jitted_float8eq");
if (func_float8eq == NULL) {
func_float8eq = float8eq_codegen();
}
res1 = inner_builder.CreateCall(func_float8eq, {inargs[0], inargs[1]}, "float8_eq");
} break;
case BooleanEqualOperator: {
llvm::Function* func_booleq = llvmCodeGen->module()->getFunction("Jitted_booleq");
if (func_booleq == NULL) {
func_booleq = booleq_codegen();
}
res1 = inner_builder.CreateCall(func_booleq, {inargs[0], inargs[1]}, "booleq");
} break;
case DATEEQOID: {
llvm::Function* func_dateeq = llvmCodeGen->module()->getFunction("Jitted_dateeq");
if (func_dateeq == NULL) {
func_dateeq = date_eq_codegen();
}
res1 = inner_builder.CreateCall(func_dateeq, {inargs[0], inargs[1]}, "date_eq");
} break;
case TIMESTAMPEQOID: {
llvm::Function* func_timestampeq = llvmCodeGen->module()->getFunction("Jitted_timestampeq");
if (func_timestampeq == NULL) {
func_timestampeq = timestamp_eq_codegen();
}
res1 = inner_builder.CreateCall(func_timestampeq, {inargs[0], inargs[1]}, "timestamp_eq");
} break;
case TEXTEQOID: {
llvm::Function* func_texteq = llvmCodeGen->module()->getFunction("Jitted_texteq");
if (func_texteq == NULL) {
func_texteq = texteq_codegen();
}
res1 = inner_builder.CreateCall(func_texteq, {inargs[0], inargs[1]}, "texteq");
} break;
case BPCHAREQOID: {
llvm::Function* func_bpchareq = llvmCodeGen->module()->getFunction("Jitted_bpchareq");
if (func_bpchareq == NULL) {
func_bpchareq = bpchareq_codegen();
}
res1 = inner_builder.CreateCall(func_bpchareq, {inargs[0], inargs[1]}, "bpchareq");
} break;
case NUMERICEQOID: {
llvm::Function* func_numericeq = llvmCodeGen->module()->getFunction("Jitted_numericeq");
if (func_numericeq == NULL) {
func_numericeq = numeric_sop_codegen<BIEQ>();
}
res1 = inner_builder.CreateCall(func_numericeq, {inargs[0], inargs[1]}, "numericeq");
} break;
default: {
* first prepare the parameters used by EvalFuncResult,
* then invoke the origial c-function by WrapVecStrictOperFunc.
*/
LLVMFuncCallInfo lfcinfo;
lfcinfo.nargs = list_length(fcache->args);
lfcinfo.args = &inargs[0];
lfcinfo.argnulls = &inargnulls[0];
res1 = EvalFuncResultCodeGen(&inner_builder, fcache, isNull, &lfcinfo);
} break;
}
cmp = inner_builder.CreateICmpEQ(res1, Datum_1);
inner_builder.CreateCondBr(cmp, if_then, if_else);
inner_builder.SetInsertPoint(if_then);
inner_builder.CreateStore(null_true, isNull);
ret1 = Datum_0;
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(if_else);
inner_builder.CreateBr(be_null);
inner_builder.SetInsertPoint(be_null);
inner_builder.CreateStore(inargnulls[0], isNull);
ret2 = inargs[0];
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(ret_bb);
llvm::PHINode* Phi_ret = inner_builder.CreatePHI(int64Type, 3);
Phi_ret->addIncoming(ret1, if_then);
Phi_ret->addIncoming(ret2, be_null);
inner_builder.CreateRet(Phi_ret);
llvmCodeGen->FinalizeFunction(jitted_vnullif);
result = outer_builder->CreateCall(
jitted_vnullif, {args->llvm_args[0], args->llvm_args[1], args->llvm_args[2]}, "EvalVecNullif");
return result;
}
llvm::Value* VecExprCodeGen::RelabelCodeGen(ExprCodeGenArgs* args)
{
GenericExprState* gstate = (GenericExprState*)args->exprstate;
ExprState* ert = gstate->arg;
llvm::Value* result = NULL;
ExprCodeGenArgs rtargs;
rtargs = *args;
rtargs.exprstate = ert;
result = CodeGen(&rtargs);
return result;
}
llvm::Value* VecExprCodeGen::FuncCodeGen(ExprCodeGenArgs* args)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder* outer_builder = args->builder;
GsCodeGen::LlvmBuilder inner_builder(context);
DEFINE_CG_TYPE(int1Type, BITOID);
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int32Type, INT4OID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
DEFINE_CGVAR_INT8(null_false, 0);
DEFINE_CGVAR_INT8(null_true, 1);
DEFINE_CGVAR_INT64(Datum_0, 0);
llvm::Value* llvmargs[3];
llvm::Value* result = NULL;
llvm::Value* inargs[MAX_ARGS_NUM];
llvm::Value* inargnulls[MAX_ARGS_NUM];
llvm::Value* res1 = NULL;
llvm::Value* res2 = NULL;
DEFINE_FUNCTION_WITH_3_ARGS(
jitted_vfunc, "JittedVecFunc", "econtext", ExprContextPtrType, "isNull", int8PtrType, "loop_index", int64Type);
llvm::Value* isNull = llvmargs[1];
llvm::BasicBlock* entry = &jitted_vfunc->getEntryBlock();
* Different FuncExprs have different number of arguments.
* Get the argument value according to listlength(FuncExpr->args)
* and all the cases should not be confused.
*/
FuncExprState* fcache = (FuncExprState*)args->exprstate;
FuncExpr* funcexpr = (FuncExpr*)(args->exprstate->expr);
List* func_args = fcache->args;
int num_args;
ExprState* func_arg1 = NULL;
ExprState* func_arg2 = NULL;
ExprState* func_arg3 = NULL;
Oid funcid = funcexpr->funcid;
const FmgrBuiltin* fbp = NULL;
bool func_is_strict = false;
* First check if the current func is strict or not.
* Fast path for builtin functions: don't bother consulting pg_proc
*/
if ((fbp = fmgr_isbuiltin(funcid)) != NULL) {
func_is_strict = fbp->strict;
} else {
HeapTuple procedureTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(procedureTuple))
ereport(ERROR,
(errcode(ERRCODE_CACHE_LOOKUP_FAILED),
errmodule(MOD_LLVM),
errmsg("cache lookup failed for function %u", funcid)));
Form_pg_proc procedureStruct = (Form_pg_proc)GETSTRUCT(procedureTuple);
func_is_strict = procedureStruct->proisstrict;
ReleaseSysCache(procedureTuple);
}
inner_builder.SetInsertPoint(entry);
num_args = funcexpr->args->length;
* Evaluate all the arguments of the FuncExpr and consider the combination
* of the null flag.
*/
llvm::Value* cmpor = NULL;
if (num_args > 0) {
func_arg1 = (ExprState*)linitial(func_args);
ExprCodeGenArgs largs = *args;
largs.exprstate = func_arg1;
largs.builder = &inner_builder;
largs.llvm_args = &llvmargs[0];
inargs[0] = CodeGen(&largs);
inargnulls[0] = llvmargs[1];
inargnulls[0] = inner_builder.CreateLoad(int8Type, inargnulls[0], "lflag");
cmpor = inargnulls[0];
if (!inargs[0]) {
ereport(ERROR,
(errcode(ERRCODE_CODEGEN_ERROR),
errmodule(MOD_LLVM),
errmsg("Codegen failed on the first argument of FuncExpr!\n")));
}
}
if (num_args > 1) {
func_arg2 = (ExprState*)lsecond(func_args);
ExprCodeGenArgs rargs = *args;
rargs.exprstate = func_arg2;
rargs.builder = &inner_builder;
rargs.llvm_args = &llvmargs[0];
inargs[1] = CodeGen(&rargs);
inargnulls[1] = llvmargs[1];
inargnulls[1] = inner_builder.CreateLoad(int8Type, inargnulls[1], "rflag");
cmpor = inner_builder.CreateOr(cmpor, inargnulls[1]);
if (!inargs[1]) {
ereport(ERROR,
(errcode(ERRCODE_CODEGEN_ERROR),
errmodule(MOD_LLVM),
errmsg("Codegen failed on the second argument of FuncExpr!\n")));
}
}
if (num_args > 2) {
func_arg3 = (ExprState*)lthird(func_args);
ExprCodeGenArgs targs = *args;
targs.exprstate = func_arg3;
targs.builder = &inner_builder;
targs.llvm_args = &llvmargs[0];
inargs[2] = CodeGen(&targs);
inargnulls[2] = llvmargs[1];
inargnulls[2] = inner_builder.CreateLoad(int8Type, inargnulls[2], "tflag");
cmpor = inner_builder.CreateOr(cmpor, inargnulls[2]);
if (!inargs[2]) {
ereport(ERROR,
(errcode(ERRCODE_CODEGEN_ERROR),
errmodule(MOD_LLVM),
errmsg("Codegen failed on the third argument of FuncExpr!\n")));
}
}
if (func_is_strict) {
DEFINE_BLOCK(bnot_null, jitted_vfunc);
DEFINE_BLOCK(be_null, jitted_vfunc);
DEFINE_BLOCK(ret_bb, jitted_vfunc);
cmpor = inner_builder.CreateTrunc(cmpor, int1Type);
inner_builder.CreateCondBr(cmpor, be_null, bnot_null);
inner_builder.SetInsertPoint(bnot_null);
switch (funcid) {
case SUBSTRFUNCOID: {
inargs[1] = inner_builder.CreateTrunc(inargs[1], int32Type);
inargs[2] = inner_builder.CreateTrunc(inargs[2], int32Type);
llvm::Function* func_substr = llvmCodeGen->module()->getFunction("Jittedsubstr");
if (func_substr == NULL) {
func_substr = substr_codegen();
}
* here we should consider the ORC compatiblity setting,
* if sql_compatiblity = ORC_FORMAT, and length of result is 0 (indicates by the 'isNull' flag),
* then we have to set 'isNull' flag to True,
* and then jump to the be_null block.
*/
if (u_sess->attr.attr_sql.sql_compatibility == A_FORMAT && !ACCEPT_EMPTY_STR) {
res1 = inner_builder.CreateCall(func_substr, {inargs[0], inargs[1], inargs[2], isNull});
llvm::Value* res_flag = inner_builder.CreateLoad(int8Type, isNull, "resflag");
llvm::Value* cmp = inner_builder.CreateICmpEQ(res_flag, null_true, "check");
inner_builder.CreateCondBr(cmp, be_null, ret_bb);
} else {
res1 = inner_builder.CreateCall(func_substr, {inargs[0], inargs[1], inargs[2]});
inner_builder.CreateStore(null_false, isNull);
inner_builder.CreateBr(ret_bb);
}
} break;
case RTRIM1FUNCOID:
case RTRIMPARAFUNCOID: {
llvm::Function* func_rtrim1 = llvmCodeGen->module()->getFunction("Jittedrtrim1");
if (func_rtrim1 == NULL) {
func_rtrim1 = rtrim1_codegen();
}
* here we should consider the ORC compatiblity setting,
* if sql_compatiblity = ORC_FORMAT, and length of result is 0 (indicates by the 'isNull' flag),
* then we have to set 'isNull' flag to True,
* and then jump to the be_null block.
*/
if (u_sess->attr.attr_sql.sql_compatibility == A_FORMAT && !ACCEPT_EMPTY_STR) {
res1 = inner_builder.CreateCall(func_rtrim1, {inargs[0], isNull});
llvm::Value* res_flag = inner_builder.CreateLoad(int8Type, isNull, "resflag");
llvm::Value* cmp = inner_builder.CreateICmpEQ(res_flag, null_true, "check");
inner_builder.CreateCondBr(cmp, be_null, ret_bb);
} else {
res1 = inner_builder.CreateCall(func_rtrim1, inargs[0]);
inner_builder.CreateStore(null_false, isNull);
inner_builder.CreateBr(ret_bb);
}
} break;
case BTRIMFUNCOID: {
llvm::Function* func_btrim1 = llvmCodeGen->module()->getFunction("Jittedbtrim1");
if (func_btrim1 == NULL) {
func_btrim1 = btrim1_codegen();
}
* here we should consider the ORC compatiblity setting,
* if sql_compatiblity = ORC_FORMAT, and length of result is 0 (indicates by the 'isNull' flag),
* then we have to set 'isNull' flag to True,
* and then jump to the be_null block.
*/
if (u_sess->attr.attr_sql.sql_compatibility == A_FORMAT && !ACCEPT_EMPTY_STR) {
res1 = inner_builder.CreateCall(func_btrim1, {inargs[0], isNull});
llvm::Value* res_flag = inner_builder.CreateLoad(int8Type, isNull, "resflag");
llvm::Value* cmp = inner_builder.CreateICmpEQ(res_flag, null_true, "check");
inner_builder.CreateCondBr(cmp, be_null, ret_bb);
} else {
res1 = inner_builder.CreateCall(func_btrim1, inargs[0]);
inner_builder.CreateStore(null_false, isNull);
inner_builder.CreateBr(ret_bb);
}
} break;
case BPLENFUNCOID: {
if (!u_sess->attr.attr_sql.dolphin) {
int current_encoding = GetDatabaseEncoding();
llvm::Function* func_bpcahrlen = llvmCodeGen->module()->getFunction("Jitted_bpcharlen");
if (func_bpcahrlen == NULL) {
func_bpcahrlen = bpcharlen_codegen(current_encoding);
}
res1 = inner_builder.CreateCall(func_bpcahrlen, inargs[0]);
inner_builder.CreateStore(null_false, isNull);
inner_builder.CreateBr(ret_bb);
break;
}
}
default: {
LLVMFuncCallInfo lfcinfo;
lfcinfo.nargs = list_length(funcexpr->args);
lfcinfo.args = &inargs[0];
res1 = EvalFuncResultCodeGen(&inner_builder, fcache, isNull, &lfcinfo);
inner_builder.CreateBr(ret_bb);
} break;
}
inner_builder.SetInsertPoint(be_null);
res2 = Datum_0;
inner_builder.CreateStore(null_true, isNull);
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(ret_bb);
llvm::PHINode* Phi_ret = inner_builder.CreatePHI(int64Type, 2);
Phi_ret->addIncoming(res1, bnot_null);
Phi_ret->addIncoming(res2, be_null);
inner_builder.CreateRet(Phi_ret);
} else {
LLVMFuncCallInfo lfcinfo;
lfcinfo.nargs = num_args;
lfcinfo.args = &inargs[0];
lfcinfo.argnulls = &inargnulls[0];
llvm::Value* res = EvalFuncResultCodeGen(&inner_builder, fcache, isNull, &lfcinfo);
inner_builder.CreateRet(res);
}
llvmCodeGen->FinalizeFunction(jitted_vfunc);
result = outer_builder->CreateCall(
jitted_vfunc, {args->llvm_args[0], args->llvm_args[1], args->llvm_args[2]}, "EvalVecFunc");
return result;
}
llvm::Value* VecExprCodeGen::OpCodeGen(ExprCodeGenArgs* args)
{
FuncExprState* fcache = (FuncExprState*)args->exprstate;
OpExpr* opexpr = (OpExpr*)(args->exprstate->expr);
List* op_args = fcache->args;
ExprState* lestate = NULL;
ExprState* restate = NULL;
int num_args = list_length(op_args);
if (num_args != 2)
return NULL;
dorado::GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
GsCodeGen::LlvmBuilder* outer_builder = args->builder;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder inner_builder(context);
llvm::Value* isNull = NULL;
llvm::Value* inargs[MAX_ARGS_NUM];
llvm::Value* inargnulls[MAX_ARGS_NUM];
llvm::Value* result = NULL;
llvm::Value* res1 = NULL;
llvm::Value* res2 = NULL;
llvm::Value* cmpor = NULL;
llvm::Value* llvmargs[3];
DEFINE_CG_TYPE(int1Type, BITOID);
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
DEFINE_CGVAR_INT8(null_false, 0);
DEFINE_CGVAR_INT8(null_true, 1);
DEFINE_CGVAR_INT64(Datum_0, 0);
DEFINE_CGVAR_INT64(Datum_1, 1);
DEFINE_FUNCTION_WITH_3_ARGS(
jitted_vop, "JittedVecOper", "econtext", ExprContextPtrType, "isNull", int8PtrType, "loop_index", int64Type);
isNull = llvmargs[1];
llvm::BasicBlock* entry = &jitted_vop->getEntryBlock();
lestate = (ExprState*)linitial(op_args);
restate = (ExprState*)lsecond(op_args);
inner_builder.SetInsertPoint(entry);
ExprCodeGenArgs largs;
largs = *args;
largs.exprstate = lestate;
largs.builder = &inner_builder;
largs.llvm_args = &llvmargs[0];
inargs[0] = CodeGen(&largs);
inargnulls[0] = llvmargs[1];
inargnulls[0] = inner_builder.CreateLoad(int8Type, inargnulls[0], "lflag");
ExprCodeGenArgs rargs;
rargs = *args;
rargs.exprstate = restate;
rargs.builder = &inner_builder;
rargs.llvm_args = &llvmargs[0];
inargs[1] = CodeGen(&rargs);
inargnulls[1] = llvmargs[1];
inargnulls[1] = inner_builder.CreateLoad(int8Type, inargnulls[1], "rflag");
if (inargs[0] == NULL || inargs[1] == NULL)
return NULL;
const FmgrBuiltin* fbp = NULL;
bool func_is_strict = false;
* Fast path for builtin functions: don't bother consulting pg_proc
*/
if ((fbp = fmgr_isbuiltin(opexpr->opfuncid)) != NULL) {
func_is_strict = fbp->strict;
} else {
HeapTuple procedureTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(opexpr->opfuncid));
if (!HeapTupleIsValid(procedureTuple))
ereport(ERROR,
(errcode(ERRCODE_CACHE_LOOKUP_FAILED),
errmodule(MOD_LLVM),
errmsg("cache lookup failed for function %u", opexpr->opfuncid)));
Form_pg_proc procedureStruct = (Form_pg_proc)GETSTRUCT(procedureTuple);
func_is_strict = procedureStruct->proisstrict;
ReleaseSysCache(procedureTuple);
}
* If the function is strict, we should not continue the evalution if one
* of the parameter is NULL. While for non-strict functions, do evalation
* directly without consider the null flag.
*/
if (func_is_strict) {
DEFINE_BLOCK(bnot_null, jitted_vop);
DEFINE_BLOCK(be_null, jitted_vop);
DEFINE_BLOCK(ret_bb, jitted_vop);
cmpor = inner_builder.CreateOr(inargnulls[0], inargnulls[1]);
cmpor = inner_builder.CreateTrunc(cmpor, int1Type);
inner_builder.CreateCondBr(cmpor, be_null, bnot_null);
inner_builder.SetInsertPoint(bnot_null);
* Only call the IR function when both the operands are not NULL.
* Once we have generated the IR function, we will not generate
* it again at the next time. The following functions we realized
* are all strict.
*/
switch (opexpr->opno) {
case OID_TEXT_LIKE_OP: {
llvm::Function* func_textlike = llvmCodeGen->module()->getFunction("Jitted_textlike");
if (func_textlike == NULL) {
func_textlike = textlike_codegen();
}
res1 = inner_builder.CreateCall(func_textlike, {inargs[0], inargs[1]}, "textlike");
} break;
case TEXTNOTLIKEOID: {
llvm::Function* func_textnlike = llvmCodeGen->module()->getFunction("Jitted_textnotlike");
if (func_textnlike == NULL) {
func_textnlike = textnlike_codegen();
}
res1 = inner_builder.CreateCall(func_textnlike, {inargs[0], inargs[1]}, "textnotlike");
} break;
case TEXTEQOID: {
llvm::Function* func_texteq = llvmCodeGen->module()->getFunction("Jitted_texteq");
if (func_texteq == NULL) {
func_texteq = texteq_codegen();
}
res1 = inner_builder.CreateCall(func_texteq, {inargs[0], inargs[1]}, "texteq");
} break;
case TEXTLTOID: {
DEFINE_CGVAR_INT32(collid, (long long)opexpr->inputcollid);
llvm::Function* func_textlt = llvmCodeGen->module()->getFunction("Jitted_textlt");
if (func_textlt == NULL) {
func_textlt = textlt_codegen();
}
res1 = inner_builder.CreateCall(func_textlt, {inargs[0], inargs[1], collid}, "textlt");
} break;
case TEXTGTOID: {
DEFINE_CGVAR_INT32(collid, (long long)opexpr->inputcollid);
llvm::Function* func_textgt = llvmCodeGen->module()->getFunction("Jitted_textgt");
if (func_textgt == NULL) {
func_textgt = textgt_codegen();
}
res1 = inner_builder.CreateCall(func_textgt, {inargs[0], inargs[1], collid}, "textgt");
} break;
case BPCHAREQOID:
case BPCHARNEOID: {
* 'const = var'. We could generate a fast path when the var
* length equals to the length of the const bpchar data.
*/
Expr* lexpr = lestate->expr;
Expr* rexpr = restate->expr;
bool fast_path = false;
Var* var = NULL;
Const* cst = NULL;
llvm::Value* const_data = NULL;
llvm::Value* len_val = NULL;
llvm::Value* var_data = NULL;
if (IsA(lexpr, Var) && IsA(rexpr, Const)) {
var = (Var*)lexpr;
cst = (Const*)rexpr;
var_data = inargs[0];
} else if (IsA(rexpr, Var) && IsA(lexpr, Const)) {
var = (Var*)rexpr;
cst = (Const*)lexpr;
var_data = inargs[1];
}
if (var != NULL && cst != NULL) {
int var_len = var->vartypmod - VARHDRSZ;
Datum const_val = cst->constvalue;
BpChar* const_bpchar = DatumGetBpCharPP(const_val);
int const_len = VARSIZE_ANY_EXHDR(const_bpchar);
if (var_len > 0 && var_len == const_len) {
llvm::Function* func_varlena = llvmCodeGen->module()->getFunction("JittedEvalVarlena");
if (func_varlena == NULL) {
func_varlena = VarlenaCvtCodeGen();
}
var_data = inner_builder.CreateCall(func_varlena, var_data, "var_val");
var_data = inner_builder.CreateExtractValue(var_data, 1);
char* const_char = VARDATA_ANY(const_bpchar);
const_data = llvmCodeGen->CastPtrToLlvmPtr(int8PtrType, (void*)const_char);
len_val = llvmCodeGen->getIntConstant(INT4OID, var_len);
fast_path = true;
}
}
if (opexpr->opno == BPCHAREQOID) {
if (fast_path) {
* the same length
*/
llvm::Function* func_memcmp = llvmCodeGen->module()->getFunction("LLVMIRmemcmp");
if (func_memcmp == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_IR_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Failed on getting IR function : LLVMIRmemcmp!\n")));
}
res1 = inner_builder.CreateCall(func_memcmp, {var_data, const_data, len_val}, "memcmp");
} else {
llvm::Function* func_bpchareq = llvmCodeGen->module()->getFunction("Jitted_bpchareq");
if (func_bpchareq == NULL) {
func_bpchareq = bpchareq_codegen();
}
res1 = inner_builder.CreateCall(func_bpchareq, {inargs[0], inargs[1]}, "bpchareq");
}
} else {
if (fast_path) {
* the same length
*/
llvm::Function* func_memcmp = llvmCodeGen->module()->getFunction("LLVMIRmemcmp");
if (func_memcmp == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_IR_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Failed on getting IR function : LLVMIRmemcmp!\n")));
}
res1 = inner_builder.CreateCall(func_memcmp, {var_data, const_data, len_val}, "memcmp");
res1 = inner_builder.CreateICmpNE(res1, Datum_1);
res1 = inner_builder.CreateZExt(res1, int64Type);
} else {
llvm::Function* func_bpcharne = llvmCodeGen->module()->getFunction("Jitted_bpcharne");
if (func_bpcharne == NULL) {
func_bpcharne = bpcharne_codegen();
}
res1 = inner_builder.CreateCall(func_bpcharne, {inargs[0], inargs[1]}, "bpcharne");
}
}
} break;
case DATEEQOID: {
llvm::Function* func_dateeq = llvmCodeGen->module()->getFunction("Jitted_dateeq");
if (func_dateeq == NULL) {
func_dateeq = date_eq_codegen();
}
res1 = inner_builder.CreateCall(func_dateeq, {inargs[0], inargs[1]}, "date_eq");
} break;
case DATENEOID: {
llvm::Function* func_datene = llvmCodeGen->module()->getFunction("Jitted_datene");
if (func_datene == NULL) {
func_datene = date_ne_codegen();
}
res1 = inner_builder.CreateCall(func_datene, {inargs[0], inargs[1]}, "date_ne");
} break;
case DATELTOID: {
llvm::Function* func_datelt = llvmCodeGen->module()->getFunction("Jitted_datelt");
if (func_datelt == NULL) {
func_datelt = date_lt_codegen();
}
res1 = inner_builder.CreateCall(func_datelt, {inargs[0], inargs[1]}, "date_lt");
} break;
case DATELEOID: {
llvm::Function* func_datele = llvmCodeGen->module()->getFunction("Jitted_datele");
if (func_datele == NULL) {
func_datele = date_le_codegen();
}
res1 = inner_builder.CreateCall(func_datele, {inargs[0], inargs[1]}, "date_le");
} break;
case DATEGTOID: {
llvm::Function* func_dategt = llvmCodeGen->module()->getFunction("Jitted_dategt");
if (func_dategt == NULL) {
func_dategt = date_gt_codegen();
}
res1 = inner_builder.CreateCall(func_dategt, {inargs[0], inargs[1]}, "date_gt");
} break;
case DATEGEOID: {
llvm::Function* func_datege = llvmCodeGen->module()->getFunction("Jitted_datege");
if (func_datege == NULL) {
func_datege = date_ge_codegen();
}
res1 = inner_builder.CreateCall(func_datege, {inargs[0], inargs[1]}, "date_ge");
} break;
case INT2EQOID: {
llvm::Function* func_int2eq = llvmCodeGen->module()->getFunction("Jitted_int2eq");
if (func_int2eq == NULL) {
func_int2eq = int2_sop_codegen<SOP_EQ>();
}
res1 = inner_builder.CreateCall(func_int2eq, {inargs[0], inargs[1]}, "int2_eq");
} break;
case INT24EQOID: {
llvm::Function* func_int24eq = llvmCodeGen->module()->getFunction("Jitted_int24eq");
if (func_int24eq == NULL) {
func_int24eq = int2_int4_sop_codegen<SOP_EQ, INT2OID>();
}
res1 = inner_builder.CreateCall(func_int24eq, {inargs[0], inargs[1]}, "int24_eq");
} break;
case INT42EQOID: {
llvm::Function* func_int42eq = llvmCodeGen->module()->getFunction("Jitted_int42eq");
if (func_int42eq == NULL) {
func_int42eq = int2_int4_sop_codegen<SOP_EQ, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int42eq, {inargs[0], inargs[1]}, "int42_eq");
} break;
case INT24NEOID: {
llvm::Function* func_int24ne = llvmCodeGen->module()->getFunction("Jitted_int24ne");
if (func_int24ne == NULL) {
func_int24ne = int2_int4_sop_codegen<SOP_NEQ, INT2OID>();
}
res1 = inner_builder.CreateCall(func_int24ne, {inargs[0], inargs[1]}, "int24_ne");
} break;
case INT42NEOID: {
llvm::Function* func_int42ne = llvmCodeGen->module()->getFunction("Jitted_int42ne");
if (func_int42ne == NULL) {
func_int42ne = int2_int4_sop_codegen<SOP_NEQ, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int42ne, {inargs[0], inargs[1]}, "int42_ne");
} break;
case INT24LTOID: {
llvm::Function* func_int24lt = llvmCodeGen->module()->getFunction("Jitted_int24lt");
if (func_int24lt == NULL) {
func_int24lt = int2_int4_sop_codegen<SOP_LT, INT2OID>();
}
res1 = inner_builder.CreateCall(func_int24lt, {inargs[0], inargs[1]}, "int24_lt");
} break;
case INT42LTOID: {
llvm::Function* func_int42lt = llvmCodeGen->module()->getFunction("Jitted_int42lt");
if (func_int42lt == NULL) {
func_int42lt = int2_int4_sop_codegen<SOP_LT, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int42lt, {inargs[0], inargs[1]}, "int42_lt");
} break;
case INT24LEOID: {
llvm::Function* func_int24le = llvmCodeGen->module()->getFunction("Jitted_int24le");
if (func_int24le == NULL) {
func_int24le = int2_int4_sop_codegen<SOP_LE, INT2OID>();
}
res1 = inner_builder.CreateCall(func_int24le, {inargs[0], inargs[1]}, "int24_le");
} break;
case INT42LEOID: {
llvm::Function* func_int42le = llvmCodeGen->module()->getFunction("Jitted_int42le");
if (func_int42le == NULL) {
func_int42le = int2_int4_sop_codegen<SOP_LE, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int42le, {inargs[0], inargs[1]}, "int42_le");
} break;
case INT24GTOID: {
llvm::Function* func_int24gt = llvmCodeGen->module()->getFunction("Jitted_int24gt");
if (func_int24gt == NULL) {
func_int24gt = int2_int4_sop_codegen<SOP_GT, INT2OID>();
}
res1 = inner_builder.CreateCall(func_int24gt, {inargs[0], inargs[1]}, "int24_gt");
} break;
case INT42GTOID: {
llvm::Function* func_int42gt = llvmCodeGen->module()->getFunction("Jitted_int42gt");
if (func_int42gt == NULL) {
func_int42gt = int2_int4_sop_codegen<SOP_GT, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int42gt, {inargs[0], inargs[1]}, "int42_gt");
} break;
case INT24GEOID: {
llvm::Function* func_int24ge = llvmCodeGen->module()->getFunction("Jitted_int24ge");
if (func_int24ge == NULL) {
func_int24ge = int2_int4_sop_codegen<SOP_GE, INT2OID>();
}
res1 = inner_builder.CreateCall(func_int24ge, {inargs[0], inargs[1]}, "int24_ge");
} break;
case INT42GEOID: {
llvm::Function* func_int42ge = llvmCodeGen->module()->getFunction("Jitted_int42ge");
if (func_int42ge == NULL) {
func_int42ge = int2_int4_sop_codegen<SOP_GE, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int42ge, {inargs[0], inargs[1]}, "int42_ge");
} break;
case INT48EQOID: {
llvm::Function* func_int48eq = llvmCodeGen->module()->getFunction("Jitted_int48eq");
if (func_int48eq == NULL) {
func_int48eq = int4_int8_sop_codegen<SOP_EQ, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int48eq, {inargs[0], inargs[1]}, "int48_eq");
} break;
case INT4EQOID: {
llvm::Function* func_int4eq = llvmCodeGen->module()->getFunction("Jitted_int4eq");
if (func_int4eq == NULL) {
func_int4eq = int4_sop_codegen<SOP_EQ>();
}
res1 = inner_builder.CreateCall(func_int4eq, {inargs[0], inargs[1]}, "int4_eq");
} break;
case INT84EQOID: {
llvm::Function* func_int84eq = llvmCodeGen->module()->getFunction("Jitted_int84eq");
if (func_int84eq == NULL) {
func_int84eq = int4_int8_sop_codegen<SOP_EQ, INT8OID>();
}
res1 = inner_builder.CreateCall(func_int84eq, {inargs[0], inargs[1]}, "int84_eq");
} break;
case INT8EQOID: {
llvm::Function* func_int8eq = llvmCodeGen->module()->getFunction("Jitted_int8eq");
if (func_int8eq == NULL) {
func_int8eq = int8_sop_codegen<SOP_EQ>();
}
res1 = inner_builder.CreateCall(func_int8eq, {inargs[0], inargs[1]}, "int8_eq");
} break;
case INT2NEOID: {
llvm::Function* func_int2ne = llvmCodeGen->module()->getFunction("Jitted_int2ne");
if (func_int2ne == NULL) {
func_int2ne = int2_sop_codegen<SOP_NEQ>();
}
res1 = inner_builder.CreateCall(func_int2ne, {inargs[0], inargs[1]}, "int2_ne");
} break;
case INT4NEOID: {
llvm::Function* func_int4ne = llvmCodeGen->module()->getFunction("Jitted_int4ne");
if (func_int4ne == NULL) {
func_int4ne = int4_sop_codegen<SOP_NEQ>();
}
res1 = inner_builder.CreateCall(func_int4ne, {inargs[0], inargs[1]}, "int4_ne");
} break;
case INT8NEOID: {
llvm::Function* func_int8ne = llvmCodeGen->module()->getFunction("Jitted_int8ne");
if (func_int8ne == NULL) {
func_int8ne = int8_sop_codegen<SOP_NEQ>();
}
res1 = inner_builder.CreateCall(func_int8ne, {inargs[0], inargs[1]}, "int8_ne");
} break;
case INT84NEOID: {
llvm::Function* func_int84ne = llvmCodeGen->module()->getFunction("Jitted_int84ne");
if (func_int84ne == NULL) {
func_int84ne = int4_int8_sop_codegen<SOP_NEQ, INT8OID>();
}
res1 = inner_builder.CreateCall(func_int84ne, {inargs[0], inargs[1]}, "int84_ne");
} break;
case INT48NEOID: {
llvm::Function* func_int48ne = llvmCodeGen->module()->getFunction("Jitted_int48ne");
if (func_int48ne == NULL) {
func_int48ne = int4_int8_sop_codegen<SOP_NEQ, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int48ne, {inargs[0], inargs[1]}, "int48_ne");
} break;
case INT2LTOID: {
llvm::Function* func_int2lt = llvmCodeGen->module()->getFunction("Jitted_int2lt");
if (func_int2lt == NULL) {
func_int2lt = int2_sop_codegen<SOP_LT>();
}
res1 = inner_builder.CreateCall(func_int2lt, {inargs[0], inargs[1]}, "int2_lt");
} break;
case INT4LTOID: {
llvm::Function* func_int4lt = llvmCodeGen->module()->getFunction("Jitted_int4lt");
if (func_int4lt == NULL) {
func_int4lt = int4_sop_codegen<SOP_LT>();
}
res1 = inner_builder.CreateCall(func_int4lt, {inargs[0], inargs[1]}, "int4_lt");
} break;
case INT48LTOID: {
llvm::Function* func_int48lt = llvmCodeGen->module()->getFunction("Jitted_int48lt");
if (func_int48lt == NULL) {
func_int48lt = int4_int8_sop_codegen<SOP_LT, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int48lt, {inargs[0], inargs[1]}, "int48_lt");
} break;
case INT8LTOID: {
llvm::Function* func_int8lt = llvmCodeGen->module()->getFunction("Jitted_int8lt");
if (func_int8lt == NULL) {
func_int8lt = int8_sop_codegen<SOP_LT>();
}
res1 = inner_builder.CreateCall(func_int8lt, {inargs[0], inargs[1]}, "int8_lt");
} break;
case INT84LTOID: {
llvm::Function* func_int84lt = llvmCodeGen->module()->getFunction("Jitted_int84lt");
if (func_int84lt == NULL) {
func_int84lt = int4_int8_sop_codegen<SOP_LT, INT8OID>();
}
res1 = inner_builder.CreateCall(func_int84lt, {inargs[0], inargs[1]}, "int84_lt");
} break;
case INT2LEOID: {
llvm::Function* func_int2le = llvmCodeGen->module()->getFunction("Jitted_int2le");
if (func_int2le == NULL) {
func_int2le = int2_sop_codegen<SOP_LE>();
}
res1 = inner_builder.CreateCall(func_int2le, {inargs[0], inargs[1]}, "int2_le");
} break;
case INT4LEOID: {
llvm::Function* func_int4le = llvmCodeGen->module()->getFunction("Jitted_int4le");
if (func_int4le == NULL) {
func_int4le = int4_sop_codegen<SOP_LE>();
}
res1 = inner_builder.CreateCall(func_int4le, {inargs[0], inargs[1]}, "int4_le");
} break;
case INT8LEOID: {
llvm::Function* func_int8le = llvmCodeGen->module()->getFunction("Jitted_int8le");
if (func_int8le == NULL) {
func_int8le = int8_sop_codegen<SOP_LE>();
}
res1 = inner_builder.CreateCall(func_int8le, {inargs[0], inargs[1]}, "int8_le");
} break;
case INT84LEOID: {
llvm::Function* func_int84le = llvmCodeGen->module()->getFunction("Jitted_int84le");
if (func_int84le == NULL) {
func_int84le = int4_int8_sop_codegen<SOP_LE, INT8OID>();
}
res1 = inner_builder.CreateCall(func_int84le, {inargs[0], inargs[1]}, "int84_le");
} break;
case INT48LEOID: {
llvm::Function* func_int48le = llvmCodeGen->module()->getFunction("Jitted_int48le");
if (func_int48le == NULL) {
func_int48le = int4_int8_sop_codegen<SOP_LE, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int48le, {inargs[0], inargs[1]}, "int48_le");
} break;
case INT2GTOID: {
llvm::Function* func_int2gt = llvmCodeGen->module()->getFunction("Jitted_int2gt");
if (func_int2gt == NULL) {
func_int2gt = int2_sop_codegen<SOP_GT>();
}
res1 = inner_builder.CreateCall(func_int2gt, {inargs[0], inargs[1]}, "int2_gt");
} break;
case INT4GTOID: {
llvm::Function* func_int4gt = llvmCodeGen->module()->getFunction("Jitted_int4gt");
if (func_int4gt == NULL) {
func_int4gt = int4_sop_codegen<SOP_GT>();
}
res1 = inner_builder.CreateCall(func_int4gt, {inargs[0], inargs[1]}, "int4_gt");
} break;
case INT48GTOID: {
llvm::Function* func_int48gt = llvmCodeGen->module()->getFunction("Jitted_int48gt");
if (func_int48gt == NULL) {
func_int48gt = int4_int8_sop_codegen<SOP_GT, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int48gt, {inargs[0], inargs[1]}, "int48_gt");
} break;
case INT84GTOID: {
llvm::Function* func_int84gt = llvmCodeGen->module()->getFunction("Jitted_int84gt");
if (func_int84gt == NULL) {
func_int84gt = int4_int8_sop_codegen<SOP_GT, INT8OID>();
}
res1 = inner_builder.CreateCall(func_int84gt, {inargs[0], inargs[1]}, "int84_gt");
} break;
case INT8GTOID: {
llvm::Function* func_int8gt = llvmCodeGen->module()->getFunction("Jitted_int8gt");
if (func_int8gt == NULL) {
func_int8gt = int8_sop_codegen<SOP_GT>();
}
res1 = inner_builder.CreateCall(func_int8gt, {inargs[0], inargs[1]}, "int8_gt");
} break;
case INT2GEOID: {
llvm::Function* func_int2ge = llvmCodeGen->module()->getFunction("Jitted_int2ge");
if (func_int2ge == NULL) {
func_int2ge = int2_sop_codegen<SOP_GE>();
}
res1 = inner_builder.CreateCall(func_int2ge, {inargs[0], inargs[1]}, "int2_ge");
} break;
case INT4GEOID: {
llvm::Function* func_int4ge = llvmCodeGen->module()->getFunction("Jitted_int4ge");
if (func_int4ge == NULL) {
func_int4ge = int4_sop_codegen<SOP_GE>();
}
res1 = inner_builder.CreateCall(func_int4ge, {inargs[0], inargs[1]}, "int4_ge");
} break;
case INT48GEOID: {
llvm::Function* func_int48ge = llvmCodeGen->module()->getFunction("Jitted_int48ge");
if (func_int48ge == NULL) {
func_int48ge = int4_int8_sop_codegen<SOP_GE, INT4OID>();
}
res1 = inner_builder.CreateCall(func_int48ge, {inargs[0], inargs[1]}, "int48_ge");
} break;
case INT8GEOID: {
llvm::Function* func_int8ge = llvmCodeGen->module()->getFunction("Jitted_int8ge");
if (func_int8ge == NULL) {
func_int8ge = int8_sop_codegen<SOP_GE>();
}
res1 = inner_builder.CreateCall(func_int8ge, {inargs[0], inargs[1]}, "int8_ge");
} break;
case INT84GEOID: {
llvm::Function* func_int84ge = llvmCodeGen->module()->getFunction("Jitted_int84ge");
if (func_int84ge == NULL) {
func_int84ge = int4_int8_sop_codegen<SOP_GE, INT8OID>();
}
res1 = inner_builder.CreateCall(func_int84ge, {inargs[0], inargs[1]}, "int84_ge");
} break;
case INT4MULOID: {
llvm::Function* func_int4mul = llvmCodeGen->module()->getFunction("Jitted_int4mul");
if (func_int4mul == NULL) {
func_int4mul = int4mul_codegen();
}
res1 = inner_builder.CreateCall(func_int4mul, {inargs[0], inargs[1]}, "int4_mul");
} break;
case INT8MULOID: {
llvm::Function* func_int8mul = llvmCodeGen->module()->getFunction("Jitted_int8mul");
if (func_int8mul == NULL) {
func_int8mul = int8mul_codegen();
}
res1 = inner_builder.CreateCall(func_int8mul, {inargs[0], inargs[1]}, "int8_mul");
} break;
case INT48MULOID: {
llvm::Function* func_int48mul = llvmCodeGen->module()->getFunction("Jitted_int48mul");
if (func_int48mul == NULL) {
func_int48mul = int48mul_codegen();
}
res1 = inner_builder.CreateCall(func_int48mul, {inargs[0], inargs[1]}, "int48_mul");
} break;
case INT84MULOID: {
llvm::Function* func_int84mul = llvmCodeGen->module()->getFunction("Jitted_int84mul");
if (func_int84mul == NULL) {
func_int84mul = int84mul_codegen();
}
res1 = inner_builder.CreateCall(func_int84mul, {inargs[0], inargs[1]}, "int84_mul");
} break;
case INT4PLOID: {
llvm::Function* func_int4pl = llvmCodeGen->module()->getFunction("Jitted_int4pl");
if (func_int4pl == NULL) {
func_int4pl = int4pl_codegen();
}
res1 = inner_builder.CreateCall(func_int4pl, {inargs[0], inargs[1]}, "int4_pl");
} break;
case INT8PLOID: {
llvm::Function* func_int8pl = llvmCodeGen->module()->getFunction("Jitted_int8pl");
if (func_int8pl == NULL) {
func_int8pl = int8pl_codegen();
}
res1 = inner_builder.CreateCall(func_int8pl, {inargs[0], inargs[1]}, "int8_pl");
} break;
case INT48PLOID: {
llvm::Function* func_int48pl = llvmCodeGen->module()->getFunction("Jitted_int48pl");
if (func_int48pl == NULL) {
func_int48pl = int48pl_codegen();
}
res1 = inner_builder.CreateCall(func_int48pl, {inargs[0], inargs[1]}, "int48_pl");
} break;
case INT84PLOID: {
llvm::Function* func_int84pl = llvmCodeGen->module()->getFunction("Jitted_int84pl");
if (func_int84pl == NULL) {
func_int84pl = int84pl_codegen();
}
res1 = inner_builder.CreateCall(func_int84pl, {inargs[0], inargs[1]}, "int84_pl");
} break;
case INT4MIOID: {
llvm::Function* func_int4mi = llvmCodeGen->module()->getFunction("Jitted_int4mi");
if (func_int4mi == NULL) {
func_int4mi = int4mi_codegen();
}
res1 = inner_builder.CreateCall(func_int4mi, {inargs[0], inargs[1]}, "int4_mi");
} break;
case INT8MIOID: {
llvm::Function* func_int8mi = llvmCodeGen->module()->getFunction("Jitted_int8mi");
if (func_int8mi == NULL) {
func_int8mi = int8mi_codegen();
}
res1 = inner_builder.CreateCall(func_int8mi, {inargs[0], inargs[1]}, "int8_mi");
} break;
case INT48MIOID: {
llvm::Function* func_int48mi = llvmCodeGen->module()->getFunction("Jitted_int48mi");
if (func_int48mi == NULL) {
func_int48mi = int48mi_codegen();
}
res1 = inner_builder.CreateCall(func_int48mi, {inargs[0], inargs[1]}, "int48_mi");
} break;
case INT84MIOID: {
llvm::Function* func_int84mi = llvmCodeGen->module()->getFunction("Jitted_int84mi");
if (func_int84mi == NULL) {
func_int84mi = int84mi_codegen();
}
res1 = inner_builder.CreateCall(func_int84mi, {inargs[0], inargs[1]}, "int84_mi");
} break;
case INT4DIVOID: {
llvm::Function* func_int4div = llvmCodeGen->module()->getFunction("Jitted_int4div");
if (func_int4div == NULL) {
func_int4div = int4div_codegen();
}
res1 = inner_builder.CreateCall(func_int4div, {inargs[0], inargs[1]}, "int4_div");
} break;
case INT8DIVOID: {
llvm::Function* func_int8div = llvmCodeGen->module()->getFunction("Jitted_int8div");
if (func_int8div == NULL) {
func_int8div = int8div_codegen();
}
res1 = inner_builder.CreateCall(func_int8div, {inargs[0], inargs[1]}, "int8_div");
} break;
case INT48DIVOID: {
llvm::Function* func_int48div = llvmCodeGen->module()->getFunction("Jitted_int48div");
if (func_int48div == NULL) {
func_int48div = int48div_codegen();
}
res1 = inner_builder.CreateCall(func_int48div, {inargs[0], inargs[1]}, "int48_div");
} break;
case INT84DIVOID: {
llvm::Function* func_int84div = llvmCodeGen->module()->getFunction("Jitted_int84div");
if (func_int84div == NULL) {
func_int84div = int84div_codegen();
}
res1 = inner_builder.CreateCall(func_int84div, {inargs[0], inargs[1]}, "int84_div");
} break;
case FLOAT8EQOID: {
llvm::Function* func_float8eq = llvmCodeGen->module()->getFunction("Jitted_float8eq");
if (func_float8eq == NULL) {
func_float8eq = float8eq_codegen();
}
res1 = inner_builder.CreateCall(func_float8eq, {inargs[0], inargs[1]}, "float8_eq");
} break;
case FLOAT8NEOID: {
llvm::Function* func_float8ne = llvmCodeGen->module()->getFunction("Jitted_float8ne");
if (func_float8ne == NULL) {
func_float8ne = float8ne_codegen();
}
res1 = inner_builder.CreateCall(func_float8ne, {inargs[0], inargs[1]}, "float8_ne");
} break;
case FLOAT8LTOID: {
llvm::Function* func_float8lt = llvmCodeGen->module()->getFunction("Jitted_float8lt");
if (func_float8lt == NULL) {
func_float8lt = float8lt_codegen();
}
res1 = inner_builder.CreateCall(func_float8lt, {inargs[0], inargs[1]}, "float8_lt");
} break;
case FLOAT8LEOID: {
llvm::Function* func_float8le = llvmCodeGen->module()->getFunction("Jitted_float8le");
if (func_float8le == NULL) {
func_float8le = float8le_codegen();
}
res1 = inner_builder.CreateCall(func_float8le, {inargs[0], inargs[1]}, "float8_le");
} break;
case FLOAT8GTOID: {
llvm::Function* func_float8gt = llvmCodeGen->module()->getFunction("Jitted_float8gt");
if (func_float8gt == NULL) {
func_float8gt = float8gt_codegen();
}
res1 = inner_builder.CreateCall(func_float8gt, {inargs[0], inargs[1]}, "float8_gt");
} break;
case FLOAT8GEOID: {
llvm::Function* func_float8ge = llvmCodeGen->module()->getFunction("Jitted_float8ge");
if (func_float8ge == NULL) {
func_float8ge = float8ge_codegen();
}
res1 = inner_builder.CreateCall(func_float8ge, {inargs[0], inargs[1]}, "float8_ge");
} break;
case TIMESTAMPEQOID: {
llvm::Function* func_timestampeq = llvmCodeGen->module()->getFunction("Jitted_timestampeq");
if (func_timestampeq == NULL) {
func_timestampeq = timestamp_eq_codegen();
}
res1 = inner_builder.CreateCall(func_timestampeq, {inargs[0], inargs[1]}, "timestamp_eq");
} break;
case TIMESTAMPNEOID: {
llvm::Function* func_timestampne = llvmCodeGen->module()->getFunction("Jitted_timestampne");
if (func_timestampne == NULL) {
func_timestampne = timestamp_ne_codegen();
}
res1 = inner_builder.CreateCall(func_timestampne, {inargs[0], inargs[1]}, "timestamp_ne");
} break;
case TIMESTAMPLTOID: {
llvm::Function* func_timestamplt = llvmCodeGen->module()->getFunction("Jitted_timestamplt");
if (func_timestamplt == NULL) {
func_timestamplt = timestamp_lt_codegen();
}
res1 = inner_builder.CreateCall(func_timestamplt, {inargs[0], inargs[1]}, "timestamp_lt");
} break;
case TIMESTAMPLEOID: {
llvm::Function* func_timestample = llvmCodeGen->module()->getFunction("Jitted_timestample");
if (func_timestample == NULL) {
func_timestample = timestamp_le_codegen();
}
res1 = inner_builder.CreateCall(func_timestample, {inargs[0], inargs[1]}, "timestamp_le");
} break;
case TIMESTAMPGTOID: {
llvm::Function* func_timestampgt = llvmCodeGen->module()->getFunction("Jitted_timestampgt");
if (func_timestampgt == NULL) {
func_timestampgt = timestamp_gt_codegen();
}
res1 = inner_builder.CreateCall(func_timestampgt, {inargs[0], inargs[1]}, "timestamp_gt");
} break;
case TIMESTAMPGEOID: {
llvm::Function* func_timestampge = llvmCodeGen->module()->getFunction("Jitted_timestampge");
if (func_timestampge == NULL) {
func_timestampge = timestamp_ge_codegen();
}
res1 = inner_builder.CreateCall(func_timestampge, {inargs[0], inargs[1]}, "timestamp_ge");
} break;
case NUMERICADDOID: {
llvm::Function* func_numericadd = llvmCodeGen->module()->getFunction("Jitted_numericadd");
if (func_numericadd == NULL) {
func_numericadd = numeric_sop_codegen<BIADD>();
}
res1 = inner_builder.CreateCall(func_numericadd, {inargs[0], inargs[1]}, "numeric_add");
} break;
case NUMERICSUBOID: {
llvm::Function* func_numericsub = llvmCodeGen->module()->getFunction("Jitted_numericsub");
if (func_numericsub == NULL) {
func_numericsub = numeric_sop_codegen<BISUB>();
}
res1 = inner_builder.CreateCall(func_numericsub, {inargs[0], inargs[1]}, "numeric_sub");
} break;
case NUMERICMULOID: {
llvm::Function* func_numericmul = llvmCodeGen->module()->getFunction("Jitted_numericmul");
if (func_numericmul == NULL) {
func_numericmul = numeric_sop_codegen<BIMUL>();
}
res1 = inner_builder.CreateCall(func_numericmul, {inargs[0], inargs[1]}, "numeric_mul");
} break;
case NUMERICDIVOID: {
llvm::Function* func_numericdiv = llvmCodeGen->module()->getFunction("Jitted_numericdiv");
if (func_numericdiv == NULL) {
func_numericdiv = numeric_sop_codegen<BIDIV>();
}
res1 = inner_builder.CreateCall(func_numericdiv, {inargs[0], inargs[1]}, "numeric_div");
} break;
case NUMERICEQOID:
case NUMERICNEOID:
case NUMERICLEOID:
case NUMERICLTOID:
case NUMERICGTOID:
case NUMERICGEOID: {
bool fast_numericop = NumericOpFastJittable(args->exprstate);
if (fast_numericop) {
res1 = FastNumericOpCodeGen(&inner_builder, args->exprstate, inargs[0], inargs[1]);
} else {
res1 = NormalNumericOpCodeGen(&inner_builder, opexpr->opno, inargs[0], inargs[1]);
}
} break;
default: {
LLVMFuncCallInfo lfcinfo;
lfcinfo.nargs = num_args;
lfcinfo.args = &inargs[0];
res1 = EvalFuncResultCodeGen(&inner_builder, fcache, isNull, &lfcinfo);
} break;
}
inner_builder.CreateStore(null_false, isNull);
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(be_null);
res2 = Datum_0;
inner_builder.CreateStore(null_true, isNull);
inner_builder.CreateBr(ret_bb);
inner_builder.SetInsertPoint(ret_bb);
llvm::PHINode* Phi_ret = inner_builder.CreatePHI(int64Type, 2);
Phi_ret->addIncoming(res1, bnot_null);
Phi_ret->addIncoming(res2, be_null);
inner_builder.CreateRet(Phi_ret);
} else {
LLVMFuncCallInfo lfcinfo;
lfcinfo.nargs = num_args;
lfcinfo.args = &inargs[0];
lfcinfo.argnulls = &inargnulls[0];
llvm::Value* res = EvalFuncResultCodeGen(&inner_builder, fcache, isNull, &lfcinfo);
inner_builder.CreateRet(res);
}
llvmCodeGen->FinalizeFunction(jitted_vop);
result = outer_builder->CreateCall(
jitted_vop, {args->llvm_args[0], args->llvm_args[1], args->llvm_args[2]}, "EvalVecOp");
return result;
}
llvm::Value* VecExprCodeGen::FastNumericOpCodeGen(
GsCodeGen::LlvmBuilder* ptrbuilder, ExprState* estate, llvm::Value* larg, llvm::Value* rarg)
{
dorado::GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
FuncExprState* fcache = (FuncExprState*)estate;
OpExpr* opexpr = (OpExpr*)(estate->expr);
List* op_args = fcache->args;
ExprState* lestate = (ExprState*)linitial(op_args);
;
ExprState* restate = (ExprState*)lsecond(op_args);
;
bool isvarconst = true;
if (!(IsA(lestate->expr, Var) && IsA(restate->expr, Const)))
isvarconst = false;
llvm::Value* result = NULL;
switch (opexpr->opno) {
case NUMERICEQOID: {
if (isvarconst) {
llvm::Function* func_fnumericeq = llvmCodeGen->module()->getFunction("Jitted_fast_numericeq");
if (func_fnumericeq == NULL) {
func_fnumericeq = fast_numericbi_sop_codegen<BIEQ>();
}
result = ptrbuilder->CreateCall(func_fnumericeq, {larg, rarg}, "numeric_eq");
} else {
llvm::Function* func_fnumericeq = llvmCodeGen->module()->getFunction("Jitted_fast_revnumericeq");
if (func_fnumericeq == NULL) {
func_fnumericeq = fast_numericbi_sop_codegen<BIEQ>();
}
result = ptrbuilder->CreateCall(func_fnumericeq, {rarg, larg}, "numeric_eq");
}
} break;
case NUMERICNEOID: {
if (isvarconst) {
llvm::Function* func_fnumericne = llvmCodeGen->module()->getFunction("Jitted_fast_numericne");
if (func_fnumericne == NULL) {
func_fnumericne = fast_numericbi_sop_codegen<BINEQ>();
}
result = ptrbuilder->CreateCall(func_fnumericne, {larg, rarg}, "numeric_ne");
} else {
llvm::Function* func_fnumericne = llvmCodeGen->module()->getFunction("Jitted_fast_revnumericne");
if (func_fnumericne == NULL) {
func_fnumericne = fast_numericbi_sop_codegen<BINEQ>();
}
result = ptrbuilder->CreateCall(func_fnumericne, {rarg, larg}, "numeric_ne");
}
} break;
case NUMERICLTOID: {
if (isvarconst) {
llvm::Function* func_fnumericlt = llvmCodeGen->module()->getFunction("Jitted_fast_numericlt");
if (func_fnumericlt == NULL) {
func_fnumericlt = fast_numericbi_sop_codegen<BILT>();
}
result = ptrbuilder->CreateCall(func_fnumericlt, {larg, rarg}, "numeric_lt");
} else {
llvm::Function* func_fnumericlt = llvmCodeGen->module()->getFunction("Jitted_fast_revnumericlt");
if (func_fnumericlt == NULL) {
func_fnumericlt = fast_numericbi_sop_codegen<BIGT>();
}
result = ptrbuilder->CreateCall(func_fnumericlt, {rarg, larg}, "reverse_numeric_gt");
}
} break;
case NUMERICLEOID: {
if (isvarconst) {
llvm::Function* func_fnumericle = llvmCodeGen->module()->getFunction("Jitted_fast_numericle");
if (func_fnumericle == NULL) {
func_fnumericle = fast_numericbi_sop_codegen<BILE>();
}
result = ptrbuilder->CreateCall(func_fnumericle, {larg, rarg}, "numeric_le");
} else {
llvm::Function* func_fnumericle = llvmCodeGen->module()->getFunction("Jitted_fast_revnumericle");
if (func_fnumericle == NULL) {
func_fnumericle = fast_numericbi_sop_codegen<BIGE>();
}
result = ptrbuilder->CreateCall(func_fnumericle, {rarg, larg}, "reverse_numeric_ge");
}
} break;
case NUMERICGTOID: {
if (isvarconst) {
llvm::Function* func_fnumericgt = llvmCodeGen->module()->getFunction("Jitted_fast_numericgt");
if (func_fnumericgt == NULL) {
func_fnumericgt = fast_numericbi_sop_codegen<BIGT>();
}
result = ptrbuilder->CreateCall(func_fnumericgt, {larg, rarg}, "numeric_gt");
} else {
llvm::Function* func_fnumericgt = llvmCodeGen->module()->getFunction("Jitted_fast_revnumericgt");
if (func_fnumericgt == NULL) {
func_fnumericgt = fast_numericbi_sop_codegen<BILT>();
}
result = ptrbuilder->CreateCall(func_fnumericgt, {rarg, larg}, "reverse_numeric_lt");
}
} break;
case NUMERICGEOID: {
if (isvarconst) {
llvm::Function* func_fnumericge = llvmCodeGen->module()->getFunction("Jitted_fast_numericge");
if (func_fnumericge == NULL) {
func_fnumericge = fast_numericbi_sop_codegen<BIGE>();
}
result = ptrbuilder->CreateCall(func_fnumericge, {larg, rarg}, "numeric_ge");
} else {
llvm::Function* func_fnumericge = llvmCodeGen->module()->getFunction("Jitted_fast_revnumericge");
if (func_fnumericge == NULL) {
func_fnumericge = fast_numericbi_sop_codegen<BILE>();
}
result = ptrbuilder->CreateCall(func_fnumericge, {rarg, larg}, "reverse_numeric_le");
}
} break;
default:
Assert(0);
break;
}
return result;
}
llvm::Value* VecExprCodeGen::NormalNumericOpCodeGen(
GsCodeGen::LlvmBuilder* ptrbuilder, Oid funcoid, llvm::Value* larg, llvm::Value* rarg)
{
llvm::Value* result = NULL;
dorado::GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
switch (funcoid) {
case NUMERICEQOID: {
llvm::Function* func_numericeq = llvmCodeGen->module()->getFunction("Jitted_numericeq");
if (func_numericeq == NULL) {
func_numericeq = numeric_sop_codegen<BIEQ>();
}
result = ptrbuilder->CreateCall(func_numericeq, {larg, rarg}, "numeric_eq");
} break;
case NUMERICNEOID: {
llvm::Function* func_numericne = llvmCodeGen->module()->getFunction("Jitted_numericne");
if (func_numericne == NULL) {
func_numericne = numeric_sop_codegen<BINEQ>();
}
result = ptrbuilder->CreateCall(func_numericne, {larg, rarg}, "numeric_ne");
} break;
case NUMERICLEOID: {
llvm::Function* func_numericle = llvmCodeGen->module()->getFunction("Jitted_numericle");
if (func_numericle == NULL) {
func_numericle = numeric_sop_codegen<BILE>();
}
result = ptrbuilder->CreateCall(func_numericle, {larg, rarg}, "numeric_le");
} break;
case NUMERICLTOID: {
llvm::Function* func_numericlt = llvmCodeGen->module()->getFunction("Jitted_numericlt");
if (func_numericlt == NULL) {
func_numericlt = numeric_sop_codegen<BILT>();
}
result = ptrbuilder->CreateCall(func_numericlt, {larg, rarg}, "numeric_lt");
} break;
case NUMERICGEOID: {
llvm::Function* func_numericge = llvmCodeGen->module()->getFunction("Jitted_numericge");
if (func_numericge == NULL) {
func_numericge = numeric_sop_codegen<BIGE>();
}
result = ptrbuilder->CreateCall(func_numericge, {larg, rarg}, "numeric_ge");
} break;
case NUMERICGTOID: {
llvm::Function* func_numericgt = llvmCodeGen->module()->getFunction("Jitted_numericgt");
if (func_numericgt == NULL) {
func_numericgt = numeric_sop_codegen<BIGT>();
}
result = ptrbuilder->CreateCall(func_numericgt, {larg, rarg}, "numeric_gt");
} break;
default:
Assert(0);
break;
}
return result;
}
llvm::Value* VecExprCodeGen::VarCodeGen(ExprCodeGenArgs* args)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder* outer_builder = args->builder;
GsCodeGen::LlvmBuilder inner_builder(context);
llvm::Value* econtext = NULL;
llvm::Value* isNull = NULL;
llvm::Value* loop_index = NULL;
DEFINE_CG_TYPE(int8Type, BOOLOID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
DEFINE_CG_PTRTYPE(VecBatchPtrType, "class.VectorBatch");
DEFINE_CG_PTRTYPE(ScalarVectorPtrType, "class.ScalarVector");
DEFINE_CGVAR_INT8(null_false, 0);
DEFINE_CGVAR_INT8(null_true, 1);
DEFINE_CGVAR_INT32(m_flagoffset, 3);
DEFINE_CGVAR_INT32(m_arroffset, 4);
DEFINE_CGVAR_INT32(m_valsoffset, 5);
DEFINE_CGVAR_INT32(ecxt_scanbatch_offset, 17);
DEFINE_CGVAR_INT32(ecxt_innerbatch_offset, 18);
DEFINE_CGVAR_INT32(ecxt_outerbatch_offset, 19);
DEFINE_CGVAR_INT64(val_0, 0);
llvm::Value* llvmargs[3];
llvm::Value* argVals[2];
llvm::Value* ecxt_batch = NULL;
llvm::Value* argFlag = NULL;
llvm::Value* argVector = NULL;
llvm::Value* result = NULL;
llvm::Value* val1 = NULL;
llvm::Value* val2 = NULL;
DEFINE_FUNCTION_WITH_3_ARGS(jitted_sval,
"JittedVecScanVar",
"econtext",
ExprContextPtrType,
"isNull",
int8PtrType,
"loop_index",
int64Type);
econtext = llvmargs[0];
isNull = llvmargs[1];
loop_index = llvmargs[2];
* Get the VectorBatch from econtext according to varno.
*
* The second value of array argVals represents the ordinal number in data
* structure 'ExprContext', say, *ecxt->innerbatch is the 18th element of
* ExprContext. It also means if the order is changed, we should change these
* values correspondingly.
*/
Var* var = (Var*)((args->exprstate)->expr);
bool is_notnull = false;
FormData_pg_attribute* attr = NULL;
if ((args->parent != NULL) && IsA(args->parent, CStoreScanState)) {
CStoreScanState* scanstate = (CStoreScanState*)args->parent;
if (!scanstate->isPartTbl && scanstate->ss_currentRelation) {
attr = &scanstate->ss_currentRelation->rd_att->attrs[var->varattno - 1];
is_notnull = attr->attnotnull;
}
}
argVals[0] = val_0;
if (var->varno == INNER_VAR) {
argVals[1] = ecxt_innerbatch_offset;
} else if (var->varno == OUTER_VAR) {
argVals[1] = ecxt_outerbatch_offset;
} else {
argVals[1] = ecxt_scanbatch_offset;
}
ecxt_batch = inner_builder.CreateInBoundsGEP(econtext, argVals);
ecxt_batch = inner_builder.CreateLoad(VecBatchPtrType, ecxt_batch, "batch");
argVals[1] = m_arroffset;
argVector = inner_builder.CreateInBoundsGEP(ecxt_batch, argVals);
argVector = inner_builder.CreateLoad(ScalarVectorPtrType, argVector, "m_arr");
DEFINE_CGVAR_INT64(m_attno, var->varattno - 1);
* if the attribute is defined with 'NOT NULL' constraint, we no need to
* load the m_flag, else check the m_flag to see is this value is NULL.
*/
if (!is_notnull) {
llvm::BasicBlock* entry = &jitted_sval->getEntryBlock();
DEFINE_BLOCK(if_then, jitted_sval);
DEFINE_BLOCK(if_else, jitted_sval);
DEFINE_BLOCK(if_end, jitted_sval);
argVals[0] = m_attno;
argVals[1] = m_flagoffset;
argFlag = inner_builder.CreateInBoundsGEP(argVector, argVals);
argFlag = inner_builder.CreateLoad(int8PtrType, argFlag, "m_flag");
inner_builder.SetInsertPoint(entry);
llvm::Value* tmpNull = inner_builder.CreateInBoundsGEP(argFlag, loop_index);
tmpNull = inner_builder.CreateLoad(int8Type, tmpNull);
* As we do in c-code, we should use (flag)&V_NULL_MASK to get the actual
* flag. After this, mask isNull with null_true and null_false.
*/
tmpNull = inner_builder.CreateAnd(tmpNull, null_true);
llvm::Value* cmp = inner_builder.CreateICmpEQ(tmpNull, null_false);
inner_builder.CreateCondBr(cmp, if_then, if_else);
inner_builder.SetInsertPoint(if_then);
argVals[1] = m_valsoffset;
argVector = inner_builder.CreateInBoundsGEP(argVector, argVals);
argVector = inner_builder.CreateLoad(int64PtrType, argVector, "m_vals");
argVector = inner_builder.CreateInBoundsGEP(argVector, loop_index);
val1 = inner_builder.CreateLoad(int64Type, argVector);
inner_builder.CreateStore(null_false, isNull);
inner_builder.CreateBr(if_end);
inner_builder.SetInsertPoint(if_else);
val2 = val_0;
inner_builder.CreateStore(null_true, isNull);
inner_builder.CreateBr(if_end);
inner_builder.SetInsertPoint(if_end);
llvm::PHINode* Phi_ret = inner_builder.CreatePHI(int64Type, 2);
Phi_ret->addIncoming(val1, if_then);
Phi_ret->addIncoming(val2, if_else);
inner_builder.CreateRet(Phi_ret);
} else {
argVals[0] = m_attno;
argVals[1] = m_valsoffset;
argVector = inner_builder.CreateInBoundsGEP(argVector, argVals);
argVector = inner_builder.CreateLoad(int64PtrType, argVector, "m_vals");
argVector = inner_builder.CreateInBoundsGEP(argVector, loop_index);
llvm::Value* res = inner_builder.CreateLoad(int64Type, argVector);
inner_builder.CreateStore(null_false, isNull);
inner_builder.CreateRet(res);
}
llvmCodeGen->FinalizeFunction(jitted_sval);
result = outer_builder->CreateCall(
jitted_sval, {args->llvm_args[0], args->llvm_args[1], args->llvm_args[2]}, "VecEvalVar");
return result;
}
llvm::Value* VecExprCodeGen::ConstCodeGen(ExprCodeGenArgs* args)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder* outer_builder = args->builder;
GsCodeGen::LlvmBuilder inner_builder(context);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
llvm::Value* llvmargs[3];
llvm::Value* isNull = NULL;
llvm::Value* tmpNull = NULL;
llvm::Value* result = NULL;
DEFINE_FUNCTION_WITH_3_ARGS(
jitted_cst, "JittedEvalConst", "econtext", ExprContextPtrType, "isNull", int8PtrType, "loop_index", int64Type);
isNull = llvmargs[1];
Const* cst = (Const*)((args->exprstate)->expr);
tmpNull = llvmCodeGen->getIntConstant(CHAROID, cst->constisnull);
inner_builder.CreateStore(tmpNull, isNull);
ScalarValue val = ScalarVector::DatumToScalar(cst->constvalue, cst->consttype, cst->constisnull);
result = llvmCodeGen->getIntConstant(INT8OID, val);
inner_builder.CreateRet(result);
llvmCodeGen->FinalizeFunction(jitted_cst);
result = outer_builder->CreateCall(
jitted_cst, {args->llvm_args[0], args->llvm_args[1], args->llvm_args[2]}, "VecEvalConst");
return result;
}
* We show here an example to interpret the generated IR function with the
* following IR API Builder Code. If we have the query:
* select (a + 1) * 2 from test;
* then we arrived at the following IR function:
* define i8 @JittedVecTargetList(%struct.ExprContext* %econtext, %class.VectorBatch* %pBatch) {
* entry:
* %0 = alloca i8
* %1 = call %class.VectorBatch* @LLVMWrapGetVecBatch(%struct.ExprContext* %econtext)
* %2 = getelementptr inbounds %class.VectorBatch* %1, i64 0, i32 0
* %m_rows = load i32* %2, align 4
* %3 = getelementptr inbounds %class.VectorBatch* %pBatch, i64 0, i32 0
* store i32 %m_rows, i32* %3, align 4
* %4 = icmp sgt i32 %m_rows, 0
* br i1 %4, label %for_body, label %ret_bb
* for_body: ; preds = %bb_end, %entry
* %5 = phi i64 [ 0, %entry ], [ %6, %bb_end ]
* %6 = add i64 %5, 1
* %7 = getelementptr inbounds %class.VectorBatch* %pBatch, i64 0, i32 4
* %m_arr = load %class.ScalarVector** %7, align 8
* %EvalVecOp = call i64 @JittedVecOper(%struct.ExprContext* %econtext, i8* %0, i64 %5)
* %8 = getelementptr inbounds %class.ScalarVector* %m_arr, i32 0, i32 5
* %m_vals = load i64** %8, align 8
* %9 = getelementptr inbounds i64* %m_vals, i64 %5
* store i64 %EvalVecOp, i64* %9, align 8
* %10 = getelementptr inbounds %class.ScalarVector* %m_arr, i32 0, i32 3
* %m_flag = load i8** %10, align 1
* %11 = getelementptr inbounds i8* %m_flag, i64 %5
* %12 = load i8* %0, align 1
* store i8 %12, i8* %11, align 1
* br label %bb_end
* bb_end: ; preds = %for_body
* %13 = trunc i64 %6 to i32
* %14 = icmp eq i32 %13, %m_rows
* br i1 %14, label %for_end, label %for_body
* for_end: ; preds = %bb_end
* %15 = getelementptr inbounds %class.ScalarVector* %m_arr, i32 0, i32 0
* store i32 %m_rows, i32* %15, align 4
* br label %ret_bb
* ret_bb: ; preds = %for_end, %entry
* ret i8 1
* }
* */
llvm::Function* VecExprCodeGen::TargetListCodeGen(List* targetlist, PlanState* parent)
{
Assert(NULL != (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj);
dorado::GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
if (!TargetListJittable(targetlist))
return NULL;
* If we already have a module, we do not need to load the IR
* file to get the module.
*/
llvmCodeGen->loadIRFile();
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int32Type, INT4OID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_TYPE(boolType, BOOLOID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
DEFINE_CG_PTRTYPE(VectorBatchPtrType, "class.VectorBatch");
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
DEFINE_CG_PTRTYPE(ScalarVectorPtrType, "class.ScalarVector");
DEFINE_CG_PTRTYPE(MemContextPtrType, "struct.MemoryContextData");
DEFINE_CGVAR_INT8(int8_1, 1);
DEFINE_CGVAR_INT32(int32_0, 0);
DEFINE_CGVAR_INT32(m_flagoffset, 3);
DEFINE_CGVAR_INT32(m_arroffset, 4);
DEFINE_CGVAR_INT32(m_valsoffset, 5);
DEFINE_CGVAR_INT32(ecxt_tupmem_offset, 5);
DEFINE_CGVAR_INT64(Datum_0, 0);
DEFINE_CGVAR_INT64(Datum_1, 1);
llvm::BasicBlock* bb_next = NULL;
llvm::BasicBlock** bb_list = NULL;
llvm::PHINode* Phi_idx = NULL;
llvm::Value* econtext = NULL;
llvm::Value* pBatch = NULL;
llvm::Value* isNull = NULL;
llvm::Value* res = NULL;
llvm::Value* val = NULL;
llvm::Value* val1 = NULL;
llvm::Value* ecxt_batch = NULL;
llvm::Value* nsize = NULL;
llvm::Value* idx_next = NULL;
llvm::Value* loop_index = NULL;
llvm::Value* argArr = NULL;
llvm::Value* argVec = NULL;
llvm::Value* argVal = NULL;
llvm::Value* argFlag = NULL;
llvm::Value* curr_Context = NULL;
llvm::Value* cg_oldContext = NULL;
llvm::Value* Vals[] = {Datum_0, int32_0};
llvm::Value* llvmargs[3];
llvm::Value* exprargs[3];
llvm::Function* jitted_vectarget = NULL;
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "JittedVecTargetList", boolType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("econtext", ExprContextPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("pBatch", VectorBatchPtrType));
jitted_vectarget = fn_prototype.generatePrototype(&builder, &llvmargs[0]);
econtext = llvmargs[0];
pBatch = llvmargs[1];
isNull = builder.CreateAlloca(int8Type);
* Get number of rows of this vectorbatch : since different node get their
* data source from different sub-tree, we should get the actual batch
* info. from econtext.
*/
ecxt_batch = WrapGetVectorBatchCodeGen(&builder, econtext);
Vals[0] = Datum_0;
Vals[1] = int32_0;
val = builder.CreateInBoundsGEP(ecxt_batch, Vals);
nsize = builder.CreateLoad(int32Type, val, "m_rows");
llvm::Value* mrows = builder.CreateInBoundsGEP(pBatch, Vals);
builder.CreateStore(nsize, mrows);
Vals[1] = ecxt_tupmem_offset;
curr_Context = builder.CreateInBoundsGEP(econtext, Vals);
curr_Context = builder.CreateLoad(MemContextPtrType, curr_Context, "per_tuple_memory");
cg_oldContext = MemCxtSwitToCodeGen(&builder, curr_Context);
llvm::BasicBlock* entry = &jitted_vectarget->getEntryBlock();
DEFINE_BLOCK(for_body, jitted_vectarget);
DEFINE_BLOCK(bb_end, jitted_vectarget);
DEFINE_BLOCK(for_end, jitted_vectarget);
DEFINE_BLOCK(ret_bb, jitted_vectarget);
builder.SetInsertPoint(entry);
val = builder.CreateICmpSGT(nsize, int32_0);
builder.CreateCondBr(val, for_body, ret_bb);
builder.SetInsertPoint(for_body);
Phi_idx = builder.CreatePHI(int64Type, 2);
idx_next = builder.CreateAdd(Phi_idx, Datum_1);
Phi_idx->addIncoming(Datum_0, entry);
Phi_idx->addIncoming(idx_next, bb_end);
* For each time, we deal with one tuple. Phi_idx should be passed
* as 'loop index' in 'for' structure.
*/
loop_index = (llvm::Value*)Phi_idx;
int target_len = list_length(targetlist);
int tl_index = 0;
ListCell* cell = NULL;
if (target_len > 1) {
bb_list = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * target_len);
bb_list[0] = for_body;
}
ExprCodeGenArgs args;
args.parent = parent;
args.builder = &builder;
exprargs[0] = econtext;
exprargs[1] = isNull;
exprargs[2] = loop_index;
args.llvm_args = &exprargs[0];
Vals[1] = m_arroffset;
argArr = builder.CreateInBoundsGEP(pBatch, Vals);
argArr = builder.CreateLoad(ScalarVectorPtrType, argArr, "m_arr");
foreach (cell, targetlist) {
GenericExprState* gstate = (GenericExprState*)lfirst(cell);
ExprState* tstate = gstate->arg;
TargetEntry* tle = (TargetEntry*)gstate->xprstate.expr;
;
AttrNumber resind = tle->resno - 1;
args.exprstate = tstate;
res = CodeGen(&args);
if (res == NULL) {
jitted_vectarget->eraseFromParent();
ereport(ERROR,
(errcode(ERRCODE_CODEGEN_ERROR),
errmodule(MOD_LLVM),
errmsg("Codegen failed on the procedure of ExecVecTargetList!")));
}
* Restore the result to pBatch->m_arr[resind]->m_vals[Phi_idx]
*/
DEFINE_CGVAR_INT32(colind, resind);
Vals[0] = colind;
Vals[1] = m_valsoffset;
argVec = builder.CreateInBoundsGEP(argArr, Vals);
argVec = builder.CreateLoad(int64PtrType, argVec, "m_vals");
argVal = builder.CreateInBoundsGEP(argVec, loop_index);
builder.CreateStore(res, argVal);
Vals[1] = m_flagoffset;
argFlag = builder.CreateInBoundsGEP(argArr, Vals);
argFlag = builder.CreateLoad(int8PtrType, argFlag, "m_flag");
llvm::Value* tmpFlag = builder.CreateInBoundsGEP(argFlag, loop_index);
llvm::Value* tmpNull = isNull;
tmpNull = builder.CreateLoad(int8Type, tmpNull);
builder.CreateStore(tmpNull, tmpFlag);
* Since in LLVM we deal with one block at a time, we should check
* if there exists more predicates.
*/
if (cell->next == NULL) {
builder.CreateBr(bb_end);
} else {
bb_next = llvm::BasicBlock::Create(context, "bb", jitted_vectarget);
builder.CreateBr(bb_next);
builder.SetInsertPoint(bb_next);
bb_list[++tl_index] = bb_next;
}
}
builder.SetInsertPoint(bb_end);
llvm::Value* vtmp = builder.CreateTrunc(idx_next, int32Type);
vtmp = builder.CreateICmpEQ(vtmp, nsize);
builder.CreateCondBr(vtmp, for_end, for_body);
builder.SetInsertPoint(for_end);
foreach (cell, targetlist) {
GenericExprState* gstate = (GenericExprState*)lfirst(cell);
TargetEntry* tle = (TargetEntry*)gstate->xprstate.expr;
;
AttrNumber resind = tle->resno - 1;
DEFINE_CGVAR_INT32(colind, resind);
Vals[0] = colind;
Vals[1] = int32_0;
val1 = builder.CreateInBoundsGEP(argArr, Vals);
builder.CreateStore(nsize, val1);
}
builder.CreateBr(ret_bb);
builder.SetInsertPoint(ret_bb);
(void)MemCxtSwitToCodeGen(&builder, cg_oldContext);
builder.CreateRet(int8_1);
if (target_len > 1) {
pfree_ext(bb_list);
}
int plan_node_id = parent->plan->plan_node_id;
llvmCodeGen->FinalizeFunction(jitted_vectarget, plan_node_id);
llvmCodeGen->dumpCFunctionCalls("Targetlist", plan_node_id);
* If coden_strategy is CODEGEN_PURE and having C-function call in codegen,
* we need to discard the generated IR function.
*/
if (llvmCodeGen->hasCFunctionCalls()) {
llvmCodeGen->clearCFunctionCalls();
if (u_sess->attr.attr_sql.codegen_strategy == CODEGEN_PURE)
return NULL;
}
return jitted_vectarget;
}
* Function pointer to point to the actual LLVM assemble function.
*/
llvm::Value* VecExprCodeGen::CodeGen(ExprCodeGenArgs* args)
{
return (*(VectorExprCodeGen)(args->exprstate->exprCodeGen))(args);
}
llvm::Value* VecExprCodeGen::WrapChooExtFunCodeGen(GsCodeGen::LlvmBuilder* ptrbuilder, Oid argtyp, llvm::Value* argval)
{
llvm::Value* res = NULL;
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
DEFINE_CG_TYPE(int64Type, INT8OID);
llvm::Value* intmp = ptrbuilder->CreateAlloca(int64Type);
ptrbuilder->CreateStore(argval, intmp);
if (COL_IS_ENCODE(argtyp)) {
switch (argtyp) {
case MACADDROID:
case TIMETZOID:
case ARRAYTIMETZOID:
case TINTERVALOID:
case INTERVALOID:
case ARRAYINTERVALOID:
case ARRAYTINTERVALOID:
case NAMEOID:
res = WrapExtFixedTypeCodeGen(ptrbuilder, intmp);
break;
case UNKNOWNOID:
case CSTRINGOID:
res = WrapExtCStrTypeCodeGen(ptrbuilder, intmp);
break;
default:
res = WrapExtVarTypeCodeGen(ptrbuilder, intmp);
break;
}
} else if (argtyp == TIDOID) {
res = WrapExtAddrTypeCodeGen(ptrbuilder, intmp);
} else {
res = WrapExtVarTypeCodeGen(ptrbuilder, intmp);
}
return res;
}
llvm::Value* VecExprCodeGen::WrapExtCStrTypeCodeGen(GsCodeGen::LlvmBuilder* ptrbuilder, llvm::Value* data)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
llvm::Value* result = NULL;
llvm::Function* jitted_wrapctcg = llvmCodeGen->module()->getFunction("LLVMWrapExtCStrTyp");
if (jitted_wrapctcg == NULL) {
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "LLVMWrapExtCStrTyp", int64Type);
fn_prototype.addArgument(GsCodeGen::NamedVariable("data", int64PtrType));
jitted_wrapctcg = fn_prototype.generatePrototype(NULL, NULL);
llvm::sys::DynamicLibrary::AddSymbol("LLVMWrapExtCStrTyp", (void*)ExtractCstringType);
}
llvmCodeGen->FinalizeFunction(jitted_wrapctcg);
result = ptrbuilder->CreateCall(jitted_wrapctcg, data);
return result;
}
llvm::Value* VecExprCodeGen::WrapExtVarTypeCodeGen(GsCodeGen::LlvmBuilder* ptrbuilder, llvm::Value* data)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
llvm::Value* result = NULL;
llvm::Function* jitted_wrapvarcg = llvmCodeGen->module()->getFunction("LLVMWrapExtVarTyp");
if (jitted_wrapvarcg == NULL) {
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "LLVMWrapExtVarTyp", int64Type);
fn_prototype.addArgument(GsCodeGen::NamedVariable("data", int64PtrType));
jitted_wrapvarcg = fn_prototype.generatePrototype(NULL, NULL);
llvm::sys::DynamicLibrary::AddSymbol("LLVMWrapExtVarTyp", (void*)ExtractVarType);
}
llvmCodeGen->FinalizeFunction(jitted_wrapvarcg);
result = ptrbuilder->CreateCall(jitted_wrapvarcg, data);
return result;
}
llvm::Value* VecExprCodeGen::WrapExtFixedTypeCodeGen(GsCodeGen::LlvmBuilder* ptrbuilder, llvm::Value* data)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
llvm::Value* result = NULL;
llvm::Function* jitted_wrapftcg = llvmCodeGen->module()->getFunction("LLVMWrapExtFixedTyp");
if (jitted_wrapftcg == NULL) {
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "LLVMWrapExtFixedTyp", int64Type);
fn_prototype.addArgument(GsCodeGen::NamedVariable("data", int64PtrType));
jitted_wrapftcg = fn_prototype.generatePrototype(NULL, NULL);
llvm::sys::DynamicLibrary::AddSymbol("LLVMWrapExtFixedTyp", (void*)ExtractFixedType);
}
llvmCodeGen->FinalizeFunction(jitted_wrapftcg);
result = ptrbuilder->CreateCall(jitted_wrapftcg, data);
return result;
}
llvm::Value* VecExprCodeGen::WrapExtAddrTypeCodeGen(GsCodeGen::LlvmBuilder* ptrbuilder, llvm::Value* data)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
llvm::Value* result = NULL;
llvm::Function* jitted_wrapatcg = llvmCodeGen->module()->getFunction("LLVMWrapExtAddrTyp");
if (jitted_wrapatcg == NULL) {
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "LLVMWrapExtAddrTyp", int64Type);
fn_prototype.addArgument(GsCodeGen::NamedVariable("data", int64PtrType));
jitted_wrapatcg = fn_prototype.generatePrototype(NULL, NULL);
llvm::sys::DynamicLibrary::AddSymbol("LLVMWrapExtAddrTyp", (void*)ExtractAddrType);
}
llvmCodeGen->FinalizeFunction(jitted_wrapatcg);
result = ptrbuilder->CreateCall(jitted_wrapatcg, data);
return result;
}
llvm::Value* VecExprCodeGen::WrapDCStrToScalCodeGen(GsCodeGen::LlvmBuilder* ptrbuilder, llvm::Value* val)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
DEFINE_CG_TYPE(int64Type, INT8OID);
llvm::Value* result = NULL;
llvm::Function* jitted_wrapdcsts = llvmCodeGen->module()->getFunction("LLVMWrapDatumCStrToScal");
if (jitted_wrapdcsts == NULL) {
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "LLVMWrapDatumCStrToScal", int64Type);
fn_prototype.addArgument(GsCodeGen::NamedVariable("val", int64Type));
jitted_wrapdcsts = fn_prototype.generatePrototype(NULL, NULL);
llvm::sys::DynamicLibrary::AddSymbol("LLVMWrapDatumCStrToScal", (void*)WrapDatumCstringToScalar);
}
llvmCodeGen->FinalizeFunction(jitted_wrapdcsts);
result = ptrbuilder->CreateCall(jitted_wrapdcsts, val);
return result;
}
llvm::Value* VecExprCodeGen::WrapDFixLToScalCodeGen(
GsCodeGen::LlvmBuilder* ptrbuilder, llvm::Value* val, llvm::Value* len)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_TYPE(int32Type, INT4OID);
llvm::Value* result = NULL;
llvm::Function* jitted_wrapdflts = llvmCodeGen->module()->getFunction("LLVMWrapDatumFixLToScal");
if (jitted_wrapdflts == NULL) {
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "LLVMWrapDatumFixLToScal", int64Type);
fn_prototype.addArgument(GsCodeGen::NamedVariable("val", int64Type));
fn_prototype.addArgument(GsCodeGen::NamedVariable("len", int32Type));
jitted_wrapdflts = fn_prototype.generatePrototype(NULL, NULL);
llvm::sys::DynamicLibrary::AddSymbol("LLVMWrapDatumFixLToScal", (void*)WrapDatumFixLenToScalar);
}
llvmCodeGen->FinalizeFunction(jitted_wrapdflts);
result = ptrbuilder->CreateCall(jitted_wrapdflts, {val, len});
return result;
}
llvm::Value* VecExprCodeGen::WrapGetVectorBatchCodeGen(GsCodeGen::LlvmBuilder* ptrbuilder, llvm::Value* econtext)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
DEFINE_CG_PTRTYPE(exprContextPtrType, "struct.ExprContext");
DEFINE_CG_PTRTYPE(vectorBatchPtrType, "class.VectorBatch");
llvm::Value* result = NULL;
llvm::Function* jitted_wrapgetvb = llvmCodeGen->module()->getFunction("LLVMWrapGetVecBatch");
if (jitted_wrapgetvb == NULL) {
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "LLVMWrapGetVecBatch", vectorBatchPtrType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("econtext", exprContextPtrType));
jitted_wrapgetvb = fn_prototype.generatePrototype(NULL, NULL);
llvm::sys::DynamicLibrary::AddSymbol("LLVMWrapGetVecBatch", (void*)WrapGetVectorBatch);
}
llvmCodeGen->FinalizeFunction(jitted_wrapgetvb);
result = ptrbuilder->CreateCall(jitted_wrapgetvb, econtext);
return result;
}
llvm::Value* VecExprCodeGen::WrapStrictOpFuncCodeGen(
GsCodeGen::LlvmBuilder* ptrbuilder, llvm::Value* fcinfo, llvm::Value* arg, llvm::Value* isNull)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, BOOLOID);
DEFINE_CG_PTRTYPE(FuncCallInfoPtrType, "struct.FunctionCallInfoData");
llvm::Value* result = NULL;
llvm::Function* jitted_wrapsopexpr = llvmCodeGen->module()->getFunction("LLVMWrapStrictOpExprFunc");
if (jitted_wrapsopexpr == NULL) {
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "LLVMWrapStrictOpExprFunc", int64Type);
fn_prototype.addArgument(GsCodeGen::NamedVariable("fcinfo", FuncCallInfoPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("arg", int64PtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("isNull", int8PtrType));
jitted_wrapsopexpr = fn_prototype.generatePrototype(NULL, NULL);
llvm::sys::DynamicLibrary::AddSymbol("LLVMWrapStrictOpExprFunc", (void*)WrapVecStrictOperFunc);
}
llvmCodeGen->FinalizeFunction(jitted_wrapsopexpr);
result = ptrbuilder->CreateCall(jitted_wrapsopexpr, {fcinfo, arg, isNull});
return result;
}
llvm::Value* VecExprCodeGen::WrapNonStrictOpFuncCodeGen(GsCodeGen::LlvmBuilder* ptrbuilder, llvm::Value* fcinfo,
llvm::Value* arg, llvm::Value* argnull, llvm::Value* isNull)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, BOOLOID);
DEFINE_CG_PTRTYPE(FuncCallInfoPtrType, "struct.FunctionCallInfoData");
llvm::Value* result = NULL;
llvm::Function* jitted_wrapnsopexpr = llvmCodeGen->module()->getFunction("LLVMWrapNStrictOpExprFunc");
if (jitted_wrapnsopexpr == NULL) {
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "LLVMWrapNStrictOpExprFunc", int64Type);
fn_prototype.addArgument(GsCodeGen::NamedVariable("fcinfo", FuncCallInfoPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("arg", int64PtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("argnull", int8PtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("isNull", int8PtrType));
jitted_wrapnsopexpr = fn_prototype.generatePrototype(NULL, NULL);
llvm::sys::DynamicLibrary::AddSymbol("LLVMWrapNStrictOpExprFunc", (void*)WrapVecNonStrictOperFunc);
}
llvmCodeGen->FinalizeFunction(jitted_wrapnsopexpr);
result = ptrbuilder->CreateCall(jitted_wrapnsopexpr, {fcinfo, arg, argnull, isNull});
return result;
}
llvm::Value* VecExprCodeGen::MemCxtSwitToCodeGen(GsCodeGen::LlvmBuilder* ptrbuilder, llvm::Value* context)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
DEFINE_CG_PTRTYPE(MemCxtDataType, "struct.MemoryContextData");
llvm::Value* result = NULL;
llvm::Function* jitted_wrapmcst = llvmCodeGen->module()->getFunction("LLVMWrapMemCxtSwitTo");
if (jitted_wrapmcst == NULL) {
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "LLVMWrapMemCxtSwitTo", MemCxtDataType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("context", MemCxtDataType));
jitted_wrapmcst = fn_prototype.generatePrototype(NULL, NULL);
llvm::sys::DynamicLibrary::AddSymbol("LLVMWrapMemCxtSwitTo", (void*)WrapMemoryContextSwitchTo);
}
llvmCodeGen->FinalizeFunction(jitted_wrapmcst);
result = ptrbuilder->CreateCall(jitted_wrapmcst, context);
return result;
}
llvm::Value* VecExprCodeGen::EvalFuncResultCodeGen(
GsCodeGen::LlvmBuilder* ptrbuilder, FuncExprState* fcache, llvm::Value* isNull, LLVMFuncCallInfo* lfcinfo)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
Oid funcid = 0;
Oid Collation = 0;
Oid datumType = 0;
ExprState* cestate = (ExprState*)fcache;
Expr* node = cestate->expr;
int num_args = list_length(fcache->args);
Assert(num_args == lfcinfo->nargs);
switch (nodeTag(node)) {
case T_OpExpr: {
OpExpr* opexpr = (OpExpr*)node;
funcid = opexpr->opfuncid;
Collation = opexpr->inputcollid;
} break;
case T_FuncExpr: {
FuncExpr* funcexpr = (FuncExpr*)node;
funcid = funcexpr->funcid;
Collation = funcexpr->inputcollid;
} break;
case T_ScalarArrayOpExpr: {
ScalarArrayOpExpr* saop = (ScalarArrayOpExpr*)node;
funcid = saop->opfuncid;
Collation = saop->inputcollid;
break;
}
case T_NullIfExpr: {
NullIfExpr* nullifexpr = (NullIfExpr*)node;
funcid = nullifexpr->opfuncid;
Collation = nullifexpr->inputcollid;
} break;
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmodule(MOD_LLVM),
errmsg("Not supported expr node %d yet!", nodeTag(node))));
break;
}
llvm::Value* res0 = NULL;
llvm::Value* res = NULL;
DEFINE_CG_TYPE(int8Type, BOOLOID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CGVAR_INT64(Datum_0, 0);
DEFINE_CGVAR_INT64(Datum_1, 1);
DEFINE_CGVAR_INT64(Datum_2, 2);
DEFINE_CG_PTRTYPE(FuncCallInfoDataPtrType, "struct.FunctionCallInfoData");
* Fill the most elements of FunctionCallInfoData as we do in ExecEvalVecOper
* and ExecEvalVecFunc. For the args in FunctionCallInfo, we should fill
* these values during actual execution.
*/
FunctionCallInfo fcinfo;
initVectorFcache(funcid, Collation, fcache, CurrentMemoryContext);
fcinfo = &fcache->fcinfo_data;
Assert(fcinfo->flinfo->vec_fn_addr == NULL);
const FmgrBuiltin* fbp = fmgr_isbuiltin(fcinfo->flinfo->fn_oid);
char* name = NULL;
if (fbp != NULL) {
name = const_cast<char*>(fbp->funcName);
} else {
name = (char*)palloc0(MAX_OID_LENGTH);
int rc = sprintf_s(name, MAX_OID_LENGTH, "%u", fcinfo->flinfo->fn_oid);
securec_check_ss(rc, "\0", "\0");
}
llvmCodeGen->recordCFunctionCalls(name);
* In the following cases, we have to make it possible to re-enter DispatchVectorFunction:
* (1) codegen_strategy is CODEGEN_PURE, then this expr will be execute in vector engine;
* (2) this expr is the innHashKey of a hashClause, then it will be execute in vector engine.
* we have not discovery other case that need to re-enter DispatchVectorFunction until now.
*/
if (u_sess->attr.attr_sql.codegen_strategy == CODEGEN_PURE || IsA(node, NullIfExpr)) {
fcache->func.fn_oid = InvalidOid;
}
if (fcinfo->flinfo->fn_rettype == NUMERICOID) {
if (u_sess->attr.attr_sql.enable_fast_numeric) {
bool found = false;
VecFuncCacheEntry* entry =
(VecFuncCacheEntry*)hash_search(g_instance.vec_func_hash, &fcinfo->flinfo->fn_oid, HASH_FIND, &found);
if (found && entry->vec_transform_function[0] != NULL)
fcinfo->flinfo->fn_addr = entry->vec_transform_function[0];
else {
const FmgrBuiltin* fmgrbp = fmgr_isbuiltin(fcinfo->flinfo->fn_oid);
if (fmgrbp != NULL)
ereport(DEBUG1,
(errmodule(MOD_LLVM), errmsg("non-optimized big integer function: %s", fmgrbp->funcName)));
else
ereport(DEBUG1,
(errmodule(MOD_LLVM),
errmsg("non-optimized big integer function :%u", fcinfo->flinfo->fn_oid)));
}
}
}
llvm::Value* cg_fcinfo = llvmCodeGen->CastPtrToLlvmPtr(FuncCallInfoDataPtrType, fcinfo);
* Allocate an array according to the actual number of arguments
* of Func. And we need to restore these values(llvm former) to
* this array. We alloc one more element to record the flag of the
* result.
*/
DEFINE_CGVAR_INT32(nargs, num_args);
llvm::Value* inargs = ptrbuilder->CreateAlloca(int64Type, nargs);
llvm::Value* inargflags = ptrbuilder->CreateAlloca(int8Type, nargs);
ListCell* cell = NULL;
int i = 0;
Oid argtyp[MAX_ARGS_NUM] = {0};
foreach (cell, fcache->args) {
ExprState* argstate = (ExprState*)lfirst(cell);
Oid funcrettype;
TupleDesc tupdesc;
(void)get_expr_result_type((Node*)argstate->expr, &funcrettype, &tupdesc);
argtyp[i] = funcrettype;
i++;
}
bool is_func_strict = fcache->func.fn_strict;
if (num_args > 0) {
llvm::Value* lhs_value = lfcinfo->args[0];
llvm::Value* arg1 = ptrbuilder->CreateInBoundsGEP(inargs, Datum_0);
lhs_value = WrapChooExtFunCodeGen(ptrbuilder, argtyp[0], lhs_value);
ptrbuilder->CreateStore(lhs_value, arg1);
if (!is_func_strict) {
llvm::Value* lhs_flag = lfcinfo->argnulls[0];
llvm::Value* argflag1 = ptrbuilder->CreateInBoundsGEP(inargflags, Datum_0);
ptrbuilder->CreateStore(lhs_flag, argflag1);
}
}
if (num_args > 1) {
llvm::Value* rhs_value = lfcinfo->args[1];
llvm::Value* arg2 = ptrbuilder->CreateInBoundsGEP(inargs, Datum_1);
rhs_value = WrapChooExtFunCodeGen(ptrbuilder, argtyp[1], rhs_value);
ptrbuilder->CreateStore(rhs_value, arg2);
if (!is_func_strict) {
llvm::Value* rhs_flag = lfcinfo->argnulls[1];
llvm::Value* argflag2 = ptrbuilder->CreateInBoundsGEP(inargflags, Datum_1);
ptrbuilder->CreateStore(rhs_flag, argflag2);
}
}
if (num_args > 2) {
llvm::Value* thd_value = lfcinfo->args[2];
llvm::Value* arg3 = ptrbuilder->CreateInBoundsGEP(inargs, Datum_2);
thd_value = WrapChooExtFunCodeGen(ptrbuilder, argtyp[2], thd_value);
ptrbuilder->CreateStore(thd_value, arg3);
if (!is_func_strict) {
llvm::Value* thd_flag = lfcinfo->argnulls[2];
llvm::Value* argflag3 = ptrbuilder->CreateInBoundsGEP(inargflags, Datum_2);
ptrbuilder->CreateStore(thd_flag, argflag3);
}
}
* call orginal c-function
*
* For most of the functions, if the input arguments are not NULL,
* the returned value will not be NULL. While for some functions,
* like text_substr_null, replace_text, the returned value could not
* be NULL again. So we should record the null flag according to the
* actual result.
*/
if (is_func_strict) {
res0 = WrapStrictOpFuncCodeGen(ptrbuilder, cg_fcinfo, inargs, isNull);
} else {
res0 = WrapNonStrictOpFuncCodeGen(ptrbuilder, cg_fcinfo, inargs, inargflags, isNull);
}
* get the result according to the return type not just the result type
* of expressions.
*/
datumType = fcinfo->flinfo->fn_rettype;
if (COL_IS_ENCODE(datumType)) {
switch (datumType) {
case MACADDROID: {
DEFINE_CGVAR_INT32(arglen, 6);
res = WrapDFixLToScalCodeGen(ptrbuilder, res0, arglen);
} break;
case TIMETZOID:
case TINTERVALOID: {
DEFINE_CGVAR_INT32(arglen, 12);
res = WrapDFixLToScalCodeGen(ptrbuilder, res0, arglen);
} break;
case INTERVALOID: {
DEFINE_CGVAR_INT32(arglen, 16);
res = WrapDFixLToScalCodeGen(ptrbuilder, res0, arglen);
} break;
case NAMEOID: {
DEFINE_CGVAR_INT32(arglen, 64);
res = WrapDFixLToScalCodeGen(ptrbuilder, res0, arglen);
} break;
case UNKNOWNOID:
case CSTRINGOID: {
res = WrapDCStrToScalCodeGen(ptrbuilder, res0);
} break;
default: {
res = res0;
} break;
}
} else {
res = res0;
}
return res;
}
* @Description : convert the cstring data type to scalar value.
*/
Datum WrapDatumCstringToScalar(Datum data)
{
Size len = strlen((char*)data);
Datum val = ScalarVector::DatumCstringToScalar(data, len);
return val;
}
* @Description : convert the fix-len data type to scalar value.
*/
Datum WrapDatumFixLenToScalar(Datum data, Size len)
{
Datum val;
val = ScalarVector::DatumFixLenToScalar(data, len);
return val;
}
* @Description : Get the result of the particular function.
* @in fcinfo : FunctionCallInfo data with respect to funcid.
* @in arg : arguments needed by func and the flag of the result.
* @return : the result of the function defined in (fcinfo)->flinfo->fn_addr
*/
Datum WrapVecStrictOperFunc(FunctionCallInfo fcinfo, Datum* arg, bool* isNull)
{
Datum result = 0;
* get the arguments during execution and invoke the pre-defined function
*/
int nargs = fcinfo->nargs;
for (int i = 0; i < nargs; i++) {
fcinfo->arg[i] = arg[i];
}
* we should reset then isnull flag here since the pre-defined function use it directly
*/
fcinfo->isnull = false;
result = FunctionCallInvoke(fcinfo);
*isNull = fcinfo->isnull;
return result;
}
* @Description : Get the result of the particular function.
* @in fcinfo : FunctionCallInfo data with respect to funcid.
* @in arg : arguments needed by func and the flag of the result.
* @return : the result of the function defined in (fcinfo)->flinfo->fn_addr
* @Notes : Only consider functions with non-strict attribute.
*/
Datum WrapVecNonStrictOperFunc(FunctionCallInfo fcinfo, Datum* arg, const bool* argnull, bool* isNull)
{
Datum result = 0;
* get the arguments during execution and invoke the pre-defined function
*/
int nargs = fcinfo->nargs;
for (int i = 0; i < nargs; i++) {
fcinfo->arg[i] = arg[i];
fcinfo->argnull[i] = argnull[i];
}
fcinfo->isnull = false;
result = FunctionCallInvoke(fcinfo);
*isNull = fcinfo->isnull;
return result;
}
* @Description : Get the vectorbatch needed during projection. To Scan Operator,
* we use scanbatch, while to Join Operator, we use innberbatch
* and outerbatch.
* @in econtext : ExprContext of current Expr.
* @return : scanbatch needed during eval targetlist.
*/
VectorBatch* WrapGetVectorBatch(ExprContext* econtext)
{
VectorBatch* resBatch = NULL;
if (econtext->ecxt_scanbatch)
resBatch = econtext->ecxt_scanbatch;
else if (econtext->ecxt_innerbatch)
resBatch = econtext->ecxt_innerbatch;
else if (econtext->ecxt_outerbatch)
resBatch = econtext->ecxt_outerbatch;
else
ereport(ERROR,
(errcode(ERRCODE_UNEXPECTED_NODE_STATE),
errmodule(MOD_LLVM),
errmsg("Unexpected batch information from ExprContext.")));
return resBatch;
}
* @Description : Switch current context memory to 'context' Context
* @in econtext : Current memory context.
* @return : Old memory context.
*/
MemoryContext WrapMemoryContextSwitchTo(MemoryContext context)
{
MemoryContext old = CurrentMemoryContext;
CurrentMemoryContext = context;
return old;
}
}