diff options
Diffstat (limited to 'lib/hipe')
25 files changed, 1392 insertions, 1010 deletions
diff --git a/lib/hipe/cerl/cerl_closurean.erl b/lib/hipe/cerl/cerl_closurean.erl index 12771668ac..021acd5b35 100644 --- a/lib/hipe/cerl/cerl_closurean.erl +++ b/lib/hipe/cerl/cerl_closurean.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% ===================================================================== @@ -808,7 +808,7 @@ take_work({Queue0, Set0}) -> is_escape_op(match_fail, 1) -> false; is_escape_op(F, A) when is_atom(F), is_integer(A) -> true. --spec is_escape_op(module(), atom(), arity()) -> boolean(). +-spec is_escape_op(atom(), atom(), arity()) -> boolean(). is_escape_op(erlang, error, 1) -> false; is_escape_op(erlang, error, 2) -> false; @@ -825,7 +825,7 @@ is_escape_op(M, F, A) when is_atom(M), is_atom(F), is_integer(A) -> true. is_literal_op(match_fail, 1) -> true; is_literal_op(F, A) when is_atom(F), is_integer(A) -> false. --spec is_literal_op(module(), atom(), arity()) -> boolean(). +-spec is_literal_op(atom(), atom(), arity()) -> boolean(). is_literal_op(erlang, '+', 2) -> true; is_literal_op(erlang, '-', 2) -> true; diff --git a/lib/hipe/cerl/cerl_messagean.erl b/lib/hipe/cerl/cerl_messagean.erl index 0753376e7d..6dd93adaa3 100644 --- a/lib/hipe/cerl/cerl_messagean.erl +++ b/lib/hipe/cerl/cerl_messagean.erl @@ -1,19 +1,19 @@ %% ===================================================================== %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% Message analysis of Core Erlang programs. @@ -1043,7 +1043,7 @@ get_deps(L, Dep) -> %% is_escape_op(_F, _A) -> []. --spec is_escape_op(module(), atom(), arity()) -> [arity()]. +-spec is_escape_op(atom(), atom(), arity()) -> [arity()]. is_escape_op(erlang, '!', 2) -> [2]; is_escape_op(erlang, send, 2) -> [2]; @@ -1064,7 +1064,7 @@ is_escape_op(_M, _F, _A) -> []. is_imm_op(match_fail, 1) -> true; is_imm_op(_, _) -> false. --spec is_imm_op(module(), atom(), arity()) -> boolean(). +-spec is_imm_op(atom(), atom(), arity()) -> boolean(). is_imm_op(erlang, self, 0) -> true; is_imm_op(erlang, '=:=', 2) -> true; @@ -1102,4 +1102,4 @@ is_imm_op(erlang, throw, 1) -> true; is_imm_op(erlang, exit, 1) -> true; is_imm_op(erlang, error, 1) -> true; is_imm_op(erlang, error, 2) -> true; -is_imm_op(_, _, _) -> false. +is_imm_op(_M, _F, _A) -> false. diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index be3073c0e6..30b911c41b 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -48,6 +48,7 @@ t_boolean/0, t_byte/0, t_char/0, + t_charlist/0, t_cons/0, t_cons/2, t_cons_hd/1, @@ -124,7 +125,8 @@ t_tuple/1, t_tuple_args/1, t_tuple_size/1, - t_tuple_subtypes/1 + t_tuple_subtypes/1, + t_unicode_string/0 ]). -ifdef(DO_ERL_BIF_TYPES_TEST). @@ -143,128 +145,65 @@ type(M, F, A) -> -spec type(atom(), atom(), arity(), [erl_types:erl_type()]) -> erl_types:erl_type(). -%%-- code --------------------------------------------------------------------- -type(code, add_path, 1, Xs) -> - strict(arg_types(code, add_path, 1), Xs, - fun (_) -> - t_sup(t_boolean(), - t_tuple([t_atom('error'), t_atom('bad_directory')])) +%%-- binary ------------------------------------------------------------------- +type(binary, at, 2, Xs) -> + strict(arg_types(binary, at, 2), Xs, fun(_) -> t_integer() end); +type(binary, bin_to_list, Arity, Xs) when 1 =< Arity, Arity =< 3 -> + strict(arg_types(binary, bin_to_list, Arity), Xs, + fun(_) -> t_list(t_integer()) end); +type(binary, compile_pattern, 1, Xs) -> + strict(arg_types(binary, compile_pattern, 1), Xs, + fun(_) -> t_tuple([t_atom(bm),t_binary()]) end); +type(binary, copy, Arity, Xs) when Arity =:= 1; Arity =:= 2 -> + strict(arg_types(binary, copy, Arity), Xs, + fun(_) -> t_binary() end); +type(binary, decode_unsigned, Arity, Xs) when Arity =:= 1; Arity =:= 2 -> + strict(arg_types(binary, decode_unsigned, Arity), Xs, + fun(_) -> t_non_neg_integer() end); +type(binary, encode_unsigned, Arity, Xs) when Arity =:= 1; Arity =:= 2 -> + strict(arg_types(binary, encode_unsigned, Arity), Xs, + fun(_) -> t_binary() end); +type(binary, first, 1, Xs) -> + strict(arg_types(binary, first, 1), Xs, fun(_) -> t_non_neg_integer() end); +type(binary, last, 1, Xs) -> + strict(arg_types(binary, last, 1), Xs, fun(_) -> t_non_neg_integer() end); +type(binary, list_to_bin, 1, Xs) -> + type(erlang, list_to_binary, 1, Xs); +type(binary, longest_common_prefix, 1, Xs) -> + strict(arg_types(binary, longest_common_prefix, 1), Xs, + fun(_) -> t_integer() end); +type(binary, longest_common_suffix, 1, Xs) -> + strict(arg_types(binary, longest_common_suffix, 1), Xs, + fun(_) -> t_integer() end); +type(binary, match, Arity, Xs) when Arity =:= 2; Arity =:= 3 -> + strict(arg_types(binary, match, Arity), Xs, + fun(_) -> + t_sup(t_atom('nomatch'), t_binary_canonical_part()) end); -type(code, add_patha, 1, Xs) -> - type(code, add_path, 1, Xs); -type(code, add_paths, 1, Xs) -> - strict(arg_types(code, add_paths, 1), Xs, fun(_) -> t_atom('ok') end); -type(code, add_pathsa, 1, Xs) -> - type(code, add_paths, 1, Xs); -type(code, add_pathsz, 1, Xs) -> - type(code, add_paths, 1, Xs); -type(code, add_pathz, 1, Xs) -> - type(code, add_path, 1, Xs); -type(code, all_loaded, 0, _) -> - t_list(t_tuple([t_atom(), t_code_loaded_fname_or_status()])); -type(code, compiler_dir, 0, _) -> - t_string(); -type(code, del_path, 1, Xs) -> - strict(arg_types(code, del_path, 1), Xs, - fun (_) -> - t_sup(t_boolean(), - t_tuple([t_atom('error'), t_atom('bad_name')])) - end); -type(code, delete, 1, Xs) -> - strict(arg_types(code, delete, 1), Xs, fun (_) -> t_boolean() end); -type(code, ensure_loaded, 1, Xs) -> - type(code, load_file, 1, Xs); +type(binary, matches, Arity, Xs) when Arity =:= 2; Arity =:= 3 -> + strict(arg_types(binary, matches, Arity), Xs, + fun(_) -> t_list(t_binary_canonical_part()) end); +type(binary, part, 2, Xs) -> + type(erlang, binary_part, 2, Xs); +type(binary, part, 3, Xs) -> + type(erlang, binary_part, 3, Xs); +type(binary, referenced_byte_size, 1, Xs) -> + strict(arg_types(binary, referenced_byte_size, 1), Xs, + fun(_) -> t_non_neg_integer() end); +%%-- code --------------------------------------------------------------------- type(code, get_chunk, 2, Xs) -> strict(arg_types(code, get_chunk, 2), Xs, fun (_) -> t_sup(t_binary(), t_atom('undefined')) end); -type(code, get_object_code, 1, Xs) -> - strict(arg_types(code, get_object_code, 1), Xs, - fun (_) -> - t_sup(t_tuple([t_atom(), t_binary(), t_string()]), - t_atom('error')) - end); -type(code, get_path, 0, _) -> - t_list(t_string()); -type(code, is_loaded, 1, Xs) -> - strict(arg_types(code, is_loaded, 1), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('file'), t_code_loaded_fname_or_status()]), - t_atom('false')]) - end); -type(code, is_sticky, 1, Xs) -> - strict(arg_types(code, is_sticky, 1), Xs, fun (_) -> t_boolean() end); type(code, is_module_native, 1, Xs) -> strict(arg_types(code, is_module_native, 1), Xs, fun (_) -> t_sup(t_boolean(), t_atom('undefined')) end); -type(code, lib_dir, 0, _) -> - t_string(); -type(code, lib_dir, 1, Xs) -> - strict(arg_types(code, lib_dir, 1), Xs, - fun (_) -> - t_sup(t_string(), - t_tuple([t_atom('error'), t_atom('bad_name')])) - end); -type(code, load_abs, 1, Xs) -> - strict(arg_types(code, load_abs, 1), Xs, - fun ([_File]) -> t_code_load_return(t_atom()) end); % XXX: cheating -type(code, load_abs, 2, Xs) -> - strict(arg_types(code, load_abs, 2), Xs, - fun ([_File,Mod]) -> t_code_load_return(Mod) end); -type(code, load_binary, 3, Xs) -> - strict(arg_types(code, load_binary, 3), Xs, - fun ([Mod,_File,_Bin]) -> t_code_load_return(Mod) end); -type(code, load_file, 1, Xs) -> - strict(arg_types(code, load_file, 1), Xs, - fun ([Mod]) -> t_code_load_return(Mod) end); -type(code, load_native_partial, 2, Xs) -> - strict(arg_types(code, load_native_partial, 2), Xs, - fun ([Mod,_Bin]) -> t_code_load_return(Mod) end); -type(code, load_native_sticky, 3, Xs) -> - strict(arg_types(code, load_native_sticky, 3), Xs, - fun ([Mod,_Bin,_]) -> t_code_load_return(Mod) end); type(code, module_md5, 1, Xs) -> strict(arg_types(code, module_md5, 1), Xs, fun (_) -> t_sup(t_binary(), t_atom('undefined')) end); type(code, make_stub_module, 3, Xs) -> strict(arg_types(code, make_stub_module, 3), Xs, fun ([Mod,_,_]) -> Mod end); -type(code, priv_dir, 1, Xs) -> - strict(arg_types(code, priv_dir, 1), Xs, - fun (_) -> - t_sup(t_string(), t_tuple([t_atom('error'), t_atom('bad_name')])) - end); -type(code, purge, 1, Xs) -> - type(code, delete, 1, Xs); -type(code, rehash, 0, _) -> t_atom('ok'); -type(code, replace_path, 2, Xs) -> - strict(arg_types(code, replace_path, 2), Xs, - fun (_) -> - t_sup([t_atom('true'), - t_tuple([t_atom('error'), t_atom('bad_name')]), - t_tuple([t_atom('error'), t_atom('bad_directory')]), - t_tuple([t_atom('error'), - t_tuple([t_atom('badarg'), t_any()])])]) - end); -type(code, root_dir, 0, _) -> - t_string(); -type(code, set_path, 1, Xs) -> - strict(arg_types(code, set_path, 1), Xs, - fun (_) -> - t_sup([t_atom('true'), - t_tuple([t_atom('error'), t_atom('bad_path')]), - t_tuple([t_atom('error'), t_atom('bad_directory')])]) - end); -type(code, soft_purge, 1, Xs) -> - type(code, delete, 1, Xs); -type(code, stick_mod, 1, Xs) -> - strict(arg_types(code, stick_mod, 1), Xs, fun (_) -> t_atom('true') end); -type(code, unstick_mod, 1, Xs) -> - type(code, stick_mod, 1, Xs); -type(code, which, 1, Xs) -> - strict(arg_types(code, which, 1), Xs, - fun (_) -> - t_sup([t_code_loaded_fname_or_status(), - t_atom('non_existing')]) - end); +type(code, rehash, 0, _) -> + t_atom('ok'); %%-- erl_ddll ----------------------------------------------------------------- type(erl_ddll, demonitor, 1, Xs) -> type(erlang, demonitor, 1, Xs); @@ -665,6 +604,14 @@ type(erlang, 'bnot', 1, Xs) -> %% strict(arg_types(erlang, 'bnot', 1), Xs, fun (_) -> t_integer() end); type(erlang, abs, 1, Xs) -> strict(arg_types(erlang, abs, 1), Xs, fun ([X]) -> X end); +type(erlang, adler32, 1, Xs) -> + strict(arg_types(erlang, adler32, 1), Xs, fun (_) -> t_adler32() end); +type(erlang, adler32, 2, Xs) -> + strict(arg_types(erlang, adler32, 2), Xs, fun (_) -> t_adler32() end); +type(erlang, adler32_combine, 3, Xs) -> + strict(arg_types(erlang, adler32_combine, 3), Xs, + fun (_) -> t_adler32() end); +type(erlang, append, 2, Xs) -> type(erlang, '++', 2, Xs); % alias type(erlang, append_element, 2, Xs) -> strict(arg_types(erlang, append_element, 2), Xs, fun (_) -> t_tuple() end); type(erlang, apply, 2, Xs) -> @@ -683,6 +630,10 @@ type(erlang, atom_to_binary, 2, Xs) -> strict(arg_types(erlang, atom_to_binary, 2), Xs, fun (_) -> t_binary() end); type(erlang, atom_to_list, 1, Xs) -> strict(arg_types(erlang, atom_to_list, 1), Xs, fun (_) -> t_string() end); +type(erlang, binary_part, 2, Xs) -> + strict(arg_types(erlang, binary_part, 2), Xs, fun (_) -> t_binary() end); +type(erlang, binary_part, 3, Xs) -> + strict(arg_types(erlang, binary_part, 3), Xs, fun (_) -> t_binary() end); type(erlang, binary_to_atom, 2, Xs) -> strict(arg_types(erlang, binary_to_atom, 2), Xs, fun (_) -> t_atom() end); type(erlang, binary_to_existing_atom, 2, Xs) -> @@ -726,11 +677,11 @@ type(erlang, check_process_code, 2, Xs) -> type(erlang, concat_binary, 1, Xs) -> strict(arg_types(erlang, concat_binary, 1), Xs, fun (_) -> t_binary() end); type(erlang, crc32, 1, Xs) -> - strict(arg_types(erlang, crc32, 1), Xs, fun (_) -> t_integer() end); + strict(arg_types(erlang, crc32, 1), Xs, fun (_) -> t_crc32() end); type(erlang, crc32, 2, Xs) -> - strict(arg_types(erlang, crc32, 2), Xs, fun (_) -> t_integer() end); + strict(arg_types(erlang, crc32, 2), Xs, fun (_) -> t_crc32() end); type(erlang, crc32_combine, 3, Xs) -> - strict(arg_types(erlang, crc32_combine, 3), Xs, fun (_) -> t_integer() end); + strict(arg_types(erlang, crc32_combine, 3), Xs, fun (_) -> t_crc32() end); type(erlang, date, 0, _) -> t_date(); type(erlang, decode_packet, 3, Xs) -> @@ -752,6 +703,10 @@ type(erlang, demonitor, 2, Xs) -> type(erlang, disconnect_node, 1, Xs) -> strict(arg_types(erlang, disconnect_node, 1), Xs, fun (_) -> t_boolean() end); type(erlang, display, 1, _) -> t_atom('true'); +type(erlang, display_string, 1, Xs) -> + strict(arg_types(erlang, display_string, 1), Xs, fun(_) -> t_atom('true') end); +type(erlang, display_nl, 0, _) -> + t_atom('true'); type(erlang, dist_exit, 3, Xs) -> strict(arg_types(erlang, dist_exit, 3), Xs, fun (_) -> t_atom('true') end); type(erlang, element, 2, Xs) -> @@ -802,6 +757,8 @@ type(erlang, fun_to_list, 1, Xs) -> type(erlang, garbage_collect, 0, _) -> t_atom('true'); type(erlang, garbage_collect, 1, Xs) -> strict(arg_types(erlang, garbage_collect, 1), Xs, fun (_) -> t_boolean() end); +type(erlang, garbage_collect_message_area, 0, _) -> + t_boolean(); type(erlang, get, 0, _) -> t_list(t_tuple(2)); type(erlang, get, 1, _) -> t_any(); % | t_atom('undefined') type(erlang, get_cookie, 0, _) -> t_atom(); % | t_atom('nocookie') @@ -1155,6 +1112,10 @@ type(erlang, monitor_node, 2, Xs) -> type(erlang, monitor_node, 3, Xs) -> strict(arg_types(erlang, monitor_node, 3), Xs, fun (_) -> t_atom('true') end); +type(erlang, nif_error, 1, _) -> + t_any(); % this BIF and the next one are stubs for NIFs and never return +type(erlang, nif_error, 2, Xs) -> + strict(arg_types(erlang, nif_error, 2), Xs, fun (_) -> t_any() end); type(erlang, node, 0, _) -> t_node(); type(erlang, node, 1, Xs) -> strict(arg_types(erlang, node, 1), Xs, fun (_) -> t_node() end); @@ -1173,8 +1134,8 @@ type(erlang, phash2, 2, Xs) -> strict(arg_types(erlang, phash2, 2), Xs, fun (_) -> t_non_neg_integer() end); type(erlang, pid_to_list, 1, Xs) -> strict(arg_types(erlang, pid_to_list, 1), Xs, fun (_) -> t_string() end); -type(erlang, port_call, 3, Xs) -> - strict(arg_types(erlang, port_call, 3), Xs, fun (_) -> t_any() end); +type(erlang, port_call, Arity, Xs) when Arity =:= 2; Arity =:= 3 -> + strict(arg_types(erlang, port_call, Arity), Xs, fun (_) -> t_any() end); type(erlang, port_close, 1, Xs) -> strict(arg_types(erlang, port_close, 1), Xs, fun (_) -> t_atom('true') end); @@ -1503,6 +1464,7 @@ type(erlang, statistics, 1, Xs) -> T_statistics_1 end end); +type(erlang, subtract, 2, Xs) -> type(erlang, '--', 2, Xs); % alias type(erlang, suspend_process, 1, Xs) -> strict(arg_types(erlang, suspend_process, 1), Xs, fun (_) -> t_atom('true') end); @@ -1570,7 +1532,6 @@ type(erlang, system_info, 1, Xs) -> t_non_neg_integer()])])); ['allocator'] -> t_tuple([t_sup([t_atom('undefined'), - t_atom('elib_malloc'), t_atom('glibc')]), t_list(t_integer()), t_list(t_atom()), @@ -1591,11 +1552,10 @@ type(erlang, system_info, 1, Xs) -> t_binary(); ['dist_ctrl'] -> t_list(t_tuple([t_atom(), t_sup([t_pid(), t_port])])); - ['elib_malloc'] -> - t_sup([t_atom('false'), - t_list(t_tuple([t_atom(), t_any()]))]); + %% elib_malloc is intentionally not included, + %% because it scheduled for removal in R15. ['endian'] -> - t_sup([t_atom('big'), t_atom('little')]); + t_endian(); ['fullsweep_after'] -> t_tuple([t_atom('fullsweep_after'), t_non_neg_integer()]); ['garbage_collection'] -> @@ -1607,9 +1567,8 @@ type(erlang, system_info, 1, Xs) -> ['heap_type'] -> t_sup([t_atom('private'), t_atom('hybrid')]); ['hipe_architecture'] -> - t_sup([t_atom('amd64'), t_atom('arm'), - t_atom('powerpc'), t_atom('undefined'), - t_atom('ultrasparc'), t_atom('x86')]); + t_atoms(['amd64', 'arm', 'powerpc', 'ppc64', + 'undefined', 'ultrasparc', 'x86']); ['info'] -> t_binary(); ['internal_cpu_topology'] -> %% Undocumented internal feature @@ -1785,11 +1744,23 @@ type(erts_debug, disassemble, 1, Xs) -> fun (_) -> t_sup([t_atom('false'), t_atom('undef'), t_tuple([t_integer(), t_binary(), t_mfa()])]) end); +type(erts_debug, display, 1, _) -> + t_string(); type(erts_debug, dist_ext_to_term, 2, Xs) -> strict(arg_types(erts_debug, dist_ext_to_term, 2), Xs, fun (_) -> t_any() end); +type(erts_debug, dump_monitors, 1, Xs) -> + strict(arg_types(erts_debug, dump_monitors, 1), Xs, + fun(_) -> t_atom('true') end); +type(erts_debug, dump_links, 1, Xs) -> + strict(arg_types(erts_debug, dump_links, 1), Xs, + fun(_) -> t_atom('true') end); type(erts_debug, flat_size, 1, Xs) -> strict(arg_types(erts_debug, flat_size, 1), Xs, fun (_) -> t_integer() end); +type(erts_debug, get_internal_state, 1, _) -> + t_any(); +type(erts_debug, instructions, 0, _) -> + t_list(t_list(t_byte())); type(erts_debug, lock_counters, 1, Xs) -> strict(arg_types(erts_debug, lock_counters, 1), Xs, fun ([Arg]) -> @@ -1810,6 +1781,8 @@ type(erts_debug, lock_counters, 1, Xs) -> end); type(erts_debug, same, 2, Xs) -> strict(arg_types(erts_debug, same, 2), Xs, fun (_) -> t_boolean() end); +type(erts_debug, set_internal_state, 2, _) -> + t_any(); %%-- ets ---------------------------------------------------------------------- type(ets, all, 0, _) -> t_list(t_tab()); @@ -1893,38 +1866,40 @@ type(ets, slot, 2, Xs) -> strict(arg_types(ets, slot, 2), Xs, fun (_) -> t_sup(t_list(t_tuple()), t_atom('$end_of_table')) end); type(ets, update_counter, 3, Xs) -> - strict(arg_types(ets, update_counter, 3), Xs, fun (_) -> t_integer() end); + strict(arg_types(ets, update_counter, 3), Xs, + fun ([_, _, Op]) -> + case t_is_integer(Op) of + true -> t_integer(); + false -> + case t_is_tuple(Op) of + true -> t_integer(); + false -> + case t_is_list(Op) of + true -> t_list(t_integer()); + false -> + case t_is_nil(Op) of + true -> t_nil(); + false -> t_sup([t_integer(), t_list(t_integer())]) + end + end + end + end + end); type(ets, update_element, 3, Xs) -> strict(arg_types(ets, update_element, 3), Xs, fun (_) -> t_boolean() end); %%-- file --------------------------------------------------------------------- -type(file, close, 1, Xs) -> - strict(arg_types(file, close, 1), Xs, fun (_) -> t_file_return() end); -type(file, delete, 1, Xs) -> - strict(arg_types(file, delete, 1), Xs, fun (_) -> t_file_return() end); -type(file, get_cwd, 0, _) -> - t_sup(t_tuple([t_atom('ok'), t_string()]), - t_tuple([t_atom('error'), t_file_posix_error()])); -type(file, make_dir, 1, Xs) -> - strict(arg_types(file, make_dir, 1), Xs, fun (_) -> t_file_return() end); -type(file, open, 2, Xs) -> - strict(arg_types(file, open, 2), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('ok'), t_file_io_device()]), - t_tuple([t_atom('error'), t_file_posix_error()])]) - end); -type(file, read_file, 1, Xs) -> - strict(arg_types(file, read_file, 1), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('ok'), t_binary()]), - t_tuple([t_atom('error'), t_file_posix_error()])]) - end); -type(file, set_cwd, 1, Xs) -> - strict(arg_types(file, set_cwd, 1), Xs, - fun (_) -> t_sup(t_atom('ok'), - t_tuple([t_atom('error'), t_file_posix_error()])) - end); -type(file, write_file, 2, Xs) -> - strict(arg_types(file, write_file, 2), Xs, fun (_) -> t_file_return() end); +type(file, native_name_encoding, 0, _) -> + t_file_encoding(); +%%-- prim_file ---------------------------------------------------------------- +type(prim_file, internal_name2native, 1, Xs) -> + strict(arg_types(prim_file, internal_name2native, 1), Xs, + fun (_) -> t_binary() end); +type(prim_file, internal_native2name, 1, Xs) -> + strict(arg_types(prim_file, internal_native2name, 1), Xs, + fun (_) -> t_prim_file_name() end); +type(prim_file, internal_normalize_utf8, 1, Xs) -> + strict(arg_types(prim_file, internal_normalize_utf8, 1), Xs, + fun (_) -> t_binary() end); %%-- gen_tcp ------------------------------------------------------------------ %% NOTE: All type information for this module added to avoid loss of precision type(gen_tcp, accept, 1, Xs) -> @@ -2099,7 +2074,7 @@ type(hipe_bifs, set_native_address, 3, Xs) -> strict(arg_types(hipe_bifs, set_native_address, 3), Xs, fun (_) -> t_nil() end); type(hipe_bifs, system_crc, 1, Xs) -> - strict(arg_types(hipe_bifs, system_crc, 1), Xs, fun (_) -> t_integer() end); + strict(arg_types(hipe_bifs, system_crc, 1), Xs, fun (_) -> t_crc32() end); type(hipe_bifs, term_to_word, 1, Xs) -> strict(arg_types(hipe_bifs, term_to_word, 1), Xs, fun (_) -> t_integer() end); @@ -2258,8 +2233,7 @@ type(lists, flatten, 1, Xs) -> t_list(); false -> X2 = type(lists, flatten, 1, [t_inf(X1, t_list())]), - t_sup(t_list(t_subtract(X1, t_list())), - X2) + t_sup(t_list(t_subtract(X1, t_list())), X2) end end end); @@ -2270,10 +2244,20 @@ type(lists, flatmap, 2, Xs) -> true -> t_nil(); false -> case check_fun_application(F, [t_list_elements(List)]) of - ok -> - case t_is_cons(List) of - true -> t_nonempty_list(t_list_elements(t_fun_range(F))); - false -> t_list(t_list_elements(t_fun_range(F))) + ok -> + R = t_fun_range(F), + case t_is_nil(R) of + true -> t_nil(); + false -> + Elems = t_list_elements(R), + case t_is_cons(List) of + true -> + case t_is_subtype(t_nil(), R) of + true -> t_list(Elems); + false -> t_nonempty_list(Elems) + end; + false -> t_list(Elems) + end end; error -> case t_is_cons(List) of @@ -3194,81 +3178,64 @@ arith(Op, X1, X2) -> -spec arg_types(atom(), atom(), arity()) -> [erl_types:erl_type()] | 'unknown'. +%%------- binary -------------------------------------------------------------- +arg_types(binary, at, 2) -> + [t_binary(), t_non_neg_integer()]; +arg_types(binary, bin_to_list, 1) -> + [t_binary()]; +arg_types(binary, bin_to_list, 2) -> + [t_binary(), t_binary_part()]; +arg_types(binary, bin_to_list, 3) -> + [t_binary(), t_integer(), t_non_neg_integer()]; +arg_types(binary, compile_pattern, 1) -> + [t_sup(t_binary(), t_list(t_binary()))]; +arg_types(binary, copy, 1) -> + [t_binary()]; +arg_types(binary, copy, 2) -> + [t_binary(), t_non_neg_integer()]; +arg_types(binary, decode_unsigned, 1) -> + [t_binary()]; +arg_types(binary, decode_unsigned, 2) -> + [t_binary(), t_endian()]; +arg_types(binary, encode_unsigned, 1) -> + [t_non_neg_integer()]; +arg_types(binary, encode_unsigned, 2) -> + [t_non_neg_integer(), t_endian()]; +arg_types(binary, first, 1) -> + [t_binary()]; +arg_types(binary, last, 1) -> + [t_binary()]; +arg_types(binary, list_to_bin, 1) -> + arg_types(erlang, list_to_binary, 1); +arg_types(binary, longest_common_prefix, 1) -> + [t_list(t_binary())]; +arg_types(binary, longest_common_suffix, 1) -> + [t_list(t_binary())]; +arg_types(binary, match, 2) -> + [t_binary(), t_binary_pattern()]; +arg_types(binary, match, 3) -> + [t_binary(), t_binary_pattern(), t_binary_options()]; +arg_types(binary, matches, 2) -> + [t_binary(), t_binary_pattern()]; +arg_types(binary, matches, 3) -> + [t_binary(), t_binary_pattern(), t_binary_options()]; +arg_types(binary, part, 2) -> + arg_types(erlang, binary_part, 2); +arg_types(binary, part, 3) -> + arg_types(erlang, binary_part, 3); +arg_types(binary, referenced_byte_size, 1) -> + [t_binary()]; %%------- code ---------------------------------------------------------------- -arg_types(code, add_path, 1) -> - [t_string()]; -arg_types(code, add_patha, 1) -> - arg_types(code, add_path, 1); -arg_types(code, add_paths, 1) -> - [t_list(t_string())]; -arg_types(code, add_pathsa, 1) -> - arg_types(code, add_paths, 1); -arg_types(code, add_pathsz, 1) -> - arg_types(code, add_paths, 1); -arg_types(code, add_pathz, 1) -> - arg_types(code, add_path, 1); -arg_types(code, all_loaded, 0) -> - []; -arg_types(code, compiler_dir, 0) -> - []; -arg_types(code, del_path, 1) -> - [t_sup(t_string(), t_atom())]; % OBS: doc differs from add_path/1 - why? -arg_types(code, delete, 1) -> - [t_atom()]; -arg_types(code, ensure_loaded, 1) -> - arg_types(code, load_file, 1); arg_types(code, get_chunk, 2) -> [t_binary(), t_string()]; -arg_types(code, get_object_code, 1) -> - [t_atom()]; -arg_types(code, get_path, 0) -> - []; -arg_types(code, is_loaded, 1) -> - [t_atom()]; -arg_types(code, is_sticky, 1) -> - [t_atom()]; arg_types(code, is_module_native, 1) -> [t_atom()]; -arg_types(code, lib_dir, 0) -> - []; -arg_types(code, lib_dir, 1) -> - [t_atom()]; -arg_types(code, load_abs, 1) -> - [t_string()]; -arg_types(code, load_abs, 2) -> - [t_code_loaded_fname_or_status(), t_atom()]; -arg_types(code, load_binary, 3) -> - [t_atom(), t_code_loaded_fname_or_status(), t_binary()]; -arg_types(code, load_file, 1) -> - [t_atom()]; -arg_types(code, load_native_partial, 2) -> - [t_atom(), t_binary()]; -arg_types(code, load_native_sticky, 3) -> - [t_atom(), t_binary(), t_sup(t_binary(), t_atom('false'))]; arg_types(code, module_md5, 1) -> [t_binary()]; arg_types(code, make_stub_module, 3) -> [t_atom(), t_binary(), t_tuple([t_list(), t_list()])]; -arg_types(code, priv_dir, 1) -> - [t_atom()]; -arg_types(code, purge, 1) -> - arg_types(code, delete, 1); arg_types(code, rehash, 0) -> []; -arg_types(code, replace_path, 2) -> - [t_atom(), t_string()]; -arg_types(code, root_dir, 0) -> - []; -arg_types(code, set_path, 1) -> - [t_string()]; -arg_types(code, soft_purge, 1) -> - arg_types(code, delete, 1); -arg_types(code, stick_mod, 1) -> - [t_atom()]; -arg_types(code, unstick_mod, 1) -> - arg_types(code, stick_mod, 1); -arg_types(code, which, 1) -> - [t_atom()]; %%------- erl_ddll ------------------------------------------------------------ arg_types(erl_ddll, demonitor, 1) -> arg_types(erlang, demonitor, 1); @@ -3375,6 +3342,14 @@ arg_types(erlang, 'bnot', 1) -> [t_integer()]; arg_types(erlang, abs, 1) -> [t_number()]; +arg_types(erlang, adler32, 1) -> + [t_iodata()]; +arg_types(erlang, adler32, 2) -> + [t_adler32(), t_iodata()]; +arg_types(erlang, adler32_combine, 3) -> + [t_adler32(), t_adler32(), t_non_neg_integer()]; +arg_types(erlang, append, 2) -> + arg_types(erlang, '++', 2); arg_types(erlang, append_element, 2) -> [t_tuple(), t_any()]; arg_types(erlang, apply, 2) -> @@ -3388,6 +3363,10 @@ arg_types(erlang, atom_to_binary, 2) -> [t_atom(), t_encoding_a2b()]; arg_types(erlang, atom_to_list, 1) -> [t_atom()]; +arg_types(erlang, binary_part, 2) -> + [t_binary(), t_tuple([t_non_neg_integer(), t_integer()])]; +arg_types(erlang, binary_part, 3) -> + [t_binary(), t_non_neg_integer(), t_integer()]; arg_types(erlang, binary_to_atom, 2) -> [t_binary(), t_encoding_a2b()]; arg_types(erlang, binary_to_existing_atom, 2) -> @@ -3423,9 +3402,9 @@ arg_types(erlang, concat_binary, 1) -> arg_types(erlang, crc32, 1) -> [t_iodata()]; arg_types(erlang, crc32, 2) -> - [t_integer(), t_iodata()]; + [t_crc32(), t_iodata()]; arg_types(erlang, crc32_combine, 3) -> - [t_integer(), t_integer(), t_integer()]; + [t_crc32(), t_crc32(), t_non_neg_integer()]; arg_types(erlang, date, 0) -> []; arg_types(erlang, decode_packet, 3) -> @@ -3440,6 +3419,10 @@ arg_types(erlang, disconnect_node, 1) -> [t_node()]; arg_types(erlang, display, 1) -> [t_any()]; +arg_types(erlang, display_nl, 0) -> + []; +arg_types(erlang, display_string, 1) -> + [t_string()]; arg_types(erlang, dist_exit, 3) -> [t_pid(), t_dist_exit(), t_sup(t_pid(), t_port())]; arg_types(erlang, element, 2) -> @@ -3476,6 +3459,8 @@ arg_types(erlang, garbage_collect, 0) -> []; arg_types(erlang, garbage_collect, 1) -> [t_pid()]; +arg_types(erlang, garbage_collect_message_area, 0) -> + []; arg_types(erlang, get, 0) -> []; arg_types(erlang, get, 1) -> @@ -3628,6 +3613,10 @@ arg_types(erlang, monitor_node, 2) -> [t_node(), t_boolean()]; arg_types(erlang, monitor_node, 3) -> [t_node(), t_boolean(), t_list(t_atom('allow_passive_connect'))]; +arg_types(erlang, nif_error, 1) -> + [t_any()]; +arg_types(erlang, nif_error, 2) -> + [t_any(), t_list()]; arg_types(erlang, node, 0) -> []; arg_types(erlang, node, 1) -> @@ -3640,9 +3629,10 @@ arg_types(erlang, nodes, 1) -> arg_types(erlang, now, 0) -> []; arg_types(erlang, open_port, 2) -> + ArgT = t_sup(t_unicode_string(), t_binary()), [t_sup(t_atom(), t_sup([t_tuple([t_atom('spawn'), t_string()]), t_tuple([t_atom('spawn_driver'), t_string()]), - t_tuple([t_atom('spawn_executable'), t_string()]), + t_tuple([t_atom('spawn_executable'), ArgT]), t_tuple([t_atom('fd'), t_integer(), t_integer()])])), t_list(t_sup(t_sup([t_atom('stream'), t_atom('exit_status'), @@ -3658,8 +3648,8 @@ arg_types(erlang, open_port, 2) -> t_tuple([t_atom('line'), t_integer()]), t_tuple([t_atom('cd'), t_string()]), t_tuple([t_atom('env'), t_list(t_tuple(2))]), % XXX: More - t_tuple([t_atom('args'), t_list(t_string())]), - t_tuple([t_atom('arg0'), t_string()])])))]; + t_tuple([t_atom('args'), t_list(ArgT)]), + t_tuple([t_atom('arg0'), ArgT])])))]; arg_types(erlang, phash, 2) -> [t_any(), t_pos_integer()]; arg_types(erlang, phash2, 1) -> @@ -3668,6 +3658,8 @@ arg_types(erlang, phash2, 2) -> [t_any(), t_pos_integer()]; arg_types(erlang, pid_to_list, 1) -> [t_pid()]; +arg_types(erlang, port_call, 2) -> + [t_sup(t_port(), t_atom()), t_any()]; arg_types(erlang, port_call, 3) -> [t_sup(t_port(), t_atom()), t_integer(), t_any()]; arg_types(erlang, port_close, 1) -> @@ -3795,6 +3787,8 @@ arg_types(erlang, statistics, 1) -> t_atom('run_queue'), t_atom('runtime'), t_atom('wall_clock')])]; +arg_types(erlang, subtract, 2) -> + arg_types(erlang, '--', 2); arg_types(erlang, suspend_process, 1) -> [t_pid()]; arg_types(erlang, suspend_process, 2) -> @@ -3874,7 +3868,8 @@ arg_types(erlang, trace_info, 2) -> t_atom('flags'), t_atom('tracer'), %% while the following are items about a func t_atom('traced'), t_atom('match_spec'), t_atom('meta'), - t_atom('meta_match_spec'), t_atom('call_count'), t_atom('all')])]; + t_atom('meta_match_spec'), t_atom('call_count'), + t_atom('call_time'), t_atom('all')])]; arg_types(erlang, trace_pattern, 2) -> [t_sup(t_tuple([t_atom(), t_atom(), t_sup(t_arity(), t_atom('_'))]), t_atom('on_load')), @@ -3883,7 +3878,7 @@ arg_types(erlang, trace_pattern, 3) -> arg_types(erlang, trace_pattern, 2) ++ [t_list(t_sup([t_atom('global'), t_atom('local'), t_atom('meta'), t_tuple([t_atom('meta'), t_pid()]), - t_atom('call_count')]))]; + t_atom('call_count'), t_atom('call_time')]))]; arg_types(erlang, trunc, 1) -> [t_number()]; arg_types(erlang, tuple_size, 1) -> @@ -3917,10 +3912,20 @@ arg_types(erts_debug, breakpoint, 2) -> [t_tuple([t_atom(), t_atom(), t_sup(t_integer(), t_atom('_'))]), t_boolean()]; arg_types(erts_debug, disassemble, 1) -> [t_sup(t_mfa(), t_integer())]; +arg_types(erts_debug, display, 1) -> + [t_any()]; arg_types(erts_debug, dist_ext_to_term, 2) -> [t_tuple(), t_binary()]; +arg_types(erts_debug, dump_monitors, 1) -> + [t_sup([t_pid(),t_atom()])]; +arg_types(erts_debug, dump_links, 1) -> + [t_sup([t_pid(),t_atom(),t_port()])]; arg_types(erts_debug, flat_size, 1) -> [t_any()]; +arg_types(erts_debug, get_internal_state, 1) -> + [t_any()]; +arg_types(erts_debug, instructions, 0) -> + []; arg_types(erts_debug, lock_counters, 1) -> [t_sup([t_atom(enabled), t_atom(info), @@ -3929,6 +3934,8 @@ arg_types(erts_debug, lock_counters, 1) -> t_tuple([t_atom(process_locks), t_boolean()])])]; arg_types(erts_debug, same, 2) -> [t_any(), t_any()]; +arg_types(erts_debug, set_internal_state, 2) -> + [t_any(), t_any()]; %%------- ets ----------------------------------------------------------------- arg_types(ets, all, 0) -> []; @@ -4011,32 +4018,22 @@ arg_types(ets, setopts, 2) -> t_tuple([t_atom('heir'), t_atom('none')])), [t_tab(), t_sup(Opt, t_list(Opt))]; arg_types(ets, update_counter, 3) -> - [t_tab(), t_any(), t_sup(t_integer(), - t_sup(t_tuple([t_integer(), t_integer()]), - t_tuple([t_integer(), t_integer(), - t_integer(), t_integer()])))]; + Int = t_integer(), + UpdateOp = t_sup(t_tuple([Int, Int]), t_tuple([Int, Int, Int, Int])), + [t_tab(), t_any(), t_sup([UpdateOp, t_list(UpdateOp), Int])]; arg_types(ets, update_element, 3) -> PosValue = t_tuple([t_integer(), t_any()]), [t_tab(), t_any(), t_sup(PosValue, t_list(PosValue))]; %%------- file ---------------------------------------------------------------- -arg_types(file, close, 1) -> - [t_file_io_device()]; -arg_types(file, delete, 1) -> - [t_file_name()]; -arg_types(file, get_cwd, 0) -> +arg_types(file, native_name_encoding, 0) -> []; -arg_types(file, make_dir, 1) -> - [t_file_name()]; -arg_types(file, open, 2) -> - [t_file_name(), t_list(t_file_open_option())]; -arg_types(file, read_file, 1) -> - [t_file_name()]; -arg_types(file, set_cwd, 1) -> - [t_file_name()]; -arg_types(file, write, 2) -> - [t_file_io_device(), t_iodata()]; -arg_types(file, write_file, 2) -> - [t_file_name(), t_sup(t_binary(), t_list())]; +%%-- prim_file ---------------------------------------------------------------- +arg_types(prim_file, internal_name2native, 1) -> + [t_prim_file_name()]; +arg_types(prim_file, internal_native2name, 1) -> + [t_binary()]; +arg_types(prim_file, internal_normalize_utf8, 1) -> + [t_binary()]; %%------- gen_tcp ------------------------------------------------------------- arg_types(gen_tcp, accept, 1) -> [t_socket()]; @@ -4109,7 +4106,7 @@ arg_types(hipe_bifs, call_count_off, 1) -> arg_types(hipe_bifs, call_count_on, 1) -> [t_mfa()]; arg_types(hipe_bifs, check_crc, 1) -> - [t_integer()]; + [t_crc32()]; arg_types(hipe_bifs, enter_code, 2) -> [t_binary(), t_sup(t_nil(), t_tuple())]; arg_types(hipe_bifs, enter_sdesc, 1) -> @@ -4153,7 +4150,7 @@ arg_types(hipe_bifs, set_funinfo_native_address, 3) -> arg_types(hipe_bifs, set_native_address, 3) -> [t_mfa(), t_integer(), t_boolean()]; arg_types(hipe_bifs, system_crc, 1) -> - [t_integer()]; + [t_crc32()]; arg_types(hipe_bifs, term_to_word, 1) -> [t_any()]; arg_types(hipe_bifs, update_code_size, 3) -> @@ -4355,11 +4352,11 @@ arg_types(os, timestamp, 0) -> arg_types(re, compile, 1) -> [t_iodata()]; arg_types(re, compile, 2) -> - [t_iodata(), t_list(t_re_compile_option())]; + [t_sup(t_iodata(), t_charlist()), t_list(t_re_compile_option())]; arg_types(re, run, 2) -> - [t_iodata(), t_re_RE()]; + [t_sup(t_iodata(), t_charlist()), t_re_RE()]; arg_types(re, run, 3) -> - [t_iodata(), t_re_RE(), t_list(t_re_run_option())]; + [t_sup(t_iodata(), t_charlist()), t_re_RE(), t_list(t_re_run_option())]; %%------- string -------------------------------------------------------------- arg_types(string, chars, 2) -> [t_char(), t_non_neg_integer()]; @@ -4467,6 +4464,30 @@ t_httppacket() -> t_sup([t_HttpRequest(), t_HttpResponse(), t_HttpHeader(), t_atom('http_eoh'), t_HttpError()]). +t_endian() -> + t_sup(t_atom('big'), t_atom('little')). + +%% ===================================================================== +%% Types for the binary module +%% ===================================================================== + +t_binary_part() -> + t_tuple([t_non_neg_integer(), t_integer()]). + +t_binary_canonical_part() -> + t_tuple([t_non_neg_integer(), t_non_neg_integer()]). + +t_binary_pattern() -> + t_sup([t_binary(), + t_list(t_binary()), + t_binary_compiled_pattern()]). + +t_binary_compiled_pattern() -> + t_tuple([t_atom('cp'), t_binary()]). + +t_binary_options() -> + t_list(t_tuple([t_atom('scope'), t_binary_part()])). + %% ===================================================================== %% HTTP types documented in R12B-4 %% ===================================================================== @@ -4475,16 +4496,16 @@ t_HttpRequest() -> t_tuple([t_atom('http_request'), t_HttpMethod(), t_HttpUri(), t_HttpVersion()]). t_HttpResponse() -> - t_tuple([t_atom('http_response'), t_HttpVersion(), t_integer(), t_string()]). + t_tuple([t_atom('http_response'), t_HttpVersion(), t_integer(), t_HttpString()]). t_HttpHeader() -> - t_tuple([t_atom('http_header'), t_integer(), t_HttpField(), t_any(), t_string()]). + t_tuple([t_atom('http_header'), t_integer(), t_HttpField(), t_any(), t_HttpString()]). t_HttpError() -> - t_tuple([t_atom('http_error'), t_string()]). + t_tuple([t_atom('http_error'), t_HttpString()]). t_HttpMethod() -> - t_sup(t_HttpMethodAtom(), t_string()). + t_sup(t_HttpMethodAtom(), t_HttpString()). t_HttpMethodAtom() -> t_atoms(['OPTIONS', 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE']). @@ -4493,18 +4514,18 @@ t_HttpUri() -> t_sup([t_atom('*'), t_tuple([t_atom('absoluteURI'), t_sup(t_atom('http'), t_atom('https')), - t_string(), + t_HttpString(), t_sup(t_non_neg_integer(), t_atom('undefined')), - t_string()]), - t_tuple([t_atom('scheme'), t_string(), t_string()]), - t_tuple([t_atom('abs_path'), t_string()]), - t_string()]). + t_HttpString()]), + t_tuple([t_atom('scheme'), t_HttpString(), t_HttpString()]), + t_tuple([t_atom('abs_path'), t_HttpString()]), + t_HttpString()]). t_HttpVersion() -> t_tuple([t_non_neg_integer(), t_non_neg_integer()]). t_HttpField() -> - t_sup(t_HttpFieldAtom(), t_string()). + t_sup(t_HttpFieldAtom(), t_HttpString()). t_HttpFieldAtom() -> t_atoms(['Cache-Control', 'Connection', 'Date', 'Pragma', 'Transfer-Encoding', @@ -4521,6 +4542,9 @@ t_HttpFieldAtom() -> 'Set-Cookie', 'Set-Cookie2', 'X-Forwarded-For', 'Cookie', 'Keep-Alive', 'Proxy-Connection']). +t_HttpString() -> + t_sup(t_string(),t_binary()). + %% ===================================================================== %% These are used for the built-in functions of 'code' %% ===================================================================== @@ -4549,6 +4573,12 @@ t_code_loaded_fname_or_status() -> %% These are used for the built-in functions of 'erlang' %% ===================================================================== +t_adler32() -> + t_non_neg_integer(). + +t_crc32() -> + t_non_neg_integer(). + t_decode_packet_option() -> t_sup([t_tuple([t_atom('packet_size'), t_non_neg_integer()]), t_tuple([t_atom('line_length'), t_non_neg_integer()])]). @@ -4606,7 +4636,8 @@ t_process_priority_level() -> t_sup([t_atom('max'), t_atom('high'), t_atom('normal'), t_atom('low')]). t_process_status() -> - t_sup([t_atom('runnable'), t_atom('running'), + t_sup([t_atom('exiting'), t_atom('garbage_collecting'), + t_atom('runnable'), t_atom('running'), t_atom('suspended'), t_atom('waiting')]). t_raise_errorclass() -> @@ -4745,10 +4776,11 @@ t_matchres() -> %% From the 'ets' documentation %%----------------------------- %% Option = Type | Access | named_table | {keypos,Pos} -%% | {heir,pid(),HeirData} | {heir,none} -%% | {write_concurrency,boolean()} +%% | {heir,pid(),HeirData} | {heir,none} | Tweaks %% Type = set | ordered_set | bag | duplicate_bag %% Access = public | protected | private +%% Tweaks = {write_concurrency,boolean()} +%% | {read_concurrency,boolean()} | compressed %% Pos = integer() %% HeirData = term() t_ets_new_options() -> @@ -4760,10 +4792,12 @@ t_ets_new_options() -> t_atom('protected'), t_atom('private'), t_atom('named_table'), + t_tuple([t_atom('keypos'), t_integer()]), t_tuple([t_atom('heir'), t_pid(), t_any()]), t_tuple([t_atom('heir'), t_atom('none')]), - t_tuple([t_atom('keypos'), t_integer()]), - t_tuple([t_atom('write_concurrency'), t_boolean()])])). + t_tuple([t_atom('write_concurrency'), t_boolean()]), + t_tuple([t_atom('read_concurrency'), t_boolean()]), + t_atom('compressed')])). t_ets_info_items() -> t_sup([t_atom('fixed'), @@ -4779,68 +4813,11 @@ t_ets_info_items() -> t_atom('type')]). %% ===================================================================== -%% These are used for the built-in functions of 'file' +%% These are used for the built-in functions of 'prim_file' %% ===================================================================== -t_file_io_device() -> - t_sup(t_pid(), t_tuple([t_atom('file_descriptor'), t_atom(), t_any()])). - -t_file_name() -> - t_sup([t_atom(), - t_string(), - %% DeepList = [char() | atom() | DeepList] -- approximation below - t_list(t_sup([t_atom(), t_string(), t_list()]))]). - -t_file_open_option() -> - t_sup([t_atom('read'), - t_atom('write'), - t_atom('append'), - t_atom('raw'), - t_atom('binary'), - t_atom('delayed_write'), - t_atom('read_ahead'), - t_atom('compressed'), - t_tuple([t_atom('delayed_write'), - t_pos_integer(), t_non_neg_integer()]), - t_tuple([t_atom('read_ahead'), t_pos_integer()])]). - -%% This lists all Posix errors that can occur in file:*/* functions -t_file_posix_error() -> - t_sup([t_atom('eacces'), - t_atom('eagain'), - t_atom('ebadf'), - t_atom('ebusy'), - t_atom('edquot'), - t_atom('eexist'), - t_atom('efault'), - t_atom('efbig'), - t_atom('eintr'), - t_atom('einval'), - t_atom('eio'), - t_atom('eisdir'), - t_atom('eloop'), - t_atom('emfile'), - t_atom('emlink'), - t_atom('enametoolong'), - t_atom('enfile'), - t_atom('enodev'), - t_atom('enoent'), - t_atom('enomem'), - t_atom('enospc'), - t_atom('enotblk'), - t_atom('enotdir'), - t_atom('enotsup'), - t_atom('enxio'), - t_atom('eperm'), - t_atom('epipe'), - t_atom('erofs'), - t_atom('espipe'), - t_atom('esrch'), - t_atom('estale'), - t_atom('exdev')]). - -t_file_return() -> - t_sup(t_atom('ok'), t_tuple([t_atom('error'), t_file_posix_error()])). +t_prim_file_name() -> + t_sup(t_unicode_string(), t_binary()). %% ===================================================================== %% These are used for the built-in functions of 'gen_tcp' @@ -4997,13 +4974,14 @@ t_re_MP() -> %% it's supposed to be an opaque data type t_tuple([t_atom('re_pattern'), t_integer(), t_integer(), t_binary()]). t_re_RE() -> - t_sup(t_re_MP(), t_iodata()). + t_sup([t_re_MP(), t_iodata(), t_charlist()]). t_re_compile_option() -> - t_sup([t_atoms(['anchored', 'caseless', 'dollar_endonly', 'dotall', - 'extended', 'firstline', 'multiline', 'no_auto_capture', - 'dupnames', 'ungreedy']), - t_tuple([t_atom('newline'), t_re_NLSpec()])]). + t_sup([t_atoms(['unicode', 'anchored', 'caseless', 'dollar_endonly', + 'dotall', 'extended', 'firstline', 'multiline', + 'no_auto_capture', 'dupnames', 'ungreedy']), + t_tuple([t_atom('newline'), t_re_NLSpec()]), + t_atoms(['bsr_anycrlf', 'bsr_unicode'])]). t_re_run_option() -> t_sup([t_atoms(['anchored', 'global', 'notbol', 'noteol', 'notempty']), @@ -5020,7 +4998,7 @@ t_re_Type() -> t_atoms(['index', 'list', 'binary']). t_re_NLSpec() -> - t_atoms(['cr', 'crlf', 'lf', 'anycrlf']). + t_atoms(['cr', 'crlf', 'lf', 'anycrlf', 'any']). t_re_ValueSpec() -> t_sup(t_atoms(['all', 'all_but_first', 'first', 'none']), t_re_ValueList()). @@ -5042,7 +5020,12 @@ t_ML() -> % a binary or a possibly deep list of integers or binaries t_sup(t_list(t_sup([t_integer(), t_binary(), t_list()])), t_binary()). t_encoding() -> - t_atoms(['latin1', 'unicode', 'utf8', 'utf16', 'utf32']). + t_sup([t_atoms(['latin1', 'unicode', 'utf8', 'utf16', 'utf32']), + t_tuple([t_atom('utf16'), t_endian()]), + t_tuple([t_atom('utf32'), t_endian()])]). + +t_file_encoding() -> + t_atoms(['latin1', 'utf8']). t_encoding_a2b() -> % for the 2nd arg of atom_to_binary/2 and binary_to_atom/2 t_atoms(['latin1', 'unicode', 'utf8']). diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index f3b91b3953..080d6936b2 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -29,7 +29,7 @@ %% In late 2008, Manouk Manoukian and Kostis Sagonas added support for %% opaque types to the structure-based representation of types. %% During February and March 2009, Kostis Sagonas significantly -%% cleaned up the type representation added spec declarations. +%% cleaned up the type representation and added spec declarations. %% %% ====================================================================== @@ -62,6 +62,7 @@ t_boolean/0, t_byte/0, t_char/0, + t_charlist/0, t_collect_vars/1, t_cons/0, t_cons/2, @@ -178,7 +179,7 @@ t_remote/3, t_string/0, t_struct_from_opaque/2, - t_solve_remote/2, + t_solve_remote/3, t_subst/2, t_subtract/2, t_subtract_list/2, @@ -195,6 +196,7 @@ t_tuple_size/1, t_tuple_sizes/1, t_tuple_subtypes/1, + t_unicode_string/0, t_unify/2, t_unify/3, t_unit/0, @@ -205,11 +207,14 @@ t_var_name/1, %% t_assign_variables_to_subtype/2, type_is_defined/3, + record_field_diffs_to_string/2, subst_all_vars_to_any/1, - lift_list_to_pos_empty/1 + lift_list_to_pos_empty/1, + is_erl_type/1 ]). %%-define(DO_ERL_TYPES_TEST, true). +-compile({no_auto_import,[min/2,max/2]}). -ifdef(DO_ERL_TYPES_TEST). -export([test/0]). @@ -221,6 +226,8 @@ -export([t_is_identifier/1]). -endif. +-export_type([erl_type/0]). + %%============================================================================= %% %% Definition of the type structure @@ -299,7 +306,7 @@ %% Auxiliary types and convenient macros %% --type parse_form() :: {atom(), _, _} | {atom(), _, _, _}. %% XXX: Temporarily +-type parse_form() :: {atom(), _, _} | {atom(), _, _, _} | {'op', _, _, _, _}. %% XXX: Temporarily -type rng_elem() :: 'pos_inf' | 'neg_inf' | integer(). -record(int_set, {set :: [integer()]}). @@ -398,7 +405,8 @@ t_is_none(_) -> false. -spec t_opaque(module(), atom(), [_], erl_type()) -> erl_type(). t_opaque(Mod, Name, Args, Struct) -> - ?opaque(set_singleton(#opaque{mod=Mod, name=Name, args=Args, struct=Struct})). + O = #opaque{mod = Mod, name = Name, args = Args, struct = Struct}, + ?opaque(set_singleton(O)). -spec t_is_opaque(erl_type()) -> boolean(). @@ -427,7 +435,7 @@ t_opaque_structure(?opaque(Elements)) -> t_opaque_module(?opaque(Elements)) -> case ordsets:size(Elements) of 1 -> - [#opaque{mod=Module}] = ordsets:to_list(Elements), + [#opaque{mod = Module}] = ordsets:to_list(Elements), Module; _ -> throw({error, "Unexpected multiple opaque types"}) end. @@ -631,7 +639,7 @@ t_unopaque_on_mismatch(GenType, Type, Opaques) -> case t_inf(GenType, Type) of ?none -> Unopaqued = t_unopaque(Type, Opaques), - %% Unions might be a problem, must investigate. + %% XXX: Unions might be a problem, must investigate. case t_inf(GenType, Unopaqued) of ?none -> Type; _ -> Unopaqued @@ -643,12 +651,12 @@ t_unopaque_on_mismatch(GenType, Type, Opaques) -> module_builtin_opaques(Module) -> [O || O <- all_opaque_builtins(), t_opaque_module(O) =:= Module]. - + %%----------------------------------------------------------------------------- -%% Remote types -%% These types are used for preprocessing they should never reach the analysis stage +%% Remote types: these types are used for preprocessing; +%% they should never reach the analysis stage. --spec t_remote(module(), atom(), [_]) -> erl_type(). +-spec t_remote(atom(), atom(), [erl_type()]) -> erl_type(). t_remote(Mod, Name, Args) -> ?remote(set_singleton(#remote{mod = Mod, name = Name, args = Args})). @@ -658,126 +666,135 @@ t_remote(Mod, Name, Args) -> t_is_remote(?remote(_)) -> true; t_is_remote(_) -> false. --spec t_solve_remote(erl_type(), dict()) -> erl_type(). +-spec t_solve_remote(erl_type(), set(), dict()) -> erl_type(). -t_solve_remote(Type , Records) -> - {RT, _RR} = t_solve_remote(Type, Records, []), +t_solve_remote(Type, ExpTypes, Records) -> + {RT, _RR} = t_solve_remote(Type, ExpTypes, Records, []), RT. -t_solve_remote(?function(Domain, Range), R, C) -> - {RT1, RR1} = t_solve_remote(Domain, R, C), - {RT2, RR2} = t_solve_remote(Range, R, C), +t_solve_remote(?function(Domain, Range), ET, R, C) -> + {RT1, RR1} = t_solve_remote(Domain, ET, R, C), + {RT2, RR2} = t_solve_remote(Range, ET, R, C), {?function(RT1, RT2), RR1 ++ RR2}; -t_solve_remote(?list(Types, Term, Size), R, C) -> - {RT, RR} = t_solve_remote(Types, R, C), +t_solve_remote(?list(Types, Term, Size), ET, R, C) -> + {RT, RR} = t_solve_remote(Types, ET, R, C), {?list(RT, Term, Size), RR}; -t_solve_remote(?product(Types), R, C) -> - {RL, RR} = list_solve_remote(Types, R, C), +t_solve_remote(?product(Types), ET, R, C) -> + {RL, RR} = list_solve_remote(Types, ET, R, C), {?product(RL), RR}; -t_solve_remote(?opaque(Set), R, C) -> +t_solve_remote(?opaque(Set), ET, R, C) -> List = ordsets:to_list(Set), - {NewList, RR} = opaques_solve_remote(List, R, C), + {NewList, RR} = opaques_solve_remote(List, ET, R, C), {?opaque(ordsets:from_list(NewList)), RR}; -t_solve_remote(?tuple(?any, _, _) = T, _R, _C) -> {T, []}; -t_solve_remote(?tuple(Types, Arity, Tag), R, C) -> - {RL, RR} = list_solve_remote(Types, R, C), +t_solve_remote(?tuple(?any, _, _) = T, _ET, _R, _C) -> {T, []}; +t_solve_remote(?tuple(Types, Arity, Tag), ET, R, C) -> + {RL, RR} = list_solve_remote(Types, ET, R, C), {?tuple(RL, Arity, Tag), RR}; -t_solve_remote(?tuple_set(Set), R, C) -> - {NewSet, RR} = tuples_solve_remote(Set, R, C), +t_solve_remote(?tuple_set(Set), ET, R, C) -> + {NewSet, RR} = tuples_solve_remote(Set, ET, R, C), {?tuple_set(NewSet), RR}; -t_solve_remote(?remote(Set), R, C) -> +t_solve_remote(?remote(Set), ET, R, C) -> RemoteList = ordsets:to_list(Set), - {RL, RR} = list_solve_remote_type(RemoteList, R, C), + {RL, RR} = list_solve_remote_type(RemoteList, ET, R, C), {t_sup(RL), RR}; -t_solve_remote(?union(List), R, C) -> - {RL, RR} = list_solve_remote(List, R, C), +t_solve_remote(?union(List), ET, R, C) -> + {RL, RR} = list_solve_remote(List, ET, R, C), {t_sup(RL), RR}; -t_solve_remote(T, _R, _C) -> {T, []}. +t_solve_remote(T, _ET, _R, _C) -> {T, []}. t_solve_remote_type(#remote{mod = RemMod, name = Name, args = Args} = RemType, - R, C) -> + ET, R, C) -> + ArgsLen = length(Args), case dict:find(RemMod, R) of error -> - Msg = io_lib:format("Cannot locate module ~w to " - "resolve the remote type: ~w:~w()~n", - [RemMod, RemMod, Name]), - throw({error, Msg}); + self() ! {self(), ext_types, {RemMod, Name, ArgsLen}}, + {t_any(), []}; {ok, RemDict} -> - case lookup_type(Name, RemDict) of - {type, {_Mod, Type, ArgNames}} when length(Args) =:= length(ArgNames) -> - {NewType, NewCycle, NewRR} = - case unfold(RemType, C) of - true -> - List = lists:zip(ArgNames, Args), - TmpVarDict = dict:from_list(List), - {t_from_form(Type, RemDict, TmpVarDict), [RemType|C], []}; - false -> {t_any(), C, [RemType]} - end, - {RT, RR} = t_solve_remote(NewType, R, NewCycle), - RetRR = NewRR ++ RR, - RT1 = - case lists:member(RemType, RetRR) of - true -> t_limit(RT, ?REC_TYPE_LIMIT); - false -> RT - end, - {RT1, RetRR}; - {opaque, {Mod, Type, ArgNames}} when length(Args) =:= length(ArgNames) -> - List = lists:zip(ArgNames, Args), - TmpVarDict = dict:from_list(List), - {Rep, NewCycle, NewRR} = - case unfold(RemType, C) of - true -> {t_from_form(Type, RemDict, TmpVarDict), [RemType|C], []}; - false -> {t_any(), C, [RemType]} - end, - {NewRep, RR} = t_solve_remote(Rep, R, NewCycle), - RetRR = NewRR ++ RR, - RT1 = - case lists:member(RemType, RetRR) of - true -> t_limit(NewRep, ?REC_TYPE_LIMIT); - false -> NewRep - end, - {t_from_form({opaque, -1, Name, {Mod, Args, RT1}}, - RemDict, TmpVarDict), - RetRR}; - {type, _} -> - Msg = io_lib:format("Unknown remote type ~w\n", [Name]), - throw({error, Msg}); - {opaque, _} -> - Msg = io_lib:format("Unknown remote opaque type ~w\n", [Name]), - throw({error, Msg}); - error -> - Msg = io_lib:format("Unable to find remote type ~w:~w()\n", - [RemMod, Name]), - throw({error, Msg}) + MFA = {RemMod, Name, ArgsLen}, + case sets:is_element(MFA, ET) of + true -> + case lookup_type(Name, RemDict) of + {type, {_Mod, Type, ArgNames}} when ArgsLen =:= length(ArgNames) -> + {NewType, NewCycle, NewRR} = + case can_unfold_more(RemType, C) of + true -> + List = lists:zip(ArgNames, Args), + TmpVarDict = dict:from_list(List), + {t_from_form(Type, RemDict, TmpVarDict), [RemType|C], []}; + false -> + {t_any(), C, [RemType]} + end, + {RT, RR} = t_solve_remote(NewType, ET, R, NewCycle), + RetRR = NewRR ++ RR, + RT1 = + case lists:member(RemType, RetRR) of + true -> t_limit(RT, ?REC_TYPE_LIMIT); + false -> RT + end, + {RT1, RetRR}; + {opaque, {Mod, Type, ArgNames}} when ArgsLen =:= length(ArgNames) -> + List = lists:zip(ArgNames, Args), + TmpVarDict = dict:from_list(List), + {Rep, NewCycle, NewRR} = + case can_unfold_more(RemType, C) of + true -> + {t_from_form(Type, RemDict, TmpVarDict), [RemType|C], []}; + false -> + {t_any(), C, [RemType]} + end, + {NewRep, RR} = t_solve_remote(Rep, ET, R, NewCycle), + RetRR = NewRR ++ RR, + RT1 = + case lists:member(RemType, RetRR) of + true -> t_limit(NewRep, ?REC_TYPE_LIMIT); + false -> NewRep + end, + {t_from_form({opaque, -1, Name, {Mod, Args, RT1}}, + RemDict, TmpVarDict), + RetRR}; + {type, _} -> + Msg = io_lib:format("Unknown remote type ~w\n", [Name]), + throw({error, Msg}); + {opaque, _} -> + Msg = io_lib:format("Unknown remote opaque type ~w\n", [Name]), + throw({error, Msg}); + error -> + Msg = io_lib:format("Unable to find remote type ~w:~w()\n", + [RemMod, Name]), + throw({error, Msg}) + end; + false -> + self() ! {self(), ext_types, {RemMod, Name, ArgsLen}}, + {t_any(), []} end end. -list_solve_remote([], _R, _C) -> +list_solve_remote([], _ET, _R, _C) -> {[], []}; -list_solve_remote([Type|Types], R, C) -> - {RT, RR1} = t_solve_remote(Type, R, C), - {RL, RR2} = list_solve_remote(Types, R, C), +list_solve_remote([Type|Types], ET, R, C) -> + {RT, RR1} = t_solve_remote(Type, ET, R, C), + {RL, RR2} = list_solve_remote(Types, ET, R, C), {[RT|RL], RR1 ++ RR2}. -list_solve_remote_type([], _R, _C) -> +list_solve_remote_type([], _ET, _R, _C) -> {[], []}; -list_solve_remote_type([Type|Types], R, C) -> - {RT, RR1} = t_solve_remote_type(Type, R, C), - {RL, RR2} = list_solve_remote_type(Types, R, C), +list_solve_remote_type([Type|Types], ET, R, C) -> + {RT, RR1} = t_solve_remote_type(Type, ET, R, C), + {RL, RR2} = list_solve_remote_type(Types, ET, R, C), {[RT|RL], RR1 ++ RR2}. -opaques_solve_remote([], _R, _C) -> +opaques_solve_remote([], _ET, _R, _C) -> {[], []}; -opaques_solve_remote([#opaque{struct = Struct} = Remote|Tail], R, C) -> - {RT, RR1} = t_solve_remote(Struct, R, C), - {LOp, RR2} = opaques_solve_remote(Tail, R, C), +opaques_solve_remote([#opaque{struct = Struct} = Remote|Tail], ET, R, C) -> + {RT, RR1} = t_solve_remote(Struct, ET, R, C), + {LOp, RR2} = opaques_solve_remote(Tail, ET, R, C), {[Remote#opaque{struct = RT}|LOp], RR1 ++ RR2}. -tuples_solve_remote([], _R, _C) -> +tuples_solve_remote([], _ET, _R, _C) -> {[], []}; -tuples_solve_remote([{Sz, Tuples}|Tail], R, C) -> - {RL, RR1} = list_solve_remote(Tuples, R, C), - {LSzTpls, RR2} = tuples_solve_remote(Tail, R, C), +tuples_solve_remote([{Sz, Tuples}|Tail], ET, R, C) -> + {RL, RR1} = list_solve_remote(Tuples, ET, R, C), + {LSzTpls, RR2} = tuples_solve_remote(Tail, ET, R, C), {[{Sz, RL}|LSzTpls], RR1 ++ RR2}. %%----------------------------------------------------------------------------- @@ -801,7 +818,7 @@ t_is_none_or_unit(?unit) -> true; t_is_none_or_unit(_) -> false. %%----------------------------------------------------------------------------- -%% Atoms and the derived type bool +%% Atoms and the derived type boolean %% -spec t_atom() -> erl_type(). @@ -1440,6 +1457,26 @@ t_is_tuple(_) -> false. %% Non-primitive types, including some handy syntactic sugar types %% +-spec t_unicode_string() -> erl_type(). + +t_unicode_string() -> + t_list(t_unicode_char()). + +-spec t_charlist() -> erl_type(). + +t_charlist() -> + t_charlist(1). + +-spec t_charlist(non_neg_integer()) -> erl_type(). + +t_charlist(N) when N > 0 -> + t_maybe_improper_list(t_sup([t_unicode_char(), + t_unicode_binary(), + t_charlist(N-1)]), + t_sup(t_unicode_binary(), t_nil())); +t_charlist(0) -> + t_maybe_improper_list(t_any(), t_sup(t_unicode_binary(), t_nil())). + -spec t_constant() -> erl_type(). t_constant() -> @@ -1534,6 +1571,16 @@ t_parameterized_module() -> t_timeout() -> t_sup(t_non_neg_integer(), t_atom('infinity')). +-spec t_unicode_binary() -> erl_type(). + +t_unicode_binary() -> + t_binary(). % with characters encoded in UTF-8 coding standard + +-spec t_unicode_char() -> erl_type(). + +t_unicode_char() -> + t_integer(). % representing a valid unicode codepoint + %%----------------------------------------------------------------------------- %% Some built-in opaque types %% @@ -1596,7 +1643,7 @@ t_set() -> t_tid() -> t_opaque(ets, tid, [], t_integer()). --spec all_opaque_builtins() -> [erl_type()]. +-spec all_opaque_builtins() -> [erl_type(),...]. all_opaque_builtins() -> [t_array(), t_dict(), t_digraph(), t_gb_set(), @@ -2112,7 +2159,8 @@ t_elements(?identifier(IDs)) -> t_elements(?list(_, _, _) = T) -> [T]; t_elements(?number(_, _) = T) -> case T of - ?number(?any, ?unknown_qual) -> [T]; + ?number(?any, ?unknown_qual) -> + [?float, ?integer(?any)]; ?float -> [T]; ?integer(?any) -> [T]; ?int_range(_, _) -> [T]; @@ -2159,10 +2207,10 @@ t_inf(?var(_), T, _Mode) -> subst_all_vars_to_any(T); t_inf(T, ?var(_), _Mode) -> subst_all_vars_to_any(T); t_inf(?any, T, _Mode) -> subst_all_vars_to_any(T); t_inf(T, ?any, _Mode) -> subst_all_vars_to_any(T); -t_inf(?unit, _, _Mode) -> ?unit; -t_inf(_, ?unit, _Mode) -> ?unit; t_inf(?none, _, _Mode) -> ?none; t_inf(_, ?none, _Mode) -> ?none; +t_inf(?unit, _, _Mode) -> ?unit; % ?unit cases should appear below ?none +t_inf(_, ?unit, _Mode) -> ?unit; t_inf(T, T, _Mode) -> subst_all_vars_to_any(T); t_inf(?atom(Set1), ?atom(Set2), _) -> case set_intersection(Set1, Set2) of @@ -2371,14 +2419,16 @@ inf_tuple_sets(L1, L2, Mode) -> List -> ?tuple_set(List) end. -inf_tuple_sets([{Arity, Tuples1}|Left1], [{Arity, Tuples2}|Left2], Acc, Mode) -> +inf_tuple_sets([{Arity, Tuples1}|Ts1], [{Arity, Tuples2}|Ts2], Acc, Mode) -> case inf_tuples_in_sets(Tuples1, Tuples2, Mode) of - [] -> inf_tuple_sets(Left1, Left2, Acc, Mode); - NewTuples -> inf_tuple_sets(Left1, Left2, [{Arity, NewTuples}|Acc], Mode) + [] -> inf_tuple_sets(Ts1, Ts2, Acc, Mode); + [?tuple_set([{Arity, NewTuples}])] -> + inf_tuple_sets(Ts1, Ts2, [{Arity, NewTuples}|Acc], Mode); + NewTuples -> inf_tuple_sets(Ts1, Ts2, [{Arity, NewTuples}|Acc], Mode) end; -inf_tuple_sets(L1 = [{Arity1, _}|Left1], L2 = [{Arity2, _}|Left2], Acc, Mode) -> - if Arity1 < Arity2 -> inf_tuple_sets(Left1, L2, Acc, Mode); - Arity1 > Arity2 -> inf_tuple_sets(L1, Left2, Acc, Mode) +inf_tuple_sets([{Arity1, _}|Ts1] = L1, [{Arity2, _}|Ts2] = L2, Acc, Mode) -> + if Arity1 < Arity2 -> inf_tuple_sets(Ts1, L2, Acc, Mode); + Arity1 > Arity2 -> inf_tuple_sets(L1, Ts2, Acc, Mode) end; inf_tuple_sets([], _, Acc, _Mode) -> lists:reverse(Acc); inf_tuple_sets(_, [], Acc, _Mode) -> lists:reverse(Acc). @@ -2394,17 +2444,17 @@ inf_tuples_in_sets(L1, [?tuple(Elements2, _, ?any)], Mode) -> inf_tuples_in_sets(L1, L2, Mode) -> inf_tuples_in_sets(L1, L2, [], Mode). -inf_tuples_in_sets([?tuple(Elements1, Arity, Tag)|Left1], - [?tuple(Elements2, Arity, Tag)|Left2], Acc, Mode) -> +inf_tuples_in_sets([?tuple(Elements1, Arity, Tag)|Ts1], + [?tuple(Elements2, Arity, Tag)|Ts2], Acc, Mode) -> case t_inf_lists_strict(Elements1, Elements2, Mode) of - bottom -> inf_tuples_in_sets(Left1, Left2, Acc, Mode); - NewElements -> - inf_tuples_in_sets(Left1, Left2, [?tuple(NewElements, Arity, Tag)|Acc], Mode) + bottom -> inf_tuples_in_sets(Ts1, Ts2, Acc, Mode); + NewElements -> + inf_tuples_in_sets(Ts1, Ts2, [?tuple(NewElements, Arity, Tag)|Acc], Mode) end; -inf_tuples_in_sets([?tuple(_, _, Tag1)|Left1] = L1, - [?tuple(_, _, Tag2)|Left2] = L2, Acc, Mode) -> - if Tag1 < Tag2 -> inf_tuples_in_sets(Left1, L2, Acc, Mode); - Tag1 > Tag2 -> inf_tuples_in_sets(L1, Left2, Acc, Mode) +inf_tuples_in_sets([?tuple(_, _, Tag1)|Ts1] = L1, + [?tuple(_, _, Tag2)|Ts2] = L2, Acc, Mode) -> + if Tag1 < Tag2 -> inf_tuples_in_sets(Ts1, L2, Acc, Mode); + Tag1 > Tag2 -> inf_tuples_in_sets(L1, Ts2, Acc, Mode) end; inf_tuples_in_sets([], _, Acc, _Mode) -> lists:reverse(Acc); inf_tuples_in_sets(_, [], Acc, _Mode) -> lists:reverse(Acc). @@ -2523,12 +2573,14 @@ t_subst(T, _Dict, _Fun) -> %% Unification %% --spec t_unify(erl_type(), erl_type()) -> {erl_type(), [{_, erl_type()}]}. +-type t_unify_ret() :: {erl_type(), [{_, erl_type()}]}. + +-spec t_unify(erl_type(), erl_type()) -> t_unify_ret(). t_unify(T1, T2) -> t_unify(T1, T2, []). --spec t_unify(erl_type(), erl_type(), [erl_type()]) -> {erl_type(), [{_, erl_type()}]}. +-spec t_unify(erl_type(), erl_type(), [erl_type()]) -> t_unify_ret(). t_unify(T1, T2, Opaques) -> {T, Dict} = t_unify(T1, T2, dict:new(), Opaques), @@ -2541,7 +2593,7 @@ t_unify(?var(Id1) = T, ?var(Id2), Dict, Opaques) -> error -> case dict:find(Id2, Dict) of error -> {T, dict:store(Id2, T, Dict)}; - {ok, Type} -> {Type, t_unify(T, Type, Dict, Opaques)} + {ok, Type} -> t_unify(T, Type, Dict, Opaques) end; {ok, Type1} -> case dict:find(Id2, Dict) of @@ -2749,7 +2801,9 @@ t_subtract_list(T, []) -> -spec t_subtract(erl_type(), erl_type()) -> erl_type(). t_subtract(_, ?any) -> ?none; +t_subtract(_, ?var(_)) -> ?none; t_subtract(?any, _) -> ?any; +t_subtract(?var(_) = T, _) -> T; t_subtract(T, ?unit) -> T; t_subtract(?unit, _) -> ?unit; t_subtract(?none, _) -> ?none; @@ -2777,13 +2831,13 @@ t_subtract(?opaque(Set1), ?opaque(Set2)) -> Set -> ?opaque(Set) end; t_subtract(?matchstate(Pres1, Slots1), ?matchstate(Pres2, _Slots2)) -> - Pres = t_subtract(Pres1,Pres2), + Pres = t_subtract(Pres1, Pres2), case t_is_none(Pres) of true -> ?none; - false -> ?matchstate(Pres,Slots1) + false -> ?matchstate(Pres, Slots1) end; -t_subtract(?matchstate(Present,Slots),_) -> - ?matchstate(Present,Slots); +t_subtract(?matchstate(Present, Slots), _) -> + ?matchstate(Present, Slots); t_subtract(?nil, ?nil) -> ?none; t_subtract(?nil, ?nonempty_list(_, _)) -> @@ -2803,7 +2857,7 @@ t_subtract(?list(Contents1, Termination1, Size1) = T, true -> case {Size1, Size2} of {?nonempty_qual, ?unknown_qual} -> ?none; - {?unknown_qual, ?nonempty_qual} -> Termination1; + {?unknown_qual, ?nonempty_qual} -> ?nil; {S, S} -> ?none end; false -> @@ -2905,7 +2959,7 @@ t_subtract(T, ?product(_)) -> T; t_subtract(?union(U1), ?union(U2)) -> subtract_union(U1, U2); -t_subtract(T1, T2) -> +t_subtract(T1, T2) -> ?union(U1) = force_union(T1), ?union(U2) = force_union(T2), subtract_union(U1, U2). @@ -3298,28 +3352,44 @@ record_to_string(Tag, [_|Fields], FieldNames, RecDict) -> FieldStrings = record_fields_to_string(Fields, FieldNames, RecDict, []), "#" ++ atom_to_list(Tag) ++ "{" ++ sequence(FieldStrings, [], ",") ++ "}". -record_fields_to_string([Field|Left1], [{FieldName, DeclaredType}|Left2], - RecDict, Acc) -> - PrintType = - case t_is_equal(Field, DeclaredType) of - true -> false; +record_fields_to_string([F|Fs], [{FName, _DefType}|FDefs], RecDict, Acc) -> + NewAcc = + case t_is_any(F) orelse t_is_atom('undefined', F) of + true -> Acc; false -> - case t_is_any(DeclaredType) andalso t_is_atom(undefined, Field) of - true -> false; - false -> - TmpType = t_subtract(DeclaredType, t_atom(undefined)), - not t_is_equal(Field, TmpType) - end + StrFV = atom_to_list(FName) ++ "::" ++ t_to_string(F, RecDict), + %% ActualDefType = t_subtract(DefType, t_atom('undefined')), + %% Str = case t_is_any(ActualDefType) of + %% true -> StrFV; + %% false -> StrFV ++ "::" ++ t_to_string(ActualDefType, RecDict) + %% end, + [StrFV|Acc] end, - case PrintType of - false -> record_fields_to_string(Left1, Left2, RecDict, Acc); - true -> - String = atom_to_list(FieldName) ++ "::" ++ t_to_string(Field, RecDict), - record_fields_to_string(Left1, Left2, RecDict, [String|Acc]) - end; + record_fields_to_string(Fs, FDefs, RecDict, NewAcc); record_fields_to_string([], [], _RecDict, Acc) -> lists:reverse(Acc). +-spec record_field_diffs_to_string(erl_type(), dict()) -> string(). + +record_field_diffs_to_string(?tuple([_|Fs], Arity, Tag), RecDict) -> + [TagAtom] = t_atom_vals(Tag), + {ok, FieldNames} = lookup_record(TagAtom, Arity-1, RecDict), + %% io:format("RecCElems = ~p\nRecTypes = ~p\n", [Fs, FieldNames]), + FieldDiffs = field_diffs(Fs, FieldNames, RecDict, []), + sequence(FieldDiffs, [], " and "). + +field_diffs([F|Fs], [{FName, DefType}|FDefs], RecDict, Acc) -> + NewAcc = + case t_is_subtype(F, DefType) of + true -> Acc; + false -> + Str = atom_to_list(FName) ++ "::" ++ t_to_string(DefType, RecDict), + [Str|Acc] + end, + field_diffs(Fs, FDefs, RecDict, NewAcc); +field_diffs([], [], _, Acc) -> + lists:reverse(Acc). + comma_sequence(Types, RecDict) -> List = [case T =:= ?any of true -> "_"; @@ -3338,8 +3408,8 @@ sequence([], [], _Delimiter) -> []; sequence([T], Acc, _Delimiter) -> lists:flatten(lists:reverse([T|Acc])); -sequence([T|Left], Acc, Delimiter) -> - sequence(Left, [T ++ Delimiter|Acc], Delimiter). +sequence([T|Ts], Acc, Delimiter) -> + sequence(Ts, [T ++ Delimiter|Acc], Delimiter). %%============================================================================= %% @@ -3360,188 +3430,263 @@ t_from_form(Form, RecDict) -> -spec t_from_form(parse_form(), dict(), dict()) -> erl_type(). t_from_form(Form, RecDict, VarDict) -> - {T, _R} = t_from_form(Form, [], RecDict, VarDict), + {T, _R} = t_from_form(Form, [], false, RecDict, VarDict), T. -type type_names() :: [{'type' | 'opaque' | 'record', atom()}]. --spec t_from_form(parse_form(), type_names(), dict(), dict()) -> +-spec t_from_form(parse_form(), type_names(), boolean(), dict(), dict()) -> {erl_type(), type_names()}. -t_from_form({var, _L, '_'}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({var, _L, '_'}, _TypeNames, _InOpaque, _RecDict, _VarDict) -> {t_any(), []}; -t_from_form({var, _L, Name}, _TypeNames, _RecDict, VarDict) -> +t_from_form({var, _L, Name}, _TypeNames, _InOpaque, _RecDict, VarDict) -> case dict:find(Name, VarDict) of error -> {t_var(Name), []}; {ok, Val} -> {Val, []} end; -t_from_form({ann_type, _L, [_Var, Type]}, TypeNames, RecDict, VarDict) -> - t_from_form(Type, TypeNames, RecDict, VarDict); -t_from_form({paren_type, _L, [Type]}, TypeNames, RecDict, VarDict) -> - t_from_form(Type, TypeNames, RecDict, VarDict); +t_from_form({ann_type, _L, [_Var, Type]}, TypeNames, InOpaque, RecDict, + VarDict) -> + t_from_form(Type, TypeNames, InOpaque, RecDict, VarDict); +t_from_form({paren_type, _L, [Type]}, TypeNames, InOpaque, RecDict, + VarDict) -> + t_from_form(Type, TypeNames, InOpaque, RecDict, VarDict); t_from_form({remote_type, _L, [{atom, _, Module}, {atom, _, Type}, Args]}, - TypeNames, RecDict, VarDict) -> - {L, R} = list_from_form(Args, TypeNames, RecDict, VarDict), + TypeNames, InOpaque, RecDict, VarDict) -> + {L, R} = list_from_form(Args, TypeNames, InOpaque, RecDict, VarDict), {t_remote(Module, Type, L), R}; -t_from_form({atom, _L, Atom}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({atom, _L, Atom}, _TypeNames, _InOpaque, _RecDict, _VarDict) -> {t_atom(Atom), []}; -t_from_form({integer, _L, Int}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({integer, _L, Int}, _TypeNames, _InOpaque, _RecDict, _VarDict) -> {t_integer(Int), []}; -t_from_form({type, _L, any, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({op, _L, _Op, _Arg} = Op, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> + case erl_eval:partial_eval(Op) of + {integer, _, Val} -> + {t_integer(Val), []}; + _ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Op])}) + end; +t_from_form({op, _L, _Op, _Arg1, _Arg2} = Op, _TypeNames, _InOpaque, + _RecDict, _VarDict) -> + case erl_eval:partial_eval(Op) of + {integer, _, Val} -> + {t_integer(Val), []}; + _ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Op])}) + end; +t_from_form({type, _L, any, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_any(), []}; -t_from_form({type, _L, arity, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, arity, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_arity(), []}; -t_from_form({type, _L, array, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, array, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_array(), []}; -t_from_form({type, _L, atom, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, atom, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_atom(), []}; -t_from_form({type, _L, binary, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, binary, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_binary(), []}; -t_from_form({type, _L, binary, [{integer, _, Base}, {integer, _, Unit}]}, - _TypeNames, _RecDict, _VarDict) -> - {t_bitstr(Unit, Base), []}; -t_from_form({type, _L, bitstring, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, binary, [Base, Unit]} = Type, + _TypeNames, _InOpaque, _RecDict, _VarDict) -> + case {erl_eval:partial_eval(Base), erl_eval:partial_eval(Unit)} of + {{integer, _, BaseVal}, + {integer, _, UnitVal}} + when BaseVal >= 0, UnitVal >= 0 -> + {t_bitstr(UnitVal, BaseVal), []}; + _ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Type])}) + end; +t_from_form({type, _L, bitstring, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_bitstr(), []}; -t_from_form({type, _L, bool, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, bool, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_boolean(), []}; % XXX: Temporarily -t_from_form({type, _L, boolean, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, boolean, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_boolean(), []}; -t_from_form({type, _L, byte, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, byte, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_byte(), []}; -t_from_form({type, _L, char, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, char, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_char(), []}; -t_from_form({type, _L, dict, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, dict, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_dict(), []}; -t_from_form({type, _L, digraph, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, digraph, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_digraph(), []}; -t_from_form({type, _L, float, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, float, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_float(), []}; -t_from_form({type, _L, function, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, function, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_fun(), []}; -t_from_form({type, _L, 'fun', []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, 'fun', []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_fun(), []}; t_from_form({type, _L, 'fun', [{type, _, any, []}, Range]}, TypeNames, - RecDict, VarDict) -> - {T, R} = t_from_form(Range, TypeNames, RecDict, VarDict), + InOpaque, RecDict, VarDict) -> + {T, R} = t_from_form(Range, TypeNames, InOpaque, RecDict, VarDict), {t_fun(T), R}; t_from_form({type, _L, 'fun', [{type, _, product, Domain}, Range]}, - TypeNames, RecDict, VarDict) -> - {L, R1} = list_from_form(Domain, TypeNames, RecDict, VarDict), - {T, R2} = t_from_form(Range, TypeNames, RecDict, VarDict), + TypeNames, InOpaque, RecDict, VarDict) -> + {L, R1} = list_from_form(Domain, TypeNames, InOpaque, RecDict, VarDict), + {T, R2} = t_from_form(Range, TypeNames, InOpaque, RecDict, VarDict), {t_fun(L, T), R1 ++ R2}; -t_from_form({type, _L, gb_set, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, gb_set, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_gb_set(), []}; -t_from_form({type, _L, gb_tree, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, gb_tree, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_gb_tree(), []}; -t_from_form({type, _L, identifier, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, identifier, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_identifier(), []}; -t_from_form({type, _L, integer, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, integer, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_integer(), []}; -t_from_form({type, _L, iodata, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, iodata, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_iodata(), []}; -t_from_form({type, _L, iolist, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, iolist, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_iolist(), []}; -t_from_form({type, _L, list, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, list, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_list(), []}; -t_from_form({type, _L, list, [Type]}, TypeNames, RecDict, VarDict) -> - {T, R} = t_from_form(Type, TypeNames, RecDict, VarDict), +t_from_form({type, _L, list, [Type]}, TypeNames, InOpaque, RecDict, + VarDict) -> + {T, R} = t_from_form(Type, TypeNames, InOpaque, RecDict, VarDict), {t_list(T), R}; -t_from_form({type, _L, mfa, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, mfa, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_mfa(), []}; -t_from_form({type, _L, module, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, module, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_module(), []}; -t_from_form({type, _L, nil, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, nil, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_nil(), []}; -t_from_form({type, _L, neg_integer, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, neg_integer, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_neg_integer(), []}; -t_from_form({type, _L, non_neg_integer, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, non_neg_integer, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_non_neg_integer(), []}; -t_from_form({type, _L, no_return, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, no_return, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_unit(), []}; -t_from_form({type, _L, node, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, node, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_node(), []}; -t_from_form({type, _L, none, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, none, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_none(), []}; -t_from_form({type, _L, nonempty_list, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, nonempty_list, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_nonempty_list(), []}; -t_from_form({type, _L, nonempty_list, [Type]}, TypeNames, RecDict, VarDict) -> - {T, R} = t_from_form(Type, TypeNames, RecDict, VarDict), +t_from_form({type, _L, nonempty_list, [Type]}, TypeNames, InOpaque, RecDict, + VarDict) -> + {T, R} = t_from_form(Type, TypeNames, InOpaque, RecDict, VarDict), {t_nonempty_list(T), R}; t_from_form({type, _L, nonempty_improper_list, [Cont, Term]}, TypeNames, - RecDict, VarDict) -> - {T1, R1} = t_from_form(Cont, TypeNames, RecDict, VarDict), - {T2, R2} = t_from_form(Term, TypeNames, RecDict, VarDict), + InOpaque, RecDict, VarDict) -> + {T1, R1} = t_from_form(Cont, TypeNames, InOpaque, RecDict, VarDict), + {T2, R2} = t_from_form(Term, TypeNames, InOpaque, RecDict, VarDict), {t_cons(T1, T2), R1 ++ R2}; t_from_form({type, _L, nonempty_maybe_improper_list, []}, _TypeNames, - _RecDict, _VarDict) -> + _InOpaque, _RecDict, _VarDict) -> {t_cons(?any, ?any), []}; -t_from_form({type, _L, nonempty_maybe_improper_list, [Cont, Term]}, TypeNames, - RecDict, VarDict) -> - {T1, R1} = t_from_form(Cont, TypeNames, RecDict, VarDict), - {T2, R2} = t_from_form(Term, TypeNames, RecDict, VarDict), +t_from_form({type, _L, nonempty_maybe_improper_list, [Cont, Term]}, + TypeNames, InOpaque, RecDict, VarDict) -> + {T1, R1} = t_from_form(Cont, TypeNames, InOpaque, RecDict, VarDict), + {T2, R2} = t_from_form(Term, TypeNames, InOpaque, RecDict, VarDict), {t_cons(T1, T2), R1 ++ R2}; -t_from_form({type, _L, nonempty_string, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, nonempty_string, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_nonempty_string(), []}; -t_from_form({type, _L, number, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, number, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_number(), []}; -t_from_form({type, _L, pid, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, pid, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_pid(), []}; -t_from_form({type, _L, port, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, port, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_port(), []}; -t_from_form({type, _L, pos_integer, []}, _TypeNames, _RecDict, _VarDict) -> - {t_pos_integer(), []}; -t_from_form({type, _L, maybe_improper_list, []}, _TypeNames, _RecDict, +t_from_form({type, _L, pos_integer, []}, _TypeNames, _InOpaque, _RecDict, _VarDict) -> + {t_pos_integer(), []}; +t_from_form({type, _L, maybe_improper_list, []}, _TypeNames, _InOpaque, + _RecDict, _VarDict) -> {t_maybe_improper_list(), []}; -t_from_form({type, _L, maybe_improper_list, [Content, Termination]}, TypeNames, - RecDict, VarDict) -> - {T1, R1} = t_from_form(Content, TypeNames, RecDict, VarDict), - {T2, R2} = t_from_form(Termination, TypeNames, RecDict, VarDict), +t_from_form({type, _L, maybe_improper_list, [Content, Termination]}, + TypeNames, InOpaque, RecDict, VarDict) -> + {T1, R1} = t_from_form(Content, TypeNames, InOpaque, RecDict, VarDict), + {T2, R2} = t_from_form(Termination, TypeNames, InOpaque, RecDict, VarDict), {t_maybe_improper_list(T1, T2), R1 ++ R2}; -t_from_form({type, _L, product, Elements}, TypeNames, RecDict, VarDict) -> - {L, R} = list_from_form(Elements, TypeNames, RecDict, VarDict), +t_from_form({type, _L, product, Elements}, TypeNames, InOpaque, RecDict, + VarDict) -> + {L, R} = list_from_form(Elements, TypeNames, InOpaque, RecDict, VarDict), {t_product(L), R}; -t_from_form({type, _L, queue, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, queue, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_queue(), []}; -t_from_form({type, _L, range, [{integer, _, From}, {integer, _, To}]}, - _TypeNames, _RecDict, _VarDict) -> - {t_from_range(From, To), []}; -t_from_form({type, _L, record, [Name|Fields]}, TypeNames, RecDict, VarDict) -> - record_from_form(Name, Fields, TypeNames, RecDict, VarDict); -t_from_form({type, _L, reference, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, range, [From, To]} = Type, + _TypeNames, _InOpaque, _RecDict, _VarDict) -> + case {erl_eval:partial_eval(From), erl_eval:partial_eval(To)} of + {{integer, _, FromVal}, {integer, _, ToVal}} -> + {t_from_range(FromVal, ToVal), []}; + _ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Type])}) + end; +t_from_form({type, _L, record, [Name|Fields]}, TypeNames, InOpaque, RecDict, + VarDict) -> + record_from_form(Name, Fields, TypeNames, InOpaque, RecDict, VarDict); +t_from_form({type, _L, reference, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_reference(), []}; -t_from_form({type, _L, set, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, set, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_set(), []}; -t_from_form({type, _L, string, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, string, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_string(), []}; -t_from_form({type, _L, term, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, term, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_any(), []}; -t_from_form({type, _L, tid, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, tid, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_tid(), []}; -t_from_form({type, _L, timeout, []}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, timeout, []}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_timeout(), []}; -t_from_form({type, _L, tuple, any}, _TypeNames, _RecDict, _VarDict) -> +t_from_form({type, _L, tuple, any}, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {t_tuple(), []}; -t_from_form({type, _L, tuple, Args}, TypeNames, RecDict, VarDict) -> - {L, R} = list_from_form(Args, TypeNames, RecDict, VarDict), +t_from_form({type, _L, tuple, Args}, TypeNames, InOpaque, RecDict, VarDict) -> + {L, R} = list_from_form(Args, TypeNames, InOpaque, RecDict, VarDict), {t_tuple(L), R}; -t_from_form({type, _L, union, Args}, TypeNames, RecDict, VarDict) -> - {L, R} = list_from_form(Args, TypeNames, RecDict, VarDict), +t_from_form({type, _L, union, Args}, TypeNames, InOpaque, RecDict, VarDict) -> + {L, R} = list_from_form(Args, TypeNames, InOpaque, RecDict, VarDict), {t_sup(L), R}; -t_from_form({type, _L, Name, Args}, TypeNames, RecDict, VarDict) -> +t_from_form({type, _L, Name, Args}, TypeNames, InOpaque, RecDict, VarDict) -> case lookup_type(Name, RecDict) of {type, {_Module, Type, ArgNames}} when length(Args) =:= length(ArgNames) -> - case unfold({type, Name}, TypeNames) of + case can_unfold_more({type, Name}, TypeNames) of true -> List = lists:zipwith( fun(ArgName, ArgType) -> {Ttemp, _R} = t_from_form(ArgType, TypeNames, - RecDict, VarDict), + InOpaque, RecDict, + VarDict), {ArgName, Ttemp} end, ArgNames, Args), TmpVarDict = dict:from_list(List), - {T, R} = t_from_form(Type, [{type, Name}|TypeNames], RecDict, - TmpVarDict), + {T, R} = t_from_form(Type, [{type, Name}|TypeNames], InOpaque, + RecDict, TmpVarDict), case lists:member({type, Name}, R) of true -> {t_limit(T, ?REC_TYPE_LIMIT), R}; false -> {T, R} @@ -3550,26 +3695,32 @@ t_from_form({type, _L, Name, Args}, TypeNames, RecDict, VarDict) -> end; {opaque, {Module, Type, ArgNames}} when length(Args) =:= length(ArgNames) -> {Rep, Rret} = - case unfold({opaque, Name}, TypeNames) of + case can_unfold_more({opaque, Name}, TypeNames) of true -> List = lists:zipwith( fun(ArgName, ArgType) -> - {Ttemp, _R} = t_from_form(ArgType, TypeNames, - RecDict, VarDict), + {Ttemp, _R} = t_from_form(ArgType, TypeNames, + InOpaque, RecDict, + VarDict), {ArgName, Ttemp} end, ArgNames, Args), TmpVarDict = dict:from_list(List), - {T, R} = t_from_form(Type, [{opaque, Name}|TypeNames], RecDict, - TmpVarDict), + {T, R} = t_from_form(Type, [{opaque, Name}|TypeNames], true, + RecDict, TmpVarDict), case lists:member({opaque, Name}, R) of true -> {t_limit(T, ?REC_TYPE_LIMIT), R}; false -> {T, R} end; false -> {t_any(), [{opaque, Name}]} end, - Tret = t_from_form({opaque, -1, Name, {Module, Args, Rep}}, - RecDict, VarDict), + Tret = + case InOpaque of + true -> Rep; + false -> + t_from_form({opaque, -1, Name, {Module, Args, Rep}}, + RecDict, VarDict) + end, {Tret, Rret}; {type, _} -> throw({error, io_lib:format("Unknown type ~w\n", [Name])}); @@ -3578,15 +3729,16 @@ t_from_form({type, _L, Name, Args}, TypeNames, RecDict, VarDict) -> error -> throw({error, io_lib:format("Unable to find type ~w\n", [Name])}) end; -t_from_form({opaque, _L, Name, {Mod, Args, Rep}}, _TypeNames, _RecDict, - _VarDict) -> +t_from_form({opaque, _L, Name, {Mod, Args, Rep}}, _TypeNames, _InOpaque, + _RecDict, _VarDict) -> case Args of [] -> {t_opaque(Mod, Name, Args, Rep), []}; _ -> throw({error, "Polymorphic opaque types not supported yet"}) end. -record_from_form({atom, _, Name}, ModFields, TypeNames, RecDict, VarDict) -> - case unfold({record, Name}, TypeNames) of +record_from_form({atom, _, Name}, ModFields, TypeNames, InOpaque, RecDict, + VarDict) -> + case can_unfold_more({record, Name}, TypeNames) of true -> case lookup_record(Name, RecDict) of {ok, DeclFields} -> @@ -3596,14 +3748,15 @@ record_from_form({atom, _, Name}, ModFields, TypeNames, RecDict, VarDict) -> {DeclFields1, R1} = case lists:all(fun(Elem) -> Elem end, AreTyped) of true -> {DeclFields, []}; - false -> fields_from_form(DeclFields, TypeNames1, + false -> fields_from_form(DeclFields, TypeNames1, InOpaque, RecDict, dict:new()) end, {GetModRec, R2} = get_mod_record(ModFields, DeclFields1, - TypeNames1, RecDict, VarDict), + TypeNames1, InOpaque, + RecDict, VarDict), case GetModRec of {error, FieldName} -> - throw({error, io_lib:format("Illegal declaration of ~w#{~w}\n", + throw({error, io_lib:format("Illegal declaration of #~w{~w}\n", [Name, FieldName])}); {ok, NewFields} -> {t_tuple( @@ -3611,17 +3764,18 @@ record_from_form({atom, _, Name}, ModFields, TypeNames, RecDict, VarDict) -> R1 ++ R2} end; error -> - throw({error, erlang:error(io_lib:format("Unknown record #~w{}\n", - [Name]))}) + throw({error, io_lib:format("Unknown record #~w{}\n", [Name])}) end; false -> {t_any(), []} end. -get_mod_record([], DeclFields, _TypeNames, _RecDict, _VarDict) -> +get_mod_record([], DeclFields, _TypeNames, _InOpaque, _RecDict, + _VarDict) -> {{ok, DeclFields}, []}; -get_mod_record(ModFields, DeclFields, TypeNames, RecDict, VarDict) -> +get_mod_record(ModFields, DeclFields, TypeNames, InOpaque, RecDict, + VarDict) -> DeclFieldsDict = orddict:from_list(DeclFields), - {ModFieldsDict, R} = build_field_dict(ModFields, TypeNames, + {ModFieldsDict, R} = build_field_dict(ModFields, TypeNames, InOpaque, RecDict, VarDict), case get_mod_record(DeclFieldsDict, ModFieldsDict, []) of {error, _FieldName} = Error -> {Error, R}; @@ -3631,21 +3785,23 @@ get_mod_record(ModFields, DeclFields, TypeNames, RecDict, VarDict) -> R} end. -build_field_dict(FieldTypes, TypeNames, RecDict, VarDict) -> - build_field_dict(FieldTypes, TypeNames, RecDict, VarDict, []). +build_field_dict(FieldTypes, TypeNames, InOpaque, RecDict, VarDict) -> + build_field_dict(FieldTypes, TypeNames, InOpaque, RecDict, VarDict, []). build_field_dict([{type, _, field_type, [{atom, _, Name}, Type]}|Left], - TypeNames, RecDict, VarDict, Acc) -> - {T, R1} = t_from_form(Type, TypeNames, RecDict, VarDict), + TypeNames, InOpaque, RecDict, VarDict, Acc) -> + {T, R1} = t_from_form(Type, TypeNames, InOpaque, RecDict, VarDict), NewAcc = [{Name, T}|Acc], - {D, R2} = build_field_dict(Left, TypeNames, RecDict, VarDict, NewAcc), + {D, R2} = build_field_dict(Left, TypeNames, InOpaque, RecDict, VarDict, + NewAcc), {D, R1 ++ R2}; -build_field_dict([], _TypeNames, _RecDict, _VarDict, Acc) -> +build_field_dict([], _TypeNames, _InOpaque, _RecDict, _VarDict, Acc) -> {orddict:from_list(Acc), []}. get_mod_record([{FieldName, DeclType}|Left1], [{FieldName, ModType}|Left2], Acc) -> - case t_is_var(ModType) orelse t_is_subtype(ModType, DeclType) of + case t_is_var(ModType) orelse t_is_remote(ModType) orelse + t_is_subtype(ModType, DeclType) of false -> {error, FieldName}; true -> get_mod_record(Left1, Left2, [{FieldName, ModType}|Acc]) end; @@ -3658,18 +3814,19 @@ get_mod_record(DeclFields, [], Acc) -> get_mod_record(_, [{FieldName2, _ModType}|_], _Acc) -> {error, FieldName2}. -fields_from_form([], _TypeNames, _RecDict, _VarDict) -> +fields_from_form([], _TypeNames, _InOpaque, _RecDict, _VarDict) -> {[], []}; -fields_from_form([{Name, Type}|Tail], TypeNames, RecDict, VarDict) -> - {T, R1} = t_from_form(Type, TypeNames, RecDict, VarDict), - {F, R2} = fields_from_form(Tail, TypeNames, RecDict, VarDict), +fields_from_form([{Name, Type}|Tail], TypeNames, InOpaque, RecDict, + VarDict) -> + {T, R1} = t_from_form(Type, TypeNames, InOpaque, RecDict, VarDict), + {F, R2} = fields_from_form(Tail, TypeNames, InOpaque, RecDict, VarDict), {[{Name, T}|F], R1 ++ R2}. -list_from_form([], _TypeNames, _RecDict, _VarDict) -> +list_from_form([], _TypeNames, _InOpaque, _RecDict, _VarDict) -> {[], []}; -list_from_form([H|Tail], TypeNames, RecDict, VarDict) -> - {T, R1} = t_from_form(H, TypeNames, RecDict, VarDict), - {L, R2} = list_from_form(Tail, TypeNames, RecDict, VarDict), +list_from_form([H|Tail], TypeNames, InOpaque, RecDict, VarDict) -> + {T, R1} = t_from_form(H, TypeNames, InOpaque, RecDict, VarDict), + {L, R2} = list_from_form(Tail, TypeNames, InOpaque, RecDict, VarDict), {[T|L], R1 ++ R2}. -spec t_form_to_string(parse_form()) -> string(). @@ -3679,6 +3836,16 @@ t_form_to_string({var, _L, Name}) -> atom_to_list(Name); t_form_to_string({atom, _L, Atom}) -> io_lib:write_string(atom_to_list(Atom), $'); % To quote or not to quote... ' t_form_to_string({integer, _L, Int}) -> integer_to_list(Int); +t_form_to_string({op, _L, _Op, _Arg} = Op) -> + case erl_eval:partial_eval(Op) of + {integer, _, _} = Int -> t_form_to_string(Int); + _ -> io_lib:format("Bad formed type ~w",[Op]) + end; +t_form_to_string({op, _L, _Op, _Arg1, _Arg2} = Op) -> + case erl_eval:partial_eval(Op) of + {integer, _, _} = Int -> t_form_to_string(Int); + _ -> io_lib:format("Bad formed type ~w",[Op]) + end; t_form_to_string({ann_type, _L, [Var, Type]}) -> t_form_to_string(Var) ++ "::" ++ t_form_to_string(Type); t_form_to_string({paren_type, _L, [Type]}) -> @@ -3705,8 +3872,12 @@ t_form_to_string({type, _L, nonempty_list, [Type]}) -> t_form_to_string({type, _L, nonempty_string, []}) -> "nonempty_string()"; t_form_to_string({type, _L, product, Elements}) -> "<" ++ sequence(t_form_to_string_list(Elements), ",") ++ ">"; -t_form_to_string({type, _L, range, [{integer, _, From}, {integer, _, To}]}) -> - io_lib:format("~w..~w", [From, To]); +t_form_to_string({type, _L, range, [From, To]} = Type) -> + case {erl_eval:partial_eval(From), erl_eval:partial_eval(To)} of + {{integer, _, FromVal}, {integer, _, ToVal}} -> + io_lib:format("~w..~w", [FromVal, ToVal]); + _ -> io_lib:format("Bad formed type ~w",[Type]) + end; t_form_to_string({type, _L, record, [{atom, _, Name}]}) -> io_lib:format("#~w{}", [Name]); t_form_to_string({type, _L, record, [{atom, _, Name}|Fields]}) -> @@ -3725,13 +3896,17 @@ t_form_to_string({type, _L, Name, []} = T) -> try t_to_string(t_from_form(T)) catch throw:{error, _} -> atom_to_list(Name) ++ "()" end; -t_form_to_string({type, _L, binary, [{integer, _, X}, {integer, _, Y}]}) -> - case Y of - 0 -> - case X of - 0 -> "<<>>"; - _ -> io_lib:format("<<_:~w>>", [X]) - end +t_form_to_string({type, _L, binary, [X,Y]} = Type) -> + case {erl_eval:partial_eval(X), erl_eval:partial_eval(Y)} of + {{integer, _, XVal}, {integer, _, YVal}} -> + case YVal of + 0 -> + case XVal of + 0 -> "<<>>"; + _ -> io_lib:format("<<_:~w>>", [XVal]) + end + end; + _ -> io_lib:format("Bad formed type ~w",[Type]) end; t_form_to_string({type, _L, Name, List}) -> io_lib:format("~w(~s)", [Name, sequence(t_form_to_string_list(List), ",")]). @@ -3763,6 +3938,8 @@ any_none_or_unit([?unit|_]) -> true; any_none_or_unit([_|Left]) -> any_none_or_unit(Left); any_none_or_unit([]) -> false. +-spec is_erl_type(any()) -> boolean(). + is_erl_type(?any) -> true; is_erl_type(?none) -> true; is_erl_type(?unit) -> true; @@ -3808,8 +3985,9 @@ lookup_type(Name, RecDict) -> type_is_defined(TypeOrOpaque, Name, RecDict) -> dict:is_key({TypeOrOpaque, Name}, RecDict). -unfold(TypeName, TypeNames) -> - not lists:member(TypeName, TypeNames). +can_unfold_more(TypeName, TypeNames) -> + Fun = fun(E, Acc) -> case E of TypeName -> Acc + 1; _ -> Acc end end, + lists:foldl(Fun, 0, TypeNames) < ?REC_TYPE_LIMIT. %% ----------------------------------- %% Set diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml index 2c78558190..434bfac64c 100644 --- a/lib/hipe/doc/src/notes.xml +++ b/lib/hipe/doc/src/notes.xml @@ -30,6 +30,218 @@ </header> <p>This document describes the changes made to HiPE.</p> +<section><title>Hipe 3.7.9</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix erroneous fail info of a hipe_bs_primop</p> + <p> + Own Id: OTP-9036</p> + </item> + <item> + <p> + The change fixes a bug in the translation of 'bs_add' + BEAM instruction to HiPE's Icode representation. When + these instructions appeared in a guard context the + previous translation was obviously buggy.</p> + <p> + Own Id: OTP-9044</p> + </item> + <item> + <p> + Sanitize the specs of the code module</p> + <p> + After the addition of unicode_binary() to the + file:filename() type, dialyzer started complaining about + erroneous or incomplete specs in some functions of the + 'code' module. The culprit was hard-coded information in + erl_bif_types for functions of this module, which were + not updated. Since these functions have proper specs + these days and code duplication (pun intended) is never a + good idea, their type information was removed from + erl_bif_types.</p> + <p> + While doing this, some erroneous comments were fixed in + the code module and also made sure that the code now runs + without dialyzer warnings even when the + -Wunmatched_returns option is used.</p> + <p> + Some cleanups were applied to erl_bif_types too.</p> + <p> + Own Id: OTP-9100</p> + </item> + <item> + <p> + Fix bug in the simplification of inexact comparisons</p> + <p> + On 31/1/2011 Paul Guyot reported a bug in the native code + compilation of inexact equality/inequality tests between + floats and integers. The relevant test was:</p> + <p> + f(X) -> Y = X / 2, Y == 0.</p> + <p> + and hipe erroneously evaluated the calls f(0) and f(0.0) + to 'false'.</p> + <p> + The culprit was in the simplification code of the Icode + range analysis which used an erroneous test (lists:any/1 + instead of lists:all/1).</p> + <p> + Own Id: OTP-9101</p> + </item> + <item> + <p> + Document exiting and garbage_collecting process statuses</p> + <p> + Own Id: OTP-9102</p> + </item> + <item> + <p> + Remove hipe constants pool</p> + <p> + Hipe constants used to be allocated within a single, + fixed-size pool for interaction with the garbage + collector. However, the garbage collector no longer + depends on constants being allocated within a single + pool, and the fixed size of the pool both meant + unnecessary allocations on most deployments and crashes + on deployments requiring more constants.</p> + <p> + The code was simplified to directly invoke erts_alloc. + Debugging and undocumented function + hipe_bifs:show_literals/0 was removed (it returned true + and output text to the console), and debugging and + undocumented function hipe_bifs:constants_size/0 was + rewritten with a global to count the size of allocated + constants.</p> + <p> + Own Id: OTP-9128</p> + </item> + </list> + </section> + +</section> + +<section><title>Hipe 3.7.8.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Several type specifications for standard libraries were + wrong in the R14B01 release. This is now corrected. The + corrections concern types in re,io,filename and the + module erlang itself.</p> + <p> + Own Id: OTP-9008</p> + </item> + </list> + </section> + +</section> + +<section><title>Hipe 3.7.8</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Compiler warnings were eliminated.</p> + <p> + Own Id: OTP-8855</p> + </item> + </list> + </section> + +</section> + +<section><title>Hipe 3.7.7</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>The HiPE compiler could crash when compiling certain + modules (the bug has been latent, and been exposed by new + optimizations introduced in the BEAM compiler in R14A). + (Thanks to Mikael Pettersson.)</p> + <p> + Own Id: OTP-8800</p> + </item> + <item> + <p> + hipe:load/1 was broken. (Thanks to Paul Guyot.)</p> + <p> + Own Id: OTP-8802</p> + </item> + </list> + </section> + +</section> + +<section><title>Hipe 3.7.6</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p><c>receive</c> statements that can only read out a + newly created reference are now specially optimized so + that it will execute in constant time regardless of the + number of messages in the receive queue for the process. + That optimization will benefit calls to + <c>gen_server:call()</c>. (See <c>gen:do_call/4</c> for + an example of a receive statement that will be + optimized.)</p> + <p> + Own Id: OTP-8623</p> + </item> + <item> + <p> + Various changes to dialyzer-related files for R14.</p> + <p> + - Dialyzer properly supports the new attribute + -export_type and checks that remote types only refer to + exported types. A warning is produced if some + files/applications refer to types defined in modules + which are neither in the PLT nor in the analyzed + applications.</p> + <p> + - Support for detecting data races involving whereis/1 + and unregister/1.</p> + <p> + - More precise identification of the reason(s) why a + record construction violates the types declared for its + fields.</p> + <p> + - Fixed bug in the handling of the 'or' guard.</p> + <p> + - Better handling of the erlang:element/2 BIF.</p> + <p> + - Complete handling of Erlang BIFs.</p> + <p> + Own Id: OTP-8699</p> + </item> + <item> + <p><c>eprof</c> has been reimplemented with support in + the Erlang virtual machine and is now both faster (i.e. + slows down the code being measured less) and scales much + better. In measurements we saw speed-ups compared to the + old eprof ranging from 6 times (for sequential code that + only uses one scheduler/core) up to 84 times (for + parallel code that uses 8 cores).</p> + <p>Note: The API for the <c>eprof</c> has been cleaned up + and extended. See the documentation.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-8706</p> + </item> + </list> + </section> + +</section> + <section><title>Hipe 3.7.5</title> <section><title>Improvements and New Features</title> diff --git a/lib/hipe/doc/src/ref_man.xml b/lib/hipe/doc/src/ref_man.xml index 09d10147ee..bdafb61d08 100644 --- a/lib/hipe/doc/src/ref_man.xml +++ b/lib/hipe/doc/src/ref_man.xml @@ -4,7 +4,7 @@ <application xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>1996</year><year>2009</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/hipe/flow/hipe_dominators.erl b/lib/hipe/flow/hipe_dominators.erl index 3bfa6d43c4..17357461a5 100644 --- a/lib/hipe/flow/hipe_dominators.erl +++ b/lib/hipe/flow/hipe_dominators.erl @@ -1,20 +1,20 @@ %% -*- erlang-indent-level: 2 -*- %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %%------------------------------------------------------------------------ @@ -37,6 +37,8 @@ domFrontier_create/2, domFrontier_get/2]). +-export_type([domTree/0]). + -include("cfg.hrl"). %%======================================================================== diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl index b9679fbb12..d7eb035551 100644 --- a/lib/hipe/icode/hipe_beam_to_icode.erl +++ b/lib/hipe/icode/hipe_beam_to_icode.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -369,6 +369,10 @@ trans_fun([{bif,BifName,{f,Lbl},[_] = Args,Reg}|Instructions], Env) -> trans_fun([{bif,BifName,{f,Lbl},[_,_] = Args,Reg}|Instructions], Env) -> {BifInsts,Env1} = trans_bif(2,BifName,Lbl,Args,Reg,Env), [hipe_icode:mk_comment({bif2,BifName})|BifInsts] ++ trans_fun(Instructions,Env1); +%%--- bif3 --- +trans_fun([{bif,BifName,{f,Lbl},[_,_,_] = Args,Reg}|Instructions], Env) -> + {BifInsts,Env1} = trans_bif(3,BifName,Lbl,Args,Reg,Env), + [hipe_icode:mk_comment({bif3,BifName})|BifInsts] ++ trans_fun(Instructions,Env1); %%--- allocate trans_fun([{allocate,StackSlots,_}|Instructions], Env) -> trans_allocate(StackSlots) ++ trans_fun(Instructions,Env); @@ -895,11 +899,6 @@ trans_fun([{bs_init_bits,{f,Lbl},Size,_Words,_LiveRegs,{field_flags,Flags0},X}| end, trans_bin_call({hipe_bs_primop,Name}, Lbl, Args, [Dst, Base, Offset], Base, Offset, Env, Instructions); -trans_fun([{bs_bits_to_bytes2, Bits, Bytes}|Instructions], Env) -> - Src = trans_arg(Bits), - Dst = mk_var(Bytes), - [hipe_icode:mk_primop([Dst], 'bsl', [Src, hipe_icode:mk_const(3)])| - trans_fun(Instructions,Env)]; trans_fun([{bs_add, {f,Lbl}, [Old,New,Unit], Res}|Instructions], Env) -> Dst = mk_var(Res), Temp = mk_var(new), @@ -919,7 +918,7 @@ trans_fun([{bs_add, {f,Lbl}, [Old,New,Unit], Res}|Instructions], Env) -> Succ = mk_label(new), [hipe_icode:mk_primop([Temp], '*', [NewVar, hipe_icode:mk_const(Unit)], - hipe_icode:label_name(Succ), Lbl), + hipe_icode:label_name(Succ), map_label(Lbl)), Succ] end end, @@ -931,7 +930,7 @@ trans_fun([{bs_add, {f,Lbl}, [Old,New,Unit], Res}|Instructions], Env) -> [FailLbl, hipe_icode:mk_fail([hipe_icode:mk_const(badarg)], error)]}; true -> - {Lbl, []} + {map_label(Lbl), []} end, IsPos = [hipe_icode:mk_if('>=', [Temp, hipe_icode:mk_const(0)], @@ -1129,13 +1128,6 @@ trans_fun([{gc_bif,Name,Fail,_Live,SrcRs,DstR}|Instructions], Env) -> trans_fun([{bif,Name,Fail,SrcRs,DstR}|Instructions], Env) end; %%-------------------------------------------------------------------- -%% Instruction for constant pool added in February 2007 for R11B-4. -%%-------------------------------------------------------------------- -trans_fun([{put_literal,{literal,Literal},DstR}|Instructions], Env) -> - DstV = mk_var(DstR), - Move = hipe_icode:mk_move(DstV, hipe_icode:mk_const(Literal)), - [Move | trans_fun(Instructions, Env)]; -%%-------------------------------------------------------------------- %% New test instruction added in July 2007 for R12. %%-------------------------------------------------------------------- %%--- is_bitstr --- diff --git a/lib/hipe/icode/hipe_icode_callgraph.erl b/lib/hipe/icode/hipe_icode_callgraph.erl index 95182fc002..ae4b5785c4 100644 --- a/lib/hipe/icode/hipe_icode_callgraph.erl +++ b/lib/hipe/icode/hipe_icode_callgraph.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,8 +25,6 @@ %% in hipe_icode_type.erl. %% %% Created : 7 Jun 2004 by Tobias Lindahl <[email protected]> -%% -%% $Id$ %%----------------------------------------------------------------------- -module(hipe_icode_callgraph). @@ -48,7 +46,7 @@ -type mfa_icode() :: {mfa(), #icode{}}. --record(icode_callgraph, {codedict :: dict(), ordered_sccs :: [[atom()]]}). +-record(icode_callgraph, {codedict :: dict(), ordered_sccs :: [[mfa()]]}). %%------------------------------------------------------------------------ %% Exported functions @@ -78,7 +76,7 @@ construct_callgraph(List) -> to_list(#icode_callgraph{codedict = Dict, ordered_sccs = SCCs}) -> FlatList = lists:flatten(SCCs), - [{Mod, dict:fetch(Mod, Dict)} || Mod <- FlatList]. + [{MFA, dict:fetch(MFA, Dict)} || MFA <- FlatList]. %%------------------------------------------------------------------------ diff --git a/lib/hipe/icode/hipe_icode_exceptions.erl b/lib/hipe/icode/hipe_icode_exceptions.erl index 787fb05415..00caffb24b 100644 --- a/lib/hipe/icode/hipe_icode_exceptions.erl +++ b/lib/hipe/icode/hipe_icode_exceptions.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -344,6 +344,16 @@ pop_catch(Cs) -> pop_catch_1([[_|C] | Cs]) -> [C | pop_catch_1(Cs)]; +pop_catch_1([[] | Cs]) -> + %% The elements in the list represent different possible incoming + %% stacks of catch handlers to this BB. Before the fixpoint has + %% been found these elements are underapproximations of the true + %% stacks, therefore it's possible for these elements to be too + %% short for the number of pops implied by the code in the BB. + %% We must not fail in that case, so we set pop([]) = []. + %% This fixes find_catches_crash.erl and compiler_tests in the + %% HiPE test suite. + [[] | pop_catch_1(Cs)]; pop_catch_1([]) -> []. diff --git a/lib/hipe/icode/hipe_icode_primops.erl b/lib/hipe/icode/hipe_icode_primops.erl index b0fe7eb708..a413531c07 100644 --- a/lib/hipe/icode/hipe_icode_primops.erl +++ b/lib/hipe/icode/hipe_icode_primops.erl @@ -2,19 +2,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. -%% +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -26,9 +26,6 @@ %% Notes : %% History : * 2001-06-13 Erik Johansson ([email protected]): %% Created. -%% -%% $Id$ -%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -module(hipe_icode_primops). @@ -197,7 +194,7 @@ 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}, _}}) -> false; +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; diff --git a/lib/hipe/icode/hipe_icode_range.erl b/lib/hipe/icode/hipe_icode_range.erl index bcc857acf4..c222e8a5d5 100644 --- a/lib/hipe/icode/hipe_icode_range.erl +++ b/lib/hipe/icode/hipe_icode_range.erl @@ -1,20 +1,20 @@ %% -*- erlang-indent-level: 2 -*- %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %%%------------------------------------------------------------------- @@ -59,15 +59,17 @@ -record(range, {range :: range_rep(), other :: boolean()}). +-type range() :: #range{}. --record(ann, {range :: #range{}, +-record(ann, {range :: range(), type :: erl_types:erl_type(), count :: integer()}). +-type ann() :: #ann{}. --type range_anno() :: {range_anno, #ann{}, fun((#ann{}) -> string())}. --type args_fun() :: fun((mfa(),cfg()) -> [#range{}]). --type call_fun() :: fun((mfa(),[#range{}]) -> #range{}). --type final_fun() :: fun((mfa(),[#range{}]) -> ok). +-type range_anno() :: {'range_anno', ann(), fun((ann()) -> string())}. +-type args_fun() :: fun((mfa(), cfg()) -> [range()]). +-type call_fun() :: fun((mfa(), [range()]) -> range()). +-type final_fun() :: fun((mfa(), [range()]) -> 'ok'). -type data() :: {mfa(), args_fun(), call_fun(), final_fun()}. -type label() :: non_neg_integer(). -type info() :: gb_tree(). @@ -75,15 +77,15 @@ -type variable() :: #icode_variable{}. -type annotated_variable() :: #icode_variable{}. -type argument() :: #icode_const{} | variable(). --type three_range_fun() :: fun((#range{},#range{},#range{}) -> #range{}). +-type three_range_fun() :: fun((range(),range(),range()) -> range()). -type instr_split_info() :: {icode_instr(), [{label(),info()}]}. --type last_instr_return() :: {instr_split_info(), #range{}}. +-type last_instr_return() :: {instr_split_info(), range()}. -record(state, {info_map = gb_trees:empty() :: info(), counter = dict:new() :: dict(), cfg :: cfg(), liveness = gb_trees:empty() :: gb_tree(), - ret_type :: #range{}, + ret_type :: range(), lookup_fun :: call_fun(), result_action :: final_fun()}). @@ -108,8 +110,8 @@ cfg(Cfg, MFA, Options, Servers) -> -spec concurrent_cfg(cfg(), mfa(), pid()) -> cfg(). concurrent_cfg(Cfg, MFA, CompServer) -> - CompServer ! {ready, {MFA,self()}}, - {ArgsFun,CallFun,FinalFun} = do_analysis(Cfg, MFA), + CompServer ! {ready, {MFA, self()}}, + {ArgsFun, CallFun, FinalFun} = do_analysis(Cfg, MFA), Ans = do_rewrite(Cfg, MFA, ArgsFun, CallFun, FinalFun), CompServer ! {done_rewrite, MFA}, Ans. @@ -227,7 +229,7 @@ analyse_block(Label, Info, State, Rewrite) -> state__update_info(State2, InfoList, Rewrite). -spec analyse_BB([icode_instr()], info(), [icode_instr()], boolean(), call_fun()) -> - {[icode_instr()], [{label(),info()}], #range{}}. + {[icode_instr()], [{label(),info()}], range()}. analyse_BB([Last], Info, Code, Rewrite, LookupFun) -> {{NewI, LabelInfoList}, RetType} = @@ -266,9 +268,9 @@ handle_args(I, Info, WidenFun) -> %% io:format("Uses: ~p~nRanges: ~p~n", [Uses, PresentRanges]), JoinFun = fun(Var, Range) -> update_info(Var, Range, WidenFun) end, NewUses = lists:zipwith(JoinFun, Uses, PresentRanges), - hipe_icode:subst_uses(lists:zip(Uses, NewUses),I). + hipe_icode:subst_uses(lists:zip(Uses, NewUses), I). --spec join_info(#ann{}, #range{}, three_range_fun()) -> #ann{}. +-spec join_info(ann(), range(), three_range_fun()) -> ann(). join_info(Ann = #ann{range = R1, type = Type, count = ?WIDEN}, R2, Fun) -> Ann#ann{range = Fun(R1, R2, range_from_simple_type(Type))}; @@ -278,17 +280,17 @@ join_info(Ann = #ann{range = R1, type = Type, count = C}, R2, _Fun) when C < ?WI NewR -> Ann#ann{range = NewR, count = C+1} end. --spec join_three(#range{}, #range{}, #range{}) -> #range{}. +-spec join_three(range(), range(), range()) -> range(). join_three(R1, R2, R3) -> inf(sup(R1, R2), R3). --spec update_info(variable(), #range{}) -> annotated_variable(). +-spec update_info(variable(), range()) -> annotated_variable(). update_info(Var, Range) -> update_info(Var, Range, fun update_three/3). --spec update_info(variable(), #range{}, three_range_fun()) -> annotated_variable(). +-spec update_info(variable(), range(), three_range_fun()) -> annotated_variable(). update_info(Arg, R, Fun) -> case hipe_icode:is_annotated_variable(Arg) of @@ -299,7 +301,7 @@ update_info(Arg, R, Fun) -> Arg end. --spec update_info1(any(), #range{}, three_range_fun()) -> range_anno(). +-spec update_info1(any(), range(), three_range_fun()) -> range_anno(). update_info1({range_anno, Ann, _}, R2, Fun) -> make_range_anno(update_ann(Ann,R2,Fun)); @@ -314,71 +316,71 @@ update_ann(Ann = #ann{range = R1, type = Type, count = C}, R2, _Fun) -> NewR -> Ann#ann{range = NewR, count = C+1} end. --spec type_to_ann(erl_types:erl_type()) -> #ann{}. +-spec type_to_ann(erl_types:erl_type()) -> ann(). type_to_ann(Type) -> - #ann{range = range_from_simple_type(Type), type = t_limit(Type,1), count=1}. + #ann{range = range_from_simple_type(Type), type = t_limit(Type,1), count = 1}. --spec make_range_anno(#ann{}) -> range_anno(). +-spec make_range_anno(ann()) -> range_anno(). make_range_anno(Ann) -> {range_anno, Ann, fun pp_ann/1}. --spec update_three(#range{}, #range{}, #range{}) -> #range{}. +-spec update_three(range(), range(), range()) -> range(). update_three(_R1, R2, R3) -> inf(R2, R3). --spec safe_widen(#range{}, #range{}, #range{}) -> #range{}. +-spec safe_widen(range(), range(), range()) -> range(). safe_widen(#range{range=Old}, #range{range=New}, T = #range{range=Wide}) -> ResRange = - case {Old,New,Wide} of - {{Min,Max1},{Min,Max2},{_,Max}} -> - case inf_geq(OMax = next_up_limit(inf_max([Max1,Max2])),Max) of + case {Old, New, Wide} of + {{Min,Max1}, {Min,Max2}, {_,Max}} -> + case inf_geq(OMax = next_up_limit(inf_max([Max1, Max2])), Max) of true -> {Min,Max}; false -> {Min,OMax} end; - {{Min1,Max},{Min2,Max},{Min,_}} -> - case inf_geq(Min, OMin = next_down_limit(inf_min([Min1,Min2]))) of + {{Min1,Max}, {Min2,Max}, {Min,_}} -> + case inf_geq(Min, OMin = next_down_limit(inf_min([Min1, Min2]))) of true -> {Min,Max}; false -> {OMin,Max} end; - {{Min1,Max1},{Min2,Max2},{Min,Max}} -> + {{Min1,Max1}, {Min2,Max2}, {Min,Max}} -> RealMax = - case inf_geq(OMax = next_up_limit(inf_max([Max1,Max2])),Max) of + case inf_geq(OMax = next_up_limit(inf_max([Max1, Max2])), Max) of true -> Max; false -> OMax end, RealMin = - case inf_geq(Min, OMin = next_down_limit(inf_min([Min1,Min2]))) of + case inf_geq(Min, OMin = next_down_limit(inf_min([Min1, Min2]))) of true -> Min; false -> OMin end, - {RealMin,RealMax}; + {RealMin, RealMax}; _ -> Wide end, - T#range{range=ResRange}. + T#range{range = ResRange}. --spec widen(#range{}, #range{}, #range{}) -> #range{}. +-spec widen(range(), range(), range()) -> range(). widen(#range{range=Old}, #range{range=New}, T = #range{range=Wide}) -> ResRange = - case {Old,New,Wide} of - {{Min,_},{Min,Max2},{_,Max}} -> - case inf_geq(OMax = next_up_limit(Max2),Max) of + case {Old, New, Wide} of + {{Min,_}, {Min,Max2}, {_,Max}} -> + case inf_geq(OMax = next_up_limit(Max2), Max) of true -> {Min,Max}; false -> {Min,OMax} end; - {{_,Max},{Min2,Max},{Min,_}} -> + {{_,Max}, {Min2,Max}, {Min,_}} -> case inf_geq(Min, OMin = next_down_limit(Min2)) of true -> {Min,Max}; false -> {OMin,Max} end; - {_,{Min2,Max2},{Min,Max}} -> + {_, {Min2,Max2}, {Min,Max}} -> RealMax = - case inf_geq(OMax = next_up_limit(Max2),Max) of + case inf_geq(OMax = next_up_limit(Max2), Max) of true -> Max; false -> OMax end, @@ -387,11 +389,11 @@ widen(#range{range=Old}, #range{range=New}, T = #range{range=Wide}) -> true -> Min; false -> OMin end, - {RealMin,RealMax}; + {RealMin, RealMax}; _ -> Wide end, - T#range{range=ResRange}. + T#range{range = ResRange}. -spec analyse_call(#icode_call{}, call_fun()) -> #icode_call{}. @@ -421,7 +423,7 @@ analyse_move(Move) -> analyse_begin_handler(Handler) -> SubstList = - [{Dst,update_info(Dst,any_type())} || + [{Dst, update_info(Dst, any_type())} || Dst <- hipe_icode:begin_handler_dstlist(Handler)], hipe_icode:subst_defines(SubstList, Handler). @@ -494,14 +496,14 @@ analyse_switch_val(Switch, Info, Rewrite) -> end end. --spec update_infos(argument(), info(), [{#range{},label()}]) -> [{label(),info()}]. +-spec update_infos(argument(), info(), [{range(),label()}]) -> [{label(),info()}]. update_infos(Arg, Info, [{Range, Label}|Rest]) -> - [{Label,enter_define({Arg,Range},Info)} | update_infos(Arg,Info,Rest)]; + [{Label,enter_define({Arg,Range},Info)} | update_infos(Arg, Info, Rest)]; update_infos(_, _, []) -> []. --spec get_range_label_list([{argument(),label()}], #range{}, [{#range{},label()}]) -> - {#range{},[{#range{},label()}]}. +-spec get_range_label_list([{argument(),label()}], range(), [{range(),label()}]) -> + {range(),[{range(),label()}]}. get_range_label_list([{Val,Label}|Cases], SRange, Acc) -> VRange = get_range_from_arg(Val), @@ -516,7 +518,7 @@ get_range_label_list([], SRange, Acc) -> {PointTypes, _} = lists:unzip(Acc), {remove_point_types(SRange, PointTypes), Acc}. --spec update_switch(#icode_switch_val{}, [{#range{},label()}], boolean()) -> +-spec update_switch(#icode_switch_val{}, [{range(),label()}], boolean()) -> #icode_switch_val{}. update_switch(Switch, LabelRangeList, KeepFail) -> @@ -524,14 +526,14 @@ update_switch(Switch, LabelRangeList, KeepFail) -> case label_range_list_to_cases(LabelRangeList, []) of no_update -> Switch; - Cases -> + Cases -> hipe_icode:switch_val_cases_update(Switch, Cases) end, if KeepFail -> S2; true -> S2 end. --spec label_range_list_to_cases([{#range{},label()}], [{#icode_const{},label()}]) -> +-spec label_range_list_to_cases([{range(),label()}], [{#icode_const{},label()}]) -> 'no_update' | [{#icode_const{},label()}]. label_range_list_to_cases([{#range{range={C,C},other=false},Label}|Rest], @@ -586,9 +588,9 @@ analyse_last_call(Call, Info, LookupFun) -> NewInfo = enter_vals(NewI, Info), case hipe_icode:call_fail_label(Call) of [] -> - {NewI, [{Continuation,NewInfo}]}; + {NewI, [{Continuation, NewInfo}]}; Fail -> - {NewI, [{Continuation,NewInfo}, {Fail,Info}]} + {NewI, [{Continuation, NewInfo}, {Fail, Info}]} end. -spec analyse_if(#icode_if{}, info(), boolean()) -> @@ -596,16 +598,16 @@ analyse_last_call(Call, Info, LookupFun) -> analyse_if(If, Info, Rewrite) -> case hipe_icode:if_args(If) of - Args = [_,_] -> + [_, _] = Args -> analyse_sane_if(If, Info, Args, get_range_from_args(Args), Rewrite); _ -> TrueLabel = hipe_icode:if_true_label(If), FalseLabel = hipe_icode:if_false_label(If), - {If, [{TrueLabel,Info},{FalseLabel,Info}]} + {If, [{TrueLabel, Info}, {FalseLabel, Info}]} end. -spec analyse_sane_if(#icode_if{}, info(), [argument(),...], - [#range{},...], boolean()) -> + [range(),...], boolean()) -> {#icode_goto{} | #icode_if{}, [{label(), info()}]}. analyse_sane_if(If, Info, [Arg1, Arg2], [Range1, Range2], Rewrite) -> @@ -613,59 +615,61 @@ analyse_sane_if(If, Info, [Arg1, Arg2], [Range1, Range2], Rewrite) -> '>' -> {TrueRange2, TrueRange1, FalseRange2, FalseRange1} = range_inequality_propagation(Range2, Range1); - '==' -> - {TempTrueRange1, TempTrueRange2, FalseRange1, FalseRange2}= - range_equality_propagation(Range1, Range2), - TrueRange1 = set_other(TempTrueRange1,other(Range1)), - TrueRange2 = set_other(TempTrueRange2,other(Range2)); '<' -> - {TrueRange1, TrueRange2, FalseRange1, FalseRange2} = + {TrueRange1, TrueRange2, FalseRange1, FalseRange2} = range_inequality_propagation(Range1, Range2); '>=' -> {FalseRange1, FalseRange2, TrueRange1, TrueRange2} = range_inequality_propagation(Range1, Range2); '=<' -> - {FalseRange2, FalseRange1, TrueRange2, TrueRange1} = + {FalseRange2, FalseRange1, TrueRange2, TrueRange1} = range_inequality_propagation(Range2, Range1); '=:=' -> - {TrueRange1, TrueRange2, FalseRange1, FalseRange2}= + {TrueRange1, TrueRange2, FalseRange1, FalseRange2} = range_equality_propagation(Range1, Range2); '=/=' -> {FalseRange1, FalseRange2, TrueRange1, TrueRange2} = range_equality_propagation(Range1, Range2); + '==' -> + {TempTrueRange1, TempTrueRange2, FalseRange1, FalseRange2} = + range_equality_propagation(Range1, Range2), + TrueRange1 = set_other(TempTrueRange1, other(Range1)), + TrueRange2 = set_other(TempTrueRange2, other(Range2)); '/=' -> - {TempFalseRange1, TempFalseRange2, TrueRange1, TrueRange2}= + {TempFalseRange1, TempFalseRange2, TrueRange1, TrueRange2} = range_equality_propagation(Range1, Range2), - FalseRange1 = set_other(TempFalseRange1,other(Range1)), - FalseRange2 = set_other(TempFalseRange2,other(Range2)) + FalseRange1 = set_other(TempFalseRange1, other(Range1)), + FalseRange2 = set_other(TempFalseRange2, other(Range2)) end, - TrueLabel = hipe_icode:if_true_label(If), - FalseLabel = hipe_icode:if_false_label(If), - TrueInfo = - enter_defines([{Arg1,TrueRange1}, {Arg2,TrueRange2}],Info), - FalseInfo = - enter_defines([{Arg1,FalseRange1}, {Arg2,FalseRange2}],Info), - True = - case lists:any(fun range__is_none/1,[TrueRange1,TrueRange2]) of + %% io:format("TR1 = ~w\nTR2 = ~w\n", [TrueRange1, TrueRange2]), + True = + case lists:all(fun range__is_none/1, [TrueRange1, TrueRange2]) of true -> []; - false -> [{TrueLabel,TrueInfo}] + false -> + TrueLabel = hipe_icode:if_true_label(If), + TrueArgRanges = [{Arg1, TrueRange1}, {Arg2, TrueRange2}], + TrueInfo = enter_defines(TrueArgRanges, Info), + [{TrueLabel, TrueInfo}] end, - False = - case lists:any(fun range__is_none/1, [FalseRange1,FalseRange2]) of + %% io:format("FR1 = ~w\nFR2 = ~w\n", [FalseRange1, FalseRange2]), + False = + case lists:all(fun range__is_none/1, [FalseRange1, FalseRange2]) of true -> []; - false -> [{FalseLabel,FalseInfo}] + false -> + FalseLabel = hipe_icode:if_false_label(If), + FalseArgRanges = [{Arg1, FalseRange1}, {Arg2, FalseRange2}], + FalseInfo = enter_defines(FalseArgRanges, Info), + [{FalseLabel, FalseInfo}] end, - UpdateInfo = True++False, + UpdateInfo = True ++ False, NewIF = if Rewrite -> - %%io:format("~w~n~w~n", [{Arg1,FalseRange1},{Arg2,FalseRange2}]), - %%io:format("Any none: ~w~n", [lists:any(fun range__is_none/1,[FalseRange1,FalseRange2])]), case UpdateInfo of - [] -> %%This is weird + [] -> %% This is weird If; - [{Label,_Info}] -> + [{Label, _Info}] -> hipe_icode:mk_goto(Label); - [_,_] -> + [_, _] -> If end; true -> @@ -686,13 +690,13 @@ normalize_name(Name) -> Name -> Name end. --spec range_equality_propagation(#range{}, #range{}) -> - {#range{}, #range{}, #range{}, #range{}}. +-spec range_equality_propagation(range(), range()) -> + {range(), range(), range(), range()}. range_equality_propagation(Range_1, Range_2) -> True_range = inf(Range_1, Range_2), case {range(Range_1), range(Range_2)} of - {{N,N},{ N,N}} -> + {{N,N}, {N,N}} -> False_range_1 = none_range(), False_range_2 = none_range(); {{N1,N1}, {N2,N2}} -> @@ -710,8 +714,8 @@ range_equality_propagation(Range_1, Range_2) -> end, {True_range, True_range, False_range_1, False_range_2}. --spec range_inequality_propagation(#range{}, #range{}) -> - {#range{}, #range{}, #range{}, #range{}}. +-spec range_inequality_propagation(range(), range()) -> + {range(), range(), range(), range()}. %% Range1 < Range2 range_inequality_propagation(Range1, Range2) -> @@ -781,26 +785,24 @@ analyse_type(Type, Info, Rewrite) -> TrueRange = inf(any_range(), OldVarRange), FalseRange = inf(none_range(), OldVarRange); _ -> - TrueRange = inf(none_range(),OldVarRange), + TrueRange = inf(none_range(), OldVarRange), FalseRange = OldVarRange end, TrueLabel = hipe_icode:type_true_label(Type), FalseLabel = hipe_icode:type_false_label(Type), - TrueInfo = - enter_define({Arg,TrueRange},Info), - FalseInfo = - enter_define({Arg,FalseRange},Info), - True = + TrueInfo = enter_define({Arg, TrueRange}, Info), + FalseInfo = enter_define({Arg, FalseRange}, Info), + True = case range__is_none(TrueRange) of true -> []; - false -> [{TrueLabel,TrueInfo}] + false -> [{TrueLabel, TrueInfo}] end, - False = + False = case range__is_none(FalseRange) of true -> []; - false -> [{FalseLabel,FalseInfo}] + false -> [{FalseLabel, FalseInfo}] end, - UpdateInfo = True++False, + UpdateInfo = True ++ False, NewType = if Rewrite -> case UpdateInfo of @@ -808,15 +810,15 @@ analyse_type(Type, Info, Rewrite) -> Type; [{Label,_Info}] -> hipe_icode:mk_goto(Label); - [_,_] -> + [_, _] -> Type end; true -> Type end, - {NewType,True ++ False}. + {NewType, True ++ False}. --spec compare_with_integer(integer(), #range{}) -> {#range{}, #range{}}. +-spec compare_with_integer(integer(), range()) -> {range(), range()}. compare_with_integer(N, OldVarRange) -> TestRange = range_init({N, N}, false), @@ -843,13 +845,13 @@ compare_with_integer(N, OldVarRange) -> %%== Ranges ================================================================== --spec pp_ann(#ann{} | erl_types:erl_type()) -> [string()]. +-spec pp_ann(ann() | erl_types:erl_type()) -> string(). -pp_ann(#ann{range=#range{range=R, other=false}}) -> +pp_ann(#ann{range = #range{range = R, other = false}}) -> pp_range(R); -pp_ann(#ann{range=#range{range=empty, other=true}, type=Type}) -> +pp_ann(#ann{range = #range{range = empty, other = true}, type = Type}) -> t_to_string(Type); -pp_ann(#ann{range=#range{range=R, other=true}, type=Type}) -> +pp_ann(#ann{range = #range{range = R, other = true}, type = Type}) -> pp_range(R) ++ " | " ++ t_to_string(Type); pp_ann(Type) -> t_to_string(Type). @@ -867,12 +869,12 @@ val_to_string(pos_inf) -> "inf"; val_to_string(neg_inf) -> "-inf"; val_to_string(X) when is_integer(X) -> integer_to_list(X). --spec range_from_type(erl_types:erl_type()) -> [#range{}]. +-spec range_from_type(erl_types:erl_type()) -> [range()]. range_from_type(Type) -> [range_from_simple_type(T) || T <- t_to_tlist(Type)]. --spec range_from_simple_type(erl_types:erl_type()) -> #range{}. +-spec range_from_simple_type(erl_types:erl_type()) -> range(). range_from_simple_type(Type) -> None = t_none(), @@ -887,7 +889,7 @@ range_from_simple_type(Type) -> #range{range = Range, other = true} end. --spec range_init(range_rep(), boolean()) -> #range{}. +-spec range_init(range_rep(), boolean()) -> range(). range_init({Min, Max} = Range, Other) -> case inf_geq(Max, Min) of @@ -899,39 +901,39 @@ range_init({Min, Max} = Range, Other) -> range_init(empty, Other) -> #range{range = empty, other = Other}. --spec range(#range{}) -> range_rep(). +-spec range(range()) -> range_rep(). range(#range{range = R}) -> R. --spec other(#range{}) -> boolean(). +-spec other(range()) -> boolean(). other(#range{other = O}) -> O. --spec set_other(#range{}, boolean()) -> #range{}. +-spec set_other(range(), boolean()) -> range(). set_other(R, O) -> R#range{other = O}. --spec range__min(#range{}) -> 'empty' | 'neg_inf' | integer(). +-spec range__min(range()) -> 'empty' | 'neg_inf' | integer(). -range__min(#range{range=empty}) -> empty; -range__min(#range{range={Min,_}}) -> Min. +range__min(#range{range = empty}) -> empty; +range__min(#range{range = {Min,_}}) -> Min. --spec range__max(#range{}) -> 'empty' | 'pos_inf' | integer(). +-spec range__max(range()) -> 'empty' | 'pos_inf' | integer(). -range__max(#range{range=empty}) -> empty; -range__max(#range{range={_,Max}}) -> Max. +range__max(#range{range = empty}) -> empty; +range__max(#range{range = {_,Max}}) -> Max. --spec range__is_none(#range{}) -> boolean(). +-spec range__is_none(range()) -> boolean(). -range__is_none(#range{range=empty, other=false}) -> true; +range__is_none(#range{range = empty, other = false}) -> true; range__is_none(#range{}) -> false. --spec range__is_empty(#range{}) -> boolean(). +-spec range__is_empty(range()) -> boolean(). -range__is_empty(#range{range=empty}) -> true; -range__is_empty(#range{range={_,_}}) -> false. +range__is_empty(#range{range = empty}) -> true; +range__is_empty(#range{range = {_,_}}) -> false. --spec remove_point_types(#range{}, [#range{}]) -> #range{}. +-spec remove_point_types(range(), [range()]) -> range(). remove_point_types(Range, Ranges) -> Sorted = lists:sort(Ranges), @@ -939,35 +941,35 @@ remove_point_types(Range, Ranges) -> Range1 = lists:foldl(FoldFun, Range, Sorted), lists:foldl(FoldFun, Range1, lists:reverse(Sorted)). --spec range__remove_constant(#range{}, #range{}) -> #range{}. +-spec range__remove_constant(range(), range()) -> range(). -range__remove_constant(R = #range{range={C,C}}, #range{range={C,C}}) -> - R#range{range=empty}; -range__remove_constant(R = #range{range={C,H}}, #range{range={C,C}}) -> - R#range{range={C+1,H}}; -range__remove_constant(R = #range{range={L,C}}, #range{range={C,C}}) -> - R#range{range={L,C-1}}; -range__remove_constant(R = #range{}, #range{range={C,C}}) -> +range__remove_constant(#range{range = {C, C}} = R, #range{range = {C, C}}) -> + R#range{range = empty}; +range__remove_constant(#range{range = {C, H}} = R, #range{range = {C, C}}) -> + R#range{range = {C+1, H}}; +range__remove_constant(#range{range = {L, C}} = R, #range{range = {C, C}}) -> + R#range{range = {L, C-1}}; +range__remove_constant(#range{} = R, #range{range = {C,C}}) -> R; -range__remove_constant(R = #range{}, _) -> +range__remove_constant(#range{} = R, _) -> R. --spec any_type() -> #range{}. +-spec any_type() -> range(). any_type() -> - #range{range=any_r(), other=true}. + #range{range = any_r(), other = true}. --spec any_range() -> #range{}. +-spec any_range() -> range(). any_range() -> - #range{range=any_r(), other=false}. + #range{range = any_r(), other = false}. --spec none_range() -> #range{}. +-spec none_range() -> range(). none_range() -> - #range{range=empty, other=true}. + #range{range = empty, other = true}. --spec none_type() -> #range{}. +-spec none_type() -> range(). none_type() -> #range{range = empty, other = false}. @@ -976,12 +978,12 @@ none_type() -> any_r() -> {neg_inf, pos_inf}. --spec get_range_from_args([argument()]) -> [#range{}]. +-spec get_range_from_args([argument()]) -> [range()]. get_range_from_args(Args) -> [get_range_from_arg(Arg) || Arg <- Args]. --spec get_range_from_arg(argument()) -> #range{}. +-spec get_range_from_arg(argument()) -> range(). get_range_from_arg(Arg) -> case hipe_icode:is_const(Arg) of @@ -989,15 +991,15 @@ get_range_from_arg(Arg) -> Value = hipe_icode:const_value(Arg), case is_integer(Value) of true -> - #range{range={Value,Value}, other=false}; + #range{range = {Value, Value}, other = false}; false -> - #range{range=empty, other=true} + #range{range = empty, other = true} end; false -> case hipe_icode:is_annotated_variable(Arg) of true -> case hipe_icode:variable_annotation(Arg) of - {range_anno, #ann{range=Range}, _} -> + {range_anno, #ann{range = Range}, _} -> Range; {type_anno, Type, _} -> range_from_simple_type(Type) @@ -1012,7 +1014,7 @@ get_range_from_arg(Arg) -> %% inf([R1,R2|Rest]) -> %% inf([inf(R1,R2)|Rest]). --spec inf(#range{}, #range{}) -> #range{}. +-spec inf(range(), range()) -> range(). inf(#range{range=R1, other=O1}, #range{range=R2, other=O2}) -> #range{range=range_inf(R1,R2), other=other_inf(O1,O2)}. @@ -1022,8 +1024,8 @@ inf(#range{range=R1, other=O1}, #range{range=R2, other=O2}) -> range_inf(empty, _) -> empty; range_inf(_, empty) -> empty; range_inf({Min1,Max1}, {Min2,Max2}) -> - NewMin = inf_max([Min1,Min2]), - NewMax = inf_min([Max1,Max2]), + NewMin = inf_max([Min1, Min2]), + NewMax = inf_min([Max1, Max2]), case inf_geq(NewMax, NewMin) of true -> {NewMin, NewMax}; @@ -1035,14 +1037,14 @@ range_inf({Min1,Max1}, {Min2,Max2}) -> other_inf(O1, O2) -> O1 and O2. --spec sup([#range{},...]) -> #range{}. +-spec sup([range(),...]) -> range(). sup([R]) -> R; sup([R1,R2|Rest]) -> sup([sup(R1, R2)|Rest]). --spec sup(#range{}, #range{}) -> #range{}. +-spec sup(range(), range()) -> range(). sup(#range{range=R1,other=O1}, #range{range=R2,other=O2}) -> #range{range=range_sup(R1,R2), other=other_sup(O1,O2)}. @@ -1063,7 +1065,7 @@ other_sup(O1, O2) -> O1 or O2. %%== Call Support ============================================================= -spec analyse_call_or_enter_fun(fun_name(), [argument()], - icode_call_type(), call_fun()) -> [#range{}]. + icode_call_type(), call_fun()) -> [range()]. analyse_call_or_enter_fun(Fun, Args, CallType, LookupFun) -> %%io:format("Fun: ~p~n Args: ~p~n CT: ~p~n LF: ~p~n", [Fun, Args, CallType, LookupFun]), @@ -1105,19 +1107,19 @@ analyse_call_or_enter_fun(Fun, Args, CallType, LookupFun) -> [any_type()]; {hipe_bs_primop, {bs_get_integer, Size, Flags}} -> {Min, Max} = analyse_bs_get_integer(Size, Flags, length(Args) =:= 1), - [#range{range={Min, Max}, other=false}, any_type()]; + [#range{range = {Min, Max}, other = false}, any_type()]; {hipe_bs_primop, _} = Primop -> Type = hipe_icode_primops:type(Primop), range_from_type(Type) end. --type bin_operation() :: fun((#range{},#range{}) -> #range{}). --type unary_operation() :: fun((#range{}) -> #range{}). +-type bin_operation() :: fun((range(), range()) -> range()). +-type unary_operation() :: fun((range()) -> range()). -spec basic_type(fun_name()) -> 'not_int' | 'not_analysed' - | {bin, bin_operation()} - | {unary, unary_operation()} - | {fcall, mfa()} | {hipe_bs_primop, _}. + | {'bin', bin_operation()} + | {'unary', unary_operation()} + | {'fcall', mfa()} | {'hipe_bs_primop', _}. %% Arithmetic operations basic_type('+') -> {bin, fun(R1, R2) -> range_add(R1, R2) end}; @@ -1214,7 +1216,7 @@ analyse_bs_get_integer(Size, Flags, false) when is_integer(Size), %% Arithmetic --spec range_add(#range{}, #range{}) -> #range{}. +-spec range_add(range(), range()) -> range(). range_add(Range1, Range2) -> NewMin = inf_add(range__min(Range1), range__min(Range2)), @@ -1222,7 +1224,7 @@ range_add(Range1, Range2) -> Other = other(Range1) orelse other(Range2), range_init({NewMin, NewMax}, Other). --spec range_sub(#range{}, #range{}) -> #range{}. +-spec range_sub(range(), range()) -> range(). range_sub(Range1, Range2) -> Min_sub = inf_min([inf_inv(range__max(Range2)), @@ -1234,7 +1236,7 @@ range_sub(Range1, Range2) -> Other = other(Range1) orelse other(Range2), range_init({NewMin, NewMax}, Other). --spec range_mult(#range{}, #range{}) -> #range{}. +-spec range_mult(range(), range()) -> range(). range_mult(#range{range=empty, other=true}, _Range2) -> range_init(empty, true); @@ -1274,7 +1276,7 @@ range_mult(Range1, Range2) -> Other = other(Range1) orelse other(Range2), range_init(Range, Other). --spec extreme_divisors(#range{}) -> range_tuple(). +-spec extreme_divisors(range()) -> range_tuple(). extreme_divisors(#range{range={0,0}}) -> {0,0}; extreme_divisors(#range{range={0,Max}}) -> {1,Max}; @@ -1289,7 +1291,7 @@ extreme_divisors(#range{range={Min,Max}}) -> end end. --spec range_div(#range{}, #range{}) -> #range{}. +-spec range_div(range(), range()) -> range(). %% this is div, not /. range_div(_, #range{range={0,0}}) -> @@ -1306,7 +1308,7 @@ range_div(Range1, Den) -> inf_div(Max1, Min2), inf_div(Max1, Max2)], range_init({inf_min(Min_max_list), inf_max(Min_max_list)}, false). --spec range_rem(#range{}, #range{}) -> #range{}. +-spec range_rem(range(), range()) -> range(). range_rem(Range1, Range2) -> %% Range1 desides the sign of the answer. @@ -1332,7 +1334,7 @@ range_rem(Range1, Range2) -> %%--- Bit operations ---------------------------- --spec range_bsr(#range{}, #range{}) -> #range{}. +-spec range_bsr(range(), range()) -> range(). range_bsr(Range1, Range2=#range{range={Min, Max}}) -> New_Range2 = range_init({inf_inv(Max), inf_inv(Min)}, other(Range2)), @@ -1340,7 +1342,7 @@ range_bsr(Range1, Range2=#range{range={Min, Max}}) -> %% io:format("bsr res:~w~nInput:= ~w~n", [Ans, {Range1,Range2}]), Ans. --spec range_bsl(#range{}, #range{}) -> #range{}. +-spec range_bsl(range(), range()) -> range(). range_bsl(Range1, Range2) -> Min1 = range__min(Range1), @@ -1359,13 +1361,13 @@ range_bsl(Range1, Range2) -> end, range_init(MinMax, false). --spec range_bnot(#range{}) -> #range{}. +-spec range_bnot(range()) -> range(). range_bnot(Range) -> Minus_one = range_init({-1,-1}, false), range_add(range_mult(Range, Minus_one), Minus_one). --spec width(range_rep() | integer()) -> 'pos_inf' | non_neg_integer(). +-spec width(range_rep() | inf_integer()) -> 'pos_inf' | non_neg_integer(). width({Min, Max}) -> inf_max([width(Min), width(Max)]); width(pos_inf) -> pos_inf; @@ -1389,7 +1391,7 @@ negwidth(X, N) -> false -> negwidth(X, N+1) end. --spec range_band(#range{}, #range{}) -> #range{}. +-spec range_band(range(), range()) -> range(). range_band(R1, R2) -> {_Min1, Max1} = MM1 = range(R1), @@ -1423,7 +1425,7 @@ range_band(R1, R2) -> end, range_init(Range, false). --spec range_bor(#range{}, #range{}) -> #range{}. +-spec range_bor(range(), range()) -> range(). range_bor(R1, R2) -> {Min1, _Max1} = MM1 = range(R1), @@ -1457,7 +1459,7 @@ range_bor(R1, R2) -> end, range_init(Range, false). --spec classify_range(#range{}) -> 'minus_minus' | 'minus_plus' | 'plus_plus'. +-spec classify_range(range()) -> 'minus_minus' | 'minus_plus' | 'plus_plus'. classify_range(Range) -> case range(Range) of @@ -1480,7 +1482,7 @@ classify_int_range(_Number1, Number2) when Number2 < 0 -> classify_int_range(_Number1, _Number2) -> minus_plus. --spec range_bxor(#range{}, #range{}) -> #range{}. +-spec range_bxor(range(), range()) -> range(). range_bxor(R1, R2) -> {Min1, Max1} = MM1 = range(R1), @@ -1895,7 +1897,7 @@ convert_ann_to_types(#ann{range=#range{other=true}, type=Type}) -> %% Icode Coordinator Callbacks %%===================================================================== --spec replace_nones([#range{}]) -> [#range{}]. +-spec replace_nones([range()]) -> [range()]. replace_nones(Args) -> [replace_none(Arg) || Arg <- Args]. @@ -1905,7 +1907,7 @@ replace_none(Arg) -> false -> Arg end. --spec update__info([#range{}], [#range{}]) -> {boolean(), [#ann{}]}. +-spec update__info([range()], [range()]) -> {boolean(), [ann()]}. update__info(NewRanges, OldRanges) -> SupFun = fun (Ann, Range) -> join_info(Ann, Range, fun safe_widen/3) @@ -1915,19 +1917,19 @@ update__info(NewRanges, OldRanges) -> Change = lists:zipwith(EqFun, ResRanges, OldRanges), {lists:all(fun (X) -> X end, Change), ResRanges}. --spec new__info/1 :: ([#range{}]) -> [#ann{}]. +-spec new__info([range()]) -> [ann()]. new__info(NewRanges) -> [#ann{range=Range,count=1,type=t_any()} || Range <- NewRanges]. --spec return__info/1 :: ([#ann{}]) -> [#range{}]. +-spec return__info([ann()]) -> [range()]. return__info(Ranges) -> [Range || #ann{range=Range} <- Ranges]. --spec return_none/0 :: () -> [#range{},...]. +-spec return_none() -> [range(),...]. return_none() -> [none_type()]. --spec return_none_args/2 :: (#cfg{}, mfa()) -> [#range{}]. +-spec return_none_args(cfg(), mfa()) -> [range()]. return_none_args(Cfg, {_M,_F,A}) -> NoArgs = case hipe_icode_cfg:is_closure(Cfg) of @@ -1936,7 +1938,7 @@ return_none_args(Cfg, {_M,_F,A}) -> end, lists:duplicate(NoArgs, none_type()). --spec return_any_args/2 :: (#cfg{}, mfa()) -> [#range{}]. +-spec return_any_args(cfg(), mfa()) -> [range()]. return_any_args(Cfg, {_M,_F,A}) -> NoArgs = case hipe_icode_cfg:is_closure(Cfg) of diff --git a/lib/hipe/icode/hipe_icode_type.erl b/lib/hipe/icode/hipe_icode_type.erl index 28198467f7..3f9488d7c3 100644 --- a/lib/hipe/icode/hipe_icode_type.erl +++ b/lib/hipe/icode/hipe_icode_type.erl @@ -2,19 +2,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. -%% +%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %%%-------------------------------------------------------------------- @@ -23,8 +23,6 @@ %%% Description : Propagate type information. %%% %%% Created : 25 Feb 2003 by Tobias Lindahl <[email protected]> -%%% -%%% $Id$ %%%-------------------------------------------------------------------- -module(hipe_icode_type). @@ -78,7 +76,7 @@ %-define(server_debug, fun(X, Y) -> io:format("~p server: ~s ~p~n", [self(), X, Y]) end). -define(server_debug, fun(_, _) -> ok end). --import(erl_types, [min/2, max/2, number_min/1, number_max/1, +-import(erl_types, [number_min/1, number_max/1, t_any/0, t_atom/1, t_atom/0, t_atom_vals/1, t_binary/0, t_bitstr/0, t_bitstr_base/1, t_bitstr_unit/1, t_boolean/0, t_cons/0, t_constant/0, @@ -494,10 +492,10 @@ integer_range_less_then_propagator(IntArg1, IntArg2) -> Min2 = number_min(IntArg2), Max2 = number_max(IntArg2), %% is this the same as erl_types:t_subtract?? no ... ?? - TrueMax1 = min(Max1, erl_bif_types:infinity_add(Max2, -1)), - TrueMin2 = max(erl_bif_types:infinity_add(Min1, 1), Min2), - FalseMin1 = max(Min1, Min2), - FalseMax2 = min(Max1, Max2), + TrueMax1 = erl_types:min(Max1, erl_bif_types:infinity_add(Max2, -1)), + TrueMin2 = erl_types:max(erl_bif_types:infinity_add(Min1, 1), Min2), + FalseMin1 = erl_types:max(Min1, Min2), + FalseMax2 = erl_types:min(Max1, Max2), {t_from_range(Min1, TrueMax1), t_from_range(TrueMin2, Max2), t_from_range(FalseMin1, Max1), diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl index ed722fecba..570e4d9d17 100644 --- a/lib/hipe/main/hipe.erl +++ b/lib/hipe/main/hipe.erl @@ -1,20 +1,20 @@ %% -*- erlang-indent-level: 2 -*- %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% ==================================================================== @@ -25,7 +25,6 @@ %% Purpose : %% Notes : %% History : * 1998-01-28 Erik Johansson ([email protected]): Created. -%% CVS : $Id$ %% ==================================================================== %% @doc This is the direct interface to the HiPE compiler. %% @@ -274,7 +273,7 @@ load(Mod, BeamFileName) when is_list(BeamFileName) -> Architecture = erlang:system_info(hipe_architecture), ChunkName = hipe_unified_loader:chunk_name(Architecture), case beam_lib:chunks(BeamFileName, [ChunkName]) of - {ok,{_,[{_,Bin}]}} when is_binary(Bin) -> do_load(Mod, Bin, Bin); + {ok,{_,[{_,Bin}]}} when is_binary(Bin) -> do_load(Mod, Bin, BeamFileName); Error -> {error, Error} end. @@ -506,7 +505,7 @@ compile(Name, File, Opts0) -> run_compiler(Name, DisasmFun, IcodeFun, NewOpts) end. --spec compile_core(mod(), _, compile_file(), comp_options()) -> +-spec compile_core(mod(), cerl:c_module(), compile_file(), comp_options()) -> {'ok', compile_ret()} | {'error', term()}. compile_core(Name, Core0, File, Opts) -> @@ -535,7 +534,7 @@ compile_core(Name, Core0, File, Opts) -> %% %% @see compile/3 --spec compile(mod(), _, compile_file(), comp_options()) -> +-spec compile(mod(), cerl:c_module() | [], compile_file(), comp_options()) -> {'ok', compile_ret()} | {'error', term()}. compile(Name, [], File, Opts) -> @@ -790,7 +789,7 @@ finalize_fun(MfaIcodeList, Exports, Opts) -> FalseVal when (FalseVal =:= undefined) orelse (FalseVal =:= false) -> [finalize_fun_sequential(MFAIcode, Opts, #comp_servers{}) || {_MFA, _Icode} = MFAIcode <- MfaIcodeList]; - TrueVal when (TrueVal =:= true) or (TrueVal =:= debug) -> + TrueVal when (TrueVal =:= true) orelse (TrueVal =:= debug) -> finalize_fun_concurrent(MfaIcodeList, Exports, Opts) end. @@ -913,7 +912,7 @@ do_load(Mod, Bin, WholeModule) -> %% In this case, the emulated code for the module must be loaded. {module, Mod} = code:ensure_loaded(Mod), code:load_native_partial(Mod, Bin); - BinCode when is_binary(BinCode) -> + BeamBinOrPath when is_binary(BeamBinOrPath) orelse is_list(BeamBinOrPath) -> case code:is_sticky(Mod) of true -> %% We unpack and repack the Beam binary as a workaround to @@ -939,6 +938,8 @@ assemble(CompiledCode, Closures, Exports, Options) -> hipe_sparc_assemble:assemble(CompiledCode, Closures, Exports, Options); powerpc -> hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options); + ppc64 -> + hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options); arm -> hipe_arm_assemble:assemble(CompiledCode, Closures, Exports, Options); x86 -> @@ -1048,7 +1049,7 @@ post(Res, Icode, Options) -> %% -------------------------------------------------------------------- %% @doc Returns the current HiPE version as a string(). --spec version() -> string(). +-spec version() -> nonempty_string(). version() -> ?VERSION_STRING(). @@ -1390,6 +1391,8 @@ o1_opts() -> Common; powerpc -> Common; + ppc64 -> + Common; arm -> Common -- [inline_fp]; % Pointless optimising for absent hardware x86 -> @@ -1411,6 +1414,8 @@ o2_opts() -> Common; powerpc -> Common; + ppc64 -> + Common; arm -> Common; x86 -> @@ -1429,6 +1434,8 @@ o3_opts() -> Common; powerpc -> Common; + ppc64 -> + Common; arm -> Common; x86 -> diff --git a/lib/hipe/main/hipe_main.erl b/lib/hipe/main/hipe_main.erl index fe9bc83fd2..e81642fb33 100644 --- a/lib/hipe/main/hipe_main.erl +++ b/lib/hipe/main/hipe_main.erl @@ -1,20 +1,20 @@ %% -*- erlang-indent-level: 2 -*- %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% @doc This is the HiPE compiler's main "loop". @@ -102,7 +102,7 @@ compile_icode(MFA, LinearIcode0, Options, Servers, DebugState) -> ?opt_start_timer("Icode"), LinearIcode1 = icode_no_comment(LinearIcode0, Options), IcodeCfg0 = icode_linear_to_cfg(LinearIcode1, Options), - %%hipe_icode_cfg:pp(IcodeCfg1), + %% hipe_icode_cfg:pp(IcodeCfg0), IcodeCfg1 = icode_handle_exceptions(IcodeCfg0, MFA, Options), IcodeCfg3 = icode_inline_bifs(IcodeCfg1, Options), pp(IcodeCfg3, MFA, icode, pp_icode, Options, Servers), diff --git a/lib/hipe/regalloc/hipe_graph_coloring_regalloc.erl b/lib/hipe/regalloc/hipe_graph_coloring_regalloc.erl index ac555b933c..6ba4ac814e 100644 --- a/lib/hipe/regalloc/hipe_graph_coloring_regalloc.erl +++ b/lib/hipe/regalloc/hipe_graph_coloring_regalloc.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -389,23 +389,23 @@ decrement_each([N|Ns], OldLow, IG, Vis, K) -> %% {Spilled_node, Low_degree_neighbors, New_interference_graph} spill(IG, Vis, Spill, K, SpillLimit, Target) -> - Ns = list_ig(IG), - Costs = spill_costs(Ns, IG, Vis, Spill, SpillLimit, Target), - ?report3("spill costs are ~p~n",[Costs]), - ActualCosts = lists:sort(Costs), - ?report3("actual costs are ~p~n",[ActualCosts]), + Ns = list_ig(IG), + Costs = spill_costs(Ns, IG, Vis, Spill, SpillLimit, Target), + ?report3("spill costs are ~p~n", [Costs]), + ActualCosts = lists:sort(Costs), + ?report3("actual costs are ~p~n", [ActualCosts]), case ActualCosts of - [] -> - ?error_msg("There is no node to spill",[]), + [] -> + ?error_msg("There is no node to spill", []), ?EXIT('no node to spill'); [{_Cost,N}|_] -> {Low, NewIG} = decrement_neighbors(N, [], IG, Vis, K), - %?report("spilled node ~p at cost ~p (~p now ready)~n",[N,Cost,Low]), + %% ?report("spilled node ~p at cost ~p (~p now ready)~n", [N,Cost,Low]), {N, Low, NewIG} end. spill_costs([], _IG, _Vis, _Spill, _SpillLimit, _Target) -> - []; + []; spill_costs([{N,Info}|Ns], IG, Vis, Spill, SpillLimit, Target) -> case degree(Info) of 0 -> spill_costs(Ns,IG,Vis,Spill, SpillLimit, Target); @@ -451,28 +451,28 @@ select_colors([{X,colorable}|Xs], IG, Cols, PhysRegs, K) -> {Reg,NewCols} = select_color(X, IG, Cols, PhysRegs), ?report("~p~n",[Reg]), [{X,{reg,Reg}} | select_colors(Xs, IG, NewCols, PhysRegs, K)]; -%select_colors([{X,{spill,M}}|Xs], IG, Cols, PhysRegs, K) -> -% ?report('spilled: ~p~n',[X]), -% %% Check if optimistic coloring could have found a color -% case catch select_color(X,IG,Cols,K) of -% {'EXIT',_} -> % no color possible -% ?report('(no optimistic color)~n',[]), -% [{X,{spill,M}}|select_colors(Xs, IG, Cols, PhysRegs, K)]; -% {Reg,NewCols} -> -% ?report('(optimistic color: ~p)~n',[Reg]), -% [{X,{reg,Reg}}|select_colors(Xs, IG, Cols, PhysRegs, K)] -% end. +%%select_colors([{X,{spill,M}}|Xs], IG, Cols, PhysRegs, K) -> +%% ?report('spilled: ~p~n',[X]), +%% %% Check if optimistic coloring could have found a color +%% case catch select_color(X,IG,Cols,K) of +%% {'EXIT',_} -> % no color possible +%% ?report('(no optimistic color)~n',[]), +%% [{X,{spill,M}}|select_colors(Xs, IG, Cols, PhysRegs, K)]; +%% {Reg,NewCols} -> +%% ?report('(optimistic color: ~p)~n',[Reg]), +%% [{X,{reg,Reg}}|select_colors(Xs, IG, Cols, PhysRegs, K)] +%% end. %% Old code / pessimistic coloring: select_colors([{X,{spill,M}}|Xs], IG, Cols, PhysRegs, K) -> ?report("spilled: ~p~n",[X]), %% Check if optimistic coloring could have found a color -% case catch select_color(X,IG,Cols,K) of -% {'EXIT',_} -> % no color possible -% ?report('(no optimistic color)~n',[]); -% {Reg,NewCols} -> -% ?report('(optimistic color: ~p)~n',[Reg]) -% end, +%% case catch select_color(X,IG,Cols,K) of +%% {'EXIT',_} -> % no color possible +%% ?report('(no optimistic color)~n',[]); +%% {Reg,NewCols} -> +%% ?report('(optimistic color: ~p)~n',[Reg]) +%% end, [{X,{spill,M}} | select_colors(Xs, IG, Cols, PhysRegs, K)]. select_color(X, IG, Cols, PhysRegs) -> diff --git a/lib/hipe/rtl/hipe_rtl.erl b/lib/hipe/rtl/hipe_rtl.erl index ef06b2abf8..29e9c8c8fe 100644 --- a/lib/hipe/rtl/hipe_rtl.erl +++ b/lib/hipe/rtl/hipe_rtl.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -354,6 +354,8 @@ phi_arglist_update/2, phi_redirect_pred/3]). +-export_type([alub_cond/0]). + %% %% RTL %% @@ -590,6 +592,9 @@ branch_pred(#branch{p=P}) -> P. %% alub %% +-type alub_cond() :: 'eq' | 'ne' | 'ge' | 'geu' | 'gt' | 'gtu' | 'le' + | 'leu' | 'lt' | 'ltu' | 'overflow' | 'not_overflow'. + mk_alub(Dst, Src1, Op, Src2, Cond, True, False) -> mk_alub(Dst, Src1, Op, Src2, Cond, True, False, 0.5). mk_alub(Dst, Src1, Op, Src2, Cond, True, False, P) -> diff --git a/lib/hipe/rtl/hipe_rtl_arith.inc b/lib/hipe/rtl/hipe_rtl_arith.inc index 31fedd927e..e608506234 100644 --- a/lib/hipe/rtl/hipe_rtl_arith.inc +++ b/lib/hipe/rtl/hipe_rtl_arith.inc @@ -3,7 +3,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -119,7 +119,8 @@ eval_alu(Op, Arg1, Arg2) -> %% there are cases where we can evaluate a subset of the bits, but can %% not do a full eval-alub call (eg. a + 0 gives no carry) %% --spec eval_cond_bits(atom(), boolean(), boolean(), boolean(), boolean()) -> boolean(). +-spec eval_cond_bits(hipe_rtl:alub_cond(), boolean(), + boolean(), boolean(), boolean()) -> boolean(). eval_cond_bits(Cond, N, Z, V, C) -> case Cond of @@ -146,9 +147,7 @@ eval_cond_bits(Cond, N, Z, V, C) -> 'overflow' -> V; 'not_overflow' -> - not V; - _ -> - ?EXIT({'condition code not handled',Cond}) + not V end. eval_alub(Op, Cond, Arg1, Arg2) -> diff --git a/lib/hipe/rtl/hipe_rtl_primops.erl b/lib/hipe/rtl/hipe_rtl_primops.erl index 560e0259f8..5f273d8251 100644 --- a/lib/hipe/rtl/hipe_rtl_primops.erl +++ b/lib/hipe/rtl/hipe_rtl_primops.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -701,9 +701,9 @@ gen_cons(Dst, [Arg1, Arg2]) -> %% Increase refcount %% fe->refc++; %% -%% Link to the process off_heap.funs list -%% funp->next = p->off_heap.funs; -%% p->off_heap.funs = funp; +%% Link to the process off_heap list +%% funp->next = p->off_heap.first; +%% p->off_heap.first = funp; %% %% Tag the thing %% return make_fun(funp); @@ -729,9 +729,9 @@ gen_mkfun([Dst], {_Mod, _FunId, _Arity} = MFidA, MagicNr, Index, FreeVars) -> %% fe->refc++; SkeletonCode = gen_fun_thing_skeleton(HP, MFidA, NumFree, MagicNr, Index), - %% Link to the process off_heap.funs list - %% funp->next = p->off_heap.funs; - %% p->off_heap.funs = funp; + %% Link to the process off_heap list + %% funp->next = p->off_heap.first; + %% p->off_heap.first = funp; LinkCode = gen_link_closure(HP), %% Tag the thing and increase the heap_pointer. @@ -797,14 +797,14 @@ gen_link_closure(FUNP) -> end. gen_link_closure_private(FUNP) -> - %% Link to the process off_heap.funs list - %% funp->next = p->off_heap.funs; - %% p->off_heap.funs = funp; + %% Link fun to the process off_heap list + %% funp->next = p->off_heap.first; + %% p->off_heap.first = funp; FunsVar = hipe_rtl:mk_new_reg(), - [load_p_field(FunsVar,?P_OFF_HEAP_FUNS), + [load_p_field(FunsVar,?P_OFF_HEAP_FIRST), hipe_rtl:mk_store(FUNP, hipe_rtl:mk_imm(?EFT_NEXT), FunsVar), - store_p_field(FUNP,?P_OFF_HEAP_FUNS)]. + store_p_field(FUNP,?P_OFF_HEAP_FIRST)]. gen_link_closure_non_private(_FUNP) -> []. diff --git a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl b/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl index 76c0a88933..194cf29b64 100644 --- a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl +++ b/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -93,8 +93,6 @@ -include("../ssa/hipe_ssa_const_prop.inc"). -type bool_lattice() :: 'true' | 'false' | 'top' | 'bottom'. --type conditional() :: 'eq' | 'ne' | 'ge' | 'geu' | 'gt' | 'gtu' | 'le' - | 'leu' | 'lt' | 'ltu' | 'overflow' | 'not_overflow'. %%----------------------------------------------------------------------------- %% Procedure : visit_expression/2 @@ -400,7 +398,7 @@ maybe_top_or_bottom([top | Rest], _) -> maybe_top_or_bottom(Rest, top); maybe_top_or_bottom([bottom | _], _) -> bottom; maybe_top_or_bottom([_ | Rest], TB) -> maybe_top_or_bottom(Rest, TB). --spec partial_eval_branch(conditional(), bool_lattice(), bool_lattice(), +-spec partial_eval_branch(hipe_rtl:alub_cond(), bool_lattice(), bool_lattice(), bool_lattice() | 0, bool_lattice() | 0) -> bool_lattice(). partial_eval_branch(Cond, N0, Z0, V0, C0) -> @@ -441,14 +439,14 @@ visit_alub(Inst, Env) -> hipe_rtl:alub_false_label(Inst)]; top -> []; _ -> - %if the partial branch cannot be evaluated we must execute the - % instruction at runtime. + %% if the partial branch cannot be evaluated we must execute the + %% instruction at runtime. case partial_eval_branch(hipe_rtl:alub_cond(Inst), N, Z, C, V) of bottom -> [hipe_rtl:alub_true_label(Inst), hipe_rtl:alub_false_label(Inst)]; top -> []; - true -> [hipe_rtl:alub_true_label(Inst) ]; - false -> [hipe_rtl:alub_false_label(Inst) ] + true -> [hipe_rtl:alub_true_label(Inst)]; + false -> [hipe_rtl:alub_false_label(Inst)] end end, {[], NewSSA, NewEnv} = set_to(hipe_rtl:alub_dst(Inst), NewVal, Env), @@ -944,8 +942,8 @@ update_branch(Inst, Env) -> %% some small helpers. alub_to_move(Inst, Res, Lab) -> - [ hipe_rtl:mk_move(hipe_rtl:alub_dst(Inst), Res), - hipe_rtl:mk_goto(Lab) ]. + [hipe_rtl:mk_move(hipe_rtl:alub_dst(Inst), Res), + hipe_rtl:mk_goto(Lab)]. make_alub_subst_list(bottom, _, Tail) -> Tail; make_alub_subst_list(top, Src, _) -> @@ -970,13 +968,13 @@ update_alub(Inst, Env) -> %% move and the branch. We can however replace variable with constants: S1 = make_alub_subst_list(Val1, Src1, []), S2 = make_alub_subst_list(Val2, Src2, S1), - [ hipe_rtl:subst_uses(S2, Inst) ]; - _ -> % we know where we will be going, let's find out what Dst should be. - % knowing where we are going means that at most one of the values is - % bottom, hence we can replace the alu-instr with a move. - % remember, a = b + 0 can give us enough info to know what jump to - % do without knowing the value of a. (I wonder if this will ever - % actualy happen ;) + [hipe_rtl:subst_uses(S2, Inst)]; + _ -> %% we know where we will be going, let's find out what Dst should be. + %% knowing where we are going means that at most one of the values is + %% bottom, hence we can replace the alu-instr with a move. + %% remember, a = b + 0 can give us enough info to know what jump to + %% do without knowing the value of a. (I wonder if this will ever + %% actualy happen ;) Res = case ResVal of bottom -> % something nonconstant. if (Val1 =:= bottom) -> Src1; @@ -985,11 +983,12 @@ update_alub(Inst, Env) -> _ -> hipe_rtl:mk_imm(ResVal) end, case CondRes of - top -> io:format("oops. something VERY bad: ~w ~w V1 & 2 ~w ~w\n", - [Inst, {ResVal, N, Z, C, V} , Val1, Val2]), - [Inst ]; - true -> alub_to_move(Inst, Res, hipe_rtl:alub_true_label(Inst)); - false -> alub_to_move(Inst, Res, hipe_rtl:alub_false_label(Inst)) + top -> + io:format("oops. something VERY bad: ~w ~w V1 & 2 ~w ~w\n", + [Inst, {ResVal, N, Z, C, V} , Val1, Val2]), + [Inst]; + true -> alub_to_move(Inst, Res, hipe_rtl:alub_true_label(Inst)); + false -> alub_to_move(Inst, Res, hipe_rtl:alub_false_label(Inst)) end end. @@ -1050,7 +1049,7 @@ update_phi(Instruction, Environment) -> %%----------------------------------------------------------------------------- -%% make sure that all precoloured rgisters are taken out of the equation. +%% make sure that all precoloured registers are taken out of the equation. lookup_lattice_value(X, Environment) -> case hipe_rtl_arch:is_precoloured(X) or hipe_rtl:is_const_label(X) of true -> diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl index dc44b803a1..5859c345d0 100644 --- a/lib/hipe/rtl/hipe_tagscheme.erl +++ b/lib/hipe/rtl/hipe_tagscheme.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -849,9 +849,9 @@ create_refc_binary(Base, Size, Flags, Dst) -> heap_arch_spec(HP) -> Tmp1 = hipe_rtl:mk_new_reg(), % MSO state - [hipe_rtl_arch:pcb_load(Tmp1, ?P_OFF_HEAP_MSO), + [hipe_rtl_arch:pcb_load(Tmp1, ?P_OFF_HEAP_FIRST), set_field_from_pointer({proc_bin, next}, HP, Tmp1), - hipe_rtl_arch:pcb_store(?P_OFF_HEAP_MSO, HP)]. + hipe_rtl_arch:pcb_store(?P_OFF_HEAP_FIRST, HP)]. test_heap_binary(Binary, TrueLblName, FalseLblName) -> Tmp1 = hipe_rtl:mk_new_reg_gcsafe(), diff --git a/lib/hipe/tools/hipe_tool.erl b/lib/hipe/tools/hipe_tool.erl index a1bd79895d..990805ceca 100644 --- a/lib/hipe/tools/hipe_tool.erl +++ b/lib/hipe/tools/hipe_tool.erl @@ -56,9 +56,9 @@ -record(state, {win_created = false :: boolean(), mindex = 0 :: integer(), - mod :: module(), + mod :: atom(), funs = [] :: [fa()], - mods = [] :: [module()], + mods = [] :: [atom()], options = [o2] :: comp_options(), compiling = false :: 'false' | pid() }). @@ -291,8 +291,7 @@ update_code_listbox(State) -> integer_to_list(length(Mods))++")"), catch gs:config(code_listbox, [{data, Mods}, {items, Mods}, - {selection, 0} - ]), + {selection, 0}]), update_module_box(State#state{mods = Mods}, 0, Mods, "") end end. @@ -367,7 +366,7 @@ update_text(Lab, Text) -> %% @doc Returns a list of all loaded modules. %%--------------------------------------------------------------------- --spec mods() -> [module()]. +-spec mods() -> [atom()]. mods() -> [Mod || {Mod,_File} <- code:all_loaded()]. @@ -382,25 +381,26 @@ funs(Mod) -> native_code(Mod) -> Mod:module_info(native_addresses). --spec mfas(module(), [fa()]) -> [mfa()]. +-spec mfas(atom(), [fa()]) -> [mfa()]. mfas(Mod, Funs) -> [{Mod,F,A} || {F,A} <- Funs]. --spec fun_names(module(), [fa()], [fa_address()], boolean()) -> string(). +-spec fun_names(atom(), [fa()], [fa_address()], boolean()) -> [string()]. fun_names(M, Funs, NativeCode, Prof) -> - [list_to_atom(atom_to_list(F) ++ "/" ++ integer_to_list(A) ++ - (case in_native(F, A, NativeCode) of - true -> " [native] "; - false -> "" - end) - ++ - if Prof -> - (catch integer_to_list(hipe_bifs:call_count_get({M,F,A}))); - true -> "" - end) || - {F,A} <- Funs]. + [atom_to_list(F) ++ "/" ++ integer_to_list(A) + ++ + (case in_native(F, A, NativeCode) of + true -> " [native] "; + false -> "" + end) + ++ + if Prof -> + (catch integer_to_list(hipe_bifs:call_count_get({M,F,A}))); + true -> "" + end + || {F,A} <- Funs]. -spec in_native(atom(), arity(), [fa_address()]) -> boolean(). @@ -461,7 +461,7 @@ get_compile(Info) -> false -> [] end. --spec is_profiled(module()) -> boolean(). +-spec is_profiled(atom()) -> boolean(). is_profiled(Mod) -> case hipe_bifs:call_count_get({Mod,module_info,0}) of @@ -478,7 +478,7 @@ compile(State) -> P = spawn(fun() -> c(Parent, State#state.mod, State#state.options) end), State#state{compiling = P}. --spec c(pid(), module(), comp_options()) -> 'ok'. +-spec c(pid(), atom(), comp_options()) -> 'ok'. c(Parent, Mod, Options) -> Res = hipe:c(Mod, Options), diff --git a/lib/hipe/util/hipe_digraph.erl b/lib/hipe/util/hipe_digraph.erl index a62e913fe5..fcfaa64684 100644 --- a/lib/hipe/util/hipe_digraph.erl +++ b/lib/hipe/util/hipe_digraph.erl @@ -1,20 +1,20 @@ %% -*- erlang-indent-level: 2 -*- %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %%----------------------------------------------------------------------- @@ -30,6 +30,8 @@ from_list/1, to_list/1, get_parents/2, get_children/2]). -export([reverse_preorder_sccs/1]). +-export_type([hdg/0]). + %%------------------------------------------------------------------------ -type ordset(T) :: [T]. % XXX: temporarily diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk index 129718a305..6ba9009a24 100644 --- a/lib/hipe/vsn.mk +++ b/lib/hipe/vsn.mk @@ -1 +1 @@ -HIPE_VSN = 3.7.5 +HIPE_VSN = 3.7.9 diff --git a/lib/hipe/x86/hipe_x86_spill_restore.erl b/lib/hipe/x86/hipe_x86_spill_restore.erl index e60c446e17..cd927669fb 100644 --- a/lib/hipe/x86/hipe_x86_spill_restore.erl +++ b/lib/hipe/x86/hipe_x86_spill_restore.erl @@ -1,20 +1,20 @@ %% -*- erlang-indent-level: 2 -*- %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% %% ==================================================================== @@ -71,9 +71,9 @@ firstPass(Defun) -> case hipe_x86_cfg:reverse_postorder(CFG0) of [Label1, Label2|_] -> SaveTreeElement = saveTreeLookup(Label2, SaveTree), - %% FilteredSaveTreeElement is the to be spilled temps around the function call. - %% They are spilled just before move formals - FilteredSaveTreeElement = [Temp || Temp <- SaveTreeElement, temp_is_pseudo(Temp)], + %% FilteredSaveTreeElement is the to be spilled temps around the + %% function call. They are spilled just before move formals. + FilteredSaveTreeElement = [T || T <- SaveTreeElement, temp_is_pseudo(T)], Block = hipe_x86_cfg:bb(CFG1, Label1), Code = hipe_bb:code(Block), %% The following statements are tedious but work ok. @@ -83,7 +83,7 @@ firstPass(Defun) -> %% Another solution may be to introduce another block. MoveCodes = lists:sublist(Code, length(Code)-1), JumpCode = lists:last(Code), - hipe_x86_cfg:bb_add(CFG1, Label1, hipe_bb:mk_bb(MoveCodes ++ [hipe_x86:mk_pseudo_spill(FilteredSaveTreeElement)] ++ [JumpCode])); + hipe_x86_cfg:bb_add(CFG1, Label1, hipe_bb:mk_bb(MoveCodes ++ [hipe_x86:mk_pseudo_spill(FilteredSaveTreeElement), JumpCode])); _ -> CFG1 end. @@ -110,13 +110,12 @@ firstPassHelper([Label|Labels], Liveness, CFG, SaveTree) -> NewBlock = hipe_bb:code_update(Block, NewCode), NewCFG = hipe_x86_cfg:bb_add(CFG, Label, NewBlock), SizeOfSet = setSize(NewIntersectedList), - %% if the Intersected Save List is not empty, insert it in the save tree. if SizeOfSet =/= 0 -> - UpdatedSaveTree = gb_trees:insert(Label,NewIntersectedList,SaveTree), - firstPassHelper(Labels, Liveness, NewCFG,UpdatedSaveTree); + UpdatedSaveTree = gb_trees:insert(Label, NewIntersectedList, SaveTree), + firstPassHelper(Labels, Liveness, NewCFG, UpdatedSaveTree); true -> - firstPassHelper(Labels, Liveness, NewCFG,SaveTree) + firstPassHelper(Labels, Liveness, NewCFG, SaveTree) end; firstPassHelper([], _, CFG, SaveTree) -> {CFG, SaveTree}. @@ -125,17 +124,15 @@ firstPassHelper([], _, CFG, SaveTree) -> firstPassDoBlock(Insts, LiveOut, IntersectedSaveList) -> lists:foldr(fun firstPassDoInsn/2, {LiveOut,IntersectedSaveList,[]}, Insts). -firstPassDoInsn(I, {LiveOut,IntersectedSaveList,PrevInsts} ) -> +firstPassDoInsn(I, {LiveOut,IntersectedSaveList,PrevInsts}) -> case I of #pseudo_call{} -> do_pseudo_call(I, {LiveOut,IntersectedSaveList,PrevInsts}); _ -> % other instructions DefinedList = from_list( ?HIPE_X86_LIVENESS:defines(I)), UsedList = from_list(?HIPE_X86_LIVENESS:uses(I)), - NewLiveOut = subtract(union(LiveOut, UsedList), DefinedList), - NewIntersectedSaveList = subtract(IntersectedSaveList, DefinedList), - + NewIntersectedSaveList = subtract(IntersectedSaveList, DefinedList), {NewLiveOut, NewIntersectedSaveList, [I|PrevInsts]} end. @@ -162,7 +159,7 @@ saveTreeLookup(Label, SaveTree) -> [] end. -%% Performs the second pass of the algoritm. +%% Performs the second pass of the algorithm. %% It basically eliminates the unnecessary spills and introduces restores. %% Works top down secondPass(CFG0) -> @@ -306,7 +303,8 @@ addRestoreBlockToEdge(PseudoCall, ContLabel, CFG, TempArgsList) -> NewCFG = hipe_x86_cfg:bb_add(CFG, NextLabel, NewBlock), {NewCFG, NewPseudoCall}. -%% used instead of hipe_x86_cfg:redirect_jmp since it does not handle pseudo_call calls. +%% used instead of hipe_x86_cfg:redirect_jmp since it does not handle +%% pseudo_call calls. redirect_pseudo_call(I = #pseudo_call{contlab=ContLabel}, Old, New) -> case Old =:= ContLabel of true -> I#pseudo_call{contlab=New}; @@ -323,8 +321,8 @@ temp_is_pseudo(Temp) -> %% Set operations where the module name is an easily changeable macro %%--------------------------------------------------------------------- -union(Set1,Set2) -> - ?SET_MODULE:union(Set1,Set2). +union(Set1, Set2) -> + ?SET_MODULE:union(Set1, Set2). setSize(Set) -> ?SET_MODULE:size(Set). |