Files
mercury/compiler/code_info.m
Zoltan Somogyi 624aaa01f1 Pack subword-sized arguments next to a local sectag.
compiler/du_type_layout.m:
    If a new option is set, then try to represent function symbols with
    only subword-sized arguments by packing those arguments into the same word
    as the primary tag and (if it is needed) a secondary tag.

    If there are too many such function symbols for the available number of
    bits, pick the ones that need the least number of bits, in order to
    allow us to use this representation for as many such function symbols
    as possible.

    This diff implements this packing only for types that have more than one
    argument, because implementing it for types that have only one argument
    has two extra complications. One is the need for another new cons_id
    (see below), which would make this diff bigger and harder to review.
    The other is the need to consider interactions with the direct_arg
    optimization.

    Don't invoke the code for deciding the representation of arguments
    if either (a) the function symbol has no arguments, or (b) its cons_id
    alone dictates how we will treat its argument (in such cases, there is
    always exactly one).

    Fix a bug in computing the number of bits needed to distinguish N things.

    Store the value of the "experiment" option in the params for now,
    since it has helped track down bugs in this change, and may do the same
    for my next change. It costs next to nothing.

compiler/options.m:
    Add an option that controls whether we allow du_type_layout to pack
    arguments next to local secondary tags. The default value is "no",
    since "yes" may break binary compatibility.

    Add an option that controls whether we allow du_type_layout to pack
    arguments next to remote secondary tags. This option is not yet used.

compiler/hlds_data.m:
    Add a new cons_id, shared_local_tag_with_args, to represent function
    symbols in which the arguments are packed next to a local secondary tag.
    Rename the existing shared_local_tag cons_id as shared_local_tag_no_args,
    to clarify the distinction.

    Redesign the representation of secondary tags a bit, to meet the
    requirements I discovered while implementing the new data representation.

compiler/prog_data.m:
    Document the now-expanded uses of the arg_pos_width type.

compiler/ml_unify_gen.m:
compiler/unify_gen.m:
    Implement unifications involving the new cons_id.

compiler/var_locn.m:
    Implement deconstruction unifications involving both right-to-left data
    flow and the new cons_id for the LLDS backend requires var_locn.m
    to implement a new kind of assignment to a variable: one that updates
    its old value. Add a predicate for this. (Previously, deconstructions
    with right-to-left flow could update the old value of a word in a
    memory cell, whose state var_locn.m does *not* track.)

compiler/code_loc_dep.m:
    Provide the interface between unify_gen. and var_locn.m.

compiler/code_info.m:
    Store the number of primary tag bits in the code_info, to save it looking
    up in the globals structure, since with its new code, unify_gen.m needs it
    more often now.

compiler/hlds_out_module.m:
doc/user_guide.texi:
    Implement the capability of restricting the dump of the type table
    to only the types defined in the module being compiled. Without this,
    the type table is cluttered with information about types in other
    modules, including the automatically-included builtin modules.

compiler/handle_options.m:
    Add a new value of the -D option. The new value, du, asks for the
    dumping out of the representations of only the locally defined types.

compiler/ml_gen_info.m:
    Store the number of primary tag bits as a uint8, not as int.

compiler/ml_tag_switch.m:
compiler/switch_util.m:
compiler/tag_switch.m:
    Update the code that generates switches on du types to handle
    local secondary tags that must be masked off before use.

compiler/rtti.m:
    Update the compiler's representation of RTTI information to account for
    the new data representation.

compiler/type_ctor_info.m:
    Construct the updated RTTI representation.

compiler/bytecode_gen.m:
compiler/export.m:
compiler/ml_switch_gen.m:
compiler/ml_type_gen.m:
compiler/modecheck_goal.m:
compiler/rtti_out.m:
compiler/rtti_to_mlds.m:
    Conform for the changes above.

runtime/mercury_type_info.h:
    Extend the representation of du functors in the RTTI to account for
    the new data representation scheme. The extensions add only to the
    *ends* of structures, or to lists of enum values, with the extensions
    only being used if the representation is actually used, which should
    allow the updated runtime to also work with .c files that were compiled
    with a compiler that does *not* have this diff. For the same reason,
    make the old enum value MR_SECTAG_LOCAL a synonym for the new
    MR_SECTAG_LOCAL_REST_OF_WORD, which expresses a distinction that
    did not previously exist.

    Delete a reference to a file that no longer exists.

runtime/mercury_dotnet.cs.in:
library/rtti_implementation.m:
    Update the C# and Mercury mirrors of the types updated in
    mercury_type_info.h.

runtime/mercury_deconstruct.c:
runtime/mercury_deconstruct_macros.h:
runtime/mercury_ml_expand_body.h:
    Implement the deconstruction of terms using the new data representation.

runtime/mercury_deep_copy_body.h:
    Implement the copying of terms using the new data representation.

runtime/mercury_table_type_body.h:
    Implement the tabling of terms using the new data representation.

runtime/mercury_term_size.c:
    Implement computing the size of terms using the new data representation.

runtime/mercury_unify_compare_body.h:
    Implement RTTI-based unifications of terms using the new data
    representation. (Or at least make a first attempt at this implementation.
    We never use RTTI-based unification, so this code has not been tested,
    but it is not clear that it *needs* to be tested.)

library/construct.m:
    Implement the construction of terms using the new data representation.

