Deadcode elimination pass
This commit is contained in:
parent
cbc8909954
commit
e94b5379ed
@ -1007,13 +1007,16 @@ lambda_lift_exprs(As) -> [lambda_lift_expr(A) || A <- As].
|
|||||||
|
|
||||||
-spec optimize_fcode(fcode()) -> fcode().
|
-spec optimize_fcode(fcode()) -> fcode().
|
||||||
optimize_fcode(Code = #{ functions := Funs }) ->
|
optimize_fcode(Code = #{ functions := Funs }) ->
|
||||||
Code#{ functions := maps:map(fun(Name, Def) -> optimize_fun(Code, Name, Def) end, Funs) }.
|
Code1 = Code#{ functions := maps:map(fun(Name, Def) -> optimize_fun(Code, Name, Def) end, Funs) },
|
||||||
|
eliminate_dead_code(Code1).
|
||||||
|
|
||||||
-spec optimize_fun(fcode(), fun_name(), fun_def()) -> fun_def().
|
-spec optimize_fun(fcode(), fun_name(), fun_def()) -> fun_def().
|
||||||
optimize_fun(Fcode, Fun, Def = #{ body := Body }) ->
|
optimize_fun(Fcode, Fun, Def = #{ body := Body }) ->
|
||||||
%% io:format("Optimizing ~p =\n~s\n", [_Fun, prettypr:format(pp_fexpr(_Body))]),
|
%% io:format("Optimizing ~p =\n~s\n", [_Fun, prettypr:format(pp_fexpr(_Body))]),
|
||||||
Def#{ body := inliner(Fcode, Fun, Body) }.
|
Def#{ body := inliner(Fcode, Fun, Body) }.
|
||||||
|
|
||||||
|
%% --- Inlining ---
|
||||||
|
|
||||||
-spec inliner(fcode(), fun_name(), fexpr()) -> fexpr().
|
-spec inliner(fcode(), fun_name(), fexpr()) -> fexpr().
|
||||||
inliner(Fcode, Fun, {def, Fun1, Args} = E) when Fun1 /= Fun ->
|
inliner(Fcode, Fun, {def, Fun1, Args} = E) when Fun1 /= Fun ->
|
||||||
case should_inline(Fcode, Fun1) of
|
case should_inline(Fcode, Fun1) of
|
||||||
@ -1026,6 +1029,33 @@ should_inline(_Fcode, _Fun1) -> false == list_to_atom("true"). %% Dialyzer
|
|||||||
|
|
||||||
inline(_Fcode, Fun, Args) -> {def, Fun, Args}. %% TODO
|
inline(_Fcode, Fun, Args) -> {def, Fun, Args}. %% TODO
|
||||||
|
|
||||||
|
%% --- Deadcode elimination ---
|
||||||
|
|
||||||
|
-spec eliminate_dead_code(fcode()) -> fcode().
|
||||||
|
eliminate_dead_code(Code = #{ functions := Funs }) ->
|
||||||
|
UsedFuns = used_functions(Funs),
|
||||||
|
Code#{ functions := maps:filter(fun(Name, _) -> maps:is_key(Name, UsedFuns) end,
|
||||||
|
Funs) }.
|
||||||
|
|
||||||
|
-spec used_functions(#{ fun_name() => fun_def() }) -> #{ fun_name() => true }.
|
||||||
|
used_functions(Funs) ->
|
||||||
|
Exported = [ Fun || {Fun, #{ attrs := Attrs }} <- maps:to_list(Funs),
|
||||||
|
not lists:member(private, Attrs) ],
|
||||||
|
used_functions(#{}, Exported, Funs).
|
||||||
|
|
||||||
|
used_functions(Used, [], _) -> Used;
|
||||||
|
used_functions(Used, [Name | Rest], Defs) ->
|
||||||
|
case maps:is_key(Name, Used) of
|
||||||
|
true -> used_functions(Used, Rest, Defs);
|
||||||
|
false ->
|
||||||
|
New =
|
||||||
|
case maps:get(Name, Defs, undef) of
|
||||||
|
undef -> []; %% We might be compiling a stub
|
||||||
|
#{ body := Body } -> used_defs(Body)
|
||||||
|
end,
|
||||||
|
used_functions(Used#{ Name => true }, New ++ Rest, Defs)
|
||||||
|
end.
|
||||||
|
|
||||||
%% -- Helper functions -------------------------------------------------------
|
%% -- Helper functions -------------------------------------------------------
|
||||||
|
|
||||||
%% -- Types --
|
%% -- Types --
|
||||||
@ -1195,6 +1225,34 @@ free_vars(Expr) ->
|
|||||||
{'case', P, A} -> free_vars(A) -- lists:sort(fsplit_pat_vars(P))
|
{'case', P, A} -> free_vars(A) -- lists:sort(fsplit_pat_vars(P))
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
used_defs(Xs) when is_list(Xs) ->
|
||||||
|
lists:umerge([ used_defs(X) || X <- Xs ]);
|
||||||
|
used_defs(Expr) ->
|
||||||
|
case Expr of
|
||||||
|
{var, _} -> [];
|
||||||
|
{lit, _} -> [];
|
||||||
|
nil -> [];
|
||||||
|
{def, F, As} -> lists:umerge([F], used_defs(As));
|
||||||
|
{def_u, F, _} -> [F];
|
||||||
|
{remote, _, _, Ct, _, As} -> used_defs([Ct | As]);
|
||||||
|
{remote_u, _, _, Ct, _} -> used_defs(Ct);
|
||||||
|
{builtin, _, As} -> used_defs(As);
|
||||||
|
{builtin_u, _, _} -> [];
|
||||||
|
{con, _, _, As} -> used_defs(As);
|
||||||
|
{tuple, As} -> used_defs(As);
|
||||||
|
{proj, A, _} -> used_defs(A);
|
||||||
|
{set_proj, A, _, B} -> used_defs([A, B]);
|
||||||
|
{op, _, As} -> used_defs(As);
|
||||||
|
{'let', _, A, B} -> used_defs([A, B]);
|
||||||
|
{funcall, A, Bs} -> used_defs([A | Bs]);
|
||||||
|
{lam, _, B} -> used_defs(B);
|
||||||
|
{closure, F, A} -> lists:umerge([F], used_defs(A));
|
||||||
|
{switch, A} -> used_defs(A);
|
||||||
|
{split, _, _, As} -> used_defs(As);
|
||||||
|
{nosplit, A} -> used_defs(A);
|
||||||
|
{'case', _, A} -> used_defs(A)
|
||||||
|
end.
|
||||||
|
|
||||||
get_named_args(NamedArgsT, Args) ->
|
get_named_args(NamedArgsT, Args) ->
|
||||||
IsNamed = fun({named_arg, _, _, _}) -> true;
|
IsNamed = fun({named_arg, _, _, _}) -> true;
|
||||||
(_) -> false end,
|
(_) -> false end,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user