From 60a950b1fc06695d5bb16bfefddaf7203566455b Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Thu, 20 Oct 2016 20:19:27 +0200 Subject: [PATCH] Add a codegen parameters struct as a means to influence code generation. --- base/reflection.jl | 35 +++++++++++++++++--- src/alloc.c | 2 +- src/cgutils.cpp | 16 ++++++++++ src/codegen.cpp | 76 +++++++++++++++++++++++++++++++++----------- src/gf.c | 6 ++-- src/jltypes.c | 4 +++ src/julia.h | 16 ++++++++++ src/julia_internal.h | 2 +- 8 files changed, 128 insertions(+), 29 deletions(-) diff --git a/base/reflection.jl b/base/reflection.jl index 3dcf854b15e29..ac9784bcea1ba 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -493,8 +493,31 @@ function uncompressed_ast(m::Method, s::CodeInfo) return s end +# this type mirrors jl_cgparams_t (documented in julia.h) +immutable CodegenParams + cached::Cint + + runtime::Cint + exceptions::Cint + track_allocations::Cint + code_coverage::Cint + static_alloc::Cint + dynamic_alloc::Cint + + 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) = + new(Cint(cached), + Cint(runtime), Cint(exceptions), + Cint(track_allocations), Cint(code_coverage), + Cint(static_alloc), Cint(dynamic_alloc)) +end + # Printing code representations in IR and assembly -function _dump_function(f::ANY, t::ANY, native::Bool, wrapper::Bool, strip_ir_metadata::Bool, dump_module::Bool, syntax::Symbol=:att) +function _dump_function(f::ANY, t::ANY, native::Bool, wrapper::Bool, + strip_ir_metadata::Bool, dump_module::Bool, syntax::Symbol=:att, + optimize::Bool=true, params::CodegenParams=CodegenParams()) ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions") if isa(f, Core.Builtin) throw(ArgumentError("argument is not a generic function")) @@ -509,17 +532,19 @@ function _dump_function(f::ANY, t::ANY, native::Bool, wrapper::Bool, strip_ir_me meth = func_for_method_checked(meth, tt) linfo = ccall(:jl_specializations_get_linfo, Ref{Core.MethodInstance}, (Any, Any, Any), meth, tt, env) # get the code for it - return _dump_function(linfo, native, wrapper, strip_ir_metadata, dump_module, syntax) + return _dump_function(linfo, native, wrapper, strip_ir_metadata, dump_module, syntax, optimize, params) end -function _dump_function(linfo::Core.MethodInstance, native::Bool, wrapper::Bool, strip_ir_metadata::Bool, dump_module::Bool, syntax::Symbol=:att) +function _dump_function(linfo::Core.MethodInstance, native::Bool, wrapper::Bool, + strip_ir_metadata::Bool, dump_module::Bool, syntax::Symbol=:att, + optimize::Bool=true, params::CodegenParams=CodegenParams()) if syntax != :att && syntax != :intel throw(ArgumentError("'syntax' must be either :intel or :att")) end if native - llvmf = ccall(:jl_get_llvmf_decl, Ptr{Void}, (Any, Bool), linfo, wrapper) + llvmf = ccall(:jl_get_llvmf_decl, Ptr{Void}, (Any, Bool, CodegenParams), linfo, wrapper, params) else - llvmf = ccall(:jl_get_llvmf_defn, Ptr{Void}, (Any, Bool), linfo, wrapper) + llvmf = ccall(:jl_get_llvmf_defn, Ptr{Void}, (Any, Bool, Bool, CodegenParams), linfo, wrapper, optimize, params) end if llvmf == C_NULL error("could not compile the specified method") diff --git a/src/alloc.c b/src/alloc.c index ff12b5baedeee..a768ea66243d4 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -457,7 +457,7 @@ STATIC_INLINE jl_value_t *jl_call_staged(jl_svec_t *sparam_vals, jl_method_insta fptr.fptr = generator->fptr; fptr.jlcall_api = generator->jlcall_api; if (__unlikely(fptr.fptr == NULL || fptr.jlcall_api == 0)) { - void *F = jl_compile_linfo(generator, (jl_code_info_t*)generator->inferred).functionObject; + void *F = jl_compile_linfo(generator, (jl_code_info_t*)generator->inferred, &jl_default_cgparams).functionObject; fptr = jl_generate_fptr(generator, F); } assert(jl_svec_len(generator->def->sparam_syms) == jl_svec_len(sparam_vals)); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 1fcde70c96793..a01e13338a6bd 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -26,6 +26,18 @@ static Value *prepare_call(Value *Callee) } +// --- 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); + + // --- string constants --- static StringMap stringConstants; static Value *stringConstPtr(IRBuilder<> &builder, const std::string &txt) @@ -660,6 +672,7 @@ static void error_unless(Value *cond, const std::string &msg, jl_codectx_t *ctx) static void raise_exception(Value *exc, jl_codectx_t *ctx, BasicBlock *contBB=nullptr) { + JL_FEAT_REQUIRE(ctx, runtime); #if JL_LLVM_VERSION >= 30700 builder.CreateCall(prepare_call(jlthrow_func), { exc }); #else @@ -1566,6 +1579,9 @@ static void emit_cpointercheck(const jl_cgval_t &x, const std::string &msg, jl_c // 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); + int osize; int offset = jl_gc_classify_pools(static_size, &osize); Value *ptls_ptr = emit_bitcast(ctx->ptlsStates, T_pint8); diff --git a/src/codegen.cpp b/src/codegen.cpp index 5f403d90002b1..e1e394f5123e0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -544,6 +544,7 @@ typedef struct { jl_array_t *code; const char *name; StringRef file; + ssize_t *line; Value *spvals_ptr; Value *argArray; Value *argCount; @@ -559,6 +560,8 @@ typedef struct { bool debug_enabled; bool is_inbounds{false}; + + jl_cgparams_t *params; } jl_codectx_t; static jl_cgval_t emit_expr(jl_value_t *expr, jl_codectx_t *ctx); @@ -819,7 +822,7 @@ void jl_dump_compiles(void *s) // --- entry point --- //static int n_emit=0; -static std::unique_ptr emit_function(jl_method_instance_t *lam, jl_code_info_t *src, jl_llvm_functions_t *declarations); +static std::unique_ptr emit_function(jl_method_instance_t *lam, jl_code_info_t *src, jl_llvm_functions_t *declarations, jl_cgparams_t *params); void jl_add_linfo_in_flight(StringRef name, jl_method_instance_t *linfo, const DataLayout &DL); // this generates llvm code for the lambda info @@ -827,7 +830,7 @@ void jl_add_linfo_in_flight(StringRef name, jl_method_instance_t *linfo, const D // (and the shadow module), but doesn't yet compile // or generate object code for it extern "C" -jl_llvm_functions_t jl_compile_linfo(jl_method_instance_t *li, jl_code_info_t *src) +jl_llvm_functions_t jl_compile_linfo(jl_method_instance_t *li, jl_code_info_t *src, jl_cgparams_t *params) { JL_TIMING(CODEGEN); assert(jl_is_method_instance(li)); @@ -840,12 +843,12 @@ jl_llvm_functions_t jl_compile_linfo(jl_method_instance_t *li, jl_code_info_t *s // try to infer it for ourself // first see if it is already compiled decls = li->functionObjectsDecls; - if (decls.functionObject != NULL || li->jlcall_api == 2) { + if ((params->cached && decls.functionObject != NULL) || li->jlcall_api == 2) { return decls; } JL_LOCK(&codegen_lock); decls = li->functionObjectsDecls; - if (decls.functionObject != NULL || li->jlcall_api == 2) { + if ((params->cached && decls.functionObject != NULL) || li->jlcall_api == 2) { JL_UNLOCK(&codegen_lock); return decls; } @@ -871,12 +874,12 @@ jl_llvm_functions_t jl_compile_linfo(jl_method_instance_t *li, jl_code_info_t *s // similar to above, but never returns a NULL // decl (unless compile fails), even if jlcall_api == 2 decls = li->functionObjectsDecls; - if (decls.functionObject != NULL) { + if (params->cached && decls.functionObject != NULL) { return decls; } JL_LOCK(&codegen_lock); decls = li->functionObjectsDecls; - if (decls.functionObject != NULL) { + if (params->cached && decls.functionObject != NULL) { JL_UNLOCK(&codegen_lock); return decls; } @@ -894,9 +897,9 @@ jl_llvm_functions_t jl_compile_linfo(jl_method_instance_t *li, jl_code_info_t *s // Step 3. actually do the work of emitting the function std::unique_ptr m; - Function *f = NULL, *specf = NULL; + Function *f = (Function*)decls.functionObject, *specf = (Function*)decls.specFunctionObject; JL_TRY { - m = emit_function(li, src, &li->functionObjectsDecls); + m = emit_function(li, src, &li->functionObjectsDecls, params); decls = li->functionObjectsDecls; //n_emit++; } @@ -913,6 +916,10 @@ jl_llvm_functions_t jl_compile_linfo(jl_method_instance_t *li, jl_code_info_t *s JL_UNLOCK(&codegen_lock); // Might GC jl_rethrow_with_add("error compiling %s", jl_symbol_name(li->def ? li->def->name : anonymous_sym)); } + if (!params->cached) { + li->functionObjectsDecls.functionObject = f; + li->functionObjectsDecls.specFunctionObject = specf; + } f = (Function*)decls.functionObject; specf = (Function*)decls.specFunctionObject; @@ -1137,7 +1144,7 @@ jl_generic_fptr_t jl_generate_fptr(jl_method_instance_t *li, void *_F) unspec->functionObjectsDecls.functionObject = NULL; unspec->functionObjectsDecls.specFunctionObject = NULL; } - F = (Function*)jl_compile_linfo(unspec, src).functionObject; + F = (Function*)jl_compile_linfo(unspec, src, &jl_default_cgparams).functionObject; if (unspec == li) { unspec->functionObjectsDecls = decls; } @@ -1249,7 +1256,7 @@ void jl_extern_c(jl_function_t *f, jl_value_t *rt, jl_value_t *argt, char *name) // this is paired with jl_dump_function_ir and jl_dump_function_asm in particular ways: // misuse will leak memory or cause read-after-free extern "C" JL_DLLEXPORT -void *jl_get_llvmf_defn(jl_method_instance_t *linfo, bool getwrapper) +void *jl_get_llvmf_defn(jl_method_instance_t *linfo, bool getwrapper, bool optimize, jl_cgparams_t params) { // `source` is `NULL` for generated functions. // The `isstaged` check can be removed if that is not the case anymore. @@ -1276,7 +1283,7 @@ void *jl_get_llvmf_defn(jl_method_instance_t *linfo, bool getwrapper) jl_llvm_functions_t declarations; std::unique_ptr m; JL_TRY { - m = emit_function(linfo, src, &declarations); + m = emit_function(linfo, src, &declarations, ¶ms); } JL_CATCH { // something failed! @@ -1295,7 +1302,8 @@ void *jl_get_llvmf_defn(jl_method_instance_t *linfo, bool getwrapper) } nested_compile = last_n_c; - jl_globalPM->run(*m.get()); + if (optimize) + jl_globalPM->run(*m.get()); Function *f = (llvm::Function*)declarations.functionObject; Function *specf = (llvm::Function*)declarations.specFunctionObject; // swap declarations for definitions and destroy declarations @@ -1330,7 +1338,7 @@ void *jl_get_llvmf_defn(jl_method_instance_t *linfo, bool getwrapper) extern "C" JL_DLLEXPORT -void *jl_get_llvmf_decl(jl_method_instance_t *linfo, bool getwrapper) +void *jl_get_llvmf_decl(jl_method_instance_t *linfo, bool getwrapper, jl_cgparams_t params) { // `source` is `NULL` for generated functions. // The `isstaged` check can be removed if that is not the case anymore. @@ -1353,7 +1361,7 @@ void *jl_get_llvmf_decl(jl_method_instance_t *linfo, bool getwrapper) if (!src) { src = linfo->def->isstaged ? jl_code_for_staged(linfo) : linfo->def->source; } - decls = jl_compile_linfo(linfo, src); + decls = jl_compile_linfo(linfo, src, ¶ms); linfo->functionObjectsDecls = decls; } JL_UNLOCK(&codegen_lock); @@ -1389,9 +1397,9 @@ void *jl_get_llvmf(jl_tupletype_t *tt, bool getwrapper, bool getdeclarations) } void *f; if (getdeclarations) - f = jl_get_llvmf_decl(linfo, getwrapper); + f = jl_get_llvmf_decl(linfo, getwrapper, jl_default_cgparams); else - f = jl_get_llvmf_defn(linfo, getwrapper); + f = jl_get_llvmf_defn(linfo, getwrapper, true, jl_default_cgparams); JL_GC_POP(); return f; } @@ -1775,6 +1783,7 @@ static void cg_bdw(jl_binding_t *b, jl_codectx_t *ctx) // try to statically evaluate, NULL if not possible static jl_value_t *static_eval(jl_value_t *ex, jl_codectx_t *ctx, int sparams=true, int allow_alloc=true) { + if (!JL_FEAT_TEST(ctx, static_alloc)) allow_alloc = 0; if (jl_is_symbol(ex)) { jl_sym_t *sym = (jl_sym_t*)ex; if (jl_is_const(ctx->module, sym)) @@ -2274,6 +2283,7 @@ static Value *emit_f_is(const jl_cgval_t &arg1, const jl_cgval_t &arg2, jl_codec return builder.CreateICmpEQ(boxed(arg1, ctx), boxed(arg2, ctx)); } + JL_FEAT_REQUIRE(ctx, runtime); Value *varg1 = boxed(arg1, ctx); Value *varg2 = boxed(arg2, ctx, false); // potentially unrooted! #if JL_LLVM_VERSION >= 30700 @@ -2353,6 +2363,7 @@ static bool emit_builtin_call(jl_cgval_t *ret, jl_value_t *f, jl_value_t **args, } if (jl_subtype(ty, (jl_value_t*)jl_type_type, 0)) { *ret = emit_expr(args[1], ctx); + JL_FEAT_REQUIRE(ctx, runtime); #if JL_LLVM_VERSION >= 30700 builder.CreateCall(prepare_call(jltypeassert_func), {boxed(*ret, ctx), boxed(emit_expr(args[2], ctx), ctx)}); #else @@ -2421,6 +2432,7 @@ static bool emit_builtin_call(jl_cgval_t *ret, jl_value_t *f, jl_value_t **args, #ifdef _P64 nva = builder.CreateTrunc(nva, T_int32); #endif + JL_FEAT_REQUIRE(ctx, runtime); Value *r = #if JL_LLVM_VERSION >= 30700 builder.CreateCall(prepare_call(jlapply2va_func), {theF, @@ -2916,7 +2928,7 @@ static jl_cgval_t emit_invoke(jl_expr_t *ex, jl_codectx_t *ctx) if (lival.constant) { jl_method_instance_t *li = (jl_method_instance_t*)lival.constant; assert(jl_is_method_instance(li)); - jl_llvm_functions_t decls = jl_compile_linfo(li, NULL); + jl_llvm_functions_t decls = jl_compile_linfo(li, NULL, ctx->params); if (li->jlcall_api == 2) { assert(li->inferred); return mark_julia_const(li->inferred); @@ -2932,6 +2944,7 @@ static jl_cgval_t emit_invoke(jl_expr_t *ex, jl_codectx_t *ctx) } } } + JL_FEAT_REQUIRE(ctx, runtime); jl_cgval_t result = mark_julia_type(emit_jlcall(prepare_call(jlinvoke_func), boxed(lival, ctx, false), &args[1], nargs, ctx), true, expr_type((jl_value_t*)ex, ctx), ctx); @@ -2981,6 +2994,16 @@ static jl_cgval_t emit_call(jl_expr_t *ex, jl_codectx_t *ctx) } } + 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!=NULL ? name : ""); + } + // emit function and arguments nargs++; // add function to nargs count jl_cgval_t *anArg = (jl_cgval_t*)alloca(sizeof(jl_cgval_t) * nargs); @@ -3033,6 +3056,7 @@ static Value *global_binding_pointer(jl_module_t *m, jl_sym_t *s, 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 = ConstantPointerNull::get((PointerType*)T_pjlvalue); @@ -3199,6 +3223,7 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx) if (bp == NULL && s != NULL) bp = global_binding_pointer(ctx->module, s, &bnd, true, ctx); if (bp != NULL) { // it's a global + JL_FEAT_REQUIRE(ctx, runtime); assert(bnd); Value *rval = boxed(emit_expr(r, ctx), ctx, false); // no root needed since this is about to be assigned to a global #if JL_LLVM_VERSION >= 30700 @@ -3320,6 +3345,7 @@ static void emit_stmtpos(jl_value_t *expr, jl_codectx_t *ctx) } else if (head == leave_sym) { assert(jl_is_long(args[0])); + JL_FEAT_REQUIRE(ctx, runtime); builder.CreateCall(prepare_call(jlleave_func), ConstantInt::get(T_int32, jl_unbox_long(args[0]))); } @@ -3427,6 +3453,7 @@ static jl_cgval_t emit_expr(jl_value_t *expr, jl_codectx_t *ctx) 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; @@ -3461,6 +3488,7 @@ static jl_cgval_t emit_expr(jl_value_t *expr, jl_codectx_t *ctx) else if (head == const_sym) { jl_sym_t *sym = (jl_sym_t*)args[0]; if (jl_is_symbol(sym)) { + JL_FEAT_REQUIRE(ctx, runtime); jl_binding_t *bnd = NULL; (void)global_binding_pointer(ctx->module, sym, &bnd, true, ctx); assert(bnd); builder.CreateCall(prepare_call(jldeclareconst_func), @@ -3486,6 +3514,7 @@ static jl_cgval_t emit_expr(jl_value_t *expr, jl_codectx_t *ctx) true, jl_any_type, ctx); } 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); @@ -3521,6 +3550,7 @@ static jl_cgval_t emit_expr(jl_value_t *expr, jl_codectx_t *ctx) jl_error("syntax: prefix \"$\" in non-quoted expression"); if (jl_is_toplevel_only_expr(expr) && ctx->linfo->def == NULL) { + JL_FEAT_REQUIRE(ctx, runtime); // call interpreter to run a toplevel expr from inside a // compiled toplevel thunk. builder.CreateCall(prepare_call(jltopeval_func), literal_pointer_val(expr)); @@ -3543,6 +3573,8 @@ static jl_cgval_t emit_expr(jl_value_t *expr, jl_codectx_t *ctx) // gc frame emission static void allocate_gc_frame(BasicBlock *b0, jl_codectx_t *ctx) { + // TODO: requires the runtime, but is generated unconditionally + // allocate a placeholder gc instruction ctx->ptlsStates = builder.CreateCall(prepare_call(jltls_states_func)); int nthfield = offsetof(jl_tls_states_t, safepoint) / sizeof(void*); @@ -3587,7 +3619,7 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t jl_code_info_t *src = NULL; if (!lam->inferred) // TODO: this isn't ideal to be unconditionally calling type inference from here src = jl_type_infer(lam, 0); - jl_compile_linfo(lam, src); + jl_compile_linfo(lam, src, &jl_default_cgparams); if (lam->jlcall_api != 2) { if (lam->functionObjectsDecls.functionObject == NULL || jl_jlcall_api(lam->functionObjectsDecls.functionObject) != 1) { @@ -3632,6 +3664,7 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t ctx.linfo = lam; ctx.sret = false; ctx.spvals_ptr = NULL; + ctx.params = &jl_default_cgparams; allocate_gc_frame(b0, &ctx); // Save the Function object reference @@ -3994,6 +4027,7 @@ static Function *gen_jlcall_wrapper(jl_method_instance_t *lam, Function *f, bool ctx.linfo = lam; ctx.sret = false; ctx.spvals_ptr = NULL; + ctx.params = &jl_default_cgparams; allocate_gc_frame(b0, &ctx); size_t nargs = lam->def->nargs; @@ -4043,7 +4077,7 @@ static Function *gen_jlcall_wrapper(jl_method_instance_t *lam, Function *f, bool } // Compile to LLVM IR, using a specialized signature if applicable. -static std::unique_ptr emit_function(jl_method_instance_t *lam, jl_code_info_t *src, jl_llvm_functions_t *declarations) +static std::unique_ptr emit_function(jl_method_instance_t *lam, jl_code_info_t *src, jl_llvm_functions_t *declarations, jl_cgparams_t *params) { jl_ptls_t ptls = jl_get_ptls_states(); assert(declarations && "Capturing declarations is always required"); @@ -4067,6 +4101,7 @@ static std::unique_ptr emit_function(jl_method_instance_t *lam, jl_code_ ctx.funcName = ctx.name; ctx.vaSlot = -1; ctx.vaStack = false; + ctx.params = params; ctx.spvals_ptr = NULL; ctx.nargs = lam->def ? lam->def->nargs : 0; @@ -4732,6 +4767,7 @@ static std::unique_ptr emit_function(jl_method_instance_t *lam, jl_code_ }; StmtProp cur_prop{topdebugloc, filename, toplineno, false, true, false, false}; + ctx.line = &cur_prop.line; if (coverage_mode != JL_LOG_NONE || malloc_log_mode) { cur_prop.in_user_code = (!jl_is_submodule(ctx.module, jl_base_module) && !jl_is_submodule(ctx.module, jl_core_module)); @@ -4950,10 +4986,12 @@ static std::unique_ptr emit_function(jl_method_instance_t *lam, jl_code_ }; auto do_coverage = [&] (bool in_user_code) { + if (!JL_FEAT_TEST(&ctx, code_coverage)) return false; return (coverage_mode == JL_LOG_ALL || (coverage_mode == JL_LOG_USER && in_user_code)); }; auto do_malloc_log = [&] (bool in_user_code) { + if (!JL_FEAT_TEST(&ctx, track_allocations)) return false; return (malloc_log_mode == JL_LOG_ALL || (malloc_log_mode == JL_LOG_USER && in_user_code)); }; diff --git a/src/gf.c b/src/gf.c index 783a4b8d81335..95c0ec68a7a02 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1261,7 +1261,7 @@ jl_llvm_functions_t jl_compile_for_dispatch(jl_method_instance_t *li) decls = li->functionObjectsDecls; if (decls.functionObject != NULL || li->jlcall_api == 2) return decls; - return jl_compile_linfo(li, src); + return jl_compile_linfo(li, src, &jl_default_cgparams); } // compile-time method lookup @@ -1310,7 +1310,7 @@ JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types) if (jl_is_uninferred(li)) src = jl_type_infer(li, 0); if (li->jlcall_api != 2) - jl_compile_linfo(li, src); + jl_compile_linfo(li, src, &jl_default_cgparams); return 1; } @@ -1550,7 +1550,7 @@ static void _compile_all_deq(jl_array_t *found) linfo->fptr = (jl_fptr_t)(uintptr_t)-1; } else { - jl_compile_linfo(linfo, src); + jl_compile_linfo(linfo, src, &jl_default_cgparams); assert(linfo->functionObjectsDecls.functionObject != NULL); } } diff --git a/src/jltypes.c b/src/jltypes.c index 0816ad4330f75..bfc012b1f3cc5 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -68,6 +68,8 @@ JL_DLLEXPORT jl_value_t *jl_emptytuple=NULL; jl_svec_t *jl_emptysvec; jl_value_t *jl_nothing; +jl_cgparams_t jl_default_cgparams; + // --- type properties and predicates --- STATIC_INLINE int is_unspec(jl_datatype_t *dt) @@ -3531,6 +3533,8 @@ void jl_init_types(void) jl_type_type_mt = jl_new_method_table(jl_type_type->name->name, ptls->current_module); jl_type_type->name->mt = jl_type_type_mt; + jl_default_cgparams = (jl_cgparams_t){1, 1, 1, 1, 1, 1, 1}; + // initialize them. lots of cycles. jl_datatype_type->name = jl_new_typename(jl_symbol("DataType")); jl_datatype_type->name->primary = (jl_value_t*)jl_datatype_type; diff --git a/src/julia.h b/src/julia.h index 04f1ab4ab3ab6..7619a5e0632dd 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1754,6 +1754,22 @@ typedef struct { #define jl_exception_in_transit (jl_get_ptls_states()->exception_in_transit) #define jl_task_arg_in_transit (jl_get_ptls_states()->task_arg_in_transit) + +// codegen interface ---------------------------------------------------------- + +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)? +} jl_cgparams_t; +extern JL_DLLEXPORT jl_cgparams_t jl_default_cgparams; + #ifdef __cplusplus } #endif diff --git a/src/julia_internal.h b/src/julia_internal.h index 4dc13a15b8b96..2528b20676bdd 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -188,7 +188,7 @@ STATIC_INLINE void *jl_gc_alloc_buf(jl_ptls_t ptls, size_t sz) jl_code_info_t *jl_type_infer(jl_method_instance_t *li, int force); jl_generic_fptr_t jl_generate_fptr(jl_method_instance_t *li, void *F); -jl_llvm_functions_t jl_compile_linfo(jl_method_instance_t *li, jl_code_info_t *src); +jl_llvm_functions_t jl_compile_linfo(jl_method_instance_t *li, jl_code_info_t *src, jl_cgparams_t *params); jl_llvm_functions_t jl_compile_for_dispatch(jl_method_instance_t *li); JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types); jl_code_info_t *jl_new_code_info_from_ast(jl_expr_t *ast);