Files
mercury/compiler/ml_gen_info.m
Julien Fischer 4cd5c17f61 Fix more copyright notices ...
... and other minor fixes.

library/*.m:
library/LIB_FLAGS.in:
compiler/*.m:
mdbcomp/*.m:
    Fix and update copyright notices.

    Fix spelling.

    Delete trailing whitespace.
2024-02-20 17:18:52 +11:00

1274 lines
54 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2009, 2011-2012 The University of Melbourne.
% Copyright (C) 2014-2015, 2017-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.
%---------------------------------------------------------------------------%
%
% File: ml_code_util.m.
% Main author: fjh.
%
% This module is part of the MLDS code generator.
% It defines the ml_gen_info type and its access routines.
%
%---------------------------------------------------------------------------%
:- module ml_backend.ml_gen_info.
:- interface.
:- import_module hlds.
:- import_module hlds.code_model.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
:- import_module hlds.mark_tail_calls. % for nontail_rec_call_reason
:- import_module libs.
:- import_module libs.globals.
:- import_module libs.optimization_options.
:- import_module ml_backend.ml_global_data.
:- import_module ml_backend.mlds.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.set_of_var.
:- import_module parse_tree.var_table.
:- import_module assoc_list.
:- import_module bool.
:- import_module counter.
:- import_module list.
:- import_module map.
:- import_module one_or_more.
:- import_module set.
%---------------------------------------------------------------------------%
%
% The `ml_gen_info' ADT.
%
% The `ml_gen_info' type holds information used during
% MLDS code generation for a given procedure.
%
:- type ml_gen_info.
%---------------------------------------------------------------------------%
%
% Operations on the ml_gen_info that are more than getters and setters.
%
:- pred ml_gen_info_get_globals(ml_gen_info::in, globals::out) is det.
:- pred ml_gen_info_get_module_name(ml_gen_info::in, mercury_module_name::out)
is det.
% Look up the --put-commit-in-nested-func option.
%
:- pred ml_gen_info_put_commit_in_own_func(ml_gen_info::in, bool::out) is det.
% Generate a new label number for use in label statements.
% This is used to give unique names to the case labels generated
% for dense switch statements.
%
:- type label_num == int.
:- pred ml_gen_info_new_label(label_num::out,
ml_gen_info::in, ml_gen_info::out) is det.
% Generate a new function label number. This is used to give unique names
% to the nested functions used when generating code for nondet procedures.
%
:- pred ml_gen_info_new_aux_func_id(mlds_maybe_aux_func_id::out,
ml_gen_info::in, ml_gen_info::out) is det.
% Increase the function label and const sequence number counters by some
% amount which is presumed to be sufficient to ensure that if we start
% again with a fresh ml_gen_info and then call this function, we won't
% encounter any already-used function labels or constants. (This is used
% when generating wrapper functions for type class methods.)
%
:- pred ml_gen_info_bump_counters(ml_gen_info::in, ml_gen_info::out) is det.
% Generate a new auxiliary variable of the given kind,
% with a sequence number that differentiates this aux var from all others.
%
% Auxiliary variables are used for purposes such as commit label numbers
% and holding table indexes in switches.
%
:- pred ml_gen_info_new_aux_var_name(mlds_compiler_aux_var::in,
mlds_local_var_name::out, ml_gen_info::in, ml_gen_info::out) is det.
% Generate a new `cond' variable number.
%
:- type cond_seq ---> cond_seq(int).
:- pred ml_gen_info_new_cond_var(cond_seq::out,
ml_gen_info::in, ml_gen_info::out) is det.
% Generate a new `conv' variable number. This is used to give unique names
% to the local variables generated by ml_gen_box_or_unbox_lval, which are
% used to handle boxing/unboxing argument conversions.
%
:- type conv_seq ---> conv_seq(int).
:- pred ml_gen_info_new_conv_var(conv_seq::out,
ml_gen_info::in, ml_gen_info::out) is det.
:- type bitfield
---> bitfield(arg_shift, arg_num_bits, fill_kind).
% A bitfield inside a packed argument word. It is defined by
% its position, size and the nature of the value inside it.
:- type bitfield_value
---> bv_var(prog_var)
; bv_rval(mlds_rval)
; bv_const(uint).
:- type filled_bitfield
---> filled_bitfield(bitfield, bitfield_value).
:- type packed_word == one_or_more(bitfield).
:- type filled_packed_word == one_or_more(filled_bitfield).
% get_unfilled_filled_packed_words(HeadFilledBitfield, TailFilledBitfields,
% PackedWord, FilledPackedWord):
%
% Given a word containing [HeadFilledBitfield | TailFilledBitfields],
% return its filled_packed_word representation as FilledPackedWord,
% and its unfilled version (obtaining by simply throwing away the value
% of every bitfield) as PackedWord.
%
:- pred get_unfilled_filled_packed_words(
filled_bitfield::in, list(filled_bitfield)::in,
packed_word::out, filled_packed_word::out) is det.
% A filled_packed_word is an instance of a packed_word if it has
% the exact same sequence of bitfields inside it, but with a value
% in each bitfield. We record the rval where the filled in instance
% is available.
:- type packed_word_instance
---> packed_word_instance(filled_packed_word, mlds_rval).
% Given a packed word represented as a sequence of bitfields,
% return a list of the different ways in which we have seen those
% bitfields have been filled, with each way being accompanied
% by the rval that stores the resulting word value.
%
% We support three different ways to specify a packed word.
%
% - Packed word scheme 1 contains two or more arguments packed into
% one word in a memory cell, with the first being apw_partial_first
% and the others being apw_partial_shifted.
%
% - Packed word scheme 2 contains a remote secondary tag and one or more
% arguments packed into the first word in a memory cell, with the first
% bitfield being the remote sectag and the rest being the arguments,
% which must all be apw_partial_shifted.
%
% - Packed word scheme 3 contains a primary tag, a local secondary tag
% and one or more arguments packed into a word (which need not be
% in memory, but could be in a register), with the first bitfield
% being the *combined* ptag and sectag, and rest being the arguments,
% which again must all be apw_partial_shifted.
%
% Some rules apply to all three schemes:
%
% - All three schemes require the bitfields involved to be nonoverlapping.
% - All imply that any bits not covered by any of the bitfields
% will be zeroes.
% - None of them contain any bitfields for apw_none_shifted arguments,
% since those bitfields would contain zero bits.
% - In all three cases, the arguments should be in the list in ascending
% order of argument number, which means that they should be in
% *descending* order of offset. This rule applies *only* to the bitfields
% containing arguments: a bitfield contain a tag or tags always has
% to be at the front of the list, even though it will always have
% the lowest offset.
%
:- type packed_word_map == map(packed_word, one_or_more(packed_word_instance)).
% Generate a new unique `ml_packed_args' variable. Such compiler-generated
% variables hold the packed-together values of two or more user variables.
%
:- pred ml_gen_info_new_packed_word_var(mlds_compiler_var::out,
ml_gen_info::in, ml_gen_info::out) is det.
:- type ml_ground_term
---> ml_ground_term(
% The value of the ground term.
mlds_rval,
% The type of the ground term (actually, the type of the
% variable the ground term was constructed for).
mer_type,
% The corresponding MLDS type. It could be computed from the
% Mercury type, but there is no point in doing so when using
% the ground term as well when constructing it.
mlds_type
).
:- type ml_ground_term_map == map(prog_var, ml_ground_term).
:- type ml_const_struct_map == map(int, ml_ground_term).
% Set the `const' variable name corresponding to the given HLDS variable.
%
:- pred ml_gen_info_set_const_var(prog_var::in, ml_ground_term::in,
ml_gen_info::in, ml_gen_info::out) is det.
% Look up the `const' sequence number corresponding to a given HLDS
% variable.
%
:- pred ml_gen_info_lookup_const_var(ml_gen_info::in, prog_var::in,
ml_ground_term::out) is det.
:- pred ml_gen_info_search_const_var(ml_gen_info::in, prog_var::in,
ml_ground_term::out) is semidet.
% A success continuation specifies the (rval for the variable holding
% the address of the) function that a nondet procedure should call
% if it succeeds, and possibly also the (rval for the variable holding)
% the environment pointer for that function, and possibly also the
% (list of rvals for the) arguments to the continuation.
%
:- type success_cont
---> success_cont(
% Function pointer.
mlds_rval,
% Environment pointer. Note that if we are using
% nested functions, then the environment pointer
% will not be used.
mlds_rval,
% The arguments, together with their types, if there are any.
% (We do not include the environment pointer in this list.)
% The list will be non-empty only if the --nondet-copy-out
% option is enabled.
assoc_list(mlds_lval, mlds_type)
).
% The ml_gen_info contains a stack of success continuations.
% The following routines provide access to that stack.
%
:- pred ml_gen_info_push_success_cont(success_cont::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_pop_success_cont(ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_current_success_cont(ml_gen_info::in, success_cont::out)
is det.
% The ml_gen_info contains a record of how many nested functions
% we are inside. These predicates provide access to the nesting depth.
%
:- pred ml_gen_info_increment_func_nest_depth(
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_decrement_func_nest_depth(
ml_gen_info::in, ml_gen_info::out) is det.
% We keep a partial mapping from vars to lvals. This is used in special
% cases to override the normal lval for a variable. ml_gen_var will check
% this map first, and if the variable is not in this map, then it will go
% ahead and generate an lval for it as usual.
%
% Set the lval for a variable.
%
:- pred ml_gen_info_set_var_lval(prog_var::in, mlds_lval::in,
ml_gen_info::in, ml_gen_info::out) is det.
% The ml_gen_info contains a list of extra definitions of functions or
% global constants which should be inserted before the definition of the
% function for the current procedure. This is used for the definitions
% of the wrapper functions needed for closures. When generating code
% for a procedure that creates a closure, we insert the definition of
% the wrapper function used for that closure into this list.
%
% Insert an extra definition at the start of the list of extra
% definitions.
%
:- pred ml_gen_info_add_closure_wrapper_defn(mlds_function_defn::in,
ml_gen_info::in, ml_gen_info::out) is det.
% Add the given string as the name of an environment variable used by
% the function being generated.
%
:- pred ml_gen_info_add_env_var_name(string::in,
ml_gen_info::in, ml_gen_info::out) is det.
% Get the value of the copy_out option appropriate to the given code model.
%
:- pred ml_gen_info_get_copy_out(ml_gen_info::in, code_model::in, bool::out)
is det.
:- type target_of_self_tail_rec_call
---> is_not_target_of_self_trcall
; is_target_of_self_trcall.
:- type target_of_mutual_tail_rec_call
---> is_not_target_of_mutual_trcall
; is_target_of_mutual_trcall.
:- type nontail_rec_call_warn_status
---> nontail_rec_call_warn_disabled
; nontail_rec_call_warn_enabled.
:- type nontail_rec_call
---> nontail_rec_call(
ntrc_caller :: pred_proc_id,
ntrc_callee :: pred_proc_id,
ntrc_context :: prog_context,
ntrc_reason :: nontail_rec_call_reason,
ntrc_obviousness :: nontail_rec_obviousness,
ntrc_warn_status :: nontail_rec_call_warn_status
).
% This map should have an entry for each procedure in the TSCC.
% The set of keys in the map won't change and neither will
% the target mechanism of each, which tells the code generator
% how to generate code for a tail recursive call to the given
% procedure, but if the code generator *does* generate such
% a tail recursive call, it should set the
% have_we_done_tail_rec field to have_done_tail_rec.
:- type in_scc_map == map(pred_proc_id, in_scc_info).
:- type in_scc_info
---> in_scc_info(
% If this procedure is in the TSCC of the procedure we are
% currently generating code for, this field contains the
% information we need to generate tail recursive calls to it.
isi_maybe_in_tscc :: maybe_in_tscc_target_info,
% The next three fields say whether we have called
% this procedure in various ways. They are updated as
% we compile *all* the procedures in the TSCC.
% In a tail call from itself?
isi_is_target_of_self_tr :: target_of_self_tail_rec_call,
% In a tail call from another procedure in the TSCC?
isi_is_target_of_mutual_tr :: target_of_mutual_tail_rec_call,
% In a NONtail call, from anywhere in the *SCC*?
% This list gives, for each non-tail call to this procedure
% from *any* procedure in its SCC (including itself),
% the details of the call site.
%
% We use this field to gather a list of all the calls between
% the procedures in the TSCC that are *not* tail recursive.
% We store it in pieces, with one piece for each callee,
% because we already have the infrastructure for this
% in the form of the in_scc_map, and because storing
% the list as a whole in a data structure that is always
% passed along next to the in_scc_map would incur
% greater overheads, in both space and time, than this field.
isi_is_target_of_non_tail_rec :: list(nontail_rec_call)
).
:- type maybe_in_tscc_target_info
---> not_in_tscc
; in_tscc(
% The identifying small sequence number of this procedure
% in its TSCC. These numbers are assigned sequentially
% starting at 1, and are wrapped up in function symbol
% to distinguish them from other integers.
itti_id :: proc_id_in_tscc,
% The list of the *input* arguments of the procedure.
itti_input_args :: list(mlds_argument)
).
:- type tail_rec_loop_kind
---> tail_rec_loop_while_continue
; tail_rec_loop_label_goto.
:- type tscc_kind
---> tscc_self_rec_only
; tscc_self_and_mutual_rec.
:- type tail_rec_info
---> tail_rec_info(
% If a procedure has an entry in tri_target_map, then
% calls to that procedure should look at the corresponding
% value. They should update the field that says whether
% the actual kind of call has occurred, and they can turn
% tail calls into assignments to the trti_input_args,
% followed by a transfer of control to the start of the callee.
tri_in_scc_map :: in_scc_map,
% These two fields say how that transfer of control should be
% done. The tri_loop_kind field says whether the procedure body
% should start with a label, so that tail calls are a goto
% to that label, or whether the procedure body or bodies
% are wrapped up in an infinite while loop, with tail calls
% jumping back to its start via a "continue" statement.
% The tri_tscc_kind field says whether the loop contains
% just procedure body, or several. In the latter case,
% each procedure will either have its own label,
% or the body of the while loop will be a switch on
% lvnc_tscc_proc_selector, with each procedure body
% being one of the cases of the switch. The id of the label,
% or the value of the selector, is given by the trti_id field
% of the callee in tri_target_map.
tri_loop_kind :: tail_rec_loop_kind,
tri_tscc_kind :: tscc_kind
).
:- func generate_tail_rec_start_label(tscc_kind, proc_id_in_tscc) = mlds_label.
%---------------------------------------------------------------------------%
%
% Initialize the ml_gen_info, which contains the state of the code generator
% while it generates MLDS code for a HLDS procedure.
%
% When the HLDS procedure is part of a TSCC of several mutually-tail-recursive
% procedures, we bundle the code we generate for each procedure into
% a single piece of code for *each* entry procedure of the TSCC.
% To help prevent accidental name collisions between the compiler-generated
% local variables of the different procedures, we get those procedures
% to use non-overlapping sets of sequence numbers in the names of those
% compiler-generated variables, by
%
% - creating an initial set of counters (the sources of those sequence numbers)
% before starting to generate code for a TSCC, and
% - threading the values of those counters from one procedure to the next,
% by calling ml_gen_info_final to pick up the values of those counters
% after code generation is finished for one procedure, and passing them
% to ml_gen_info_init when starting to generate code for the next procedure.
%
% The ml_gen_tscc_info structure contains not just these counters, but also
% information about tail recursion. By definition, the procedures in a TSCC
% contain tail recursive calls to the same set of procedures (the procedures
% of the TSCC), but TSCCs are computed from calls in the HLDS. A call that is
% a tail call in the HLDS is sometimes not a tail call in the MLDS, which can
% happen if making the call a tail call would leave a dangling reference.
% We therefore need to record whether each procedure in the TSCC has an
% *MLDS* tail call generated to it from any of the *other* procedures
% in the TSCC, because if it doesn't, then its MLDS code isn't actually
% mutually-tail-recursive, and it should be handled as such. (This is because
% the code we generate for only *self*-tail-recursive procedures has lower
% overhead than the code we generate for *mutually*-tail-recursive procedures.)
:- type ml_gen_tscc_info
---> ml_gen_tscc_info(
mgti_func_label_counter :: counter,
mgti_label_counter :: counter,
mgti_aux_var_counter :: counter,
mgti_cond_var_counter :: counter,
mgti_conv_var_counter :: counter,
mgti_packed_word_counter :: counter,
mgti_tail_rec_info :: tail_rec_info
).
:- pred init_ml_gen_tscc_info(module_info::in, in_scc_map::in, tscc_kind::in,
ml_gen_tscc_info::out) is det.
% Initialize the ml_gen_info, so that it is almost ready for
% generating code for the given procedure. (The "almost" is because
% the caller still needs to set the byref_output_vars field. We don't
% set it to a meaningful value here, because the code for setting it
% itself needs an ml_gen_info.)
%
% The second last argument records the persistent information
% accumulated by the code generator so far during the processing of
% previous procedures. The role of the last argument is described above.
%
:- func ml_gen_info_init(module_info, mlds_target_lang, ml_const_struct_map,
pred_proc_id, proc_info, ml_global_data, ml_gen_tscc_info) = ml_gen_info.
% ml_gen_info_final(Info, EnvVarNames, ClosureWrapperDefns, GlobalData,
% TsccInfo):
%
% Return
%
% - the values of those fields that are actually part of the MLDS
% structure we are generating (EnvVarNames, ClosureWrapperDefns and
% GlobalData),
% - the values of the counters that our caller may need when
% initializating the *next* ml_gen_info (in TsccInfo),
% - the values of the fields that the code generator needs
% to decide what code to generate for this procedure (in TsccInfo).
%
:- pred ml_gen_info_final(ml_gen_info::in, set(string)::out,
list(mlds_function_defn)::out, ml_global_data::out, ml_gen_tscc_info::out)
is det.
%---------------------------------------------------------------------------%
%
% Getters and setters of the ml_gen_info structure.
%
:- pred ml_gen_info_get_const_var_map(ml_gen_info::in,
ml_ground_term_map::out) is det.
:- pred ml_gen_info_get_used_succeeded_var(ml_gen_info::in, bool::out) is det.
:- pred ml_gen_info_get_closure_wrapper_defns(ml_gen_info::in,
list(mlds_function_defn)::out) is det.
:- pred ml_gen_info_get_global_data(ml_gen_info::in, ml_global_data::out)
is det.
:- pred ml_gen_info_get_module_info(ml_gen_info::in, module_info::out) is det.
:- pred ml_gen_info_get_pred_proc_id(ml_gen_info::in,
pred_proc_id::out) is det.
:- pred ml_gen_info_get_var_table(ml_gen_info::in, var_table::out) is det.
:- pred ml_gen_info_get_high_level_data(ml_gen_info::in, bool::out) is det.
:- pred ml_gen_info_get_target(ml_gen_info::in, mlds_target_lang::out) is det.
:- pred ml_gen_info_get_gc(ml_gen_info::in, gc_method::out) is det.
:- pred ml_gen_info_get_det_copy_out(ml_gen_info::in, bool::out) is det.
:- pred ml_gen_info_get_nondet_copy_out(ml_gen_info::in, bool::out) is det.
:- pred ml_gen_info_get_use_atomic_cells(ml_gen_info::in,
maybe_use_atomic_cells::out) is det.
:- pred ml_gen_info_get_profile_memory(ml_gen_info::in, bool::out) is det.
:- pred ml_gen_info_get_num_ptag_bits(ml_gen_info::in, uint8::out) is det.
:- pred ml_gen_info_get_const_struct_map(ml_gen_info::in,
map(int, ml_ground_term)::out) is det.
:- pred ml_gen_info_get_var_lvals(ml_gen_info::in,
map(prog_var, mlds_lval)::out) is det.
:- pred ml_gen_info_get_env_var_names(ml_gen_info::in, set(string)::out)
is det.
:- pred ml_gen_info_get_disabled_warnings(ml_gen_info::in,
set(goal_warning)::out) is det.
:- pred ml_gen_info_get_tail_rec_info(ml_gen_info::in,
tail_rec_info::out) is det.
:- pred ml_gen_info_get_byref_output_vars(ml_gen_info::in,
set_of_progvar::out) is det.
:- pred ml_gen_info_get_packed_word_map(ml_gen_info::in,
packed_word_map::out) is det.
:- pred ml_gen_info_get_func_nest_depth(ml_gen_info::in, int::out) is det.
:- pred ml_gen_info_set_const_var_map(ml_ground_term_map::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_used_succeeded_var(bool::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_global_data(ml_global_data::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_module_info(module_info::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_var_table(var_table::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_var_lvals(map(prog_var, mlds_lval)::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_disabled_warnings(set(goal_warning)::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_tail_rec_info(tail_rec_info::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_byref_output_vars(set_of_progvar::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_packed_word_map(packed_word_map::in,
ml_gen_info::in, ml_gen_info::out) is det.
%---------------------------------------------------------------------------%
:- implementation.
:- import_module libs.options.
:- import_module ml_backend.ml_target_util.
:- import_module ml_backend.ml_util.
:- import_module int.
:- import_module stack.
:- import_module string.
:- import_module uint8.
%---------------------------------------------------------------------------%
ml_gen_info_get_globals(Info, Globals) :-
ml_gen_info_get_module_info(Info, ModuleInfo),
module_info_get_globals(ModuleInfo, Globals).
ml_gen_info_get_module_name(Info, ModuleName) :-
ml_gen_info_get_module_info(Info, ModuleInfo),
module_info_get_name(ModuleInfo, ModuleName).
ml_gen_info_put_commit_in_own_func(Info, PutCommitInNestedFunc) :-
ml_gen_info_get_globals(Info, Globals),
globals.lookup_bool_option(Globals, put_commit_in_own_func,
PutCommitInNestedFunc).
ml_gen_info_new_label(Label, !Info) :-
ml_gen_info_get_label_counter(!.Info, Counter0),
counter.allocate(Label, Counter0, Counter),
ml_gen_info_set_label_counter(Counter, !Info).
ml_gen_info_new_aux_func_id(MaybeAux, !Info) :-
ml_gen_info_get_func_counter(!.Info, Counter0),
counter.allocate(Num, Counter0, Counter),
MaybeAux = proc_aux_func(Num),
ml_gen_info_set_func_counter(Counter, !Info).
ml_gen_info_bump_counters(!Info) :-
ml_gen_info_get_func_counter(!.Info, FuncLabelCounter0),
counter.allocate(FuncLabel, FuncLabelCounter0, _),
FuncLabelCounter = counter.init(FuncLabel + 10000),
ml_gen_info_set_func_counter(FuncLabelCounter, !Info).
ml_gen_info_new_aux_var_name(AuxVar, VarName, !Info) :-
ml_gen_info_get_aux_var_counter(!.Info, AuxVarCounter0),
counter.allocate(AuxVarNum, AuxVarCounter0, AuxVarCounter),
ml_gen_info_set_aux_var_counter(AuxVarCounter, !Info),
VarName = lvn_comp_var(lvnc_aux_var(AuxVar, AuxVarNum)).
ml_gen_info_new_cond_var(cond_seq(CondNum), !Info) :-
ml_gen_info_get_cond_var_counter(!.Info, CondCounter0),
counter.allocate(CondNum, CondCounter0, CondCounter),
ml_gen_info_set_cond_var_counter(CondCounter, !Info).
ml_gen_info_new_conv_var(conv_seq(ConvNum), !Info) :-
ml_gen_info_get_conv_var_counter(!.Info, ConvCounter0),
counter.allocate(ConvNum, ConvCounter0, ConvCounter),
ml_gen_info_set_conv_var_counter(ConvCounter, !Info).
get_unfilled_filled_packed_words(HeadFilledBitfield, TailFilledBitfields,
PackedWord, FilledPackedWord) :-
HeadBitfield = get_unfilled_bitfield(HeadFilledBitfield),
TailBitfields = list.map(get_unfilled_bitfield, TailFilledBitfields),
PackedWord = one_or_more(HeadBitfield, TailBitfields),
FilledPackedWord = one_or_more(HeadFilledBitfield, TailFilledBitfields).
:- func get_unfilled_bitfield(filled_bitfield) = bitfield.
get_unfilled_bitfield(FilledBitfield) = Bitfield :-
FilledBitfield = filled_bitfield(Bitfield, _Value).
ml_gen_info_new_packed_word_var(LocalVarName, !Info) :-
ml_gen_info_get_packed_word_counter(!.Info, PackedWordCounter0),
counter.allocate(PackedWordNum, PackedWordCounter0, PackedWordCounter),
LocalVarName = lvnc_packed_word(PackedWordNum),
ml_gen_info_set_packed_word_counter(PackedWordCounter, !Info).
ml_gen_info_set_const_var(Var, GroundTerm, !Info) :-
ml_gen_info_get_const_var_map(!.Info, ConstVarMap0),
% We cannot call map.det_insert, because we do not (yet) clean up the
% const_var_map at the start of later branches of a branched goal,
% and thus when generating code for a later branch, we may come across
% an entry left by an earlier branch. Using map.set instead throws away
% such obsolete entries.
map.set(Var, GroundTerm, ConstVarMap0, ConstVarMap),
ml_gen_info_set_const_var_map(ConstVarMap, !Info).
ml_gen_info_lookup_const_var(Info, Var, GroundTerm) :-
ml_gen_info_get_const_var_map(Info, ConstVarMap),
map.lookup(ConstVarMap, Var, GroundTerm).
ml_gen_info_search_const_var(Info, Var, GroundTerm) :-
ml_gen_info_get_const_var_map(Info, ConstVarMap),
map.search(ConstVarMap, Var, GroundTerm).
ml_gen_info_push_success_cont(SuccCont, !Info) :-
ml_gen_info_get_success_cont_stack(!.Info, Stack0),
stack.push(SuccCont, Stack0, Stack),
ml_gen_info_set_success_cont_stack(Stack, !Info).
ml_gen_info_pop_success_cont(!Info) :-
ml_gen_info_get_success_cont_stack(!.Info, Stack0),
stack.det_pop(_SuccCont, Stack0, Stack),
ml_gen_info_set_success_cont_stack(Stack, !Info).
ml_gen_info_current_success_cont(Info, SuccCont) :-
ml_gen_info_get_success_cont_stack(Info, Stack),
stack.det_top(Stack, SuccCont).
ml_gen_info_increment_func_nest_depth(!Info) :-
ml_gen_info_get_func_nest_depth(!.Info, Depth0),
Depth = Depth0 + 1,
ml_gen_info_set_func_nest_depth(Depth, !Info).
ml_gen_info_decrement_func_nest_depth(!Info) :-
ml_gen_info_get_func_nest_depth(!.Info, Depth0),
Depth = Depth0 - 1,
ml_gen_info_set_func_nest_depth(Depth, !Info).
ml_gen_info_set_var_lval(Var, Lval, !Info) :-
ml_gen_info_get_var_lvals(!.Info, VarLvals0),
map.set(Var, Lval, VarLvals0, VarLvals),
ml_gen_info_set_var_lvals(VarLvals, !Info).
ml_gen_info_add_closure_wrapper_defn(ClosureWrapperDefn, !Info) :-
ml_gen_info_get_closure_wrapper_defns(!.Info, ClosureWrapperDefns0),
ClosureWrapperDefns = [ClosureWrapperDefn | ClosureWrapperDefns0],
ml_gen_info_set_closure_wrapper_defns(ClosureWrapperDefns, !Info).
ml_gen_info_add_env_var_name(Name, !Info) :-
ml_gen_info_get_env_var_names(!.Info, EnvVarNames0),
set.insert(Name, EnvVarNames0, EnvVarNames),
ml_gen_info_set_env_var_names(EnvVarNames, !Info).
ml_gen_info_get_copy_out(Info, CodeModel, CopyOut) :-
(
( CodeModel = model_det
; CodeModel = model_semi
),
ml_gen_info_get_det_copy_out(Info, CopyOut)
;
CodeModel = model_non,
ml_gen_info_get_nondet_copy_out(Info, CopyOut)
).
%---------------------------------------------------------------------------%
generate_tail_rec_start_label(TsccKind, Id) = Label :-
(
TsccKind = tscc_self_rec_only,
Label = mlds_label("top_of_proc")
;
TsccKind = tscc_self_and_mutual_rec,
Id = proc_id_in_tscc(IdNum),
Label = mlds_label(string.format("top_of_proc_%d", [i(IdNum)]))
).
%---------------------------------------------------------------------------%
%
% The definition of the `ml_gen_info' ADT.
%
% The ml_gen_info structure is logically an atomic structure,
% but we split it up into three pieces for performance reasons.
% The most frequently updated fields are at the top level, in the ml_gen_info
% structure, whose size is limited to eight fields. This makes it (just) fit
% into one of Boehm gc's size categories, and it limits the amount of copying
% that needs to be done when one of the fields is updated. The other fields
% are stored in one of two substructures. The ml_gen_rare_info is for the
% fields that are never or almost-never updated, while the ml_gen_sub_info
% is for the fields that are updated reasonably frequently, though not
% so frequently as to deserve a spot in the top level structure.
:- type ml_gen_info
---> ml_gen_info(
% A variable can be bound to a constant in one branch
% of a control structure and to a non-constant term
% in another branch. We store information about variables
% bound to constants in the mgsi_const_var_map field.
%
% Branched control structures should reset the map
% to its original value at the start of every branch
% after the first (to prevent a later branch from using
% information that is applicable only in a previous branch).
%
% They must also ensure that the const_var_map at the
% program point just after the branched control structure
% contains only entries that exist at the ends of all the
% branches whose ends are actually reachable (to prevent
% the code after it using information whose correctness
% depends on the exact route that execution took to there).
/* 1 */ mgi_const_var_map :: ml_ground_term_map,
/* 2 */ mgi_func_counter :: counter,
/* 3 */ mgi_conv_var_counter :: counter,
/* 4 */ mgi_used_succeeded_var :: bool,
/* 5 */ mgi_closure_wrapper_defns :: list(mlds_function_defn),
/* 6 */ mgi_global_data :: ml_global_data,
/* 7 */ mgi_rare_info :: ml_gen_rare_info,
/* 8 */ mgi_sub_info :: ml_gen_sub_info
).
:- type ml_gen_rare_info
---> ml_gen_rare_info(
% The module_info. Read-only except when ml_accurate_gc.m
% makes new type_info variables.
%
% XXX This is because it creates them by calling
% polymorphism_make_type_info_var_raw, which updates
% the module_info. It should be possible to avoid this.
/* 1 */ mgri_module_info :: module_info,
% The identity of the procedure we are generating code for.
% Read-only.
/* 2 */ mgri_pred_proc_id :: pred_proc_id,
% The table containing information about the names and types
% of the variables in the procedure we are generating code for.
% Read-only except when ml_accurate_gc.m makes new type_info
% variables.
/* 3 */ mgri_var_table :: var_table,
% Quick-access read-only copies of parts of the globals
% structure taken from the module_info. Read-only.
/* 4 */ mgri_high_level_data :: bool,
/* - */ mgri_target :: mlds_target_lang,
/* - */ mgri_gc :: gc_method,
/* - */ mgri_det_copy_out :: bool,
/* - */ mgri_nondet_copy_out :: bool,
/* - */ mgri_use_atomic_cells :: maybe_use_atomic_cells,
/* - */ mgri_profile_memory :: bool,
/* - */ mgri_num_ptag_bits :: uint8,
% The map of the constant ground structures generated by
% ml_code_gen before we start generating code for procedures.
% Read-only.
/* 5 */ mgri_const_struct_map :: map(int, ml_ground_term),
% Normally, we convert each HLDS variable to its own MLDS lval
% each time the HLDS code refers it, using a simple
% determininistic algorithm (the ml_gen_var function).
% However, inside a commit scope, we currently translate
% the output variables of that scope not to the MLDS lval
% that the code outside the commit uses to refer to the
% variable, but to a local *copy* of that variable;
% when the goal inside the commit succeeds, we then assign
% the value of the local copy to the MLDS variable used
% outside the scope. The var_lvals field maps each output var
% of every commit scope we are in to the local copy MLDS
% variable.
%
% Currenly, this complexity is not actually necessary for the
% C backend, which has nondet_copy_out set to "no". When the
% output variable is generated, the code inside the commit
% could assign its new value to the usual MLDS variable
% (the one returned by ml_gen_var) directly. I (zs) have
% just tried a bootcheck which did that, and it works.
%
% However, in the future, when we generate implicitly
% AND-parallel MLDS code, this could come in useful for C as
% well. This is because it is possible for an output variable
% of a commit scope to become bound many times inside the scope
% before the scope as a whole succeeds, if each binding but
% the last is followed by a local failure. We want to signal
% any consumer of the variable *outside* the scope that
% the variable has actually been bound only when the commit
% scope succeeds and *its usual MLDS variable* is assigned to,
% while we want to signal any consumer *inside* the scope
% when *the local copy* is assigned to. The distinction
% would then give us two separate assignments to follow with
% two separate signal operations for two separate classes
% of consumers.
%
% Writeable.
/* 6 */ mgri_var_lvals :: map(prog_var, mlds_lval),
% The set of used environment variables. Writeable.
/* 7 */ mgri_env_var_names :: set(string),
% The set of warnings disabled in the current scope. Writeable.
/* 8 */ mgri_disabled_warnings :: set(goal_warning),
/* 9 */ % For each procedure to whose tail calls we can apply
% tail recursion optimization, this maps the label of that
% procedure to (a) the information we need to generate
% the code to jump to the start of that procedure, and
% (b) a record of whether we *have* generated (either tail-
% or nontail-) calls to this procedure.
%
% This field also contains the information we need to generate
% the right set of warnings for calls marked as tail recursive
% by mark_tail_calls.m but which we cannot actually turn
% into tail calls, and the warnings so generated.
%
% Writeable.
mgri_tail_rec_info :: tail_rec_info
).
:- type ml_gen_sub_info
---> ml_gen_sub_info(
% Output arguments that are passed by reference.
% (We used to store the list of output arguments that are
% returned as values in another field, but we don't need that
% information anymore.)
/* 1 */ mgsi_byref_output_vars :: set_of_progvar,
/* 2 */ mgsi_label_counter :: counter,
/* 3 */ mgsi_aux_var_counter :: counter,
/* 4 */ mgsi_cond_var_counter :: counter,
/* 5 */ mgsi_packed_word_counter :: counter,
/* 6 */ mgsi_packed_word_map :: packed_word_map,
/* 7 */ mgsi_success_cont_stack :: stack(success_cont),
/* 8 */ mgsi_func_nest_depth :: int
).
% Access stats for the ml_gen_info structure:
%
% i read same diff same%
% 0 18766903 0 0 module_info
% 1 548868 0 0 high_level_data
% 2 232588 0 0 target
% 3 2721027 0 0 gc
% 4 158848 0 0 pred_id
% 5 158848 0 0 proc_id
% 6 4647635 0 0 varset
% 7 7835272 0 0 vartypes
% 8 2964012 64588 11516 84.87% byref_output_vars
% 9 0 65734 11516 85.09% value_output_vars
% 10 2998238 594 0 100.00% var_lvals
% 11 135553 13144 27277 32.52% global_data
% 12 53820 0 53820 0.00% func_counter
% 13 237 0 237 0.00% label_counter
% 14 1805 0 1805 0.00% aux_var_counter
% 15 21 0 21 0.00% cond_var_counter
% 16 52544 0 52544 0.00% conv_var_counter
% 17 727348 151728 477494 24.11% const_var_map
% 18 32375 0 0 const_struct_map
% 19 14408 0 8197 0.00% success_cont_stack
% 20 127335 0 32258 0.00% closure_wrapper_defns
% 21 77412 8 8 50.00% env_var_names
% 22 352575 0 2 0.00% disabled_warnings
% 23 77250 341887 45872 88.17% used_succeeded_var
%---------------------------------------------------------------------------%
:- pragma inline(pred(init_ml_gen_tscc_info/4)).
init_ml_gen_tscc_info(ModuleInfo, InSccMap, TsccKind, TsccInfo) :-
% XXX FuncLabelCounter needs to start at 1 rather than 0,
% otherwise the transformation for adding the shadow stack
% for accurate garbage collection does not work properly,
% and we will end up generating two C functions with the same name
% (see ml_elim_nested.gen_gc_trace_func/8 for details).
counter.init(1, FuncLabelCounter),
counter.init(0, LabelCounter),
counter.init(0, AuxVarCounter),
counter.init(0, CondVarCounter),
counter.init(0, PackedWordCounter),
counter.init(0, ConvVarCounter),
module_info_get_globals(ModuleInfo, Globals),
globals.get_target(Globals, Target),
% Can we implement tail calls by adding a label at the start of
% the function, translating tail calls into a goto to that label?
SupportsGoto = target_supports_goto(Target),
% Can we implement tail calls by wrapping the function body inside
% `while (true) { ... break; }', translating tail calls into `continue'?
% Yes: all the current MLDS target languages support break and continue.
% SupportsBreakContinue = target_supports_break_and_continue(Target),
SupportsBreakContinue = yes,
(
% SupportsBreakContinue = no,
% SupportsGoto = no,
% unexpected($pred, "SupportsGoto = SupportsBreakContinue = no")
% ;
% SupportsBreakContinue = no,
% SupportsGoto = yes,
% LoopKind = tail_rec_loop_label_goto
% ;
SupportsBreakContinue = yes,
SupportsGoto = no,
LoopKind = tail_rec_loop_while_continue
;
SupportsBreakContinue = yes,
SupportsGoto = yes,
(
TsccKind = tscc_self_rec_only,
PreferBreakContinueOption = prefer_while_loop_over_jump_self
;
TsccKind = tscc_self_and_mutual_rec,
PreferBreakContinueOption = prefer_while_loop_over_jump_mutual
),
globals.lookup_bool_option(Globals, PreferBreakContinueOption,
PreferBreakContinue),
(
PreferBreakContinue = no,
LoopKind = tail_rec_loop_label_goto
;
PreferBreakContinue = yes,
LoopKind = tail_rec_loop_while_continue
)
),
TailRecInfo = tail_rec_info(InSccMap, LoopKind, TsccKind),
TsccInfo = ml_gen_tscc_info(FuncLabelCounter, LabelCounter,
AuxVarCounter, CondVarCounter, PackedWordCounter, ConvVarCounter,
TailRecInfo).
ml_gen_info_init(ModuleInfo, Target, ConstStructMap, PredProcId, ProcInfo,
GlobalData, TsccInfo) = Info :-
TsccInfo = ml_gen_tscc_info(FuncLabelCounter, LabelCounter,
AuxVarCounter, CondVarCounter, PackedWordCounter, ConvVarCounter,
TailRecInfo),
proc_info_get_var_table(ProcInfo, VarTable),
HighLevelData = mlds_target_high_level_data(Target),
module_info_get_globals(ModuleInfo, Globals),
globals.get_gc_method(Globals, GC),
globals.lookup_bool_option(Globals, det_copy_out, DetCopyOut),
globals.lookup_bool_option(Globals, nondet_copy_out, NondetCopyOut),
globals.get_opt_tuple(Globals, OptTuple),
UseAtomicCells = OptTuple ^ ot_use_atomic_cells,
globals.lookup_bool_option(Globals, profile_memory, ProfileMemory),
globals.lookup_int_option(Globals, num_ptag_bits, NumPtagBitsInt),
NumPtagBits = uint8.det_from_int(NumPtagBitsInt),
map.init(VarLvals),
set.init(EnvVarNames),
set.init(DisabledWarnings),
RareInfo = ml_gen_rare_info(
ModuleInfo,
PredProcId,
VarTable,
HighLevelData,
Target,
GC,
DetCopyOut,
NondetCopyOut,
UseAtomicCells,
ProfileMemory,
NumPtagBits,
ConstStructMap,
VarLvals,
EnvVarNames,
DisabledWarnings,
TailRecInfo
),
set_of_var.init(ByRefOutputVars),
map.init(PackedWordMap),
stack.init(SuccContStack),
FuncNestDepth = 0,
SubInfo = ml_gen_sub_info(
ByRefOutputVars,
LabelCounter,
AuxVarCounter,
CondVarCounter,
PackedWordCounter,
PackedWordMap,
SuccContStack,
FuncNestDepth
),
map.init(ConstVarMap),
UsedSucceededVar = no,
ClosureWrapperDefns = [],
Info = ml_gen_info(
ConstVarMap,
FuncLabelCounter,
ConvVarCounter,
UsedSucceededVar,
ClosureWrapperDefns,
GlobalData,
RareInfo,
SubInfo
).
ml_gen_info_final(Info, EnvVarNames, ClosureWrapperDefns, GlobalData,
TsccInfo) :-
Info = ml_gen_info(
_ConstVarMap,
FuncLabelCounter,
ConvVarCounter,
_UsedSucceededVar,
ClosureWrapperDefns,
GlobalData,
RareInfo,
SubInfo
),
RareInfo = ml_gen_rare_info(
_ModuleInfo,
_PredProcId,
_VarTable,
_HighLevelData,
_Target,
_GC,
_DetCopyOut,
_NondetCopyOut,
_UseAtomicCells,
_ProfileMemory,
_NumPtagBits,
_ConstStructMap,
_VarLvals,
EnvVarNames,
_DisabledWarnings,
TailRecInfo
),
SubInfo = ml_gen_sub_info(
_ByRefOutputVars,
LabelCounter,
AuxVarCounter,
CondVarCounter,
PackedWordCounter,
_PackedWordMap,
_SuccContStack,
_FuncNestDepth
),
TsccInfo = ml_gen_tscc_info(FuncLabelCounter, LabelCounter,
AuxVarCounter, CondVarCounter, PackedWordCounter, ConvVarCounter,
TailRecInfo).
%---------------------------------------------------------------------------%
:- pred ml_gen_info_get_func_counter(ml_gen_info::in, counter::out) is det.
:- pred ml_gen_info_get_conv_var_counter(ml_gen_info::in, counter::out) is det.
:- pred ml_gen_info_get_label_counter(ml_gen_info::in, counter::out) is det.
:- pred ml_gen_info_get_aux_var_counter(ml_gen_info::in, counter::out) is det.
:- pred ml_gen_info_get_cond_var_counter(ml_gen_info::in, counter::out) is det.
:- pred ml_gen_info_get_packed_word_counter(ml_gen_info::in,
counter::out) is det.
:- pred ml_gen_info_get_success_cont_stack(ml_gen_info::in,
stack(success_cont)::out) is det.
ml_gen_info_get_const_var_map(Info, X) :-
X = Info ^ mgi_const_var_map.
ml_gen_info_get_func_counter(Info, X) :-
X = Info ^ mgi_func_counter.
ml_gen_info_get_conv_var_counter(Info, X) :-
X = Info ^ mgi_conv_var_counter.
ml_gen_info_get_used_succeeded_var(Info, X) :-
X = Info ^ mgi_used_succeeded_var.
ml_gen_info_get_closure_wrapper_defns(Info, X) :-
X = Info ^ mgi_closure_wrapper_defns.
ml_gen_info_get_global_data(Info, X) :-
X = Info ^ mgi_global_data.
ml_gen_info_get_module_info(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_module_info.
ml_gen_info_get_pred_proc_id(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_pred_proc_id.
ml_gen_info_get_var_table(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_var_table.
ml_gen_info_get_high_level_data(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_high_level_data.
ml_gen_info_get_target(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_target.
ml_gen_info_get_gc(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_gc.
ml_gen_info_get_det_copy_out(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_det_copy_out.
ml_gen_info_get_nondet_copy_out(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_nondet_copy_out.
ml_gen_info_get_use_atomic_cells(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_use_atomic_cells.
ml_gen_info_get_profile_memory(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_profile_memory.
ml_gen_info_get_num_ptag_bits(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_num_ptag_bits.
ml_gen_info_get_const_struct_map(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_const_struct_map.
ml_gen_info_get_var_lvals(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_var_lvals.
ml_gen_info_get_env_var_names(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_env_var_names.
ml_gen_info_get_disabled_warnings(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_disabled_warnings.
ml_gen_info_get_tail_rec_info(Info, X) :-
X = Info ^ mgi_rare_info ^ mgri_tail_rec_info.
ml_gen_info_get_byref_output_vars(Info, X) :-
X = Info ^ mgi_sub_info ^ mgsi_byref_output_vars.
ml_gen_info_get_label_counter(Info, X) :-
X = Info ^ mgi_sub_info ^ mgsi_label_counter.
ml_gen_info_get_aux_var_counter(Info, X) :-
X = Info ^ mgi_sub_info ^ mgsi_aux_var_counter.
ml_gen_info_get_cond_var_counter(Info, X) :-
X = Info ^ mgi_sub_info ^ mgsi_cond_var_counter.
ml_gen_info_get_packed_word_counter(Info, X) :-
X = Info ^ mgi_sub_info ^ mgsi_packed_word_counter.
ml_gen_info_get_packed_word_map(Info, X) :-
X = Info ^ mgi_sub_info ^ mgsi_packed_word_map.
ml_gen_info_get_success_cont_stack(Info, X) :-
X = Info ^ mgi_sub_info ^ mgsi_success_cont_stack.
ml_gen_info_get_func_nest_depth(Info, X) :-
X = Info ^ mgi_sub_info ^ mgsi_func_nest_depth.
:- pred ml_gen_info_set_func_counter(counter::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_conv_var_counter(counter::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_closure_wrapper_defns(list(mlds_function_defn)::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_env_var_names(set(string)::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_label_counter(counter::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_aux_var_counter(counter::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_cond_var_counter(counter::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_packed_word_counter(counter::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_success_cont_stack(stack(success_cont)::in,
ml_gen_info::in, ml_gen_info::out) is det.
:- pred ml_gen_info_set_func_nest_depth(int::in,
ml_gen_info::in, ml_gen_info::out) is det.
ml_gen_info_set_const_var_map(X, !Info) :-
( if private_builtin.pointer_equal(X, !.Info ^ mgi_const_var_map) then
true
else
!Info ^ mgi_const_var_map := X
).
ml_gen_info_set_func_counter(X, !Info) :-
!Info ^ mgi_func_counter := X.
ml_gen_info_set_conv_var_counter(X, !Info) :-
!Info ^ mgi_conv_var_counter := X.
ml_gen_info_set_used_succeeded_var(X, !Info) :-
( if X = !.Info ^ mgi_used_succeeded_var then
true
else
!Info ^ mgi_used_succeeded_var := X
).
ml_gen_info_set_closure_wrapper_defns(X, !Info) :-
!Info ^ mgi_closure_wrapper_defns := X.
ml_gen_info_set_global_data(X, !Info) :-
( if private_builtin.pointer_equal(X, !.Info ^ mgi_global_data) then
true
else
!Info ^ mgi_global_data := X
).
ml_gen_info_set_module_info(X, !Info) :-
RareInfo0 = !.Info ^ mgi_rare_info,
RareInfo = RareInfo0 ^ mgri_module_info := X,
!Info ^ mgi_rare_info := RareInfo.
ml_gen_info_set_var_table(X, !Info) :-
RareInfo0 = !.Info ^ mgi_rare_info,
RareInfo = RareInfo0 ^ mgri_var_table := X,
!Info ^ mgi_rare_info := RareInfo.
ml_gen_info_set_var_lvals(X, !Info) :-
RareInfo0 = !.Info ^ mgi_rare_info,
( if private_builtin.pointer_equal(X, RareInfo0 ^ mgri_var_lvals) then
true
else
RareInfo = RareInfo0 ^ mgri_var_lvals := X,
!Info ^ mgi_rare_info := RareInfo
).
ml_gen_info_set_env_var_names(X, !Info) :-
RareInfo0 = !.Info ^ mgi_rare_info,
RareInfo = RareInfo0 ^ mgri_env_var_names := X,
!Info ^ mgi_rare_info := RareInfo.
ml_gen_info_set_disabled_warnings(X, !Info) :-
RareInfo0 = !.Info ^ mgi_rare_info,
RareInfo = RareInfo0 ^ mgri_disabled_warnings := X,
!Info ^ mgi_rare_info := RareInfo.
ml_gen_info_set_tail_rec_info(X, !Info) :-
RareInfo0 = !.Info ^ mgi_rare_info,
RareInfo = RareInfo0 ^ mgri_tail_rec_info := X,
!Info ^ mgi_rare_info := RareInfo.
ml_gen_info_set_byref_output_vars(X, !Info) :-
SubInfo0 = !.Info ^ mgi_sub_info,
( if
private_builtin.pointer_equal(X, SubInfo0 ^ mgsi_byref_output_vars)
then
true
else
SubInfo = SubInfo0 ^ mgsi_byref_output_vars := X,
!Info ^ mgi_sub_info := SubInfo
).
ml_gen_info_set_label_counter(X, !Info) :-
SubInfo0 = !.Info ^ mgi_sub_info,
SubInfo = SubInfo0 ^ mgsi_label_counter := X,
!Info ^ mgi_sub_info := SubInfo.
ml_gen_info_set_aux_var_counter(X, !Info) :-
SubInfo0 = !.Info ^ mgi_sub_info,
SubInfo = SubInfo0 ^ mgsi_aux_var_counter := X,
!Info ^ mgi_sub_info := SubInfo.
ml_gen_info_set_cond_var_counter(X, !Info) :-
SubInfo0 = !.Info ^ mgi_sub_info,
SubInfo = SubInfo0 ^ mgsi_cond_var_counter := X,
!Info ^ mgi_sub_info := SubInfo.
ml_gen_info_set_packed_word_counter(X, !Info) :-
SubInfo0 = !.Info ^ mgi_sub_info,
SubInfo = SubInfo0 ^ mgsi_packed_word_counter := X,
!Info ^ mgi_sub_info := SubInfo.
ml_gen_info_set_packed_word_map(X, !Info) :-
SubInfo0 = !.Info ^ mgi_sub_info,
( if
private_builtin.pointer_equal(X, SubInfo0 ^ mgsi_packed_word_map)
then
true
else
SubInfo = SubInfo0 ^ mgsi_packed_word_map := X,
!Info ^ mgi_sub_info := SubInfo
).
ml_gen_info_set_success_cont_stack(X, !Info) :-
SubInfo0 = !.Info ^ mgi_sub_info,
SubInfo = SubInfo0 ^ mgsi_success_cont_stack := X,
!Info ^ mgi_sub_info := SubInfo.
ml_gen_info_set_func_nest_depth(X, !Info) :-
SubInfo0 = !.Info ^ mgi_sub_info,
SubInfo = SubInfo0 ^ mgsi_func_nest_depth := X,
!Info ^ mgi_sub_info := SubInfo.
%---------------------------------------------------------------------------%
:- end_module ml_backend.ml_gen_info.
%---------------------------------------------------------------------------%