diff --git a/lib/compiler/src/beam_ssa_destructive_update.erl b/lib/compiler/src/beam_ssa_destructive_update.erl index 33a3343f56f6..8efd84aadc1b 100644 --- a/lib/compiler/src/beam_ssa_destructive_update.erl +++ b/lib/compiler/src/beam_ssa_destructive_update.erl @@ -961,9 +961,8 @@ merge_patches({self,heap_tuple}, Other) -> Other. patch_phi(I0=#b_set{op=phi,args=Args0}, Patches, Cnt0) -> - L2P = foldl(fun(Phi={phi,_,Lbl,_,_}, Acc) -> - Acc#{Lbl => Phi} - end, #{}, Patches), + ?DP("Patching Phi:~n args: ~p~n patches: ~p~n", [Args0, Patches]), + L2P = foldl(fun merge_phi_patch/2, #{}, Patches), {Args, Extra, Cnt} = foldr(fun(Arg0={_,Lbl}, {ArgsAcc,ExtraAcc,CntAcc}) -> case L2P of @@ -979,6 +978,15 @@ patch_phi(I0=#b_set{op=phi,args=Args0}, Patches, Cnt0) -> I = I0#b_set{op=phi,args=Args}, {I, Extra, Cnt}. +merge_phi_patch({phi,Var,Lbl,Lit,E}, Acc) -> + case Acc of + #{Lbl:={phi,Var,Lbl,Lit,Old}} -> + Acc#{Lbl => {phi,Var,Lbl,Lit,merge_patches(E, Old)}}; + #{} -> + false = is_map_key(Lbl, Acc), %% Assert + Acc#{Lbl => {phi,Var,Lbl,Lit,E}} + end. + %% Should return the instructions in reversed order patch_literal_term(Tuple, {tuple_elements,Elems}, Cnt) -> Es = [{tuple_element,I,E,0} || {I,E} <:- keysort(1, Elems)], diff --git a/lib/compiler/test/beam_ssa_check_SUITE_data/private_append.erl b/lib/compiler/test/beam_ssa_check_SUITE_data/private_append.erl index 6c36fd429d3e..5524da9f6ea8 100644 --- a/lib/compiler/test/beam_ssa_check_SUITE_data/private_append.erl +++ b/lib/compiler/test/beam_ssa_check_SUITE_data/private_append.erl @@ -82,7 +82,9 @@ bs_create_bin_on_literal/0, crash_in_value_tracking/3, - crash_in_value_tracking_inner/3]). + crash_in_value_tracking_inner/3, + + gh9100/0]). %% Trivial smoke test transformable0(L) -> @@ -1036,3 +1038,42 @@ crash_in_value_tracking(_, _V0, _) -> ((<<((crash_in_value_tracking_inner( {#{#{ ok => ok || _ := _ <- ok} => ok}, _V0, false, _V0, "Bo"}, _V0, ok)))/bytes>>) =/= ok). + +gh9100() -> + gh9100(#{prev => nil, + next => + [{equal, <<"a">>}, + {delete, <<"y">>}]}, + {{<<>>, <<>>}}). + +%% We could fail to update multiple elements of a tuple, it was a +%% literal tuple in a Phi-instruction. +gh9100(#{next := [{Op, Text} | Next]} = Diffs, + {{TextDelete, TextInsert}}) -> +%ssa% (_, Acc) when post_ssa_opt -> +%ssa% switch(X, Fail, [{'delete',_},{'equal',Equal},...]), +%ssa% label Equal, +%ssa% A = bs_init_writable(_), +%ssa% B = bs_init_writable(_), +%ssa% C = put_tuple(A, B), +%ssa% D = put_tuple(C). + Acc = + case Op of + insert -> + {{TextDelete, + <>}}; + delete -> + {{<>, + TextInsert}}; + equal -> + {{<<>>, <<>>}} %% Bug is here. + end, + gh9100(#{prev => + case Diffs of + #{prev := Prev} -> + Prev; + Other -> + ex:no_parens_remote(Other) + end, + next => Next}, + Acc).