Commit e6f86f8d authored by Andres Freund's avatar Andres Freund

jit: Remove redundancies in expression evaluation code generation.

This merges the code emission for a number of opcodes by handling the
behavioural difference more locally. This reduces code, and also
improves the generated code a bit in some cases, by removing redundant
constants.

Author: Andres Freund
Discussion: https://postgr.es/m/20191023163849.sosqbfs5yenocez3@alap3.anarazel.de
parent 8c276940
...@@ -471,6 +471,7 @@ llvm_compile_expr(ExprState *state) ...@@ -471,6 +471,7 @@ llvm_compile_expr(ExprState *state)
} }
case EEOP_ASSIGN_TMP: case EEOP_ASSIGN_TMP:
case EEOP_ASSIGN_TMP_MAKE_RO:
{ {
LLVMValueRef v_value, LLVMValueRef v_value,
v_isnull; v_isnull;
...@@ -490,43 +491,18 @@ llvm_compile_expr(ExprState *state) ...@@ -490,43 +491,18 @@ llvm_compile_expr(ExprState *state)
v_risnullp = v_risnullp =
LLVMBuildGEP(b, v_resultnulls, &v_resultnum, 1, ""); LLVMBuildGEP(b, v_resultnulls, &v_resultnum, 1, "");
/* and store */ /* store nullness */
LLVMBuildStore(b, v_value, v_rvaluep);
LLVMBuildStore(b, v_isnull, v_risnullp); LLVMBuildStore(b, v_isnull, v_risnullp);
LLVMBuildBr(b, opblocks[opno + 1]); /* make value readonly if necessary */
break; if (opcode == EEOP_ASSIGN_TMP_MAKE_RO)
}
case EEOP_ASSIGN_TMP_MAKE_RO:
{ {
LLVMBasicBlockRef b_notnull; LLVMBasicBlockRef b_notnull;
LLVMValueRef v_params[1]; LLVMValueRef v_params[1];
LLVMValueRef v_ret;
LLVMValueRef v_value,
v_isnull;
LLVMValueRef v_rvaluep,
v_risnullp;
LLVMValueRef v_resultnum;
size_t resultnum = op->d.assign_tmp.resultnum;
b_notnull = l_bb_before_v(opblocks[opno + 1], b_notnull = l_bb_before_v(opblocks[opno + 1],
"op.%d.assign_tmp.notnull", opno); "op.%d.assign_tmp.notnull", opno);
/* load data */
v_value = LLVMBuildLoad(b, v_tmpvaluep, "");
v_isnull = LLVMBuildLoad(b, v_tmpisnullp, "");
/* compute addresses of targets */
v_resultnum = l_int32_const(resultnum);
v_rvaluep = LLVMBuildGEP(b, v_resultvalues,
&v_resultnum, 1, "");
v_risnullp = LLVMBuildGEP(b, v_resultnulls,
&v_resultnum, 1, "");
/* store nullness */
LLVMBuildStore(b, v_isnull, v_risnullp);
/* check if value is NULL */ /* check if value is NULL */
LLVMBuildCondBr(b, LLVMBuildCondBr(b,
LLVMBuildICmp(b, LLVMIntEQ, v_isnull, LLVMBuildICmp(b, LLVMIntEQ, v_isnull,
...@@ -536,13 +512,19 @@ llvm_compile_expr(ExprState *state) ...@@ -536,13 +512,19 @@ llvm_compile_expr(ExprState *state)
/* if value is not null, convert to RO datum */ /* if value is not null, convert to RO datum */
LLVMPositionBuilderAtEnd(b, b_notnull); LLVMPositionBuilderAtEnd(b, b_notnull);
v_params[0] = v_value; v_params[0] = v_value;
v_ret = v_value =
LLVMBuildCall(b, LLVMBuildCall(b,
llvm_get_decl(mod, FuncMakeExpandedObjectReadOnlyInternal), llvm_get_decl(mod, FuncMakeExpandedObjectReadOnlyInternal),
v_params, lengthof(v_params), ""); v_params, lengthof(v_params), "");
/* store value */ /*
LLVMBuildStore(b, v_ret, v_rvaluep); * Falling out of the if () with builder in b_notnull,
* which is fine - the null is already stored above.
*/
}
/* and finally store result */
LLVMBuildStore(b, v_value, v_rvaluep);
LLVMBuildBr(b, opblocks[opno + 1]); LLVMBuildBr(b, opblocks[opno + 1]);
break; break;
...@@ -563,12 +545,18 @@ llvm_compile_expr(ExprState *state) ...@@ -563,12 +545,18 @@ llvm_compile_expr(ExprState *state)
break; break;
} }
case EEOP_FUNCEXPR:
case EEOP_FUNCEXPR_STRICT: case EEOP_FUNCEXPR_STRICT:
{ {
FunctionCallInfo fcinfo = op->d.func.fcinfo_data; FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
LLVMValueRef v_fcinfo_isnull;
LLVMValueRef v_retval;
if (opcode == EEOP_FUNCEXPR_STRICT)
{
LLVMBasicBlockRef b_nonull; LLVMBasicBlockRef b_nonull;
LLVMValueRef v_fcinfo;
LLVMBasicBlockRef *b_checkargnulls; LLVMBasicBlockRef *b_checkargnulls;
LLVMValueRef v_fcinfo;
/* /*
* Block for the actual function call, if args are * Block for the actual function call, if args are
...@@ -595,7 +583,8 @@ llvm_compile_expr(ExprState *state) ...@@ -595,7 +583,8 @@ llvm_compile_expr(ExprState *state)
palloc(sizeof(LLVMBasicBlockRef *) * op->d.func.nargs); palloc(sizeof(LLVMBasicBlockRef *) * op->d.func.nargs);
for (int argno = 0; argno < op->d.func.nargs; argno++) for (int argno = 0; argno < op->d.func.nargs; argno++)
b_checkargnulls[argno] = b_checkargnulls[argno] =
l_bb_before_v(b_nonull, "b.%d.isnull.%d", opno, argno); l_bb_before_v(b_nonull, "b.%d.isnull.%d", opno,
argno);
/* jump to check of first argument */ /* jump to check of first argument */
LLVMBuildBr(b, b_checkargnulls[0]); LLVMBuildBr(b, b_checkargnulls[0]);
...@@ -608,7 +597,10 @@ llvm_compile_expr(ExprState *state) ...@@ -608,7 +597,10 @@ llvm_compile_expr(ExprState *state)
LLVMPositionBuilderAtEnd(b, b_checkargnulls[argno]); LLVMPositionBuilderAtEnd(b, b_checkargnulls[argno]);
/* compute block to jump to if argument is not null */ /*
* Compute block to jump to if argument is not
* null.
*/
if (argno + 1 == op->d.func.nargs) if (argno + 1 == op->d.func.nargs)
b_argnotnull = b_nonull; b_argnotnull = b_nonull;
else else
...@@ -627,13 +619,6 @@ llvm_compile_expr(ExprState *state) ...@@ -627,13 +619,6 @@ llvm_compile_expr(ExprState *state)
LLVMPositionBuilderAtEnd(b, b_nonull); LLVMPositionBuilderAtEnd(b, b_nonull);
} }
/* FALLTHROUGH */
case EEOP_FUNCEXPR:
{
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
LLVMValueRef v_fcinfo_isnull;
LLVMValueRef v_retval;
v_retval = BuildV1Call(context, b, mod, fcinfo, v_retval = BuildV1Call(context, b, mod, fcinfo,
&v_fcinfo_isnull); &v_fcinfo_isnull);
...@@ -657,24 +642,14 @@ llvm_compile_expr(ExprState *state) ...@@ -657,24 +642,14 @@ llvm_compile_expr(ExprState *state)
LLVMBuildBr(b, opblocks[opno + 1]); LLVMBuildBr(b, opblocks[opno + 1]);
break; break;
case EEOP_BOOL_AND_STEP_FIRST:
{
LLVMValueRef v_boolanynullp;
v_boolanynullp = l_ptr_const(op->d.boolexpr.anynull,
l_ptr(TypeStorageBool));
LLVMBuildStore(b, l_sbool_const(0), v_boolanynullp);
}
/* FALLTHROUGH */
/* /*
* Treat them the same for now, optimizer can remove * Treat them the same for now, optimizer can remove
* redundancy. Could be worthwhile to optimize during emission * redundancy. Could be worthwhile to optimize during emission
* though. * though.
*/ */
case EEOP_BOOL_AND_STEP_LAST: case EEOP_BOOL_AND_STEP_FIRST:
case EEOP_BOOL_AND_STEP: case EEOP_BOOL_AND_STEP:
case EEOP_BOOL_AND_STEP_LAST:
{ {
LLVMValueRef v_boolvalue; LLVMValueRef v_boolvalue;
LLVMValueRef v_boolnull; LLVMValueRef v_boolnull;
...@@ -700,6 +675,9 @@ llvm_compile_expr(ExprState *state) ...@@ -700,6 +675,9 @@ llvm_compile_expr(ExprState *state)
v_boolanynullp = l_ptr_const(op->d.boolexpr.anynull, v_boolanynullp = l_ptr_const(op->d.boolexpr.anynull,
l_ptr(TypeStorageBool)); l_ptr(TypeStorageBool));
if (opcode == EEOP_BOOL_AND_STEP_FIRST)
LLVMBuildStore(b, l_sbool_const(0), v_boolanynullp);
v_boolnull = LLVMBuildLoad(b, v_resnullp, ""); v_boolnull = LLVMBuildLoad(b, v_resnullp, "");
v_boolvalue = LLVMBuildLoad(b, v_resvaluep, ""); v_boolvalue = LLVMBuildLoad(b, v_resvaluep, "");
...@@ -759,23 +737,15 @@ llvm_compile_expr(ExprState *state) ...@@ -759,23 +737,15 @@ llvm_compile_expr(ExprState *state)
LLVMBuildBr(b, opblocks[opno + 1]); LLVMBuildBr(b, opblocks[opno + 1]);
break; break;
} }
case EEOP_BOOL_OR_STEP_FIRST:
{
LLVMValueRef v_boolanynullp;
v_boolanynullp = l_ptr_const(op->d.boolexpr.anynull,
l_ptr(TypeStorageBool));
LLVMBuildStore(b, l_sbool_const(0), v_boolanynullp);
}
/* FALLTHROUGH */
/* /*
* Treat them the same for now, optimizer can remove * Treat them the same for now, optimizer can remove
* redundancy. Could be worthwhile to optimize during emission * redundancy. Could be worthwhile to optimize during emission
* though. * though.
*/ */
case EEOP_BOOL_OR_STEP_LAST: case EEOP_BOOL_OR_STEP_FIRST:
case EEOP_BOOL_OR_STEP: case EEOP_BOOL_OR_STEP:
case EEOP_BOOL_OR_STEP_LAST:
{ {
LLVMValueRef v_boolvalue; LLVMValueRef v_boolvalue;
LLVMValueRef v_boolnull; LLVMValueRef v_boolnull;
...@@ -802,6 +772,8 @@ llvm_compile_expr(ExprState *state) ...@@ -802,6 +772,8 @@ llvm_compile_expr(ExprState *state)
v_boolanynullp = l_ptr_const(op->d.boolexpr.anynull, v_boolanynullp = l_ptr_const(op->d.boolexpr.anynull,
l_ptr(TypeStorageBool)); l_ptr(TypeStorageBool));
if (opcode == EEOP_BOOL_OR_STEP_FIRST)
LLVMBuildStore(b, l_sbool_const(0), v_boolanynullp);
v_boolnull = LLVMBuildLoad(b, v_resnullp, ""); v_boolnull = LLVMBuildLoad(b, v_resnullp, "");
v_boolvalue = LLVMBuildLoad(b, v_resvaluep, ""); v_boolvalue = LLVMBuildLoad(b, v_resvaluep, "");
...@@ -1958,8 +1930,18 @@ llvm_compile_expr(ExprState *state) ...@@ -1958,8 +1930,18 @@ llvm_compile_expr(ExprState *state)
break; break;
case EEOP_AGG_STRICT_DESERIALIZE: case EEOP_AGG_STRICT_DESERIALIZE:
case EEOP_AGG_DESERIALIZE:
{ {
AggState *aggstate;
FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data; FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
LLVMValueRef v_retval;
LLVMValueRef v_fcinfo_isnull;
LLVMValueRef v_tmpcontext;
LLVMValueRef v_oldcontext;
if (opcode == EEOP_AGG_STRICT_DESERIALIZE)
{
LLVMValueRef v_fcinfo; LLVMValueRef v_fcinfo;
LLVMValueRef v_argnull0; LLVMValueRef v_argnull0;
LLVMBasicBlockRef b_deserialize; LLVMBasicBlockRef b_deserialize;
...@@ -1981,17 +1963,6 @@ llvm_compile_expr(ExprState *state) ...@@ -1981,17 +1963,6 @@ llvm_compile_expr(ExprState *state)
b_deserialize); b_deserialize);
LLVMPositionBuilderAtEnd(b, b_deserialize); LLVMPositionBuilderAtEnd(b, b_deserialize);
} }
/* FALLTHROUGH */
case EEOP_AGG_DESERIALIZE:
{
AggState *aggstate;
FunctionCallInfo fcinfo;
LLVMValueRef v_retval;
LLVMValueRef v_fcinfo_isnull;
LLVMValueRef v_tmpcontext;
LLVMValueRef v_oldcontext;
aggstate = castNode(AggState, state->parent); aggstate = castNode(AggState, state->parent);
fcinfo = op->d.agg_deserialize.fcinfo_data; fcinfo = op->d.agg_deserialize.fcinfo_data;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment