aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src/beam_ssa_dead.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler/src/beam_ssa_dead.erl')
-rw-r--r--lib/compiler/src/beam_ssa_dead.erl104
1 files changed, 51 insertions, 53 deletions
diff --git a/lib/compiler/src/beam_ssa_dead.erl b/lib/compiler/src/beam_ssa_dead.erl
index c573c869cf..088d90b405 100644
--- a/lib/compiler/src/beam_ssa_dead.erl
+++ b/lib/compiler/src/beam_ssa_dead.erl
@@ -89,12 +89,11 @@ shortcut_opt(#st{bs=Blocks}=St) ->
%% running scripts/diffable with both PO and RPO and looking at
%% the diff.)
Ls = beam_ssa:rpo(Blocks),
- shortcut_opt(Ls, #{from=>0}, St).
+ shortcut_opt(Ls, #{}, St).
-shortcut_opt([L|Ls], Bs0, #st{bs=Blocks0}=St) ->
+shortcut_opt([L|Ls], Bs, #st{bs=Blocks0}=St) ->
#b_blk{is=Is,last=Last0} = Blk0 = get_block(L, St),
- Bs = Bs0#{from:=L},
- case shortcut_terminator(Last0, Is, Bs, St) of
+ case shortcut_terminator(Last0, Is, L, Bs, St) of
Last0 ->
%% No change. No need to update the block.
shortcut_opt(Ls, Bs, St);
@@ -108,17 +107,17 @@ shortcut_opt([L|Ls], Bs0, #st{bs=Blocks0}=St) ->
shortcut_opt([], _, St) -> St.
shortcut_terminator(#b_br{bool=#b_literal{val=true},succ=Succ0},
- _Is, Bs, St0) ->
+ _Is, From, Bs, St0) ->
St = St0#st{rel_op=none},
- shortcut(Succ0, Bs, St);
+ shortcut(Succ0, From, Bs, St);
shortcut_terminator(#b_br{bool=#b_var{}=Bool,succ=Succ0,fail=Fail0}=Br,
- Is, Bs, St0) ->
+ Is, From, Bs, St0) ->
St = St0#st{target=one_way},
RelOp = get_rel_op(Bool, Is),
SuccBs = bind_var(Bool, #b_literal{val=true}, Bs),
- BrSucc = shortcut(Succ0, SuccBs, St#st{rel_op=RelOp}),
+ BrSucc = shortcut(Succ0, From, SuccBs, St#st{rel_op=RelOp}),
FailBs = bind_var(Bool, #b_literal{val=false}, Bs),
- BrFail = shortcut(Fail0, FailBs, St#st{rel_op=invert_op(RelOp)}),
+ BrFail = shortcut(Fail0, From, FailBs, St#st{rel_op=invert_op(RelOp)}),
case {BrSucc,BrFail} of
{#b_br{bool=#b_literal{val=true},succ=Succ},
#b_br{bool=#b_literal{val=true},succ=Fail}}
@@ -129,25 +128,25 @@ shortcut_terminator(#b_br{bool=#b_var{}=Bool,succ=Succ0,fail=Fail0}=Br,
%% No change.
Br
end;
-shortcut_terminator(#b_switch{arg=Bool,list=List0}=Sw, _Is, Bs, St) ->
- List = shortcut_switch(List0, Bool, Bs, St),
+shortcut_terminator(#b_switch{arg=Bool,list=List0}=Sw, _Is, From, Bs, St) ->
+ List = shortcut_switch(List0, Bool, From, Bs, St),
beam_ssa:normalize(Sw#b_switch{list=List});
-shortcut_terminator(Last, _Is, _Bs, _St) ->
+shortcut_terminator(Last, _Is, _Bs, _From, _St) ->
Last.
-shortcut_switch([{Lit,L0}|T], Bool, Bs, St0) ->
+shortcut_switch([{Lit,L0}|T], Bool, From, Bs, St0) ->
RelOp = {'=:=',Bool,Lit},
St = St0#st{rel_op=RelOp},
#b_br{bool=#b_literal{val=true},succ=L} =
- shortcut(L0, bind_var(Bool, Lit, Bs), St#st{target=one_way}),
- [{Lit,L}|shortcut_switch(T, Bool, Bs, St0)];
-shortcut_switch([], _, _, _) -> [].
+ shortcut(L0, From, bind_var(Bool, Lit, Bs), St#st{target=one_way}),
+ [{Lit,L}|shortcut_switch(T, Bool, From, Bs, St0)];
+shortcut_switch([], _, _, _, _) -> [].
-shortcut(L, Bs, St) ->
- shortcut_1(L, Bs, ordsets:new(), St).
+shortcut(L, From, Bs, St) ->
+ shortcut_1(L, From, Bs, ordsets:new(), St).
-shortcut_1(L, Bs0, UnsetVars0, St) ->
- case shortcut_2(L, Bs0, UnsetVars0, St) of
+shortcut_1(L, From, Bs0, UnsetVars0, St) ->
+ case shortcut_2(L, From, Bs0, UnsetVars0, St) of
none ->
%% No more shortcuts found. Package up the previous
%% label in an unconditional branch.
@@ -157,13 +156,13 @@ shortcut_1(L, Bs0, UnsetVars0, St) ->
Br;
{#b_br{bool=#b_literal{val=true},succ=Succ},Bs,UnsetVars} ->
%% This is a safe `br`, but try to find a better one.
- shortcut_1(Succ, Bs#{from:=L}, UnsetVars, St)
+ shortcut_1(Succ, L, Bs, UnsetVars, St)
end.
%% Try to shortcut this block, branching to a successor.
-shortcut_2(L, Bs0, UnsetVars0, St) ->
+shortcut_2(L, From, Bs0, UnsetVars0, St) ->
#b_blk{is=Is,last=Last} = get_block(L, St),
- case eval_is(Is, Bs0, St) of
+ case eval_is(Is, From, Bs0, St) of
none ->
%% It is not safe to avoid this block because it
%% has instructions with potential side effects.
@@ -187,25 +186,24 @@ shortcut_2(L, Bs0, UnsetVars0, St) ->
%% It is unsafe to use this br,
%% because it refers to a variable defined
%% in this block.
- shortcut_unsafe_br(Br, Bs, UnsetVars0, St);
+ shortcut_unsafe_br(Br, L, Bs, UnsetVars0, St);
UnsetVars ->
%% Continue checking whether this br is
%% suitable.
- shortcut_test_br(Br, Bs#{from:=L},
- UnsetVars, St)
+ shortcut_test_br(Br, L, Bs, UnsetVars, St)
end
end
end.
-shortcut_test_br(Br, Bs, UnsetVars, St) ->
+shortcut_test_br(Br, From, Bs, UnsetVars, St) ->
case is_br_safe(UnsetVars, Br, St) of
false ->
- shortcut_unsafe_br(Br, Bs, UnsetVars, St);
+ shortcut_unsafe_br(Br, From, Bs, UnsetVars, St);
true ->
- shortcut_safe_br(Br, Bs, UnsetVars, St)
+ shortcut_safe_br(Br, From, Bs, UnsetVars, St)
end.
-shortcut_unsafe_br(Br, Bs, UnsetVars, #st{target=Target}=St) ->
+shortcut_unsafe_br(Br, From, Bs, UnsetVars, #st{target=Target}=St) ->
%% Branching using this `br` is unsafe, either because it
%% is an unconditional branch to a phi node, or because
%% one or more of the variables that are not set will be
@@ -221,7 +219,7 @@ shortcut_unsafe_br(Br, Bs, UnsetVars, #st{target=Target}=St) ->
_ ->
%% Try following this branch to see whether it
%% leads to a safe `br`.
- shortcut_2(L, Bs, UnsetVars, St)
+ shortcut_2(L, From, Bs, UnsetVars, St)
end;
#b_br{bool=#b_var{},succ=Succ,fail=Fail} ->
case {Succ,Fail} of
@@ -230,23 +228,23 @@ shortcut_unsafe_br(Br, Bs, UnsetVars, #st{target=Target}=St) ->
%% Try following the success label to see
%% whether it also ultimately ends up at the
%% forced target.
- shortcut_2(L, Bs, UnsetVars, St);
+ shortcut_2(L, From, Bs, UnsetVars, St);
{Target,L} ->
%% The success label is the forced target.
%% Try following the failure label to see
%% whether it also ultimately ends up at the
%% forced target.
- shortcut_2(L, Bs, UnsetVars, St);
+ shortcut_2(L, From, Bs, UnsetVars, St);
{_,_} ->
case Target of
any ->
%% This two-way branch is unsafe. Try
%% reducing it to a one-way branch.
- shortcut_two_way(Br, Bs, UnsetVars, St);
+ shortcut_two_way(Br, From, Bs, UnsetVars, St);
one_way ->
%% This two-way branch is unsafe. Try
%% reducing it to a one-way branch.
- shortcut_two_way(Br, Bs, UnsetVars, St);
+ shortcut_two_way(Br, From, Bs, UnsetVars, St);
_ when is_integer(Target) ->
%% This two-way branch is unsafe, and
%% there already is a forced target.
@@ -256,7 +254,7 @@ shortcut_unsafe_br(Br, Bs, UnsetVars, #st{target=Target}=St) ->
end
end.
-shortcut_safe_br(Br, Bs, UnsetVars, #st{target=Target}=St) ->
+shortcut_safe_br(Br, From, Bs, UnsetVars, #st{target=Target}=St) ->
%% This `br` instruction is safe. It does not branch to a phi
%% node, and all variables that will be used are guaranteed to be
%% defined.
@@ -278,7 +276,7 @@ shortcut_safe_br(Br, Bs, UnsetVars, #st{target=Target}=St) ->
%% Wrong forced target. Try following this branch
%% to see if it ultimately ends up at the forced
%% target.
- shortcut_2(L, Bs, UnsetVars, St)
+ shortcut_2(L, From, Bs, UnsetVars, St)
end;
#b_br{bool=#b_var{}} ->
%% This is a two-way branch.
@@ -286,7 +284,7 @@ shortcut_safe_br(Br, Bs, UnsetVars, #st{target=Target}=St) ->
Target =:= any; Target =:= one_way ->
%% No specific forced target. Try to reduce the
%% two-way branch to an one-way branch.
- case shortcut_two_way(Br, Bs, UnsetVars, St) of
+ case shortcut_two_way(Br, From, Bs, UnsetVars, St) of
none when Target =:= any ->
%% This `br` can't be reduced to a one-way
%% branch. Return the `br` as-is.
@@ -342,12 +340,13 @@ update_unset_vars(L, Is, Br, UnsetVars, #st{skippable=Skippable}) ->
ordsets:union(UnsetVars, ordsets:from_list(SetInThisBlock))
end.
-shortcut_two_way(#b_br{succ=Succ,fail=Fail}, Bs0, UnsetVars0, St) ->
- case shortcut_2(Succ, Bs0, UnsetVars0, St#st{target=Fail}) of
+shortcut_two_way(#b_br{succ=Succ,fail=Fail}, From, Bs0, UnsetVars0, St0) ->
+ case shortcut_2(Succ, From, Bs0, UnsetVars0, St0#st{target=Fail}) of
{#b_br{bool=#b_literal{},succ=Fail},_,_}=Res ->
Res;
none ->
- case shortcut_2(Fail, Bs0, UnsetVars0, St#st{target=Succ}) of
+ St = St0#st{target=Succ},
+ case shortcut_2(Fail, From, Bs0, UnsetVars0, St) of
{#b_br{bool=#b_literal{},succ=Succ},_,_}=Res ->
Res;
none ->
@@ -389,40 +388,39 @@ is_forbidden(L, St) ->
%% Return the updated bindings, or 'none' if there is
%% any instruction with potential side effects.
-eval_is([#b_set{op=phi,dst=Dst,args=Args}|Is], Bs0, St) ->
- From = map_get(from, Bs0),
+eval_is([#b_set{op=phi,dst=Dst,args=Args}|Is], From, Bs0, St) ->
Val = get_phi_arg(Args, From),
Bs = bind_var(Dst, Val, Bs0),
- eval_is(Is, Bs, St);
-eval_is([#b_set{op={bif,_},dst=Dst}=I0|Is], Bs, St) ->
+ eval_is(Is, From, Bs, St);
+eval_is([#b_set{op={bif,_},dst=Dst}=I0|Is], From, Bs, St) ->
I = sub(I0, Bs),
case eval_bif(I, St) of
#b_literal{}=Val ->
- eval_is(Is, bind_var(Dst, Val, Bs), St);
+ eval_is(Is, From, bind_var(Dst, Val, Bs), St);
none ->
- eval_is(Is, Bs, St)
+ eval_is(Is, From, Bs, St)
end;
-eval_is([#b_set{op=Op,dst=Dst}=I|Is], Bs, St)
+eval_is([#b_set{op=Op,dst=Dst}=I|Is], From, Bs, St)
when Op =:= is_tagged_tuple; Op =:= is_nonempty_list ->
#b_set{args=Args} = sub(I, Bs),
case eval_rel_op(Op, Args, St) of
#b_literal{}=Val ->
- eval_is(Is, bind_var(Dst, Val, Bs), St);
+ eval_is(Is, From, bind_var(Dst, Val, Bs), St);
none ->
- eval_is(Is, Bs, St)
+ eval_is(Is, From, Bs, St)
end;
-eval_is([#b_set{}=I|Is], Bs, St) ->
+eval_is([#b_set{}=I|Is], From, Bs, St) ->
case beam_ssa:no_side_effect(I) of
true ->
%% This instruction has no side effects. It can
%% safely be omitted.
- eval_is(Is, Bs, St);
+ eval_is(Is, From, Bs, St);
false ->
%% This instruction may have some side effect.
%% It is not safe to avoid this instruction.
none
end;
-eval_is([], Bs, _St) -> Bs.
+eval_is([], _From, Bs, _St) -> Bs.
get_phi_arg([{Val,From}|_], From) -> Val;
get_phi_arg([_|As], From) -> get_phi_arg(As, From).