mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-22 12:53:47 +00:00
Estimated hours taken: 220
Aditi update syntax, type and mode checking.
Change the hlds_goal for constructions in preparation for
structure reuse to avoid making multiple conflicting changes.
compiler/hlds_goal.m:
Merge `higher_order_call' and `class_method_call' into a single
`generic_call' goal type. This also has alternatives for the
various Aditi builtins for which type declarations can't
be written.
Remove the argument types field from higher-order/class method calls.
It wasn't used often, and wasn't updated by optimizations
such as inlining. The types can be obtained from the vartypes
field of the proc_info.
Add a `lambda_eval_method' field to lambda_goals.
Add a field to constructions to identify which RL code fragment should
be used for an top-down Aditi closure.
Add fields to constructions to hold structure reuse information.
This is currently ignored -- the changes to implement structure
reuse will be committed to the alias branch.
This is included here to avoid lots of CVS conflicts caused by
changing the definition of `hlds_goal' twice.
Add a field to `some' goals to specify whether the quantification
can be removed. This is used to make it easier to ensure that
indexes are used for updates.
Add a field to lambda_goals to describe whether the modes were
guessed by the compiler and may need fixing up after typechecking
works out the argument types.
Add predicate `hlds_goal__generic_call_id' to work out a call_id
for a generic call for use in error messages.
compiler/purity.m:
compiler/post_typecheck.m:
Fill in the modes of Aditi builtin calls and closure constructions.
This needs to know which are the `aditi__state' arguments, so
it must be done after typechecking.
compiler/prog_data.m:
Added `:- type sym_name_and_arity ---> sym_name/arity'.
Add a type `lambda_eval_method', which describes how a closure
is to be executed. The alternatives are normal Mercury execution,
bottom-up execution by Aditi and top-down execution by Aditi.
compiler/prog_out.m:
Add predicate `prog_out__write_sym_name_and_arity', which
replaces duplicated inline code in a few places.
compiler/hlds_data.m:
Add a `lambda_eval_method' field to `pred_const' cons_ids and
`pred_closure_tag' cons_tags.
compiler/hlds_pred.m:
Remove type `pred_call_id', replace it with type `simple_call_id',
which combines a `pred_or_func' and a `sym_name_and_arity'.
Add a type `call_id' which describes all the different types of call,
including normal calls, higher-order and class-method calls
and Aditi builtins.
Add `aditi_top_down' to the type `marker'.
Remove `aditi_interface' from type `marker'. Interfacing to
Aditi predicates is now handled by `generic_call' hlds_goals.
Add a type `rl_exprn_id' which identifies a predicate to
be executed top-down by Aditi.
Add a `maybe(rl_exprn_id)' field to type `proc_info'.
Add predicate `adjust_func_arity' to convert between the arity
of a function to its arity as a predicate.
Add predicates `get_state_args' and `get_state_args_det' to
extract the DCG state arguments from an argument list.
Add predicate `pred_info_get_call_id' to get a `simple_call_id'
for a predicate for use in error messages.
compiler/hlds_out.m:
Write the new representation for call_ids.
Add a predicate `hlds_out__write_call_arg_id' which
replaces similar code in mode_errors.m and typecheck.m.
compiler/prog_io_goal.m:
Add support for `aditi_bottom_up' and `aditi_top_down' annotations
on pred expressions.
compiler/prog_io_util.m:
compiler/prog_io_pragma.m:
Add predicates
- `prog_io_util:parse_name_and_arity' to parse `SymName/Arity'
(moved from prog_io_pragma.m).
- `prog_io_util:parse_pred_or_func_name_and_arity to parse
`pred SymName/Arity' or `func SymName/Arity'.
- `prog_io_util:parse_pred_or_func_and_args' to parse terms resembling
a clause head (moved from prog_io_pragma.m).
compiler/type_util.m:
Add support for `aditi_bottom_up' and `aditi_top_down' annotations
on higher-order types.
Add predicates `construct_higher_order_type',
`construct_higher_order_pred_type' and
`construct_higher_order_func_type' to avoid some code duplication.
compiler/mode_util.m:
Add predicate `unused_mode/1', which returns `builtin:unused'.
Add functions `aditi_di_mode/0', `aditi_ui_mode/0' and
`aditi_uo_mode/0' which return `in', `in', and `out', but will
be changed to return `di', `ui' and `uo' when alias tracking
is implemented.
compiler/goal_util.m:
Add predicate `goal_util__generic_call_vars' which returns
any arguments to a generic_call which are not in the argument list,
for example the closure passed to a higher-order call or
the typeclass_info for a class method call.
compiler/llds.m:
compiler/exprn_aux.m:
compiler/dupelim.m:
compiler/llds_out.m:
compiler/opt_debug.m:
Add builtin labels for the Aditi update operations.
compiler/hlds_module.m:
Add predicate predicate_table_search_pf_sym, used for finding
possible matches for a call with the wrong number of arguments.
compiler/intermod.m:
Don't write predicates which build `aditi_top_down' goals,
because there is currently no way to tell importing modules
which RL code fragment to use.
compiler/simplify.m:
Obey the `cannot_remove' field of explicit quantification goals.
compiler/make_hlds.m:
Parse Aditi updates.
Don't typecheck clauses for which syntax errors in Aditi updates
are found - this avoids spurious "undefined predicate `aditi_insert/3'"
errors.
Factor out some common code to handle terms of the form `Head :- Body'.
Factor out common code in the handling of pred and func expressions.
compiler/typecheck.m:
Typecheck Aditi builtins.
Allow the argument types of matching predicates to be adjusted
when typechecking the higher-order arguments of Aditi builtins.
Change `typecheck__resolve_pred_overloading' to take a list of
argument types rather than a `map(var, type)' and a list of
arguments to allow a transformation to be performed on the
argument types before passing them.
compiler/error_util.m:
Move the part of `report_error_num_args' which writes
"wrong number of arguments (<x>; expected <y>)" from
typecheck.m for use by make_hlds.m when reporting errors
for Aditi builtins.
compiler/modes.m:
compiler/unique_modes.m:
compiler/modecheck_call.m:
Modecheck Aditi builtins.
compiler/lambda.m:
Handle the markers for predicates introduced for
`aditi_top_down' and `aditi_bottom_up' lambda expressions.
compiler/polymorphism.m:
Add extra type_infos to `aditi_insert' calls
describing the tuple to insert.
compiler/call_gen.m:
Generate code for Aditi builtins.
compiler/unify_gen.m:
compiler/bytecode_gen.m:
Abort on `aditi_top_down' and `aditi_bottom_up' lambda
expressions - code generation for them is not yet implemented.
compiler/magic.m:
Use the `aditi_call' generic_call rather than create
a new procedure for each Aditi predicate called from C.
compiler/rl_out.pp:
compiler/rl_gen.m:
compiler/rl.m:
Move some utility code used by magic.m and call_gen.m into rl.m.
Remove an XXX comment about reference counting being not yet
implemented - Evan has fixed that.
library/ops.m:
compiler/mercury_to_mercury.m:
doc/transition_guide.texi:
Add unary prefix operators `aditi_bottom_up' and `aditi_top_down',
used as qualifiers on lambda expressions.
Add infix operator `==>' to separate the tuples in an
`aditi_modify' call.
compiler/follow_vars.m:
Thread a `map(prog_var, type)' through, needed because
type information is no longer held in higher-order call goals.
compiler/table_gen.m:
Use the `make_*_construction' predicates in hlds_goal.m
to construct constants.
compiler/*.m:
Trivial changes to add extra fields to hlds_goal structures.
doc/reference_manual.texi:
Document Aditi updates.
Use @samp{pragma base_relation} instead of
@samp{:- pragma base_relation} throughout the Aditi documentation
to be consistent with other parts of the reference manual.
tests/valid/Mmakefile:
tests/valid/aditi_update.m:
tests/valid/aditi.m:
Test case.
tests/valid/Mmakefile:
Remove some hard-coded --intermodule-optimization rules which are
no longer needed because `mmake depend' is now run in this directory.
tests/invalid/*.err_exp:
Fix expected output for changes in reporting of call_ids
in typecheck.m.
tests/invalid/Mmakefile
tests/invalid/aditi_update_errors.{m,err_exp}:
tests/invalid/aditi_update_mode_errors.{m,err_exp}:
Test error messages for Aditi updates.
tests/valid/aditi.m:
tests/invalid/aditi.m:
Cut down version of extras/aditi/aditi.m to provide basic declarations
for Aditi compilation such as `aditi__state' and the modes
`aditi_di', `aditi_uo' and `aditi_ui'. Installing extras/aditi/aditi.m
somewhere would remove the need for these.
668 lines
26 KiB
Mathematica
668 lines
26 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-1999 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: continuation_info.m.
|
|
% Main author: trd.
|
|
% Extensive modifications by zs.
|
|
%
|
|
% This file defines the data structures the code generator uses to collect
|
|
% information that will later be converted into layout tables for accurate
|
|
% garbage collection, for stack tracing, execution tracing and perhaps
|
|
% other purposes.
|
|
%
|
|
% Information is collected in several passes.
|
|
%
|
|
% 1 Before we start generating code for a procedure,
|
|
% we initialize the set of internal labels for which we have
|
|
% layout information to the empty set. This set is stored in
|
|
% the code generator state.
|
|
%
|
|
% 2 During code generation for the procedure, provided the option
|
|
% trace_stack_layouts is set, we add layout information for labels
|
|
% that represent trace ports to the code generator state. If
|
|
% agc_stack_layouts is set, we add layout information for the stack
|
|
% label in each resumption point. And regardless of option settings,
|
|
% we also generate layouts to be attached to any closures we create.
|
|
%
|
|
% 3 After we finish generating code for a procedure, we record
|
|
% all the static information about the procedure (some of which
|
|
% is available only after code generation), together with the
|
|
% info about internal labels accumulated in the code generator state,
|
|
% in the global_data structure.
|
|
%
|
|
% 4 If agc_stack_layouts is set, we make a pass over the
|
|
% optimized code recorded in the final LLDS instructions.
|
|
% In this pass, we collect information from call instructions
|
|
% about the internal labels to which calls can return.
|
|
% This info will also go straight into the global_data.
|
|
%
|
|
% This module defines the data structures used by all passes. It also
|
|
% implements the whole of pass 4, and various fractions of the other passes.
|
|
%
|
|
% stack_layout.m converts the information collected in this module into
|
|
% stack_layout tables.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module continuation_info.
|
|
|
|
:- interface.
|
|
|
|
:- import_module llds, hlds_module, hlds_pred, prog_data.
|
|
:- import_module (inst), instmap, trace, globals.
|
|
:- import_module std_util, bool, list, assoc_list, set, map.
|
|
|
|
%
|
|
% Information for any procedure, includes information about the
|
|
% procedure itself, and any internal labels within it.
|
|
%
|
|
:- type proc_layout_info
|
|
---> proc_layout_info(
|
|
label, % The entry label.
|
|
determinism, % Determines which stack is used.
|
|
int, % Number of stack slots.
|
|
maybe(int), % Location of succip on stack.
|
|
maybe(label), % If the trace level is not none,
|
|
% this contains the label associated
|
|
% with the call event, whose stack
|
|
% layout says which variables were
|
|
% live and where on entry.
|
|
trace_slot_info,% Info about the stack slots used
|
|
% for tracing.
|
|
bool, % Do we require the procedure id
|
|
% section of the procedure layout
|
|
% to be present, even if the option
|
|
% procid_stack_layout is not set?
|
|
proc_label_layout_info
|
|
% Info for each internal label,
|
|
% needed for basic_stack_layouts.
|
|
).
|
|
|
|
%
|
|
% Information about the labels internal to a procedure.
|
|
%
|
|
:- type proc_label_layout_info == map(label, internal_layout_info).
|
|
|
|
%
|
|
% Information for an internal label.
|
|
%
|
|
% There are two ways for the compiler to generate labels for
|
|
% which layouts may be required:
|
|
%
|
|
% (a) as the label associated with a trace port, and
|
|
% (b) as the return label of some kind of call (plain, method or h-o).
|
|
%
|
|
% Label optimizations may redirect a call return away from the
|
|
% originally generated label to another label, possibly one
|
|
% that is associated with a trace port. This optimization may
|
|
% also direct returns from more than one call to the same label.
|
|
%
|
|
% We may be interested in the layout of things at a label for three
|
|
% different reasons: for stack tracing, for accurate gc, and for
|
|
% execution tracing (which may include up-level printing from the
|
|
% debugger).
|
|
%
|
|
% - For stack tracing, we are interested only in call return labels.
|
|
% Even for these, we need only the pointer to the procedure layout
|
|
% info; we do not need any information about variables.
|
|
%
|
|
% - For accurate gc, we are interested only in call return labels.
|
|
% We need to know about all the variables that can be accessed
|
|
% after the label; this is the intersection of all the variables
|
|
% denoted as live in the call instructions. (Variables which
|
|
% are not in the intersection are not guaranteed to have a
|
|
% meaningful value on all execution paths that lead to the label.)
|
|
%
|
|
% - For execution tracing, our primary interest is in trace port
|
|
% labels. At these labels we only want info about named variables,
|
|
% but we may want this info even if the variable will never be
|
|
% referred to again.
|
|
%
|
|
% When the trace level requires support for up-level printing,
|
|
% execution tracing also requires information about return labels.
|
|
% The variables about which we want info at these labels is a subset
|
|
% of the variables agc is interested in (the named subset).
|
|
% We do not collect this set explicitly. Instead, if we are doing
|
|
% execution tracing, we collect agc layout info as usual, and
|
|
% (if we not really doing agc) remove the unnamed variables
|
|
% in stack_layout.m.
|
|
%
|
|
% For labels which correspond to a trace port (part (a) above),
|
|
% we record information in the first field. Since trace.m generates
|
|
% a unique label for each trace port, this field is never updated
|
|
% once it is set in pass 2. For labels which correspond to a call
|
|
% return, we record information in the second field during pass 4.
|
|
% Since a label can serve as the return label for more than once call,
|
|
% this field can be updated (by taking the intersection of the live
|
|
% variables) after it is set. Since a call may return to the label
|
|
% of an internal port, it is possible for both fields to be set.
|
|
% In this case, stack_layout.m will take the union of the relevant
|
|
% info. If neither field is set, then the label's layout is required
|
|
% only for stack tracing.
|
|
%
|
|
:- type internal_layout_info
|
|
---> internal_layout_info(
|
|
maybe(layout_label_info),
|
|
maybe(layout_label_info)
|
|
).
|
|
|
|
%
|
|
% Information about the layout of live data for a label.
|
|
%
|
|
:- type layout_label_info
|
|
---> layout_label_info(
|
|
set(var_info),
|
|
% live vars and their locations/names
|
|
map(tvar, set(layout_locn))
|
|
% locations of polymorphic type vars
|
|
).
|
|
|
|
:- type var_info
|
|
---> var_info(
|
|
layout_locn, % the location of the variable
|
|
live_value_type % info about the variable
|
|
).
|
|
|
|
:- type closure_layout_info
|
|
---> closure_layout_info(
|
|
list(closure_arg_info),
|
|
% there is one closure_arg_info for each
|
|
% argument of the called procedure,
|
|
% even the args which are not in the closure
|
|
map(tvar, set(layout_locn))
|
|
% locations of polymorphic type vars,
|
|
% encoded so that rN refers to argument N
|
|
).
|
|
|
|
:- type closure_arg_info
|
|
---> closure_arg_info(
|
|
type, % The type of the argument.
|
|
(inst) % The initial inst of the argument.
|
|
|
|
% It may be useful in the future to include
|
|
% info about the final insts and about
|
|
% the determinism. This would allow us
|
|
% to implement checked dynamic inst casts,
|
|
% which may be helpful for dynamic loading.
|
|
% It may also be useful for printing
|
|
% closures and for providing user-level
|
|
% RTTI access.
|
|
).
|
|
|
|
:- type slot_contents
|
|
---> ticket % a ticket (trail pointer)
|
|
; ticket_counter % a copy of the ticket counter
|
|
; trace_data
|
|
; sync_term % a syncronization term used
|
|
% at the end of par_conjs.
|
|
% see par_conj_gen.m for details.
|
|
; lval(lval).
|
|
|
|
% Call continuation_info__maybe_process_proc_llds on the code
|
|
% of every procedure in the list.
|
|
:- pred continuation_info__maybe_process_llds(list(c_procedure)::in,
|
|
module_info::in, global_data::in, global_data::out) is det.
|
|
|
|
% Check whether this procedure ought to have any layout structures
|
|
% generated for it. If yes, then update the global_data to
|
|
% include all the continuation labels within a proc. Whether or not
|
|
% the information about a continuation label includes the variables
|
|
% live at that label depends on the values of options.
|
|
:- pred continuation_info__maybe_process_proc_llds(list(instruction)::in,
|
|
pred_proc_id::in, module_info::in,
|
|
global_data::in, global_data::out) is det.
|
|
|
|
% Check whether the given procedure should have at least (a) a basic
|
|
% stack layout, and (b) a procedure id layout generated for it.
|
|
% The two bools returned answer these two questions respectively.
|
|
:- pred continuation_info__basic_stack_layout_for_proc(pred_info::in,
|
|
globals::in, bool::out, bool::out) is det.
|
|
|
|
% Generate the layout information we need for the return point
|
|
% of a call.
|
|
:- pred continuation_info__generate_return_live_lvalues(
|
|
assoc_list(prog_var, arg_loc)::in, instmap::in, list(prog_var)::in,
|
|
map(prog_var, set(rval))::in, assoc_list(lval, slot_contents)::in,
|
|
proc_info::in, globals::in, list(liveinfo)::out) is det.
|
|
|
|
% Generate the layout information we need for a resumption point,
|
|
% a label where forward execution can restart after backtracking.
|
|
:- pred continuation_info__generate_resume_layout(map(prog_var, set(rval))::in,
|
|
assoc_list(lval, slot_contents)::in, instmap::in, proc_info::in,
|
|
layout_label_info::out) is det.
|
|
|
|
% Generate the layout information we need to include in a closure.
|
|
:- pred continuation_info__generate_closure_layout(module_info::in,
|
|
pred_id::in, proc_id::in, closure_layout_info::out) is det.
|
|
|
|
% For each type variable in the given list, find out where the
|
|
% typeinfo var for that type variable is.
|
|
:- pred continuation_info__find_typeinfos_for_tvars(list(tvar)::in,
|
|
map(prog_var, set(rval))::in, proc_info::in,
|
|
map(tvar, set(layout_locn))::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds_goal, code_util, type_util, options.
|
|
:- import_module string, require, varset, term.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Exported predicates.
|
|
|
|
continuation_info__maybe_process_llds([], _) --> [].
|
|
continuation_info__maybe_process_llds([Proc | Procs], ModuleInfo) -->
|
|
{ Proc = c_procedure(_, _, PredProcId, Instrs) },
|
|
continuation_info__maybe_process_proc_llds(Instrs, PredProcId,
|
|
ModuleInfo),
|
|
continuation_info__maybe_process_llds(Procs, ModuleInfo).
|
|
|
|
continuation_info__maybe_process_proc_llds(Instructions, PredProcId,
|
|
ModuleInfo, ContInfo0, ContInfo) :-
|
|
PredProcId = proc(PredId, _),
|
|
module_info_pred_info(ModuleInfo, PredId, PredInfo),
|
|
module_info_globals(ModuleInfo, Globals),
|
|
continuation_info__basic_stack_layout_for_proc(PredInfo, Globals,
|
|
Layout, _),
|
|
( Layout = yes ->
|
|
globals__want_return_var_layouts(Globals, WantReturnLayout),
|
|
continuation_info__process_proc_llds(PredProcId, Instructions,
|
|
WantReturnLayout, ContInfo0, ContInfo)
|
|
;
|
|
ContInfo = ContInfo0
|
|
).
|
|
|
|
%
|
|
% Process the list of instructions for this proc, adding
|
|
% all internal label information to global_data.
|
|
%
|
|
:- pred continuation_info__process_proc_llds(pred_proc_id::in,
|
|
list(instruction)::in, bool::in,
|
|
global_data::in, global_data::out) is det.
|
|
|
|
continuation_info__process_proc_llds(PredProcId, Instructions,
|
|
WantReturnInfo, GlobalData0, GlobalData) :-
|
|
|
|
% Get all the continuation info from the call instructions.
|
|
global_data_get_proc_layout(GlobalData0, PredProcId, ProcLayoutInfo0),
|
|
ProcLayoutInfo0 = proc_layout_info(A, B, C, D, E, F, G, Internals0),
|
|
GetCallLivevals = lambda([Instr::in, Pair::out] is semidet, (
|
|
Instr = call(_, label(Label), LiveInfo, _) - _Comment,
|
|
Pair = Label - LiveInfo
|
|
)),
|
|
list__filter_map(GetCallLivevals, Instructions, Calls),
|
|
|
|
% Process the continuation label info.
|
|
list__foldl(continuation_info__process_continuation(WantReturnInfo),
|
|
Calls, Internals0, Internals),
|
|
|
|
ProcLayoutInfo = proc_layout_info(A, B, C, D, E, F, G, Internals),
|
|
global_data_update_proc_layout(GlobalData0, PredProcId, ProcLayoutInfo,
|
|
GlobalData).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
%
|
|
% Collect the liveness information from a single return label
|
|
% and add it to the internals.
|
|
%
|
|
:- pred continuation_info__process_continuation(bool::in,
|
|
pair(label, list(liveinfo))::in,
|
|
proc_label_layout_info::in, proc_label_layout_info::out) is det.
|
|
|
|
continuation_info__process_continuation(WantReturnInfo, Label - LiveInfoList,
|
|
Internals0, Internals) :-
|
|
( map__search(Internals0, Label, Internal0) ->
|
|
Internal0 = internal_layout_info(Port0, Return0)
|
|
;
|
|
Port0 = no,
|
|
Return0 = no
|
|
),
|
|
( WantReturnInfo = yes ->
|
|
continuation_info__convert_return_data(LiveInfoList,
|
|
VarInfoSet, TypeInfoMap),
|
|
(
|
|
Return0 = no,
|
|
Return = yes(layout_label_info(VarInfoSet,
|
|
TypeInfoMap))
|
|
;
|
|
% If a var is known to be dead
|
|
% on return from one call, it
|
|
% cannot be accessed on returning
|
|
% from the other calls that reach
|
|
% the same return address either.
|
|
Return0 = yes(layout_label_info(LV0, TV0)),
|
|
set__intersect(LV0, VarInfoSet, LV),
|
|
map__intersect(set__intersect, TV0, TypeInfoMap, TV),
|
|
Return = yes(layout_label_info(LV, TV))
|
|
)
|
|
;
|
|
Return = Return0
|
|
),
|
|
Internal = internal_layout_info(Port0, Return),
|
|
map__set(Internals0, Label, Internal, Internals).
|
|
|
|
:- pred continuation_info__convert_return_data(list(liveinfo)::in,
|
|
set(var_info)::out, map(tvar, set(layout_locn))::out) is det.
|
|
|
|
continuation_info__convert_return_data(LiveInfos, VarInfoSet, TypeInfoMap) :-
|
|
GetVarInfo = lambda([LiveLval::in, VarInfo::out] is det, (
|
|
LiveLval = live_lvalue(Lval, LiveValueType, _),
|
|
VarInfo = var_info(Lval, LiveValueType)
|
|
)),
|
|
list__map(GetVarInfo, LiveInfos, VarInfoList),
|
|
GetTypeInfo = lambda([LiveLval::in, LiveTypeInfoMap::out] is det, (
|
|
LiveLval = live_lvalue(_, _, LiveTypeInfoMap)
|
|
)),
|
|
list__map(GetTypeInfo, LiveInfos, TypeInfoMapList),
|
|
map__init(Empty),
|
|
list__foldl(lambda([TIM1::in, TIM2::in, TIM::out] is det,
|
|
map__union(set__intersect, TIM1, TIM2, TIM)),
|
|
TypeInfoMapList, Empty, TypeInfoMap),
|
|
set__list_to_set(VarInfoList, VarInfoSet).
|
|
|
|
:- pred continuation_info__filter_named_vars(list(liveinfo)::in,
|
|
list(liveinfo)::out) is det.
|
|
|
|
continuation_info__filter_named_vars([], []).
|
|
continuation_info__filter_named_vars([LiveInfo | LiveInfos], Filtered) :-
|
|
continuation_info__filter_named_vars(LiveInfos, Filtered1),
|
|
(
|
|
LiveInfo = live_lvalue(_, LiveType, _),
|
|
LiveType = var(_, Name, _, _),
|
|
Name \= ""
|
|
->
|
|
Filtered = [LiveInfo | Filtered1]
|
|
;
|
|
Filtered = Filtered1
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
continuation_info__basic_stack_layout_for_proc(PredInfo, Globals,
|
|
BasicLayout, ForceProcIdLayout) :-
|
|
(
|
|
globals__lookup_bool_option(Globals, stack_trace_higher_order,
|
|
yes),
|
|
continuation_info__some_arg_is_higher_order(PredInfo)
|
|
->
|
|
BasicLayout = yes,
|
|
ForceProcIdLayout = yes
|
|
;
|
|
globals__lookup_bool_option(Globals, basic_stack_layout, yes)
|
|
->
|
|
BasicLayout = yes,
|
|
ForceProcIdLayout = no
|
|
;
|
|
BasicLayout = no,
|
|
ForceProcIdLayout = no
|
|
).
|
|
|
|
:- pred continuation_info__some_arg_is_higher_order(pred_info::in) is semidet.
|
|
|
|
continuation_info__some_arg_is_higher_order(PredInfo) :-
|
|
pred_info_arg_types(PredInfo, ArgTypes),
|
|
some([Type], (
|
|
list__member(Type, ArgTypes),
|
|
type_is_higher_order(Type, _, _, _)
|
|
)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
continuation_info__generate_return_live_lvalues(OutputArgLocs, ReturnInstMap,
|
|
Vars, VarLocs, Temps, ProcInfo, Globals, LiveLvalues) :-
|
|
globals__want_return_var_layouts(Globals, WantReturnVarLayout),
|
|
proc_info_stack_slots(ProcInfo, StackSlots),
|
|
continuation_info__find_return_var_lvals(Vars, StackSlots,
|
|
OutputArgLocs, VarLvals),
|
|
continuation_info__generate_var_live_lvalues(VarLvals, ReturnInstMap,
|
|
VarLocs, ProcInfo, WantReturnVarLayout, VarLiveLvalues),
|
|
continuation_info__generate_temp_live_lvalues(Temps, TempLiveLvalues),
|
|
list__append(VarLiveLvalues, TempLiveLvalues, LiveLvalues).
|
|
|
|
:- pred continuation_info__find_return_var_lvals(list(prog_var)::in,
|
|
stack_slots::in, assoc_list(prog_var, arg_loc)::in,
|
|
assoc_list(prog_var, lval)::out) is det.
|
|
|
|
continuation_info__find_return_var_lvals([], _, _, []).
|
|
continuation_info__find_return_var_lvals([Var | Vars], StackSlots,
|
|
OutputArgLocs, [Var - Lval | VarLvals]) :-
|
|
( assoc_list__search(OutputArgLocs, Var, ArgLoc) ->
|
|
% On return, output arguments are in their registers.
|
|
code_util__arg_loc_to_register(ArgLoc, Lval)
|
|
;
|
|
% On return, other live variables are in their stack slots.
|
|
map__lookup(StackSlots, Var, Lval)
|
|
),
|
|
continuation_info__find_return_var_lvals(Vars, StackSlots,
|
|
OutputArgLocs, VarLvals).
|
|
|
|
:- pred continuation_info__generate_temp_live_lvalues(
|
|
assoc_list(lval, slot_contents)::in, list(liveinfo)::out) is det.
|
|
|
|
continuation_info__generate_temp_live_lvalues([], []).
|
|
continuation_info__generate_temp_live_lvalues([Temp | Temps], [Live | Lives]) :-
|
|
Temp = Slot - Contents,
|
|
continuation_info__live_value_type(Contents, LiveLvalueType),
|
|
map__init(Empty),
|
|
Live = live_lvalue(direct(Slot), LiveLvalueType, Empty),
|
|
continuation_info__generate_temp_live_lvalues(Temps, Lives).
|
|
|
|
:- pred continuation_info__generate_var_live_lvalues(
|
|
assoc_list(prog_var, lval)::in, instmap::in,
|
|
map(prog_var, set(rval))::in, proc_info::in,
|
|
bool::in, list(liveinfo)::out) is det.
|
|
|
|
continuation_info__generate_var_live_lvalues([], _, _, _, _, []).
|
|
continuation_info__generate_var_live_lvalues([Var - Lval | VarLvals], InstMap,
|
|
VarLocs, ProcInfo, WantReturnVarLayout, [Live | Lives]) :-
|
|
( WantReturnVarLayout = yes ->
|
|
continuation_info__generate_layout_for_var(Var, InstMap,
|
|
ProcInfo, LiveValueType, TypeVars),
|
|
continuation_info__find_typeinfos_for_tvars(TypeVars,
|
|
VarLocs, ProcInfo, TypeParams),
|
|
Live = live_lvalue(direct(Lval), LiveValueType, TypeParams)
|
|
;
|
|
map__init(Empty),
|
|
Live = live_lvalue(direct(Lval), unwanted, Empty)
|
|
),
|
|
continuation_info__generate_var_live_lvalues(VarLvals, InstMap,
|
|
VarLocs, ProcInfo, WantReturnVarLayout, Lives).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
continuation_info__generate_resume_layout(ResumeMap, Temps, InstMap,
|
|
ProcInfo, Layout) :-
|
|
map__to_assoc_list(ResumeMap, ResumeList),
|
|
set__init(TVars0),
|
|
continuation_info__generate_resume_layout_for_vars(ResumeList,
|
|
InstMap, ProcInfo, VarInfos, TVars0, TVars),
|
|
set__list_to_set(VarInfos, VarInfoSet),
|
|
set__to_sorted_list(TVars, TVarList),
|
|
continuation_info__find_typeinfos_for_tvars(TVarList, ResumeMap,
|
|
ProcInfo, TVarInfoMap),
|
|
continuation_info__generate_temp_var_infos(Temps, TempInfos),
|
|
set__list_to_set(TempInfos, TempInfoSet),
|
|
set__union(VarInfoSet, TempInfoSet, AllInfoSet),
|
|
Layout = layout_label_info(AllInfoSet, TVarInfoMap).
|
|
|
|
:- pred continuation_info__generate_resume_layout_for_vars(
|
|
assoc_list(prog_var, set(rval))::in, instmap::in, proc_info::in,
|
|
list(var_info)::out, set(tvar)::in, set(tvar)::out) is det.
|
|
|
|
continuation_info__generate_resume_layout_for_vars([], _, _, [], TVars, TVars).
|
|
continuation_info__generate_resume_layout_for_vars([Var - RvalSet | VarRvals],
|
|
InstMap, ProcInfo, [VarInfo | VarInfos], TVars0, TVars) :-
|
|
continuation_info__generate_resume_layout_for_var(Var, RvalSet,
|
|
InstMap, ProcInfo, VarInfo, TypeVars),
|
|
set__insert_list(TVars0, TypeVars, TVars1),
|
|
continuation_info__generate_resume_layout_for_vars(VarRvals,
|
|
InstMap, ProcInfo, VarInfos, TVars1, TVars).
|
|
|
|
:- pred continuation_info__generate_resume_layout_for_var(prog_var::in,
|
|
set(rval)::in, instmap::in, proc_info::in,
|
|
var_info::out, list(tvar)::out) is det.
|
|
|
|
continuation_info__generate_resume_layout_for_var(Var, RvalSet, InstMap,
|
|
ProcInfo, VarInfo, TypeVars) :-
|
|
set__to_sorted_list(RvalSet, RvalList),
|
|
( RvalList = [RvalPrime] ->
|
|
Rval = RvalPrime
|
|
;
|
|
error("var has more than one rval in stack resume map")
|
|
),
|
|
( Rval = lval(LvalPrime) ->
|
|
Lval = LvalPrime
|
|
;
|
|
error("var rval is not lval in stack resume map")
|
|
),
|
|
continuation_info__generate_layout_for_var(Var, InstMap, ProcInfo,
|
|
LiveValueType, TypeVars),
|
|
VarInfo = var_info(direct(Lval), LiveValueType).
|
|
|
|
:- pred continuation_info__generate_temp_var_infos(
|
|
assoc_list(lval, slot_contents)::in, list(var_info)::out) is det.
|
|
|
|
continuation_info__generate_temp_var_infos([], []).
|
|
continuation_info__generate_temp_var_infos([Temp | Temps], [Live | Lives]) :-
|
|
Temp = Slot - Contents,
|
|
continuation_info__live_value_type(Contents, LiveLvalueType),
|
|
Live = var_info(direct(Slot), LiveLvalueType),
|
|
continuation_info__generate_temp_var_infos(Temps, Lives).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred continuation_info__generate_layout_for_var(prog_var::in, instmap::in,
|
|
proc_info::in, live_value_type::out, list(tvar)::out) is det.
|
|
|
|
continuation_info__generate_layout_for_var(Var, InstMap, ProcInfo,
|
|
LiveValueType, TypeVars) :-
|
|
proc_info_varset(ProcInfo, VarSet),
|
|
proc_info_vartypes(ProcInfo, VarTypes),
|
|
( varset__search_name(VarSet, Var, GivenName) ->
|
|
Name = GivenName
|
|
;
|
|
Name = ""
|
|
),
|
|
instmap__lookup_var(InstMap, Var, Inst),
|
|
map__lookup(VarTypes, Var, Type),
|
|
LiveValueType = var(Var, Name, Type, Inst),
|
|
type_util__vars(Type, TypeVars).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
continuation_info__generate_closure_layout(ModuleInfo, PredId, ProcId,
|
|
ClosureLayout) :-
|
|
module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo),
|
|
proc_info_headvars(ProcInfo, HeadVars),
|
|
proc_info_arg_info(ProcInfo, ArgInfos),
|
|
proc_info_vartypes(ProcInfo, VarTypes),
|
|
proc_info_get_initial_instmap(ProcInfo, ModuleInfo, InstMap),
|
|
map__init(VarLocs0),
|
|
set__init(TypeVars0),
|
|
assoc_list__from_corresponding_lists(HeadVars, ArgInfos, VarArgInfos),
|
|
continuation_info__build_closure_info(VarArgInfos, ArgLayouts,
|
|
VarTypes, InstMap, VarLocs0, VarLocs, TypeVars0, TypeVars),
|
|
set__to_sorted_list(TypeVars, TypeVarsList),
|
|
continuation_info__find_typeinfos_for_tvars(TypeVarsList, VarLocs,
|
|
ProcInfo, TypeInfoDataMap),
|
|
ClosureLayout = closure_layout_info(ArgLayouts, TypeInfoDataMap).
|
|
|
|
:- pred continuation_info__build_closure_info(
|
|
assoc_list(prog_var, arg_info)::in, list(closure_arg_info)::out,
|
|
map(prog_var, type)::in, instmap::in,
|
|
map(prog_var, set(rval))::in, map(prog_var, set(rval))::out,
|
|
set(tvar)::in, set(tvar)::out) is det.
|
|
|
|
continuation_info__build_closure_info([], [], _, _, VarLocs, VarLocs,
|
|
TypeVars, TypeVars).
|
|
continuation_info__build_closure_info([Var - ArgInfo | VarArgInfos],
|
|
[Layout | Layouts], VarTypes, InstMap,
|
|
VarLocs0, VarLocs, TypeVars0, TypeVars) :-
|
|
ArgInfo = arg_info(ArgLoc, _ArgMode),
|
|
map__lookup(VarTypes, Var, Type),
|
|
instmap__lookup_var(InstMap, Var, Inst),
|
|
Layout = closure_arg_info(Type, Inst),
|
|
set__singleton_set(Locations, lval(reg(r, ArgLoc))),
|
|
map__det_insert(VarLocs0, Var, Locations, VarLocs1),
|
|
type_util__vars(Type, VarTypeVars),
|
|
set__insert_list(TypeVars0, VarTypeVars, TypeVars1),
|
|
continuation_info__build_closure_info(VarArgInfos, Layouts,
|
|
VarTypes, InstMap, VarLocs1, VarLocs, TypeVars1, TypeVars).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
continuation_info__find_typeinfos_for_tvars(TypeVars, VarLocs, ProcInfo,
|
|
TypeInfoDataMap) :-
|
|
proc_info_varset(ProcInfo, VarSet),
|
|
proc_info_typeinfo_varmap(ProcInfo, TypeInfoMap),
|
|
map__apply_to_list(TypeVars, TypeInfoMap, TypeInfoLocns),
|
|
FindLocn = lambda([TypeInfoLocn::in, Locns::out] is det, (
|
|
type_info_locn_var(TypeInfoLocn, TypeInfoVar),
|
|
(
|
|
map__search(VarLocs, TypeInfoVar, TypeInfoRvalSet)
|
|
->
|
|
ConvertRval = lambda([Locn::out] is nondet, (
|
|
set__member(Rval, TypeInfoRvalSet),
|
|
Rval = lval(Lval),
|
|
(
|
|
TypeInfoLocn = typeclass_info(_,
|
|
FieldNum),
|
|
Locn = indirect(Lval, FieldNum)
|
|
;
|
|
TypeInfoLocn = type_info(_),
|
|
Locn = direct(Lval)
|
|
)
|
|
)),
|
|
solutions_set(ConvertRval, Locns)
|
|
;
|
|
varset__lookup_name(VarSet, TypeInfoVar,
|
|
VarString),
|
|
string__format("%s: %s %s",
|
|
[s("code_info__find_typeinfos_for_tvars"),
|
|
s("can't find lval for type_info var"),
|
|
s(VarString)], ErrStr),
|
|
error(ErrStr)
|
|
)
|
|
)),
|
|
list__map(FindLocn, TypeInfoLocns, TypeInfoVarLocns),
|
|
map__from_corresponding_lists(TypeVars, TypeInfoVarLocns,
|
|
TypeInfoDataMap).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred continuation_info__live_value_type(slot_contents::in,
|
|
live_value_type::out) is det.
|
|
|
|
continuation_info__live_value_type(lval(succip), succip).
|
|
continuation_info__live_value_type(lval(hp), hp).
|
|
continuation_info__live_value_type(lval(maxfr), maxfr).
|
|
continuation_info__live_value_type(lval(curfr), curfr).
|
|
continuation_info__live_value_type(lval(succfr(_)), unwanted).
|
|
continuation_info__live_value_type(lval(prevfr(_)), unwanted).
|
|
continuation_info__live_value_type(lval(redofr(_)), unwanted).
|
|
continuation_info__live_value_type(lval(redoip(_)), unwanted).
|
|
continuation_info__live_value_type(lval(succip(_)), unwanted).
|
|
continuation_info__live_value_type(lval(sp), unwanted).
|
|
continuation_info__live_value_type(lval(lvar(_)), unwanted).
|
|
continuation_info__live_value_type(lval(field(_, _, _)), unwanted).
|
|
continuation_info__live_value_type(lval(temp(_, _)), unwanted).
|
|
continuation_info__live_value_type(lval(reg(_, _)), unwanted).
|
|
continuation_info__live_value_type(lval(stackvar(_)), unwanted).
|
|
continuation_info__live_value_type(lval(framevar(_)), unwanted).
|
|
continuation_info__live_value_type(lval(mem_ref(_)), unwanted). % XXX
|
|
continuation_info__live_value_type(ticket, unwanted). % XXX we may need to
|
|
% modify this, if the GC is going
|
|
% to garbage-collect the trail.
|
|
continuation_info__live_value_type(ticket_counter, unwanted).
|
|
continuation_info__live_value_type(sync_term, unwanted).
|
|
continuation_info__live_value_type(trace_data, unwanted).
|
|
|
|
%-----------------------------------------------------------------------------%
|