From 969ed722f3e199e17aae8e44345df3cec6704cec Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 17 Aug 2015 01:00:05 -0400 Subject: [PATCH] precompile cfunction calls. fixes #12256 --- src/ccall.cpp | 39 +++++++++++++++++++++++++++++++++++++ src/codegen.cpp | 52 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index 60a3117e4f609..76cdd15cd151b 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -1172,6 +1172,7 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) if (fptr == (void *) &jl_is_leaf_type || ((f_lib==NULL || (intptr_t)f_lib==2) && f_name && !strcmp(f_name, "jl_is_leaf_type"))) { + assert(nargt == 1); jl_value_t *arg = args[4]; jl_value_t *ty = expr_type(arg, ctx); if (jl_is_type_type(ty) && !jl_is_typevar(jl_tparam0(ty))) { @@ -1180,6 +1181,44 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) return ConstantInt::get(T_int32, isleaf); } } + if (fptr == (void*)&jl_function_ptr || + ((f_lib==NULL || (intptr_t)f_lib==2) + && f_name && !strcmp(f_name, "jl_function_ptr"))) { + assert(nargt == 3); + jl_value_t *f = static_eval(args[4], ctx, false, false); + jl_value_t *frt = expr_type(args[6], ctx); + if (f && jl_is_function(f) && + (jl_is_type_type((jl_value_t*)frt) && !jl_has_typevars(jl_tparam0(frt)))) { + jl_value_t *fargt = static_eval(args[8], ctx, true, true); + if (fargt) { + if (jl_is_tuple(fargt)) { + // TODO: maybe deprecation warning, better checking + fargt = (jl_value_t*)jl_apply_tuple_type_v((jl_value_t**)jl_data_ptr(fargt), jl_nfields(fargt)); + } + } + else { + fargt = expr_type(args[8], ctx); + if (jl_is_type_type((jl_value_t*)fargt)) + fargt = jl_tparam0(fargt); + } + if (jl_is_tuple_type(fargt) && jl_is_leaf_type(fargt)) { + frt = jl_tparam0(frt); + JL_TRY { + Value *llvmf = prepare_call( + jl_cfunction_object((jl_function_t*)f, frt, (jl_tupletype_t*)fargt)); + // make sure to emit any side-effects that may have been part of the original expression + emit_expr(args[4], ctx); + emit_expr(args[6], ctx); + emit_expr(args[8], ctx); + JL_GC_POP(); + return mark_or_box_ccall_result(builder.CreateBitCast(llvmf, lrt), + args[2], rt, static_rt, ctx); + } + JL_CATCH { + } + } + } + } // save place before arguments, for possible insertion of temp arg // area saving code. diff --git a/src/codegen.cpp b/src/codegen.cpp index 9f3901f42ad2e..bdc2633b2f9e2 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -894,17 +894,6 @@ void *jl_function_ptr(jl_function_t *f, jl_value_t *rt, jl_value_t *argt) assert(llvmf); JL_GC_POP(); #ifdef USE_MCJIT - if (imaging_mode) { - // Copy the function out of the shadow module, unless this was done before - void *addr = (void*)(intptr_t)jl_ExecutionEngine->getFunctionAddress(llvmf->getName()); - if (addr != nullptr) { - return addr; - } - Module *m = new Module("julia", jl_LLVMContext); - jl_setup_module(m, true); - FunctionMover mover(m, shadow_module); - llvmf = mover.CloneFunction(llvmf); - } return (void*)(intptr_t)jl_ExecutionEngine->getFunctionAddress(llvmf->getName()); #else return jl_ExecutionEngine->getPointerToFunction(llvmf); @@ -3562,9 +3551,22 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t if (fargt.size() != fargt_sig.size()) jl_error("va_arg syntax not allowed for cfunction argument list"); + jl_compile(ff); + if (!lam->functionObject) { + jl_errorf("error compiling %s while creating cfunction", lam->name->name); + } + std::stringstream funcName; funcName << "jlcapi_" << lam->name->name << "_" << globalUnique++; + // Backup the info for the nested compile + JL_SIGATOMIC_BEGIN(); // no errors expected beyond this point + BasicBlock *old = nested_compile ? builder.GetInsertBlock() : NULL; + DebugLoc olddl = builder.getCurrentDebugLocation(); + bool last_n_c = nested_compile; + nested_compile = true; + jl_gc_inhibit_finalizers(nested_compile); // no allocations expected between the top of this function (when last scanned lam->cFunctionList) and here, which might have triggered running julia code + // Create the Function stub Module *m; #ifdef USE_MCJIT @@ -3604,7 +3606,6 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t lam->cFunctionList = list2; // See whether this function is specsig or jlcall - jl_compile(ff); bool specsig; Function *theFptr; if (lam->specFunctionObject != NULL) { @@ -3614,10 +3615,8 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t else { theFptr = (Function*)lam->functionObject; specsig = false; - if (!theFptr) { - jl_errorf("error compiling %s while creating cfunction", lam->name->name); - } } + assert(theFptr); // Alright, let's do this! // let's first emit the arguments @@ -3739,6 +3738,29 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t } #endif +#ifdef USE_MCJIT + if (imaging_mode) { + // Copy the function out of the shadow module + Module *m = new Module("julia", jl_LLVMContext); + jl_setup_module(m, true); + FunctionMover mover(m, shadow_module); + Function *clone = mover.CloneFunction(cw); + FPM->run(*clone); + } + else { + FPM->run(*cw); + } +#endif + + // Restore the previous compile context + if (old != NULL) { + builder.SetInsertPoint(old); + builder.SetCurrentDebugLocation(olddl); + } + nested_compile = last_n_c; + jl_gc_inhibit_finalizers(nested_compile); + JL_SIGATOMIC_END(); + return cw; }