aboutsummaryrefslogtreecommitdiff
path: root/src/backend/jit/llvm/llvmjit_expr.c
diff options
context:
space:
mode:
authorAndres Freund <andres@anarazel.de>2020-02-06 19:45:45 -0800
committerAndres Freund <andres@anarazel.de>2020-02-06 20:01:23 -0800
commite6f86f8dd9835b18890fd8e9868884dec37e3bd7 (patch)
treed927b2e70f70be06288371ca53de6a95d1f92713 /src/backend/jit/llvm/llvmjit_expr.c
parent8c2769405ff1f4617b0d3af50760b1ee357733ef (diff)
downloadpostgresql-e6f86f8dd9835b18890fd8e9868884dec37e3bd7.tar.gz
postgresql-e6f86f8dd9835b18890fd8e9868884dec37e3bd7.zip
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
Diffstat (limited to 'src/backend/jit/llvm/llvmjit_expr.c')
-rw-r--r--src/backend/jit/llvm/llvmjit_expr.c277
1 files changed, 124 insertions, 153 deletions
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index cd9d8c1c760..44a221b9a3a 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -471,6 +471,7 @@ llvm_compile_expr(ExprState *state)
}
case EEOP_ASSIGN_TMP:
+ case EEOP_ASSIGN_TMP_MAKE_RO:
{
LLVMValueRef v_value,
v_isnull;
@@ -490,59 +491,40 @@ llvm_compile_expr(ExprState *state)
v_risnullp =
LLVMBuildGEP(b, v_resultnulls, &v_resultnum, 1, "");
- /* and store */
- LLVMBuildStore(b, v_value, v_rvaluep);
+ /* store nullness */
LLVMBuildStore(b, v_isnull, v_risnullp);
- LLVMBuildBr(b, opblocks[opno + 1]);
- break;
- }
-
- case EEOP_ASSIGN_TMP_MAKE_RO:
- {
- LLVMBasicBlockRef b_notnull;
- 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],
- "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, "");
+ /* make value readonly if necessary */
+ if (opcode == EEOP_ASSIGN_TMP_MAKE_RO)
+ {
+ LLVMBasicBlockRef b_notnull;
+ LLVMValueRef v_params[1];
- /* store nullness */
- LLVMBuildStore(b, v_isnull, v_risnullp);
+ b_notnull = l_bb_before_v(opblocks[opno + 1],
+ "op.%d.assign_tmp.notnull", opno);
- /* check if value is NULL */
- LLVMBuildCondBr(b,
- LLVMBuildICmp(b, LLVMIntEQ, v_isnull,
- l_sbool_const(0), ""),
- b_notnull, opblocks[opno + 1]);
+ /* check if value is NULL */
+ LLVMBuildCondBr(b,
+ LLVMBuildICmp(b, LLVMIntEQ, v_isnull,
+ l_sbool_const(0), ""),
+ b_notnull, opblocks[opno + 1]);
+
+ /* if value is not null, convert to RO datum */
+ LLVMPositionBuilderAtEnd(b, b_notnull);
+ v_params[0] = v_value;
+ v_value =
+ LLVMBuildCall(b,
+ llvm_get_decl(mod, FuncMakeExpandedObjectReadOnlyInternal),
+ v_params, lengthof(v_params), "");
- /* if value is not null, convert to RO datum */
- LLVMPositionBuilderAtEnd(b, b_notnull);
- v_params[0] = v_value;
- v_ret =
- LLVMBuildCall(b,
- llvm_get_decl(mod, FuncMakeExpandedObjectReadOnlyInternal),
- v_params, lengthof(v_params), "");
+ /*
+ * Falling out of the if () with builder in b_notnull,
+ * which is fine - the null is already stored above.
+ */
+ }
- /* store value */
- LLVMBuildStore(b, v_ret, v_rvaluep);
+ /* and finally store result */
+ LLVMBuildStore(b, v_value, v_rvaluep);
LLVMBuildBr(b, opblocks[opno + 1]);
break;
@@ -563,78 +545,81 @@ llvm_compile_expr(ExprState *state)
break;
}
+ case EEOP_FUNCEXPR:
case EEOP_FUNCEXPR_STRICT:
{
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
- LLVMBasicBlockRef b_nonull;
- LLVMValueRef v_fcinfo;
- LLVMBasicBlockRef *b_checkargnulls;
-
- /*
- * Block for the actual function call, if args are
- * non-NULL.
- */
- b_nonull = l_bb_before_v(opblocks[opno + 1],
- "b.%d.no-null-args", opno);
+ LLVMValueRef v_fcinfo_isnull;
+ LLVMValueRef v_retval;
- /* should make sure they're optimized beforehand */
- if (op->d.func.nargs == 0)
- elog(ERROR, "argumentless strict functions are pointless");
+ if (opcode == EEOP_FUNCEXPR_STRICT)
+ {
+ LLVMBasicBlockRef b_nonull;
+ LLVMBasicBlockRef *b_checkargnulls;
+ LLVMValueRef v_fcinfo;
- v_fcinfo =
- l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
+ /*
+ * Block for the actual function call, if args are
+ * non-NULL.
+ */
+ b_nonull = l_bb_before_v(opblocks[opno + 1],
+ "b.%d.no-null-args", opno);
- /*
- * set resnull to true, if the function is actually
- * called, it'll be reset
- */
- LLVMBuildStore(b, l_sbool_const(1), v_resnullp);
+ /* should make sure they're optimized beforehand */
+ if (op->d.func.nargs == 0)
+ elog(ERROR, "argumentless strict functions are pointless");
- /* create blocks for checking args, one for each */
- b_checkargnulls =
- palloc(sizeof(LLVMBasicBlockRef *) * op->d.func.nargs);
- for (int argno = 0; argno < op->d.func.nargs; argno++)
- b_checkargnulls[argno] =
- l_bb_before_v(b_nonull, "b.%d.isnull.%d", opno, argno);
+ v_fcinfo =
+ l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
- /* jump to check of first argument */
- LLVMBuildBr(b, b_checkargnulls[0]);
+ /*
+ * set resnull to true, if the function is actually
+ * called, it'll be reset
+ */
+ LLVMBuildStore(b, l_sbool_const(1), v_resnullp);
- /* check each arg for NULLness */
- for (int argno = 0; argno < op->d.func.nargs; argno++)
- {
- LLVMValueRef v_argisnull;
- LLVMBasicBlockRef b_argnotnull;
+ /* create blocks for checking args, one for each */
+ b_checkargnulls =
+ palloc(sizeof(LLVMBasicBlockRef *) * op->d.func.nargs);
+ for (int argno = 0; argno < op->d.func.nargs; argno++)
+ b_checkargnulls[argno] =
+ l_bb_before_v(b_nonull, "b.%d.isnull.%d", opno,
+ argno);
- LLVMPositionBuilderAtEnd(b, b_checkargnulls[argno]);
+ /* jump to check of first argument */
+ LLVMBuildBr(b, b_checkargnulls[0]);
- /* compute block to jump to if argument is not null */
- if (argno + 1 == op->d.func.nargs)
- b_argnotnull = b_nonull;
- else
- b_argnotnull = b_checkargnulls[argno + 1];
+ /* check each arg for NULLness */
+ for (int argno = 0; argno < op->d.func.nargs; argno++)
+ {
+ LLVMValueRef v_argisnull;
+ LLVMBasicBlockRef b_argnotnull;
+
+ LLVMPositionBuilderAtEnd(b, b_checkargnulls[argno]);
+
+ /*
+ * Compute block to jump to if argument is not
+ * null.
+ */
+ if (argno + 1 == op->d.func.nargs)
+ b_argnotnull = b_nonull;
+ else
+ b_argnotnull = b_checkargnulls[argno + 1];
+
+ /* and finally load & check NULLness of arg */
+ v_argisnull = l_funcnull(b, v_fcinfo, argno);
+ LLVMBuildCondBr(b,
+ LLVMBuildICmp(b, LLVMIntEQ,
+ v_argisnull,
+ l_sbool_const(1),
+ ""),
+ opblocks[opno + 1],
+ b_argnotnull);
+ }
- /* and finally load & check NULLness of arg */
- v_argisnull = l_funcnull(b, v_fcinfo, argno);
- LLVMBuildCondBr(b,
- LLVMBuildICmp(b, LLVMIntEQ,
- v_argisnull,
- l_sbool_const(1),
- ""),
- opblocks[opno + 1],
- b_argnotnull);
+ 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_fcinfo_isnull);
LLVMBuildStore(b, v_retval, v_resvaluep);
@@ -657,24 +642,14 @@ llvm_compile_expr(ExprState *state)
LLVMBuildBr(b, opblocks[opno + 1]);
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
* redundancy. Could be worthwhile to optimize during emission
* though.
*/
- case EEOP_BOOL_AND_STEP_LAST:
+ case EEOP_BOOL_AND_STEP_FIRST:
case EEOP_BOOL_AND_STEP:
+ case EEOP_BOOL_AND_STEP_LAST:
{
LLVMValueRef v_boolvalue;
LLVMValueRef v_boolnull;
@@ -700,6 +675,9 @@ llvm_compile_expr(ExprState *state)
v_boolanynullp = l_ptr_const(op->d.boolexpr.anynull,
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_boolvalue = LLVMBuildLoad(b, v_resvaluep, "");
@@ -759,23 +737,15 @@ llvm_compile_expr(ExprState *state)
LLVMBuildBr(b, opblocks[opno + 1]);
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
* redundancy. Could be worthwhile to optimize during emission
* though.
*/
- case EEOP_BOOL_OR_STEP_LAST:
+ case EEOP_BOOL_OR_STEP_FIRST:
case EEOP_BOOL_OR_STEP:
+ case EEOP_BOOL_OR_STEP_LAST:
{
LLVMValueRef v_boolvalue;
LLVMValueRef v_boolnull;
@@ -802,6 +772,8 @@ llvm_compile_expr(ExprState *state)
v_boolanynullp = l_ptr_const(op->d.boolexpr.anynull,
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_boolvalue = LLVMBuildLoad(b, v_resvaluep, "");
@@ -1958,41 +1930,40 @@ llvm_compile_expr(ExprState *state)
break;
case EEOP_AGG_STRICT_DESERIALIZE:
- {
- FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
- LLVMValueRef v_fcinfo;
- LLVMValueRef v_argnull0;
- LLVMBasicBlockRef b_deserialize;
-
- b_deserialize = l_bb_before_v(opblocks[opno + 1],
- "op.%d.deserialize", opno);
-
- v_fcinfo = l_ptr_const(fcinfo,
- l_ptr(StructFunctionCallInfoData));
- v_argnull0 = l_funcnull(b, v_fcinfo, 0);
-
- LLVMBuildCondBr(b,
- LLVMBuildICmp(b,
- LLVMIntEQ,
- v_argnull0,
- l_sbool_const(1),
- ""),
- opblocks[op->d.agg_deserialize.jumpnull],
- b_deserialize);
- LLVMPositionBuilderAtEnd(b, b_deserialize);
- }
- /* FALLTHROUGH */
-
case EEOP_AGG_DESERIALIZE:
{
AggState *aggstate;
- FunctionCallInfo fcinfo;
+ 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_argnull0;
+ LLVMBasicBlockRef b_deserialize;
+
+ b_deserialize = l_bb_before_v(opblocks[opno + 1],
+ "op.%d.deserialize", opno);
+
+ v_fcinfo = l_ptr_const(fcinfo,
+ l_ptr(StructFunctionCallInfoData));
+ v_argnull0 = l_funcnull(b, v_fcinfo, 0);
+
+ LLVMBuildCondBr(b,
+ LLVMBuildICmp(b,
+ LLVMIntEQ,
+ v_argnull0,
+ l_sbool_const(1),
+ ""),
+ opblocks[op->d.agg_deserialize.jumpnull],
+ b_deserialize);
+ LLVMPositionBuilderAtEnd(b, b_deserialize);
+ }
+
aggstate = castNode(AggState, state->parent);
fcinfo = op->d.agg_deserialize.fcinfo_data;