| 867 | } |
| 868 | |
| 869 | Status LlvmCodeGen::LoadFunction(const TFunction& fn, const string& symbol, |
| 870 | const ColumnType* return_type, const vector<ColumnType>& arg_types, |
| 871 | int num_fixed_args, bool has_varargs, llvm::Function** llvm_fn, |
| 872 | LibCacheEntry** cache_entry) { |
| 873 | DCHECK_GE(arg_types.size(), num_fixed_args); |
| 874 | DCHECK(has_varargs || arg_types.size() == num_fixed_args); |
| 875 | DCHECK(!has_varargs || arg_types.size() > num_fixed_args); |
| 876 | // from_utc_timestamp() and to_utc_timestamp() have inline ASM that cannot be JIT'd. |
| 877 | // TimestampFunctions::AddSub() contains a try/catch which doesn't work in JIT'd |
| 878 | // code. Always use the interpreted version of these functions. |
| 879 | // TODO: fix these built-in functions so we don't need 'broken_builtin' below. |
| 880 | bool broken_builtin = fn.name.function_name == "from_utc_timestamp" |
| 881 | || fn.name.function_name == "to_utc_timestamp" |
| 882 | || symbol.find("AddSub") != string::npos; |
| 883 | if (fn.binary_type == TFunctionBinaryType::NATIVE |
| 884 | || (fn.binary_type == TFunctionBinaryType::BUILTIN && broken_builtin)) { |
| 885 | // In this path, we are calling a precompiled native function, either a UDF |
| 886 | // in a .so or a builtin using the UDF interface. |
| 887 | void* fn_ptr; |
| 888 | Status status = LibCache::instance()->GetSoFunctionPtr( |
| 889 | fn.hdfs_location, symbol, fn.last_modified_time, &fn_ptr, cache_entry); |
| 890 | if (!status.ok() && fn.binary_type == TFunctionBinaryType::BUILTIN) { |
| 891 | // Builtins symbols should exist unless there is a version mismatch. |
| 892 | status.AddDetail( |
| 893 | ErrorMsg(TErrorCode::MISSING_BUILTIN, fn.name.function_name, symbol).msg()); |
| 894 | } |
| 895 | RETURN_IF_ERROR(status); |
| 896 | DCHECK(fn_ptr != NULL); |
| 897 | |
| 898 | // Per the x64 ABI, DecimalVals are returned via a DecimalVal* output argument. |
| 899 | // So, the return type is void. |
| 900 | bool is_decimal = return_type != NULL && return_type->type == TYPE_DECIMAL; |
| 901 | llvm::Type* llvm_return_type = return_type == NULL || is_decimal ? |
| 902 | void_type() : |
| 903 | CodegenAnyVal::GetLoweredType(this, *return_type); |
| 904 | |
| 905 | // Convert UDF function pointer to Function*. Start by creating a function |
| 906 | // prototype for it. |
| 907 | FnPrototype prototype(this, symbol, llvm_return_type); |
| 908 | |
| 909 | if (is_decimal) { |
| 910 | // Per the x64 ABI, DecimalVals are returned via a DecmialVal* output argument |
| 911 | llvm::Type* output_type = CodegenAnyVal::GetUnloweredPtrType(this, *return_type); |
| 912 | prototype.AddArgument("output", output_type); |
| 913 | } |
| 914 | |
| 915 | // The "FunctionContext*" argument. |
| 916 | prototype.AddArgument("ctx", GetNamedPtrType("class.impala_udf::FunctionContext")); |
| 917 | |
| 918 | // The "fixed" arguments for the UDF function, followed by the variable arguments, |
| 919 | // if any. |
| 920 | for (int i = 0; i < num_fixed_args; ++i) { |
| 921 | llvm::Type* arg_type = CodegenAnyVal::GetUnloweredPtrType(this, arg_types[i]); |
| 922 | prototype.AddArgument(Substitute("fixed_arg_$0", i), arg_type); |
| 923 | } |
| 924 | |
| 925 | if (has_varargs) { |
| 926 | prototype.AddArgument("num_var_arg", i32_type()); |
no test coverage detected