mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-18 02:43:40 +00:00
4649 lines
189 KiB
Mathematica
4649 lines
189 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1996-2012 The University of Melbourne.
|
|
% 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 check_hlds.
|
|
:- import_module check_hlds.mode_constraint_robdd.
|
|
:- import_module check_hlds.mode_errors.
|
|
:- 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_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.prog_type.
|
|
:- import_module parse_tree.set_of_var.
|
|
:- import_module parse_tree.var_table.
|
|
:- import_module parse_tree.vartypes.
|
|
:- import_module transform_hlds.
|
|
:- import_module transform_hlds.term_constr_main_types.
|
|
:- import_module transform_hlds.term_util.
|
|
|
|
:- import_module assoc_list.
|
|
:- 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 check_hlds.inst_match.
|
|
:- import_module check_hlds.mode_test.
|
|
:- import_module check_hlds.mode_util.
|
|
:- import_module check_hlds.type_util.
|
|
:- import_module hlds.goal_form.
|
|
:- import_module hlds.goal_util.
|
|
:- import_module hlds.hlds_args.
|
|
:- import_module hlds.hlds_data.
|
|
:- import_module libs.options.
|
|
:- import_module mdbcomp.builtin_modules.
|
|
:- import_module parse_tree.builtin_lib_types.
|
|
:- import_module parse_tree.prog_detism.
|
|
:- import_module parse_tree.prog_util.
|
|
|
|
:- import_module counter.
|
|
:- 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)
|
|
; generic_call_id(generic_call_id).
|
|
|
|
:- 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 pred_proc_list == list(pred_proc_id).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- 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.
|
|
|
|
% Predicates can be marked with various boolean flags, called "markers".
|
|
|
|
% A set of pred_markers.
|
|
:- type pred_markers == set(pred_marker).
|
|
|
|
:- type pred_marker
|
|
---> marker_stub
|
|
% The predicate has no clauses. typecheck.m will generate a body
|
|
% for the predicate which just throws an exception. This marker
|
|
% is used to tell purity analysis and determinism analysis
|
|
% not to issue warnings for these predicates.
|
|
|
|
; marker_builtin_stub
|
|
% This predicate is a builtin but has no clauses for whatever
|
|
% reason. typecheck.m should generate a stub clause for it but no
|
|
% warn about it.
|
|
|
|
; marker_infer_type
|
|
% Requests type inference for the predicate. These markers are
|
|
% inserted by make_hlds for undeclared predicates.
|
|
|
|
; marker_infer_modes
|
|
% Requests mode inference for the predicate. These markers are
|
|
% inserted by make_hlds for undeclared predicates.
|
|
|
|
; marker_no_pred_decl
|
|
% This predicate had no (valid) `:- pred' or `:- func' declaration.
|
|
% Since we have generated an error message about this, suppress
|
|
% the generation of any similar messages about missing mode
|
|
% declarations, since the missing (or invalid) declaration
|
|
% could have been a combined predmode declaration.
|
|
|
|
; marker_no_detism_warning
|
|
% Requests no warnings about the determinism of this predicate
|
|
% being too loose.
|
|
% Used for pragma(no_determinism_warning).
|
|
|
|
; marker_user_marked_inline
|
|
% The user requests that this be predicate should be inlined,
|
|
% even if it exceeds the usual size limits. Used for
|
|
% pragma(inline). Mutually exclusive with
|
|
% marker_user_marked_no_inline.
|
|
|
|
; marker_heuristic_inline
|
|
% The compiler (meaning probably inlining.m) requests that this
|
|
% predicate be inlined. Does not override
|
|
% marker_user_marked_no_inline.
|
|
|
|
; marker_user_marked_no_inline
|
|
% The user requests that this be predicate should not be inlined.
|
|
% Used for pragma(no_inline). Mutually exclusive with
|
|
% marker_user_marked_inline.
|
|
|
|
; marker_mmc_marked_no_inline
|
|
% The compiler requests that this be predicate should not be
|
|
% inlined. Used for pragma(mode_check_clauses). Mutually exclusive
|
|
% with marker_user_marked_inline.
|
|
|
|
; marker_consider_used
|
|
% The user has requested that this predicate be considered used
|
|
% when we consider which procedures are dead, so we can generate
|
|
% dead procedure warnings for them. If this marker is present
|
|
% on a predicate, then neither the procedures of this predicate
|
|
% nor the other procedures they call, directly or indirectly,
|
|
% should get dead procedure warnings.
|
|
|
|
; marker_class_method
|
|
% Requests that this predicate be transformed into the appropriate
|
|
% call to a class method.
|
|
|
|
; marker_class_instance_method
|
|
% This predicate was automatically generated for the implementation
|
|
% of a class method for an instance.
|
|
|
|
; marker_named_class_instance_method
|
|
% This predicate was automatically generated for the implementation
|
|
% of a class method for an instance, and the instance was defined
|
|
% using the named syntax (e.g. "pred(...) is ...") rather than
|
|
% the clause syntax. (For such predicates, we output slightly
|
|
% different error messages.)
|
|
|
|
; marker_is_impure
|
|
% Requests that no transformation that would be inappropriate for
|
|
% impure code be performed on calls to this predicate. This
|
|
% includes reordering calls to it relative to other goals
|
|
% (in both conjunctions and disjunctions), and removing
|
|
% redundant calls to it.
|
|
|
|
; marker_is_semipure
|
|
% Requests that no transformation that would be inappropriate
|
|
% for semipure code be performed on calls to this predicate.
|
|
% This includes removing redundant calls to it on different sides
|
|
% of an impure goal.
|
|
|
|
; marker_promised_pure
|
|
% Requests that calls to this predicate be transformed as usual,
|
|
% despite any impure or semipure markers present.
|
|
|
|
; marker_promised_semipure
|
|
% Requests that calls to this predicate be treated as semipure,
|
|
% despite any impure calls in the body.
|
|
|
|
; marker_promised_equivalent_clauses
|
|
% Promises that all modes of the predicate have equivalent
|
|
% semantics, event if they are defined by different sets of
|
|
% mode-specific clauses.
|
|
|
|
% The terminates and does_not_terminate pragmas are kept as markers
|
|
% to ensure that conflicting declarations are not made by the user.
|
|
% Otherwise, the information could be added to the ProcInfos directly.
|
|
|
|
; marker_terminates
|
|
% The user guarantees that this predicate will terminate
|
|
% for all (finite?) input.
|
|
|
|
; marker_does_not_terminate
|
|
% States that this predicate does not terminate. This is useful
|
|
% for pragma foreign_code, which the compiler assumes to be
|
|
% terminating.
|
|
|
|
; marker_check_termination
|
|
% The user requires the compiler to guarantee the termination
|
|
% of this predicate. If the compiler cannot guarantee termination
|
|
% then it must give an error message.
|
|
|
|
; marker_calls_are_fully_qualified
|
|
% All calls in this predicate are fully qualified. This occurs for
|
|
% predicates read from `.opt' files and compiler-generated
|
|
% predicates.
|
|
|
|
; marker_mode_check_clauses
|
|
% Each clause of the predicate should be modechecked separately.
|
|
% Used for predicates defined by lots of clauses (usually facts)
|
|
% for which the compiler's quadratic behavior during mode checking
|
|
% (in inst_match.bound_inst_list_contains_instname and
|
|
% instmap.merge) would be unacceptable.
|
|
|
|
; marker_mutable_access_pred
|
|
% This predicate is part of the machinery used to access mutables.
|
|
% This marker is used to inform inlining that we should _always_
|
|
% attempt to inline this predicate across module boundaries.
|
|
|
|
; marker_has_require_scope
|
|
% The body of this predicate contains a require_complete_switch
|
|
% or require_detism scope. This marker is set if applicable during
|
|
% determinism inference. It is used during determinism reporting:
|
|
% procedures in predicates that have this marker are checked
|
|
% for violations of the requirements of these scopes even if
|
|
% the overall determinism of the procedure body is correct.
|
|
|
|
; marker_has_incomplete_switch
|
|
% The body of this predicate contains an incomplete switch
|
|
% (one for which the switched-on variable may have a value
|
|
% that does not match any of the cases). This marker is set
|
|
% if applicable during determinism inference. It is used during
|
|
% determinism reporting: if the inform_incomplete_switch option
|
|
% is set, then procedures in predicates that have this marker
|
|
% are traversed again to generate informational messages about
|
|
% these incomplete switches, even if the overall determinism
|
|
% of the procedure body is correct.
|
|
|
|
; marker_has_format_call
|
|
% The body of this predicate contains calls to predicates
|
|
% recognized by format_call.is_format_call. This marker is set
|
|
% (if applicable) during determinism analysis, when the predicate
|
|
% body has to be traversed anyway. It is used by the simplification
|
|
% pass at the end of semantic analysis, both to warn about
|
|
% incorrect (or at least not verifiably correct) format calls,
|
|
% and to optimize correct format calls. Neither the warnings
|
|
% nor the optimizations can be applicable to predicates that
|
|
% do not contain format calls, as shown by not having this marker.
|
|
|
|
; marker_has_rhs_lambda
|
|
% The body of this predicate contains a unification whose
|
|
% right hand side is a lambda goal. This marker is set by
|
|
% the typecheck pass, and it is used (as of this writing)
|
|
% only by the post-typecheck pass.
|
|
|
|
; marker_fact_table_semantic_errors.
|
|
% This predicate has a fact_table pragma for it, so it is
|
|
% *expected* not to have any clauses in the program itself,
|
|
% but the compiler found some problems with its declaration,
|
|
% and so the compiler did not generate clauses (actually,
|
|
% foreign_procs) for it either. Therefore its procedures
|
|
% have no implementations, but there should be no separate
|
|
% error message about this: since they would probably generate
|
|
% more confusion than enlightenment. The error messages generated
|
|
% by fact_table.m should be entirely sufficient.
|
|
|
|
:- pred marker_name(pred_marker::in, string::out) is det.
|
|
|
|
:- type need_to_requantify
|
|
---> need_to_requantify
|
|
; do_not_need_to_requantify.
|
|
|
|
% 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
|
|
---> format_call(
|
|
% The context of the format_call pragma whose into
|
|
% 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,
|
|
prog_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, prog_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, string::out, arity::out, pred_or_func::out,
|
|
pred_origin::out, pred_status::out, pred_markers::out, list(mer_type)::out,
|
|
tvarset::out, tvarset::out, existq_tvars::out, int::out,
|
|
prog_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)::out,
|
|
list(mer_type)::out) is det.
|
|
|
|
:- pred pred_create(module_name::in, string::in, arity::in, pred_or_func::in,
|
|
pred_origin::in, pred_status::in, pred_markers::in, list(mer_type)::in,
|
|
tvarset::in, tvarset::in, existq_tvars::in, int::in, prog_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)::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, prog_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.
|
|
|
|
% 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.
|
|
|
|
% Pred_info_orig_arity returns the arity of the predicate
|
|
% *not* counting inserted type_info arguments for polymorphic preds.
|
|
%
|
|
:- func pred_info_orig_arity(pred_info) = arity.
|
|
:- func pred_info_pred_form_arity(pred_info) = pred_form_arity.
|
|
:- func pred_info_user_arity(pred_info) = user_arity.
|
|
|
|
% 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 pred_info_get_module_name(pred_info::in,
|
|
module_name::out) is det.
|
|
:- pred pred_info_get_name(pred_info::in,
|
|
string::out) is det.
|
|
:- pred pred_info_get_orig_arity(pred_info::in,
|
|
arity::out) is det.
|
|
:- pred pred_info_get_is_pred_or_func(pred_info::in,
|
|
pred_or_func::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,
|
|
prog_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(pred_info::in,
|
|
maybe(format_call)::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_name(string::in,
|
|
pred_info::in, pred_info::out) is det.
|
|
|
|
:- pred pred_info_set_orig_arity(arity::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_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(prog_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(maybe(format_call)::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 all the proc_ids for the valid modes of this predicate.
|
|
% This does not include candidate modes that were generated during mode
|
|
% inference but which mode inference found were not valid modes.
|
|
%
|
|
:- func pred_info_valid_procids(pred_info) = list(proc_id).
|
|
|
|
% Return a list of the proc_ids for all the modes of this predicate,
|
|
% including invalid modes.
|
|
%
|
|
:- func pred_info_all_procids(pred_info) = list(proc_id).
|
|
|
|
% Return a list of the proc_ids for all the valid modes of this predicate
|
|
% that are not imported.
|
|
%
|
|
:- func pred_info_valid_non_imported_procids(pred_info) = list(proc_id).
|
|
|
|
% Return a list of the proc_ids for all the modes of this predicate
|
|
% that are not imported (including invalid modes).
|
|
%
|
|
% XXX The implementation of this function is currently identical
|
|
% to the implementation of pred_info_non_imported_procids.
|
|
%
|
|
:- func pred_info_all_non_imported_procids(pred_info) = list(proc_id).
|
|
|
|
% Return a list of the proc_ids for all the valid modes of this predicate
|
|
% that are exported.
|
|
%
|
|
:- func pred_info_valid_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 purity_to_markers(purity::in, list(pred_marker)::out) is det.
|
|
|
|
:- 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.
|
|
|
|
% Create an empty set of markers.
|
|
%
|
|
:- pred init_markers(pred_markers::out) is det.
|
|
|
|
% Check if a particular is in the set.
|
|
%
|
|
:- pred check_marker(pred_markers::in, pred_marker::in) is semidet.
|
|
|
|
% Add some markers to the set.
|
|
%
|
|
:- pred add_marker(pred_marker::in,
|
|
pred_markers::in, pred_markers::out) is det.
|
|
:- pred add_markers(list(pred_marker)::in,
|
|
pred_markers::in, pred_markers::out) is det.
|
|
|
|
% Remove a marker from the set.
|
|
%
|
|
:- pred remove_marker(pred_marker::in,
|
|
pred_markers::in, pred_markers::out) is det.
|
|
|
|
% Convert the set to and from a list.
|
|
%
|
|
:- pred markers_to_marker_list(pred_markers::in, list(pred_marker)::out)
|
|
is det.
|
|
:- pred marker_list_to_markers(list(pred_marker)::in, pred_markers::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 check_marker(Markers, marker_calls_are_fully_qualified) then
|
|
is_fully_qualified
|
|
else
|
|
may_be_partially_qualified
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% For markers that we add to a predicate because of a pragma on that predicate,
|
|
% the marker name MUST correspond to the name of the pragma.
|
|
marker_name(marker_stub, "stub").
|
|
marker_name(marker_builtin_stub, "builtin_stub").
|
|
marker_name(marker_infer_type, "infer_type").
|
|
marker_name(marker_infer_modes, "infer_modes").
|
|
marker_name(marker_user_marked_inline, "inline").
|
|
marker_name(marker_heuristic_inline, "heuristic_inline").
|
|
marker_name(marker_no_pred_decl, "no_pred_decl").
|
|
marker_name(marker_user_marked_no_inline, "no_inline").
|
|
marker_name(marker_mmc_marked_no_inline, "mmc_no_inline").
|
|
marker_name(marker_consider_used, "consider_used").
|
|
marker_name(marker_no_detism_warning, "no_determinism_warning").
|
|
marker_name(marker_class_method, "class_method").
|
|
marker_name(marker_class_instance_method, "class_instance_method").
|
|
marker_name(marker_named_class_instance_method, "named_class_instance_method").
|
|
marker_name(marker_is_impure, "impure").
|
|
marker_name(marker_is_semipure, "semipure").
|
|
marker_name(marker_promised_pure, "promise_pure").
|
|
marker_name(marker_promised_semipure, "promise_semipure").
|
|
marker_name(marker_promised_equivalent_clauses, "promise_equivalent_clauses").
|
|
marker_name(marker_terminates, "terminates").
|
|
marker_name(marker_check_termination, "check_termination").
|
|
marker_name(marker_does_not_terminate, "does_not_terminate").
|
|
marker_name(marker_calls_are_fully_qualified, "calls_are_fully_qualified").
|
|
marker_name(marker_mode_check_clauses, "mode_check_clauses").
|
|
marker_name(marker_mutable_access_pred, "mutable_access_pred").
|
|
marker_name(marker_has_require_scope, "has_require_scope").
|
|
marker_name(marker_has_incomplete_switch, "has_incomplete_switch").
|
|
marker_name(marker_has_format_call, "has_format_call").
|
|
marker_name(marker_has_rhs_lambda, "has_rhs_lambda").
|
|
marker_name(marker_fact_table_semantic_errors, "fact_table_semantic_errors").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% 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,
|
|
|
|
% Predicate name.
|
|
/* 2 */ 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.
|
|
% XXX ARITY Make the type pred_form_arity.
|
|
/* 3 */ pi_orig_arity :: arity,
|
|
|
|
% Is this "predicate" really a predicate or a function?
|
|
/* 4 */ pi_is_pred_or_func :: pred_or_func,
|
|
|
|
% 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 :: prog_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 :: maybe(format_call),
|
|
|
|
% 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
|
|
PredFormArity = pred_form_arity(PredFormArityInt),
|
|
% 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),
|
|
% XXX ARITY The PredFormArityInt should be just PredFormArity.
|
|
PredInfo = pred_info(PredModuleName, PredName, PredFormArityInt,
|
|
PredOrFunc, 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, Arity),
|
|
% 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, PredName, Arity, PredOrFunc,
|
|
Origin, Status, Markers, ArgTypes, TypeVarSet, TypeVarSet,
|
|
ExistQVars, ClassContext, ClausesInfo, ProcTable, PredSubInfo).
|
|
|
|
pred_prepare_to_clone(PredInfo, ModuleName, PredName, Arity, PredOrFunc,
|
|
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, PredName, Arity, PredOrFunc,
|
|
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, PredName, Arity, PredOrFunc,
|
|
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, PredName, Arity, PredOrFunc,
|
|
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.
|
|
goal_util.goal_vars(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).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% 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_orig_arity(PI) = Arity :-
|
|
pred_info_get_orig_arity(PI, Arity).
|
|
pred_info_pred_form_arity(PI) = pred_form_arity(Arity) :-
|
|
pred_info_get_orig_arity(PI, Arity).
|
|
pred_info_user_arity(PI) = UserArity :-
|
|
pred_info_get_is_pred_or_func(PI, PredOrFunc),
|
|
PredFormArity = pred_info_pred_form_arity(PI),
|
|
user_arity_pred_form_arity(PredOrFunc, UserArity, PredFormArity).
|
|
pred_info_is_pred_or_func(PI) = X :-
|
|
pred_info_get_is_pred_or_func(PI, X).
|
|
|
|
pred_info_get_module_name(!.PI, X) :-
|
|
X = !.PI ^ pi_module_name.
|
|
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_is_pred_or_func(!.PI, X) :-
|
|
X = !.PI ^ pi_is_pred_or_func.
|
|
|
|
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(!.PI, X) :-
|
|
X = !.PI ^ pi_pred_sub_info ^ psi_format_call.
|
|
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_name(X, !PI) :-
|
|
!PI ^ pi_name := X.
|
|
pred_info_set_orig_arity(X, !PI) :-
|
|
!PI ^ pi_orig_arity := 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_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(X, !PI) :-
|
|
!PI ^ pi_pred_sub_info ^ psi_format_call := 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_valid_procids(PredInfo) = ValidProcIds :-
|
|
AllProcIds = pred_info_all_procids(PredInfo),
|
|
pred_info_get_proc_table(PredInfo, ProcTable),
|
|
IsValid =
|
|
( pred(ProcId::in) is semidet :-
|
|
ProcInfo = map.lookup(ProcTable, ProcId),
|
|
proc_info_is_valid_mode(ProcInfo)
|
|
),
|
|
list.filter(IsValid, AllProcIds, ValidProcIds).
|
|
|
|
pred_info_all_procids(PredInfo) = ProcIds :-
|
|
pred_info_get_proc_table(PredInfo, ProcTable),
|
|
map.keys(ProcTable, ProcIds).
|
|
|
|
pred_info_valid_non_imported_procids(PredInfo) = ProcIds :-
|
|
% The codes of pred_info_{valid,all}_non_imported_procids
|
|
% should be kept identical, except for the calls to
|
|
% pred_info_{valid,all}_procids respectively.
|
|
pred_info_get_status(PredInfo, pred_status(OldImportStatus)),
|
|
(
|
|
( OldImportStatus = status_imported(_)
|
|
; OldImportStatus = status_external(_)
|
|
),
|
|
ProcIds = []
|
|
;
|
|
OldImportStatus = status_pseudo_imported,
|
|
ProcIds0 = pred_info_valid_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_valid_procids(PredInfo)
|
|
).
|
|
|
|
pred_info_all_non_imported_procids(PredInfo) = ProcIds :-
|
|
% The codes of pred_info_{valid,all}_non_imported_procids
|
|
% should be kept identical, except for the calls to
|
|
% pred_info_{valid,all}_procids respectively.
|
|
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_valid_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_valid_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)
|
|
;
|
|
GoalType0 = goal_for_promise(_),
|
|
unexpected($pred, "promise")
|
|
),
|
|
% ( if GoalType = GoalType0 then
|
|
% % Avoid unnecessary memory allocation.
|
|
% true
|
|
% else
|
|
pred_info_set_goal_type(GoalType, !PredInfo).
|
|
% ).
|
|
|
|
pred_info_requested_inlining(PredInfo0) :-
|
|
pred_info_get_markers(PredInfo0, Markers),
|
|
( check_marker(Markers, marker_user_marked_inline)
|
|
; check_marker(Markers, marker_heuristic_inline)
|
|
).
|
|
|
|
pred_info_requested_no_inlining(PredInfo0) :-
|
|
pred_info_get_markers(PredInfo0, Markers),
|
|
( check_marker(Markers, marker_user_marked_no_inline)
|
|
; check_marker(Markers, marker_mmc_marked_no_inline)
|
|
).
|
|
|
|
pred_info_get_purity(PredInfo0, Purity) :-
|
|
pred_info_get_markers(PredInfo0, Markers),
|
|
( if check_marker(Markers, marker_is_impure) then
|
|
Purity = purity_impure
|
|
else if check_marker(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 check_marker(Markers, marker_promised_pure) then
|
|
MaybePromisedPurity = yes(purity_pure)
|
|
else if check_marker(Markers, marker_promised_semipure) then
|
|
MaybePromisedPurity = yes(purity_semipure)
|
|
else
|
|
MaybePromisedPurity = no
|
|
).
|
|
|
|
pred_info_infer_modes(PredInfo) :-
|
|
pred_info_get_markers(PredInfo, Markers),
|
|
check_marker(Markers, marker_infer_modes).
|
|
|
|
purity_to_markers(purity_pure, []).
|
|
purity_to_markers(purity_semipure, [marker_is_semipure]).
|
|
purity_to_markers(purity_impure, [marker_is_impure]).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
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).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
init_markers(set.init).
|
|
|
|
check_marker(MarkerSet, Marker) :-
|
|
set.member(Marker, MarkerSet).
|
|
|
|
add_marker(Marker, !MarkerSet) :-
|
|
set.insert(Marker, !MarkerSet).
|
|
|
|
add_markers(Markers, !MarkerSet) :-
|
|
set.insert_list(Markers, !MarkerSet).
|
|
|
|
remove_marker(Marker, !MarkerSet) :-
|
|
set.delete(Marker, !MarkerSet).
|
|
|
|
markers_to_marker_list(MarkerSet, Markers) :-
|
|
set.to_sorted_list(MarkerSet, Markers).
|
|
|
|
marker_list_to_markers(Markers, MarkerSet) :-
|
|
set.list_to_set(Markers, MarkerSet).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% 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 llds:layout_locn, but it refers to slots in
|
|
% the extended answer blocks used by I/O action tabling for declarative
|
|
% debugging, not to lvals.
|
|
:- 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, prog_vars)
|
|
).
|
|
|
|
:- 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, list(mode_error_info)::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, list(mode_error_info)::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_mode_errors(proc_info::in,
|
|
list(mode_error_info)::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_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_mode_errors(list(mode_error_info)::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 make_var_table(module_info::in, prog_varset::in, vartypes::in,
|
|
var_table::out) is det.
|
|
:- pred split_var_table(var_table::in, prog_varset::out, vartypes::out) is det.
|
|
|
|
:- pred vars_types_to_var_table(module_info::in, prog_varset::in,
|
|
assoc_list(prog_var, mer_type)::in, var_table::out) is det.
|
|
|
|
:- pred corresponding_vars_types_to_var_table(module_info::in, prog_varset::in,
|
|
list(prog_var)::in, list(mer_type)::in, var_table::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,
|
|
prog_vars::out, list(mer_type)::out, structure_sharing_domain::out)
|
|
is semidet.
|
|
|
|
:- pred proc_info_set_imported_structure_sharing(prog_vars::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,
|
|
prog_vars::out, list(mer_type)::out, structure_reuse_domain::out)
|
|
is semidet.
|
|
|
|
:- pred proc_info_set_imported_structure_reuse(prog_vars::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.
|
|
|
|
:- pred proc_info_head_modes_constraint(proc_info::in, mode_constraint::out)
|
|
is det.
|
|
:- pred proc_info_declared_argmodes(proc_info::in, list(mer_mode)::out) is det.
|
|
|
|
% See also proc_info_interface_code_model in code_model.m.
|
|
%
|
|
:- pred proc_info_interface_determinism(proc_info::in, determinism::out)
|
|
is det.
|
|
|
|
:- type can_proc_succeed
|
|
---> proc_can_maybe_succeed
|
|
; proc_cannot_succeed.
|
|
|
|
% Return whether the procedure can ever succeed according to
|
|
% its declared determinism. If it has no declared determinism,
|
|
% return proc_can_maybe_succeed.
|
|
%
|
|
:- pred proc_info_never_succeeds(proc_info::in, can_proc_succeed::out) is det.
|
|
|
|
:- pred proc_info_arglives(module_info::in, proc_info::in,
|
|
list(is_live)::out) is det.
|
|
:- pred proc_info_arg_info(proc_info::in, list(arg_info)::out) is det.
|
|
:- pred proc_info_get_initial_instmap(module_info::in, proc_info::in,
|
|
instmap::out) is det.
|
|
|
|
% Create a new variable of the given type to the procedure.
|
|
%
|
|
:- pred proc_info_create_var_from_type(string::in, mer_type::in,
|
|
is_dummy_type::in, prog_var::out, proc_info::in, proc_info::out) is det.
|
|
|
|
% Create a new variable for each element of the list of types.
|
|
%
|
|
:- pred proc_info_create_vars_from_types(module_info::in, list(mer_type)::in,
|
|
list(prog_var)::out, proc_info::in, proc_info::out) is det.
|
|
|
|
% Given a procedure, return a list of all its headvars which are
|
|
% (further) instantiated by the procedure.
|
|
%
|
|
:- pred proc_info_instantiated_head_vars(module_info::in, proc_info::in,
|
|
list(prog_var)::out) is det.
|
|
|
|
% Given a procedure, return a list of all its headvars which are
|
|
% not (further) instantiated by the procedure.
|
|
%
|
|
:- pred proc_info_uninstantiated_head_vars(module_info::in, proc_info::in,
|
|
list(prog_var)::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.
|
|
|
|
% If the procedure has a input/output pair of io.state arguments,
|
|
% return the positions of those arguments in the argument list.
|
|
% The positions are given as argument numbers, with the first argument
|
|
% in proc_info_get_headvars being position 1, and so on. The first output
|
|
% argument gives the position of the input state, the second the
|
|
% position of the output state.
|
|
%
|
|
% Note that the automatically constructed unify, index and compare
|
|
% procedures for the io:state type are not counted as having io:state
|
|
% args, since they do not fall into the scheme of one input and one
|
|
% output arg. Since they should never be called, this should not matter.
|
|
%
|
|
:- pred proc_info_has_io_state_pair(module_info::in, proc_info::in,
|
|
int::out, int::out) is semidet.
|
|
|
|
:- pred proc_info_has_io_state_pair_from_details(module_info::in,
|
|
var_table::in, list(prog_var)::in, list(mer_mode)::in,
|
|
int::out, int::out) is semidet.
|
|
|
|
:- pred proc_info_has_higher_order_arg_from_details(module_info::in,
|
|
var_table::in, list(prog_var)::in) is semidet.
|
|
|
|
% Given a procedure table and the id of a procedure in that table,
|
|
% return a procedure id to be attached to a clone of that procedure.
|
|
% (The task of creating the clone proc_info and inserting into the
|
|
% procedure table is the task of the caller.)
|
|
%
|
|
:- pred clone_proc_id(proc_table::in, proc_id::in, proc_id::out) is det.
|
|
|
|
% When mode inference is enabled, we record for each inferred mode
|
|
% whether it is valid or not by keeping a list of error messages
|
|
% in the proc_info. The mode is valid iff this list is empty.
|
|
%
|
|
:- pred proc_info_is_valid_mode(proc_info::in) is semidet.
|
|
|
|
% Make sure that all headvars are named. This can be useful e.g.
|
|
% because the debugger ignores unnamed variables.
|
|
%
|
|
:- pred ensure_all_headvars_are_named(proc_info::in, proc_info::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 seems to be the
|
|
% optimal arrangement (zs).
|
|
%
|
|
% XXX Fusing the varset and vartypes fields together into
|
|
% the var_table field has left room for a field to be
|
|
% "promoted" from the proc_sub_info to the proc_info.
|
|
|
|
/* 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,
|
|
|
|
% This field is used only by mode analysis and unique mode
|
|
% analysis. Almost all the time, it contains an empty list.
|
|
% XXX This info should be stored in a separate data structure
|
|
% maintained by mode analysis.
|
|
/* 12 */ proc_mode_errors :: list(mode_error_info),
|
|
|
|
/* 13 */ 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 :: prog_vars,
|
|
|
|
% 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 :: prog_vars,
|
|
|
|
% 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,
|
|
ModeErrors = [],
|
|
|
|
ProcInfo = proc_info(
|
|
HeadVars,
|
|
BodyGoal,
|
|
VarTable,
|
|
RttiVarMaps,
|
|
InstVarSet,
|
|
DeclaredModes,
|
|
Modes,
|
|
MaybeArgLives,
|
|
MaybeDeclaredDetism,
|
|
InferredDetism,
|
|
EvalMethod,
|
|
ModeErrors,
|
|
ProcSubInfo).
|
|
|
|
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,
|
|
ModeErrors = [],
|
|
|
|
ProcInfo = proc_info(
|
|
HeadVars,
|
|
Goal,
|
|
VarTable,
|
|
RttiVarMaps,
|
|
InstVarSet,
|
|
DeclaredModes,
|
|
Modes,
|
|
MaybeArgLives,
|
|
MaybeDeclaredDetism,
|
|
Detism,
|
|
EvalMethod,
|
|
ModeErrors,
|
|
ProcSubInfo).
|
|
|
|
proc_prepare_to_clone(ProcInfo, HeadVars, Goal, VarTable, RttiVarMaps,
|
|
InstVarSet, DeclaredModes, Modes, MaybeArgLives,
|
|
MaybeDeclaredDetism, Detism, EvalMethod, ModeErrors,
|
|
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,
|
|
ModeErrors,
|
|
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, ModeErrors,
|
|
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,
|
|
ModeErrors,
|
|
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_mode_errors(PI, X) :-
|
|
X = PI ^ proc_mode_errors.
|
|
|
|
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_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_mode_errors(X, !PI) :-
|
|
!PI ^ proc_mode_errors := 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.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
make_var_table(ModuleInfo, VarSet, VarTypes, VarTable) :-
|
|
vartypes_to_sorted_assoc_list(VarTypes, VarTypesAL),
|
|
make_var_table_loop(ModuleInfo, VarSet, 1, VarTypesAL,
|
|
[], RevVarTableAL0),
|
|
(
|
|
RevVarTableAL0 = [],
|
|
LastAllocVarNum0 = 0
|
|
;
|
|
RevVarTableAL0 = [Var - _ | _],
|
|
LastAllocVarNum0 = var_to_int(Var)
|
|
),
|
|
MaxVarInVarSet = varset.max_var(VarSet),
|
|
MaxVarNumInVarSet = var_to_int(MaxVarInVarSet),
|
|
( if MaxVarNumInVarSet > LastAllocVarNum0 then
|
|
LastAllocVarNum = MaxVarNumInVarSet,
|
|
extend_var_table_loop(VarSet, LastAllocVarNum0 + 1, LastAllocVarNum,
|
|
RevVarTableAL0, RevVarTableAL)
|
|
else
|
|
LastAllocVarNum = LastAllocVarNum0,
|
|
RevVarTableAL = RevVarTableAL0
|
|
),
|
|
counter.init(LastAllocVarNum + 1, Counter),
|
|
map.from_rev_sorted_assoc_list(RevVarTableAL, VarTableMap),
|
|
construct_var_table(Counter, VarTableMap, VarTable).
|
|
|
|
:- pred make_var_table_loop(module_info::in, prog_varset::in, int::in,
|
|
assoc_list(prog_var, mer_type)::in,
|
|
assoc_list(prog_var, var_table_entry)::in,
|
|
assoc_list(prog_var, var_table_entry)::out) is det.
|
|
|
|
make_var_table_loop(_, _, _, [], !RevVarTableAL).
|
|
make_var_table_loop(ModuleInfo, VarSet, CurVarNum, [Var - Type | VarsTypes0],
|
|
!RevVarTableAL) :-
|
|
VarNum = term.var_to_int(Var),
|
|
( if CurVarNum = VarNum then
|
|
( if varset.search_name(VarSet, Var, NamePrime) then
|
|
Name = NamePrime
|
|
else
|
|
Name = ""
|
|
),
|
|
IsDummy = is_type_a_dummy(ModuleInfo, Type),
|
|
Entry = vte(Name, Type, IsDummy),
|
|
!:RevVarTableAL = [Var - Entry | !.RevVarTableAL],
|
|
VarsTypes = VarsTypes0
|
|
else if CurVarNum < VarNum then
|
|
record_untyped_var(VarSet, CurVarNum, !RevVarTableAL),
|
|
% We did not Process Var in this iteration.
|
|
VarsTypes = [Var - Type | VarsTypes0]
|
|
else
|
|
unexpected($pred, "CurVarNum > VarNum")
|
|
),
|
|
make_var_table_loop(ModuleInfo, VarSet, CurVarNum + 1,
|
|
VarsTypes, !RevVarTableAL).
|
|
|
|
:- pred extend_var_table_loop(prog_varset::in, int::in, int::in,
|
|
assoc_list(prog_var, var_table_entry)::in,
|
|
assoc_list(prog_var, var_table_entry)::out) is det.
|
|
|
|
extend_var_table_loop(VarSet, CurVarNum, MaxVarNum, !RevVarTableAL) :-
|
|
( if CurVarNum =< MaxVarNum then
|
|
record_untyped_var(VarSet, CurVarNum, !RevVarTableAL),
|
|
extend_var_table_loop(VarSet, CurVarNum + 1, MaxVarNum, !RevVarTableAL)
|
|
else
|
|
true
|
|
).
|
|
|
|
% Record a variable number that was allocated in the varset,
|
|
% but whose type was not recorded.
|
|
%
|
|
% Before we started using var_tables, a lookup of such a variable
|
|
% would succeed in the varset but fail in the vartypes.
|
|
%
|
|
% The var_table we are constructing will have valid info for the name,
|
|
% but dummy info for the type.
|
|
%
|
|
:- pred record_untyped_var(prog_varset::in, int::in,
|
|
assoc_list(prog_var, var_table_entry)::in,
|
|
assoc_list(prog_var, var_table_entry)::out) is det.
|
|
|
|
record_untyped_var(VarSet, VarNum, !RevVarTableAL) :-
|
|
Var = force_construct_var(VarNum),
|
|
( if varset.search_name(VarSet, Var, NamePrime) then
|
|
Name = NamePrime
|
|
else
|
|
Name = ""
|
|
),
|
|
VarEntry = vte(Name, void_type, is_dummy_type),
|
|
!:RevVarTableAL = [Var - VarEntry | !.RevVarTableAL].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- 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).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
split_var_table(VarTable, VarSet, VarTypes) :-
|
|
deconstruct_var_table(VarTable, Counter, VarTableMap),
|
|
map.to_sorted_assoc_list(VarTableMap, VarsEntries),
|
|
split_var_table_loop(VarsEntries, [], RevVarTypes, [], RevVarNames),
|
|
vartypes_from_rev_sorted_assoc_list(RevVarTypes, VarTypes),
|
|
map.from_rev_sorted_assoc_list(RevVarNames, VarNameMap),
|
|
(
|
|
RevVarTypes = [],
|
|
LastVarNum = 0
|
|
;
|
|
RevVarTypes = [Var - _ | _],
|
|
LastVarNum = var_to_int(Var)
|
|
),
|
|
counter.allocate(NextVarNum, Counter, _),
|
|
expect(unify(LastVarNum + 1, NextVarNum), $pred,
|
|
"LastVarNum + 1 != NextVarNum"),
|
|
construct_varset(LastVarNum, VarNameMap, VarSet).
|
|
|
|
:- pred split_var_table_loop(assoc_list(prog_var, var_table_entry)::in,
|
|
assoc_list(prog_var, mer_type)::in, assoc_list(prog_var, mer_type)::out,
|
|
assoc_list(prog_var, string)::in, assoc_list(prog_var, string)::out)
|
|
is det.
|
|
|
|
split_var_table_loop([], !RevVarTypes, !RevVarNames).
|
|
split_var_table_loop([Var - Entry | VarsEntries],
|
|
!RevVarTypes, !RevVarNames) :-
|
|
Entry = vte(Name, Type, _IsDummy),
|
|
!:RevVarTypes = [Var - Type | !.RevVarTypes],
|
|
( if Name = "" then
|
|
true
|
|
else
|
|
!:RevVarNames = [Var - Name | !.RevVarNames]
|
|
),
|
|
split_var_table_loop(VarsEntries, !RevVarTypes, !RevVarNames).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
vars_types_to_var_table(ModuleInfo, VarSet, VarsTypes, VarTable) :-
|
|
vars_types_to_vars_entries(ModuleInfo, VarSet, VarsTypes, [], VarsEntries),
|
|
list.sort(VarsEntries, SortedVarsEntries),
|
|
var_table_from_sorted_assoc_list(SortedVarsEntries, VarTable).
|
|
|
|
:- pred vars_types_to_vars_entries(module_info::in, prog_varset::in,
|
|
assoc_list(prog_var, mer_type)::in,
|
|
assoc_list(prog_var, var_table_entry)::in,
|
|
assoc_list(prog_var, var_table_entry)::out) is det.
|
|
|
|
vars_types_to_vars_entries(_, _, [], !VarsEntries).
|
|
vars_types_to_vars_entries(ModuleInfo, VarSet, [Var - Type | VarsTypes],
|
|
!VarsEntries) :-
|
|
( if varset.search_name(VarSet, Var, Name0) then
|
|
Name = Name0
|
|
else
|
|
Name = ""
|
|
),
|
|
IsDummy = is_type_a_dummy(ModuleInfo, Type),
|
|
Entry = vte(Name, Type, IsDummy),
|
|
!:VarsEntries = [Var - Entry | !.VarsEntries],
|
|
vars_types_to_vars_entries(ModuleInfo, VarSet, VarsTypes, !VarsEntries).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
corresponding_vars_types_to_var_table(ModuleInfo, VarSet, Vars, Types,
|
|
VarTable) :-
|
|
corresponding_vars_types_to_vars_entries(ModuleInfo, VarSet, Vars, Types,
|
|
[], VarsEntries),
|
|
list.sort(VarsEntries, SortedVarsEntries),
|
|
var_table_from_sorted_assoc_list(SortedVarsEntries, VarTable).
|
|
|
|
:- pred corresponding_vars_types_to_vars_entries(module_info::in,
|
|
prog_varset::in, list(prog_var)::in, list(mer_type)::in,
|
|
assoc_list(prog_var, var_table_entry)::in,
|
|
assoc_list(prog_var, var_table_entry)::out) is det.
|
|
|
|
corresponding_vars_types_to_vars_entries(_, _, [], [], !VarsEntries).
|
|
corresponding_vars_types_to_vars_entries(_, _, [], [_ | _], !VarsEntries) :-
|
|
unexpected($pred, "length mismatch").
|
|
corresponding_vars_types_to_vars_entries(_, _, [_ | _], [], !VarsEntries) :-
|
|
unexpected($pred, "length mismatch").
|
|
corresponding_vars_types_to_vars_entries(ModuleInfo, VarSet,
|
|
[Var | Vars], [Type | Types], !VarsEntries) :-
|
|
( if varset.search_name(VarSet, Var, Name0) then
|
|
Name = Name0
|
|
else
|
|
Name = ""
|
|
),
|
|
IsDummy = is_type_a_dummy(ModuleInfo, Type),
|
|
Entry = vte(Name, Type, IsDummy),
|
|
!:VarsEntries = [Var - Entry | !.VarsEntries],
|
|
corresponding_vars_types_to_vars_entries(ModuleInfo, VarSet, Vars, Types,
|
|
!VarsEntries).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
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_info_head_modes_constraint(ProcInfo, HeadModesConstraint) :-
|
|
MaybeHeadModesConstraint =
|
|
ProcInfo ^ proc_sub_info ^ psi_maybe_head_modes_constr,
|
|
(
|
|
MaybeHeadModesConstraint = yes(HeadModesConstraint)
|
|
;
|
|
MaybeHeadModesConstraint = no,
|
|
unexpected($pred, "no constraint")
|
|
).
|
|
|
|
proc_info_declared_argmodes(ProcInfo, ArgModes) :-
|
|
proc_info_get_maybe_declared_argmodes(ProcInfo, MaybeArgModes),
|
|
(
|
|
MaybeArgModes = yes(ArgModes1),
|
|
ArgModes = ArgModes1
|
|
;
|
|
MaybeArgModes = no,
|
|
proc_info_get_argmodes(ProcInfo, ArgModes)
|
|
).
|
|
|
|
proc_info_interface_determinism(ProcInfo, Determinism) :-
|
|
proc_info_get_declared_determinism(ProcInfo, MaybeDeterminism),
|
|
(
|
|
MaybeDeterminism = no,
|
|
proc_info_get_inferred_determinism(ProcInfo, Determinism)
|
|
;
|
|
MaybeDeterminism = yes(Determinism)
|
|
).
|
|
|
|
% Return Result = yes if the called predicate is known to never succeed.
|
|
%
|
|
proc_info_never_succeeds(ProcInfo, CanSucceed) :-
|
|
proc_info_get_declared_determinism(ProcInfo, DeclaredDeterminism),
|
|
(
|
|
DeclaredDeterminism = no,
|
|
CanSucceed = proc_can_maybe_succeed
|
|
;
|
|
DeclaredDeterminism = yes(Determinism),
|
|
determinism_components(Determinism, _, MaxSoln),
|
|
(
|
|
MaxSoln = at_most_zero,
|
|
CanSucceed = proc_cannot_succeed
|
|
;
|
|
( MaxSoln = at_most_one
|
|
; MaxSoln = at_most_many
|
|
; MaxSoln = at_most_many_cc
|
|
),
|
|
CanSucceed = proc_can_maybe_succeed
|
|
)
|
|
).
|
|
|
|
proc_info_arglives(ModuleInfo, ProcInfo, ArgLives) :-
|
|
proc_info_get_maybe_arglives(ProcInfo, MaybeArgLives),
|
|
(
|
|
MaybeArgLives = yes(ArgLives0),
|
|
ArgLives = ArgLives0
|
|
;
|
|
MaybeArgLives = no,
|
|
proc_info_get_argmodes(ProcInfo, Modes),
|
|
get_arg_lives(ModuleInfo, Modes, ArgLives)
|
|
).
|
|
|
|
proc_info_arg_info(ProcInfo, ArgInfo) :-
|
|
proc_info_get_maybe_arg_info(ProcInfo, MaybeArgInfo0),
|
|
(
|
|
MaybeArgInfo0 = yes(ArgInfo)
|
|
;
|
|
MaybeArgInfo0 = no,
|
|
unexpected($pred, "arg_info not set")
|
|
).
|
|
|
|
proc_info_get_initial_instmap(ModuleInfo, ProcInfo, InstMap) :-
|
|
proc_info_get_headvars(ProcInfo, HeadVars),
|
|
proc_info_get_argmodes(ProcInfo, ArgModes),
|
|
mode_list_get_initial_insts(ModuleInfo, ArgModes, InitialInsts),
|
|
assoc_list.from_corresponding_lists(HeadVars, InitialInsts, InstAL),
|
|
InstMap = instmap_from_assoc_list(InstAL).
|
|
|
|
proc_info_create_var_from_type(Name, Type, IsDummy, Var, !ProcInfo) :-
|
|
proc_info_get_var_table(!.ProcInfo, VarTable0),
|
|
Entry = vte(Name, Type, IsDummy),
|
|
add_var_entry(Entry, Var, VarTable0, VarTable),
|
|
proc_info_set_var_table(VarTable, !ProcInfo).
|
|
|
|
proc_info_create_vars_from_types(ModuleInfo, Types, Vars, !ProcInfo) :-
|
|
proc_info_get_var_table(!.ProcInfo, VarTable0),
|
|
AddVar =
|
|
( pred(T::in, V::out, VT0::in, VT::out) is det :-
|
|
IsDummy = is_type_a_dummy(ModuleInfo, T),
|
|
Entry = vte("", T, IsDummy),
|
|
add_var_entry(Entry, V, VT0, VT)
|
|
),
|
|
list.map_foldl(AddVar, Types, Vars, VarTable0, VarTable),
|
|
proc_info_set_var_table(VarTable, !ProcInfo).
|
|
|
|
proc_info_instantiated_head_vars(ModuleInfo, ProcInfo, ChangedInstHeadVars) :-
|
|
proc_info_get_headvars(ProcInfo, HeadVars),
|
|
proc_info_get_argmodes(ProcInfo, ArgModes),
|
|
proc_info_get_var_table(ProcInfo, VarTable),
|
|
assoc_list.from_corresponding_lists(HeadVars, ArgModes, HeadVarModes),
|
|
IsInstChanged =
|
|
( pred(VarMode::in, Var::out) is semidet :-
|
|
VarMode = Var - Mode,
|
|
lookup_var_type(VarTable, Var, Type),
|
|
mode_get_insts(ModuleInfo, Mode, Inst1, Inst2),
|
|
not inst_matches_binding(ModuleInfo, Type, Inst1, Inst2)
|
|
),
|
|
list.filter_map(IsInstChanged, HeadVarModes, ChangedInstHeadVars).
|
|
|
|
proc_info_uninstantiated_head_vars(ModuleInfo, ProcInfo,
|
|
UnchangedInstHeadVars) :-
|
|
proc_info_get_headvars(ProcInfo, HeadVars),
|
|
proc_info_get_argmodes(ProcInfo, ArgModes),
|
|
proc_info_get_var_table(ProcInfo, VarTable),
|
|
assoc_list.from_corresponding_lists(HeadVars, ArgModes, HeadVarModes),
|
|
IsInstUnchanged =
|
|
( pred(VarMode::in, Var::out) is semidet :-
|
|
VarMode = Var - Mode,
|
|
lookup_var_type(VarTable, Var, Type),
|
|
mode_get_insts(ModuleInfo, Mode, Inst1, Inst2),
|
|
inst_matches_binding(ModuleInfo, Type, Inst1, Inst2)
|
|
),
|
|
list.filter_map(IsInstUnchanged, HeadVarModes, UnchangedInstHeadVars).
|
|
|
|
proc_interface_should_use_typeinfo_liveness(PredInfo, ProcId, Globals,
|
|
InterfaceTypeInfoLiveness) :-
|
|
PredModule = pred_info_module(PredInfo),
|
|
PredName = pred_info_name(PredInfo),
|
|
PredArity = pred_info_orig_arity(PredInfo),
|
|
( if no_type_info_builtin(PredModule, PredName, PredArity) 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),
|
|
PredArity = pred_info_orig_arity(PredInfo),
|
|
( if no_type_info_builtin(PredModule, PredName, PredArity) 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).
|
|
|
|
proc_info_has_io_state_pair(ModuleInfo, ProcInfo, InArgNum, OutArgNum) :-
|
|
proc_info_get_headvars(ProcInfo, HeadVars),
|
|
proc_info_get_argmodes(ProcInfo, ArgModes),
|
|
proc_info_get_var_table(ProcInfo, VarTable),
|
|
proc_info_has_io_state_pair_from_details(ModuleInfo, VarTable,
|
|
HeadVars, ArgModes, InArgNum, OutArgNum).
|
|
|
|
proc_info_has_io_state_pair_from_details(ModuleInfo, VarTable,
|
|
HeadVars, ArgModes, InArgNum, OutArgNum) :-
|
|
assoc_list.from_corresponding_lists(HeadVars, ArgModes, HeadVarsModes),
|
|
proc_info_has_io_state_pair_2(ModuleInfo, VarTable, 1, HeadVarsModes,
|
|
no, MaybeIn, no, MaybeOut),
|
|
( if
|
|
MaybeIn = yes(In),
|
|
MaybeOut = yes(Out)
|
|
then
|
|
InArgNum = In,
|
|
OutArgNum = Out
|
|
else
|
|
fail
|
|
).
|
|
|
|
:- pred proc_info_has_io_state_pair_2(module_info::in, var_table::in,
|
|
int::in, assoc_list(prog_var, mer_mode)::in,
|
|
maybe(int)::in, maybe(int)::out, maybe(int)::in, maybe(int)::out)
|
|
is semidet.
|
|
|
|
proc_info_has_io_state_pair_2(_, _, _, [], !MaybeIn, !MaybeOut).
|
|
proc_info_has_io_state_pair_2(ModuleInfo, VarTable, ArgNum,
|
|
[Var - Mode | VarModes], !MaybeIn, !MaybeOut) :-
|
|
( if
|
|
lookup_var_type(VarTable, Var, VarType),
|
|
type_is_io_state(VarType)
|
|
then
|
|
( if mode_is_fully_input(ModuleInfo, Mode) then
|
|
(
|
|
!.MaybeIn = no,
|
|
!:MaybeIn = yes(ArgNum)
|
|
;
|
|
!.MaybeIn = yes(_),
|
|
% Procedures with two input arguments of type io.state
|
|
% (e.g. the automatically generated unification or comparison
|
|
% procedure for the io.state type) do not fall into the
|
|
% one input/one output pattern we are looking for.
|
|
fail
|
|
)
|
|
else if mode_is_fully_output(ModuleInfo, Mode) then
|
|
(
|
|
!.MaybeOut = no,
|
|
!:MaybeOut = yes(ArgNum)
|
|
;
|
|
!.MaybeOut = yes(_),
|
|
% Procedures with two output arguments of type io.state
|
|
% do not fall into the one input/one output pattern we are
|
|
% looking for.
|
|
fail
|
|
)
|
|
else
|
|
fail
|
|
)
|
|
else
|
|
true
|
|
),
|
|
proc_info_has_io_state_pair_2(ModuleInfo, VarTable, ArgNum + 1,
|
|
VarModes, !MaybeIn, !MaybeOut).
|
|
|
|
proc_info_has_higher_order_arg_from_details(ModuleInfo, VarTable,
|
|
[HeadVar | HeadVars]) :-
|
|
(
|
|
lookup_var_type(VarTable, HeadVar, VarType),
|
|
type_is_higher_order(VarType)
|
|
;
|
|
proc_info_has_higher_order_arg_from_details(ModuleInfo, VarTable,
|
|
HeadVars)
|
|
).
|
|
|
|
clone_proc_id(ProcTable, _ProcId, CloneProcId) :-
|
|
find_lowest_unused_proc_id(ProcTable, CloneProcId).
|
|
|
|
:- pred find_lowest_unused_proc_id(proc_table::in, proc_id::out) is det.
|
|
|
|
find_lowest_unused_proc_id(ProcTable, CloneProcId) :-
|
|
find_lowest_unused_proc_id_2(0, ProcTable, CloneProcId).
|
|
|
|
:- pred find_lowest_unused_proc_id_2(proc_id::in, proc_table::in, proc_id::out)
|
|
is det.
|
|
|
|
find_lowest_unused_proc_id_2(TrialProcId, ProcTable, CloneProcId) :-
|
|
( if map.search(ProcTable, TrialProcId, _) then
|
|
find_lowest_unused_proc_id_2(TrialProcId + 1, ProcTable, CloneProcId)
|
|
else
|
|
CloneProcId = TrialProcId
|
|
).
|
|
|
|
proc_info_is_valid_mode(ProcInfo) :-
|
|
proc_info_get_mode_errors(ProcInfo, ModeErrors),
|
|
ModeErrors = [].
|
|
|
|
ensure_all_headvars_are_named(!ProcInfo) :-
|
|
proc_info_get_headvars(!.ProcInfo, HeadVars),
|
|
proc_info_get_var_table(!.ProcInfo, VarTable0),
|
|
ensure_all_headvars_are_named_loop(HeadVars, 1, VarTable0, VarTable),
|
|
proc_info_set_var_table(VarTable, !ProcInfo).
|
|
|
|
:- pred ensure_all_headvars_are_named_loop(list(prog_var)::in, int::in,
|
|
var_table::in, var_table::out) is det.
|
|
|
|
ensure_all_headvars_are_named_loop([], _, !VarTable).
|
|
ensure_all_headvars_are_named_loop([Var | Vars], SeqNum, !VarTable) :-
|
|
lookup_var_entry(!.VarTable, Var, Entry0),
|
|
Entry0 = vte(Name0, Type, IsDummy),
|
|
( if Name0 = "" then
|
|
Name = "HeadVar__" ++ int_to_string(SeqNum),
|
|
Entry = vte(Name, Type, IsDummy),
|
|
update_var_entry(Var, Entry, !VarTable)
|
|
else
|
|
true
|
|
),
|
|
ensure_all_headvars_are_named_loop(Vars, SeqNum + 1, !VarTable).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Predicates to deal with record syntax.
|
|
|
|
:- interface.
|
|
|
|
% field_extraction_function_args(Args, InputTermArg).
|
|
% Work out which arguments of a field access correspond to the
|
|
% field being extracted/set, and which are the container arguments.
|
|
%
|
|
:- pred field_extraction_function_args(list(prog_var)::in, prog_var::out)
|
|
is det.
|
|
|
|
% field_update_function_args(Args, InputTermArg, FieldArg).
|
|
%
|
|
:- pred field_update_function_args(list(prog_var)::in, prog_var::out,
|
|
prog_var::out) is det.
|
|
|
|
% field_access_function_name(AccessType, FieldName, FuncName).
|
|
%
|
|
% From the access type and the name of the field,
|
|
% construct a function name.
|
|
%
|
|
:- pred 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).
|
|
%
|
|
% Inverse of the above.
|
|
%
|
|
:- pred is_field_access_function_name(module_info::in, sym_name::in,
|
|
arity::out, field_access_type::out, sym_name::out) is semidet.
|
|
|
|
:- pred pred_info_is_field_access_function(module_info::in, pred_info::in)
|
|
is semidet.
|
|
|
|
:- implementation.
|
|
|
|
field_extraction_function_args(Args, TermInputArg) :-
|
|
( if Args = [TermInputArg0] then
|
|
TermInputArg = TermInputArg0
|
|
else
|
|
unexpected($pred, "num_args != 1")
|
|
).
|
|
|
|
field_update_function_args(Args, TermInputArg, FieldArg) :-
|
|
( if Args = [TermInputArg0, FieldArg0] then
|
|
FieldArg = FieldArg0,
|
|
TermInputArg = TermInputArg0
|
|
else
|
|
unexpected($pred, "num_args != 2")
|
|
).
|
|
|
|
field_access_function_name(get, FieldName, FieldName).
|
|
field_access_function_name(set, FieldName, FuncName) :-
|
|
add_sym_name_suffix(FieldName, " :=", FuncName).
|
|
|
|
is_field_access_function_name(ModuleInfo, FuncName, Arity,
|
|
AccessType, FieldName) :-
|
|
( 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.contains(CtorFieldTable, FieldName).
|
|
|
|
pred_info_is_field_access_function(ModuleInfo, PredInfo) :-
|
|
pred_info_is_pred_or_func(PredInfo) = pf_function,
|
|
Module = pred_info_module(PredInfo),
|
|
Name = pred_info_name(PredInfo),
|
|
PredArity = pred_info_orig_arity(PredInfo),
|
|
adjust_func_arity(pf_function, FuncArity, PredArity),
|
|
is_field_access_function_name(ModuleInfo, qualified(Module, Name),
|
|
FuncArity, _, _).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% 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)).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- interface.
|
|
|
|
% Check if the given evaluation method is allowed with
|
|
% the given determinism.
|
|
%
|
|
:- func valid_determinism_for_tabled_eval_method(tabled_eval_method,
|
|
determinism) = bool.
|
|
|
|
% Return true if the given evaluation method requires a
|
|
% stratification check.
|
|
%
|
|
:- func tabled_eval_method_needs_stratification(tabled_eval_method) = bool.
|
|
|
|
% Return true if the given evaluation method uses a per-procedure
|
|
% tabling pointer. If so, the back-end must generate a declaration
|
|
% for the variable to hold the table.
|
|
%
|
|
:- func tabled_eval_method_has_per_proc_tabling_pointer(tabled_eval_method)
|
|
= bool.
|
|
|
|
% Return true if the given evaluation method requires the arguments
|
|
% of the procedure using it to be non-unique.
|
|
%
|
|
:- func tabled_eval_method_destroys_uniqueness(tabled_eval_method) = bool.
|
|
|
|
% Return the change a given evaluation method can do to a given
|
|
% determinism.
|
|
%
|
|
:- func eval_method_change_determinism(eval_method, determinism) = determinism.
|
|
|
|
:- implementation.
|
|
|
|
valid_determinism_for_tabled_eval_method(TabledMethod, Detism) = Valid :-
|
|
(
|
|
( TabledMethod = tabled_loop_check
|
|
; TabledMethod = tabled_memo(_)
|
|
),
|
|
determinism_components(Detism, _, MaxSoln),
|
|
(
|
|
MaxSoln = at_most_zero,
|
|
Valid = no
|
|
;
|
|
( MaxSoln = at_most_one
|
|
; MaxSoln = at_most_many
|
|
; MaxSoln = at_most_many_cc
|
|
),
|
|
Valid = yes
|
|
)
|
|
;
|
|
TabledMethod = tabled_io(_, _),
|
|
unexpected($pred, "called after tabling phase")
|
|
;
|
|
TabledMethod = tabled_minimal(_),
|
|
% The following reasons specify why a particular determinism is
|
|
% incompatible with minimal model tabling.
|
|
%
|
|
% Reason 1:
|
|
% Determinism analysis isn't yet smart enough to know whether
|
|
% a cannot_fail execution path is guaranteed not to go through a call
|
|
% to a predicate that is mutually recursive with this one, which
|
|
% (if this predicate is minimal model) is the only way that the
|
|
% predicate can be properly cannot_fail. The problem is that
|
|
% in general, the mutually recursive predicate may be in
|
|
% another module.
|
|
%
|
|
% Reason 2:
|
|
% The transformation, as currently implemented, assumes that
|
|
% it is possible to reach the call table tip, and generates HLDS
|
|
% that refers to the introduced variable representing this tip.
|
|
% This variable however, will be optimized away if the code
|
|
% cannot succeed, causing a code generator abort.
|
|
%
|
|
% Reason 3:
|
|
% Minimal model semantics requires computing to a fixpoint, and
|
|
% this is incompatible with the notion of committed choice.
|
|
%
|
|
% Reason 4:
|
|
% Doing the analysis required to ensure that a predicate can't have
|
|
% more than one solution is much harder if the predicate concerned is
|
|
% minimal_model. In theory, this analysis could be done, but it would
|
|
% take a lot of programming, and since there is a simple workaround
|
|
% (make the predicate nondet, and check the number of solutions at the
|
|
% caller), this would not be cost-effective.
|
|
(
|
|
Detism = detism_det,
|
|
Valid = no % Reason 1
|
|
;
|
|
Detism = detism_semi,
|
|
Valid = no % Reason 4
|
|
;
|
|
Detism = detism_multi, % Reason 1
|
|
Valid = yes
|
|
;
|
|
Detism = detism_non,
|
|
Valid = yes
|
|
;
|
|
Detism = detism_cc_multi, % Reason 3
|
|
Valid = no
|
|
;
|
|
Detism = detism_cc_non, % Reason 3
|
|
Valid = no
|
|
;
|
|
Detism = detism_erroneous, % Reason 2
|
|
Valid = no
|
|
;
|
|
Detism = detism_failure, % Reason 2
|
|
Valid = no
|
|
)
|
|
).
|
|
|
|
tabled_eval_method_needs_stratification(TabledMethod) = NeedsStratification :-
|
|
(
|
|
( TabledMethod = tabled_loop_check
|
|
; TabledMethod = tabled_memo(_)
|
|
; TabledMethod = tabled_io(_, _)
|
|
),
|
|
NeedsStratification = no
|
|
;
|
|
TabledMethod = tabled_minimal(_),
|
|
NeedsStratification = yes
|
|
).
|
|
|
|
tabled_eval_method_has_per_proc_tabling_pointer(TabledMethod) = TablingPtr :-
|
|
(
|
|
( TabledMethod = tabled_io(_, _)
|
|
; TabledMethod = tabled_minimal(own_stacks_consumer)
|
|
),
|
|
TablingPtr = no
|
|
;
|
|
( TabledMethod = tabled_loop_check
|
|
; TabledMethod = tabled_memo(_)
|
|
; TabledMethod = tabled_minimal(stack_copy)
|
|
; TabledMethod = tabled_minimal(own_stacks_generator)
|
|
),
|
|
TablingPtr = yes
|
|
).
|
|
|
|
tabled_eval_method_destroys_uniqueness(tabled_loop_check) = yes.
|
|
tabled_eval_method_destroys_uniqueness(tabled_io(_, _)) = no.
|
|
tabled_eval_method_destroys_uniqueness(tabled_memo(_)) = yes.
|
|
tabled_eval_method_destroys_uniqueness(tabled_minimal(_)) = yes.
|
|
|
|
eval_method_change_determinism(eval_normal, Detism) = Detism.
|
|
eval_method_change_determinism(eval_tabled(TabledMethoed), Detism) =
|
|
tabled_eval_method_change_determinism(TabledMethoed, Detism).
|
|
|
|
:- func tabled_eval_method_change_determinism(tabled_eval_method, determinism)
|
|
= determinism.
|
|
|
|
tabled_eval_method_change_determinism(tabled_loop_check, Detism) = Detism.
|
|
tabled_eval_method_change_determinism(tabled_io(_, _), Detism) = Detism.
|
|
tabled_eval_method_change_determinism(tabled_memo(_), Detism) = Detism.
|
|
tabled_eval_method_change_determinism(tabled_minimal(_), Detism0) = Detism :-
|
|
det_conjunction_detism(detism_semi, Detism0, Detism).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module hlds.hlds_pred.
|
|
%---------------------------------------------------------------------------%
|