library/private_builtin.m:
    List MR_SECTAG_LOCAL_REST_OF_WORD as a synonym of MR_SECTAG_LOCAL for Java,
    since rtti_to_mlds.m will now emit the new version.

    Note that the new data representation is not applicable to Java (or C#),
    so it should never see the other kind of sectag (MR_SECTAG_LOCAL_BITS).

tests/hard_coded/sectag_bits.{m,exp}:
tests/hard_coded/sectag_bits_test_data:
    A new test case to test the reading in and writing out (and therefore
    the construction and deconstruction) of terms containing arguments
    packed with a local sectag.

tests/hard_coded/Mmakefile:
    Enable the new test case.
2018-07-08 17:54:11 +02:00

1198 lines
44 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 1994-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: code_info.m.
% Main authors: conway, zs.
%
% This file defines the code_info type and various operations on it.
% The code_info structure is the persistent part of the 'state'
% of the code generator. The other part of the code generator state,
% the location-dependent part, is in code_loc_dep.m.
%
% This file is organized into three submodules:
%
% - the code_info structure and its access predicates
% - simple wrappers around access predicates
% - managing stack slots
%
%---------------------------------------------------------------------------%
:- module ll_backend.code_info.
:- interface.
:- import_module check_hlds.
:- import_module check_hlds.type_util.
:- import_module hlds.code_model.
:- import_module hlds.hlds_data.
:- import_module hlds.hlds_goal.
:- import_module hlds.hlds_llds.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
:- import_module hlds.vartypes.
:- import_module libs.
:- import_module libs.globals.
:- import_module ll_backend.continuation_info.
:- import_module ll_backend.global_data.
:- import_module ll_backend.layout.
:- import_module ll_backend.llds.
:- import_module ll_backend.trace_gen.
:- import_module mdbcomp.
:- import_module mdbcomp.goal_path.
:- import_module mdbcomp.prim_data.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.set_of_var.
:- import_module bool.
:- import_module counter.
:- import_module list.
:- import_module map.
:- import_module maybe.
:- import_module set.
:- import_module set_tree234.
:- import_module term.
%----------------------------------------------------------------------------%
%----------------------------------------------------------------------------%
:- implementation.
:- import_module backend_libs.
:- import_module backend_libs.proc_label.
:- import_module libs.options.
:- import_module libs.trace_params.
:- import_module ll_backend.code_util.
:- import_module parse_tree.prog_type.
:- import_module cord.
:- import_module int.
:- import_module pair.
:- import_module require.
:- import_module string.
:- import_module uint8.
:- import_module varset.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
% Submodule for the code_info type and its access predicates.
%
% This submodule has the following components:
%
% declarations for exported access predicates
% declarations for non-exported access predicates
% the definition of the type and the init predicate
% the definition of the get access predicates
% the definition of the set access predicates
%
% Please keep the order of mention of the various fields
% consistent in each of these five components.
:- interface.
:- type code_info.
% Create a new code_info structure. Also return info about the non-fixed
% stack slots used for tracing purposes.
%
:- pred code_info_init(module_info::in, pred_id::in, proc_id::in,
pred_info::in, proc_info::in, bool::in, static_cell_info::in,
const_struct_map::in, maybe(containing_goal_map)::in,
list(string)::in, int::in, trace_slot_info::out, code_info::out) is det.
:- pred get_module_info(code_info::in, module_info::out) is det.
:- pred get_globals(code_info::in, globals::out) is det.
:- pred get_exprn_opts(code_info::in, exprn_opts::out) is det.
:- pred get_pred_id(code_info::in, pred_id::out) is det.
:- pred get_proc_id(code_info::in, proc_id::out) is det.
:- pred get_pred_info(code_info::in, pred_info::out) is det.
:- pred get_proc_info(code_info::in, proc_info::out) is det.
:- pred get_proc_label(code_info::in, proc_label::out) is det.
:- pred get_varset(code_info::in, prog_varset::out) is det.
:- pred get_vartypes(code_info::in, vartypes::out) is det.
:- pred get_var_slot_count(code_info::in, int::out) is det.
:- pred get_maybe_trace_info(code_info::in, maybe(trace_info)::out) is det.
:- pred get_opt_no_return_calls(code_info::in, bool::out) is det.
:- pred get_emit_trail_ops(code_info::in, add_trail_ops::out) is det.
:- pred get_opt_trail_ops(code_info::in, bool::out) is det.
:- pred get_emit_region_ops(code_info::in, add_region_ops::out) is det.
:- pred get_opt_region_ops(code_info::in, bool::out) is det.
:- pred get_auto_comments(code_info::in, bool::out) is det.
:- pred get_lcmc_null(code_info::in, bool::out) is det.
:- pred get_profile_memory(code_info::in, bool::out) is det.
:- pred get_may_use_atomic_alloc(code_info::in,
may_use_atomic_alloc::out) is det.
:- pred get_num_ptag_bits(code_info::in, uint8::out) is det.
:- pred get_gc_method(code_info::in, gc_method::out) is det.
:- pred get_maybe_containing_goal_map(code_info::in,
maybe(containing_goal_map)::out) is det.
:- pred get_const_struct_map(code_info::in, const_struct_map::out) is det.
:- pred get_label_counter(code_info::in, counter::out) is det.
:- pred get_succip_used(code_info::in, bool::out) is det.
:- pred get_layout_info(code_info::in, proc_label_layout_info::out) is det.
:- pred get_proc_trace_events(code_info::in, bool::out) is det.
:- pred get_max_regs_in_use_at_trace(code_info::in, int::out, int::out) is det.
:- pred get_created_temp_frame(code_info::in, bool::out) is det.
:- pred get_max_temp_slot_count(code_info::in, int::out) is det.
:- pred get_temp_content_map(code_info::in, map(lval, slot_contents)::out)
is det.
:- pred get_persistent_temps(code_info::in, set(lval)::out) is det.
% get_closure_seq_counter is not exported.
:- pred get_closure_layouts(code_info::in, list(closure_proc_id_data)::out)
is det.
:- pred get_static_cell_info(code_info::in, static_cell_info::out) is det.
:- pred get_alloc_sites(code_info::in, set_tree234(alloc_site_info)::out)
is det.
:- pred get_used_env_vars(code_info::in, set(string)::out) is det.
:- pred get_out_of_line_code(code_info::in, llds_code::out) is det.
% set_maybe_trace_info is not exported.
% set_label_counter is not exported.
% set_succip_used is not exported.
% set_layout_info is not exported.
:- pred set_proc_trace_events(bool::in,
code_info::in, code_info::out) is det.
:- pred set_max_regs_in_use_at_trace(int::in, int::in,
code_info::in, code_info::out) is det.
:- pred set_max_temp_slot_count(int::in,
code_info::in, code_info::out) is det.
:- pred set_temp_content_map(map(lval, slot_contents)::in,
code_info::in, code_info::out) is det.
:- pred set_persistent_temps(set(lval)::in,
code_info::in, code_info::out) is det.
% set_closure_seq_counter is not exported.
% set_closure_layouts is not exported.
:- pred set_created_temp_frame(bool::in,
code_info::in, code_info::out) is det.
:- pred set_static_cell_info(static_cell_info::in,
code_info::in, code_info::out) is det.
:- pred set_alloc_sites(set_tree234(alloc_site_info)::in,
code_info::in, code_info::out) is det.
:- pred set_used_env_vars(set(string)::in,
code_info::in, code_info::out) is det.
%---------------------------------------------------------------------------%
:- implementation.
:- pred get_closure_seq_counter(code_info::in, counter::out) is det.
:- pred set_maybe_trace_info(maybe(trace_info)::in,
code_info::in, code_info::out) is det.
:- pred set_label_counter(counter::in,
code_info::in, code_info::out) is det.
:- pred set_succip_used(bool::in,
code_info::in, code_info::out) is det.
:- pred set_layout_info(proc_label_layout_info::in,
code_info::in, code_info::out) is det.
:- pred set_closure_layouts(list(closure_proc_id_data)::in,
code_info::in, code_info::out) is det.
:- pred set_closure_seq_counter(counter::in,
code_info::in, code_info::out) is det.
%---------------------------------------------------------------------------%
% The code_info structure has two groups of fields.
%
% Some fields are static; they are set when the code_info structure
% is initialized, and never changed afterwards.
%
% The other fields record persistent information that does not depend
% on a code location. Updates to these fields must remain effective
% even when the code generator resets its location-dependent state.
:- type code_info
---> code_info(
code_info_static :: code_info_static,
code_info_persistent :: code_info_persistent
).
:- type code_info_static
---> code_info_static(
% The module_info structure - you just never know
% when you might need it.
cis_module_info :: module_info,
% For the code generation options.
cis_globals :: globals,
cis_exprn_opts :: exprn_opts,
% The id of the current predicate.
cis_pred_id :: pred_id,
% The id of the current procedure.
cis_proc_id :: proc_id,
% The pred_info for the predicate containing this procedure.
cis_pred_info :: pred_info,
% The proc_info for this procedure.
cis_proc_info :: proc_info,
% The proc_label for this procedure.
cis_proc_label :: proc_label,
% The variables in this procedure.
cis_varset :: prog_varset,
cis_vartypes :: vartypes,
% The number of stack slots allocated. for storing variables.
% (Some extra stack slots are used for saving and restoring
% registers.)
cis_var_slot_count :: int,
% Information about which stack slots the call sequence number
% and depth are stored in, provided tracing is switched on.
cis_maybe_trace_info :: maybe(trace_info),
% Should we optimize calls that cannot return?
cis_opt_no_return_calls :: bool,
% Should we emit trail operations?
cis_emit_trail_ops :: add_trail_ops,
% Should we try to avoid generating trail operations?
cis_opt_trail_ops :: bool,
% Should we emit region operations?
cis_emit_region_ops :: add_region_ops,
% Should we try to avoid generating region operations?
cis_opt_region_ops :: bool,
% The setting of --auto-comments.
cis_auto_comments :: bool,
% The settings of --optimize-constructor-last-call-null,
% --profile-memory, and --use-atomic-cells.
cis_lcmc_null :: bool,
cis_profile_memory :: bool,
cis_may_use_atomic_alloc :: may_use_atomic_alloc,
% The number of primary tags bits we are using.
cis_num_ptag_bits :: uint8,
% The GC method.
cis_gc_method :: gc_method,
cis_containing_goal_map :: maybe(containing_goal_map),
% Maps the number of an entry in the module's const_struct_db
% to its rval.
cis_const_struct_map :: const_struct_map
).
:- type code_info_persistent
---> code_info_persistent(
% Counter for the local labels used by this procedure.
cip_label_num_src :: counter,
% Do we need to store succip?
cip_store_succip :: bool,
% Information on which values are live and where at which
% labels, for tracing and/or accurate gc.
cip_label_layout_info :: proc_label_layout_info,
% Did the procedure have any trace events?
cip_proc_trace_events :: bool,
% At each call to MR_trace, we compute the highest rN and fN
% registers that contain useful values. These slot contain the
% maximum of these highest values. Therefore at all calls to
% MR_trace in the procedure, we need only save the registers
% whose numbers are equal to or smaller than this field.
% This slot contains -1 if tracing is not enabled.
cip_max_reg_r_used :: int,
cip_max_reg_f_used :: int,
% The maximum number of extra temporary stackslots that
% have been used during the procedure.
cip_stackslot_max :: int,
% The temporary locations that have ever been used on the
% stack, and what they contain. Once we have used a stack slot
% to store e.g. a ticket, we never reuse that slot to hold
% something else, e.g. a saved hp. This policy prevents us
% from making such conflicting choices in parallel branches,
% which would make it impossible to describe to gc what the
% slot contains after the end of the branched control
% structure.
cip_temp_content_map :: map(lval, slot_contents),
% Stack slot locations that should not be released even when
% the code generator resets its location-dependent state.
cip_persistent_temps :: set(lval),
cip_closure_layout_seq :: counter,
% Closure layout structures generated by this procedure.
cip_closure_layouts :: list(closure_proc_id_data),
% True iff the procedure has created one or more temporary
% nondet frames.
cip_created_temp_frame :: bool,
cip_static_cell_info :: static_cell_info,
cip_alloc_sites :: set_tree234(alloc_site_info),
cip_used_env_vars :: set(string),
% A counter and table for allocating and maintaining slots
% where string IDs will be placed at runtime for threadscope
% profiling. The actual string IDs are allocated at runtime
% and their IDs are placed in an array slot which can be
% referred to statically.
cip_ts_string_table_size :: int,
cip_ts_rev_string_table :: list(string),
% Code that is part of this procedure, but that can be placed
% after the procedure without a cache penalty. For example,
% code that is spawned off by loop control is placed here.
cip_out_of_line_code :: llds_code
).
%---------------------------------------------------------------------------%
code_info_init(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo,
SaveSuccip, StaticCellInfo, ConstStructMap, MaybeContainingGoalMap,
TSRevStringTable, TSStringTableSize, TraceSlotInfo, CodeInfo) :-
% argument ModuleInfo
module_info_get_globals(ModuleInfo, Globals),
ExprnOpts = init_exprn_opts(Globals),
% argument PredId
% argument ProcId
% argument PredInfo
% argument ProcInfo
ProcLabel = make_proc_label(ModuleInfo, PredId, ProcId),
proc_info_get_varset(ProcInfo, VarSet),
proc_info_get_vartypes(ProcInfo, VarTypes),
proc_info_get_stack_slots(ProcInfo, StackSlots),
max_var_slot(StackSlots, VarSlotMax),
trace_reserved_slots(ModuleInfo, PredInfo, ProcInfo, Globals,
FixedSlots, _),
int.max(VarSlotMax, FixedSlots, SlotMax),
MaybeTraceInfo = no,
globals.lookup_bool_option(Globals, opt_no_return_calls,
OptNoReturnCalls),
globals.lookup_bool_option(Globals, use_trail, UseTrail),
globals.lookup_bool_option(Globals, disable_trail_ops, DisableTrailOps),
( if
UseTrail = yes,
DisableTrailOps = no
then
EmitTrailOps = add_trail_ops
else
EmitTrailOps = do_not_add_trail_ops
),
globals.lookup_bool_option(Globals, optimize_trail_usage, OptTrailOps),
globals.lookup_bool_option(Globals, region_analysis, UseRegions),
(
UseRegions = yes,
EmitRegionOps = add_region_ops
;
UseRegions = no,
EmitRegionOps = do_not_add_region_ops
),
globals.lookup_bool_option(Globals, optimize_region_ops, OptRegionOps),
globals.lookup_bool_option(Globals, auto_comments, AutoComments),
globals.lookup_bool_option(Globals, optimize_constructor_last_call_null,
LCMCNull),
globals.lookup_bool_option(Globals, profile_memory, ProfileMemory),
globals.lookup_bool_option(Globals, use_atomic_cells, UseAtomicCells),
(
UseAtomicCells = no,
InitMayUseAtomic = may_not_use_atomic_alloc
;
UseAtomicCells = yes,
InitMayUseAtomic = may_use_atomic_alloc
),
globals.lookup_int_option(Globals, num_ptag_bits, NumPtagBitsInt),
NumPtagBits = uint8.det_from_int(NumPtagBitsInt),
globals.get_gc_method(Globals, GCMethod),
% argument MaybeContainingGoalMap
% argument ConstStructMap
CodeInfoStatic0 = code_info_static(
ModuleInfo,
Globals,
ExprnOpts,
PredId,
ProcId,
PredInfo,
ProcInfo,
ProcLabel,
VarSet,
VarTypes,
SlotMax,
MaybeTraceInfo,
OptNoReturnCalls,
EmitTrailOps,
OptTrailOps,
EmitRegionOps,
OptRegionOps,
AutoComments,
LCMCNull,
ProfileMemory,
InitMayUseAtomic,
NumPtagBits,
GCMethod,
MaybeContainingGoalMap,
ConstStructMap
),
LabelNumCounter0 = counter.init(1),
% argument SaveSuccip
globals.get_trace_level(Globals, TraceLevel),
map.init(LayoutMap),
ProcTraceEvents = no,
MaxRegRUsed = -1,
MaxRegFUsed = -1,
MaxTempSlotCount = 0,
map.init(TempContentMap),
set.init(PersistentTemps),
ClosureLayoutSeqNumCounter0 = counter.init(1),
ClosureLayouts = [],
CreatedTempFrame = no,
% argument StaticCellInfo
AllocSitesMap0 = set_tree234.init,
set.init(UsedEnvVars),
OutOfLineCode = cord.init,
CodeInfoPersistent0 = code_info_persistent(
LabelNumCounter0,
SaveSuccip,
LayoutMap,
ProcTraceEvents,
MaxRegRUsed,
MaxRegFUsed,
MaxTempSlotCount,
TempContentMap,
PersistentTemps,
ClosureLayoutSeqNumCounter0,
ClosureLayouts,
CreatedTempFrame,
StaticCellInfo,
AllocSitesMap0,
UsedEnvVars,
TSStringTableSize,
TSRevStringTable,
OutOfLineCode
),
CodeInfo0 = code_info(CodeInfoStatic0, CodeInfoPersistent0),
init_maybe_trace_info(TraceLevel, Globals, ModuleInfo,
PredInfo, ProcInfo, TraceSlotInfo, CodeInfo0, CodeInfo).
:- func init_exprn_opts(globals) = exprn_opts.
init_exprn_opts(Globals) = ExprnOpts :-
globals.lookup_bool_option(Globals, gcc_non_local_gotos, OptNLG),
(
OptNLG = yes,
NLG = have_non_local_gotos
;
OptNLG = no,
NLG = do_not_have_non_local_gotos
),
globals.lookup_bool_option(Globals, asm_labels, OptASM),
(
OptASM = yes,
ASM = have_asm_labels
;
OptASM = no,
ASM = do_not_have_asm_labels
),
globals.lookup_bool_option(Globals, static_ground_cells, OptSGCell),
(
OptSGCell = yes,
SGCell = have_static_ground_cells
;
OptSGCell = no,
SGCell = do_not_have_static_ground_cells
),
globals.lookup_bool_option(Globals, unboxed_float, OptUBF),
(
OptUBF = yes,
UBF = have_unboxed_floats
;
OptUBF = no,
UBF = do_not_have_unboxed_floats
),
globals.lookup_bool_option(Globals, use_float_registers, OptFloatRegs),
(
OptFloatRegs = yes,
UseFloatRegs = use_float_registers
;
OptFloatRegs = no,
UseFloatRegs = do_not_use_float_registers
),
double_width_floats_on_det_stack(Globals, FloatDwords),
(
FloatDwords = yes,
DetStackFloatWidth = double_width
;
FloatDwords = no,
DetStackFloatWidth = single_width
),
globals.lookup_bool_option(Globals, unboxed_int64s, OptUBI64s),
(
OptUBI64s = yes,
UBI64s = have_unboxed_int64s
;
OptUBI64s = no,
UBI64s = do_not_have_unboxed_int64s
),
globals.lookup_bool_option(Globals, static_ground_floats, OptSGFloat),
(
OptSGFloat = yes,
SGFloat = have_static_ground_floats
;
OptSGFloat = no,
SGFloat = do_not_have_static_ground_floats
),
globals.lookup_bool_option(Globals, static_ground_int64s, OptSGInt64s),
(
OptSGInt64s = yes,
SGInt64s = have_static_ground_int64s
;
OptSGInt64s = no,
SGInt64s = do_not_have_static_ground_int64s
),
globals.lookup_bool_option(Globals, static_code_addresses,
OptStaticCodeAddr),
(
OptStaticCodeAddr = yes,
StaticCodeAddrs = have_static_code_addresses
;
OptStaticCodeAddr = no,
StaticCodeAddrs = do_not_have_static_code_addresses
),
ExprnOpts = exprn_opts(NLG, ASM, UBF, UseFloatRegs, DetStackFloatWidth,
UBI64s, SGCell, SGFloat, SGInt64s, StaticCodeAddrs).
:- pred max_var_slot(stack_slots::in, int::out) is det.
max_var_slot(StackSlots, SlotCount) :-
map.values(StackSlots, StackSlotList),
max_var_slot_2(StackSlotList, 0, SlotCount).
:- pred max_var_slot_2(list(stack_slot)::in, int::in, int::out) is det.
max_var_slot_2([], !Max).
max_var_slot_2([Slot | Slots], !Max) :-
(
Slot = det_slot(N, Width)
;
Slot = parent_det_slot(N, Width)
;
Slot = nondet_slot(N),
Width = single_width
),
(
Width = single_width,
int.max(N, !Max)
;
Width = double_width,
int.max(N + 1, !Max)
),
max_var_slot_2(Slots, !Max).
:- pred init_maybe_trace_info(trace_level::in, globals::in,
module_info::in, pred_info::in, proc_info::in, trace_slot_info::out,
code_info::in, code_info::out) is det.
init_maybe_trace_info(TraceLevel, Globals, ModuleInfo, PredInfo,
ProcInfo, TraceSlotInfo, !CI) :-
TraceLevelIsNone =
eff_trace_level_is_none(ModuleInfo, PredInfo, ProcInfo, TraceLevel),
(
TraceLevelIsNone = no,
proc_info_get_has_tail_rec_call(ProcInfo, HasTailRecCall),
HasTailRecCall =
has_tail_rec_call(HasSelfTailRecCall, _HasMutualTailRecCall),
(
HasSelfTailRecCall = has_self_tail_rec_call,
get_next_label(TailRecLabel, !CI),
MaybeTailRecLabel = yes(TailRecLabel)
;
HasSelfTailRecCall = has_no_self_tail_rec_call,
MaybeTailRecLabel = no
),
trace_setup(ModuleInfo, PredInfo, ProcInfo, Globals, MaybeTailRecLabel,
TraceSlotInfo, TraceInfo, !CI),
set_maybe_trace_info(yes(TraceInfo), !CI)
;
TraceLevelIsNone = yes,
TraceSlotInfo = trace_slot_info(no, no, no, no, no, no)
).
%---------------------------------------------------------------------------%
get_module_info(CI, X) :-
X = CI ^ code_info_static ^ cis_module_info.
get_globals(CI, X) :-
X = CI ^ code_info_static ^ cis_globals.
get_exprn_opts(CI, X) :-
X = CI ^ code_info_static ^ cis_exprn_opts.
get_pred_id(CI, X) :-
X = CI ^ code_info_static ^ cis_pred_id.
get_proc_id(CI, X) :-
X = CI ^ code_info_static ^ cis_proc_id.
get_pred_info(CI, X) :-
X = CI ^ code_info_static ^ cis_pred_info.
get_proc_info(CI, X) :-
X = CI ^ code_info_static ^ cis_proc_info.
get_proc_label(CI, X) :-
X = CI ^ code_info_static ^ cis_proc_label.
get_varset(CI, X) :-
X = CI ^ code_info_static ^ cis_varset.
get_vartypes(CI, X) :-
X = CI ^ code_info_static ^ cis_vartypes.
get_var_slot_count(CI, X) :-
X = CI ^ code_info_static ^ cis_var_slot_count.
get_maybe_trace_info(CI, X) :-
X = CI ^ code_info_static ^ cis_maybe_trace_info.
get_opt_no_return_calls(CI, X) :-
X = CI ^ code_info_static ^ cis_opt_no_return_calls.
get_emit_trail_ops(CI, X) :-
X = CI ^ code_info_static ^ cis_emit_trail_ops.
get_opt_trail_ops(CI, X) :-
X = CI ^ code_info_static ^ cis_opt_trail_ops.
get_emit_region_ops(CI, X) :-
X = CI ^ code_info_static ^ cis_emit_region_ops.
get_opt_region_ops(CI, X) :-
X = CI ^ code_info_static ^ cis_opt_region_ops.
get_auto_comments(CI, X) :-
X = CI ^ code_info_static ^ cis_auto_comments.
get_lcmc_null(CI, X) :-
X = CI ^ code_info_static ^ cis_lcmc_null.
get_profile_memory(CI, X) :-
X = CI ^ code_info_static ^ cis_profile_memory.
get_may_use_atomic_alloc(CI, X) :-
X = CI ^ code_info_static ^ cis_may_use_atomic_alloc.
get_num_ptag_bits(CI, X) :-
X = CI ^ code_info_static ^ cis_num_ptag_bits.
get_gc_method(CI, X) :-
X = CI ^ code_info_static ^ cis_gc_method.
get_maybe_containing_goal_map(CI, X) :-
X = CI ^ code_info_static ^ cis_containing_goal_map.
get_const_struct_map(CI, X) :-
X = CI ^ code_info_static ^ cis_const_struct_map.
get_label_counter(CI, X) :-
X = CI ^ code_info_persistent ^ cip_label_num_src.
get_succip_used(CI, X) :-
X = CI ^ code_info_persistent ^ cip_store_succip.
get_layout_info(CI, X) :-
X = CI ^ code_info_persistent ^ cip_label_layout_info.
get_proc_trace_events(CI, X) :-
X = CI ^ code_info_persistent ^ cip_proc_trace_events.
get_max_regs_in_use_at_trace(CI, MaxRegR, MaxRegF) :-
MaxRegR = CI ^ code_info_persistent ^ cip_max_reg_r_used,
MaxRegF = CI ^ code_info_persistent ^ cip_max_reg_f_used.
get_created_temp_frame(CI, X) :-
X = CI ^ code_info_persistent ^ cip_created_temp_frame.
get_max_temp_slot_count(CI, X) :-
X = CI ^ code_info_persistent ^ cip_stackslot_max.
get_temp_content_map(CI, X) :-
X = CI ^ code_info_persistent ^ cip_temp_content_map.
get_persistent_temps(CI, X) :-
X = CI ^ code_info_persistent ^ cip_persistent_temps.
get_closure_seq_counter(CI, X) :-
X = CI ^ code_info_persistent ^ cip_closure_layout_seq.
get_closure_layouts(CI, X) :-
X = CI ^ code_info_persistent ^ cip_closure_layouts.
get_static_cell_info(CI, X) :-
X = CI ^ code_info_persistent ^ cip_static_cell_info.
get_alloc_sites(CI, X) :-
X = CI ^ code_info_persistent ^ cip_alloc_sites.
get_used_env_vars(CI, X) :-
X = CI ^ code_info_persistent ^ cip_used_env_vars.
get_out_of_line_code(CI, X) :-
X = CI ^ code_info_persistent ^ cip_out_of_line_code.
set_maybe_trace_info(X, !CI) :-
!CI ^ code_info_static ^ cis_maybe_trace_info := X.
set_label_counter(X, !CI) :-
!CI ^ code_info_persistent ^ cip_label_num_src := X.
set_succip_used(X, !CI) :-
!CI ^ code_info_persistent ^ cip_store_succip := X.
set_layout_info(X, !CI) :-
!CI ^ code_info_persistent ^ cip_label_layout_info := X.
set_proc_trace_events(X, !CI) :-
!CI ^ code_info_persistent ^ cip_proc_trace_events := X.
set_max_regs_in_use_at_trace(MR, MF, !CI) :-
!CI ^ code_info_persistent ^ cip_max_reg_r_used := MR,
!CI ^ code_info_persistent ^ cip_max_reg_f_used := MF.
set_max_temp_slot_count(X, !CI) :-
!CI ^ code_info_persistent ^ cip_stackslot_max := X.
set_temp_content_map(X, !CI) :-
!CI ^ code_info_persistent ^ cip_temp_content_map := X.
set_persistent_temps(X, !CI) :-
!CI ^ code_info_persistent ^ cip_persistent_temps := X.
set_closure_seq_counter(X, !CI) :-
!CI ^ code_info_persistent ^ cip_closure_layout_seq := X.
set_closure_layouts(X, !CI) :-
!CI ^ code_info_persistent ^ cip_closure_layouts := X.
set_created_temp_frame(X, !CI) :-
!CI ^ code_info_persistent ^ cip_created_temp_frame := X.
set_static_cell_info(X, !CI) :-
!CI ^ code_info_persistent ^ cip_static_cell_info := X.
set_alloc_sites(X, !CI) :-
!CI ^ code_info_persistent ^ cip_alloc_sites := X.
set_used_env_vars(X, !CI) :-
!CI ^ code_info_persistent ^ cip_used_env_vars := X.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
% Submodule for simple wrappers around access predicates.
:- interface.
% Get the hlds mapping from variables to stack slots.
%
:- pred get_stack_slots(code_info::in, stack_slots::out) is det.
% Find out whether the body of the current procedure should use
% typeinfo liveness.
%
:- func body_typeinfo_liveness(code_info) = bool.
% Find out the type of the given variable.
%
:- func variable_type(code_info, prog_var) = mer_type.
:- func variable_is_of_dummy_type(code_info, prog_var) = is_dummy_type.
% Compute the principal type constructor of the given type, and return
% the definition of this type constructor, if it has one (some type
% constructors are built in, and some are hidden behind abstraction
% barriers).
%
:- pred search_type_defn(code_info::in, mer_type::in, hlds_type_defn::out) is
semidet.
% Compute the principal type constructor of the given type, and return
% the definition of this type constructor. Abort if it doesn't have a
% definition (e.g. because it is a builtin).
%
:- func lookup_type_defn(code_info, mer_type) = hlds_type_defn.
:- func lookup_cheaper_tag_test(code_info, mer_type) = maybe_cheaper_tag_test.
:- func filter_region_vars(code_info, set_of_progvar) = set_of_progvar.
% Get the code model of the current procedure.
%
:- func get_proc_model(code_info) = code_model.
% Get the list of the head variables of the current procedure.
%
:- func get_headvars(code_info) = list(prog_var).
% Get the call argument information for the current procedure
%
:- func get_arginfo(code_info) = list(arg_info).
% Get the call argument info for a given mode of a given predicate
%
:- func get_pred_proc_arginfo(code_info, pred_id, proc_id) = list(arg_info).
:- func variable_name(code_info, prog_var) = string.
% Create a code address which holds the address of the specified procedure.
% The fourth argument should be `no' if the caller wants the
% returned address to be valid from everywhere in the program.
% If being valid from within the current procedure is enough,
% this argument should be `yes' wrapped around the value of the
% --procs-per-c-function option and the current procedure id.
% Using an address that is only valid from within the current
% procedure may make jumps more efficient.
%
% If the procs_per_c_function option tells us to put more than one
% procedure into each C function, but not all procedures in the module
% are in one function, then we would like to be able to use the
% fast form of reference to a procedure for references not only from
% within the same procedure but also from other procedures within
% the same C function. However, at the time of code generation,
% we do not yet know which procedures will be put into the same
% C functions, and so we cannot do this.
%
:- func make_proc_entry_label(code_info, module_info, pred_id, proc_id, bool)
= code_addr.
% Generate the next local label in sequence.
%
:- pred get_next_label(label::out, code_info::in, code_info::out)
is det.
% Note that the succip slot is used, and thus cannot be optimized away.
%
:- pred succip_is_used(code_info::in, code_info::out) is det.
:- pred add_trace_layout_for_label(label::in, term.context::in, trace_port::in,
bool::in, forward_goal_path::in, maybe(user_event_info)::in,
layout_label_info::in, code_info::in, code_info::out) is det.
:- pred get_next_closure_seq_no(int::out,
code_info::in, code_info::out) is det.
:- pred add_resume_layout_for_label(label::in,
layout_label_info::in, code_info::in, code_info::out) is det.
:- pred add_closure_layout(closure_proc_id_data::in,
code_info::in, code_info::out) is det.
:- pred add_threadscope_string(string::in, int::out,
code_info::in, code_info::out) is det.
:- pred get_threadscope_rev_string_table(code_info::in,
list(string)::out, int::out) is det.
:- pred add_scalar_static_cell(list(typed_rval)::in,
data_id::out, code_info::in, code_info::out) is det.
:- pred add_scalar_static_cell_natural_types(list(rval)::in,
data_id::out, code_info::in, code_info::out) is det.
:- pred add_vector_static_cell(list(llds_type)::in, list(list(rval))::in,
data_id::out, code_info::in, code_info::out) is det.
:- pred maybe_add_alloc_site_info(prog_context::in, string::in, int::in,
maybe(alloc_site_id)::out, code_info::in, code_info::out) is det.
:- pred add_alloc_site_info(prog_context::in, string::in, int::in,
alloc_site_id::out, code_info::in, code_info::out) is det.
% Should we add trail ops to the code we generate for the goal with the
% given goal_info. This will be 'no' unless we are in a trailing grade.
%
:- func should_add_trail_ops(code_info, hlds_goal_info) = add_trail_ops.
% Should we add region ops to the code we generate for the goal with the
% given goal_info. This will be 'no' unless we are in a rbmm grade.
%
:- func should_add_region_ops(code_info, hlds_goal_info) = add_region_ops.
:- pred get_containing_goal_map(code_info::in, containing_goal_map::out)
is det.
:- pred add_out_of_line_code(llds_code::in, code_info::in, code_info::out)
is det.
%---------------------------------------------------------------------------%
:- implementation.
get_stack_slots(CI, StackSlots) :-
get_proc_info(CI, ProcInfo),
proc_info_get_stack_slots(ProcInfo, StackSlots).
body_typeinfo_liveness(CI) = TypeInfoLiveness :-
get_module_info(CI, ModuleInfo),
get_pred_id(CI, PredId),
module_info_pred_info(ModuleInfo, PredId, PredInfo),
get_globals(CI, Globals),
body_should_use_typeinfo_liveness(PredInfo, Globals, TypeInfoLiveness).
variable_type(CI, Var) = Type :-
get_vartypes(CI, VarTypes),
lookup_var_type(VarTypes, Var, Type).
variable_is_of_dummy_type(CI, Var) = IsDummy :-
VarType = variable_type(CI, Var),
get_module_info(CI, ModuleInfo),
IsDummy = is_type_a_dummy(ModuleInfo, VarType).
search_type_defn(CI, Type, TypeDefn) :-
get_module_info(CI, ModuleInfo),
type_to_ctor_det(Type, TypeCtor),
module_info_get_type_table(ModuleInfo, TypeTable),
search_type_ctor_defn(TypeTable, TypeCtor, TypeDefn).
lookup_type_defn(CI, Type) = TypeDefn :-
( if search_type_defn(CI, Type, TypeDefnPrime) then
TypeDefn = TypeDefnPrime
else
unexpected($pred, "type ctor has no definition")
).
lookup_cheaper_tag_test(CI, Type) = CheaperTagTest :-
( if
search_type_defn(CI, Type, TypeDefn),
get_type_defn_body(TypeDefn, TypeBody),
TypeBody = hlds_du_type(_, _, MaybeRepn, _),
MaybeRepn = yes(Repn)
then
CheaperTagTest = Repn ^ dur_cheaper_tag_test
else
CheaperTagTest = no_cheaper_tag_test
).
filter_region_vars(CI, ForwardLiveVarsBeforeGoal) = RegionVars :-
get_vartypes(CI, VarTypes),
RegionVars = set_of_var.filter(is_region_var(VarTypes),
ForwardLiveVarsBeforeGoal).
%---------------------------------------------------------------------------%
get_proc_model(CI) = CodeModel :-
get_proc_info(CI, ProcInfo),
CodeModel = proc_info_interface_code_model(ProcInfo).
get_headvars(CI) = HeadVars :-
get_module_info(CI, ModuleInfo),
get_pred_id(CI, PredId),
get_proc_id(CI, ProcId),
module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo),
proc_info_get_headvars(ProcInfo, HeadVars).
get_arginfo(CI) = ArgInfo :-
get_pred_id(CI, PredId),
get_proc_id(CI, ProcId),
ArgInfo = get_pred_proc_arginfo(CI, PredId, ProcId).
get_pred_proc_arginfo(CI, PredId, ProcId) = ArgInfo :-
get_module_info(CI, ModuleInfo),
module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo),
proc_info_arg_info(ProcInfo, ArgInfo).
variable_name(CI, Var) = Name :-
get_varset(CI, Varset),
varset.lookup_name(Varset, Var, Name).
%---------------------------------------------------------------------------%
make_proc_entry_label(CI, ModuleInfo, PredId, ProcId, Immed0) = CodeAddr :-
(
Immed0 = no,
Immed = no
;
Immed0 = yes,
get_globals(CI, Globals),
globals.lookup_int_option(Globals, procs_per_c_function, ProcsPerFunc),
get_pred_id(CI, CurPredId),
get_proc_id(CI, CurProcId),
Immed = yes(ProcsPerFunc - proc(CurPredId, CurProcId))
),
CodeAddr = make_entry_label(ModuleInfo, PredId, ProcId, Immed).
get_next_label(Label, !CI) :-
get_proc_label(!.CI, ProcLabel),
get_label_counter(!.CI, C0),
counter.allocate(N, C0, C),
set_label_counter(C, !CI),
Label = internal_label(N, ProcLabel).
succip_is_used(!CI) :-
set_succip_used(yes, !CI).
add_trace_layout_for_label(Label, Context, Port, IsHidden, GoalPath,
MaybeSolverEventInfo, Layout, !CI) :-
get_layout_info(!.CI, Internals0),
Exec = yes(trace_port_layout_info(Context, Port, IsHidden, GoalPath,
MaybeSolverEventInfo, Layout)),
(
Label = internal_label(LabelNum, _)
;
Label = entry_label(_, _),
unexpected($pred, "entry")
),
( if map.search(Internals0, LabelNum, Internal0) then
Internal0 = internal_layout_info(Exec0, Resume, Return),
(
Exec0 = no
;
Exec0 = yes(_),
unexpected($pred, "already known label")
),
Internal = internal_layout_info(Exec, Resume, Return),
map.det_update(LabelNum, Internal, Internals0, Internals)
else
Internal = internal_layout_info(Exec, no, no),
map.det_insert(LabelNum, Internal, Internals0, Internals)
),
set_layout_info(Internals, !CI).
add_resume_layout_for_label(Label, LayoutInfo, !CI) :-
get_layout_info(!.CI, Internals0),
Resume = yes(LayoutInfo),
(
Label = internal_label(LabelNum, _)
;
Label = entry_label(_, _),
unexpected($pred, "entry")
),
( if map.search(Internals0, LabelNum, Internal0) then
Internal0 = internal_layout_info(Exec, Resume0, Return),
(
Resume0 = no
;
Resume0 = yes(_),
unexpected($pred, "already known label")
),
Internal = internal_layout_info(Exec, Resume, Return),
map.det_update(LabelNum, Internal, Internals0, Internals)
else
Internal = internal_layout_info(no, Resume, no),
map.det_insert(LabelNum, Internal, Internals0, Internals)
),
set_layout_info(Internals, !CI).
get_next_closure_seq_no(SeqNo, !CI) :-
get_closure_seq_counter(!.CI, C0),
counter.allocate(SeqNo, C0, C),
set_closure_seq_counter(C, !CI).
add_closure_layout(ClosureLayout, !CI) :-
get_closure_layouts(!.CI, ClosureLayouts),
set_closure_layouts([ClosureLayout | ClosureLayouts], !CI).
add_threadscope_string(String, SlotNum, !CI) :-
Persistent0 = !.CI ^ code_info_persistent,
Size0 = Persistent0 ^ cip_ts_string_table_size,
RevTable0 = Persistent0 ^ cip_ts_rev_string_table,
SlotNum = Size0,
Size = Size0 + 1,
RevTable = [String | RevTable0],
Persistent1 = Persistent0 ^ cip_ts_string_table_size := Size,
Persistent = Persistent1 ^ cip_ts_rev_string_table := RevTable,
!CI ^ code_info_persistent := Persistent.
get_threadscope_rev_string_table(CI, RevTable, TableSize) :-
RevTable = CI ^ code_info_persistent ^ cip_ts_rev_string_table,
TableSize = CI ^ code_info_persistent ^ cip_ts_string_table_size.
add_scalar_static_cell(RvalsTypes, DataAddr, !CI) :-
get_static_cell_info(!.CI, StaticCellInfo0),
global_data.add_scalar_static_cell(RvalsTypes, DataAddr,
StaticCellInfo0, StaticCellInfo),
set_static_cell_info(StaticCellInfo, !CI).
add_scalar_static_cell_natural_types(Rvals, DataAddr, !CI) :-
get_static_cell_info(!.CI, StaticCellInfo0),
global_data.add_scalar_static_cell_natural_types(Rvals, DataAddr,
StaticCellInfo0, StaticCellInfo),
set_static_cell_info(StaticCellInfo, !CI).
add_vector_static_cell(Types, Vector, DataAddr, !CI) :-
get_static_cell_info(!.CI, StaticCellInfo0),
global_data.add_vector_static_cell(Types, Vector, DataAddr,
StaticCellInfo0, StaticCellInfo),
set_static_cell_info(StaticCellInfo, !CI).
maybe_add_alloc_site_info(Context, VarTypeMsg, Size, MaybeAllocId, !CI) :-
get_profile_memory(!.CI, ProfileMemory),
(
ProfileMemory = yes,
add_alloc_site_info(Context, VarTypeMsg, Size, AllocId, !CI),
MaybeAllocId = yes(AllocId)
;
ProfileMemory = no,
MaybeAllocId = no
).
add_alloc_site_info(Context, VarTypeMsg, Size, AllocId, !CI) :-
get_proc_label(!.CI, ProcLabel),
AllocSite = alloc_site_info(ProcLabel, Context, VarTypeMsg, Size),
AllocId = alloc_site_id(AllocSite),
get_alloc_sites(!.CI, AllocSites0),
set_tree234.insert(AllocSite, AllocSites0, AllocSites),
set_alloc_sites(AllocSites, !CI).
%---------------------------------------------------------------------------%
should_add_trail_ops(CodeInfo, _GoalInfo) = AddTrailOps :-
% XXX We will eventually need to make use of GoalInfo here.
get_emit_trail_ops(CodeInfo, AddTrailOps).
should_add_region_ops(CodeInfo, _GoalInfo) = AddRegionOps :-
% XXX We will eventually need to make use of GoalInfo here.
get_emit_region_ops(CodeInfo, AddRegionOps).
%---------------------------------------------------------------------------%
get_containing_goal_map(CI, ContainingGoalMap) :-
get_maybe_containing_goal_map(CI, MaybeContainingGoalMap),
(
MaybeContainingGoalMap = yes(ContainingGoalMap)
;
MaybeContainingGoalMap = no,
unexpected($pred, "no map")
).
add_out_of_line_code(NewCode, !CI) :-
Code0 = !.CI ^ code_info_persistent ^ cip_out_of_line_code,
Code = Code0 ++ NewCode,
!CI ^ code_info_persistent ^ cip_out_of_line_code := Code.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
% Submodule for managing stack slots.
:- interface.
% Return the lval of the stack slot in which the given variable is stored.
% Aborts if the variable does not have a stack slot an assigned to it.
%
:- pred get_variable_slot(code_info::in, prog_var::in, lval::out) is det.
% Returns the total stackslot count, but not including space for
% succip, and without padding for alignment. This total can change in the
% future if this call is followed by further allocations of temp slots.
%
:- pred get_total_stackslot_count(code_info::in, int::out) is det.
% If necessary, round up a det stack frame allocation so that the stack
% pointer remains on an even word boundary.
%
:- func round_det_stack_frame_size(code_info, int) = int.
%---------------------------------------------------------------------------%
:- implementation.
get_variable_slot(CI, Var, Slot) :-
get_stack_slots(CI, StackSlots),
( if map.search(StackSlots, Var, SlotLocn) then
Slot = stack_slot_to_lval(SlotLocn)
else
Name = variable_name(CI, Var),
term.var_to_int(Var, Num),
string.int_to_string(Num, NumStr),
Str = "variable `" ++ Name ++ "' " ++ "(" ++ NumStr ++ ") not found",
unexpected($pred, Str)
).
get_total_stackslot_count(CI, NumSlots) :-
get_var_slot_count(CI, SlotsForVars),
get_max_temp_slot_count(CI, SlotsForTemps),
NumSlots = SlotsForVars + SlotsForTemps.
round_det_stack_frame_size(CI, NumSlots) = NumSlotsRoundup :-
( if
odd(NumSlots),
get_exprn_opts(CI, ExprnOpts),
get_det_stack_float_width(ExprnOpts) = double_width
then
NumSlotsRoundup = NumSlots + 1
else
NumSlotsRoundup = NumSlots
).
%---------------------------------------------------------------------------%
:- end_module ll_backend.code_info.
%---------------------------------------------------------------------------%