diff options
Diffstat (limited to 'src/backend/jit/llvm/llvmjit_expr.c')
-rw-r--r-- | src/backend/jit/llvm/llvmjit_expr.c | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c index 27f94f90070..48ccdb942a2 100644 --- a/src/backend/jit/llvm/llvmjit_expr.c +++ b/src/backend/jit/llvm/llvmjit_expr.c @@ -1900,6 +1900,210 @@ llvm_compile_expr(ExprState *state) LLVMBuildBr(b, opblocks[opno + 1]); break; + case EEOP_HASHDATUM_SET_INITVAL: + { + LLVMValueRef v_initvalue; + + v_initvalue = l_sizet_const(op->d.hashdatum_initvalue.init_value); + + LLVMBuildStore(b, v_initvalue, v_resvaluep); + LLVMBuildStore(b, l_sbool_const(0), v_resnullp); + LLVMBuildBr(b, opblocks[opno + 1]); + break; + } + + case EEOP_HASHDATUM_FIRST: + case EEOP_HASHDATUM_FIRST_STRICT: + case EEOP_HASHDATUM_NEXT32: + case EEOP_HASHDATUM_NEXT32_STRICT: + { + FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data; + LLVMValueRef v_fcinfo; + LLVMValueRef v_fcinfo_isnull; + LLVMValueRef v_retval; + LLVMBasicBlockRef b_checkargnull; + LLVMBasicBlockRef b_ifnotnull; + LLVMBasicBlockRef b_ifnullblock; + LLVMValueRef v_argisnull; + LLVMValueRef v_prevhash = NULL; + + /* + * When performing the next hash and not in strict mode we + * perform a rotation of the previously stored hash value + * before doing the NULL check. We want to do this even + * when we receive a NULL Datum to hash. In strict mode, + * we do this after the NULL check so as not to waste the + * effort of rotating the bits when we're going to throw + * away the hash value and return NULL. + */ + if (opcode == EEOP_HASHDATUM_NEXT32) + { + LLVMValueRef v_tmp1; + LLVMValueRef v_tmp2; + + /* + * Fetch the previously hashed value from where the + * EEOP_HASHDATUM_FIRST operation stored it. + */ + v_prevhash = l_load(b, TypeSizeT, v_resvaluep, + "prevhash"); + + /* + * Rotate bits left by 1 bit. Be careful not to + * overflow uint32 when working with size_t. + */ + v_tmp1 = LLVMBuildShl(b, v_prevhash, l_sizet_const(1), + ""); + v_tmp1 = LLVMBuildAnd(b, v_tmp1, + l_sizet_const(0xffffffff), ""); + v_tmp2 = LLVMBuildLShr(b, v_prevhash, + l_sizet_const(31), ""); + v_prevhash = LLVMBuildOr(b, v_tmp1, v_tmp2, + "rotatedhash"); + } + + /* + * Block for the actual function call, if args are + * non-NULL. + */ + b_ifnotnull = l_bb_before_v(opblocks[opno + 1], + "b.%d.ifnotnull", + opno); + + /* we expect the hash function to have 1 argument */ + if (fcinfo->nargs != 1) + elog(ERROR, "incorrect number of function arguments"); + + v_fcinfo = l_ptr_const(fcinfo, + l_ptr(StructFunctionCallInfoData)); + + b_checkargnull = l_bb_before_v(b_ifnotnull, + "b.%d.isnull.0", opno); + + LLVMBuildBr(b, b_checkargnull); + + /* + * Determine what to do if we find the argument to be + * NULL. + */ + if (opcode == EEOP_HASHDATUM_FIRST_STRICT || + opcode == EEOP_HASHDATUM_NEXT32_STRICT) + { + b_ifnullblock = l_bb_before_v(b_ifnotnull, + "b.%d.strictnull", + opno); + + LLVMPositionBuilderAtEnd(b, b_ifnullblock); + + /* + * In strict node, NULL inputs result in NULL. Save + * the NULL result and goto jumpdone. + */ + LLVMBuildStore(b, l_sbool_const(1), v_resnullp); + LLVMBuildStore(b, l_sizet_const(0), v_resvaluep); + LLVMBuildBr(b, opblocks[op->d.hashdatum.jumpdone]); + } + else + { + b_ifnullblock = l_bb_before_v(b_ifnotnull, + "b.%d.null", + opno); + + LLVMPositionBuilderAtEnd(b, b_ifnullblock); + + + LLVMBuildStore(b, l_sbool_const(0), v_resnullp); + + if (opcode == EEOP_HASHDATUM_NEXT32) + { + Assert(v_prevhash != NULL); + + /* + * Save the rotated hash value and skip to the + * next op. + */ + LLVMBuildStore(b, v_prevhash, v_resvaluep); + } + else + { + Assert(opcode == EEOP_HASHDATUM_FIRST); + + /* + * Store a zero Datum when the Datum to hash is + * NULL + */ + LLVMBuildStore(b, l_sizet_const(0), v_resvaluep); + } + + LLVMBuildBr(b, opblocks[opno + 1]); + } + + LLVMPositionBuilderAtEnd(b, b_checkargnull); + + /* emit code to check if the input parameter is NULL */ + v_argisnull = l_funcnull(b, v_fcinfo, 0); + LLVMBuildCondBr(b, + LLVMBuildICmp(b, + LLVMIntEQ, + v_argisnull, + l_sbool_const(1), + ""), + b_ifnullblock, + b_ifnotnull); + + LLVMPositionBuilderAtEnd(b, b_ifnotnull); + + /* + * Rotate the previously stored hash value when performing + * NEXT32 in strict mode. In non-strict mode we already + * did this before checking for NULLs. + */ + if (opcode == EEOP_HASHDATUM_NEXT32_STRICT) + { + LLVMValueRef v_tmp1; + LLVMValueRef v_tmp2; + + /* + * Fetch the previously hashed value from where the + * EEOP_HASHDATUM_FIRST_STRICT operation stored it. + */ + v_prevhash = l_load(b, TypeSizeT, v_resvaluep, + "prevhash"); + + /* + * Rotate bits left by 1 bit. Be careful not to + * overflow uint32 when working with size_t. + */ + v_tmp1 = LLVMBuildShl(b, v_prevhash, l_sizet_const(1), + ""); + v_tmp1 = LLVMBuildAnd(b, v_tmp1, + l_sizet_const(0xffffffff), ""); + v_tmp2 = LLVMBuildLShr(b, v_prevhash, + l_sizet_const(31), ""); + v_prevhash = LLVMBuildOr(b, v_tmp1, v_tmp2, + "rotatedhash"); + } + + /* call the hash function */ + v_retval = BuildV1Call(context, b, mod, fcinfo, + &v_fcinfo_isnull); + + /* + * For NEXT32 ops, XOR (^) the returned hash value with + * the existing hash value. + */ + if (opcode == EEOP_HASHDATUM_NEXT32 || + opcode == EEOP_HASHDATUM_NEXT32_STRICT) + v_retval = LLVMBuildXor(b, v_prevhash, v_retval, + "xorhash"); + + LLVMBuildStore(b, v_retval, v_resvaluep); + LLVMBuildStore(b, l_sbool_const(0), v_resnullp); + + LLVMBuildBr(b, opblocks[opno + 1]); + break; + } + case EEOP_CONVERT_ROWTYPE: build_EvalXFunc(b, mod, "ExecEvalConvertRowtype", v_state, op, v_econtext); |