Files
mercury/compiler/prog_data_pragma.m
Julien Fischer 153590a30f Update and fix more copyright notices.
compiler/*.m:
    As above.
2024-12-30 16:01:59 +11:00

533 lines
19 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2016-2022, 2024 The Mercury team.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%---------------------------------------------------------------------------%
%
% This module defines the types that represent information related to pragmas
% in the parse tree.
%
%---------------------------------------------------------------------------%
:- module parse_tree.prog_data_pragma.
:- interface.
:- import_module libs.
:- import_module libs.compiler_util.
:- import_module libs.rat.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.set_of_var.
:- import_module bool.
:- import_module list.
:- import_module maybe.
:- import_module one_or_more.
:- import_module pair.
:- import_module set.
:- import_module unit.
:- implementation.
:- import_module require.
%---------------------------------------------------------------------------%
%
% Stuff for tabling pragmas.
%
:- interface.
% The evaluation method that should be used for a procedure.
%
:- type eval_method
---> eval_normal % normal mercury evaluation
; eval_tabled(tabled_eval_method). % tabled evaluation
% The evaluation method that should be used for a procedure.
%
:- type tabled_eval_method
---> tabled_loop_check
% loop check only
; tabled_memo(
% memoing + loop check
% Preserve the value of this attribute until the invocation
% of the relevant code in table_gen.m.
table_attr_backend_warning
)
; tabled_io(
% memoing I/O actions for debugging
table_io_entry_kind,
table_io_is_unitize
)
; tabled_minimal(
% minimal model evaluation
eval_minimal_method
).
:- type eval_minimal_method
---> stack_copy
% Each minimal model procedure saves and restores stack segments
% as necessary. See the paper "Tabling in Mercury" by Zoltan
% Somogyi and Konstantinos Sagonas.
; own_stacks_consumer
; own_stacks_generator.
% Each minimal model procedure is split into two: the consumer
% and the generator. Each generator runs in its own context,
% and thus has its own stacks.
:- type table_attributes
---> table_attributes(
table_attr_strictness :: call_table_strictness,
table_attr_size_limit :: maybe(int),
table_attr_statistics :: table_attr_statistics,
table_attr_allow_reset :: table_attr_allow_reset,
table_attr_backend_warning :: table_attr_backend_warning
).
:- func default_memo_table_attributes = table_attributes.
:- type table_attr_statistics
---> table_do_not_gather_statistics
; table_gather_statistics.
:- type table_attr_allow_reset
---> table_do_not_allow_reset
; table_allow_reset.
% If the current backend cannot implement the requested form of tabling,
% and is therefore forced to ignore it, should the compiler generate
% a warning?
:- type table_attr_backend_warning
---> table_attr_ignore_with_warning % Yes, generate a warning.
; table_attr_ignore_without_warning. % Do not generate a warning.
:- type call_table_strictness
---> cts_all_strict
; cts_all_fast_loose
; cts_specified(
list(maybe(arg_tabling_method)),
% This list contains one element for each user-visible
% argument of the predicate. Elements that correspond
% to output arguments should be "no". Elements that
% correspond to input arguments should be "yes",
% specifying how to look up that argument in the call table.
hidden_arg_tabling_method
% This specifies the tabling method for hidden arguments
% introduced by the compiler.
).
:- type arg_tabling_method
---> arg_value
; arg_addr
; arg_promise_implied.
:- type hidden_arg_tabling_method
---> table_hidden_arg_value
; table_hidden_arg_addr.
:- type table_io_entry_kind
---> entry_stores_outputs
% Each entry in the I/O table stores only the outputs of the
% action. The I/O action will be idempotent across retries
% in mdb, but attempts to print out the action will cause
% a core dump. This option is intended only for implementors
% measuring the overheads of the two alternatives just below.
; entry_stores_procid_outputs
% Each entry in the I/O table starts with a pointer to the
% MR_TableIoEntry structure of the procedure that performed
% the action, and also contains the outputs of the action.
% This makes the I/O action idempotent across retries and
% allows the *name* of the I/O predicate to be printed
% by mdb's "print action N" command, but not the values
% of the arguments. Not even the output arguments can be printed,
% since doing so requires knowing their types, and in general
% that requires access to input type_info arguments.
; entry_stores_procid_inputs_outputs.
% Each entry in the I/O table starts with a pointer to the
% MR_TableIoEntry structure of the procedure that performed
% the action, and also contains both the inputs and outputs
% of the action.
%
% This makes the I/O action idempotent across retries and
% allows both the name and all the arguments of the I/O predicate
% to be printed by mdb's "print action N" command. It also
% allows the declarative debugger to consider the action to
% be part of the effect of a call to its ancestors.
:- type table_io_is_unitize
---> table_io_unitize % The procedure is tabled for I/O
% together with its Mercury descendants.
; table_io_alone. % The procedure is tabled for I/O by itself;
% it can have no Mercury descendants.
:- func tabled_eval_method_to_table_type(tabled_eval_method) = string.
:- implementation.
default_memo_table_attributes =
table_attributes(cts_all_strict, no, table_do_not_gather_statistics,
table_do_not_allow_reset, table_attr_ignore_with_warning).
tabled_eval_method_to_table_type(EvalMethod) = TableTypeStr :-
(
EvalMethod = tabled_io(_, _),
unexpected($pred, "eval_table_io")
;
EvalMethod = tabled_loop_check,
TableTypeStr = "MR_TABLE_TYPE_LOOPCHECK"
;
EvalMethod = tabled_memo(_),
TableTypeStr = "MR_TABLE_TYPE_MEMO"
;
EvalMethod = tabled_minimal(stack_copy),
TableTypeStr = "MR_TABLE_TYPE_MINIMAL_MODEL_STACK_COPY"
;
EvalMethod = tabled_minimal(own_stacks_consumer),
unexpected($pred, "own_stacks_consumer")
;
EvalMethod = tabled_minimal(own_stacks_generator),
TableTypeStr = "MR_TABLE_TYPE_MINIMAL_MODEL_OWN_STACKS"
).
%---------------------------------------------------------------------------%
%
% Stuff for the `termination_info' pragma.
% See term_util.m.
%
:- interface.
:- type generic_arg_size_info(ErrorInfo)
---> finite(int, list(bool))
% The termination constant is a finite integer. The list of bool
% has a 1:1 correspondence with the input arguments of the
% procedure. It stores whether the argument contributes to the
% size of the output arguments.
; infinite(ErrorInfo).
% There is no finite integer for which the above equation is true.
:- type generic_termination_info(TermInfo, ErrorInfo)
---> cannot_loop(TermInfo)
% This procedure definitely terminates for all possible inputs.
; can_loop(ErrorInfo).
% This procedure might not terminate.
:- type pragma_arg_size_info == generic_arg_size_info(unit).
:- type pragma_termination_info == generic_termination_info(unit, unit).
%---------------------------------------------------------------------------%
%
% Stuff for the `termination2_info' pragma.
%
:- interface.
% This is the form in which termination information from other
% modules (imported via `.opt' or `.trans_opt' files) comes.
% We convert this to an intermediate form and let the termination
% analyser convert it to the correct form.
%
% NOTE: the reason that we cannot convert it to the correct form
% is that we don't have complete information about how many typeinfo
% related arguments there are until after the polymorphism pass.
%
:- type arg_size_constr
---> le(list(arg_size_term), rat)
; eq(list(arg_size_term), rat).
:- type arg_size_term
---> arg_size_term(
as_term_var :: int,
as_term_coeff :: rat
).
:- type pragma_constr_arg_size_info == list(arg_size_constr).
%---------------------------------------------------------------------------%
%
% Stuff for the `structure_sharing_info' pragma.
%
:- interface.
% Whenever structure sharing analysis is unable to determine a good
% approximation of the set of structure sharing pairs that might exist
% during the execution of a program, it must use "top" as the only safe
% approximation.
%
% We divide the reasons for approximating by `top' into two cases:
%
% - the procedure calls some imported procedure for which we don't have an
% answer (yet). The result might be improved if we did have that
% information.
%
% - the procedure calls some imported procedure for which we managed to
% look up the answer, and that answer was `top'.
%
% - the procedure contains a call to foreign or generic code.
% Reanalysis will not improve the result.
%
:- type top_feedback
---> top_failed_lookup(shrouded_pred_proc_id)
; top_from_lookup(shrouded_pred_proc_id)
; top_cannot_improve(string).
% Elements of the structure sharing domain lattice are either bottom
% (no structure sharing), top (any kind of structure sharing), or
% a list of structure sharing pairs.
%
% This is the public representation of the type "sharing_as".
%
:- type structure_sharing_domain
---> structure_sharing_bottom
; structure_sharing_real(structure_sharing)
; structure_sharing_top(set(top_feedback)).
% Public representation of structure sharing.
%
:- type structure_sharing == list(structure_sharing_pair).
% A structure sharing pair represents the information that two
% data structures might be represented by the same memoryspace, hence
% its representation as a pair of datastructs.
%
:- type structure_sharing_pair == pair(datastruct).
% A datastruct is a concept that designates a particular subterm of the
% term to which a particular variable may be bound. The selector is
% normalized.
%
:- type datastruct
---> selected_cel(
sc_var :: prog_var,
sc_selector :: selector
).
% A selector describes a path in a type-tree.
%
:- type selector == list(unit_selector).
% Unit-selectors are either term selectors or type selectors.
% - A term selector selects a subterm f/n of a term, where f is a functor
% (identified by the cons_id), and n an integer.
% - A type selector designates any subterm that has that specific type.
%
:- type unit_selector
---> termsel(cons_id, int) % term selector
; typesel(mer_type). % type selector
% Type to represent the sharing information that is manually added
% to procedures implemented as foreign_procs.
%
:- type user_annotated_sharing
---> no_user_annotated_sharing
; user_sharing(
sharing :: structure_sharing_domain,
maybe_types :: maybe(user_sharing_type_information)
).
% The user may have declared the sharing in terms of type variables. In
% that case, we record the types, and the type variable set.
%
:- type user_sharing_type_information
---> user_type_info(
types :: list(mer_type),
typevarset :: tvarset
).
%---------------------------------------------------------------------------%
%
% Stuff for the `structure_reuse_info' pragma.
%
:- interface.
:- type dead_var == prog_var.
:- type dead_datastruct == datastruct.
:- type dead_datastructs == set(dead_datastruct).
:- type live_var == prog_var.
:- type set_of_live_var == set_of_progvar.
:- type live_datastruct == datastruct.
% This is the public representation of the type "reuse_as".
%
:- type structure_reuse_domain
---> has_no_reuse
; has_only_unconditional_reuse
; has_conditional_reuse(list(structure_reuse_condition)).
% A structure reuse condition specifies all the information needed to
% verify whether some memory cells can safely be considered as dead at
% some program point, depending on the calling context.
% This information consists of three parts:
% - a list of dead datastructures specifying which memory cells
% might become dead, hence reusable;
% - a list of live datastructures that specifies which memory cells
% are always live at the place where the above dead datastructures might
% become dead;
% - a description of the structure sharing existing at the place
% where these datastructures might become dead.
%
:- type structure_reuse_condition
---> structure_reuse_condition(
dead_nodes :: dead_datastructs,
local_use_nodes :: list(live_datastruct),
local_sharing :: structure_sharing_domain
).
%---------------------------------------------------------------------------%
%
% Stuff for the `unused_args' pragma.
%
:- interface.
% This `mode_num' type is only used for mode numbers written out in
% automatically-generated `pragma unused_args' pragmas in `.opt' files.
% The mode_num gets converted to an HLDS proc_id by make_hlds.m.
% We don't want to use the `proc_id' type here since the parse tree
% (prog_data.m and prog_item.m) should not depend on the HLDS.
%
:- type mode_num == int.
%---------------------------------------------------------------------------%
%
% Stuff for the `exceptions' pragma.
%
:- interface.
:- type exception_status
---> will_not_throw
% This procedure will not throw an exception.
; may_throw(exception_type)
% This procedure may throw an exception. The exception is
% classified by the `exception_type' type.
; throw_conditional.
% Whether the procedure will not throw an exception depends upon
% the value of one or more polymorphic arguments. XXX This needs
% to be extended for ho preds. (See exception_analysis.m for
% more details).
:- type exception_type
---> user_exception
% The exception that might be thrown is of a result of some code
% calling exception.throw/1.
; type_exception.
% The exception is a result of a compiler introduced
% unification/comparison maybe throwing an exception
% (in the case of user-defined equality or comparison) or
% propagating an exception from them.
%---------------------------------------------------------------------------%
%
% Stuff for the `format_call' pragma.
%
:- interface.
:- type format_string_values
---> format_string_values(
% The format_call pragma allows users to specify pairs of
% argument numbers, the first specifying the arg containing
% the format string, the second the arg containing the
% values list (as a list of poly_types).
% The first pair of arguments contain the argument numbers
% given by the user. The first user-visible arg is arg 1,
% the second is arg 2, and so on.
%
% All error messages generated for invalid argument numbers
% use this pair.
fsv_user_fs :: int,
fsv_user_vl :: int,
% The second pair of arguments is derived from the first pair,
% but are incremented by the number of any additional
% type_info and/or typeclass_info arguments added by the
% polymorphism pass. The code of check_pragma_format_call.m
% finds the argument types and modes to check by indexing
% into argument lists using these numbers.
fsv_cur_fs :: int,
fsv_cur_vl :: int
).
%---------------------------------------------------------------------------%
%
% Stuff for the `type_spec' pragma.
%
:- interface.
% The type substitution for a `pragma type_spec' declaration.
% Elsewhere in the compiler we generally use the `tsubst' type
% which is a map rather than (effectively) an assoc_list.
%
:- type type_subst == one_or_more(tvar_subst).
:- type tvar_subst
---> tvar_subst(tvar, mer_type).
%---------------------------------------------------------------------------%
%
% Stuff for the `require_feature_set' pragma.
%
:- interface.
:- type required_feature
---> reqf_concurrency
; reqf_single_prec_float
; reqf_double_prec_float
; reqf_memo
; reqf_parallel_conj
; reqf_trailing
; reqf_strict_sequential
; reqf_conservative_gc.
%---------------------------------------------------------------------------%
%
% Require tail recursion pragma.
%
:- interface.
:- type require_tail_recursion
---> suppress_tailrec_warnings(
rtrs_context :: prog_context
)
; enable_tailrec_warnings(
rtre_warn_or_error :: warning_or_error,
rtre_recursion_type :: require_tail_recursion_type,
rtre_context :: prog_context
).
:- type require_tail_recursion_type
---> only_self_recursion_must_be_tail
; both_self_and_mutual_recursion_must_be_tail.
:- pred require_tailrec_type_string(require_tail_recursion_type, string).
:- mode require_tailrec_type_string(in, out) is det.
:- mode require_tailrec_type_string(out, in) is semidet.
:- implementation.
require_tailrec_type_string(only_self_recursion_must_be_tail,
"self_recursion_only").
require_tailrec_type_string(both_self_and_mutual_recursion_must_be_tail,
"self_or_mutual_recursion").
%---------------------------------------------------------------------------%
:- end_module parse_tree.prog_data_pragma.
%---------------------------------------------------------------------------%