FunctionCallInfo fcinfo, AggStatePerTrans pertrans,
int transno, int setno, int setoff, bool ishash)
{
- int adjust_init_jumpnull = -1;
- int adjust_strict_jumpnull = -1;
ExprContext *aggcontext;
if (ishash)
aggcontext = aggstate->aggcontexts[setno];
/*
+ * Determine appropriate transition implementation.
+ *
+ * For non-ordered aggregates:
+ *
* If the initial value for the transition state doesn't exist in the
* pg_aggregate table then we will let the first non-NULL value returned
* from the outer procNode become the initial value. (This is useful for
* aggregates like max() and min().) The noTransValue flag signals that we
- * still need to do this.
+ * need to do so. If true, generate a
+ * EEOP_AGG_INIT_STRICT_PLAIN_TRANS{,_BYVAL} step. This step also needs to
+ * do the work described next:
+ *
+ * If the function is strict, but does have an initial value, choose
+ * EEOP_AGG_STRICT_PLAIN_TRANS{,_BYVAL}, which skips the transition
+ * function if the transition value has become NULL (because a previous
+ * transition function returned NULL). This step also needs to do the work
+ * described next:
+ *
+ * Otherwise we call EEOP_AGG_PLAIN_TRANS{,_BYVAL}, which does not have to
+ * perform either of the above checks.
+ *
+ * Having steps with overlapping responsibilities is not nice, but
+ * aggregations are very performance sensitive, making this worthwhile.
+ *
+ * For ordered aggregates:
+ *
+ * Only need to choose between the faster path for a single orderred
+ * column, and the one between multiple columns. Checking strictness etc
+ * is done when finalizing the aggregate. See
+ * process_ordered_aggregate_{single, multi} and
+ * advance_transition_function.
*/
- if (pertrans->numSortCols == 0 &&
- fcinfo->flinfo->fn_strict &&
- pertrans->initValueIsNull)
- {
- scratch->opcode = EEOP_AGG_INIT_TRANS;
- scratch->d.agg_init_trans.pertrans = pertrans;
- scratch->d.agg_init_trans.setno = setno;
- scratch->d.agg_init_trans.setoff = setoff;
- scratch->d.agg_init_trans.transno = transno;
- scratch->d.agg_init_trans.aggcontext = aggcontext;
- scratch->d.agg_init_trans.jumpnull = -1; /* adjust later */
- ExprEvalPushStep(state, scratch);
-
- /* see comment about jumping out below */
- adjust_init_jumpnull = state->steps_len - 1;
- }
-
- if (pertrans->numSortCols == 0 &&
- fcinfo->flinfo->fn_strict)
+ if (pertrans->numSortCols == 0)
{
- scratch->opcode = EEOP_AGG_STRICT_TRANS_CHECK;
- scratch->d.agg_strict_trans_check.setno = setno;
- scratch->d.agg_strict_trans_check.setoff = setoff;
- scratch->d.agg_strict_trans_check.transno = transno;
- scratch->d.agg_strict_trans_check.jumpnull = -1; /* adjust later */
- ExprEvalPushStep(state, scratch);
-
- /*
- * Note, we don't push into adjust_bailout here - those jump to the
- * end of all transition value computations. Here a single transition
- * value is NULL, so just skip processing the individual value.
- */
- adjust_strict_jumpnull = state->steps_len - 1;
+ if (pertrans->transtypeByVal)
+ {
+ if (fcinfo->flinfo->fn_strict &&
+ pertrans->initValueIsNull)
+ scratch->opcode = EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL;
+ else if (fcinfo->flinfo->fn_strict)
+ scratch->opcode = EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL;
+ else
+ scratch->opcode = EEOP_AGG_PLAIN_TRANS_BYVAL;
+ }
+ else
+ {
+ if (fcinfo->flinfo->fn_strict &&
+ pertrans->initValueIsNull)
+ scratch->opcode = EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF;
+ else if (fcinfo->flinfo->fn_strict)
+ scratch->opcode = EEOP_AGG_PLAIN_TRANS_STRICT_BYREF;
+ else
+ scratch->opcode = EEOP_AGG_PLAIN_TRANS_BYREF;
+ }
}
-
- /* invoke appropriate transition implementation */
- if (pertrans->numSortCols == 0 && pertrans->transtypeByVal)
- scratch->opcode = EEOP_AGG_PLAIN_TRANS_BYVAL;
- else if (pertrans->numSortCols == 0)
- scratch->opcode = EEOP_AGG_PLAIN_TRANS;
else if (pertrans->numInputs == 1)
scratch->opcode = EEOP_AGG_ORDERED_TRANS_DATUM;
else
scratch->d.agg_trans.transno = transno;
scratch->d.agg_trans.aggcontext = aggcontext;
ExprEvalPushStep(state, scratch);
-
- /* adjust jumps so they jump till after transition invocation */
- if (adjust_init_jumpnull != -1)
- {
- ExprEvalStep *as = &state->steps[adjust_init_jumpnull];
-
- Assert(as->d.agg_init_trans.jumpnull == -1);
- as->d.agg_init_trans.jumpnull = state->steps_len;
- }
- if (adjust_strict_jumpnull != -1)
- {
- ExprEvalStep *as = &state->steps[adjust_strict_jumpnull];
-
- Assert(as->d.agg_strict_trans_check.jumpnull == -1);
- as->d.agg_strict_trans_check.jumpnull = state->steps_len;
- }
}
/*
static Datum ExecJustAssignOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
static Datum ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
+/* execution helper functions */
+static pg_attribute_always_inline void
+ExecAggPlainTransByVal(AggState *aggstate, AggStatePerTrans pertrans,
+ AggStatePerGroup pergroup,
+ ExprContext *aggcontext, int setno);
+
+static pg_attribute_always_inline void
+ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
+ AggStatePerGroup pergroup,
+ ExprContext *aggcontext, int setno);
/*
* Prepare ExprState for interpreted execution.
&&CASE_EEOP_AGG_DESERIALIZE,
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
- &&CASE_EEOP_AGG_INIT_TRANS,
- &&CASE_EEOP_AGG_STRICT_TRANS_CHECK,
+ &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
+ &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL,
&&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
- &&CASE_EEOP_AGG_PLAIN_TRANS,
+ &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF,
+ &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYREF,
+ &&CASE_EEOP_AGG_PLAIN_TRANS_BYREF,
&&CASE_EEOP_AGG_ORDERED_TRANS_DATUM,
&&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE,
&&CASE_EEOP_LAST
}
/*
- * Initialize an aggregate's first value if necessary.
+ * Different types of aggregate transition functions are implemented
+ * as different types of steps, to avoid incurring unnecessary
+ * overhead. There's a step type for each valid combination of having
+ * a by value / by reference transition type, [not] needing to the
+ * initialize the transition value for the first row in a group from
+ * input, and [not] strict transition function.
+ *
+ * Could optimize further by splitting off by-reference for
+ * fixed-length types, but currently that doesn't seem worth it.
*/
- EEO_CASE(EEOP_AGG_INIT_TRANS)
+
+ EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL)
{
AggState *aggstate = castNode(AggState, state->parent);
- AggStatePerGroup pergroup;
+ AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
+ AggStatePerGroup pergroup = &aggstate->all_pergroups
+ [op->d.agg_trans.setoff]
+ [op->d.agg_trans.transno];
- pergroup = &aggstate->all_pergroups
- [op->d.agg_init_trans.setoff]
- [op->d.agg_init_trans.transno];
+ Assert(pertrans->transtypeByVal);
- /* If transValue has not yet been initialized, do so now. */
if (pergroup->noTransValue)
{
- AggStatePerTrans pertrans = op->d.agg_init_trans.pertrans;
-
- aggstate->curaggcontext = op->d.agg_init_trans.aggcontext;
- aggstate->current_set = op->d.agg_init_trans.setno;
-
- ExecAggInitGroup(aggstate, pertrans, pergroup);
-
+ /* If transValue has not yet been initialized, do so now. */
+ ExecAggInitGroup(aggstate, pertrans, pergroup,
+ op->d.agg_trans.aggcontext);
/* copied trans value from input, done this round */
- EEO_JUMP(op->d.agg_init_trans.jumpnull);
+ }
+ else if (likely(!pergroup->transValueIsNull))
+ {
+ /* invoke transition function, unless prevented by strictness */
+ ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
+ op->d.agg_trans.aggcontext,
+ op->d.agg_trans.setno);
}
EEO_NEXT();
}
- /* check that a strict aggregate's input isn't NULL */
- EEO_CASE(EEOP_AGG_STRICT_TRANS_CHECK)
+ /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
+ EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL)
{
AggState *aggstate = castNode(AggState, state->parent);
- AggStatePerGroup pergroup;
+ AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
+ AggStatePerGroup pergroup = &aggstate->all_pergroups
+ [op->d.agg_trans.setoff]
+ [op->d.agg_trans.transno];
- pergroup = &aggstate->all_pergroups
- [op->d.agg_strict_trans_check.setoff]
- [op->d.agg_strict_trans_check.transno];
+ Assert(pertrans->transtypeByVal);
- if (unlikely(pergroup->transValueIsNull))
- EEO_JUMP(op->d.agg_strict_trans_check.jumpnull);
+ if (likely(!pergroup->transValueIsNull))
+ ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
+ op->d.agg_trans.aggcontext,
+ op->d.agg_trans.setno);
EEO_NEXT();
}
- /*
- * Evaluate aggregate transition / combine function that has a
- * by-value transition type. That's a separate case from the
- * by-reference implementation because it's a bit simpler.
- */
+ /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYVAL)
{
AggState *aggstate = castNode(AggState, state->parent);
- AggStatePerTrans pertrans;
- AggStatePerGroup pergroup;
- FunctionCallInfo fcinfo;
- MemoryContext oldContext;
- Datum newVal;
-
- pertrans = op->d.agg_trans.pertrans;
-
- pergroup = &aggstate->all_pergroups
+ AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
+ AggStatePerGroup pergroup = &aggstate->all_pergroups
[op->d.agg_trans.setoff]
[op->d.agg_trans.transno];
Assert(pertrans->transtypeByVal);
- fcinfo = pertrans->transfn_fcinfo;
-
- /* cf. select_current_set() */
- aggstate->curaggcontext = op->d.agg_trans.aggcontext;
- aggstate->current_set = op->d.agg_trans.setno;
-
- /* set up aggstate->curpertrans for AggGetAggref() */
- aggstate->curpertrans = pertrans;
-
- /* invoke transition function in per-tuple context */
- oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
-
- fcinfo->args[0].value = pergroup->transValue;
- fcinfo->args[0].isnull = pergroup->transValueIsNull;
- fcinfo->isnull = false; /* just in case transfn doesn't set it */
-
- newVal = FunctionCallInvoke(fcinfo);
-
- pergroup->transValue = newVal;
- pergroup->transValueIsNull = fcinfo->isnull;
-
- MemoryContextSwitchTo(oldContext);
+ ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
+ op->d.agg_trans.aggcontext,
+ op->d.agg_trans.setno);
EEO_NEXT();
}
- /*
- * Evaluate aggregate transition / combine function that has a
- * by-reference transition type.
- *
- * Could optimize a bit further by splitting off by-reference
- * fixed-length types, but currently that doesn't seem worth it.
- */
- EEO_CASE(EEOP_AGG_PLAIN_TRANS)
+ /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
+ EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF)
{
AggState *aggstate = castNode(AggState, state->parent);
- AggStatePerTrans pertrans;
- AggStatePerGroup pergroup;
- FunctionCallInfo fcinfo;
- MemoryContext oldContext;
- Datum newVal;
-
- pertrans = op->d.agg_trans.pertrans;
-
- pergroup = &aggstate->all_pergroups
+ AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
+ AggStatePerGroup pergroup = &aggstate->all_pergroups
[op->d.agg_trans.setoff]
[op->d.agg_trans.transno];
Assert(!pertrans->transtypeByVal);
- fcinfo = pertrans->transfn_fcinfo;
-
- /* cf. select_current_set() */
- aggstate->curaggcontext = op->d.agg_trans.aggcontext;
- aggstate->current_set = op->d.agg_trans.setno;
+ if (pergroup->noTransValue)
+ ExecAggInitGroup(aggstate, pertrans, pergroup,
+ op->d.agg_trans.aggcontext);
+ else if (likely(!pergroup->transValueIsNull))
+ ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
+ op->d.agg_trans.aggcontext,
+ op->d.agg_trans.setno);
- /* set up aggstate->curpertrans for AggGetAggref() */
- aggstate->curpertrans = pertrans;
+ EEO_NEXT();
+ }
- /* invoke transition function in per-tuple context */
- oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
+ /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
+ EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYREF)
+ {
+ AggState *aggstate = castNode(AggState, state->parent);
+ AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
+ AggStatePerGroup pergroup = &aggstate->all_pergroups
+ [op->d.agg_trans.setoff]
+ [op->d.agg_trans.transno];
- fcinfo->args[0].value = pergroup->transValue;
- fcinfo->args[0].isnull = pergroup->transValueIsNull;
- fcinfo->isnull = false; /* just in case transfn doesn't set it */
+ Assert(!pertrans->transtypeByVal);
- newVal = FunctionCallInvoke(fcinfo);
+ if (likely(!pergroup->transValueIsNull))
+ ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
+ op->d.agg_trans.aggcontext,
+ op->d.agg_trans.setno);
+ EEO_NEXT();
+ }
- /*
- * For pass-by-ref datatype, must copy the new value into
- * aggcontext and free the prior transValue. But if transfn
- * returned a pointer to its first input, we don't need to do
- * anything. Also, if transfn returned a pointer to a R/W
- * expanded object that is already a child of the aggcontext,
- * assume we can adopt that value without copying it.
- *
- * It's safe to compare newVal with pergroup->transValue without
- * regard for either being NULL, because ExecAggTransReparent()
- * takes care to set transValue to 0 when NULL. Otherwise we could
- * end up accidentally not reparenting, when the transValue has
- * the same numerical value as newValue, despite being NULL. This
- * is a somewhat hot path, making it undesirable to instead solve
- * this with another branch for the common case of the transition
- * function returning its (modified) input argument.
- */
- if (DatumGetPointer(newVal) != DatumGetPointer(pergroup->transValue))
- newVal = ExecAggTransReparent(aggstate, pertrans,
- newVal, fcinfo->isnull,
- pergroup->transValue,
- pergroup->transValueIsNull);
+ /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
+ EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYREF)
+ {
+ AggState *aggstate = castNode(AggState, state->parent);
+ AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
+ AggStatePerGroup pergroup = &aggstate->all_pergroups
+ [op->d.agg_trans.setoff]
+ [op->d.agg_trans.transno];
- pergroup->transValue = newVal;
- pergroup->transValueIsNull = fcinfo->isnull;
+ Assert(!pertrans->transtypeByVal);
- MemoryContextSwitchTo(oldContext);
+ ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
+ op->d.agg_trans.aggcontext,
+ op->d.agg_trans.setno);
EEO_NEXT();
}
* value for a group. We use it as the initial value for transValue.
*/
void
-ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup)
+ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup,
+ ExprContext *aggcontext)
{
FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
MemoryContext oldContext;
* that the agg's input type is binary-compatible with its transtype, so
* straight copy here is OK.)
*/
- oldContext = MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
+ oldContext = MemoryContextSwitchTo(aggcontext->ecxt_per_tuple_memory);
pergroup->transValue = datumCopy(fcinfo->args[1].value,
pertrans->transtypeByVal,
pertrans->transtypeLen);
ExecStoreVirtualTuple(pertrans->sortslot);
tuplesort_puttupleslot(pertrans->sortstates[setno], pertrans->sortslot);
}
+
+/* implementation of transition function invocation for byval types */
+static pg_attribute_always_inline void
+ExecAggPlainTransByVal(AggState *aggstate, AggStatePerTrans pertrans,
+ AggStatePerGroup pergroup,
+ ExprContext *aggcontext, int setno)
+{
+ FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
+ MemoryContext oldContext;
+ Datum newVal;
+
+ /* cf. select_current_set() */
+ aggstate->curaggcontext = aggcontext;
+ aggstate->current_set = setno;
+
+ /* set up aggstate->curpertrans for AggGetAggref() */
+ aggstate->curpertrans = pertrans;
+
+ /* invoke transition function in per-tuple context */
+ oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
+
+ fcinfo->args[0].value = pergroup->transValue;
+ fcinfo->args[0].isnull = pergroup->transValueIsNull;
+ fcinfo->isnull = false; /* just in case transfn doesn't set it */
+
+ newVal = FunctionCallInvoke(fcinfo);
+
+ pergroup->transValue = newVal;
+ pergroup->transValueIsNull = fcinfo->isnull;
+
+ MemoryContextSwitchTo(oldContext);
+}
+
+/* implementation of transition function invocation for byref types */
+static pg_attribute_always_inline void
+ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
+ AggStatePerGroup pergroup,
+ ExprContext *aggcontext, int setno)
+{
+ FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
+ MemoryContext oldContext;
+ Datum newVal;
+
+ /* cf. select_current_set() */
+ aggstate->curaggcontext = aggcontext;
+ aggstate->current_set = setno;
+
+ /* set up aggstate->curpertrans for AggGetAggref() */
+ aggstate->curpertrans = pertrans;
+
+ /* invoke transition function in per-tuple context */
+ oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
+
+ fcinfo->args[0].value = pergroup->transValue;
+ fcinfo->args[0].isnull = pergroup->transValueIsNull;
+ fcinfo->isnull = false; /* just in case transfn doesn't set it */
+
+ newVal = FunctionCallInvoke(fcinfo);
+
+ /*
+ * For pass-by-ref datatype, must copy the new value into
+ * aggcontext and free the prior transValue. But if transfn
+ * returned a pointer to its first input, we don't need to do
+ * anything. Also, if transfn returned a pointer to a R/W
+ * expanded object that is already a child of the aggcontext,
+ * assume we can adopt that value without copying it.
+ *
+ * It's safe to compare newVal with pergroup->transValue without
+ * regard for either being NULL, because ExecAggTransReparent()
+ * takes care to set transValue to 0 when NULL. Otherwise we could
+ * end up accidentally not reparenting, when the transValue has
+ * the same numerical value as newValue, despite being NULL. This
+ * is a somewhat hot path, making it undesirable to instead solve
+ * this with another branch for the common case of the transition
+ * function returning its (modified) input argument.
+ */
+ if (DatumGetPointer(newVal) != DatumGetPointer(pergroup->transValue))
+ newVal = ExecAggTransReparent(aggstate, pertrans,
+ newVal, fcinfo->isnull,
+ pergroup->transValue,
+ pergroup->transValueIsNull);
+
+ pergroup->transValue = newVal;
+ pergroup->transValueIsNull = fcinfo->isnull;
+
+ MemoryContextSwitchTo(oldContext);
+}
break;
}
- case EEOP_AGG_INIT_TRANS:
- {
- AggStatePerTrans pertrans;
-
- LLVMValueRef v_aggstatep;
- LLVMValueRef v_pertransp;
-
- LLVMValueRef v_allpergroupsp;
-
- LLVMValueRef v_pergroupp;
-
- LLVMValueRef v_setoff,
- v_transno;
-
- LLVMValueRef v_notransvalue;
-
- LLVMBasicBlockRef b_init;
-
- pertrans = op->d.agg_init_trans.pertrans;
-
- v_aggstatep =
- LLVMBuildBitCast(b, v_parent, l_ptr(StructAggState), "");
- v_pertransp = l_ptr_const(pertrans,
- l_ptr(StructAggStatePerTransData));
-
- /*
- * pergroup = &aggstate->all_pergroups
- * [op->d.agg_init_trans_check.setoff]
- * [op->d.agg_init_trans_check.transno];
- */
- v_allpergroupsp =
- l_load_struct_gep(b, v_aggstatep,
- FIELDNO_AGGSTATE_ALL_PERGROUPS,
- "aggstate.all_pergroups");
- v_setoff = l_int32_const(op->d.agg_init_trans.setoff);
- v_transno = l_int32_const(op->d.agg_init_trans.transno);
- v_pergroupp =
- LLVMBuildGEP(b,
- l_load_gep1(b, v_allpergroupsp, v_setoff, ""),
- &v_transno, 1, "");
-
- v_notransvalue =
- l_load_struct_gep(b, v_pergroupp,
- FIELDNO_AGGSTATEPERGROUPDATA_NOTRANSVALUE,
- "notransvalue");
-
- b_init = l_bb_before_v(opblocks[opno + 1],
- "op.%d.inittrans", opno);
-
- LLVMBuildCondBr(b,
- LLVMBuildICmp(b, LLVMIntEQ, v_notransvalue,
- l_sbool_const(1), ""),
- b_init,
- opblocks[opno + 1]);
-
- LLVMPositionBuilderAtEnd(b, b_init);
-
- {
- LLVMValueRef params[3];
- LLVMValueRef v_curaggcontext;
- LLVMValueRef v_current_set;
- LLVMValueRef v_aggcontext;
-
- v_aggcontext = l_ptr_const(op->d.agg_init_trans.aggcontext,
- l_ptr(StructExprContext));
-
- v_current_set =
- LLVMBuildStructGEP(b,
- v_aggstatep,
- FIELDNO_AGGSTATE_CURRENT_SET,
- "aggstate.current_set");
- v_curaggcontext =
- LLVMBuildStructGEP(b,
- v_aggstatep,
- FIELDNO_AGGSTATE_CURAGGCONTEXT,
- "aggstate.curaggcontext");
-
- LLVMBuildStore(b, l_int32_const(op->d.agg_init_trans.setno),
- v_current_set);
- LLVMBuildStore(b, v_aggcontext,
- v_curaggcontext);
-
- params[0] = v_aggstatep;
- params[1] = v_pertransp;
- params[2] = v_pergroupp;
-
- LLVMBuildCall(b,
- llvm_pg_func(mod, "ExecAggInitGroup"),
- params, lengthof(params),
- "");
- }
- LLVMBuildBr(b, opblocks[op->d.agg_init_trans.jumpnull]);
-
- break;
- }
-
- case EEOP_AGG_STRICT_TRANS_CHECK:
- {
- LLVMValueRef v_setoff,
- v_transno;
-
- LLVMValueRef v_aggstatep;
- LLVMValueRef v_allpergroupsp;
-
- LLVMValueRef v_transnull;
- LLVMValueRef v_pergroupp;
-
- int jumpnull = op->d.agg_strict_trans_check.jumpnull;
-
- v_aggstatep =
- LLVMBuildBitCast(b, v_parent, l_ptr(StructAggState), "");
-
- /*
- * pergroup = &aggstate->all_pergroups
- * [op->d.agg_strict_trans_check.setoff]
- * [op->d.agg_init_trans_check.transno];
- */
- v_allpergroupsp =
- l_load_struct_gep(b, v_aggstatep,
- FIELDNO_AGGSTATE_ALL_PERGROUPS,
- "aggstate.all_pergroups");
- v_setoff =
- l_int32_const(op->d.agg_strict_trans_check.setoff);
- v_transno =
- l_int32_const(op->d.agg_strict_trans_check.transno);
- v_pergroupp =
- LLVMBuildGEP(b,
- l_load_gep1(b, v_allpergroupsp, v_setoff, ""),
- &v_transno, 1, "");
-
- v_transnull =
- l_load_struct_gep(b, v_pergroupp,
- FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUEISNULL,
- "transnull");
-
- LLVMBuildCondBr(b,
- LLVMBuildICmp(b, LLVMIntEQ, v_transnull,
- l_sbool_const(1), ""),
- opblocks[jumpnull],
- opblocks[opno + 1]);
-
- break;
- }
-
+ case EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL:
+ case EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL:
case EEOP_AGG_PLAIN_TRANS_BYVAL:
- case EEOP_AGG_PLAIN_TRANS:
+ case EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF:
+ case EEOP_AGG_PLAIN_TRANS_STRICT_BYREF:
+ case EEOP_AGG_PLAIN_TRANS_BYREF:
{
AggState *aggstate;
AggStatePerTrans pertrans;
l_load_gep1(b, v_allpergroupsp, v_setoff, ""),
&v_transno, 1, "");
+
+ if (opcode == EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL ||
+ opcode == EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF)
+ {
+ LLVMValueRef v_notransvalue;
+ LLVMBasicBlockRef b_init;
+ LLVMBasicBlockRef b_no_init;
+
+ v_notransvalue =
+ l_load_struct_gep(b, v_pergroupp,
+ FIELDNO_AGGSTATEPERGROUPDATA_NOTRANSVALUE,
+ "notransvalue");
+
+ b_init = l_bb_before_v(opblocks[opno + 1],
+ "op.%d.inittrans", opno);
+ b_no_init = l_bb_before_v(opblocks[opno + 1],
+ "op.%d.no_inittrans", opno);
+
+ LLVMBuildCondBr(b,
+ LLVMBuildICmp(b, LLVMIntEQ, v_notransvalue,
+ l_sbool_const(1), ""),
+ b_init,
+ b_no_init);
+
+ /* block to init the transition value if necessary */
+ {
+ LLVMValueRef params[4];
+
+ LLVMPositionBuilderAtEnd(b, b_init);
+
+ v_aggcontext = l_ptr_const(op->d.agg_trans.aggcontext,
+ l_ptr(StructExprContext));
+
+ params[0] = v_aggstatep;
+ params[1] = v_pertransp;
+ params[2] = v_pergroupp;
+ params[3] = v_aggcontext;
+
+ LLVMBuildCall(b,
+ llvm_pg_func(mod, "ExecAggInitGroup"),
+ params, lengthof(params),
+ "");
+
+ LLVMBuildBr(b, opblocks[opno + 1]);
+
+ }
+
+ LLVMPositionBuilderAtEnd(b, b_no_init);
+ }
+
+ if (opcode == EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL ||
+ opcode == EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF ||
+ opcode == EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL ||
+ opcode == EEOP_AGG_PLAIN_TRANS_STRICT_BYREF)
+ {
+ LLVMValueRef v_transnull;
+ LLVMBasicBlockRef b_strictpass;
+
+ b_strictpass = l_bb_before_v(opblocks[opno + 1],
+ "op.%d.strictpass", opno);
+ v_transnull =
+ l_load_struct_gep(b, v_pergroupp,
+ FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUEISNULL,
+ "transnull");
+
+ LLVMBuildCondBr(b,
+ LLVMBuildICmp(b, LLVMIntEQ, v_transnull,
+ l_sbool_const(1), ""),
+ opblocks[opno + 1],
+ b_strictpass);
+
+ LLVMPositionBuilderAtEnd(b, b_strictpass);
+ }
+
+
v_fcinfo = l_ptr_const(fcinfo,
l_ptr(StructFunctionCallInfoData));
v_aggcontext = l_ptr_const(op->d.agg_trans.aggcontext,
* child of the aggcontext, assume we can adopt that value
* without copying it.
*/
- if (opcode == EEOP_AGG_PLAIN_TRANS)
+ if (opcode == EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF ||
+ opcode == EEOP_AGG_PLAIN_TRANS_STRICT_BYREF ||
+ opcode == EEOP_AGG_PLAIN_TRANS_BYREF)
{
LLVMBasicBlockRef b_call;
LLVMBasicBlockRef b_nocall;