mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 09:23:44 +00:00
... and other minor fixes.
library/*.m:
library/LIB_FLAGS.in:
compiler/*.m:
mdbcomp/*.m:
Fix and update copyright notices.
Fix spelling.
Delete trailing whitespace.
1274 lines
54 KiB
Mathematica
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.
|
|
%---------------------------------------------------------------------------%
|