Files
mercury/compiler/continuation_info.m
Simon Taylor 2725b1a331 Aditi update syntax, type and mode checking.
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.
1999-07-13 08:55:28 +00:00

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).
%-----------------------------------------------------------------------------%