Files
mercury/compiler/stack_layout.m
Zoltan Somogyi 1c3bc03415 Make the system compiler with --warn-unused-imports.
Estimated hours taken: 2
Branches: main, release

Make the system compiler with --warn-unused-imports.

browser/*.m:
library/*.m:
compiler/*.m:
	Remove unnecesary imports as flagged by --warn-unused-imports.

	In some files, do some minor cleanup along the way.
2010-12-30 11:18:04 +00:00

2567 lines
102 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 1997-2010 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: stack_layout.m.
% Main authors: trd, zs.
%
% This module generates label, procedure, module and closure layout structures
% for code in the current module for the LLDS backend. Layout structures are
% used by the parts of the runtime system that need to look at the stacks
% (and sometimes the registers) and make sense of their contents. The parts
% of the runtime system that need to do this include exception handling,
% the debugger, and (eventually) the accurate garbage collector.
%
% The tables we generate are mostly of (Mercury) types defined in layout.m,
% which are turned into C code (global variable declarations and
% initializations) by layout_out.m.
%
% The C types of the structures we generate are defined and documented in
% runtime/mercury_stack_layout.h.
%
% TODO: Handle the parent_sp register and parent stack variables.
%
%---------------------------------------------------------------------------%
:- module ll_backend.stack_layout.
:- interface.
:- import_module hlds.hlds_goal.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
:- 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.prog_rep.
:- import_module mdbcomp.prim_data.
:- import_module mdbcomp.program_representation.
:- import_module parse_tree.prog_data.
:- import_module assoc_list.
:- import_module list.
:- import_module map.
:- import_module maybe.
%---------------------------------------------------------------------------%
% Process all the continuation information stored in the HLDS,
% converting it into LLDS data structures.
%
:- pred generate_llds_layout_data(module_info::in,
global_data::in, global_data::out,
list(rval)::out, list(int)::out, list(int)::out, list(int)::out,
list(maybe(int))::out, list(user_event_data)::out,
list(label_layout_no_vars)::out,
list(label_layout_short_vars)::out, list(label_layout_long_vars)::out,
map(label, layout_slot_name)::out, map(label, data_id)::out,
list(call_site_static_data)::out, list(coverage_point_info)::out,
list(proc_layout_proc_static)::out,
list(int)::out, list(int)::out, list(int)::out,
list(table_io_decl_data)::out, map(pred_proc_id, layout_slot_name)::out,
list(layout_slot_name)::out, list(proc_layout_exec_trace)::out,
list(proc_layout_data)::out, list(module_layout_data)::out) is det.
:- pred construct_closure_layout(proc_label::in, int::in,
closure_layout_info::in, proc_label::in, module_name::in,
string::in, int::in, pred_origin::in, string::in,
static_cell_info::in, static_cell_info::out,
assoc_list(rval, llds_type)::out, closure_proc_id_data::out) is det.
:- pred convert_table_arg_info(table_arg_infos::in, int::out,
rval::out, rval::out, static_cell_info::in, static_cell_info::out) is det.
% Construct a representation of a variable location as a 32-bit
% integer.
%
:- pred represent_locn_as_int(layout_locn::in, int::out) is det.
% Construct a representation of the interface determinism of a procedure.
%
:- pred represent_determinism_rval(determinism::in, rval::out) is det.
:- type string_table.
:- pred lookup_string_in_table(string::in, int::out,
string_table::in, string_table::out) is det.
%---------------------------------------------------------------------------%
:- pred compute_var_number_map(list(prog_var)::in, prog_varset::in,
assoc_list(int, internal_layout_info)::in, hlds_goal::in,
var_num_map::out) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module backend_libs.proc_label.
:- import_module backend_libs.rtti.
:- import_module check_hlds.type_util.
:- import_module hlds.code_model.
:- import_module hlds.goal_util.
:- import_module hlds.hlds_pred.
:- import_module hlds.hlds_rtti.
:- import_module libs.globals.
:- import_module libs.options.
:- import_module libs.trace_params.
:- import_module ll_backend.layout.
:- import_module ll_backend.layout_out.
:- import_module ll_backend.ll_pseudo_type_info.
:- import_module ll_backend.trace_gen.
:- import_module parse_tree.prog_event.
:- import_module bool.
:- import_module cord.
:- import_module counter.
:- import_module int.
:- import_module map.
:- import_module pair.
:- import_module require.
:- import_module set.
:- import_module string.
:- import_module svmap.
:- import_module term.
:- import_module varset.
%---------------------------------------------------------------------------%
generate_llds_layout_data(ModuleInfo, !GlobalData,
PseudoTypeInfoRvals, HLDSVarNums, ShortLocns, LongLocns,
UserEventVarNums, UserEvents,
NoVarLabelLayouts, SVarLabelLayouts, LVarLabelLayouts,
InternalLabelToLayoutMap, ProcLabelToLayoutMap,
CallSiteStatics, CoveragePoints, ProcStatics,
ProcHeadVarNums, ProcVarNames, ProcBodyBytecodes,
TableIoDecls, TableIoDeclMap, ProcEventLayouts, ExecTraces,
ProcLayouts, ModuleLayouts) :-
Params = init_stack_layout_params(ModuleInfo),
map.init(LabelTables0),
StringTable0 = init_string_table,
global_data_get_static_cell_info(!.GlobalData, StaticCellInfo0),
LabelLayoutInfo0 = init_label_layouts_info,
ProcLayoutInfo0 = init_proc_layouts_info,
global_data_get_all_proc_layouts(!.GlobalData, ProcLayoutList),
list.foldl5(construct_proc_and_label_layouts_for_proc(Params),
ProcLayoutList,
LabelTables0, LabelTables,
StringTable0, StringTable,
StaticCellInfo0, StaticCellInfo1,
LabelLayoutInfo0, LabelLayoutInfo,
ProcLayoutInfo0, ProcLayoutInfo),
LabelsCounter = LabelLayoutInfo ^ lli_label_counter,
counter.allocate(NumLabels, LabelsCounter, _),
RevCallSiteStatics =
ProcLayoutInfo ^ pli_proc_statics ^ psi_rev_call_sites,
RevCoveragePoints =
ProcLayoutInfo ^ pli_proc_statics ^ psi_rev_coverage_points,
RevProcStatics =
ProcLayoutInfo ^ pli_proc_statics ^ psi_rev_proc_statics,
list.reverse(RevCallSiteStatics, CallSiteStatics),
list.reverse(RevCoveragePoints, CoveragePoints),
list.reverse(RevProcStatics, ProcStatics),
RevProcHeadVarNums =
ProcLayoutInfo ^ pli_exec_traces ^ eti_rev_proc_head_var_nums,
RevProcVarNames =
ProcLayoutInfo ^ pli_exec_traces ^ eti_rev_proc_var_names,
RevProcEventLayouts =
ProcLayoutInfo ^ pli_exec_traces ^ eti_rev_proc_event_layouts,
RevTableIoDecls =
ProcLayoutInfo ^ pli_exec_traces ^ eti_rev_table_io_decl_datas,
RevExecTraces =
ProcLayoutInfo ^ pli_exec_traces ^ eti_rev_exec_traces,
list.reverse(RevProcHeadVarNums, ProcHeadVarNums),
list.reverse(RevProcVarNames, ProcVarNames),
list.reverse(RevProcEventLayouts, ProcEventLayouts),
list.reverse(RevTableIoDecls, TableIoDecls),
list.reverse(RevExecTraces, ExecTraces),
TableIoDeclMap = ProcLayoutInfo ^ pli_exec_traces ^ eti_table_io_decl_map,
RevProcBodyBytecodes = ProcLayoutInfo ^ pli_rev_proc_bytes,
RevProcLayouts = ProcLayoutInfo ^ pli_rev_proc_layouts,
RevProcLayoutNames = ProcLayoutInfo ^ pli_rev_proc_layout_names,
list.reverse(RevProcBodyBytecodes, ProcBodyBytecodes),
list.reverse(RevProcLayouts, ProcLayouts),
list.reverse(RevProcLayoutNames, ProcLayoutNames),
RevPseudoTypeInfoRvals = LabelLayoutInfo ^ lli_rev_ptis,
RevLongLocns = LabelLayoutInfo ^ lli_rev_long_locns,
RevShortLocns = LabelLayoutInfo ^ lli_rev_short_locns,
RevHLDSVarNums = LabelLayoutInfo ^ lli_rev_hlds_var_nums,
list.reverse(RevPseudoTypeInfoRvals, PseudoTypeInfoRvals),
list.reverse(RevLongLocns, LongLocns),
list.reverse(RevShortLocns, ShortLocns),
list.reverse(RevHLDSVarNums, HLDSVarNums),
UserEventVarNumsCord = LabelLayoutInfo ^ lli_user_event_var_nums,
UserEventsCord = LabelLayoutInfo ^ lli_user_events,
UserEventVarNums = cord.list(UserEventVarNumsCord),
UserEvents = cord.list(UserEventsCord),
RevNoVarLabelLayouts = LabelLayoutInfo ^ lli_rev_no_var_label_layouts,
RevSVarLabelLayouts = LabelLayoutInfo ^ lli_rev_svar_label_layouts,
RevLVarLabelLayouts = LabelLayoutInfo ^ lli_rev_lvar_label_layouts,
list.reverse(RevNoVarLabelLayouts, NoVarLabelLayouts),
list.reverse(RevSVarLabelLayouts, SVarLabelLayouts),
list.reverse(RevLVarLabelLayouts, LVarLabelLayouts),
InternalLabelToLayoutMap = LabelLayoutInfo ^ lli_i_label_to_layout_map,
ProcLabelToLayoutMap = ProcLayoutInfo ^ pli_p_label_to_layout_map,
StringTable = string_table(_, RevStringList, StringOffset),
list.reverse(RevStringList, StringList),
ConcatStrings = string_with_0s(StringList),
TraceLayout = Params ^ slp_trace_stack_layout,
(
TraceLayout = yes,
module_info_get_name(ModuleInfo, ModuleName),
RttiLineNumbers = Params ^ slp_rtti_line_numbers,
(
RttiLineNumbers = yes,
EffLabelTables = LabelTables
;
RttiLineNumbers = no,
map.init(EffLabelTables)
),
format_label_tables(EffLabelTables, SourceFileLayouts),
TraceSuppress = Params ^ slp_trace_suppress,
SuppressedEvents = encode_suppressed_events(TraceSuppress),
(
UserEvents = [],
HasUserEvent = no
;
UserEvents = [_ | _],
HasUserEvent = yes
),
(
HasUserEvent = no,
MaybeEventSet = no,
StaticCellInfo = StaticCellInfo1
;
HasUserEvent = yes,
module_info_get_event_set(ModuleInfo, EventSet),
EventSetData = derive_event_set_data(EventSet),
list.foldl2(build_event_arg_type_info_map,
EventSetData ^ event_set_data_specs,
map.init, EventArgTypeInfoMap,
StaticCellInfo1, StaticCellInfo),
EventSetLayoutData = event_set_layout_data(EventSetData,
EventArgTypeInfoMap),
MaybeEventSet = yes(EventSetLayoutData)
),
ModuleCommonLayout = module_layout_common_data(ModuleName,
StringOffset, ConcatStrings),
ModuleCommonLayoutName = module_common_layout(ModuleName),
TraceLevel = Params ^ slp_trace_level,
ModuleLayout = module_layout_data(ModuleName,
ModuleCommonLayoutName, ProcLayoutNames, SourceFileLayouts,
TraceLevel, SuppressedEvents, NumLabels, MaybeEventSet),
ModuleLayouts = [ModuleCommonLayout, ModuleLayout]
;
TraceLayout = no,
DeepProfiling = Params ^ slp_deep_profiling,
(
DeepProfiling = yes,
module_info_get_name(ModuleInfo, ModuleName),
ModuleCommonLayout = module_layout_common_data(ModuleName,
StringOffset, ConcatStrings),
ModuleLayouts = [ModuleCommonLayout]
;
DeepProfiling = no,
ModuleLayouts = []
),
StaticCellInfo = StaticCellInfo1
),
global_data_set_static_cell_info(StaticCellInfo, !GlobalData).
:- pred valid_proc_layout(proc_layout_info::in) is semidet.
valid_proc_layout(ProcLayoutInfo) :-
EntryLabel = ProcLayoutInfo ^ pli_entry_label,
ProcLabel = get_proc_label(EntryLabel),
(
ProcLabel = ordinary_proc_label(_, _, DeclModule, Name, Arity, _),
\+ no_type_info_builtin(DeclModule, Name, Arity)
;
ProcLabel = special_proc_label(_, _, _, _, _, _)
).
:- pred build_event_arg_type_info_map(event_spec::in,
map(int, rval)::in, map(int, rval)::out,
static_cell_info::in, static_cell_info::out) is det.
build_event_arg_type_info_map(EventSpec, !EventArgTypeInfoMap,
!StaticCellInfo) :-
EventNumber = EventSpec ^ event_spec_num,
Attrs = EventSpec ^ event_spec_attrs,
list.map_foldl(build_event_arg_type_info, Attrs, RvalsAndTypes,
!StaticCellInfo),
add_scalar_static_cell(RvalsAndTypes, TypesDataAddr, !StaticCellInfo),
Rval = const(llconst_data_addr(TypesDataAddr, no)),
svmap.det_insert(EventNumber, Rval, !EventArgTypeInfoMap).
:- pred build_event_arg_type_info(event_attribute::in,
pair(rval, llds_type)::out,
static_cell_info::in, static_cell_info::out) is det.
build_event_arg_type_info(Attr, TypeRvalAndType, !StaticCellInfo) :-
Type = Attr ^ attr_type,
ExistQTvars = [],
NumUnivQTvars = -1,
ll_pseudo_type_info.construct_typed_llds_pseudo_type_info(Type,
NumUnivQTvars, ExistQTvars, !StaticCellInfo, TypeRval, TypeRvalType),
TypeRvalAndType = TypeRval - TypeRvalType.
%---------------------------------------------------------------------------%
:- pred format_label_tables(map(string, file_label_table)::in,
list(file_layout_data)::out) is det.
format_label_tables(LabelTableMap, SourceFileLayouts) :-
map.to_assoc_list(LabelTableMap, LabelTableList),
list.map(format_label_table, LabelTableList, SourceFileLayouts).
:- pred format_label_table(pair(string, file_label_table)::in,
file_layout_data::out) is det.
format_label_table(FileName - LineNoMap, FileLayoutData) :-
% This step should produce a list ordered on line numbers.
map.to_assoc_list(LineNoMap, LineNoList),
% And this step should preserve that order.
flatten_label_table(LineNoList, [], FlatLineNoList),
Filter = (pred(LineNoInfo::in, FilteredLineNoInfo::out) is det :-
LineNoInfo = LineNo - (Label - _IsReturn),
FilteredLineNoInfo = LineNo - Label
),
list.map(Filter, FlatLineNoList, FilteredList),
FileLayoutData = file_layout_data(FileName, FilteredList).
:- pred flatten_label_table(assoc_list(int, list(line_no_info))::in,
assoc_list(int, line_no_info)::in,
assoc_list(int, line_no_info)::out) is det.
flatten_label_table([], RevList, List) :-
list.reverse(RevList, List).
flatten_label_table([LineNo - LinesInfos | Lines], RevList0, List) :-
list.foldl(add_line_no(LineNo), LinesInfos, RevList0, RevList1),
flatten_label_table(Lines, RevList1, List).
:- pred add_line_no(int::in, line_no_info::in,
assoc_list(int, line_no_info)::in,
assoc_list(int, line_no_info)::out) is det.
add_line_no(LineNo, LineInfo, RevList0, RevList) :-
RevList = [LineNo - LineInfo | RevList0].
%---------------------------------------------------------------------------%
% The per-sourcefile label table maps line numbers to the list of
% labels that correspond to that line. Each label is accompanied
% by a flag that says whether the label is the return site of a call
% or not, and if it is, whether the called procedure is known.
%
:- type is_label_return
---> known_callee(label)
; unknown_callee
; not_a_return.
:- type line_no_info == pair(layout_slot_name, is_label_return).
:- type file_label_table == map(int, list(line_no_info)).
:- type label_tables == map(string, file_label_table).
% Construct the layouts that concern a single procedure: the procedure
% layout and the layouts of the labels inside that procedure. Also update
% the module-wide label table with the labels defined in this procedure.
%
:- pred construct_proc_and_label_layouts_for_proc(stack_layout_params::in,
proc_layout_info::in,
label_tables::in, label_tables::out,
string_table::in, string_table::out,
static_cell_info::in, static_cell_info::out,
label_layouts_info::in, label_layouts_info::out,
proc_layouts_info::in, proc_layouts_info::out) is det.
construct_proc_and_label_layouts_for_proc(Params, PLI, !LabelTables,
!StringTable, !StaticCellInfo, !LabelLayoutInfo, !ProcLayoutInfo) :-
PLI = proc_layout_info(RttiProcLabel, EntryLabel,
_Detism, _StackSlots, _SuccipLoc, _EvalMethod, _EffTraceLevel,
_MaybeCallLabel, _MaxTraceReg, HeadVars, _ArgModes,
Goal, _NeedGoalRep, _InstMap,
_TraceSlotInfo, ForceProcIdLayout, VarSet, _VarTypes,
InternalMap, MaybeTableIoDecl, _NeedsAllNames, _MaybeDeepProfInfo),
map.to_assoc_list(InternalMap, Internals),
compute_var_number_map(HeadVars, VarSet, Internals, Goal, VarNumMap),
ProcLabel = get_proc_label(EntryLabel),
bool.or(Params ^ slp_procid_stack_layout, ForceProcIdLayout, ProcIdLayout),
(
( ProcIdLayout = yes
; MaybeTableIoDecl = yes(_)
)
->
UserOrUci = proc_label_user_or_uci(ProcLabel),
Kind = proc_layout_proc_id(UserOrUci)
;
Kind = proc_layout_traversal
),
ProcLayoutName = proc_layout(RttiProcLabel, Kind),
(
( Params ^ slp_agc_stack_layout = yes
; Params ^ slp_trace_stack_layout = yes
),
valid_proc_layout(PLI)
->
list.map_foldl3(
construct_internal_layout(Params, ProcLabel, ProcLayoutName,
VarNumMap),
Internals, InternalLabelInfos,
!StringTable, !StaticCellInfo, !LabelLayoutInfo)
;
InternalLabelInfos = []
),
list.foldl(update_label_table, InternalLabelInfos, !LabelTables),
construct_proc_layout(Params, PLI, ProcLayoutName, Kind,
InternalLabelInfos, VarNumMap, !.LabelLayoutInfo,
!StringTable, !StaticCellInfo, !ProcLayoutInfo).
%---------------------------------------------------------------------------%
:- type internal_label_info
---> internal_label_info(
containing_proc :: proc_label,
label_num_in_proc :: int,
maybe_has_var_info :: label_vars,
slot_in_array :: int,
internal_layout_info :: internal_layout_info
).
% Add the given label layout to the module-wide label tables.
%
:- pred update_label_table(internal_label_info::in,
map(string, file_label_table)::in, map(string, file_label_table)::out)
is det.
update_label_table(InternalLabelInfo, !LabelTables) :-
InternalLabelInfo = internal_label_info(_ProcLabel, _LabelNum, LabelVars,
Slot, InternalInfo),
InternalInfo = internal_layout_info(Port, _, Return),
(
Return = yes(return_layout_info(TargetsContexts, _)),
find_valid_return_context(TargetsContexts, Target, Context, _GoalPath)
->
( Target = code_label(TargetLabel) ->
IsReturn = known_callee(TargetLabel)
;
IsReturn = unknown_callee
),
update_label_table_2(LabelVars, Slot, Context, IsReturn, !LabelTables)
;
Port = yes(trace_port_layout_info(Context, _, _, _, _, _)),
context_is_valid(Context)
->
update_label_table_2(LabelVars, Slot, Context, not_a_return,
!LabelTables)
;
true
).
:- pred update_label_table_2(label_vars::in, int::in, context::in,
is_label_return::in,
map(string, file_label_table)::in, map(string, file_label_table)::out)
is det.
update_label_table_2(LabelVars, Slot, Context, IsReturn, !LabelTables) :-
term.context_file(Context, File),
term.context_line(Context, Line),
( map.search(!.LabelTables, File, LabelTable0) ->
LabelLayout = layout_slot(label_layout_array(LabelVars), Slot),
( map.search(LabelTable0, Line, LineInfo0) ->
LineInfo = [LabelLayout - IsReturn | LineInfo0],
map.det_update(LabelTable0, Line, LineInfo, LabelTable),
svmap.det_update(File, LabelTable, !LabelTables)
;
LineInfo = [LabelLayout - IsReturn],
map.det_insert(LabelTable0, Line, LineInfo, LabelTable),
svmap.det_update(File, LabelTable, !LabelTables)
)
;
( context_is_valid(Context) ->
map.init(LabelTable0),
LabelLayout = layout_slot(label_layout_array(LabelVars), Slot),
LineInfo = [LabelLayout - IsReturn],
map.det_insert(LabelTable0, Line, LineInfo, LabelTable),
svmap.det_insert(File, LabelTable, !LabelTables)
;
% We don't have a valid context for this label,
% so we don't enter it into any tables.
true
)
).
:- pred find_valid_return_context(
assoc_list(code_addr, pair(prog_context, forward_goal_path))::in,
code_addr::out, prog_context::out, forward_goal_path::out) is semidet.
find_valid_return_context([TargetContext | TargetContexts],
ValidTarget, ValidContext, ValidGoalPath) :-
TargetContext = Target - (Context - GoalPath),
( context_is_valid(Context) ->
ValidTarget = Target,
ValidContext = Context,
ValidGoalPath = GoalPath
;
find_valid_return_context(TargetContexts, ValidTarget, ValidContext,
ValidGoalPath)
).
:- pred context_is_valid(prog_context::in) is semidet.
context_is_valid(Context) :-
term.context_file(Context, File),
term.context_line(Context, Line),
File \= "",
Line > 0.
%---------------------------------------------------------------------------%
%
% Construct proc layouts.
%
% Construct a procedure-specific layout.
%
:- pred construct_proc_layout(stack_layout_params::in, proc_layout_info::in,
layout_name::in, proc_layout_kind::in, list(internal_label_info)::in,
var_num_map::in,
label_layouts_info::in, string_table::in, string_table::out,
static_cell_info::in, static_cell_info::out,
proc_layouts_info::in, proc_layouts_info::out) is det.
construct_proc_layout(Params, PLI, ProcLayoutName, Kind,
InternalLabelInfos, VarNumMap, LabelLayoutInfo,
!StringTable, !StaticCellInfo, !ProcLayoutInfo) :-
PLI = proc_layout_info(RttiProcLabel, EntryLabel,
Detism, StackSlots, SuccipLoc, EvalMethod, EffTraceLevel,
MaybeCallLabel, MaxTraceReg, HeadVars, ArgModes,
Goal, NeedGoalRep, InstMap,
TraceSlotInfo, _ForceProcIdLayout, VarSet, VarTypes,
InternalMap, MaybeTableInfo, NeedsAllNames, MaybeDeepProfInfo),
construct_proc_traversal(Params, EntryLabel, Detism, StackSlots,
SuccipLoc, Traversal),
PredId = RttiProcLabel ^ rpl_pred_id,
ProcId = RttiProcLabel ^ rpl_proc_id,
PredProcId = proc(PredId, ProcId),
(
MaybeTableInfo = no,
MaybeTableSlotName = no
;
MaybeTableInfo = yes(TableInfo),
TableExecTraceInfo0 = !.ProcLayoutInfo ^ pli_exec_traces,
construct_exec_trace_table_data(PredProcId, ProcLayoutName, TableInfo,
MaybeTableSlotName, !StaticCellInfo,
TableExecTraceInfo0, TableExecTraceInfo),
!ProcLayoutInfo ^ pli_exec_traces := TableExecTraceInfo
),
(
Kind = proc_layout_traversal,
More = no_proc_id_and_more
;
Kind = proc_layout_proc_id(_),
TraceStackLayout = Params ^ slp_trace_stack_layout,
(
TraceStackLayout = yes,
not map.is_empty(InternalMap),
valid_proc_layout(PLI)
->
ExecTraceInfo0 = !.ProcLayoutInfo ^ pli_exec_traces,
construct_exec_trace_layout(Params, RttiProcLabel,
EvalMethod, EffTraceLevel, MaybeCallLabel, MaybeTableSlotName,
MaxTraceReg, HeadVars, ArgModes, TraceSlotInfo,
VarSet, VarTypes, MaybeTableInfo, NeedsAllNames,
VarNumMap, InternalLabelInfos, ExecTraceSlotName,
LabelLayoutInfo, !StringTable,
ExecTraceInfo0, ExecTraceInfo),
!ProcLayoutInfo ^ pli_exec_traces := ExecTraceInfo,
MaybeExecTraceSlotName = yes(ExecTraceSlotName)
;
MaybeExecTraceSlotName = no
),
ModuleInfo = Params ^ slp_module_info,
DeepProfiling = Params ^ slp_deep_profiling,
(
( NeedGoalRep = trace_needs_body_rep
; DeepProfiling = yes
)
->
(
DeepProfiling = yes,
IncludeVarTable = include_variable_table
;
DeepProfiling = no,
IncludeVarTable = do_not_include_variable_table
),
% When the program is compiled with deep profiling, use
% the version of the procedure saved before the deep profiling
% transformation as the program representation.
(
MaybeDeepProfInfo = yes(DeepProfInfo),
ProcStaticInfo0 = !.ProcLayoutInfo ^ pli_proc_statics,
construct_proc_static_layout(DeepProfInfo, ProcStaticSlotName,
ProcStaticInfo0, ProcStaticInfo),
!ProcLayoutInfo ^ pli_proc_statics := ProcStaticInfo,
MaybeProcStaticSlotName = yes(ProcStaticSlotName),
DeepOriginalBody = DeepProfInfo ^ pdpi_orig_body,
DeepOriginalBody = deep_original_body(BytecodeBody,
BytecodeHeadVars, BytecodeInstMap, BytecodeVarTypes,
BytecodeDetism, BytecodeVarSet),
compute_var_number_map(BytecodeHeadVars, BytecodeVarSet, [],
BytecodeBody, BytecodeVarNumMap)
;
MaybeDeepProfInfo = no,
MaybeProcStaticSlotName = no,
BytecodeHeadVars = HeadVars,
BytecodeBody = Goal,
BytecodeInstMap = InstMap,
BytecodeVarTypes = VarTypes,
BytecodeDetism = Detism,
BytecodeVarNumMap = VarNumMap
),
represent_proc_as_bytecodes(BytecodeHeadVars, BytecodeBody,
BytecodeInstMap, BytecodeVarTypes, BytecodeVarNumMap,
ModuleInfo, IncludeVarTable, BytecodeDetism, !StringTable,
ProcBytes),
% Calling find_sequence on ProcBytes is very unlikely to find
% any matching sequences, though there is no reason why we
% cannot try.
list.reverse(ProcBytes, RevProcBytes),
list.length(ProcBytes, NumProcBytes),
RevAllProcBytes0 = !.ProcLayoutInfo ^ pli_rev_proc_bytes,
RevAllProcBytes = RevProcBytes ++ RevAllProcBytes0,
!ProcLayoutInfo ^ pli_rev_proc_bytes := RevAllProcBytes,
NextProcByte0 = !.ProcLayoutInfo ^ pli_next_proc_byte,
ProcByteSlot = NextProcByte0,
NextProcByte = NumProcBytes + NextProcByte0,
!ProcLayoutInfo ^ pli_next_proc_byte := NextProcByte,
ProcBytesSlotName = layout_slot(proc_body_bytecodes_array,
ProcByteSlot),
MaybeProcBytesSlotName = yes(ProcBytesSlotName)
;
(
MaybeDeepProfInfo = yes(DeepProfInfo),
ProcStaticInfo0 = !.ProcLayoutInfo ^ pli_proc_statics,
construct_proc_static_layout(DeepProfInfo, ProcStaticSlotName,
ProcStaticInfo0, ProcStaticInfo),
!ProcLayoutInfo ^ pli_proc_statics := ProcStaticInfo,
MaybeProcStaticSlotName = yes(ProcStaticSlotName)
;
MaybeDeepProfInfo = no,
MaybeProcStaticSlotName = no
),
MaybeProcBytesSlotName = no
),
module_info_get_name(ModuleInfo, ModuleName),
ModuleCommonLayoutName = module_common_layout(ModuleName),
More = proc_id_and_more(MaybeProcStaticSlotName,
MaybeExecTraceSlotName, MaybeProcBytesSlotName,
ModuleCommonLayoutName)
),
ProcLayout = proc_layout_data(RttiProcLabel, Traversal, More),
RevProcLayouts0 = !.ProcLayoutInfo ^ pli_rev_proc_layouts,
RevProcLayouts = [ProcLayout | RevProcLayouts0],
!ProcLayoutInfo ^ pli_rev_proc_layouts := RevProcLayouts,
RevProcLayoutNames0 = !.ProcLayoutInfo ^ pli_rev_proc_layout_names,
RevProcLayoutNames = [ProcLayoutName | RevProcLayoutNames0],
!ProcLayoutInfo ^ pli_rev_proc_layout_names := RevProcLayoutNames,
LabelToLayoutMap0 = !.ProcLayoutInfo ^ pli_p_label_to_layout_map,
map.det_insert(LabelToLayoutMap0, EntryLabel, layout_id(ProcLayoutName),
LabelToLayoutMap),
!ProcLayoutInfo ^ pli_p_label_to_layout_map := LabelToLayoutMap.
:- pred construct_proc_traversal(stack_layout_params::in, label::in,
determinism::in, int::in, maybe(int)::in, proc_layout_stack_traversal::out)
is det.
construct_proc_traversal(Params, EntryLabel, Detism, NumStackSlots,
MaybeSuccipLoc, Traversal) :-
(
MaybeSuccipLoc = yes(Location),
( determinism_components(Detism, _, at_most_many) ->
SuccipLval = framevar(Location)
;
SuccipLval = stackvar(Location)
),
represent_locn_as_int(locn_direct(SuccipLval), SuccipInt),
MaybeSuccipInt = yes(SuccipInt)
;
MaybeSuccipLoc = no,
% Use a dummy location if there is no succip slot on the stack.
%
% This case can arise in two circumstances. First, procedures that
% use the nondet stack have a special slot for the succip, so the
% succip is not stored in a general purpose slot. Second, procedures
% that use the det stack but which do not call other procedures
% do not save the succip on the stack.
%
% The tracing system does not care about the location of the saved
% succip. The accurate garbage collector does. It should know from
% the determinism that the procedure uses the nondet stack, which
% takes care of the first possibility above. Procedures that do not
% call other procedures do not establish resumption points and thus
% agc is not interested in them. As far as stack dumps go, calling
% error counts as a call, so any procedure that may call error
% (directly or indirectly) will have its saved succip location
% recorded, so the stack dump will work.
%
% Future uses of stack layouts will have to have similar constraints.
MaybeSuccipInt = no
),
StaticCodeAddr = Params ^ slp_static_code_addresses,
(
StaticCodeAddr = yes,
MaybeEntryLabel = yes(EntryLabel)
;
StaticCodeAddr = no,
MaybeEntryLabel = no
),
Traversal = proc_layout_stack_traversal(MaybeEntryLabel,
MaybeSuccipInt, NumStackSlots, Detism).
:- type proc_layouts_info
---> proc_layouts_info(
pli_proc_statics :: proc_statics_info,
pli_exec_traces :: exec_traces_info,
pli_next_proc_byte :: int,
pli_rev_proc_bytes :: list(int),
% The list of proc_layouts in the module.
pli_rev_proc_layouts :: list(proc_layout_data),
pli_rev_proc_layout_names :: list(layout_name),
% This maps each proc label with a layout
% to the id of its layout structure.
pli_p_label_to_layout_map :: map(label, data_id)
).
:- func init_proc_layouts_info = proc_layouts_info.
init_proc_layouts_info = Info :-
ProcStaticInfo = init_proc_statics_info,
ExecTraceInfo = init_exec_traces_info,
Info = proc_layouts_info(ProcStaticInfo, ExecTraceInfo,
0, [], [], [], map.init).
%---------------------------------------------------------------------------%
%
% Construct proc static structures.
%
:- pred construct_proc_static_layout(proc_deep_prof_info::in,
layout_slot_name::out,
proc_statics_info::in, proc_statics_info::out) is det.
construct_proc_static_layout(DeepProfInfo, ProcStaticSlotName,
!ProcStaticInfo) :-
DeepProfInfo = proc_deep_prof_info(HLDSProcStatic, DeepExcpSlots,
_OrigBody),
HLDSProcStatic = hlds_proc_static(FileName, LineNumber, IsInInterface,
CallSites, CoveragePoints),
(
CallSites = [],
MaybeCallSitesTuple = no
;
CallSites = [_ | _],
list.reverse(CallSites, RevCallSites),
list.length(CallSites, NumCallSites),
RevAllCallSites0 = !.ProcStaticInfo ^ psi_rev_call_sites,
RevAllCallSites = RevCallSites ++ RevAllCallSites0,
!ProcStaticInfo ^ psi_rev_call_sites := RevAllCallSites,
NextCallSite0 = !.ProcStaticInfo ^ psi_next_call_site,
CallSiteSlot = NextCallSite0,
NextCallSite = NextCallSite0 + NumCallSites,
!ProcStaticInfo ^ psi_next_call_site := NextCallSite,
MaybeCallSitesTuple = yes({CallSiteSlot, NumCallSites})
),
(
CoveragePoints = [],
MaybeCoveragePointsTuple = no
;
CoveragePoints = [_ | _],
list.reverse(CoveragePoints, RevCoveragePoints),
list.length(CoveragePoints, NumCoveragePoints),
RevAllCoveragePoints0 = !.ProcStaticInfo ^ psi_rev_coverage_points,
RevAllCoveragePoints = RevCoveragePoints ++ RevAllCoveragePoints0,
!ProcStaticInfo ^ psi_rev_coverage_points := RevAllCoveragePoints,
NextCoveragePoint0 = !.ProcStaticInfo ^ psi_next_coverage_point,
CoveragePointSlot = NextCoveragePoint0,
NextCoveragePoint = NextCoveragePoint0 + NumCoveragePoints,
!ProcStaticInfo ^ psi_next_coverage_point := NextCoveragePoint,
MaybeCoveragePointsTuple = yes({CoveragePointSlot, NumCoveragePoints})
),
ProcStatic = proc_layout_proc_static(FileName, LineNumber, IsInInterface,
DeepExcpSlots, MaybeCallSitesTuple, MaybeCoveragePointsTuple),
RevProcStatics0 = !.ProcStaticInfo ^ psi_rev_proc_statics,
RevProcStatics = [ProcStatic | RevProcStatics0],
!ProcStaticInfo ^ psi_rev_proc_statics := RevProcStatics,
ProcStaticCounter0 = !.ProcStaticInfo ^ psi_next_proc_static,
counter.allocate(ProcStaticSlot, ProcStaticCounter0, ProcStaticCounter),
ProcStaticSlotName = layout_slot(proc_static_array, ProcStaticSlot),
!ProcStaticInfo ^ psi_next_proc_static := ProcStaticCounter.
%---------------------------------------------------------------------------%
:- type proc_statics_info
---> proc_statics_info(
% The arrays that hold (components of) proc static structures.
psi_next_call_site :: int,
psi_next_coverage_point :: int,
psi_next_proc_static :: counter,
psi_rev_call_sites :: list(call_site_static_data),
psi_rev_coverage_points :: list(coverage_point_info),
psi_rev_proc_statics :: list(proc_layout_proc_static)
).
:- func init_proc_statics_info = proc_statics_info.
init_proc_statics_info = Info :-
Info = proc_statics_info(0, 0, counter.init(0), [], [], []).
%---------------------------------------------------------------------------%
%
% Construct exec trace structures.
%
:- pred construct_exec_trace_layout(stack_layout_params::in,
rtti_proc_label::in, eval_method::in, trace_level::in, maybe(label)::in,
maybe(layout_slot_name)::in, int::in,
list(prog_var)::in, list(mer_mode)::in,
trace_slot_info::in, prog_varset::in, vartypes::in,
maybe(proc_layout_table_info)::in, bool::in, var_num_map::in,
list(internal_label_info)::in, layout_slot_name::out,
label_layouts_info::in,
string_table::in, string_table::out,
exec_traces_info::in, exec_traces_info::out) is det.
construct_exec_trace_layout(Params, RttiProcLabel, EvalMethod,
EffTraceLevel, MaybeCallLabel, MaybeTableSlotName, MaxTraceReg,
HeadVars, ArgModes, TraceSlotInfo, _VarSet, VarTypes, MaybeTableInfo,
NeedsAllNames, VarNumMap, InternalLabelInfos, ExecTraceName,
LabelLayoutInfo, !StringTable, !ExecTraceInfo) :-
collect_event_data_addrs(InternalLabelInfos,
[], RevInterfaceEventLayoutNames, [], RevInternalEventLayoutNames),
list.reverse(RevInterfaceEventLayoutNames, InterfaceEventLayoutNames),
list.reverse(RevInternalEventLayoutNames, InternalEventLayoutNames),
construct_var_name_vector(VarNumMap,
NeedsAllNames, MaxVarNum, VarNameVector, !StringTable),
list.map(convert_var_to_int(VarNumMap), HeadVars, HeadVarNumVector),
TraceSlotInfo = trace_slot_info(MaybeFromFullSlot, MaybeIoSeqSlot,
MaybeTrailSlots, MaybeMaxfrSlot, MaybeCallTableSlot, MaybeTailRecSlot),
ModuleInfo = Params ^ slp_module_info,
(
MaybeCallLabel = yes(CallLabel),
map.lookup(LabelLayoutInfo ^ lli_i_label_to_layout_map, CallLabel,
CallLabelSlotName),
MaybeCallLabelSlotName = yes(CallLabelSlotName)
;
MaybeCallLabel = no,
MaybeCallLabelSlotName = no
),
(
MaybeTableInfo = no,
MaybeTable = no
;
MaybeTableInfo = yes(TableInfo),
(
TableInfo = proc_table_io_decl(_),
(
MaybeTableSlotName = yes(TableSlotName),
MaybeTable = yes(data_or_slot_is_slot(TableSlotName))
;
MaybeTableSlotName = no,
unexpected(this_file,
"construct_exec_trace_layout: MaybeTableSlotName = no")
)
;
TableInfo = proc_table_struct(_),
expect(unify(MaybeTableSlotName, no), this_file,
"construct_exec_trace_layout: MaybeTableSlotName != no"),
ProcLabel = make_proc_label_from_rtti(RttiProcLabel),
TableDataId = proc_tabling_data_id(ProcLabel, tabling_info),
MaybeTable = yes(data_or_slot_is_data(TableDataId))
)
),
RevEventLayouts0 = !.ExecTraceInfo ^ eti_rev_proc_event_layouts,
ProcEventLayouts = InterfaceEventLayoutNames ++ InternalEventLayoutNames,
list.reverse(ProcEventLayouts, RevProcEventLayouts),
RevEventLayouts = RevProcEventLayouts ++ RevEventLayouts0,
!ExecTraceInfo ^ eti_rev_proc_event_layouts := RevEventLayouts,
NextEventLayout0 = !.ExecTraceInfo ^ eti_next_proc_event_layout,
EventLayoutsSlot = NextEventLayout0,
list.length(ProcEventLayouts, NumProcEventLayouts),
NextEventLayout = NextEventLayout0 + NumProcEventLayouts,
!ExecTraceInfo ^ eti_next_proc_event_layout := NextEventLayout,
EventLayoutsSlotName = layout_slot(proc_event_layouts_array,
EventLayoutsSlot),
CompressArrays = Params ^ slp_compress_arrays,
(
HeadVarNumVector = [_ | _],
RevHeadVarNums0 = !.ExecTraceInfo ^ eti_rev_proc_head_var_nums,
NextHeadVarNum0 = !.ExecTraceInfo ^ eti_next_proc_head_var_num,
list.reverse(HeadVarNumVector, RevHeadVarNumVector),
list.length(HeadVarNumVector, NumHeadVars),
(
CompressArrays = yes,
find_sequence(RevHeadVarNumVector, RevHeadVarNums0,
0, OldHeadVarNumOffset)
->
HeadVarNumSlot = NextHeadVarNum0 - OldHeadVarNumOffset - NumHeadVars
;
RevHeadVarNums = RevHeadVarNumVector ++ RevHeadVarNums0,
!ExecTraceInfo ^ eti_rev_proc_head_var_nums := RevHeadVarNums,
HeadVarNumSlot = NextHeadVarNum0,
NextHeadVarNum = NextHeadVarNum0 + NumHeadVars,
!ExecTraceInfo ^ eti_next_proc_head_var_num := NextHeadVarNum
),
HeadVarNumSlotName = layout_slot(proc_head_var_nums_array,
HeadVarNumSlot),
MaybeHeadVarsSlotName = yes(HeadVarNumSlotName)
;
HeadVarNumVector = [],
MaybeHeadVarsSlotName = no,
NumHeadVars = 0
),
(
VarNameVector = [_ | _],
RevVarNames0 = !.ExecTraceInfo ^ eti_rev_proc_var_names,
NextVarName0 = !.ExecTraceInfo ^ eti_next_proc_var_name,
list.reverse(VarNameVector, RevVarNameVector),
list.length(VarNameVector, NumVarNames),
(
CompressArrays = yes,
find_sequence(RevVarNameVector, RevVarNames0, 0, OldVarNameOffset)
->
VarNameSlot = NextVarName0 - OldVarNameOffset - NumVarNames
;
RevVarNames = RevVarNameVector ++ RevVarNames0,
!ExecTraceInfo ^ eti_rev_proc_var_names := RevVarNames,
VarNameSlot = NextVarName0,
NextVarName = NextVarName0 + NumVarNames,
!ExecTraceInfo ^ eti_next_proc_var_name := NextVarName
),
VarNameSlotName = layout_slot(proc_var_names_array, VarNameSlot),
MaybeVarNamesSlotName = yes(VarNameSlotName)
;
VarNameVector = [],
MaybeVarNamesSlotName = no
),
encode_exec_trace_flags(ModuleInfo, HeadVars, ArgModes, VarTypes,
0, Flags),
ExecTrace = proc_layout_exec_trace(MaybeCallLabelSlotName,
EventLayoutsSlotName, NumProcEventLayouts, MaybeTable,
MaybeHeadVarsSlotName, NumHeadVars, MaybeVarNamesSlotName,
MaxVarNum, MaxTraceReg, MaybeFromFullSlot, MaybeIoSeqSlot,
MaybeTrailSlots, MaybeMaxfrSlot, EvalMethod,
MaybeCallTableSlot, MaybeTailRecSlot, EffTraceLevel, Flags),
RevExecTraces0 = !.ExecTraceInfo ^ eti_rev_exec_traces,
RevExecTraces = [ExecTrace | RevExecTraces0],
!ExecTraceInfo ^ eti_rev_exec_traces := RevExecTraces,
ExecTraceCounter0 = !.ExecTraceInfo ^ eti_next_exec_trace,
counter.allocate(ExecTraceSlot, ExecTraceCounter0, ExecTraceCounter),
ExecTraceName = layout_slot(proc_exec_trace_array, ExecTraceSlot),
!ExecTraceInfo ^ eti_next_exec_trace := ExecTraceCounter.
%---------------------------------------------------------------------------%
:- pred construct_exec_trace_table_data(pred_proc_id::in, layout_name::in,
proc_layout_table_info::in, maybe(layout_slot_name)::out,
static_cell_info::in, static_cell_info::out,
exec_traces_info::in, exec_traces_info::out) is det.
construct_exec_trace_table_data(PredProcId, ProcLayoutName, TableInfo,
MaybeTableSlotName, !StaticCellInfo, !ExecTraceInfo) :-
(
TableInfo = proc_table_io_decl(TableIOInfo),
TableIOInfo = proc_table_io_info(TableArgInfos),
convert_table_arg_info(TableArgInfos, NumPTIs, PTIVectorRval,
TVarVectorRval, !StaticCellInfo),
TableIoDeclData = table_io_decl_data(ProcLayoutName,
NumPTIs, PTIVectorRval, TVarVectorRval),
RevTableIoDeclDatas0 = !.ExecTraceInfo ^ eti_rev_table_io_decl_datas,
RevTableIoDeclDatas = [TableIoDeclData | RevTableIoDeclDatas0],
!ExecTraceInfo ^ eti_rev_table_io_decl_datas := RevTableIoDeclDatas,
TableDataCounter0 = !.ExecTraceInfo ^ eti_next_table_io_decl_data,
counter.allocate(Slot, TableDataCounter0, TableDataCounter),
!ExecTraceInfo ^ eti_next_table_io_decl_data := TableDataCounter,
TableDataSlotName = layout_slot(proc_table_io_decl_array, Slot),
MaybeTableSlotName = yes(TableDataSlotName),
TableIoDeclMap0 = !.ExecTraceInfo ^ eti_table_io_decl_map,
map.det_insert(TableIoDeclMap0, PredProcId, TableDataSlotName,
TableIoDeclMap),
!ExecTraceInfo ^ eti_table_io_decl_map := TableIoDeclMap
;
TableInfo = proc_table_struct(_TableStructInfo),
% This structure is generated by add_tabling_info_struct in proc_gen.m.
MaybeTableSlotName = no
).
convert_table_arg_info(TableArgInfos, NumPTIs,
PTIVectorRval, TVarVectorRval, !StaticCellInfo) :-
TableArgInfos = table_arg_infos(Args, TVarSlotMap),
list.length(Args, NumPTIs),
list.map_foldl(construct_table_arg_pti_rval, Args, PTIRvalsTypes,
!StaticCellInfo),
add_scalar_static_cell(PTIRvalsTypes, PTIVectorAddr, !StaticCellInfo),
PTIVectorRval = const(llconst_data_addr(PTIVectorAddr, no)),
map.map_values_only(convert_slot_to_locn_map, TVarSlotMap, TVarLocnMap),
construct_tvar_vector(TVarLocnMap, TVarVectorRval, !StaticCellInfo).
:- pred convert_slot_to_locn_map(table_locn::in, set(layout_locn)::out) is det.
convert_slot_to_locn_map(SlotLocn, LvalLocns) :-
(
SlotLocn = table_locn_direct(SlotNum),
LvalLocn = locn_direct(reg(reg_r, SlotNum))
;
SlotLocn = table_locn_indirect(SlotNum, Offset),
LvalLocn = locn_indirect(reg(reg_r, SlotNum), Offset)
),
LvalLocns = set.make_singleton_set(LvalLocn).
:- pred construct_table_arg_pti_rval(
table_arg_info::in, pair(rval, llds_type)::out,
static_cell_info::in, static_cell_info::out) is det.
construct_table_arg_pti_rval(ClosureArg, ArgRval - ArgRvalType,
!StaticCellInfo) :-
ClosureArg = table_arg_info(_, _, _, Type),
ExistQTvars = [],
NumUnivQTvars = -1,
ll_pseudo_type_info.construct_typed_llds_pseudo_type_info(Type,
NumUnivQTvars, ExistQTvars, !StaticCellInfo, ArgRval, ArgRvalType).
%---------------------------------------------------------------------------%
:- pred collect_event_data_addrs(list(internal_label_info)::in,
list(layout_slot_name)::in, list(layout_slot_name)::out,
list(layout_slot_name)::in, list(layout_slot_name)::out) is det.
collect_event_data_addrs([], !RevInterfaces, !RevInternals).
collect_event_data_addrs([Info | Infos], !RevInterfaces, !RevInternals) :-
Info = internal_label_info(_ProcLabel, _LabelNum, LabelVars, Slot,
InternalInfo),
InternalInfo = internal_layout_info(MaybePortInfo, _, _),
(
MaybePortInfo = no
;
MaybePortInfo = yes(PortInfo),
Port = PortInfo ^ port_type,
(
( Port = port_call
; Port = port_exit
; Port = port_redo
; Port = port_fail
; Port = port_tailrec_call
),
LayoutName = layout_slot(label_layout_array(LabelVars), Slot),
!:RevInterfaces = [LayoutName | !.RevInterfaces]
;
( Port = port_ite_cond
; Port = port_ite_then
; Port = port_ite_else
; Port = port_neg_enter
; Port = port_neg_success
; Port = port_neg_failure
; Port = port_disj_first
; Port = port_disj_later
; Port = port_switch
; Port = port_nondet_foreign_proc_first
; Port = port_nondet_foreign_proc_later
; Port = port_user
),
LayoutName = layout_slot(label_layout_array(LabelVars), Slot),
!:RevInternals = [LayoutName | !.RevInternals]
;
Port = port_exception
% This port is attached to call sites, so there is no event here.
)
),
collect_event_data_addrs(Infos, !RevInterfaces, !RevInternals).
%---------------------------------------------------------------------------%
:- pred encode_exec_trace_flags(module_info::in, list(prog_var)::in,
list(mer_mode)::in, vartypes::in, int::in, int::out) is det.
encode_exec_trace_flags(ModuleInfo, HeadVars, ArgModes, VarTypes, !Flags) :-
(
proc_info_has_io_state_pair_from_details(ModuleInfo, HeadVars,
ArgModes, VarTypes, _, _)
->
!:Flags = !.Flags + 1
;
true
).
%---------------------------------------------------------------------------%
:- pred construct_var_name_vector(var_num_map::in,
bool::in, int::out, list(int)::out,
string_table::in, string_table::out) is det.
construct_var_name_vector(VarNumMap, NeedsAllNames, MaxVarNum, Offsets,
!StringTable) :-
map.values(VarNumMap, VarNames0),
(
NeedsAllNames = yes,
VarNames = VarNames0
;
NeedsAllNames = no,
list.filter(var_has_name, VarNames0, VarNames)
),
list.sort(VarNames, SortedVarNames),
( SortedVarNames = [FirstVarNum - _ | _] ->
MaxVarNum0 = FirstVarNum,
construct_var_name_rvals(SortedVarNames, 1, MaxVarNum0, MaxVarNum,
Offsets, !StringTable)
;
% Since variable numbers start at 1, MaxVarNum = 0 implies
% an empty array.
MaxVarNum = 0,
Offsets = []
).
:- pred var_has_name(pair(int, string)::in) is semidet.
var_has_name(_VarNum - VarName) :-
VarName \= "".
:- pred construct_var_name_rvals(assoc_list(int, string)::in,
int::in, int::in, int::out, list(int)::out,
string_table::in, string_table::out) is det.
construct_var_name_rvals([], _CurNum, MaxNum, MaxNum, [], !StringTable).
construct_var_name_rvals([Var - Name | VarNamesTail], CurNum,
!MaxNum, [Offset | OffsetsTail], !StringTable) :-
( Var = CurNum ->
lookup_string_in_table(Name, Offset, !StringTable),
!:MaxNum = Var,
VarNames = VarNamesTail
;
Offset = 0,
VarNames = [Var - Name | VarNamesTail]
),
construct_var_name_rvals(VarNames, CurNum + 1,
!MaxNum, OffsetsTail, !StringTable).
%---------------------------------------------------------------------------%
compute_var_number_map(HeadVars, VarSet, Internals, Goal, VarNumMap) :-
some [!VarNumMap, !Counter] (
!:VarNumMap = map.init,
!:Counter = counter.init(1), % to match term.var_supply_init
goal_util.goal_vars(Goal, GoalVarSet),
set.to_sorted_list(GoalVarSet, GoalVars),
list.foldl2(add_var_to_var_number_map(VarSet), GoalVars,
!VarNumMap, !Counter),
list.foldl2(add_var_to_var_number_map(VarSet), HeadVars,
!VarNumMap, !Counter),
list.foldl2(internal_var_number_map(VarSet), Internals, !VarNumMap,
!.Counter, _),
VarNumMap = !.VarNumMap
).
:- pred internal_var_number_map(prog_varset::in,
pair(int, internal_layout_info)::in,
var_num_map::in, var_num_map::out, counter::in, counter::out) is det.
internal_var_number_map(VarSet, _Label - Internal, !VarNumMap, !Counter) :-
Internal = internal_layout_info(MaybeTrace, MaybeResume, MaybeReturn),
(
MaybeTrace = yes(Trace),
Trace = trace_port_layout_info(_, _, _, _, MaybeUser, TraceLayout),
label_layout_var_number_map(TraceLayout, !VarNumMap, !Counter),
(
MaybeUser = no
;
MaybeUser = yes(UserEvent),
UserEvent = user_event_info(_UserEventNumber, Attributes),
list.foldl2(user_attribute_var_num_map(VarSet), Attributes,
!VarNumMap, !Counter)
)
;
MaybeTrace = no
),
(
MaybeResume = yes(ResumeLayout),
label_layout_var_number_map(ResumeLayout, !VarNumMap, !Counter)
;
MaybeResume = no
),
(
MaybeReturn = yes(Return),
Return = return_layout_info(_, ReturnLayout),
label_layout_var_number_map(ReturnLayout, !VarNumMap, !Counter)
;
MaybeReturn = no
).
:- pred label_layout_var_number_map(layout_label_info::in,
var_num_map::in, var_num_map::out, counter::in, counter::out) is det.
label_layout_var_number_map(LabelLayout, !VarNumMap, !Counter) :-
LabelLayout = layout_label_info(VarInfoSet, _),
VarInfos = set.to_sorted_list(VarInfoSet),
FindVar = (pred(VarInfo::in, Var - Name::out) is semidet :-
VarInfo = layout_var_info(_, LiveValueType, _),
LiveValueType = live_value_var(Var, Name, _, _)
),
list.filter_map(FindVar, VarInfos, VarsNames),
list.foldl2(add_named_var_to_var_number_map, VarsNames,
!VarNumMap, !Counter).
:- pred user_attribute_var_num_map(prog_varset::in, maybe(user_attribute)::in,
var_num_map::in, var_num_map::out, counter::in, counter::out) is det.
user_attribute_var_num_map(VarSet, MaybeAttribute, !VarNumMap, !Counter) :-
(
MaybeAttribute = yes(Attribute),
Attribute = user_attribute(_Locn, Var),
add_var_to_var_number_map(VarSet, Var, !VarNumMap, !Counter)
;
MaybeAttribute = no
).
:- pred add_var_to_var_number_map(prog_varset::in, prog_var::in,
var_num_map::in, var_num_map::out, counter::in, counter::out) is det.
add_var_to_var_number_map(VarSet, Var, !VarNumMap, !Counter) :-
( varset.search_name(VarSet, Var, VarName) ->
Name = VarName
;
Name = ""
),
add_named_var_to_var_number_map(Var - Name, !VarNumMap, !Counter).
:- pred add_named_var_to_var_number_map(pair(prog_var, string)::in,
var_num_map::in, var_num_map::out, counter::in, counter::out) is det.
add_named_var_to_var_number_map(Var - Name, !VarNumMap, !Counter) :-
( map.search(!.VarNumMap, Var, _) ->
% Name shouldn't differ from the name recorded in !.VarNumMap.
true
;
counter.allocate(VarNum, !Counter),
map.det_insert(!.VarNumMap, Var, VarNum - Name, !:VarNumMap)
).
%---------------------------------------------------------------------------%
:- type exec_traces_info
---> exec_traces_info(
% The arrays that hold (components of) exec trace structures.
eti_next_proc_head_var_num :: int,
eti_next_proc_var_name :: int,
eti_next_proc_event_layout :: int,
eti_next_table_io_decl_data :: counter,
eti_next_exec_trace :: counter,
eti_rev_proc_head_var_nums :: list(int),
eti_rev_proc_var_names :: list(int),
eti_rev_proc_event_layouts :: list(layout_slot_name),
eti_rev_table_io_decl_datas :: list(table_io_decl_data),
eti_rev_exec_traces :: list(proc_layout_exec_trace),
eti_table_io_decl_map :: map(pred_proc_id,
layout_slot_name)
).
:- func init_exec_traces_info = exec_traces_info.
init_exec_traces_info = Info :-
Info = exec_traces_info(0, 0, 0, counter.init(0), counter.init(0),
[], [], [], [], [], map.init).
%---------------------------------------------------------------------------%
%
% Construct label layout structures.
%
% Construct the layout describing a single internal label
% for accurate GC and/or execution tracing.
%
:- pred construct_internal_layout(stack_layout_params::in,
proc_label::in, layout_name::in, var_num_map::in,
pair(int, internal_layout_info)::in, internal_label_info::out,
string_table::in, string_table::out,
static_cell_info::in, static_cell_info::out,
label_layouts_info::in, label_layouts_info::out) is det.
construct_internal_layout(Params, ProcLabel, ProcLayoutName, VarNumMap,
LabelNum - Internal, LabelLayout,
!StringTable, !StaticCellInfo, !LabelLayoutInfo) :-
Internal = internal_layout_info(Trace, Resume, Return),
(
Trace = no,
set.init(TraceLiveVarSet),
map.init(TraceTypeVarMap),
MaybeUserInfo = no
;
Trace = yes(trace_port_layout_info(_,_,_,_, MaybeUserInfo,
TraceLayout)),
TraceLayout = layout_label_info(TraceLiveVarSet, TraceTypeVarMap)
),
(
Resume = no,
set.init(ResumeLiveVarSet),
map.init(ResumeTypeVarMap)
;
Resume = yes(ResumeLayout),
ResumeLayout = layout_label_info(ResumeLiveVarSet, ResumeTypeVarMap)
),
(
Trace = yes(trace_port_layout_info(_, Port, IsHidden, GoalPath, _, _)),
Return = no,
MaybePort = yes(Port),
MaybeIsHidden = yes(IsHidden),
GoalPathStr = goal_path_to_string(GoalPath),
lookup_string_in_table(GoalPathStr, GoalPathNum, !StringTable),
MaybeGoalPath = yes(GoalPathNum)
;
Trace = no,
Return = yes(ReturnInfo),
% We only ever use the port fields of these layout structures
% when we process exception events. (Since exception events are
% interface events, the goal path field is not meaningful then.)
MaybePort = yes(port_exception),
MaybeIsHidden = yes(no),
% We only ever use the goal path fields of these layout structures
% when we process "fail" commands in the debugger.
ReturnInfo = return_layout_info(TargetsContexts, _),
( find_valid_return_context(TargetsContexts, _, _, GoalPath) ->
GoalPathStr = goal_path_to_string(GoalPath),
lookup_string_in_table(GoalPathStr, GoalPathNum, !StringTable),
MaybeGoalPath = yes(GoalPathNum)
;
% If tracing is enabled, then exactly one of the calls for which
% this label is a return site would have had a valid context.
% If none do, then tracing is not enabled, and therefore the goal
% path of this label will not be accessed.
MaybeGoalPath = no
)
;
Trace = no,
Return = no,
MaybePort = no,
MaybeIsHidden = no,
MaybeGoalPath = no
;
Trace = yes(_),
Return = yes(_),
unexpected(this_file, "label has both trace and return layout info")
),
AgcStackLayout = Params ^ slp_agc_stack_layout,
(
Return = no,
set.init(ReturnLiveVarSet),
map.init(ReturnTypeVarMap)
;
Return = yes(return_layout_info(_, ReturnLayout)),
ReturnLayout = layout_label_info(ReturnLiveVarSet0, ReturnTypeVarMap0),
(
AgcStackLayout = yes,
ReturnLiveVarSet = ReturnLiveVarSet0,
ReturnTypeVarMap = ReturnTypeVarMap0
;
AgcStackLayout = no,
% This set of variables must be for uplevel printing in execution
% tracing, so we are interested only in (a) variables, not
% temporaries, (b) only named variables, and (c) only those
% on the stack, not the return values.
set.to_sorted_list(ReturnLiveVarSet0, ReturnLiveVarList0),
select_trace_return(
ReturnLiveVarList0, ReturnTypeVarMap0,
ReturnLiveVarList, ReturnTypeVarMap),
set.list_to_set(ReturnLiveVarList, ReturnLiveVarSet)
)
),
(
Trace = no,
Resume = no,
Return = no
->
MaybeVarInfo = no_var_info
;
% XXX Ignore differences in insts inside layout_var_infos.
set.union(TraceLiveVarSet, ResumeLiveVarSet, LiveVarSet0),
set.union(LiveVarSet0, ReturnLiveVarSet, LiveVarSet),
map.union(set.intersect, TraceTypeVarMap, ResumeTypeVarMap,
TypeVarMap0),
map.union(set.intersect, TypeVarMap0, ReturnTypeVarMap, TypeVarMap),
construct_label_var_info(Params, LiveVarSet, VarNumMap, TypeVarMap,
MaybeVarInfo, !StaticCellInfo, !LabelLayoutInfo)
),
(
MaybeUserInfo = no,
MaybeUserDataSlot = no
;
MaybeUserInfo = yes(UserInfo),
UserInfo = user_event_info(UserEventNumber, Attributes),
construct_user_data_array(Params, VarNumMap, Attributes,
UserLocnsArray, UserAttrMaybeVarNums, !StaticCellInfo),
add_scalar_static_cell(UserLocnsArray, UserLocnsDataAddr,
!StaticCellInfo),
UserLocnsRval = const(llconst_data_addr(UserLocnsDataAddr, no)),
list.length(UserAttrMaybeVarNums, NumVarNums),
VarNumSlotNum0 = !.LabelLayoutInfo ^ lli_next_user_event_var_num,
VarNumSlotNum = VarNumSlotNum0 + NumVarNums,
!LabelLayoutInfo ^ lli_next_user_event_var_num := VarNumSlotNum,
UserAttrVarNumsSlot = layout_slot(user_event_var_nums_array,
VarNumSlotNum0),
VarNums0 = !.LabelLayoutInfo ^ lli_user_event_var_nums,
VarNums = VarNums0 ++ cord.from_list(UserAttrMaybeVarNums),
!LabelLayoutInfo ^ lli_user_event_var_nums := VarNums,
UserEventCounter0 = !.LabelLayoutInfo ^ lli_next_user_event,
counter.allocate(UserEventSlotNum,
UserEventCounter0, UserEventCounter),
!LabelLayoutInfo ^ lli_next_user_event := UserEventCounter,
UserEventSlot = layout_slot(user_event_layout_array, UserEventSlotNum),
UserData = user_event_data(UserEventNumber, UserLocnsRval,
UserAttrVarNumsSlot),
UserEvents0 = !.LabelLayoutInfo ^ lli_user_events,
UserEvents = UserEvents0 ++ cord.singleton(UserData),
!LabelLayoutInfo ^ lli_user_events := UserEvents,
MaybeUserDataSlot = yes(UserEventSlot)
),
(
Trace = yes(_),
LabelNumCounter0 = !.LabelLayoutInfo ^ lli_label_counter,
counter.allocate(LabelNumber0, LabelNumCounter0, LabelNumCounter),
!LabelLayoutInfo ^ lli_label_counter := LabelNumCounter,
% MR_ml_label_exec_count[0] is never written out; it is reserved for
% cases like this, for labels without events, and for handwritten
% labels.
( LabelNumber0 < (1 << 16) ->
LabelNumber = LabelNumber0
;
LabelNumber = 0
)
;
Trace = no,
LabelNumber = 0
),
Label = internal_label(LabelNum, ProcLabel),
BasicLayout = basic_label_layout(ProcLabel, LabelNum, ProcLayoutName,
MaybePort, MaybeIsHidden, LabelNumber, MaybeGoalPath,
MaybeUserDataSlot),
(
MaybeVarInfo = no_var_info,
LabelVars = label_has_no_var_info,
NoVarsLayout = label_layout_no_vars(BasicLayout),
add_no_vars_internal_layout_data(Label, NoVarsLayout, Slot,
!LabelLayoutInfo)
;
MaybeVarInfo = short_var_info(SLayoutVarInfo),
LabelVars = label_has_short_var_info,
SVarsLayout = label_layout_short_vars(BasicLayout, SLayoutVarInfo),
add_short_vars_internal_layout_data(Label, SVarsLayout, Slot,
!LabelLayoutInfo)
;
MaybeVarInfo = long_var_info(LLayoutVarInfo),
LabelVars = label_has_long_var_info,
LVarsLayout = label_layout_long_vars(BasicLayout, LLayoutVarInfo),
add_long_vars_internal_layout_data(Label, LVarsLayout, Slot,
!LabelLayoutInfo)
),
LabelLayout = internal_label_info(ProcLabel, LabelNum, LabelVars, Slot,
Internal).
:- pred add_no_vars_internal_layout_data(label::in, label_layout_no_vars::in,
int::out, label_layouts_info::in, label_layouts_info::out) is det.
add_no_vars_internal_layout_data(Label, Layout, Slot, !LLI) :-
RevLayouts0 = !.LLI ^ lli_rev_no_var_label_layouts,
RevLayouts = [Layout | RevLayouts0],
Counter0 = !.LLI ^ lli_next_no_var_label_layout,
counter.allocate(Slot, Counter0, Counter),
LayoutName = layout_slot(label_layout_array(label_has_no_var_info), Slot),
LabelToLayoutMap0 = !.LLI ^ lli_i_label_to_layout_map,
map.det_insert(LabelToLayoutMap0, Label, LayoutName, LabelToLayoutMap),
!LLI ^ lli_rev_no_var_label_layouts := RevLayouts,
!LLI ^ lli_next_no_var_label_layout := Counter,
!LLI ^ lli_i_label_to_layout_map := LabelToLayoutMap.
:- pred add_short_vars_internal_layout_data(label::in,
label_layout_short_vars::in, int::out,
label_layouts_info::in, label_layouts_info::out) is det.
add_short_vars_internal_layout_data(Label, Layout, Slot, !LLI) :-
RevLayouts0 = !.LLI ^ lli_rev_svar_label_layouts,
RevLayouts = [Layout | RevLayouts0],
Counter0 = !.LLI ^ lli_next_svar_label_layout,
counter.allocate(Slot, Counter0, Counter),
LayoutArray = label_layout_array(label_has_short_var_info),
LayoutName = layout_slot(LayoutArray, Slot),
LabelToLayoutMap0 = !.LLI ^ lli_i_label_to_layout_map,
map.det_insert(LabelToLayoutMap0, Label, LayoutName, LabelToLayoutMap),
!LLI ^ lli_rev_svar_label_layouts := RevLayouts,
!LLI ^ lli_next_svar_label_layout := Counter,
!LLI ^ lli_i_label_to_layout_map := LabelToLayoutMap.
:- pred add_long_vars_internal_layout_data(label::in,
label_layout_long_vars::in, int::out,
label_layouts_info::in, label_layouts_info::out) is det.
add_long_vars_internal_layout_data(Label, Layout, Slot, !LLI) :-
RevLayouts0 = !.LLI ^ lli_rev_lvar_label_layouts,
RevLayouts = [Layout | RevLayouts0],
Counter0 = !.LLI ^ lli_next_lvar_label_layout,
counter.allocate(Slot, Counter0, Counter),
LayoutArray = label_layout_array(label_has_long_var_info),
LayoutName = layout_slot(LayoutArray, Slot),
LabelToLayoutMap0 = !.LLI ^ lli_i_label_to_layout_map,
map.det_insert(LabelToLayoutMap0, Label, LayoutName, LabelToLayoutMap),
!LLI ^ lli_rev_lvar_label_layouts := RevLayouts,
!LLI ^ lli_next_lvar_label_layout := Counter,
!LLI ^ lli_i_label_to_layout_map := LabelToLayoutMap.
:- pred construct_user_data_array(stack_layout_params::in, var_num_map::in,
list(maybe(user_attribute))::in,
assoc_list(rval, llds_type)::out, list(maybe(int))::out,
static_cell_info::in, static_cell_info::out) is det.
construct_user_data_array(_, _, [], [], [], !Info).
construct_user_data_array(Params, VarNumMap, [MaybeAttr | MaybeAttrs],
[LocnRvalAndType | LocnRvalAndTypes], [MaybeVarNum | MaybeVarNums],
!StaticCellInfo) :-
(
MaybeAttr = yes(Attr),
Attr = user_attribute(Locn, Var),
represent_locn_or_const_as_int_rval(Params, Locn, LocnRval,
LocnRvalType, !StaticCellInfo),
LocnRvalAndType = LocnRval - LocnRvalType,
convert_var_to_int(VarNumMap, Var, VarNum),
MaybeVarNum = yes(VarNum)
;
MaybeAttr = no,
LocnRvalAndType = const(llconst_int(0)) - lt_unsigned,
MaybeVarNum = no
),
construct_user_data_array(Params, VarNumMap, MaybeAttrs,
LocnRvalAndTypes, MaybeVarNums, !StaticCellInfo).
%---------------------------------------------------------------------------%
% Given a list of layout_var_infos and the type variables that occur
% in them, select only the layout_var_infos that may be required
% by up-level printing in the trace-based debugger. At the moment
% the typeinfo list we return may be bigger than necessary, but this
% does not compromise correctness; we do this to avoid having to
% scan the types of all the selected layout_var_infos.
%
:- pred select_trace_return(
list(layout_var_info)::in, map(tvar, set(layout_locn))::in,
list(layout_var_info)::out, map(tvar, set(layout_locn))::out) is det.
select_trace_return(Infos, TVars, TraceReturnInfos, TVars) :-
IsNamedReturnVar = (pred(LocnInfo::in) is semidet :-
LocnInfo = layout_var_info(Locn, LvalType, _),
LvalType = live_value_var(_, Name, _, _),
Name \= "",
( Locn = locn_direct(Lval) ; Locn = locn_indirect(Lval, _)),
( Lval = stackvar(_) ; Lval = framevar(_) )
),
list.filter(IsNamedReturnVar, Infos, TraceReturnInfos).
% Given a list of layout_var_infos, put the ones that tracing can be
% interested in (whether at an internal port or for uplevel printing)
% in a block at the start, and both this block and the remaining
% block. The division into two blocks can make the job of the
% debugger somewhat easier, the sorting of the named var block makes
% the output of the debugger look nicer, and the sorting of the both
% blocks makes it more likely that different labels' layout structures
% will have common parts (e.g. name vectors).
%
:- pred sort_livevals(list(layout_var_info)::in, list(layout_var_info)::out)
is det.
sort_livevals(OrigInfos, FinalInfos) :-
IsNamedVar = (pred(LvalInfo::in) is semidet :-
LvalInfo = layout_var_info(_Lval, LvalType, _),
LvalType = live_value_var(_, Name, _, _),
Name \= ""
),
list.filter(IsNamedVar, OrigInfos, NamedVarInfos0, OtherInfos0),
CompareVarInfos = (pred(Var1::in, Var2::in, Result::out) is det :-
Var1 = layout_var_info(Lval1, LiveType1, _),
Var2 = layout_var_info(Lval2, LiveType2, _),
get_name_from_live_value_type(LiveType1, Name1),
get_name_from_live_value_type(LiveType2, Name2),
compare(NameResult, Name1, Name2),
(
NameResult = (=),
compare(Result, Lval1, Lval2)
;
( NameResult = (<)
; NameResult = (>)
),
Result = NameResult
)
),
list.sort(CompareVarInfos, NamedVarInfos0, NamedVarInfos),
list.sort(CompareVarInfos, OtherInfos0, OtherInfos),
FinalInfos = NamedVarInfos ++ OtherInfos.
:- pred get_name_from_live_value_type(live_value_type::in,
string::out) is det.
get_name_from_live_value_type(LiveType, Name) :-
( LiveType = live_value_var(_, NamePrime, _, _) ->
Name = NamePrime
;
Name = ""
).
%---------------------------------------------------------------------------%
% Given a association list of type variables and their locations
% sorted on the type variables, represent them in an array of
% location descriptions indexed by the type variable. The next
% slot to fill is given by the second argument.
%
:- pred construct_type_param_locn_vector(
assoc_list(tvar, set(layout_locn))::in,
int::in, assoc_list(rval, llds_type)::out) is det.
construct_type_param_locn_vector([], _, []).
construct_type_param_locn_vector([TVar - Locns | TVarLocns], CurSlot,
Vector) :-
term.var_to_int(TVar, TVarNum),
NextSlot = CurSlot + 1,
( TVarNum = CurSlot ->
( set.remove_least(Locns, LeastLocn, _) ->
Locn = LeastLocn
;
unexpected(this_file, "tvar has empty set of locations")
),
represent_locn_as_int_rval(Locn, Rval),
construct_type_param_locn_vector(TVarLocns, NextSlot, VectorTail),
Vector = [Rval - lt_unsigned | VectorTail]
; TVarNum > CurSlot ->
construct_type_param_locn_vector([TVar - Locns | TVarLocns], NextSlot,
VectorTail),
% This slot will never be referred to.
Vector = [const(llconst_int(0)) - lt_unsigned | VectorTail]
;
unexpected(this_file,
"unsorted tvars in construct_type_param_locn_vector")
).
%---------------------------------------------------------------------------%
:- type liveval_array_slot
---> liveval_array_slot(
% This rval is the pseudo_type_info for the type of the
% live value.
lai_type :: rval,
% This is the variable number of a live value. Contains zero
% if the live value is not a variable, and contains the
% hightest possible uint_least16 value if the variable number
% does not fit in 16 bits.
lai_hlds_var_num :: int,
% This describes the location of the live value as either
% a MR_LongLval or MR_ShortLval.
lai_locn_desc :: int
).
:- func project_array_slot_pti(liveval_array_slot) = rval.
project_array_slot_pti(liveval_array_slot(PTI, _, _)) = PTI.
:- func project_array_slot_hlds_var_num(liveval_array_slot) = int.
project_array_slot_hlds_var_num(liveval_array_slot(_, VarNum, _)) = VarNum.
:- func project_array_slot_locn(liveval_array_slot) = int.
project_array_slot_locn(liveval_array_slot(_, _, Locn)) = Locn.
%---------------------------------------------------------------------------%
:- type maybe_var_info
---> no_var_info
; short_var_info(label_short_var_info)
; long_var_info(label_long_var_info).
:- pred construct_label_var_info(stack_layout_params::in,
set(layout_var_info)::in, var_num_map::in, map(tvar, set(layout_locn))::in,
maybe_var_info::out, static_cell_info::in, static_cell_info::out,
label_layouts_info::in, label_layouts_info::out) is det.
construct_label_var_info(Params, VarInfoSet, VarNumMap, TVarLocnMap,
MaybeVarInfo, !StaticCellInfo, !LabelLayoutInfo) :-
construct_tvar_vector(TVarLocnMap, TypeParamsRval, !StaticCellInfo),
set.to_sorted_list(VarInfoSet, VarInfos0),
sort_livevals(VarInfos0, VarInfos),
int.pow(2, short_count_bits, BytesLimit),
ModuleInfo = Params ^ slp_module_info,
construct_liveval_array_slots(VarInfos, ModuleInfo, VarNumMap,
0, BytesLimit, LongArrayInfos, ShortArrayInfos, !StaticCellInfo),
AllArrayInfos = LongArrayInfos ++ ShortArrayInfos,
PTIs = list.map(project_array_slot_pti, AllArrayInfos),
HLDSVarNums = list.map(project_array_slot_hlds_var_num, AllArrayInfos),
ShortLocns = list.map(project_array_slot_locn, ShortArrayInfos),
LongLocns = list.map(project_array_slot_locn, LongArrayInfos),
list.length(PTIs, NumPTIs),
list.length(HLDSVarNums, NumHLDSVarNums),
list.length(ShortLocns, NumShortLocns),
list.length(LongLocns, NumLongLocns),
expect(unify(NumPTIs, NumHLDSVarNums), this_file,
"construct_liveval_arrays: NumPTIs != NumHLDSVarNums"),
expect(unify(NumPTIs, NumLongLocns + NumShortLocns), this_file,
"construct_liveval_arrays: NumPTIs != NumLongLocns + NumShortLocns"),
EncodedLength = NumLongLocns << short_count_bits + NumShortLocns,
% XXX As an optimization, instead of always adding PTIs, HLDSVarNums,
% ShortLocns and LongLocns to their respective arrays, we could see
% whether those arrays already contain the required sequences.
CompressArrays = Params ^ slp_compress_arrays,
( NumPTIs > 0 ->
AllRevPTIs0 = !.LabelLayoutInfo ^ lli_rev_ptis,
NextPTISlot0 = !.LabelLayoutInfo ^ lli_next_pti,
list.reverse(PTIs, RevPTIs),
(
CompressArrays = yes,
find_sequence(RevPTIs, AllRevPTIs0, 0, OldPTIOffset)
->
PTISlot = NextPTISlot0 - OldPTIOffset - NumPTIs
;
AllRevPTIs = RevPTIs ++ AllRevPTIs0,
!LabelLayoutInfo ^ lli_rev_ptis := AllRevPTIs,
PTISlot = NextPTISlot0,
NextPTISlot = NextPTISlot0 + NumPTIs,
!LabelLayoutInfo ^ lli_next_pti := NextPTISlot
)
;
PTISlot = -1
),
% The garbage collector does not need HLDS variable numbers; only the
% debugger does.
(
NumHLDSVarNums > 0,
Params ^ slp_trace_stack_layout = yes
->
AllRevHLDSVarNums0 = !.LabelLayoutInfo ^ lli_rev_hlds_var_nums,
NextHLDSVarNumSlot0 = !.LabelLayoutInfo ^ lli_next_hlds_var_num,
list.reverse(HLDSVarNums, RevHLDSVarNums),
(
CompressArrays = yes,
find_sequence(RevHLDSVarNums, AllRevHLDSVarNums0,
0, OldHLDSVarNumsOffset)
->
HLDSVarNumSlot = NextHLDSVarNumSlot0 - OldHLDSVarNumsOffset -
NumHLDSVarNums
;
AllRevHLDSVarNums = RevHLDSVarNums ++ AllRevHLDSVarNums0,
!LabelLayoutInfo ^ lli_rev_hlds_var_nums := AllRevHLDSVarNums,
HLDSVarNumSlot = NextHLDSVarNumSlot0,
NextHLDSVarNumSlot = NextHLDSVarNumSlot0 + NumHLDSVarNums,
!LabelLayoutInfo ^ lli_next_hlds_var_num := NextHLDSVarNumSlot
)
;
HLDSVarNumSlot = -1
),
( NumShortLocns > 0 ->
AllRevShortLocns0 = !.LabelLayoutInfo ^ lli_rev_short_locns,
NextShortLocnSlot0 = !.LabelLayoutInfo ^ lli_next_short_locn,
list.reverse(ShortLocns, RevShortLocns),
(
CompressArrays = yes,
find_sequence(RevShortLocns, AllRevShortLocns0,
0, OldShortLocnsOffset)
->
ShortLocnSlot = NextShortLocnSlot0 - OldShortLocnsOffset -
NumShortLocns
;
AllRevShortLocns = RevShortLocns ++ AllRevShortLocns0,
!LabelLayoutInfo ^ lli_rev_short_locns := AllRevShortLocns,
ShortLocnSlot = NextShortLocnSlot0,
NextShortLocnSlot = NextShortLocnSlot0 + NumShortLocns,
!LabelLayoutInfo ^ lli_next_short_locn := NextShortLocnSlot
)
;
ShortLocnSlot = -1
),
( NumLongLocns > 0 ->
AllRevLongLocns0 = !.LabelLayoutInfo ^ lli_rev_long_locns,
NextLongLocnSlot0 = !.LabelLayoutInfo ^ lli_next_long_locn,
list.reverse(LongLocns, RevLongLocns),
(
CompressArrays = yes,
find_sequence(RevLongLocns, AllRevLongLocns0,
0, OldLongLocnsOffset)
->
LongLocnSlot = NextLongLocnSlot0 - OldLongLocnsOffset -
NumLongLocns
;
AllRevLongLocns = RevLongLocns ++ AllRevLongLocns0,
!LabelLayoutInfo ^ lli_rev_long_locns := AllRevLongLocns,
LongLocnSlot = NextLongLocnSlot0,
NextLongLocnSlot = NextLongLocnSlot0 + NumLongLocns,
!LabelLayoutInfo ^ lli_next_long_locn := NextLongLocnSlot
),
LVarInfo = label_long_var_info(EncodedLength, TypeParamsRval,
PTISlot, HLDSVarNumSlot, ShortLocnSlot, LongLocnSlot),
MaybeVarInfo = long_var_info(LVarInfo)
;
SVarInfo = label_short_var_info(EncodedLength, TypeParamsRval,
PTISlot, HLDSVarNumSlot, ShortLocnSlot),
MaybeVarInfo = short_var_info(SVarInfo)
).
:- pred construct_liveval_array_slots(list(layout_var_info)::in,
module_info::in, var_num_map::in, int::in, int::in,
list(liveval_array_slot)::out, list(liveval_array_slot)::out,
static_cell_info::in, static_cell_info::out) is det.
construct_liveval_array_slots([], _, _, _, _, [], [], !Info).
construct_liveval_array_slots([VarInfo | VarInfos], ModuleInfo, VarNumMap,
BytesSoFar, BytesLimit, LongArraySlots, ShortArraySlots,
!StaticCellInfo) :-
VarInfo = layout_var_info(Locn, LiveValueType, _),
represent_live_value_type_and_var_num(VarNumMap, LiveValueType,
TypeRval, VarNum, !StaticCellInfo),
(
LiveValueType = live_value_var(_, _, Type, _),
check_dummy_type(ModuleInfo, Type) = is_dummy_type,
% We want to preserve I/O states in registers.
\+ (
Locn = locn_direct(reg(_, _))
)
->
unexpected(this_file, "construct_liveval_array_slots: " ++
"unexpected reference to dummy value")
;
BytesSoFar < BytesLimit,
represent_locn_as_byte(Locn, ShortLocn)
->
ArraySlot = liveval_array_slot(TypeRval, VarNum, ShortLocn),
construct_liveval_array_slots(VarInfos, ModuleInfo, VarNumMap,
BytesSoFar + 1, BytesLimit, LongArraySlots, ShortArraySlots0,
!StaticCellInfo),
ShortArraySlots = [ArraySlot | ShortArraySlots0]
;
represent_locn_as_int(Locn, LongLocn),
ArraySlot = liveval_array_slot(TypeRval, VarNum, LongLocn),
construct_liveval_array_slots(VarInfos, ModuleInfo, VarNumMap,
BytesSoFar, BytesLimit, LongArraySlots0, ShortArraySlots,
!StaticCellInfo),
LongArraySlots = [ArraySlot | LongArraySlots0]
).
:- pred construct_tvar_vector(map(tvar, set(layout_locn))::in,
rval::out, static_cell_info::in, static_cell_info::out) is det.
construct_tvar_vector(TVarLocnMap, TypeParamRval, !StaticCellInfo) :-
( map.is_empty(TVarLocnMap) ->
TypeParamRval = const(llconst_int(0))
;
construct_tvar_rvals(TVarLocnMap, Vector),
add_scalar_static_cell(Vector, DataAddr, !StaticCellInfo),
TypeParamRval = const(llconst_data_addr(DataAddr, no))
).
:- pred construct_tvar_rvals(map(tvar, set(layout_locn))::in,
assoc_list(rval, llds_type)::out) is det.
construct_tvar_rvals(TVarLocnMap, Vector) :-
map.to_assoc_list(TVarLocnMap, TVarLocns),
construct_type_param_locn_vector(TVarLocns, 1, TypeParamLocs),
list.length(TypeParamLocs, TypeParamsLength),
LengthRval = const(llconst_int(TypeParamsLength)),
Vector = [LengthRval - lt_unsigned | TypeParamLocs].
%---------------------------------------------------------------------------%
%
% Construct closure layout structures.
%
construct_closure_layout(CallerProcLabel, SeqNo,
ClosureLayoutInfo, ClosureProcLabel, ModuleName,
FileName, LineNumber, Origin, GoalPath, !StaticCellInfo,
RvalsTypes, Data) :-
% The representation we build here should be kept in sync
% with runtime/mercury_ho_call.h, which contains macros to access
% the data structures we build here.
%
ClosureId = closure_proc_id(CallerProcLabel, SeqNo, ClosureProcLabel),
DataId = layout_id(ClosureId),
Data = closure_proc_id_data(CallerProcLabel, SeqNo, ClosureProcLabel,
ModuleName, FileName, LineNumber, Origin, GoalPath),
ProcIdRvalType = const(llconst_data_addr(DataId, no)) - lt_data_ptr,
ClosureLayoutInfo = closure_layout_info(ClosureArgs, TVarLocnMap),
construct_closure_arg_rvals(ClosureArgs,
ClosureArgRvalsTypes, !StaticCellInfo),
construct_tvar_vector(TVarLocnMap, TVarVectorRval, !StaticCellInfo),
RvalsTypes = [ProcIdRvalType, TVarVectorRval - lt_data_ptr |
ClosureArgRvalsTypes].
:- pred construct_closure_arg_rvals(list(closure_arg_info)::in,
assoc_list(rval, llds_type)::out,
static_cell_info::in, static_cell_info::out) is det.
construct_closure_arg_rvals(ClosureArgs, ClosureArgRvalsTypes,
!StaticCellInfo) :-
list.map_foldl(construct_closure_arg_rval, ClosureArgs, ArgRvalsTypes,
!StaticCellInfo),
list.length(ArgRvalsTypes, Length),
ClosureArgRvalsTypes =
[const(llconst_int(Length)) - lt_integer | ArgRvalsTypes].
:- pred construct_closure_arg_rval(closure_arg_info::in,
pair(rval, llds_type)::out,
static_cell_info::in, static_cell_info::out) is det.
construct_closure_arg_rval(ClosureArg, ArgRval - ArgRvalType,
!StaticCellInfo) :-
ClosureArg = closure_arg_info(Type, _Inst),
% For a stack layout, we can treat all type variables as universally
% quantified. This is not the argument of a constructor, so we do not need
% to distinguish between type variables that are and aren't in scope;
% we can take the variable number directly from the procedure's tvar set.
ExistQTvars = [],
NumUnivQTvars = -1,
ll_pseudo_type_info.construct_typed_llds_pseudo_type_info(Type,
NumUnivQTvars, ExistQTvars, !StaticCellInfo, ArgRval, ArgRvalType).
%---------------------------------------------------------------------------%
% Construct a representation of the type of a value.
%
% For values representing variables, this will be a pseudo_type_info
% describing the type of the variable.
%
% For the kinds of values used internally by the compiler,
% this will be a pointer to a specific type_ctor_info (acting as a
% type_info) defined by hand in builtin.m to stand for values of
% each such kind; one for succips, one for hps, etc.
%
:- pred represent_live_value_type_and_var_num(var_num_map::in,
live_value_type::in, rval::out, int::out,
static_cell_info::in, static_cell_info::out) is det.
represent_live_value_type_and_var_num(VarNumMap, LiveValueType, TypeRval,
VarNum, !StaticCellInfo) :-
(
(
LiveValueType = live_value_succip,
Name = "succip"
;
LiveValueType = live_value_hp,
Name = "hp"
;
LiveValueType = live_value_curfr,
Name = "curfr"
;
LiveValueType = live_value_maxfr,
Name = "maxfr"
;
LiveValueType = live_value_redofr,
Name = "redofr"
;
LiveValueType = live_value_redoip,
Name = "redoip"
;
LiveValueType = live_value_trail_ptr,
Name = "trailptr"
;
LiveValueType = live_value_ticket,
Name = "ticket"
;
% Neither the garbage collector nor the debugger need info about
% regions.
LiveValueType = live_value_region_ite,
Name = "unwanted"
;
LiveValueType = live_value_region_disj,
Name = "unwanted"
;
LiveValueType = live_value_region_commit,
Name = "unwanted"
;
LiveValueType = live_value_unwanted,
Name = "unwanted"
),
represent_special_live_value_type(Name, TypeRval),
VarNum = 0
;
LiveValueType = live_value_var(Var, _, Type, _),
% For a stack layout, we can treat all type variables as universally
% quantified. This is not the argument of a constructor, so we do not
% need to distinguish between type variables that are and are not
% in scope; we can take the variable number directly from the
% procedure's tvar set.
ExistQTvars = [],
NumUnivQTvars = -1,
ll_pseudo_type_info.construct_llds_pseudo_type_info(Type,
NumUnivQTvars, ExistQTvars, !StaticCellInfo, TypeRval),
convert_var_to_int(VarNumMap, Var, VarNum)
).
:- pred represent_special_live_value_type(string::in, rval::out) is det.
represent_special_live_value_type(SpecialTypeName, Rval) :-
RttiTypeCtor = rtti_type_ctor(unqualified(""), SpecialTypeName, 0),
DataId =
rtti_data_id(ctor_rtti_id(RttiTypeCtor, type_ctor_type_ctor_info)),
Rval = const(llconst_data_addr(DataId, no)).
:- pred convert_var_to_int(var_num_map::in, prog_var::in, int::out) is det.
convert_var_to_int(VarNumMap, Var, VarNum) :-
map.lookup(VarNumMap, Var, VarNum0 - _),
% The variable number has to fit into two bytes. We reserve the largest
% such number (Limit) to mean that the variable number is too large
% to be represented. This ought not to happen, since compilation
% would be glacial at best for procedures with that many variables.
Limit = (1 << (2 * byte_bits)) - 1,
int.min(VarNum0, Limit, VarNum).
%---------------------------------------------------------------------------%
:- pred represent_locn_or_const_as_int_rval(stack_layout_params::in,
rval::in, rval::out, llds_type::out,
static_cell_info::in, static_cell_info::out) is det.
represent_locn_or_const_as_int_rval(Params, LvalOrConst, Rval, Type,
!StaticCellInfo) :-
(
LvalOrConst = lval(Lval),
represent_locn_as_int_rval(locn_direct(Lval), Rval),
Type = lt_unsigned
;
LvalOrConst = const(_Const),
UnboxedFloats = Params ^ slp_unboxed_floats,
LLDSType = rval_type_as_arg(UnboxedFloats, LvalOrConst),
add_scalar_static_cell([LvalOrConst - LLDSType], DataId,
!StaticCellInfo),
Rval = const(llconst_data_addr(DataId, no)),
Type = lt_data_ptr
;
LvalOrConst = mkword(Tag, LvalOrConstBase),
represent_locn_or_const_as_int_rval(Params, LvalOrConstBase, BaseRval,
Type, !StaticCellInfo),
Rval = mkword(Tag, BaseRval)
;
( LvalOrConst = binop(_, _, _)
; LvalOrConst = unop(_, _)
; LvalOrConst = mem_addr(_)
; LvalOrConst = var(_)
),
unexpected(this_file, "represent_locn_or_const_as_int_rval: bad rval")
).
%---------------------------------------------------------------------------%
% Construct a representation of a variable location as a 32-bit integer.
%
% Most of the time, a layout specifies a location as an lval.
% However, a type_info variable may be hidden inside a typeclass_info,
% In this case, accessing the type_info requires indirection.
% The address of the typeclass_info is given as an lval, and
% the location of the typeinfo within the typeclass_info as an index;
% private_builtin.type_info_from_typeclass_info interprets the index.
%
% This one level of indirection is sufficient, since type_infos
% cannot be nested inside typeclass_infos any deeper than this.
% A more general representation that would allow more indirection
% would be much harder to fit into one machine word.
%
:- pred represent_locn_as_int_rval(layout_locn::in, rval::out) is det.
represent_locn_as_int_rval(Locn, Rval) :-
represent_locn_as_int(Locn, Word),
Rval = const(llconst_int(Word)).
represent_locn_as_int(locn_direct(Lval), Word) :-
represent_lval(Lval, Word).
represent_locn_as_int(locn_indirect(Lval, Offset), Word) :-
represent_lval(Lval, BaseWord),
expect((1 << long_lval_offset_bits) > Offset, this_file,
"represent_locn: offset too large to be represented"),
BaseAndOffset = (BaseWord << long_lval_offset_bits) + Offset,
make_tagged_word(lval_indirect, BaseAndOffset, Word).
% Construct a four byte representation of an lval.
%
:- pred represent_lval(lval::in, int::out) is det.
represent_lval(reg(reg_r, Num), Word) :-
make_tagged_word(lval_r_reg, Num, Word).
represent_lval(reg(reg_f, Num), Word) :-
make_tagged_word(lval_f_reg, Num, Word).
represent_lval(stackvar(Num), Word) :-
expect(Num > 0, this_file, "represent_lval: bad stackvar"),
make_tagged_word(lval_stackvar, Num, Word).
represent_lval(parent_stackvar(Num), Word) :-
expect(Num > 0, this_file, "represent_lval: bad parent_stackvar"),
make_tagged_word(lval_parent_stackvar, Num, Word).
represent_lval(framevar(Num), Word) :-
expect(Num > 0, this_file, "represent_lval: bad framevar"),
make_tagged_word(lval_framevar, Num, Word).
represent_lval(succip, Word) :-
make_tagged_word(lval_succip, 0, Word).
represent_lval(maxfr, Word) :-
make_tagged_word(lval_maxfr, 0, Word).
represent_lval(curfr, Word) :-
make_tagged_word(lval_curfr, 0, Word).
represent_lval(hp, Word) :-
make_tagged_word(lval_hp, 0, Word).
represent_lval(sp, Word) :-
make_tagged_word(lval_sp, 0, Word).
represent_lval(parent_sp, Word) :-
make_tagged_word(lval_parent_sp, 0, Word).
represent_lval(temp(_, _), _) :-
unexpected(this_file, "continuation live value stored in temp register").
represent_lval(succip_slot(_), _) :-
unexpected(this_file, "continuation live value stored in fixed slot").
represent_lval(redoip_slot(_), _) :-
unexpected(this_file, "continuation live value stored in fixed slot").
represent_lval(redofr_slot(_), _) :-
unexpected(this_file, "continuation live value stored in fixed slot").
represent_lval(succfr_slot(_), _) :-
unexpected(this_file, "continuation live value stored in fixed slot").
represent_lval(prevfr_slot(_), _) :-
unexpected(this_file, "continuation live value stored in fixed slot").
represent_lval(field(_, _, _), _) :-
unexpected(this_file, "continuation live value stored in field").
represent_lval(mem_ref(_), _) :-
unexpected(this_file, "continuation live value stored in mem_ref").
represent_lval(global_var_ref(_), _) :-
unexpected(this_file, "continuation live value stored in global_var_ref").
represent_lval(lvar(_), _) :-
unexpected(this_file, "continuation live value stored in lvar").
% Some things in this module are encoded using a low tag. This is not
% done using the normal compiler mkword, but by doing the bit shifting
% here.
%
% This allows us to use more than the usual 2 or 3 bits, but we have to
% use low tags and cannot tag pointers this way.
%
:- pred make_tagged_word(locn_type::in, int::in, int::out) is det.
make_tagged_word(Locn, Value, TaggedValue) :-
locn_type_code(Locn, Tag),
TaggedValue = (Value << long_lval_tag_bits) + Tag.
:- type locn_type
---> lval_r_reg
; lval_f_reg
; lval_stackvar
; lval_framevar
; lval_succip
; lval_maxfr
; lval_curfr
; lval_hp
; lval_sp
; lval_indirect
; lval_parent_sp
; lval_parent_stackvar.
:- pred locn_type_code(locn_type::in, int::out) is det.
% The code of this predicate should be kept in sync with the enum type
% MR_LongLvalType in runtime/mercury_stack_layout.h. Note that the values
% equal to 0 modulo 4 are reserved for representing constants.
locn_type_code(lval_r_reg, 1).
locn_type_code(lval_f_reg, 2).
locn_type_code(lval_stackvar, 3).
locn_type_code(lval_parent_stackvar, 3). % XXX placeholder only
locn_type_code(lval_framevar, 5).
locn_type_code(lval_succip, 6).
locn_type_code(lval_maxfr, 7).
locn_type_code(lval_curfr, 9).
locn_type_code(lval_hp, 10).
locn_type_code(lval_sp, 11).
locn_type_code(lval_parent_sp, 11). % XXX placeholder only
locn_type_code(lval_indirect, 13).
% This number of tag bits must be able to encode all values of
% locn_type_code.
%
:- func long_lval_tag_bits = int.
long_lval_tag_bits = 4.
% This number of tag bits must be able to encode the largest offset
% of a type_info within a typeclass_info.
%
:- func long_lval_offset_bits = int.
long_lval_offset_bits = 6.
%---------------------------------------------------------------------------%
% Construct a representation of a variable location as a byte,
% if this is possible.
%
:- pred represent_locn_as_byte(layout_locn::in, int::out) is semidet.
represent_locn_as_byte(LayoutLocn, Byte) :-
LayoutLocn = locn_direct(Lval),
represent_lval_as_byte(Lval, Byte),
0 =< Byte,
Byte < 256.
% Construct a representation of an lval in a byte, if possible.
%
:- pred represent_lval_as_byte(lval::in, int::out) is semidet.
represent_lval_as_byte(reg(reg_r, Num), Byte) :-
expect(Num > 0, this_file, "represent_lval_as_byte: bad reg"),
make_tagged_byte(0, Num, Byte).
represent_lval_as_byte(stackvar(Num), Byte) :-
expect(Num > 0, this_file, "represent_lval_as_byte: bad stackvar"),
make_tagged_byte(1, Num, Byte).
represent_lval_as_byte(parent_stackvar(Num), Byte) :-
expect(Num > 0, this_file, "represent_lval_as_byte: bad parent_stackvar"),
make_tagged_byte(1, Num, Byte). % XXX placeholder only
represent_lval_as_byte(framevar(Num), Byte) :-
expect(Num > 0, this_file, "represent_lval_as_byte: bad framevar"),
make_tagged_byte(2, Num, Byte).
represent_lval_as_byte(succip, Byte) :-
locn_type_code(lval_succip, Val),
make_tagged_byte(3, Val, Byte).
represent_lval_as_byte(maxfr, Byte) :-
locn_type_code(lval_maxfr, Val),
make_tagged_byte(3, Val, Byte).
represent_lval_as_byte(curfr, Byte) :-
locn_type_code(lval_curfr, Val),
make_tagged_byte(3, Val, Byte).
represent_lval_as_byte(hp, Byte) :-
locn_type_code(lval_hp, Val),
make_tagged_byte(3, Val, Byte).
represent_lval_as_byte(sp, Byte) :-
locn_type_code(lval_sp, Val),
make_tagged_byte(3, Val, Byte).
represent_lval_as_byte(parent_sp, Byte) :-
locn_type_code(lval_parent_sp, Val),
make_tagged_byte(3, Val, Byte). % XXX placeholder only
:- pred make_tagged_byte(int::in, int::in, int::out) is det.
make_tagged_byte(Tag, Value, TaggedValue) :-
TaggedValue = unchecked_left_shift(Value, short_lval_tag_bits) + Tag.
:- func short_lval_tag_bits = int.
short_lval_tag_bits = 2.
:- func short_count_bits = int.
short_count_bits = 10.
:- func byte_bits = int.
byte_bits = 8.
%---------------------------------------------------------------------------%
:- type label_layouts_info
---> label_layouts_info(
% The arrays that hold components of label layouts.
lli_next_pti :: int,
lli_next_long_locn :: int,
lli_next_short_locn :: int,
lli_next_hlds_var_num :: int,
lli_rev_ptis :: list(rval),
lli_rev_long_locns :: list(int),
lli_rev_short_locns :: list(int),
lli_rev_hlds_var_nums :: list(int),
lli_next_user_event :: counter,
lli_next_user_event_var_num :: int,
lli_user_events :: cord(user_event_data),
lli_user_event_var_nums :: cord(maybe(int)),
% The list of slots in the with-var-info and without-var-info
% label layout arrays.
lli_next_no_var_label_layout:: counter,
lli_next_svar_label_layout :: counter,
lli_next_lvar_label_layout :: counter,
lli_rev_no_var_label_layouts:: list(label_layout_no_vars),
lli_rev_svar_label_layouts :: list(label_layout_short_vars),
lli_rev_lvar_label_layouts :: list(label_layout_long_vars),
lli_label_counter :: counter,
% This maps each internal label with a layout
% to the id of its layout structure.
lli_i_label_to_layout_map :: map(label, layout_slot_name)
).
:- func init_label_layouts_info = label_layouts_info.
init_label_layouts_info = Info :-
Info = label_layouts_info(0, 0, 0, 0, [], [], [], [],
counter.init(0), 0, cord.empty, cord.empty,
counter.init(0), counter.init(0), counter.init(0), [], [], [],
counter.init(1), map.init).
%---------------------------------------------------------------------------%
% Look for Search as a sub-sequence in the second argument, and
% return its offset if it exists. We use this to avoid adding existing
% sequences to arrays.
%
% When we stored information about pseudo-typeinfos, variable numbers,
% and variable locations in separate structures (not arrays), our use
% of common structures for them ensured that any identical copies of
% such structures would be optimized away. This optimization is even
% more effective, since it it allows the sequence we need for one label
% to be found as (a) a subsequence of the longer sequence for another
% label, and (b) straddling the sequences of two (or possibly even more)
% other labels.
%
% We use the straightforward, brute force algorithm instead of more
% sophisticated algorithms like Knuth-Morris-Pratt because (a) those
% algorithms are nontrivial to adapt to working on lists instead of arrays
% without losing their edge, and (b) this algorithm is fast enough.
% Turning this on optimization reduces the size of the generated .c and .o
% files by about 12% and 11% respectively (measured on the files in the
% library, mdbcomp and compiler directories in grade asm_fast.gc.debug),
% but even without the type_spec pragmas, it increases sequential bootcheck
% time only a little bit, from 3hr2m to 3hr6m (on alys, which is a Dell
% Inspiron 9400 laptop).
%
% Another possible optimization would be to look whether some sequence of
% elements at the current end of the array could be extended into the
% search sequence, instead of adding the whole search sequence to the
% array.
%
:- pred find_sequence(list(T)::in, list(T)::in, int::in, int::out) is semidet.
:- pragma type_spec(find_sequence/4, T = int).
:- pragma type_spec(find_sequence/4, T = rval).
find_sequence(Search, [Head | Tail], CurOffset, FoundAtOffset) :-
( find_sequence_attempt(Search, [Head | Tail]) ->
FoundAtOffset = CurOffset
;
find_sequence(Search, Tail, CurOffset + 1, FoundAtOffset)
).
:- pred find_sequence_attempt(list(T)::in, list(T)::in) is semidet.
:- pragma type_spec(find_sequence_attempt/2, T = int).
:- pragma type_spec(find_sequence_attempt/2, T = rval).
find_sequence_attempt([], _).
find_sequence_attempt([SearchHead | SearchTail], [Head | Tail]) :-
SearchHead = Head,
find_sequence_attempt(SearchTail, Tail).
%---------------------------------------------------------------------------%
represent_determinism_rval(Detism,
const(llconst_int(code_model.represent_determinism(Detism)))).
%---------------------------------------------------------------------------%
%
% The structure holding all the relevant parameters.
%
:- type stack_layout_params
---> stack_layout_params(
slp_module_info :: module_info,
% What kind of execution tracing, if any, are we doing?
slp_trace_level :: trace_level,
slp_trace_suppress :: trace_suppress_items,
% Is deep profiling enabled?
slp_deep_profiling :: bool,
% Should we generate agc info?
slp_agc_stack_layout :: bool,
% Should we generate tracing info?
slp_trace_stack_layout :: bool,
% Should we generate proc id info?
slp_procid_stack_layout :: bool,
% Should we try to compress arrays?
slp_compress_arrays :: bool,
% Do we have static code addresses or unboxed floats?
slp_static_code_addresses :: bool,
slp_unboxed_floats :: have_unboxed_floats,
% Do we want to include information about labels' line numbers?
slp_rtti_line_numbers :: bool
).
:- func init_stack_layout_params(module_info) = stack_layout_params.
init_stack_layout_params(ModuleInfo) = Params :-
module_info_get_globals(ModuleInfo, Globals),
globals.get_trace_level(Globals, TraceLevel),
globals.get_trace_suppress(Globals, TraceSuppress),
globals.lookup_bool_option(Globals, profile_deep, DeepProfiling),
globals.lookup_bool_option(Globals, agc_stack_layout, AgcLayout),
globals.lookup_bool_option(Globals, trace_stack_layout, TraceLayout),
globals.lookup_bool_option(Globals, procid_stack_layout, ProcIdLayout),
globals.lookup_bool_option(Globals, common_layout_data, CommonLayoutData),
globals.lookup_bool_option(Globals, static_code_addresses, StaticCodeAddr),
globals.lookup_bool_option(Globals, unboxed_float, UnboxedFloatOpt),
globals.lookup_bool_option(Globals, rtti_line_numbers, RttiLineNumbers),
(
UnboxedFloatOpt = no,
UnboxedFloat = do_not_have_unboxed_floats
;
UnboxedFloatOpt = yes,
UnboxedFloat = have_unboxed_floats
),
Params = stack_layout_params(ModuleInfo, TraceLevel, TraceSuppress,
DeepProfiling, AgcLayout, TraceLayout, ProcIdLayout, CommonLayoutData,
StaticCodeAddr, UnboxedFloat, RttiLineNumbers).
%---------------------------------------------------------------------------%
%
% The string_table data structure.
%
:- type string_table
---> string_table(
% Maps strings to their offsets.
map(string, int),
% The list of strings so far, in reverse order.
list(string),
% The next available offset.
int
).
:- func init_string_table = string_table.
init_string_table = !:StringTable :-
map.init(StringMap0),
!:StringTable = string_table(StringMap0, [], 0),
lookup_string_in_table("", _, !StringTable),
lookup_string_in_table("<too many variables>", _, !StringTable).
lookup_string_in_table(String, Offset, !StringTable) :-
!.StringTable = string_table(TableMap0, TableList0, TableOffset0),
( map.search(TableMap0, String, OldOffset) ->
Offset = OldOffset
;
string.length(String, Length),
TableOffset = TableOffset0 + Length + 1,
% We use a 32 bit unsigned integer to represent the offset.
% Computing that limit exactly without getting an overflow
% or using unportable code isn't trivial. The code below
% is overly conservative, requiring the offset to be
% representable in only 30 bits. The over-conservatism
% should not be an issue; the machine will run out of
% virtual memory before the test below fails, for the
% next several years anyway. (Compiling a module that has
% a 1 Gb string table will require several tens of Gb
% of other compiler structures.)
TableOffset < (1 << ((4 * byte_bits) - 2))
->
Offset = TableOffset0,
map.det_insert(TableMap0, String, TableOffset0, TableMap),
TableList = [String | TableList0],
!:StringTable = string_table(TableMap, TableList, TableOffset)
;
% Says that the name of the variable is "TOO_MANY_VARIABLES".
Offset = 1
).
%---------------------------------------------------------------------------%
:- func this_file = string.
this_file = "stack_layout.m".
%---------------------------------------------------------------------------%