mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 05:44:58 +00:00
722 lines
27 KiB
Mathematica
722 lines
27 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-1998 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.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% This module generates the LLDS code that defines global constants to
|
|
% hold the `stack_layout' structures of the stack frames defined by the
|
|
% current module.
|
|
%
|
|
% The tables generated have a number of `create' rvals within them.
|
|
% llds_common.m converts these into static data structures.
|
|
%
|
|
% We can create several types of stack layouts. Which kind we generate
|
|
% depends on the values of several options.
|
|
%
|
|
% Main author: trd.
|
|
% Modifications by zs.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Data Stucture: stack_layouts
|
|
%
|
|
% If the option basic_stack_layout is set, we generate a stack layout table
|
|
% for each procedure. This table will be stored in the global variable
|
|
% whose name is
|
|
% mercury_data__stack_layout__mercury__<proc_label>.
|
|
% This table will always contain the following information:
|
|
%
|
|
% code address (Code *) - address of entry
|
|
% determinism (Integer) actually, type MR_Determinism
|
|
% number of stack slots (Integer)
|
|
% succip stack location (Integer) actually, type MR_Live_Lval
|
|
% (the location will be set to -1
|
|
% if there is no succip available).
|
|
%
|
|
% If the option procid_stack_layout is set, i.e. if we are doing stack
|
|
% tracing, execution tracing or profiling, the table will also include
|
|
% information on the identity of the procedure. This information will take
|
|
% one of two forms. Almost all procedures use the first form:
|
|
%
|
|
% predicate/function (Int) actually, MR_pred_func
|
|
% declaring module name (String)
|
|
% defining module name (String)
|
|
% predicate name (String)
|
|
% predicate arity (Integer)
|
|
% procedure number (Integer)
|
|
%
|
|
% Automatically generated unification, index and comparison predicates
|
|
% use the second form:
|
|
%
|
|
% type name (String)
|
|
% type module's name (String)
|
|
% defining module name (String)
|
|
% predicate name (String)
|
|
% predicate arity (Integer)
|
|
% procedure number (Integer)
|
|
%
|
|
% The runtime system can figure out which form is present by testing
|
|
% the value of the first slot. A value of 0 or 1 indicates the first form;
|
|
% any higher value indicates the second form.
|
|
%
|
|
% The meanings of the fields in both forms are the same as in procedure labels.
|
|
%
|
|
% If the option trace_stack_layout is set, i.e. if we are doing execution
|
|
% tracing, the table will also include one extra field:
|
|
%
|
|
% call trace info (Word *) - pointer to label stack layout
|
|
%
|
|
% This will point to the per-label layout info for the label associated
|
|
% with the call event at the entry to the procedure. The purpose of this
|
|
% information is to allow the runtime debugger to find out which variables
|
|
% are where on entry, so it can reexecute the procedure if asked to do so
|
|
% and if the values of the required variables are still available.
|
|
%
|
|
% If the option basic_stack_layout is set, we generate stack layout tables
|
|
% for some labels internal to the procedure. This table will be stored in the
|
|
% global variable whose name is
|
|
% mercury_data__stack_layout__mercury__<proc_label>_i<label_number>.
|
|
% This table has the following format:
|
|
%
|
|
% procedure info (Word *) - pointer to procedure stack layout
|
|
% internal label number (Integer)
|
|
% # of live vars (Integer)
|
|
% live data pairs (Word *) - pointer to vector of pairs
|
|
% containing MR_Live_Lval and MR_Live_Type
|
|
% live data names (Word *) - pointer to vector of String
|
|
% type parameters (Word *) - pointer to vector of MR_Live_Lval
|
|
%
|
|
% The internal label number field is just for the convenience of those
|
|
% implementors who are debugging stack layout dependent code. It holds
|
|
% either the label number, or -1 indicating the entry label.
|
|
%
|
|
% The live data pair vector will have an entry for each live variable.
|
|
% The entry will give the location of the variable and its type. (It also
|
|
% has room for its instantiation state, but this is not filled in yet.)
|
|
%
|
|
% The live data name vector pointer will be NULL. If it is not, the vector
|
|
% will have an entry for each live variable, with each entry giving the name
|
|
% of the variable (it is either a pointer to a string, or a NULL pointer,
|
|
% which means that the variable has no name).
|
|
%
|
|
% The number of type parameters is never stored as it is not needed --
|
|
% the type parameter vector will simply be indexed by the type variable's
|
|
% variable number stored within pseudo-typeinfos inside the elements
|
|
% of the live data pairs vectors. Since we allocate type variable numbers
|
|
% sequentially, the type parameter vector will usually be dense. However,
|
|
% after all variables whose types include e.g. type variable 2 have gone
|
|
% out of scope, variables whose types include type variable 3 may still
|
|
% be around.
|
|
%
|
|
% We need detailed information about the variables that are live at an
|
|
% internal label in two kinds of circumstances. Stack layout information
|
|
% will be present only for labels that fall into one or both of these
|
|
% circumstances.
|
|
%
|
|
% - The option trace_stack_layout is set, and the label represents
|
|
% a traced event at which variable info is needed (call, exit,
|
|
% or entrance to one branch of a branched control structure;
|
|
% fail events have no variable information).
|
|
%
|
|
% - The option agc_stack_layout is set, and the label represents
|
|
% a point where execution can resume after a procedure call or
|
|
% after backtracking.
|
|
%
|
|
% If there are no number of live variables at a label, the "# of live vars"
|
|
% field will be zero and the last four fields will not be present.
|
|
% Even if there are some live variables at a label, however, the pointer
|
|
% to the live data names vector will be NULL unless the first condition
|
|
% holds for the label (i.e. the label is used in execution tracing).
|
|
%
|
|
% XXX: Presently, type parameter vectors are not created, and
|
|
% inst information is ignored. We also do not yet enable procid stack
|
|
% layouts for profiling, since profiling does not yet use stack layouts.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module stack_layout.
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds_module, llds.
|
|
:- import_module list, set_bbbtree.
|
|
|
|
:- pred stack_layout__generate_llds(module_info::in, module_info::out,
|
|
list(c_module)::out, set_bbbtree(label)::out) is det.
|
|
|
|
:- implementation.
|
|
|
|
:- import_module globals, options, continuation_info, llds_out.
|
|
:- import_module hlds_data, hlds_pred, base_type_layout, prog_data, prog_out.
|
|
:- import_module assoc_list, bool, string, int, require.
|
|
:- import_module map, std_util, term, set.
|
|
|
|
:- type stack_layout_info --->
|
|
stack_layout_info(
|
|
module_name, % module name
|
|
int, % next available cell number
|
|
bool, % generate agc layout info?
|
|
bool, % generate tracing layout info?
|
|
bool, % generate procedure id layout info?
|
|
list(c_module), % generated data
|
|
set_bbbtree(label)
|
|
% the set of labels with stack layouts
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Process all the continuation information stored in the HLDS,
|
|
% converting it into LLDS data structures.
|
|
|
|
stack_layout__generate_llds(ModuleInfo0, ModuleInfo, CModules,
|
|
StackLayoutLabels) :-
|
|
module_info_get_continuation_info(ModuleInfo0, ContinuationInfo),
|
|
continuation_info__get_all_proc_layouts(ContinuationInfo,
|
|
ProcLayoutList),
|
|
|
|
module_info_name(ModuleInfo0, ModuleName),
|
|
module_info_get_cell_count(ModuleInfo0, CellCount),
|
|
module_info_globals(ModuleInfo0, Globals),
|
|
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,
|
|
ProcInfoLayout),
|
|
set_bbbtree__init(StackLayoutLabels0),
|
|
|
|
LayoutInfo0 = stack_layout_info(ModuleName, CellCount, AgcLayout,
|
|
TraceLayout, ProcInfoLayout, [], StackLayoutLabels0),
|
|
list__foldl(stack_layout__construct_layouts, ProcLayoutList,
|
|
LayoutInfo0, LayoutInfo),
|
|
|
|
stack_layout__get_cmodules(CModules, LayoutInfo, _),
|
|
stack_layout__get_label_set(StackLayoutLabels, LayoutInfo, _),
|
|
stack_layout__get_cell_number(FinalCellCount, LayoutInfo, _),
|
|
module_info_set_cell_count(ModuleInfo0, FinalCellCount, ModuleInfo).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Construct the layouts that concern a single procedure:
|
|
% the procedure-specific layout and the layouts of the labels
|
|
% inside that procedure.
|
|
|
|
:- pred stack_layout__construct_layouts(proc_layout_info::in,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__construct_layouts(ProcLayoutInfo) -->
|
|
{ ProcLayoutInfo = proc_layout_info(ProcLabel, Detism,
|
|
StackSlots, SuccipLoc, CallLabel, InternalMap) },
|
|
stack_layout__construct_proc_layout(ProcLabel, Detism,
|
|
StackSlots, SuccipLoc, CallLabel),
|
|
{ map__to_assoc_list(InternalMap, Internals) },
|
|
list__foldl(stack_layout__construct_internal_layout(ProcLabel),
|
|
Internals).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Construct a procedure-specific layout.
|
|
|
|
:- pred stack_layout__construct_proc_layout(proc_label::in,
|
|
determinism::in, int::in, maybe(int)::in, maybe(label)::in,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__construct_proc_layout(ProcLabel, Detism, StackSlots,
|
|
MaybeSuccipLoc, MaybeCallLabel) -->
|
|
{
|
|
MaybeSuccipLoc = yes(Location0)
|
|
->
|
|
Location = Location0
|
|
;
|
|
% Use a dummy location of -1 if there is
|
|
% no succip 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.
|
|
Location = -1
|
|
},
|
|
{ determinism_components(Detism, _, at_most_many) ->
|
|
SuccipLval = framevar(Location)
|
|
;
|
|
SuccipLval = stackvar(Location)
|
|
},
|
|
{ Label = local(ProcLabel) },
|
|
{ stack_layout__represent_lval(SuccipLval, SuccipRval) },
|
|
{ StackSlotsRval = const(int_const(StackSlots)) },
|
|
{ CodeAddrRval = const(code_addr_const(label(Label))) },
|
|
|
|
{ stack_layout__represent_determinism(Detism, DetismRval) },
|
|
{ MaybeRvals0 = [yes(CodeAddrRval), yes(DetismRval),
|
|
yes(StackSlotsRval), yes(SuccipRval)] },
|
|
|
|
stack_layout__get_procid_stack_layout(ProcIdLayout),
|
|
(
|
|
{ ProcIdLayout = yes }
|
|
->
|
|
{ stack_layout__construct_procid_rvals(ProcLabel, IdRvals) },
|
|
{ list__append(MaybeRvals0, IdRvals, MaybeRvals1) }
|
|
;
|
|
{ MaybeRvals1 = MaybeRvals0 }
|
|
),
|
|
|
|
stack_layout__get_module_name(ModuleName),
|
|
stack_layout__get_trace_stack_layout(TraceLayout),
|
|
(
|
|
{ TraceLayout = yes }
|
|
->
|
|
( { MaybeCallLabel = yes(CallLabel) } ->
|
|
{ CallRval = yes(const(data_addr_const(
|
|
data_addr(ModuleName,
|
|
stack_layout(CallLabel))))) },
|
|
{ list__append(MaybeRvals1, [CallRval], MaybeRvals) }
|
|
;
|
|
{ error("stack_layout__construct_proc_layout: call label not present") }
|
|
)
|
|
;
|
|
{ MaybeRvals = MaybeRvals1 }
|
|
),
|
|
|
|
{ CModule = c_data(ModuleName, stack_layout(Label), yes,
|
|
MaybeRvals, []) },
|
|
stack_layout__add_cmodule(CModule, Label).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred stack_layout__construct_procid_rvals(proc_label::in,
|
|
list(maybe(rval))::out) is det.
|
|
|
|
stack_layout__construct_procid_rvals(ProcLabel, Rvals) :-
|
|
(
|
|
ProcLabel = proc(DefModule, PredFunc, DeclModule,
|
|
PredName, Arity, ProcId),
|
|
stack_layout__represent_pred_or_func(PredFunc, PredFuncCode),
|
|
prog_out__sym_name_to_string(DefModule, DefModuleString),
|
|
prog_out__sym_name_to_string(DeclModule, DeclModuleString),
|
|
proc_id_to_int(ProcId, Mode),
|
|
Rvals = [
|
|
yes(const(int_const(PredFuncCode))),
|
|
yes(const(string_const(DeclModuleString))),
|
|
yes(const(string_const(DefModuleString))),
|
|
yes(const(string_const(PredName))),
|
|
yes(const(int_const(Arity))),
|
|
yes(const(int_const(Mode)))
|
|
]
|
|
;
|
|
ProcLabel = special_proc(DefModule, PredName, TypeModule,
|
|
TypeName, Arity, ProcId),
|
|
prog_out__sym_name_to_string(TypeModule, TypeModuleString),
|
|
prog_out__sym_name_to_string(DefModule, DefModuleString),
|
|
proc_id_to_int(ProcId, Mode),
|
|
Rvals = [
|
|
yes(const(string_const(TypeName))),
|
|
yes(const(string_const(TypeModuleString))),
|
|
yes(const(string_const(DefModuleString))),
|
|
yes(const(string_const(PredName))),
|
|
yes(const(int_const(Arity))),
|
|
yes(const(int_const(Mode)))
|
|
]
|
|
).
|
|
|
|
:- pred stack_layout__represent_pred_or_func(pred_or_func::in, int::out) is det.
|
|
|
|
stack_layout__represent_pred_or_func(predicate, 0).
|
|
stack_layout__represent_pred_or_func(function, 1).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Construct the layout describing a single internal label.
|
|
|
|
:- pred stack_layout__construct_internal_layout(proc_label::in,
|
|
pair(label, internal_layout_info)::in,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__construct_internal_layout(ProcLabel, Label - Internal) -->
|
|
% generate the required rvals
|
|
stack_layout__get_module_name(ModuleName),
|
|
{ EntryAddrRval = const(data_addr_const(data_addr(ModuleName,
|
|
stack_layout(local(ProcLabel))))) },
|
|
{ Label = local(_, LabelNum0) ->
|
|
LabelNum = LabelNum0
|
|
;
|
|
LabelNum = -1
|
|
},
|
|
{ LabelNumRval = const(int_const(LabelNum)) },
|
|
stack_layout__construct_internal_rvals(Internal, AgcRvals),
|
|
{ LayoutRvals = [yes(EntryAddrRval), yes(LabelNumRval) | AgcRvals] },
|
|
{ CModule = c_data(ModuleName, stack_layout(Label), yes,
|
|
LayoutRvals, []) },
|
|
stack_layout__add_cmodule(CModule, Label).
|
|
|
|
% Construct the rvals required for accurate GC or for tracing.
|
|
|
|
:- pred stack_layout__construct_internal_rvals(internal_layout_info::in,
|
|
list(maybe(rval))::out,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__construct_internal_rvals(Internal, RvalList) -->
|
|
(
|
|
{ Internal = yes(layout_label_info(LiveLvalSet, TVars)) }
|
|
->
|
|
stack_layout__construct_livelval_rvals(LiveLvalSet, TVars,
|
|
RvalList)
|
|
;
|
|
% This label is not being used as a continuation,
|
|
% or we are not doing accurate GC, so we record
|
|
% no live values here.
|
|
% This might not be a true reflection of the
|
|
% liveness at this point, so the values cannot
|
|
% be relied upon by the runtime system unless
|
|
% you know you are at a continuation (and doing
|
|
% accurate GC).
|
|
{ RvalList = [yes(const(int_const(0)))] }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred stack_layout__construct_livelval_rvals(set(var_info),
|
|
set(pair(tvar, lval)), list(maybe(rval)),
|
|
stack_layout_info, stack_layout_info).
|
|
:- mode stack_layout__construct_livelval_rvals(in, in, out, in, out) is det.
|
|
|
|
stack_layout__construct_livelval_rvals(LiveLvalSet, TVarLocnSet, RvalList) -->
|
|
{ set__to_sorted_list(LiveLvalSet, LiveLvals) },
|
|
{ list__length(LiveLvals, Length) },
|
|
{ VarLengthRval = const(int_const(Length)) },
|
|
( { Length > 0 } ->
|
|
stack_layout__construct_liveval_pairs(LiveLvals, LiveValRval,
|
|
NamesRval),
|
|
|
|
{ set__to_sorted_list(TVarLocnSet, TVarLocns) },
|
|
stack_layout__construct_type_param_locn_vector(TVarLocns, 1,
|
|
TypeParamLocs),
|
|
stack_layout__get_next_cell_number(CNum1),
|
|
{ TypeParamRval = create(0, TypeParamLocs, no, CNum1,
|
|
"stack_layout_type_param_locn_vector") },
|
|
{ list__length(TypeParamLocs, TypeParamsLength) },
|
|
{ TypeParamLengthRval = const(int_const(TypeParamsLength)) },
|
|
|
|
{ RvalList = [yes(VarLengthRval), yes(LiveValRval),
|
|
yes(NamesRval), yes(TypeParamLengthRval),
|
|
yes(TypeParamRval)] }
|
|
;
|
|
{ RvalList = [yes(VarLengthRval)] }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% 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 stack_layout__construct_type_param_locn_vector(
|
|
assoc_list(tvar, lval)::in, int::in, list(maybe(rval))::out,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__construct_type_param_locn_vector([], _, []) --> [].
|
|
stack_layout__construct_type_param_locn_vector([TVar - Locn | TVarLocns],
|
|
CurSlot, Vector) -->
|
|
{ term__var_to_int(TVar, TVarNum) },
|
|
{ NextSlot is CurSlot + 1 },
|
|
( { TVarNum = CurSlot } ->
|
|
{ stack_layout__represent_lval(Locn, Rval) },
|
|
stack_layout__construct_type_param_locn_vector(TVarLocns,
|
|
NextSlot, VectorTail),
|
|
{ Vector = [yes(Rval) | VectorTail] }
|
|
; { TVarNum > CurSlot } ->
|
|
stack_layout__construct_type_param_locn_vector(TVarLocns,
|
|
NextSlot, VectorTail),
|
|
% This slot will never be referred to.
|
|
{ Vector = [yes(const(int_const(0))) | VectorTail] }
|
|
;
|
|
|
|
{ error("unsorted tvars in construct_type_param_locn_vector") }
|
|
).
|
|
|
|
% Construct a vector of (lval, live_value_type) pairs,
|
|
% and a corresponding vector of variable names.
|
|
|
|
:- pred stack_layout__construct_liveval_pairs(list(var_info)::in,
|
|
rval::out, rval::out, stack_layout_info::in, stack_layout_info::out)
|
|
is det.
|
|
|
|
stack_layout__construct_liveval_pairs(LiveLvals, LocnVector, NameVector) -->
|
|
list__map_foldl(stack_layout__construct_liveval_pair, LiveLvals,
|
|
LocnTypePairs),
|
|
{ list__condense(LocnTypePairs, LocnTypeVectorArgs) },
|
|
stack_layout__get_next_cell_number(CNum1),
|
|
{ LocnVector = create(0, LocnTypeVectorArgs, no, CNum1,
|
|
"stack_layout_locn_vector") },
|
|
|
|
{ list__map(stack_layout__construct_liveval_name, LiveLvals, Names) },
|
|
stack_layout__get_next_cell_number(CNum2),
|
|
{ NameVector = create(0, Names, no, CNum2,
|
|
"stack_layout_name_vector") }.
|
|
|
|
% Construct a pair of (lval, live_value_type) representations.
|
|
|
|
:- pred stack_layout__construct_liveval_pair(var_info::in,
|
|
list(maybe(rval))::out, stack_layout_info::in, stack_layout_info::out)
|
|
is det.
|
|
|
|
stack_layout__construct_liveval_pair(var_info(Lval, LiveValueType, _),
|
|
MaybeRvals) -->
|
|
{ stack_layout__represent_lval(Lval, Rval0) },
|
|
stack_layout__represent_live_value_type(LiveValueType, Rval1),
|
|
{ MaybeRvals = [yes(Rval0), yes(Rval1)] }.
|
|
|
|
:- pred stack_layout__construct_liveval_name(var_info::in, maybe(rval)::out)
|
|
is det.
|
|
|
|
stack_layout__construct_liveval_name(var_info(_, _, Name), MaybeRval) :-
|
|
( Name = "" ->
|
|
% We prefer a null pointer to a pointer to an empty string,
|
|
% since this way we don't need many copies of the empty string.
|
|
Rval = const(int_const(0))
|
|
;
|
|
Rval = const(string_const(Name))
|
|
),
|
|
MaybeRval = yes(Rval).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% The constants and representations here should be kept in sync
|
|
% with constants in the runtime system:
|
|
% mercury_stack_layout.h - contains macros to access these
|
|
% constants.
|
|
|
|
% Construct a representation of a live_value_type.
|
|
%
|
|
% Low integers for special values, a pointer for other values.
|
|
% (Remember to keep the low integers below the max varint value in
|
|
% runtime/mercury_type_info.h).
|
|
|
|
:- pred stack_layout__represent_live_value_type(live_value_type, rval,
|
|
stack_layout_info, stack_layout_info).
|
|
:- mode stack_layout__represent_live_value_type(in, out, in, out) is det.
|
|
|
|
stack_layout__represent_live_value_type(succip, Rval) -->
|
|
{ Rval = const(int_const(0)) }.
|
|
stack_layout__represent_live_value_type(hp, Rval) -->
|
|
{ Rval = const(int_const(1)) }.
|
|
stack_layout__represent_live_value_type(curfr, Rval) -->
|
|
{ Rval = const(int_const(2)) }.
|
|
stack_layout__represent_live_value_type(maxfr, Rval) -->
|
|
{ Rval = const(int_const(3)) }.
|
|
stack_layout__represent_live_value_type(redoip, Rval) -->
|
|
{ Rval = const(int_const(4)) }.
|
|
stack_layout__represent_live_value_type(unwanted, Rval) -->
|
|
{ Rval = const(int_const(5)) }.
|
|
stack_layout__represent_live_value_type(var(Type, _Inst), Rval) -->
|
|
stack_layout__get_cell_number(CNum0),
|
|
{ base_type_layout__construct_pseudo_type_info(Type, Rval0,
|
|
CNum0, CNum1) },
|
|
stack_layout__set_cell_number(CNum1),
|
|
% XXX hack - don't yet write out insts
|
|
{ Rval1 = const(int_const(-1)) },
|
|
stack_layout__get_next_cell_number(CNum2),
|
|
{ Rval = create(0, [yes(Rval0), yes(Rval1)], no, CNum2,
|
|
"stack_layout_pair") }.
|
|
|
|
% Construct a representation of an lval.
|
|
|
|
:- pred stack_layout__represent_lval(lval, rval).
|
|
:- mode stack_layout__represent_lval(in, out) is det.
|
|
|
|
stack_layout__represent_lval(reg(r, Num), Rval) :-
|
|
stack_layout__make_tagged_rval(0, Num, Rval).
|
|
stack_layout__represent_lval(reg(f, Num), Rval) :-
|
|
stack_layout__make_tagged_rval(1, Num, Rval).
|
|
|
|
stack_layout__represent_lval(stackvar(Num), Rval) :-
|
|
stack_layout__make_tagged_rval(2, Num, Rval).
|
|
stack_layout__represent_lval(framevar(Num), Rval) :-
|
|
stack_layout__make_tagged_rval(3, Num, Rval).
|
|
|
|
stack_layout__represent_lval(succip, Rval) :-
|
|
stack_layout__make_tagged_rval(4, 0, Rval).
|
|
stack_layout__represent_lval(maxfr, Rval) :-
|
|
stack_layout__make_tagged_rval(5, 0, Rval).
|
|
stack_layout__represent_lval(curfr, Rval) :-
|
|
stack_layout__make_tagged_rval(6, 0, Rval).
|
|
stack_layout__represent_lval(hp, Rval) :-
|
|
stack_layout__make_tagged_rval(7, 0, Rval).
|
|
stack_layout__represent_lval(sp, Rval) :-
|
|
stack_layout__make_tagged_rval(8, 0, Rval).
|
|
|
|
stack_layout__represent_lval(temp(_, _), _) :-
|
|
error("stack_layout: continuation live value stored in temp register").
|
|
|
|
stack_layout__represent_lval(succip(_), _) :-
|
|
error("stack_layout: continuation live value stored in code address").
|
|
stack_layout__represent_lval(redoip(_), _) :-
|
|
error("stack_layout: continuation live value stored in code address").
|
|
stack_layout__represent_lval(succfr(_), _) :-
|
|
error("stack_layout: continuation live value stored in code address").
|
|
stack_layout__represent_lval(prevfr(_), _) :-
|
|
error("stack_layout: continuation live value stored in code address").
|
|
|
|
stack_layout__represent_lval(field(_, _, _), _) :-
|
|
error("stack_layout: continuation live value stored in field").
|
|
stack_layout__represent_lval(mem_ref(_), _) :-
|
|
error("stack_layout: continuation live value stored in mem_ref").
|
|
stack_layout__represent_lval(lvar(_), _) :-
|
|
error("stack_layout: 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 stack_layout__make_tagged_rval(int::in, int::in, rval::out) is det.
|
|
|
|
stack_layout__make_tagged_rval(Tag, Value, Rval) :-
|
|
stack_layout__make_tagged_word(Tag, Value, TaggedValue),
|
|
Rval = const(int_const(TaggedValue)).
|
|
|
|
:- pred stack_layout__make_tagged_word(int::in, int::in, int::out) is det.
|
|
|
|
stack_layout__make_tagged_word(Tag, Value, TaggedValue) :-
|
|
stack_layout__tag_bits(Bits),
|
|
TaggedValue = (Value << Bits) + Tag.
|
|
|
|
:- pred stack_layout__tag_bits(int::out) is det.
|
|
|
|
stack_layout__tag_bits(8).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Construct a representation of the interface determinism of a
|
|
% procedure. The code we have chosen is not sequential; instead
|
|
% it encodes the various properties of each determinism.
|
|
%
|
|
% The 8 bit is set iff the context is first_solution.
|
|
% The 4 bit is set iff the min number of solutions is more than zero.
|
|
% The 2 bit is set iff the max number of solutions is more than zero.
|
|
% The 1 bit is set iff the max number of solutions is more than one.
|
|
|
|
:- pred stack_layout__represent_determinism(determinism::in, rval::out) is det.
|
|
|
|
stack_layout__represent_determinism(Detism, const(int_const(Code))) :-
|
|
(
|
|
Detism = det,
|
|
Code = 6 /* 0110 */
|
|
;
|
|
Detism = semidet, /* 0010 */
|
|
Code = 2
|
|
;
|
|
Detism = nondet,
|
|
Code = 3 /* 0011 */
|
|
;
|
|
Detism = multidet,
|
|
Code = 7 /* 0111 */
|
|
;
|
|
Detism = erroneous,
|
|
Code = 4 /* 0100 */
|
|
;
|
|
Detism = failure,
|
|
Code = 0 /* 0000 */
|
|
;
|
|
Detism = cc_nondet,
|
|
Code = 10 /* 1010 */
|
|
;
|
|
Detism = cc_multidet,
|
|
Code = 14 /* 1110 */
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Access to the stack_layout data structure.
|
|
|
|
:- pred stack_layout__get_module_name(module_name::out,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__get_module_name(ModuleName, LayoutInfo, LayoutInfo) :-
|
|
LayoutInfo = stack_layout_info(ModuleName, _, _, _, _, _, _).
|
|
|
|
:- pred stack_layout__get_next_cell_number(int::out,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__get_next_cell_number(CNum0, LayoutInfo0, LayoutInfo) :-
|
|
LayoutInfo0 = stack_layout_info(A, CNum0, C, D, E, F, G),
|
|
CNum is CNum0 + 1,
|
|
LayoutInfo = stack_layout_info(A, CNum, C, D, E, F, G).
|
|
|
|
:- pred stack_layout__get_cell_number(int::out,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__get_cell_number(CNum, LayoutInfo, LayoutInfo) :-
|
|
LayoutInfo = stack_layout_info(_, CNum, _, _, _, _, _).
|
|
|
|
:- pred stack_layout__get_agc_stack_layout(bool::out,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__get_agc_stack_layout(AgcStackLayout, LayoutInfo, LayoutInfo) :-
|
|
LayoutInfo = stack_layout_info(_, _, AgcStackLayout, _, _, _, _).
|
|
|
|
:- pred stack_layout__get_trace_stack_layout(bool::out,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__get_trace_stack_layout(TraceStackLayout, LayoutInfo,
|
|
LayoutInfo) :-
|
|
LayoutInfo = stack_layout_info(_, _, _, TraceStackLayout, _, _, _).
|
|
|
|
:- pred stack_layout__get_procid_stack_layout(bool::out,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__get_procid_stack_layout(ProcIdStackLayout, LayoutInfo,
|
|
LayoutInfo) :-
|
|
LayoutInfo = stack_layout_info(_, _, _, _, ProcIdStackLayout, _, _).
|
|
|
|
:- pred stack_layout__get_cmodules(list(c_module)::out,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__get_cmodules(CModules, LayoutInfo, LayoutInfo) :-
|
|
LayoutInfo = stack_layout_info(_, _, _, _, _, CModules, _).
|
|
|
|
:- pred stack_layout__get_label_set(set_bbbtree(label)::out,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__get_label_set(StackLayoutLabels, LayoutInfo, LayoutInfo) :-
|
|
LayoutInfo = stack_layout_info(_, _, _, _, _, _, StackLayoutLabels).
|
|
|
|
:- pred stack_layout__add_cmodule(c_module::in, label::in,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__add_cmodule(CModule, Label, LayoutInfo0, LayoutInfo) :-
|
|
LayoutInfo0 = stack_layout_info(A, B, C, D, E, CModules0,
|
|
StackLayoutLabels0),
|
|
CModules = [CModule | CModules0],
|
|
set_bbbtree__insert(StackLayoutLabels0, Label, StackLayoutLabels),
|
|
LayoutInfo = stack_layout_info(A, B, C, D, E, CModules,
|
|
StackLayoutLabels).
|
|
|
|
:- pred stack_layout__set_cell_number(int::in,
|
|
stack_layout_info::in, stack_layout_info::out) is det.
|
|
|
|
stack_layout__set_cell_number(CNum, LayoutInfo0, LayoutInfo) :-
|
|
LayoutInfo0 = stack_layout_info(A, _, C, D, E, F, G),
|
|
LayoutInfo = stack_layout_info(A, CNum, C, D, E, F, G).
|