* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* 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.
* ---------------------------------------------------------------------------------------
*
* vechashaggcodegen.cpp
* Routines to handle vector hashagg nodes. We only focuse on
* the CPU intensive part of hashagg operation.
* IDENTIFICATION
* src/gausskernel/runtime/codegen/vecexecutor/vechashaggcodegen.cpp
*
* ---------------------------------------------------------------------------------------
*/
#include "codegen/gscodegen.h"
#include "codegen/vechashaggcodegen.h"
#include "codegen/vecsortcodegen.h"
#include "codegen/codegendebuger.h"
#include "codegen/builtinscodegen.h"
#include "codegen/vecexprcodegen.h"
#include "catalog/pg_operator.h"
#include "pgxc/pgxc.h"
#include "vecexecutor/vecexecutor.h"
void WrapAllocHashSlot(HashAggRunner* haRunner, VectorBatch* batch, int idx, int keysimple);
void WrapSglTblAllocHashSlot(HashAggRunner* haRunner, VectorBatch* batch, int idx, int keysimple);
void WrapResetExprContext(ExprContext* econtext);
#define PREFETCH_AGGHASHING_DISTANCE1 4
#define PREFETCH_AGGHASHING_DISTANCE2 2
#define PREFETCH_BATCHAGGREGATION_DISTANCE 2
#define AGG_ECONOMY_RATION 0.001
namespace dorado {
llvm::Function* prefetchAggHashingCodeGen();
llvm::Function* prefetchBatchAggregationCodeGen();
llvm::Function* prefetchAggSglTblHashingCodeGen();
int VecHashAggCodeGen::GetAlignedScale(Expr* node)
{
int resscale = 0;
* Get into this function only when fast_aggref is true, which means
* we could apply fast codegen path for this expression node.
*/
switch (nodeTag(node)) {
case T_TargetEntry: {
TargetEntry* tentry = (TargetEntry*)node;
resscale = GetAlignedScale(tentry->expr);
} break;
case T_OpExpr: {
OpExpr* opexpr = (OpExpr*)node;
Expr* lexpr = (Expr*)linitial(opexpr->args);
Expr* rexpr = (Expr*)lsecond(opexpr->args);
int lscale = GetAlignedScale(lexpr);
int rscale = GetAlignedScale(rexpr);
* Only when AggRefFastJittable is satisfied, we evaluate the scale
* of the aggref expression. So, no need to consider NUMERICDIVOID.
*/
if (opexpr->opno == NUMERICADDOID || opexpr->opno == NUMERICSUBOID) {
if (lscale < rscale)
resscale = rscale;
else
resscale = lscale;
} else if (opexpr->opno == NUMERICMULOID)
resscale = lscale + rscale;
else
ereport(ERROR, (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmodule(MOD_LLVM),
errmsg("Unsupported operation %u in FastAgg.", opexpr->opno)));
} break;
case T_Var: {
Var* var = (Var*)node;
Assert(var->vartype == NUMERICOID);
resscale = (var->vartypmod - VARHDRSZ) & NUMERIC_BI_SCALEMASK;
} break;
case T_Const: {
Const* cst = (Const*)node;
Assert(cst->consttype == NUMERICOID);
ScalarValue val = ScalarVector::DatumToScalar(cst->constvalue, cst->consttype, cst->constisnull);
resscale = NUMERIC_BI_SCALE((Numeric)val);
} break;
default:
Assert(0);
break;
}
return resscale;
}
bool VecHashAggCodeGen::AggRefJittable(ExprState* state)
{
Expr* node = state->expr;
switch (nodeTag(node)) {
* there always be a targetentry in AggrefExprState, so extract
* targetentry first.
*/
case T_TargetEntry: {
GenericExprState* gstate = (GenericExprState*)state;
ExprState* tstate = gstate->arg;
if (!AggRefJittable(tstate))
return false;
} break;
case T_Var: {
Var* var = (Var*)state->expr;
if (var->varattno < 0)
return false;
switch (var->vartype) {
case INT8OID:
case NUMERICOID:
break;
default:
return false;
}
if (var->vartype == NUMERICOID) {
* do not consider numeric data type without precision
* specfied, since it changed during evaluation.
*/
if (var->vartypmod == -1)
return false;
}
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::VarCodeGen;
} break;
case T_Const: {
Const* con = (Const*)state->expr;
switch (con->consttype) {
case INT8OID:
case NUMERICOID:
break;
default:
return false;
}
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::ConstCodeGen;
} break;
case T_OpExpr: {
OpExpr* opexpr = (OpExpr*)state->expr;
FuncExprState* fstate = (FuncExprState*)state;
if (list_length(opexpr->args) == 1)
return false;
switch (opexpr->opno) {
* only support limited math operations
*/
case INT8PLOID:
case INT8MIOID:
case INT8MULOID:
case INT8DIVOID:
case NUMERICADDOID:
case NUMERICSUBOID:
case NUMERICMULOID:
case NUMERICDIVOID:
break;
default:
return false;
}
* now consider the args of this operation expression.
*/
ExprState* lestate = (ExprState*)linitial(fstate->args);
ExprState* restate = (ExprState*)lsecond(fstate->args);
if (!AggRefJittable(lestate) || !AggRefJittable(restate))
return false;
state->exprCodeGen = (exprFakeCodeGenSig)&VecExprCodeGen::OpCodeGen;
} break;
default:
return false;
}
return true;
}
bool VecHashAggCodeGen::AggRefFastJittable(ExprState* state)
{
Expr* node = state->expr;
switch (nodeTag(node)) {
case T_TargetEntry: {
GenericExprState* gstate = (GenericExprState*)state;
ExprState* tstate = (ExprState*)(gstate->arg);
if (!AggRefFastJittable(tstate))
return false;
} break;
case T_Var: {
Var* var = (Var*)node;
if (var->vartype != NUMERICOID || var->vartypmod == -1)
return false;
int prec = (var->vartypmod >> 16) & 0xFFFF;
if (prec > 18)
return false;
} break;
case T_Const: {
Const* cst = (Const*)(state->expr);
if (cst->consttype != NUMERICOID || cst->constisnull)
return false;
ScalarValue val = ScalarVector::DatumToScalar(cst->constvalue, cst->consttype, cst->constisnull);
if (!cst->constisnull) {
if ((((NumericData*)val)->choice.n_header & NUMERIC_BI_MASK) != NUMERIC_64)
return false;
}
} break;
case T_OpExpr: {
OpExpr* opexpr = (OpExpr*)state->expr;
FuncExprState* fstate = (FuncExprState*)state;
if (list_length(opexpr->args) == 1)
return false;
switch (opexpr->opno) {
case NUMERICADDOID:
case NUMERICSUBOID:
case NUMERICMULOID:
break;
default:
return false;
}
ExprState* lestate = (ExprState*)linitial(fstate->args);
ExprState* restate = (ExprState*)lsecond(fstate->args);
if (!AggRefFastJittable(lestate) || !AggRefFastJittable(restate))
return false;
} break;
default:
Assert(0);
return false;
}
return true;
}
bool VecHashAggCodeGen::AgghashingJittable(VecAggState* node)
{
VecAgg* vecagg = (VecAgg*)(node->ss.ps.plan);
if (!u_sess->attr.attr_sql.enable_codegen || IS_PGXC_COORDINATOR)
return false;
if (vecagg->aggstrategy != AGG_HASHED)
return false;
* Get the input variable from the outer plan, and we only
* support char, varchar, text, int4, int8 and timestamp(date).
*/
List* tlist = (outerPlan(vecagg))->targetlist;
int numkeys = vecagg->numCols;
AttrNumber* keyIdx = vecagg->grpColIdx;
for (int i = 0; i < numkeys; i++) {
AttrNumber key = keyIdx[i] - 1;
TargetEntry* tle = (TargetEntry*)list_nth(tlist, key);
switch (nodeTag(tle->expr)) {
case T_Var: {
Var* var = (Var*)(tle->expr);
switch (var->vartype) {
case BPCHAROID: {
int len = var->vartypmod - VARHDRSZ;
if (len < 0)
return false;
} break;
case INT4OID:
case INT8OID:
case TIMESTAMPOID:
case DATEOID:
case TEXTOID:
case VARCHAROID:
break;
default:
return false;
}
} break;
case T_FuncExpr: {
FuncExpr* funcexpr = (FuncExpr*)(tle->expr);
if (funcexpr->funcid != SUBSTRFUNCOID)
return false;
int current_encoding = GetDatabaseEncoding();
if (current_encoding != PG_SQL_ASCII && current_encoding != PG_UTF8)
return false;
List* func_args = funcexpr->args;
Expr* aexpr1 = (Expr*)linitial(func_args);
Expr* aexpr2 = (Expr*)lsecond(func_args);
Expr* aexpr3 = (Expr*)lthird(func_args);
if (!IsA(aexpr1, RelabelType) && !IsA(aexpr1, Var))
return false;
if (!IsA(aexpr2, Const) || !IsA(aexpr3, Const))
return false;
} break;
default:
return false;
}
* timestamp_hash, and hashbpchar functions
*/
Oid fnoid = node->hashfunctions[i].fn_oid;
switch (fnoid) {
case HASHINT4OID:
case HASHINT8OID:
case HASHBPCHAROID:
case HASHTEXTOID:
break;
case TIMESTAMPHASHOID: {
#ifdef HAVE_INT64_TIMESTAMP
#else
return false;
#endif
} break;
default:
return false;
}
}
return true;
}
bool VecHashAggCodeGen::BatchAggJittable(VecAggState* node, bool isSonic)
{
int i = 0;
VecAgg* vecagg = (VecAgg*)(node->ss.ps.plan);
VecAggStatePerAgg peragg = node->pervecagg;
if (!u_sess->attr.attr_sql.enable_codegen || IS_PGXC_COORDINATOR)
return false;
if (vecagg->aggstrategy != AGG_HASHED)
return false;
if (0 == node->numaggs)
return false;
for (i = 0; i < node->numaggs; i++) {
AggrefExprState* aggexprstate = peragg[i].aggrefstate;
Aggref* aggref = peragg[i].aggref;
switch (aggref->aggfnoid) {
case INT8AVGFUNCOID:
case INT8SUMFUNCOID:
if (isSonic)
return false;
break;
case NUMERICAVGFUNCOID:
case NUMERICSUMFUNCOID:
case COUNTOID:
break;
default:
return false;
}
if (aggref->aggfnoid == COUNTOID)
continue;
ExprState* estate = (ExprState*)linitial(aggexprstate->args);
if (!AggRefJittable(estate))
return false;
}
return true;
}
void VecHashAggCodeGen::HashAggCodeGen(VecAggState* node)
{
* Codegeneration for hashagg:
* Since the whole HashAggRunner::BuildAggTbl has been divided into three
* part, we should do codegeneration separately.
*/
Assert(NULL != (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj);
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::Function* jitted_vechashing = NULL;
llvm::Function* jitted_vecsglhashing = NULL;
llvm::Function* jitted_vecbatchagg = NULL;
llvm::Function* jitted_SortAggMatchKey = NULL;
* For aggregation, if economy is too small, which means number of distinct
* values is very large, we meet cachemiss during batch aggregation, so
* consider prefetch in this case.
*/
if (0) {
jitted_vechashing = AgghashingWithPrefetchCodeGenorSglTbl<false>(node);
jitted_vecsglhashing = AgghashingWithPrefetchCodeGenorSglTbl<true>(node);
} else {
jitted_vechashing = AgghashingCodeGenorSglTbl<false>(node);
jitted_vecsglhashing = AgghashingCodeGenorSglTbl<true>(node);
}
if (NULL != jitted_vechashing)
llvmCodeGen->addFunctionToMCJit(jitted_vechashing, reinterpret_cast<void**>(&(node->jitted_hashing)));
if (NULL != jitted_vecsglhashing)
llvmCodeGen->addFunctionToMCJit(jitted_vecsglhashing, reinterpret_cast<void**>(&(node->jitted_sglhashing)));
jitted_vecbatchagg = dorado::VecHashAggCodeGen::BatchAggregationCodeGen(node, false);
if (NULL != jitted_vecbatchagg)
llvmCodeGen->addFunctionToMCJit(jitted_vecbatchagg, reinterpret_cast<void**>(&(node->jitted_batchagg)));
jitted_SortAggMatchKey = dorado::VecSortCodeGen::SortAggMatchKeyCodeGen(node);
node->jitted_SortAggMatchKey = NULL;
if (NULL != jitted_SortAggMatchKey)
llvmCodeGen->addFunctionToMCJit(
jitted_SortAggMatchKey, reinterpret_cast<void**>(&(node->jitted_SortAggMatchKey)));
llvm::Function* jitted_vectarget = NULL;
jitted_vectarget = dorado::VecExprCodeGen::TargetListCodeGen(node->ss.ps.targetlist, (PlanState*)node);
if (NULL != jitted_vectarget)
llvmCodeGen->addFunctionToMCJit(
jitted_vectarget, reinterpret_cast<void**>(&(node->ss.ps.ps_ProjInfo->jitted_vectarget)));
}
void VecHashAggCodeGen::SonicHashAggCodeGen(VecAggState* node)
{
Assert(NULL != (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj);
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::Function* jitted_sonicbatchagg = NULL;
jitted_sonicbatchagg = SonicBatchAggregationCodeGen(node, false);
if (NULL != jitted_sonicbatchagg)
llvmCodeGen->addFunctionToMCJit(jitted_sonicbatchagg, reinterpret_cast<void**>(&(node->jitted_sonicbatchagg)));
}
static void VecAggCheckUnique(VecAgg* vecagg, GsCodeGen::LlvmBuilder* builder)
{
const char* errorstr = "more than one row returned by a subquery used as an expression";
if (vecagg->unique_check) {
DebugerCodeGen::CodeGenElogInfo(builder, ERROR, errorstr);
}
}
template <bool isSglTbl>
llvm::Function* VecHashAggCodeGen::AgghashingCodeGenorSglTbl(VecAggState* node)
{
Assert(NULL != (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj);
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
if (!AgghashingJittable(node))
return NULL;
llvmCodeGen->loadIRFile();
int i = 0;
VecAgg* vecagg = (VecAgg*)(node->ss.ps.plan);
int numkeys = vecagg->numCols;
AttrNumber* keyIdx = vecagg->grpColIdx;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
llvm::Value* hAggRunner = NULL;
llvm::Value* batch = NULL;
llvm::Value* tmpval = NULL;
llvm::Value* cmpval = NULL;
llvm::Value* idx_next = NULL;
llvm::Value* llvmargs[2];
llvm::PHINode* phi_idx = NULL;
llvm::Function* jitted_agghashing = NULL;
DEFINE_CG_VOIDTYPE(voidType);
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int32Type, INT4OID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(int32PtrType, INT4OID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
DEFINE_CG_PTRTYPE(hashCellPtrType, "struct.hashCell");
DEFINE_CG_PTRPTRTYPE(hashCellPtrPtrType, "struct.hashCell");
DEFINE_CG_PTRTYPE(vectorBatchPtrType, "class.VectorBatch");
DEFINE_CG_PTRTYPE(hashAggRunnerPtrType, "class.HashAggRunner");
DEFINE_CG_PTRTYPE(scalarVecPtrType, "class.ScalarVector");
DEFINE_CG_PTRTYPE(hashSegTblPtrType, "struct.HashSegTbl");
DEFINE_CGVAR_INT32(int32_m1, -1);
DEFINE_CGVAR_INT32(int32_0, 0);
DEFINE_CGVAR_INT32(int32_1, 1);
DEFINE_CGVAR_INT32(int32_pos_hBOper_cols, pos_hBOper_cols);
DEFINE_CGVAR_INT32(int32_pos_hBOper_cacheLoc, pos_hBOper_cacheLoc);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hashVal, pos_hAggR_hashVal);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hSegTbl, pos_hAggR_hSegTbl);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hsegmax, pos_hAggR_hsegmax);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hashSize, pos_hAggR_hashSize);
DEFINE_CGVAR_INT32(int32_pos_bAggR_keyIdxInCell, pos_bAggR_keyIdxInCell);
DEFINE_CGVAR_INT32(int32_pos_bAggR_Loc, pos_bAggR_Loc);
DEFINE_CGVAR_INT32(int32_pos_bAggR_keySimple, pos_bAggR_keySimple);
DEFINE_CGVAR_INT32(int32_pos_hcell_mval, pos_hcell_mval);
DEFINE_CGVAR_INT32(int32_pos_batch_marr, pos_batch_marr);
DEFINE_CGVAR_INT32(int32_pos_scalvec_vals, pos_scalvec_vals);
DEFINE_CGVAR_INT32(int32_pos_scalvec_flag, pos_scalvec_flag);
DEFINE_CGVAR_INT64(Datum_0, 0);
DEFINE_CGVAR_INT64(Datum_1, 1);
llvm::Value* Vals[2] = {Datum_0, int32_0};
llvm::Value* Vals3[3] = {Datum_0, int32_0, int32_0};
llvm::Value* Vals4[4] = {Datum_0, int32_0, int32_0, int32_0};
llvm::Value* Vals5[5] = {Datum_0, int32_0, int32_0, int32_0, int32_0};
const char* name = NULL;
if (isSglTbl) {
name = "JittedSglTblAggHashing";
} else {
name = "JittedAggHashing";
}
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, name, voidType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("hashAggRunner", hashAggRunnerPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("batch", vectorBatchPtrType));
jitted_agghashing = fn_prototype.generatePrototype(&builder, &llvmargs[0]);
hAggRunner = llvmargs[0];
batch = llvmargs[1];
tmpval = builder.CreateInBoundsGEP(batch, Vals);
llvm::Value* nValues = builder.CreateLoad(int32Type, tmpval, "m_rows");
Vals[1] = int32_pos_hAggR_hashSize;
tmpval = builder.CreateInBoundsGEP(hAggRunner, Vals);
llvm::Value* maskval = builder.CreateLoad(int64Type, tmpval, "m_hashSize");
maskval = builder.CreateSub(maskval, Datum_1, "mask");
Vals4[3] = int32_pos_hBOper_cols;
llvm::Value* m_colsVal = builder.CreateInBoundsGEP(hAggRunner, Vals4);
llvm::BasicBlock* entry = &jitted_agghashing->getEntryBlock();
DEFINE_BLOCK(for_body, jitted_agghashing);
DEFINE_BLOCK(for_end, jitted_agghashing);
DEFINE_BLOCK(for_inc, jitted_agghashing);
DEFINE_BLOCK(while_body, jitted_agghashing);
DEFINE_BLOCK(key_match, jitted_agghashing);
DEFINE_BLOCK(hashval_eq, jitted_agghashing);
DEFINE_BLOCK(next_cell, jitted_agghashing);
DEFINE_BLOCK(alloc_hashslot, jitted_agghashing);
llvm::Value** keyIdxInCell = (llvm::Value**)palloc(sizeof(llvm::Value*) * numkeys);
llvm::Value** pVector = (llvm::Value**)palloc(sizeof(llvm::Value*) * numkeys);
llvm::Value** pFlag = (llvm::Value**)palloc(sizeof(llvm::Value*) * numkeys);
Vals3[0] = Datum_0;
Vals3[1] = int32_0;
Vals3[2] = int32_pos_bAggR_keyIdxInCell;
llvm::Value* cellkeyIdx = builder.CreateInBoundsGEP(hAggRunner, Vals3);
cellkeyIdx = builder.CreateLoad(int32PtrType, cellkeyIdx, "keyIdxInCellArr");
for (i = 0; i < numkeys; i++) {
tmpval = llvmCodeGen->getIntConstant(INT4OID, i);
keyIdxInCell[i] = builder.CreateInBoundsGEP(cellkeyIdx, tmpval);
keyIdxInCell[i] = builder.CreateLoad(int32Type, keyIdxInCell[i], "m_keyIdxInCell");
}
Vals[0] = Datum_0;
Vals[1] = int32_pos_batch_marr;
tmpval = builder.CreateInBoundsGEP(batch, Vals);
llvm::Value* tmparr = builder.CreateLoad(scalarVecPtrType, tmpval, "m_arr");
for (i = 0; i < numkeys; i++) {
AttrNumber key = keyIdx[i] - 1;
Vals[0] = llvmCodeGen->getIntConstant(INT8OID, key);
Vals[1] = int32_pos_scalvec_vals;
llvm::Value* pVec = builder.CreateInBoundsGEP(tmparr, Vals);
pVector[i] = builder.CreateLoad(int64PtrType, pVec, "pVector");
Vals[1] = int32_pos_scalvec_flag;
llvm::Value* Flag = builder.CreateInBoundsGEP(tmparr, Vals);
pFlag[i] = builder.CreateLoad(int8PtrType, Flag, "pFlag");
}
* Begin to loop the whole batch to evaluation hashval and initialize
* the hash cell by matching hashval and key
*/
builder.SetInsertPoint(entry);
tmpval = builder.CreateICmpSGT(nValues, int32_0);
builder.CreateCondBr(tmpval, for_body, for_end);
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, for_inc);
llvm::Value* hash_res = int32_m1;
bool rehash = false;
for (i = 0; i < numkeys; i++) {
if (i > 0)
rehash = true;
llvm::Function* func_hashbatch = HashBatchCodeGen(node, i, rehash);
if (func_hashbatch == NULL) {
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmodule(MOD_LLVM),
errmsg("Failed on generating HashBatchCodeGen!\n")));
}
llvm::Value* pval = builder.CreateInBoundsGEP(pVector[i], phi_idx);
pval = builder.CreateLoad(int64Type, pval, "pval");
llvm::Value* pflag = builder.CreateInBoundsGEP(pFlag[i], phi_idx);
pflag = builder.CreateLoad(int8Type, pflag, "pflag");
hash_res = builder.CreateCall(func_hashbatch, {pval, pflag, hash_res});
}
Vals3[1] = int32_pos_hAggR_hashVal;
Vals3[2] = phi_idx;
llvm::Value* hashValSlot = builder.CreateInBoundsGEP(hAggRunner, Vals3);
llvm::Value* hash_res64 = builder.CreateZExt(hash_res, int64Type);
builder.CreateStore(hash_res64, hashValSlot);
llvm::Value* cacheLocVal = builder.CreateAnd(hash_res64, maskval, "cacheLoc");
Vals5[3] = int32_pos_hBOper_cacheLoc;
Vals5[4] = phi_idx;
llvm::Value* cacheLoc_i = builder.CreateInBoundsGEP(hAggRunner, Vals5);
builder.CreateStore(cacheLocVal, cacheLoc_i);
llvm::Value* segmaxval = NULL;
llvm::Value* nsegsval = NULL;
llvm::Value* pos = NULL;
if (!isSglTbl) {
Vals[0] = Datum_0;
Vals[1] = int32_pos_hAggR_hsegmax;
segmaxval = builder.CreateInBoundsGEP(hAggRunner, Vals);
segmaxval = builder.CreateLoad(int32Type, segmaxval, "segmax");
segmaxval = builder.CreateSExt(segmaxval, int64Type);
nsegsval = builder.CreateExactUDiv(cacheLocVal, segmaxval, "nsegs");
nsegsval = builder.CreateTrunc(nsegsval, int32Type);
pos = builder.CreateSRem(cacheLocVal, segmaxval, "pos");
}
Vals[0] = Datum_0;
Vals[1] = int32_pos_hAggR_hSegTbl;
llvm::Value* hashData = builder.CreateInBoundsGEP(hAggRunner, Vals);
hashData = builder.CreateLoad(hashSegTblPtrType, hashData, "m_hashData");
if (isSglTbl) {
Vals[0] = int32_0;
} else {
Vals[0] = nsegsval;
}
Vals[1] = int32_1;
llvm::Value* tbldata = builder.CreateInBoundsGEP(hashData, Vals);
tbldata = builder.CreateLoad(hashCellPtrPtrType, tbldata, "tbl_data");
if (isSglTbl) {
tmpval = builder.CreateInBoundsGEP(tbldata, cacheLocVal);
} else {
tmpval = builder.CreateInBoundsGEP(tbldata, pos);
}
llvm::Value* cellval = builder.CreateLoad(hashCellPtrType, tmpval, "cell");
tmpval = builder.CreatePtrToInt(cellval, int64Type);
if (!isSglTbl) {
cellval = builder.CreateIntToPtr(tmpval, hashCellPtrType);
}
cmpval = builder.CreateICmpEQ(tmpval, Datum_0);
builder.CreateCondBr(cmpval, alloc_hashslot, while_body);
builder.SetInsertPoint(while_body);
llvm::PHINode* phi_cell = builder.CreatePHI(hashCellPtrType, 2);
builder.SetInsertPoint(next_cell);
Vals3[0] = Datum_0;
Vals3[1] = int32_0;
Vals3[2] = int32_0;
llvm::Value* nextcellval = builder.CreateInBoundsGEP(phi_cell, Vals3);
nextcellval = builder.CreateLoad(hashCellPtrType, nextcellval, "nextcellval");
tmpval = builder.CreatePtrToInt(nextcellval, int64Type);
cmpval = builder.CreateICmpEQ(tmpval, Datum_0);
builder.CreateCondBr(cmpval, alloc_hashslot, while_body);
builder.SetInsertPoint(while_body);
phi_cell->addIncoming(nextcellval, next_cell);
phi_cell->addIncoming(cellval, for_body);
tmpval = builder.CreateLoad(int32Type, m_colsVal, "m_cols");
tmpval = builder.CreateZExt(tmpval, int64Type);
Vals4[0] = Datum_0;
Vals4[1] = int32_pos_hcell_mval;
Vals4[2] = tmpval;
Vals4[3] = int32_0;
tmpval = builder.CreateInBoundsGEP(phi_cell, Vals4);
tmpval = builder.CreateLoad(int64Type, tmpval, "hashval_cell");
llvm::Value* cmp_hashval = builder.CreateICmpEQ(hash_res64, tmpval);
builder.CreateCondBr(cmp_hashval, hashval_eq, next_cell);
* When hash val is equal, we only consider the result of matchkey.
* Loop over all the keys, once the key is not matched, get the
* next cell. If all the keys have been compared, find the next cell
* or keymatched according to the result. The following code is the
* codegeneration of the following code:
* if (true && match_key(<simple>)(batch, i, cell))
* { ...; break; }
* cell = cell->flag.m_next
*/
builder.SetInsertPoint(hashval_eq);
for (i = 0; i < numkeys; i++) {
llvm::Function* func_matchonekey = MatchOneKeyCodeGen(node, i);
if (NULL == func_matchonekey) {
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmodule(MOD_LLVM),
errmsg("Failed on generating MatchOneKey Function!\n")));
}
llvm::Value* pval = builder.CreateInBoundsGEP(pVector[i], phi_idx);
pval = builder.CreateLoad(int64Type, pval, "pval");
llvm::Value* pflag = builder.CreateInBoundsGEP(pFlag[i], phi_idx);
pflag = builder.CreateLoad(int8Type, pflag, "pflag");
llvm::Value* res = builder.CreateCall(func_matchonekey, {pval, pflag, phi_cell, keyIdxInCell[i]});
cmpval = builder.CreateICmpEQ(res, Datum_0);
if (i == numkeys - 1)
builder.CreateCondBr(cmpval, next_cell, key_match);
else {
DEFINE_BLOCK(next_bb, jitted_agghashing);
builder.CreateCondBr(cmpval, next_cell, next_bb);
builder.SetInsertPoint(next_bb);
}
}
* when both hash value and all keys are matched, remember this
* hash cell and go to next tuple.
*/
builder.SetInsertPoint(key_match);
VecAggCheckUnique(vecagg, &builder);
Vals4[0] = Datum_0;
Vals4[1] = int32_0;
Vals4[2] = int32_pos_bAggR_Loc;
Vals4[3] = phi_idx;
tmpval = builder.CreateInBoundsGEP(hAggRunner, Vals4);
builder.CreateStore(phi_cell, tmpval);
builder.CreateBr(for_inc);
builder.SetInsertPoint(alloc_hashslot);
Vals3[0] = Datum_0;
Vals3[1] = int32_0;
Vals3[2] = int32_pos_bAggR_keySimple;
llvm::Value* simple_key = builder.CreateInBoundsGEP(hAggRunner, Vals3);
simple_key = builder.CreateLoad(int32Type, simple_key, "key_simple");
if (isSglTbl) {
WarpSglTblAllocHashSlotCodeGen(&builder, hAggRunner, batch, phi_idx, simple_key);
} else {
WarpAllocHashSlotCodeGen(&builder, hAggRunner, batch, phi_idx, simple_key);
}
builder.CreateBr(for_inc);
builder.SetInsertPoint(for_inc);
tmpval = builder.CreateTrunc(idx_next, int32Type);
tmpval = builder.CreateICmpEQ(tmpval, nValues);
builder.CreateCondBr(tmpval, for_end, for_body);
builder.SetInsertPoint(for_end);
builder.CreateRetVoid();
llvmCodeGen->FinalizeFunction(jitted_agghashing, vecagg->plan.plan_node_id);
return jitted_agghashing;
}
* AgghashingWithPrefetchCodeGen
* @Description : Codegeneration for hashing batch and match key in
* buildAggTbl. To reduce cache miss, we need to prefetch
* the hash cell. Different from the original function,
* we use two loops to handle the hashing and match key
* separately, since cache miss mostly happens during
* matching key.
*
* AggSglTblhashingWithPrefetchCodeGen
* @Description : Codegeneration for hashing batch and match key in
* buildAggTbl. To reduce cache miss, we need to prefetch
* the hash cell. Different from the original function,
* we use two loops to handle the hashing and match key
* separately, since cache miss mostly happens during
* matching key.
*/
template <bool isSglTbl>
llvm::Function* VecHashAggCodeGen::AgghashingWithPrefetchCodeGenorSglTbl(VecAggState* node)
{
Assert(NULL != (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj);
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
if (!AgghashingJittable(node))
return NULL;
llvmCodeGen->loadIRFile();
int i = 0;
VecAgg* vecagg = (VecAgg*)(node->ss.ps.plan);
int numkeys = vecagg->numCols;
AttrNumber* keyIdx = vecagg->grpColIdx;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
llvm::Value* hAggRunner = NULL;
llvm::Value* batch = NULL;
llvm::Value* tmpval = NULL;
llvm::Value* cmpval = NULL;
llvm::Value* idx_next = NULL;
llvm::Value* llvmargs[2];
llvm::PHINode* phi_idx = NULL;
llvm::Function* jitted_agghashing = NULL;
DEFINE_CG_VOIDTYPE(voidType);
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int32Type, INT4OID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(int32PtrType, INT4OID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
DEFINE_CG_PTRTYPE(hashCellPtrType, "struct.hashCell");
DEFINE_CG_PTRPTRTYPE(hashCellPtrPtrType, "struct.hashCell");
DEFINE_CG_PTRTYPE(vectorBatchPtrType, "class.VectorBatch");
DEFINE_CG_PTRTYPE(scalarVecPtrType, "class.ScalarVector");
DEFINE_CG_PTRTYPE(hashAggRunnerPtrType, "class.HashAggRunner");
DEFINE_CG_PTRTYPE(hashSegTblPtrType, "struct.HashSegTbl");
DEFINE_CGVAR_INT32(int32_m1, -1);
DEFINE_CGVAR_INT32(int32_0, 0);
DEFINE_CGVAR_INT32(int32_1, 1);
DEFINE_CGVAR_INT32(int32_pos_hBOper_cols, pos_hBOper_cols);
DEFINE_CGVAR_INT32(int32_pos_hBOper_cacheLoc, pos_hBOper_cacheLoc);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hashVal, pos_hAggR_hashVal);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hSegTbl, pos_hAggR_hSegTbl);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hsegmax, pos_hAggR_hsegmax);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hashSize, pos_hAggR_hashSize);
DEFINE_CGVAR_INT32(int32_pos_bAggR_keyIdxInCell, pos_bAggR_keyIdxInCell);
DEFINE_CGVAR_INT32(int32_pos_bAggR_Loc, pos_bAggR_Loc);
DEFINE_CGVAR_INT32(int32_pos_bAggR_keySimple, pos_bAggR_keySimple);
DEFINE_CGVAR_INT32(int32_pos_hcell_mval, pos_hcell_mval);
DEFINE_CGVAR_INT32(int32_pos_batch_marr, pos_batch_marr);
DEFINE_CGVAR_INT32(int32_pos_scalvec_vals, pos_scalvec_vals);
DEFINE_CGVAR_INT32(int32_pos_scalvec_flag, pos_scalvec_flag);
DEFINE_CGVAR_INT64(Datum_0, 0);
DEFINE_CGVAR_INT64(Datum_1, 1);
llvm::Value* Vals[2] = {Datum_0, int32_0};
llvm::Value* Vals3[3] = {Datum_0, int32_0, int32_0};
llvm::Value* Vals4[4] = {Datum_0, int32_0, int32_0, int32_0};
llvm::Value* Vals5[5] = {Datum_0, int32_0, int32_0, int32_0, int32_0};
const char* name = NULL;
if (isSglTbl) {
name = "JittedSglTblAggHashingWithPreFetch";
} else {
name = "JittedAggHashingWithPreFetch";
}
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, name, voidType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("hashAggRunner", hashAggRunnerPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("batch", vectorBatchPtrType));
jitted_agghashing = fn_prototype.generatePrototype(&builder, &llvmargs[0]);
hAggRunner = llvmargs[0];
batch = llvmargs[1];
tmpval = builder.CreateInBoundsGEP(batch, Vals);
llvm::Value* nValues = builder.CreateLoad(int32Type, tmpval, "m_rows");
Vals[1] = int32_pos_hAggR_hashSize;
tmpval = builder.CreateInBoundsGEP(hAggRunner, Vals);
llvm::Value* maskval = builder.CreateLoad(int64Type, tmpval, "m_hashSize");
maskval = builder.CreateSub(maskval, Datum_1, "mask");
Vals4[3] = int32_pos_hBOper_cols;
llvm::Value* m_colsVal = builder.CreateInBoundsGEP(hAggRunner, Vals4);
llvm::BasicBlock* entry = &jitted_agghashing->getEntryBlock();
DEFINE_BLOCK(hashing_for_body, jitted_agghashing);
DEFINE_BLOCK(hashing_for_end, jitted_agghashing);
DEFINE_BLOCK(hashing_for_inc, jitted_agghashing);
DEFINE_BLOCK(for_body, jitted_agghashing);
DEFINE_BLOCK(for_end, jitted_agghashing);
DEFINE_BLOCK(for_inc, jitted_agghashing);
DEFINE_BLOCK(while_body, jitted_agghashing);
DEFINE_BLOCK(key_match, jitted_agghashing);
DEFINE_BLOCK(hashval_eq, jitted_agghashing);
DEFINE_BLOCK(next_cell, jitted_agghashing);
DEFINE_BLOCK(alloc_hashslot, jitted_agghashing);
llvm::Value** keyIdxInCell = (llvm::Value**)palloc(sizeof(llvm::Value*) * numkeys);
llvm::Value** pVector = (llvm::Value**)palloc(sizeof(llvm::Value*) * numkeys);
llvm::Value** pFlag = (llvm::Value**)palloc(sizeof(llvm::Value*) * numkeys);
Vals3[0] = Datum_0;
Vals3[1] = int32_0;
Vals3[2] = int32_pos_bAggR_keyIdxInCell;
llvm::Value* cellkeyIdx = builder.CreateInBoundsGEP(hAggRunner, Vals3);
cellkeyIdx = builder.CreateLoad(int32PtrType, cellkeyIdx, "keyIdxInCellArr");
for (i = 0; i < numkeys; i++) {
tmpval = llvmCodeGen->getIntConstant(INT4OID, i);
keyIdxInCell[i] = builder.CreateInBoundsGEP(cellkeyIdx, tmpval);
keyIdxInCell[i] = builder.CreateLoad(int32Type, keyIdxInCell[i], "m_keyIdxInCell");
}
Vals[0] = Datum_0;
Vals[1] = int32_pos_batch_marr;
tmpval = builder.CreateInBoundsGEP(batch, Vals);
llvm::Value* tmparr = builder.CreateLoad(scalarVecPtrType, tmpval, "m_arr");
for (i = 0; i < numkeys; i++) {
AttrNumber key = keyIdx[i] - 1;
Vals[0] = llvmCodeGen->getIntConstant(INT8OID, key);
Vals[1] = int32_pos_scalvec_vals;
llvm::Value* pVec = builder.CreateInBoundsGEP(tmparr, Vals);
pVector[i] = builder.CreateLoad(int64PtrType, pVec, "pVector");
Vals[1] = int32_pos_scalvec_flag;
llvm::Value* Flag = builder.CreateInBoundsGEP(tmparr, Vals);
pFlag[i] = builder.CreateLoad(int8PtrType, Flag, "pFlag");
}
* Begin to loop the whole batch to evaluation hashval
*/
builder.SetInsertPoint(entry);
tmpval = builder.CreateICmpSGT(nValues, int32_0);
builder.CreateCondBr(tmpval, hashing_for_body, for_end);
builder.SetInsertPoint(hashing_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, hashing_for_inc);
llvm::Value* hash_res = int32_m1;
bool rehash = false;
for (i = 0; i < numkeys; i++) {
if (i > 0)
rehash = true;
llvm::Function* func_hashbatch = HashBatchCodeGen(node, i, rehash);
if (func_hashbatch == NULL) {
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmodule(MOD_LLVM),
errmsg("Failed on generating HashBatchCodeGen!\n")));
}
llvm::Value* pval = builder.CreateInBoundsGEP(pVector[i], phi_idx);
pval = builder.CreateLoad(int64Type, pval, "pval");
llvm::Value* pflag = builder.CreateInBoundsGEP(pFlag[i], phi_idx);
pflag = builder.CreateLoad(int8Type, pflag, "pflag");
hash_res = builder.CreateCall(func_hashbatch, {pval, pflag, hash_res});
}
Vals3[1] = int32_pos_hAggR_hashVal;
Vals3[2] = phi_idx;
llvm::Value* hashValSlot = builder.CreateInBoundsGEP(hAggRunner, Vals3);
llvm::Value* hash_res64 = builder.CreateZExt(hash_res, int64Type);
builder.CreateStore(hash_res64, hashValSlot);
builder.CreateBr(hashing_for_inc);
builder.SetInsertPoint(hashing_for_inc);
tmpval = builder.CreateTrunc(idx_next, int32Type);
tmpval = builder.CreateICmpEQ(tmpval, nValues);
builder.CreateCondBr(tmpval, hashing_for_end, hashing_for_body);
builder.SetInsertPoint(hashing_for_end);
builder.CreateBr(for_body);
* Ending the hashing loop and starting the loop for match_key.
* Initializing hash cell according to the match key result.
*/
builder.SetInsertPoint(for_body);
phi_idx = builder.CreatePHI(int64Type, 2);
idx_next = builder.CreateAdd(phi_idx, Datum_1);
phi_idx->addIncoming(Datum_0, hashing_for_end);
phi_idx->addIncoming(idx_next, for_inc);
if (isSglTbl) {
llvm::Function* func_sgltblprefetch = llvmCodeGen->module()->getFunction("prefetchAggSglTblHashing");
if (func_sgltblprefetch == NULL) {
func_sgltblprefetch = prefetchAggSglTblHashingCodeGen();
}
llvm::Value* nrows = builder.CreateZExt(nValues, int64Type);
builder.CreateCall(func_sgltblprefetch, {hAggRunner, phi_idx, nrows});
} else {
llvm::Function* func_prefetch = llvmCodeGen->module()->getFunction("prefetchAggHashing");
if (func_prefetch == NULL) {
func_prefetch = prefetchAggHashingCodeGen();
}
llvm::Value* nrows = builder.CreateZExt(nValues, int64Type);
builder.CreateCall(func_prefetch, {hAggRunner, phi_idx, nrows});
}
Vals3[1] = int32_pos_hAggR_hashVal;
Vals3[2] = phi_idx;
hashValSlot = builder.CreateInBoundsGEP(hAggRunner, Vals3);
hash_res64 = builder.CreateLoad(int64Type, hashValSlot, "m_hashVal");
hash_res = builder.CreateTrunc(hash_res64, int32Type);
llvm::Value* cacheLocVal = builder.CreateAnd(hash_res64, maskval, "cacheLoc");
Vals5[3] = int32_pos_hBOper_cacheLoc;
Vals5[4] = phi_idx;
llvm::Value* cacheLoc_i = builder.CreateInBoundsGEP(hAggRunner, Vals5);
builder.CreateStore(cacheLocVal, cacheLoc_i);
llvm::Value* segmaxval = NULL;
llvm::Value* nsegsval = NULL;
llvm::Value* pos = NULL;
if (!isSglTbl) {
Vals[0] = Datum_0;
Vals[1] = int32_pos_hAggR_hsegmax;
segmaxval = builder.CreateInBoundsGEP(hAggRunner, Vals);
segmaxval = builder.CreateLoad(int32Type, segmaxval, "segmax");
segmaxval = builder.CreateSExt(segmaxval, int64Type);
nsegsval = builder.CreateExactUDiv(cacheLocVal, segmaxval, "nsegs");
nsegsval = builder.CreateTrunc(nsegsval, int32Type);
pos = builder.CreateSRem(cacheLocVal, segmaxval, "pos");
}
Vals[0] = Datum_0;
Vals[1] = int32_pos_hAggR_hSegTbl;
llvm::Value* hashData = builder.CreateInBoundsGEP(hAggRunner, Vals);
hashData = builder.CreateLoad(hashSegTblPtrType, hashData, "m_hashData");
if (isSglTbl) {
Vals[0] = int32_0;
} else {
Vals[0] = nsegsval;
}
Vals[1] = int32_1;
llvm::Value* tbldata = builder.CreateInBoundsGEP(hashData, Vals);
tbldata = builder.CreateLoad(hashCellPtrPtrType, tbldata, "tbl_data");
if (isSglTbl) {
tmpval = builder.CreateInBoundsGEP(tbldata, cacheLocVal);
} else {
tmpval = builder.CreateInBoundsGEP(tbldata, pos);
}
llvm::Value* cellval = builder.CreateLoad(hashCellPtrType, tmpval, "cell");
tmpval = builder.CreatePtrToInt(cellval, int64Type);
cmpval = builder.CreateICmpEQ(tmpval, Datum_0);
builder.CreateCondBr(cmpval, alloc_hashslot, while_body);
builder.SetInsertPoint(while_body);
llvm::PHINode* phi_cell = builder.CreatePHI(hashCellPtrType, 2);
builder.SetInsertPoint(next_cell);
Vals3[0] = Datum_0;
Vals3[1] = int32_0;
Vals3[2] = int32_0;
llvm::Value* nextcellval = builder.CreateInBoundsGEP(phi_cell, Vals3);
nextcellval = builder.CreateLoad(hashCellPtrType, nextcellval, "nextcellval");
tmpval = builder.CreatePtrToInt(nextcellval, int64Type);
cmpval = builder.CreateICmpEQ(tmpval, Datum_0);
builder.CreateCondBr(cmpval, alloc_hashslot, while_body);
builder.SetInsertPoint(while_body);
phi_cell->addIncoming(nextcellval, next_cell);
phi_cell->addIncoming(cellval, for_body);
tmpval = builder.CreateLoad(int32Type, m_colsVal, "m_cols");
tmpval = builder.CreateZExt(tmpval, int64Type);
Vals4[0] = Datum_0;
Vals4[1] = int32_pos_hcell_mval;
Vals4[2] = tmpval;
Vals4[3] = int32_0;
tmpval = builder.CreateInBoundsGEP(phi_cell, Vals4);
tmpval = builder.CreateLoad(int64Type, tmpval, "hashval_cell");
llvm::Value* cmp_hashval = builder.CreateICmpEQ(hash_res64, tmpval);
builder.CreateCondBr(cmp_hashval, hashval_eq, next_cell);
* When hash val is equal, we only consider the result of matchkey.
* Loop over all the keys, once the key is not matched, get the
* next cell. If all the keys have been compared, find the next cell
* or keymatched according to the result. The following code is the
* codegeneration of the following code:
* if (true && match_key(<simple>)(batch, i, cell))
* { ...; break; }
* cell = cell->flag.m_next
*/
builder.SetInsertPoint(hashval_eq);
for (i = 0; i < numkeys; i++) {
llvm::Function* func_matchonekey = MatchOneKeyCodeGen(node, i);
if (NULL == func_matchonekey) {
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE),
errmodule(MOD_LLVM),
errmsg("Failed on generating MatchOneKey Function!\n")));
}
llvm::Value* pval = builder.CreateInBoundsGEP(pVector[i], phi_idx);
pval = builder.CreateLoad(int64Type, pval, "pval");
llvm::Value* pflag = builder.CreateInBoundsGEP(pFlag[i], phi_idx);
pflag = builder.CreateLoad(int8Type, pflag, "pflag");
llvm::Value* res = builder.CreateCall(func_matchonekey, {pval, pflag, phi_cell, keyIdxInCell[i]});
cmpval = builder.CreateICmpEQ(res, Datum_0);
if (i == numkeys - 1)
builder.CreateCondBr(cmpval, next_cell, key_match);
else {
DEFINE_BLOCK(next_bb, jitted_agghashing);
builder.CreateCondBr(cmpval, next_cell, next_bb);
builder.SetInsertPoint(next_bb);
}
}
* when both hash value and all keys are matched, remember this
* hash cell and go to next tuple.
*/
builder.SetInsertPoint(key_match);
VecAggCheckUnique(vecagg, &builder);
Vals4[0] = Datum_0;
Vals4[1] = int32_0;
Vals4[2] = int32_pos_bAggR_Loc;
Vals4[3] = phi_idx;
tmpval = builder.CreateInBoundsGEP(hAggRunner, Vals4);
builder.CreateStore(phi_cell, tmpval);
builder.CreateBr(for_inc);
builder.SetInsertPoint(alloc_hashslot);
Vals3[0] = Datum_0;
Vals3[1] = int32_0;
Vals3[2] = int32_pos_bAggR_keySimple;
llvm::Value* simple_key = builder.CreateInBoundsGEP(hAggRunner, Vals3);
simple_key = builder.CreateLoad(int32Type, simple_key, "key_simple");
WarpAllocHashSlotCodeGen(&builder, hAggRunner, batch, phi_idx, simple_key);
builder.CreateBr(for_inc);
builder.SetInsertPoint(for_inc);
tmpval = builder.CreateTrunc(idx_next, int32Type);
tmpval = builder.CreateICmpEQ(tmpval, nValues);
builder.CreateCondBr(tmpval, for_end, for_body);
builder.SetInsertPoint(for_end);
builder.CreateRetVoid();
llvmCodeGen->FinalizeFunction(jitted_agghashing, vecagg->plan.plan_node_id);
return jitted_agghashing;
}
llvm::Function* VecHashAggCodeGen::BatchAggregationCodeGen(VecAggState* node, bool use_prefetch)
{
int numaggs = node->numaggs;
VecAggStatePerAgg peragg = node->pervecagg;
Assert(NULL != (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj);
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
if (!BatchAggJittable(node, false))
return NULL;
llvmCodeGen->loadIRFile();
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
llvm::Module* mod = llvmCodeGen->module();
int i;
int exprscale = 0;
bool fast_aggref = false;
ExprState* estate = NULL;
llvm::Value* nValues = NULL;
llvm::Value* tmpval = NULL;
llvm::Value* idx_next = NULL;
llvm::Value* cell = NULL;
llvm::Value* result = NULL;
llvm::Value* expres = NULL;
llvm::Value* llvmargs[4];
Aggref* aggref = NULL;
llvm::Function* jitted_batchagg = NULL;
DEFINE_CG_VOIDTYPE(voidType);
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(int32PtrType, INT4OID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
DEFINE_CG_PTRTYPE(hashCellPtrType, "struct.hashCell");
DEFINE_CG_PTRPTRTYPE(hashCellPtrPtrType, "struct.hashCell");
DEFINE_CG_PTRTYPE(exprCxtPtrType, "struct.ExprContext");
DEFINE_CG_PTRTYPE(vecBatchPtrType, "class.VectorBatch");
DEFINE_CG_PTRTYPE(scalarVecPtrType, "class.ScalarVector");
DEFINE_CG_PTRTYPE(hashAggRunnerPtrType, "class.HashAggRunner");
DEFINE_CG_PTRTYPE(numericPtrType, "struct.NumericData");
DEFINE_CG_PTRTYPE(memCxtDataPtrType, "struct.MemoryContextData");
llvm::Type* Elements[] = {int16Type, int64Type};
llvm::Type* SiNumeric64Type = llvm::StructType::create(context, Elements, "SiNumeric64");
DEFINE_CGVAR_INT8(int8_0, 0);
DEFINE_CGVAR_INT8(int8_1, 1);
DEFINE_CGVAR_INT16(val_mask, NUMERIC_BI_MASK);
DEFINE_CGVAR_INT16(val_binum64, NUMERIC_64);
DEFINE_CGVAR_INT32(int32_0, 0);
DEFINE_CGVAR_INT32(int32_1, 1);
DEFINE_CGVAR_INT64(int64_0, 0);
DEFINE_CGVAR_INT64(int64_1, 1);
DEFINE_CGVAR_INT64(int64_6, 6);
DEFINE_CGVAR_INT32(int32_pos_batch_marr, pos_batch_marr);
DEFINE_CGVAR_INT32(int32_pos_scalvec_vals, pos_scalvec_vals);
DEFINE_CGVAR_INT32(int32_pos_scalvec_flag, pos_scalvec_flag);
DEFINE_CGVAR_INT32(int32_pos_ecxt_pertuple, pos_ecxt_pertuple);
DEFINE_CGVAR_INT32(int32_pos_ecxt_outerbatch, pos_ecxt_outerbatch);
DEFINE_CGVAR_INT32(int32_pos_hBOper_hcxt, pos_hBOper_hcxt);
DEFINE_CGVAR_INT32(int32_pos_bAggR_econtext, pos_bAggR_econtext);
DEFINE_CGVAR_INT32(int32_pos_hcell_mval, pos_hcell_mval);
llvm::Value* Vals[2] = {int64_0, int32_0};
llvm::Value* Vals3[3] = {int64_0, int32_0, int32_0};
llvm::Value* Vals4[4] = {int64_0, int32_0, int32_0, int32_0};
llvm::Value** aggIdxList = (llvm::Value**)palloc(sizeof(llvm::Value*) * numaggs);
llvm::Value** batch_vals = (llvm::Value**)palloc(sizeof(llvm::Value*) * numaggs);
llvm::Value** batch_flag = (llvm::Value**)palloc(sizeof(llvm::Value*) * numaggs);
llvm::BasicBlock** agg_bb = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * numaggs);
llvm::BasicBlock** flag_then = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * numaggs);
llvm::BasicBlock** flag_else = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * numaggs);
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "JittedFastBatchAgg", voidType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("haRuner", hashAggRunnerPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("Loc", hashCellPtrPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("batch", vecBatchPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("aggIdx", int32PtrType));
jitted_batchagg = fn_prototype.generatePrototype(&builder, &llvmargs[0]);
llvm::Value* hAggRunner = llvmargs[0];
llvm::Value* hashCellPP = llvmargs[1];
llvm::Value* batch = llvmargs[2];
llvm::Value* aggIdx = llvmargs[3];
llvm::Value* isNull = builder.CreateAlloca(int8Type);
Vals4[3] = int32_pos_hBOper_hcxt;
llvm::Value* hcxt = builder.CreateInBoundsGEP(hAggRunner, Vals4);
hcxt = builder.CreateLoad(memCxtDataPtrType, hcxt, "hashContext");
tmpval = builder.CreateInBoundsGEP(batch, Vals);
nValues = builder.CreateLoad(int32Type, tmpval, "m_rows");
Vals[0] = int64_0;
Vals[1] = int32_pos_batch_marr;
llvm::Value* argVector = builder.CreateInBoundsGEP(batch, Vals);
argVector = builder.CreateLoad(scalarVecPtrType, argVector, "m_arr");
llvm::Value** econtext = (llvm::Value**)palloc(sizeof(llvm::Value*) * numaggs);
for (i = 0; i < numaggs; i++) {
econtext[i] = NULL;
VecAggStatePerAgg peraggstate = &node->pervecagg[numaggs - i - 1];
aggref = (Aggref*)(peraggstate->aggref);
if (peraggstate->evalproj != NULL && aggref->aggfnoid != COUNTOID) {
ExprContext* exprcontext = peragg[numaggs - 1 - i].evalproj->pi_exprContext;
econtext[i] = llvmCodeGen->CastPtrToLlvmPtr(exprCxtPtrType, exprcontext);
}
}
llvm::BasicBlock* entry = &jitted_batchagg->getEntryBlock();
DEFINE_BLOCK(for_body, jitted_batchagg);
DEFINE_BLOCK(for_inc, jitted_batchagg);
DEFINE_BLOCK(for_end, jitted_batchagg);
for (i = 0; i < numaggs; i++) {
llvm::Value* tmpidx = llvmCodeGen->getIntConstant(INT4OID, i);
tmpval = builder.CreateInBoundsGEP(aggIdx, tmpidx);
tmpval = builder.CreateLoad(int32Type, tmpval, "aggIdx");
aggIdxList[i] = builder.CreateSExt(tmpval, int64Type);
agg_bb[i] = llvm::BasicBlock::Create(context, "agg_bb", jitted_batchagg);
flag_then[i] = llvm::BasicBlock::Create(context, "flag_then", jitted_batchagg);
flag_else[i] = llvm::BasicBlock::Create(context, "flag_else", jitted_batchagg);
}
* Start the main process for batchaggregation, which has the following
* pedudo code:
* for (j = 0; j < nrows; j++){
* for (i = 0; i < m_aggNum; i++){
* peraggstate = peragg[numaggs - 1 - i];
* pbatch = ExecVecProject (peraggstate->evalproj)
* AggregationOnScalar(aggInfo[i], &pbatch->m_arr[0], aggidx[i], m_Loc)
* }
* }
*/
builder.SetInsertPoint(entry);
* First get the ecxt_per_tuple_memory, since we need to switch to this
* memory context.
*/
Vals3[2] = int32_pos_bAggR_econtext;
llvm::Value* mecontext = builder.CreateInBoundsGEP(hAggRunner, Vals3);
mecontext = builder.CreateLoad(exprCxtPtrType, mecontext, "m_econtext");
Vals[1] = int32_pos_ecxt_pertuple;
llvm::Value* agg_expr_context = builder.CreateInBoundsGEP(mecontext, Vals);
agg_expr_context = builder.CreateLoad(memCxtDataPtrType, agg_expr_context, "agg_per_tuple_memory");
llvm::Value* agg_oldcontext = VecExprCodeGen::MemCxtSwitToCodeGen(&builder, agg_expr_context);
* Load value and flag from batch before the batch loop when we have
* simple vars in transition level.
*/
for (i = 0; i < numaggs; i++) {
int numSimpleVars = 0;
VecAggStatePerAgg peraggstate = &node->pervecagg[numaggs - i - 1];
aggref = (Aggref*)(peraggstate->aggref);
ProjectionInfo* projInfo = (ProjectionInfo*)(peraggstate->evalproj);
if (aggref->aggstage == 0 && aggref->aggfnoid != COUNTOID) {
numSimpleVars = projInfo->pi_numSimpleVars;
if (numSimpleVars > 0) {
int* varNumbers = projInfo->pi_varNumbers;
int varNumber = varNumbers[0] - 1;
Vals[0] = llvmCodeGen->getIntConstant(INT8OID, varNumber);
Vals[1] = int32_pos_scalvec_vals;
tmpval = builder.CreateInBoundsGEP(argVector, Vals);
tmpval = builder.CreateLoad(int64PtrType, tmpval, "m_vals");
batch_vals[i] = tmpval;
Vals[1] = int32_pos_scalvec_flag;
llvm::Value* argFlag = builder.CreateInBoundsGEP(argVector, Vals);
argFlag = builder.CreateLoad(int8PtrType, argFlag, "m_flag");
batch_flag[i] = argFlag;
}
}
}
tmpval = builder.CreateICmpSGT(nValues, int32_0);
builder.CreateCondBr(tmpval, for_body, for_end);
builder.SetInsertPoint(for_body);
llvm::PHINode* phi_idx = builder.CreatePHI(int64Type, 2);
idx_next = builder.CreateAdd(phi_idx, int64_1);
phi_idx->addIncoming(int64_0, entry);
phi_idx->addIncoming(idx_next, for_inc);
if (use_prefetch) {
llvm::Function* func_prefetch = llvmCodeGen->module()->getFunction("prefetchBatchAggregation");
if (NULL == func_prefetch) {
func_prefetch = prefetchBatchAggregationCodeGen();
}
llvm::Value* nrows = builder.CreateZExt(nValues, int64Type);
builder.CreateCall(func_prefetch, {hashCellPP, phi_idx, nrows});
}
* get the hashcell : cell = Loc[i] (see vnumeric_sum and vint8_sum)
* and check if it is NULL
*/
tmpval = builder.CreateInBoundsGEP(hashCellPP, phi_idx);
cell = builder.CreateLoad(hashCellPtrType, tmpval, "hashCell");
tmpval = builder.CreatePtrToInt(cell, int64Type);
tmpval = builder.CreateICmpEQ(tmpval, int64_0);
builder.CreateCondBr(tmpval, for_inc, agg_bb[0]);
int numSimpleVars = 0;
for (i = 0; i < numaggs; i++) {
llvm::BasicBlock* bisum_bb = NULL;
llvm::BasicBlock* numsum_bb = NULL;
VecAggStatePerAgg peraggstate = &node->pervecagg[numaggs - i - 1];
aggref = (Aggref*)(peraggstate->aggref);
ProjectionInfo* projInfo = (ProjectionInfo*)(peraggstate->evalproj);
builder.SetInsertPoint(agg_bb[i]);
if (aggref->aggstage == 0) {
if (aggref->aggfnoid != COUNTOID) {
Assert(peraggstate->evalproj != NULL);
AggrefExprState* aggexprstate = peraggstate->aggrefstate;
estate = (ExprState*)linitial(aggexprstate->args);
fast_aggref = AggRefFastJittable(estate);
* Do not consider collection and finalization level for
* numeric_avg to avoid deconstruct_array.
*/
if (aggref->aggfnoid == NUMERICAVGFUNCOID && aggref->aggstage > 0)
fast_aggref = false;
* load it from the batch directly
*/
if (projInfo == NULL) {
ereport(ERROR,
(errcode(ERRCODE_UNEXPECTED_NULL_VALUE),
errmodule(MOD_LLVM),
errmsg("Unexpected NULL project information.")));
}
numSimpleVars = projInfo->pi_numSimpleVars;
if (numSimpleVars > 0) {
tmpval = batch_vals[i];
tmpval = builder.CreateInBoundsGEP(tmpval, phi_idx);
result = builder.CreateLoad(int64Type, tmpval, "val");
tmpval = batch_flag[i];
tmpval = builder.CreateInBoundsGEP(tmpval, phi_idx);
tmpval = builder.CreateLoad(int8Type, tmpval, "flag");
builder.CreateStore(tmpval, isNull);
} else {
Vals[0] = int64_0;
Vals[1] = int32_pos_ecxt_outerbatch;
llvm::Value* tmp_outerbatch = builder.CreateInBoundsGEP(econtext[i], Vals);
builder.CreateStore(batch, tmp_outerbatch);
* If fast_aggref is true, we could try to evaluate the
* expression value by using BI64 all the way, and turn
* to original path once meet outofbound.
*/
if (fast_aggref) {
llvm::BasicBlock* bb_last = builder.GetInsertBlock();
DEFINE_BLOCK(bb_null, jitted_batchagg);
DEFINE_BLOCK(bb_outofbound, jitted_batchagg);
if (NULL == bisum_bb) {
bisum_bb = llvm::BasicBlock::Create(context, "bisum_bb", jitted_batchagg);
}
if (NULL == numsum_bb) {
numsum_bb = llvm::BasicBlock::Create(context, "numsum_bb", jitted_batchagg);
}
llvm::Value* tmpexpres = EvalFastExprInBatchAgg(estate,
builder,
jitted_batchagg,
&bb_null,
&bb_last,
&bb_outofbound,
econtext[i],
argVector,
phi_idx);
builder.SetInsertPoint(bb_last);
builder.CreateStore(int8_0, isNull);
llvm::Value* tmp_scale = builder.CreateExtractValue(tmpexpres, 0);
llvm::Value* tmp_value = builder.CreateExtractValue(tmpexpres, 1);
expres = llvm::UndefValue::get(SiNumeric64Type);
expres = builder.CreateInsertValue(expres, tmp_scale, 0);
expres = builder.CreateInsertValue(expres, tmp_value, 1);
builder.CreateBr(bisum_bb);
builder.SetInsertPoint(bb_null);
builder.CreateStore(int8_1, isNull);
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
* the original path
*/
builder.SetInsertPoint(bb_outofbound);
Vals[0] = int64_0;
Vals[1] = int32_pos_ecxt_pertuple;
llvm::Value* curr_Context = builder.CreateInBoundsGEP(econtext[i], Vals);
curr_Context = builder.CreateLoad(memCxtDataPtrType, curr_Context, "per_tuple_memory");
llvm::Value* cg_oldContext = VecExprCodeGen::MemCxtSwitToCodeGen(&builder, curr_Context);
result = EvalSimpleExprInBatchAgg(estate, builder, econtext[i], phi_idx, isNull);
(void)VecExprCodeGen::MemCxtSwitToCodeGen(&builder, cg_oldContext);
} else {
* corresponding to ExecVecProject(peraggstate->evalproj) :
* to evaluate expressions, we should turn to per_tuple_memory.
*/
Vals[0] = int64_0;
Vals[1] = int32_pos_ecxt_pertuple;
llvm::Value* curr_Context = builder.CreateInBoundsGEP(econtext[i], Vals);
curr_Context = builder.CreateLoad(memCxtDataPtrType, curr_Context, "per_tuple_memory");
llvm::Value* cg_oldContext = VecExprCodeGen::MemCxtSwitToCodeGen(&builder, curr_Context);
result = EvalSimpleExprInBatchAgg(estate, builder, econtext[i], phi_idx, isNull);
(void)VecExprCodeGen::MemCxtSwitToCodeGen(&builder, cg_oldContext);
}
}
} else {
* When current stage is transaction and aggfnoid is COUNTOID, no need to
* load any batch information. since we only need to plus one when cell
* is not null.
*/
result = int64_0;
builder.CreateStore(int8_0, isNull);
}
} else {
* When aggref->stage is not transiction, the aggref expr is always
* be var, so get the value from batch directly (projInfo is not null).
*/
if (projInfo != NULL) {
int* varNumbers = projInfo->pi_varNumbers;
int varNumber = varNumbers[0] - 1;
Vals[0] = llvmCodeGen->getIntConstant(INT8OID, varNumber);
Vals[1] = int32_pos_scalvec_vals;
tmpval = builder.CreateInBoundsGEP(argVector, Vals);
tmpval = builder.CreateLoad(int64PtrType, tmpval, "m_vals");
tmpval = builder.CreateInBoundsGEP(tmpval, phi_idx);
result = builder.CreateLoad(int64Type, tmpval, "val");
Vals[1] = int32_pos_scalvec_flag;
llvm::Value* argFlag = builder.CreateInBoundsGEP(argVector, Vals);
argFlag = builder.CreateLoad(int8PtrType, argFlag, "m_flag");
tmpval = builder.CreateInBoundsGEP(argFlag, phi_idx);
tmpval = builder.CreateLoad(int8Type, tmpval, "flag");
builder.CreateStore(tmpval, isNull);
} else {
ereport(ERROR,
(errcode(ERRCODE_UNEXPECTED_NULL_VALUE),
errmodule(MOD_LLVM),
errmsg("Unexpected NULL project information.")));
}
}
if (aggref->aggfnoid == COUNTOID) {
flag_then[i]->eraseFromParent();
flag_else[i]->eraseFromParent();
char* Jittedname = NULL;
if (aggref->aggstage == 0)
Jittedname = "Jitted_count_0";
else
Jittedname = "Jitted_count_1";
llvm::Function* func_vcount = llvmCodeGen->module()->getFunction(Jittedname);
if (NULL == func_vcount) {
func_vcount = vec_count_codegen(aggref);
}
builder.CreateCall(func_vcount, {cell, aggIdxList[i], result});
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
} else {
* now we already get HashCell cell(cellval) and pVector(result), check
* the flag and do aggregation.
*/
llvm::Value* tmpnull = builder.CreateLoad(int8Type, isNull, "tmpnull");
tmpnull = builder.CreateAnd(tmpnull, int8_1);
llvm::Value* flag_cmp = builder.CreateICmpEQ(tmpnull, int8_0);
builder.CreateCondBr(flag_cmp, flag_then[i], flag_else[i]);
builder.SetInsertPoint(flag_then[i]);
switch (aggref->aggfnoid) {
case INT8SUMFUNCOID: {
llvm::Function* func_vint8sum = llvmCodeGen->module()->getFunction("Jitted_int8sum");
if (NULL == func_vint8sum) {
func_vint8sum = int8_sum_codegen(aggref);
}
builder.CreateCall(func_vint8sum, {cell, hcxt, aggIdxList[i], result});
} break;
case INT8AVGFUNCOID: {
llvm::Function* func_vint8avg = llvmCodeGen->module()->getFunction("Jitted_int8avg");
if (NULL == func_vint8avg) {
func_vint8avg = int8_avg_codegen(aggref);
}
builder.CreateCall(func_vint8avg, {cell, hcxt, aggIdxList[i], result});
} break;
case NUMERICSUMFUNCOID: {
* If aggref can be evaluated in fast path and just be
* simple vars, use the result from batch.
*/
if (fast_aggref && (numSimpleVars > 0)) {
DEFINE_BLOCK(agg_then, jitted_batchagg);
DEFINE_BLOCK(agg_else, jitted_batchagg);
DEFINE_BLOCK(agg_end, jitted_batchagg);
DEFINE_BLOCK(normal_bb, jitted_batchagg);
DEFINE_BLOCK(var_bisum_bb, jitted_batchagg);
DEFINE_BLOCK(var_numsum_bb, jitted_batchagg);
Vals4[0] = int64_0;
Vals4[1] = int32_pos_hcell_mval;
Vals4[2] = aggIdxList[i];
Vals4[3] = int32_0;
llvm::Value* cellval = builder.CreateInBoundsGEP(cell, Vals4);
Vals4[3] = int32_1;
llvm::Value* cellflag = builder.CreateInBoundsGEP(cell, Vals4);
tmpval = builder.CreateLoad(int8Type, cellflag, "cellFlag");
tmpval = builder.CreateAnd(tmpval, int8_1);
tmpval = builder.CreateICmpEQ(tmpval, int8_0);
builder.CreateCondBr(tmpval, agg_else, agg_then);
builder.SetInsertPoint(agg_then);
* should make a new context to record the result : the
* following code corresponding to:
* 'leftarg = DatumGetBINumeric(pVal[i]);
* cell->m_val[idx].val = addVariable(context, NumericGetDatum(leftarg));'.
*/
tmpval = DatumGetBINumericCodeGen(&builder, result);
tmpval = builder.CreatePtrToInt(tmpval, int64Type);
tmpval = WrapaddVariableCodeGen(&builder, hcxt, tmpval);
builder.CreateStore(tmpval, cellval);
builder.CreateStore(int8_0, cellflag);
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
builder.SetInsertPoint(agg_else);
* When fast_aggref is true and numSimpleVars is greater than zero,
* the expr is numeric type var. Convert this numeric type data to
* SiNumeric data to get the value.
*/
llvm::Value* bires = DatumGetBINumericCodeGen(&builder, result);
Vals4[0] = int64_0;
Vals4[1] = int32_1;
Vals4[2] = int32_0;
Vals4[3] = int32_0;
tmpval = builder.CreateInBoundsGEP(bires, Vals4);
tmpval = builder.CreateLoad(int16Type, tmpval, "biheader");
llvm::Value* rflag = builder.CreateAnd(tmpval, val_mask);
llvm::Value* real_cellval = builder.CreateLoad(int64Type, cellval, "cell_val");
llvm::Value* cellarg = builder.CreateIntToPtr(real_cellval, numericPtrType);
tmpval = builder.CreateInBoundsGEP(cellarg, Vals4);
tmpval = builder.CreateLoad(int16Type, tmpval, "cellheader");
llvm::Value* lflag = builder.CreateAnd(tmpval, val_mask);
llvm::Value* oparg1 = builder.CreateICmpEQ(lflag, val_binum64);
llvm::Value* oparg2 = builder.CreateICmpEQ(rflag, val_binum64);
llvm::Value* bothbi64 = builder.CreateAnd(oparg1, oparg2);
builder.CreateCondBr(bothbi64, var_bisum_bb, var_numsum_bb);
builder.SetInsertPoint(var_bisum_bb);
Vals4[0] = int64_0;
Vals4[1] = int32_1;
Vals4[2] = int32_0;
Vals4[3] = int32_1;
tmpval = builder.CreateInBoundsGEP(bires, Vals4);
tmpval = builder.CreateBitCast(tmpval, int64PtrType);
llvm::Value* resval = builder.CreateLoad(int64Type, tmpval, "value");
llvm::Value* cell_addr = builder.CreateAdd(real_cellval, int64_6);
cell_addr = builder.CreateIntToPtr(cell_addr, int64PtrType);
llvm::Value* mid_cell_val = builder.CreateLoad(int64Type, cell_addr);
llvm::Type* Intrinsic_Tys[] = {int64Type};
llvm::Function* func_sadd_overflow =
llvm::Intrinsic::getDeclaration(mod, llvm_sadd_with_overflow, Intrinsic_Tys);
if (func_sadd_overflow == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Cannot get the llvm::Intrinsic::sadd_with_overflow function!\n")));
}
llvm::Value* aggres = builder.CreateCall(func_sadd_overflow, {resval, mid_cell_val});
llvm::Value* oflag = builder.CreateExtractValue(aggres, 1);
builder.CreateCondBr(oflag, var_numsum_bb, normal_bb);
builder.SetInsertPoint(var_numsum_bb);
llvm::Function* func_vnumericsum = llvmCodeGen->module()->getFunction("Jitted_numericsum");
if (NULL == func_vnumericsum) {
func_vnumericsum = numeric_sum_codegen(aggref);
}
builder.CreateCall(func_vnumericsum, {cell, hcxt, aggIdxList[i], result});
builder.CreateBr(agg_end);
builder.SetInsertPoint(normal_bb);
llvm::Value* sumval = builder.CreateExtractValue(aggres, 0);
builder.CreateStore(sumval, cell_addr);
builder.CreateBr(agg_end);
builder.SetInsertPoint(agg_end);
} else if (fast_aggref) {
* If aggref can be evaluated in fast path and be numeric
* expressions, use the result from fastexpr.
*/
Assert(bisum_bb != NULL);
Assert(numsum_bb != NULL);
DEFINE_BLOCK(agg_end, jitted_batchagg);
DEFINE_BLOCK(agg_then, jitted_batchagg);
DEFINE_BLOCK(agg_else, jitted_batchagg);
DEFINE_BLOCK(normal_bb, jitted_batchagg);
DEFINE_BLOCK(expr_bisum_bb, jitted_batchagg);
DEFINE_BLOCK(bioverflow_bb, jitted_batchagg);
* if the result of expression is outofbound, turn to
* original numeric path.
*/
builder.CreateBr(numsum_bb);
* if the result of expression is BI64, extract it.
*/
builder.SetInsertPoint(bisum_bb);
llvm::Value* resval = builder.CreateExtractValue(expres, 1);
Vals4[0] = int64_0;
Vals4[1] = int32_pos_hcell_mval;
Vals4[2] = aggIdxList[i];
Vals4[3] = int32_0;
llvm::Value* cellval = builder.CreateInBoundsGEP(cell, Vals4);
Vals4[3] = int32_1;
llvm::Value* cellflag = builder.CreateInBoundsGEP(cell, Vals4);
tmpval = builder.CreateLoad(int8Type, cellflag, "cellFlag");
tmpval = builder.CreateAnd(tmpval, int8_1);
tmpval = builder.CreateICmpEQ(tmpval, int8_0);
builder.CreateCondBr(tmpval, agg_else, agg_then);
builder.SetInsertPoint(agg_then);
exprscale = GetAlignedScale(estate->expr);
llvm::Value* alignedscale = llvmCodeGen->getIntConstant(CHAROID, exprscale);
* should make a new context to record the result : the
* following code corresponding to:
* 'leftarg = DatumGetBINumeric(pVal[i]);
* cell->m_val[idx].val = addVariable(context, NumericGetDatum(leftarg));'.
*/
tmpval = WrapmakeNumeric64CodeGen(&builder, resval, alignedscale);
tmpval = DatumGetBINumericCodeGen(&builder, tmpval);
tmpval = builder.CreatePtrToInt(tmpval, int64Type);
tmpval = WrapaddVariableCodeGen(&builder, hcxt, tmpval);
builder.CreateStore(tmpval, cellval);
builder.CreateStore(int8_0, cellflag);
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
builder.SetInsertPoint(agg_else);
llvm::Value* real_cellval = builder.CreateLoad(int64Type, cellval, "cell_val");
Vals4[0] = int64_0;
Vals4[1] = int32_1;
Vals4[2] = int32_0;
Vals4[3] = int32_0;
llvm::Value* cellarg = builder.CreateIntToPtr(real_cellval, numericPtrType);
tmpval = builder.CreateInBoundsGEP(cellarg, Vals4);
tmpval = builder.CreateLoad(int16Type, tmpval, "cellheader");
llvm::Value* biflag = builder.CreateAnd(tmpval, val_mask);
llvm::Value* isbi64 = builder.CreateICmpEQ(biflag, val_binum64);
builder.CreateCondBr(isbi64, expr_bisum_bb, bioverflow_bb);
* do aggregation directly only when both expr value
* and cell value is bi64.
*/
builder.SetInsertPoint(expr_bisum_bb);
llvm::Value* cell_ptr = builder.CreateAdd(real_cellval, int64_6);
cell_ptr = builder.CreateIntToPtr(cell_ptr, int64PtrType);
llvm::Value* mid_cell_val = builder.CreateLoad(int64Type, cell_ptr);
llvm::Type* Intrinsic_Tys[] = {int64Type};
llvm::Function* func_sadd_overflow =
llvm::Intrinsic::getDeclaration(mod, llvm_sadd_with_overflow, Intrinsic_Tys);
if (func_sadd_overflow == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Cannot get the llvm::Intrinsic::sadd_with_overflow function!\n")));
}
llvm::Value* aggres = builder.CreateCall(func_sadd_overflow, {resval, mid_cell_val});
llvm::Value* oflag = builder.CreateExtractValue(aggres, 1);
builder.CreateCondBr(oflag, bioverflow_bb, normal_bb);
builder.SetInsertPoint(bioverflow_bb);
exprscale = GetAlignedScale(estate->expr);
llvm::Value* ascale = llvmCodeGen->getIntConstant(CHAROID, exprscale);
llvm::Value* bioverres = WrapmakeNumeric64CodeGen(&builder, resval, ascale);
builder.CreateBr(numsum_bb);
builder.SetInsertPoint(numsum_bb);
llvm::PHINode* numres = builder.CreatePHI(int64Type, 2);
numres->addIncoming(result, flag_then[i]);
numres->addIncoming(bioverres, bioverflow_bb);
llvm::Value* evalval = (llvm::Value*)numres;
llvm::Function* func_vnumericsum = llvmCodeGen->module()->getFunction("Jitted_numericsum");
if (NULL == func_vnumericsum) {
func_vnumericsum = numeric_sum_codegen(aggref);
}
builder.CreateCall(func_vnumericsum, {cell, hcxt, aggIdxList[i], evalval});
builder.CreateBr(agg_end);
builder.SetInsertPoint(normal_bb);
llvm::Value* sumval = builder.CreateExtractValue(aggres, 0);
builder.CreateStore(sumval, cell_ptr);
builder.CreateBr(agg_end);
builder.SetInsertPoint(agg_end);
} else {
llvm::Function* func_vnumericsum = llvmCodeGen->module()->getFunction("Jitted_numericsum");
if (NULL == func_vnumericsum) {
func_vnumericsum = numeric_sum_codegen(aggref);
}
builder.CreateCall(func_vnumericsum, {cell, hcxt, aggIdxList[i], result});
}
} break;
case NUMERICAVGFUNCOID: {
* If aggref can be evaluated in fast path and just be
* simple vars, use the result from batch.
*/
if (fast_aggref && (numSimpleVars > 0)) {
DEFINE_BLOCK(agg_then, jitted_batchagg);
DEFINE_BLOCK(agg_else, jitted_batchagg);
DEFINE_BLOCK(agg_end, jitted_batchagg);
DEFINE_BLOCK(normal_bb, jitted_batchagg);
DEFINE_BLOCK(bisum_bblock, jitted_batchagg);
DEFINE_BLOCK(numsum_bblock, jitted_batchagg);
Vals4[0] = int64_0;
Vals4[1] = int32_pos_hcell_mval;
Vals4[2] = aggIdxList[i];
Vals4[3] = int32_0;
llvm::Value* cellval = builder.CreateInBoundsGEP(cell, Vals4);
Vals4[2] = builder.CreateAdd(aggIdxList[i], int64_1, "val_plus");
llvm::Value* cellval2 = builder.CreateInBoundsGEP(cell, Vals4);
Vals4[2] = aggIdxList[i];
Vals4[3] = int32_1;
llvm::Value* cellflag = builder.CreateInBoundsGEP(cell, Vals4);
Vals4[2] = builder.CreateAdd(aggIdxList[i], int64_1, "flag_plus");
llvm::Value* cellflag2 = builder.CreateInBoundsGEP(cell, Vals4);
tmpval = builder.CreateLoad(int8Type, cellflag, "cellFlag");
tmpval = builder.CreateAnd(tmpval, int8_1);
tmpval = builder.CreateICmpEQ(tmpval, int8_0);
builder.CreateCondBr(tmpval, agg_else, agg_then);
builder.SetInsertPoint(agg_then);
tmpval = DatumGetBINumericCodeGen(&builder, result);
tmpval = builder.CreatePtrToInt(tmpval, int64Type);
tmpval = WrapaddVariableCodeGen(&builder, hcxt, tmpval);
builder.CreateStore(tmpval, cellval);
builder.CreateStore(int64_1, cellval2);
builder.CreateStore(int8_0, cellflag);
builder.CreateStore(int8_0, cellflag2);
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
builder.SetInsertPoint(agg_else);
* When fast_aggref is true and numSimpleVars is greater than zero,
* the expr is numeric type var. Convert this numeric type data to
* SiNumeric data to get the value.
*/
llvm::Value* bires = DatumGetBINumericCodeGen(&builder, result);
Vals4[0] = int64_0;
Vals4[1] = int32_1;
Vals4[2] = int32_0;
Vals4[3] = int32_0;
tmpval = builder.CreateInBoundsGEP(bires, Vals4);
tmpval = builder.CreateLoad(int16Type, tmpval, "biheader");
llvm::Value* rflag = builder.CreateAnd(tmpval, val_mask);
llvm::Value* real_cellval = builder.CreateLoad(int64Type, cellval, "cell_val");
llvm::Value* cellarg = builder.CreateIntToPtr(real_cellval, numericPtrType);
tmpval = builder.CreateInBoundsGEP(cellarg, Vals4);
tmpval = builder.CreateLoad(int16Type, tmpval, "cellheader");
llvm::Value* lflag = builder.CreateAnd(tmpval, val_mask);
llvm::Value* oparg1 = builder.CreateICmpEQ(lflag, val_binum64);
llvm::Value* oparg2 = builder.CreateICmpEQ(rflag, val_binum64);
llvm::Value* bothbi64 = builder.CreateAnd(oparg1, oparg2);
builder.CreateCondBr(bothbi64, bisum_bblock, numsum_bblock);
builder.SetInsertPoint(bisum_bblock);
Vals4[0] = int64_0;
Vals4[1] = int32_1;
Vals4[2] = int32_0;
Vals4[3] = int32_1;
tmpval = builder.CreateInBoundsGEP(bires, Vals4);
tmpval = builder.CreateBitCast(tmpval, int64PtrType);
llvm::Value* resval = builder.CreateLoad(int64Type, tmpval, "value");
llvm::Value* cell_addr = builder.CreateAdd(real_cellval, int64_6);
cell_addr = builder.CreateIntToPtr(cell_addr, int64PtrType);
llvm::Value* mid_cell_val = builder.CreateLoad(int64Type, cell_addr);
llvm::Type* Intrinsic_Tys[] = {int64Type};
llvm::Function* func_sadd_overflow =
llvm::Intrinsic::getDeclaration(mod, llvm_sadd_with_overflow, Intrinsic_Tys);
if (func_sadd_overflow == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Cannot get the llvm::Intrinsic::sadd_with_overflow function!\n")));
}
llvm::Value* aggres = builder.CreateCall(func_sadd_overflow, {resval, mid_cell_val});
llvm::Value* oflag = builder.CreateExtractValue(aggres, 1);
builder.CreateCondBr(oflag, numsum_bblock, normal_bb);
builder.SetInsertPoint(numsum_bblock);
llvm::Function* func_vnumericavg = llvmCodeGen->module()->getFunction("Jitted_numericavg");
if (NULL == func_vnumericavg) {
func_vnumericavg = numeric_avg_codegen(aggref);
}
builder.CreateCall(func_vnumericavg, {cell, hcxt, aggIdxList[i], result});
builder.CreateBr(agg_end);
builder.SetInsertPoint(normal_bb);
llvm::Value* sumval = builder.CreateExtractValue(aggres, 0);
builder.CreateStore(sumval, cell_addr);
tmpval = builder.CreateLoad(int64Type, cellval2, "count");
tmpval = builder.CreateAdd(tmpval, int64_1);
builder.CreateStore(tmpval, cellval2);
builder.CreateBr(agg_end);
builder.SetInsertPoint(agg_end);
} else if (fast_aggref) {
* If aggref can be evaluated in fast path and be numeric
* expressions, use the result from fastexpr.
*/
Assert(bisum_bb != NULL);
Assert(numsum_bb != NULL);
DEFINE_BLOCK(agg_end, jitted_batchagg);
DEFINE_BLOCK(agg_then, jitted_batchagg);
DEFINE_BLOCK(agg_else, jitted_batchagg);
DEFINE_BLOCK(normal_bb, jitted_batchagg);
DEFINE_BLOCK(expr_bisum_bb, jitted_batchagg);
DEFINE_BLOCK(bioverflow_bb, jitted_batchagg);
builder.CreateBr(numsum_bb);
builder.SetInsertPoint(bisum_bb);
llvm::Value* resval = builder.CreateExtractValue(expres, 1);
Vals4[0] = int64_0;
Vals4[1] = int32_pos_hcell_mval;
Vals4[2] = aggIdxList[i];
Vals4[3] = int32_0;
llvm::Value* cellval = builder.CreateInBoundsGEP(cell, Vals4);
Vals4[2] = builder.CreateAdd(aggIdxList[i], int64_1, "val_plus");
llvm::Value* cellval2 = builder.CreateInBoundsGEP(cell, Vals4);
;
Vals4[2] = aggIdxList[i];
Vals4[3] = int32_1;
llvm::Value* cellflag = builder.CreateInBoundsGEP(cell, Vals4);
Vals4[2] = builder.CreateAdd(aggIdxList[i], int64_1, "flag_plus");
llvm::Value* cellflag2 = builder.CreateInBoundsGEP(cell, Vals4);
tmpval = builder.CreateLoad(int8Type, cellflag, "cellFlag");
tmpval = builder.CreateAnd(tmpval, int8_1);
tmpval = builder.CreateICmpEQ(tmpval, int8_0);
builder.CreateCondBr(tmpval, agg_else, agg_then);
builder.SetInsertPoint(agg_then);
exprscale = GetAlignedScale(estate->expr);
llvm::Value* alignedscale = llvmCodeGen->getIntConstant(CHAROID, exprscale);
* should make a new context to record the result : the
* following code corresponding to:
* 'leftarg = DatumGetBINumeric(pVal[i]);
* cell->m_val[idx].val = addVariable(context, NumericGetDatum(leftarg));'.
*/
tmpval = WrapmakeNumeric64CodeGen(&builder, resval, alignedscale);
tmpval = DatumGetBINumericCodeGen(&builder, tmpval);
tmpval = builder.CreatePtrToInt(tmpval, int64Type);
tmpval = WrapaddVariableCodeGen(&builder, hcxt, tmpval);
builder.CreateStore(tmpval, cellval);
builder.CreateStore(int64_1, cellval2);
builder.CreateStore(int8_0, cellflag);
builder.CreateStore(int8_0, cellflag2);
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
builder.SetInsertPoint(agg_else);
llvm::Value* real_cellval = builder.CreateLoad(int64Type, cellval, "cell_val");
Vals4[0] = int64_0;
Vals4[1] = int32_1;
Vals4[2] = int32_0;
Vals4[3] = int32_0;
llvm::Value* cellarg = builder.CreateIntToPtr(real_cellval, numericPtrType);
tmpval = builder.CreateInBoundsGEP(cellarg, Vals4);
tmpval = builder.CreateLoad(int16Type, tmpval, "cellheader");
llvm::Value* biflag = builder.CreateAnd(tmpval, val_mask);
llvm::Value* isbi64 = builder.CreateICmpEQ(biflag, val_binum64);
builder.CreateCondBr(isbi64, expr_bisum_bb, bioverflow_bb);
* do aggregation directly only when both expr value
* and cell value is bi64.
*/
builder.SetInsertPoint(expr_bisum_bb);
llvm::Value* cell_ptr = builder.CreateAdd(real_cellval, int64_6);
cell_ptr = builder.CreateIntToPtr(cell_ptr, int64PtrType);
llvm::Value* mid_cell_val = builder.CreateLoad(int64Type, cell_ptr);
llvm::Type* Intrinsic_Tys[] = {int64Type};
llvm::Function* func_sadd_overflow =
llvm::Intrinsic::getDeclaration(mod, llvm_sadd_with_overflow, Intrinsic_Tys);
if (func_sadd_overflow == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Cannot get the llvm::Intrinsic::sadd_with_overflow function!\n")));
}
llvm::Value* aggres = builder.CreateCall(func_sadd_overflow, {resval, mid_cell_val});
llvm::Value* oflag = builder.CreateExtractValue(aggres, 1);
builder.CreateCondBr(oflag, bioverflow_bb, normal_bb);
builder.SetInsertPoint(bioverflow_bb);
exprscale = GetAlignedScale(estate->expr);
llvm::Value* ascale = llvmCodeGen->getIntConstant(CHAROID, exprscale);
llvm::Value* bioverres = WrapmakeNumeric64CodeGen(&builder, resval, ascale);
builder.CreateBr(numsum_bb);
builder.SetInsertPoint(numsum_bb);
llvm::PHINode* numres = builder.CreatePHI(int64Type, 2);
numres->addIncoming(result, flag_then[i]);
numres->addIncoming(bioverres, bioverflow_bb);
llvm::Value* evalval = (llvm::Value*)numres;
llvm::Function* func_vnumericavg = llvmCodeGen->module()->getFunction("Jitted_numericavg");
if (NULL == func_vnumericavg) {
func_vnumericavg = numeric_avg_codegen(aggref);
}
builder.CreateCall(func_vnumericavg, {cell, hcxt, aggIdxList[i], evalval});
builder.CreateBr(agg_end);
builder.SetInsertPoint(normal_bb);
llvm::Value* sumval = builder.CreateExtractValue(aggres, 0);
builder.CreateStore(sumval, cell_ptr);
tmpval = builder.CreateLoad(int64Type, cellval2, "count");
tmpval = builder.CreateAdd(tmpval, int64_1);
builder.CreateStore(tmpval, cellval2);
builder.CreateBr(agg_end);
builder.SetInsertPoint(agg_end);
} else {
llvm::Function* func_vnumericavg = llvmCodeGen->module()->getFunction("Jitted_numericavg");
if (NULL == func_vnumericavg) {
func_vnumericavg = numeric_avg_codegen(aggref);
}
builder.CreateCall(func_vnumericavg, {cell, hcxt, aggIdxList[i], result});
}
} break;
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmodule(MOD_LLVM),
errmsg("Unsupported agg function %u!", aggref->aggfnoid)));
break;
}
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
builder.SetInsertPoint(flag_else[i]);
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
}
}
builder.SetInsertPoint(for_inc);
tmpval = builder.CreateTrunc(idx_next, int32Type);
tmpval = builder.CreateICmpEQ(tmpval, nValues);
builder.CreateCondBr(tmpval, for_end, for_body);
builder.SetInsertPoint(for_end);
(void)VecExprCodeGen::MemCxtSwitToCodeGen(&builder, agg_oldcontext);
(void)WrapResetEContextCodeGen(&builder, mecontext);
for (i = 0; i < numaggs; i++) {
if (econtext[i])
(void)WrapResetEContextCodeGen(&builder, econtext[i]);
}
builder.CreateRetVoid();
pfree_ext(aggIdxList);
pfree_ext(agg_bb);
pfree_ext(flag_then);
pfree_ext(flag_else);
pfree_ext(econtext);
pfree_ext(batch_vals);
pfree_ext(batch_flag);
llvmCodeGen->FinalizeFunction(jitted_batchagg, node->ss.ps.plan->plan_node_id);
return jitted_batchagg;
}
llvm::Function* VecHashAggCodeGen::HashBatchCodeGen(VecAggState* node, int idx, bool rehash)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvmCodeGen->loadIRFile();
VecAgg* vecagg = (VecAgg*)(node->ss.ps.plan);
List* tlist = (outerPlan(vecagg))->targetlist;
AttrNumber* keyIdx = vecagg->grpColIdx;
AttrNumber key = keyIdx[idx] - 1;
TargetEntry* tentry = (TargetEntry*)list_nth(tlist, key);
int bpchar_len = 0;
Assert(IsA(tentry->expr, Var) || IsA(tentry->expr, FuncExpr));
Oid rettype = InvalidOid;
switch (nodeTag(tentry->expr)) {
case T_Var: {
Var* var = (Var*)(tentry->expr);
rettype = var->vartype;
if (var->vartype == BPCHAROID)
bpchar_len = var->vartypmod - VARHDRSZ;
} break;
case T_FuncExpr: {
FuncExpr* funcexpr = (FuncExpr*)(tentry->expr);
rettype = funcexpr->funcresulttype;
} break;
default:
Assert(0);
break;
}
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
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(int16PtrType, INT2OID);
DEFINE_CG_PTRTYPE(int32PtrType, INT4OID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
DEFINE_CGVAR_INT8(int8_0, 0);
DEFINE_CGVAR_INT8(int8_1, 1);
DEFINE_CGVAR_INT32(int32_0, 0);
DEFINE_CGVAR_INT32(int32_2, 2);
DEFINE_CGVAR_INT32(int32_4, 4);
DEFINE_CGVAR_INT64(Datum_0, 0);
llvm::Function* jitted_hashbatch = NULL;
llvm::Value* llvmargs[3];
llvm::Value* hash_res1 = NULL;
llvm::Value* hash_res2 = NULL;
llvm::Value* lt0_hash = NULL;
llvm::BasicBlock* EQ0_bb = NULL;
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "JittedHashBatch", int32Type);
fn_prototype.addArgument(GsCodeGen::NamedVariable("value", int64Type));
fn_prototype.addArgument(GsCodeGen::NamedVariable("flag", int8Type));
fn_prototype.addArgument(GsCodeGen::NamedVariable("hash_val", int32Type));
jitted_hashbatch = fn_prototype.generatePrototype(&builder, &llvmargs[0]);
llvm::Value* pval = llvmargs[0];
llvm::Value* flag = llvmargs[1];
llvm::Value* hash_val = llvmargs[2];
llvm::BasicBlock* entry = &jitted_hashbatch->getEntryBlock();
DEFINE_BLOCK(be_not_null, jitted_hashbatch);
DEFINE_BLOCK(be_null, jitted_hashbatch);
DEFINE_BLOCK(end_null, jitted_hashbatch);
builder.SetInsertPoint(entry);
flag = builder.CreateAnd(flag, int8_1);
llvm::Value* cmp = builder.CreateICmpEQ(flag, int8_0);
builder.CreateCondBr(cmp, be_not_null, be_null);
* corresponding to likely(NOT_NULL(flag[j])) branch in hashColT function.
*/
builder.SetInsertPoint(be_not_null);
llvm::Module* mod = llvmCodeGen->module();
switch (rettype) {
case INT4OID: {
hash_res1 = hash_val;
pval = builder.CreateTrunc(pval, int32Type);
llvm_crc32_32_32(hash_res1, hash_res1, pval);
} break;
case INT8OID:
case DATEOID:
case TIMESTAMPOID: {
hash_res1 = hash_val;
llvm_crc32_32_64(hash_res1, hash_res1, pval);
} break;
case BPCHAROID: {
int len = bpchar_len;
llvm::Function* func_evalvar = llvmCodeGen->module()->getFunction("JittedEvalVarlena");
if (func_evalvar == NULL) {
func_evalvar = VarlenaCvtCodeGen();
}
llvm::Value* res = builder.CreateCall(func_evalvar, pval, "func_evalvar");
llvm::Value* data1 = builder.CreateExtractValue(res, 1);
data1 = builder.CreatePtrToInt(data1, int64Type);
data1 = builder.CreateIntToPtr(data1, int8PtrType);
hash_res1 = hash_val;
if (len >= 8) {
int k = 0;
llvm::Value* big_data = builder.CreateBitCast(data1, int64PtrType);
llvm::Value* kidx = NULL;
while (len >= 8) {
kidx = llvmCodeGen->getIntConstant(INT4OID, k);
pval = builder.CreateInBoundsGEP(big_data, kidx);
pval = builder.CreateLoad(int64Type, pval, "bigdat");
llvm_crc32_32_64(hash_res1, hash_res1, pval);
len = len - 8;
k++;
}
kidx = llvmCodeGen->getIntConstant(INT4OID, k * 8);
data1 = builder.CreateInBoundsGEP(data1, kidx);
}
if (len >= 4) {
llvm::Value* data = builder.CreateBitCast(data1, int32PtrType);
pval = builder.CreateInBoundsGEP(data, Datum_0);
pval = builder.CreateLoad(int32Type, pval, "intdat");
llvm_crc32_32_32(hash_res1, hash_res1, pval);
data1 = builder.CreateInBoundsGEP(data1, int32_4);
len = len - 4;
}
if (len >= 2) {
llvm::Value* short_data = builder.CreateBitCast(data1, int16PtrType);
pval = builder.CreateInBoundsGEP(short_data, Datum_0);
pval = builder.CreateLoad(int16Type, pval, "shortdat");
llvm_crc32_32_16(hash_res1, hash_res1, pval);
data1 = builder.CreateInBoundsGEP(data1, int32_2);
len = len - 2;
}
if (len == 1) {
pval = builder.CreateLoad(int8Type, data1, "val_char");
llvm_crc32_32_8(hash_res1, hash_res1, pval);
}
} break;
case VARCHAROID:
case TEXTOID: {
* Different from bpchar type, we should create hash table according
* to the actual length of varchar or text.
*/
llvm::Value* cmpval = NULL;
llvm::Value* data = NULL;
llvm::Value* nxt_len = NULL;
llvm::Value* nxt_pos = NULL;
llvm::Value* nxt_hash = NULL;
DEFINE_CGVAR_INT32(int32_8, 8);
DEFINE_CGVAR_INT32(int32_4, 4);
DEFINE_CGVAR_INT32(int32_2, 2);
DEFINE_CGVAR_INT32(int32_1, 1);
DEFINE_BLOCK(GE8_bb, jitted_hashbatch);
DEFINE_BLOCK(end_GE8_bb, jitted_hashbatch);
DEFINE_BLOCK(LT8_bb, jitted_hashbatch);
DEFINE_BLOCK(GE4_bb, jitted_hashbatch);
DEFINE_BLOCK(LT4_bb, jitted_hashbatch);
DEFINE_BLOCK(GE2_bb, jitted_hashbatch);
DEFINE_BLOCK(LT2_bb, jitted_hashbatch);
DEFINE_BLOCK(EQ1_bb, jitted_hashbatch);
if (NULL == EQ0_bb) {
EQ0_bb = llvm::BasicBlock::Create(context, "EQ0_bb", jitted_hashbatch);
}
llvm::Function* func_evalvar = llvmCodeGen->module()->getFunction("JittedEvalVarlena");
if (func_evalvar == NULL) {
func_evalvar = VarlenaCvtCodeGen();
}
llvm::Value* res = builder.CreateCall(func_evalvar, pval, "func_evalvar");
llvm::Value* vlen = builder.CreateExtractValue(res, 0);
llvm::Value* vdata = builder.CreateExtractValue(res, 1);
vdata = builder.CreatePtrToInt(vdata, int64Type);
vdata = builder.CreateIntToPtr(vdata, int8PtrType);
hash_res1 = hash_val;
llvm::Value* bighash = builder.CreateZExt(hash_res1, int64Type);
llvm::Value* bigdata = builder.CreateBitCast(vdata, int64PtrType);
cmpval = builder.CreateICmpSGE(vlen, int32_8, "if_ge8");
builder.CreateCondBr(cmpval, GE8_bb, LT8_bb);
builder.SetInsertPoint(GE8_bb);
llvm::PHINode* phi_whl_len = builder.CreatePHI(int32Type, 2);
llvm::PHINode* phi_whl_pos = builder.CreatePHI(int32Type, 2);
llvm::PHINode* phi_whl_hash = builder.CreatePHI(int64Type, 2);
llvm::Value* whl_len = (llvm::Value*)phi_whl_len;
nxt_len = builder.CreateSub(whl_len, int32_8);
phi_whl_len->addIncoming(vlen, be_not_null);
phi_whl_len->addIncoming(nxt_len, GE8_bb);
llvm::Value* whl_pos = (llvm::Value*)phi_whl_pos;
nxt_pos = builder.CreateAdd(whl_pos, int32_1);
phi_whl_pos->addIncoming(int32_0, be_not_null);
phi_whl_pos->addIncoming(nxt_pos, GE8_bb);
llvm::Value* whl_hash = (llvm::Value*)phi_whl_hash;
whl_hash = builder.CreateTrunc(whl_hash, int32Type);
llvm::Value* whl_data = builder.CreateInBoundsGEP(bigdata, whl_pos);
whl_data = builder.CreateLoad(int64Type, whl_data, "whl_data");
llvm_crc32_32_64(nxt_hash, whl_hash, whl_data);
phi_whl_hash->addIncoming(bighash, be_not_null);
nxt_hash = builder.CreateZExt(nxt_hash, int64Type);
phi_whl_hash->addIncoming(nxt_hash, GE8_bb);
cmpval = builder.CreateICmpSGE(nxt_len, int32_8);
builder.CreateCondBr(cmpval, GE8_bb, end_GE8_bb);
builder.SetInsertPoint(end_GE8_bb);
llvm::Value* ge8_len = nxt_len;
llvm::Value* ge8_hash = builder.CreateTrunc(nxt_hash, int32Type);
llvm::Value* ge8_data = builder.CreateInBoundsGEP(bigdata, nxt_pos);
ge8_data = builder.CreateBitCast(ge8_data, int8PtrType);
builder.CreateBr(LT8_bb);
builder.SetInsertPoint(LT8_bb);
llvm::PHINode* phi_lt8_len = builder.CreatePHI(int32Type, 2);
phi_lt8_len->addIncoming(vlen, be_not_null);
phi_lt8_len->addIncoming(ge8_len, end_GE8_bb);
llvm::Value* lt8_len = (llvm::Value*)phi_lt8_len;
llvm::PHINode* phi_lt8_hash = builder.CreatePHI(int32Type, 2);
phi_lt8_hash->addIncoming(hash_res1, be_not_null);
phi_lt8_hash->addIncoming(ge8_hash, end_GE8_bb);
llvm::Value* lt8_hash = (llvm::Value*)phi_lt8_hash;
llvm::PHINode* phi_lt8_data = builder.CreatePHI(int8PtrType, 2);
phi_lt8_data->addIncoming(vdata, be_not_null);
phi_lt8_data->addIncoming(ge8_data, end_GE8_bb);
llvm::Value* lt8_data = (llvm::Value*)phi_lt8_data;
cmpval = builder.CreateICmpSGE(lt8_len, int32_4);
builder.CreateCondBr(cmpval, GE4_bb, LT4_bb);
builder.SetInsertPoint(GE4_bb);
data = builder.CreateBitCast(lt8_data, int32PtrType);
data = builder.CreateInBoundsGEP(data, Datum_0);
data = builder.CreateLoad(int32Type, data, "intdat");
llvm::Value* ge4_hash = NULL;
llvm_crc32_32_32(ge4_hash, lt8_hash, data);
llvm::Value* ge4_data = builder.CreateInBoundsGEP(lt8_data, int32_4);
llvm::Value* ge4_len = builder.CreateSub(lt8_len, int32_4);
builder.CreateBr(LT4_bb);
builder.SetInsertPoint(LT4_bb);
llvm::PHINode* phi_lt4_len = builder.CreatePHI(int32Type, 2);
phi_lt4_len->addIncoming(lt8_len, LT8_bb);
phi_lt4_len->addIncoming(ge4_len, GE4_bb);
llvm::Value* lt4_len = (llvm::Value*)phi_lt4_len;
llvm::PHINode* phi_lt4_hash = builder.CreatePHI(int32Type, 2);
phi_lt4_hash->addIncoming(lt8_hash, LT8_bb);
phi_lt4_hash->addIncoming(ge4_hash, GE4_bb);
llvm::Value* lt4_hash = (llvm::Value*)phi_lt4_hash;
llvm::PHINode* phi_lt4_data = builder.CreatePHI(int8PtrType, 2);
phi_lt4_data->addIncoming(lt8_data, LT8_bb);
phi_lt4_data->addIncoming(ge4_data, GE4_bb);
llvm::Value* lt4_data = (llvm::Value*)phi_lt4_data;
cmpval = builder.CreateICmpSGE(lt4_len, int32_2);
builder.CreateCondBr(cmpval, GE2_bb, LT2_bb);
builder.SetInsertPoint(GE2_bb);
data = builder.CreateBitCast(lt4_data, int16PtrType);
data = builder.CreateInBoundsGEP(data, Datum_0);
data = builder.CreateLoad(int16Type, data, "shortdat");
llvm::Value* ge2_hash = NULL;
llvm_crc32_32_16(ge2_hash, lt4_hash, data);
llvm::Value* ge2_data = builder.CreateInBoundsGEP(lt4_data, int32_2);
llvm::Value* ge2_len = builder.CreateSub(lt4_len, int32_2);
builder.CreateBr(LT2_bb);
builder.SetInsertPoint(LT2_bb);
llvm::PHINode* phi_lt2_len = builder.CreatePHI(int32Type, 2);
phi_lt2_len->addIncoming(lt4_len, LT4_bb);
phi_lt2_len->addIncoming(ge2_len, GE2_bb);
llvm::Value* lt2_len = (llvm::Value*)phi_lt2_len;
llvm::PHINode* phi_lt2_hash = builder.CreatePHI(int32Type, 2);
phi_lt2_hash->addIncoming(lt4_hash, LT4_bb);
phi_lt2_hash->addIncoming(ge2_hash, GE2_bb);
llvm::Value* lt2_hash = (llvm::Value*)phi_lt2_hash;
llvm::PHINode* phi_lt2_data = builder.CreatePHI(int8PtrType, 2);
phi_lt2_data->addIncoming(lt4_data, LT4_bb);
phi_lt2_data->addIncoming(ge2_data, GE2_bb);
llvm::Value* lt2_data = (llvm::Value*)phi_lt2_data;
cmpval = builder.CreateICmpEQ(lt2_len, int32_1);
builder.CreateCondBr(cmpval, EQ1_bb, EQ0_bb);
builder.SetInsertPoint(EQ1_bb);
data = builder.CreateLoad(int8Type, lt2_data, "val_char");
llvm::Value* lt1_hash = NULL;
llvm_crc32_32_8(lt1_hash, lt2_hash, data);
builder.CreateBr(EQ0_bb);
builder.SetInsertPoint(EQ0_bb);
llvm::PHINode* phi_lt0_hash = builder.CreatePHI(int32Type, 2);
phi_lt0_hash->addIncoming(lt2_hash, LT2_bb);
phi_lt0_hash->addIncoming(lt1_hash, EQ1_bb);
lt0_hash = (llvm::Value*)phi_lt0_hash;
} break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmodule(MOD_LLVM),
errmsg("Type %u is not supported yet in hashBatch", rettype)));
break;
}
builder.CreateBr(end_null);
* corresponding to the else branch:
* if (!rehash) { hashRes[j] = 0 }
*/
builder.SetInsertPoint(be_null);
if (!rehash)
hash_res2 = int32_0;
else
hash_res2 = hash_val;
builder.CreateBr(end_null);
builder.SetInsertPoint(end_null);
if (rettype != VARCHAROID && rettype != TEXTOID) {
llvm::PHINode* Phi_hash = builder.CreatePHI(int32Type, 2);
Phi_hash->addIncoming(hash_res1, be_not_null);
Phi_hash->addIncoming(hash_res2, be_null);
builder.CreateRet(Phi_hash);
} else {
llvm::PHINode* Phi_hash = builder.CreatePHI(int32Type, 2);
Phi_hash->addIncoming(lt0_hash, EQ0_bb);
Phi_hash->addIncoming(hash_res2, be_null);
builder.CreateRet(Phi_hash);
}
llvmCodeGen->FinalizeFunction(jitted_hashbatch, node->ss.ps.plan->plan_node_id);
return jitted_hashbatch;
}
llvm::Function* VecHashAggCodeGen::MatchOneKeyCodeGen(VecAggState* node, int idx)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvmCodeGen->loadIRFile();
VecAgg* vecagg = (VecAgg*)(node->ss.ps.plan);
List* tlist = (outerPlan(vecagg))->targetlist;
AttrNumber* keyIdx = vecagg->grpColIdx;
AttrNumber key = keyIdx[idx] - 1;
TargetEntry* tentry = (TargetEntry*)list_nth(tlist, key);
Assert(IsA(tentry->expr, Var) || IsA(tentry->expr, FuncExpr));
Oid rettype = InvalidOid;
int bpchar_len = 0;
switch (nodeTag(tentry->expr)) {
case T_Var: {
Var* var = (Var*)(tentry->expr);
rettype = var->vartype;
if (var->vartype == BPCHAROID)
bpchar_len = var->vartypmod - VARHDRSZ;
} break;
case T_FuncExpr: {
FuncExpr* funcexpr = (FuncExpr*)(tentry->expr);
rettype = funcexpr->funcresulttype;
} break;
default:
Assert(0);
break;
}
Var* var = (Var*)(tentry->expr);
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_PTRTYPE(hashCellPtrType, "struct.hashCell");
DEFINE_CGVAR_INT8(int8_0, 0);
DEFINE_CGVAR_INT8(int8_1, 1);
DEFINE_CGVAR_INT32(int32_0, 0);
DEFINE_CGVAR_INT32(int32_1, 1);
DEFINE_CGVAR_INT64(Datum_0, 0);
DEFINE_CGVAR_INT64(Datum_1, 1);
DEFINE_CGVAR_INT32(int32_pos_hcell_mval, pos_hcell_mval);
llvm::Function* jitted_matchonekey = NULL;
llvm::Value* tmpval = NULL;
llvm::Value* llvmargs[4];
llvm::Value* Vals4[4] = {Datum_0, int32_0, int32_0, int32_0};
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "JittedOneMatchKey", int64Type);
fn_prototype.addArgument(GsCodeGen::NamedVariable("value", int64Type));
fn_prototype.addArgument(GsCodeGen::NamedVariable("flag", int8Type));
fn_prototype.addArgument(GsCodeGen::NamedVariable("hashcell", hashCellPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("keycell_idx", int32Type));
jitted_matchonekey = fn_prototype.generatePrototype(&builder, &llvmargs[0]);
llvm::Value* pval = llvmargs[0];
llvm::Value* pflg = llvmargs[1];
llvm::Value* hashcell = llvmargs[2];
llvm::Value* keyidxincell = llvmargs[3];
DEFINE_BLOCK(bnot_null, jitted_matchonekey);
DEFINE_BLOCK(may_null, jitted_matchonekey);
DEFINE_BLOCK(both_null, jitted_matchonekey);
DEFINE_BLOCK(one_null, jitted_matchonekey);
DEFINE_BLOCK(check_end, jitted_matchonekey);
keyidxincell = builder.CreateSExt(keyidxincell, int64Type);
Vals4[0] = Datum_0;
Vals4[1] = int32_pos_hcell_mval;
Vals4[2] = keyidxincell;
Vals4[3] = int32_0;
tmpval = builder.CreateInBoundsGEP(hashcell, Vals4);
llvm::Value* keyval = builder.CreateLoad(int64Type, tmpval, "keyincell");
Vals4[3] = int32_1;
tmpval = builder.CreateInBoundsGEP(hashcell, Vals4);
llvm::Value* keyflg = builder.CreateLoad(int8Type, tmpval, "flagincell");
llvm::Value* cmp1 = NULL;
llvm::Value* cmp2 = NULL;
llvm::Value* cmpand = NULL;
llvm::Value* cmpor = NULL;
llvm::Value* res1 = NULL;
llvm::Value* res2 = NULL;
llvm::Value* res3 = NULL;
pflg = builder.CreateAnd(pflg, int8_1);
cmp1 = builder.CreateICmpEQ(pflg, int8_0);
keyflg = builder.CreateAnd(keyflg, int8_1);
cmp2 = builder.CreateICmpEQ(keyflg, int8_0);
cmpand = builder.CreateAnd(cmp1, cmp2);
cmpor = builder.CreateOr(cmp1, cmp2);
builder.CreateCondBr(cmpand, bnot_null, may_null);
builder.SetInsertPoint(bnot_null);
switch (rettype) {
case INT4OID: {
* should first truncate the keyval to make sure we compare the
* right value
*/
keyval = builder.CreateTrunc(keyval, int32Type);
pval = builder.CreateTrunc(pval, int32Type);
res1 = builder.CreateICmpEQ(keyval, pval);
res1 = builder.CreateZExt(res1, int64Type);
} break;
case INT8OID:
case DATEOID:
case TIMESTAMPOID: {
res1 = builder.CreateICmpEQ(keyval, pval);
res1 = builder.CreateZExt(res1, int64Type);
} break;
case BPCHAROID: {
llvm::Function* func_evalvar = llvmCodeGen->module()->getFunction("JittedEvalVarlena");
if (func_evalvar == NULL) {
func_evalvar = dorado::VarlenaCvtCodeGen();
}
llvm::Value* vecval = builder.CreateCall(func_evalvar, pval, "evalbatchvar");
llvm::Value* vecdata = builder.CreateExtractValue(vecval, 1);
llvm::Value* cellval = builder.CreateCall(func_evalvar, keyval, "evalcellvar");
llvm::Value* celldata = builder.CreateExtractValue(cellval, 1);
llvm::Function* evalmemcmp = llvmCodeGen->module()->getFunction("LLVMIRmemcmp");
if (evalmemcmp == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_IR_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Failed on getting IR function : LLVMIRmemcmp!\n")));
}
llvm::Value* lendat = llvmCodeGen->getIntConstant(INT4OID, bpchar_len);
res1 = builder.CreateCall(evalmemcmp, {celldata, vecdata, lendat}, "memcmp");
} break;
case TEXTOID:
case VARCHAROID: {
llvm::Function* func_evalvar = llvmCodeGen->module()->getFunction("JittedEvalVarlena");
if (func_evalvar == NULL) {
func_evalvar = VarlenaCvtCodeGen();
}
llvm::Value* vecval = builder.CreateCall(func_evalvar, pval, "evalbatchvar");
llvm::Value* veclen = builder.CreateExtractValue(vecval, 0);
llvm::Value* vecdata = builder.CreateExtractValue(vecval, 1);
llvm::Value* cellval = builder.CreateCall(func_evalvar, keyval, "evalcellvar");
llvm::Value* celllen = builder.CreateExtractValue(cellval, 0);
llvm::Value* celldata = builder.CreateExtractValue(cellval, 1);
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")));
}
res1 = builder.CreateCall(func_texteq_cc, {veclen, vecdata, celllen, celldata}, "texteq");
} break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmodule(MOD_LLVM),
(errmsg("Type %u is not supported yet in match_key", var->vartype))));
break;
}
builder.CreateBr(check_end);
builder.SetInsertPoint(may_null);
builder.CreateCondBr(cmpor, one_null, both_null);
builder.SetInsertPoint(both_null);
res2 = Datum_1;
builder.CreateBr(check_end);
builder.SetInsertPoint(one_null);
res3 = Datum_0;
builder.CreateBr(check_end);
builder.SetInsertPoint(check_end);
llvm::PHINode* Phi_ret = builder.CreatePHI(int64Type, 3);
Phi_ret->addIncoming(res1, bnot_null);
Phi_ret->addIncoming(res2, both_null);
Phi_ret->addIncoming(res3, one_null);
builder.CreateRet(Phi_ret);
llvmCodeGen->FinalizeFunction(jitted_matchonekey, node->ss.ps.plan->plan_node_id);
return jitted_matchonekey;
}
llvm::Value* VecHashAggCodeGen::EvalFastExprInBatchAgg(ExprState* state, GsCodeGen::LlvmBuilder& builder,
llvm::Function* jitted_func, llvm::BasicBlock** bb_null, llvm::BasicBlock** bb_last,
llvm::BasicBlock** bb_outofbound, llvm::Value* econtext, llvm::Value* argVector, llvm::Value* phi_idx)
{
dorado::GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::Module* mod = llvmCodeGen->module();
llvm::LLVMContext& context = llvmCodeGen->context();
DEFINE_CG_TYPE(int8Type, CHAROID);
DEFINE_CG_TYPE(int16Type, INT2OID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
DEFINE_CGVAR_INT8(int8_0, 0);
DEFINE_CGVAR_INT8(int8_1, 1);
DEFINE_CGVAR_INT16(int16_0, 0);
DEFINE_CGVAR_INT16(val_numeric64, NUMERIC_64);
DEFINE_CGVAR_INT16(val_bimask, NUMERIC_BI_MASK);
DEFINE_CGVAR_INT16(val_scalemask, NUMERIC_BI_SCALEMASK);
DEFINE_CGVAR_INT32(int32_pos_scalvec_vals, pos_scalvec_vals);
DEFINE_CGVAR_INT32(int32_pos_scalvec_flag, pos_scalvec_flag);
DEFINE_CGVAR_INT32(int32_0, 0);
DEFINE_CGVAR_INT32(int32_1, 1);
DEFINE_CGVAR_INT64(int64_0, 0);
llvm::Value* tmpval = NULL;
llvm::Value* cmpval = NULL;
llvm::Value* phi_val = NULL;
llvm::Value* result = NULL;
llvm::Value* multi_bound = NULL;
llvm::Value* left_scaled1 = NULL;
llvm::Value* left_scaled2 = NULL;
llvm::Value* right_scaled1 = NULL;
llvm::Value* right_scaled2 = NULL;
llvm::Value* resscale1 = NULL;
llvm::Value* resscale2 = NULL;
llvm::Value* res1 = NULL;
llvm::Value* lval = NULL;
llvm::Value* rval = NULL;
llvm::PHINode* left_scaled = NULL;
llvm::PHINode* right_scaled = NULL;
llvm::PHINode* resscale = NULL;
llvm::Type* Intrinsic_Tys[] = {int64Type};
llvm::Value* Vals[2] = {int64_0, int32_0};
llvm::Value* Vals4[4] = {int64_0, int32_0, int32_0, int32_0};
llvm::Type* Elements[] = {int16Type, int64Type};
llvm::Type* SiNumeric64Type = llvm::StructType::create(context, Elements, "SiNumeric64");
if (*bb_last)
builder.SetInsertPoint(*bb_last);
switch (nodeTag(state->expr)) {
case T_TargetEntry: {
GenericExprState* gstate = (GenericExprState*)state;
ExprState* estate = gstate->arg;
result = EvalFastExprInBatchAgg(
estate, builder, jitted_func, bb_null, bb_last, bb_outofbound, econtext, argVector, phi_idx);
} break;
case T_OpExpr: {
DEFINE_BLOCK(both_bi64, jitted_func);
DEFINE_BLOCK(not_both_bi64, jitted_func);
OpExpr* opexpr = (OpExpr*)state->expr;
FuncExprState* fstate = (FuncExprState*)state;
List* op_args = fstate->args;
ExprState* lestate = (ExprState*)linitial(op_args);
ExprState* restate = (ExprState*)lsecond(op_args);
lval = EvalFastExprInBatchAgg(
lestate, builder, jitted_func, bb_null, bb_last, bb_outofbound, econtext, argVector, phi_idx);
rval = EvalFastExprInBatchAgg(
restate, builder, jitted_func, bb_null, bb_last, bb_outofbound, econtext, argVector, phi_idx);
if (*bb_last)
builder.SetInsertPoint(*bb_last);
llvm::Value* lheader = builder.CreateExtractValue(lval, 0);
llvm::Value* rheader = builder.CreateExtractValue(rval, 0);
llvm::Value* lvalscale = builder.CreateAnd(lheader, val_scalemask);
llvm::Value* rvalscale = builder.CreateAnd(rheader, val_scalemask);
llvm::Value* lvalmask = builder.CreateAnd(lheader, val_bimask);
llvm::Value* lvalbi64 = builder.CreateICmpEQ(lvalmask, val_numeric64);
llvm::Value* rvalmask = builder.CreateAnd(rheader, val_bimask);
llvm::Value* rvalbi64 = builder.CreateICmpEQ(rvalmask, val_numeric64);
llvm::Value* bebi64 = builder.CreateAnd(lvalbi64, rvalbi64);
builder.CreateCondBr(bebi64, both_bi64, not_both_bi64);
builder.SetInsertPoint(both_bi64);
llvm::Value* leftval = builder.CreateExtractValue(lval, 1);
llvm::Value* rightval = builder.CreateExtractValue(rval, 1);
* adjust the scale and value, first define outofbound block
*/
if (opexpr->opno == NUMERICADDOID || opexpr->opno == NUMERICSUBOID) {
DEFINE_BLOCK(delta_large, jitted_func);
DEFINE_BLOCK(delta_small, jitted_func);
DEFINE_BLOCK(adjust_true, jitted_func);
DEFINE_BLOCK(adjust_overflow_bb, jitted_func);
DEFINE_BLOCK(adjust_normal_bb, jitted_func);
llvm::Value* delta_scale = builder.CreateSub(lvalscale, rvalscale, "delta_scale");
cmpval = builder.CreateICmpSGE(delta_scale, int16_0, "cmp_delta_scale");
builder.CreateCondBr(cmpval, delta_large, delta_small);
builder.SetInsertPoint(delta_large);
tmpval = builder.CreateSub(int64_0, rightval);
cmpval = builder.CreateICmpSLT(rightval, int64_0, "negative_cmp");
phi_val = builder.CreateSelect(cmpval, rightval, tmpval);
left_scaled1 = leftval;
llvm::Value* mulscale = ScaleMultiCodeGen(&builder, delta_scale);
right_scaled1 = builder.CreateMul(rightval, mulscale);
resscale1 = lvalscale;
multi_bound = GetInt64MulOutofBoundCodeGen(&builder, delta_scale);
cmpval = builder.CreateICmpSGE(phi_val, multi_bound, "bound_check");
builder.CreateCondBr(cmpval, adjust_true, *bb_outofbound);
builder.SetInsertPoint(delta_small);
tmpval = builder.CreateSub(int64_0, leftval);
cmpval = builder.CreateICmpSLT(leftval, int64_0, "negative_cmp");
phi_val = builder.CreateSelect(cmpval, leftval, tmpval);
llvm::Value* mdelta_scale = builder.CreateSub(int16_0, delta_scale);
llvm::Value* mmulscale = ScaleMultiCodeGen(&builder, mdelta_scale);
left_scaled2 = builder.CreateMul(leftval, mmulscale);
right_scaled2 = rightval;
resscale2 = rvalscale;
multi_bound = GetInt64MulOutofBoundCodeGen(&builder, mdelta_scale);
cmpval = builder.CreateICmpSGE(phi_val, multi_bound, "bound_check");
builder.CreateCondBr(cmpval, adjust_true, *bb_outofbound);
builder.SetInsertPoint(adjust_true);
left_scaled = builder.CreatePHI(int64Type, 2);
right_scaled = builder.CreatePHI(int64Type, 2);
resscale = builder.CreatePHI(int16Type, 2);
left_scaled->addIncoming(left_scaled1, delta_large);
left_scaled->addIncoming(left_scaled2, delta_small);
right_scaled->addIncoming(right_scaled1, delta_large);
right_scaled->addIncoming(right_scaled2, delta_small);
resscale->addIncoming(resscale1, delta_large);
resscale->addIncoming(resscale2, delta_small);
switch (opexpr->opno) {
case NUMERICADDOID: {
llvm::Function* func_sadd_overflow =
llvm::Intrinsic::getDeclaration(mod, llvm_sadd_with_overflow, Intrinsic_Tys);
if (func_sadd_overflow == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Cannot get the llvm::Intrinsic::sadd_with_overflow function!\n")));
}
llvm::Value* res = builder.CreateCall(func_sadd_overflow, {left_scaled, right_scaled}, "sadd");
llvm::Value* overflow_flag = builder.CreateExtractValue(res, 1);
builder.CreateCondBr(overflow_flag, adjust_overflow_bb, adjust_normal_bb);
builder.SetInsertPoint(adjust_normal_bb);
res1 = builder.CreateExtractValue(res, 0);
result = llvm::UndefValue::get(SiNumeric64Type);
llvm::Value* tmphead = builder.CreateAdd(val_numeric64, resscale);
result = builder.CreateInsertValue(result, tmphead, 0);
result = builder.CreateInsertValue(result, res1, 1);
*bb_last = adjust_normal_bb;
builder.SetInsertPoint(adjust_overflow_bb);
builder.CreateBr(*bb_outofbound);
} break;
case NUMERICSUBOID: {
llvm::Function* func_ssub_overflow =
llvm::Intrinsic::getDeclaration(mod, llvm_ssub_with_overflow, Intrinsic_Tys);
if (func_ssub_overflow == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Cannot get the llvm::Intrinsic::sasub_with_overflow function!\n")));
}
llvm::Value* res = builder.CreateCall(func_ssub_overflow, {left_scaled, right_scaled}, "sadd");
llvm::Value* overflow_flag = builder.CreateExtractValue(res, 1);
builder.CreateCondBr(overflow_flag, adjust_overflow_bb, adjust_normal_bb);
builder.SetInsertPoint(adjust_normal_bb);
res1 = builder.CreateExtractValue(res, 0);
result = llvm::UndefValue::get(SiNumeric64Type);
llvm::Value* tmphead = builder.CreateAdd(val_numeric64, resscale);
result = builder.CreateInsertValue(result, tmphead, 0);
result = builder.CreateInsertValue(result, res1, 1);
*bb_last = adjust_normal_bb;
builder.SetInsertPoint(adjust_overflow_bb);
builder.CreateBr(*bb_outofbound);
} break;
default:
Assert(0);
break;
}
} else if (opexpr->opno == NUMERICMULOID) {
DEFINE_BLOCK(mul64, jitted_func);
DEFINE_BLOCK(mul128, jitted_func);
DEFINE_CGVAR_INT16(maxInt64digitsNum, MAXINT64DIGIT);
llvm::Value* res_scale = builder.CreateAdd(lvalscale, rvalscale, "res_scale");
cmpval = builder.CreateICmpSLE(res_scale, maxInt64digitsNum, "cmp_delta_scale");
llvm::Function* func_smul_overflow =
llvm::Intrinsic::getDeclaration(mod, llvm_smul_with_overflow, Intrinsic_Tys);
if (func_smul_overflow == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Cannot get the llvm::Intrinsic::smul_with_overflow function!")));
}
llvm::Value* res = builder.CreateCall(func_smul_overflow, {leftval, rightval}, "smul");
llvm::Value* overflow_flag = builder.CreateExtractValue(res, 1);
llvm::Value* res_64 = builder.CreateExtractValue(res, 0);
cmpval = builder.CreateAnd(cmpval, builder.CreateNot(overflow_flag));
builder.CreateCondBr(cmpval, mul64, mul128);
builder.SetInsertPoint(mul64);
res1 = res_64;
result = llvm::UndefValue::get(SiNumeric64Type);
llvm::Value* tmphead = builder.CreateAdd(val_numeric64, res_scale);
result = builder.CreateInsertValue(result, tmphead, 0);
result = builder.CreateInsertValue(result, res_64, 1);
*bb_last = mul64;
builder.SetInsertPoint(mul128);
builder.CreateBr(*bb_outofbound);
} else {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmodule(MOD_LLVM),
errmsg("Unexpected operation %u!", opexpr->opno)));
}
* when one of the argument is bi128 : note that at most
* one of the argument is bi128.
*/
builder.SetInsertPoint(not_both_bi64);
builder.CreateBr(*bb_outofbound);
} break;
case T_Var: {
Var* var = (Var*)(state->expr);
llvm::Value* m_attno = llvmCodeGen->getIntConstant(INT8OID, var->varattno - 1);
Vals[0] = m_attno;
Vals[1] = int32_pos_scalvec_vals;
tmpval = builder.CreateInBoundsGEP(argVector, Vals);
tmpval = builder.CreateLoad(int64PtrType, tmpval, "m_vals");
tmpval = builder.CreateInBoundsGEP(tmpval, phi_idx);
llvm::Value* res = builder.CreateLoad(int64Type, tmpval, "val");
Vals[1] = int32_pos_scalvec_flag;
tmpval = builder.CreateInBoundsGEP(argVector, Vals);
tmpval = builder.CreateLoad(int8PtrType, tmpval, "m_flag");
tmpval = builder.CreateInBoundsGEP(tmpval, phi_idx);
llvm::Value* flg = builder.CreateLoad(int8Type, tmpval, "flag");
llvm::Value* tmpNull = builder.CreateAnd(flg, int8_1);
tmpval = builder.CreateICmpEQ(tmpNull, int8_0);
DEFINE_BLOCK(var_bb, jitted_func);
builder.CreateCondBr(tmpval, var_bb, *bb_null);
builder.SetInsertPoint(var_bb);
Assert(NUMERICOID == var->vartype);
result = llvm::UndefValue::get(SiNumeric64Type);
llvm::Value* bires = DatumGetBINumericCodeGen(&builder, res);
Vals4[0] = int64_0;
Vals4[1] = int32_1;
Vals4[2] = int32_0;
Vals4[3] = int32_0;
tmpval = builder.CreateInBoundsGEP(bires, Vals4);
tmpval = builder.CreateLoad(int16Type, tmpval, "header");
result = builder.CreateInsertValue(result, tmpval, 0);
Vals4[3] = int32_1;
tmpval = builder.CreateInBoundsGEP(bires, Vals4);
tmpval = builder.CreateBitCast(tmpval, int64PtrType);
tmpval = builder.CreateLoad(int64Type, tmpval, "value");
result = builder.CreateInsertValue(result, tmpval, 1);
*bb_last = var_bb;
return result;
} break;
case T_Const: {
Const* cst = (Const*)(state->expr);
ScalarValue val = ScalarVector::DatumToScalar(cst->constvalue, cst->consttype, cst->constisnull);
Assert(NUMERICOID == cst->consttype);
uint16 header;
Datum numval;
* first 4 bits to distinguish bi64 and bi128, next
* 4 bits are not used, the last 8 bits store the scale of bit integer
*/
Numeric arg = DatumGetBINumeric(val);
header = arg->choice.n_header;
numval = *(int64*)(arg->choice.n_bi.n_data);
result = llvm::UndefValue::get(SiNumeric64Type);
llvm::Value* hed = llvmCodeGen->getIntConstant(INT2OID, header);
llvm::Value* res = llvmCodeGen->getIntConstant(INT8OID, numval);
result = builder.CreateInsertValue(result, hed, 0);
result = builder.CreateInsertValue(result, res, 1);
return result;
} break;
default:
Assert(0);
break;
}
return result;
}
llvm::Value* VecHashAggCodeGen::EvalSimpleExprInBatchAgg(
ExprState* state, GsCodeGen::LlvmBuilder& builder, llvm::Value* econtext, llvm::Value* phi_idx, llvm::Value* isNull)
{
llvm::Value* result = NULL;
switch (nodeTag(state->expr)) {
case T_TargetEntry: {
GenericExprState* gstate = (GenericExprState*)state;
ExprState* estate = gstate->arg;
result = EvalSimpleExprInBatchAgg(estate, builder, econtext, phi_idx, isNull);
} break;
case T_Var:
case T_Const:
case T_OpExpr: {
llvm::Value* llvmargs[3];
llvmargs[0] = econtext;
llvmargs[1] = isNull;
llvmargs[2] = phi_idx;
* Prepare the parameters that needed by OpCodeGen.
*/
ExprCodeGenArgs args;
args.exprstate = state;
args.parent = NULL;
args.builder = &builder;
args.llvm_args = &llvmargs[0];
result = dorado::VecExprCodeGen::CodeGen(&args);
} break;
default:
Assert(0);
break;
}
return result;
}
llvm::Function* VecHashAggCodeGen::SonicBatchAggregationCodeGen(VecAggState* node, bool use_prefetch)
{
int numaggs = node->numaggs;
Assert(NULL != (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj);
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
if (!BatchAggJittable(node, true))
return NULL;
llvmCodeGen->loadIRFile();
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
llvm::Module* mod = llvmCodeGen->module();
int i;
int exprscale = 0;
bool fast_aggref = false;
ExprState* estate = NULL;
llvm::Value* nValues = NULL;
llvm::Value* tmpval = NULL;
llvm::Value* idx_next = NULL;
llvm::Value* locidx = NULL;
llvm::Value* result = NULL;
llvm::Value* expres = NULL;
llvm::Value* nbit = NULL;
llvm::Value* arrIdx = NULL;
llvm::Value* atomIdx = NULL;
llvm::Value* atom = NULL;
llvm::Value* cntatom = NULL;
llvm::Value* atomsize = NULL;
llvm::Value* data = NULL;
llvm::Value* cntdata = NULL;
llvm::Value* scount = NULL;
llvm::Value* llvmargs[3];
Aggref* aggref = NULL;
llvm::Function* jitted_sonicbatchagg = NULL;
DEFINE_CG_VOIDTYPE(voidType);
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(int16PtrType, INT2OID);
DEFINE_CG_PTRTYPE(int64PtrType, INT8OID);
DEFINE_CG_PTRTYPE(exprCxtPtrType, "struct.ExprContext");
DEFINE_CG_PTRTYPE(vecBatchPtrType, "class.VectorBatch");
DEFINE_CG_PTRTYPE(scalarVecPtrType, "class.ScalarVector");
DEFINE_CG_PTRTYPE(sonicEncodingDatumArrayPtrType, "class.SonicEncodingDatumArray");
DEFINE_CG_PTRTYPE(numericPtrType, "struct.NumericData");
DEFINE_CG_PTRTYPE(sonicHashAggPtrType, "class.SonicHashAgg");
DEFINE_CG_PTRTYPE(atomPtrType, "struct.atom");
DEFINE_CG_PTRPTRTYPE(atomPtrPtrType, "struct.atom");
DEFINE_CG_PTRTYPE(memCxtDataPtrType, "struct.MemoryContextData");
DEFINE_CG_PTRTYPE(sonicDatumArrayPtrType, "class.SonicDatumArray");
DEFINE_CG_PTRPTRTYPE(sonicDatumArrayPtrPtrType, "class.SonicDatumArray");
llvm::Type* Elements[] = {int16Type, int64Type};
llvm::Type* SiNumeric64Type = llvm::StructType::create(context, Elements, "SiNumeric64");
DEFINE_CGVAR_INT8(int8_0, 0);
DEFINE_CGVAR_INT8(int8_1, 1);
DEFINE_CGVAR_INT16(val_mask, NUMERIC_BI_MASK);
DEFINE_CGVAR_INT16(val_binum64, NUMERIC_64);
DEFINE_CGVAR_INT32(int32_0, 0);
DEFINE_CGVAR_INT32(int32_1, 1);
DEFINE_CGVAR_INT64(int64_0, 0);
DEFINE_CGVAR_INT64(int64_1, 1);
DEFINE_CGVAR_INT64(int64_6, 6);
DEFINE_CGVAR_INT32(int32_pos_batch_marr, pos_batch_marr);
DEFINE_CGVAR_INT32(int32_pos_scalvec_vals, pos_scalvec_vals);
DEFINE_CGVAR_INT32(int32_pos_scalvec_flag, pos_scalvec_flag);
DEFINE_CGVAR_INT32(int32_pos_ecxt_pertuple, pos_ecxt_pertuple);
DEFINE_CGVAR_INT32(int32_pos_ecxt_outerbatch, pos_ecxt_outerbatch);
DEFINE_CGVAR_INT32(int32_pos_shash_data, pos_shash_data);
DEFINE_CGVAR_INT32(int32_pos_shash_sonichmemctl, pos_shash_sonichmemctl);
DEFINE_CGVAR_INT32(int32_pos_shash_loc, pos_shash_loc);
DEFINE_CGVAR_INT32(int32_pos_sonichmemctl_hcxt, pos_sonichmemctl_hcxt);
DEFINE_CGVAR_INT32(int32_pos_shashagg_ecxt, pos_shashagg_ecxt);
DEFINE_CGVAR_INT32(int32_pos_sdarray_nbit, pos_sdarray_nbit);
DEFINE_CGVAR_INT32(int32_pos_sdarray_atomsize, pos_sdarray_atomsize);
DEFINE_CGVAR_INT32(int32_pos_sdarray_arr, pos_sdarray_arr);
DEFINE_CGVAR_INT32(int32_pos_atom_data, pos_atom_data);
DEFINE_CGVAR_INT32(int32_pos_atom_nullflag, pos_atom_nullflag);
llvm::Value* Vals[2] = {int64_0, int32_0};
llvm::Value* Vals3[3] = {int64_0, int32_0, int32_0};
llvm::Value* Vals4[4] = {int64_0, int32_0, int32_0, int32_0};
llvm::Value** aggIdxList = (llvm::Value**)palloc(sizeof(llvm::Value*) * numaggs);
llvm::Value** batch_vals = (llvm::Value**)palloc(sizeof(llvm::Value*) * numaggs);
llvm::Value** batch_flag = (llvm::Value**)palloc(sizeof(llvm::Value*) * numaggs);
llvm::Value** sdata = (llvm::Value**)palloc(sizeof(llvm::Value*) * numaggs);
llvm::BasicBlock** agg_bb = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * numaggs);
llvm::BasicBlock** flag_then = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * numaggs);
llvm::BasicBlock** flag_else = (llvm::BasicBlock**)palloc(sizeof(llvm::BasicBlock*) * numaggs);
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "JittedSonicFastBatchAgg", voidType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("sonicHashAgg", sonicHashAggPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("batch", vecBatchPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("aggIdx", int16PtrType));
jitted_sonicbatchagg = fn_prototype.generatePrototype(&builder, &llvmargs[0]);
llvm::Value* sonicHashAgg = llvmargs[0];
llvm::Value* batch = llvmargs[1];
llvm::Value* aggIdx = llvmargs[2];
llvm::Value* isNull = builder.CreateAlloca(int8Type);
Vals4[2] = int32_pos_shash_sonichmemctl;
Vals4[3] = int32_pos_sonichmemctl_hcxt;
llvm::Value* hcxt = builder.CreateInBoundsGEP(sonicHashAgg, Vals4);
hcxt = builder.CreateLoad(memCxtDataPtrType, hcxt, "hashContext");
tmpval = builder.CreateInBoundsGEP(batch, Vals);
nValues = builder.CreateLoad(int32Type, tmpval, "m_rows");
Vals[0] = int64_0;
Vals[1] = int32_pos_batch_marr;
llvm::Value* argVector = builder.CreateInBoundsGEP(batch, Vals);
argVector = builder.CreateLoad(scalarVecPtrType, argVector, "m_arr");
ExprContext* exprcontext = node->ss.ps.ps_ExprContext;
llvm::Value* econtext = llvmCodeGen->CastPtrToLlvmPtr(exprCxtPtrType, exprcontext);
Vals3[2] = int32_pos_shash_data;
llvm::Value* sdataptr = builder.CreateInBoundsGEP(sonicHashAgg, Vals3);
sdataptr = builder.CreateLoad(sonicDatumArrayPtrPtrType, sdataptr, "m_data");
Vals4[2] = int32_pos_shash_loc;
Vals4[3] = int64_0;
llvm::Value* loc = builder.CreateInBoundsGEP(sonicHashAgg, Vals4);
llvm::BasicBlock* entry = &jitted_sonicbatchagg->getEntryBlock();
DEFINE_BLOCK(for_body, jitted_sonicbatchagg);
DEFINE_BLOCK(for_inc, jitted_sonicbatchagg);
DEFINE_BLOCK(for_end, jitted_sonicbatchagg);
for (i = 0; i < numaggs; i++) {
llvm::Value* tmpidx = llvmCodeGen->getIntConstant(INT4OID, i);
tmpval = builder.CreateInBoundsGEP(aggIdx, tmpidx);
tmpval = builder.CreateLoad(int16Type, tmpval, "aggIdx");
aggIdxList[i] = builder.CreateSExt(tmpval, int64Type);
tmpval = builder.CreateInBoundsGEP(sdataptr, aggIdxList[i]);
sdata[i] = builder.CreateLoad(sonicDatumArrayPtrType, tmpval, "sonicdata");
agg_bb[i] = llvm::BasicBlock::Create(context, "agg_bb", jitted_sonicbatchagg);
flag_then[i] = llvm::BasicBlock::Create(context, "flag_then", jitted_sonicbatchagg);
flag_else[i] = llvm::BasicBlock::Create(context, "flag_else", jitted_sonicbatchagg);
}
* Start the main process for SonicHashAgg::batchaggregation, which has the following
* pedudo code:
* for (j = 0; j < nrows; j++){
* for (i = 0; i < m_aggNum; i++){
* peraggstate = peragg[numaggs - 1 - i];
* pbatch = ExecVecProject (peraggstate->evalproj)
* AggregationOnScalar(aggInfo[i], &pbatch->m_arr[0], aggidx[i], m_Loc)
* }
* }
*/
builder.SetInsertPoint(entry);
* First get the ecxt_per_tuple_memory, since we need to switch to this
* memory context.
*/
Vals[1] = int32_pos_shashagg_ecxt;
llvm::Value* mecontext = builder.CreateInBoundsGEP(sonicHashAgg, Vals);
mecontext = builder.CreateLoad(exprCxtPtrType, mecontext, "m_econtext");
Vals[1] = int32_pos_ecxt_pertuple;
llvm::Value* agg_expr_context = builder.CreateInBoundsGEP(mecontext, Vals);
agg_expr_context = builder.CreateLoad(memCxtDataPtrType, agg_expr_context, "agg_per_tuple_memory");
llvm::Value* agg_oldcontext = VecExprCodeGen::MemCxtSwitToCodeGen(&builder, agg_expr_context);
* Load value and flag from batch before the batch loop when we have
* simple vars in transition level.
*/
for (i = 0; i < numaggs; i++) {
int numSimpleVars = 0;
VecAggStatePerAgg peraggstate = &node->pervecagg[numaggs - i - 1];
aggref = (Aggref*)(peraggstate->aggref);
ProjectionInfo* projInfo = (ProjectionInfo*)(peraggstate->evalproj);
if (aggref->aggstage == 0 && aggref->aggfnoid != COUNTOID) {
numSimpleVars = projInfo->pi_numSimpleVars;
if (numSimpleVars > 0) {
int* varNumbers = projInfo->pi_varNumbers;
int varNumber = varNumbers[0] - 1;
Vals[0] = llvmCodeGen->getIntConstant(INT8OID, varNumber);
Vals[1] = int32_pos_scalvec_vals;
tmpval = builder.CreateInBoundsGEP(argVector, Vals);
tmpval = builder.CreateLoad(int64PtrType, tmpval, "m_vals");
batch_vals[i] = tmpval;
Vals[1] = int32_pos_scalvec_flag;
llvm::Value* argFlag = builder.CreateInBoundsGEP(argVector, Vals);
argFlag = builder.CreateLoad(int8PtrType, argFlag, "m_flag");
batch_flag[i] = argFlag;
} else {
batch_vals[i] = NULL;
batch_flag[i] = NULL;
}
}
}
tmpval = builder.CreateICmpSGT(nValues, int32_0);
builder.CreateCondBr(tmpval, for_body, for_end);
builder.SetInsertPoint(for_body);
llvm::PHINode* phi_idx = builder.CreatePHI(int64Type, 2);
idx_next = builder.CreateAdd(phi_idx, int64_1);
phi_idx->addIncoming(int64_0, entry);
phi_idx->addIncoming(idx_next, for_inc);
tmpval = builder.CreateInBoundsGEP(loc, phi_idx);
locidx = builder.CreateLoad(int32Type, tmpval, "loc_i");
tmpval = builder.CreateICmpEQ(locidx, int32_0);
builder.CreateCondBr(tmpval, for_inc, agg_bb[0]);
int numSimpleVars = 0;
for (i = 0; i < numaggs; i++) {
llvm::BasicBlock* bisum_bb = NULL;
llvm::BasicBlock* numsum_bb = NULL;
VecAggStatePerAgg peraggstate = &node->pervecagg[numaggs - i - 1];
aggref = (Aggref*)(peraggstate->aggref);
ProjectionInfo* projInfo = (ProjectionInfo*)(peraggstate->evalproj);
builder.SetInsertPoint(agg_bb[i]);
if (aggref->aggfnoid == NUMERICAVGFUNCOID) {
llvm::Value* aggplus = builder.CreateAdd(aggIdxList[i], int64_1);
tmpval = builder.CreateInBoundsGEP(sdataptr, aggplus);
scount = builder.CreateLoad(sonicDatumArrayPtrType, tmpval, "scount");
}
if (aggref->aggstage == 0) {
if (aggref->aggfnoid != COUNTOID) {
Assert(peraggstate->evalproj != NULL);
AggrefExprState* aggexprstate = peraggstate->aggrefstate;
estate = (ExprState*)linitial(aggexprstate->args);
fast_aggref = AggRefFastJittable(estate);
* Do not consider collection and finalization level for
* numeric_avg to avoid deconstruct_array.
*/
if (aggref->aggfnoid == NUMERICAVGFUNCOID && aggref->aggstage > 0)
fast_aggref = false;
* load it from the batch directly
*/
if (projInfo == NULL) {
ereport(ERROR,
(errcode(ERRCODE_UNEXPECTED_NULL_VALUE),
errmodule(MOD_LLVM),
errmsg("Unexpected NULL project information.")));
}
numSimpleVars = projInfo->pi_numSimpleVars;
if (numSimpleVars > 0) {
tmpval = batch_vals[i];
tmpval = builder.CreateInBoundsGEP(tmpval, phi_idx);
result = builder.CreateLoad(int64Type, tmpval, "val");
tmpval = batch_flag[i];
tmpval = builder.CreateInBoundsGEP(tmpval, phi_idx);
tmpval = builder.CreateLoad(int8Type, tmpval, "flag");
builder.CreateStore(tmpval, isNull);
} else {
Vals[0] = int64_0;
Vals[1] = int32_pos_ecxt_outerbatch;
llvm::Value* tmp_outerbatch = builder.CreateInBoundsGEP(econtext, Vals);
builder.CreateStore(batch, tmp_outerbatch);
* If fast_aggref is true, we could try to evaluate the
* expression value by using BI64 all the way, and turn
* to original path once meet outofbound.
*/
if (fast_aggref) {
llvm::BasicBlock* bb_last = builder.GetInsertBlock();
DEFINE_BLOCK(bb_null, jitted_sonicbatchagg);
DEFINE_BLOCK(bb_outofbound, jitted_sonicbatchagg);
if (NULL == bisum_bb) {
bisum_bb = llvm::BasicBlock::Create(context, "bisum_bb", jitted_sonicbatchagg);
}
if (NULL == numsum_bb) {
numsum_bb = llvm::BasicBlock::Create(context, "numsum_bb", jitted_sonicbatchagg);
}
llvm::Value* tmpexpres = EvalFastExprInBatchAgg(estate,
builder,
jitted_sonicbatchagg,
&bb_null,
&bb_last,
&bb_outofbound,
econtext,
argVector,
phi_idx);
builder.SetInsertPoint(bb_last);
builder.CreateStore(int8_0, isNull);
llvm::Value* tmp_scale = builder.CreateExtractValue(tmpexpres, 0);
llvm::Value* tmp_value = builder.CreateExtractValue(tmpexpres, 1);
expres = llvm::UndefValue::get(SiNumeric64Type);
expres = builder.CreateInsertValue(expres, tmp_scale, 0);
expres = builder.CreateInsertValue(expres, tmp_value, 1);
builder.CreateBr(bisum_bb);
builder.SetInsertPoint(bb_null);
builder.CreateStore(int8_1, isNull);
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
* the original path
*/
builder.SetInsertPoint(bb_outofbound);
Vals[0] = int64_0;
Vals[1] = int32_pos_ecxt_pertuple;
llvm::Value* curr_Context = builder.CreateInBoundsGEP(econtext, Vals);
curr_Context = builder.CreateLoad(memCxtDataPtrType, curr_Context, "per_tuple_memory");
llvm::Value* cg_oldContext = VecExprCodeGen::MemCxtSwitToCodeGen(&builder, curr_Context);
result = EvalSimpleExprInBatchAgg(estate, builder, econtext, phi_idx, isNull);
(void)VecExprCodeGen::MemCxtSwitToCodeGen(&builder, cg_oldContext);
} else {
* corresponding to ExecVecProject(peraggstate->evalproj) :
* to evaluate expressions, we should turn to per_tuple_memory.
*/
Vals[0] = int64_0;
Vals[1] = int32_pos_ecxt_pertuple;
llvm::Value* curr_Context = builder.CreateInBoundsGEP(econtext, Vals);
curr_Context = builder.CreateLoad(memCxtDataPtrType, curr_Context, "per_tuple_memory");
llvm::Value* cg_oldContext = VecExprCodeGen::MemCxtSwitToCodeGen(&builder, curr_Context);
result = EvalSimpleExprInBatchAgg(estate, builder, econtext, phi_idx, isNull);
(void)VecExprCodeGen::MemCxtSwitToCodeGen(&builder, cg_oldContext);
}
}
} else {
* When current stage is transaction and aggfnoid is COUNTOID, no need to
* load any batch information. since we only need to plus one when cell
* is not null.
*/
result = int64_0;
builder.CreateStore(int8_0, isNull);
}
} else {
* When aggref->stage is not transiction, the aggref expr is always
* be var, so get the value from batch directly (projInfo is not null).
*/
if (projInfo != NULL) {
int* varNumbers = projInfo->pi_varNumbers;
int varNumber = varNumbers[0] - 1;
Vals[0] = llvmCodeGen->getIntConstant(INT8OID, varNumber);
Vals[1] = int32_pos_scalvec_vals;
tmpval = builder.CreateInBoundsGEP(argVector, Vals);
tmpval = builder.CreateLoad(int64PtrType, tmpval, "m_vals");
tmpval = builder.CreateInBoundsGEP(tmpval, phi_idx);
result = builder.CreateLoad(int64Type, tmpval, "val");
Vals[1] = int32_pos_scalvec_flag;
llvm::Value* argFlag = builder.CreateInBoundsGEP(argVector, Vals);
argFlag = builder.CreateLoad(int8PtrType, argFlag, "m_flag");
tmpval = builder.CreateInBoundsGEP(argFlag, phi_idx);
tmpval = builder.CreateLoad(int8Type, tmpval, "flag");
builder.CreateStore(tmpval, isNull);
} else {
ereport(ERROR,
(errcode(ERRCODE_UNEXPECTED_NULL_VALUE),
errmodule(MOD_LLVM),
errmsg("Unexpected NULL project information.")));
}
}
if (aggref->aggfnoid == COUNTOID) {
flag_then[i]->eraseFromParent();
flag_else[i]->eraseFromParent();
char* Jittedname = NULL;
if (aggref->aggstage == 0)
Jittedname = "Jitted_scount_0";
else
Jittedname = "Jitted_scount_1";
llvm::Function* func_vscount = llvmCodeGen->module()->getFunction(Jittedname);
if (NULL == func_vscount) {
func_vscount = vsonic_count_codegen(aggref);
}
builder.CreateCall(func_vscount, {sdata[i], locidx, result});
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
} else {
* now we already get sonic datum (data and locidx) and pVector(result), check
* the flag and do aggregation.
*/
llvm::Value* tmpnull = builder.CreateLoad(int8Type, isNull, "tmpnull");
tmpnull = builder.CreateAnd(tmpnull, int8_1);
llvm::Value* flag_cmp = builder.CreateICmpEQ(tmpnull, int8_0);
builder.CreateCondBr(flag_cmp, flag_then[i], flag_else[i]);
builder.SetInsertPoint(flag_then[i]);
switch (aggref->aggfnoid) {
case NUMERICSUMFUNCOID: {
* If aggref can be evaluated in fast path and just be
* simple vars, use the result from batch.
*/
if (fast_aggref && (numSimpleVars > 0)) {
DEFINE_BLOCK(agg_then, jitted_sonicbatchagg);
DEFINE_BLOCK(agg_else, jitted_sonicbatchagg);
DEFINE_BLOCK(agg_end, jitted_sonicbatchagg);
DEFINE_BLOCK(normal_bb, jitted_sonicbatchagg);
DEFINE_BLOCK(var_bisum_bb, jitted_sonicbatchagg);
DEFINE_BLOCK(var_numsum_bb, jitted_sonicbatchagg);
Vals[0] = int64_0;
Vals[1] = int32_pos_sdarray_nbit;
nbit = builder.CreateInBoundsGEP(sdata[i], Vals);
nbit = builder.CreateLoad(int32Type, nbit, "arridx");
arrIdx = builder.CreateLShr(locidx, nbit);
arrIdx = builder.CreateSExt(arrIdx, int64Type);
Vals[1] = int32_pos_sdarray_atomsize;
atomsize = builder.CreateInBoundsGEP(sdata[i], Vals);
atomsize = builder.CreateLoad(int32Type, atomsize, "atomsize");
atomsize = builder.CreateSub(atomsize, int32_1);
atomIdx = builder.CreateAnd(atomsize, locidx);
atomIdx = builder.CreateSExt(atomIdx, int64Type);
Vals[1] = int32_pos_sdarray_arr;
atom = builder.CreateInBoundsGEP(sdata[i], Vals);
atom = builder.CreateLoad(atomPtrPtrType, atom, "atom**");
atom = builder.CreateInBoundsGEP(atom, arrIdx);
atom = builder.CreateLoad(atomPtrType, atom, "atom*");
Vals[1] = int32_pos_atom_data;
data = builder.CreateInBoundsGEP(atom, Vals);
data = builder.CreateLoad(int8PtrType, data, "data");
data = builder.CreateBitCast(data, int64PtrType);
llvm::Value* dataptr = builder.CreateInBoundsGEP(data, atomIdx);
Vals[1] = int32_pos_atom_nullflag;
llvm::Value* nullflag = builder.CreateInBoundsGEP(atom, Vals);
nullflag = builder.CreateLoad(int8PtrType, nullflag, "nullflagptr");
nullflag = builder.CreateInBoundsGEP(nullflag, atomIdx);
tmpval = builder.CreateLoad(int8Type, nullflag, "nullFlag");
tmpval = builder.CreateAnd(tmpval, int8_1);
tmpval = builder.CreateICmpEQ(tmpval, int8_0);
builder.CreateCondBr(tmpval, agg_else, agg_then);
builder.SetInsertPoint(agg_then);
* should make a new context to record the result : the
* following code corresponding to:
* 'leftarg = DatumGetBINumeric(pVal[i]);
* data->setValue(NumericGetDatum(leftarg, false, arrIndx, atomIdx))'.
*/
tmpval = DatumGetBINumericCodeGen(&builder, result);
tmpval = builder.CreatePtrToInt(tmpval, int64Type);
tmpval = WrapaddVariableCodeGen(&builder, hcxt, tmpval);
builder.CreateStore(tmpval, dataptr);
builder.CreateStore(int8_0, nullflag);
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
builder.SetInsertPoint(agg_else);
* When fast_aggref is true and numSimpleVars is greater than zero,
* the expr is numeric type var. Convert this numeric type data to
* SiNumeric data to get the value.
*/
llvm::Value* bires = DatumGetBINumericCodeGen(&builder, result);
Vals4[0] = int64_0;
Vals4[1] = int32_1;
Vals4[2] = int32_0;
Vals4[3] = int32_0;
tmpval = builder.CreateInBoundsGEP(bires, Vals4);
tmpval = builder.CreateLoad(int16Type, tmpval, "biheader");
llvm::Value* rflag = builder.CreateAnd(tmpval, val_mask);
llvm::Value* realdata = builder.CreateLoad(int64Type, dataptr, "dataval");
llvm::Value* leftarg = DatumGetBINumericCodeGen(&builder, realdata);
tmpval = builder.CreateInBoundsGEP(leftarg, Vals4);
tmpval = builder.CreateLoad(int16Type, tmpval, "sonicheader");
llvm::Value* lflag = builder.CreateAnd(tmpval, val_mask);
llvm::Value* oparg1 = builder.CreateICmpEQ(lflag, val_binum64);
llvm::Value* oparg2 = builder.CreateICmpEQ(rflag, val_binum64);
llvm::Value* bothbi64 = builder.CreateAnd(oparg1, oparg2);
builder.CreateCondBr(bothbi64, var_bisum_bb, var_numsum_bb);
builder.SetInsertPoint(var_bisum_bb);
Vals4[0] = int64_0;
Vals4[1] = int32_1;
Vals4[2] = int32_0;
Vals4[3] = int32_1;
tmpval = builder.CreateInBoundsGEP(bires, Vals4);
tmpval = builder.CreateBitCast(tmpval, int64PtrType);
llvm::Value* resval = builder.CreateLoad(int64Type, tmpval, "bivalue");
llvm::Value* sonicptr = builder.CreateAdd(realdata, int64_6);
sonicptr = builder.CreateIntToPtr(sonicptr, int64PtrType);
llvm::Value* midval = builder.CreateLoad(int64Type, sonicptr, "intvalue");
llvm::Type* Intrinsic_Tys[] = {int64Type};
llvm::Function* func_sonicadd_overflow =
llvm::Intrinsic::getDeclaration(mod, llvm_sadd_with_overflow, Intrinsic_Tys);
if (func_sonicadd_overflow == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Cannot get the llvm::Intrinsic::sadd_with_overflow function!\n")));
}
llvm::Value* aggres = builder.CreateCall(func_sonicadd_overflow, {resval, midval});
llvm::Value* oflag = builder.CreateExtractValue(aggres, 1);
builder.CreateCondBr(oflag, var_numsum_bb, normal_bb);
builder.SetInsertPoint(var_numsum_bb);
llvm::Function* func_vsnumericsum =
llvmCodeGen->module()->getFunction("Jitted_sonic_numericsum");
if (NULL == func_vsnumericsum) {
func_vsnumericsum = vsnumeric_sum_codegen(aggref);
}
sdata[i] = builder.CreateBitCast(sdata[i], sonicEncodingDatumArrayPtrType);
builder.CreateCall(func_vsnumericsum, {sdata[i], locidx, result});
builder.CreateBr(agg_end);
builder.SetInsertPoint(normal_bb);
llvm::Value* sumval = builder.CreateExtractValue(aggres, 0);
builder.CreateStore(sumval, sonicptr);
builder.CreateBr(agg_end);
builder.SetInsertPoint(agg_end);
} else if (fast_aggref) {
* If aggref can be evaluated in fast path and be numeric
* expressions, use the result from fastexpr.
*/
Assert(bisum_bb != NULL);
Assert(numsum_bb != NULL);
DEFINE_BLOCK(agg_end, jitted_sonicbatchagg);
DEFINE_BLOCK(agg_then, jitted_sonicbatchagg);
DEFINE_BLOCK(agg_else, jitted_sonicbatchagg);
DEFINE_BLOCK(normal_bb, jitted_sonicbatchagg);
DEFINE_BLOCK(expr_bisum_bb, jitted_sonicbatchagg);
DEFINE_BLOCK(bioverflow_bb, jitted_sonicbatchagg);
* if the result of expression is outofbound, turn to
* original numeric path.
*/
builder.CreateBr(numsum_bb);
* if the result of expression is BI64, extract it.
*/
builder.SetInsertPoint(bisum_bb);
llvm::Value* resval = builder.CreateExtractValue(expres, 1);
Vals[1] = int32_pos_sdarray_nbit;
nbit = builder.CreateInBoundsGEP(sdata[i], Vals);
nbit = builder.CreateLoad(int32Type, nbit, "arridx");
arrIdx = builder.CreateLShr(locidx, nbit);
arrIdx = builder.CreateSExt(arrIdx, int64Type);
Vals[1] = int32_pos_sdarray_atomsize;
atomsize = builder.CreateInBoundsGEP(sdata[i], Vals);
atomsize = builder.CreateLoad(int32Type, atomsize, "atomsize");
atomsize = builder.CreateSub(atomsize, int32_1);
atomIdx = builder.CreateAnd(atomsize, locidx);
atomIdx = builder.CreateSExt(atomIdx, int64Type);
Vals[1] = int32_pos_sdarray_arr;
atom = builder.CreateInBoundsGEP(sdata[i], Vals);
atom = builder.CreateLoad(atomPtrPtrType, atom, "atom**");
atom = builder.CreateInBoundsGEP(atom, arrIdx);
atom = builder.CreateLoad(atomPtrType, atom, "atom*");
Vals[1] = int32_pos_atom_data;
data = builder.CreateInBoundsGEP(atom, Vals);
data = builder.CreateLoad(int8PtrType, data, "data");
data = builder.CreateBitCast(data, int64PtrType);
llvm::Value* dataptr = builder.CreateInBoundsGEP(data, atomIdx);
Vals[1] = int32_pos_atom_nullflag;
llvm::Value* nullflag = builder.CreateInBoundsGEP(atom, Vals);
nullflag = builder.CreateLoad(int8PtrType, nullflag, "nullflagptr");
nullflag = builder.CreateInBoundsGEP(nullflag, atomIdx);
tmpval = builder.CreateLoad(int8Type, nullflag, "nullFlag");
tmpval = builder.CreateAnd(tmpval, int8_1);
tmpval = builder.CreateICmpEQ(tmpval, int8_0);
builder.CreateCondBr(tmpval, agg_else, agg_then);
builder.SetInsertPoint(agg_then);
exprscale = GetAlignedScale(estate->expr);
llvm::Value* alignedscale = llvmCodeGen->getIntConstant(CHAROID, exprscale);
* should make a new context to record the result : the
* following code corresponding to:
* 'leftarg = DatumGetBINumeric(pVal[i]);
* cell->m_val[idx].val = addVariable(context, NumericGetDatum(leftarg));'.
*/
tmpval = WrapmakeNumeric64CodeGen(&builder, resval, alignedscale);
tmpval = DatumGetBINumericCodeGen(&builder, tmpval);
tmpval = builder.CreatePtrToInt(tmpval, int64Type);
tmpval = WrapaddVariableCodeGen(&builder, hcxt, tmpval);
builder.CreateStore(tmpval, dataptr);
builder.CreateStore(int8_0, nullflag);
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
builder.SetInsertPoint(agg_else);
llvm::Value* realdata = builder.CreateLoad(int64Type, dataptr, "dataval");
llvm::Value* leftarg = DatumGetBINumericCodeGen(&builder, realdata);
Vals4[0] = int64_0;
Vals4[1] = int32_1;
Vals4[2] = int32_0;
Vals4[3] = int32_0;
tmpval = builder.CreateInBoundsGEP(leftarg, Vals4);
tmpval = builder.CreateLoad(int16Type, tmpval, "leftheader");
llvm::Value* biflag = builder.CreateAnd(tmpval, val_mask);
llvm::Value* isbi64 = builder.CreateICmpEQ(biflag, val_binum64);
builder.CreateCondBr(isbi64, expr_bisum_bb, bioverflow_bb);
* do aggregation directly only when both expr value
* and cell value is bi64.
*/
builder.SetInsertPoint(expr_bisum_bb);
llvm::Value* sonicptr = builder.CreateAdd(realdata, int64_6);
sonicptr = builder.CreateIntToPtr(sonicptr, int64PtrType);
llvm::Value* midval = builder.CreateLoad(int64Type, sonicptr, "intvalue");
llvm::Type* Intrinsic_Tys[] = {int64Type};
llvm::Function* func_sonicadd_overflow =
llvm::Intrinsic::getDeclaration(mod, llvm_sadd_with_overflow, Intrinsic_Tys);
if (func_sonicadd_overflow == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Cannot get the llvm::Intrinsic::sadd_with_overflow function!")));
}
llvm::Value* aggres = builder.CreateCall(func_sonicadd_overflow, {resval, midval});
llvm::Value* oflag = builder.CreateExtractValue(aggres, 1);
builder.CreateCondBr(oflag, bioverflow_bb, normal_bb);
builder.SetInsertPoint(bioverflow_bb);
exprscale = GetAlignedScale(estate->expr);
llvm::Value* ascale = llvmCodeGen->getIntConstant(CHAROID, exprscale);
llvm::Value* bioverres = WrapmakeNumeric64CodeGen(&builder, resval, ascale);
builder.CreateBr(numsum_bb);
builder.SetInsertPoint(numsum_bb);
llvm::PHINode* numres = builder.CreatePHI(int64Type, 2);
numres->addIncoming(result, flag_then[i]);
numres->addIncoming(bioverres, bioverflow_bb);
llvm::Value* evalval = (llvm::Value*)numres;
llvm::Function* func_vsnumericsum =
llvmCodeGen->module()->getFunction("Jitted_sonic_numericsum");
if (NULL == func_vsnumericsum) {
func_vsnumericsum = vsnumeric_sum_codegen(aggref);
}
sdata[i] = builder.CreateBitCast(sdata[i], sonicEncodingDatumArrayPtrType);
builder.CreateCall(func_vsnumericsum, {sdata[i], locidx, evalval});
builder.CreateBr(agg_end);
builder.SetInsertPoint(normal_bb);
llvm::Value* sumval = builder.CreateExtractValue(aggres, 0);
builder.CreateStore(sumval, sonicptr);
builder.CreateBr(agg_end);
builder.SetInsertPoint(agg_end);
} else {
llvm::Function* func_vsnumericsum =
llvmCodeGen->module()->getFunction("Jitted_sonic_numericsum");
if (NULL == func_vsnumericsum) {
func_vsnumericsum = vsnumeric_sum_codegen(aggref);
}
sdata[i] = builder.CreateBitCast(sdata[i], sonicEncodingDatumArrayPtrType);
builder.CreateCall(func_vsnumericsum, {sdata[i], locidx, result});
}
} break;
case NUMERICAVGFUNCOID: {
* If aggref can be evaluated in fast path and just be
* simple vars, use the result from batch.
*/
if (fast_aggref && (numSimpleVars > 0)) {
DEFINE_BLOCK(agg_then, jitted_sonicbatchagg);
DEFINE_BLOCK(agg_else, jitted_sonicbatchagg);
DEFINE_BLOCK(agg_end, jitted_sonicbatchagg);
DEFINE_BLOCK(normal_bb, jitted_sonicbatchagg);
DEFINE_BLOCK(bisum_bblock, jitted_sonicbatchagg);
DEFINE_BLOCK(numsum_bblock, jitted_sonicbatchagg);
Vals[0] = int64_0;
Vals[1] = int32_pos_sdarray_nbit;
nbit = builder.CreateInBoundsGEP(sdata[i], Vals);
nbit = builder.CreateLoad(int32Type, nbit, "arridx");
arrIdx = builder.CreateLShr(locidx, nbit);
arrIdx = builder.CreateSExt(arrIdx, int64Type);
Vals[1] = int32_pos_sdarray_atomsize;
atomsize = builder.CreateInBoundsGEP(sdata[i], Vals);
atomsize = builder.CreateLoad(int32Type, atomsize, "atomsize");
atomsize = builder.CreateSub(atomsize, int32_1);
atomIdx = builder.CreateAnd(atomsize, locidx);
atomIdx = builder.CreateSExt(atomIdx, int64Type);
Vals[1] = int32_pos_sdarray_arr;
atom = builder.CreateInBoundsGEP(sdata[i], Vals);
atom = builder.CreateLoad(atomPtrPtrType, atom, "atom**");
atom = builder.CreateInBoundsGEP(atom, arrIdx);
atom = builder.CreateLoad(atomPtrType, atom, "atom*");
Vals[1] = int32_pos_atom_data;
data = builder.CreateInBoundsGEP(atom, Vals);
data = builder.CreateLoad(int8PtrType, data, "data");
data = builder.CreateBitCast(data, int64PtrType);
llvm::Value* dataptr = builder.CreateInBoundsGEP(data, atomIdx);
Vals[1] = int32_pos_sdarray_arr;
cntatom = builder.CreateInBoundsGEP(scount, Vals);
cntatom = builder.CreateLoad(atomPtrPtrType, cntatom, "cntatom**");
cntatom = builder.CreateInBoundsGEP(cntatom, arrIdx);
cntatom = builder.CreateLoad(atomPtrType, cntatom, "cntatom*");
Vals[1] = int32_pos_atom_data;
cntdata = builder.CreateInBoundsGEP(cntatom, Vals);
cntdata = builder.CreateLoad(int8PtrType, cntdata, "cntdata");
cntdata = builder.CreateBitCast(cntdata, int64PtrType);
llvm::Value* cntptr = builder.CreateInBoundsGEP(cntdata, atomIdx);
Vals[1] = int32_pos_atom_nullflag;
llvm::Value* dataflag = builder.CreateInBoundsGEP(atom, Vals);
dataflag = builder.CreateLoad(int8PtrType, dataflag, "dataflagptr");
dataflag = builder.CreateInBoundsGEP(dataflag, atomIdx);
Vals[1] = int32_pos_atom_nullflag;
llvm::Value* cntflag = builder.CreateInBoundsGEP(cntatom, Vals);
cntflag = builder.CreateLoad(int8PtrType, cntflag, "cntflagptr");
cntflag = builder.CreateInBoundsGEP(cntflag, atomIdx);
tmpval = builder.CreateLoad(int8Type, dataflag, "dataFlag");
tmpval = builder.CreateAnd(tmpval, int8_1);
tmpval = builder.CreateICmpEQ(tmpval, int8_0);
builder.CreateCondBr(tmpval, agg_else, agg_then);
builder.SetInsertPoint(agg_then);
tmpval = DatumGetBINumericCodeGen(&builder, result);
tmpval = builder.CreatePtrToInt(tmpval, int64Type);
tmpval = WrapaddVariableCodeGen(&builder, hcxt, tmpval);
builder.CreateStore(tmpval, dataptr);
builder.CreateStore(int64_1, cntptr);
builder.CreateStore(int8_0, dataflag);
builder.CreateStore(int8_0, cntflag);
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
builder.SetInsertPoint(agg_else);
* When fast_aggref is true and numSimpleVars is greater than zero,
* the expr is numeric type var. Convert this numeric type data to
* SiNumeric data to get the value.
*/
llvm::Value* bires = DatumGetBINumericCodeGen(&builder, result);
Vals4[0] = int64_0;
Vals4[1] = int32_1;
Vals4[2] = int32_0;
Vals4[3] = int32_0;
tmpval = builder.CreateInBoundsGEP(bires, Vals4);
tmpval = builder.CreateLoad(int16Type, tmpval, "biheader");
llvm::Value* rflag = builder.CreateAnd(tmpval, val_mask);
llvm::Value* realdata = builder.CreateLoad(int64Type, dataptr, "dataval");
llvm::Value* leftarg = builder.CreateIntToPtr(realdata, numericPtrType);
tmpval = builder.CreateInBoundsGEP(leftarg, Vals4);
tmpval = builder.CreateLoad(int16Type, tmpval, "sonicheader");
llvm::Value* lflag = builder.CreateAnd(tmpval, val_mask);
llvm::Value* oparg1 = builder.CreateICmpEQ(lflag, val_binum64);
llvm::Value* oparg2 = builder.CreateICmpEQ(rflag, val_binum64);
llvm::Value* bothbi64 = builder.CreateAnd(oparg1, oparg2);
builder.CreateCondBr(bothbi64, bisum_bblock, numsum_bblock);
builder.SetInsertPoint(bisum_bblock);
Vals4[0] = int64_0;
Vals4[1] = int32_1;
Vals4[2] = int32_0;
Vals4[3] = int32_1;
tmpval = builder.CreateInBoundsGEP(bires, Vals4);
tmpval = builder.CreateBitCast(tmpval, int64PtrType);
llvm::Value* resval = builder.CreateLoad(int64Type, tmpval, "value");
llvm::Value* sonicptr = builder.CreateAdd(realdata, int64_6);
sonicptr = builder.CreateIntToPtr(sonicptr, int64PtrType);
llvm::Value* midval = builder.CreateLoad(int64Type, sonicptr);
llvm::Type* Intrinsic_Tys[] = {int64Type};
llvm::Function* func_sonicadd_overflow =
llvm::Intrinsic::getDeclaration(mod, llvm_sadd_with_overflow, Intrinsic_Tys);
if (func_sonicadd_overflow == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Cannot get the llvm::Intrinsic::sadd_with_overflow function!\n")));
}
llvm::Value* aggres = builder.CreateCall(func_sonicadd_overflow, {resval, midval});
llvm::Value* oflag = builder.CreateExtractValue(aggres, 1);
builder.CreateCondBr(oflag, numsum_bblock, normal_bb);
builder.SetInsertPoint(numsum_bblock);
llvm::Function* func_vsnumericavg =
llvmCodeGen->module()->getFunction("Jitted_sonic_numericavg");
if (NULL == func_vsnumericavg) {
func_vsnumericavg = vsnumeric_avg_codegen(aggref);
}
sdata[i] = builder.CreateBitCast(sdata[i], sonicEncodingDatumArrayPtrType);
builder.CreateCall(func_vsnumericavg, {sdata[i], scount, locidx, result});
builder.CreateBr(agg_end);
builder.SetInsertPoint(normal_bb);
llvm::Value* sumval = builder.CreateExtractValue(aggres, 0);
builder.CreateStore(sumval, sonicptr);
tmpval = builder.CreateLoad(int64Type, cntptr, "count");
tmpval = builder.CreateAdd(tmpval, int64_1);
builder.CreateStore(tmpval, cntptr);
builder.CreateBr(agg_end);
builder.SetInsertPoint(agg_end);
} else if (fast_aggref) {
* If aggref can be evaluated in fast path and be numeric
* expressions, use the result from fastexpr.
*/
Assert(bisum_bb != NULL);
Assert(numsum_bb != NULL);
DEFINE_BLOCK(agg_end, jitted_sonicbatchagg);
DEFINE_BLOCK(agg_then, jitted_sonicbatchagg);
DEFINE_BLOCK(agg_else, jitted_sonicbatchagg);
DEFINE_BLOCK(normal_bb, jitted_sonicbatchagg);
DEFINE_BLOCK(expr_bisum_bb, jitted_sonicbatchagg);
DEFINE_BLOCK(bioverflow_bb, jitted_sonicbatchagg);
builder.CreateBr(numsum_bb);
builder.SetInsertPoint(bisum_bb);
llvm::Value* resval = builder.CreateExtractValue(expres, 1);
Vals[0] = int64_0;
Vals[1] = int32_pos_sdarray_nbit;
nbit = builder.CreateInBoundsGEP(sdata[i], Vals);
nbit = builder.CreateLoad(int32Type, nbit, "arridx");
arrIdx = builder.CreateLShr(locidx, nbit);
arrIdx = builder.CreateSExt(arrIdx, int64Type);
Vals[1] = int32_pos_sdarray_atomsize;
atomsize = builder.CreateInBoundsGEP(sdata[i], Vals);
atomsize = builder.CreateLoad(int32Type, atomsize, "atomsize");
atomsize = builder.CreateSub(atomsize, int32_1);
atomIdx = builder.CreateAnd(atomsize, locidx);
atomIdx = builder.CreateSExt(atomIdx, int64Type);
Vals[1] = int32_pos_sdarray_arr;
atom = builder.CreateInBoundsGEP(sdata[i], Vals);
atom = builder.CreateLoad(atomPtrPtrType, atom, "atom**");
atom = builder.CreateInBoundsGEP(atom, arrIdx);
atom = builder.CreateLoad(atomPtrType, atom, "atom*");
Vals[1] = int32_pos_atom_data;
data = builder.CreateInBoundsGEP(atom, Vals);
data = builder.CreateLoad(int8PtrType, data, "data");
data = builder.CreateBitCast(data, int64PtrType);
llvm::Value* dataptr = builder.CreateInBoundsGEP(data, atomIdx);
Vals[1] = int32_pos_sdarray_arr;
cntatom = builder.CreateInBoundsGEP(scount, Vals);
cntatom = builder.CreateLoad(atomPtrPtrType, cntatom, "cnt atom**");
cntatom = builder.CreateInBoundsGEP(cntatom, arrIdx);
cntatom = builder.CreateLoad(atomPtrType, cntatom, "cnt atom*");
Vals[1] = int32_pos_atom_data;
cntdata = builder.CreateInBoundsGEP(cntatom, Vals);
cntdata = builder.CreateLoad(int8PtrType, cntdata, "cntdata");
cntdata = builder.CreateBitCast(cntdata, int64PtrType);
llvm::Value* cntptr = builder.CreateInBoundsGEP(cntdata, atomIdx);
Vals[1] = int32_pos_atom_nullflag;
llvm::Value* dataflag = builder.CreateInBoundsGEP(atom, Vals);
dataflag = builder.CreateLoad(int8PtrType, dataflag, "dataflagptr");
dataflag = builder.CreateInBoundsGEP(dataflag, atomIdx);
Vals[1] = int32_pos_atom_nullflag;
llvm::Value* cntflag = builder.CreateInBoundsGEP(cntatom, Vals);
cntflag = builder.CreateLoad(int8PtrType, cntflag, "cntflagptr");
cntflag = builder.CreateInBoundsGEP(cntflag, atomIdx);
tmpval = builder.CreateLoad(int8Type, dataflag, "dataFlag");
tmpval = builder.CreateAnd(tmpval, int8_1);
tmpval = builder.CreateICmpEQ(tmpval, int8_0);
builder.CreateCondBr(tmpval, agg_else, agg_then);
builder.SetInsertPoint(agg_then);
exprscale = GetAlignedScale(estate->expr);
llvm::Value* alignedscale = llvmCodeGen->getIntConstant(CHAROID, exprscale);
* should make a new context to record the result : the
* following code corresponding to:
* 'leftarg = DatumGetBINumeric(pVal[i]);
* data->setValue(NumericGetDatum(leftarg), false, arrIdx, atomIdx);'.
*/
tmpval = WrapmakeNumeric64CodeGen(&builder, resval, alignedscale);
tmpval = DatumGetBINumericCodeGen(&builder, tmpval);
tmpval = builder.CreatePtrToInt(tmpval, int64Type);
tmpval = WrapaddVariableCodeGen(&builder, hcxt, tmpval);
builder.CreateStore(tmpval, dataptr);
builder.CreateStore(int64_1, cntptr);
builder.CreateStore(int8_0, dataflag);
builder.CreateStore(int8_0, cntflag);
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
builder.SetInsertPoint(agg_else);
llvm::Value* realdata = builder.CreateLoad(int64Type, dataptr, "cell_val");
Vals4[0] = int64_0;
Vals4[1] = int32_1;
Vals4[2] = int32_0;
Vals4[3] = int32_0;
llvm::Value* leftflag = builder.CreateIntToPtr(realdata, numericPtrType);
tmpval = builder.CreateInBoundsGEP(leftflag, Vals4);
tmpval = builder.CreateLoad(int16Type, tmpval, "leftheader");
llvm::Value* biflag = builder.CreateAnd(tmpval, val_mask);
llvm::Value* isbi64 = builder.CreateICmpEQ(biflag, val_binum64);
builder.CreateCondBr(isbi64, expr_bisum_bb, bioverflow_bb);
* do aggregation directly only when both expr value
* and cell value is bi64.
*/
builder.SetInsertPoint(expr_bisum_bb);
llvm::Value* sonicptr = builder.CreateAdd(realdata, int64_6);
sonicptr = builder.CreateIntToPtr(sonicptr, int64PtrType);
llvm::Value* midval = builder.CreateLoad(int64Type, sonicptr);
llvm::Type* Intrinsic_Tys[] = {int64Type};
llvm::Function* func_sonicadd_overflow =
llvm::Intrinsic::getDeclaration(mod, llvm_sadd_with_overflow, Intrinsic_Tys);
if (func_sonicadd_overflow == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Cannot get the llvm::Intrinsic::sadd_with_overflow function!\n")));
}
llvm::Value* aggres = builder.CreateCall(func_sonicadd_overflow, {resval, midval});
llvm::Value* oflag = builder.CreateExtractValue(aggres, 1);
builder.CreateCondBr(oflag, bioverflow_bb, normal_bb);
builder.SetInsertPoint(bioverflow_bb);
exprscale = GetAlignedScale(estate->expr);
llvm::Value* ascale = llvmCodeGen->getIntConstant(CHAROID, exprscale);
llvm::Value* bioverres = WrapmakeNumeric64CodeGen(&builder, resval, ascale);
builder.CreateBr(numsum_bb);
builder.SetInsertPoint(numsum_bb);
llvm::PHINode* numres = builder.CreatePHI(int64Type, 2);
numres->addIncoming(result, flag_then[i]);
numres->addIncoming(bioverres, bioverflow_bb);
llvm::Value* evalval = (llvm::Value*)numres;
llvm::Function* func_vsnumericavg =
llvmCodeGen->module()->getFunction("Jitted_sonic_numericavg");
if (NULL == func_vsnumericavg) {
func_vsnumericavg = vsnumeric_avg_codegen(aggref);
}
sdata[i] = builder.CreateBitCast(sdata[i], sonicEncodingDatumArrayPtrType);
builder.CreateCall(func_vsnumericavg, {sdata[i], scount, locidx, evalval});
builder.CreateBr(agg_end);
builder.SetInsertPoint(normal_bb);
llvm::Value* sumval = builder.CreateExtractValue(aggres, 0);
builder.CreateStore(sumval, sonicptr);
tmpval = builder.CreateLoad(int64Type, cntptr, "count");
tmpval = builder.CreateAdd(tmpval, int64_1);
builder.CreateStore(tmpval, cntptr);
builder.CreateBr(agg_end);
builder.SetInsertPoint(agg_end);
} else {
llvm::Function* func_vsnumericavg =
llvmCodeGen->module()->getFunction("Jitted_sonic_numericavg");
if (NULL == func_vsnumericavg) {
func_vsnumericavg = vsnumeric_avg_codegen(aggref);
}
sdata[i] = builder.CreateBitCast(sdata[i], sonicEncodingDatumArrayPtrType);
builder.CreateCall(func_vsnumericavg, {sdata[i], scount, locidx, result});
}
} break;
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmodule(MOD_LLVM),
errmsg("Unsupported agg function %u!", aggref->aggfnoid)));
break;
}
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
builder.SetInsertPoint(flag_else[i]);
if (i == numaggs - 1)
builder.CreateBr(for_inc);
else
builder.CreateBr(agg_bb[i + 1]);
}
}
builder.SetInsertPoint(for_inc);
tmpval = builder.CreateTrunc(idx_next, int32Type);
tmpval = builder.CreateICmpEQ(tmpval, nValues);
builder.CreateCondBr(tmpval, for_end, for_body);
builder.SetInsertPoint(for_end);
(void)VecExprCodeGen::MemCxtSwitToCodeGen(&builder, agg_oldcontext);
(void)WrapResetEContextCodeGen(&builder, mecontext);
(void)WrapResetEContextCodeGen(&builder, econtext);
builder.CreateRetVoid();
pfree_ext(aggIdxList);
pfree_ext(sdata);
pfree_ext(agg_bb);
pfree_ext(flag_then);
pfree_ext(flag_else);
pfree_ext(batch_vals);
pfree_ext(batch_flag);
llvmCodeGen->FinalizeFunction(jitted_sonicbatchagg, node->ss.ps.plan->plan_node_id);
return jitted_sonicbatchagg;
}
void VecHashAggCodeGen::WarpAllocHashSlotCodeGen(GsCodeGen::LlvmBuilder* ptrbuilder, llvm::Value* hAggRunner,
llvm::Value* batch, llvm::Value* idx, llvm::Value* keysimple)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
DEFINE_CG_VOIDTYPE(voidType);
DEFINE_CG_TYPE(int32Type, INT4OID);
DEFINE_CG_PTRTYPE(vectorBatchPtrType, "class.VectorBatch");
DEFINE_CG_PTRTYPE(hashAggRunnerPtrType, "class.HashAggRunner");
llvm::Function* func_allochashslot = llvmCodeGen->module()->getFunction("IRAllocHashSlot");
if (NULL == func_allochashslot) {
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "IRAllocHashSlot", voidType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("hAggRunner", hashAggRunnerPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("batch", vectorBatchPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("idx", int32Type));
fn_prototype.addArgument(GsCodeGen::NamedVariable("keysimple", int32Type));
func_allochashslot = fn_prototype.generatePrototype(NULL, NULL);
llvm::sys::DynamicLibrary::AddSymbol("IRAllocHashSlot", (void*)WrapAllocHashSlot);
}
idx = ptrbuilder->CreateTrunc(idx, int32Type);
ptrbuilder->CreateCall(func_allochashslot, {hAggRunner, batch, idx, keysimple});
return;
}
void VecHashAggCodeGen::WarpSglTblAllocHashSlotCodeGen(GsCodeGen::LlvmBuilder* ptrbuilder, llvm::Value* hAggRunner,
llvm::Value* batch, llvm::Value* idx, llvm::Value* keysimple)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
DEFINE_CG_VOIDTYPE(voidType);
DEFINE_CG_TYPE(int32Type, INT4OID);
DEFINE_CG_PTRTYPE(vectorBatchPtrType, "class.VectorBatch");
DEFINE_CG_PTRTYPE(hashAggRunnerPtrType, "class.HashAggRunner");
llvm::Function* func_sgltblallochashslot = llvmCodeGen->module()->getFunction("IRSglTblAllocHashSlot");
if (NULL == func_sgltblallochashslot) {
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "IRSglTblAllocHashSlot", voidType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("hAggRunner", hashAggRunnerPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("batch", vectorBatchPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("idx", int32Type));
fn_prototype.addArgument(GsCodeGen::NamedVariable("keysimple", int32Type));
func_sgltblallochashslot = fn_prototype.generatePrototype(NULL, NULL);
llvm::sys::DynamicLibrary::AddSymbol("IRSglTblAllocHashSlot", (void*)WrapSglTblAllocHashSlot);
}
idx = ptrbuilder->CreateTrunc(idx, int32Type);
ptrbuilder->CreateCall(func_sgltblallochashslot, {hAggRunner, batch, idx, keysimple});
return;
}
void VecHashAggCodeGen::WrapResetEContextCodeGen(GsCodeGen::LlvmBuilder* ptrbuilder, llvm::Value* econtext)
{
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
DEFINE_CG_VOIDTYPE(voidType);
DEFINE_CG_PTRTYPE(ExprContextPtrType, "struct.ExprContext");
llvm::Function* func_resetec = llvmCodeGen->module()->getFunction("IRResetExprContext");
if (NULL == func_resetec) {
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "IRResetExprContext", voidType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("econtext", ExprContextPtrType));
func_resetec = fn_prototype.generatePrototype(NULL, NULL);
llvm::sys::DynamicLibrary::AddSymbol("IRResetExprContext", (void*)WrapResetExprContext);
}
ptrbuilder->CreateCall(func_resetec, econtext);
return;
}
* @Description : Generate the function to prefetch the hash cell ahead
* of 2, which means hint fetch loc[i+2]. This function
* is called by BatchAggregation.
* @return : return llvm prefetch function for batchaggregation.
*/
llvm::Function* prefetchBatchAggregationCodeGen()
{
Assert(NULL != (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj);
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
llvm::Value* tmpval = NULL;
llvm::Value* llvmargs[3];
llvm::Function* jitted_batchagg_prefetch = NULL;
DEFINE_CG_VOIDTYPE(voidType);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(hashCellPtrType, "struct.hashCell");
DEFINE_CG_PTRPTRTYPE(hashCellPtrPtrType, "struct.hashCell");
DEFINE_CGVAR_INT32(int32_0, 0);
DEFINE_CGVAR_INT32(int32_1, 1);
DEFINE_CGVAR_INT32(int32_3, 3);
DEFINE_CGVAR_INT64(int64_distance, PREFETCH_BATCHAGGREGATION_DISTANCE);
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "prefetchBatchAggregation", voidType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("Loc", hashCellPtrPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("Idx", int64Type));
fn_prototype.addArgument(GsCodeGen::NamedVariable("nrows", int64Type));
jitted_batchagg_prefetch = fn_prototype.generatePrototype(&builder, &llvmargs[0]);
llvm::Value* Loc = llvmargs[0];
llvm::Value* idx = llvmargs[1];
llvm::Value* nrows = llvmargs[2];
DEFINE_BLOCK(prefetch_bb, jitted_batchagg_prefetch);
DEFINE_BLOCK(ret_bb, jitted_batchagg_prefetch);
llvm::Value* prefetchIdx = builder.CreateAdd(idx, int64_distance);
tmpval = builder.CreateICmpSLT(prefetchIdx, nrows);
builder.CreateCondBr(tmpval, prefetch_bb, ret_bb);
builder.SetInsertPoint(prefetch_bb);
llvm::Function* fn_prefetch = llvm::Intrinsic::getDeclaration(llvmCodeGen->module(), llvm_prefetch);
if (fn_prefetch == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmsg("Failed to get llvm function Intrinsic::prefetch!\n")));
}
tmpval = builder.CreateInBoundsGEP(Loc, prefetchIdx);
tmpval = builder.CreateLoad(hashCellPtrType, tmpval, "hashCell");
tmpval = builder.CreateBitCast(tmpval, int8PtrType);
builder.CreateCall(fn_prefetch, {tmpval, int32_0, int32_3, int32_1});
builder.CreateBr(ret_bb);
builder.SetInsertPoint(ret_bb);
builder.CreateRetVoid();
llvmCodeGen->FinalizeFunction(jitted_batchagg_prefetch);
return jitted_batchagg_prefetch;
}
* @Description : Generate the function to prefetch the hash cell ahead
* of 2, which means hint fetch loc[i+2], and prefetch the
* address of m_data ahead of 4, which means hint fetch
* m_data[m_cacheLoc[i+4]]. This function is called in the
* loop of the matching key.
* @return : return llvm function for building hash table in batchagg.
*/
llvm::Function* prefetchAggHashingCodeGen()
{
Assert(NULL != (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj);
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
llvm::Value* tmpval = NULL;
llvm::Value* llvmargs[3];
llvm::Function* jitted_hashing_prefetch = NULL;
DEFINE_CG_VOIDTYPE(voidType);
DEFINE_CG_TYPE(int32Type, INT4OID);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(hashAggRunnerPtrType, "class.HashAggRunner");
DEFINE_CG_PTRTYPE(hashSegTblPtrType, "struct.HashSegTbl");
DEFINE_CG_PTRTYPE(hashCellPtrType, "struct.hashCell");
DEFINE_CG_PTRPTRTYPE(hashCellPtrPtrType, "struct.hashCell");
DEFINE_CGVAR_INT32(int32_0, 0);
DEFINE_CGVAR_INT32(int32_1, 1);
DEFINE_CGVAR_INT32(int32_3, 3);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hashVal, pos_hAggR_hashVal);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hSegTbl, pos_hAggR_hSegTbl);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hsegmax, pos_hAggR_hsegmax);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hashSize, pos_hAggR_hashSize);
DEFINE_CGVAR_INT64(int64_0, 0);
DEFINE_CGVAR_INT64(int64_1, 1);
DEFINE_CGVAR_INT64(int64_distance1, PREFETCH_AGGHASHING_DISTANCE1);
DEFINE_CGVAR_INT64(int64_distance2, PREFETCH_AGGHASHING_DISTANCE2);
llvm::Value* Vals2[2] = {int64_0, int32_0};
llvm::Value* Vals3[3] = {int64_0, int32_0, int32_0};
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "prefetchAggHashing", voidType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("hAggRunner", hashAggRunnerPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("Idx", int64Type));
fn_prototype.addArgument(GsCodeGen::NamedVariable("nrows", int64Type));
jitted_hashing_prefetch = fn_prototype.generatePrototype(&builder, &llvmargs[0]);
llvm::Value* hAggRunner = llvmargs[0];
llvm::Value* idx = llvmargs[1];
llvm::Value* nrows = llvmargs[2];
DEFINE_BLOCK(prefetch_hashData_bb, jitted_hashing_prefetch);
DEFINE_BLOCK(prefetch_cell_bb, jitted_hashing_prefetch);
DEFINE_BLOCK(ret_bb, jitted_hashing_prefetch);
* try to prefetch hashData[m_cacheLoc[i+4]] : only do this when we have
* enough rows.
*/
llvm::Value* prefetchIdx = builder.CreateAdd(idx, int64_distance1);
tmpval = builder.CreateICmpSLT(prefetchIdx, nrows);
builder.CreateCondBr(tmpval, prefetch_hashData_bb, ret_bb);
builder.SetInsertPoint(prefetch_hashData_bb);
Vals2[1] = int32_pos_hAggR_hashSize;
tmpval = builder.CreateInBoundsGEP(hAggRunner, Vals2);
llvm::Value* maskval = builder.CreateLoad(int64Type, tmpval, "m_hashSize");
maskval = builder.CreateSub(maskval, int64_1, "mask");
llvm::Value* next_hashData_idx = builder.CreateAdd(idx, int64_distance1);
Vals3[1] = int32_pos_hAggR_hashVal;
Vals3[2] = next_hashData_idx;
llvm::Value* hashValSlot = builder.CreateInBoundsGEP(hAggRunner, Vals3);
llvm::Value* hashVal64 = builder.CreateLoad(int64Type, hashValSlot, "hashVal");
llvm::Value* cacheLocVal = builder.CreateAnd(hashVal64, maskval);
Vals2[0] = int64_0;
Vals2[1] = int32_pos_hAggR_hsegmax;
llvm::Value* segmaxval = builder.CreateInBoundsGEP(hAggRunner, Vals2);
segmaxval = builder.CreateLoad(int32Type, segmaxval, "segmax");
segmaxval = builder.CreateSExt(segmaxval, int64Type);
llvm::Value* nsegsval = builder.CreateExactUDiv(cacheLocVal, segmaxval, "nsegs");
nsegsval = builder.CreateTrunc(nsegsval, int32Type);
llvm::Value* pos = builder.CreateSRem(cacheLocVal, segmaxval, "pos");
Vals2[0] = int64_0;
Vals2[1] = int32_pos_hAggR_hSegTbl;
llvm::Value* hashData = builder.CreateInBoundsGEP(hAggRunner, Vals2);
hashData = builder.CreateLoad(hashSegTblPtrType, hashData, "m_hashData");
Vals2[0] = nsegsval;
Vals2[1] = int32_1;
llvm::Value* tbldata = builder.CreateInBoundsGEP(hashData, Vals2);
tbldata = builder.CreateLoad(hashCellPtrPtrType, tbldata, "tbl_data");
llvm::Value* next_hashData_addr = builder.CreateInBoundsGEP(tbldata, pos);
llvm::Function* fn_prefetch = llvm::Intrinsic::getDeclaration(llvmCodeGen->module(), llvm_prefetch);
if (fn_prefetch == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Failed to get function Intrinsic::prefetch!\n")));
}
tmpval = builder.CreateBitCast(next_hashData_addr, int8PtrType);
builder.CreateCall(fn_prefetch, {tmpval, int32_0, int32_3, int32_1});
llvm::Value* next_cell_idx = builder.CreateAdd(idx, int64_distance2);
Vals3[1] = int32_pos_hAggR_hashVal;
Vals3[2] = next_cell_idx;
hashValSlot = builder.CreateInBoundsGEP(hAggRunner, Vals3);
hashVal64 = builder.CreateLoad(int64Type, hashValSlot, "hashVal");
cacheLocVal = builder.CreateAnd(hashVal64, maskval);
llvm::Value* nsegsval2 = builder.CreateExactUDiv(cacheLocVal, segmaxval, "nsegs");
nsegsval2 = builder.CreateTrunc(nsegsval2, int32Type);
llvm::Value* pos2 = builder.CreateSRem(cacheLocVal, segmaxval, "pos");
Vals2[0] = nsegsval2;
Vals2[1] = int32_1;
llvm::Value* tbldata2 = builder.CreateInBoundsGEP(hashData, Vals2);
tbldata2 = builder.CreateLoad(hashCellPtrPtrType, tbldata2, "tbl_data");
tmpval = builder.CreateInBoundsGEP(tbldata2, pos2);
llvm::Value* next_cell = builder.CreateLoad(hashCellPtrType, tmpval, "cell");
tmpval = builder.CreatePtrToInt(next_cell, int64Type);
tmpval = builder.CreateICmpEQ(tmpval, int64_0);
builder.CreateCondBr(tmpval, ret_bb, prefetch_cell_bb);
builder.SetInsertPoint(prefetch_cell_bb);
next_cell = builder.CreateBitCast(next_cell, int8PtrType);
builder.CreateCall(fn_prefetch, {next_cell, int32_0, int32_3, int32_1});
builder.CreateBr(ret_bb);
builder.SetInsertPoint(ret_bb);
builder.CreateRetVoid();
llvmCodeGen->FinalizeFunction(jitted_hashing_prefetch);
return jitted_hashing_prefetch;
}
* @Description : Generate the function to prefetch the hash cell ahead
* of 2, which means hint fetch loc[i+2], and prefetch the
* address of m_data ahead of 4, which means hint fetch
* m_data[m_cacheLoc[i+4]]. This function is called in the
* loop of the matching key.
* @return : return llvm function for building hash table in batchagg.
*/
llvm::Function* prefetchAggSglTblHashingCodeGen()
{
Assert(NULL != (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj);
GsCodeGen* llvmCodeGen = (GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj;
llvm::LLVMContext& context = llvmCodeGen->context();
GsCodeGen::LlvmBuilder builder(context);
llvm::Value* tmpval = NULL;
llvm::Value* llvmargs[3];
llvm::Function* jitted_hashing_prefetch = NULL;
DEFINE_CG_VOIDTYPE(voidType);
DEFINE_CG_TYPE(int64Type, INT8OID);
DEFINE_CG_PTRTYPE(int8PtrType, CHAROID);
DEFINE_CG_PTRTYPE(hashAggRunnerPtrType, "class.HashAggRunner");
DEFINE_CG_PTRTYPE(hashCellPtrType, "struct.hashCell");
DEFINE_CG_PTRPTRTYPE(hashCellPtrPtrType, "struct.hashCell");
DEFINE_CG_PTRTYPE(hashSegTblPtrType, "struct.HashSegTbl");
DEFINE_CGVAR_INT32(int32_0, 0);
DEFINE_CGVAR_INT32(int32_1, 1);
DEFINE_CGVAR_INT32(int32_3, 3);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hashVal, pos_hAggR_hashVal);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hSegTbl, pos_hAggR_hSegTbl);
DEFINE_CGVAR_INT32(int32_pos_hAggR_hashSize, pos_hAggR_hashSize);
DEFINE_CGVAR_INT64(int64_0, 0);
DEFINE_CGVAR_INT64(int64_1, 1);
DEFINE_CGVAR_INT64(int64_distance1, PREFETCH_AGGHASHING_DISTANCE1);
DEFINE_CGVAR_INT64(int64_distance2, PREFETCH_AGGHASHING_DISTANCE2);
llvm::Value* Vals2[2] = {int64_0, int32_0};
llvm::Value* Vals3[3] = {int64_0, int32_0, int32_0};
GsCodeGen::FnPrototype fn_prototype(llvmCodeGen, "prefetchAggSglTblHashing", voidType);
fn_prototype.addArgument(GsCodeGen::NamedVariable("hAggRunner", hashAggRunnerPtrType));
fn_prototype.addArgument(GsCodeGen::NamedVariable("Idx", int64Type));
fn_prototype.addArgument(GsCodeGen::NamedVariable("nrows", int64Type));
jitted_hashing_prefetch = fn_prototype.generatePrototype(&builder, &llvmargs[0]);
llvm::Value* hAggRunner = llvmargs[0];
llvm::Value* idx = llvmargs[1];
llvm::Value* nrows = llvmargs[2];
DEFINE_BLOCK(prefetch_hashData_bb, jitted_hashing_prefetch);
DEFINE_BLOCK(prefetch_cell_bb, jitted_hashing_prefetch);
DEFINE_BLOCK(ret_bb, jitted_hashing_prefetch);
* try to prefetch hashData[m_cacheLoc[i+4]] : only do this when we have
* enough rows.
*/
llvm::Value* prefetchIdx = builder.CreateAdd(idx, int64_distance1);
tmpval = builder.CreateICmpSLT(prefetchIdx, nrows);
builder.CreateCondBr(tmpval, prefetch_hashData_bb, ret_bb);
builder.SetInsertPoint(prefetch_hashData_bb);
Vals2[1] = int32_pos_hAggR_hashSize;
tmpval = builder.CreateInBoundsGEP(hAggRunner, Vals2);
llvm::Value* maskval = builder.CreateLoad(int64Type, tmpval, "m_hashSize");
maskval = builder.CreateSub(maskval, int64_1, "mask");
llvm::Value* next_hashData_idx = builder.CreateAdd(idx, int64_distance1);
Vals3[1] = int32_pos_hAggR_hashVal;
Vals3[2] = next_hashData_idx;
llvm::Value* hashValSlot = builder.CreateInBoundsGEP(hAggRunner, Vals3);
llvm::Value* hashVal64 = builder.CreateLoad(int64Type, hashValSlot, "hashVal");
llvm::Value* cacheLocVal = builder.CreateAnd(hashVal64, maskval);
Vals2[0] = int64_0;
Vals2[1] = int32_pos_hAggR_hSegTbl;
llvm::Value* hashData = builder.CreateInBoundsGEP(hAggRunner, Vals2);
hashData = builder.CreateLoad(hashSegTblPtrType, hashData, "m_hashData");
Vals2[0] = int64_0;
Vals2[1] = int32_1;
llvm::Value* tbldata = builder.CreateInBoundsGEP(hashData, Vals2);
tbldata = builder.CreateLoad(hashCellPtrPtrType, tbldata, "tbl_data");
llvm::Value* next_hashData_addr = builder.CreateInBoundsGEP(tbldata, cacheLocVal);
llvm::Function* fn_prefetch = llvm::Intrinsic::getDeclaration(llvmCodeGen->module(), llvm_prefetch);
if (fn_prefetch == NULL) {
ereport(ERROR,
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED),
errmodule(MOD_LLVM),
errmsg("Failed to get function Intrinsic::prefetch!\n")));
}
tmpval = builder.CreateBitCast(next_hashData_addr, int8PtrType);
builder.CreateCall(fn_prefetch, {tmpval, int32_0, int32_3, int32_1});
llvm::Value* next_cell_idx = builder.CreateAdd(idx, int64_distance2);
Vals3[1] = int32_pos_hAggR_hashVal;
Vals3[2] = next_cell_idx;
hashValSlot = builder.CreateInBoundsGEP(hAggRunner, Vals3);
hashVal64 = builder.CreateLoad(int64Type, hashValSlot, "hashVal");
cacheLocVal = builder.CreateAnd(hashVal64, maskval);
llvm::Value* next_cell = builder.CreateInBoundsGEP(tbldata, cacheLocVal);
next_cell = builder.CreateLoad(hashCellPtrType, next_cell, "cell");
tmpval = builder.CreatePtrToInt(next_cell, int64Type);
tmpval = builder.CreateICmpEQ(tmpval, int64_0);
builder.CreateCondBr(tmpval, ret_bb, prefetch_cell_bb);
builder.SetInsertPoint(prefetch_cell_bb);
next_cell = builder.CreateBitCast(next_cell, int8PtrType);
builder.CreateCall(fn_prefetch, {next_cell, int32_0, int32_3, int32_1});
builder.CreateBr(ret_bb);
builder.SetInsertPoint(ret_bb);
builder.CreateRetVoid();
llvmCodeGen->FinalizeFunction(jitted_hashing_prefetch);
return jitted_hashing_prefetch;
}
}
* @Description : If current hashcell is not matched, allocate a new hash cell and
* initialize the hash value.
* @in haRunner : HashAggRunner data structure.
* @in batch : Batch value used to initialize the hash cell.
* @in idx : The row index of current tuple in batch.
* @in keysimple : the match key is simple when true.
*/
void WrapAllocHashSlot(HashAggRunner* haRunner, VectorBatch* batch, int idx, int keysimple)
{
if (keysimple)
haRunner->AllocHashSlot<true, false>(batch, idx);
else
haRunner->AllocHashSlot<false, false>(batch, idx);
}
* @Description : If current hashcell is not matched, allocate a new hash cell and
* initialize the hash value with only one segment hash table case.
* @in haRunner : HashAggRunner data structure.
* @in batch : Batch value used to initialize the hash cell.
* @in idx : The row index of current tuple in batch.
* @in keysimple : the match key is simple when true.
*/
void WrapSglTblAllocHashSlot(HashAggRunner* haRunner, VectorBatch* batch, int idx, int keysimple)
{
if (keysimple)
haRunner->AllocHashSlot<true, true>(batch, idx);
else
haRunner->AllocHashSlot<false, true>(batch, idx);
}
* @Description : Reset current expr context.
* @econtext : Current expr context.
*/
void WrapResetExprContext(ExprContext* econtext)
{
if (econtext != NULL)
ResetExprContext(econtext);
}