mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 09:53:36 +00:00
If a module has two or more import_module or use_module declarations
for the same module, (typically, but not always, one being in its interface
and one in its implementation), generate an informational message about
each redundant declaration if --warn-unused-imports is enabled.
compiler/hlds_module.m:
We used to record the set of imported/used modules, and the set of
modules imported/used in the interface of the current module. However,
these sets
- did not record the distinction between imports and uses;
- did not allow distinction between single and multiple imports/uses;
- did not record the locations of the imports/uses.
The first distinction was needed only by module_qual.m, which *did*
pay attention to it; the other two were not needed at all.
To generate messages for imports/uses shadowing other imports/uses,
we need all three, so change the data structure storing such information
for *direct* imports to one that records all three of the above kinds
of information. (For imports made by read-in interface and optimization
files, the old set of modules approach is fine, and this diff leaves
the set of thus *indirectly* imported module names alone.)
compiler/unused_imports.m:
Use the extra information now available to generate a
severity_informational message about any import or use that is made
redundant by an earlier, more general import or use.
Fix two bugs in the code that generated warnings for just plain unused
modules.
(1) It did not consider that a use of the builtin type char justified
an import of char.m, but without that import, the type is not visible.
(2) It scanned cons_ids in goals in procedure bodies, but did not scan
cons_ids that have been put into the const_struct_db. (I did not update
the code here when I added the const_struct_db.)
Also, add a (hopefully temporary) workaround for a bug in
make_hlds_passes.m, which is noted below.
However, there are at least three problems that prevent us from enabling
--warn-unused-imports by default.
(1) In some places, the import of a module is used only by clauses for
a predicate that also has foreign procs. When compiled in a grade that
selects one of those foreign_procs as the implementation of the predicate,
the clauses are discarded *without* being added to the HLDS at all.
This leads unused_imports.m to generate an uncalled-for warning in such
cases. To fix this, we would need to preserve the Mercury clauses for
*all* predicates, even those with foreign procs, and do all the semantic
checks on them before throwing them away. (I tried to do this once, and
failed, but the task should be easier after the item list change.)
(2) We have two pieces of code to generate import warnings. The one in
unused_imports.m operates on the HLDS after type and mode checking,
while module_qual.m operates on the parse tree before the creation of
the HLDS. The former is more powerful, since it knows e.g. what types and
modes are used in the bodies of predicates, and hence can generate warnings
about an import being unused *anywhere* in a module, as opposed to just
unused in its interface.
If --warn-unused-imports is enabled, we will get two separate set of
reports about an interface import being unused in the interface,
*unless* we get a type or mode error, in which case unused_imports.m
won't be invoked. But in case we do get such errors, we don't want to
throw away the warnings from module_qual.m. We could store them and
throw them away only after we know we won't need them, or just get
the two modules to generate identical error_specs for each warning,
so that the sort_and_remove_dups of the error specs will do the
throwing away for us for free, if we get that far.
(3) The valid/bug100.m test case was added as a regression test for a bug
that was fixed in module_qual.m. However the bug is still present in
unused_imports.m.
compiler/make_hlds_passes.m:
Give hlds_module.m the extra information it now needs for each item_avail.
Add an XXX for a bug that cannot be fixed right now: the setting of
the status of abstract instances to abstract_imported. (The "abstract"
part is correct; the "imported" part may not be.)
compiler/intermod.m:
compiler/try_expand.m:
compiler/xml_documentation.m:
Conform to the change in hlds_module.m.
compiler/module_qual.m:
Update the documentation of the relationship of this module
with unused_imports.m.
compiler/hlds_data.m:
Document a problem with the status of instance definitions.
compiler/hlds_out_module.m:
Update the code that prints out the module_info to conform to the change
to hlds_module.m.
Print status information about instances, which was needed to diagnose
one of the bugs in unused_imports.m. Format the output for instances
nicer.
compiler/prog_item.m:
Add a convenience predicate.
compiler/prog_data.m:
Remove a type synonym that makes things harder to understand, not easier.
compiler/modules.m:
Delete an XXX that asks for the feature this diff implements.
Add another XXX about how that feature could be improved.
compiler/Mercury.options.m:
Add some more modules to the list of modules on which the compiler
should be invoked with --no-warn-unused-imports.
compiler/*.m:
library/*.m:
mdbcomp/*.m:
browser/*.m:
deep_profiler/*.m:
mfilterjavac/*.m:
Delete unneeded imports. Many of these shadow other imports, and some
are just plain unneeded, as shown by --warn-unused-imports. In a few
modules, there were a *lot* of unneeded imports, but most had just
one or two.
In a few cases, removing an import from a module, because it *itself*
does not need it, required adding that same import to those of its
submodules which *do* need it.
In a few cases, conform to other changes above.
tests/invalid/Mercury.options:
Test the generation of messages about import shadowing on the existing
import_in_parent.m test case (although it was also tested very thoroughly
when giving me the information needed for the deletion of all the
unneeded imports above).
tests/*/*.{m,*exp}:
Delete unneeded imports, and update any expected error messages
to expect the now-smaller line numbers.
1098 lines
40 KiB
Mathematica
1098 lines
40 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.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.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.goal_path.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- 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.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 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_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 setting of --optimize-constructor-last-call-null.
|
|
cis_lcmc_null :: bool,
|
|
|
|
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) :-
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
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),
|
|
ExprnOpts = init_exprn_opts(Globals),
|
|
globals.get_trace_level(Globals, TraceLevel),
|
|
map.init(TempContentMap),
|
|
set.init(PersistentTemps),
|
|
map.init(LayoutMap),
|
|
max_var_slot(StackSlots, VarSlotMax),
|
|
trace_reserved_slots(ModuleInfo, PredInfo, ProcInfo, Globals,
|
|
FixedSlots, _),
|
|
int.max(VarSlotMax, FixedSlots, SlotMax),
|
|
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),
|
|
(
|
|
UseTrail = yes,
|
|
DisableTrailOps = no
|
|
->
|
|
EmitTrailOps = add_trail_ops
|
|
;
|
|
EmitTrailOps = do_not_add_trail_ops
|
|
),
|
|
globals.lookup_bool_option(Globals, optimize_trail_usage, OptTrailOps),
|
|
globals.lookup_bool_option(Globals, optimize_region_ops, OptRegionOps),
|
|
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, auto_comments, AutoComments),
|
|
globals.lookup_bool_option(Globals, optimize_constructor_last_call_null,
|
|
LCMCNull),
|
|
CodeInfo0 = code_info(
|
|
code_info_static(
|
|
ModuleInfo,
|
|
Globals,
|
|
ExprnOpts,
|
|
PredId,
|
|
ProcId,
|
|
PredInfo,
|
|
ProcInfo,
|
|
ProcLabel,
|
|
VarSet,
|
|
VarTypes,
|
|
SlotMax,
|
|
no,
|
|
OptNoReturnCalls,
|
|
EmitTrailOps,
|
|
OptTrailOps,
|
|
EmitRegionOps,
|
|
OptRegionOps,
|
|
AutoComments,
|
|
LCMCNull,
|
|
MaybeContainingGoalMap,
|
|
ConstStructMap
|
|
),
|
|
code_info_persistent(
|
|
counter.init(1),
|
|
SaveSuccip,
|
|
LayoutMap,
|
|
no,
|
|
-1,
|
|
-1,
|
|
0,
|
|
TempContentMap,
|
|
PersistentTemps,
|
|
counter.init(1),
|
|
[],
|
|
no,
|
|
StaticCellInfo,
|
|
set_tree234.init,
|
|
set.init,
|
|
TSStringTableSize,
|
|
TSRevStringTable,
|
|
cord.empty
|
|
)
|
|
),
|
|
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, 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_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,
|
|
SGCell, SGFloat, 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_call_event(ProcInfo, HasTailCallEvents),
|
|
(
|
|
HasTailCallEvents = has_tail_call_event,
|
|
get_next_label(TailRecLabel, !CI),
|
|
MaybeTailRecLabel = yes(TailRecLabel)
|
|
;
|
|
HasTailCallEvents = has_no_tail_call_event,
|
|
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_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 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 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 = check_dummy_type(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 :-
|
|
( search_type_defn(CI, Type, TypeDefnPrime) ->
|
|
TypeDefn = TypeDefnPrime
|
|
;
|
|
unexpected($module, $pred, "type ctor has no definition")
|
|
).
|
|
|
|
lookup_cheaper_tag_test(CI, Type) = CheaperTagTest :-
|
|
(
|
|
search_type_defn(CI, Type, TypeDefn),
|
|
get_type_defn_body(TypeDefn, TypeBody),
|
|
TypeBody = hlds_du_type(_, _, CheaperTagTestPrime, _, _, _, _, _, _)
|
|
->
|
|
CheaperTagTest = CheaperTagTestPrime
|
|
;
|
|
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($module, $pred, "entry")
|
|
),
|
|
( map.search(Internals0, LabelNum, Internal0) ->
|
|
Internal0 = internal_layout_info(Exec0, Resume, Return),
|
|
(
|
|
Exec0 = no
|
|
;
|
|
Exec0 = yes(_),
|
|
unexpected($module, $pred, "already known label")
|
|
),
|
|
Internal = internal_layout_info(Exec, Resume, Return),
|
|
map.det_update(LabelNum, Internal, Internals0, Internals)
|
|
;
|
|
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($module, $pred, "entry")
|
|
),
|
|
( map.search(Internals0, LabelNum, Internal0) ->
|
|
Internal0 = internal_layout_info(Exec, Resume0, Return),
|
|
(
|
|
Resume0 = no
|
|
;
|
|
Resume0 = yes(_),
|
|
unexpected($module, $pred, "already known label")
|
|
),
|
|
Internal = internal_layout_info(Exec, Resume, Return),
|
|
map.det_update(LabelNum, Internal, Internals0, Internals)
|
|
;
|
|
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).
|
|
|
|
add_alloc_site_info(Context, Type, Size, AllocId, !CI) :-
|
|
get_proc_label(!.CI, ProcLabel),
|
|
AllocSite = alloc_site_info(ProcLabel, Context, Type, 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($module, $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),
|
|
( map.search(StackSlots, Var, SlotLocn) ->
|
|
Slot = stack_slot_to_lval(SlotLocn)
|
|
;
|
|
Name = variable_name(CI, Var),
|
|
term.var_to_int(Var, Num),
|
|
string.int_to_string(Num, NumStr),
|
|
Str = "variable `" ++ Name ++ "' " ++ "(" ++ NumStr ++ ") not found",
|
|
unexpected($module, $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 :-
|
|
(
|
|
odd(NumSlots),
|
|
get_exprn_opts(CI, ExprnOpts),
|
|
get_det_stack_float_width(ExprnOpts) = double_width
|
|
->
|
|
NumSlotsRoundup = NumSlots + 1
|
|
;
|
|
NumSlotsRoundup = NumSlots
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module ll_backend.code_info.
|
|
%---------------------------------------------------------------------------%
|