for review: changes to termination analysis and stack tracing [2/3]
Zoltan Somogyi
zs at cs.mu.oz.au
Tue Dec 2 15:19:58 AEDT 1997
[continued from part 1]
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
% Copyright (C) 1997 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.
%-----------------------------------------------------------------------------%
%
% term_util.m
% Main author: crs.
%
% This module:
%
% - defines the types used by termination analysis
% - defines predicates for computing functor norms
% - defines some utility predicates
%
%-----------------------------------------------------------------------------%
:- module term_util.
:- interface.
:- import_module term_errors, prog_data.
:- import_module hlds_module, hlds_pred, hlds_data, hlds_goal.
:- import_module bool, int, list, map, bag, term.
%-----------------------------------------------------------------------------%
% The arg size info defines an upper bound on the difference
% between the sizes of the output arguments of a procedure and the sizes
% of the input arguments:
%
% | input arguments | + constant >= | output arguments |
%
% where | | represents a semilinear norm.
:- type arg_size_info
---> finite(int, list(bool))
% The termination constant is a finite integer.
% The list of bool has a 1:1 correspondance
% with the input arguments of the procedure.
% It stores whether the argument contributes
% to the size of the output arguments.
; infinite(list(term_errors__error)).
% There is no finite integer for which the
% above equation is true. The argument says
% why the analysis failed to find a finite
% constant.
:- type termination_info
---> cannot_loop % This procedure terminates for all
% possible inputs.
; can_loop(list(term_errors__error)).
% The analysis could not prove that the
% procedure terminates.
:- type used_args == map(pred_proc_id, list(bool)).
%-----------------------------------------------------------------------------%
% We use semilinear norms (denoted by ||) to compute the sizes of terms.
% These have the form
%
% | f(t1, ... tn) | = weight(f) + sum of | ti |
% where i is an element of a set I, and I is a subset of {1, ... n}
%
% We currently support four kinds of semilinear norms.
:- type functor_info
---> simple % All non-constant functors have weight 1,
% while constants have weight 0.
% Use the size of all subterms (I = {1, ..., n}.
; total % All functors have weight = arity of the functor.
% Use the size of all subterms (I = {1, ..., n}.
; use_map(weight_table)
% The weight of each functor is given by the table.
% Use the size of all subterms (I = {1, ..., n}.
; use_map_and_args(weight_table).
% The weight of each functor is given by the table,
% and so is the set of arguments of the functor whose
% size should be counted (I is given by the table
% entry of the functor).
:- type unify_info == pair(map(var, type), functor_info).
:- type weight_info ---> weight(int, list(bool)).
:- type weight_table == map(pair(type_id, cons_id), weight_info).
:- pred find_weights(module_info::in, weight_table::out) is det.
% This predicate is computes the weight of a functor and the set of arguments
% of that functor whose sizes should be counted towards the size of the whole
% term.
:- pred functor_norm(functor_info::in, type_id::in, cons_id::in,
module_info::in, int::out, list(var)::in, list(var)::out,
list(uni_mode)::in, list(uni_mode)::out) is det.
%-----------------------------------------------------------------------------%
% This predicate partitions the arguments of a call into a list of input
% variables and a list of output variables,
:- pred partition_call_args(module_info::in, list(mode)::in, list(var)::in,
bag(var)::out, bag(var)::out) is det.
% Given a list of variables from a unification, this predicate divides the
% list into a bag of input variables, and a bag of output variables.
:- pred split_unification_vars(list(var)::in, list(uni_mode)::in,
module_info::in, bag(var)::out, bag(var)::out) is det.
% Used to create lists of boolean values, which are used for used_args.
% make_bool_list(HeadVars, BoolIn, BoolOut) creates a bool list which is
% (length(HeadVars) - length(BoolIn)) `no' followed by BoolIn. This is
% used to set the used args for compiler generated predicates. The no's
% at the start are because the Type infos are not used. length(BoolIn)
% should equal the arity of the predicate, and the difference in length
% between the arity of the procedure and the arity of the predicate is
% the number of type infos.
:- pred term_util__make_bool_list(list(_T)::in, list(bool)::in,
list(bool)::out) is det.
% Removes variables from the InVarBag that are not used in the call.
% remove_unused_args(InVarBag0, VarList, BoolList, InVarBag)
% VarList and BoolList are corresponding lists. Any variable in VarList
% that has a `no' in the corresponding place in the BoolList is removed
% from InVarBag.
:- pred remove_unused_args(bag(var), list(var), list(bool), bag(var)).
:- mode remove_unused_args(in, in, in, out) is det.
% This predicate sets the argument size info of a given a list of procedures.
:- pred set_pred_proc_ids_arg_size_info(list(pred_proc_id)::in,
arg_size_info::in, module_info::in, module_info::out) is det.
% This predicate sets the termination info of a given a list of procedures.
:- pred set_pred_proc_ids_termination_info(list(pred_proc_id)::in,
termination_info::in, module_info::in, module_info::out) is det.
:- pred lookup_proc_termination_info(module_info::in, pred_proc_id::in,
maybe(termination_info)::out) is det.
:- pred lookup_proc_arg_size_info(module_info::in, pred_proc_id::in,
maybe(arg_size_info)::out) is det.
% Succeeds if one or more variables in the list are higher order.
:- pred horder_vars(list(var), map(var, type)).
:- mode horder_vars(in, in) is semidet.
% Succeeds if all values of the given type are zero size (for all norms).
:- pred zero_size_type(type, module_info).
:- mode zero_size_type(in, in) is semidet.
:- pred get_context_from_scc(list(pred_proc_id)::in, module_info::in,
term__context::out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module inst_match, prog_out, mode_util, type_util.
:- import_module globals, options.
:- import_module io, std_util, assoc_list, require.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
% Calculate the weight to be assigned to each function symbol for the
% use_map and use_map_and_args semilinear norms.
%
% Given a type definition such as
%
% :- type t(Tk) ---> f1(a11, ... a1n1) where n1 is the arity of f1
% ; ...
% ; fm(am1, ... amnm) where nm is the arity of fm
%
% we check, for each aij, whether its type is recursive (i.e. it is t with
% type variable arguments that are a permutation of Tk). The weight info
% we compute for each functor will have a boolean list that has a `yes'
% for each recursive argument and a `no' for each nonrecursive argument.
% The weight to be assigned to the functor is the number of nonrecursive
% arguments, except that we assign a weight of at least 1 to all functors
% which are not constants.
find_weights(ModuleInfo, Weights) :-
module_info_types(ModuleInfo, TypeTable),
map__to_assoc_list(TypeTable, TypeList),
map__init(Weights0),
find_weights_for_type_list(TypeList, Weights0, Weights).
:- pred find_weights_for_type_list(assoc_list(type_id, hlds_type_defn)::in,
weight_table::in, weight_table::out) is det.
find_weights_for_type_list([], Weights, Weights).
find_weights_for_type_list([TypeId - TypeDefn | TypeList], Weights0, Weights) :-
find_weights_for_type(TypeId, TypeDefn, Weights0, Weights1),
find_weights_for_type_list(TypeList, Weights1, Weights).
:- pred find_weights_for_type(type_id::in, hlds_type_defn::in,
weight_table::in, weight_table::out) is det.
find_weights_for_type(TypeId, TypeDefn, Weights0, Weights) :-
hlds_data__get_type_defn_body(TypeDefn, TypeBody),
(
TypeBody = du_type(Constructors, _, _, _),
hlds_data__get_type_defn_tparams(TypeDefn, TypeParams),
find_weights_for_cons_list(Constructors, TypeId, TypeParams,
Weights0, Weights)
;
TypeBody = uu_type(_),
error("undiscriminated union types not yet implemented")
;
% This type does not introduce any functors
TypeBody = eqv_type(_),
Weights = Weights0
;
% This type may introduce some functors,
% but we will never see them in this analysis
TypeBody = abstract_type,
Weights = Weights0
).
:- pred find_weights_for_cons_list(list(constructor)::in,
type_id::in, list(type_param)::in,
weight_table::in, weight_table::out) is det.
find_weights_for_cons_list([], _, _, Weights, Weights).
find_weights_for_cons_list([Constructor | Constructors], TypeId, Params,
Weights0, Weights) :-
find_weights_for_cons(Constructor, TypeId, Params, Weights0, Weights1),
find_weights_for_cons_list(Constructors, TypeId, Params,
Weights1, Weights).
:- pred find_weights_for_cons(constructor::in,
type_id::in, list(type_param)::in,
weight_table::in, weight_table::out) is det.
find_weights_for_cons(SymName - Args, TypeId, Params, Weights0, Weights) :-
list__length(Args, Arity),
( Arity > 0 ->
find_and_count_nonrec_args(Args, TypeId, Params,
NumNonRec, ArgInfos0),
( NumNonRec = 0 ->
Weight = 1,
list__duplicate(Arity, yes, ArgInfos)
;
Weight = NumNonRec,
ArgInfos = ArgInfos0
),
WeightInfo = weight(Weight, ArgInfos)
;
WeightInfo = weight(0, [])
),
ConsId = cons(SymName, Arity),
map__det_insert(Weights0, TypeId - ConsId, WeightInfo, Weights).
:- pred find_and_count_nonrec_args(list(constructor_arg)::in,
type_id::in, list(type_param)::in,
int::out, list(bool)::out) is det.
find_and_count_nonrec_args([], _, _, 0, []).
find_and_count_nonrec_args([Arg | Args], Id, Params, NonRecArgs, ArgInfo) :-
find_and_count_nonrec_args(Args, Id, Params, NonRecArgs0, ArgInfo0),
( is_arg_recursive(Arg, Id, Params) ->
NonRecArgs = NonRecArgs0,
ArgInfo = [yes | ArgInfo0]
;
NonRecArgs is NonRecArgs0 + 1,
ArgInfo = [no | ArgInfo0]
).
:- pred is_arg_recursive(constructor_arg::in,
type_id::in, list(type_param)::in) is semidet.
is_arg_recursive(Arg, Id, Params) :-
Arg = _Name - ArgType,
type_to_type_id(ArgType, ArgTypeId, ArgTypeParams),
Id = ArgTypeId,
list__perm(Params, ArgTypeParams).
%-----------------------------------------------------------------------------%
% Although the module info is not used in either of these norms, it could
% be needed for other norms, so it should not be removed.
functor_norm(simple, _, ConsId, _, Int, Args, Args, Modes, Modes) :-
(
ConsId = cons(_, Arity),
Arity \= 0
->
Int = 1
;
Int = 0
).
functor_norm(total, _, ConsId, _Module, Int, Args, Args, Modes, Modes) :-
( ConsId = cons(_, Arity) ->
Int = Arity
;
Int = 0
).
functor_norm(use_map(WeightMap), TypeId, ConsId, _Module, Int,
Args, Args, Modes, Modes) :-
( map__search(WeightMap, TypeId - ConsId, WeightInfo) ->
WeightInfo = weight(Int, _)
;
Int = 0
).
functor_norm(use_map_and_args(WeightMap), TypeId, ConsId, _Module, Int,
Args0, Args, Modes0, Modes) :-
( map__search(WeightMap, TypeId - ConsId, WeightInfo) ->
WeightInfo = weight(Int, UseArgList),
(
functor_norm_filter_args(UseArgList, Args0, Args1,
Modes0, Modes1)
->
Modes = Modes1,
Args = Args1
;
error("Unmatched lists in functor_norm_filter_args.")
)
;
Int = 0,
Modes = Modes0,
Args = Args0
).
% This predicate will fail if the length of the input lists are not matched.
:- pred functor_norm_filter_args(list(bool), list(var), list(var),
list(uni_mode), list(uni_mode)).
:- mode functor_norm_filter_args(in, in, out, in, out) is semidet.
functor_norm_filter_args([], [], [], [], []).
functor_norm_filter_args([yes | Bools], [Arg0 | Args0], [Arg0 | Args],
[Mode0 | Modes0], [Mode0 | Modes]) :-
functor_norm_filter_args(Bools, Args0, Args, Modes0, Modes).
functor_norm_filter_args([no | Bools], [_Arg0 | Args0], Args,
[_Mode0 | Modes0], Modes) :-
functor_norm_filter_args(Bools, Args0, Args, Modes0, Modes).
%-----------------------------------------------------------------------------%
partition_call_args(Module, ArgModes, Args, InVarsBag, OutVarsBag) :-
partition_call_args_2(Module, ArgModes, Args, InVars, OutVars),
bag__from_list(InVars, InVarsBag),
bag__from_list(OutVars, OutVarsBag).
:- pred partition_call_args_2(module_info::in, list(mode)::in, list(var)::in,
list(var)::out, list(var)::out) is det.
partition_call_args_2(_, [], [], [], []).
partition_call_args_2(_, [], [_ | _], _, _) :-
error("Unmatched variables in term_util:partition_call_args").
partition_call_args_2(_, [_ | _], [], _, _) :-
error("Unmatched variables in term_util__partition_call_args").
partition_call_args_2(ModuleInfo, [ArgMode | ArgModes], [Arg | Args],
InputArgs, OutputArgs) :-
partition_call_args_2(ModuleInfo, ArgModes, Args,
InputArgs1, OutputArgs1),
( mode_is_input(ModuleInfo, ArgMode) ->
InputArgs = [Arg | InputArgs1],
OutputArgs = OutputArgs1
; mode_is_output(ModuleInfo, ArgMode) ->
InputArgs = InputArgs1,
OutputArgs = [Arg | OutputArgs1]
;
InputArgs = InputArgs1,
OutputArgs = OutputArgs1
).
% For these next two predicates (split_unification_vars and
% partition_call_args) there is a problem of what needs to be done for
% partially instantiated data structures. The correct answer is that the
% system shoud use a norm such that the size of the uninstantiated parts of
% a partially instantiated structure have no effect on the size of the data
% structure according to the norm. For example when finding the size of a
% list-skeleton, list-length norm should be used. Therefore, the size of
% any term must be given by
% sizeof(term) = constant + sum of the size of each
% (possibly partly) instantiated subterm.
% It is probably easiest to implement this by modifying term_weights.
% The current implementation does not correctly handle partially
% instantiated data structures.
split_unification_vars([], Modes, _ModuleInfo, Vars, Vars) :-
bag__init(Vars),
( Modes = [] ->
true
;
error("term_util:split_unification_vars: Unmatched Variables")
).
split_unification_vars([Arg | Args], Modes, ModuleInfo,
InVars, OutVars):-
( Modes = [UniMode | UniModes] ->
split_unification_vars(Args, UniModes, ModuleInfo,
InVars0, OutVars0),
UniMode = ((_VarInit - ArgInit) -> (_VarFinal - ArgFinal)),
( % if
inst_is_bound(ModuleInfo, ArgInit)
->
% Variable is an input variable
bag__insert(InVars0, Arg, InVars),
OutVars = OutVars0
; % else if
inst_is_free(ModuleInfo, ArgInit),
inst_is_bound(ModuleInfo, ArgFinal)
->
% Variable is an output variable
InVars = InVars0,
bag__insert(OutVars0, Arg, OutVars)
; % else
InVars = InVars0,
OutVars = OutVars0
)
;
error("term_util__split_unification_vars: Unmatched Variables")
).
%-----------------------------------------------------------------------------%
term_util__make_bool_list(HeadVars0, Bools, Out) :-
list__length(Bools, Arity),
( list__drop(Arity, HeadVars0, HeadVars1) ->
HeadVars = HeadVars1
;
error("Unmatched variables in term_util:make_bool_list")
),
term_util__make_bool_list_2(HeadVars, Bools, Out).
:- pred term_util__make_bool_list_2(list(_T), list(bool), list(bool)).
:- mode term_util__make_bool_list_2(in, in, out) is det.
term_util__make_bool_list_2([], Bools, Bools).
term_util__make_bool_list_2([ _ | Vars ], Bools, [no | Out]) :-
term_util__make_bool_list_2(Vars, Bools, Out).
remove_unused_args(Vars, [], [], Vars).
remove_unused_args(Vars, [], [_X | _Xs], Vars) :-
error("Unmatched variables in term_util:remove_unused_args").
remove_unused_args(Vars, [_X | _Xs], [], Vars) :-
error("Unmatched variables in term_util__remove_unused_args").
remove_unused_args(Vars0, [ Arg | Args ], [ UsedVar | UsedVars ], Vars) :-
( UsedVar = yes ->
% The variable is used, so leave it
remove_unused_args(Vars0, Args, UsedVars, Vars)
;
% The variable is not used in producing output vars, so
% dont include it as an input variable.
bag__delete(Vars0, Arg, Vars1),
remove_unused_args(Vars1, Args, UsedVars, Vars)
).
%-----------------------------------------------------------------------------%
set_pred_proc_ids_arg_size_info([], _ArgSize, Module, Module).
set_pred_proc_ids_arg_size_info([PPId | PPIds], ArgSize, Module0, Module) :-
PPId = proc(PredId, ProcId),
module_info_preds(Module0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo0),
pred_info_procedures(PredInfo0, ProcTable0),
map__lookup(ProcTable0, ProcId, ProcInfo0),
proc_info_set_maybe_arg_size_info(ProcInfo0, yes(ArgSize), ProcInfo),
map__det_update(ProcTable0, ProcId, ProcInfo, ProcTable),
pred_info_set_procedures(PredInfo0, ProcTable, PredInfo),
map__det_update(PredTable0, PredId, PredInfo, PredTable),
module_info_set_preds(Module0, PredTable, Module1),
set_pred_proc_ids_arg_size_info(PPIds, ArgSize, Module1, Module).
set_pred_proc_ids_termination_info([], _Termination, Module, Module).
set_pred_proc_ids_termination_info([PPId | PPIds], Termination,
Module0, Module) :-
PPId = proc(PredId, ProcId),
module_info_preds(Module0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo0),
pred_info_procedures(PredInfo0, ProcTable0),
map__lookup(ProcTable0, ProcId, ProcInfo0),
proc_info_set_maybe_termination_info(ProcInfo0, yes(Termination),
ProcInfo),
map__det_update(ProcTable0, ProcId, ProcInfo, ProcTable),
pred_info_set_procedures(PredInfo0, ProcTable, PredInfo),
map__det_update(PredTable0, PredId, PredInfo, PredTable),
module_info_set_preds(Module0, PredTable, Module1),
set_pred_proc_ids_termination_info(PPIds, Termination,
Module1, Module).
lookup_proc_termination_info(Module, PredProcId, MaybeTermination) :-
PredProcId = proc(PredId, ProcId),
module_info_pred_proc_info(Module, PredId, ProcId, _, ProcInfo),
proc_info_get_maybe_termination_info(ProcInfo, MaybeTermination).
lookup_proc_arg_size_info(Module, PredProcId, MaybeArgSize) :-
PredProcId = proc(PredId, ProcId),
module_info_pred_proc_info(Module, PredId, ProcId, _, ProcInfo),
proc_info_get_maybe_arg_size_info(ProcInfo, MaybeArgSize).
horder_vars([Arg | Args], VarType) :-
(
map__lookup(VarType, Arg, Type),
type_is_higher_order(Type, _, _)
;
horder_vars(Args, VarType)
).
zero_size_type(Type, Module) :-
classify_type(Type, Module, TypeCategory),
zero_size_type_category(TypeCategory, Type, Module, yes).
% User_type could be a type_info, which should be called size 0.
% This is not a big problem, as most type_infos are input.
:- pred zero_size_type_category(builtin_type, type, module_info, bool).
:- mode zero_size_type_category(in, in, in, out) is det.
zero_size_type_category(int_type, _, _, yes).
zero_size_type_category(char_type, _, _, yes).
zero_size_type_category(str_type, _, _, yes).
zero_size_type_category(float_type, _, _, yes).
zero_size_type_category(pred_type, _, _, no).
zero_size_type_category(enum_type, _, _, yes).
zero_size_type_category(polymorphic_type, _, _, no).
zero_size_type_category(user_type, _, _, no).
%-----------------------------------------------------------------------------%
get_context_from_scc(SCC, Module, Context) :-
( SCC = [proc(PredId, _) | _] ->
module_info_pred_info(Module, PredId, PredInfo),
pred_info_context(PredInfo, Context)
;
error("Empty SCC in pass 2 of termination analysis")
).
%-----------------------------------------------------------------------------%
%----------------------------------------------------------------------------%
% Copyright (C) 1997 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.
%----------------------------------------------------------------------------%
%
% termination.m
%
% Main author: crs.
% Significant modifications by zs.
%
% This termination analysis is based on the algorithm given by Gerhard Groeger
% and Lutz Plumer in their paper "Handling of Mutual Recursion in Automatic
% Termination Proofs for Logic Programs" which was printed in JICSLP '92
% (the proceedings of the Joint International Conference and Symposium on
% Logic Programming 1992) pages 336 - 350.
%
% Details about this implementation are covered in:
% Chris Speirs, Zoltan Somogyi, and Harald Sondergaard. Termination
% analysis for Mercury. In P. Van Hentenryck, editor, Static Analysis:
% Proceedings of the 4th International Symposium, Lecture Notes in Computer
% Science. Springer, 1997. A more detailed version is available for
% download from http://www.cs.mu.oz.au/publications/tr_db/mu_97_09.ps.gz
%
% Currently, this implementation assumes that all c_code terminates.
% It also fails to prove termination for any predicate that involves higher
% order calls.
%
% The termination analysis may use a number of different norms to calculate
% the size of a term. These are set by using the --termination-norm string
% option. To add a new norm, the following files must be modified:
%
% globals.m To change the termination_norm type and
% convert_termination_norm predicate.
%
% handle_options.m To change the error message that is produced when
% an incorrect argument is given to --termination-norm.
%
% term_util.m To change the functor_norm predicate and change the
% functor_alg type.
%
% termination.m To change the set_functor_info predicate.
%
%----------------------------------------------------------------------------%
:- module termination.
:- interface.
:- import_module io.
:- import_module hlds_module, term_util.
% Perform termination analysis on the module.
:- pred termination__pass(module_info::in, module_info::out,
io__state::di, io__state::uo) is det.
% Write the given arg size info; verbose if the second arg is yes.
:- pred termination__write_maybe_arg_size_info(maybe(arg_size_info)::in,
bool::in, io__state::di, io__state::uo) is det.
% Write the given termination info; verbose if the second arg is yes.
:- pred termination__write_maybe_termination_info(maybe(termination_info)::in,
bool::in, io__state::di, io__state::uo) is det.
% This predicate outputs termination_info pragmas;
% such annotations can be part of .opt and .trans_opt files.
:- pred termination__write_pragma_termination_info(pred_or_func::in,
sym_name::in, list(mode)::in, term__context::in,
maybe(arg_size_info)::in, maybe(termination_info)::in,
io__state::di, io__state::uo) is det.
%----------------------------------------------------------------------------%
:- implementation.
:- import_module term_pass1, term_pass2, term_errors.
:- import_module inst_match, passes_aux, options, globals, prog_data.
:- import_module hlds_data, hlds_pred, hlds_goal, dependency_graph.
:- import_module mode_util, hlds_out, code_util, prog_out.
:- import_module mercury_to_mercury, varset, type_util, special_pred.
:- import_module map, std_util, bool, int, char, string, relation.
:- import_module list, require, bag, set, term.
%----------------------------------------------------------------------------%
termination__pass(Module0, Module) -->
% Find out what norm we should use, and set up for using it
globals__io_get_termination_norm(TermNorm),
{ set_functor_info(TermNorm, Module0, FunctorInfo) },
% Process builtin and compiler-generated predicates,
% and user-supplied pragmas.
{ module_info_predids(Module0, PredIds) },
check_preds(PredIds, Module0, Module1),
% Process all the SCCs of the call graph in a bottom up order.
{ module_info_ensure_dependency_info(Module1, Module2) },
{ module_info_dependency_info(Module2, DepInfo) },
{ hlds_dependency_info_get_dependency_ordering(DepInfo, SCCs) },
termination__process_all_sccs(SCCs, Module2, FunctorInfo, Module),
globals__io_lookup_bool_option(make_optimization_interface,
MakeOptInt),
( { MakeOptInt = yes } ->
termination__make_opt_int(PredIds, Module)
;
[]
).
% This predicate sets the functor info depending on the value of the
% termination_norm option. The functor info field stores the weight which
% is associated with each functor, and may contain information about which
% subterms contribute to the size of that functor.
:- pred set_functor_info(globals__termination_norm, module_info, functor_info).
:- mode set_functor_info(in, in, out) is det.
set_functor_info(total, _Module, total).
set_functor_info(simple, _Module, simple).
set_functor_info(num_data_elems, Module, use_map_and_args(WeightMap)) :-
find_weights(Module, WeightMap).
set_functor_info(size_data_elems, Module, use_map(WeightMap)) :-
find_weights(Module, WeightMap).
%----------------------------------------------------------------------------%
:- pred termination__process_all_sccs(list(list(pred_proc_id)), module_info,
functor_info, module_info, io__state, io__state).
:- mode termination__process_all_sccs(in, in, in, out, di, uo) is det.
termination__process_all_sccs([], Module, _, Module) --> [].
termination__process_all_sccs([SCC | SCCs], Module0, FunctorInfo, Module) -->
termination__process_scc(SCC, Module0, FunctorInfo, Module1),
termination__process_all_sccs(SCCs, Module1, FunctorInfo, Module).
% For each SCC, we first find out the relationships among
% the sizes of the arguments of the procedures of the SCC,
% and then attempt to prove termination of the procedures.
:- pred termination__process_scc(list(pred_proc_id), module_info, functor_info,
module_info, io__state, io__state).
:- mode termination__process_scc(in, in, in, out, di, uo) is det.
termination__process_scc(SCC, Module0, FunctorInfo, Module) -->
{ IsArgSizeKnown = lambda([PPId::in] is semidet, (
PPId = proc(PredId, ProcId),
module_info_pred_proc_info(Module0, PredId, ProcId,
_, ProcInfo),
proc_info_get_maybe_arg_size_info(ProcInfo, yes(_))
)) },
{ list__filter(IsArgSizeKnown, SCC,
_SCCArgSizeKnown, SCCArgSizeUnknown) },
( { SCCArgSizeUnknown = [] } ->
{ ArgSizeErrors = [] },
{ TermErrors = [] },
{ Module1 = Module0 }
;
find_arg_sizes_in_scc(SCCArgSizeUnknown, Module0, FunctorInfo,
ArgSizeResult, TermErrors),
{
ArgSizeResult = ok(Solutions, OutputSupplierMap),
set_finite_arg_size_infos(Solutions,
OutputSupplierMap, Module0, Module1),
ArgSizeErrors = []
;
ArgSizeResult = error(Errors),
set_infinite_arg_size_infos(SCCArgSizeUnknown,
infinite(Errors), Module0, Module1),
ArgSizeErrors = Errors
}
),
{ IsTerminationKnown = lambda([PPId::in] is semidet, (
PPId = proc(PredId, ProcId),
module_info_pred_proc_info(Module0, PredId, ProcId,
_, ProcInfo),
proc_info_get_maybe_arg_size_info(ProcInfo, yes(_))
)) },
{ list__filter(IsTerminationKnown, SCC,
_SCCTerminationKnown, SCCTerminationUnknown) },
( { SCCTerminationUnknown = [] } ->
{ Module = Module1 }
;
{ IsFatal = lambda([ContextError::in] is semidet, (
ContextError = _Context - Error,
( Error = horder_call
; Error = horder_args(_, _)
; Error = imported_pred
)
)) },
{ list__filter(IsFatal, ArgSizeErrors, FatalErrors) },
{ list__append(TermErrors, FatalErrors, BothErrors) },
( { BothErrors = [_ | _] } ->
% These errors prevent pass 2 from proving termination
% in any case, so we may as well not prove it quickly.
{ list__take_upto(3, BothErrors, ReportedErrors) },
{ TerminationResult = can_loop(ReportedErrors) }
;
globals__io_lookup_int_option(termination_single_args,
SingleArgs),
{ prove_termination_in_scc(SCCTerminationUnknown,
Module1, FunctorInfo, SingleArgs,
TerminationResult) }
),
{ set_termination_infos(SCCTerminationUnknown,
TerminationResult, Module1, Module2) },
( { TerminationResult = can_loop(TerminationErrors) } ->
report_termination_errors(SCC, TerminationErrors,
Module2, Module)
;
{ Module = Module2 }
)
).
%----------------------------------------------------------------------------%
% This predicate takes the results from solve_equations
% and inserts these results into the module info.
:- pred set_finite_arg_size_infos(list(pair(pred_proc_id, int))::in,
used_args::in, module_info::in, module_info::out) is det.
set_finite_arg_size_infos([], _, Module, Module).
set_finite_arg_size_infos([Soln | Solns], OutputSupplierMap, Module0, Module) :-
Soln = PPId - Gamma,
PPId = proc(PredId, ProcId),
module_info_preds(Module0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo),
pred_info_procedures(PredInfo, ProcTable),
map__lookup(ProcTable, ProcId, ProcInfo),
map__lookup(OutputSupplierMap, PPId, OutputSuppliers),
ArgSizeInfo = finite(Gamma, OutputSuppliers),
proc_info_set_maybe_arg_size_info(ProcInfo, yes(ArgSizeInfo),
ProcInfo1),
map__set(ProcTable, ProcId, ProcInfo1, ProcTable1),
pred_info_set_procedures(PredInfo, ProcTable1, PredInfo1),
map__set(PredTable0, PredId, PredInfo1, PredTable),
module_info_set_preds(Module0, PredTable, Module1),
set_finite_arg_size_infos(Solns, OutputSupplierMap, Module1, Module).
:- pred set_infinite_arg_size_infos(list(pred_proc_id)::in,
arg_size_info::in, module_info::in, module_info::out) is det.
set_infinite_arg_size_infos([], _, Module, Module).
set_infinite_arg_size_infos([PPId | PPIds], ArgSizeInfo, Module0, Module) :-
PPId = proc(PredId, ProcId),
module_info_preds(Module0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo),
pred_info_procedures(PredInfo, ProcTable),
map__lookup(ProcTable, ProcId, ProcInfo),
proc_info_set_maybe_arg_size_info(ProcInfo, yes(ArgSizeInfo),
ProcInfo1),
map__set(ProcTable, ProcId, ProcInfo1, ProcTable1),
pred_info_set_procedures(PredInfo, ProcTable1, PredInfo1),
map__set(PredTable0, PredId, PredInfo1, PredTable),
module_info_set_preds(Module0, PredTable, Module1),
set_infinite_arg_size_infos(PPIds, ArgSizeInfo, Module1, Module).
%----------------------------------------------------------------------------%
:- pred set_termination_infos(list(pred_proc_id)::in, termination_info::in,
module_info::in, module_info::out) is det.
set_termination_infos([], _, Module, Module).
set_termination_infos([PPId | PPIds], TerminationInfo, Module0, Module) :-
PPId = proc(PredId, ProcId),
module_info_preds(Module0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo0),
pred_info_procedures(PredInfo0, ProcTable0),
map__lookup(ProcTable0, ProcId, ProcInfo0),
proc_info_set_maybe_termination_info(ProcInfo0, yes(TerminationInfo),
ProcInfo),
map__det_update(ProcTable0, ProcId, ProcInfo, ProcTable),
pred_info_set_procedures(PredInfo0, ProcTable, PredInfo),
map__det_update(PredTable0, PredId, PredInfo, PredTable),
module_info_set_preds(Module0, PredTable, Module1),
set_termination_infos(PPIds, TerminationInfo, Module1, Module).
:- pred report_termination_errors(list(pred_proc_id)::in,
list(term_errors__error)::in, module_info::in, module_info::out,
io__state::di, io__state::uo) is det.
report_termination_errors(SCC, Errors, Module0, Module) -->
globals__io_lookup_bool_option(check_termination,
NormalErrors),
globals__io_lookup_bool_option(verbose_check_termination,
VerboseErrors),
(
{ IsCheckTerm = lambda([PPId::in] is semidet, (
PPId = proc(PredId, ProcId),
module_info_pred_proc_info(Module0, PredId, ProcId,
PredInfo, _),
\+ pred_info_is_imported(PredInfo),
pred_info_get_markers(PredInfo, Markers),
check_marker(Markers, check_termination)
)) },
{ list__filter(IsCheckTerm, SCC, CheckTermPPIds) },
{ CheckTermPPIds = [_ | _] }
->
% If any procedure in the SCC has a check_terminates pragma,
% print out one error message for the whole SCC and indicate
% an error.
term_errors__report_term_errors(SCC, Errors, Module0),
io__set_exit_status(1),
{ module_info_incr_errors(Module0, Module) }
;
{ IsNonImported = lambda([PPId::in] is semidet, (
PPId = proc(PredId, ProcId),
module_info_pred_proc_info(Module0, PredId, ProcId,
PredInfo, _),
\+ pred_info_is_imported(PredInfo)
)) },
{ list__filter(IsNonImported, SCC, NonImportedPPIds) },
{ NonImportedPPIds = [_ | _] },
% Only output warnings of non-termination for
% important errors, unless verbose errors are
% enabled. Important errors are errors where the
% compiler analysed the code and was not able to
% prove termination. Unimportant warnings are
% created when code is used/called which the
% compiler was unable to analyse/prove termination
% of.
{ VerboseErrors = yes ->
PrintErrors = Errors
; NormalErrors = yes ->
IsNonSimple = lambda([ContextError::in] is semidet, (
ContextError = _Context - Error,
\+ simple_error(Error)
)),
list__filter(IsNonSimple, Errors, PrintErrors)
;
fail
}
->
term_errors__report_term_errors(SCC, PrintErrors, Module0),
{ Module = Module0 }
;
{ Module = Module0 }
).
%----------------------------------------------------------------------------%
:- pred check_preds(list(pred_id), module_info, module_info,
io__state, io__state).
:- mode check_preds(in, in, out, di, uo) is det.
% This predicate processes each predicate and sets the termination property
% if possible. This is done as follows: Set the termination to yes if:
% - there is a terminates pragma defined for the predicate
% - there is a `check_termination' pragma defined for the predicate, and it
% is imported, and the compiler is not currently generating the
% intermodule optimization file.
% - the predicate is a builtin predicate or is compiler generated (This
% also sets the termination constant and UsedArgs).
%
% Set the termination to dont_know if:
% - there is a `does_not_terminate' pragma defined for this predicate.
% - the predicate is imported and there is no other source of information
% about it (termination_info pragmas, terminates pragmas,
% check_termination pragmas, builtin/compiler generated).
check_preds([], Module, Module, State, State).
check_preds([PredId | PredIds] , Module0, Module, State0, State) :-
globals__io_lookup_bool_option(make_optimization_interface,
MakeOptInt, State0, State1),
module_info_preds(Module0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo0),
pred_info_import_status(PredInfo0, ImportStatus),
pred_info_context(PredInfo0, Context),
pred_info_procedures(PredInfo0, ProcTable0),
pred_info_get_markers(PredInfo0, Markers),
map__keys(ProcTable0, ProcIds),
(
% It is possible for compiler generated/mercury builtin
% predicates to be imported or locally defined, so they
% must be covered here, separately.
set_compiler_gen_terminates(PredInfo0, ProcIds, PredId,
Module0, ProcTable0, ProcTable1)
->
ProcTable2 = ProcTable1
;
( ImportStatus = exported
; ImportStatus = local
; ImportStatus = pseudo_exported
)
->
( check_marker(Markers, terminates) ->
change_procs_termination_info(ProcIds, yes,
cannot_loop, ProcTable0, ProcTable2)
;
ProcTable2 = ProcTable0
)
;
( ImportStatus = imported
; ImportStatus = opt_imported
; ImportStatus = pseudo_imported % should this be here?
)
->
% All of the predicates that are processed in this section
% are imported in some way.
% With imported predicates, any 'check_termination'
% pragmas will be checked by the compiler when it compiles
% the relevant source file (that the predicate was imported
% from). When making the intermodule optimizations, the
% check_termination will not be checked when the relevant
% source file is compiled, so it cannot be depended upon.
(
(
check_marker(Markers, terminates)
;
MakeOptInt = no,
check_marker(Markers, check_termination)
)
->
change_procs_termination_info(ProcIds, yes,
cannot_loop, ProcTable0, ProcTable1)
;
TerminationError = Context - imported_pred,
TerminationInfo = can_loop([TerminationError]),
change_procs_termination_info(ProcIds, no,
TerminationInfo, ProcTable0, ProcTable1)
),
ArgSizeError = imported_pred,
ArgSizeInfo = infinite([Context - ArgSizeError]),
change_procs_arg_size_info(ProcIds, no, ArgSizeInfo,
ProcTable1, ProcTable2)
;
% ( ImportStatus = abstract_imported
% ; ImportStatus = abstract_exported
% ),
% This should not happen, as procedures are being processed
% here, and these import_status' refer to abstract types.
error("termination__check_preds: Unexpected import status")
),
( check_marker(Markers, does_not_terminate) ->
RequestError = Context - does_not_term_pragma(PredId),
RequestTerminationInfo = can_loop([RequestError]),
change_procs_termination_info(ProcIds, yes,
RequestTerminationInfo, ProcTable2, ProcTable)
;
ProcTable = ProcTable2
),
pred_info_set_procedures(PredInfo0, ProcTable, PredInfo),
map__set(PredTable0, PredId, PredInfo, PredTable),
module_info_set_preds(Module0, PredTable, Module1),
check_preds(PredIds, Module1, Module, State1, State).
%----------------------------------------------------------------------------%
% This predicate checks each ProcId in the list to see if it is a compiler
% generated predicate, or a mercury_builtin predicate. If it is, then the
% compiler sets the termination property of the ProcIds accordingly.
:- pred set_compiler_gen_terminates(pred_info, list(proc_id), pred_id,
module_info, proc_table, proc_table).
:- mode set_compiler_gen_terminates(in, in, in, in, in, out) is semidet.
set_compiler_gen_terminates(PredInfo, ProcIds, PredId, Module,
ProcTable0, ProcTable) :-
(
code_util__predinfo_is_builtin(PredInfo)
->
set_builtin_terminates(ProcIds, PredId, PredInfo, Module,
ProcTable0, ProcTable)
;
pred_info_name(PredInfo, Name),
pred_info_arity(PredInfo, Arity),
(
special_pred_name_arity(SpecPredId0, Name, _, Arity),
pred_info_module(PredInfo, ModuleName),
ModuleName = "mercury_builtin"
->
SpecialPredId = SpecPredId0
;
special_pred_name_arity(SpecialPredId, _, Name, Arity)
)
->
set_generated_terminates(ProcIds, SpecialPredId,
ProcTable0, ProcTable)
;
fail
).
:- pred set_generated_terminates(list(proc_id), special_pred_id,
proc_table, proc_table).
:- mode set_generated_terminates(in, in, in, out) is det.
set_generated_terminates([], _, ProcTable, ProcTable).
set_generated_terminates([ProcId | ProcIds], SpecialPredId,
ProcTable0, ProcTable) :-
map__lookup(ProcTable0, ProcId, ProcInfo0),
proc_info_headvars(ProcInfo0, HeadVars),
special_pred_id_to_termination(SpecialPredId, HeadVars,
ArgSize, Termination),
proc_info_set_maybe_arg_size_info(ProcInfo0, yes(ArgSize), ProcInfo1),
proc_info_set_maybe_termination_info(ProcInfo1, yes(Termination),
ProcInfo),
map__det_update(ProcTable0, ProcId, ProcInfo, ProcTable1),
set_generated_terminates(ProcIds, SpecialPredId,
ProcTable1, ProcTable).
:- pred special_pred_id_to_termination(special_pred_id::in,
list(var)::in, arg_size_info::out, termination_info::out) is det.
special_pred_id_to_termination(compare, HeadVars, ArgSize, Termination) :-
term_util__make_bool_list(HeadVars, [no, no, no], OutList),
ArgSize = finite(0, OutList),
Termination = cannot_loop.
special_pred_id_to_termination(unify, HeadVars, ArgSize, Termination) :-
term_util__make_bool_list(HeadVars, [yes, yes], OutList),
ArgSize = finite(0, OutList),
Termination = cannot_loop.
special_pred_id_to_termination(index, HeadVars, ArgSize, Termination) :-
term_util__make_bool_list(HeadVars, [no, no], OutList),
ArgSize = finite(0, OutList),
Termination = cannot_loop.
% The list of proc_ids must refer to builtin predicates. This predicate
% sets the termination information of builtin predicates.
:- pred set_builtin_terminates(list(proc_id), pred_id, pred_info, module_info,
proc_table, proc_table).
:- mode set_builtin_terminates(in, in, in, in, in, out) is det.
set_builtin_terminates([], _, _, _, ProcTable, ProcTable).
set_builtin_terminates([ProcId | ProcIds], PredId, PredInfo, Module,
ProcTable0, ProcTable) :-
map__lookup(ProcTable0, ProcId, ProcInfo0),
( all_args_input_or_zero_size(Module, PredInfo, ProcInfo0) ->
% The size of the output arguments will all be 0,
% independent of the size of the input variables.
% UsedArgs should be set to yes([no, no, ...]).
proc_info_headvars(ProcInfo0, HeadVars),
term_util__make_bool_list(HeadVars, [], UsedArgs),
ArgSizeInfo = yes(finite(0, UsedArgs))
;
pred_info_context(PredInfo, Context),
Error = is_builtin(PredId),
ArgSizeInfo = yes(infinite([Context - Error]))
),
proc_info_set_maybe_arg_size_info(ProcInfo0, ArgSizeInfo, ProcInfo1),
proc_info_set_maybe_termination_info(ProcInfo1, yes(cannot_loop),
ProcInfo),
map__det_update(ProcTable0, ProcId, ProcInfo, ProcTable1),
set_builtin_terminates(ProcIds, PredId, PredInfo, Module,
ProcTable1, ProcTable).
:- pred all_args_input_or_zero_size(module_info, pred_info, proc_info).
:- mode all_args_input_or_zero_size(in, in, in) is semidet.
all_args_input_or_zero_size(Module, PredInfo, ProcInfo) :-
pred_info_arg_types(PredInfo, _, TypeList),
proc_info_argmodes(ProcInfo, ModeList),
all_args_input_or_zero_size_2(TypeList, ModeList, Module).
:- pred all_args_input_or_zero_size_2(list(type), list(mode), module_info).
:- mode all_args_input_or_zero_size_2(in, in, in) is semidet.
all_args_input_or_zero_size_2([], [], _).
all_args_input_or_zero_size_2([], [_|_], _) :-
error("all_args_input_or_zero_size_2: Unmatched variables.").
all_args_input_or_zero_size_2([_|_], [], _) :-
error("all_args_input_or_zero_size_2: Unmatched variables").
all_args_input_or_zero_size_2([Type | Types], [Mode | Modes], Module) :-
( mode_is_input(Module, Mode) ->
% The variable is an input variables, so its size is
% irrelevant.
all_args_input_or_zero_size_2(Types, Modes, Module)
;
zero_size_type(Type, Module),
all_args_input_or_zero_size_2(Types, Modes, Module)
).
%----------------------------------------------------------------------------%
% This predicate sets the arg_size_info property of the given list
% of procedures.
%
% change_procs_arg_size_info(ProcList, Override, TerminationInfo,
% ProcTable, ProcTable)
%
% If Override is yes, then this predicate overrides any existing arg_size
% information. If Override is no, then it leaves the proc_info of a procedure
% unchanged unless the proc_info had no arg_size information (i.e. the
% maybe(arg_size_info) field was set to "no").
:- pred change_procs_arg_size_info(list(proc_id)::in, bool::in,
arg_size_info::in, proc_table::in, proc_table::out) is det.
change_procs_arg_size_info([], _, _, ProcTable, ProcTable).
change_procs_arg_size_info([ProcId | ProcIds], Override, ArgSize,
ProcTable0, ProcTable) :-
map__lookup(ProcTable0, ProcId, ProcInfo0),
(
(
Override = yes
;
proc_info_get_maybe_arg_size_info(ProcInfo0, no)
)
->
proc_info_set_maybe_arg_size_info(ProcInfo0,
yes(ArgSize), ProcInfo),
map__det_update(ProcTable0, ProcId, ProcInfo, ProcTable1)
;
ProcTable1 = ProcTable0
),
change_procs_arg_size_info(ProcIds, Override, ArgSize,
ProcTable1, ProcTable).
% This predicate sets the termination_info property of the given list
% of procedures.
%
% change_procs_termination_info(ProcList, Override, TerminationInfo,
% ProcTable, ProcTable)
%
% If Override is yes, then this predicate overrides any existing termination
% information. If Override is no, then it leaves the proc_info of a procedure
% unchanged unless the proc_info had no termination information (i.e. the
% maybe(termination_info) field was set to "no").
:- pred change_procs_termination_info(list(proc_id)::in, bool::in,
termination_info::in, proc_table::in, proc_table::out) is det.
change_procs_termination_info([], _, _, ProcTable, ProcTable).
change_procs_termination_info([ProcId | ProcIds], Override, Termination,
ProcTable0, ProcTable) :-
map__lookup(ProcTable0, ProcId, ProcInfo0),
(
(
Override = yes
;
proc_info_get_maybe_termination_info(ProcInfo0, no)
)
->
proc_info_set_maybe_termination_info(ProcInfo0,
yes(Termination), ProcInfo),
map__det_update(ProcTable0, ProcId, ProcInfo, ProcTable1)
;
ProcTable1 = ProcTable0
),
change_procs_termination_info(ProcIds, Override, Termination,
ProcTable1, ProcTable).
%----------------------------------------------------------------------------%
%----------------------------------------------------------------------------%
% These predicates are used to add the termination_info pragmas to the .opt
% file. It is oftern better to use the .trans_opt file, as it gives
% much better accuracy. The two files are not mutually exclusive, and
% termination information may be stored in both.
:- pred termination__make_opt_int(list(pred_id), module_info, io__state,
io__state).
:- mode termination__make_opt_int(in, in, di, uo) is det.
termination__make_opt_int(PredIds, Module) -->
{ module_info_name(Module, ModuleName) },
{ string__append(ModuleName, ".opt.tmp", OptFileName) },
io__open_append(OptFileName, OptFileRes),
( { OptFileRes = ok(OptFile) } ->
io__set_output_stream(OptFile, OldStream),
termination__make_opt_int_preds(PredIds, Module),
io__set_output_stream(OldStream, _),
io__close_output(OptFile)
;
% failed to open the .opt file for processing
io__write_strings(["Cannot open `",
OptFileName, "' for output\n"]),
io__set_exit_status(1)
).
:- pred termination__make_opt_int_preds(list(pred_id), module_info,
io__state, io__state).
:- mode termination__make_opt_int_preds(in, in, di, uo) is det.
termination__make_opt_int_preds([], _Module) --> [].
termination__make_opt_int_preds([ PredId | PredIds ], Module) -->
{ module_info_preds(Module, PredTable) },
{ map__lookup(PredTable, PredId, PredInfo) },
{ pred_info_import_status(PredInfo, ImportStatus) },
(
{ ImportStatus = exported },
{ \+ code_util__compiler_generated(PredInfo) }
->
{ pred_info_name(PredInfo, PredName) },
{ pred_info_procedures(PredInfo, ProcTable) },
{ pred_info_procids(PredInfo, ProcIds) },
{ pred_info_get_is_pred_or_func(PredInfo, PredOrFunc) },
{ pred_info_module(PredInfo, ModuleName) },
{ pred_info_context(PredInfo, Context) },
{ SymName = qualified(ModuleName, PredName) },
termination__make_opt_int_procs(PredId, ProcIds, ProcTable,
PredOrFunc, SymName, Context)
;
[]
),
termination__make_opt_int_preds(PredIds, Module).
:- pred termination__make_opt_int_procs(pred_id, list(proc_id), proc_table,
pred_or_func, sym_name, term__context, io__state, io__state).
:- mode termination__make_opt_int_procs(in, in, in, in, in, in, di, uo) is det.
termination__make_opt_int_procs(_PredId, [], _, _, _, _) --> [].
termination__make_opt_int_procs(PredId, [ ProcId | ProcIds ], ProcTable,
PredOrFunc, SymName, Context) -->
{ map__lookup(ProcTable, ProcId, ProcInfo) },
{ proc_info_get_maybe_arg_size_info(ProcInfo, ArgSize) },
{ proc_info_get_maybe_termination_info(ProcInfo, Termination) },
{ proc_info_declared_argmodes(ProcInfo, ModeList) },
termination__write_pragma_termination_info(PredOrFunc, SymName,
ModeList, Context, ArgSize, Termination),
termination__make_opt_int_procs(PredId, ProcIds, ProcTable,
PredOrFunc, SymName, Context).
%----------------------------------------------------------------------------%
% These predicates are used to print out the termination_info pragmas.
% If they are changed, then prog_io_pragma.m must also be changed so that
% it can parse the resulting pragma termination_info declarations.
termination__write_pragma_termination_info(PredOrFunc, SymName,
ModeList, Context, MaybeArgSize, MaybeTermination) -->
io__write_string(":- pragma termination_info("),
{ varset__init(InitVarSet) },
(
{ PredOrFunc = predicate },
mercury_output_pred_mode_subdecl(InitVarSet, SymName,
ModeList, no, Context)
;
{ PredOrFunc = function },
{ pred_args_to_func_args(ModeList, FuncModeList, RetMode) },
mercury_output_func_mode_subdecl(InitVarSet, SymName,
FuncModeList, RetMode, no, Context)
),
io__write_string(", "),
termination__write_maybe_arg_size_info(MaybeArgSize, no),
io__write_string(", "),
termination__write_maybe_termination_info(MaybeTermination, no),
io__write_string(").\n").
termination__write_maybe_arg_size_info(MaybeArgSizeInfo, Verbose) -->
(
{ MaybeArgSizeInfo = no },
io__write_string("not_set")
;
{ MaybeArgSizeInfo = yes(infinite(Error)) },
io__write_string("infinite"),
( { Verbose = yes } ->
io__write_string("("),
io__write(Error),
io__write_string(")")
;
[]
)
;
{ MaybeArgSizeInfo = yes(finite(Const, UsedArgs)) },
io__write_string("finite("),
io__write_int(Const),
io__write_string(", "),
termination__write_used_args(UsedArgs),
io__write_string(")")
).
:- pred termination__write_used_args(list(bool)::in,
io__state::di, io__state::uo) is det.
termination__write_used_args([]) -->
io__write_string("[]").
termination__write_used_args([UsedArg | UsedArgs]) -->
io__write_string("["),
io__write(UsedArg),
termination__write_used_args_2(UsedArgs),
io__write_string("]").
:- pred termination__write_used_args_2(list(bool)::in,
io__state::di, io__state::uo) is det.
termination__write_used_args_2([]) --> [].
termination__write_used_args_2([ UsedArg | UsedArgs ]) -->
io__write_string(", "),
io__write(UsedArg),
termination__write_used_args_2(UsedArgs).
termination__write_maybe_termination_info(MaybeTerminationInfo, Verbose) -->
(
{ MaybeTerminationInfo = no },
io__write_string("not_set")
;
{ MaybeTerminationInfo = yes(cannot_loop) },
io__write_string("cannot_loop")
;
{ MaybeTerminationInfo = yes(can_loop(Error)) },
io__write_string("can_loop"),
( { Verbose = yes } ->
io__write_string("("),
io__write(Error),
io__write_string(")")
;
[]
)
).
Index: compiler/bytecode_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/bytecode_gen.m,v
retrieving revision 1.30
diff -u -r1.30 bytecode_gen.m
--- bytecode_gen.m 1997/09/01 14:00:22 1.30
+++ bytecode_gen.m 1997/11/15 02:24:40
@@ -89,7 +89,7 @@
proc_info_goal(ProcInfo, Goal),
proc_info_vartypes(ProcInfo, VarTypes),
- proc_info_variables(ProcInfo, VarSet),
+ proc_info_varset(ProcInfo, VarSet),
proc_info_interface_determinism(ProcInfo, Detism),
determinism_to_code_model(Detism, CodeModel),
Index: compiler/code_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/code_gen.m,v
retrieving revision 1.39
diff -u -r1.39 code_gen.m
--- code_gen.m 1997/11/08 13:11:09 1.39
+++ code_gen.m 1997/11/15 02:24:53
@@ -180,7 +180,7 @@
% get the goal for this procedure
proc_info_goal(ProcInfo, Goal),
% get the information about this procedure that we need.
- proc_info_variables(ProcInfo, VarInfo),
+ proc_info_varset(ProcInfo, VarInfo),
proc_info_liveness_info(ProcInfo, Liveness),
proc_info_stack_slots(ProcInfo, StackSlots),
proc_info_get_initial_instmap(ProcInfo, ModuleInfo, InitialInst),
Index: compiler/constraint.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/constraint.m,v
retrieving revision 1.35
diff -u -r1.35 constraint.m
--- constraint.m 1997/09/01 14:00:47 1.35
+++ constraint.m 1997/11/15 02:25:06
@@ -88,7 +88,7 @@
map__lookup(ProcTable0, ProcId, ProcInfo0),
proc_info_goal(ProcInfo0, Goal0),
- proc_info_variables(ProcInfo0, VarSet0),
+ proc_info_varset(ProcInfo0, VarSet0),
varset__vars(VarSet0, VarList),
set__list_to_set(VarList, VarSet1),
@@ -104,7 +104,7 @@
mode_info_get_var_types(ModeInfo, VarTypes),
mode_info_get_module_info(ModeInfo, ModuleInfo1),
- proc_info_set_variables(ProcInfo0, VarSet, ProcInfo1),
+ proc_info_set_varset(ProcInfo0, VarSet, ProcInfo1),
proc_info_set_vartypes(ProcInfo1, VarTypes, ProcInfo2),
proc_info_set_goal(ProcInfo2, Goal, ProcInfo),
Index: compiler/cse_detection.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/cse_detection.m,v
retrieving revision 1.48
diff -u -r1.48 cse_detection.m
--- cse_detection.m 1997/09/01 14:00:51 1.48
+++ cse_detection.m 1997/11/15 02:25:16
@@ -135,7 +135,7 @@
proc_info_goal(ProcInfo0, Goal0),
proc_info_get_initial_instmap(ProcInfo0, ModuleInfo0, InstMap0),
- proc_info_variables(ProcInfo0, Varset0),
+ proc_info_varset(ProcInfo0, Varset0),
proc_info_vartypes(ProcInfo0, VarTypes0),
CseInfo0 = cse_info(Varset0, VarTypes0, ModuleInfo0),
detect_cse_in_goal(Goal0, InstMap0, CseInfo0, CseInfo, Redo, Goal1),
@@ -154,7 +154,7 @@
VarTypes1, Goal, Varset, VarTypes, _Warnings),
proc_info_set_goal(ProcInfo0, Goal, ProcInfo1),
- proc_info_set_variables(ProcInfo1, Varset, ProcInfo2),
+ proc_info_set_varset(ProcInfo1, Varset, ProcInfo2),
proc_info_set_vartypes(ProcInfo2, VarTypes, ProcInfo),
map__det_update(ProcTable0, ProcId, ProcInfo, ProcTable),
Index: compiler/det_analysis.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/det_analysis.m,v
retrieving revision 1.124
diff -u -r1.124 det_analysis.m
--- det_analysis.m 1997/11/17 05:47:30 1.124
+++ det_analysis.m 1997/11/19 01:29:36
@@ -747,11 +747,11 @@
_TypeContext)
->
( CanFail = can_fail ->
- proc_info_variables(ProcInfo, VarSet),
+ proc_info_varset(ProcInfo, VarSet),
Msgs = [cc_unify_can_fail(GoalInfo, Var, Type,
VarSet, GoalContext) | Msgs0]
; SolnContext \= first_soln ->
- proc_info_variables(ProcInfo, VarSet),
+ proc_info_varset(ProcInfo, VarSet),
Msgs = [cc_unify_in_wrong_context(GoalInfo, Var,
Type, VarSet, GoalContext) | Msgs0]
;
Index: compiler/det_report.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/det_report.m,v
retrieving revision 1.43
diff -u -r1.43 det_report.m
--- det_report.m 1997/11/17 05:47:33 1.43
+++ det_report.m 1997/11/19 01:22:15
@@ -419,7 +419,7 @@
DetInfo),
prog_out__write_context(Context),
{ det_get_proc_info(DetInfo, ProcInfo) },
- { proc_info_variables(ProcInfo, Varset) },
+ { proc_info_varset(ProcInfo, Varset) },
{ det_info_get_module_info(DetInfo, ModuleInfo) },
(
{ det_lookup_var_type(ModuleInfo, ProcInfo, Var,
@@ -700,7 +700,7 @@
DetInfo) -->
prog_out__write_context(Context),
{ det_get_proc_info(DetInfo, ProcInfo) },
- { proc_info_variables(ProcInfo, Varset) },
+ { proc_info_varset(ProcInfo, Varset) },
{ SwitchContext = switch_context(Var, ConsId) },
io__write_string(" Inside the case "),
hlds_out__write_cons_id(ConsId),
@@ -780,7 +780,7 @@
hlds_out__write_unify_context(First0, UnifyContext, Context, First),
prog_out__write_context(Context),
{ det_get_proc_info(DetInfo, ProcInfo) },
- { proc_info_variables(ProcInfo, Varset) },
+ { proc_info_varset(ProcInfo, Varset) },
{ det_info_get_module_info(DetInfo, ModuleInfo) },
( { First = yes } ->
( { Last = yes } ->
Index: compiler/dnf.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/dnf.m,v
retrieving revision 1.24
diff -u -r1.24 dnf.m
--- dnf.m 1997/11/24 07:26:38 1.24
+++ dnf.m 1997/11/25 07:32:54
@@ -138,7 +138,7 @@
pred_info_typevarset(PredInfo0, TVarSet),
pred_info_get_markers(PredInfo0, Markers),
proc_info_goal(ProcInfo0, Goal0),
- proc_info_variables(ProcInfo0, VarSet),
+ proc_info_varset(ProcInfo0, VarSet),
proc_info_vartypes(ProcInfo0, VarTypes),
DnfInfo = dnf_info(TVarSet, VarTypes, VarSet, Markers),
Index: compiler/excess.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/excess.m,v
retrieving revision 1.24
diff -u -r1.24 excess.m
--- excess.m 1997/09/01 14:01:24 1.24
+++ excess.m 1997/11/15 02:26:10
@@ -53,7 +53,7 @@
proc_info_set_goal(ProcInfo0, Goal, ProcInfo1),
% XXX We probably ought to remove these vars from the type map as well.
- proc_info_variables(ProcInfo1, Varset0),
+ proc_info_varset(ProcInfo1, Varset0),
varset__delete_vars(Varset0, ElimVars, Varset),
proc_info_set_varset(ProcInfo1, Varset, ProcInfo).
Index: compiler/follow_code.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/follow_code.m,v
retrieving revision 1.43
diff -u -r1.43 follow_code.m
--- follow_code.m 1997/09/01 14:01:28 1.43
+++ follow_code.m 1997/11/15 02:26:22
@@ -43,7 +43,7 @@
globals__lookup_bool_option(Globals, prev_code, PrevCode),
Flags = FollowCode - PrevCode,
proc_info_goal(ProcInfo0, Goal0),
- proc_info_variables(ProcInfo0, Varset0),
+ proc_info_varset(ProcInfo0, Varset0),
proc_info_vartypes(ProcInfo0, VarTypes0),
(
move_follow_code_in_goal(Goal0, Goal1, Flags, no, Res),
Index: compiler/higher_order.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/higher_order.m,v
retrieving revision 1.34
diff -u -r1.34 higher_order.m
--- higher_order.m 1997/11/24 07:26:40 1.34
+++ higher_order.m 1997/11/25 07:32:59
@@ -251,11 +251,11 @@
traverse_goal(Goal0, Goal1, proc(PredId, ProcId), _, _,
Info0, info(_, Requests1,_,_)),
proc_info_headvars(ProcInfo0, HeadVars),
- proc_info_variables(ProcInfo0, Varset0),
+ proc_info_varset(ProcInfo0, Varset0),
implicitly_quantify_clause_body(HeadVars, Goal1, Varset0, VarTypes0,
Goal, Varset, VarTypes, _),
proc_info_set_goal(ProcInfo0, Goal, ProcInfo1),
- proc_info_set_variables(ProcInfo1, Varset, ProcInfo2),
+ proc_info_set_varset(ProcInfo1, Varset, ProcInfo2),
proc_info_set_vartypes(ProcInfo2, VarTypes, ProcInfo),
map__det_update(Procs0, ProcId, ProcInfo, Procs1),
traverse_other_procs(PredId, ProcIds, ModuleInfo, Requests1,
@@ -927,13 +927,13 @@
set__init(Requests0),
traverse_goal(Goal0, Goal1, PredProcId, _, _,
info(PredVars0, Requests0, NewPreds, ModuleInfo0), _),
- proc_info_variables(ProcInfo0, Varset0),
+ proc_info_varset(ProcInfo0, Varset0),
proc_info_headvars(ProcInfo0, HeadVars),
proc_info_vartypes(ProcInfo0, VarTypes0),
implicitly_quantify_clause_body(HeadVars, Goal1, Varset0, VarTypes0,
Goal, Varset, VarTypes, _),
proc_info_set_goal(ProcInfo0, Goal, ProcInfo1),
- proc_info_set_variables(ProcInfo1, Varset, ProcInfo2),
+ proc_info_set_varset(ProcInfo1, Varset, ProcInfo2),
proc_info_set_vartypes(ProcInfo2, VarTypes, ProcInfo),
map__det_update(Procs0, ProcId, ProcInfo, Procs),
pred_info_set_procedures(PredInfo0, Procs, PredInfo),
@@ -1016,7 +1016,7 @@
info(PredVars0, Requests0, NewPredMap, ModuleInfo0),
info(_, Requests1,_,_)),
map__set(GoalSizes0, NewPredId, GoalSize, GoalSizes1),
- proc_info_variables(NewProcInfo1, Varset0),
+ proc_info_varset(NewProcInfo1, Varset0),
implicitly_quantify_clause_body(HeadVars, Goal2, Varset0, VarTypes1,
Goal3, Varset, VarTypes, _),
@@ -1024,7 +1024,7 @@
recompute_instmap_delta(no, Goal3, Goal4, InstMap0,
ModuleInfo0, ModuleInfo1),
proc_info_set_goal(NewProcInfo1, Goal4, NewProcInfo1a),
- proc_info_set_variables(NewProcInfo1a, Varset, NewProcInfo2),
+ proc_info_set_varset(NewProcInfo1a, Varset, NewProcInfo2),
proc_info_set_vartypes(NewProcInfo2, VarTypes, NewProcInfo3),
proc_info_set_argmodes(NewProcInfo3, ArgModes, NewProcInfo4),
proc_info_set_headvars(NewProcInfo4, HeadVars, NewProcInfo),
@@ -1083,9 +1083,9 @@
;
error("list__split_list_failed")
),
- proc_info_variables(ProcInfo0, Varset0),
+ proc_info_varset(ProcInfo0, Varset0),
varset__new_vars(Varset0, NumArgs, NewHeadVars0, Varset1),
- proc_info_set_variables(ProcInfo0, Varset1, ProcInfo1),
+ proc_info_set_varset(ProcInfo0, Varset1, ProcInfo1),
% Find the type substitution and work out the types
% of the new variables.
Index: compiler/hlds_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_out.m,v
retrieving revision 1.175
diff -u -r1.175 hlds_out.m
--- hlds_out.m 1997/11/24 07:26:42 1.175
+++ hlds_out.m 1997/11/25 07:34:19
@@ -1856,12 +1856,13 @@
{ proc_info_vartypes(Proc, VarTypes) },
{ proc_info_declared_determinism(Proc, DeclaredDeterminism) },
{ proc_info_inferred_determinism(Proc, InferredDeterminism) },
- { proc_info_variables(Proc, VarSet) },
+ { proc_info_varset(Proc, VarSet) },
{ proc_info_headvars(Proc, HeadVars) },
{ proc_info_argmodes(Proc, HeadModes) },
{ proc_info_goal(Proc, Goal) },
{ proc_info_context(Proc, ModeContext) },
- { proc_info_termination(Proc, Termination) },
+ { proc_info_get_maybe_arg_size_info(Proc, MaybeArgSize) },
+ { proc_info_get_maybe_termination_info(Proc, MaybeTermination) },
{ proc_info_typeinfo_varmap(Proc, TypeInfoMap) },
{ Indent1 is Indent + 1 },
@@ -1879,13 +1880,13 @@
globals__io_lookup_string_option(verbose_dump_hlds, Verbose),
( { string__contains_char(Verbose, 't') } ->
- io__write_string("% Inferred termination: "),
- termination__out(Termination),
+ io__write_string("% Arg size properties: "),
+ termination__write_maybe_arg_size_info(MaybeArgSize, yes),
io__nl,
- io__write_string("% Termination - used args: "),
- termination__out_used_args(Termination),
- io__nl,
- term_errors__output_hlds(PredId, ProcId, ModuleInfo)
+ io__write_string("% Termination properties: "),
+ termination__write_maybe_termination_info(MaybeTermination,
+ yes),
+ io__nl
;
[]
),
Index: compiler/hlds_pred.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_pred.m,v
retrieving revision 1.38
diff -u -r1.38 hlds_pred.m
--- hlds_pred.m 1997/11/24 07:26:44 1.38
+++ hlds_pred.m 1997/11/25 07:33:01
@@ -458,7 +458,7 @@
next_mode_id(Procs0, MaybeDetism, ProcId),
map__det_insert(Procs0, ProcId, ProcInfo, Procs),
list__length(Types, Arity),
- proc_info_variables(ProcInfo, VarSet),
+ proc_info_varset(ProcInfo, VarSet),
proc_info_vartypes(ProcInfo, VarTypes),
proc_info_headvars(ProcInfo, HeadVars),
unqualify_name(SymName, PredName),
@@ -667,9 +667,10 @@
:- pred proc_info_set(maybe(determinism), varset, map(var, type), list(var),
list(mode), maybe(list(is_live)), hlds_goal, term__context,
stack_slots, determinism, bool, list(arg_info), liveness_info,
- map(tvar, var), termination, proc_info).
+ map(tvar, var), maybe(arg_size_info), maybe(termination_info),
+ proc_info).
:- mode proc_info_set(in, in, in, in, in, in, in, in, in, in, in, in, in, in,
- in, out) is det.
+ in, in, out) is det.
:- pred proc_info_create(varset, map(var, type), list(var), list(mode),
determinism, hlds_goal, term__context, map(tvar, var), proc_info).
@@ -697,15 +698,12 @@
:- pred proc_info_never_succeeds(proc_info, bool).
:- mode proc_info_never_succeeds(in, out) is det.
-:- pred proc_info_variables(proc_info, varset).
-:- mode proc_info_variables(in, out) is det.
+:- pred proc_info_varset(proc_info, varset).
+:- mode proc_info_varset(in, out) is det.
:- pred proc_info_set_varset(proc_info, varset, proc_info).
:- mode proc_info_set_varset(in, in, out) is det.
-:- pred proc_info_set_variables(proc_info, varset, proc_info).
-:- mode proc_info_set_variables(in, in, out) is det.
-
:- pred proc_info_vartypes(proc_info, map(var, type)).
:- mode proc_info_vartypes(in, out) is det.
@@ -770,11 +768,20 @@
:- pred proc_info_set_stack_slots(proc_info, stack_slots, proc_info).
:- mode proc_info_set_stack_slots(in, in, out) is det.
-:- pred proc_info_termination(proc_info, termination).
-:- mode proc_info_termination(in, out) is det.
+:- pred proc_info_get_maybe_arg_size_info(proc_info, maybe(arg_size_info)).
+:- mode proc_info_get_maybe_arg_size_info(in, out) is det.
-:- pred proc_info_set_termination(proc_info, termination, proc_info).
-:- mode proc_info_set_termination(in, in, out) is det.
+:- pred proc_info_set_maybe_arg_size_info(proc_info, maybe(arg_size_info),
+ proc_info).
+:- mode proc_info_set_maybe_arg_size_info(in, in, out) is det.
+
+:- pred proc_info_get_maybe_termination_info(proc_info,
+ maybe(termination_info)).
+:- mode proc_info_get_maybe_termination_info(in, out) is det.
+
+:- pred proc_info_set_maybe_termination_info(proc_info,
+ maybe(termination_info), proc_info).
+:- mode proc_info_set_maybe_termination_info(in, in, out) is det.
:- pred proc_info_set_can_process(proc_info, bool, proc_info).
:- mode proc_info_set_can_process(in, in, out) is det.
@@ -849,9 +856,15 @@
% for code generation
map(tvar, var), % typeinfo vars for
% type parameters
- termination, % The termination properties of the
- % procedure. Initially 'not_set'.
- % Final value inferred by termination.m
+ maybe(arg_size_info),
+ % Information about the relative sizes
+ % of the input and output args of the
+ % procedure. Set by termination
+ % analysis.
+ maybe(termination_info),
+ % The termination properties of the
+ % procedure. Set by termination
+ % analysis.
maybe(list(mode))
% declared modes of arguments.
).
@@ -878,37 +891,36 @@
ClauseBody = conj([]) - GoalInfo,
CanProcess = yes,
map__init(TVarsMap),
- term_util__init(Termination),
NewProc = procedure(
MaybeDet, BodyVarSet, BodyTypes, HeadVars, Modes, MaybeArgLives,
ClauseBody, MContext, StackSlots, InferredDet, CanProcess,
- ArgInfo, InitialLiveness, TVarsMap, Termination, DeclaredModes
+ ArgInfo, InitialLiveness, TVarsMap, no, no, DeclaredModes
).
proc_info_set(DeclaredDetism, BodyVarSet, BodyTypes, HeadVars, HeadModes,
HeadLives, Goal,
Context, StackSlots, InferredDetism, CanProcess,
- ArgInfo, Liveness, TVarMap, Termination, ProcInfo) :-
+ ArgInfo, Liveness, TVarMap, ArgSizes, Termination, ProcInfo) :-
ProcInfo = procedure(
DeclaredDetism, BodyVarSet, BodyTypes, HeadVars, HeadModes,
HeadLives, Goal, Context, StackSlots, InferredDetism,
- CanProcess, ArgInfo, Liveness, TVarMap, Termination, no).
+ CanProcess, ArgInfo, Liveness, TVarMap, ArgSizes, Termination,
+ no).
proc_info_create(VarSet, VarTypes, HeadVars, HeadModes, Detism, Goal,
Context, TVarMap, ProcInfo) :-
map__init(StackSlots),
set__init(Liveness),
- term_util__init(Termination),
MaybeHeadLives = no,
ProcInfo = procedure(yes(Detism), VarSet, VarTypes, HeadVars, HeadModes,
MaybeHeadLives, Goal, Context, StackSlots, Detism, yes, [],
- Liveness, TVarMap, Termination, no).
+ Liveness, TVarMap, no, no, no).
proc_info_set_body(ProcInfo0, VarSet, VarTypes, HeadVars, Goal, ProcInfo) :-
ProcInfo0 = procedure(A, _, _, _, E, F, _,
- H, I, J, K, L, M, N, O, P),
+ H, I, J, K, L, M, N, O, P, Q),
ProcInfo = procedure(A, VarSet, VarTypes, HeadVars, E, F, Goal,
- H, I, J, K, L, M, N, O, P).
+ H, I, J, K, L, M, N, O, P, Q).
proc_info_interface_determinism(ProcInfo, Determinism) :-
proc_info_declared_determinism(ProcInfo, MaybeDeterminism),
@@ -956,48 +968,6 @@
assoc_list__from_corresponding_lists(HeadVars, InitialInsts, InstAL),
instmap__from_assoc_list(InstAL, InstMap).
-proc_info_declared_determinism(ProcInfo, Detism) :-
- ProcInfo = procedure(Detism, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
-proc_info_variables(ProcInfo, VarSet) :-
- ProcInfo = procedure(_, VarSet, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
-proc_info_vartypes(ProcInfo, VarTypes) :-
- ProcInfo = procedure(_, _, VarTypes, _, _, _, _, _,
- _, _, _, _, _, _, _, _).
-proc_info_headvars(ProcInfo, HeadVars) :-
- ProcInfo = procedure(_, _, _, HeadVars, _, _, _, _,
- _, _, _, _, _, _, _, _).
-proc_info_argmodes(ProcInfo, Modes) :-
- ProcInfo = procedure(_, _, _, _, Modes, _, _, _, _, _, _, _, _, _, _, _).
-proc_info_maybe_arglives(ProcInfo, ArgLives) :-
- ProcInfo = procedure(_, _, _, _, _, ArgLives,
- _, _, _, _, _, _, _, _, _, _).
-proc_info_goal(ProcInfo, Goal) :-
- ProcInfo = procedure(_, _, _, _, _, _, Goal, _, _, _, _, _, _, _, _, _).
-proc_info_context(ProcInfo, Context) :-
- ProcInfo = procedure(_, _, _, _, _, _, _, Context, _, _, _, _, _, _, _, _).
-proc_info_stack_slots(ProcInfo, StackSlots) :-
- ProcInfo = procedure(_, _, _, _, _, _, _, _, StackSlots,
- _, _, _, _, _, _, _).
-proc_info_inferred_determinism(ProcInfo, Detism) :-
- ProcInfo = procedure(_, _, _, _, _, _, _, _, _, Detism, _, _, _, _, _, _).
-proc_info_can_process(ProcInfo, CanProcess) :-
- ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, CanProcess,
- _, _, _, _, _).
-proc_info_arg_info(ProcInfo, ArgInfo) :-
- ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, ArgInfo,
- _, _, _, _).
-proc_info_liveness_info(ProcInfo, Liveness) :-
- ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, Liveness,
- _, _, _).
-proc_info_typeinfo_varmap(ProcInfo, TVarMap) :-
- ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, TVarMap, _, _).
-proc_info_termination(ProcInfo, Termination) :-
- ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _,
- Termination, _).
-proc_info_maybe_declared_argmodes(ProcInfo, MaybeArgModes) :-
- ProcInfo = procedure(_, _, _, _, _, _, _,
- _, _, _, _, _, _, _, _, MaybeArgModes).
-
proc_info_declared_argmodes(ProcInfo, ArgModes) :-
proc_info_maybe_declared_argmodes(ProcInfo, MaybeArgModes),
( MaybeArgModes = yes(ArgModes1) ->
@@ -1006,6 +976,57 @@
proc_info_argmodes(ProcInfo, ArgModes)
).
+proc_info_declared_determinism(ProcInfo, A) :-
+ ProcInfo = procedure(A, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
+
+proc_info_varset(ProcInfo, B) :-
+ ProcInfo = procedure(_, B, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
+
+proc_info_vartypes(ProcInfo, C) :-
+ ProcInfo = procedure(_, _, C, _, _, _, _, _, _, _, _, _, _, _, _, _, _).
+
+proc_info_headvars(ProcInfo, D) :-
+ ProcInfo = procedure(_, _, _, D, _, _, _, _, _, _, _, _, _, _, _, _, _).
+
+proc_info_argmodes(ProcInfo, E) :-
+ ProcInfo = procedure(_, _, _, _, E, _, _, _, _, _, _, _, _, _, _, _, _).
+
+proc_info_maybe_arglives(ProcInfo, F) :-
+ ProcInfo = procedure(_, _, _, _, _, F, _, _, _, _, _, _, _, _, _, _, _).
+
+proc_info_goal(ProcInfo, G) :-
+ ProcInfo = procedure(_, _, _, _, _, _, G, _, _, _, _, _, _, _, _, _, _).
+
+proc_info_context(ProcInfo, H) :-
+ ProcInfo = procedure(_, _, _, _, _, _, _, H, _, _, _, _, _, _, _, _, _).
+
+proc_info_stack_slots(ProcInfo, I) :-
+ ProcInfo = procedure(_, _, _, _, _, _, _, _, I, _, _, _, _, _, _, _, _).
+
+proc_info_inferred_determinism(ProcInfo, J) :-
+ ProcInfo = procedure(_, _, _, _, _, _, _, _, _, J, _, _, _, _, _, _, _).
+
+proc_info_can_process(ProcInfo, K) :-
+ ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, K, _, _, _, _, _, _).
+
+proc_info_arg_info(ProcInfo, L) :-
+ ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, L, _, _, _, _, _).
+
+proc_info_liveness_info(ProcInfo, M) :-
+ ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, M, _, _, _, _).
+
+proc_info_typeinfo_varmap(ProcInfo, N) :-
+ ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, N, _, _, _).
+
+proc_info_get_maybe_arg_size_info(ProcInfo, O) :-
+ ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, O, _, _).
+
+proc_info_get_maybe_termination_info(ProcInfo, P) :-
+ ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, P, _).
+
+proc_info_maybe_declared_argmodes(ProcInfo, R) :-
+ ProcInfo = procedure(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, R).
+
% :- type proc_info ---> procedure(
% A maybe(determinism),% _declared_ detism
% B varset, % variable names
@@ -1027,72 +1048,69 @@
% M liveness_info % the initial liveness
% N map(tvar, var) % typeinfo vars to
% % vars.
-% O termination % Termination analys
-% P maybe(list(mode)) % declared modes
+% O maybe(arg_size_info)
+% % Termination analys
+% P maybe(termination_info)
+% % Termination analys
+% Q maybe(list(mode)) % declared modes
% % of args
% ).
-proc_info_set_varset(ProcInfo0, VarSet, ProcInfo) :-
- ProcInfo0 = procedure(A, _, C, D, E, F, G, H, I, J, K, L, M, N, O, P),
- ProcInfo = procedure(A, VarSet, C, D, E, F, G, H, I, J, K, L, M, N, O, P).
-
-proc_info_set_variables(ProcInfo0, Vars, ProcInfo) :-
- ProcInfo0 = procedure(A, _, C, D, E, F, G, H, I, J, K, L, M, N, O, P),
- ProcInfo = procedure(A, Vars, C, D, E, F, G, H, I, J, K, L, M, N, O, P).
-
-proc_info_set_vartypes(ProcInfo0, Vars, ProcInfo) :-
- ProcInfo0 = procedure(A, B, _, D, E, F, G, H, I, J, K, L, M, N, O, P),
- ProcInfo = procedure(A, B, Vars, D, E, F, G, H, I, J, K, L, M, N, O, P).
-
-proc_info_set_headvars(ProcInfo0, HdVars, ProcInfo) :-
- ProcInfo0 = procedure(A, B, C, _, E, F, G, H, I, J, K, L, M, N, O, P),
- ProcInfo = procedure(A, B, C, HdVars, E, F, G, H, I, J, K, L, M, N, O, P).
-
-proc_info_set_argmodes(ProcInfo0, ArgModes, ProcInfo) :-
- ProcInfo0 = procedure(A, B, C, D, _, F, G, H, I, J, K, L, M, N, O, P),
- ProcInfo = procedure(A, B, C, D, ArgModes, F, G, H, I,
- J, K, L, M, N, O, P).
-
-proc_info_set_maybe_arglives(ProcInfo0, ArgLives, ProcInfo) :-
- ProcInfo0 = procedure(A, B, C, D, E, _, G, H, I, J, K, L, M, N, O, P),
- ProcInfo = procedure(A, B, C, D, E, ArgLives, G, H, I,
- J, K, L, M, N, O, P).
-
-proc_info_set_inferred_determinism(ProcInfo0, Detism, ProcInfo) :-
- ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, _, K, L, M, N, O, P),
- ProcInfo = procedure(A, B, C, D, E, F, G, H, I, Detism, K, L, M, N, O, P).
-
-proc_info_set_can_process(ProcInfo0, CanProcess, ProcInfo) :-
- ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, _, L, M, N, O, P),
- ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, CanProcess,
- L, M, N, O, P).
-
-proc_info_set_goal(ProcInfo0, Goal, ProcInfo) :-
- ProcInfo0 = procedure(A, B, C, D, E, F, _, H, I, J, K, L, M, N, O, P),
- ProcInfo = procedure(A, B, C, D, E, F, Goal, H, I, J, K, L, M, N, O, P).
-
-proc_info_set_stack_slots(ProcInfo0, StackSlots, ProcInfo) :-
- ProcInfo0 = procedure(A, B, C, D, E, F, G, H, _, J, K, L, M, N, O, P),
- ProcInfo = procedure(A, B, C, D, E, F, G, H, StackSlots, J, K,
- L, M, N, O, P).
-
-proc_info_set_arg_info(ProcInfo0, ArgInfo, ProcInfo) :-
- ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, _, M, N, O, P),
- ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, ArgInfo, M, N, O, P).
-
-proc_info_set_liveness_info(ProcInfo0, Liveness, ProcInfo) :-
- ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, _, N, O, P),
- ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, Liveness,
- N, O, P).
-
-proc_info_set_typeinfo_varmap(ProcInfo0, TVarMap, ProcInfo) :-
- ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, _, O, P),
- ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, TVarMap, O, P).
-
-proc_info_set_termination(ProcInfo0, Terminat, ProcInfo) :-
- ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, _, P),
- ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L,
- M, N, Terminat, P).
+proc_info_set_varset(ProcInfo0, B, ProcInfo) :-
+ ProcInfo0 = procedure(A, _, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
+
+proc_info_set_vartypes(ProcInfo0, C, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, _, D, E, F, G, H, I, J, K, L, M, N, O, P, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
+
+proc_info_set_headvars(ProcInfo0, D, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, C, _, E, F, G, H, I, J, K, L, M, N, O, P, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
+
+proc_info_set_argmodes(ProcInfo0, E, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, C, D, _, F, G, H, I, J, K, L, M, N, O, P, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
+
+proc_info_set_maybe_arglives(ProcInfo0, F, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, C, D, E, _, G, H, I, J, K, L, M, N, O, P, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
+
+proc_info_set_goal(ProcInfo0, G, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, C, D, E, F, _, H, I, J, K, L, M, N, O, P, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
+
+proc_info_set_stack_slots(ProcInfo0, I, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, C, D, E, F, G, H, _, J, K, L, M, N, O, P, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
+
+proc_info_set_inferred_determinism(ProcInfo0, J, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, _, K, L, M, N, O, P, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
+
+proc_info_set_can_process(ProcInfo0, K, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, _, L, M, N, O, P, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
+
+proc_info_set_arg_info(ProcInfo0, L, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, _, M, N, O, P, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
+
+proc_info_set_liveness_info(ProcInfo0, M, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, _, N, O, P, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
+
+proc_info_set_typeinfo_varmap(ProcInfo0, N, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, _, O, P, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
+
+proc_info_set_maybe_arg_size_info(ProcInfo0, O, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, _, P, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
+
+proc_info_set_maybe_termination_info(ProcInfo0, P, ProcInfo) :-
+ ProcInfo0 = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, _, Q),
+ ProcInfo = procedure(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q).
proc_info_get_typeinfo_vars_setwise(ProcInfo, Vars, TypeInfoVars) :-
set__to_sorted_list(Vars, VarList),
@@ -1133,26 +1151,26 @@
proc_info_ensure_unique_names(ProcInfo0, ProcInfo) :-
proc_info_vartypes(ProcInfo0, VarTypes),
map__keys(VarTypes, AllVars),
- proc_info_variables(ProcInfo0, VarSet0),
+ proc_info_varset(ProcInfo0, VarSet0),
varset__ensure_unique_names(AllVars, "p", VarSet0, VarSet),
- proc_info_set_variables(ProcInfo0, VarSet, ProcInfo).
+ proc_info_set_varset(ProcInfo0, VarSet, ProcInfo).
proc_info_create_var_from_type(ProcInfo0, Type, NewVar, ProcInfo) :-
- proc_info_variables(ProcInfo0, VarSet0),
+ proc_info_varset(ProcInfo0, VarSet0),
proc_info_vartypes(ProcInfo0, VarTypes0),
varset__new_var(VarSet0, NewVar, VarSet),
map__det_insert(VarTypes0, NewVar, Type, VarTypes),
- proc_info_set_variables(ProcInfo0, VarSet, ProcInfo1),
+ proc_info_set_varset(ProcInfo0, VarSet, ProcInfo1),
proc_info_set_vartypes(ProcInfo1, VarTypes, ProcInfo).
proc_info_create_vars_from_types(ProcInfo0, Types, NewVars, ProcInfo) :-
list__length(Types, NumVars),
- proc_info_variables(ProcInfo0, VarSet0),
+ proc_info_varset(ProcInfo0, VarSet0),
proc_info_vartypes(ProcInfo0, VarTypes0),
varset__new_vars(VarSet0, NumVars, NewVars, VarSet),
map__det_insert_from_corresponding_lists(VarTypes0,
NewVars, Types, VarTypes),
- proc_info_set_variables(ProcInfo0, VarSet, ProcInfo1),
+ proc_info_set_varset(ProcInfo0, VarSet, ProcInfo1),
proc_info_set_vartypes(ProcInfo1, VarTypes, ProcInfo).
%-----------------------------------------------------------------------------%
Index: compiler/inlining.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/inlining.m,v
retrieving revision 1.69
diff -u -r1.69 inlining.m
--- inlining.m 1997/09/01 14:02:31 1.69
+++ inlining.m 1997/11/15 02:27:22
@@ -338,7 +338,7 @@
pred_info_typevarset(PredInfo0, TypeVarSet0),
proc_info_goal(ProcInfo0, Goal0),
- proc_info_variables(ProcInfo0, VarSet0),
+ proc_info_varset(ProcInfo0, VarSet0),
proc_info_vartypes(ProcInfo0, VarTypes0),
proc_info_typeinfo_varmap(ProcInfo0, TypeInfoVarMap0),
@@ -354,7 +354,7 @@
pred_info_set_typevarset(PredInfo0, TypeVarSet, PredInfo1),
- proc_info_set_variables(ProcInfo0, VarSet, ProcInfo1),
+ proc_info_set_varset(ProcInfo0, VarSet, ProcInfo1),
proc_info_set_vartypes(ProcInfo1, VarTypes, ProcInfo2),
proc_info_set_typeinfo_varmap(ProcInfo2, TypeInfoVarMap, ProcInfo3),
proc_info_set_goal(ProcInfo3, Goal, ProcInfo),
@@ -427,7 +427,7 @@
% Callee has
module_info_pred_proc_info(ModuleInfo, PredId, ProcId,
PredInfo, ProcInfo),
- proc_info_variables(ProcInfo, CalleeVarset),
+ proc_info_varset(ProcInfo, CalleeVarset),
varset__vars(CalleeVarset, CalleeListOfVars),
list__length(CalleeListOfVars, CalleeThisMany),
TotalVars is ThisMany + CalleeThisMany,
Index: compiler/lambda.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/lambda.m,v
retrieving revision 1.33
diff -u -r1.33 lambda.m
--- lambda.m 1997/11/24 07:26:46 1.33
+++ lambda.m 1997/11/25 07:33:03
@@ -120,7 +120,7 @@
pred_info_name(PredInfo0, PredName),
pred_info_get_is_pred_or_func(PredInfo0, PredOrFunc),
pred_info_typevarset(PredInfo0, TypeVarSet0),
- proc_info_variables(ProcInfo0, VarSet0),
+ proc_info_varset(ProcInfo0, VarSet0),
proc_info_vartypes(ProcInfo0, VarTypes0),
proc_info_goal(ProcInfo0, Goal0),
proc_info_typeinfo_varmap(ProcInfo0, TVarMap0),
@@ -136,7 +136,7 @@
% set the new values of the fields in proc_info and pred_info
proc_info_set_goal(ProcInfo0, Goal, ProcInfo1),
- proc_info_set_variables(ProcInfo1, VarSet, ProcInfo2),
+ proc_info_set_varset(ProcInfo1, VarSet, ProcInfo2),
proc_info_set_vartypes(ProcInfo2, VarTypes, ProcInfo3),
proc_info_set_typeinfo_varmap(ProcInfo3, TVarMap, ProcInfo),
pred_info_set_typevarset(PredInfo0, TypeVarSet, PredInfo).
Index: compiler/liveness.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/liveness.m,v
retrieving revision 1.84
diff -u -r1.84 liveness.m
--- liveness.m 1997/10/20 07:35:22 1.84
+++ liveness.m 1997/11/15 02:27:36
@@ -153,7 +153,7 @@
detect_liveness_proc(ProcInfo0, ModuleInfo, ProcInfo) :-
requantify_proc(ProcInfo0, ProcInfo1),
proc_info_goal(ProcInfo1, Goal0),
- proc_info_variables(ProcInfo1, Varset),
+ proc_info_varset(ProcInfo1, Varset),
proc_info_vartypes(ProcInfo1, VarTypes),
live_info_init(ModuleInfo, ProcInfo1, VarTypes, Varset, LiveInfo),
Index: compiler/make_hlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make_hlds.m,v
retrieving revision 1.245
diff -u -r1.245 make_hlds.m
--- make_hlds.m 1997/11/24 07:26:48 1.245
+++ make_hlds.m 1997/11/25 07:33:05
@@ -383,7 +383,7 @@
{ Module = Module0 }
;
{ Pragma = termination_info(PredOrFunc, SymName, ModeList,
- Termination) },
+ MaybeArgSizeInfo, MaybeTerminationInfo) },
{ module_info_get_predicate_table(Module0, Preds) },
{ list__length(ModeList, Arity) },
(
@@ -405,8 +405,11 @@
ModeList, Module0, ProcId) }
->
{ map__lookup(ProcTable0, ProcId, ProcInfo0) },
- { proc_info_set_termination(ProcInfo0,
- Termination, ProcInfo) },
+ { proc_info_set_maybe_arg_size_info(ProcInfo0,
+ MaybeArgSizeInfo, ProcInfo1) },
+ { proc_info_set_maybe_termination_info(
+ ProcInfo1,
+ MaybeTerminationInfo, ProcInfo) },
{ map__det_update(ProcTable0, ProcId, ProcInfo,
ProcTable) },
{ pred_info_set_procedures(PredInfo0,
Index: compiler/mercury_to_c.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_to_c.m,v
retrieving revision 1.28
diff -u -r1.28 mercury_to_c.m
--- mercury_to_c.m 1997/11/24 23:08:21 1.28
+++ mercury_to_c.m 1997/11/25 07:33:07
@@ -231,7 +231,7 @@
c_gen_proc(Indent, ModuleInfo, PredId, ProcId, Pred, Proc) -->
{ proc_info_interface_determinism(Proc, InterfaceDeterminism) },
- { proc_info_variables(Proc, VarSet) },
+ { proc_info_varset(Proc, VarSet) },
{ proc_info_headvars(Proc, HeadVars) },
{ pred_info_name(Pred, PredName) },
{ proc_info_vartypes(Proc, VarTypes) },
@@ -348,7 +348,7 @@
PredInfo, ProcInfo) },
{ proc_info_interface_code_model(ProcInfo, CodeModel) },
- { proc_info_variables(ProcInfo, VarSet) },
+ { proc_info_varset(ProcInfo, VarSet) },
{ proc_info_headvars(ProcInfo, HeadVars) },
{ pred_info_arg_types(PredInfo, _HeadTypeVarSet, HeadTypes) },
{ proc_info_argmodes(ProcInfo, HeadModes) },
Index: compiler/mercury_to_mercury.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_to_mercury.m,v
retrieving revision 1.121
diff -u -r1.121 mercury_to_mercury.m
--- mercury_to_mercury.m 1997/11/23 05:18:23 1.121
+++ mercury_to_mercury.m 1997/11/25 07:33:08
@@ -311,9 +311,10 @@
mercury_output_pragma_fact_table(Pred, Arity, FileName)
;
{ Pragma = termination_info(PredOrFunc, PredName,
- ModeList, Termination) },
- termination__output_pragma_termination_info(PredOrFunc,
- PredName, ModeList, Termination, Context)
+ ModeList, MaybeArgSizeInfo, MaybeTerminationInfo) },
+ termination__write_pragma_termination_info(PredOrFunc,
+ PredName, ModeList, Context,
+ MaybeArgSizeInfo, MaybeTerminationInfo)
;
{ Pragma = terminates(Pred, Arity) },
mercury_output_pragma_decl(Pred, Arity, predicate, "terminates")
Index: compiler/mode_info.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mode_info.m,v
retrieving revision 1.40
diff -u -r1.40 mode_info.m
--- mode_info.m 1997/10/14 09:18:44 1.40
+++ mode_info.m 1997/11/15 02:28:00
@@ -336,7 +336,7 @@
map__lookup(Preds, PredId, PredInfo),
pred_info_procedures(PredInfo, Procs),
map__lookup(Procs, ProcId, ProcInfo),
- proc_info_variables(ProcInfo, VarSet),
+ proc_info_varset(ProcInfo, VarSet),
proc_info_vartypes(ProcInfo, VarTypes),
LiveVarsList = [LiveVars],
Index: compiler/modes.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modes.m,v
retrieving revision 1.209
diff -u -r1.209 modes.m
--- modes.m 1997/11/24 23:10:25 1.209
+++ modes.m 1997/11/25 07:33:10
@@ -684,7 +684,7 @@
mode_info_get_varset(ModeInfo, VarSet),
mode_info_get_var_types(ModeInfo, VarTypes),
proc_info_set_goal(ProcInfo0, Body, ProcInfo1),
- proc_info_set_variables(ProcInfo1, VarSet, ProcInfo2),
+ proc_info_set_varset(ProcInfo1, VarSet, ProcInfo2),
proc_info_set_vartypes(ProcInfo2, VarTypes, ProcInfo3),
proc_info_set_argmodes(ProcInfo3, ArgModes, ProcInfo).
Index: compiler/module_qual.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/module_qual.m,v
retrieving revision 1.24
diff -u -r1.24 module_qual.m
--- module_qual.m 1997/10/09 09:38:57 1.24
+++ module_qual.m 1997/11/05 03:34:02
@@ -608,8 +608,8 @@
Info, Info) --> [].
qualify_pragma(fact_table(SymName, Arity, FileName),
fact_table(SymName, Arity, FileName), Info, Info) --> [].
-qualify_pragma(termination_info(PredOrFunc, SymName, ModeList0, Termination),
- termination_info(PredOrFunc, SymName, ModeList, Termination),
+qualify_pragma(termination_info(PredOrFunc, SymName, ModeList0, Args, Term),
+ termination_info(PredOrFunc, SymName, ModeList, Args, Term),
Info0, Info) -->
qualify_mode_list(ModeList0, ModeList, Info0, Info).
qualify_pragma(terminates(A, B), terminates(A, B), Info, Info) --> [].
Index: compiler/modules.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.43
diff -u -r1.43 modules.m
--- modules.m 1997/11/21 08:08:23 1.43
+++ modules.m 1997/11/25 07:33:11
@@ -257,7 +257,7 @@
{ Pragma \= terminates(_, _) },
{ Pragma \= does_not_terminate(_, _) },
{ Pragma \= check_termination(_, _) },
- { Pragma \= termination_info(_, _, _, _) }
+ { Pragma \= termination_info(_, _, _, _, _) }
->
prog_out__write_context(Context),
report_warning("Warning: pragma in module interface.\n"),
Index: compiler/options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.211
diff -u -r1.211 options.m
--- options.m 1997/11/13 06:27:17 1.211
+++ options.m 1997/11/24 06:43:49
@@ -197,6 +197,7 @@
; verbose_check_termination
; termination_single_args
; termination_norm
+ ; termination_error_limit
% - HLDS->LLDS
; smart_indexing
; dense_switch_req_density
@@ -428,8 +429,9 @@
check_termination - bool(no),
verbose_check_termination - bool(no),
termination - bool(no),
- termination_single_args - bool(no),
+ termination_single_args - int(0),
termination_norm - string("total"),
+ termination_error_limit - int(3),
split_c_files - bool(no)
]).
option_defaults_2(optimization_option, [
@@ -754,6 +756,8 @@
long_option("term-single-arg", termination_single_args).
long_option("termination-norm", termination_norm).
long_option("term-norm", termination_norm).
+long_option("termination-error-limit", termination_error_limit).
+long_option("term-err-limit", termination_error_limit).
% HLDS->LLDS optimizations
long_option("smart-indexing", smart_indexing).
@@ -1490,6 +1494,10 @@
io__write_string("\t--verb-chk-term, --verb-check-term, --verbose-check-termination\n"),
io__write_string("\t\tEnable termination analysis, and emit warnings for all\n"),
io__write_string("\t\tpredicates or functions that cannot be proved to terminate.\n"),
+ io__write_string("\t--term-single-arg <n>, --termination-single-argument-analysis <n>\n"),
+ io__write_string("\t\tWhen performing termination analysis, try analyzing\n"),
+ io__write_string("\t\trecursion on single arguments in strongly connected\n"),
+ io__write_string("\t\tcomponents of the call graph that have up to n procedures.\n"),
io__write_string("\t--termination-norm {simple, total, num-data-elems}\n"),
io__write_string("\t\tThe norm defines how termination analysis measures the size\n"),
io__write_string("\t\tof a memory cell. The simple norm says that size is always one.\n"),
@@ -1497,6 +1505,8 @@
io__write_string("\t\tThe num-data-elems norm says that it is the number of words in\n"),
io__write_string("\t\tthe cell that contain something other than pointers to cells of\n"),
io__write_string("\t\tthe same type.\n"),
+ io__write_string("\t--termination-error-limit <n>, --term-err-limit <n>\n"),
+ io__write_string("\t\tPrint at most n reasons for any single termination error.\n"),
io__write_string("\t--split-c-files\n"),
io__write_string("\t\tGenerate each C function in its own C file,\n"),
io__write_string("\t\tso that the linker will optimize away unused code.\n"),
Index: compiler/polymorphism.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/polymorphism.m,v
retrieving revision 1.118
diff -u -r1.118 polymorphism.m
--- polymorphism.m 1997/10/14 09:27:53 1.118
+++ polymorphism.m 1997/11/15 02:28:20
@@ -302,7 +302,7 @@
pred_info_typevarset(PredInfo0, TypeVarSet0),
pred_info_name(PredInfo0, PredName),
proc_info_headvars(ProcInfo0, HeadVars0),
- proc_info_variables(ProcInfo0, VarSet0),
+ proc_info_varset(ProcInfo0, VarSet0),
proc_info_vartypes(ProcInfo0, VarTypes0),
proc_info_goal(ProcInfo0, Goal0),
proc_info_argmodes(ProcInfo0, ArgModes0),
Index: compiler/prog_data.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_data.m,v
retrieving revision 1.26
diff -u -r1.26 prog_data.m
--- prog_data.m 1997/10/09 09:39:05 1.26
+++ prog_data.m 1997/11/05 03:26:56
@@ -131,7 +131,7 @@
% Predname, Arity, Fact file name.
; termination_info(pred_or_func, sym_name, list(mode),
- termination)
+ maybe(arg_size_info), maybe(termination_info))
% the list(mode) is the declared argmodes of the
% procedure, unless there are no declared argmodes,
% in which case the inferred argmodes are used.
Index: compiler/prog_io_pragma.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_io_pragma.m,v
retrieving revision 1.8
diff -u -r1.8 prog_io_pragma.m
--- prog_io_pragma.m 1997/11/02 12:29:23 1.8
+++ prog_io_pragma.m 1997/11/25 06:20:03
@@ -327,9 +327,8 @@
(
PragmaTerms = [
PredAndModesTerm0,
- ConstTerm,
- TerminatesTerm,
- MaybeUsedArgsTerm
+ ArgSizeTerm,
+ TerminationTerm
],
(
PredAndModesTerm0 = term__functor(Const, Terms0, _)
@@ -360,44 +359,35 @@
),
convert_mode_list(ModeListTerm, ModeList),
(
- ConstTerm = term__functor(term__atom("not_set"), [], _),
- TerminationConst = not_set
+ ArgSizeTerm = term__functor(term__atom("not_set"), [], _),
+ MaybeArgSizeInfo = no
;
- ConstTerm = term__functor(
- term__atom("infinite"), [], ConstContext),
- TerminationConst = inf(ConstContext - imported_pred)
+ ArgSizeTerm = term__functor(term__atom("infinite"), [],
+ ArgSizeContext),
+ MaybeArgSizeInfo = yes(infinite(
+ [ArgSizeContext - imported_pred]))
;
- ConstTerm = term__functor(term__atom("set"), [IntTerm], _),
+ ArgSizeTerm = term__functor(term__atom("finite"),
+ [IntTerm, UsedArgsTerm], _),
IntTerm = term__functor(term__integer(Int), [], _),
- TerminationConst = set(Int)
+ convert_bool_list(UsedArgsTerm, UsedArgs),
+ MaybeArgSizeInfo = yes(finite(Int, UsedArgs))
),
(
- TerminatesTerm = term__functor(term__atom("not_set"), [], _),
- Terminates = not_set,
- MaybeError = no
- ;
- TerminatesTerm = term__functor(
- term__atom("dont_know"), [], TermContext),
- Terminates = dont_know,
- MaybeError = yes(TermContext - imported_pred)
- ;
- TerminatesTerm = term__functor(term__atom("yes"), [], _),
- Terminates = yes,
- MaybeError = no
- ),
- (
- MaybeUsedArgsTerm = term__functor(
- term__atom("yes"), [BoolListTerm], _),
- convert_bool_list(BoolListTerm, BoolList),
- MaybeUsedArgs = yes(BoolList)
+ TerminationTerm = term__functor(term__atom("not_set"), [], _),
+ MaybeTerminationInfo = no
;
- MaybeUsedArgsTerm = term__functor(term__atom("no"), [], _),
- MaybeUsedArgs = no
+ TerminationTerm = term__functor(term__atom("can_loop"),
+ [], TermContext),
+ MaybeTerminationInfo = yes(can_loop(
+ [TermContext - imported_pred]))
+ ;
+ TerminationTerm = term__functor(term__atom("cannot_loop"),
+ [], _),
+ MaybeTerminationInfo = yes(cannot_loop)
),
- Termination = term(TerminationConst, Terminates,
- MaybeUsedArgs, MaybeError),
Result0 = ok(pragma(termination_info(PredOrFunc, PredName,
- ModeList, Termination)))
+ ModeList, MaybeArgSizeInfo, MaybeTerminationInfo)))
;
Result0 = error("unexpected variable in pragma termination_info",
ErrorTerm)
@@ -408,7 +398,6 @@
Result = error("syntax error in `pragma termination_info'", ErrorTerm)
).
-
parse_pragma_type(ModuleName, "terminates", PragmaTerms,
ErrorTerm, _VarSet, Result) :-
parse_simple_pragma(ModuleName, "terminates",
[continued in part 3]
More information about the developers
mailing list