diff options
Diffstat (limited to 'lib/compiler/src/cerl_inline.erl')
-rw-r--r-- | lib/compiler/src/cerl_inline.erl | 72 |
1 files changed, 30 insertions, 42 deletions
diff --git a/lib/compiler/src/cerl_inline.erl b/lib/compiler/src/cerl_inline.erl index caff47dbcb..8a2ea77b99 100644 --- a/lib/compiler/src/cerl_inline.erl +++ b/lib/compiler/src/cerl_inline.erl @@ -65,7 +65,7 @@ map_pair_op/1, map_pair_key/1, map_pair_val/1 ]). --import(lists, [foldl/3, foldr/3, mapfoldl/3, reverse/1]). +-import(lists, [foldl/3, foldr/3, member/2, mapfoldl/3, reverse/1]). %% %% Constants @@ -142,7 +142,7 @@ weight(module) -> 1. % Like a letrec with a constant body %% environment, the state location, and the effort counter at the call %% site (cf. `visit'). --record(opnd, {expr, ren, env, loc, effort}). +-record(opnd, {expr, ren, env, loc, effort, no_inline}). %% Since expressions are only visited in `effect' context when they are %% not bound to a referenced variable, only expressions visited in @@ -903,10 +903,14 @@ i_fun(E, Ctxt, Ren, Env, S) -> %% side of each definition. i_letrec(E, Ctxt, Ren, Env, S) -> + %% We must turn off inlining if this `letrec' is specially + %% implemented. + NoInline = member(letrec_goto, get_ann(E)), + %% Note that we pass an empty list for the auto-referenced %% (exported) functions here. {Es, B, _, S1} = i_letrec(letrec_defs(E), letrec_body(E), [], Ctxt, - Ren, Env, S), + Ren, Env, NoInline, S), %% If no bindings remain, only the body is returned. case Es of @@ -920,12 +924,13 @@ i_letrec(E, Ctxt, Ren, Env, S) -> %% The major part of this is shared by letrec-expressions and module %% definitions alike. -i_letrec(Es, B, Xs, Ctxt, Ren, Env, S) -> +i_letrec(Es, B, Xs, Ctxt, Ren, Env, NoInline, S) -> %% First, we create operands with dummy renamings and environments, %% and with fresh store locations for cached expressions and operand %% info. {Opnds, S1} = mapfoldl(fun ({_, E}, S) -> - make_opnd(E, undefined, undefined, S) + make_opnd(E, undefined, undefined, + NoInline, S) end, S, Es), @@ -1277,7 +1282,7 @@ i_module(E, Ctxt, Ren, Env, S) -> %% "body" parameter. Exps = i_module_exports(E), {Es, _, Xs1, S1} = i_letrec(module_defs(E), void(), - Exps, Ctxt, Ren, Env, S), + Exps, Ctxt, Ren, Env, false, S), %% Sanity check: case Es of [] -> @@ -1500,23 +1505,15 @@ inline(E, #app{opnds = Opnds, ctxt = Ctxt, loc = L}, Ren, Env, S) -> %% respective operand structures from the app-structure. {Rs, Ren1, Env1, S1} = bind_locals(Vs, Opnds, Ren, Env, S), - %% function_clause exceptions that have been inlined - %% into another function (or even into the same function) - %% will not work properly. The v3_kernel pass will - %% take care of it, but we will need to help it by - %% removing any function_name annotations on match_fail - %% primops that we inline. - E1 = kill_function_name_anns(fun_body(E)), - %% Visit the body in the context saved in the structure. - {E2, S2} = i(E1, Ctxt, Ren1, Env1, S1), + {E1, S2} = i(fun_body(E), Ctxt, Ren1, Env1, S1), %% Create necessary bindings and/or set flags. - {E3, S3} = make_let_bindings(Rs, E2, S2), + {E2, S3} = make_let_bindings(Rs, E1, S2), %% Lastly, flag the application as inlined, since the inlining %% attempt was not aborted before we reached this point. - {E3, st__set_app_inlined(L, S3)} + {E2, st__set_app_inlined(L, S3)} end. %% For the (possibly renamed) argument variables to an inlined call, @@ -1674,6 +1671,8 @@ copy_var(R, Ctxt, Env, S) -> end end. +copy_1(R, #opnd{no_inline = true}, _E, _Ctxt, _Env, S) -> + residualize_var(R, S); copy_1(R, Opnd, E, Ctxt, Env, S) -> case type(E) of 'fun' -> @@ -2075,9 +2074,13 @@ ref_to_var(#ref{name = Name}) -> %% passive, the operands will also be processed with a passive counter. make_opnd(E, Ren, Env, S) -> + make_opnd(E, Ren, Env, false, S). + +make_opnd(E, Ren, Env, NoInline, S) -> {L, S1} = st__new_opnd_loc(S), C = st__get_effort(S1), - Opnd = #opnd{expr = E, ren = Ren, env = Env, loc = L, effort = C}, + Opnd = #opnd{expr = E, ren = Ren, env = Env, loc = L, + effort = C, no_inline = NoInline}, {Opnd, S1}. keep_referenced(Rs, S) -> @@ -2469,19 +2472,6 @@ kill_id_anns([A | As]) -> kill_id_anns([]) -> []. -kill_function_name_anns(Body) -> - F = fun(P) -> - case type(P) of - primop -> - Ann = get_ann(P), - Ann1 = lists:keydelete(function_name, 1, Ann), - set_ann(P, Ann1); - _ -> - P - end - end, - cerl_trees:map(F, Body). - %% ===================================================================== %% General utilities @@ -2526,21 +2516,19 @@ set_clause_bodies([], _) -> %% Abstract datatype: renaming() ren__identity() -> - dict:new(). + #{}. ren__add(X, Y, Ren) -> - dict:store(X, Y, Ren). + Ren#{X=>Y}. ren__map(X, Ren) -> - case dict:find(X, Ren) of - {ok, Y} -> - Y; - error -> - X + case Ren of + #{X:=Y} -> Y; + #{} -> X end. ren__add_identity(X, Ren) -> - dict:erase(X, Ren). + maps:remove(X, Ren). %% ===================================================================== @@ -2633,7 +2621,7 @@ st__new(Effort, Size, Unroll) -> size = counter__new_passive(Size), effort = counter__new_passive(Effort), unroll = Unroll, - cache = dict:new(), + cache = maps:new(), var_flags = ets:new(var, EtsOpts), opnd_flags = ets:new(opnd, EtsOpts), app_flags = ets:new(app, EtsOpts)}. @@ -2664,12 +2652,12 @@ st__get_var_referenced(L, S) -> ets:lookup_element(S#state.var_flags, L, #var_flags.referenced). st__lookup_opnd_cache(L, S) -> - dict:find(L, S#state.cache). + maps:find(L, S#state.cache). %% Note that setting the cache should only be done once. st__set_opnd_cache(L, C, S) -> - S#state{cache = dict:store(L, C, S#state.cache)}. + S#state{cache = maps:put(L, C, S#state.cache)}. st__set_opnd_effect(L, S) -> T = S#state.opnd_flags, |