mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 17:33:38 +00:00
The code that checks whether a bound inst wrapped around
a list of bound_functors matched the ground inst did several things
in a suboptimal fashion.
- It looked up the definition of the type constructor of the relevant type
(the type of the variable the inst is for) more than once. (This was
not easily visible because the lookups were in different predicates.)
This diff factors these out, not for the immesurably small speedup,
but to make possible the fixes for the next two issues.
- To simplify the "is there a bound_functor for each constructor in the type"
check, it sorted the constructors of the type by name and arity. (Lists of
bound_functors are always sorted by name and arity.) Given that most
modules contain more than one bound inst for any given type constructor,
any sorting after the first was unnecessarily repeated work. This diff
therefore extends the representation of du types, which until now has
include only a list of the data constructors in the type definition
in definition order, with a list of those exact same data constructors
in name/arity order.
- Even if a list of bound_functors lists all the constructors of a type,
the bound inst containing them is not equivalent to ground if the inst
of some argument of some bound_inst is not equivalent to ground.
This means that we need to know the actual argument of each constructor.
The du type definition lists argument types that refer to the type
constructor's type parameters; we need the instances of these argument types
that apply to type of the variable at hand, which usually binds concrete
types to those type parameters.
We used to apply the type-parameter-to-actual-type substitution to
each argument of each data constructor in the type before we compared
the resulting filled-in data constructor descriptions against the list of
bound_functors. However, in cases where the comparison fails, the
substitution applications to arguments beyond the point of failure
are all wasted work. This diff therefore applies the substitution
only when its result is about to be needed.
This diff leads to a speedup of about 3.5% on tools/speedtest,
and about 38% (yes, more than a third) when compiling options.m.
compiler/hlds_data.m:
Add the new field to the representation of du types.
Add a utility predicate that helps construct that field, since it is
now needed by two modules (add_type.m and equiv_type_hlds.m).
Delete two functions that were used only by det_check_switch.m,
which this diff moves to that module (in modified form).
compiler/inst_match.m:
Implement the first and third changes listed above, and take advantage
of the second.
The old call to all_du_ctor_arg_types, which this diff replaces,
effectively lied about the list of constructors it returned,
by simply not returning any constructors containing existentially
quantified types, on the grounds that they "were not handled yet".
We now fail explicitly when we find any such constructors.
Perform the check for one-to-one match between bound_functors and
constructors with less argument passing.
compiler/det_check_switch.m:
Move the code deleted from hlds_data.m here, and simplify it,
taking advantage of the new field in du types.
compiler/Mercury.options:
Specify --optimize-constructor-last-call for det_check_switch.m
to optimize the updated moved code.
compiler/add_foreign_enum.m:
compiler/add_special_pred.m:
compiler/add_type.m:
compiler/check_typeclass.m:
compiler/code_info.m:
compiler/dead_proc_elim.m:
compiler/direct_arg_in_out.m:
compiler/du_type_layout.m:
compiler/equiv_type_hlds.m:
compiler/hlds_out_type_table.m:
compiler/inst_check.m:
compiler/intermod.m:
compiler/intermod_decide.m:
compiler/lookup_switch_util.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen_test.m:
compiler/ml_unify_gen_util.m:
compiler/mlds.m:
compiler/post_term_analysis.m:
compiler/recompilation.usage.m:
compiler/resolve_unify_functor.m:
compiler/simplify_goal_ite.m:
compiler/table_gen.m:
compiler/tag_switch_util.m:
compiler/term_norm.m:
compiler/type_ctor_info.m:
compiler/type_util.m:
compiler/typecheck_coerce.m:
compiler/unify_proc.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
Conform to the changes above. This mostly means handling
the new field in du types (usually by ignoring it).
1211 lines
44 KiB
Mathematica
1211 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 hlds.
|
|
:- 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 libs.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.optimization_options.
|
|
:- import_module libs.trace_params.
|
|
:- 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 parse_tree.var_table.
|
|
|
|
:- import_module bool.
|
|
:- import_module counter.
|
|
:- import_module io.
|
|
:- 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 hlds.hlds_proc_util.
|
|
:- import_module hlds.type_util.
|
|
:- import_module libs.options.
|
|
:- 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.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% 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, var_table::in, bool::in,
|
|
static_cell_info::in, const_struct_map::in, io.text_output_stream::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_eff_trace_level(code_info::in, eff_trace_level::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_var_table(code_info::in, var_table::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, maybe_opt_lcmc_null::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.
|
|
% get_progress_stream is not exported.
|
|
|
|
:- 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.
|
|
|
|
:- func init_exprn_opts(globals) = exprn_opts.
|
|
|
|
:- pred init_maybe_trace_info(globals::in, proc_info::in, eff_trace_level::in,
|
|
trace_slot_info::out, code_info::in, code_info::out) is det.
|
|
|
|
:- pred get_progress_stream(code_info::in, io.text_output_stream::out) is det.
|
|
:- 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_seq_counter(counter::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.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% 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,
|
|
|
|
cis_eff_trace_level :: eff_trace_level,
|
|
|
|
% 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_var_table :: var_table,
|
|
|
|
% 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 :: maybe_opt_lcmc_null,
|
|
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,
|
|
|
|
% The stream to write any debugging output to.
|
|
cis_progress_stream :: io.text_output_stream
|
|
).
|
|
|
|
:- 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, VarTable,
|
|
SaveSuccip, StaticCellInfo, ConstStructMap, ProgressStream,
|
|
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_stack_slots(ProcInfo, StackSlots),
|
|
max_var_slot(StackSlots, VarSlotMax),
|
|
globals.get_trace_level(Globals, TraceLevel),
|
|
EffTraceLevel =
|
|
eff_trace_level_for_proc(ModuleInfo, PredInfo, ProcInfo, TraceLevel),
|
|
trace_reserved_slots(Globals, ProcInfo, EffTraceLevel, 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.get_opt_tuple(Globals, OptTuple),
|
|
UseRegions = OptTuple ^ ot_analyse_regions,
|
|
(
|
|
UseRegions = analyse_regions,
|
|
EmitRegionOps = add_region_ops
|
|
;
|
|
UseRegions = do_not_analyse_regions,
|
|
EmitRegionOps = do_not_add_region_ops
|
|
),
|
|
globals.lookup_bool_option(Globals, optimize_region_ops, OptRegionOps),
|
|
globals.lookup_bool_option(Globals, auto_comments, AutoComments),
|
|
LCMCNull = OptTuple ^ ot_opt_lcmc_null,
|
|
globals.lookup_bool_option(Globals, profile_memory, ProfileMemory),
|
|
UseAtomicCells = OptTuple ^ ot_use_atomic_cells,
|
|
(
|
|
UseAtomicCells = do_not_use_atomic_cells,
|
|
InitMayUseAtomic = may_not_use_atomic_alloc
|
|
;
|
|
UseAtomicCells = use_atomic_cells,
|
|
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,
|
|
EffTraceLevel,
|
|
PredId,
|
|
ProcId,
|
|
PredInfo,
|
|
ProcInfo,
|
|
ProcLabel,
|
|
VarTable,
|
|
SlotMax,
|
|
MaybeTraceInfo,
|
|
OptNoReturnCalls,
|
|
EmitTrailOps,
|
|
OptTrailOps,
|
|
EmitRegionOps,
|
|
OptRegionOps,
|
|
AutoComments,
|
|
LCMCNull,
|
|
ProfileMemory,
|
|
InitMayUseAtomic,
|
|
NumPtagBits,
|
|
GCMethod,
|
|
MaybeContainingGoalMap,
|
|
ConstStructMap,
|
|
ProgressStream
|
|
),
|
|
|
|
LabelNumCounter0 = counter.init(1),
|
|
% argument SaveSuccip
|
|
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(Globals, ProcInfo, EffTraceLevel, TraceSlotInfo,
|
|
CodeInfo0, CodeInfo).
|
|
|
|
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.get_opt_tuple(Globals, OptTuple),
|
|
OptSGCell = OptTuple ^ ot_use_static_ground_cells,
|
|
(
|
|
OptSGCell = use_static_ground_cells,
|
|
SGCell = have_static_ground_cells
|
|
;
|
|
OptSGCell = do_not_use_static_ground_cells,
|
|
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
|
|
),
|
|
OptSGFloat = OptTuple ^ ot_use_static_ground_floats,
|
|
(
|
|
OptSGFloat = use_static_ground_floats,
|
|
SGFloat = have_static_ground_floats
|
|
;
|
|
OptSGFloat = do_not_use_static_ground_floats,
|
|
SGFloat = do_not_have_static_ground_floats
|
|
),
|
|
OptSGInt64s = OptTuple ^ ot_use_static_ground_int64s,
|
|
(
|
|
OptSGInt64s = use_static_ground_int64s,
|
|
SGInt64s = have_static_ground_int64s
|
|
;
|
|
OptSGInt64s = do_not_use_static_ground_int64s,
|
|
SGInt64s = do_not_have_static_ground_int64s
|
|
),
|
|
OptStaticCodeAddr = OptTuple ^ ot_use_static_code_addresses,
|
|
(
|
|
OptStaticCodeAddr = use_static_code_addresses,
|
|
StaticCodeAddrs = have_static_code_addresses
|
|
;
|
|
OptStaticCodeAddr = do_not_use_static_code_addresses,
|
|
StaticCodeAddrs = do_not_have_static_code_addresses
|
|
),
|
|
ExprnOpts = exprn_opts(NLG, ASM, UBF, UseFloatRegs, DetStackFloatWidth,
|
|
UBI64s, SGCell, SGFloat, SGInt64s, StaticCodeAddrs).
|
|
|
|
init_maybe_trace_info(Globals, ProcInfo, EffTraceLevel, TraceSlotInfo, !CI) :-
|
|
TraceEnabled = is_exec_trace_enabled_at_eff_trace_level(EffTraceLevel),
|
|
(
|
|
TraceEnabled = exec_trace_is_enabled,
|
|
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(Globals, ProcInfo, EffTraceLevel, MaybeTailRecLabel,
|
|
TraceSlotInfo, TraceInfo, !CI),
|
|
set_maybe_trace_info(yes(TraceInfo), !CI)
|
|
;
|
|
TraceEnabled = exec_trace_is_not_enabled,
|
|
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_eff_trace_level(CI, X) :-
|
|
X = CI ^ code_info_static ^ cis_eff_trace_level.
|
|
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_var_table(CI, X) :-
|
|
X = CI ^ code_info_static ^ cis_var_table.
|
|
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_progress_stream(CI, X) :-
|
|
X = CI ^ code_info_static ^ cis_progress_stream.
|
|
|
|
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.
|
|
|
|
:- pred max_var_slot(stack_slots::in, int::out) is det.
|
|
|
|
max_var_slot(StackSlots, SlotCount) :-
|
|
map.values(StackSlots, StackSlotList),
|
|
max_var_slot_loop(StackSlotList, 0, SlotCount).
|
|
|
|
:- pred max_var_slot_loop(list(stack_slot)::in, int::in, int::out) is det.
|
|
|
|
max_var_slot_loop([], !Max).
|
|
max_var_slot_loop([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_loop(Slots, !Max).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% 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.
|
|
|
|
% 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).
|
|
|
|
:- type for_call_or_closure
|
|
---> for_immediate_call
|
|
; for_closure.
|
|
|
|
% Create a code address which holds the address of the specified procedure.
|
|
% The fourth argument should be `for_immediate_call' if the caller
|
|
% will use the returned address only to construct calls from the
|
|
% current procedure, and `for_closure' if the returned address is
|
|
% to be put into a closure. (These are the only circumstances in which
|
|
% this predicate is called.)
|
|
%
|
|
:- func make_proc_entry_label(code_info, module_info, pred_id, proc_id,
|
|
for_call_or_closure) = 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.
|
|
|
|
% Should we trace the operation of the code generator?
|
|
%
|
|
:- pred should_trace_code_gen(code_info::in, maybe(io.text_output_stream)::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_var_table(CI, VarTable),
|
|
lookup_var_entry(VarTable, Var, Entry),
|
|
Type = Entry ^ vte_type.
|
|
|
|
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(type_body_du(_, _, _, _, MaybeRepn, _)),
|
|
MaybeRepn = yes(Repn)
|
|
then
|
|
CheaperTagTest = Repn ^ dur_cheaper_tag_test
|
|
else
|
|
CheaperTagTest = no_cheaper_tag_test
|
|
).
|
|
|
|
filter_region_vars(CI, ForwardLiveVarsBeforeGoal) = RegionVars :-
|
|
get_var_table(CI, VarTable),
|
|
RegionVars = set_of_var.filter(is_region_var(VarTable),
|
|
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).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
make_proc_entry_label(CI, ModuleInfo, PredId, ProcId, CallOrClosure)
|
|
= CodeAddr :-
|
|
(
|
|
CallOrClosure = for_closure,
|
|
ForFromWhere = for_from_everywhere
|
|
;
|
|
CallOrClosure = for_immediate_call,
|
|
get_globals(CI, Globals),
|
|
globals.get_opt_tuple(Globals, OptTuple),
|
|
UseJustOneCFunc = OptTuple ^ ot_use_just_one_c_func,
|
|
get_pred_id(CI, CurPredId),
|
|
get_proc_id(CI, CurProcId),
|
|
ForFromWhere = for_from_proc(UseJustOneCFunc, CurPredId, CurProcId)
|
|
),
|
|
CodeAddr = make_entry_label(ModuleInfo, PredId, ProcId, ForFromWhere).
|
|
|
|
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).
|
|
|
|
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_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).
|
|
|
|
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.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
should_trace_code_gen(CI, ShouldDebug) :-
|
|
get_pred_id(CI, PredId),
|
|
pred_id_to_int(PredId, PredIdInt),
|
|
get_module_info(CI, ModuleInfo),
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
globals.lookup_int_option(Globals, debug_code_gen_pred_id, DebugPredIdInt),
|
|
( if PredIdInt = DebugPredIdInt then
|
|
get_progress_stream(CI, ProgressStream),
|
|
ShouldDebug = yes(ProgressStream)
|
|
else
|
|
ShouldDebug = no
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% 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
|
|
get_var_table(CI, VarTable),
|
|
lookup_var_entry(VarTable, Var, Entry),
|
|
Name = var_entry_name(Var, Entry),
|
|
term.var_to_int(Var, VarNum),
|
|
string.format("variable `%s' (%d) not found",
|
|
[s(Name), i(VarNum)], Msg),
|
|
unexpected($pred, Msg)
|
|
).
|
|
|
|
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.
|
|
%---------------------------------------------------------------------------%
|