@@ -815,9 +815,8 @@ do_sanitize_is(#b_set{op=Op,dst=Dst,args=Args0}=I0,
815
815
Is , Last , InBlocks , Blocks , Count , Values , Changed0 , Acc ) ->
816
816
Args = sanitize_args (Args0 , Values ),
817
817
case sanitize_instr (Op , Args , I0 , Blocks ) of
818
- {value ,Value0 } ->
819
- Value = # b_literal {val = Value0 },
820
- sanitize_is (Is , Last , InBlocks , Blocks , Count , Values #{Dst => Value },
818
+ {subst ,Subst } ->
819
+ sanitize_is (Is , Last , InBlocks , Blocks , Count , Values #{Dst => Subst },
821
820
true , Acc );
822
821
{ok ,I } ->
823
822
sanitize_is (Is , Last , InBlocks , Blocks , Count , Values , true , [I |Acc ]);
@@ -865,20 +864,43 @@ sanitize_arg(Arg, _Values) ->
865
864
sanitize_instr (phi , PhiArgs0 , I , Blocks ) ->
866
865
PhiArgs = [{V ,L } || {V ,L } <- PhiArgs0 ,
867
866
is_map_key (L , Blocks )],
868
- case phi_all_same_literal (PhiArgs ) of
867
+ case phi_all_same (PhiArgs ) of
869
868
true ->
870
869
% % (Can only happen when some optimizations have been
871
870
% % turned off.)
872
871
% %
873
- % % This phi node always produces the same literal value.
874
- % % We must do constant propagation of the value to ensure
875
- % % that we can sanitize any instructions that don't accept
876
- % % literals (such as `get_hd`). This is necessary for
877
- % % correctness, because beam_ssa_codegen:prefer_xregs/2
878
- % % does constant propagation and could propagate a literal
879
- % % into an instruction that don't accept literals.
880
- [{# b_literal {val = Val },_ }|_ ] = PhiArgs ,
881
- {value ,Val };
872
+ % % This phi node always produces the same literal value or
873
+ % % variable.
874
+ % %
875
+ % % We must do constant propagation of literal values to
876
+ % % ensure that we can sanitize any instructions that don't
877
+ % % accept literals (such as `get_hd`). This is necessary
878
+ % % for correctness, because
879
+ % % beam_ssa_codegen:prefer_xregs/2 does constant
880
+ % % propagation and could propagate a literal into an
881
+ % % instruction that don't accept literals.
882
+ % %
883
+ % % The singleton phi nodes generated for the try/catch
884
+ % % construct are problematic. For example:
885
+ % %
886
+ % % try B = (A = bit_size(iolist_to_binary("a"))) rem 1 of
887
+ % % _ -> A;
888
+ % % _ -> B
889
+ % % after
890
+ % % ok
891
+ % % end.
892
+ % %
893
+ % % The try expression exports three values, resulting in three
894
+ % % singleton phi nodes (with optimizations disabled):
895
+ % %
896
+ % % _4 = phi { B, ^15 }
897
+ % % A = phi { _2, ^15 }
898
+ % % _14 = phi { B, ^15 }
899
+ % %
900
+ % % All three variable will be assigned to the same register,
901
+ % % causing the correct variable (`A`) to be overwritten by `_14`.
902
+ [{Subst ,_ }|_ ] = PhiArgs ,
903
+ {subst ,Subst };
882
904
false ->
883
905
{ok ,I # b_set {args = PhiArgs }}
884
906
end ;
@@ -891,7 +913,7 @@ sanitize_instr({bif,Bif}, [#b_literal{val=Lit}], _I) ->
891
913
ok ;
892
914
true ->
893
915
try
894
- {value , erlang :Bif (Lit )}
916
+ {subst , # b_literal { val = erlang :Bif (Lit )} }
895
917
catch
896
918
error :_ ->
897
919
ok
@@ -900,7 +922,7 @@ sanitize_instr({bif,Bif}, [#b_literal{val=Lit}], _I) ->
900
922
sanitize_instr ({bif ,Bif }, [# b_literal {val = Lit1 },# b_literal {val = Lit2 }], _I ) ->
901
923
true = erl_bifs :is_pure (erlang , Bif , 2 ), % Assertion.
902
924
try
903
- {value , erlang :Bif (Lit1 , Lit2 )}
925
+ {subst , # b_literal { val = erlang :Bif (Lit1 , Lit2 )} }
904
926
catch
905
927
error :_ ->
906
928
ok
@@ -913,43 +935,44 @@ sanitize_instr(bs_match, Args, I) ->
913
935
% % other data types as well.
914
936
{ok ,I # b_set {op = bs_get ,args = Args }};
915
937
sanitize_instr (get_hd , [# b_literal {val = [Hd |_ ]}], _I ) ->
916
- {value , Hd };
938
+ {subst , # b_literal { val = Hd } };
917
939
sanitize_instr (get_tl , [# b_literal {val = [_ |Tl ]}], _I ) ->
918
- {value , Tl };
940
+ {subst , # b_literal { val = Tl } };
919
941
sanitize_instr (get_tuple_element , [# b_literal {val = T },
920
942
# b_literal {val = I }], _I )
921
943
when I < tuple_size (T ) ->
922
- {value ,element (I + 1 , T )};
923
- sanitize_instr (is_nonempty_list , [# b_literal {val = Lit }], _I ) ->
924
- {value ,case Lit of
925
- [_ |_ ] -> true ;
926
- _ -> false
927
- end };
944
+ {subst ,# b_literal {val = element (I + 1 , T )}};
945
+ sanitize_instr (is_nonempty_list , [# b_literal {val = Term }], _I ) ->
946
+ Lit = case Term of
947
+ [_ |_ ] -> true ;
948
+ _ -> false
949
+ end ,
950
+ {subst ,# b_literal {val = Lit }};
928
951
sanitize_instr (is_tagged_tuple , [# b_literal {val = Tuple },
929
952
# b_literal {val = Arity },
930
953
# b_literal {val = Tag }], _I )
931
954
when is_integer (Arity ), is_atom (Tag ) ->
932
955
if
933
956
tuple_size (Tuple ) =:= Arity , element (1 , Tuple ) =:= Tag ->
934
- {value , true };
957
+ {subst , # b_literal { val = true } };
935
958
true ->
936
- {value , false }
959
+ {subst , # b_literal { val = false } }
937
960
end ;
938
961
sanitize_instr (succeeded , [# b_literal {}], _I ) ->
939
- {value , true };
962
+ {subst , # b_literal { val = true } };
940
963
sanitize_instr (_ , _ , _ ) ->
941
964
ok .
942
965
943
- phi_all_same_literal ([{# b_literal {} = Arg , _From } | Phis ]) ->
944
- phi_all_same_literal_1 (Phis , Arg );
945
- phi_all_same_literal ([_ |_ ]) ->
966
+ phi_all_same ([{Arg ,_From }| Phis ]) ->
967
+ phi_all_same_1 (Phis , Arg );
968
+ phi_all_same ([_ |_ ]) ->
946
969
false .
947
970
948
- phi_all_same_literal_1 ([{Arg , _From } | Phis ], Arg ) ->
949
- phi_all_same_literal_1 (Phis , Arg );
950
- phi_all_same_literal_1 ([], _Arg ) ->
971
+ phi_all_same_1 ([{Arg ,_From }| Phis ], Arg ) ->
972
+ phi_all_same_1 (Phis , Arg );
973
+ phi_all_same_1 ([], _Arg ) ->
951
974
true ;
952
- phi_all_same_literal_1 (_Phis , _Arg ) ->
975
+ phi_all_same_1 (_Phis , _Arg ) ->
953
976
false .
954
977
955
978
% %% Rewrite certain calls to erlang:error/{1,2} to specialized
0 commit comments