diff options
Diffstat (limited to 'lib/hipe/icode/hipe_icode_primops.erl')
-rw-r--r-- | lib/hipe/icode/hipe_icode_primops.erl | 999 |
1 files changed, 0 insertions, 999 deletions
diff --git a/lib/hipe/icode/hipe_icode_primops.erl b/lib/hipe/icode/hipe_icode_primops.erl deleted file mode 100644 index 2941cf15fc..0000000000 --- a/lib/hipe/icode/hipe_icode_primops.erl +++ /dev/null @@ -1,999 +0,0 @@ -%% -*- erlang-indent-level: 2 -*- -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Copyright (c) 2001 by Erik Johansson. All Rights Reserved -%% ==================================================================== -%% Filename : hipe_icode_primops.erl -%% Module : hipe_icode_primops -%% Purpose : -%% Notes : -%% History : * 2001-06-13 Erik Johansson (happi@it.uu.se): -%% Created. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - --module(hipe_icode_primops). - --export([is_safe/1, fails/1, pp/2, type/1, type/2, arg_types/1]). - --include("hipe_icode.hrl"). --include("hipe_icode_primops.hrl"). - -%%--------------------------------------------------------------------- - -%% Note that 'unsafe_...' operations are generally "safe", i.e., it is -%% typically unsafe to use them unless you have extra information about -%% the call (e.g., if the types are known). However, if they have been -%% correctly introduced in the code, most of them are also OK to remove -%% if the result is not used. - --spec is_safe(icode_primop()) -> boolean(). - -is_safe('+') -> false; -is_safe('/') -> false; -is_safe('*') -> false; -is_safe('-') -> false; -is_safe('bsr') -> false; -is_safe('bsl') -> false; -is_safe('band') -> false; -is_safe('bor') -> false; -is_safe('bxor') -> false; -is_safe('bnot') -> false; -is_safe('div') -> false; -is_safe('rem') -> false; -is_safe(call_fun) -> false; -is_safe(check_get_msg) -> false; -is_safe(clear_timeout) -> false; -is_safe(cons) -> true; -%% is_safe(conv_to_float) -> false; -is_safe(extra_unsafe_add) -> true; -is_safe(extra_unsafe_sub) -> true; -is_safe(fcheckerror) -> false; -is_safe(fclearerror) -> false; -is_safe(fp_add) -> false; -is_safe(fp_div) -> false; -is_safe(fp_mul) -> false; -is_safe(fp_sub) -> false; -is_safe(mktuple) -> true; -is_safe(next_msg) -> false; -is_safe(recv_mark) -> false; -is_safe(recv_set) -> false; -is_safe(redtest) -> false; -is_safe(select_msg) -> false; -is_safe(self) -> true; -is_safe(set_timeout) -> false; -is_safe(suspend_msg) -> false; -is_safe(unsafe_add) -> true; -is_safe(unsafe_band) -> true; -is_safe(unsafe_bnot) -> true; -is_safe(unsafe_bor) -> true; -is_safe(unsafe_bsl) -> true; -is_safe(unsafe_bsr) -> true; -is_safe(unsafe_bxor) -> true; -is_safe(unsafe_hd) -> true; -is_safe(unsafe_sub) -> true; -is_safe(unsafe_tag_float) -> true; -is_safe(unsafe_tl) -> true; -is_safe(unsafe_untag_float) -> true; -is_safe(#apply_N{}) -> false; -is_safe(#closure_element{}) -> true; -is_safe(#element{}) -> false; -%% is_safe(#gc_test{}) -> ??? -is_safe({hipe_bs_primop, {bs_start_match, _}}) -> false; -is_safe({hipe_bs_primop, {{bs_start_match, bitstr}, _}}) -> true; -is_safe({hipe_bs_primop, {{bs_start_match, ok_matchstate}, _}}) -> false; -is_safe({hipe_bs_primop, {bs_get_binary, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_get_binary_all, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_get_binary_all_2, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_get_integer, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_get_float, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_skip_bits, _}}) -> false; -is_safe({hipe_bs_primop, {bs_skip_bits_all, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_test_tail, _}}) -> false; -is_safe({hipe_bs_primop, {bs_restore, _}}) -> true; -is_safe({hipe_bs_primop, {bs_save, _}}) -> true; -is_safe({hipe_bs_primop, {bs_add, _}}) -> false; -is_safe({hipe_bs_primop, {bs_add, _, _}}) -> false; -is_safe({hipe_bs_primop, bs_bits_to_bytes}) -> false; -is_safe({hipe_bs_primop, bs_bits_to_bytes2}) -> false; -is_safe({hipe_bs_primop, {bs_init, _}}) -> false; -is_safe({hipe_bs_primop, {bs_init, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_init_bits, _}}) -> false; -is_safe({hipe_bs_primop, {bs_init_bits, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_put_binary, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_put_binary_all, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_put_float, _, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_put_integer, _, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_put_string, _, _}}) -> false; -is_safe({hipe_bs_primop, bs_put_utf8}) -> false; -is_safe({hipe_bs_primop, bs_utf8_size}) -> true; -is_safe({hipe_bs_primop, bs_get_utf8}) -> false; -is_safe({hipe_bs_primop, bs_utf16_size}) -> true; -is_safe({hipe_bs_primop, {bs_put_utf16, _}}) -> false; -is_safe({hipe_bs_primop, {bs_get_utf16, _}}) -> false; -is_safe({hipe_bs_primop, bs_validate_unicode}) -> false; -is_safe({hipe_bs_primop, bs_validate_unicode_retract}) -> false; -is_safe({hipe_bs_primop, {unsafe_bs_put_integer, _, _, _}}) -> false; -is_safe({hipe_bs_primop, bs_final}) -> true; -is_safe({hipe_bs_primop, bs_context_to_binary}) -> true; -is_safe({hipe_bs_primop, {bs_test_unit, _}}) -> false; -is_safe({hipe_bs_primop, {bs_match_string, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_append, _, _, _, _}}) -> false; -is_safe({hipe_bs_primop, {bs_private_append, _, _}}) -> false; -is_safe({hipe_bs_primop, bs_init_writable}) -> true; -is_safe(build_stacktrace) -> true; -is_safe(raw_raise) -> false; -is_safe(#mkfun{}) -> true; -is_safe(#unsafe_element{}) -> true; -is_safe(#unsafe_update_element{}) -> true; -is_safe(debug_native_called) -> false. - - --spec fails(icode_funcall()) -> boolean(). - -fails('+') -> true; -fails('-') -> true; -fails('*') -> true; -fails('/') -> true; -fails('bnot') -> true; -fails('band') -> true; -fails('bor') -> true; -fails('bsl') -> true; -fails('bsr') -> true; -fails('bxor') -> true; -fails('div') -> true; -fails('rem') -> true; -fails(call_fun) -> true; -fails(check_get_msg) -> true; -fails(clear_timeout) -> false; -fails(cons) -> false; -fails(conv_to_float) -> true; -fails(extra_unsafe_add) -> false; -fails(extra_unsafe_sub) -> false; -fails(fcheckerror) -> true; -fails(fclearerror) -> false; -fails(fp_add) -> false; -fails(fp_div) -> false; -fails(fp_mul) -> false; -fails(fp_sub) -> false; -fails(mktuple) -> false; -fails(next_msg) -> false; -fails(recv_mark) -> false; -fails(recv_set) -> false; -fails(redtest) -> false; -fails(select_msg) -> false; -fails(self) -> false; -fails(set_timeout) -> true; -fails(suspend_msg) -> false; -fails(unsafe_untag_float) -> false; -fails(unsafe_tag_float) -> false; -fails(unsafe_add) -> false; -fails(unsafe_band) -> false; -fails(unsafe_bnot) -> false; -fails(unsafe_bor) -> false; -fails(unsafe_bsl) -> false; -fails(unsafe_bsr) -> false; -fails(unsafe_bxor) -> false; -fails(unsafe_hd) -> false; -fails(unsafe_sub) -> false; -%% fails(unsafe_tag_float) -> false; -fails(unsafe_tl) -> false; -%% fails(unsafe_untag_float) -> false; -fails(#apply_N{}) -> true; -fails(#closure_element{}) -> false; -fails(#element{}) -> true; -%% fails(#gc_test{}) -> ??? -fails({hipe_bs_primop, {bs_start_match, _}}) -> true; -fails({hipe_bs_primop, {{bs_start_match, bitstr}, _}}) -> true; -fails({hipe_bs_primop, {{bs_start_match, ok_matchstate}, _}}) -> true; -fails({hipe_bs_primop, {bs_get_binary, _, _}}) -> true; -fails({hipe_bs_primop, {bs_get_binary_all, _, _}}) -> true; -fails({hipe_bs_primop, {bs_get_binary_all_2, _, _}}) -> true; -fails({hipe_bs_primop, {bs_get_integer, _, _}}) -> true; -fails({hipe_bs_primop, {bs_get_float, _, _}}) -> true; -fails({hipe_bs_primop, {bs_skip_bits, _}}) -> true; -fails({hipe_bs_primop, {bs_skip_bits_all, _, _}}) -> true; -fails({hipe_bs_primop, {bs_test_tail, _}}) -> true; -fails({hipe_bs_primop, {bs_restore, _}}) -> false; -fails({hipe_bs_primop, {bs_save, _}}) -> false; -fails({hipe_bs_primop, bs_context_to_binary}) -> false; -fails({hipe_bs_primop, {bs_test_unit, _}}) -> true; -fails({hipe_bs_primop, {bs_match_string, _, _}}) -> true; -fails({hipe_bs_primop, {bs_add, _}}) -> true; -fails({hipe_bs_primop, {bs_add, _, _}}) -> true; -fails({hipe_bs_primop, bs_bits_to_bytes}) -> true; -fails({hipe_bs_primop, bs_bits_to_bytes2}) -> true; -fails({hipe_bs_primop, {bs_init, _}}) -> true; -fails({hipe_bs_primop, {bs_init, _, _}}) -> true; -fails({hipe_bs_primop, {bs_init_bits, _}}) -> true; -fails({hipe_bs_primop, {bs_init_bits, _, _}}) -> true; -fails({hipe_bs_primop, {bs_put_binary, _, _}}) -> true; -fails({hipe_bs_primop, {bs_put_binary_all, _, _}}) -> true; -fails({hipe_bs_primop, {bs_put_float, _, _, _}}) -> true; -fails({hipe_bs_primop, {bs_put_integer, _, _, _}}) -> true; -fails({hipe_bs_primop, {bs_put_string, _, _}}) -> true; -fails({hipe_bs_primop, bs_put_utf8}) -> true; -fails({hipe_bs_primop, bs_utf8_size}) -> false; -fails({hipe_bs_primop, bs_get_utf8}) -> true; -fails({hipe_bs_primop, bs_utf16_size}) -> false; -fails({hipe_bs_primop, {bs_put_utf16, _}}) -> true; -fails({hipe_bs_primop, {bs_get_utf16, _}}) -> true; -fails({hipe_bs_primop, bs_validate_unicode}) -> true; -fails({hipe_bs_primop, bs_validate_unicode_retract}) -> true; -fails({hipe_bs_primop, {unsafe_bs_put_integer, _, _, _}}) -> true; -fails({hipe_bs_primop, bs_final}) -> false; -fails({hipe_bs_primop, {bs_append, _, _, _, _}}) -> true; -fails({hipe_bs_primop, {bs_private_append, _, _}}) -> true; -fails({hipe_bs_primop, bs_init_writable}) -> true; -fails(build_stacktrace) -> false; -fails(raw_raise) -> true; -fails(#mkfun{}) -> false; -fails(#unsafe_element{}) -> false; -fails(#unsafe_update_element{}) -> false; -fails(debug_native_called) -> false; -%% Apparently, we are calling fails/1 for all MFAs which are compiled. -%% This is weird and we should restructure the compiler to avoid -%% calling fails/1 for things that are not primops. -fails({M, F, A}) when is_atom(M), is_atom(F), is_integer(A), 0 =< A, A =< 255 -> - %% Yes, we should move this. - not erl_bifs:is_safe(M, F, A). - -%%===================================================================== -%% Pretty printing -%%===================================================================== - --spec pp(io:device(), icode_primop()) -> 'ok'. - -pp(Dev, Op) -> - case Op of - #apply_N{arity = N} -> - io:format(Dev, "apply_N<~w>/", [N]); - #closure_element{n = N} -> - io:format(Dev, "closure_element<~w>", [N]); - #element{} -> - io:format(Dev, "element", []); - #gc_test{need = N} -> - io:format(Dev, "gc_test<~w>", [N]); - {hipe_bs_primop, BsOp} -> - case BsOp of - {bs_put_binary_all, Unit, Flags} -> - io:format(Dev, "bs_put_binary_all<~w, ~w>", [Unit,Flags]); - {bs_put_binary, Size} -> - io:format(Dev, "bs_put_binary<~w>", [Size]); - {bs_put_binary, Flags, Size} -> - io:format(Dev, "bs_put_binary<~w, ~w>", [Flags, Size]); - {bs_put_float, Flags, Size, _ConstInfo} -> - io:format(Dev, "bs_put_float<~w, ~w>", [Flags, Size]); - {bs_put_string, String, SizeInBytes} -> - io:format(Dev, "bs_put_string<~w, ~w>", [String, SizeInBytes]); - {bs_put_integer, Bits, Flags, _ConstInfo} -> - io:format(Dev, "bs_put_integer<~w, ~w>", [Bits, Flags]); - {unsafe_bs_put_integer, Bits, Flags, _ConstInfo} -> - io:format(Dev, "unsafe_bs_put_integer<~w, ~w>", [Bits, Flags]); - {bs_skip_bits_all, Unit, Flags} -> - io:format(Dev, "bs_skip_bits_all<~w,~w>", [Unit, Flags]); - {bs_skip_bits, Unit} -> - io:format(Dev, "bs_skip_bits<~w>", [Unit]); - {bs_start_match, Max} -> - io:format(Dev, "bs_start_match<~w>", [Max]); - {{bs_start_match, Type}, Max} -> - io:format(Dev, "bs_start_match<~w,~w>", [Type,Max]); - {bs_match_string, String, SizeInBits} -> - io:format(Dev, "bs_match_string<~w, ~w>", [String, SizeInBits]); - {bs_get_integer, Size, Flags} -> - io:format(Dev, "bs_get_integer<~w, ~w>", [Size, Flags]); - {bs_get_float, Size, Flags} -> - io:format(Dev, "bs_get_float<~w, ~w>", [Size, Flags]); - {bs_get_binary, Size, Flags} -> - io:format(Dev, "bs_get_binary<~w, ~w>", [Size, Flags]); - {bs_get_binary_all, Unit, Flags} -> - io:format(Dev, "bs_get_binary_all<~w,~w>", [Unit, Flags]); - {bs_get_binary_all_2, Unit, Flags} -> - io:format(Dev, "bs_get_binary_all<~w,~w>", [Unit, Flags]); - {bs_test_tail, NumBits} -> - io:format(Dev, "bs_test_tail<~w>", [NumBits]); - {bs_test_unit, Unit} -> - io:format(Dev, "bs_test_unit<~w>", [Unit]); - bs_context_to_binary -> - io:format(Dev, "bs_context_to_binary", []); - {bs_restore, Index} -> - io:format(Dev, "bs_restore<~w>", [Index]); - {bs_save, Index} -> - io:format(Dev, "bs_save<~w>", [Index]); - {bs_init, Size, Flags} -> - io:format(Dev, "bs_init<~w, ~w>", [Size, Flags]); - {bs_init,Flags} -> - io:format(Dev, "bs_init<~w>", [Flags]); - {bs_init_bits, Size, Flags} -> - io:format(Dev, "bs_init_bits<~w, ~w>", [Size, Flags]); - {bs_init_bits, Flags} -> - io:format(Dev, "bs_init_bits<~w>", [Flags]); - {bs_add, Unit} -> - io:format(Dev, "bs_add<~w>", [Unit]); - {bs_add, Const, Unit} -> - io:format(Dev, "bs_add<~w, ~w>", [Const, Unit]); - {bs_append, X, Y, Z, W} -> - io:format(Dev, "bs_append<~w, ~w, ~w, ~w>", [X, Y, Z, W]); - {bs_private_append, U, Flags} -> - io:format(Dev, "bs_private_append<~w, ~w>", [U, Flags]); - bs_bits_to_bytes -> - io:format(Dev, "bs_bits_to_bytes", []); - bs_bits_to_bytes2 -> - io:format(Dev, "bs_bits_to_bytes2", []); - bs_utf8_size -> - io:format(Dev, "bs_utf8_size", []); - bs_put_utf8 -> - io:format(Dev, "bs_put_utf8", []); - bs_get_utf8 -> - io:format(Dev, "bs_get_utf8", []); - bs_utf16_size -> - io:format(Dev, "bs_utf16_size", []); - {bs_put_utf16, Flags} -> - io:format(Dev, "bs_put_utf16<~w>", [Flags]); - {bs_get_utf16, Flags} -> - io:format(Dev, "bs_get_utf16<~w>", [Flags]); - bs_validate_unicode -> - io:format(Dev, "bs_validate_unicode", []); - bs_validate_unicode_retract -> - io:format(Dev, "bs_validate_unicode_retract", []); - bs_final -> - io:format(Dev, "bs_final", []); - bs_final2 -> - io:format(Dev, "bs_final2", []); - bs_init_writable -> - io:format(Dev, "bs_init_writable", []) - end; - #mkfun{mfa = {Mod, Fun, Arity}, magic_num = Unique, index = I} -> - io:format(Dev, "mkfun<~w,~w,~w,~w,~w>", [Mod, Fun, Arity, Unique, I]); - #unsafe_element{index = N} -> - io:format(Dev, "unsafe_element<~w>", [N]); - #unsafe_update_element{index = N} -> - io:format(Dev, "unsafe_update_element<~w>", [N]); - Fun when is_atom(Fun) -> - io:format(Dev, "~w", [Fun]) - end. - -%%===================================================================== -%% Type handling -%%===================================================================== - --spec type(icode_funcall(), [erl_types:erl_type()]) -> erl_types:erl_type(). - -type(Primop, Args) -> - case Primop of -%%% ----------------------------------------------------- -%%% Arithops - '+' -> - erl_bif_types:type(erlang, '+', 2, Args); - '-' -> - erl_bif_types:type(erlang, '-', 2, Args); - '*' -> - erl_bif_types:type(erlang, '*', 2, Args); - '/' -> - erl_bif_types:type(erlang, '/', 2, Args); - 'band' -> - erl_bif_types:type(erlang, 'band', 2, Args); - 'bnot' -> - erl_bif_types:type(erlang, 'bnot', 1, Args); - 'bor' -> - erl_bif_types:type(erlang, 'bor', 2, Args); - 'bxor' -> - erl_bif_types:type(erlang, 'bxor', 2, Args); - 'bsl' -> - erl_bif_types:type(erlang, 'bsl', 2, Args); - 'bsr' -> - erl_bif_types:type(erlang, 'bsr', 2, Args); - 'div' -> - erl_bif_types:type(erlang, 'div', 2, Args); - 'rem' -> - erl_bif_types:type(erlang, 'rem', 2, Args); - extra_unsafe_add -> - erl_bif_types:type(erlang, '+', 2, Args); - unsafe_add -> - erl_bif_types:type(erlang, '+', 2, Args); - unsafe_bnot -> - erl_bif_types:type(erlang, 'bnot', 1, Args); - unsafe_bor -> - erl_bif_types:type(erlang, 'bor', 2, Args); - unsafe_band -> - erl_bif_types:type(erlang, 'band', 2, Args); - unsafe_bxor -> - erl_bif_types:type(erlang, 'bxor', 2, Args); - unsafe_sub -> - erl_bif_types:type(erlang, '-', 2, Args); -%%% ----------------------------------------------------- -%%% Lists - cons -> - [HeadType, TailType] = Args, - erl_types:t_cons(HeadType, TailType); - unsafe_hd -> - [Type] = Args, - case erl_types:t_is_cons(Type) of - true -> erl_types:t_cons_hd(Type); - false -> erl_types:t_none() - end; - unsafe_tl -> - [Type] = Args, - case erl_types:t_is_cons(Type) of - true -> erl_types:t_cons_tl(Type); - false -> erl_types:t_none() - end; -%%% ----------------------------------------------------- -%%% Tuples - mktuple -> - erl_types:t_tuple(Args); - #element{} -> - erl_bif_types:type(erlang, element, 2, Args); - #unsafe_element{index = N} -> - Index = erl_types:t_from_term(N), - erl_bif_types:type(erlang, element, 2, [Index | Args]); - #unsafe_update_element{index = N} -> - %% Same, same - erl_bif_types:type(erlang, setelement, 3, [erl_types:t_integer(N)|Args]); -%%% ----------------------------------------------------- -%%% Floats - fclearerror -> - erl_types:t_any(); - fcheckerror -> - erl_types:t_any(); - unsafe_tag_float -> - erl_types:t_float(); - %% These might look surprising, but the return is an untagged - %% float and we have no type for untagged values. - conv_to_float -> - erl_types:t_any(); - unsafe_untag_float -> - erl_types:t_any(); - fp_add -> - erl_types:t_any(); - fp_sub -> - erl_types:t_any(); - fp_mul -> - erl_types:t_any(); - fp_div -> - erl_types:t_any(); - fnegate -> - erl_types:t_any(); -%%% ----------------------------------------------------- -%%% - {hipe_bs_primop, {bs_start_match, Max}} -> - [Type] = Args, - Init = - erl_types:t_sup( - erl_types:t_matchstate_present(Type), - erl_types:t_inf(erl_types:t_bitstr(1, 0), Type)), - case erl_types:t_is_none(Init) of - true -> - erl_types:t_none(); - false -> - erl_types:t_matchstate(Init, Max) - end; - {hipe_bs_primop, {{bs_start_match, _}, Max}} -> - [Type] = Args, - Init = - erl_types:t_sup( - erl_types:t_matchstate_present(Type), - erl_types:t_inf(erl_types:t_bitstr(1, 0), Type)), - case erl_types:t_is_none(Init) of - true -> - erl_types:t_none(); - false -> - erl_types:t_matchstate(Init, Max) - end; - {hipe_bs_primop, {bs_get_integer, Size, Flags}} -> - Signed = Flags band 4, - [MatchState|RestArgs] = Args, - BinType = erl_types:t_matchstate_present(MatchState), - case RestArgs of - [] -> - NewBinType = match_bin(erl_types:t_bitstr(0, Size), BinType), - NewMatchState = - erl_types:t_matchstate_update_present(NewBinType, MatchState), - Range = - case Signed of - 0 -> - UpperBound = inf_add(safe_bsl_1(Size), -1), - erl_types:t_from_range(0, UpperBound); - 4 -> - Bound = safe_bsl_1(Size - 1), - erl_types:t_from_range(inf_inv(Bound), inf_add(Bound, -1)) - end, - erl_types:t_product([Range, NewMatchState]); - [_Arg] -> - NewBinType = match_bin(erl_types:t_bitstr(Size, 0), BinType), - NewMatchState = - erl_types:t_matchstate_update_present(NewBinType, MatchState), - erl_types:t_product([erl_types:t_integer(), NewMatchState]) - end; - {hipe_bs_primop, {bs_get_float, Size, _Flags}} -> - [MatchState|RestArgs] = Args, - BinType = erl_types:t_matchstate_present(MatchState), - NewBinType = - case RestArgs of - [] -> - match_bin(erl_types:t_bitstr(0,Size),BinType); - [_Arg] -> - erl_types:t_sup(match_bin(erl_types:t_bitstr(0, 32), BinType), - match_bin(erl_types:t_bitstr(0, 64), BinType)) - end, - NewMatchState = erl_types:t_matchstate_update_present(NewBinType, MatchState), - erl_types:t_product([erl_types:t_float(), NewMatchState]); - {hipe_bs_primop, {bs_get_binary, Size, _Flags}} -> - [MatchState|RestArgs] = Args, - BinType = erl_types:t_matchstate_present(MatchState), - case RestArgs of - [] -> - NewBinType = match_bin(erl_types:t_bitstr(0, Size), BinType), - NewMatchState = erl_types:t_matchstate_update_present(NewBinType, MatchState), - erl_types:t_product([erl_types:t_bitstr(0,Size), NewMatchState]); - [ArgType] -> - Posint = erl_types:t_inf(erl_types:t_non_neg_integer(), ArgType), - case erl_types:t_is_none(Posint) of - true -> - erl_types:t_product([erl_types:t_none(), - erl_types:t_matchstate_update_present( - erl_types:t_none(), - MatchState)]); - false -> - OutBinType = - erl_types:t_bitstr(Size,erl_types:number_min(Posint)*Size), - NewBinType = match_bin(OutBinType,BinType), - NewMatchState = erl_types:t_matchstate_update_present(NewBinType, MatchState), - erl_types:t_product([OutBinType, NewMatchState]) - end - end; - {hipe_bs_primop, {bs_get_binary_all, Unit, _Flags}} -> - [MatchState] = Args, - BinType = erl_types:t_matchstate_present(MatchState), - erl_types:t_inf(BinType, erl_types:t_bitstr(Unit, 0)); - {hipe_bs_primop, {bs_get_binary_all_2, Unit, _Flags}} -> - [MatchState] = Args, - BinType = erl_types:t_matchstate_present(MatchState), - erl_types:t_product( - [erl_types:t_inf(BinType,erl_types:t_bitstr(Unit, 0)), - erl_types:t_matchstate_update_present( - erl_types:t_bitstr(0, 0), MatchState)]); - {hipe_bs_primop, {bs_skip_bits_all, _Unit, _Flags}} -> - [MatchState] = Args, - erl_types:t_matchstate_update_present(erl_types:t_bitstr(0,0),MatchState); - {hipe_bs_primop, {bs_skip_bits, Size}} -> - [MatchState|RestArgs] = Args, - BinType = erl_types:t_matchstate_present(MatchState), - NewBinType = - case RestArgs of - [] -> - match_bin(erl_types:t_bitstr(0, Size), BinType); - [_Arg] -> - match_bin(erl_types:t_bitstr(Size, 0), BinType) - end, - erl_types:t_matchstate_update_present(NewBinType, MatchState); - {hipe_bs_primop, {bs_save, Slot}} -> - [MatchState] = Args, - BinType = erl_types:t_matchstate_present(MatchState), - erl_types:t_matchstate_update_slot(BinType, MatchState, Slot); - {hipe_bs_primop, {bs_restore, Slot}} -> - [MatchState] = Args, - BinType = erl_types:t_matchstate_slot(MatchState, Slot), - erl_types:t_matchstate_update_present(BinType, MatchState); - {hipe_bs_primop, bs_context_to_binary} -> - [Type] = Args, - erl_types:t_sup( - erl_types:t_subtract(Type, erl_types:t_matchstate()), - erl_types:t_matchstate_slot( - erl_types:t_inf(Type, erl_types:t_matchstate()), 0)); - {hipe_bs_primop, {bs_match_string,_,Bits}} -> - [MatchState] = Args, - BinType = erl_types:t_matchstate_present(MatchState), - NewBinType = match_bin(erl_types:t_bitstr(0, Bits), BinType), - erl_types:t_matchstate_update_present(NewBinType, MatchState); - {hipe_bs_primop, {bs_test_unit,Unit}} -> - [MatchState] = Args, - BinType = erl_types:t_matchstate_present(MatchState), - NewBinType = erl_types:t_inf(erl_types:t_bitstr(Unit, 0), BinType), - erl_types:t_matchstate_update_present(NewBinType, MatchState); - {hipe_bs_primop, {bs_add, _, _}} -> - erl_types:t_integer(); - {hipe_bs_primop, {bs_add, _}} -> - erl_types:t_integer(); - {hipe_bs_primop, bs_bits_to_bytes} -> - erl_types:t_integer(); - {hipe_bs_primop, bs_bits_to_bytes2} -> - erl_types:t_integer(); - {hipe_bs_primop, {Name, Size, _Flags, _ConstInfo}} - when Name =:= bs_put_integer; - Name =:= bs_put_float -> - case Args of - [_SrcType, _Base, Type] -> - erl_types:t_bitstr_concat(Type, erl_types:t_bitstr(0, Size)); - [_SrcType,_BitsType, _Base, Type] -> - erl_types:t_bitstr_concat(Type, erl_types:t_bitstr(Size, 0)) - end; - {hipe_bs_primop, {bs_put_binary, Size, _Flags}} -> - case Args of - [_SrcType, _Base, Type] -> - erl_types:t_bitstr_concat(Type, erl_types:t_bitstr(0, Size)); - [_SrcType, _BitsType, _Base, Type] -> - erl_types:t_bitstr_concat(Type, erl_types:t_bitstr(Size, 0)) - end; - {hipe_bs_primop, {bs_put_binary_all, Unit, _Flags}} -> - [SrcType0, _Base, Type] = Args, - SrcType = erl_types:t_inf(erl_types:t_bitstr(Unit, 0), SrcType0), - erl_types:t_bitstr_concat(SrcType,Type); - {hipe_bs_primop, {bs_put_string, _, Size}} -> - [_Base, Type] = Args, - erl_types:t_bitstr_concat(Type, erl_types:t_bitstr(0, 8*Size)); - {hipe_bs_primop, bs_utf8_size} -> - [_Arg] = Args, - erl_types:t_from_range(1, 4); - {hipe_bs_primop, bs_utf16_size} -> - [_Arg] = Args, - erl_types:t_from_range(2, 4); % XXX: really 2 | 4 - {hipe_bs_primop, bs_final} -> - [_Base, Type] = Args, - Type; - {hipe_bs_primop, {bs_init, Size, _Flags}} -> - erl_types:t_product( - [erl_types:t_bitstr(0, Size*8), - erl_types:t_any(), - erl_types:t_bitstr(0, 0)]); - {hipe_bs_primop, {bs_init, _Flags}} -> - erl_types:t_product( - [erl_types:t_binary(), - erl_types:t_any(), - erl_types:t_bitstr(0, 0)]); - {hipe_bs_primop, {bs_init_bits, Size, _Flags}} -> - erl_types:t_product( - [erl_types:t_bitstr(0, Size), - erl_types:t_any(), - erl_types:t_bitstr(0, 0)]); - {hipe_bs_primop, {bs_init_bits, _Flags}} -> - erl_types:t_product( - [erl_types:t_bitstr(), - erl_types:t_any(), - erl_types:t_bitstr(0, 0)]); - {hipe_bs_primop, {bs_private_append, _U, _Flags}} -> - erl_types:t_product( - [erl_types:t_bitstr(), - erl_types:t_any(), - erl_types:t_bitstr()]); - {hipe_bs_primop, {bs_append, _W, _R, _U, _Flags}} -> - erl_types:t_product( - [erl_types:t_bitstr(), - erl_types:t_any(), - erl_types:t_bitstr()]); - {hipe_bs_primop, bs_init_writable} -> - erl_types:t_bitstr(0, 0); - {hipe_bs_primop, _BsOp} -> - erl_types:t_any(); -%%% ----------------------------------------------------- -%%% Funs - #mkfun{mfa = {_M, _F, A}} -> - %% Note that the arity includes the bound variables in args - erl_types:t_fun(A - length(Args), erl_types:t_any()); - #apply_N{} -> - erl_types:t_any(); - Op when Op =:= call_fun orelse Op =:= enter_fun -> - [Fun0|TailArgs0] = lists:reverse(Args), - TailArgs = lists:reverse(TailArgs0), - Fun = erl_types:t_inf(erl_types:t_fun(), Fun0), - case erl_types:t_is_fun(Fun) of - true -> - case erl_types:t_fun_args(Fun) of - unknown -> - erl_types:t_any(); - FunArgs -> - case check_fun_args(FunArgs, TailArgs) of - ok -> - erl_types:t_fun_range(Fun); - error -> - erl_types:t_none() - end - end; - false -> - erl_types:t_none() - end; -%%% ----------------------------------------------------- -%%% Communication - check_get_msg -> - erl_types:t_any(); - clear_timeout -> - erl_types:t_any(); - next_msg -> - erl_types:t_any(); - recv_mark -> - erl_types:t_any(); - recv_set -> - erl_types:t_any(); - select_msg -> - erl_types:t_any(); - set_timeout -> - erl_types:t_any(); - suspend_msg -> - erl_types:t_any(); -%%% ----------------------------------------------------- -%%% Other - #closure_element{} -> - erl_types:t_any(); - redtest -> - erl_types:t_any(); - debug_native_called -> - erl_types:t_any(); - build_stacktrace -> - erl_types:t_list(); - raw_raise -> - erl_types:t_atom(); - {M, F, A} -> - erl_bif_types:type(M, F, A, Args) - end. - - --spec type(icode_funcall()) -> erl_types:erl_type(). - -type(Primop) -> - case Primop of -%%% ----------------------------------------------------- -%%% Arithops - 'bnot' -> - erl_bif_types:type(erlang, 'bnot', 1); - '+' -> - erl_bif_types:type(erlang, '+', 2); - '-' -> - erl_bif_types:type(erlang, '-', 2); - '*' -> - erl_bif_types:type(erlang, '*', 2); - '/' -> - erl_bif_types:type(erlang, '/', 2); - 'div' -> - erl_bif_types:type(erlang, 'div', 2); - 'rem' -> - erl_bif_types:type(erlang, 'rem', 2); - 'band' -> - erl_bif_types:type(erlang, 'band', 2); - 'bor' -> - erl_bif_types:type(erlang, 'bor', 2); - 'bxor' -> - erl_bif_types:type(erlang, 'bxor', 2); - 'bsr' -> - erl_bif_types:type(erlang, 'bsr', 2); - 'bsl' -> - erl_bif_types:type(erlang, 'bsl', 2); - unsafe_add -> - erl_bif_types:type(erlang, '+', 2); - extra_unsafe_add -> - erl_bif_types:type(erlang, '+', 2); - unsafe_sub -> - erl_bif_types:type(erlang, '-', 2); - unsafe_bor -> - erl_bif_types:type(erlang, 'bor', 2); - unsafe_band -> - erl_bif_types:type(erlang, 'band', 2); - unsafe_bxor -> - erl_bif_types:type(erlang, 'bxor', 2); -%%% ----------------------------------------------------- -%%% Lists - cons -> - erl_types:t_cons(); - unsafe_hd -> - erl_bif_types:type(erlang, hd, 1); - unsafe_tl -> - erl_bif_types:type(erlang, tl, 1); -%%% ----------------------------------------------------- -%%% Tuples - mktuple -> - erl_types:t_tuple(); - #element{} -> - erl_bif_types:type(erlang, element, 2); - #unsafe_element{} -> - erl_bif_types:type(erlang, element, 2); - #unsafe_update_element{} -> - erl_bif_types:type(erlang, setelement, 3); -%%% ----------------------------------------------------- -%%% Floats - fclearerror -> - erl_types:t_any(); - fcheckerror -> - erl_types:t_any(); - unsafe_tag_float -> - erl_types:t_float(); - %% These might look surprising, but the return is an untagged - %% float and we have no type for untagged values. - conv_to_float -> - erl_types:t_any(); - unsafe_untag_float -> - erl_types:t_any(); - fp_add -> - erl_types:t_any(); - fp_sub -> - erl_types:t_any(); - fp_mul -> - erl_types:t_any(); - fp_div -> - erl_types:t_any(); - fnegate -> - erl_types:t_any(); -%%% ----------------------------------------------------- -%%% Binaries - {hipe_bs_primop, bs_get_utf8} -> - erl_types:t_product([erl_types:t_integer(), erl_types:t_matchstate()]); - {hipe_bs_primop, {bs_get_utf16, _Flags}} -> - erl_types:t_product([erl_types:t_integer(), erl_types:t_matchstate()]); - {hipe_bs_primop, {bs_get_integer, _Size, _Flags}} -> - erl_types:t_product([erl_types:t_integer(), erl_types:t_matchstate()]); - {hipe_bs_primop, {bs_get_float, _, _}} -> - erl_types:t_product([erl_types:t_float(), erl_types:t_matchstate()]); - {hipe_bs_primop, {bs_get_binary, _, _}} -> - erl_types:t_product([erl_types:t_bitstr(), erl_types:t_matchstate()]); - {hipe_bs_primop, {bs_get_binary_all, _, _}} -> - erl_types:t_bitstr(); - {hipe_bs_primop, {bs_get_binary_all_2, _, _}} -> - erl_types:t_product([erl_types:t_bitstr(), erl_types:t_matchstate()]); - {hipe_bs_primop, bs_final} -> - erl_types:t_bitstr(); - {hipe_bs_primop, {bs_init, _, _}} -> - erl_types:t_product([erl_types:t_binary(), erl_types:t_bitstr(), - erl_types:t_bitstr()]); - {hipe_bs_primop, {bs_init, _}} -> - erl_types:t_product([erl_types:t_binary(), erl_types:t_bitstr(), - erl_types:t_bitstr()]); - {hipe_bs_primop, {bs_init_bits, Size, _}} -> - erl_types:t_product([erl_types:t_bitstr(0, Size), erl_types:t_bitstr(), - erl_types:t_bitstr()]); - {hipe_bs_primop, {bs_init_bits, _}} -> - erl_types:t_product([erl_types:t_bitstr(), erl_types:t_bitstr(), - erl_types:t_bitstr()]); - {hipe_bs_primop, {bs_add, _, _}} -> - erl_types:t_integer(); - {hipe_bs_primop, {bs_add, _}} -> - erl_types:t_integer(); - {hipe_bs_primop, bs_bits_to_bytes} -> - erl_types:t_integer(); - {hipe_bs_primop, bs_bits_to_bytes2} -> - erl_types:t_integer(); - {hipe_bs_primop, {bs_private_append, _U, _Flags}} -> - erl_types:t_product( - [erl_types:t_bitstr(), - erl_types:t_any(), - erl_types:t_bitstr()]); - {hipe_bs_primop, {bs_append, _W, _R, _U, _Flags}} -> - erl_types:t_product( - [erl_types:t_bitstr(), - erl_types:t_any(), - erl_types:t_bitstr()]); - {hipe_bs_primop, bs_init_writable} -> - erl_types:t_bitstr(); - {hipe_bs_primop, _BsOp} -> - erl_types:t_any(); -%%% ----------------------------------------------------- -%%% Funs - #mkfun{} -> - %% Note that the arity includes the bound variables in args - erl_types:t_fun(); - #apply_N{} -> - erl_types:t_any(); - call_fun -> - erl_types:t_any(); - enter_fun -> - erl_types:t_any(); -%%% ----------------------------------------------------- -%%% Communication - check_get_msg -> - erl_types:t_any(); - clear_timeout -> - erl_types:t_any(); - next_msg -> - erl_types:t_any(); - recv_mark -> - erl_types:t_any(); - recv_set -> - erl_types:t_any(); - select_msg -> - erl_types:t_any(); - set_timeout -> - erl_types:t_any(); - suspend_msg -> - erl_types:t_any(); -%%% ----------------------------------------------------- -%%% Other - build_stacktrace -> - erl_types:t_any(); - raw_raise -> - erl_types:t_any(); - #closure_element{} -> - erl_types:t_any(); - redtest -> - erl_types:t_any(); - debug_native_called -> - erl_types:t_any(); - {M, F, A} -> - erl_bif_types:type(M, F, A) - end. - - -%% ===================================================================== -%% @doc -%% function arg_types returns a list of the demanded argument types for -%% a bif to succeed. - --spec arg_types(icode_funcall()) -> [erl_types:erl_type()] | 'unknown'. - -arg_types(Primop) -> - case Primop of - {M, F, A} -> - erl_bif_types:arg_types(M, F, A); - #element{} -> - [erl_types:t_pos_fixnum(), erl_types:t_tuple()]; - '+' -> - erl_bif_types:arg_types(erlang, '+', 2); - '-' -> - erl_bif_types:arg_types(erlang, '-', 2); - '*' -> - erl_bif_types:arg_types(erlang, '*', 2); - '/' -> - erl_bif_types:arg_types(erlang, '/', 2); - 'band' -> - erl_bif_types:arg_types(erlang, 'band', 2); - 'bnot' -> - erl_bif_types:arg_types(erlang, 'bnot', 1); - 'bor' -> - erl_bif_types:arg_types(erlang, 'bor', 2); - 'bxor' -> - erl_bif_types:arg_types(erlang, 'bxor', 2); - 'bsl' -> - erl_bif_types:arg_types(erlang, 'bsl', 2); - 'bsr' -> - erl_bif_types:arg_types(erlang, 'bsr', 2); - 'div' -> - erl_bif_types:arg_types(erlang, 'div', 2); - 'rem' -> - erl_bif_types:arg_types(erlang, 'rem', 2); - _ -> - unknown % safe approximation for all primops. - end. - -%%===================================================================== -%% Auxiliary functions -%%===================================================================== - -check_fun_args([T1|Left1], [T2|Left2]) -> - Inf = erl_types:t_inf(T1, T2), - case erl_types:t_inf(Inf, T2) of - Inf -> - check_fun_args(Left1, Left2); - _ -> - error - end; -check_fun_args([], []) -> - ok; -check_fun_args(_, _) -> - error. - -match_bin(Pattern, Match) -> - erl_types:t_bitstr_match(Pattern, Match). - --spec safe_bsl_1(non_neg_integer()) -> non_neg_integer() | 'pos_inf'. - -safe_bsl_1(Shift) when Shift =< 128 -> 1 bsl Shift; -safe_bsl_1(_Shift) -> pos_inf. - -%% -%% The following two functions are stripped-down versions of more -%% general functions that exist in hipe_icode_range.erl -%% - -inf_inv(pos_inf) -> neg_inf; -inf_inv(Number) when is_integer(Number) -> -Number. - -inf_add(pos_inf, _Number) -> pos_inf; -inf_add(Number1, Number2) when is_integer(Number1), is_integer(Number2) -> - Number1 + Number2. |