From 9460b3e9dd3102f1cfcff7bb3b4bd27992bfe614 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 26 Feb 2020 18:18:19 -0500 Subject: [PATCH] add per-module optimization level macro --- base/experimental.jl | 14 ++++ src/ast.c | 2 + src/codegen.cpp | 9 +-- src/debuginfo.cpp | 8 ++- src/dump.c | 2 + src/interpreter.c | 6 ++ src/jitlayers.cpp | 67 +++++++++++++++++-- src/jitlayers.h | 7 +- src/julia.h | 3 + src/julia_internal.h | 1 + src/module.c | 16 +++++ .../InteractiveUtils/src/InteractiveUtils.jl | 2 + stdlib/REPL/src/REPL.jl | 2 + 13 files changed, 124 insertions(+), 15 deletions(-) diff --git a/base/experimental.jl b/base/experimental.jl index a4b3da0831b30..743833dc40c02 100644 --- a/base/experimental.jl +++ b/base/experimental.jl @@ -100,5 +100,19 @@ macro sync(block) end end +""" + Experimental.@optlevel n + +Set the optimization level (equivalent to the `-O` command line argument) +for code in the current module. + +Supported values are 0, 1, 2, and 3. + +The effective optimization level is the minimum of that specified on the +command line and in per-module settings. +""" +macro optlevel(n::Int) + return Expr(:meta, :optlevel, n) +end end diff --git a/src/ast.c b/src/ast.c index 982c96f614bc9..e9cbb4373c225 100644 --- a/src/ast.c +++ b/src/ast.c @@ -62,6 +62,7 @@ jl_sym_t *throw_undef_if_not_sym; jl_sym_t *getfield_undefref_sym; jl_sym_t *gc_preserve_begin_sym; jl_sym_t *gc_preserve_end_sym; jl_sym_t *coverageeffect_sym; jl_sym_t *escape_sym; jl_sym_t *aliasscope_sym; jl_sym_t *popaliasscope_sym; +jl_sym_t *optlevel_sym; static uint8_t flisp_system_image[] = { #include @@ -380,6 +381,7 @@ void jl_init_frontend(void) isdefined_sym = jl_symbol("isdefined"); nospecialize_sym = jl_symbol("nospecialize"); specialize_sym = jl_symbol("specialize"); + optlevel_sym = jl_symbol("optlevel"); macrocall_sym = jl_symbol("macrocall"); escape_sym = jl_symbol("escape"); hygienicscope_sym = jl_symbol("hygienic-scope"); diff --git a/src/codegen.cpp b/src/codegen.cpp index 201c864e080da..01343cf16c581 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7464,14 +7464,7 @@ extern "C" void jl_init_llvm(void) #else None; #endif - auto optlevel = -#ifdef DISABLE_OPT - CodeGenOpt::None; -#else - (jl_options.opt_level < 2 ? CodeGenOpt::None : - jl_options.opt_level == 2 ? CodeGenOpt::Default : - CodeGenOpt::Aggressive); -#endif + auto optlevel = CodeGenOptLevelFor(jl_options.opt_level); jl_TargetMachine = TheTarget->createTargetMachine( TheTriple.getTriple(), TheCPU, FeaturesStr, options, diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 1f81ee114a52f..e3133d62db591 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -87,7 +87,13 @@ void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const D { codeinst_in_flight[mangle(name, DL)] = codeinst; } - +jl_code_instance_t *jl_get_code_in_flight(StringRef name) +{ + StringMap::iterator linfo_it = codeinst_in_flight.find(name); + if (linfo_it != codeinst_in_flight.end()) + return linfo_it->second; + return NULL; +} #ifdef _OS_WINDOWS_ #if defined(_CPU_X86_64_) diff --git a/src/dump.c b/src/dump.c index 3f72455ceb204..a9554aee3977c 100644 --- a/src/dump.c +++ b/src/dump.c @@ -479,6 +479,7 @@ static void jl_serialize_module(jl_serializer_state *s, jl_module_t *m) write_uint64(s->s, m->build_id); write_int32(s->s, m->counter); write_int32(s->s, m->nospecialize); + write_int32(s->s, m->optlevel); } static int is_ir_node(jl_value_t *v) @@ -1883,6 +1884,7 @@ static jl_value_t *jl_deserialize_value_module(jl_serializer_state *s) JL_GC_DIS m->build_id = read_uint64(s->s); m->counter = read_int32(s->s); m->nospecialize = read_int32(s->s); + m->optlevel = read_int32(s->s); m->primary_world = jl_world_counter; return (jl_value_t*)m; } diff --git a/src/interpreter.c b/src/interpreter.c index 016e230469114..0e7f00cf4a245 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -798,6 +798,12 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip, if (jl_expr_nargs(stmt) == 1 && jl_exprarg(stmt, 0) == (jl_value_t*)specialize_sym) { jl_set_module_nospecialize(s->module, 0); } + if (jl_expr_nargs(stmt) == 2 && jl_exprarg(stmt, 0) == (jl_value_t*)optlevel_sym) { + if (jl_is_long(jl_exprarg(stmt, 1))) { + int n = jl_unbox_long(jl_exprarg(stmt, 1)); + jl_set_module_optlevel(s->module, n); + } + } } else { eval_stmt_value(stmt, s); diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 603bb5b2e4f64..9e560f9757490 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -436,11 +436,68 @@ void JuliaOJIT::DebugObjectRegistrar::operator()(RTDyldObjHandleT H, static_cast(&LOS)); } +CodeGenOpt::Level CodeGenOptLevelFor(int optlevel) +{ +#ifdef DISABLE_OPT + return CodeGenOpt::None; +#else + return optlevel < 2 ? CodeGenOpt::None : + optlevel == 2 ? CodeGenOpt::Default : + CodeGenOpt::Aggressive; +#endif +} + +static void addPassesForOptLevel(legacy::PassManager &PM, TargetMachine &TM, raw_svector_ostream &ObjStream, MCContext *Ctx, int optlevel) +{ + auto oldlevel = TM.getOptLevel(); + TM.setOptLevel(CodeGenOptLevelFor(optlevel)); + addTargetPasses(&PM, &TM); + addOptimizationPasses(&PM, optlevel); + if (TM.addPassesToEmitMC(PM, Ctx, ObjStream)) + llvm_unreachable("Target does not support MC emission."); + TM.setOptLevel(oldlevel); +} + +jl_code_instance_t *jl_get_code_in_flight(StringRef name); CompilerResultT JuliaOJIT::CompilerT::operator()(Module &M) { JL_TIMING(LLVM_OPT); - jit.PM.run(M); + int optlevel; + if (jl_generating_output()) { + optlevel = 0; + } + else { + optlevel = jl_options.opt_level; + for (Module::iterator fs = M.begin(); fs != M.end(); ) { + Function &F = *fs; + if (!F.getBasicBlockList().empty()) { + jl_code_instance_t *codeinst = jl_get_code_in_flight(F.getName()); + if (codeinst) { + jl_method_instance_t *mi = codeinst->def; + if (jl_is_method(mi->def.value)) { + jl_method_t *meth = mi->def.method; + int ol = jl_get_module_optlevel(meth->module); + if (ol >= 0 && ol < optlevel) + optlevel = ol; + } + } + } + ++fs; + } + } + auto oldlevel = jit.TM.getOptLevel(); + jit.TM.setOptLevel(CodeGenOptLevelFor(optlevel)); + if (optlevel == 0) + jit.PM0.run(M); + else if (optlevel == 1) + jit.PM1.run(M); + else if (optlevel == 2) + jit.PM2.run(M); + else if (optlevel >= 3) + jit.PM3.run(M); + jit.TM.setOptLevel(oldlevel); + std::unique_ptr ObjBuffer( new SmallVectorMemoryBuffer(std::move(jit.ObjBufferSV))); auto Obj = object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()); @@ -490,10 +547,10 @@ JuliaOJIT::JuliaOJIT(TargetMachine &TM) CompilerT(this) ) { - addTargetPasses(&PM, &TM); - addOptimizationPasses(&PM, jl_generating_output() ? 0 : jl_options.opt_level); - if (TM.addPassesToEmitMC(PM, Ctx, ObjStream)) - llvm_unreachable("Target does not support MC emission."); + addPassesForOptLevel(PM0, TM, ObjStream, Ctx, 0); + addPassesForOptLevel(PM1, TM, ObjStream, Ctx, 1); + addPassesForOptLevel(PM2, TM, ObjStream, Ctx, 2); + addPassesForOptLevel(PM3, TM, ObjStream, Ctx, 3); // Make sure SectionMemoryManager::getSymbolAddressInProcess can resolve // symbols in the program as well. The nullptr argument to the function diff --git a/src/jitlayers.h b/src/jitlayers.h index 773afbe60ec9e..e789e9d1394ba 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -212,7 +212,10 @@ class JuliaOJIT { // object fits in its entirety SmallVector ObjBufferSV; raw_svector_ostream ObjStream; - legacy::PassManager PM; + legacy::PassManager PM0; // per-optlevel pass managers + legacy::PassManager PM1; + legacy::PassManager PM2; + legacy::PassManager PM3; MCContext *Ctx; std::shared_ptr MemMgr; DebugObjectRegistrar registrar; @@ -243,3 +246,5 @@ static inline bool isIntrinsicFunction(Function *F) { return F->isIntrinsic() || F->getName().startswith("julia."); } + +CodeGenOpt::Level CodeGenOptLevelFor(int optlevel); diff --git a/src/julia.h b/src/julia.h index 71aababc44ec1..ce08c71feaaff 100644 --- a/src/julia.h +++ b/src/julia.h @@ -495,6 +495,7 @@ typedef struct _jl_module_t { size_t primary_world; uint32_t counter; int32_t nospecialize; // global bit flags: initialization for new methods + int32_t optlevel; uint8_t istopmod; jl_mutex_t lock; } jl_module_t; @@ -1454,6 +1455,8 @@ extern JL_DLLEXPORT jl_module_t *jl_base_module JL_GLOBALLY_ROOTED; extern JL_DLLEXPORT jl_module_t *jl_top_module JL_GLOBALLY_ROOTED; JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name); 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 int jl_get_module_optlevel(jl_module_t *m); // get binding for reading JL_DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); JL_DLLEXPORT jl_binding_t *jl_get_binding_or_error(jl_module_t *m, jl_sym_t *var); diff --git a/src/julia_internal.h b/src/julia_internal.h index 0574b40c3e167..952cc5039aa23 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1162,6 +1162,7 @@ extern jl_sym_t *throw_undef_if_not_sym; extern jl_sym_t *getfield_undefref_sym; extern jl_sym_t *gc_preserve_begin_sym; extern jl_sym_t *gc_preserve_end_sym; extern jl_sym_t *failed_sym; extern jl_sym_t *done_sym; extern jl_sym_t *runnable_sym; extern jl_sym_t *coverageeffect_sym; extern jl_sym_t *escape_sym; +extern jl_sym_t *optlevel_sym; struct _jl_sysimg_fptrs_t; diff --git a/src/module.c b/src/module.c index 33e7afedc1696..883c813ad233e 100644 --- a/src/module.c +++ b/src/module.c @@ -35,6 +35,7 @@ JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name) m->primary_world = 0; m->counter = 1; m->nospecialize = 0; + m->optlevel = -1; JL_MUTEX_INIT(&m->lock); htable_new(&m->bindings, 0); arraylist_new(&m->usings, 0); @@ -72,6 +73,21 @@ JL_DLLEXPORT void jl_set_module_nospecialize(jl_module_t *self, int on) self->nospecialize = (on ? -1 : 0); } +JL_DLLEXPORT void jl_set_module_optlevel(jl_module_t *self, int lvl) +{ + self->optlevel = lvl; +} + +JL_DLLEXPORT int jl_get_module_optlevel(jl_module_t *m) +{ + int lvl = m->optlevel; + while (lvl == -1 && m->parent != m) { + m = m->parent; + lvl = m->optlevel; + } + return lvl; +} + JL_DLLEXPORT void jl_set_istopmod(jl_module_t *self, uint8_t isprimary) { self->istopmod = 1; diff --git a/stdlib/InteractiveUtils/src/InteractiveUtils.jl b/stdlib/InteractiveUtils/src/InteractiveUtils.jl index 367889d029fe2..9556b9c9a5d30 100644 --- a/stdlib/InteractiveUtils/src/InteractiveUtils.jl +++ b/stdlib/InteractiveUtils/src/InteractiveUtils.jl @@ -2,6 +2,8 @@ module InteractiveUtils +Base.Experimental.@optlevel 1 + export apropos, edit, less, code_warntype, code_llvm, code_native, methodswith, varinfo, versioninfo, subtypes, supertypes, @which, @edit, @less, @functionloc, @code_warntype, @code_typed, @code_lowered, @code_llvm, @code_native, clipboard diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 765ce011f6083..657b2ca4c9e33 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -13,6 +13,8 @@ Run Evaluate Print Loop (REPL) """ module REPL +Base.Experimental.@optlevel 1 + using Base.Meta, Sockets import InteractiveUtils