|
30 | 30 |
|
31 | 31 | -module(beam_ssa_type). |
32 | 32 | -moduledoc false. |
33 | | --export([opt_start/2, opt_continue/4, opt_finish/3, opt_ranges/1]). |
| 33 | +-export([opt_start/2, opt_continue/4, opt_finish/3]). |
34 | 34 |
|
35 | 35 | -include("beam_ssa_opt.hrl"). |
36 | 36 | -include("beam_types.hrl"). |
@@ -678,12 +678,6 @@ benefits_from_type_anno(is_tagged_tuple, _Args) -> |
678 | 678 | true; |
679 | 679 | benefits_from_type_anno(call, [#b_var{} | _]) -> |
680 | 680 | true; |
681 | | -benefits_from_type_anno({float,convert}, _Args) -> |
682 | | - %% Note: The {float,convert} instruction does not exist when |
683 | | - %% the main type optimizer pass is run. It is created and |
684 | | - %% annotated by ssa_opt_float1 in beam_ssa_opt, and can also |
685 | | - %% be annotated by opt_ranges/1. |
686 | | - true; |
687 | 681 | benefits_from_type_anno(get_map_element, _Args) -> |
688 | 682 | true; |
689 | 683 | benefits_from_type_anno(has_map_field, _Args) -> |
@@ -821,165 +815,6 @@ opt_finish_1([Arg | Args], [TypeMap | TypeMaps], Acc0) -> |
821 | 815 | opt_finish_1([], [], Acc) -> |
822 | 816 | Acc. |
823 | 817 |
|
824 | | -%%% |
825 | | -%%% This sub pass is run once after the main type sub pass |
826 | | -%%% to annotate more instructions with integer ranges. |
827 | | -%%% |
828 | | -%%% The main type sub pass annotates certain instructions with |
829 | | -%%% their types to help the JIT generate better code. |
830 | | -%%% |
831 | | -%%% Example: |
832 | | -%%% |
833 | | -%%% foo(N0) -> |
834 | | -%%% N1 = N0 band 3, |
835 | | -%%% N = N1 + 1, % N1 is in 0..3 |
836 | | -%%% element(N, |
837 | | -%%% {zero,one,two,three}). |
838 | | -%%% |
839 | | -%%% The main type pass is able to figure out the range for `N1` but |
840 | | -%%% not for `N`. The reason is that the type pass iterates until it |
841 | | -%%% reaches a fixpoint. To guarantee that it will converge, ranges for |
842 | | -%%% results must only be calculated for operations that retain or |
843 | | -%%% shrink the ranges of their arguments. |
844 | | -%%% |
845 | | -%%% Therefore, to ensure convergence, the main type pass can only |
846 | | -%%% safely calculate ranges for results of operations such as `and`, |
847 | | -%%% `bsr`, and `rem`, but not for operations such as `+`, '-', '*', |
848 | | -%%% and `bsl`. |
849 | | -%%% |
850 | | -%%% This sub pass will start from the types found in the annotations |
851 | | -%%% and propagate them forward through arithmetic instructions within |
852 | | -%%% the same function. |
853 | | -%%% |
854 | | -%%% For the example, this sub pass adds a new annotation for `N`: |
855 | | -%%% |
856 | | -%%% foo(N0) -> |
857 | | -%%% N1 = N0 band 3, |
858 | | -%%% N = N1 + 1, % N1 is in 0..3 |
859 | | -%%% element(N, % N is in 1..4 |
860 | | -%%% {zero,one,two,three}). |
861 | | -%%% |
862 | | -%%% With a known range and known tuple size, the JIT is able to remove |
863 | | -%%% all range checks for the `element/2` instruction. |
864 | | -%%% |
865 | | - |
866 | | --spec opt_ranges(Blocks0) -> Blocks when |
867 | | - Blocks0 :: beam_ssa:block_map(), |
868 | | - Blocks :: beam_ssa:block_map(). |
869 | | - |
870 | | -opt_ranges(Blocks) -> |
871 | | - RPO = beam_ssa:rpo(Blocks), |
872 | | - Tss = #{0 => #{}, ?EXCEPTION_BLOCK => #{}}, |
873 | | - ranges(RPO, Tss, Blocks). |
874 | | - |
875 | | -ranges([L|Ls], Tss0, Blocks0) -> |
876 | | - #b_blk{is=Is0} = Blk0 = map_get(L, Blocks0), |
877 | | - Ts0 = map_get(L, Tss0), |
878 | | - {Is,Ts} = ranges_is(Is0, Ts0, []), |
879 | | - Blk = Blk0#b_blk{is=Is}, |
880 | | - Blocks = Blocks0#{L := Blk}, |
881 | | - Tss = ranges_successors(beam_ssa:successors(Blk), Ts, Tss0), |
882 | | - ranges(Ls, Tss, Blocks); |
883 | | -ranges([], _Tss, Blocks) -> Blocks. |
884 | | - |
885 | | -ranges_is([#b_set{op=Op,args=Args}=I0|Is], Ts0, Acc) -> |
886 | | - case benefits_from_type_anno(Op, Args) of |
887 | | - false -> |
888 | | - ranges_is(Is, Ts0, [I0|Acc]); |
889 | | - true -> |
890 | | - I = update_anno_types(I0, Ts0), |
891 | | - Ts = ranges_propagate_types(I, Ts0), |
892 | | - ranges_is(Is, Ts, [I|Acc]) |
893 | | - end; |
894 | | -ranges_is([], Ts, Acc) -> |
895 | | - {reverse(Acc),Ts}. |
896 | | - |
897 | | -ranges_successors([?EXCEPTION_BLOCK|Ls], Ts, Tss) -> |
898 | | - ranges_successors(Ls, Ts, Tss); |
899 | | -ranges_successors([L|Ls], Ts0, Tss0) -> |
900 | | - case Tss0 of |
901 | | - #{L := Ts1} -> |
902 | | - Ts = join_types(Ts0, Ts1), |
903 | | - Tss = Tss0#{L := Ts}, |
904 | | - ranges_successors(Ls, Ts0, Tss); |
905 | | - #{} -> |
906 | | - Tss = Tss0#{L => Ts0}, |
907 | | - ranges_successors(Ls, Ts0, Tss) |
908 | | - end; |
909 | | -ranges_successors([], _, Tss) -> Tss. |
910 | | - |
911 | | -ranges_propagate_types(#b_set{anno=Anno,op={bif,_}=Op,args=Args,dst=Dst}, Ts) -> |
912 | | - case Anno of |
913 | | - #{arg_types := ArgTypes0} -> |
914 | | - ArgTypes = ranges_get_arg_types(Args, 0, ArgTypes0), |
915 | | - case beam_call_types:arith_type(Op, ArgTypes) of |
916 | | - any -> Ts; |
917 | | - T -> Ts#{Dst => T} |
918 | | - end; |
919 | | - #{} -> |
920 | | - Ts |
921 | | - end; |
922 | | -ranges_propagate_types(_, Ts) -> Ts. |
923 | | - |
924 | | -ranges_get_arg_types([#b_var{}|As], Index, ArgTypes) -> |
925 | | - case ArgTypes of |
926 | | - #{Index := Type} -> |
927 | | - [Type|ranges_get_arg_types(As, Index + 1, ArgTypes)]; |
928 | | - #{} -> |
929 | | - [any|ranges_get_arg_types(As, Index + 1, ArgTypes)] |
930 | | - end; |
931 | | -ranges_get_arg_types([#b_literal{val=Value}|As], Index, ArgTypes) -> |
932 | | - Type = beam_types:make_type_from_value(Value), |
933 | | - [Type|ranges_get_arg_types(As, Index + 1, ArgTypes)]; |
934 | | -ranges_get_arg_types([], _, _) -> []. |
935 | | - |
936 | | -update_anno_types(#b_set{anno=Anno,args=Args}=I, Ts) -> |
937 | | - ArgTypes1 = case Anno of |
938 | | - #{arg_types := ArgTypes0} -> ArgTypes0; |
939 | | - #{} -> #{} |
940 | | - end, |
941 | | - ArgTypes = update_anno_types_1(Args, Ts, 0, ArgTypes1), |
942 | | - case Anno of |
943 | | - #{arg_types := ArgTypes} -> |
944 | | - I; |
945 | | - #{} when map_size(ArgTypes) =/= 0 -> |
946 | | - I#b_set{anno=Anno#{arg_types => ArgTypes}}; |
947 | | - #{} -> |
948 | | - I |
949 | | - end. |
950 | | - |
951 | | -update_anno_types_1([#b_var{}=V|As], Ts, Index, ArgTypes) -> |
952 | | - T0 = case ArgTypes of |
953 | | - #{Index := T00} -> T00; |
954 | | - #{} -> any |
955 | | - end, |
956 | | - T1 = case Ts of |
957 | | - #{V := T11} -> T11; |
958 | | - #{} -> any |
959 | | - end, |
960 | | - case beam_types:meet(T0, T1) of |
961 | | - any -> |
962 | | - update_anno_types_1(As, Ts, Index + 1, ArgTypes); |
963 | | - none -> |
964 | | - %% This instruction will never be reached. This happens when |
965 | | - %% compiling code such as the following: |
966 | | - %% |
967 | | - %% f(X) when is_integer(X), 0 =< X, X < 64 -> |
968 | | - %% (X = bnot X) + 1. |
969 | | - %% |
970 | | - %% The main type optimization sub pass will not find out |
971 | | - %% that `(X = bnot X)` will never succeed and that the `+` |
972 | | - %% operator is never executed, but this sub pass will. |
973 | | - %% This happens very rarely; therefore, don't bother removing |
974 | | - %% the unreachable instruction. |
975 | | - update_anno_types_1(As, Ts, Index + 1, ArgTypes); |
976 | | - T -> |
977 | | - update_anno_types_1(As, Ts, Index + 1, ArgTypes#{Index => T}) |
978 | | - end; |
979 | | -update_anno_types_1([_|As], Ts, Index, ArgTypes) -> |
980 | | - update_anno_types_1(As, Ts, Index + 1, ArgTypes); |
981 | | -update_anno_types_1([], _, _, ArgTypes) -> ArgTypes. |
982 | | - |
983 | 818 | %%% |
984 | 819 | %%% Optimization helpers |
985 | 820 | %%% |
|
0 commit comments