mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
typecheck_unify_var_functor.m used to have separate code paths
- to handle the functors of builtin types, and
- to handle the functors of all other types.
However, the second path invoked code in typecheck_cons_infos.m that
*also* handled builtin types.
compiler/typecheck_unify_var_functor.m:
Simplify this arrangement by deleting the code that chose between
the two paths, and handling functors of builtin types together with
all the other functors in (what used to be) the second path.
compiler/typecheck_cons_infos.m:
Return a distinct result for cons_ids of all builtin types
(including some that typecheck_unify_var_functor.m did not handle
via the first code path.)
Document the meanings of the possible results.
compiler/hlds_cons.m:
Change the ctor_field_table type to encode the invariant
that we don't map sym_names to the empty list of field definitions.
compiler/hlds_pred.m:
The predicates that test whether a sym_name/arity pair or pred_info
refer to a field access function must search the ctor_field_table
to answer the question. Make them return the info they get from that
search, to save their callers from having to do it again.
Give a predicate a more meaningful name.
compiler/typecheck_info.m:
Record extra info if we are typechecking in a field access function,
since it may be needed, and storing it costs next to nothing.
compiler/add_clause.m:
compiler/add_type.m:
compiler/check_field_access_functions.m:
compiler/field_access.m:
compiler/intermod_decide.m:
compiler/pre_typecheck.m:
compiler/recompilation.check.m:
compiler/recompilation.usage.m:
compiler/resolve_unify_functor.m:
compiler/typecheck_error_undef.m:
Conform to the changes above.
3605 lines
148 KiB
Mathematica
3605 lines
148 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1996-2012 The University of Melbourne.
|
|
% Copyright (C) 2013-2025 The Mercury team.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: hlds_pred.m.
|
|
% Main authors: fjh, conway.
|
|
%
|
|
% This module defines the part of the HLDS that deals with predicates
|
|
% and procedures.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module hlds.hlds_pred.
|
|
:- interface.
|
|
|
|
:- import_module analysis.
|
|
:- import_module analysis.framework.
|
|
:- import_module check_hlds.
|
|
:- import_module check_hlds.mode_constraint_robdd.
|
|
:- import_module hlds.hlds_class.
|
|
:- import_module hlds.hlds_clauses.
|
|
:- import_module hlds.hlds_cons.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_llds.
|
|
:- import_module hlds.hlds_markers.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_promise.
|
|
:- import_module hlds.hlds_rtti.
|
|
:- import_module hlds.inst_graph.
|
|
:- import_module hlds.instmap.
|
|
:- import_module hlds.pred_name.
|
|
:- import_module hlds.pred_table.
|
|
:- import_module hlds.status.
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.goal_path.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module mdbcomp.program_representation.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.error_spec.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_data_pragma.
|
|
:- import_module parse_tree.set_of_var.
|
|
:- import_module parse_tree.var_db.
|
|
:- import_module parse_tree.var_table.
|
|
:- import_module transform_hlds.
|
|
:- import_module transform_hlds.term_constr_main_types.
|
|
:- import_module transform_hlds.term_util.
|
|
|
|
:- import_module bool.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module one_or_more.
|
|
:- import_module pair.
|
|
:- import_module set.
|
|
|
|
:- implementation.
|
|
|
|
:- import_module backend_libs.
|
|
:- import_module backend_libs.builtin_ops.
|
|
:- import_module hlds.goal_form.
|
|
:- import_module hlds.goal_util.
|
|
:- import_module hlds.goal_vars.
|
|
:- import_module hlds.hlds_args.
|
|
:- import_module hlds.hlds_data.
|
|
:- import_module hlds.type_util.
|
|
:- import_module libs.options.
|
|
:- import_module mdbcomp.builtin_modules.
|
|
:- import_module parse_tree.prog_type.
|
|
:- import_module parse_tree.prog_type_scan.
|
|
:- import_module parse_tree.prog_util.
|
|
:- import_module parse_tree.vartypes.
|
|
|
|
:- import_module int.
|
|
:- import_module require.
|
|
:- import_module string.
|
|
:- import_module term.
|
|
:- import_module unit.
|
|
:- import_module varset.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- interface.
|
|
|
|
% A proc_id is the name of a mode within a particular predicate -
|
|
% not to be confused with a mode_id, which is the name of a
|
|
% user-defined mode.
|
|
|
|
:- type pred_id.
|
|
:- type proc_id.
|
|
:- type pred_proc_id
|
|
---> proc(pred_id, proc_id).
|
|
|
|
:- func pred_proc_id_project_pred_id(pred_proc_id) = pred_id.
|
|
:- func pred_proc_id_project_proc_id(pred_proc_id) = proc_id.
|
|
|
|
% Several passes operate on the module one SCC at a time. An SCC is
|
|
% a strongly connected component of the call graph, i.e. a group of
|
|
% procedures that all recursively call each other, directly or indirectly,
|
|
% which aren't mutually recursive with any procedure outside the SCC.
|
|
:- type scc == set(pred_proc_id).
|
|
|
|
% Predicate and procedure ids are abstract data types. One important
|
|
% advantage of this arrangement is to make it harder to accidentally
|
|
% confuse them for each other, or to use an integer in their place.
|
|
% However, you can convert between integers and pred_ids/proc_ids
|
|
% with the following predicates and functions.
|
|
%
|
|
:- func shroud_pred_id(pred_id) = shrouded_pred_id.
|
|
:- func shroud_proc_id(proc_id) = shrouded_proc_id.
|
|
:- func shroud_pred_proc_id(pred_proc_id) = shrouded_pred_proc_id.
|
|
|
|
:- func unshroud_pred_id(shrouded_pred_id) = pred_id.
|
|
:- func unshroud_proc_id(shrouded_proc_id) = proc_id.
|
|
:- func unshroud_pred_proc_id(shrouded_pred_proc_id) = pred_proc_id.
|
|
|
|
:- pred pred_id_to_int(pred_id, int).
|
|
:- mode pred_id_to_int(in, out) is det.
|
|
:- mode pred_id_to_int(out, in) is det.
|
|
:- func pred_id_to_int(pred_id) = int.
|
|
|
|
:- pred proc_id_to_int(proc_id, int).
|
|
:- mode proc_id_to_int(in, out) is det.
|
|
:- mode proc_id_to_int(out, in) is det.
|
|
:- func proc_id_to_int(proc_id) = int.
|
|
|
|
% Return the id of the first predicate in a module, and of the first
|
|
% procedure in a predicate.
|
|
%
|
|
:- func initial_pred_id = pred_id.
|
|
:- func initial_proc_id = proc_id.
|
|
|
|
% Return an invalid predicate or procedure id. These are intended to be
|
|
% used to initialize the relevant fields in call(...) goals before
|
|
% we do type- and mode-checks, or when those checks find that there was
|
|
% no predicate matching the call.
|
|
%
|
|
:- func invalid_pred_id = pred_id.
|
|
:- func invalid_proc_id = proc_id.
|
|
|
|
:- pred next_pred_id(pred_id::in, pred_id::out) is det.
|
|
|
|
% For semidet complicated unifications with mode (in, in), these are
|
|
% defined to have the same proc_id (0). This returns that proc_id.
|
|
%
|
|
:- pred in_in_unification_proc_id(proc_id::out) is det.
|
|
|
|
:- type pred_info.
|
|
:- type proc_info.
|
|
|
|
% These types are abstract exported to permit the proc_info fields
|
|
% of these types to be part of the argument lists of proc_prepare_to_clone
|
|
% and proc_create.
|
|
%
|
|
:- type structure_sharing_info.
|
|
:- type structure_reuse_info.
|
|
|
|
:- type proc_table == map(proc_id, proc_info).
|
|
|
|
:- pred next_proc_id(proc_table::in, proc_id::out) is det.
|
|
|
|
:- type call_id
|
|
---> plain_call_id(pf_sym_name_arity)
|
|
% The call is a plain call, and the argument specifies the callee.
|
|
; generic_call_id(var_name_source, generic_call).
|
|
% The call is a generic call, specified by the second argument.
|
|
% If it is a higher order call, then the second argument will
|
|
% specify the variable holding the identity of the callee.
|
|
% The var_name_source is needed to convert this variable
|
|
% to a printable name in diagnotics.
|
|
|
|
:- type generic_call_id
|
|
---> gcid_higher_order(purity, pred_or_func, pred_form_arity)
|
|
; gcid_class_method(class_id, pf_sym_name_arity)
|
|
; gcid_event_call(string)
|
|
; gcid_cast(cast_kind).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type implementation_language
|
|
---> impl_lang_mercury
|
|
; impl_lang_foreign(foreign_language).
|
|
|
|
% A predicate, and the goal inside it, may implement a promise declaration,
|
|
% or it may be an ordinary predicate.
|
|
:- type goal_type
|
|
---> goal_not_for_promise(np_goal_type)
|
|
; goal_for_promise(promise_type).
|
|
|
|
% An ordinary non-promise predicate may be defined by Mercury clauses,
|
|
% foreign procs, both, or neither. (The last is the recorded situation
|
|
% when we have added the predicate's declaration to the HLDS but have not
|
|
% processed any clauses or foreign procs just yet.)
|
|
%
|
|
% We use this information in two ways.
|
|
%
|
|
% First, intermod.m needs to know whether a predicate's definition
|
|
% contains any foreign_procs, because if it does, then it cannot append
|
|
% variable numbers after variable names for disambiguation, in e.g. clause
|
|
% heads, since that would screw up references to those variables in the
|
|
% foreign code.
|
|
%
|
|
% Second, purity.m has special handling for predicates that are defined
|
|
% *only* by foreign procs.
|
|
%
|
|
% Therefore the compiler does make a distinction between how it handles
|
|
% np_goal_type_foreign and np_goal_type_clause_and_foreign.
|
|
%
|
|
% As it happens, the compiler makes no distinction between how it handles
|
|
% np_goal_type_none and np_goal_type_clause, with the obvious exception
|
|
% that adding a foreign proc to the two results in no_goal_types that
|
|
% *are* distinguishable.
|
|
:- type np_goal_type
|
|
---> np_goal_type_none
|
|
; np_goal_type_clause
|
|
; np_goal_type_foreign
|
|
; np_goal_type_clause_and_foreign.
|
|
|
|
% NOTE: `liveness_info' records liveness in the sense used by code
|
|
% generation. This is *not* the same thing as the notion of liveness
|
|
% used by mode analysis! See compiler/notes/glossary.html.
|
|
%
|
|
:- type liveness_info == set_of_progvar. % The live variables.
|
|
|
|
:- type arg_info
|
|
---> arg_info(
|
|
arg_loc, % Stored location.
|
|
top_functor_mode % Mode of top functor.
|
|
).
|
|
|
|
% The top_functor_mode specifies the mode of the top-level functor
|
|
% of a term (excluding `no_tag' functors, since those have no
|
|
% representation). It is used by the code generators when determining
|
|
% how to pass the argument.
|
|
%
|
|
% For the LLDS back-end, top_in arguments are passed in registers,
|
|
% and top_out values are returned in registers; top_unused values
|
|
% are not passed at all, but they are treated as if they were top_out
|
|
% for the purpose of assigning arguments to registers. (So e.g. if
|
|
% a det procedure has three arguments with top_functor_modes top_out,
|
|
% top_unused, and top_out respectively, the last argument will be
|
|
% returned in register r3, not r2.)
|
|
%
|
|
% For the MLDS back-end, top_in values are passed as arguments.
|
|
% Top_out values are normally passed by reference, except that
|
|
% - if the procedure is model_nondet, and the --nondet-copy-out option
|
|
% is set, top_out values are passed by value to the continuation
|
|
% function;
|
|
% - if the procedure is model_det or model_semi, and the
|
|
% --det-copy-out option is set, top_out arguments in the HLDS
|
|
% are mapped to (multiple) return values in the MLDS; and
|
|
% - if the HLDS function return value for a det function has mode
|
|
% `top_out', it is mapped to an MLDS return value.
|
|
% top_unused arguments are not passed at all.
|
|
%
|
|
:- type top_functor_mode
|
|
---> top_in
|
|
; top_out
|
|
; top_unused.
|
|
|
|
:- type arg_loc
|
|
---> reg(reg_type, int).
|
|
|
|
% Are calls from a predicate with the pred_markers always fully
|
|
% qualified? Basically, this function tests for the presence or absence
|
|
% of marker_calls_are_fully_qualified.
|
|
%
|
|
:- func calls_are_fully_qualified(pred_markers) = is_fully_qualified.
|
|
|
|
%---%
|
|
|
|
% This type is isomorphic to the module_section type, but defining it here
|
|
% allows us not to depend on parse_tree.prog_item.m.
|
|
:- type decl_section
|
|
---> decl_interface
|
|
; decl_implementation.
|
|
|
|
:- type maybe_predmode_decl
|
|
---> no_predmode_decl
|
|
; predmode_decl.
|
|
|
|
:- type cur_user_decl_info
|
|
---> cur_user_decl_info(
|
|
decl_section,
|
|
maybe_predmode_decl,
|
|
item_seq_num
|
|
).
|
|
|
|
:- type format_call_info
|
|
---> format_call_info(
|
|
% The context of the format_call pragma whose info
|
|
% this field of the pred_info records. We use this
|
|
% to generate more informative error messages in cases of
|
|
% duplicate format_call pragmas.
|
|
prog_context,
|
|
|
|
% The <format string arg #, values list arg #> pairs
|
|
% listed in that pragma.
|
|
one_or_more(format_string_values)
|
|
).
|
|
|
|
% pred_info_init(PredOrFunc, PredModuleName, PredName, Arity, Context,
|
|
% Origin, Status, CurUserDecl, GoalType, Markers,
|
|
% ArgTypes, TypeVarSet, ExistQVars, ClassContext, ClassProofs,
|
|
% ClassConstraintMap, ClausesInfo, VarNameRemap, PredInfo):
|
|
%
|
|
% Return a pred_info whose fields are filled in from the information
|
|
% (direct and indirect) in the arguments, and from defaults.
|
|
%
|
|
:- pred pred_info_init(pred_or_func::in, module_name::in, string::in,
|
|
pred_form_arity::in, prog_context::in, pred_origin::in,
|
|
pred_status::in, maybe(cur_user_decl_info)::in, goal_type::in,
|
|
pred_markers::in, list(mer_type)::in, tvarset::in, existq_tvars::in,
|
|
univ_exist_constraints::in, constraint_proof_map::in, constraint_map::in,
|
|
clauses_info::in, map(prog_var, string)::in, pred_info::out) is det.
|
|
|
|
% pred_info_create(ModuleInfo, PredOrFunc, ModuleName, PredName,
|
|
% Context, Origin, Status, Markers, ArgTypes, TypeVarSet, ExistQVars,
|
|
% ClassContext, Assertions, VarNameRemap, ProcInfo, ProcId, PredInfo)
|
|
%
|
|
% Return a pred_info whose fields are filled in from the information
|
|
% (direct and indirect) in the arguments, and from defaults. The given
|
|
% proc_info becomes the only procedure of the predicate (currently)
|
|
% and its proc_id is returned as the second last argument.
|
|
%
|
|
:- pred pred_info_create(pred_or_func::in, module_name::in, string::in,
|
|
prog_context::in, pred_origin::in, pred_status::in, pred_markers::in,
|
|
list(mer_type)::in, tvarset::in, existq_tvars::in,
|
|
univ_exist_constraints::in, set(assert_id)::in,
|
|
map(prog_var, string)::in, goal_type::in, proc_info::in,
|
|
proc_id::out, pred_info::out) is det.
|
|
|
|
%---------------------%
|
|
|
|
% pred_prepare_to_clone returns all the fields of an existing pred_info,
|
|
% while pred_create constructs a new pred_info putting the supplied values
|
|
% to each field.
|
|
%
|
|
% These predicates exist because we want keep the definition of the pred_info
|
|
% type private (to make future changes easier), but we also want to make it
|
|
% possible to create slightly modified copies of existing predicates
|
|
% with the least amount of programming work. We also want to require
|
|
% (a) programmers writing such cloning code to consider what effect
|
|
% the modification may have on *all* fields of the pred_info, and
|
|
% (b) programmers who add new fields to the pred_info to update
|
|
% all the places in the compiler that do such cloning.
|
|
|
|
:- pred pred_prepare_to_clone(pred_info::in,
|
|
module_name::out, pred_or_func::out, string::out, pred_form_arity::out,
|
|
pred_origin::out, pred_status::out, pred_markers::out, list(mer_type)::out,
|
|
tvarset::out, tvarset::out, existq_tvars::out, int::out,
|
|
univ_exist_constraints::out, clauses_info::out,
|
|
proc_table::out, prog_context::out,
|
|
maybe(cur_user_decl_info)::out, goal_type::out, tvar_kind_map::out,
|
|
tsubst::out, external_type_params::out, constraint_proof_map::out,
|
|
constraint_map::out, list(prog_constraint)::out, inst_graph_info::out,
|
|
list(arg_modes_map)::out, map(prog_var, string)::out, set(assert_id)::out,
|
|
maybe(list(sym_name_arity))::out, maybe(format_call_info)::out,
|
|
list(mer_type)::out) is det.
|
|
|
|
:- pred pred_create(module_name::in,
|
|
pred_or_func::in, string::in, pred_form_arity::in, pred_origin::in,
|
|
pred_status::in, pred_markers::in, list(mer_type)::in, tvarset::in,
|
|
tvarset::in, existq_tvars::in, int::in, univ_exist_constraints::in,
|
|
clauses_info::in, proc_table::in, prog_context::in,
|
|
maybe(cur_user_decl_info)::in, goal_type::in, tvar_kind_map::in,
|
|
tsubst::in, external_type_params::in, constraint_proof_map::in,
|
|
constraint_map::in, list(prog_constraint)::in, inst_graph_info::in,
|
|
list(arg_modes_map)::in, map(prog_var, string)::in, set(assert_id)::in,
|
|
maybe(list(sym_name_arity))::in, maybe(format_call_info)::in,
|
|
list(mer_type)::in, pred_info::out) is det.
|
|
|
|
%---------------------%
|
|
|
|
% define_new_pred(SymName, Origin, TVarSet, InstVarSet, VarTable,
|
|
% RttiVarMaps, ClassContext, InstMap0, VarNameRemap,
|
|
% Markers, IsAddressTaken, HasParallelConj, PredProcId,
|
|
% ArgVars, ExtraTiTcis, Goal0, CallGoal, !ModuleInfo):
|
|
%
|
|
% Create a new predicate for the given goal, returning a goal to
|
|
% call the created predicate. ExtraArgs is the list of extra
|
|
% type_infos and typeclass_infos required by typeinfo liveness
|
|
% which were added to the front of the argument list.
|
|
%
|
|
:- pred define_new_pred(sym_name::in, pred_origin::in,
|
|
tvarset::in, inst_varset::in, var_table::in,
|
|
rtti_varmaps::in, univ_exist_constraints::in, instmap::in,
|
|
map(prog_var, string)::in, pred_markers::in,
|
|
is_address_taken::in, has_parallel_conj::in, pred_proc_id::out,
|
|
list(prog_var)::in, list(prog_var)::out, hlds_goal::in, hlds_goal::out,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
:- pred add_new_proc(module_info::in, prog_context::in, item_seq_num::in,
|
|
inst_varset::in, list(mer_mode)::in,
|
|
maybe(list(mer_mode))::in, maybe(list(is_live))::in,
|
|
detism_decl::in, maybe(determinism)::in,
|
|
is_address_taken::in, has_parallel_conj::in,
|
|
pred_info::in, pred_info::out, proc_id::out) is det.
|
|
|
|
% Various predicates for accessing the information stored in the
|
|
% pred_id and pred_info data structures.
|
|
%
|
|
:- type external_type_params == list(tvar).
|
|
|
|
:- func pred_info_module(pred_info) = module_name.
|
|
:- func pred_info_name(pred_info) = string.
|
|
|
|
% N-ary functions are converted into N+1-ary predicates.
|
|
% (Clauses are converted in make_hlds, but calls to functions
|
|
% cannot be converted until after type-checking, once we have
|
|
% resolved overloading. So we do that during mode analysis.)
|
|
% The `is_pred_or_func' field of the pred_info records whether
|
|
% a pred_info is really for a predicate or whether it is for
|
|
% what was originally a function.
|
|
%
|
|
:- func pred_info_is_pred_or_func(pred_info) = pred_or_func.
|
|
|
|
% Pred_info_orig_arity returns the arity of the predicate
|
|
% *not* counting inserted type_info arguments for polymorphic preds.
|
|
%
|
|
:- func pred_info_pred_form_arity(pred_info) = pred_form_arity.
|
|
:- func pred_info_user_arity(pred_info) = user_arity.
|
|
|
|
:- pred pred_info_get_module_name(pred_info::in,
|
|
module_name::out) is det.
|
|
:- pred pred_info_get_is_pred_or_func(pred_info::in,
|
|
pred_or_func::out) is det.
|
|
:- pred pred_info_get_name(pred_info::in,
|
|
string::out) is det.
|
|
:- pred pred_info_get_orig_arity(pred_info::in,
|
|
pred_form_arity::out) is det.
|
|
:- pred pred_info_get_context(pred_info::in,
|
|
prog_context::out) is det.
|
|
:- pred pred_info_get_cur_user_decl_info(pred_info::in,
|
|
maybe(cur_user_decl_info)::out) is det.
|
|
:- pred pred_info_get_origin(pred_info::in,
|
|
pred_origin::out) is det.
|
|
:- pred pred_info_get_status(pred_info::in,
|
|
pred_status::out) is det.
|
|
:- pred pred_info_get_goal_type(pred_info::in,
|
|
goal_type::out) is det.
|
|
:- pred pred_info_get_markers(pred_info::in,
|
|
pred_markers::out) is det.
|
|
:- pred pred_info_get_arg_types(pred_info::in,
|
|
list(mer_type)::out) is det.
|
|
:- pred pred_info_get_typevarset(pred_info::in,
|
|
tvarset::out) is det.
|
|
:- pred pred_info_get_tvar_kind_map(pred_info::in,
|
|
tvar_kind_map::out) is det.
|
|
:- pred pred_info_get_exist_quant_tvars(pred_info::in,
|
|
existq_tvars::out) is det.
|
|
:- pred pred_info_get_existq_tvar_binding(pred_info::in,
|
|
tsubst::out) is det.
|
|
:- pred pred_info_get_polymorphism_added_args(pred_info::in,
|
|
int::out) is det.
|
|
:- pred pred_info_get_external_type_params(pred_info::in,
|
|
external_type_params::out) is det.
|
|
:- pred pred_info_get_class_context(pred_info::in,
|
|
univ_exist_constraints::out) is det.
|
|
:- pred pred_info_get_constraint_proof_map(pred_info::in,
|
|
constraint_proof_map::out) is det.
|
|
:- pred pred_info_get_constraint_map(pred_info::in,
|
|
constraint_map::out) is det.
|
|
:- pred pred_info_get_unproven_body_constraints(pred_info::in,
|
|
list(prog_constraint)::out) is det.
|
|
:- pred pred_info_get_inst_graph_info(pred_info::in,
|
|
inst_graph_info::out) is det.
|
|
:- pred pred_info_get_arg_modes_maps(pred_info::in,
|
|
list(arg_modes_map)::out) is det.
|
|
:- pred pred_info_get_var_name_remap(pred_info::in,
|
|
map(prog_var, string)::out) is det.
|
|
:- pred pred_info_get_assertions(pred_info::in,
|
|
set(assert_id)::out) is det.
|
|
:- pred pred_info_get_obsolete_in_favour_of(pred_info::in,
|
|
maybe(list(sym_name_arity))::out) is det.
|
|
:- pred pred_info_get_format_call_info(pred_info::in,
|
|
maybe(format_call_info)::out) is det.
|
|
:- pred pred_info_get_instance_method_arg_types(pred_info::in,
|
|
list(mer_type)::out) is det.
|
|
:- pred pred_info_get_clauses_info(pred_info::in,
|
|
clauses_info::out) is det.
|
|
:- pred pred_info_get_proc_table(pred_info::in,
|
|
proc_table::out) is det.
|
|
|
|
% Setting any part of the sym_name of a pred_info after its creation
|
|
% won't remove its name from the indexes under its old name or insert it
|
|
% into the indexes under its new name. If is therefore safe to do this
|
|
% only after *all* the passes that look up predicates by name.
|
|
%
|
|
:- pred pred_info_set_module_name(module_name::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_is_pred_or_func(pred_or_func::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_name(string::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_orig_arity(pred_form_arity::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_origin(pred_origin::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_status(pred_status::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_goal_type(goal_type::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_markers(pred_markers::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_typevarset(tvarset::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_tvar_kind_map(tvar_kind_map::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_existq_tvar_binding(tsubst::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_polymorphism_added_args(int::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_external_type_params(external_type_params::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_class_context(univ_exist_constraints::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_constraint_proof_map(constraint_proof_map::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_constraint_map(constraint_map::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_unproven_body_constraints(list(prog_constraint)::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_inst_graph_info(inst_graph_info::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_arg_modes_maps(list(arg_modes_map)::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_var_name_remap(map(prog_var, string)::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_assertions(set(assert_id)::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_obsolete_in_favour_of(
|
|
maybe(list(sym_name_arity))::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_format_call_info(maybe(format_call_info)::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_instance_method_arg_types(list(mer_type)::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_clauses_info(clauses_info::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
:- pred pred_info_set_proc_table(proc_table::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
|
|
% Mode information for the arguments of a procedure.
|
|
% The first map gives the instantiation state on entry of the node
|
|
% corresponding to the prog_var. The second map gives the instantiation
|
|
% state on exit.
|
|
%
|
|
:- type arg_modes_map == pair(map(prog_var, bool)).
|
|
|
|
% Return a list of the proc_ids for all the modes of this predicate,
|
|
%
|
|
:- func pred_info_all_procids(pred_info) = list(proc_id).
|
|
|
|
% Return a list of the proc_ids for all the modes of this predicate
|
|
% that are not imported.
|
|
%
|
|
:- func pred_info_all_non_imported_procids(pred_info) = list(proc_id).
|
|
|
|
% Return a list of the proc_ids for all the modes of this predicate
|
|
% that are exported.
|
|
%
|
|
:- func pred_info_all_exported_procids(pred_info) = list(proc_id).
|
|
|
|
% Remove a procedure from the pred_info.
|
|
%
|
|
:- pred pred_info_remove_procid(proc_id::in, pred_info::in, pred_info::out)
|
|
is det.
|
|
|
|
:- pred pred_info_get_arg_types(pred_info::in, tvarset::out, existq_tvars::out,
|
|
list(mer_type)::out) is det.
|
|
|
|
:- pred pred_info_set_arg_types(tvarset::in, existq_tvars::in,
|
|
list(mer_type)::in, pred_info::in, pred_info::out) is det.
|
|
|
|
:- pred pred_info_get_univ_quant_tvars(pred_info::in, list(tvar)::out)
|
|
is det.
|
|
|
|
:- pred pred_info_proc_info(pred_info::in, proc_id::in, proc_info::out) is det.
|
|
|
|
:- pred pred_info_set_proc_info(proc_id::in, proc_info::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
|
|
:- pred pred_info_is_imported(pred_info::in) is semidet.
|
|
|
|
:- pred pred_info_is_imported_not_external(pred_info::in) is semidet.
|
|
|
|
:- pred pred_info_is_pseudo_imported(pred_info::in) is semidet.
|
|
|
|
% pred_info_is_exported does *not* include predicates which are
|
|
% exported_to_submodules or pseudo_exported.
|
|
%
|
|
:- pred pred_info_is_exported(pred_info::in) is semidet.
|
|
|
|
:- pred pred_info_is_opt_exported(pred_info::in) is semidet.
|
|
|
|
:- pred pred_info_is_exported_to_submodules(pred_info::in) is semidet.
|
|
|
|
:- pred pred_info_is_pseudo_exported(pred_info::in) is semidet.
|
|
|
|
% procedure_is_exported includes all modes of exported or
|
|
% exported_to_submodules predicates, plus the in-in mode
|
|
% for pseudo_exported unification predicates.
|
|
%
|
|
:- pred procedure_is_exported(module_info::in, pred_info::in, proc_id::in)
|
|
is semidet.
|
|
|
|
% Set the pred_status of the predicate to `imported'.
|
|
% This is used for `:- pragma external_{pred/func}(foo/2).'.
|
|
%
|
|
:- pred pred_info_mark_as_external(pred_info::in, pred_info::out) is det.
|
|
|
|
% Do we have a clause goal type?
|
|
% (this means either "clauses" or "clauses_and_pragmas")
|
|
%
|
|
:- pred pred_info_defn_has_clause(pred_info::in) is semidet.
|
|
|
|
% Do we have a pragma goal type?
|
|
% (this means either "pragmas" or "clauses_and_pragmas")
|
|
%
|
|
:- pred pred_info_defn_has_foreign_proc(pred_info::in) is semidet.
|
|
|
|
:- pred pred_info_update_goal_type(np_goal_type::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
|
|
% Succeeds if there was a `:- pragma inline(...)' declaration
|
|
% for this predicate. Note that the compiler may decide
|
|
% to inline a predicate even if there was no pragma inline(...)
|
|
% declaration for that predicate.
|
|
%
|
|
:- pred pred_info_requested_inlining(pred_info::in) is semidet.
|
|
|
|
% Succeeds if there was a `:- pragma no_inline(...)' declaration
|
|
% for this predicate.
|
|
%
|
|
:- pred pred_info_requested_no_inlining(pred_info::in) is semidet.
|
|
|
|
:- pred pred_info_get_purity(pred_info::in, purity::out) is det.
|
|
|
|
% If the predicate has a purity promise, return it wrapped inside a `yes'.
|
|
% Otherwise, return `no'.
|
|
%
|
|
:- pred pred_info_get_promised_purity(pred_info::in, maybe(purity)::out)
|
|
is det.
|
|
|
|
:- pred pred_info_infer_modes(pred_info::in) is semidet.
|
|
|
|
:- pred pred_info_get_pf_sym_name_arity(pred_info::in, pf_sym_name_arity::out)
|
|
is det.
|
|
|
|
:- pred pred_info_get_sym_name(pred_info::in, sym_name::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.optimization_options.
|
|
|
|
:- type pred_id
|
|
---> pred_id(int).
|
|
|
|
:- type proc_id == int.
|
|
|
|
pred_proc_id_project_pred_id(proc(PredId, _ProcId)) = PredId.
|
|
pred_proc_id_project_proc_id(proc(_PredId, ProcId)) = ProcId.
|
|
|
|
shroud_pred_id(pred_id(PredId)) = shrouded_pred_id(PredId).
|
|
shroud_proc_id(ProcId) = shrouded_proc_id(ProcId).
|
|
shroud_pred_proc_id(proc(pred_id(PredId), ProcId)) =
|
|
shrouded_pred_proc_id(PredId, ProcId).
|
|
|
|
unshroud_pred_id(shrouded_pred_id(PredId)) = pred_id(PredId).
|
|
unshroud_proc_id(shrouded_proc_id(ProcId)) = ProcId.
|
|
unshroud_pred_proc_id(shrouded_pred_proc_id(PredId, ProcId)) =
|
|
proc(pred_id(PredId), ProcId).
|
|
|
|
pred_id_to_int(pred_id(PredId), PredId).
|
|
pred_id_to_int(pred_id(PredId)) = PredId.
|
|
|
|
proc_id_to_int(ProcId, ProcId).
|
|
proc_id_to_int(ProcId) = ProcId.
|
|
|
|
initial_pred_id = pred_id(0).
|
|
initial_proc_id = 0.
|
|
|
|
invalid_pred_id = pred_id(-1).
|
|
invalid_proc_id = -1.
|
|
|
|
next_pred_id(pred_id(PredId), pred_id(NextPredId)) :-
|
|
NextPredId = PredId + 1.
|
|
|
|
in_in_unification_proc_id(0).
|
|
|
|
next_proc_id(ProcTable, ProcId) :-
|
|
% We could store the next available ModeId rather than recomputing
|
|
% it on demand, but it is probably more efficient this way.
|
|
map.to_assoc_list(ProcTable, ProcIdsInfos),
|
|
list.length(ProcIdsInfos, Num),
|
|
proc_id_to_int(ProcId, Num).
|
|
|
|
calls_are_fully_qualified(Markers) =
|
|
( if marker_is_present(Markers, marker_calls_are_fully_qualified) then
|
|
is_fully_qualified
|
|
else
|
|
may_be_partially_qualified
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Access stats for the pred_info structure, derived on 2014 dec 13:
|
|
%
|
|
% i read same diff same%
|
|
% 1 124,287,827 348,040 31,892,426 1.08% procedures
|
|
% 2 72,037,616 96,336 1,082,541 8.17% status
|
|
% 3 43,651,895 0 0 module_name
|
|
% 4 32,003,757 0 795 0.00% name
|
|
% 5 25,261,836 0 0 orig_arity
|
|
% 6 24,876,447 905,599 1,098,352 45.19% markers
|
|
% 7 22,294,552 19,444 12,496,762 0.16% clauses_info
|
|
% 8 20,415,273 0 0 arg_types
|
|
% 9 15,356,498 727 68 91.45% is_pred_or_func
|
|
% 10 12,075,408 382,680 89,618 81.03% origin
|
|
% 11 11,783,136 9,736,724 752,983 92.82% typevarset
|
|
% 12 11,128,685 4,600,914 1,642,568 73.69% three fields:
|
|
% decl_typevarset,
|
|
% exist_quant_vars and
|
|
% arg_types
|
|
% 13 7,871,038 0 2,700,797 0.00% class_context
|
|
% 14 6,629,313 100,630 1,054,197 8.71% goal_type
|
|
% 15 5,892,199 6,544 6,726 49.31% var_name_remap
|
|
% 16 3,820,195 85,054 0 100.00% tvar_kind_map
|
|
% 17 2,752,537 404,771 23,921 94.42% constraint_map
|
|
% 18 2,591,016 425,209 3,483 99.19% constraint_proof_map
|
|
% 19 1,667,832 0 0 context
|
|
% 20 1,374,911 0 0 exist_quant_vars
|
|
% 21 476,703 276,426 152,903 64.39% external_type_params
|
|
% 22 285,538 428,650 4 100.00% unproven_body_constraints
|
|
% 23 22,563 0 80 0.00% existq_tvar_binding
|
|
% 24 3,834 0 3,797 0.00% assertions
|
|
% 25 10 0 0 attributes
|
|
% 26 0 0 19,439 0.00% instance_method_arg_types
|
|
% 27 0 0 0 arg_modes_maps
|
|
% 28 0 0 0 inst_graph_info
|
|
|
|
% The information specific to a predicate, as opposed to a procedure.
|
|
% (Functions count as predicates.)
|
|
%
|
|
% The pred_info and pred_sub_info types constitute a single logical
|
|
% data structure split into two parts for efficiency purposes.
|
|
%
|
|
% The pred_info type contains the most frequently accessed and/or updated
|
|
% pieces of information about the predicate. Everything else is in the
|
|
% pred_sub_info type. This arrangement minimizes the amount of memory that
|
|
% needs to be allocated, and filled in, when a field is updated.
|
|
|
|
:- type pred_info
|
|
---> pred_info(
|
|
% The Boehm collector allocates blocks whose sizes are
|
|
% multiples of 2. Ideally, we would want the number of fields
|
|
% of pred_info to be a multiple of 2 as well, but as of
|
|
% 2017 march 15, this seems to be the optimal arrangement (zs).
|
|
|
|
% Module in which pred occurs.
|
|
/* 1 */ pi_module_name :: module_name,
|
|
|
|
% Is this "predicate" really a predicate or a function?
|
|
/* 2 */ pi_is_pred_or_func :: pred_or_func,
|
|
|
|
% Predicate name.
|
|
/* 3 */ pi_name :: string,
|
|
|
|
% The original arity of the pred, i.e. its arity *not* counting
|
|
% any type_info and/or typeclass_info arguments inserted
|
|
% automatically by the compiler.
|
|
%
|
|
% For functions, the original arity *includes* the return
|
|
% value, so that e.g. the original arity of int.+ would be 3.
|
|
/* 4 */ pi_orig_arity :: pred_form_arity,
|
|
|
|
% Where did the predicate come from?
|
|
/* 5 */ pi_pred_origin :: pred_origin,
|
|
|
|
/* 6 */ pi_status :: pred_status,
|
|
|
|
% Various boolean flags.
|
|
/* 7 */ pi_markers :: pred_markers,
|
|
|
|
% Argument types.
|
|
% Note that it is an invariant that any type_info- and/or
|
|
% typeclass_info-related variables in the arguments of a
|
|
% predicate must precede any polymorphically-typed arguments
|
|
% whose type depends on the values of those type_info- and/or
|
|
% typeclass_info-related variables; accurate GC for the MLDS
|
|
% back-end relies on this.
|
|
/* 8 */ pi_arg_types :: list(mer_type),
|
|
|
|
% Names of type vars in the predicate's type declaration.
|
|
/* 9 */ pi_decl_typevarset :: tvarset,
|
|
|
|
% Names of type vars in the predicate's type declaration
|
|
% or in the variable type assignments.
|
|
/* 10 */ pi_typevarset :: tvarset,
|
|
|
|
% The set of existentially quantified type variables in the
|
|
% predicate's type declaration.
|
|
/* 11 */ pi_exist_quant_tvars :: existq_tvars,
|
|
|
|
% The class constraints on the type variables in the
|
|
% predicate's type declaration.
|
|
%
|
|
% For predicates that represent a method of a typeclass,
|
|
% the first universal constraint will be the constraint
|
|
% for that typeclass. This is ensured by code in
|
|
% module_add_class_method, which is executed when
|
|
% the class method's pred declaration is added to the HLDS.
|
|
/* 12 */ pi_class_context :: univ_exist_constraints,
|
|
|
|
/* 13 */ pi_clauses_info :: clauses_info,
|
|
|
|
/* 14 */ pi_proc_table :: proc_table,
|
|
|
|
/* 15 */ pi_pred_sub_info :: pred_sub_info
|
|
).
|
|
|
|
:- type pred_sub_info
|
|
---> pred_sub_info(
|
|
% The location (line #) of the :- pred decl.
|
|
psi_context :: prog_context,
|
|
|
|
% If the predicate is defined (a) in the current module, and
|
|
% (b) explicitly by the user, as opposed to by the compiler,
|
|
% then this records what section the predicate declaration
|
|
% is in, and whether it is a predmode declaration.
|
|
%
|
|
% Note that "defined explicitly by the user" does not guarantee
|
|
% that the cur_user_decl_info will contain a valid
|
|
% item_seq_num, because for class methods, it won't.
|
|
% (This is because predicate declarations in typeclass items
|
|
% do not have their own separate item_seq_num.)
|
|
psi_cur_user_decl :: maybe(cur_user_decl_info),
|
|
|
|
% Whether the goals seen so far, if any, for this predicate
|
|
% are clauses or foreign_code(...) pragmas.
|
|
psi_goal_type :: goal_type,
|
|
|
|
% Kinds of the type vars.
|
|
psi_tvar_kind_map :: tvar_kind_map,
|
|
|
|
% The statically known bindings of existentially quantified
|
|
% type variables inside this predicate. This field is set
|
|
% at the end of the polymorphism stage.
|
|
psi_existq_tvar_binding :: tsubst,
|
|
|
|
% The number of type_info and/or typeclass_info arguments
|
|
% added by the polymorphism pass. This field is set
|
|
% at the end of that pass.
|
|
%
|
|
% XXX ARGVEC: When we use argvecs to record the predicate's
|
|
% argument vector, we should be able to delete this field.
|
|
psi_polymorphism_added_args :: int,
|
|
|
|
% The set of type variables which the body of the predicate
|
|
% can't bind, and whose type_infos are produced elsewhere.
|
|
% This includes universally quantified head types (the
|
|
% type_infos are passed in) plus existentially quantified types
|
|
% in preds called from the body (the type_infos are returned
|
|
% from the called predicates). Computed during type checking.
|
|
psi_external_type_params :: external_type_params,
|
|
|
|
% Explanations of how redundant constraints were eliminated.
|
|
% These are needed by polymorphism.m to work out where to get
|
|
% the typeclass_infos from. Computed during type checking.
|
|
psi_constraint_proof_map :: constraint_proof_map,
|
|
|
|
% Maps constraint identifiers to the actual constraints.
|
|
% Computed during type checking.
|
|
psi_constraint_map :: constraint_map,
|
|
|
|
% Unproven class constraints on type variables in the
|
|
% predicate's body, if any (if this remains non-empty after
|
|
% type checking has finished, post_typecheck.m will report a
|
|
% type error).
|
|
psi_unproven_body_constraints :: list(prog_constraint),
|
|
|
|
% The predicate's inst graph, for constraint based
|
|
% mode analysis.
|
|
psi_inst_graph_info :: inst_graph_info,
|
|
|
|
% Mode information extracted from constraint based
|
|
% mode analysis.
|
|
psi_arg_modes_maps :: list(arg_modes_map),
|
|
|
|
% Renames of some head variables computed by headvar_names.m,
|
|
% for use by the debugger.
|
|
psi_var_name_remap :: map(prog_var, string),
|
|
|
|
% List of assertions which mention this predicate.
|
|
psi_assertions :: set(assert_id),
|
|
|
|
% If this predicate is marked as obsolete, this will be a
|
|
% "yes(_)" wrapped around a list of the predicate names that
|
|
% the compiler should suggest as possible replacements.
|
|
% (Note that the list of possible replacements may be empty.)
|
|
% In the usual case where this predicate is NOT marked
|
|
% as obsolete, this will be "no".
|
|
psi_obsolete_in_favour_of :: maybe(list(sym_name_arity)),
|
|
|
|
% If this field contains yes(FormatCall), then this predicate
|
|
% has a format_call pragma, and FormatCall contains both the
|
|
% <format string, values list> argument number pairs
|
|
% specified in that pragma, and the context of that pragma.
|
|
% If this field contains no, then the predicate does not have
|
|
% a format_call pragma.
|
|
%
|
|
% When the HLDS is first created, the argument numbers
|
|
% in the format_string_values structures in the list
|
|
% refer to the position of the arguments in the visible
|
|
% argument list. (The numbering starts at 1.) When polymorphism
|
|
% adds compiler-generated arguments to the start of the
|
|
% argument list, it increments all the argument numbers
|
|
% in this field to compensate.
|
|
%
|
|
% Some optimizations may also add or delete arguments,
|
|
% but they don't have to update this field, because
|
|
%
|
|
% - this field is used only by format_call.m, during the
|
|
% simplification pass done at the end of the front end,
|
|
%
|
|
% - optimizations that can change argument lists are
|
|
% all run *after* the front end, and therefore after
|
|
% all code that cares about the value of this field.
|
|
psi_format_call_info :: maybe(format_call_info),
|
|
|
|
% If this predicate is a class method implementation, this
|
|
% list records the argument types before substituting the type
|
|
% variables for the instance.
|
|
% XXX does that make sense?
|
|
psi_instance_method_arg_types :: list(mer_type)
|
|
).
|
|
|
|
pred_info_init(PredOrFunc, PredModuleName, PredName, PredFormArity, Context,
|
|
Origin, Status, CurUserDecl, GoalType, Markers,
|
|
ArgTypes, TypeVarSet, ExistQVars, ClassContext, ClassProofs,
|
|
ClassConstraintMap, ClausesInfo, VarNameRemap, PredInfo) :-
|
|
% argument Context
|
|
% argument GoalType
|
|
map.init(Kinds),
|
|
% XXX kind inference:
|
|
% we assume all tvars have kind `star'.
|
|
map.init(ExistQVarBindings),
|
|
PolymorphismAddedArgs = 0,
|
|
type_vars_in_types(ArgTypes, TVars),
|
|
list.delete_elems(TVars, ExistQVars, HeadTypeParams),
|
|
% argument ClassProofs
|
|
% argument ClassConstraintMap
|
|
UnprovenBodyConstraints = [],
|
|
InstGraphInfo = inst_graph_info_init,
|
|
ArgModesMaps = [],
|
|
% argument VarNameRemap
|
|
set.init(Assertions),
|
|
ObsoleteInFavourOf = maybe.no,
|
|
FormatCall = maybe.no,
|
|
InstanceMethodArgTypes = [],
|
|
PredSubInfo = pred_sub_info(Context, CurUserDecl, GoalType,
|
|
Kinds, ExistQVarBindings, PolymorphismAddedArgs, HeadTypeParams,
|
|
ClassProofs, ClassConstraintMap,
|
|
UnprovenBodyConstraints, InstGraphInfo, ArgModesMaps,
|
|
VarNameRemap, Assertions, ObsoleteInFavourOf, FormatCall,
|
|
InstanceMethodArgTypes),
|
|
|
|
% argument PredModuleName
|
|
% argument PredName
|
|
% NOTE We cannot assert anything about the relationship
|
|
% between PredFormArity and the number of arguments in ArgTypes, because
|
|
%
|
|
% - ArgTypes may be have more arguments than PredFormArity,
|
|
% due to the type_info/typeclass_info arguments added by the
|
|
% polymorphism pass, and
|
|
%
|
|
% - ArgTypes have have fewer arguments than PredFormArity,
|
|
% because some arguments may have been removed by the unused_args pass.
|
|
%
|
|
% XXX ARGVEC Eventually, when we start using arg vectors, the arguments
|
|
% added by the polymorphism pass would be counted separately.
|
|
%
|
|
% XXX ARITY The unused_args pass *should* decrement PredFormArity
|
|
% by the number of arguments it eliminates, but at the moment, it does not.
|
|
%
|
|
% argument PredOrFunc
|
|
% argument Origin
|
|
% argument Status
|
|
% argument Markers
|
|
% argument ArgTypes
|
|
% argument TypeVarSet
|
|
% argument ExistQVars
|
|
% argument ClassContext
|
|
% argument ClausesInfo
|
|
map.init(ProcTable),
|
|
PredInfo = pred_info(PredModuleName, PredOrFunc, PredName, PredFormArity,
|
|
Origin, Status, Markers, ArgTypes, TypeVarSet, TypeVarSet,
|
|
ExistQVars, ClassContext, ClausesInfo, ProcTable, PredSubInfo).
|
|
|
|
pred_info_create(PredOrFunc, PredModuleName, PredName,
|
|
Context, Origin, Status, Markers, ArgTypes, TypeVarSet,
|
|
ExistQVars, ClassContext, Assertions, VarNameRemap, GoalType,
|
|
ProcInfo, ProcId, PredInfo) :-
|
|
% argument Context
|
|
CurUserDecl = maybe.no,
|
|
% argument GoalType
|
|
map.init(Kinds),
|
|
% XXX kind inference:
|
|
% we assume all tvars have kind `star'.
|
|
map.init(ExistQVarBindings),
|
|
PolymorphismAddedArgs = 0,
|
|
type_vars_in_types(ArgTypes, TVars),
|
|
list.delete_elems(TVars, ExistQVars, HeadTypeParams),
|
|
map.init(ClassProofs),
|
|
map.init(ClassConstraintMap),
|
|
UnprovenBodyConstraints = [],
|
|
InstGraphInfo = inst_graph_info_init,
|
|
ArgModesMaps = [],
|
|
% argument VarNameRemap
|
|
% argument Assertions
|
|
ObsoleteInFavourOf = maybe.no,
|
|
FormatCall = maybe.no,
|
|
InstanceMethodArgTypes = [],
|
|
|
|
PredSubInfo = pred_sub_info(Context, CurUserDecl, GoalType,
|
|
Kinds, ExistQVarBindings, PolymorphismAddedArgs, HeadTypeParams,
|
|
ClassProofs, ClassConstraintMap,
|
|
UnprovenBodyConstraints, InstGraphInfo, ArgModesMaps,
|
|
VarNameRemap, Assertions, ObsoleteInFavourOf, FormatCall,
|
|
InstanceMethodArgTypes),
|
|
|
|
% The VarSet and ExplicitVarTypes fields are not needed after typechecking.
|
|
varset.init(VarSet),
|
|
init_vartypes(ExplicitVarTypes),
|
|
proc_info_get_var_table(ProcInfo, VarTable),
|
|
map.init(TVarNameMap),
|
|
proc_info_get_headvars(ProcInfo, HeadVars),
|
|
HeadVarVec = proc_arg_vector_init(PredOrFunc, HeadVars),
|
|
% The empty list of clauses is a little white lie.
|
|
ClausesRep = init_clauses_rep,
|
|
ItemNumbers = init_clause_item_numbers_user,
|
|
proc_info_get_rtti_varmaps(ProcInfo, RttiVarMaps),
|
|
ClausesInfo = clauses_info(VarSet, ExplicitVarTypes, VarTable, RttiVarMaps,
|
|
TVarNameMap, HeadVarVec, ClausesRep, ItemNumbers,
|
|
no_foreign_lang_clauses, no_clause_syntax_errors),
|
|
|
|
% argument PredModuleName
|
|
% argument PredName
|
|
list.length(ArgTypes, NumArgs),
|
|
PredFormArity = pred_form_arity(NumArgs),
|
|
% argument PredOrFunc
|
|
% argument Origin
|
|
% argument Status
|
|
% argument Markers
|
|
% argument ArgTypes
|
|
% argument TypeVarSet
|
|
% argument ExistQVars
|
|
% argument ClassContext
|
|
map.init(ProcTable0),
|
|
next_proc_id(ProcTable0, ProcId),
|
|
map.det_insert(ProcId, ProcInfo, ProcTable0, ProcTable),
|
|
PredInfo = pred_info(PredModuleName, PredOrFunc, PredName, PredFormArity,
|
|
Origin, Status, Markers, ArgTypes, TypeVarSet, TypeVarSet,
|
|
ExistQVars, ClassContext, ClausesInfo, ProcTable, PredSubInfo).
|
|
|
|
pred_prepare_to_clone(PredInfo, ModuleName, PredOrFunc, PredName,
|
|
PredFormArity, Origin, Status, Markers, ArgTypes,
|
|
DeclTypeVarSet, TypeVarSet, ExistQVars, PolymorphismAddedArgs,
|
|
ClassContext, ClausesInfo, ProcTable, Context,
|
|
CurUserDecl, GoalType, Kinds, ExistQVarBindings, HeadTypeParams,
|
|
ClassProofs, ClassConstraintMap, UnprovenBodyConstraints,
|
|
InstGraphInfo, ArgModesMaps, VarNameRemap, Assertions,
|
|
ObsoleteInFavourOf, FormatCall, InstanceMethodArgTypes) :-
|
|
PredInfo = pred_info(ModuleName, PredOrFunc, PredName, PredFormArity,
|
|
Origin, Status, Markers, ArgTypes, DeclTypeVarSet, TypeVarSet,
|
|
ExistQVars, ClassContext, ClausesInfo, ProcTable, PredSubInfo),
|
|
PredSubInfo = pred_sub_info(Context, CurUserDecl, GoalType,
|
|
Kinds, ExistQVarBindings, PolymorphismAddedArgs, HeadTypeParams,
|
|
ClassProofs, ClassConstraintMap,
|
|
UnprovenBodyConstraints, InstGraphInfo, ArgModesMaps,
|
|
VarNameRemap, Assertions, ObsoleteInFavourOf, FormatCall,
|
|
InstanceMethodArgTypes).
|
|
|
|
pred_create(ModuleName, PredOrFunc, PredName, PredFormArity,
|
|
Origin, Status, Markers, ArgTypes, DeclTypeVarSet, TypeVarSet,
|
|
ExistQVars, PolymorphismAddedArgs,
|
|
ClassContext, ClausesInfo, ProcTable, Context,
|
|
CurUserDecl, GoalType, Kinds, ExistQVarBindings, HeadTypeParams,
|
|
ClassProofs, ClassConstraintMap, UnprovenBodyConstraints,
|
|
InstGraphInfo, ArgModesMaps, VarNameRemap, Assertions,
|
|
ObsoleteInFavourOf, FormatCall, InstanceMethodArgTypes, PredInfo) :-
|
|
PredSubInfo = pred_sub_info(Context, CurUserDecl, GoalType,
|
|
Kinds, ExistQVarBindings, PolymorphismAddedArgs, HeadTypeParams,
|
|
ClassProofs, ClassConstraintMap,
|
|
UnprovenBodyConstraints, InstGraphInfo, ArgModesMaps,
|
|
VarNameRemap, Assertions, ObsoleteInFavourOf, FormatCall,
|
|
InstanceMethodArgTypes),
|
|
PredInfo = pred_info(ModuleName, PredOrFunc, PredName, PredFormArity,
|
|
Origin, Status, Markers, ArgTypes, DeclTypeVarSet, TypeVarSet,
|
|
ExistQVars, ClassContext, ClausesInfo, ProcTable, PredSubInfo).
|
|
|
|
define_new_pred(PredSymName, Origin, TVarSet, InstVarSet,
|
|
VarTable0, RttiVarMaps, ClassContext, InstMap0, VarNameRemap,
|
|
Markers, IsAddressTaken, HasParallelConj, PredProcId,
|
|
ArgVars0, ExtraTiTcis, Goal0, CallGoal, !ModuleInfo) :-
|
|
Goal0 = hlds_goal(_GoalExpr, GoalInfo),
|
|
InstMapDelta = goal_info_get_instmap_delta(GoalInfo),
|
|
apply_instmap_delta(InstMapDelta, InstMap0, InstMap),
|
|
|
|
% XXX The set of existentially quantified type variables
|
|
% here might not be correct.
|
|
ExistQVars = [],
|
|
|
|
% If interface typeinfo liveness is set, all type_infos for the
|
|
% arguments need to be passed in, not just the ones that are used.
|
|
% Similarly if the address of a procedure of this predicate is taken,
|
|
% so that we can copy the closure.
|
|
module_info_get_globals(!.ModuleInfo, Globals),
|
|
PredStatus = pred_status(status_local),
|
|
non_special_interface_should_use_typeinfo_liveness(PredStatus,
|
|
IsAddressTaken, Globals, TypeInfoLiveness),
|
|
(
|
|
TypeInfoLiveness = yes,
|
|
NonLocals = goal_info_get_nonlocals(GoalInfo),
|
|
goal_util.extra_nonlocal_typeinfos_typeclass_infos(RttiVarMaps,
|
|
VarTable0, ExistQVars, NonLocals, ExtraTiTcis0),
|
|
set_of_var.delete_list(ArgVars0, ExtraTiTcis0, ExtraTiTcis1),
|
|
set_of_var.to_sorted_list(ExtraTiTcis1, ExtraTiTcis),
|
|
ArgVars = ExtraTiTcis ++ ArgVars0
|
|
;
|
|
TypeInfoLiveness = no,
|
|
ArgVars = ArgVars0,
|
|
ExtraTiTcis = []
|
|
),
|
|
|
|
Context = goal_info_get_context(GoalInfo),
|
|
ItemNumber = item_no_seq_num,
|
|
Detism = goal_info_get_determinism(GoalInfo),
|
|
compute_arg_types_modes(VarTable0, InstMap0, InstMap,
|
|
ArgVars, ArgTypes, ArgModes),
|
|
|
|
(
|
|
PredSymName = qualified(PredModuleName, PredName)
|
|
;
|
|
PredSymName = unqualified(PredName),
|
|
module_info_get_name(!.ModuleInfo, ModuleName),
|
|
PredModuleName = ModuleName
|
|
),
|
|
|
|
% Remove unneeded variables from the var_table.
|
|
vars_in_goal(Goal0, GoalVars0),
|
|
set_of_var.insert_list(ArgVars, GoalVars0, GoalVars),
|
|
GoalVarsSet = set_of_var.bitset_to_set(GoalVars),
|
|
var_table_select(GoalVarsSet, VarTable0, VarTable),
|
|
|
|
% Approximate the termination information for the new procedure.
|
|
( if goal_cannot_loop_term_info(!.ModuleInfo, Goal0) then
|
|
TermInfo = yes(cannot_loop(unit))
|
|
else
|
|
TermInfo = no
|
|
),
|
|
|
|
MaybeDeclaredDetism = no,
|
|
proc_info_create_with_declared_detism(Context, ItemNumber,
|
|
VarTable, ArgVars, InstVarSet, ArgModes,
|
|
detism_decl_none, MaybeDeclaredDetism, Detism, Goal0,
|
|
RttiVarMaps, IsAddressTaken, HasParallelConj, VarNameRemap, ProcInfo0),
|
|
proc_info_set_maybe_termination_info(TermInfo, ProcInfo0, ProcInfo),
|
|
|
|
set.init(Assertions),
|
|
GoalType = goal_not_for_promise(np_goal_type_none),
|
|
pred_info_create(pf_predicate, PredModuleName, PredName,
|
|
Context, Origin, PredStatus, Markers, ArgTypes, TVarSet, ExistQVars,
|
|
ClassContext, Assertions, VarNameRemap, GoalType, ProcInfo,
|
|
ProcId, PredInfo),
|
|
|
|
module_info_get_predicate_table(!.ModuleInfo, PredTable0),
|
|
predicate_table_insert(PredInfo, PredId, PredTable0, PredTable),
|
|
module_info_set_predicate_table(PredTable, !ModuleInfo),
|
|
|
|
CallGoalExpr =
|
|
plain_call(PredId, ProcId, ArgVars, not_builtin, no, PredSymName),
|
|
CallGoal = hlds_goal(CallGoalExpr, GoalInfo),
|
|
PredProcId = proc(PredId, ProcId).
|
|
|
|
:- pred compute_arg_types_modes(var_table::in, instmap::in, instmap::in,
|
|
list(prog_var)::in, list(mer_type)::out, list(mer_mode)::out) is det.
|
|
|
|
compute_arg_types_modes(_, _, _, [], [], []).
|
|
compute_arg_types_modes(VarTable, InstMapInit, InstMapFinal,
|
|
[Var | Vars], [Type | Types], [Mode | Modes]) :-
|
|
lookup_var_type(VarTable, Var, Type),
|
|
instmap_lookup_var(InstMapInit, Var, InstInit),
|
|
instmap_lookup_var(InstMapFinal, Var, InstFinal),
|
|
Mode = from_to_mode(InstInit, InstFinal),
|
|
compute_arg_types_modes(VarTable, InstMapInit, InstMapFinal,
|
|
Vars, Types, Modes).
|
|
|
|
add_new_proc(ModuleInfo, Context, SeqNum, InstVarSet, ArgModes,
|
|
MaybeDeclaredArgModes, MaybeArgLives, DetismDecl, MaybeDetism,
|
|
IsAddressTaken, HasParallelConj, !PredInfo, ProcId) :-
|
|
pred_info_get_arg_types(!.PredInfo, ArgTypes),
|
|
pred_info_get_var_name_remap(!.PredInfo, VarNameRemap),
|
|
proc_info_init(ModuleInfo, Context, SeqNum, ArgTypes,
|
|
MaybeDeclaredArgModes, ArgModes, MaybeArgLives,
|
|
DetismDecl, MaybeDetism, IsAddressTaken, HasParallelConj,
|
|
VarNameRemap, ProcInfo0),
|
|
proc_info_set_inst_varset(InstVarSet, ProcInfo0, ProcInfo),
|
|
|
|
pred_info_get_proc_table(!.PredInfo, ProcTable0),
|
|
next_proc_id(ProcTable0, ProcId),
|
|
map.det_insert(ProcId, ProcInfo, ProcTable0, ProcTable),
|
|
pred_info_set_proc_table(ProcTable, !PredInfo).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% The trivial access predicates.
|
|
|
|
pred_info_module(PI) = X :-
|
|
pred_info_get_module_name(PI, X).
|
|
pred_info_name(PI) = X :-
|
|
pred_info_get_name(PI, X).
|
|
pred_info_is_pred_or_func(PI) = X :-
|
|
pred_info_get_is_pred_or_func(PI, X).
|
|
pred_info_pred_form_arity(PI) = PredFormArity :-
|
|
pred_info_get_orig_arity(PI, PredFormArity).
|
|
pred_info_user_arity(PI) = UserArity :-
|
|
pred_info_get_is_pred_or_func(PI, PredOrFunc),
|
|
pred_info_get_orig_arity(PI, PredFormArity),
|
|
user_arity_pred_form_arity(PredOrFunc, UserArity, PredFormArity).
|
|
|
|
pred_info_get_module_name(PI, X) :-
|
|
X = PI ^ pi_module_name.
|
|
pred_info_get_is_pred_or_func(PI, X) :-
|
|
X = PI ^ pi_is_pred_or_func.
|
|
pred_info_get_name(PI, X) :-
|
|
X = PI ^ pi_name.
|
|
pred_info_get_orig_arity(PI, X) :-
|
|
X = PI ^ pi_orig_arity.
|
|
|
|
pred_info_get_context(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_context.
|
|
pred_info_get_cur_user_decl_info(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_cur_user_decl.
|
|
pred_info_get_origin(PI, X) :-
|
|
X = PI ^ pi_pred_origin.
|
|
pred_info_get_status(PI, X) :-
|
|
X = PI ^ pi_status.
|
|
pred_info_get_goal_type(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_goal_type.
|
|
pred_info_get_markers(PI, X) :-
|
|
X = PI ^ pi_markers.
|
|
pred_info_get_arg_types(PI, X) :-
|
|
X = PI ^ pi_arg_types.
|
|
pred_info_get_typevarset(PI, X) :-
|
|
X = PI ^ pi_typevarset.
|
|
pred_info_get_tvar_kind_map(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_tvar_kind_map.
|
|
pred_info_get_exist_quant_tvars(PI, X) :-
|
|
X = PI ^ pi_exist_quant_tvars.
|
|
pred_info_get_existq_tvar_binding(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_existq_tvar_binding.
|
|
pred_info_get_polymorphism_added_args(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_polymorphism_added_args.
|
|
pred_info_get_external_type_params(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_external_type_params.
|
|
pred_info_get_class_context(PI, X) :-
|
|
X = PI ^ pi_class_context.
|
|
pred_info_get_constraint_proof_map(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_constraint_proof_map.
|
|
pred_info_get_constraint_map(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_constraint_map.
|
|
pred_info_get_unproven_body_constraints(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_unproven_body_constraints.
|
|
pred_info_get_inst_graph_info(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_inst_graph_info.
|
|
pred_info_get_arg_modes_maps(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_arg_modes_maps.
|
|
pred_info_get_var_name_remap(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_var_name_remap.
|
|
pred_info_get_assertions(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_assertions.
|
|
pred_info_get_obsolete_in_favour_of(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_obsolete_in_favour_of.
|
|
pred_info_get_format_call_info(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_format_call_info.
|
|
pred_info_get_instance_method_arg_types(PI, X) :-
|
|
X = PI ^ pi_pred_sub_info ^ psi_instance_method_arg_types.
|
|
pred_info_get_clauses_info(PI, X) :-
|
|
X = PI ^ pi_clauses_info.
|
|
pred_info_get_proc_table(PI, X) :-
|
|
X = PI ^ pi_proc_table.
|
|
|
|
pred_info_set_module_name(X, !PI) :-
|
|
!PI ^ pi_module_name := X.
|
|
pred_info_set_is_pred_or_func(X, !PI) :-
|
|
( if X = !.PI ^ pi_is_pred_or_func then
|
|
true
|
|
else
|
|
!PI ^ pi_is_pred_or_func := X
|
|
).
|
|
pred_info_set_name(X, !PI) :-
|
|
!PI ^ pi_name := X.
|
|
pred_info_set_orig_arity(X, !PI) :-
|
|
!PI ^ pi_orig_arity := X.
|
|
pred_info_set_origin(X, !PI) :-
|
|
( if private_builtin.pointer_equal(X, !.PI ^ pi_pred_origin) then
|
|
true
|
|
else
|
|
!PI ^ pi_pred_origin := X
|
|
).
|
|
pred_info_set_status(X, !PI) :-
|
|
!PI ^ pi_status := X.
|
|
pred_info_set_goal_type(X, !PI) :-
|
|
!PI ^ pi_pred_sub_info ^ psi_goal_type := X.
|
|
pred_info_set_markers(X, !PI) :-
|
|
!PI ^ pi_markers := X.
|
|
pred_info_set_typevarset(X, !PI) :-
|
|
( if private_builtin.pointer_equal(X, !.PI ^ pi_typevarset) then
|
|
true
|
|
else
|
|
!PI ^ pi_typevarset := X
|
|
).
|
|
pred_info_set_tvar_kind_map(X, !PI) :-
|
|
( if
|
|
private_builtin.pointer_equal(X,
|
|
!.PI ^ pi_pred_sub_info ^ psi_tvar_kind_map)
|
|
then
|
|
true
|
|
else
|
|
!PI ^ pi_pred_sub_info ^ psi_tvar_kind_map:= X
|
|
).
|
|
pred_info_set_existq_tvar_binding(X, !PI) :-
|
|
!PI ^ pi_pred_sub_info ^ psi_existq_tvar_binding := X.
|
|
pred_info_set_polymorphism_added_args(X, !PI) :-
|
|
!PI ^ pi_pred_sub_info ^ psi_polymorphism_added_args := X.
|
|
pred_info_set_external_type_params(X, !PI) :-
|
|
( if
|
|
private_builtin.pointer_equal(X,
|
|
!.PI ^ pi_pred_sub_info ^ psi_external_type_params)
|
|
then
|
|
true
|
|
else
|
|
!PI ^ pi_pred_sub_info ^ psi_external_type_params := X
|
|
).
|
|
pred_info_set_class_context(X, !PI) :-
|
|
!PI ^ pi_class_context := X.
|
|
pred_info_set_constraint_proof_map(X, !PI) :-
|
|
( if
|
|
private_builtin.pointer_equal(X,
|
|
!.PI ^ pi_pred_sub_info ^ psi_constraint_proof_map)
|
|
then
|
|
true
|
|
else
|
|
!PI ^ pi_pred_sub_info ^ psi_constraint_proof_map := X
|
|
).
|
|
pred_info_set_constraint_map(X, !PI) :-
|
|
( if
|
|
private_builtin.pointer_equal(X,
|
|
!.PI ^ pi_pred_sub_info ^ psi_constraint_map)
|
|
then
|
|
true
|
|
else
|
|
!PI ^ pi_pred_sub_info ^ psi_constraint_map := X
|
|
).
|
|
pred_info_set_unproven_body_constraints(X, !PI) :-
|
|
( if
|
|
private_builtin.pointer_equal(X,
|
|
!.PI ^ pi_pred_sub_info ^ psi_unproven_body_constraints)
|
|
then
|
|
true
|
|
else
|
|
!PI ^ pi_pred_sub_info ^ psi_unproven_body_constraints := X
|
|
).
|
|
pred_info_set_inst_graph_info(X, !PI) :-
|
|
!PI ^ pi_pred_sub_info ^ psi_inst_graph_info := X.
|
|
pred_info_set_arg_modes_maps(X, !PI) :-
|
|
!PI ^ pi_pred_sub_info ^ psi_arg_modes_maps := X.
|
|
pred_info_set_var_name_remap(X, !PI) :-
|
|
( if
|
|
private_builtin.pointer_equal(X,
|
|
!.PI ^ pi_pred_sub_info ^ psi_var_name_remap)
|
|
then
|
|
true
|
|
else
|
|
!PI ^ pi_pred_sub_info ^ psi_var_name_remap := X
|
|
).
|
|
pred_info_set_assertions(X, !PI) :-
|
|
!PI ^ pi_pred_sub_info ^ psi_assertions := X.
|
|
pred_info_set_obsolete_in_favour_of(X, !PI) :-
|
|
!PI ^ pi_pred_sub_info ^ psi_obsolete_in_favour_of := X.
|
|
pred_info_set_format_call_info(X, !PI) :-
|
|
!PI ^ pi_pred_sub_info ^ psi_format_call_info := X.
|
|
pred_info_set_instance_method_arg_types(X, !PI) :-
|
|
!PI ^ pi_pred_sub_info ^ psi_instance_method_arg_types := X.
|
|
pred_info_set_clauses_info(X, !PI) :-
|
|
!PI ^ pi_clauses_info := X.
|
|
pred_info_set_proc_table(X, !PI) :-
|
|
!PI ^ pi_proc_table := X.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% The non-trivial access predicates.
|
|
|
|
pred_info_all_procids(PredInfo) = ProcIds :-
|
|
pred_info_get_proc_table(PredInfo, ProcTable),
|
|
map.keys(ProcTable, ProcIds).
|
|
|
|
pred_info_all_non_imported_procids(PredInfo) = ProcIds :-
|
|
pred_info_get_status(PredInfo, pred_status(OldImportStatus)),
|
|
(
|
|
( OldImportStatus = status_imported(_)
|
|
; OldImportStatus = status_external(_)
|
|
),
|
|
ProcIds = []
|
|
;
|
|
OldImportStatus = status_pseudo_imported,
|
|
ProcIds0 = pred_info_all_procids(PredInfo),
|
|
% For pseudo_imported preds, procid 0 is imported
|
|
list.delete_all(ProcIds0, 0, ProcIds)
|
|
;
|
|
( OldImportStatus = status_opt_imported
|
|
; OldImportStatus = status_abstract_imported
|
|
; OldImportStatus = status_exported
|
|
; OldImportStatus = status_opt_exported
|
|
; OldImportStatus = status_abstract_exported
|
|
; OldImportStatus = status_pseudo_exported
|
|
; OldImportStatus = status_exported_to_submodules
|
|
; OldImportStatus = status_local
|
|
),
|
|
ProcIds = pred_info_all_procids(PredInfo)
|
|
).
|
|
|
|
pred_info_all_exported_procids(PredInfo) = ProcIds :-
|
|
pred_info_get_status(PredInfo, pred_status(OldImportStatus)),
|
|
(
|
|
( OldImportStatus = status_exported
|
|
; OldImportStatus = status_opt_exported
|
|
; OldImportStatus = status_exported_to_submodules
|
|
),
|
|
ProcIds = pred_info_all_procids(PredInfo)
|
|
;
|
|
OldImportStatus = status_pseudo_exported,
|
|
ProcIds = [0]
|
|
;
|
|
( OldImportStatus = status_imported(_)
|
|
; OldImportStatus = status_opt_imported
|
|
; OldImportStatus = status_abstract_imported
|
|
; OldImportStatus = status_pseudo_imported
|
|
; OldImportStatus = status_abstract_exported
|
|
; OldImportStatus = status_local
|
|
; OldImportStatus = status_external(_)
|
|
),
|
|
ProcIds = []
|
|
).
|
|
|
|
pred_info_remove_procid(ProcId, !PredInfo) :-
|
|
pred_info_get_proc_table(!.PredInfo, Procs0),
|
|
map.delete(ProcId, Procs0, Procs),
|
|
pred_info_set_proc_table(Procs, !PredInfo).
|
|
|
|
pred_info_get_arg_types(PredInfo, X, Y, Z) :-
|
|
X = PredInfo ^ pi_decl_typevarset,
|
|
Y = PredInfo ^ pi_exist_quant_tvars,
|
|
Z = PredInfo ^ pi_arg_types.
|
|
|
|
pred_info_set_arg_types(X, Y, Z, !PredInfo) :-
|
|
!PredInfo ^ pi_decl_typevarset := X,
|
|
!PredInfo ^ pi_exist_quant_tvars := Y,
|
|
!PredInfo ^ pi_arg_types := Z.
|
|
|
|
pred_info_get_univ_quant_tvars(PredInfo, UnivQVars) :-
|
|
pred_info_get_arg_types(PredInfo, ArgTypes),
|
|
type_vars_in_types(ArgTypes, ArgTypeVars0),
|
|
list.sort_and_remove_dups(ArgTypeVars0, ArgTypeVars),
|
|
pred_info_get_exist_quant_tvars(PredInfo, ExistQVars),
|
|
list.delete_elems(ArgTypeVars, ExistQVars, UnivQVars).
|
|
|
|
pred_info_proc_info(PredInfo, ProcId, ProcInfo) :-
|
|
pred_info_get_proc_table(PredInfo, ProcTable),
|
|
map.lookup(ProcTable, ProcId, ProcInfo).
|
|
|
|
pred_info_set_proc_info(ProcId, ProcInfo, !PredInfo) :-
|
|
pred_info_get_proc_table(!.PredInfo, ProcTable0),
|
|
map.det_update(ProcId, ProcInfo, ProcTable0, ProcTable),
|
|
pred_info_set_proc_table(ProcTable, !PredInfo).
|
|
|
|
pred_info_is_imported(PredInfo) :-
|
|
pred_info_get_status(PredInfo, PredStatus),
|
|
( PredStatus = pred_status(status_imported(_))
|
|
; PredStatus = pred_status(status_external(_))
|
|
).
|
|
|
|
pred_info_is_imported_not_external(PredInfo) :-
|
|
pred_info_get_status(PredInfo, PredStatus),
|
|
PredStatus = pred_status(status_imported(_)).
|
|
|
|
pred_info_is_pseudo_imported(PredInfo) :-
|
|
pred_info_get_status(PredInfo, PredStatus),
|
|
PredStatus = pred_status(status_pseudo_imported).
|
|
|
|
pred_info_is_exported(PredInfo) :-
|
|
pred_info_get_status(PredInfo, PredStatus),
|
|
PredStatus = pred_status(status_exported).
|
|
|
|
pred_info_is_opt_exported(PredInfo) :-
|
|
pred_info_get_status(PredInfo, PredStatus),
|
|
PredStatus = pred_status(status_opt_exported).
|
|
|
|
pred_info_is_exported_to_submodules(PredInfo) :-
|
|
pred_info_get_status(PredInfo, PredStatus),
|
|
PredStatus = pred_status(status_exported_to_submodules).
|
|
|
|
pred_info_is_pseudo_exported(PredInfo) :-
|
|
pred_info_get_status(PredInfo, PredStatus),
|
|
PredStatus = pred_status(status_pseudo_exported).
|
|
|
|
procedure_is_exported(ModuleInfo, PredInfo, ProcId) :-
|
|
% XXX STATUS
|
|
(
|
|
pred_info_is_exported(PredInfo)
|
|
;
|
|
pred_info_is_opt_exported(PredInfo)
|
|
;
|
|
pred_info_is_exported_to_submodules(PredInfo)
|
|
;
|
|
pred_info_is_pseudo_exported(PredInfo),
|
|
in_in_unification_proc_id(ProcId)
|
|
;
|
|
pred_info_get_status(PredInfo, PredStatus),
|
|
PredStatus = pred_status(status_external(ExternalImportStatus)),
|
|
pred_status_is_exported(pred_status(ExternalImportStatus)) = yes
|
|
;
|
|
pred_info_get_origin(PredInfo, Origin),
|
|
Origin = origin_compiler(made_for_uci(SpecialPredId, TypeCtor)),
|
|
module_info_get_type_table(ModuleInfo, TypeTable),
|
|
% If the search fails, then TypeCtor must be a builtin type
|
|
% constructor, such as the tuple constructor.
|
|
search_type_ctor_defn(TypeTable, TypeCtor, TypeDefn),
|
|
get_type_defn_in_exported_eqv(TypeDefn, yes),
|
|
require_complete_switch [SpecialPredId]
|
|
(
|
|
SpecialPredId = spec_pred_unify,
|
|
% The other proc_ids are module-specific.
|
|
in_in_unification_proc_id(ProcId)
|
|
;
|
|
SpecialPredId = spec_pred_compare
|
|
% The declared modes are all global, and we don't
|
|
% generate any modes for compare preds dynamically.
|
|
;
|
|
SpecialPredId = spec_pred_index,
|
|
% The index predicate is never called from anywhere
|
|
% except the compare predicate.
|
|
fail
|
|
)
|
|
).
|
|
|
|
pred_info_mark_as_external(!PredInfo) :-
|
|
pred_info_get_status(!.PredInfo, PredStatus0),
|
|
PredStatus0 = pred_status(OldImportStatus0),
|
|
PredStatus = pred_status(status_external(OldImportStatus0)),
|
|
pred_info_set_status(PredStatus, !PredInfo).
|
|
|
|
pred_info_defn_has_clause(PredInfo) :-
|
|
pred_info_get_goal_type(PredInfo, GoalType),
|
|
GoalType = goal_not_for_promise(NPGoalType),
|
|
goal_type_has_clause(NPGoalType).
|
|
|
|
pred_info_defn_has_foreign_proc(PredInfo) :-
|
|
pred_info_get_goal_type(PredInfo, GoalType),
|
|
GoalType = goal_not_for_promise(NPGoalType),
|
|
goal_type_has_foreign_proc(NPGoalType).
|
|
|
|
:- pred goal_type_has_clause(np_goal_type::in) is semidet.
|
|
|
|
goal_type_has_clause(np_goal_type_clause).
|
|
goal_type_has_clause(np_goal_type_clause_and_foreign).
|
|
|
|
:- pred goal_type_has_foreign_proc(np_goal_type::in) is semidet.
|
|
|
|
goal_type_has_foreign_proc(np_goal_type_foreign).
|
|
goal_type_has_foreign_proc(np_goal_type_clause_and_foreign).
|
|
|
|
pred_info_update_goal_type(NPGoalType1, !PredInfo) :-
|
|
pred_info_get_goal_type(!.PredInfo, GoalType0),
|
|
(
|
|
GoalType0 = goal_not_for_promise(NPGoalType0),
|
|
(
|
|
NPGoalType0 = np_goal_type_none,
|
|
NPGoalType = NPGoalType1
|
|
;
|
|
NPGoalType0 = np_goal_type_clause,
|
|
( if goal_type_has_foreign_proc(NPGoalType1) then
|
|
NPGoalType = np_goal_type_clause_and_foreign
|
|
else
|
|
NPGoalType = np_goal_type_clause
|
|
)
|
|
;
|
|
NPGoalType0 = np_goal_type_foreign,
|
|
( if goal_type_has_clause(NPGoalType1) then
|
|
NPGoalType = np_goal_type_clause_and_foreign
|
|
else
|
|
NPGoalType = np_goal_type_foreign
|
|
)
|
|
;
|
|
NPGoalType0 = np_goal_type_clause_and_foreign,
|
|
NPGoalType = NPGoalType0
|
|
),
|
|
GoalType = goal_not_for_promise(NPGoalType),
|
|
( if GoalType = GoalType0 then
|
|
% Avoid unnecessary memory allocation.
|
|
true
|
|
else
|
|
pred_info_set_goal_type(GoalType, !PredInfo)
|
|
)
|
|
;
|
|
GoalType0 = goal_for_promise(_),
|
|
unexpected($pred, "promise")
|
|
).
|
|
|
|
pred_info_requested_inlining(PredInfo0) :-
|
|
pred_info_get_markers(PredInfo0, Markers),
|
|
( marker_is_present(Markers, marker_user_marked_inline)
|
|
; marker_is_present(Markers, marker_heuristic_inline)
|
|
).
|
|
|
|
pred_info_requested_no_inlining(PredInfo0) :-
|
|
pred_info_get_markers(PredInfo0, Markers),
|
|
( marker_is_present(Markers, marker_user_marked_no_inline)
|
|
; marker_is_present(Markers, marker_mmc_marked_no_inline)
|
|
).
|
|
|
|
pred_info_get_purity(PredInfo0, Purity) :-
|
|
pred_info_get_markers(PredInfo0, Markers),
|
|
( if marker_is_present(Markers, marker_is_impure) then
|
|
Purity = purity_impure
|
|
else if marker_is_present(Markers, marker_is_semipure) then
|
|
Purity = purity_semipure
|
|
else
|
|
Purity = purity_pure
|
|
).
|
|
|
|
pred_info_get_promised_purity(PredInfo0, MaybePromisedPurity) :-
|
|
pred_info_get_markers(PredInfo0, Markers),
|
|
( if marker_is_present(Markers, marker_promised_pure) then
|
|
MaybePromisedPurity = yes(purity_pure)
|
|
else if marker_is_present(Markers, marker_promised_semipure) then
|
|
MaybePromisedPurity = yes(purity_semipure)
|
|
else
|
|
MaybePromisedPurity = no
|
|
).
|
|
|
|
pred_info_infer_modes(PredInfo) :-
|
|
pred_info_get_markers(PredInfo, Markers),
|
|
marker_is_present(Markers, marker_infer_modes).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
pred_info_get_pf_sym_name_arity(PredInfo, PFSymNameArity) :-
|
|
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
|
|
pred_info_get_sym_name(PredInfo, SymName),
|
|
PredFormArity = pred_info_pred_form_arity(PredInfo),
|
|
PFSymNameArity = pf_sym_name_arity(PredOrFunc, SymName, PredFormArity).
|
|
|
|
pred_info_get_sym_name(PredInfo, SymName) :-
|
|
Module = pred_info_module(PredInfo),
|
|
Name = pred_info_name(PredInfo),
|
|
SymName = qualified(Module, Name).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Various predicates for accessing the proc_info data structure,
|
|
% and the types they work with.
|
|
|
|
:- interface.
|
|
|
|
:- type is_address_taken
|
|
---> address_is_taken
|
|
; address_is_not_taken.
|
|
|
|
:- type deep_profile_role
|
|
---> deep_prof_inner_proc(
|
|
dpip_outer_proc :: pred_proc_id
|
|
)
|
|
; deep_prof_outer_proc(
|
|
dpop_inner_proc :: pred_proc_id
|
|
).
|
|
|
|
:- type deep_recursion_info
|
|
---> deep_recursion_info(
|
|
dri_role :: deep_profile_role,
|
|
|
|
% If the procedure is not tail recursive, this list is empty.
|
|
% Otherwise, it contains outer-inner pairs of procedures
|
|
% in the visible SCC, including this procedure and its copy.
|
|
dri_visible_scc :: list(visible_scc_data)
|
|
).
|
|
|
|
:- type visible_scc_data
|
|
---> visible_scc_data(
|
|
vis_outer_proc :: pred_proc_id,
|
|
vis_inner_proc :: pred_proc_id,
|
|
|
|
% A list of all the call site numbers that correspond to
|
|
% tail calls. (Call sites are numbered depth-first,
|
|
% left-to-right, starting from zero.)
|
|
rec_call_sites :: list(int)
|
|
).
|
|
|
|
:- type call_site_static_data % defines MR_CallSiteStatic
|
|
---> normal_call(
|
|
normal_callee :: rtti_proc_label,
|
|
normal_type_subst :: string,
|
|
normal_file_name :: string,
|
|
normal_line_number :: int,
|
|
normal_goal_path :: forward_goal_path
|
|
)
|
|
; special_call(
|
|
special_file_name :: string,
|
|
special_line_number :: int,
|
|
special_goal_path :: forward_goal_path
|
|
)
|
|
; higher_order_call(
|
|
higher_order_file_name :: string,
|
|
ho_line_number :: int,
|
|
ho_goal_path :: forward_goal_path
|
|
)
|
|
; method_call(
|
|
method_file_name :: string,
|
|
method_line_number :: int,
|
|
method_goal_path :: forward_goal_path
|
|
)
|
|
; callback(
|
|
callback_file_name :: string,
|
|
callback_line_number :: int,
|
|
callback_goal_path :: forward_goal_path
|
|
).
|
|
|
|
:- type hlds_proc_static
|
|
---> hlds_proc_static( % defines part of MR_ProcStatic
|
|
proc_static_file_name :: string,
|
|
proc_static_line_number :: int,
|
|
proc_is_in_interface :: bool,
|
|
call_site_statics :: list(call_site_static_data),
|
|
coverage_points :: list(coverage_point_info)
|
|
).
|
|
|
|
% The hlds_deep_excp_vars gives the variables that hold the values returned
|
|
% by the call port code, which are needed to let exception.throw perform
|
|
% the work we need to do at the excp port.
|
|
:- type hlds_deep_excp_vars
|
|
---> hlds_deep_excp_vars(
|
|
top_csd :: prog_var,
|
|
middle_csd :: prog_var,
|
|
old_outermost :: maybe(prog_var)
|
|
% Needed only with the save/restore
|
|
% approach, not the activation counting
|
|
% approach.
|
|
).
|
|
|
|
:- type hlds_deep_layout
|
|
---> hlds_deep_layout(
|
|
deep_layout_static :: hlds_proc_static,
|
|
deep_layout_excp :: hlds_deep_excp_vars
|
|
).
|
|
|
|
:- type deep_profile_proc_info
|
|
---> deep_profile_proc_info(
|
|
% This field is set during the first part of the deep profiling
|
|
% transformation; tail recursion, if that is enabled.
|
|
deep_rec :: maybe(deep_recursion_info),
|
|
|
|
% This field is set during the second part; it will be bound
|
|
% to `no' before and during the first part, and to `yes'
|
|
% after the second. The contents of this field govern
|
|
% what will go into MR_ProcStatic structures.
|
|
deep_layout :: maybe(hlds_deep_layout),
|
|
|
|
% This field stores the original body of a procedure,
|
|
% before either part of the deep profiling transformation
|
|
% was executed. For inner procedures created by the tail
|
|
% recursion part of the deep profiling transformation,
|
|
% it holds the original body of the outer procedure.
|
|
deep_orig_body :: deep_original_body
|
|
).
|
|
|
|
:- type deep_original_body
|
|
---> deep_original_body(
|
|
dob_body :: hlds_goal,
|
|
dob_head_vars :: list(prog_var),
|
|
dob_instmap :: instmap,
|
|
dob_var_table :: var_table,
|
|
dob_detism :: determinism
|
|
).
|
|
|
|
:- type table_arg_infos
|
|
---> table_arg_infos(
|
|
list(table_arg_info),
|
|
map(tvar, table_locn)
|
|
).
|
|
|
|
:- type table_arg_info
|
|
---> table_arg_info(
|
|
orig_var_num :: int,
|
|
orig_var_name :: string,
|
|
slot_num :: int,
|
|
arg_type :: mer_type
|
|
).
|
|
|
|
% This type is analogous to layout_locn in llds.m, but it refers
|
|
% not to lvals, but to slots in the extended answer blocks used by
|
|
% I/O action tabling for declarative debugging.
|
|
:- type table_locn
|
|
---> table_locn_direct(int)
|
|
; table_locn_indirect(int, int).
|
|
|
|
% This type differs from the type table_step_kind in table_statistics.m
|
|
% in the library in that
|
|
% (a) in gives more information about the type of the corresponding
|
|
% argument (if this info is needed and available),
|
|
% (b) it doesn't have to be an enum, and
|
|
% (c) it doesn't have to handle dummy steps.
|
|
%
|
|
:- type table_trie_step
|
|
---> table_trie_step_dummy
|
|
; table_trie_step_int(int_type)
|
|
; table_trie_step_char
|
|
; table_trie_step_string
|
|
; table_trie_step_float
|
|
; table_trie_step_enum(
|
|
% The int gives the maximum enum value in the enum type + 1,
|
|
% and thus the size of the corresponding trie node.
|
|
% If the enum type is not a subtype, then the value is equal to
|
|
% the number of alternatives in the type.
|
|
int
|
|
)
|
|
; table_trie_step_foreign_enum
|
|
; table_trie_step_general(
|
|
mer_type,
|
|
table_is_poly,
|
|
table_value_or_addr
|
|
)
|
|
; table_trie_step_typeinfo
|
|
; table_trie_step_typeclassinfo
|
|
; table_trie_step_promise_implied.
|
|
|
|
:- type table_is_poly
|
|
---> table_is_mono % The table type is monomorphic.
|
|
; table_is_poly. % The table type is polymorphic.
|
|
|
|
:- type table_value_or_addr
|
|
---> table_value % We are tabling the value itself.
|
|
; table_addr. % We are tabling only the address.
|
|
|
|
% Return a description of what kind of statistics we collect for a trie
|
|
% step of a given kind. The description is the name of a value in the C
|
|
% enum type MR_TableStepStatsKind. (We will need to generalize this
|
|
% when we implement tabling for non-C backends.)
|
|
%
|
|
:- func table_step_stats_kind(table_trie_step) = string.
|
|
|
|
:- type proc_table_io_info
|
|
---> proc_table_io_info(
|
|
% The information we need to display an I/O action to the user.
|
|
%
|
|
% The table_arg_infos correspond one to one to the elements
|
|
% of the block saved for an I/O action. The first element
|
|
% will be the pointer to the proc_layout of the action's
|
|
% procedure.
|
|
%
|
|
% The right tvarset for interpreting the types in the
|
|
% table_arg_infos is the one in the proc_info in which
|
|
% the proc_table_io_info is stored.
|
|
|
|
maybe(table_arg_infos)
|
|
).
|
|
|
|
:- type table_step_desc
|
|
---> table_step_desc(
|
|
tsd_var_name :: string,
|
|
tsd_step :: table_trie_step
|
|
).
|
|
|
|
:- type proc_table_struct_info
|
|
---> proc_table_struct_info(
|
|
% The information we need to create the data structures
|
|
% created by tabling for a procedure, and to interpret them
|
|
% for the debugger (except the information -such as
|
|
% determinism- that is already available from proc_layout
|
|
% structures.
|
|
%
|
|
% The table_arg_infos list first all the input arguments,
|
|
% then all the output arguments.
|
|
%
|
|
% The right tvarset for interpreting the types in the
|
|
% table_arg_infos is the one stored below. It is taken from
|
|
% the proc_info of the procedure whose table this structure
|
|
% describes. Since we care only about the shapes of the types,
|
|
% we don't care about neither the actual numerical values
|
|
% nor the names of the type variables, so we don't care if
|
|
% the tvarset in that proc_info changes after table_gen.m
|
|
% takes the snapshot stored here.
|
|
%
|
|
% We record the rtti_proc_label of the procedure whose table
|
|
% this is. We can't record its identity in the form of a
|
|
% pred_proc_id, since that won't work if the procedure is
|
|
% deleted before the code generation phase.
|
|
|
|
ptsi_proc_label :: rtti_proc_label,
|
|
ptsi_tvarset :: tvarset,
|
|
ptsi_context :: prog_context,
|
|
ptsi_num_inputs :: int,
|
|
ptsi_num_outputs :: int,
|
|
ptsi_input_steps :: list(table_step_desc),
|
|
ptsi_maybe_output_steps :: maybe(list(table_step_desc)),
|
|
ptsi_gen_arg_infos :: table_arg_infos,
|
|
ptsi_eval_method :: tabled_eval_method
|
|
).
|
|
|
|
:- type special_proc_return
|
|
---> generator_return(
|
|
% The generator is stored in this location. We can't use an
|
|
% rval to represent the location, since we don't want this
|
|
% module to depend on the ll_backend package.
|
|
generator_rval :: string,
|
|
|
|
% What should we pass as the value of the debug parameter
|
|
% in the call to MR_tbl_mmos_return_answer?
|
|
return_debug :: string
|
|
).
|
|
|
|
:- type structure_sharing_domain_and_status
|
|
---> structure_sharing_domain_and_status(
|
|
structure_sharing_domain,
|
|
analysis_status
|
|
).
|
|
|
|
:- type structure_reuse_domain_and_status
|
|
---> structure_reuse_domain_and_status(
|
|
structure_reuse_domain,
|
|
analysis_status
|
|
).
|
|
|
|
:- type untuple_proc_info
|
|
---> untuple_proc_info(
|
|
map(prog_var, list(prog_var))
|
|
).
|
|
|
|
:- type detism_decl
|
|
---> detism_decl_explicit
|
|
; detism_decl_implicit
|
|
; detism_decl_none.
|
|
% The determinism of the procedure is not declared.
|
|
|
|
:- pred proc_info_init(module_info::in, prog_context::in, item_seq_num::in,
|
|
list(mer_type)::in, maybe(list(mer_mode))::in, list(mer_mode)::in,
|
|
maybe(list(is_live))::in, detism_decl::in, maybe(determinism)::in,
|
|
is_address_taken::in, has_parallel_conj::in, map(prog_var, string)::in,
|
|
proc_info::out) is det.
|
|
|
|
:- pred proc_info_create(prog_context::in, item_seq_num::in,
|
|
var_table::in, list(prog_var)::in,
|
|
inst_varset::in, list(mer_mode)::in,
|
|
detism_decl::in, determinism::in, hlds_goal::in,
|
|
rtti_varmaps::in, is_address_taken::in, has_parallel_conj::in,
|
|
map(prog_var, string)::in, proc_info::out) is det.
|
|
|
|
%---------------------%
|
|
|
|
% proc_prepare_to_clone returns all the fields of an existing proc_info,
|
|
% while proc_create constructs a new proc_info putting the supplied values
|
|
% to each field.
|
|
%
|
|
% These predicates exist because we want keep the definition of the proc_info
|
|
% type private (to make future changes easier), but we also want to make it
|
|
% possible to create slightly modified copies of existing procedures
|
|
% with the least amount of programming work. We also want to require
|
|
% (a) programmers writing such cloning code to consider what effect
|
|
% the modification may have on *all* fields of the proc_info, and
|
|
% (b) programmers who add new fields to the proc_info to update
|
|
% all the places in the compiler that do such cloning.
|
|
|
|
:- pred proc_prepare_to_clone(proc_info::in, list(prog_var)::out,
|
|
hlds_goal::out, var_table::out, rtti_varmaps::out,
|
|
inst_varset::out, maybe(list(mer_mode))::out, list(mer_mode)::out,
|
|
maybe(list(is_live))::out, maybe(determinism)::out, determinism::out,
|
|
eval_method::out, prog_context::out, item_seq_num::out,
|
|
can_process::out, maybe(mode_constraint)::out, detism_decl::out,
|
|
list(prog_context)::out, maybe(untuple_proc_info)::out,
|
|
map(prog_var, string)::out, list(error_spec)::out, set(pred_proc_id)::out,
|
|
is_address_taken::out, proc_foreign_exports::out, has_parallel_conj::out,
|
|
has_user_event::out, has_tail_rec_call::out, list(oisu_pred_kind_for)::out,
|
|
maybe(require_tail_recursion)::out, set_of_progvar::out,
|
|
maybe(list(arg_info))::out, maybe(special_proc_return)::out,
|
|
liveness_info::out, stack_slots::out, needs_maxfr_slot::out,
|
|
maybe(prog_var)::out, maybe(proc_table_io_info)::out,
|
|
maybe(table_attributes)::out, maybe(list(sym_name_arity))::out,
|
|
maybe(deep_profile_proc_info)::out, maybe(arg_size_info)::out,
|
|
maybe(termination_info)::out, termination2_info::out,
|
|
maybe(proc_exception_info)::out, maybe(proc_trailing_info)::out,
|
|
maybe(proc_mm_tabling_info)::out, structure_sharing_info::out,
|
|
structure_reuse_info::out) is det.
|
|
|
|
:- pred proc_create(list(prog_var)::in,
|
|
hlds_goal::in, var_table::in, rtti_varmaps::in,
|
|
inst_varset::in, maybe(list(mer_mode))::in, list(mer_mode)::in,
|
|
maybe(list(is_live))::in, maybe(determinism)::in, determinism::in,
|
|
eval_method::in, prog_context::in, item_seq_num::in, can_process::in,
|
|
maybe(mode_constraint)::in, detism_decl::in,
|
|
list(prog_context)::in, maybe(untuple_proc_info)::in,
|
|
map(prog_var, string)::in, list(error_spec)::in, set(pred_proc_id)::in,
|
|
is_address_taken::in, proc_foreign_exports::in, has_parallel_conj::in,
|
|
has_user_event::in, has_tail_rec_call::in, list(oisu_pred_kind_for)::in,
|
|
maybe(require_tail_recursion)::in, set_of_progvar::in,
|
|
maybe(list(arg_info))::in, maybe(special_proc_return)::in,
|
|
liveness_info::in, stack_slots::in, needs_maxfr_slot::in,
|
|
maybe(prog_var)::in, maybe(proc_table_io_info)::in,
|
|
maybe(table_attributes)::in, maybe(list(sym_name_arity))::in,
|
|
maybe(deep_profile_proc_info)::in, maybe(arg_size_info)::in,
|
|
maybe(termination_info)::in, termination2_info::in,
|
|
maybe(proc_exception_info)::in, maybe(proc_trailing_info)::in,
|
|
maybe(proc_mm_tabling_info)::in, structure_sharing_info::in,
|
|
structure_reuse_info::in, proc_info::out) is det.
|
|
|
|
%---------------------%
|
|
|
|
:- pred proc_info_set_body(var_table::in,
|
|
list(prog_var)::in, hlds_goal::in, rtti_varmaps::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
|
|
:- type can_process
|
|
---> cannot_process_yet
|
|
; can_process_now.
|
|
|
|
:- type needs_maxfr_slot
|
|
---> needs_maxfr_slot
|
|
; does_not_need_maxfr_slot.
|
|
|
|
:- type has_parallel_conj
|
|
---> has_parallel_conj
|
|
; has_no_parallel_conj.
|
|
|
|
:- type has_user_event
|
|
---> has_user_event
|
|
; has_no_user_event.
|
|
|
|
:- type has_self_tail_rec_call
|
|
---> has_self_tail_rec_call
|
|
; has_no_self_tail_rec_call.
|
|
|
|
:- type has_mutual_tail_rec_call
|
|
---> has_mutual_tail_rec_call
|
|
; has_no_mutual_tail_rec_call.
|
|
|
|
:- type has_tail_rec_call
|
|
---> has_tail_rec_call(
|
|
has_self_tail_rec_call,
|
|
has_mutual_tail_rec_call
|
|
).
|
|
|
|
:- type oisu_pred_kind_for
|
|
---> oisu_creator_for(type_ctor)
|
|
; oisu_mutator_for(type_ctor)
|
|
; oisu_destructor_for(type_ctor).
|
|
|
|
% Is a procedure the subject of any foreign_export pragmas?
|
|
%
|
|
:- type proc_foreign_exports
|
|
---> no_foreign_exports
|
|
; has_foreign_exports.
|
|
|
|
% Gives an indication of whether or not the procedure
|
|
% might throw an exception.
|
|
%
|
|
:- type proc_exception_info
|
|
---> proc_exception_info(
|
|
proc_exception_status :: exception_status,
|
|
proc_maybe_excep_analysis_status :: maybe(analysis_status)
|
|
).
|
|
|
|
% Gives an indication of whether or not the procedure modifies the trail.
|
|
%
|
|
:- type proc_trailing_info
|
|
---> proc_trailing_info(
|
|
proc_trailing_status :: trailing_status,
|
|
proc_maybe_trail_analysis_status :: maybe(analysis_status)
|
|
).
|
|
|
|
% Gives an indication of whether or not the procedure, or one of its
|
|
% subgoals, calls a procedure that is tabled using minimal model tabling.
|
|
:- type proc_mm_tabling_info
|
|
---> proc_mm_tabling_info(
|
|
% The tabling status for this procedures as determined
|
|
% by tabling analysis.
|
|
proc_mm_status :: mm_tabling_status,
|
|
|
|
% The status of the tabling analysis results for this
|
|
% procedure. This is used by the intermodule analysis
|
|
% framework to determine if there is any benefit in
|
|
% re-analysing this procedure.
|
|
proc_mm_analysis_status :: maybe(analysis_status)
|
|
).
|
|
|
|
% Predicates to get fields of proc_infos.
|
|
|
|
:- pred proc_info_get_headvars(proc_info::in, list(prog_var)::out) is det.
|
|
:- pred proc_info_get_goal(proc_info::in, hlds_goal::out) is det.
|
|
:- pred proc_info_get_var_table(proc_info::in, var_table::out) is det.
|
|
:- pred proc_info_get_rtti_varmaps(proc_info::in, rtti_varmaps::out) is det.
|
|
:- pred proc_info_get_inst_varset(proc_info::in, inst_varset::out) is det.
|
|
:- pred proc_info_get_maybe_declared_argmodes(proc_info::in,
|
|
maybe(list(mer_mode))::out) is det.
|
|
:- pred proc_info_get_argmodes(proc_info::in, list(mer_mode)::out) is det.
|
|
:- pred proc_info_get_maybe_arglives(proc_info::in,
|
|
maybe(list(is_live))::out) is det.
|
|
:- pred proc_info_get_declared_determinism(proc_info::in,
|
|
maybe(determinism)::out) is det.
|
|
:- pred proc_info_get_inferred_determinism(proc_info::in,
|
|
determinism::out) is det.
|
|
:- pred proc_info_get_eval_method(proc_info::in, eval_method::out) is det.
|
|
|
|
:- pred proc_info_get_context(proc_info::in, prog_context::out) is det.
|
|
:- pred proc_info_get_item_number(proc_info::in, item_seq_num::out) is det.
|
|
:- pred proc_info_get_can_process(proc_info::in, can_process::out) is det.
|
|
:- pred proc_info_get_maybe_head_modes_constr(proc_info::in,
|
|
maybe(mode_constraint)::out) is det.
|
|
:- pred proc_info_get_detism_decl(proc_info::in, detism_decl::out) is det.
|
|
:- pred proc_info_get_cse_nopull_contexts(proc_info::in,
|
|
list(prog_context)::out) is det.
|
|
:- pred proc_info_get_maybe_untuple_info(proc_info::in,
|
|
maybe(untuple_proc_info)::out) is det.
|
|
:- pred proc_info_get_var_name_remap(proc_info::in,
|
|
map(prog_var, string)::out) is det.
|
|
:- pred proc_info_get_statevar_warnings(proc_info::in,
|
|
list(error_spec)::out) is det.
|
|
:- pred proc_info_get_deleted_call_callees(proc_info::in,
|
|
set(pred_proc_id)::out) is det.
|
|
:- pred proc_info_get_is_address_taken(proc_info::in,
|
|
is_address_taken::out) is det.
|
|
:- pred proc_info_get_has_any_foreign_exports(proc_info::in,
|
|
proc_foreign_exports::out) is det.
|
|
:- pred proc_info_get_has_parallel_conj(proc_info::in,
|
|
has_parallel_conj::out) is det.
|
|
:- pred proc_info_get_has_user_event(proc_info::in,
|
|
has_user_event::out) is det.
|
|
:- pred proc_info_get_has_tail_rec_call(proc_info::in,
|
|
has_tail_rec_call::out) is det.
|
|
:- pred proc_info_get_oisu_kind_fors(proc_info::in,
|
|
list(oisu_pred_kind_for)::out) is det.
|
|
:- pred proc_info_get_maybe_require_tailrec_info(proc_info::in,
|
|
maybe(require_tail_recursion)::out) is det.
|
|
:- pred proc_info_get_reg_r_headvars(proc_info::in,
|
|
set_of_progvar::out) is det.
|
|
:- pred proc_info_get_maybe_arg_info(proc_info::in,
|
|
maybe(list(arg_info))::out) is det.
|
|
:- pred proc_info_get_maybe_special_return(proc_info::in,
|
|
maybe(special_proc_return)::out) is det.
|
|
:- pred proc_info_get_liveness_info(proc_info::in, liveness_info::out) is det.
|
|
:- pred proc_info_get_stack_slots(proc_info::in, stack_slots::out) is det.
|
|
:- pred proc_info_get_needs_maxfr_slot(proc_info::in,
|
|
needs_maxfr_slot::out) is det.
|
|
:- pred proc_info_get_call_table_tip(proc_info::in,
|
|
maybe(prog_var)::out) is det.
|
|
:- pred proc_info_get_maybe_proc_table_io_info(proc_info::in,
|
|
maybe(proc_table_io_info)::out) is det.
|
|
:- pred proc_info_get_table_attributes(proc_info::in,
|
|
maybe(table_attributes)::out) is det.
|
|
:- pred proc_info_get_obsolete_in_favour_of(proc_info::in,
|
|
maybe(list(sym_name_arity))::out) is det.
|
|
:- pred proc_info_get_maybe_deep_profile_info(proc_info::in,
|
|
maybe(deep_profile_proc_info)::out) is det.
|
|
:- pred proc_info_get_maybe_arg_size_info(proc_info::in,
|
|
maybe(arg_size_info)::out) is det.
|
|
:- pred proc_info_get_maybe_termination_info(proc_info::in,
|
|
maybe(termination_info)::out) is det.
|
|
:- pred proc_info_get_termination2_info(proc_info::in,
|
|
termination2_info::out) is det.
|
|
:- pred proc_info_get_exception_info(proc_info::in,
|
|
maybe(proc_exception_info)::out) is det.
|
|
:- pred proc_info_get_trailing_info(proc_info::in,
|
|
maybe(proc_trailing_info)::out) is det.
|
|
:- pred proc_info_get_mm_tabling_info(proc_info::in,
|
|
maybe(proc_mm_tabling_info)::out) is det.
|
|
|
|
% Predicates to set fields of proc_infos.
|
|
|
|
:- pred proc_info_set_headvars(list(prog_var)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_goal(hlds_goal::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_var_table(var_table::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_rtti_varmaps(rtti_varmaps::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_inst_varset(inst_varset::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_maybe_declared_argmodes(maybe(list(mer_mode))::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_argmodes(list(mer_mode)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_maybe_arglives(maybe(list(is_live))::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_inferred_determinism(determinism::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_eval_method(eval_method::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
|
|
:- pred proc_info_set_can_process(can_process::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_head_modes_constraint(mode_constraint::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_detism_decl(detism_decl::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_cse_nopull_contexts(list(prog_context)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_maybe_untuple_info(maybe(untuple_proc_info)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_var_name_remap(map(prog_var, string)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_statevar_warnings(list(error_spec)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_deleted_call_callees(set(pred_proc_id)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_address_taken(is_address_taken::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_has_any_foreign_exports(proc_foreign_exports::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_has_parallel_conj(has_parallel_conj::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_has_user_event(has_user_event::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_has_tail_rec_call(has_tail_rec_call::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_oisu_kind_fors(list(oisu_pred_kind_for)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_require_tailrec_info(require_tail_recursion::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_reg_r_headvars(set_of_progvar::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_arg_info(list(arg_info)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_maybe_special_return(maybe(special_proc_return)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_liveness_info(liveness_info::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_stack_slots(stack_slots::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_needs_maxfr_slot(needs_maxfr_slot::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_call_table_tip(maybe(prog_var)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_maybe_proc_table_io_info(maybe(proc_table_io_info)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_table_attributes(maybe(table_attributes)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_obsolete_in_favour_of(
|
|
maybe(list(sym_name_arity))::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_maybe_deep_profile_info(
|
|
maybe(deep_profile_proc_info)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_maybe_arg_size_info(maybe(arg_size_info)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_maybe_termination_info(maybe(termination_info)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_termination2_info(termination2_info::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_exception_info(maybe(proc_exception_info)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_trailing_info(maybe(proc_trailing_info)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
:- pred proc_info_set_mm_tabling_info(maybe(proc_mm_tabling_info)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
|
|
:- pred proc_info_get_structure_sharing(proc_info::in,
|
|
maybe(structure_sharing_domain_and_status)::out) is det.
|
|
|
|
:- pred proc_info_set_structure_sharing(
|
|
structure_sharing_domain_and_status::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
|
|
:- pred proc_info_get_imported_structure_sharing(proc_info::in,
|
|
list(prog_var)::out, list(mer_type)::out, structure_sharing_domain::out)
|
|
is semidet.
|
|
|
|
:- pred proc_info_set_imported_structure_sharing(list(prog_var)::in,
|
|
list(mer_type)::in, structure_sharing_domain::in, proc_info::in,
|
|
proc_info::out) is det.
|
|
|
|
:- pred proc_info_reset_imported_structure_sharing(proc_info::in,
|
|
proc_info::out) is det.
|
|
|
|
:- pred proc_info_get_structure_reuse(proc_info::in,
|
|
maybe(structure_reuse_domain_and_status)::out) is det.
|
|
|
|
:- pred proc_info_set_structure_reuse(structure_reuse_domain_and_status::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
|
|
:- pred proc_info_get_imported_structure_reuse(proc_info::in,
|
|
list(prog_var)::out, list(mer_type)::out, structure_reuse_domain::out)
|
|
is semidet.
|
|
|
|
:- pred proc_info_set_imported_structure_reuse(list(prog_var)::in,
|
|
list(mer_type)::in, structure_reuse_domain::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
|
|
:- pred proc_info_reset_imported_structure_reuse(proc_info::in,
|
|
proc_info::out) is det.
|
|
|
|
% Return true if the interface of the given procedure must include
|
|
% typeinfos for all the type variables in the types of the arguments.
|
|
%
|
|
:- pred proc_interface_should_use_typeinfo_liveness(pred_info::in, proc_id::in,
|
|
globals::in, bool::out) is det.
|
|
|
|
% Return true if the body of a procedure from the given predicate
|
|
% must keep a typeinfo variable alive during the lifetime of all
|
|
% variables whose type includes the corresponding type variable.
|
|
% Note that body typeinfo liveness implies interface typeinfo liveness,
|
|
% but not vice versa.
|
|
%
|
|
:- pred body_should_use_typeinfo_liveness(pred_info::in, globals::in,
|
|
bool::out) is det.
|
|
|
|
:- implementation.
|
|
|
|
% The information specific to a procedure, as opposed to a predicate.
|
|
%
|
|
% The proc_info and proc_sub_info types constitute a single logical
|
|
% data structure split into two parts for efficiency purposes.
|
|
%
|
|
% The proc_info type contains the most frequently accessed and/or updated
|
|
% pieces of information about the procedure. Everything else is in the
|
|
% proc_sub_info type. This arrangement minimizes the amount of memory that
|
|
% needs to be allocated, and filled in, when a field is updated.
|
|
|
|
:- type proc_info
|
|
---> proc_info(
|
|
% The Boehm collector allocates blocks whose sizes are
|
|
% multiples (and usually powers) of 2. Ideally, we would want
|
|
% the number of fields of proc_info to match one of the Boehm
|
|
% block sizes, but as of 2017 march 15, this seemed to be the
|
|
% optimal arrangement (zs).
|
|
|
|
/* 1 */ proc_head_vars :: list(prog_var),
|
|
/* 2 */ proc_body :: hlds_goal,
|
|
|
|
/* 3 */ proc_var_table :: var_table,
|
|
|
|
% Information about type_infos and typeclass_infos.
|
|
/* 4 */ proc_rtti_varmaps :: rtti_varmaps,
|
|
|
|
/* 5 */ proc_inst_varset :: inst_varset,
|
|
|
|
% The declared modes of arguments.
|
|
/* 6 */ proc_maybe_decl_head_modes :: maybe(list(mer_mode)),
|
|
|
|
/* 7 */ proc_actual_head_modes :: list(mer_mode),
|
|
|
|
% Liveness (in the mode analysis sense) of the arguments
|
|
% in the caller; says whether each argument may be used
|
|
% after the call.
|
|
/* 8 */ proc_headvar_caller_liveness :: maybe(list(is_live)),
|
|
|
|
% The _declared_ determinism of the procedure, or `no'
|
|
% if there was no detism declaration.
|
|
/* 9 */ proc_declared_detism :: maybe(determinism),
|
|
/* 10 */ proc_inferred_detism :: determinism,
|
|
|
|
% How should the proc be evaluated.
|
|
/* 11 */ proc_eval_method :: eval_method,
|
|
|
|
/* 12 */ proc_sub_info :: proc_sub_info
|
|
).
|
|
|
|
:- type proc_sub_info
|
|
---> proc_sub_info(
|
|
% The context of the `:- mode' decl, or the context of the
|
|
% first clause if there was no mode declaration.
|
|
psi_proc_context :: prog_context,
|
|
|
|
% The item number of the mode declaration, if there was one.
|
|
psi_item_number :: item_seq_num,
|
|
|
|
% Set to cannot_process if we must not process this procedure
|
|
% just yet. This is used to delay mode checking etc. for
|
|
% complicated modes of unification predicates until the end
|
|
% of the unique_modes pass.
|
|
psi_can_process :: can_process,
|
|
|
|
% XXX The mode of the procedure in the ROBDD based
|
|
% constraint system. Whether it represents the declared
|
|
% or the actual mode is unclear, but since that constraint
|
|
% system is obsolete, this does not much matter :-(
|
|
psi_maybe_head_modes_constr :: maybe(mode_constraint),
|
|
|
|
% Was the determinism declaration explicit, or was it implicit,
|
|
% as for functions?
|
|
psi_detism_decl :: detism_decl,
|
|
|
|
% A list of all the contexts at which cse_detection.m
|
|
% declined to pull out a common deconstruction out of
|
|
% a branched control structure due to concerns about
|
|
% uniqueness in the inst of the affected variable.
|
|
% Determinism analysis wants this information so that
|
|
% it knows whether to mention this fact to the user
|
|
% as a possible cause of a determinism error.
|
|
% See Mantis bug #496.
|
|
psi_cse_nopull_contexts :: list(prog_context),
|
|
|
|
% If set, it means this procedure was created from another
|
|
% procedure by the untupling transformation. This slot records
|
|
% which of the procedure's arguments were derived from which
|
|
% arguments in the original procedure.
|
|
%
|
|
% This is effectively a record of the *procedure*'s origin.
|
|
% (The pred_origin field records the *predicate*'s origin.)
|
|
psi_maybe_untuple_info :: maybe(untuple_proc_info),
|
|
|
|
% Remaps the compiler-created variables named HeadVar__N
|
|
% to the user-given variable names that actually occupied the
|
|
% corresponding argument slots in the procedure's clauses.
|
|
% Has an entry for a head variable only if *all* the clauses
|
|
% consistently give that argument that name, if they give it
|
|
% any name at all.
|
|
% This renaming is applied only after semantic analysis,
|
|
% although it is recorded earlier. The reason for this is
|
|
% to make any error messages about the goals that unify the
|
|
% original headvar (e.g. "X") with the introduced headvar
|
|
% (e.g. "HeadVar__1") give the goal as HeadVar__1 = X,
|
|
% not as X = X, since the latter would be very confusing.
|
|
psi_proc_var_name_remap :: map(prog_var, string),
|
|
|
|
% Any warnings generated by the state variable transformation
|
|
% that we should print only if we find a mode error that could
|
|
% be caused by the problem being warned about.
|
|
psi_statevar_warnings :: list(error_spec),
|
|
|
|
% The set of procedures that the body of this procedure
|
|
% *used* to call, but doesn't anymore. This can happen
|
|
% For several reason. These reasons include the call being
|
|
% - inside a trace goal scope whose compile-time condition
|
|
% turned out to be false,
|
|
% - in the then part of an if-then-else whose condition
|
|
% never succeeds,
|
|
% - in the else part of an if-then-else whose condition
|
|
% never fails.
|
|
% We record the callees of the deleted calls so that
|
|
% dead procedure analysis does not generate warnings
|
|
% for these procedures, or the other procedures reachable
|
|
% from them.
|
|
psi_deleted_call_callees :: set(pred_proc_id),
|
|
|
|
%-----------------------------------------------------------%
|
|
% Flags that record simple properties of the procedure.
|
|
%-----------------------------------------------------------%
|
|
|
|
% Is the address of this procedure taken? If yes, we will
|
|
% need to use typeinfo liveness for them, so that deep_copy
|
|
% and accurate gc have the RTTI they need for copying closures.
|
|
%
|
|
% Note that any non-local procedure must be considered
|
|
% as having its address taken, since it is possible that
|
|
% some other module may do so.
|
|
psi_is_address_taken :: is_address_taken,
|
|
|
|
% Is the procedure mentioned in any foreign_export pragma,
|
|
% regardless of what the current supported foreign languages
|
|
% are?
|
|
psi_has_any_foreign_exports :: proc_foreign_exports,
|
|
|
|
% Does this procedure contain parallel conjunction?
|
|
% If yes, it should be run through the dependent parallel
|
|
% conjunction transformation.
|
|
%
|
|
% This slot is set by the simplification pass.
|
|
% Note that after some optimization passes, this flag
|
|
% may be a conservative approximation.
|
|
psi_proc_has_parallel_conj :: has_parallel_conj,
|
|
|
|
% Does this procedure contain a user event?
|
|
%
|
|
% This slot is set by the simplification pass.
|
|
psi_proc_has_user_event :: has_user_event,
|
|
|
|
psi_proc_has_tail_rec_call :: has_tail_rec_call,
|
|
|
|
% Is the procedure mentioned in any order-independent-state-
|
|
% update pragmas? If yes, list the role of this procedure
|
|
% for the each of the types in those pragmas.
|
|
psi_oisu_kind_fors :: list(oisu_pred_kind_for),
|
|
|
|
% Has the user requested (via a require_tail_recursion
|
|
% pragma) that we suppress or enable warnings about tail
|
|
% recursion for this procedure?
|
|
psi_maybe_require_tailrec :: maybe(require_tail_recursion),
|
|
|
|
%-----------------------------------------------------------%
|
|
% Information needed by the LLDS code generator.
|
|
%-----------------------------------------------------------%
|
|
|
|
% The head variables which must be forced to use regular
|
|
% registers by the calling convention, despite having type
|
|
% float. This is only meaningful with float registers.
|
|
psi_reg_r_headvars :: set_of_progvar,
|
|
|
|
% The calling convention of each argument: information computed
|
|
% by arg_info.m (based on the modes etc.) and used by code
|
|
% generation to determine how each argument should be passed.
|
|
psi_maybe_arg_info :: maybe(list(arg_info)),
|
|
|
|
psi_maybe_special_return :: maybe(special_proc_return),
|
|
|
|
% The initial liveness, for code generation.
|
|
psi_initial_liveness :: liveness_info,
|
|
|
|
% Allocation of variables to stack slots.
|
|
psi_stack_slots :: stack_slots,
|
|
|
|
% True iff tracing is enabled, this is a procedure that lives
|
|
% on the det stack, and the code of this procedure may create
|
|
% a frame on the det stack. (Only in these circumstances do we
|
|
% need to reserve a stack slot to hold the value of maxfr
|
|
% at the call, for use in implementing retry.) This slot
|
|
% is used only with the LLDS backend XXX. Its value is set
|
|
% during the live_vars pass; it is invalid before then.
|
|
psi_needs_maxfr_slot :: needs_maxfr_slot,
|
|
|
|
%-----------------------------------------------------------%
|
|
% Information needed for tabling.
|
|
%-----------------------------------------------------------%
|
|
|
|
% If the procedure's evaluation method is memo, loopcheck or
|
|
% minimal, this slot identifies the variable that holds the tip
|
|
% of the call table. Otherwise, this field will be set to `no'.
|
|
%
|
|
% Tabled procedures record, in the data structure identified
|
|
% by this variable, that the call is active. When performing
|
|
% a retry across such a procedure, we must reset the state
|
|
% of the call; if we don't, the retried call will find the
|
|
% active call and report an infinite loop error.
|
|
%
|
|
% Such resetting of course requires the debugger to know
|
|
% whether the procedure has reached the call table tip yet.
|
|
% Therefore when binding this variable, the code generator
|
|
% of the relevant backend must record this fact in a place
|
|
% accessible to the debugger, if debugging is enabled.
|
|
psi_call_table_tip :: maybe(prog_var),
|
|
|
|
% If set, it means that procedure has been subject to the I/O
|
|
% tabling transformation. The argument will contain all the
|
|
% information we need to display I/O actions involving
|
|
% this procedure.
|
|
%
|
|
% (If the procedure has been subject to other kinds of tabling
|
|
% transformations, the corresponding information will be
|
|
% recorded in a map in the module_info.)
|
|
% XXX For now, the compiler fully supports only procedures
|
|
% whose arguments are all either ints, floats or strings.
|
|
% However, this is still sufficient for debugging most problems
|
|
% in the tabling system.
|
|
psi_maybe_table_io_info :: maybe(proc_table_io_info),
|
|
|
|
psi_table_attributes :: maybe(table_attributes),
|
|
|
|
% If this procedure is marked as obsolete, this will be a
|
|
% "yes(_)" wrapped around a list of the predicate names that
|
|
% the compiler should suggest as possible replacements.
|
|
% (Note that the list of possible replacements may be empty.)
|
|
% In the usual case where this predicate is NOT marked
|
|
% as obsolete, this will be "no".
|
|
psi_proc_obsolete_in_favour_of :: maybe(list(
|
|
sym_name_arity)),
|
|
|
|
%-----------------------------------------------------------%
|
|
% Information needed for deep profiling.
|
|
%-----------------------------------------------------------%
|
|
|
|
psi_maybe_deep_prof_info :: maybe(deep_profile_proc_info),
|
|
|
|
%-----------------------------------------------------------%
|
|
% The results of program analyses.
|
|
%-----------------------------------------------------------%
|
|
|
|
% Information about the relative sizes of the input and output
|
|
% args of the procedure. Set by termination analysis.
|
|
psi_maybe_arg_sizes :: maybe(arg_size_info),
|
|
|
|
% The termination properties of the procedure.
|
|
% Set by termination analysis.
|
|
psi_maybe_termination :: maybe(termination_info),
|
|
|
|
% Termination properties and argument size constraints for
|
|
% the procedure. Set by termination2 analysis.
|
|
psi_termination2 :: termination2_info,
|
|
|
|
% The results of the analyses in exception_analysis.m,
|
|
% trailing_analysis.m and tabling_analysis, if available.
|
|
psi_exception_info :: maybe(proc_exception_info),
|
|
psi_trailing_info :: maybe(proc_trailing_info),
|
|
psi_mm_tabling_info :: maybe(proc_mm_tabling_info),
|
|
|
|
% Structure sharing information as obtained by the structure
|
|
% sharing analysis.
|
|
psi_structure_sharing :: structure_sharing_info,
|
|
|
|
% Structure reuse conditions obtained by the structure reuse
|
|
% analysis (CTGC).
|
|
psi_structure_reuse :: structure_reuse_info
|
|
).
|
|
|
|
:- type structure_sharing_info
|
|
---> structure_sharing_info(
|
|
maybe_sharing :: maybe(structure_sharing_domain_and_status),
|
|
maybe_imported_sharing :: maybe(imported_sharing)
|
|
% Records the sharing information from any `.opt' or
|
|
% `.trans_opt' file. This information needs to be processed at
|
|
% the beginning of structure sharing analysis. After that,
|
|
% this field is of no use.
|
|
).
|
|
|
|
% Sharing information is expressed in terms of head variables and the
|
|
% type variables occurring in their types. In order to correctly process
|
|
% (mainly renaming) this information, we need both the list of head
|
|
% variables as well as their types. As this list of head variables may
|
|
% contain any compiler-added head variables, the processing of imported
|
|
% structure sharing information needs to be postponed until the actual
|
|
% structure sharing analysis, which explains the need for the type
|
|
% imported_sharing to temporarily store the imported sharing information.
|
|
%
|
|
:- type imported_sharing
|
|
---> imported_sharing(
|
|
% The list of head variables in which terms the imported
|
|
% sharing is expressed.
|
|
s_headvars :: list(prog_var),
|
|
|
|
% The types of the head variables.
|
|
s_types :: list(mer_type),
|
|
|
|
s_sharing :: structure_sharing_domain
|
|
).
|
|
|
|
:- func structure_sharing_info_init = structure_sharing_info.
|
|
|
|
structure_sharing_info_init = structure_sharing_info(no, no).
|
|
|
|
:- type structure_reuse_info
|
|
---> structure_reuse_info(
|
|
maybe_reuse :: maybe(structure_reuse_domain_and_status),
|
|
|
|
maybe_imported_reuse :: maybe(imported_reuse)
|
|
% Records the reuse information from any `.opt' or
|
|
% `.trans_opt' file. This information needs to be processed
|
|
% at the beginning of structure reuse analysis. After that
|
|
% this field is of no use.
|
|
).
|
|
|
|
% Same rationale as for imported_sharing.
|
|
%
|
|
:- type imported_reuse
|
|
---> imported_reuse(
|
|
% The list of headvars in which terms the imported reuse
|
|
% information is expressed.
|
|
r_headvars :: list(prog_var),
|
|
|
|
% The types of the headvars.
|
|
r_types :: list(mer_type),
|
|
|
|
r_reuse :: structure_reuse_domain
|
|
).
|
|
|
|
:- func structure_reuse_info_init = structure_reuse_info.
|
|
|
|
structure_reuse_info_init = structure_reuse_info(no, no).
|
|
|
|
table_step_stats_kind(Step) = KindStr :-
|
|
(
|
|
( Step = table_trie_step_int(_)
|
|
; Step = table_trie_step_char
|
|
; Step = table_trie_step_string
|
|
; Step = table_trie_step_float
|
|
; Step = table_trie_step_typeinfo
|
|
; Step = table_trie_step_typeclassinfo
|
|
; Step = table_trie_step_foreign_enum
|
|
),
|
|
KindStr = "MR_TABLE_STATS_DETAIL_HASH"
|
|
;
|
|
Step = table_trie_step_enum(_),
|
|
KindStr = "MR_TABLE_STATS_DETAIL_ENUM"
|
|
;
|
|
Step = table_trie_step_general(_Type, IsPoly, ValueOrAddr),
|
|
(
|
|
ValueOrAddr = table_addr,
|
|
KindStr = "MR_TABLE_STATS_DETAIL_HASH"
|
|
;
|
|
ValueOrAddr = table_value,
|
|
(
|
|
IsPoly = table_is_mono,
|
|
KindStr = "MR_TABLE_STATS_DETAIL_DU"
|
|
;
|
|
IsPoly = table_is_poly,
|
|
KindStr = "MR_TABLE_STATS_DETAIL_POLY"
|
|
)
|
|
)
|
|
;
|
|
( Step = table_trie_step_promise_implied
|
|
; Step = table_trie_step_dummy
|
|
),
|
|
KindStr = "MR_TABLE_STATS_DETAIL_NONE"
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
proc_info_init(ModuleInfo, MainContext, ItemNumber, Types,
|
|
DeclaredModes, Modes, MaybeArgLives, DetismDecl, MaybeDeclaredDetism,
|
|
IsAddressTaken, HasParallelConj, VarNameRemap, ProcInfo) :-
|
|
% When this predicate is invoked during the construction of the HLDS,
|
|
% some parts of the procedure aren't known yet. In that case, we can
|
|
% simply initialize them to any old garbage which we will later throw away.
|
|
%
|
|
% However, when this predicate is invoked by HLDS transformation passes
|
|
% after the front-end has finished, this strategy won't work. We need
|
|
% to fill in every field with meaningful, correct information, unless
|
|
% we know for sure that before the next pass that needs the correct value
|
|
% in a field, we will invoke another pass that fills in the correct value
|
|
% in that field.
|
|
%
|
|
% XXX I (zs) am far from sure that all the field initializations below,
|
|
% in this predicate and in proc_info_create_with_declared_detism,
|
|
% fulfill this condition.
|
|
|
|
% Please use a variable for every field of the proc_info and proc_sub_info,
|
|
% and please keep the definitions of those variables in the same order
|
|
% as the fields themselves.
|
|
|
|
% argument MainContext
|
|
% argument ItemNumber
|
|
CanProcess = can_process_now,
|
|
% argument DetismDecl
|
|
CseNopullContexts = [],
|
|
MaybeUntupleInfo = no `with_type` maybe(untuple_proc_info),
|
|
% argument VarNameRemap
|
|
StateVarWarnings = [],
|
|
set.init(DeletedCallees),
|
|
% argument IsAddressTaken
|
|
HasForeignProcExports = no_foreign_exports,
|
|
% argument HasParallelConj
|
|
HasUserEvent = has_no_user_event,
|
|
HasTailCallEvent = has_tail_rec_call(has_no_self_tail_rec_call,
|
|
has_no_mutual_tail_rec_call),
|
|
OisuKinds = [],
|
|
MaybeRequireTailRecursion = no,
|
|
set_of_var.init(RegR_HeadVars),
|
|
MaybeArgPassInfo = no `with_type` maybe(list(arg_info)),
|
|
MaybeSpecialReturn = no `with_type` maybe(special_proc_return),
|
|
set_of_var.init(InitialLiveness),
|
|
map.init(StackSlots),
|
|
NeedsMaxfrSlot = does_not_need_maxfr_slot,
|
|
MaybeCallTableTip = no `with_type` maybe(prog_var),
|
|
MaybeTableIOInfo = no `with_type` maybe(proc_table_io_info),
|
|
MaybeTableAttrs = no `with_type` maybe(table_attributes),
|
|
MaybeObsoleteInFavourOf = no `with_type` maybe(list(sym_name_arity)),
|
|
MaybeDeepProfProcInfo = no `with_type` maybe(deep_profile_proc_info),
|
|
MaybeArgSizes = no `with_type` maybe(arg_size_info),
|
|
MaybeTermInfo = no `with_type` maybe(termination_info),
|
|
Term2Info = term_constr_main_types.term2_info_init,
|
|
MaybeExceptionInfo = no `with_type` maybe(proc_exception_info),
|
|
MaybeTrailingInfo = no `with_type` maybe(proc_trailing_info),
|
|
MaybeMMTablingInfo = no `with_type` maybe(proc_mm_tabling_info),
|
|
SharingInfo = structure_sharing_info_init,
|
|
ReuseInfo = structure_reuse_info_init,
|
|
|
|
ProcSubInfo = proc_sub_info(
|
|
MainContext,
|
|
ItemNumber,
|
|
CanProcess,
|
|
MaybeHeadModesConstr,
|
|
DetismDecl,
|
|
CseNopullContexts,
|
|
MaybeUntupleInfo,
|
|
VarNameRemap,
|
|
StateVarWarnings,
|
|
DeletedCallees,
|
|
IsAddressTaken,
|
|
HasForeignProcExports,
|
|
HasParallelConj,
|
|
HasUserEvent,
|
|
HasTailCallEvent,
|
|
OisuKinds,
|
|
MaybeRequireTailRecursion,
|
|
RegR_HeadVars,
|
|
MaybeArgPassInfo,
|
|
MaybeSpecialReturn,
|
|
InitialLiveness,
|
|
StackSlots,
|
|
NeedsMaxfrSlot,
|
|
MaybeCallTableTip,
|
|
MaybeTableIOInfo,
|
|
MaybeTableAttrs,
|
|
MaybeObsoleteInFavourOf,
|
|
MaybeDeepProfProcInfo,
|
|
MaybeArgSizes,
|
|
MaybeTermInfo,
|
|
Term2Info,
|
|
MaybeExceptionInfo,
|
|
MaybeTrailingInfo,
|
|
MaybeMMTablingInfo,
|
|
SharingInfo,
|
|
ReuseInfo),
|
|
|
|
init_var_table(VarTable0),
|
|
make_fresh_prefix_named_vars_from_types(ModuleInfo, "HeadVar__", 1,
|
|
Types, HeadVars, VarTable0, VarTable),
|
|
goal_info_init(GoalInfo),
|
|
BodyGoal = hlds_goal(conj(plain_conj, []), GoalInfo),
|
|
rtti_varmaps_init(RttiVarMaps),
|
|
varset.init(InstVarSet),
|
|
% argument DeclaredModes
|
|
% argument Modes
|
|
MaybeHeadModesConstr = no `with_type` maybe(mode_constraint),
|
|
% argument MaybeArgLives
|
|
% argument MaybeDeclaredDetism
|
|
% Inferred determinism gets initialized to `erroneous'.
|
|
% This is what `det_analysis.m' wants. det_analysis.m
|
|
% will later provide the correct inferred determinism for it.
|
|
InferredDetism = detism_erroneous,
|
|
EvalMethod = eval_normal,
|
|
|
|
ProcInfo = proc_info(
|
|
HeadVars,
|
|
BodyGoal,
|
|
VarTable,
|
|
RttiVarMaps,
|
|
InstVarSet,
|
|
DeclaredModes,
|
|
Modes,
|
|
MaybeArgLives,
|
|
MaybeDeclaredDetism,
|
|
InferredDetism,
|
|
EvalMethod,
|
|
ProcSubInfo).
|
|
|
|
:- pred make_fresh_prefix_named_vars_from_types(module_info::in,
|
|
string::in, int::in, list(mer_type)::in, list(prog_var)::out,
|
|
var_table::in, var_table::out) is det.
|
|
|
|
make_fresh_prefix_named_vars_from_types(_, _, _, [], [], !Info).
|
|
make_fresh_prefix_named_vars_from_types(ModuleInfo, BaseName, Num,
|
|
[Type | Types], [Var | Vars], !VarTable) :-
|
|
make_fresh_prefix_named_var_from_type(ModuleInfo, BaseName, Num,
|
|
Type, Var, !VarTable),
|
|
make_fresh_prefix_named_vars_from_types(ModuleInfo, BaseName, Num + 1,
|
|
Types, Vars, !VarTable).
|
|
|
|
:- pred make_fresh_prefix_named_var_from_type(module_info::in,
|
|
string::in, int::in, mer_type::in, prog_var::out,
|
|
var_table::in, var_table::out) is det.
|
|
|
|
make_fresh_prefix_named_var_from_type(ModuleInfo, BaseName, Num, Type, Var,
|
|
!VarTable) :-
|
|
string.format("%s%d", [s(BaseName), i(Num)], Name),
|
|
IsDummy = is_type_a_dummy(ModuleInfo, Type),
|
|
Entry = vte(Name, Type, IsDummy),
|
|
add_var_entry(Entry, Var, !VarTable).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
proc_info_create(Context, ItemNumber, VarTable, HeadVars,
|
|
InstVarSet, HeadModes, DetismDecl, Detism, Goal, RttiVarMaps,
|
|
IsAddressTaken, HasParallelConj, VarNameRemap, ProcInfo) :-
|
|
proc_info_create_with_declared_detism(Context, ItemNumber,
|
|
VarTable, HeadVars, InstVarSet, HeadModes,
|
|
DetismDecl, yes(Detism), Detism, Goal, RttiVarMaps, IsAddressTaken,
|
|
HasParallelConj, VarNameRemap, ProcInfo).
|
|
|
|
:- pred proc_info_create_with_declared_detism(prog_context::in,
|
|
item_seq_num::in, var_table::in, list(prog_var)::in,
|
|
inst_varset::in, list(mer_mode)::in,
|
|
detism_decl::in, maybe(determinism)::in, determinism::in, hlds_goal::in,
|
|
rtti_varmaps::in, is_address_taken::in, has_parallel_conj::in,
|
|
map(prog_var, string)::in, proc_info::out) is det.
|
|
|
|
proc_info_create_with_declared_detism(MainContext, ItemNumber,
|
|
VarTable, HeadVars, InstVarSet, Modes,
|
|
DetismDecl, MaybeDeclaredDetism, Detism, Goal, RttiVarMaps,
|
|
IsAddressTaken, HasParallelConj, VarNameRemap, ProcInfo) :-
|
|
% See the comment at the top of proc_info_init; it applies here as well.
|
|
|
|
% Please use a variable for every field of the proc_info and proc_sub_info,
|
|
% and please keep the definitions of those variables in the same order
|
|
% as the fields themselves.
|
|
|
|
% argument MainContext
|
|
% argument ItemNumber
|
|
CanProcess = can_process_now,
|
|
% argument DetismDecl
|
|
CseNopullContexts = [],
|
|
MaybeUntupleInfo = no `with_type` maybe(untuple_proc_info),
|
|
% argument VarNameRemap
|
|
StateVarWarnings = [],
|
|
set.init(DeletedCallees),
|
|
% argument IsAddressTaken
|
|
HasForeignProcExports = no_foreign_exports,
|
|
% argument HasParallelConj
|
|
HasUserEvent = has_no_user_event,
|
|
HasTailCallEvent = has_tail_rec_call(has_no_self_tail_rec_call,
|
|
has_no_mutual_tail_rec_call),
|
|
OisuKinds = [],
|
|
MaybeRequireTailRecursion = no,
|
|
set_of_var.init(RegR_HeadVars),
|
|
MaybeArgPassInfo = no `with_type` maybe(list(arg_info)),
|
|
MaybeSpecialReturn = no `with_type` maybe(special_proc_return),
|
|
set_of_var.init(InitialLiveness),
|
|
map.init(StackSlots),
|
|
NeedsMaxfrSlot = does_not_need_maxfr_slot,
|
|
MaybeCallTableTip = no `with_type` maybe(prog_var),
|
|
MaybeTableIOInfo = no `with_type` maybe(proc_table_io_info),
|
|
MaybeTableAttrs = no `with_type` maybe(table_attributes),
|
|
MaybeObsoleteInFavourOf = no `with_type` maybe(list(sym_name_arity)),
|
|
MaybeDeepProfProcInfo = no `with_type` maybe(deep_profile_proc_info),
|
|
MaybeArgSizes = no `with_type` maybe(arg_size_info),
|
|
MaybeTermInfo = no `with_type` maybe(termination_info),
|
|
Term2Info = term_constr_main_types.term2_info_init,
|
|
MaybeExceptionInfo = no `with_type` maybe(proc_exception_info),
|
|
MaybeTrailingInfo = no `with_type` maybe(proc_trailing_info),
|
|
MaybeMMTablingInfo = no `with_type` maybe(proc_mm_tabling_info),
|
|
SharingInfo = structure_sharing_info_init,
|
|
ReuseInfo = structure_reuse_info_init,
|
|
|
|
ProcSubInfo = proc_sub_info(
|
|
MainContext,
|
|
ItemNumber,
|
|
CanProcess,
|
|
MaybeHeadModesConstr,
|
|
DetismDecl,
|
|
CseNopullContexts,
|
|
MaybeUntupleInfo,
|
|
VarNameRemap,
|
|
StateVarWarnings,
|
|
DeletedCallees,
|
|
IsAddressTaken,
|
|
HasForeignProcExports,
|
|
HasParallelConj,
|
|
HasUserEvent,
|
|
HasTailCallEvent,
|
|
OisuKinds,
|
|
MaybeRequireTailRecursion,
|
|
RegR_HeadVars,
|
|
MaybeArgPassInfo,
|
|
MaybeSpecialReturn,
|
|
InitialLiveness,
|
|
StackSlots,
|
|
NeedsMaxfrSlot,
|
|
MaybeCallTableTip,
|
|
MaybeTableIOInfo,
|
|
MaybeTableAttrs,
|
|
MaybeObsoleteInFavourOf,
|
|
MaybeDeepProfProcInfo,
|
|
MaybeArgSizes,
|
|
MaybeTermInfo,
|
|
Term2Info,
|
|
MaybeExceptionInfo,
|
|
MaybeTrailingInfo,
|
|
MaybeMMTablingInfo,
|
|
SharingInfo,
|
|
ReuseInfo),
|
|
|
|
% argument HeadVars
|
|
% argument Goal
|
|
% argument VarSet
|
|
% argument VarTypes
|
|
% argument RttiVarMaps
|
|
% argument InstVarSet
|
|
DeclaredModes = no,
|
|
% argument Modes
|
|
MaybeHeadModesConstr = no `with_type` maybe(mode_constraint),
|
|
MaybeArgLives = no,
|
|
% argument MaybeDeclaredDetism
|
|
% argument Detism
|
|
EvalMethod = eval_normal,
|
|
|
|
ProcInfo = proc_info(
|
|
HeadVars,
|
|
Goal,
|
|
VarTable,
|
|
RttiVarMaps,
|
|
InstVarSet,
|
|
DeclaredModes,
|
|
Modes,
|
|
MaybeArgLives,
|
|
MaybeDeclaredDetism,
|
|
Detism,
|
|
EvalMethod,
|
|
ProcSubInfo).
|
|
|
|
proc_prepare_to_clone(ProcInfo, HeadVars, Goal, VarTable, RttiVarMaps,
|
|
InstVarSet, DeclaredModes, Modes, MaybeArgLives,
|
|
MaybeDeclaredDetism, Detism, EvalMethod,
|
|
MainContext, ItemNumber, CanProcess, MaybeHeadModesConstr, DetismDecl,
|
|
CseNopullContexts, MaybeUntupleInfo, VarNameRemap, StateVarWarnings,
|
|
DeletedCallees, IsAddressTaken, HasForeignProcExports, HasParallelConj,
|
|
HasUserEvent, HasTailCallEvent, OisuKinds, MaybeRequireTailRecursion,
|
|
RegR_HeadVars, MaybeArgPassInfo, MaybeSpecialReturn, InitialLiveness,
|
|
StackSlots, NeedsMaxfrSlot, MaybeCallTableTip, MaybeTableIOInfo,
|
|
MaybeTableAttrs, MaybeObsoleteInFavourOf, MaybeDeepProfProcInfo,
|
|
MaybeArgSizes, MaybeTermInfo, Term2Info, MaybeExceptionInfo,
|
|
MaybeTrailingInfo, MaybeMMTablingInfo, SharingInfo, ReuseInfo) :-
|
|
ProcInfo = proc_info(
|
|
HeadVars,
|
|
Goal,
|
|
VarTable,
|
|
RttiVarMaps,
|
|
InstVarSet,
|
|
DeclaredModes,
|
|
Modes,
|
|
MaybeArgLives,
|
|
MaybeDeclaredDetism,
|
|
Detism,
|
|
EvalMethod,
|
|
ProcSubInfo),
|
|
ProcSubInfo = proc_sub_info(
|
|
MainContext,
|
|
ItemNumber,
|
|
CanProcess,
|
|
MaybeHeadModesConstr,
|
|
DetismDecl,
|
|
CseNopullContexts,
|
|
MaybeUntupleInfo,
|
|
VarNameRemap,
|
|
StateVarWarnings,
|
|
DeletedCallees,
|
|
IsAddressTaken,
|
|
HasForeignProcExports,
|
|
HasParallelConj,
|
|
HasUserEvent,
|
|
HasTailCallEvent,
|
|
OisuKinds,
|
|
MaybeRequireTailRecursion,
|
|
RegR_HeadVars,
|
|
MaybeArgPassInfo,
|
|
MaybeSpecialReturn,
|
|
InitialLiveness,
|
|
StackSlots,
|
|
NeedsMaxfrSlot,
|
|
MaybeCallTableTip,
|
|
MaybeTableIOInfo,
|
|
MaybeTableAttrs,
|
|
MaybeObsoleteInFavourOf,
|
|
MaybeDeepProfProcInfo,
|
|
MaybeArgSizes,
|
|
MaybeTermInfo,
|
|
Term2Info,
|
|
MaybeExceptionInfo,
|
|
MaybeTrailingInfo,
|
|
MaybeMMTablingInfo,
|
|
SharingInfo,
|
|
ReuseInfo).
|
|
|
|
proc_create(HeadVars, Goal, VarTable, RttiVarMaps,
|
|
InstVarSet, DeclaredModes, Modes, MaybeArgLives,
|
|
MaybeDeclaredDetism, Detism, EvalMethod,
|
|
MainContext, ItemNumber, CanProcess, MaybeHeadModesConstr, DetismDecl,
|
|
CseNopullContexts, MaybeUntupleInfo, VarNameRemap, StateVarWarnings,
|
|
DeletedCallees, IsAddressTaken, HasForeignProcExports, HasParallelConj,
|
|
HasUserEvent, HasTailCallEvent, OisuKinds, MaybeRequireTailRecursion,
|
|
RegR_HeadVars, MaybeArgPassInfo, MaybeSpecialReturn, InitialLiveness,
|
|
StackSlots, NeedsMaxfrSlot, MaybeCallTableTip, MaybeTableIOInfo,
|
|
MaybeTableAttrs, MaybeObsoleteInFavourOf, MaybeDeepProfProcInfo,
|
|
MaybeArgSizes, MaybeTermInfo, Term2Info, MaybeExceptionInfo,
|
|
MaybeTrailingInfo, MaybeMMTablingInfo, SharingInfo, ReuseInfo,
|
|
ProcInfo) :-
|
|
ProcSubInfo = proc_sub_info(
|
|
MainContext,
|
|
ItemNumber,
|
|
CanProcess,
|
|
MaybeHeadModesConstr,
|
|
DetismDecl,
|
|
CseNopullContexts,
|
|
MaybeUntupleInfo,
|
|
VarNameRemap,
|
|
StateVarWarnings,
|
|
DeletedCallees,
|
|
IsAddressTaken,
|
|
HasForeignProcExports,
|
|
HasParallelConj,
|
|
HasUserEvent,
|
|
HasTailCallEvent,
|
|
OisuKinds,
|
|
MaybeRequireTailRecursion,
|
|
RegR_HeadVars,
|
|
MaybeArgPassInfo,
|
|
MaybeSpecialReturn,
|
|
InitialLiveness,
|
|
StackSlots,
|
|
NeedsMaxfrSlot,
|
|
MaybeCallTableTip,
|
|
MaybeTableIOInfo,
|
|
MaybeTableAttrs,
|
|
MaybeObsoleteInFavourOf,
|
|
MaybeDeepProfProcInfo,
|
|
MaybeArgSizes,
|
|
MaybeTermInfo,
|
|
Term2Info,
|
|
MaybeExceptionInfo,
|
|
MaybeTrailingInfo,
|
|
MaybeMMTablingInfo,
|
|
SharingInfo,
|
|
ReuseInfo),
|
|
ProcInfo = proc_info(
|
|
HeadVars,
|
|
Goal,
|
|
VarTable,
|
|
RttiVarMaps,
|
|
InstVarSet,
|
|
DeclaredModes,
|
|
Modes,
|
|
MaybeArgLives,
|
|
MaybeDeclaredDetism,
|
|
Detism,
|
|
EvalMethod,
|
|
ProcSubInfo).
|
|
|
|
proc_info_set_body(VarTable, HeadVars, Goal, RttiVarMaps, !ProcInfo) :-
|
|
!ProcInfo ^ proc_var_table := VarTable,
|
|
!ProcInfo ^ proc_head_vars := HeadVars,
|
|
!ProcInfo ^ proc_body := Goal,
|
|
!ProcInfo ^ proc_rtti_varmaps := RttiVarMaps.
|
|
|
|
proc_info_get_headvars(PI, X) :-
|
|
X = PI ^ proc_head_vars.
|
|
proc_info_get_goal(PI, X) :-
|
|
X = PI ^ proc_body.
|
|
proc_info_get_var_table(PI, X) :-
|
|
X = PI ^ proc_var_table.
|
|
proc_info_get_rtti_varmaps(PI, X) :-
|
|
X = PI ^ proc_rtti_varmaps.
|
|
proc_info_get_inst_varset(PI, X) :-
|
|
X = PI ^ proc_inst_varset.
|
|
proc_info_get_maybe_declared_argmodes(PI, X) :-
|
|
X = PI ^ proc_maybe_decl_head_modes.
|
|
proc_info_get_argmodes(PI, X) :-
|
|
X = PI ^ proc_actual_head_modes.
|
|
proc_info_get_maybe_arglives(PI, X) :-
|
|
X = PI ^ proc_headvar_caller_liveness.
|
|
proc_info_get_declared_determinism(PI, X) :-
|
|
X = PI ^ proc_declared_detism.
|
|
proc_info_get_inferred_determinism(PI, X) :-
|
|
X = PI ^ proc_inferred_detism.
|
|
proc_info_get_eval_method(PI, X) :-
|
|
X = PI ^ proc_eval_method.
|
|
|
|
proc_info_get_context(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_proc_context.
|
|
proc_info_get_item_number(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_item_number.
|
|
proc_info_get_can_process(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_can_process.
|
|
proc_info_get_maybe_head_modes_constr(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_maybe_head_modes_constr.
|
|
proc_info_get_detism_decl(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_detism_decl.
|
|
proc_info_get_cse_nopull_contexts(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_cse_nopull_contexts.
|
|
proc_info_get_maybe_untuple_info(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_maybe_untuple_info.
|
|
proc_info_get_var_name_remap(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_proc_var_name_remap.
|
|
proc_info_get_statevar_warnings(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_statevar_warnings.
|
|
proc_info_get_deleted_call_callees(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_deleted_call_callees.
|
|
proc_info_get_is_address_taken(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_is_address_taken.
|
|
proc_info_get_has_any_foreign_exports(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_has_any_foreign_exports.
|
|
proc_info_get_has_parallel_conj(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_proc_has_parallel_conj.
|
|
proc_info_get_has_user_event(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_proc_has_user_event.
|
|
proc_info_get_has_tail_rec_call(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_proc_has_tail_rec_call.
|
|
proc_info_get_oisu_kind_fors(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_oisu_kind_fors.
|
|
proc_info_get_maybe_require_tailrec_info(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_maybe_require_tailrec.
|
|
proc_info_get_reg_r_headvars(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_reg_r_headvars.
|
|
proc_info_get_maybe_arg_info(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_maybe_arg_info.
|
|
proc_info_get_maybe_special_return(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_maybe_special_return.
|
|
proc_info_get_liveness_info(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_initial_liveness.
|
|
proc_info_get_stack_slots(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_stack_slots.
|
|
proc_info_get_needs_maxfr_slot(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_needs_maxfr_slot.
|
|
proc_info_get_call_table_tip(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_call_table_tip.
|
|
proc_info_get_maybe_proc_table_io_info(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_maybe_table_io_info.
|
|
proc_info_get_table_attributes(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_table_attributes.
|
|
proc_info_get_obsolete_in_favour_of(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_proc_obsolete_in_favour_of.
|
|
proc_info_get_maybe_deep_profile_info(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_maybe_deep_prof_info.
|
|
proc_info_get_maybe_arg_size_info(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_maybe_arg_sizes.
|
|
proc_info_get_maybe_termination_info(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_maybe_termination.
|
|
proc_info_get_termination2_info(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_termination2.
|
|
proc_info_get_exception_info(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_exception_info.
|
|
proc_info_get_trailing_info(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_trailing_info.
|
|
proc_info_get_mm_tabling_info(PI, X) :-
|
|
X = PI ^ proc_sub_info ^ psi_mm_tabling_info.
|
|
|
|
proc_info_set_headvars(X, !PI) :-
|
|
!PI ^ proc_head_vars := X.
|
|
proc_info_set_goal(X, !PI) :-
|
|
!PI ^ proc_body := X.
|
|
proc_info_set_var_table(X, !PI) :-
|
|
!PI ^ proc_var_table := X.
|
|
proc_info_set_rtti_varmaps(X, !PI) :-
|
|
!PI ^ proc_rtti_varmaps := X.
|
|
proc_info_set_inst_varset(X, !PI) :-
|
|
!PI ^ proc_inst_varset := X.
|
|
proc_info_set_maybe_declared_argmodes(X, !PI) :-
|
|
!PI ^ proc_maybe_decl_head_modes := X.
|
|
proc_info_set_argmodes(X, !PI) :-
|
|
!PI ^ proc_actual_head_modes := X.
|
|
proc_info_set_maybe_arglives(X, !PI) :-
|
|
!PI ^ proc_headvar_caller_liveness := X.
|
|
proc_info_set_inferred_determinism(X, !PI) :-
|
|
!PI ^ proc_inferred_detism := X.
|
|
proc_info_set_eval_method(X, !PI) :-
|
|
!PI ^ proc_eval_method := X.
|
|
|
|
proc_info_set_can_process(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_can_process := X.
|
|
proc_info_set_head_modes_constraint(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_maybe_head_modes_constr := yes(X).
|
|
proc_info_set_detism_decl(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_detism_decl := X.
|
|
proc_info_set_cse_nopull_contexts(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_cse_nopull_contexts := X.
|
|
proc_info_set_maybe_untuple_info(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_maybe_untuple_info := X.
|
|
proc_info_set_var_name_remap(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_proc_var_name_remap := X.
|
|
proc_info_set_statevar_warnings(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_statevar_warnings := X.
|
|
proc_info_set_deleted_call_callees(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_deleted_call_callees := X.
|
|
proc_info_set_address_taken(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_is_address_taken := X.
|
|
proc_info_set_has_any_foreign_exports(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_has_any_foreign_exports := X.
|
|
proc_info_set_has_parallel_conj(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_proc_has_parallel_conj := X.
|
|
proc_info_set_has_user_event(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_proc_has_user_event := X.
|
|
proc_info_set_has_tail_rec_call(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_proc_has_tail_rec_call := X.
|
|
proc_info_set_oisu_kind_fors(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_oisu_kind_fors := X.
|
|
proc_info_set_require_tailrec_info(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_maybe_require_tailrec := yes(X).
|
|
proc_info_set_reg_r_headvars(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_reg_r_headvars := X.
|
|
proc_info_set_arg_info(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_maybe_arg_info := yes(X).
|
|
proc_info_set_maybe_special_return(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_maybe_special_return := X.
|
|
proc_info_set_liveness_info(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_initial_liveness := X.
|
|
proc_info_set_stack_slots(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_stack_slots := X.
|
|
proc_info_set_needs_maxfr_slot(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_needs_maxfr_slot := X.
|
|
proc_info_set_call_table_tip(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_call_table_tip := X.
|
|
proc_info_set_maybe_proc_table_io_info(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_maybe_table_io_info := X.
|
|
proc_info_set_table_attributes(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_table_attributes := X.
|
|
proc_info_set_obsolete_in_favour_of(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_proc_obsolete_in_favour_of := X.
|
|
proc_info_set_maybe_deep_profile_info(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_maybe_deep_prof_info := X.
|
|
proc_info_set_maybe_arg_size_info(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_maybe_arg_sizes := X.
|
|
proc_info_set_maybe_termination_info(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_maybe_termination := X.
|
|
proc_info_set_termination2_info(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_termination2 := X.
|
|
proc_info_set_exception_info(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_exception_info := X.
|
|
proc_info_set_trailing_info(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_trailing_info := X.
|
|
proc_info_set_mm_tabling_info(X, !PI) :-
|
|
!PI ^ proc_sub_info ^ psi_mm_tabling_info := X.
|
|
|
|
proc_info_get_structure_sharing(ProcInfo, MaybeSharing) :-
|
|
MaybeSharing = ProcInfo ^ proc_sub_info ^ psi_structure_sharing
|
|
^ maybe_sharing.
|
|
|
|
proc_info_set_structure_sharing(Sharing, !ProcInfo) :-
|
|
!ProcInfo ^ proc_sub_info ^ psi_structure_sharing ^ maybe_sharing :=
|
|
yes(Sharing).
|
|
|
|
proc_info_get_imported_structure_sharing(ProcInfo, HeadVars, Types, Sharing) :-
|
|
MaybeImportedSharing = ProcInfo ^ proc_sub_info ^ psi_structure_sharing
|
|
^ maybe_imported_sharing,
|
|
MaybeImportedSharing = yes(ImportedSharing),
|
|
ImportedSharing = imported_sharing(HeadVars, Types, Sharing).
|
|
|
|
proc_info_set_imported_structure_sharing(HeadVars, Types, Sharing,
|
|
!ProcInfo) :-
|
|
ImportedSharing = imported_sharing(HeadVars, Types, Sharing),
|
|
MaybeImportedSharing = yes(ImportedSharing),
|
|
!ProcInfo ^ proc_sub_info ^ psi_structure_sharing
|
|
^ maybe_imported_sharing := MaybeImportedSharing.
|
|
|
|
proc_info_reset_imported_structure_sharing(!ProcInfo) :-
|
|
!ProcInfo ^ proc_sub_info ^ psi_structure_sharing
|
|
^ maybe_imported_sharing := no.
|
|
|
|
proc_info_get_structure_reuse(ProcInfo, MaybeReuse) :-
|
|
MaybeReuse = ProcInfo ^ proc_sub_info ^ psi_structure_reuse ^ maybe_reuse.
|
|
|
|
proc_info_set_structure_reuse(Reuse, !ProcInfo) :-
|
|
!ProcInfo ^ proc_sub_info ^ psi_structure_reuse ^ maybe_reuse
|
|
:= yes(Reuse).
|
|
|
|
proc_info_get_imported_structure_reuse(ProcInfo, HeadVars, Types, Reuse) :-
|
|
MaybeImportedReuse = ProcInfo ^ proc_sub_info ^ psi_structure_reuse
|
|
^ maybe_imported_reuse,
|
|
MaybeImportedReuse = yes(ImportedReuse),
|
|
ImportedReuse = imported_reuse(HeadVars, Types, Reuse).
|
|
|
|
proc_info_set_imported_structure_reuse(HeadVars, Types, Reuse, !ProcInfo) :-
|
|
ImportedReuse = imported_reuse(HeadVars, Types, Reuse),
|
|
MaybeImportedReuse = yes(ImportedReuse),
|
|
!ProcInfo ^ proc_sub_info ^ psi_structure_reuse ^ maybe_imported_reuse :=
|
|
MaybeImportedReuse.
|
|
|
|
proc_info_reset_imported_structure_reuse(!ProcInfo) :-
|
|
!ProcInfo ^ proc_sub_info ^ psi_structure_reuse
|
|
^ maybe_imported_reuse := no.
|
|
|
|
proc_interface_should_use_typeinfo_liveness(PredInfo, ProcId, Globals,
|
|
InterfaceTypeInfoLiveness) :-
|
|
PredModule = pred_info_module(PredInfo),
|
|
PredName = pred_info_name(PredInfo),
|
|
pred_info_get_orig_arity(PredInfo, pred_form_arity(PredFormArityInt)),
|
|
( if no_type_info_builtin(PredModule, PredName, PredFormArityInt) then
|
|
InterfaceTypeInfoLiveness = no
|
|
else
|
|
pred_info_get_status(PredInfo, Status),
|
|
pred_info_get_proc_table(PredInfo, ProcTable),
|
|
map.lookup(ProcTable, ProcId, ProcInfo),
|
|
proc_info_get_is_address_taken(ProcInfo, IsAddressTaken),
|
|
non_special_interface_should_use_typeinfo_liveness(Status,
|
|
IsAddressTaken, Globals, InterfaceTypeInfoLiveness)
|
|
).
|
|
|
|
% Return true if the interface of a procedure in a non-special predicate
|
|
% with the given characteristics (import/export/local status,
|
|
% address taken status) must include typeinfos for all the type variables
|
|
% in the types of the arguments.
|
|
%
|
|
% Note that only a few predicates in the builtin modules are special
|
|
% in this sense, and that compiler-generated predicates are never special.
|
|
%
|
|
:- pred non_special_interface_should_use_typeinfo_liveness(pred_status::in,
|
|
is_address_taken::in, globals::in, bool::out) is det.
|
|
|
|
non_special_interface_should_use_typeinfo_liveness(PredStatus, IsAddressTaken,
|
|
Globals, InterfaceTypeInfoLiveness) :-
|
|
( if
|
|
(
|
|
IsAddressTaken = address_is_taken
|
|
;
|
|
% If the predicate is exported, its address may have
|
|
% been taken elsewhere. If it is imported, then it
|
|
% follows that it must be exported somewhere.
|
|
PredStatus \= pred_status(status_local)
|
|
;
|
|
% If term size profiling (of either form) is enabled,
|
|
% then we may need to access the typeinfo of any
|
|
% variable bound to a heap cell argument. The only way
|
|
% to ensure that this is possible is to preserve the
|
|
% ability to access the typeinfo of any variable.
|
|
globals.lookup_bool_option(Globals,
|
|
record_term_sizes_as_words, yes)
|
|
;
|
|
globals.lookup_bool_option(Globals,
|
|
record_term_sizes_as_cells, yes)
|
|
;
|
|
non_special_body_should_use_typeinfo_liveness(Globals, yes)
|
|
)
|
|
then
|
|
InterfaceTypeInfoLiveness = yes
|
|
else
|
|
InterfaceTypeInfoLiveness = no
|
|
).
|
|
|
|
body_should_use_typeinfo_liveness(PredInfo, Globals, BodyTypeInfoLiveness) :-
|
|
PredModule = pred_info_module(PredInfo),
|
|
PredName = pred_info_name(PredInfo),
|
|
pred_info_get_orig_arity(PredInfo, pred_form_arity(PredFormArityInt)),
|
|
( if no_type_info_builtin(PredModule, PredName, PredFormArityInt) then
|
|
BodyTypeInfoLiveness = no
|
|
else
|
|
non_special_body_should_use_typeinfo_liveness(Globals,
|
|
BodyTypeInfoLiveness)
|
|
).
|
|
|
|
% Return true if the body of a procedure in a non-special predicate
|
|
% must keep a typeinfo variable alive during the lifetime of all variables
|
|
% whose type includes the corresponding type variable.
|
|
%
|
|
:- pred non_special_body_should_use_typeinfo_liveness(globals::in,
|
|
bool::out) is det.
|
|
|
|
non_special_body_should_use_typeinfo_liveness(Globals, BodyTypeInfoLiveness) :-
|
|
globals.lookup_bool_option(Globals, body_typeinfo_liveness,
|
|
BodyTypeInfoLiveness).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Predicates to deal with record syntax.
|
|
|
|
:- interface.
|
|
|
|
% construct_field_access_function_name(AccessType, FieldName, FuncName):
|
|
%
|
|
% From the access type and the name of the field,
|
|
% construct a function name.
|
|
%
|
|
:- pred construct_field_access_function_name(field_access_type::in,
|
|
sym_name::in, sym_name::out) is det.
|
|
|
|
% is_field_access_function_name(ModuleInfo, FuncName, Arity,
|
|
% AccessType, FieldName, OoMFieldDefns):
|
|
%
|
|
% Inverse of the above.
|
|
%
|
|
% XXX ARITY The third argument should be either pred_form_arity or
|
|
% user_arity.
|
|
%
|
|
:- pred is_field_access_function_name(module_info::in, sym_name::in,
|
|
arity::out, field_access_type::out, sym_name::out,
|
|
one_or_more(hlds_ctor_field_defn)::out) is semidet.
|
|
|
|
:- pred pred_info_is_field_access_function(module_info::in, pred_info::in,
|
|
field_access_type::out, sym_name::out,
|
|
one_or_more(hlds_ctor_field_defn)::out) is semidet.
|
|
|
|
:- implementation.
|
|
|
|
construct_field_access_function_name(get, FieldName, FieldName).
|
|
construct_field_access_function_name(set, FieldName, FuncName) :-
|
|
add_sym_name_suffix(FieldName, " :=", FuncName).
|
|
|
|
is_field_access_function_name(ModuleInfo, FuncName,
|
|
Arity, AccessType, FieldName, OoMFieldDefns) :-
|
|
( if remove_sym_name_suffix(FuncName, " :=", FieldName0) then
|
|
Arity = 2,
|
|
AccessType = set,
|
|
FieldName = FieldName0
|
|
else
|
|
Arity = 1,
|
|
AccessType = get,
|
|
FieldName = FuncName
|
|
),
|
|
module_info_get_ctor_field_table(ModuleInfo, CtorFieldTable),
|
|
map.search(CtorFieldTable, FieldName, OoMFieldDefns).
|
|
|
|
pred_info_is_field_access_function(ModuleInfo, PredInfo,
|
|
Accesstype, FieldName, OoMFieldDefns) :-
|
|
pred_info_is_pred_or_func(PredInfo) = pf_function,
|
|
Module = pred_info_module(PredInfo),
|
|
Name = pred_info_name(PredInfo),
|
|
pred_info_get_orig_arity(PredInfo, PredFormArity),
|
|
user_arity_pred_form_arity(pf_function, user_arity(FuncArityInt),
|
|
PredFormArity),
|
|
is_field_access_function_name(ModuleInfo, qualified(Module, Name),
|
|
FuncArityInt, Accesstype, FieldName, OoMFieldDefns).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Predicates to deal with builtins.
|
|
|
|
:- interface.
|
|
|
|
% is_unify_pred(PredInfo) succeeds iff the PredInfo is for a
|
|
% compiler-generated instance of a type-specific unify predicate.
|
|
%
|
|
:- pred is_unify_pred(pred_info::in) is semidet.
|
|
|
|
% is_unify_index_or_compare_pred(PredInfo) succeeds iff the PredInfo
|
|
% is for a compiler generated instance of a type-specific special_pred
|
|
% (i.e. one of the unify, compare, or index predicates generated as
|
|
% a type-specific instance of unify/2, index/2, or compare/3).
|
|
%
|
|
:- pred is_unify_index_or_compare_pred(pred_info::in) is semidet.
|
|
|
|
% Is the argument the pred_info for a builtin that can be generated inline?
|
|
%
|
|
:- pred pred_info_is_builtin(pred_info::in) is semidet.
|
|
|
|
% builtin_state(ModuleInfo, CallerPredId, PredId, ProcId, BuiltinState)
|
|
%
|
|
% Is the given procedure a builtin that should be generated inline
|
|
% in the given caller?
|
|
%
|
|
:- func builtin_state(module_info, pred_id, pred_id, proc_id) = builtin_state.
|
|
|
|
% Succeeds iff PredInfo represents a promise of the given type.
|
|
%
|
|
:- pred pred_info_is_promise(pred_info::in, promise_type::out) is semidet.
|
|
|
|
:- implementation.
|
|
|
|
is_unify_pred(PredInfo) :-
|
|
pred_info_get_origin(PredInfo, Origin),
|
|
Origin = origin_compiler(made_for_uci(spec_pred_unify, _TypeCtor)).
|
|
|
|
is_unify_index_or_compare_pred(PredInfo) :-
|
|
pred_info_get_origin(PredInfo, Origin),
|
|
Origin = origin_compiler(made_for_uci(_SpecialPredId, _TypeCtor)).
|
|
|
|
pred_info_is_builtin(PredInfo) :-
|
|
ModuleName = pred_info_module(PredInfo),
|
|
PredName = pred_info_name(PredInfo),
|
|
PredFormArity = pred_info_pred_form_arity(PredInfo),
|
|
is_inline_builtin(ModuleName, PredName, PredFormArity).
|
|
|
|
builtin_state(ModuleInfo, CallerPredId, PredId, _ProcId) = BuiltinState :-
|
|
module_info_pred_info(ModuleInfo, PredId, PredInfo),
|
|
ModuleName = pred_info_module(PredInfo),
|
|
PredName = pred_info_name(PredInfo),
|
|
PredFormArity = pred_info_pred_form_arity(PredInfo),
|
|
( if
|
|
% XXX This should ask: is this an inline builtin FOR THIS BACKEND?
|
|
is_inline_builtin(ModuleName, PredName, PredFormArity),
|
|
(
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
globals.get_opt_tuple(Globals, OptTuple),
|
|
OptTuple ^ ot_allow_inlining = allow_inlining,
|
|
(
|
|
OptTuple ^ ot_inline_builtins = inline_builtins
|
|
;
|
|
PredName = "store_at_ref_impure",
|
|
ModuleName = mercury_private_builtin_module
|
|
)
|
|
;
|
|
% The "recursive" call in the automatically generated body
|
|
% of each builtin predicate MUST be generated inline.
|
|
% If it isn't generated inline, then any call to the predicate
|
|
% form of the builtin would fall into an infinite loop.
|
|
CallerPredId = PredId
|
|
)
|
|
then
|
|
BuiltinState = inline_builtin
|
|
else
|
|
BuiltinState = not_builtin
|
|
).
|
|
|
|
:- pred is_inline_builtin(module_name::in, string::in, pred_form_arity::in)
|
|
is semidet.
|
|
|
|
is_inline_builtin(ModuleName, PredName, PredFormArity) :-
|
|
PredFormArity = pred_form_arity(Arity),
|
|
% None of our inline builtins has an arity greater than three.
|
|
% Fail for predicates with arities of four or more *without*
|
|
% doing a switch on ModuleName or PredName.
|
|
Arity =< 3,
|
|
builtin_ops.test_if_builtin(ModuleName, PredName, Arity).
|
|
|
|
pred_info_is_promise(PredInfo, PromiseType) :-
|
|
pred_info_get_goal_type(PredInfo, goal_for_promise(PromiseType)).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module hlds.hlds_pred.
|
|
%---------------------------------------------------------------------------%
|