Files
mercury/compiler/code_info.m
Julien Fischer ae94e32d46 Support 64-bit integers in static ground terms with the LLDS backend.
compiler/handle_options.m:
compiler/options.m:
    Add a new internal option --static-ground-int64s, whose value
    says whether 64-bit integers may be placed in static data.
    (As with floats currently, we always do this.)

compiler/llds_out_data.m:
    If 64-bit integers are boxed, then emit a static constant to hold
    the value of each 64-bit integer literal.

compiler/llds.m:
compiler/llds_out_util.m:
compiler/code_info.m:
     Keep track of whether we are using unboxed int64s and static ground int64s
     at various points in the code generator.

     Add decl_ids for the labels we generate for 64-bit integer constants.

compiler/exprn_aux.m:
     Fix an XXX: properly determine whether an expression containing 64-bit
     integers is constant or not.

compiler/c_util.m:
    Add functions for converting 64-bit integers into strings giving
    the C literal representation of those integers.
2018-01-23 01:31:24 -05:00

1144 lines
42 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 1994-2012 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%---------------------------------------------------------------------------%
%
% File: code_info.m.
% Main authors: conway, zs.
%
% This file defines the code_info type and various operations on it.
% The code_info structure is the persistent part of the 'state'
% of the code generator. The other part of the code generator state,
% the location-dependent part, is in code_loc_dep.m.
%
% This file is organized into three submodules:
%
% - the code_info structure and its access predicates
% - simple wrappers around access predicates
% - managing stack slots
%
%---------------------------------------------------------------------------%
:- module ll_backend.code_info.
:- interface.
:- import_module check_hlds.
:- import_module check_hlds.type_util.
:- import_module hlds.code_model.
:- import_module hlds.hlds_data.
:- import_module hlds.hlds_goal.
:- import_module hlds.hlds_llds.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
:- import_module hlds.vartypes.
:- import_module libs.
:- import_module libs.globals.
:- import_module ll_backend.continuation_info.
:- import_module ll_backend.global_data.
:- import_module ll_backend.layout.
:- import_module ll_backend.llds.
:- import_module ll_backend.trace_gen.
:- import_module mdbcomp.
:- import_module mdbcomp.goal_path.
:- import_module mdbcomp.prim_data.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.set_of_var.
:- import_module bool.
:- import_module counter.
:- import_module list.
:- import_module map.
:- import_module maybe.
:- import_module set.
:- import_module set_tree234.
:- import_module term.
%----------------------------------------------------------------------------%
%----------------------------------------------------------------------------%
:- implementation.
:- import_module backend_libs.
:- import_module backend_libs.proc_label.
:- import_module libs.options.
:- import_module libs.trace_params.
:- import_module ll_backend.code_util.
:- import_module parse_tree.prog_type.
:- import_module cord.
:- import_module int.
:- import_module pair.
:- import_module require.
:- import_module string.
:- import_module 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) :-
% argument ModuleInfo
module_info_get_globals(ModuleInfo, Globals),
ExprnOpts = init_exprn_opts(Globals),
% argument PredId
% argument ProcId
% argument PredInfo
% argument ProcInfo
ProcLabel = make_proc_label(ModuleInfo, PredId, ProcId),
proc_info_get_varset(ProcInfo, VarSet),
proc_info_get_vartypes(ProcInfo, VarTypes),
proc_info_get_stack_slots(ProcInfo, StackSlots),
max_var_slot(StackSlots, VarSlotMax),
trace_reserved_slots(ModuleInfo, PredInfo, ProcInfo, Globals,
FixedSlots, _),
int.max(VarSlotMax, FixedSlots, SlotMax),
MaybeTraceInfo = no,
globals.lookup_bool_option(Globals, opt_no_return_calls,
OptNoReturnCalls),
globals.lookup_bool_option(Globals, use_trail, UseTrail),
globals.lookup_bool_option(Globals, disable_trail_ops, DisableTrailOps),
( if
UseTrail = yes,
DisableTrailOps = no
then
EmitTrailOps = add_trail_ops
else
EmitTrailOps = do_not_add_trail_ops
),
globals.lookup_bool_option(Globals, optimize_trail_usage, OptTrailOps),
globals.lookup_bool_option(Globals, region_analysis, UseRegions),
(
UseRegions = yes,
EmitRegionOps = add_region_ops
;
UseRegions = no,
EmitRegionOps = do_not_add_region_ops
),
globals.lookup_bool_option(Globals, optimize_region_ops, OptRegionOps),
globals.lookup_bool_option(Globals, auto_comments, AutoComments),
globals.lookup_bool_option(Globals, optimize_constructor_last_call_null,
LCMCNull),
% argument MaybeContainingGoalMap
% argument ConstStructMap
CodeInfoStatic0 = code_info_static(
ModuleInfo,
Globals,
ExprnOpts,
PredId,
ProcId,
PredInfo,
ProcInfo,
ProcLabel,
VarSet,
VarTypes,
SlotMax,
MaybeTraceInfo,
OptNoReturnCalls,
EmitTrailOps,
OptTrailOps,
EmitRegionOps,
OptRegionOps,
AutoComments,
LCMCNull,
MaybeContainingGoalMap,
ConstStructMap
),
LabelNumCounter0 = counter.init(1),
% argument SaveSuccip
globals.get_trace_level(Globals, TraceLevel),
map.init(LayoutMap),
ProcTraceEvents = no,
MaxRegRUsed = -1,
MaxRegFUsed = -1,
MaxTempSlotCount = 0,
map.init(TempContentMap),
set.init(PersistentTemps),
ClosureLayoutSeqNumCounter0 = counter.init(1),
ClosureLayouts = [],
CreatedTempFrame = no,
% argument StaticCellInfo
AllocSitesMap0 = set_tree234.init,
set.init(UsedEnvVars),
OutOfLineCode = cord.init,
CodeInfoPersistent0 = code_info_persistent(
LabelNumCounter0,
SaveSuccip,
LayoutMap,
ProcTraceEvents,
MaxRegRUsed,
MaxRegFUsed,
MaxTempSlotCount,
TempContentMap,
PersistentTemps,
ClosureLayoutSeqNumCounter0,
ClosureLayouts,
CreatedTempFrame,
StaticCellInfo,
AllocSitesMap0,
UsedEnvVars,
TSStringTableSize,
TSRevStringTable,
OutOfLineCode
),
CodeInfo0 = code_info(CodeInfoStatic0, CodeInfoPersistent0),
init_maybe_trace_info(TraceLevel, Globals, ModuleInfo,
PredInfo, ProcInfo, TraceSlotInfo, CodeInfo0, CodeInfo).
:- func init_exprn_opts(globals) = exprn_opts.
init_exprn_opts(Globals) = ExprnOpts :-
globals.lookup_bool_option(Globals, gcc_non_local_gotos, OptNLG),
(
OptNLG = yes,
NLG = have_non_local_gotos
;
OptNLG = no,
NLG = do_not_have_non_local_gotos
),
globals.lookup_bool_option(Globals, asm_labels, OptASM),
(
OptASM = yes,
ASM = have_asm_labels
;
OptASM = no,
ASM = do_not_have_asm_labels
),
globals.lookup_bool_option(Globals, static_ground_cells, OptSGCell),
(
OptSGCell = yes,
SGCell = have_static_ground_cells
;
OptSGCell = no,
SGCell = do_not_have_static_ground_cells
),
globals.lookup_bool_option(Globals, unboxed_float, OptUBF),
(
OptUBF = yes,
UBF = have_unboxed_floats
;
OptUBF = no,
UBF = do_not_have_unboxed_floats
),
globals.lookup_bool_option(Globals, use_float_registers, OptFloatRegs),
(
OptFloatRegs = yes,
UseFloatRegs = use_float_registers
;
OptFloatRegs = no,
UseFloatRegs = do_not_use_float_registers
),
double_width_floats_on_det_stack(Globals, FloatDwords),
(
FloatDwords = yes,
DetStackFloatWidth = double_width
;
FloatDwords = no,
DetStackFloatWidth = single_width
),
globals.lookup_bool_option(Globals, unboxed_int64s, OptUBI64s),
(
OptUBI64s = yes,
UBI64s = have_unboxed_int64s
;
OptUBI64s = no,
UBI64s = do_not_have_unboxed_int64s
),
globals.lookup_bool_option(Globals, static_ground_floats, OptSGFloat),
(
OptSGFloat = yes,
SGFloat = have_static_ground_floats
;
OptSGFloat = no,
SGFloat = do_not_have_static_ground_floats
),
globals.lookup_bool_option(Globals, static_ground_int64s, OptSGInt64s),
(
OptSGInt64s = yes,
SGInt64s = have_static_ground_int64s
;
OptSGInt64s = no,
SGInt64s = do_not_have_static_ground_int64s
),
globals.lookup_bool_option(Globals, static_code_addresses,
OptStaticCodeAddr),
(
OptStaticCodeAddr = yes,
StaticCodeAddrs = have_static_code_addresses
;
OptStaticCodeAddr = no,
StaticCodeAddrs = do_not_have_static_code_addresses
),
ExprnOpts = exprn_opts(NLG, ASM, UBF, UseFloatRegs, DetStackFloatWidth,
UBI64s, SGCell, SGFloat, SGInt64s, StaticCodeAddrs).
:- pred max_var_slot(stack_slots::in, int::out) is det.
max_var_slot(StackSlots, SlotCount) :-
map.values(StackSlots, StackSlotList),
max_var_slot_2(StackSlotList, 0, SlotCount).
:- pred max_var_slot_2(list(stack_slot)::in, int::in, int::out) is det.
max_var_slot_2([], !Max).
max_var_slot_2([Slot | Slots], !Max) :-
(
Slot = det_slot(N, Width)
;
Slot = parent_det_slot(N, Width)
;
Slot = nondet_slot(N),
Width = single_width
),
(
Width = single_width,
int.max(N, !Max)
;
Width = double_width,
int.max(N + 1, !Max)
),
max_var_slot_2(Slots, !Max).
:- pred init_maybe_trace_info(trace_level::in, globals::in,
module_info::in, pred_info::in, proc_info::in, trace_slot_info::out,
code_info::in, code_info::out) is det.
init_maybe_trace_info(TraceLevel, Globals, ModuleInfo, PredInfo,
ProcInfo, TraceSlotInfo, !CI) :-
TraceLevelIsNone =
eff_trace_level_is_none(ModuleInfo, PredInfo, ProcInfo, TraceLevel),
(
TraceLevelIsNone = no,
proc_info_get_has_tail_rec_call(ProcInfo, HasTailRecCall),
HasTailRecCall =
has_tail_rec_call(HasSelfTailRecCall, _HasMutualTailRecCall),
(
HasSelfTailRecCall = has_self_tail_rec_call,
get_next_label(TailRecLabel, !CI),
MaybeTailRecLabel = yes(TailRecLabel)
;
HasSelfTailRecCall = has_no_self_tail_rec_call,
MaybeTailRecLabel = no
),
trace_setup(ModuleInfo, PredInfo, ProcInfo, Globals, MaybeTailRecLabel,
TraceSlotInfo, TraceInfo, !CI),
set_maybe_trace_info(yes(TraceInfo), !CI)
;
TraceLevelIsNone = yes,
TraceSlotInfo = trace_slot_info(no, no, no, no, no, no)
).
%---------------------------------------------------------------------------%
get_module_info(CI, X) :-
X = CI ^ code_info_static ^ cis_module_info.
get_globals(CI, X) :-
X = CI ^ code_info_static ^ cis_globals.
get_exprn_opts(CI, X) :-
X = CI ^ code_info_static ^ cis_exprn_opts.
get_pred_id(CI, X) :-
X = CI ^ code_info_static ^ cis_pred_id.
get_proc_id(CI, X) :-
X = CI ^ code_info_static ^ cis_proc_id.
get_pred_info(CI, X) :-
X = CI ^ code_info_static ^ cis_pred_info.
get_proc_info(CI, X) :-
X = CI ^ code_info_static ^ cis_proc_info.
get_proc_label(CI, X) :-
X = CI ^ code_info_static ^ cis_proc_label.
get_varset(CI, X) :-
X = CI ^ code_info_static ^ cis_varset.
get_vartypes(CI, X) :-
X = CI ^ code_info_static ^ cis_vartypes.
get_var_slot_count(CI, X) :-
X = CI ^ code_info_static ^ cis_var_slot_count.
get_maybe_trace_info(CI, X) :-
X = CI ^ code_info_static ^ cis_maybe_trace_info.
get_opt_no_return_calls(CI, X) :-
X = CI ^ code_info_static ^ cis_opt_no_return_calls.
get_emit_trail_ops(CI, X) :-
X = CI ^ code_info_static ^ cis_emit_trail_ops.
get_opt_trail_ops(CI, X) :-
X = CI ^ code_info_static ^ cis_opt_trail_ops.
get_emit_region_ops(CI, X) :-
X = CI ^ code_info_static ^ cis_emit_region_ops.
get_opt_region_ops(CI, X) :-
X = CI ^ code_info_static ^ cis_opt_region_ops.
get_auto_comments(CI, X) :-
X = CI ^ code_info_static ^ cis_auto_comments.
get_lcmc_null(CI, X) :-
X = CI ^ code_info_static ^ cis_lcmc_null.
get_maybe_containing_goal_map(CI, X) :-
X = CI ^ code_info_static ^ cis_containing_goal_map.
get_const_struct_map(CI, X) :-
X = CI ^ code_info_static ^ cis_const_struct_map.
get_label_counter(CI, X) :-
X = CI ^ code_info_persistent ^ cip_label_num_src.
get_succip_used(CI, X) :-
X = CI ^ code_info_persistent ^ cip_store_succip.
get_layout_info(CI, X) :-
X = CI ^ code_info_persistent ^ cip_label_layout_info.
get_proc_trace_events(CI, X) :-
X = CI ^ code_info_persistent ^ cip_proc_trace_events.
get_max_regs_in_use_at_trace(CI, MaxRegR, MaxRegF) :-
MaxRegR = CI ^ code_info_persistent ^ cip_max_reg_r_used,
MaxRegF = CI ^ code_info_persistent ^ cip_max_reg_f_used.
get_created_temp_frame(CI, X) :-
X = CI ^ code_info_persistent ^ cip_created_temp_frame.
get_max_temp_slot_count(CI, X) :-
X = CI ^ code_info_persistent ^ cip_stackslot_max.
get_temp_content_map(CI, X) :-
X = CI ^ code_info_persistent ^ cip_temp_content_map.
get_persistent_temps(CI, X) :-
X = CI ^ code_info_persistent ^ cip_persistent_temps.
get_closure_seq_counter(CI, X) :-
X = CI ^ code_info_persistent ^ cip_closure_layout_seq.
get_closure_layouts(CI, X) :-
X = CI ^ code_info_persistent ^ cip_closure_layouts.
get_static_cell_info(CI, X) :-
X = CI ^ code_info_persistent ^ cip_static_cell_info.
get_alloc_sites(CI, X) :-
X = CI ^ code_info_persistent ^ cip_alloc_sites.
get_used_env_vars(CI, X) :-
X = CI ^ code_info_persistent ^ cip_used_env_vars.
get_out_of_line_code(CI, X) :-
X = CI ^ code_info_persistent ^ cip_out_of_line_code.
set_maybe_trace_info(X, !CI) :-
!CI ^ code_info_static ^ cis_maybe_trace_info := X.
set_label_counter(X, !CI) :-
!CI ^ code_info_persistent ^ cip_label_num_src := X.
set_succip_used(X, !CI) :-
!CI ^ code_info_persistent ^ cip_store_succip := X.
set_layout_info(X, !CI) :-
!CI ^ code_info_persistent ^ cip_label_layout_info := X.
set_proc_trace_events(X, !CI) :-
!CI ^ code_info_persistent ^ cip_proc_trace_events := X.
set_max_regs_in_use_at_trace(MR, MF, !CI) :-
!CI ^ code_info_persistent ^ cip_max_reg_r_used := MR,
!CI ^ code_info_persistent ^ cip_max_reg_f_used := MF.
set_max_temp_slot_count(X, !CI) :-
!CI ^ code_info_persistent ^ cip_stackslot_max := X.
set_temp_content_map(X, !CI) :-
!CI ^ code_info_persistent ^ cip_temp_content_map := X.
set_persistent_temps(X, !CI) :-
!CI ^ code_info_persistent ^ cip_persistent_temps := X.
set_closure_seq_counter(X, !CI) :-
!CI ^ code_info_persistent ^ cip_closure_layout_seq := X.
set_closure_layouts(X, !CI) :-
!CI ^ code_info_persistent ^ cip_closure_layouts := X.
set_created_temp_frame(X, !CI) :-
!CI ^ code_info_persistent ^ cip_created_temp_frame := X.
set_static_cell_info(X, !CI) :-
!CI ^ code_info_persistent ^ cip_static_cell_info := X.
set_alloc_sites(X, !CI) :-
!CI ^ code_info_persistent ^ cip_alloc_sites := X.
set_used_env_vars(X, !CI) :-
!CI ^ code_info_persistent ^ cip_used_env_vars := X.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
% Submodule for simple wrappers around access predicates.
:- interface.
% Get the hlds mapping from variables to stack slots.
%
:- pred get_stack_slots(code_info::in, stack_slots::out) is det.
% Find out whether the body of the current procedure should use
% typeinfo liveness.
%
:- func body_typeinfo_liveness(code_info) = bool.
% Find out the type of the given variable.
%
:- func variable_type(code_info, prog_var) = mer_type.
:- func variable_is_of_dummy_type(code_info, prog_var) = is_dummy_type.
% Compute the principal type constructor of the given type, and return
% the definition of this type constructor, if it has one (some type
% constructors are built in, and some are hidden behind abstraction
% barriers).
%
:- pred search_type_defn(code_info::in, mer_type::in, hlds_type_defn::out) is
semidet.
% Compute the principal type constructor of the given type, and return
% the definition of this type constructor. Abort if it doesn't have a
% definition (e.g. because it is a builtin).
%
:- func lookup_type_defn(code_info, mer_type) = hlds_type_defn.
:- func lookup_cheaper_tag_test(code_info, mer_type) = maybe_cheaper_tag_test.
:- func filter_region_vars(code_info, set_of_progvar) = set_of_progvar.
% Get the code model of the current procedure.
%
:- func get_proc_model(code_info) = code_model.
% Get the list of the head variables of the current procedure.
%
:- func get_headvars(code_info) = list(prog_var).
% Get the call argument information for the current procedure
%
:- func get_arginfo(code_info) = list(arg_info).
% Get the call argument info for a given mode of a given predicate
%
:- func get_pred_proc_arginfo(code_info, pred_id, proc_id) = list(arg_info).
:- func variable_name(code_info, prog_var) = string.
% Create a code address which holds the address of the specified procedure.
% The fourth argument should be `no' if the caller wants the
% returned address to be valid from everywhere in the program.
% If being valid from within the current procedure is enough,
% this argument should be `yes' wrapped around the value of the
% --procs-per-c-function option and the current procedure id.
% Using an address that is only valid from within the current
% procedure may make jumps more efficient.
%
% If the procs_per_c_function option tells us to put more than one
% procedure into each C function, but not all procedures in the module
% are in one function, then we would like to be able to use the
% fast form of reference to a procedure for references not only from
% within the same procedure but also from other procedures within
% the same C function. However, at the time of code generation,
% we do not yet know which procedures will be put into the same
% C functions, and so we cannot do this.
%
:- func make_proc_entry_label(code_info, module_info, pred_id, proc_id, bool)
= code_addr.
% Generate the next local label in sequence.
%
:- pred get_next_label(label::out, code_info::in, code_info::out)
is det.
% Note that the succip slot is used, and thus cannot be optimized away.
%
:- pred succip_is_used(code_info::in, code_info::out) is det.
:- pred add_trace_layout_for_label(label::in, term.context::in, trace_port::in,
bool::in, forward_goal_path::in, maybe(user_event_info)::in,
layout_label_info::in, code_info::in, code_info::out) is det.
:- pred get_next_closure_seq_no(int::out,
code_info::in, code_info::out) is det.
:- pred add_resume_layout_for_label(label::in,
layout_label_info::in, code_info::in, code_info::out) is det.
:- pred add_closure_layout(closure_proc_id_data::in,
code_info::in, code_info::out) is det.
:- pred add_threadscope_string(string::in, int::out,
code_info::in, code_info::out) is det.
:- pred get_threadscope_rev_string_table(code_info::in,
list(string)::out, int::out) is det.
:- pred add_scalar_static_cell(list(typed_rval)::in,
data_id::out, code_info::in, code_info::out) is det.
:- pred add_scalar_static_cell_natural_types(list(rval)::in,
data_id::out, code_info::in, code_info::out) is det.
:- pred add_vector_static_cell(list(llds_type)::in, list(list(rval))::in,
data_id::out, code_info::in, code_info::out) is det.
:- pred 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 :-
( if search_type_defn(CI, Type, TypeDefnPrime) then
TypeDefn = TypeDefnPrime
else
unexpected($module, $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(_, _, CheaperTagTestPrime, _, _, _, _, _, _)
then
CheaperTagTest = CheaperTagTestPrime
else
CheaperTagTest = no_cheaper_tag_test
).
filter_region_vars(CI, ForwardLiveVarsBeforeGoal) = RegionVars :-
get_vartypes(CI, VarTypes),
RegionVars = set_of_var.filter(is_region_var(VarTypes),
ForwardLiveVarsBeforeGoal).
%---------------------------------------------------------------------------%
get_proc_model(CI) = CodeModel :-
get_proc_info(CI, ProcInfo),
CodeModel = proc_info_interface_code_model(ProcInfo).
get_headvars(CI) = HeadVars :-
get_module_info(CI, ModuleInfo),
get_pred_id(CI, PredId),
get_proc_id(CI, ProcId),
module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo),
proc_info_get_headvars(ProcInfo, HeadVars).
get_arginfo(CI) = ArgInfo :-
get_pred_id(CI, PredId),
get_proc_id(CI, ProcId),
ArgInfo = get_pred_proc_arginfo(CI, PredId, ProcId).
get_pred_proc_arginfo(CI, PredId, ProcId) = ArgInfo :-
get_module_info(CI, ModuleInfo),
module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo),
proc_info_arg_info(ProcInfo, ArgInfo).
variable_name(CI, Var) = Name :-
get_varset(CI, Varset),
varset.lookup_name(Varset, Var, Name).
%---------------------------------------------------------------------------%
make_proc_entry_label(CI, ModuleInfo, PredId, ProcId, Immed0) = CodeAddr :-
(
Immed0 = no,
Immed = no
;
Immed0 = yes,
get_globals(CI, Globals),
globals.lookup_int_option(Globals, procs_per_c_function, ProcsPerFunc),
get_pred_id(CI, CurPredId),
get_proc_id(CI, CurProcId),
Immed = yes(ProcsPerFunc - proc(CurPredId, CurProcId))
),
CodeAddr = make_entry_label(ModuleInfo, PredId, ProcId, Immed).
get_next_label(Label, !CI) :-
get_proc_label(!.CI, ProcLabel),
get_label_counter(!.CI, C0),
counter.allocate(N, C0, C),
set_label_counter(C, !CI),
Label = internal_label(N, ProcLabel).
succip_is_used(!CI) :-
set_succip_used(yes, !CI).
add_trace_layout_for_label(Label, Context, Port, IsHidden, GoalPath,
MaybeSolverEventInfo, Layout, !CI) :-
get_layout_info(!.CI, Internals0),
Exec = yes(trace_port_layout_info(Context, Port, IsHidden, GoalPath,
MaybeSolverEventInfo, Layout)),
(
Label = internal_label(LabelNum, _)
;
Label = entry_label(_, _),
unexpected($module, $pred, "entry")
),
( if map.search(Internals0, LabelNum, Internal0) then
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)
else
Internal = internal_layout_info(Exec, no, no),
map.det_insert(LabelNum, Internal, Internals0, Internals)
),
set_layout_info(Internals, !CI).
add_resume_layout_for_label(Label, LayoutInfo, !CI) :-
get_layout_info(!.CI, Internals0),
Resume = yes(LayoutInfo),
(
Label = internal_label(LabelNum, _)
;
Label = entry_label(_, _),
unexpected($module, $pred, "entry")
),
( if map.search(Internals0, LabelNum, Internal0) then
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)
else
Internal = internal_layout_info(no, Resume, no),
map.det_insert(LabelNum, Internal, Internals0, Internals)
),
set_layout_info(Internals, !CI).
get_next_closure_seq_no(SeqNo, !CI) :-
get_closure_seq_counter(!.CI, C0),
counter.allocate(SeqNo, C0, C),
set_closure_seq_counter(C, !CI).
add_closure_layout(ClosureLayout, !CI) :-
get_closure_layouts(!.CI, ClosureLayouts),
set_closure_layouts([ClosureLayout | ClosureLayouts], !CI).
add_threadscope_string(String, SlotNum, !CI) :-
Persistent0 = !.CI ^ code_info_persistent,
Size0 = Persistent0 ^ cip_ts_string_table_size,
RevTable0 = Persistent0 ^ cip_ts_rev_string_table,
SlotNum = Size0,
Size = Size0 + 1,
RevTable = [String | RevTable0],
Persistent1 = Persistent0 ^ cip_ts_string_table_size := Size,
Persistent = Persistent1 ^ cip_ts_rev_string_table := RevTable,
!CI ^ code_info_persistent := Persistent.
get_threadscope_rev_string_table(CI, RevTable, TableSize) :-
RevTable = CI ^ code_info_persistent ^ cip_ts_rev_string_table,
TableSize = CI ^ code_info_persistent ^ cip_ts_string_table_size.
add_scalar_static_cell(RvalsTypes, DataAddr, !CI) :-
get_static_cell_info(!.CI, StaticCellInfo0),
global_data.add_scalar_static_cell(RvalsTypes, DataAddr,
StaticCellInfo0, StaticCellInfo),
set_static_cell_info(StaticCellInfo, !CI).
add_scalar_static_cell_natural_types(Rvals, DataAddr, !CI) :-
get_static_cell_info(!.CI, StaticCellInfo0),
global_data.add_scalar_static_cell_natural_types(Rvals, DataAddr,
StaticCellInfo0, StaticCellInfo),
set_static_cell_info(StaticCellInfo, !CI).
add_vector_static_cell(Types, Vector, DataAddr, !CI) :-
get_static_cell_info(!.CI, StaticCellInfo0),
global_data.add_vector_static_cell(Types, Vector, DataAddr,
StaticCellInfo0, StaticCellInfo),
set_static_cell_info(StaticCellInfo, !CI).
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),
( if map.search(StackSlots, Var, SlotLocn) then
Slot = stack_slot_to_lval(SlotLocn)
else
Name = variable_name(CI, Var),
term.var_to_int(Var, Num),
string.int_to_string(Num, NumStr),
Str = "variable `" ++ Name ++ "' " ++ "(" ++ NumStr ++ ") not found",
unexpected($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 :-
( 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.
%---------------------------------------------------------------------------%