From 0396074771ba7ea663291bf782240ef88e9a5ec7 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Thu, 9 Sep 2021 19:09:25 -0500 Subject: [PATCH] Add a `@compile` directive to disable interpreter (#42128) We currently use a `while false; end` hack to disable to interpreter, and this is getting more widely used outside of base. Unfortunately, improvements to the interpreter that would allow us to interpret loops would defeat the intention. This allows developers to annotate blocks with `@compile` to specify that they want to force the compiler to run on this block. --- base/expr.jl | 7 +++++++ base/timing.jl | 10 +++++----- src/toplevel.c | 12 ++++++++---- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/base/expr.jl b/base/expr.jl index 1af1e9486068ea..f68b684e13142e 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -374,6 +374,13 @@ macro propagate_inbounds(ex) esc(ex) end +""" + @compile + +Force compilation of the block or function (Julia's built-in interpreter is blocked from executing it). +""" +macro compile() Expr(:meta, :compile) end + """ @polly diff --git a/base/timing.jl b/base/timing.jl index 45a27e33789773..e229fbeb328e91 100644 --- a/base/timing.jl +++ b/base/timing.jl @@ -203,7 +203,7 @@ julia> @time begin """ macro time(ex) quote - while false; end # compiler heuristic: compile this block (alter this if the heuristic changes) + @compile local stats = gc_num() local elapsedtime = time_ns() local compile_elapsedtime = cumulative_compile_time_ns_before() @@ -249,7 +249,7 @@ pool allocs: 1 """ macro timev(ex) quote - while false; end # compiler heuristic: compile this block (alter this if the heuristic changes) + @compile local stats = gc_num() local elapsedtime = time_ns() local compile_elapsedtime = cumulative_compile_time_ns_before() @@ -282,7 +282,7 @@ julia> @elapsed sleep(0.3) """ macro elapsed(ex) quote - while false; end # compiler heuristic: compile this block (alter this if the heuristic changes) + @compile local t0 = time_ns() $(esc(ex)) (time_ns() - t0) / 1e9 @@ -314,7 +314,7 @@ julia> @allocated rand(10^6) """ macro allocated(ex) quote - while false; end # compiler heuristic: compile this block (alter this if the heuristic changes) + @compile local b0 = Ref{Int64}(0) local b1 = Ref{Int64}(0) gc_bytes(b0) @@ -362,7 +362,7 @@ julia> stats.gcstats.total_time """ macro timed(ex) quote - while false; end # compiler heuristic: compile this block (alter this if the heuristic changes) + @compile local stats = gc_num() local elapsedtime = time_ns() local val = $(esc(ex)) diff --git a/src/toplevel.c b/src/toplevel.c index c11dea57c84895..4973d09ab832cf 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -378,6 +378,8 @@ int jl_code_requires_compiler(jl_code_info_t *src) assert(jl_typeis(body, jl_array_any_type)); size_t i; int has_intrinsics = 0, has_defs = 0, has_opaque = 0; + if (jl_has_meta(body, compile_sym)) + return 1; for(i=0; i < jl_array_len(body); i++) { jl_value_t *stmt = jl_array_ptr_ref(body,i); expr_attributes(stmt, &has_intrinsics, &has_defs, &has_opaque); @@ -387,7 +389,7 @@ int jl_code_requires_compiler(jl_code_info_t *src) return 0; } -static void body_attributes(jl_array_t *body, int *has_intrinsics, int *has_defs, int *has_loops, int *has_opaque) +static void body_attributes(jl_array_t *body, int *has_intrinsics, int *has_defs, int *has_loops, int *has_opaque, int *has_compile) { size_t i; *has_loops = 0; @@ -405,6 +407,7 @@ static void body_attributes(jl_array_t *body, int *has_intrinsics, int *has_defs } expr_attributes(stmt, has_intrinsics, has_defs, has_opaque); } + *has_compile = jl_has_meta(body, compile_sym); } static jl_module_t *call_require(jl_module_t *mod, jl_sym_t *var) JL_GLOBALLY_ROOTED @@ -848,19 +851,20 @@ jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_value_t *e, int return (jl_value_t*)ex; } - int has_intrinsics = 0, has_defs = 0, has_loops = 0, has_opaque = 0; + int has_intrinsics = 0, has_defs = 0, has_loops = 0, has_opaque = 0, has_compile = 0; assert(head == thunk_sym); thk = (jl_code_info_t*)jl_exprarg(ex, 0); assert(jl_is_code_info(thk)); assert(jl_typeis(thk->code, jl_array_any_type)); - body_attributes((jl_array_t*)thk->code, &has_intrinsics, &has_defs, &has_loops, &has_opaque); + body_attributes((jl_array_t*)thk->code, &has_intrinsics, &has_defs, &has_loops, &has_opaque, &has_compile); jl_value_t *result; if (has_intrinsics || (!has_defs && fast && has_loops && jl_options.compile_enabled != JL_OPTIONS_COMPILE_OFF && jl_options.compile_enabled != JL_OPTIONS_COMPILE_MIN && jl_get_module_compile(m) != JL_OPTIONS_COMPILE_OFF && - jl_get_module_compile(m) != JL_OPTIONS_COMPILE_MIN)) { + jl_get_module_compile(m) != JL_OPTIONS_COMPILE_MIN) || + has_compile) { // use codegen mfunc = method_instance_for_thunk(thk, m); jl_resolve_globals_in_ir((jl_array_t*)thk->code, m, NULL, 0);