%---------------------------------------------------------------------------% % vim: ft=mercury ts=4 sw=4 et %---------------------------------------------------------------------------% % Copyright (C) 2009, 2011-2012 The University of Melbourne. % This file may only be copied under the terms of the GNU General % Public License - see the file COPYING in the Mercury distribution. %---------------------------------------------------------------------------% % % File: 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. %---------------------------------------------------------------------------%