summaryrefslogtreecommitdiff
path: root/lib/compiler/src/beam_ssa_funs.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler/src/beam_ssa_funs.erl')
-rw-r--r--lib/compiler/src/beam_ssa_funs.erl152
1 files changed, 0 insertions, 152 deletions
diff --git a/lib/compiler/src/beam_ssa_funs.erl b/lib/compiler/src/beam_ssa_funs.erl
deleted file mode 100644
index a7b648bc47..0000000000
--- a/lib/compiler/src/beam_ssa_funs.erl
+++ /dev/null
@@ -1,152 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2018-2021. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%%
-%%% If a fun is defined locally and only used for calls, it can be replaced
-%%% with direct calls to the relevant function. This greatly speeds up "named
-%%% functions" (which rely on make_fun to recreate themselves) and macros that
-%%% wrap their body in a fun.
-%%%
-
--module(beam_ssa_funs).
-
--export([module/2]).
-
--include("beam_ssa.hrl").
-
--import(lists, [foldl/3]).
-
--spec module(Module, Options) -> Result when
- Module :: beam_ssa:b_module(),
- Options :: [compile:option()],
- Result :: {ok, beam_ssa:b_module()}.
-
-module(#b_module{body=Fs0}=Module, _Opts) ->
- Trampolines = foldl(fun find_trampolines/2, #{}, Fs0),
- Fs = [lfo(F, Trampolines) || F <- Fs0],
- {ok, Module#b_module{body=Fs}}.
-
-%% If a function does absolutely nothing beyond calling another function with
-%% the same arguments in the same order, we can shave off a call by short-
-%% circuiting it.
-find_trampolines(#b_function{args=Args,bs=Blocks}=F, Trampolines) ->
- case map_get(0, Blocks) of
- #b_blk{is=[#b_set{op=call,
- args=[#b_local{}=Actual | Args],
- dst=Dst}],
- last=#b_ret{arg=Dst}} ->
- {_, Name, Arity} = beam_ssa:get_anno(func_info, F),
- Trampoline = #b_local{name=#b_literal{val=Name},arity=Arity},
- Trampolines#{Trampoline => Actual};
- _ ->
- Trampolines
- end.
-
-lfo(#b_function{bs=Blocks0}=F, Trampolines) ->
- Linear0 = beam_ssa:linearize(Blocks0),
- Linear = lfo_optimize(Linear0, lfo_analyze(Linear0, #{}), Trampolines),
- F#b_function{bs=maps:from_list(Linear)}.
-
-%% Gather a map of the locally defined funs that are only used for calls.
-lfo_analyze([{_L,#b_blk{is=Is,last=Last}}|Bs], LFuns0) ->
- LFuns = lfo_analyze_last(Last, lfo_analyze_is(Is, LFuns0)),
- lfo_analyze(Bs, LFuns);
-lfo_analyze([], LFuns) ->
- LFuns.
-
-lfo_analyze_is([#b_set{op=make_fun,
- dst=Dst,
- args=[#b_local{} | FreeVars]}=Def | Is],
- LFuns0) ->
- LFuns = maps:put(Dst, Def, maps:without(FreeVars, LFuns0)),
- lfo_analyze_is(Is, LFuns);
-lfo_analyze_is([#b_set{op=call,
- args=[Fun | CallArgs]} | Is],
- LFuns) when is_map_key(Fun, LFuns) ->
- #b_set{args=[#b_local{arity=Arity} | FreeVars]} = map_get(Fun, LFuns),
- case length(CallArgs) + length(FreeVars) of
- Arity ->
- lfo_analyze_is(Is, maps:without(CallArgs, LFuns));
- _ ->
- %% This will `badarity` at runtime, and it's easier to disable the
- %% optimization than to simulate it.
- lfo_analyze_is(Is, maps:without([Fun | CallArgs], LFuns))
- end;
-lfo_analyze_is([#b_set{args=Args} | Is], LFuns) when map_size(LFuns) =/= 0 ->
- %% We disqualify funs that are used outside calls because this forces them
- %% to be created anyway, and the slight performance gain from direct calls
- %% is not enough to offset the potential increase in stack frame size (the
- %% free variables need to be kept alive until the call).
- lfo_analyze_is(Is, maps:without(Args, LFuns));
-lfo_analyze_is([_ | Is], LFuns) ->
- lfo_analyze_is(Is, LFuns);
-lfo_analyze_is([], LFuns) ->
- LFuns.
-
-lfo_analyze_last(#b_switch{arg=Arg}, LFuns) ->
- maps:remove(Arg, LFuns);
-lfo_analyze_last(#b_ret{arg=Arg}, LFuns) ->
- maps:remove(Arg, LFuns);
-lfo_analyze_last(_, LFuns) ->
- LFuns.
-
-%% Replace all calls of suitable funs with a direct call to their
-%% implementation. Liveness optimization will get rid of the make_fun
-%% instruction.
-lfo_optimize(Linear, LFuns, _Trampolines) when map_size(LFuns) =:= 0 ->
- Linear;
-lfo_optimize(Linear, LFuns, Trampolines) ->
- lfo_optimize_1(Linear, LFuns, Trampolines).
-
-lfo_optimize_1([{L,#b_blk{is=Is0}=Blk}|Bs], LFuns, Trampolines) ->
- Is = lfo_optimize_is(Is0, LFuns, Trampolines),
- [{L,Blk#b_blk{is=Is}} | lfo_optimize_1(Bs, LFuns, Trampolines)];
-lfo_optimize_1([], _LFuns, _Trampolines) ->
- [].
-
-lfo_optimize_is([#b_set{op=call,
- args=[Fun | CallArgs]}=Call0 | Is],
- LFuns, Trampolines) when is_map_key(Fun, LFuns) ->
- #b_set{args=[Local | FreeVars]} = map_get(Fun, LFuns),
- Args = [lfo_short_circuit(Local, Trampolines) | CallArgs ++ FreeVars],
- Call = beam_ssa:add_anno(local_fun_opt, Fun, Call0#b_set{args=Args}),
- [Call | lfo_optimize_is(Is, LFuns, Trampolines)];
-lfo_optimize_is([I | Is], LFuns, Trampolines) ->
- [I | lfo_optimize_is(Is, LFuns, Trampolines)];
-lfo_optimize_is([], _LFuns, _Trampolines) ->
- [].
-
-lfo_short_circuit(Call, Trampolines) ->
- lfo_short_circuit(Call, Trampolines, sets:new([{version, 2}])).
-
-lfo_short_circuit(Call, Trampolines, Seen0) ->
- %% Beware of infinite loops! Get out if this call has been seen before.
- case sets:is_element(Call, Seen0) of
- true ->
- Call;
- false ->
- case Trampolines of
- #{Call := Other} ->
- Seen = sets:add_element(Call, Seen0),
- lfo_short_circuit(Other, Trampolines, Seen);
- #{} ->
- Call
- end
- end.