Skip to content

Commit

Permalink
Add @min_optlevel to set a min-optlevel for a module
Browse files Browse the repository at this point in the history
  • Loading branch information
NHDaly committed Jan 22, 2025
1 parent f91436e commit c890ba5
Show file tree
Hide file tree
Showing 10 changed files with 66 additions and 0 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ New language features
- actual running time for the task (`Base.Experimental.task_running_time_ns`), and
- wall-time for the task (`Base.Experimental.task_wall_time_ns`).
- Support for Unicode 16 ([#56925]).
* `Base.Experimental.@min_optlevel level` sets a minimum optlevel (`--min_optlevel`) for a
module, ensuring that level of optimization even if the process is run at a lower optlevel
(`-O`) ([#]).

Language changes
----------------
Expand Down
21 changes: 21 additions & 0 deletions base/experimental.jl
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,27 @@ macro optlevel(n::Int)
return Expr(:meta, :optlevel, n)
end

"""
Experimental.@min_optlevel n::Int
Set the minimum optimization level (equivalent to the `--min-optlevel` command line
argument) for code in the current module. Submodules inherit the setting of their
parent module.
Supported values are 0, 1, 2, and 3.
This sets a lower-bound for optimization level, such that the effective optimization
level, `o` is `@min_optlevel <= o <= @optlevel` and `--min-optlevel <= o <= -O`.
NOTE: This min optimization level will only be applied to LLVM functions that are compiled
from this module. If a function defined in this module is *inlined* into a function defined
outside the module, that function will not inherit this min optimization level. Consider
whether you need to introduce `@noinline` if you require users to observe your min optlevel.
"""
macro min_optlevel(n::Int)
return Expr(:meta, :min_optlevel, n)
end

"""
Experimental.@max_methods n::Int
Expand Down
2 changes: 2 additions & 0 deletions src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ JL_DLLEXPORT jl_sym_t *jl_escape_sym;
JL_DLLEXPORT jl_sym_t *jl_aliasscope_sym;
JL_DLLEXPORT jl_sym_t *jl_popaliasscope_sym;
JL_DLLEXPORT jl_sym_t *jl_optlevel_sym;
JL_DLLEXPORT jl_sym_t *jl_min_optlevel_sym;
JL_DLLEXPORT jl_sym_t *jl_thismodule_sym;
JL_DLLEXPORT jl_sym_t *jl_eval_sym;
JL_DLLEXPORT jl_sym_t *jl_include_sym;
Expand Down Expand Up @@ -392,6 +393,7 @@ void jl_init_common_symbols(void)
jl_specialize_sym = jl_symbol("specialize");
jl_nospecializeinfer_sym = jl_symbol("nospecializeinfer");
jl_optlevel_sym = jl_symbol("optlevel");
jl_min_optlevel_sym = jl_symbol("min_optlevel");
jl_compile_sym = jl_symbol("compile");
jl_force_compile_sym = jl_symbol("force_compile");
jl_infer_sym = jl_symbol("infer");
Expand Down
5 changes: 5 additions & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8673,6 +8673,11 @@ static jl_llvm_functions_t
static const char* const optLevelStrings[] = { "0", "1", "2", "3" };
FnAttrs.addAttribute("julia-optimization-level", optLevelStrings[optlevel]);
}
int min_optlevel = jl_get_module_min_optlevel(ctx.module);
if (min_optlevel >= 0 && min_optlevel <= 3) {
static const char* const optLevelStrings[] = { "0", "1", "2", "3" };
FnAttrs.addAttribute("julia-min-optimization-level", optLevelStrings[min_optlevel]);
}

ctx.f = f;

Expand Down
6 changes: 6 additions & 0 deletions src/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,12 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip,
jl_set_module_optlevel(s->module, n);
}
}
else if (jl_exprarg(stmt, 0) == (jl_value_t*)jl_min_optlevel_sym) {
if (jl_is_long(jl_exprarg(stmt, 1))) {
int n = jl_unbox_long(jl_exprarg(stmt, 1));
jl_set_module_min_optlevel(s->module, n);
}
}
else if (jl_exprarg(stmt, 0) == (jl_value_t*)jl_compile_sym) {
if (jl_is_long(jl_exprarg(stmt, 1))) {
jl_set_module_compile(s->module, jl_unbox_long(jl_exprarg(stmt, 1)));
Expand Down
8 changes: 8 additions & 0 deletions src/jitlayers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,14 @@ static orc::ThreadSafeModule selectOptLevel(orc::ThreadSafeModule TSM) JL_NOTSAF
if (ol < opt_level)
opt_level = ol;
}
attr = F.getFnAttribute("julia-min-optimization-level");
val = attr.getValueAsString();
if (val != "") {
size_t ol = (size_t)val[0] - '0';
if (ol > opt_level)
opt_level = ol;
jl_safe_printf("Function %s opt: %d\n", F.getName().str().c_str(), (int)opt_level);
}
}
}
if (opt_level < opt_level_min)
Expand Down
2 changes: 2 additions & 0 deletions src/jl_exported_funcs.inc
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@
XX(jl_get_module_infer) \
XX(jl_get_module_of_binding) \
XX(jl_get_module_optlevel) \
XX(jl_get_module_min_optlevel) \
XX(jl_get_next_task) \
XX(jl_get_nth_field) \
XX(jl_get_nth_field_checked) \
Expand Down Expand Up @@ -411,6 +412,7 @@
XX(jl_set_module_infer) \
XX(jl_set_module_nospecialize) \
XX(jl_set_module_optlevel) \
XX(jl_set_module_min_optlevel) \
XX(jl_set_module_uuid) \
XX(jl_set_next_task) \
XX(jl_set_nth_field) \
Expand Down
3 changes: 3 additions & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@ typedef struct _jl_module_t {
_Atomic(uint32_t) counter;
int32_t nospecialize; // global bit flags: initialization for new methods
int8_t optlevel;
int8_t min_optlevel;
int8_t compile;
int8_t infer;
uint8_t istopmod;
Expand Down Expand Up @@ -1989,7 +1990,9 @@ extern JL_DLLIMPORT jl_module_t *jl_libdl_module JL_GLOBALLY_ROOTED;
JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name, jl_module_t *parent);
JL_DLLEXPORT void jl_set_module_nospecialize(jl_module_t *self, int on);
JL_DLLEXPORT void jl_set_module_optlevel(jl_module_t *self, int lvl);
JL_DLLEXPORT void jl_set_module_min_optlevel(jl_module_t *self, int lvl);
JL_DLLEXPORT int jl_get_module_optlevel(jl_module_t *m);
JL_DLLEXPORT int jl_get_module_min_optlevel(jl_module_t *m);
JL_DLLEXPORT void jl_set_module_compile(jl_module_t *self, int value);
JL_DLLEXPORT int jl_get_module_compile(jl_module_t *m);
JL_DLLEXPORT void jl_set_module_infer(jl_module_t *self, int value);
Expand Down
1 change: 1 addition & 0 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1867,6 +1867,7 @@ extern JL_DLLEXPORT jl_sym_t *jl_escape_sym;
extern JL_DLLEXPORT jl_sym_t *jl_aliasscope_sym;
extern JL_DLLEXPORT jl_sym_t *jl_popaliasscope_sym;
extern JL_DLLEXPORT jl_sym_t *jl_optlevel_sym;
extern JL_DLLEXPORT jl_sym_t *jl_min_optlevel_sym;
extern JL_DLLEXPORT jl_sym_t *jl_thismodule_sym;
extern JL_DLLEXPORT jl_sym_t *jl_eval_sym;
extern JL_DLLEXPORT jl_sym_t *jl_include_sym;
Expand Down
15 changes: 15 additions & 0 deletions src/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, ui
jl_atomic_store_relaxed(&m->counter, 1);
m->nospecialize = 0;
m->optlevel = -1;
m->min_optlevel = -1;
m->compile = -1;
m->infer = -1;
m->max_methods = -1;
Expand Down Expand Up @@ -145,6 +146,10 @@ JL_DLLEXPORT void jl_set_module_optlevel(jl_module_t *self, int lvl)
{
self->optlevel = lvl;
}
JL_DLLEXPORT void jl_set_module_min_optlevel(jl_module_t *self, int lvl)
{
self->min_optlevel = lvl;
}

JL_DLLEXPORT int jl_get_module_optlevel(jl_module_t *m)
{
Expand All @@ -155,6 +160,16 @@ JL_DLLEXPORT int jl_get_module_optlevel(jl_module_t *m)
}
return lvl;
}
JL_DLLEXPORT int jl_get_module_min_optlevel(jl_module_t *m)
{
int lvl = m->min_optlevel;
while (lvl == -1 && m->parent != m && m != jl_base_module) {
m = m->parent;
lvl = m->min_optlevel;
}
return lvl;
}


JL_DLLEXPORT void jl_set_module_compile(jl_module_t *self, int value)
{
Expand Down

0 comments on commit c890ba5

Please sign in to comment.