From 47986fadf6d70dfecc856fc8c2fe14902fcacfaf Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Sun, 3 Sep 2017 15:02:07 -0400 Subject: [PATCH 1/3] Add a codegen param for preferring specsig. --- base/reflection.jl | 5 +++-- src/cgutils.cpp | 1 + src/codegen.cpp | 6 ++++-- src/jltypes.c | 2 +- src/julia.h | 1 + 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/base/reflection.jl b/base/reflection.jl index 50e26e1cc040c..f5f1979ebb72c 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -745,6 +745,7 @@ struct CodegenParams code_coverage::Cint static_alloc::Cint dynamic_alloc::Cint + prefer_specsig::Cint hooks::CodegenHooks @@ -752,12 +753,12 @@ struct CodegenParams runtime::Bool=true, exceptions::Bool=true, track_allocations::Bool=true, code_coverage::Bool=true, static_alloc::Bool=true, dynamic_alloc::Bool=true, - hooks::CodegenHooks=CodegenHooks()) = + prefer_specsig::Bool=false, hooks::CodegenHooks=CodegenHooks()) = new(Cint(cached), Cint(runtime), Cint(exceptions), Cint(track_allocations), Cint(code_coverage), Cint(static_alloc), Cint(dynamic_alloc), - hooks) + Cint(prefer_specsig), hooks) end # Printing code representations in IR and assembly diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 13ecf39ff4bc3..e0ca56dee5066 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -2355,6 +2355,7 @@ static int compare_cgparams(const jl_cgparams_t *a, const jl_cgparams_t *b) (a->code_coverage == b->code_coverage) && (a->static_alloc == b->static_alloc) && (a->dynamic_alloc == b->dynamic_alloc) && + (a->prefer_specsig == b->prefer_specsig) && // hooks (a->hooks.module_setup == b->hooks.module_setup) && (a->hooks.module_activation == b->hooks.module_activation) && diff --git a/src/codegen.cpp b/src/codegen.cpp index 96483a28f9dfc..f30113dfb4312 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4596,7 +4596,7 @@ static Function *gen_jlcall_wrapper(jl_method_instance_t *lam, const jl_returnin return w; } -static bool uses_specsig(jl_value_t *sig, jl_value_t *rettype, bool needsparam, bool va, jl_code_info_t *src) +static bool uses_specsig(jl_value_t *sig, jl_value_t *rettype, bool needsparam, bool va, jl_code_info_t *src, bool prefer_specsig) { if (va || needsparam) return false; @@ -4609,6 +4609,8 @@ static bool uses_specsig(jl_value_t *sig, jl_value_t *rettype, bool needsparam, if (jl_nparams(sig) == 0) return false; // not invalid, consider if specialized signature is worthwhile + if (prefer_specsig) + return true; if (isbits_spec(rettype, false)) return true; if (jl_is_uniontype(rettype)) { @@ -4862,7 +4864,7 @@ static std::unique_ptr emit_function( } jl_value_t *jlrettype = lam->rettype; - bool specsig = uses_specsig(lam->specTypes, jlrettype, needsparams, va, src); + bool specsig = uses_specsig(lam->specTypes, jlrettype, needsparams, va, src, params->prefer_specsig); if (!specsig) ctx.nReqArgs--; // function not part of argArray in jlcall diff --git a/src/jltypes.c b/src/jltypes.c index 6218abb83a019..4b0eaedcb6b7e 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -127,7 +127,7 @@ jl_value_t *jl_memory_exception; jl_value_t *jl_readonlymemory_exception; union jl_typemap_t jl_cfunction_list; -jl_cgparams_t jl_default_cgparams = {1, 1, 1, 1, 1, 1, 1, {NULL, NULL, NULL}}; +jl_cgparams_t jl_default_cgparams = {1, 1, 1, 1, 1, 1, 1, 0, {NULL, NULL, NULL}}; // --- type properties and predicates --- diff --git a/src/julia.h b/src/julia.h index 5fda2e5415f25..af899ff85d758 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1832,6 +1832,7 @@ typedef struct { int code_coverage; // can we measure coverage (don't if disallowed)? int static_alloc; // is the compiler allowed to allocate statically? int dynamic_alloc; // is the compiler allowed to allocate dynamically (requires runtime)? + int prefer_specsig; // are specialized function signatures preferred? jl_cghooks_t hooks; } jl_cgparams_t; From 5c6f42316c84f1e59fcb830a02dece8a8610486e Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Mon, 4 Sep 2017 18:06:57 -0400 Subject: [PATCH 2/3] Embed codegen hooks in the params object. Using pointer_objref is unsafe for the GC. --- base/reflection.jl | 26 ++++++++------------------ src/cgutils.cpp | 10 +++++----- src/jltypes.c | 8 ++++---- src/julia.h | 28 ++++++++++++---------------- 4 files changed, 29 insertions(+), 43 deletions(-) diff --git a/base/reflection.jl b/base/reflection.jl index f5f1979ebb72c..f24aae7d20d87 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -723,18 +723,6 @@ function method_instances(@nospecialize(f), @nospecialize(t), world::UInt = type return results end -# this type mirrors jl_cghooks_t (documented in julia.h) -struct CodegenHooks - module_setup::Ptr{Void} - module_activation::Ptr{Void} - raise_exception::Ptr{Void} - - CodegenHooks(;module_setup=nothing, module_activation=nothing, raise_exception=nothing) = - new(pointer_from_objref(module_setup), - pointer_from_objref(module_activation), - pointer_from_objref(raise_exception)) -end - # this type mirrors jl_cgparams_t (documented in julia.h) struct CodegenParams cached::Cint @@ -747,18 +735,20 @@ struct CodegenParams dynamic_alloc::Cint prefer_specsig::Cint - hooks::CodegenHooks + module_setup::Any + module_activation::Any + raise_exception::Any CodegenParams(;cached::Bool=true, runtime::Bool=true, exceptions::Bool=true, track_allocations::Bool=true, code_coverage::Bool=true, static_alloc::Bool=true, dynamic_alloc::Bool=true, - prefer_specsig::Bool=false, hooks::CodegenHooks=CodegenHooks()) = + prefer_specsig::Bool=false, + module_setup=nothing, module_activation=nothing, raise_exception=nothing) = new(Cint(cached), - Cint(runtime), Cint(exceptions), - Cint(track_allocations), Cint(code_coverage), - Cint(static_alloc), Cint(dynamic_alloc), - Cint(prefer_specsig), hooks) + Cint(runtime), Cint(exceptions), Cint(track_allocations), Cint(code_coverage), + Cint(static_alloc), Cint(dynamic_alloc), Cint(prefer_specsig), + module_setup, module_activation, raise_exception) end # Printing code representations in IR and assembly diff --git a/src/cgutils.cpp b/src/cgutils.cpp index e0ca56dee5066..7e7d3fa5c7a64 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -109,10 +109,10 @@ static Value *mark_callee_rooted(IRBuilder<> &irbuilder, Value *V) // --- hook checks --- -#define JL_HOOK_TEST(params,hook) ((params)->hooks.hook != jl_nothing) +#define JL_HOOK_TEST(params,hook) ((params)->hook != jl_nothing) #define JL_HOOK_CALL(params,hook,argc,...) \ - _hook_call((params)->hooks.hook, {{__VA_ARGS__}}); + _hook_call((params)->hook, {{__VA_ARGS__}}); template static inline void _hook_call(jl_value_t *hook, std::array args) { jl_value_t **argv; @@ -2357,7 +2357,7 @@ static int compare_cgparams(const jl_cgparams_t *a, const jl_cgparams_t *b) (a->dynamic_alloc == b->dynamic_alloc) && (a->prefer_specsig == b->prefer_specsig) && // hooks - (a->hooks.module_setup == b->hooks.module_setup) && - (a->hooks.module_activation == b->hooks.module_activation) && - (a->hooks.raise_exception == b->hooks.raise_exception); + (a->module_setup == b->module_setup) && + (a->module_activation == b->module_activation) && + (a->raise_exception == b->raise_exception); } diff --git a/src/jltypes.c b/src/jltypes.c index 4b0eaedcb6b7e..7a7e2e4a6fe4a 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -127,7 +127,7 @@ jl_value_t *jl_memory_exception; jl_value_t *jl_readonlymemory_exception; union jl_typemap_t jl_cfunction_list; -jl_cgparams_t jl_default_cgparams = {1, 1, 1, 1, 1, 1, 1, 0, {NULL, NULL, NULL}}; +jl_cgparams_t jl_default_cgparams = {1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL}; // --- type properties and predicates --- @@ -1663,9 +1663,9 @@ void jl_init_types(void) jl_methtable_type = jl_new_uninitialized_datatype(); jl_nothing = jl_gc_permobj(0, NULL); - jl_default_cgparams.hooks.module_setup = jl_nothing; - jl_default_cgparams.hooks.module_activation = jl_nothing; - jl_default_cgparams.hooks.raise_exception = jl_nothing; + jl_default_cgparams.module_setup = jl_nothing; + jl_default_cgparams.module_activation = jl_nothing; + jl_default_cgparams.raise_exception = jl_nothing; jl_emptysvec = (jl_svec_t*)jl_gc_permobj(sizeof(void*), jl_simplevector_type); jl_svec_set_len_unsafe(jl_emptysvec, 0); diff --git a/src/julia.h b/src/julia.h index af899ff85d758..871c2cfa43ba8 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1804,7 +1804,18 @@ typedef struct { // codegen interface ---------------------------------------------------------- typedef struct { - // to disable a hook: set to NULL or nothing + int cached; // can the compiler use/populate the compilation cache? + + int runtime; // can we call into the runtime? + int exceptions; // are exceptions supported (requires runtime)? + int track_allocations; // can we track allocations (don't if disallowed)? + int code_coverage; // can we measure coverage (don't if disallowed)? + int static_alloc; // is the compiler allowed to allocate statically? + int dynamic_alloc; // is the compiler allowed to allocate dynamically (requires runtime)? + int prefer_specsig; // are specialized function signatures preferred? + + + // hooks // module setup: prepare a module for code emission (data layout, DWARF version, ...) // parameters: LLVMModuleRef as Ptr{Void} @@ -1820,21 +1831,6 @@ typedef struct { // parameters: LLVMBasicBlockRef as Ptr{Void}, LLVMValueRef as Ptr{Void} // return value: none jl_value_t *raise_exception; -} jl_cghooks_t; - -typedef struct { - int cached; // can the compiler use/populate the compilation cache? - - // language features (C-style integer booleans) - int runtime; // can we call into the runtime? - int exceptions; // are exceptions supported (requires runtime)? - int track_allocations; // can we track allocations (don't if disallowed)? - int code_coverage; // can we measure coverage (don't if disallowed)? - int static_alloc; // is the compiler allowed to allocate statically? - int dynamic_alloc; // is the compiler allowed to allocate dynamically (requires runtime)? - int prefer_specsig; // are specialized function signatures preferred? - - jl_cghooks_t hooks; } jl_cgparams_t; extern JL_DLLEXPORT jl_cgparams_t jl_default_cgparams; From c31fdea516d186aa475e3d307543146a62367e4e Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Tue, 5 Sep 2017 00:19:58 +0200 Subject: [PATCH 3/3] Remove cgparams that disallow language features. We realistically rely on LLVM optimization passes anyway. --- base/reflection.jl | 11 +++-------- src/ccall.cpp | 6 ------ src/cgutils.cpp | 13 ------------- src/codegen.cpp | 21 --------------------- src/jltypes.c | 2 +- src/julia.h | 7 ++----- 6 files changed, 6 insertions(+), 54 deletions(-) diff --git a/base/reflection.jl b/base/reflection.jl index f24aae7d20d87..bbbbe5a43eaae 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -727,12 +727,9 @@ end struct CodegenParams cached::Cint - runtime::Cint - exceptions::Cint track_allocations::Cint code_coverage::Cint static_alloc::Cint - dynamic_alloc::Cint prefer_specsig::Cint module_setup::Any @@ -740,14 +737,12 @@ struct CodegenParams raise_exception::Any CodegenParams(;cached::Bool=true, - runtime::Bool=true, exceptions::Bool=true, track_allocations::Bool=true, code_coverage::Bool=true, - static_alloc::Bool=true, dynamic_alloc::Bool=true, - prefer_specsig::Bool=false, + static_alloc::Bool=true, prefer_specsig::Bool=false, module_setup=nothing, module_activation=nothing, raise_exception=nothing) = new(Cint(cached), - Cint(runtime), Cint(exceptions), Cint(track_allocations), Cint(code_coverage), - Cint(static_alloc), Cint(dynamic_alloc), Cint(prefer_specsig), + Cint(track_allocations), Cint(code_coverage), + Cint(static_alloc), Cint(prefer_specsig), module_setup, module_activation, raise_exception) end diff --git a/src/ccall.cpp b/src/ccall.cpp index 01f622623db34..8ca42dfdec546 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -1513,12 +1513,6 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) rt = (jl_value_t*)jl_any_type; // convert return type to jl_value_t* } - // check if we require the runtime - // TODO: could be more fine-grained, - // respecting special functions below that don't require the runtime - if (!llvmcall && (!f_lib || f_lib == JL_DL_LIBNAME)) - JL_FEAT_REQUIRE(ctx, runtime); - // some sanity checking and check whether there's a vararg bool isVa; size_t nargt; diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 7e7d3fa5c7a64..d881f9e623175 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -97,15 +97,8 @@ static Value *mark_callee_rooted(IRBuilder<> &irbuilder, Value *V) // --- language feature checks --- -// branch on whether a language feature is enabled or not #define JL_FEAT_TEST(ctx, feature) ((ctx).params->feature) -// require a language feature to be enabled -#define JL_FEAT_REQUIRE(ctx, feature) \ - if (!JL_FEAT_TEST(ctx, feature)) \ - jl_errorf("%s for %s:%d requires the " #feature " language feature, which is disabled", \ - __FUNCTION__, (ctx).file.str().c_str(), *(ctx).line); - // --- hook checks --- @@ -908,7 +901,6 @@ static void raise_exception(jl_codectx_t &ctx, Value *exc, jl_box_voidpointer(wrap(ctx.builder.GetInsertBlock())), jl_box_voidpointer(wrap(exc))); } else { - JL_FEAT_REQUIRE(ctx, runtime); ctx.builder.CreateCall(prepare_call(jlthrow_func), { mark_callee_rooted(exc) }); } ctx.builder.CreateUnreachable(); @@ -2117,8 +2109,6 @@ static void emit_cpointercheck(jl_codectx_t &ctx, const jl_cgval_t &x, const std // allocation for known size object static Value *emit_allocobj(jl_codectx_t &ctx, size_t static_size, Value *jt) { - JL_FEAT_REQUIRE(ctx, dynamic_alloc); - JL_FEAT_REQUIRE(ctx, runtime); Value *ptls_ptr = emit_bitcast(ctx, ctx.ptlsStates, T_pint8); auto call = ctx.builder.CreateCall(prepare_call(jl_alloc_obj_func), {ptls_ptr, ConstantInt::get(T_size, static_size), @@ -2349,12 +2339,9 @@ static int compare_cgparams(const jl_cgparams_t *a, const jl_cgparams_t *b) { return (a->cached == b->cached) && // language features - (a->runtime == b->runtime) && - (a->exceptions == b->exceptions) && (a->track_allocations == b->track_allocations) && (a->code_coverage == b->code_coverage) && (a->static_alloc == b->static_alloc) && - (a->dynamic_alloc == b->dynamic_alloc) && (a->prefer_specsig == b->prefer_specsig) && // hooks (a->module_setup == b->module_setup) && diff --git a/src/codegen.cpp b/src/codegen.cpp index f30113dfb4312..65d44fb75d3bc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2219,7 +2219,6 @@ static Value *emit_f_is(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgva decay_derived(varg2)); } - JL_FEAT_REQUIRE(ctx, runtime); Value *varg1 = mark_callee_rooted(boxed(ctx, arg1)); Value *varg2 = mark_callee_rooted(boxed(ctx, arg2, false)); // potentially unrooted! return ctx.builder.CreateTrunc(ctx.builder.CreateCall(prepare_call(jlegal_func), {varg1, varg2}), T_int1); @@ -2264,7 +2263,6 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, if (jl_subtype(ty.typ, (jl_value_t*)jl_type_type)) { Value *rt_arg = boxed(ctx, arg); Value *rt_ty = boxed(ctx, ty); - JL_FEAT_REQUIRE(ctx, runtime); ctx.builder.CreateCall(prepare_call(jltypeassert_func), {rt_arg, rt_ty}); *ret = arg; return true; @@ -2305,7 +2303,6 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, nva = ctx.builder.CreateTrunc(nva, T_int32); #endif Value *theArgs = ctx.builder.CreateGEP(ctx.argArray, ConstantInt::get(T_size, ctx.nReqArgs)); - JL_FEAT_REQUIRE(ctx, runtime); Value *r = ctx.builder.CreateCall(prepare_call(jlapply2va_func), { theF, theArgs, nva }); *ret = mark_julia_type(ctx, r, true, jl_any_type); return true; @@ -2964,7 +2961,6 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, jl_expr_t *ex) } } } - JL_FEAT_REQUIRE(ctx, runtime); jl_cgval_t result = mark_julia_type(ctx, emit_jlcall( ctx, @@ -3016,16 +3012,6 @@ static jl_cgval_t emit_call(jl_codectx_t &ctx, jl_expr_t *ex) } } - if (!JL_FEAT_TEST(ctx, runtime)) { - char* name = NULL; - if (jl_is_symbol(args[0])) - name = jl_symbol_name((jl_sym_t*)args[0]); - if (jl_is_globalref(args[0])) - name = jl_symbol_name(jl_globalref_name(args[0])); - jl_errorf("generic call to %s requires the runtime language feature", - name ? name : ""); - } - // emit function and arguments Value *callval = emit_jlcall(ctx, jlapplygeneric_func, nullptr, argv, nargs); return mark_julia_type(ctx, callval, true, rt); @@ -3068,7 +3054,6 @@ static Value *global_binding_pointer(jl_codectx_t &ctx, jl_module_t *m, jl_sym_t b = jl_get_binding(m, s); if (b == NULL) { // var not found. switch to delayed lookup. - JL_FEAT_REQUIRE(ctx, runtime); std::stringstream name; name << "delayedvar" << globalUnique++; Constant *initnul = V_null; @@ -3438,7 +3423,6 @@ static void emit_assignment(jl_codectx_t &ctx, jl_value_t *l, jl_value_t *r) if (bp == NULL && s != NULL) bp = global_binding_pointer(ctx, ctx.module, s, &bnd, true); if (bp != NULL) { // it's a global - JL_FEAT_REQUIRE(ctx, runtime); assert(bnd); Value *rval = mark_callee_rooted(boxed(ctx, emit_expr(ctx, r), false)); // no root needed since this is about to be assigned to a global ctx.builder.CreateCall(prepare_call(jlcheckassign_func), @@ -3655,7 +3639,6 @@ static void emit_stmtpos(jl_codectx_t &ctx, jl_value_t *expr) } else if (head == leave_sym) { assert(jl_is_long(args[0])); - JL_FEAT_REQUIRE(ctx, runtime); ctx.builder.CreateCall(prepare_call(jlleave_func), ConstantInt::get(T_int32, jl_unbox_long(args[0]))); } @@ -3765,7 +3748,6 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr) else if (head == method_sym) { jl_value_t *mn = args[0]; assert(jl_expr_nargs(ex) != 1 || jl_is_symbol(mn) || jl_is_slot(mn)); - JL_FEAT_REQUIRE(ctx, runtime); Value *bp = NULL, *name, *bp_owner = V_null; jl_binding_t *bnd = NULL; @@ -3832,7 +3814,6 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr) sym = jl_globalref_name(sym); } if (jl_is_symbol(sym)) { - JL_FEAT_REQUIRE(ctx, runtime); jl_binding_t *bnd = NULL; (void)global_binding_pointer(ctx, mod, sym, &bnd, true); assert(bnd); ctx.builder.CreateCall(prepare_call(jldeclareconst_func), @@ -3862,7 +3843,6 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr) true, jl_any_type); } else if (head == copyast_sym) { - JL_FEAT_REQUIRE(ctx, runtime); jl_value_t *arg = args[0]; if (jl_is_quotenode(arg)) { jl_value_t *arg1 = jl_fieldref(arg, 0); @@ -3900,7 +3880,6 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr) jl_error("syntax: prefix \"$\" in non-quoted expression"); if (jl_is_toplevel_only_expr(expr) && !jl_is_method(ctx.linfo->def.method)) { - JL_FEAT_REQUIRE(ctx, runtime); // call interpreter to run a toplevel expr from inside a // compiled toplevel thunk. Value *args[2] = { diff --git a/src/jltypes.c b/src/jltypes.c index 7a7e2e4a6fe4a..f7e88e05a6ad6 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -127,7 +127,7 @@ jl_value_t *jl_memory_exception; jl_value_t *jl_readonlymemory_exception; union jl_typemap_t jl_cfunction_list; -jl_cgparams_t jl_default_cgparams = {1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL}; +jl_cgparams_t jl_default_cgparams = {1, 1, 1, 1, 0, NULL, NULL, NULL}; // --- type properties and predicates --- diff --git a/src/julia.h b/src/julia.h index 871c2cfa43ba8..eba6b8007a9bc 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1806,12 +1806,9 @@ typedef struct { typedef struct { int cached; // can the compiler use/populate the compilation cache? - int runtime; // can we call into the runtime? - int exceptions; // are exceptions supported (requires runtime)? - int track_allocations; // can we track allocations (don't if disallowed)? - int code_coverage; // can we measure coverage (don't if disallowed)? + int track_allocations; // can we track allocations? + int code_coverage; // can we measure coverage? int static_alloc; // is the compiler allowed to allocate statically? - int dynamic_alloc; // is the compiler allowed to allocate dynamically (requires runtime)? int prefer_specsig; // are specialized function signatures preferred?