Skip to content

Commit

Permalink
Fix register allocation in the presence of unused phi nodes
Browse files Browse the repository at this point in the history
This fixes erlang#7248, but it might not be the best or most elegant
fix.
  • Loading branch information
bjorng committed May 17, 2023
1 parent 2c864f2 commit fb5d991
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 19 deletions.
9 changes: 6 additions & 3 deletions lib/compiler/src/beam_ssa_codegen.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1435,11 +1435,14 @@ cg_copy(T0, St) ->
cg_copy_1([#cg_set{dst=Dst0,args=Args}|T], St) ->
[Dst,Src] = beam_args([Dst0|Args], St),
Copies = cg_copy_1(T, St),
case keymember(Dst, 3, Copies) of
true ->
case {Dst,keymember(Dst, 3, Copies)} of
{{z,_},_} ->
%% This copy operation originated from an unused phi node.
Copies;
{_,true} ->
%% Will be overwritten. Don't generate a move instruction.
Copies;
false ->
{_,false} ->
[{move,Src,Dst}|Copies]
end;
cg_copy_1([], _St) -> [].
Expand Down
47 changes: 31 additions & 16 deletions lib/compiler/src/beam_ssa_pre_codegen.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2563,39 +2563,54 @@ reserve_arg_regs([#b_var{}=Arg|Is], N, Acc) ->
reserve_arg_regs([], _, Acc) -> Acc.

reserve_zregs(RPO, Blocks, Intervals, Res) ->
ShortLived0 = [V || {V,[{Start,End}]} <- Intervals, Start+2 =:= End],
ShortLived = sets:from_list(ShortLived0, [{version, 2}]),
LifeTime = #{V => if
Start + 2 =:= End -> short;
Start =:= End -> unused;
true -> normal
end || {V,[{Start,End}]} <- Intervals},
F = fun(_, #b_blk{is=Is,last=Last}, A) ->
reserve_zreg(Is, Last, ShortLived, A)
reserve_zreg(Is, Last, LifeTime, A)
end,
beam_ssa:fold_blocks(F, RPO, Res, Blocks).

reserve_zreg([#b_set{op={bif,tuple_size},dst=Dst},
#b_set{op={bif,'=:='},args=[Dst,Val],dst=Bool}],
Last, ShortLived, A) ->
Last, LifeTime, A) ->
case {Val,Last} of
{#b_literal{val=Arity},#b_br{bool=Bool}} when Arity bsr 32 =:= 0 ->
%% These two instructions can be combined to a test_arity
%% instruction provided that the arity variable is short-lived.
reserve_test_zreg(Dst, ShortLived, A);
reserve_test_zreg(Dst, LifeTime, A);
{_,_} ->
%% Either the arity is too big, or the boolean value is not
%% used in a conditional branch.
A
end;
reserve_zreg([#b_set{op={bif,tuple_size},dst=Dst}],
#b_switch{arg=Dst}, ShortLived, A) ->
reserve_test_zreg(Dst, ShortLived, A);
reserve_zreg([#b_set{op=Op,dst=Dst}], #b_br{bool=Dst}, ShortLived, A) ->
#b_switch{arg=Dst}, LifeTime, A) ->
reserve_test_zreg(Dst, LifeTime, A);
reserve_zreg([#b_set{op=Op,dst=Dst}], #b_br{bool=Dst}, LifeTime, A) ->
case use_zreg(Op) of
yes -> [{Dst,z} | A];
no -> A;
'maybe' -> reserve_test_zreg(Dst, ShortLived, A)
'maybe' -> reserve_test_zreg(Dst, LifeTime, A)
end;
reserve_zreg([#b_set{op=phi,args=[_],dst=Dst}|Is], Last, LifeTime, A) ->
case LifeTime of
#{Dst := unused} ->
%% This phi node is unused. It is important that we don't assign
%% the unused phi node to an X register. For example:
%% A = phi { x0/_2, ^42 }
%% _unused = phi { x1, ^42 }
%% ret A
reserve_zreg(Is, Last, LifeTime, [{Dst,z}|A]);
#{} ->
reserve_zreg(Is, Last, LifeTime, A)
end;
reserve_zreg([#b_set{op=Op,dst=Dst} | Is], Last, ShortLived, A) ->
reserve_zreg([#b_set{op=Op,dst=Dst} | Is], Last, LifeTime, A) ->
case use_zreg(Op) of
yes -> reserve_zreg(Is, Last, ShortLived, [{Dst,z} | A]);
_Other -> reserve_zreg(Is, Last, ShortLived, A)
yes -> reserve_zreg(Is, Last, LifeTime, [{Dst,z} | A]);
_Other -> reserve_zreg(Is, Last, LifeTime, A)
end;
reserve_zreg([], _, _, A) -> A.

Expand Down Expand Up @@ -2628,10 +2643,10 @@ use_zreg(_) -> 'maybe'.

%% If V is defined just before a branch, we may be able to combine it into a
%% test instruction.
reserve_test_zreg(#b_var{}=V, ShortLived, A) ->
case sets:is_element(V, ShortLived) of
true -> [{V,z}|A];
false -> A
reserve_test_zreg(#b_var{}=V, LifeTime, A) ->
case LifeTime of
#{V := short} -> [{V,z}|A];
#{} -> A
end.

reserve_fregs(RPO, Blocks, Res) ->
Expand Down

0 comments on commit fb5d991

Please sign in to comment.