mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-13 12:53:53 +00:00
3124 lines
107 KiB
Mathematica
3124 lines
107 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-1998 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: code_info.m
|
|
%
|
|
% Main authors: conway, zs.
|
|
%
|
|
% This file defines the code_info type and various operations on it.
|
|
% The code_info structure is the 'state' of the code generator.
|
|
%
|
|
% This file is organized into eight submodules:
|
|
%
|
|
% - the code_info structure and its access predicates
|
|
% - simple wrappers around access predicates
|
|
% - handling failure continuations
|
|
% - handling liveness issues
|
|
% - saving and restoring heap pointers, trail tickets etc
|
|
% - interfacing to code_exprn
|
|
% - managing the info required by garbage collection and value numbering
|
|
% - managing stack slots
|
|
%
|
|
% Note: Any new "state" arguments (eg counters) that should be strictly
|
|
% threaded (for example the counter used for allocating new labels) will
|
|
% require changes to code_info__slap_code_info/3.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module code_info.
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds_module, hlds_pred, hlds_goal, llds, instmap, trace.
|
|
:- import_module continuation_info, prog_data, hlds_data, globals.
|
|
|
|
:- import_module bool, set, varset, list, map, term, std_util, assoc_list.
|
|
|
|
:- implementation.
|
|
|
|
:- import_module code_util, code_exprn, prog_out.
|
|
:- import_module arg_info, type_util, mode_util, options.
|
|
|
|
:- import_module set, varset, stack.
|
|
:- import_module string, require, char, bimap, tree, int.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Submodule for the code_info type and its access predicates.
|
|
%
|
|
% This submodule has the following components:
|
|
%
|
|
% declarations for exported access predicates
|
|
% declarations for non-exported access predicates
|
|
% the definition of the type and the init predicate
|
|
% the definition of the get access predicates
|
|
% the definition of the set access predicates
|
|
%
|
|
% Please keep the order of mention of the various fields
|
|
% consistent in each of these five components.
|
|
|
|
:- interface.
|
|
|
|
:- type code_info.
|
|
|
|
% Create a new code_info structure.
|
|
:- pred code_info__init(varset, set(var), stack_slots, bool, globals,
|
|
pred_id, proc_id, proc_info, instmap, follow_vars, module_info,
|
|
int /* cell number */, code_info).
|
|
:- mode code_info__init(in, in, in, in, in, in, in, in, in, in, in, in,
|
|
out) is det.
|
|
|
|
% Get the variables for the current procedure.
|
|
:- pred code_info__get_varset(varset, code_info, code_info).
|
|
:- mode code_info__get_varset(out, in, out) is det.
|
|
|
|
% Get the id of the predicate we are generating code for.
|
|
:- pred code_info__get_pred_id(pred_id, code_info, code_info).
|
|
:- mode code_info__get_pred_id(out, in, out) is det.
|
|
|
|
% Get the id of the procedure we are generating code for.
|
|
:- pred code_info__get_proc_id(proc_id, code_info, code_info).
|
|
:- mode code_info__get_proc_id(out, in, out) is det.
|
|
|
|
% Get the HLDS of the procedure we are generating code for.
|
|
:- pred code_info__get_proc_info(proc_info, code_info, code_info).
|
|
:- mode code_info__get_proc_info(out, in, out) is det.
|
|
|
|
% Get the flag that indicates whether succip is used or not.
|
|
:- pred code_info__get_succip_used(bool, code_info, code_info).
|
|
:- mode code_info__get_succip_used(out, in, out) is det.
|
|
|
|
% Get the HLDS of the entire module.
|
|
:- pred code_info__get_module_info(module_info, code_info, code_info).
|
|
:- mode code_info__get_module_info(out, in, out) is det.
|
|
|
|
% Get the set of currently forward-live variables.
|
|
:- pred code_info__get_forward_live_vars(set(var), code_info, code_info).
|
|
:- mode code_info__get_forward_live_vars(out, in, out) is det.
|
|
|
|
% Set the set of currently forward-live variables.
|
|
:- pred code_info__set_forward_live_vars(set(var), code_info, code_info).
|
|
:- mode code_info__set_forward_live_vars(in, in, out) is det.
|
|
|
|
% Get the table mapping variables to the current
|
|
% instantiation states.
|
|
:- pred code_info__get_instmap(instmap, code_info, code_info).
|
|
:- mode code_info__get_instmap(out, in, out) is det.
|
|
|
|
% Set the table mapping variables to the current
|
|
% instantiation states.
|
|
:- pred code_info__set_instmap(instmap, code_info, code_info).
|
|
:- mode code_info__set_instmap(in, in, out) is det.
|
|
|
|
% Get the globals table.
|
|
:- pred code_info__get_globals(globals, code_info, code_info).
|
|
:- mode code_info__get_globals(out, in, out) is det.
|
|
|
|
:- pred code_info__get_layout_info(map(label, internal_layout_info),
|
|
code_info, code_info).
|
|
:- mode code_info__get_layout_info(out, in, out) is det.
|
|
|
|
:- pred code_info__get_maybe_trace_info(maybe(trace_info),
|
|
code_info, code_info).
|
|
:- mode code_info__get_maybe_trace_info(out, in, out) is det.
|
|
|
|
:- pred code_info__set_maybe_trace_info(maybe(trace_info),
|
|
code_info, code_info).
|
|
:- mode code_info__set_maybe_trace_info(in, in, out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- pred code_info__get_var_slot_count(int, code_info, code_info).
|
|
:- mode code_info__get_var_slot_count(out, in, out) is det.
|
|
|
|
:- pred code_info__get_label_count(int, code_info, code_info).
|
|
:- mode code_info__get_label_count(out, in, out) is det.
|
|
|
|
:- pred code_info__set_label_count(int, code_info, code_info).
|
|
:- mode code_info__set_label_count(in, in, out) is det.
|
|
|
|
:- pred code_info__set_cell_count(int, code_info, code_info).
|
|
:- mode code_info__set_cell_count(in, in, out) is det.
|
|
|
|
:- pred code_info__get_exprn_info(exprn_info, code_info, code_info).
|
|
:- mode code_info__get_exprn_info(out, in, out) is det.
|
|
|
|
:- pred code_info__set_exprn_info(exprn_info, code_info, code_info).
|
|
:- mode code_info__set_exprn_info(in, in, out) is det.
|
|
|
|
:- pred code_info__set_succip_used(bool, code_info, code_info).
|
|
:- mode code_info__set_succip_used(in, in, out) is det.
|
|
|
|
:- pred code_info__get_fail_stack(fail_stack, code_info, code_info).
|
|
:- mode code_info__get_fail_stack(out, in, out) is det.
|
|
|
|
:- pred code_info__set_fail_stack(fail_stack, code_info, code_info).
|
|
:- mode code_info__set_fail_stack(in, in, out) is det.
|
|
|
|
:- pred code_info__get_avail_temp_slots(set(lval), code_info, code_info).
|
|
:- mode code_info__get_avail_temp_slots(out, in, out) is det.
|
|
|
|
:- pred code_info__set_avail_temp_slots(set(lval), code_info, code_info).
|
|
:- mode code_info__set_avail_temp_slots(in, in, out) is det.
|
|
|
|
:- pred code_info__get_max_temp_slot_count(int, code_info, code_info).
|
|
:- mode code_info__get_max_temp_slot_count(out, in, out) is det.
|
|
|
|
:- pred code_info__set_max_temp_slot_count(int, code_info, code_info).
|
|
:- mode code_info__set_max_temp_slot_count(in, in, out) is det.
|
|
|
|
:- pred code_info__get_temps_in_use(map(lval, slot_contents),
|
|
code_info, code_info).
|
|
:- mode code_info__get_temps_in_use(out, in, out) is det.
|
|
|
|
:- pred code_info__set_temps_in_use(map(lval, slot_contents),
|
|
code_info, code_info).
|
|
:- mode code_info__set_temps_in_use(in, in, out) is det.
|
|
|
|
:- pred code_info__set_layout_info(map(label, internal_layout_info),
|
|
code_info, code_info).
|
|
:- mode code_info__set_layout_info(in, in, out) is det.
|
|
|
|
:- pred code_info__get_zombies(set(var), code_info, code_info).
|
|
:- mode code_info__get_zombies(out, in, out) is det.
|
|
|
|
:- pred code_info__set_zombies(set(var), code_info, code_info).
|
|
:- mode code_info__set_zombies(in, in, out) is det.
|
|
|
|
:- pred code_info__get_resume_point_stack(stack(set(var)),
|
|
code_info, code_info).
|
|
:- mode code_info__get_resume_point_stack(out, in, out) is det.
|
|
|
|
:- pred code_info__set_resume_point_stack(stack(set(var)),
|
|
code_info, code_info).
|
|
:- mode code_info__set_resume_point_stack(in, in, out) is det.
|
|
|
|
:- pred code_info__get_commit_triple_count(int, code_info, code_info).
|
|
:- mode code_info__get_commit_triple_count(out, in, out) is det.
|
|
|
|
:- pred code_info__set_commit_triple_count(int, code_info, code_info).
|
|
:- mode code_info__set_commit_triple_count(in, in, out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type code_info --->
|
|
code_info(
|
|
int, % The number of stack slots allocated.
|
|
% for storing variables.
|
|
% (Some extra stack slots are used
|
|
% for saving and restoring registers.)
|
|
int, % Counter for the local labels used
|
|
% by this procedure.
|
|
varset, % The variables in this procedure.
|
|
pred_id, % The label of the current predicate.
|
|
proc_id, % The label of the current procedure.
|
|
int, % Counter for cells in this proc.
|
|
exprn_info, % A map storing the information about
|
|
% the status of each variable.
|
|
proc_info, % The proc_info for the this procedure.
|
|
bool, % do we need to store succip?
|
|
fail_stack, % The failure continuation stack
|
|
module_info, % The module_info structure - you just
|
|
% never know when you might need it.
|
|
% It should be read-only.
|
|
set(var), % Variables that are forward live
|
|
% after this goal
|
|
instmap, % insts of variables
|
|
set(lval), % Stack variables that have been used
|
|
% for temporaries and are now again
|
|
% available for reuse.
|
|
int, % The maximum number of extra
|
|
% temporary stackslots that have been
|
|
% used during the procedure
|
|
globals, % code generation options
|
|
map(lval, slot_contents),
|
|
% The temp locations in use on the stack
|
|
% and what they contain (for gc).
|
|
map(label, internal_layout_info),
|
|
% Information on which values
|
|
% are live and where at which labels,
|
|
% for tracing and/or accurate gc.
|
|
set(var), % Zombie variables; variables that have
|
|
% been killed but are protected by a
|
|
% resume point.
|
|
stack(set(var)),
|
|
% Each resumption point has an
|
|
% associated set of variables
|
|
% whose values may be needed on
|
|
% resumption at that point.
|
|
% This field gives those variables
|
|
% for a nested set of resumption
|
|
% points. Each element must be
|
|
% a superset of the ones below.
|
|
% When a variable included in the top
|
|
% set becomes no longer forward live,
|
|
% we must save its value to the stack.
|
|
int,
|
|
% A count of how many triples of
|
|
% curfr, maxfr and redoip are live on
|
|
% the det stack. These triples are
|
|
% pushed onto the det stack when
|
|
% generating code for commits within
|
|
% model_non procedures. The value
|
|
% numbering pass and the accurate
|
|
% garbage collector need to know about
|
|
% these slots. (Triple is a misnomer:
|
|
% in grades with trailing, it is four.)
|
|
maybe(trace_info)
|
|
% Information about which stack slots
|
|
% the call sequence number and depth
|
|
% are stored, provided tracing is
|
|
% switched on.
|
|
).
|
|
|
|
:- type slot_contents
|
|
---> ticket % a ticket (trail pointer)
|
|
; ticket_counter % a copy of the ticket counter
|
|
; trace_data
|
|
; lval(lval).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__init(Varset, Liveness, StackSlots, SaveSuccip, Globals,
|
|
PredId, ProcId, ProcInfo, Requests, FollowVars,
|
|
ModuleInfo, CellCount, C) :-
|
|
proc_info_headvars(ProcInfo, HeadVars),
|
|
proc_info_arg_info(ProcInfo, ArgInfos),
|
|
assoc_list__from_corresponding_lists(HeadVars, ArgInfos, Args),
|
|
arg_info__build_input_arg_list(Args, ArgList),
|
|
globals__get_options(Globals, Options),
|
|
code_exprn__init_state(ArgList, Varset, StackSlots, FollowVars,
|
|
Options, ExprnInfo),
|
|
stack__init(Continue),
|
|
stack__init(ResumeSetStack0),
|
|
set__init(AvailSlots0),
|
|
map__init(TempsInUse0),
|
|
set__init(Zombies0),
|
|
map__init(Shapes),
|
|
code_info__max_var_slot(StackSlots, VarSlotCount0),
|
|
proc_info_interface_code_model(ProcInfo, CodeModel),
|
|
(
|
|
CodeModel = model_non
|
|
->
|
|
VarSlotCount is VarSlotCount0 + 1
|
|
;
|
|
VarSlotCount = VarSlotCount0
|
|
),
|
|
C = code_info(
|
|
VarSlotCount,
|
|
0,
|
|
Varset,
|
|
PredId,
|
|
ProcId,
|
|
CellCount,
|
|
ExprnInfo,
|
|
ProcInfo,
|
|
SaveSuccip,
|
|
Continue,
|
|
ModuleInfo,
|
|
Liveness,
|
|
Requests,
|
|
AvailSlots0,
|
|
0,
|
|
Globals,
|
|
TempsInUse0,
|
|
Shapes,
|
|
Zombies0,
|
|
ResumeSetStack0,
|
|
0,
|
|
no
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__get_var_slot_count(A, CI, CI) :-
|
|
CI = code_info(A, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_label_count(B, CI, CI) :-
|
|
CI = code_info(_, B, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_varset(C, CI, CI) :-
|
|
CI = code_info(_, _, C, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_pred_id(D, CI, CI) :-
|
|
CI = code_info(_, _, _, D, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_proc_id(E, CI, CI) :-
|
|
CI = code_info(_, _, _, _, E, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_cell_count(F, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, F, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_exprn_info(G, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, G, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_proc_info(H, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, H, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_succip_used(I, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, I, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_fail_stack(J, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, J, _, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_module_info(K, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, K, _, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_forward_live_vars(L, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, L, _, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_instmap(M, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, M, _, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_avail_temp_slots(N, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, N, _, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_max_temp_slot_count(O, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, O, _, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_globals(P, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, P, _, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_temps_in_use(Q, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, Q, _, _,
|
|
_, _, _).
|
|
|
|
code_info__get_layout_info(R, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, R, _,
|
|
_, _, _).
|
|
|
|
code_info__get_zombies(S, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, S,
|
|
_, _, _).
|
|
|
|
code_info__get_resume_point_stack(T, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
T, _, _).
|
|
|
|
code_info__get_commit_triple_count(U, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, U, _).
|
|
|
|
code_info__get_maybe_trace_info(V, CI, CI) :-
|
|
CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, V).
|
|
|
|
% :- type code_info --->
|
|
% code_info(
|
|
% A int, % The number of stack slots allocated.
|
|
% % for storing variables.
|
|
% % (Some extra stack slots are used
|
|
% % for saving and restoring registers.)
|
|
% B int, % Counter for the local labels used
|
|
% % by this procedure.
|
|
% C varset, % The variables in this procedure.
|
|
% D pred_id, % The label of the current predicate.
|
|
% E proc_id, % The label of the current procedure.
|
|
% F int, % Counter for cells in this proc.
|
|
% G exprn_info, % A map storing the information about
|
|
% % the status of each variable.
|
|
% H proc_info, % The proc_info for the this procedure.
|
|
% I bool, % do we need to store succip?
|
|
% J fail_stack, % The failure continuation stack
|
|
% K module_info, % The module_info structure - you just
|
|
% % never know when you might need it.
|
|
% % It should be read-only.
|
|
% L set(var), % Variables that are forward live
|
|
% % after this goal
|
|
% M instmap, % insts of variables
|
|
% N set(lval), % Stack variables that have been used
|
|
% % for temporaries and are now again
|
|
% % available for reuse.
|
|
% O int, % The maximum number of extra
|
|
% % temporary stackslots that have been
|
|
% % used during the procedure
|
|
% P globals, % code generation options
|
|
% Q map(lval, slot_contents),
|
|
% % The temp locations in use on the stack
|
|
% % and what they contain (for gc).
|
|
% R map(label, internal_layout_info),
|
|
% % Information on which values
|
|
% % are live and where at which labels,
|
|
% % for tracing and/or accurate gc.
|
|
% S set(var), % Zombie variables; variables that have
|
|
% % been killed but are protected by a
|
|
% % resume point.
|
|
% T stack(set(var)),
|
|
% % Each resumption point has an
|
|
% % associated set of variables
|
|
% % whose values may be needed on
|
|
% % resumption at that point.
|
|
% % This field gives those variables
|
|
% % for a nested set of resumption
|
|
% % points. Each element must be
|
|
% % a superset of the ones below.
|
|
% % When a variable included in the top
|
|
% % set becomes no longer forward live,
|
|
% % we must save its value to the stack.
|
|
% U int,
|
|
% % A count of how many triples of
|
|
% % curfr, maxfr and redoip are live on
|
|
% % the det stack. These triples are
|
|
% % pushed onto the det stack when
|
|
% % generating code for commits within
|
|
% % model_non procedures. The value
|
|
% % numbering pass and the accurate
|
|
% % garbage collector need to know about
|
|
% % these slots. (Triple is a misnomer:
|
|
% % in grades with trailing, it is four.)
|
|
% V maybe(trace_info)
|
|
% % Information about which stack slots
|
|
% % the call sequence number and depth
|
|
% % are stored, provided tracing is
|
|
% % switched on.
|
|
% ).
|
|
%
|
|
% we don't need
|
|
% code_info__set_var_slot_count
|
|
% code_info__set_varset
|
|
% code_info__set_pred_id
|
|
% code_info__set_proc_id
|
|
% code_info__set_module_info
|
|
% code_info__set_globals
|
|
% code_info__set_code_model
|
|
|
|
code_info__set_label_count(B, CI0, CI) :-
|
|
CI0 = code_info(A, _, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_cell_count(F, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, _, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_exprn_info(G, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, _, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_succip_used(I, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, _, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_fail_stack(J, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, _, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_forward_live_vars(L, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, _, M, N, O, P, Q,
|
|
R, S, T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_instmap(M, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, _, N, O, P, Q,
|
|
R, S, T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_avail_temp_slots(N, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, _, O, P, Q,
|
|
R, S, T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_max_temp_slot_count(O, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, _, P, Q,
|
|
R, S, T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_temps_in_use(Q, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, _,
|
|
R, S, T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_layout_info(R, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
_, S, T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_zombies(S, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, _, T, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_resume_point_stack(T, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, _, U, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_commit_triple_count(U, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, _, V),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
code_info__set_maybe_trace_info(V, CI0, CI) :-
|
|
CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, _),
|
|
CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
|
|
R, S, T, U, V).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Submodule for simple wrappers around access predicates.
|
|
|
|
:- interface.
|
|
|
|
% Get the hlds mapping from variables to stack slots
|
|
:- pred code_info__get_stack_slots(stack_slots, code_info, code_info).
|
|
:- mode code_info__get_stack_slots(out, in, out) is det.
|
|
|
|
% Get the table that contains advice about where
|
|
% variables should be put.
|
|
:- pred code_info__get_follow_vars(follow_vars, code_info, code_info).
|
|
:- mode code_info__get_follow_vars(out, in, out) is det.
|
|
|
|
% Set the table that contains advice about where
|
|
% variables should be put.
|
|
:- pred code_info__set_follow_vars(follow_vars, code_info, code_info).
|
|
:- mode code_info__set_follow_vars(in, in, out) is det.
|
|
|
|
% code_info__pre_goal_update(GoalInfo, Atomic, OldCodeInfo, NewCodeInfo)
|
|
% updates OldCodeInfo to produce NewCodeInfo with the changes
|
|
% specified by GoalInfo.
|
|
:- pred code_info__pre_goal_update(hlds_goal_info, bool, code_info, code_info).
|
|
:- mode code_info__pre_goal_update(in, in, in, out) is det.
|
|
|
|
% code_info__post_goal_update(GoalInfo, OldCodeInfo, NewCodeInfo)
|
|
% updates OldCodeInfo to produce NewCodeInfo with the changes described
|
|
% by GoalInfo.
|
|
:- pred code_info__post_goal_update(hlds_goal_info, code_info, code_info).
|
|
:- mode code_info__post_goal_update(in, in, out) is det.
|
|
|
|
% Find out the type of the given variable.
|
|
:- pred code_info__variable_type(var, type, code_info, code_info).
|
|
:- mode code_info__variable_type(in, out, in, out) is det.
|
|
|
|
:- pred code_info__lookup_type_defn(type, hlds_type_defn,
|
|
code_info, code_info).
|
|
:- mode code_info__lookup_type_defn(in, out, in, out) is det.
|
|
|
|
% Given a list of type variables, find the lvals where the
|
|
% corresponding type_infos and typeclass_infos are being stored.
|
|
:- pred code_info__find_type_infos(list(var), assoc_list(var, lval),
|
|
code_info, code_info).
|
|
:- mode code_info__find_type_infos(in, out, in, out) is det.
|
|
|
|
% Given a constructor id, and a variable (so that we can work out the
|
|
% type of the constructor), determine correct tag (representation)
|
|
% of that constructor.
|
|
:- pred code_info__cons_id_to_tag(var, cons_id, cons_tag, code_info, code_info).
|
|
:- mode code_info__cons_id_to_tag(in, in, out, in, out) is det.
|
|
|
|
% Get the code model of the current procedure.
|
|
:- pred code_info__get_proc_model(code_model, code_info, code_info).
|
|
:- mode code_info__get_proc_model(out, in, out) is det.
|
|
|
|
:- pred code_info__get_headvars(list(var), code_info, code_info).
|
|
:- mode code_info__get_headvars(out, in, out) is det.
|
|
|
|
% Get the call argument information for the current procedure
|
|
:- pred code_info__get_arginfo(list(arg_info), code_info, code_info).
|
|
:- mode code_info__get_arginfo(out, in, out) is det.
|
|
|
|
% Get the call argument info for a given mode of a given predicate
|
|
:- pred code_info__get_pred_proc_arginfo(pred_id, proc_id, list(arg_info),
|
|
code_info, code_info).
|
|
:- mode code_info__get_pred_proc_arginfo(in, in, out, in, out) is det.
|
|
|
|
% Pop the failure continuation stack.
|
|
:- pred code_info__pop_failure_cont(code_info, code_info).
|
|
:- mode code_info__pop_failure_cont(in, out) is det.
|
|
|
|
:- pred code_info__push_resume_point_vars(set(var), code_info, code_info).
|
|
:- mode code_info__push_resume_point_vars(in, in, out) is det.
|
|
|
|
:- pred code_info__pop_resume_point_vars(code_info, code_info).
|
|
:- mode code_info__pop_resume_point_vars(in, out) is det.
|
|
|
|
:- pred code_info__variable_to_string(var, string, code_info, code_info).
|
|
:- mode code_info__variable_to_string(in, out, in, out) is det.
|
|
|
|
:- pred code_info__grab_code_info(code_info, code_info, code_info).
|
|
:- mode code_info__grab_code_info(out, in, out) is det.
|
|
|
|
:- pred code_info__slap_code_info(code_info, code_info, code_info).
|
|
:- mode code_info__slap_code_info(in, in, out) is det.
|
|
|
|
:- pred code_info__apply_instmap_delta(instmap_delta, code_info, code_info).
|
|
:- mode code_info__apply_instmap_delta(in, in, out) is det.
|
|
|
|
% Create a code address which holds the address of the specified
|
|
% procedure.
|
|
% The fourth argument should be `no' if the the caller wants the
|
|
% returned address to be valid from everywhere in the program.
|
|
% If being valid from within the current procedure is enough,
|
|
% this argument should be `yes' wrapped around the value of the
|
|
% --procs-per-c-function option and the current procedure id.
|
|
% Using an address that is only valid from within the current
|
|
% procedure may make jumps more efficient.
|
|
% XXX
|
|
:- pred code_info__make_entry_label(module_info, pred_id, proc_id, bool,
|
|
code_addr, code_info, code_info).
|
|
:- mode code_info__make_entry_label(in, in, in, in, out, in, out) is det.
|
|
|
|
% Generate the next local label in sequence.
|
|
:- pred code_info__get_next_label(label, code_info, code_info).
|
|
:- mode code_info__get_next_label(out, in, out) is det.
|
|
|
|
% Generate the next cell number in sequence.
|
|
:- pred code_info__get_next_cell_number(int, code_info, code_info).
|
|
:- mode code_info__get_next_cell_number(out, in, out) is det.
|
|
|
|
% Get the current cell number.
|
|
:- pred code_info__get_cell_count(int, code_info, code_info).
|
|
:- mode code_info__get_cell_count(out, in, out) is det.
|
|
|
|
:- pred code_info__succip_is_used(code_info, code_info).
|
|
:- mode code_info__succip_is_used(in, out) is det.
|
|
|
|
:- pred code_info__add_layout_for_label(label, internal_layout_info,
|
|
code_info, code_info).
|
|
:- mode code_info__add_layout_for_label(in, in, in, out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- pred code_info__push_failure_cont(failure_cont, code_info, code_info).
|
|
:- mode code_info__push_failure_cont(in, in, out) is det.
|
|
|
|
% Lookup the value on the top of the failure continuation stack
|
|
|
|
:- pred code_info__top_failure_cont(failure_cont, code_info, code_info).
|
|
:- mode code_info__top_failure_cont(out, in, out) is det.
|
|
|
|
:- pred code_info__current_resume_point_vars(set(var), code_info, code_info).
|
|
:- mode code_info__current_resume_point_vars(out, in, out) is det.
|
|
|
|
:- pred code_info__add_commit_triple(code_info, code_info).
|
|
:- mode code_info__add_commit_triple(in, out) is det.
|
|
|
|
:- pred code_info__rem_commit_triple(code_info, code_info).
|
|
:- mode code_info__rem_commit_triple(in, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
code_info__get_stack_slots(StackSlots, CI, CI) :-
|
|
code_info__get_exprn_info(ExprnInfo, CI, _),
|
|
code_exprn__get_stack_slots(StackSlots, ExprnInfo, _).
|
|
|
|
code_info__get_follow_vars(FollowVars, CI, CI) :-
|
|
code_info__get_exprn_info(ExprnInfo, CI, _),
|
|
code_exprn__get_follow_vars(FollowVars, ExprnInfo, _).
|
|
|
|
code_info__set_follow_vars(FollowVars, CI0, CI) :-
|
|
code_info__get_exprn_info(ExprnInfo0, CI0, _),
|
|
code_exprn__set_follow_vars(FollowVars, ExprnInfo0, ExprnInfo),
|
|
code_info__set_exprn_info(ExprnInfo, CI0, CI).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Update the code info structure to be consistent
|
|
% immediately prior to generating a goal
|
|
code_info__pre_goal_update(GoalInfo, Atomic) -->
|
|
% The liveness pass puts resume_point annotations on some kinds
|
|
% of goals. The parts of the code generator that handle those kinds
|
|
% of goals should handle the resume point annotation as well;
|
|
% when they do, they remove the annotation. The following code
|
|
% is a sanity check to make sure that this has in fact been done.
|
|
{ goal_info_get_resume_point(GoalInfo, ResumePoint) },
|
|
(
|
|
{ ResumePoint = no_resume_point }
|
|
;
|
|
{ ResumePoint = resume_point(_, _) },
|
|
{ error("pre_goal_update with resume point") }
|
|
),
|
|
{ goal_info_get_follow_vars(GoalInfo, MaybeFollowVars) },
|
|
(
|
|
{ MaybeFollowVars = yes(FollowVars) },
|
|
code_info__set_follow_vars(FollowVars)
|
|
;
|
|
{ MaybeFollowVars = no }
|
|
),
|
|
% note: we must be careful to apply deaths before births
|
|
{ goal_info_get_pre_deaths(GoalInfo, PreDeaths) },
|
|
code_info__rem_forward_live_vars(PreDeaths),
|
|
code_info__make_vars_forward_dead(PreDeaths),
|
|
{ goal_info_get_pre_births(GoalInfo, PreBirths) },
|
|
code_info__add_forward_live_vars(PreBirths),
|
|
( { Atomic = yes } ->
|
|
{ goal_info_get_post_deaths(GoalInfo, PostDeaths) },
|
|
code_info__rem_forward_live_vars(PostDeaths)
|
|
;
|
|
[]
|
|
).
|
|
|
|
% Update the code info structure to be consistent
|
|
% immediately after generating a goal
|
|
code_info__post_goal_update(GoalInfo) -->
|
|
% note: we must be careful to apply deaths before births
|
|
{ goal_info_get_post_deaths(GoalInfo, PostDeaths) },
|
|
code_info__rem_forward_live_vars(PostDeaths),
|
|
code_info__make_vars_forward_dead(PostDeaths),
|
|
{ goal_info_get_post_births(GoalInfo, PostBirths) },
|
|
code_info__add_forward_live_vars(PostBirths),
|
|
code_info__make_vars_forward_live(PostBirths),
|
|
{ goal_info_get_instmap_delta(GoalInfo, InstMapDelta) },
|
|
code_info__apply_instmap_delta(InstMapDelta).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__variable_type(Var, Type) -->
|
|
code_info__get_proc_info(ProcInfo),
|
|
{ proc_info_vartypes(ProcInfo, VarTypes) },
|
|
{ map__lookup(VarTypes, Var, Type) }.
|
|
|
|
code_info__lookup_type_defn(Type, TypeDefn) -->
|
|
code_info__get_module_info(ModuleInfo),
|
|
{ type_to_type_id(Type, TypeIdPrime, _) ->
|
|
TypeId = TypeIdPrime
|
|
;
|
|
error("unknown type in code_aux__lookup_type_defn")
|
|
},
|
|
{ module_info_types(ModuleInfo, TypeTable) },
|
|
{ map__lookup(TypeTable, TypeId, TypeDefn) }.
|
|
|
|
code_info__find_type_infos([], []) --> [].
|
|
code_info__find_type_infos([TVar | TVars], [TVar - Lval | Lvals]) -->
|
|
code_info__get_proc_info(ProcInfo),
|
|
{ proc_info_typeinfo_varmap(ProcInfo, TypeInfoMap) },
|
|
{
|
|
map__search(TypeInfoMap, TVar, Locn)
|
|
->
|
|
type_info_locn_var(Locn, Var)
|
|
;
|
|
error("cannot find var for type variable")
|
|
},
|
|
{ proc_info_stack_slots(ProcInfo, StackSlots) },
|
|
(
|
|
{ map__search(StackSlots, Var, Lval0) }
|
|
->
|
|
{ Lval = Lval0 }
|
|
;
|
|
code_info__variable_to_string(Var, VarString),
|
|
{ string__format("code_info__find_type_infos: can't find lval for type_info var %s",
|
|
[s(VarString)], ErrStr) },
|
|
{ error(ErrStr) }
|
|
),
|
|
code_info__find_type_infos(TVars, Lvals).
|
|
|
|
code_info__cons_id_to_tag(Var, ConsId, ConsTag) -->
|
|
code_info__variable_type(Var, Type),
|
|
code_info__get_module_info(ModuleInfo),
|
|
{ code_util__cons_id_to_tag(ConsId, Type, ModuleInfo, ConsTag) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__get_proc_model(CodeModel) -->
|
|
code_info__get_proc_info(ProcInfo),
|
|
{ proc_info_interface_code_model(ProcInfo, CodeModel) }.
|
|
|
|
code_info__get_headvars(HeadVars) -->
|
|
code_info__get_module_info(ModuleInfo),
|
|
code_info__get_pred_id(PredId),
|
|
code_info__get_proc_id(ProcId),
|
|
{ module_info_preds(ModuleInfo, Preds) },
|
|
{ map__lookup(Preds, PredId, PredInfo) },
|
|
{ pred_info_procedures(PredInfo, Procs) },
|
|
{ map__lookup(Procs, ProcId, ProcInfo) },
|
|
{ proc_info_headvars(ProcInfo, HeadVars) }.
|
|
|
|
code_info__get_arginfo(ArgInfo) -->
|
|
code_info__get_pred_id(PredId),
|
|
code_info__get_proc_id(ProcId),
|
|
code_info__get_pred_proc_arginfo(PredId, ProcId, ArgInfo).
|
|
|
|
code_info__get_pred_proc_arginfo(PredId, ProcId, ArgInfo) -->
|
|
code_info__get_module_info(ModuleInfo),
|
|
{ module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo) },
|
|
{ proc_info_arg_info(ProcInfo, ArgInfo) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__push_failure_cont(Cont) -->
|
|
code_info__get_fail_stack(Fall0),
|
|
{ stack__push(Fall0, Cont, Fall) },
|
|
code_info__set_fail_stack(Fall).
|
|
|
|
code_info__pop_failure_cont -->
|
|
code_info__get_fail_stack(Fall0),
|
|
( { stack__pop(Fall0, _, Fall) } ->
|
|
code_info__set_fail_stack(Fall)
|
|
;
|
|
{ error("code_info__pop_failure_cont: empty stack") }
|
|
).
|
|
|
|
code_info__top_failure_cont(Cont) -->
|
|
code_info__get_fail_stack(Fall),
|
|
( { stack__top(Fall, Cont0) } ->
|
|
{ Cont = Cont0 }
|
|
;
|
|
{ error("code_info__failure_cont: no failure continuation") }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__current_resume_point_vars(ResumeVars) -->
|
|
code_info__get_resume_point_stack(ResumeStack),
|
|
{ stack__top(ResumeStack, TopVars) ->
|
|
ResumeVars = TopVars
|
|
;
|
|
set__init(ResumeVars)
|
|
}.
|
|
|
|
code_info__push_resume_point_vars(ResumeVars) -->
|
|
code_info__get_resume_point_stack(ResumeStack0),
|
|
{ stack__top(ResumeStack0, OldTopVars) ->
|
|
require(set__subset(OldTopVars, ResumeVars),
|
|
"new resume point variable set does not include old one")
|
|
;
|
|
true
|
|
},
|
|
{ stack__push(ResumeStack0, ResumeVars, ResumeStack) },
|
|
code_info__set_resume_point_stack(ResumeStack).
|
|
|
|
code_info__pop_resume_point_vars -->
|
|
code_info__get_resume_point_stack(ResumeStack0),
|
|
{ stack__pop_det(ResumeStack0, _, ResumeStack) },
|
|
code_info__set_resume_point_stack(ResumeStack).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__add_commit_triple -->
|
|
code_info__get_commit_triple_count(Count0),
|
|
{ Count is Count0 + 1 },
|
|
code_info__set_commit_triple_count(Count).
|
|
|
|
code_info__rem_commit_triple -->
|
|
code_info__get_commit_triple_count(Count0),
|
|
{ Count is Count0 - 1 },
|
|
code_info__set_commit_triple_count(Count).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__variable_to_string(Var, Name) -->
|
|
code_info__get_varset(Varset),
|
|
{ varset__lookup_name(Varset, Var, Name) }.
|
|
|
|
code_info__grab_code_info(C, C, C).
|
|
|
|
code_info__slap_code_info(C0, C1, C) :-
|
|
code_info__get_label_count(L, C1, _),
|
|
code_info__set_label_count(L, C0, C2),
|
|
code_info__get_succip_used(S, C1, _),
|
|
code_info__set_succip_used(S, C2, C3),
|
|
code_info__get_fail_stack(J, C0, _),
|
|
code_info__set_fail_stack(J, C3, C4),
|
|
code_info__get_max_temp_slot_count(PC, C1, _),
|
|
code_info__set_max_temp_slot_count(PC, C4, C5),
|
|
code_info__get_layout_info(LayoutInfo, C1, _),
|
|
code_info__set_layout_info(LayoutInfo, C5, C6),
|
|
code_info__get_cell_count(CellCount, C1, _),
|
|
code_info__set_cell_count(CellCount, C6, C).
|
|
|
|
code_info__apply_instmap_delta(Delta) -->
|
|
code_info__get_instmap(InstMap0),
|
|
{ instmap__apply_instmap_delta(InstMap0, Delta, InstMap) },
|
|
code_info__set_instmap(InstMap).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__make_entry_label(ModuleInfo, PredId, ProcId, Immed0, PredAddress) -->
|
|
(
|
|
{ Immed0 = no },
|
|
{ Immed = no }
|
|
;
|
|
{ Immed0 = yes },
|
|
code_info__get_globals(Globals),
|
|
{ globals__lookup_int_option(Globals, procs_per_c_function,
|
|
ProcsPerFunc) },
|
|
code_info__get_pred_id(CurPredId),
|
|
code_info__get_proc_id(CurProcId),
|
|
{ Immed = yes(ProcsPerFunc - proc(CurPredId, CurProcId)) }
|
|
),
|
|
{ code_util__make_entry_label(ModuleInfo, PredId, ProcId, Immed,
|
|
PredAddress) }.
|
|
|
|
code_info__get_next_label(Label) -->
|
|
code_info__get_module_info(ModuleInfo),
|
|
code_info__get_pred_id(PredId),
|
|
code_info__get_proc_id(ProcId),
|
|
code_info__get_label_count(N0),
|
|
{ N is N0 + 1 },
|
|
code_info__set_label_count(N),
|
|
{ code_util__make_internal_label(ModuleInfo, PredId, ProcId, N,
|
|
Label) }.
|
|
|
|
code_info__get_next_cell_number(N) -->
|
|
code_info__get_cell_count(N0),
|
|
{ N is N0 + 1 },
|
|
code_info__set_cell_count(N).
|
|
|
|
code_info__succip_is_used -->
|
|
code_info__set_succip_used(yes).
|
|
|
|
code_info__add_layout_for_label(Label, LayoutInfo) -->
|
|
code_info__get_layout_info(Internals0),
|
|
( { map__contains(Internals0, Label) } ->
|
|
{ error("adding layout for already known label") }
|
|
;
|
|
{ map__det_insert(Internals0, Label, LayoutInfo, Internals) },
|
|
code_info__set_layout_info(Internals)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Submodule for the handling of failure continuations.
|
|
|
|
:- interface.
|
|
|
|
% We manufacture a failure cont when we start generating
|
|
% code for a proc because on the failure of a procedure
|
|
% we don't need to prepare for execution to resume in this
|
|
% procedure.
|
|
|
|
:- pred code_info__manufacture_failure_cont(bool, code_info, code_info).
|
|
:- mode code_info__manufacture_failure_cont(in, in, out) is det.
|
|
|
|
% make_known_failure_cont(ResumeVars, ResumeLocs, IsNondet, Code):
|
|
% Push a new failure continuation onto the stack.
|
|
|
|
:- pred code_info__make_known_failure_cont(set(var), resume_locs, bool,
|
|
code_tree, code_info, code_info).
|
|
:- mode code_info__make_known_failure_cont(in, in, in, out, in, out)
|
|
is det.
|
|
|
|
% Generate some code to restore the current redoip, by looking
|
|
% at the top of the failure continuation stack.
|
|
|
|
:- pred code_info__restore_failure_cont(code_tree, code_info, code_info).
|
|
:- mode code_info__restore_failure_cont(out, in, out) is det.
|
|
|
|
% XXX
|
|
|
|
:- pred code_info__failure_is_direct_branch(code_addr, code_info, code_info).
|
|
:- mode code_info__failure_is_direct_branch(out, in, out) is semidet.
|
|
|
|
% XXX
|
|
|
|
:- pred code_info__generate_failure(code_tree, code_info, code_info).
|
|
:- mode code_info__generate_failure(out, in, out) is det.
|
|
|
|
% XXX
|
|
|
|
:- pred code_info__fail_if_rval_is_false(rval, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__fail_if_rval_is_false(in, out, in, out) is det.
|
|
|
|
% Set the topmost failure cont to `unknown' (e.g. after
|
|
% a nondet call or after a disjunction).
|
|
|
|
:- pred code_info__unset_failure_cont(code_tree, code_info, code_info).
|
|
:- mode code_info__unset_failure_cont(out, in, out) is det.
|
|
|
|
% Flush the variables needed for any current resumption point
|
|
% to their stack slots.
|
|
|
|
:- pred code_info__flush_resume_vars_to_stack(code_tree, code_info, code_info).
|
|
:- mode code_info__flush_resume_vars_to_stack(out, in, out) is det.
|
|
|
|
% XXX
|
|
|
|
:- pred code_info__may_use_nondet_tailcall(bool, code_info, code_info).
|
|
:- mode code_info__may_use_nondet_tailcall(out, in, out) is det.
|
|
|
|
% do_soft_cut(NondetFrameLvalAddress, SoftCutCode, SoftCutContCode)
|
|
% takes the lval where the address of the
|
|
% failure frame is stored, and it returns code to
|
|
% prune away the topmost choice point from that frame,
|
|
% typically by setting the redoip of that frame to do_fail.
|
|
% Note that the frame need not be the topmost frame -- a soft cut
|
|
% can prune away a single choice point from the middle.
|
|
% do_soft_cut also returns some additional code; in the case of
|
|
% trailing, the redoip will be set to point to that additional code,
|
|
% not to do_fail; the additional code will do a `discard_ticket'
|
|
% before branching to the usual failure continuation (e.g. do_fail).
|
|
|
|
:- pred code_info__do_soft_cut(lval, code_tree, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__do_soft_cut(in, out, out, in, out) is det.
|
|
|
|
% `generate_semi_pre_commit' and `generate_semi_commit' should be
|
|
% called before and after generating the code for the nondet goal
|
|
% being cut across. If the goal succeeds, the `commit' will cut
|
|
% any choice points generated in the goal.
|
|
%
|
|
% `generate_semi_pre_commit' returns a label (a failure cont label)
|
|
% and a tuple of stack slots; both of these should be passed to
|
|
% `generate_semi_commit'.
|
|
|
|
:- pred code_info__generate_semi_pre_commit(label, commit_slots, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__generate_semi_pre_commit(out, out, out, in, out) is det.
|
|
|
|
:- pred code_info__generate_semi_commit(label, commit_slots, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__generate_semi_commit(in, in, out, in, out) is det.
|
|
|
|
% `generate_det_pre_commit' and `generate_det_commit' should be
|
|
% called before and after generating the code for the multi goal
|
|
% being cut across. If the goal succeeds, the `commit' will cut
|
|
% any choice points generated in the goal.
|
|
%
|
|
% `generate_det_pre_commit' returns a tuple of stack slots, which
|
|
% should be passed to `generate_det_commit'.
|
|
|
|
:- pred code_info__generate_det_pre_commit(commit_slots, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__generate_det_pre_commit(out, out, in, out) is det.
|
|
|
|
:- pred code_info__generate_det_commit(commit_slots, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__generate_det_commit(in, out, in, out) is det.
|
|
|
|
:- type commit_slots
|
|
---> commit_slots(
|
|
lval, % curfr
|
|
lval, % maxfr
|
|
lval, % redoip
|
|
maybe(pair(lval, lval)) % ticket counter, trail pointer
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- type fail_stack == stack(failure_cont).
|
|
|
|
:- type failure_cont
|
|
---> failure_cont(
|
|
failure_cont_info,
|
|
resume_maps
|
|
).
|
|
|
|
:- type failure_cont_info
|
|
---> semidet
|
|
; nondet(
|
|
is_known, % Says whether on failure we can branch
|
|
% directly to one of the labels in
|
|
% the resume_maps, or if we must
|
|
% instead execute a redo.
|
|
|
|
maybe(label) % The maybe(label) is yes if we have
|
|
% created a temporary frame and we
|
|
% must restore curfr after a redo().
|
|
).
|
|
|
|
:- type is_known ---> known ; unknown.
|
|
|
|
:- type resume_map == map(var, set(rval)).
|
|
|
|
:- type resume_maps
|
|
---> orig_only(resume_map, code_addr)
|
|
; stack_only(resume_map, code_addr)
|
|
; orig_and_stack(resume_map, code_addr, resume_map, code_addr)
|
|
; stack_and_orig(resume_map, code_addr, resume_map, code_addr).
|
|
|
|
:- pred code_info__fail_cont_is_known(failure_cont_info).
|
|
:- mode code_info__fail_cont_is_known(in) is semidet.
|
|
|
|
code_info__fail_cont_is_known(FailContInfo) :-
|
|
FailContInfo \= nondet(unknown, _).
|
|
|
|
:- pred code_info__fail_cont_is_unknown(failure_cont_info).
|
|
:- mode code_info__fail_cont_is_unknown(in) is semidet.
|
|
|
|
code_info__fail_cont_is_unknown(FailContInfo) :-
|
|
FailContInfo = nondet(unknown, _).
|
|
|
|
:- pred code_info__have_temp_frame(fail_stack).
|
|
:- mode code_info__have_temp_frame(in) is semidet.
|
|
|
|
% have_temp_frame should succeed iff we have created
|
|
% a temp frame on the nondet stack. It traverses
|
|
% the entire failure continuation stack, looking for
|
|
% any failure continuations with the temp frame maybe(label)
|
|
% set to yes(_).
|
|
|
|
code_info__have_temp_frame(FailStack0) :-
|
|
stack__pop(FailStack0, FailContInfo, FailStack1),
|
|
(
|
|
FailContInfo = failure_cont(nondet(_, yes(_)), _)
|
|
;
|
|
code_info__have_temp_frame(FailStack1)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__manufacture_failure_cont(IsNondet) -->
|
|
{ map__init(Empty) },
|
|
(
|
|
{ IsNondet = no },
|
|
code_info__get_next_label(ContLab1),
|
|
{ Address1 = label(ContLab1) },
|
|
{ ResumeMap = stack_only(Empty, Address1) },
|
|
{ ContInfo = semidet }
|
|
;
|
|
{ IsNondet = yes },
|
|
{ Address1 = do_fail },
|
|
{ ResumeMap = stack_only(Empty, Address1) },
|
|
{ ContInfo = nondet(known, no) }
|
|
),
|
|
code_info__push_failure_cont(failure_cont(ContInfo, ResumeMap)).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__make_known_failure_cont(ResumeVars, ResumeLocs, IsNondet,
|
|
ModContCode) -->
|
|
code_info__get_next_label(OrigLabel),
|
|
code_info__get_next_label(StackLabel),
|
|
{ OrigAddr = label(OrigLabel) },
|
|
{ StackAddr = label(StackLabel) },
|
|
(
|
|
% In semidet continuations we don't use the redoip
|
|
% of the top stack frame.
|
|
|
|
{ IsNondet = no },
|
|
{ TempFrameCode = empty },
|
|
{ FailContInfo = semidet }
|
|
;
|
|
% In nondet continuations we may use the redoip
|
|
% of the top stack frame. Therefore we must ensure
|
|
% that this redoip is free for use, creating our own
|
|
% frame if necessary.
|
|
|
|
{ IsNondet = yes },
|
|
code_info__top_failure_cont(FailureCont),
|
|
{ FailureCont = failure_cont(OrigInfo, _) },
|
|
(
|
|
{ code_info__fail_cont_is_unknown(OrigInfo) }
|
|
->
|
|
%
|
|
% If the failure continuation is unknown,
|
|
% then we need to create a new temporary frame
|
|
% so that we can make it known
|
|
%
|
|
code_info__get_next_label(RedoLabel),
|
|
{ MaybeRedoLabel = yes(RedoLabel) },
|
|
{ RedoAddr = label(RedoLabel) },
|
|
% this code could be better
|
|
% (mkframe is a bit of a sledge hammer)
|
|
{ TempFrameCode = node([
|
|
mkframe("temp frame", 1, no, RedoAddr)
|
|
- "create a temporary frame",
|
|
assign(curfr, lval(succfr(lval(maxfr))))
|
|
- "restore curfr after mkframe"
|
|
]) }
|
|
;
|
|
%
|
|
% The failure continuation is known.
|
|
% But did we create a temp frame?
|
|
%
|
|
code_info__get_fail_stack(FailStack),
|
|
(
|
|
{ code_info__have_temp_frame(FailStack) }
|
|
->
|
|
%
|
|
% If we created a temp frame, then
|
|
% we will need to restore curfr on redo,
|
|
% so we set the failure continuation to
|
|
% the RedoAddr rather than the usual
|
|
% StackAddr. (generate_failure_cont will
|
|
% generate code for it that restores curfr.)
|
|
%
|
|
code_info__get_next_label(RedoLabel),
|
|
{ MaybeRedoLabel = yes(RedoLabel) },
|
|
{ RedoAddr = label(RedoLabel) },
|
|
{ TempFrameCode = node([
|
|
assign(redoip(lval(maxfr)),
|
|
const(code_addr_const(RedoAddr)))
|
|
- "Set failure continuation on temp frame"
|
|
]) }
|
|
;
|
|
{ MaybeRedoLabel = no },
|
|
{ TempFrameCode = node([
|
|
assign(redoip(lval(maxfr)),
|
|
const(code_addr_const(StackAddr)))
|
|
- "Set failure continuation"
|
|
]) }
|
|
)
|
|
),
|
|
{ FailContInfo = nondet(known, MaybeRedoLabel) }
|
|
),
|
|
{ set__to_sorted_list(ResumeVars, VarList) },
|
|
(
|
|
{ ResumeLocs = orig_only },
|
|
code_info__produce_resume_vars(VarList, OrigMap, OrigCode),
|
|
{ ResumeMaps = orig_only(OrigMap, OrigAddr) }
|
|
;
|
|
{ ResumeLocs = stack_only },
|
|
code_info__produce_resume_vars(VarList, _OrigMap, OrigCode),
|
|
code_info__get_stack_slots(StackSlots),
|
|
{ map__select(StackSlots, ResumeVars, StackMap0) },
|
|
{ map__to_assoc_list(StackMap0, StackList0) },
|
|
{ code_info__tweak_stacklist(StackList0, StackList) },
|
|
{ map__from_assoc_list(StackList, StackMap) },
|
|
{ ResumeMaps = stack_only(StackMap, StackAddr) }
|
|
;
|
|
{ ResumeLocs = orig_and_stack },
|
|
code_info__produce_resume_vars(VarList, OrigMap, OrigCode),
|
|
code_info__get_stack_slots(StackSlots),
|
|
{ map__select(StackSlots, ResumeVars, StackMap0) },
|
|
{ map__to_assoc_list(StackMap0, StackList0) },
|
|
{ code_info__tweak_stacklist(StackList0, StackList) },
|
|
{ map__from_assoc_list(StackList, StackMap) },
|
|
{ ResumeMaps = orig_and_stack(OrigMap, OrigAddr,
|
|
StackMap, StackAddr) }
|
|
;
|
|
{ ResumeLocs = stack_and_orig },
|
|
code_info__produce_resume_vars(VarList, OrigMap, OrigCode),
|
|
code_info__get_stack_slots(StackSlots),
|
|
{ map__select(StackSlots, ResumeVars, StackMap0) },
|
|
{ map__to_assoc_list(StackMap0, StackList0) },
|
|
{ code_info__tweak_stacklist(StackList0, StackList) },
|
|
{ map__from_assoc_list(StackList, StackMap) },
|
|
{ ResumeMaps = stack_and_orig(StackMap, StackAddr,
|
|
OrigMap, OrigAddr) }
|
|
),
|
|
code_info__push_failure_cont(failure_cont(FailContInfo, ResumeMaps)),
|
|
{ ModContCode = tree(OrigCode, TempFrameCode) }.
|
|
|
|
:- pred code_info__produce_resume_vars(list(var), map(var, set(rval)),
|
|
code_tree, code_info, code_info).
|
|
:- mode code_info__produce_resume_vars(in, out, out, in, out) is det.
|
|
|
|
code_info__produce_resume_vars([], Map, empty) -->
|
|
{ map__init(Map) }.
|
|
code_info__produce_resume_vars([V | Vs], Map, Code) -->
|
|
code_info__produce_resume_vars(Vs, Map0, Code0),
|
|
code_info__produce_variable_in_reg_or_stack(V, Code1, Rval),
|
|
{ set__singleton_set(Rvals, Rval) },
|
|
{ map__set(Map0, V, Rvals, Map) },
|
|
{ Code = tree(Code0, Code1) }.
|
|
|
|
:- pred code_info__tweak_stacklist(assoc_list(var, lval),
|
|
assoc_list(var, set(rval))).
|
|
:- mode code_info__tweak_stacklist(in, out) is det.
|
|
|
|
code_info__tweak_stacklist([], []).
|
|
code_info__tweak_stacklist([V - L | Rest0], [V - Rs | Rest]) :-
|
|
set__singleton_set(Rs, lval(L)),
|
|
code_info__tweak_stacklist(Rest0, Rest).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% :- pred code_info__modify_failure_cont(code_tree, code_info, code_info).
|
|
% :- mode code_info__modify_failure_cont(out, in, out) is det.
|
|
%
|
|
% code_info__modify_failure_cont(ModifyCode) -->
|
|
% code_info__top_failure_cont(FailureCont),
|
|
% { FailureCont = failure_cont(OldCont, MaybeRedo0, FailureMap) },
|
|
% code_info__generate_failure_cont(FailureCont, FailureCode),
|
|
% code_info__pop_failure_cont,
|
|
% code_info__get_next_label(NewRegCont),
|
|
% code_info__get_next_label(NewStackCont),
|
|
% (
|
|
% { OldCont = unknown ; OldCont = known(yes) }
|
|
% ->
|
|
% { NewCont = known(yes) },
|
|
% ( { MaybeRedo0 = yes(_OldRedo) } ->
|
|
% code_info__get_next_label(NewRedoCont),
|
|
% { MaybeRedo = yes(NewRedoCont) }
|
|
% ;
|
|
% { NewRedoCont = NewStackCont },
|
|
% { MaybeRedo = no }
|
|
% ),
|
|
% { ResetCode = node([
|
|
% assign(redoip(lval(maxfr)),
|
|
% const(code_addr_const(label(NewRedoCont)))) -
|
|
% "modify failure cont"
|
|
% ]) }
|
|
% ;
|
|
% { error("code_info__modify_failure_cont: semidet context") }
|
|
% % { NewCont = known(no) },
|
|
% % { ResetCode = empty },
|
|
% % { MaybeRedo = no }
|
|
% ),
|
|
% (
|
|
% { FailureMap = [RegMap - _RegCont, StackMap - _StackCont] }
|
|
% ->
|
|
% code_info__push_failure_cont(failure_cont(NewCont, MaybeRedo,
|
|
% [RegMap - label(NewRegCont),
|
|
% StackMap - label(NewStackCont)]))
|
|
% ;
|
|
% { error("code_info__modify_failure_cont: bad failure map.") }
|
|
% ),
|
|
% { ModifyCode = tree(FailureCode, ResetCode) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__restore_failure_cont(Code) -->
|
|
code_info__top_failure_cont(CurFailureCont),
|
|
{ CurFailureCont = failure_cont(CurContInfo, _FailureMap) },
|
|
code_info__generate_failure_cont(CurFailureCont, FailureCode),
|
|
code_info__pop_failure_cont,
|
|
% Fixup the redoip of the top frame if necessary
|
|
(
|
|
{ CurContInfo = semidet },
|
|
{ ResetCode = empty }
|
|
;
|
|
{ CurContInfo = nondet(_, _) },
|
|
code_info__top_failure_cont(EnclosingFailureCont),
|
|
{ EnclosingFailureCont = failure_cont(EnclosingContInfo, _) },
|
|
{
|
|
EnclosingContInfo = semidet,
|
|
ResetCode = empty
|
|
;
|
|
EnclosingContInfo = nondet(unknown, _),
|
|
ResetCode = node([
|
|
assign(redoip(lval(maxfr)),
|
|
const(code_addr_const(do_fail))) -
|
|
"restore failure cont"
|
|
])
|
|
;
|
|
EnclosingContInfo = nondet(known, _),
|
|
code_info__find_first_resume_label(
|
|
EnclosingFailureCont, RedoAddress),
|
|
ResetCode = node([
|
|
assign(redoip(lval(maxfr)),
|
|
const(code_addr_const(RedoAddress)))
|
|
- "restore known failure cont"
|
|
])
|
|
}
|
|
),
|
|
{ Code = tree(FailureCode, ResetCode) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% In establishing this resumption point, we may have pushed
|
|
% a temporary frame onto the nondet stack. If we have done so,
|
|
% we will have recorded this fact by setting the second argument
|
|
% of the top failure continuation to yes, with the argument of
|
|
% the yes giving the name of the label whose address was put
|
|
% into the redoip slot of that frame.
|
|
%
|
|
% When control arrives at that label, curfr will point to the
|
|
% temporary frame. However, the variables needed by the code
|
|
% at the resumption point are in the main nondet frame of the
|
|
% procedure. Since this was the current frame when we created
|
|
% the temporary frame, we can find it by following the succfr
|
|
% link in the temporary frame.
|
|
%
|
|
% The code we generate in general is
|
|
%
|
|
% label(RedoLabel)
|
|
% <reset curfr>
|
|
% label(StackLabel)
|
|
% <assume variables are where StackMap says they are>
|
|
% <copy variables to their locations according to OrigMap>
|
|
% label(OrigLabel)
|
|
% <assume variables are where OrigMap says they are>
|
|
%
|
|
% If, in establishing this resumption point, we did not create
|
|
% a temporary frame, then curfr will be OK when code to the right
|
|
% does a fail(), and hence the first label and the resetting of
|
|
% the curfr register can be omitted.
|
|
%
|
|
% Failures at different points may cause control to arrive at
|
|
% the resumption point via any one of these each labels.
|
|
% The last line above is necessary since it may arrive at OrigLabel
|
|
% without going through StackLabel first.
|
|
%
|
|
% The first two lines above are generated in this predicate;
|
|
% the others are generated in code_info__generate_resume_setup.
|
|
% It may not generate some of these other lines if it knows that
|
|
% they won't be needed.
|
|
|
|
:- pred code_info__generate_failure_cont(failure_cont, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__generate_failure_cont(in, out, in, out) is det.
|
|
|
|
code_info__generate_failure_cont(FailureCont, Code) -->
|
|
{ FailureCont = failure_cont(ContInfo, ResumeMap) },
|
|
|
|
% Did we create a temp nondet frame for this continuation?
|
|
% If not, then curfr will be right when we arrive here.
|
|
% If yes, it will be wrong, pointing to the temp frame,
|
|
% so we must restore curfr before continuing.
|
|
{
|
|
ContInfo = nondet(_, MaybeRedoLabel),
|
|
MaybeRedoLabel = yes(RedoLabel)
|
|
->
|
|
FixCurFrCode = node([
|
|
label(RedoLabel) -
|
|
"redo entry point",
|
|
assign(curfr, lval(succfr(lval(maxfr)))) -
|
|
"restore curfr"
|
|
]),
|
|
(
|
|
( ResumeMap = orig_only(_, _)
|
|
; ResumeMap = orig_and_stack(_, _, _, _)
|
|
)
|
|
->
|
|
error("redo entry before an orig resume point")
|
|
;
|
|
true
|
|
)
|
|
;
|
|
FixCurFrCode = empty
|
|
},
|
|
code_info__generate_resume_setup(ResumeMap, ResumeCode),
|
|
{ Code = tree(FixCurFrCode, ResumeCode) }.
|
|
|
|
:- pred code_info__generate_resume_setup(resume_maps, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__generate_resume_setup(in, out, in, out) is det.
|
|
|
|
code_info__generate_resume_setup(ResumeMaps, Code) -->
|
|
(
|
|
{ ResumeMaps = orig_only(Map1, Addr1) },
|
|
{ extract_label_from_code_addr(Addr1, Label1) },
|
|
{ Code = node([
|
|
label(Label1) -
|
|
"orig only failure continuation"
|
|
]) },
|
|
code_info__set_var_locations(Map1)
|
|
;
|
|
{ ResumeMaps = stack_only(Map1, Addr1) },
|
|
{ extract_label_from_code_addr(Addr1, Label1) },
|
|
{ Code = node([
|
|
label(Label1) -
|
|
"stack only failure continuation"
|
|
]) },
|
|
code_info__set_var_locations(Map1)
|
|
;
|
|
{ ResumeMaps = stack_and_orig(Map1, Addr1, Map2, Addr2) },
|
|
{ extract_label_from_code_addr(Addr1, Label1) },
|
|
{ extract_label_from_code_addr(Addr2, Label2) },
|
|
{ Label1Code = node([
|
|
label(Label1) -
|
|
"stack failure continuation before orig"
|
|
]) },
|
|
code_info__set_var_locations(Map1),
|
|
{ map__to_assoc_list(Map2, AssocList2) },
|
|
code_info__place_resume_vars(AssocList2, PlaceCode),
|
|
{ Label2Code = node([
|
|
label(Label2) -
|
|
"orig failure continuation after stack"
|
|
]) },
|
|
code_info__set_var_locations(Map2),
|
|
{ Code = tree(Label1Code, tree(PlaceCode, Label2Code)) }
|
|
;
|
|
{ ResumeMaps = orig_and_stack(Map1, Addr1, Map2, Addr2) },
|
|
{ extract_label_from_code_addr(Addr1, Label1) },
|
|
{ extract_label_from_code_addr(Addr2, Label2) },
|
|
{ Label1Code = node([
|
|
label(Label1) -
|
|
"orig failure continuation before stack"
|
|
]) },
|
|
code_info__set_var_locations(Map1),
|
|
{ map__to_assoc_list(Map2, AssocList2) },
|
|
code_info__place_resume_vars(AssocList2, PlaceCode),
|
|
{ Label2Code = node([
|
|
label(Label2) -
|
|
"stack failure continuation after orig"
|
|
]) },
|
|
code_info__set_var_locations(Map2),
|
|
{ Code = tree(Label1Code, tree(PlaceCode, Label2Code)) }
|
|
).
|
|
|
|
:- pred extract_label_from_code_addr(code_addr, label).
|
|
:- mode extract_label_from_code_addr(in, out) is det.
|
|
|
|
extract_label_from_code_addr(CodeAddr, Label) :-
|
|
( CodeAddr = label(Label0) ->
|
|
Label = Label0
|
|
;
|
|
error("code_info__generate_resume_setup: non-label!")
|
|
).
|
|
|
|
:- pred code_info__place_resume_vars(assoc_list(var, set(rval)), code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__place_resume_vars(in, out, in, out) is det.
|
|
|
|
code_info__place_resume_vars([], empty) --> [].
|
|
code_info__place_resume_vars([Var - TargetSet | Rest], Code) -->
|
|
{ set__to_sorted_list(TargetSet, Targets) },
|
|
code_info__place_resume_var(Var, Targets, FirstCode),
|
|
{ Code = tree(FirstCode, RestCode) },
|
|
code_info__place_resume_vars(Rest, RestCode).
|
|
|
|
:- pred code_info__place_resume_var(var, list(rval), code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__place_resume_var(in, in, out, in, out) is det.
|
|
|
|
code_info__place_resume_var(_Var, [], empty) --> [].
|
|
code_info__place_resume_var(Var, [Target | Targets], Code) -->
|
|
( { Target = lval(TargetLval) } ->
|
|
code_info__place_var(Var, TargetLval, FirstCode)
|
|
;
|
|
{ error("code_info__place_resume_var: not lval") }
|
|
),
|
|
{ Code = tree(FirstCode, RestCode) },
|
|
code_info__place_resume_var(Var, Targets, RestCode).
|
|
|
|
% Reset the code generator's database of what is where.
|
|
% Remember that the variables in the map are available in their
|
|
% associated rvals; forget about all other variables.
|
|
|
|
:- pred code_info__set_var_locations(map(var, set(rval)), code_info, code_info).
|
|
:- mode code_info__set_var_locations(in, in, out) is det.
|
|
|
|
code_info__set_var_locations(Map) -->
|
|
{ map__to_assoc_list(Map, List0) },
|
|
{ code_info__flatten_varlval_list(List0, List) },
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__reinit_state(List, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
:- pred code_info__flatten_varlval_list(assoc_list(var, set(rval)),
|
|
assoc_list(var, rval)).
|
|
:- mode code_info__flatten_varlval_list(in, out) is det.
|
|
|
|
code_info__flatten_varlval_list([], []).
|
|
code_info__flatten_varlval_list([V - Rvals | Rest0], All) :-
|
|
code_info__flatten_varlval_list(Rest0, Rest),
|
|
set__to_sorted_list(Rvals, RvalList),
|
|
code_info__flatten_varlval_list_2(RvalList, V, Rest1),
|
|
list__append(Rest1, Rest, All).
|
|
|
|
:- pred code_info__flatten_varlval_list_2(list(rval), var,
|
|
assoc_list(var, rval)).
|
|
:- mode code_info__flatten_varlval_list_2(in, in, out) is det.
|
|
|
|
code_info__flatten_varlval_list_2([], _V, []).
|
|
code_info__flatten_varlval_list_2([R | Rs], V, [V - R | Rest]) :-
|
|
code_info__flatten_varlval_list_2(Rs, V, Rest).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__failure_is_direct_branch(CodeAddr) -->
|
|
code_info__top_failure_cont(FailureCont),
|
|
{ FailureCont = failure_cont(ContInfo, FailureMap) },
|
|
{ code_info__fail_cont_is_known(ContInfo) },
|
|
code_info__pick_matching_resume_addr(FailureMap, CodeAddr).
|
|
|
|
code_info__generate_failure(Code) -->
|
|
code_info__top_failure_cont(FailureCont),
|
|
{ FailureCont = failure_cont(ContInfo, FailureMap) },
|
|
(
|
|
{ code_info__fail_cont_is_known(ContInfo) }
|
|
->
|
|
(
|
|
code_info__pick_matching_resume_addr(FailureMap,
|
|
FailureAddress0)
|
|
->
|
|
{ FailureAddress = FailureAddress0 },
|
|
{ PlaceCode = empty }
|
|
;
|
|
{ code_info__pick_first_resume_point(FailureMap,
|
|
Map, FailureAddress) },
|
|
{ map__to_assoc_list(Map, AssocList) },
|
|
code_info__grab_code_info(CodeInfo),
|
|
code_info__place_vars(AssocList, PlaceCode),
|
|
code_info__slap_code_info(CodeInfo)
|
|
),
|
|
{ BranchCode = node([goto(FailureAddress) - "fail"]) },
|
|
{ Code = tree(PlaceCode, BranchCode) }
|
|
;
|
|
{ Code = node([goto(do_redo) - "fail"]) }
|
|
).
|
|
|
|
code_info__fail_if_rval_is_false(Rval0, Code) -->
|
|
code_info__top_failure_cont(FailureCont),
|
|
{ FailureCont = failure_cont(ContInfo, FailureMap) },
|
|
(
|
|
{ code_info__fail_cont_is_known(ContInfo) }
|
|
->
|
|
(
|
|
code_info__pick_matching_resume_addr(FailureMap,
|
|
FailureAddress0)
|
|
->
|
|
% We branch away if the test *fails*
|
|
{ code_util__neg_rval(Rval0, Rval) },
|
|
{ Code = node([
|
|
if_val(Rval, FailureAddress0) -
|
|
"Test for failure"
|
|
]) }
|
|
;
|
|
{ code_info__pick_first_resume_point(FailureMap,
|
|
Map, FailureAddress) },
|
|
{ map__to_assoc_list(Map, AssocList) },
|
|
code_info__get_next_label(SuccessLabel),
|
|
code_info__grab_code_info(CodeInfo),
|
|
code_info__place_vars(AssocList, PlaceCode),
|
|
code_info__slap_code_info(CodeInfo),
|
|
{ SuccessAddress = label(SuccessLabel) },
|
|
% We branch away if the test *fails*,
|
|
% therefore we branch around the code
|
|
% that moves variables to their failure
|
|
% locations and branches away
|
|
% if the test succeeds
|
|
{ TestCode = node([
|
|
if_val(Rval0, SuccessAddress) -
|
|
"Test for failure"
|
|
]) },
|
|
{ TailCode = node([
|
|
goto(FailureAddress) -
|
|
"Goto failure",
|
|
label(SuccessLabel) -
|
|
"Success continuation"
|
|
]) },
|
|
{ Code = tree(TestCode, tree(PlaceCode, TailCode)) }
|
|
)
|
|
;
|
|
{ FailureAddress = do_redo },
|
|
% We branch away if the test *fails*
|
|
{ code_util__neg_rval(Rval0, Rval) },
|
|
{ Code = node([
|
|
if_val(Rval, FailureAddress) -
|
|
"Test for failure"
|
|
]) }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% See whether the current locations of variables match the locations
|
|
% associated with any of the options in the given failure map.
|
|
% If yes, return the code_addr of that option.
|
|
|
|
:- pred code_info__pick_matching_resume_addr(resume_maps, code_addr,
|
|
code_info, code_info).
|
|
:- mode code_info__pick_matching_resume_addr(in, out, in, out) is semidet.
|
|
|
|
code_info__pick_matching_resume_addr(ResumeMaps, Addr) -->
|
|
code_info__variable_locations(Locations),
|
|
{
|
|
ResumeMaps = orig_only(Map1, Addr1),
|
|
( code_info__match_resume_loc(Map1, Locations) ->
|
|
Addr = Addr1
|
|
;
|
|
fail
|
|
)
|
|
;
|
|
ResumeMaps = stack_only(Map1, Addr1),
|
|
( code_info__match_resume_loc(Map1, Locations) ->
|
|
Addr = Addr1
|
|
;
|
|
fail
|
|
)
|
|
;
|
|
ResumeMaps = orig_and_stack(Map1, Addr1, Map2, Addr2),
|
|
( code_info__match_resume_loc(Map1, Locations) ->
|
|
Addr = Addr1
|
|
; code_info__match_resume_loc(Map2, Locations) ->
|
|
Addr = Addr2
|
|
;
|
|
fail
|
|
)
|
|
;
|
|
ResumeMaps = stack_and_orig(Map1, Addr1, Map2, Addr2),
|
|
( code_info__match_resume_loc(Map1, Locations) ->
|
|
Addr = Addr1
|
|
; code_info__match_resume_loc(Map2, Locations) ->
|
|
Addr = Addr2
|
|
;
|
|
fail
|
|
)
|
|
}.
|
|
|
|
:- pred code_info__match_resume_loc(resume_map, resume_map).
|
|
:- mode code_info__match_resume_loc(in, in) is semidet.
|
|
|
|
code_info__match_resume_loc(Map, Locations0) :-
|
|
map__keys(Map, KeyList),
|
|
set__list_to_set(KeyList, Keys),
|
|
map__select(Locations0, Keys, Locations),
|
|
map__to_assoc_list(Locations, List),
|
|
\+ (
|
|
list__member(Thingy, List),
|
|
\+ (
|
|
Thingy = Var - Actual,
|
|
map__search(Map, Var, Rvals),
|
|
set__subset(Rvals, Actual)
|
|
)
|
|
).
|
|
|
|
% Find the first label that will be generated for the
|
|
% given failure continuation based on the scheme used by
|
|
% code_info__generate_failure_cont.
|
|
|
|
:- pred code_info__find_first_resume_label(failure_cont, code_addr).
|
|
:- mode code_info__find_first_resume_label(in, out) is det.
|
|
|
|
code_info__find_first_resume_label(FailureCont, Address) :-
|
|
FailureCont = failure_cont(ContInfo, FailMap),
|
|
(
|
|
ContInfo = nondet(_, MaybeRedoLabel),
|
|
MaybeRedoLabel = yes(RedoLabel)
|
|
->
|
|
Address = label(RedoLabel)
|
|
;
|
|
code_info__pick_first_resume_point(FailMap, _, Address)
|
|
).
|
|
|
|
:- pred code_info__pick_first_resume_point(resume_maps, resume_map, code_addr).
|
|
:- mode code_info__pick_first_resume_point(in, out, out) is det.
|
|
|
|
code_info__pick_first_resume_point(orig_only(Map, Addr), Map, Addr).
|
|
code_info__pick_first_resume_point(stack_only(Map, Addr), Map, Addr).
|
|
code_info__pick_first_resume_point(orig_and_stack(Map, Addr, _, _), Map, Addr).
|
|
code_info__pick_first_resume_point(stack_and_orig(Map, Addr, _, _), Map, Addr).
|
|
|
|
:- pred code_info__pick_last_resume_point(resume_maps, resume_map, code_addr).
|
|
:- mode code_info__pick_last_resume_point(in, out, out) is det.
|
|
|
|
code_info__pick_last_resume_point(orig_only(Map, Addr), Map, Addr).
|
|
code_info__pick_last_resume_point(stack_only(Map, Addr), Map, Addr).
|
|
code_info__pick_last_resume_point(orig_and_stack( _, _, Map, Addr), Map, Addr).
|
|
code_info__pick_last_resume_point(stack_and_orig( _, _, Map, Addr), Map, Addr).
|
|
|
|
:- pred code_info__pick_stack_resume_point(resume_maps, resume_map, code_addr).
|
|
:- mode code_info__pick_stack_resume_point(in, out, out) is det.
|
|
|
|
code_info__pick_stack_resume_point(orig_only(_, _), _, _) :-
|
|
error("no stack resume point").
|
|
code_info__pick_stack_resume_point(stack_only(Map, Addr), Map, Addr).
|
|
code_info__pick_stack_resume_point(orig_and_stack(_, _, Map, Addr), Map, Addr).
|
|
code_info__pick_stack_resume_point(stack_and_orig(Map, Addr, _, _), Map, Addr).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__unset_failure_cont(Code) -->
|
|
code_info__flush_resume_vars_to_stack(Code),
|
|
code_info__top_failure_cont(FailureCont0),
|
|
{ FailureCont0 = failure_cont(ContInfo0, FailureMap) },
|
|
code_info__pop_failure_cont,
|
|
{
|
|
ContInfo0 = semidet,
|
|
error("unset of semidet failure cont")
|
|
;
|
|
ContInfo0 = nondet(_, MaybeRedoLabel),
|
|
ContInfo = nondet(unknown, MaybeRedoLabel)
|
|
},
|
|
{ FailureCont = failure_cont(ContInfo, FailureMap) },
|
|
code_info__push_failure_cont(FailureCont).
|
|
|
|
code_info__flush_resume_vars_to_stack(Code) -->
|
|
code_info__top_failure_cont(FailureCont0),
|
|
{ FailureCont0 = failure_cont(_, FailureMap) },
|
|
{ code_info__pick_stack_resume_point(FailureMap, StackMap, _) },
|
|
{ map__to_assoc_list(StackMap, StackLocs) },
|
|
code_info__place_resume_vars(StackLocs, Code).
|
|
|
|
code_info__may_use_nondet_tailcall(MayTailCall) -->
|
|
code_info__top_failure_cont(FailureCont),
|
|
{ FailureCont = failure_cont(ContInfo, FailureMap) },
|
|
(
|
|
{ code_info__fail_cont_is_known(ContInfo) },
|
|
{ FailureMap = stack_only(_, do_fail) }
|
|
->
|
|
{ MayTailCall = yes }
|
|
;
|
|
{ MayTailCall = no }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__do_soft_cut(TheFrame, Code, ContCode) -->
|
|
code_info__top_failure_cont(FailureCont),
|
|
{ FailureCont = failure_cont(ContInfo, _) },
|
|
(
|
|
{ code_info__fail_cont_is_known(ContInfo) }
|
|
->
|
|
{ code_info__find_first_resume_label(FailureCont, Address) }
|
|
;
|
|
% If the newly uncovered cont is unknown then
|
|
% we must have created a new frame before the
|
|
% condition which we no longer need, so we
|
|
% set its redoip to do_fail.
|
|
{ Address = do_fail }
|
|
),
|
|
code_info__get_globals(Globals),
|
|
{ globals__lookup_bool_option(Globals, use_trail, UseTrail) },
|
|
( { UseTrail = yes } ->
|
|
code_info__get_next_label(ContLabel),
|
|
{ ContAddress = label(ContLabel) },
|
|
{ ContCode = node([
|
|
label(ContLabel) - "soft cut failure cont entry point",
|
|
discard_ticket - "pop ticket stack",
|
|
goto(Address) - "branch to prev failure continuation"
|
|
]) }
|
|
;
|
|
{ ContAddress = Address },
|
|
{ ContCode = empty }
|
|
),
|
|
{ Code = node([
|
|
assign(redoip(lval(TheFrame)),
|
|
const(code_addr_const(ContAddress)))
|
|
- "prune away the `else' case of the if-then-else"
|
|
]) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__generate_semi_pre_commit(RedoLabel, Slots, PreCommit) -->
|
|
code_info__generate_pre_commit_saves(Slots, SaveCode),
|
|
code_info__top_failure_cont(FailureCont0),
|
|
{ FailureCont0 = failure_cont(_, FailureMap0) },
|
|
code_info__clone_resume_maps(FailureMap0, FailureMap),
|
|
{ FailureCont = failure_cont(nondet(known, no), FailureMap) },
|
|
code_info__push_failure_cont(FailureCont),
|
|
code_info__get_next_label(RedoLabel),
|
|
{ HijackCode = node([
|
|
assign(redoip(lval(maxfr)),
|
|
const(code_addr_const(label(RedoLabel)))) -
|
|
"Hijack the failure cont"
|
|
]) },
|
|
{ PreCommit = tree(SaveCode, HijackCode) }.
|
|
|
|
code_info__generate_semi_commit(RedoLabel, Slots, Commit) -->
|
|
code_info__get_next_label(SuccLabel),
|
|
{ GotoSuccLabel = node([
|
|
goto(label(SuccLabel)) - "Jump to success continuation"
|
|
]) },
|
|
{ SuccLabelCode = node([
|
|
label(SuccLabel) - "Success continuation"
|
|
]) },
|
|
{ RedoLabelCode = node([
|
|
label(RedoLabel) - "Failure (redo) continuation"
|
|
]) },
|
|
|
|
code_info__grab_code_info(CodeInfo0),
|
|
code_info__top_failure_cont(FailureCont),
|
|
{ FailureCont = failure_cont(_, FailureMaps) },
|
|
code_info__generate_resume_setup(FailureMaps, FailureContCode),
|
|
code_info__pop_failure_cont,
|
|
code_info__generate_failure(Fail),
|
|
code_info__slap_code_info(CodeInfo0),
|
|
code_info__pop_failure_cont,
|
|
|
|
code_info__undo_pre_commit_saves(Slots, RestoreMaxfr, RestoreRedoip,
|
|
RestoreCurfr, SuccPopCode, FailPopCode),
|
|
|
|
{ SuccessCode =
|
|
tree(RestoreMaxfr,
|
|
tree(RestoreRedoip,
|
|
tree(RestoreCurfr,
|
|
SuccPopCode)))
|
|
},
|
|
{ FailCode =
|
|
tree(RedoLabelCode,
|
|
tree(RestoreCurfr,
|
|
tree(FailureContCode,
|
|
tree(RestoreRedoip,
|
|
tree(FailPopCode,
|
|
Fail)))))
|
|
},
|
|
{ Commit =
|
|
tree(SuccessCode,
|
|
tree(GotoSuccLabel,
|
|
tree(FailCode,
|
|
SuccLabelCode)))
|
|
}.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__generate_det_pre_commit(Slots, PreCommit) -->
|
|
code_info__generate_pre_commit_saves(Slots, PreCommit),
|
|
% Since the code we are cutting is model_non, it will call
|
|
% unset_failure_cont. If the current top entry on the failure stack
|
|
% at the time is semidet, this would cause unset_failure_cont to abort.
|
|
% We therefore push a dummy nondet failure continuation onto the
|
|
% failure stack. Since the code we are cutting across is multi,
|
|
% the failure continuation will never actually be used.
|
|
{ map__init(Empty) },
|
|
{ FailureCont = failure_cont(nondet(known, no),
|
|
stack_only(Empty, do_fail)) },
|
|
code_info__push_failure_cont(FailureCont).
|
|
|
|
code_info__generate_det_commit(Slots, Commit) -->
|
|
% Remove the dummy failure continuation pushed by det_pre_commit.
|
|
code_info__pop_failure_cont,
|
|
code_info__undo_pre_commit_saves(Slots, RestoreMaxfr, RestoreRedoip,
|
|
RestoreCurfr, SuccPopCode, _FailPopCode),
|
|
{ Commit = tree(RestoreMaxfr,
|
|
tree(RestoreRedoip,
|
|
tree(RestoreCurfr,
|
|
SuccPopCode)))
|
|
}.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred code_info__generate_pre_commit_saves(commit_slots, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__generate_pre_commit_saves(out, out, in, out) is det.
|
|
|
|
code_info__generate_pre_commit_saves(Slots, Code) -->
|
|
code_info__get_globals(Globals),
|
|
{ globals__lookup_bool_option(Globals, use_trail, UseTrail) },
|
|
( { UseTrail = yes } ->
|
|
{ NumSlots = 5 },
|
|
{ SaveMessage =
|
|
"push space for curfr, maxfr, redoip, ticket_counter and trail_ptr" }
|
|
;
|
|
{ NumSlots = 3 },
|
|
{ SaveMessage = "push space for curfr, maxfr, and redoip" }
|
|
),
|
|
code_info__get_proc_model(CodeModel),
|
|
( { CodeModel = model_non } ->
|
|
% the pushes and pops on the det stack below will cause
|
|
% problems for accurate garbage collection. Hence we
|
|
% make sure the commit vals are made live, so gc
|
|
% can figure out what is going on later.
|
|
code_info__get_module_info(ModuleInfo),
|
|
code_info__get_pred_id(PredId),
|
|
{ predicate_module(ModuleInfo, PredId, ModuleName) },
|
|
{ predicate_name(ModuleInfo, PredId, PredName) },
|
|
{ prog_out__sym_name_to_string(ModuleName, ModuleNameString) },
|
|
{ string__append_list(["commit in ",
|
|
ModuleNameString, ":", PredName], Message) },
|
|
{ PushCode = node([
|
|
incr_sp(NumSlots, Message) - SaveMessage
|
|
]) },
|
|
{ CurfrSlot = stackvar(1) },
|
|
{ MaxfrSlot = stackvar(2) },
|
|
{ RedoipSlot = stackvar(3) },
|
|
( { UseTrail = yes } ->
|
|
{ TicketCounterSlot = stackvar(4) },
|
|
{ TrailPtrSlot = stackvar(5) },
|
|
{ MaybeTrailSlots = yes(TicketCounterSlot -
|
|
TrailPtrSlot) }
|
|
;
|
|
{ MaybeTrailSlots = no }
|
|
),
|
|
{ Slots = commit_slots(CurfrSlot, MaxfrSlot, RedoipSlot,
|
|
MaybeTrailSlots) },
|
|
code_info__add_commit_triple
|
|
;
|
|
{ PushCode = empty },
|
|
code_info__acquire_temp_slot(lval(curfr), CurfrSlot),
|
|
code_info__acquire_temp_slot(lval(maxfr), MaxfrSlot),
|
|
code_info__acquire_temp_slot(lval(redoip(lval(maxfr))),
|
|
RedoipSlot),
|
|
( { UseTrail = yes } ->
|
|
code_info__acquire_temp_slot(ticket_counter,
|
|
TicketCounterSlot),
|
|
code_info__acquire_temp_slot(ticket, TrailPtrSlot),
|
|
{ MaybeTrailSlots = yes(TicketCounterSlot -
|
|
TrailPtrSlot) }
|
|
;
|
|
{ MaybeTrailSlots = no }
|
|
),
|
|
{ Slots = commit_slots(CurfrSlot, MaxfrSlot, RedoipSlot,
|
|
MaybeTrailSlots) }
|
|
),
|
|
{ SaveCode = node([
|
|
assign(CurfrSlot, lval(curfr)) -
|
|
"Save current nondet frame pointer",
|
|
assign(MaxfrSlot, lval(maxfr)) -
|
|
"Save top of nondet stack",
|
|
assign(RedoipSlot, lval(redoip(lval(maxfr)))) -
|
|
"Save the top redoip"
|
|
]) },
|
|
{ MaybeTrailSlots = yes(TheTicketCounterSlot - TheTrailPtrSlot) ->
|
|
MaybeSaveTrailCode = node([
|
|
mark_ticket_stack(TheTicketCounterSlot) -
|
|
"Save the ticket counter",
|
|
store_ticket(TheTrailPtrSlot) -
|
|
"Save the trail pointer"
|
|
])
|
|
;
|
|
MaybeSaveTrailCode = empty
|
|
},
|
|
{ Code = tree(PushCode, tree(SaveCode, MaybeSaveTrailCode)) }.
|
|
|
|
:- pred code_info__undo_pre_commit_saves(commit_slots, code_tree, code_tree,
|
|
code_tree, code_tree, code_tree, code_info, code_info).
|
|
:- mode code_info__undo_pre_commit_saves(in, out, out, out, out, out, in, out)
|
|
is det.
|
|
|
|
code_info__undo_pre_commit_saves(Slots, RestoreMaxfr, RestoreRedoip,
|
|
RestoreCurfr, SuccPopCode, FailPopCode) -->
|
|
{ Slots = commit_slots(CurfrSlot, MaxfrSlot, RedoipSlot,
|
|
MaybeTrailSlots) },
|
|
{ RestoreMaxfr = node([
|
|
assign(maxfr, lval(MaxfrSlot)) -
|
|
"Prune away unwanted choice-points"
|
|
]) },
|
|
{ RestoreRedoip = node([
|
|
assign(redoip(lval(maxfr)), lval(RedoipSlot)) -
|
|
"Restore the top redoip"
|
|
]) },
|
|
{ RestoreCurfr = node([
|
|
assign(curfr, lval(CurfrSlot)) -
|
|
"Restore nondet frame pointer"
|
|
]) },
|
|
code_info__get_proc_model(CodeModel),
|
|
( { CodeModel = model_non } ->
|
|
code_info__rem_commit_triple,
|
|
( { MaybeTrailSlots = yes(TicketCounterSlot - TrailPtrSlot) } ->
|
|
{ CommitTrail = node([
|
|
reset_ticket(lval(TrailPtrSlot), commit) -
|
|
"discard trail entries and restore trail ptr"
|
|
]) },
|
|
{ RestoreTrail = node([
|
|
reset_ticket(lval(TrailPtrSlot), undo) -
|
|
"apply trail entries and restore trail ptr"
|
|
]) },
|
|
{ RestoreTicketCounter = node([
|
|
discard_tickets_to(lval(TicketCounterSlot)) -
|
|
"restore the ticket counter"
|
|
]) },
|
|
{ NumSlots = 5 },
|
|
{ PopMessage =
|
|
"pop curfr, maxfr, redoip, ticket_counter and trail_ptr" }
|
|
;
|
|
{ CommitTrail = empty },
|
|
{ RestoreTrail = empty },
|
|
{ RestoreTicketCounter = empty },
|
|
{ NumSlots = 3 },
|
|
{ PopMessage = "pop curfr, maxfr, and redoip" }
|
|
),
|
|
{ MainPopCode = node([
|
|
decr_sp(NumSlots) - PopMessage
|
|
]) }
|
|
;
|
|
code_info__release_temp_slot(CurfrSlot),
|
|
code_info__release_temp_slot(MaxfrSlot),
|
|
code_info__release_temp_slot(RedoipSlot),
|
|
( { MaybeTrailSlots = yes(TicketCounterSlot - TrailPtrSlot) } ->
|
|
{ CommitTrail = node([
|
|
reset_ticket(lval(TrailPtrSlot), commit) -
|
|
"discard trail entries and restore trail ptr"
|
|
]) },
|
|
{ RestoreTrail = node([
|
|
reset_ticket(lval(TrailPtrSlot), undo) -
|
|
"apply trail entries and restore trail ptr"
|
|
]) },
|
|
{ RestoreTicketCounter = node([
|
|
discard_tickets_to(lval(TicketCounterSlot)) -
|
|
"restore the ticket counter"
|
|
]) },
|
|
code_info__release_temp_slot(TicketCounterSlot),
|
|
code_info__release_temp_slot(TrailPtrSlot)
|
|
;
|
|
{ CommitTrail = empty },
|
|
{ RestoreTrail = empty },
|
|
{ RestoreTicketCounter = empty }
|
|
),
|
|
{ MainPopCode = empty }
|
|
),
|
|
{ SuccPopCode =
|
|
tree(CommitTrail,
|
|
tree(RestoreTicketCounter,
|
|
MainPopCode)) },
|
|
{ FailPopCode =
|
|
tree(RestoreTrail,
|
|
tree(RestoreTicketCounter,
|
|
MainPopCode)) }.
|
|
|
|
|
|
:- pred code_info__clone_resume_maps(resume_maps, resume_maps,
|
|
code_info, code_info).
|
|
:- mode code_info__clone_resume_maps(in, out, in, out) is det.
|
|
|
|
code_info__clone_resume_maps(ResumeMaps0, ResumeMaps) -->
|
|
(
|
|
{ ResumeMaps0 = orig_only(Map1, _) },
|
|
code_info__get_next_label(Label1),
|
|
{ Addr1 = label(Label1) },
|
|
{ ResumeMaps = orig_only(Map1, Addr1) }
|
|
;
|
|
{ ResumeMaps0 = stack_only(Map1, _) },
|
|
code_info__get_next_label(Label1),
|
|
{ Addr1 = label(Label1) },
|
|
{ ResumeMaps = stack_only(Map1, Addr1) }
|
|
;
|
|
{ ResumeMaps0 = stack_and_orig(Map1, _, Map2, _) },
|
|
code_info__get_next_label(Label1),
|
|
{ Addr1 = label(Label1) },
|
|
code_info__get_next_label(Label2),
|
|
{ Addr2 = label(Label2) },
|
|
{ ResumeMaps = stack_and_orig(Map1, Addr1, Map2, Addr2) }
|
|
;
|
|
{ ResumeMaps0 = orig_and_stack(Map1, _, Map2, _) },
|
|
code_info__get_next_label(Label1),
|
|
{ Addr1 = label(Label1) },
|
|
code_info__get_next_label(Label2),
|
|
{ Addr2 = label(Label2) },
|
|
{ ResumeMaps = orig_and_stack(Map1, Addr1, Map2, Addr2) }
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Submodule to deal with liveness issues.
|
|
|
|
:- interface.
|
|
|
|
:- pred code_info__get_known_variables(list(var), code_info, code_info).
|
|
:- mode code_info__get_known_variables(out, in, out) is det.
|
|
|
|
:- pred code_info__variable_is_forward_live(var, code_info, code_info).
|
|
:- mode code_info__variable_is_forward_live(in, in, out) is semidet.
|
|
|
|
:- pred code_info__make_vars_forward_dead(set(var), code_info, code_info).
|
|
:- mode code_info__make_vars_forward_dead(in, in, out) is det.
|
|
|
|
:- pred code_info__pickup_zombies(set(var), code_info, code_info).
|
|
:- mode code_info__pickup_zombies(out, in, out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- pred code_info__add_forward_live_vars(set(var), code_info, code_info).
|
|
:- mode code_info__add_forward_live_vars(in, in, out) is det.
|
|
|
|
:- pred code_info__rem_forward_live_vars(set(var), code_info, code_info).
|
|
:- mode code_info__rem_forward_live_vars(in, in, out) is det.
|
|
|
|
% Make these variables appear magically live.
|
|
% We don't care where they are put.
|
|
|
|
:- pred code_info__make_vars_forward_live(set(var), code_info, code_info).
|
|
:- mode code_info__make_vars_forward_live(in, in, out) is det.
|
|
|
|
code_info__get_known_variables(VarList) -->
|
|
code_info__get_forward_live_vars(ForwardLiveVars),
|
|
code_info__current_resume_point_vars(ResumeVars),
|
|
{ set__union(ForwardLiveVars, ResumeVars, Vars) },
|
|
{ set__to_sorted_list(Vars, VarList) }.
|
|
|
|
code_info__variable_is_forward_live(Var) -->
|
|
code_info__get_forward_live_vars(Liveness),
|
|
{ set__member(Var, Liveness) }.
|
|
|
|
code_info__add_forward_live_vars(Births) -->
|
|
code_info__get_forward_live_vars(Liveness0),
|
|
{ set__union(Liveness0, Births, Liveness) },
|
|
code_info__set_forward_live_vars(Liveness).
|
|
|
|
code_info__rem_forward_live_vars(Deaths) -->
|
|
code_info__get_forward_live_vars(Liveness0),
|
|
{ set__difference(Liveness0, Deaths, Liveness) },
|
|
code_info__set_forward_live_vars(Liveness).
|
|
|
|
code_info__make_vars_forward_live(Vars) -->
|
|
code_info__get_stack_slots(StackSlots),
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ set__to_sorted_list(Vars, VarList) },
|
|
{ code_info__make_vars_forward_live_2(VarList, StackSlots, 1,
|
|
Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
:- pred code_info__make_vars_forward_live_2(list(var), stack_slots, int,
|
|
exprn_info, exprn_info).
|
|
:- mode code_info__make_vars_forward_live_2(in, in, in, in, out) is det.
|
|
|
|
code_info__make_vars_forward_live_2([], _, _, Exprn, Exprn).
|
|
code_info__make_vars_forward_live_2([V | Vs], StackSlots, N0, Exprn0, Exprn) :-
|
|
( map__search(StackSlots, V, Lval0) ->
|
|
Lval = Lval0,
|
|
N1 = N0
|
|
;
|
|
code_info__find_unused_reg(N0, Exprn0, N1),
|
|
Lval = reg(r, N1)
|
|
),
|
|
code_exprn__maybe_set_var_location(V, Lval, Exprn0, Exprn1),
|
|
code_info__make_vars_forward_live_2(Vs, StackSlots, N1, Exprn1, Exprn).
|
|
|
|
:- pred code_info__find_unused_reg(int, exprn_info, int).
|
|
:- mode code_info__find_unused_reg(in, in, out) is det.
|
|
|
|
code_info__find_unused_reg(N0, Exprn0, N) :-
|
|
( code_exprn__lval_in_use(reg(r, N0), Exprn0, _) ->
|
|
N1 is N0 + 1,
|
|
code_info__find_unused_reg(N1, Exprn0, N)
|
|
;
|
|
N = N0
|
|
).
|
|
|
|
code_info__make_vars_forward_dead(Vars0) -->
|
|
code_info__current_resume_point_vars(ResumeVars),
|
|
{ set__intersect(Vars0, ResumeVars, FlushVars) },
|
|
code_info__get_zombies(Zombies0),
|
|
{ set__union(Zombies0, FlushVars, Zombies) },
|
|
code_info__set_zombies(Zombies),
|
|
{ set__difference(Vars0, Zombies, Vars) },
|
|
{ set__to_sorted_list(Vars, VarList) },
|
|
code_info__make_vars_forward_dead_2(VarList).
|
|
|
|
:- pred code_info__make_vars_forward_dead_2(list(var), code_info, code_info).
|
|
:- mode code_info__make_vars_forward_dead_2(in, in, out) is det.
|
|
|
|
code_info__make_vars_forward_dead_2([]) --> [].
|
|
code_info__make_vars_forward_dead_2([V | Vs]) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__var_becomes_dead(V, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn),
|
|
code_info__make_vars_forward_dead_2(Vs).
|
|
|
|
code_info__pickup_zombies(Zombies) -->
|
|
code_info__get_zombies(Zombies),
|
|
{ set__init(Empty) },
|
|
code_info__set_zombies(Empty).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Submodule for handling the saving and restoration
|
|
% of trail tickets, heap pointers, stack pointers etc.
|
|
|
|
:- interface.
|
|
|
|
:- pred code_info__save_hp(code_tree, lval, code_info, code_info).
|
|
:- mode code_info__save_hp(out, out, in, out) is det.
|
|
|
|
:- pred code_info__restore_hp(lval, code_tree, code_info, code_info).
|
|
:- mode code_info__restore_hp(in, out, in, out) is det.
|
|
|
|
:- pred code_info__restore_and_discard_hp(lval, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__restore_and_discard_hp(in, out, in, out) is det.
|
|
|
|
:- pred code_info__discard_hp(lval, code_info, code_info).
|
|
:- mode code_info__discard_hp(in, in, out) is det.
|
|
|
|
:- pred code_info__maybe_save_hp(bool, code_tree, maybe(lval),
|
|
code_info, code_info).
|
|
:- mode code_info__maybe_save_hp(in, out, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_restore_hp(maybe(lval), code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__maybe_restore_hp(in, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_restore_and_discard_hp(maybe(lval), code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__maybe_restore_and_discard_hp(in, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_discard_hp(maybe(lval), code_info, code_info).
|
|
:- mode code_info__maybe_discard_hp(in, in, out) is det.
|
|
|
|
:- pred code_info__save_ticket(code_tree, lval, code_info, code_info).
|
|
:- mode code_info__save_ticket(out, out, in, out) is det.
|
|
|
|
:- pred code_info__reset_ticket(lval, reset_trail_reason, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__reset_ticket(in, in, out, in, out) is det.
|
|
|
|
:- pred code_info__reset_and_discard_ticket(lval, reset_trail_reason, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__reset_and_discard_ticket(in, in, out, in, out) is det.
|
|
|
|
:- pred code_info__discard_ticket(lval, code_tree, code_info, code_info).
|
|
:- mode code_info__discard_ticket(in, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_save_ticket(bool, code_tree, maybe(lval),
|
|
code_info, code_info).
|
|
:- mode code_info__maybe_save_ticket(in, out, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_reset_ticket(maybe(lval), reset_trail_reason,
|
|
code_tree, code_info, code_info).
|
|
:- mode code_info__maybe_reset_ticket(in, in, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_reset_and_discard_ticket(maybe(lval),
|
|
reset_trail_reason, code_tree, code_info, code_info).
|
|
:- mode code_info__maybe_reset_and_discard_ticket(in, in, out, in, out) is det.
|
|
|
|
:- pred code_info__maybe_discard_ticket(maybe(lval), code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__maybe_discard_ticket(in, out, in, out) is det.
|
|
|
|
:- pred code_info__save_maxfr(lval, code_tree, code_info, code_info).
|
|
:- mode code_info__save_maxfr(out, out, in, out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
code_info__save_hp(Code, HpSlot) -->
|
|
code_info__acquire_temp_slot(lval(hp), HpSlot),
|
|
{ Code = node([mark_hp(HpSlot) - "Save heap pointer"]) }.
|
|
|
|
code_info__restore_hp(HpSlot, Code) -->
|
|
{ Code = node([restore_hp(lval(HpSlot)) - "Restore heap pointer"]) }.
|
|
|
|
code_info__discard_hp(HpSlot) -->
|
|
code_info__release_temp_slot(HpSlot).
|
|
|
|
code_info__restore_and_discard_hp(HpSlot, Code) -->
|
|
{ Code = node([restore_hp(lval(HpSlot)) - "Restore heap pointer"]) },
|
|
code_info__discard_hp(HpSlot).
|
|
|
|
code_info__maybe_save_hp(Maybe, Code, MaybeHpSlot) -->
|
|
( { Maybe = yes } ->
|
|
code_info__save_hp(Code, HpSlot),
|
|
{ MaybeHpSlot = yes(HpSlot) }
|
|
;
|
|
{ Code = empty },
|
|
{ MaybeHpSlot = no }
|
|
).
|
|
|
|
code_info__maybe_restore_hp(MaybeHpSlot, Code) -->
|
|
( { MaybeHpSlot = yes(HpSlot) } ->
|
|
code_info__restore_hp(HpSlot, Code)
|
|
;
|
|
{ Code = empty }
|
|
).
|
|
|
|
code_info__maybe_restore_and_discard_hp(MaybeHpSlot, Code) -->
|
|
( { MaybeHpSlot = yes(HpSlot) } ->
|
|
code_info__restore_and_discard_hp(HpSlot, Code)
|
|
;
|
|
{ Code = empty }
|
|
).
|
|
|
|
code_info__maybe_discard_hp(MaybeHpSlot) -->
|
|
( { MaybeHpSlot = yes(HpSlot) } ->
|
|
code_info__discard_hp(HpSlot)
|
|
;
|
|
[]
|
|
).
|
|
|
|
code_info__save_ticket(Code, TicketSlot) -->
|
|
code_info__acquire_temp_slot(ticket, TicketSlot),
|
|
{ Code = node([store_ticket(TicketSlot) - "Save trail state"]) }.
|
|
|
|
code_info__reset_ticket(TicketSlot, Reason, Code) -->
|
|
{ Code = node([reset_ticket(lval(TicketSlot), Reason) - "Reset trail"]) }.
|
|
|
|
code_info__reset_and_discard_ticket(TicketSlot, Reason, Code) -->
|
|
code_info__release_temp_slot(TicketSlot),
|
|
{ Code = node([
|
|
reset_ticket(lval(TicketSlot), Reason) - "Restore trail",
|
|
discard_ticket - "Pop ticket stack"
|
|
]) }.
|
|
|
|
code_info__discard_ticket(TicketSlot, Code) -->
|
|
code_info__release_temp_slot(TicketSlot),
|
|
{ Code = node([discard_ticket - "Pop ticket stack"]) }.
|
|
|
|
code_info__maybe_save_ticket(Maybe, Code, MaybeTicketSlot) -->
|
|
( { Maybe = yes } ->
|
|
code_info__save_ticket(Code, TicketSlot),
|
|
{ MaybeTicketSlot = yes(TicketSlot) }
|
|
;
|
|
{ Code = empty },
|
|
{ MaybeTicketSlot = no }
|
|
).
|
|
|
|
code_info__maybe_reset_ticket(MaybeTicketSlot, Reason, Code) -->
|
|
( { MaybeTicketSlot = yes(TicketSlot) } ->
|
|
code_info__reset_ticket(TicketSlot, Reason, Code)
|
|
;
|
|
{ Code = empty }
|
|
).
|
|
|
|
code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot, Reason, Code) -->
|
|
( { MaybeTicketSlot = yes(TicketSlot) } ->
|
|
code_info__reset_and_discard_ticket(TicketSlot, Reason, Code)
|
|
;
|
|
{ Code = empty }
|
|
).
|
|
|
|
code_info__maybe_discard_ticket(MaybeTicketSlot, Code) -->
|
|
( { MaybeTicketSlot = yes(TicketSlot) } ->
|
|
code_info__discard_ticket(TicketSlot, Code)
|
|
;
|
|
{ Code = empty }
|
|
).
|
|
|
|
code_info__save_maxfr(MaxfrSlot, Code) -->
|
|
code_info__acquire_temp_slot(lval(maxfr), MaxfrSlot),
|
|
{ Code = node([assign(MaxfrSlot, lval(maxfr)) - "Save maxfr"]) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Submodule to deal with code_exprn.
|
|
|
|
:- interface.
|
|
|
|
:- pred code_info__variable_locations(map(var, set(rval)),
|
|
code_info, code_info).
|
|
:- mode code_info__variable_locations(out, in, out) is det.
|
|
|
|
:- pred code_info__set_var_location(var, lval, code_info, code_info).
|
|
:- mode code_info__set_var_location(in, in, in, out) is det.
|
|
|
|
:- pred code_info__cache_expression(var, rval, code_info, code_info).
|
|
:- mode code_info__cache_expression(in, in, in, out) is det.
|
|
|
|
:- pred code_info__place_var(var, lval, code_tree, code_info, code_info).
|
|
:- mode code_info__place_var(in, in, out, in, out) is det.
|
|
|
|
:- pred code_info__produce_variable(var, code_tree, rval, code_info, code_info).
|
|
:- mode code_info__produce_variable(in, out, out, in, out) is det.
|
|
|
|
:- pred code_info__produce_variable_in_reg(var, code_tree, rval,
|
|
code_info, code_info).
|
|
:- mode code_info__produce_variable_in_reg(in, out, out, in, out) is det.
|
|
|
|
:- pred code_info__produce_variable_in_reg_or_stack(var, code_tree, rval,
|
|
code_info, code_info).
|
|
:- mode code_info__produce_variable_in_reg_or_stack(in, out, out, in, out)
|
|
is det.
|
|
|
|
:- pred code_info__materialize_vars_in_rval(rval, rval, code_tree, code_info,
|
|
code_info).
|
|
:- mode code_info__materialize_vars_in_rval(in, out, out, in, out) is det.
|
|
|
|
:- pred code_info__lock_reg(lval, code_info, code_info).
|
|
:- mode code_info__lock_reg(in, in, out) is det.
|
|
|
|
:- pred code_info__unlock_reg(lval, code_info, code_info).
|
|
:- mode code_info__unlock_reg(in, in, out) is det.
|
|
|
|
:- pred code_info__acquire_reg_for_var(var, lval, code_info, code_info).
|
|
:- mode code_info__acquire_reg_for_var(in, out, in, out) is det.
|
|
|
|
:- pred code_info__acquire_reg(reg_type, lval, code_info, code_info).
|
|
:- mode code_info__acquire_reg(in, out, in, out) is det.
|
|
|
|
:- pred code_info__release_reg(lval, code_info, code_info).
|
|
:- mode code_info__release_reg(in, in, out) is det.
|
|
|
|
:- pred code_info__clear_r1(code_tree, code_info, code_info).
|
|
:- mode code_info__clear_r1(out, in, out) is det.
|
|
|
|
:- pred code_info__generate_branch_end(code_model, store_map, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__generate_branch_end(in, in, out, in, out) is det.
|
|
|
|
% code_info__remake_with_store_map throws away the exprn_info data
|
|
% structure, forgetting the current locations of all variables,
|
|
% and rebuilds it from scratch based on the given store map.
|
|
% The new exprn_info will know about only the variables present
|
|
% in the store map, and will believe they are where the store map
|
|
% says they are.
|
|
|
|
:- pred code_info__remake_with_store_map(store_map, code_info, code_info).
|
|
:- mode code_info__remake_with_store_map(in, in, out) is det.
|
|
|
|
:- type call_direction ---> caller ; callee.
|
|
|
|
% Generate code to either setup the input arguments for a call
|
|
% (i.e. in the caller), or to setup the output arguments in the
|
|
% predicate epilog (i.e. in the callee).
|
|
|
|
:- pred code_info__setup_call(assoc_list(var, arg_info),
|
|
call_direction, code_tree, code_info, code_info).
|
|
:- mode code_info__setup_call(in, in, out, in, out) is det.
|
|
|
|
:- pred code_info__clear_all_registers(code_info, code_info).
|
|
:- mode code_info__clear_all_registers(in, out) is det.
|
|
|
|
:- pred code_info__save_variable_on_stack(var, code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__save_variable_on_stack(in, out, in, out) is det.
|
|
|
|
:- pred code_info__save_variables_on_stack(list(var), code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__save_variables_on_stack(in, out, in, out) is det.
|
|
|
|
:- pred code_info__max_reg_in_use(int, code_info, code_info).
|
|
:- mode code_info__max_reg_in_use(out, in, out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- pred code_info__place_vars(assoc_list(var, set(rval)), code_tree,
|
|
code_info, code_info).
|
|
:- mode code_info__place_vars(in, out, in, out) is det.
|
|
|
|
code_info__variable_locations(Locations) -->
|
|
code_info__get_exprn_info(Exprn),
|
|
{ code_exprn__get_varlocs(Exprn, Locations) }.
|
|
|
|
code_info__set_var_location(Var, Lval) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__set_var_location(Var, Lval, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__cache_expression(Var, Rval) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__cache_exprn(Var, Rval, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__place_var(Var, Lval, Code) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__place_var(Var, Lval, Code, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__place_vars([], empty) --> [].
|
|
code_info__place_vars([V - Rs | RestList], Code) -->
|
|
(
|
|
{ set__to_sorted_list(Rs, RList) },
|
|
{ code_info__lval_in_rval_list(L, RList) }
|
|
->
|
|
code_info__place_var(V, L, ThisCode)
|
|
;
|
|
{ ThisCode = empty }
|
|
),
|
|
code_info__place_vars(RestList, RestCode),
|
|
{ Code = tree(ThisCode, RestCode) }.
|
|
|
|
:- pred code_info__lval_in_rval_list(lval, list(rval)).
|
|
:- mode code_info__lval_in_rval_list(out, in) is semidet.
|
|
|
|
code_info__lval_in_rval_list(Lval, [Rval | Rvals]) :-
|
|
( Rval = lval(Lval0) ->
|
|
Lval = Lval0
|
|
;
|
|
code_info__lval_in_rval_list(Lval, Rvals)
|
|
).
|
|
|
|
code_info__produce_variable(Var, Code, Rval) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__produce_var(Var, Rval, Code, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__produce_variable_in_reg(Var, Code, Rval) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__produce_var_in_reg(Var, Rval, Code, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__produce_variable_in_reg_or_stack(Var, Code, Rval) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__produce_var_in_reg_or_stack(Var, Rval, Code,
|
|
Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__materialize_vars_in_rval(Rval0, Rval, Code) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__materialize_vars_in_rval(Rval0, Rval, Code,
|
|
Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__lock_reg(Reg) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__lock_reg(Reg, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__unlock_reg(Reg) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__unlock_reg(Reg, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__acquire_reg_for_var(Var, Lval) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
code_info__get_follow_vars(Follow),
|
|
(
|
|
{ map__search(Follow, Var, PrefLval) },
|
|
{ PrefLval = reg(PrefRegType, PrefRegNum) }
|
|
->
|
|
{ code_exprn__acquire_reg_prefer_given(PrefRegType, PrefRegNum,
|
|
Lval, Exprn0, Exprn) }
|
|
;
|
|
{ code_exprn__acquire_reg(r, Lval, Exprn0, Exprn) }
|
|
),
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__acquire_reg(Type, Lval) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__acquire_reg(Type, Lval, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__release_reg(Lval) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__release_reg(Lval, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__clear_r1(Code) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__clear_r1(Code, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__generate_branch_end(CodeModel, StoreMap, Code) -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ map__to_assoc_list(StoreMap, VarLocs) },
|
|
{ code_exprn__place_vars(VarLocs, PlaceCode, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn),
|
|
( { CodeModel = model_non } ->
|
|
code_info__unset_failure_cont(FlushCode),
|
|
{ Code = tree(PlaceCode, FlushCode) }
|
|
;
|
|
{ Code = PlaceCode }
|
|
).
|
|
|
|
code_info__remake_with_store_map(StoreMap) -->
|
|
{ map__to_assoc_list(StoreMap, VarLvals) },
|
|
{ code_info__fixup_lvallist(VarLvals, VarRvals) },
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__reinit_state(VarRvals, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
:- pred code_info__fixup_lvallist(assoc_list(var, lval), assoc_list(var, rval)).
|
|
:- mode code_info__fixup_lvallist(in, out) is det.
|
|
|
|
code_info__fixup_lvallist([], []).
|
|
code_info__fixup_lvallist([V - L | Ls], [V - lval(L) | Rs]) :-
|
|
code_info__fixup_lvallist(Ls, Rs).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__setup_call([], _Direction, empty) --> [].
|
|
code_info__setup_call([V - arg_info(Loc, Mode) | Rest], Direction, Code) -->
|
|
(
|
|
{
|
|
Mode = top_in,
|
|
Direction = caller
|
|
;
|
|
Mode = top_out,
|
|
Direction = callee
|
|
}
|
|
->
|
|
{ code_util__arg_loc_to_register(Loc, Reg) },
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__place_var(V, Reg, Code0, Exprn0, Exprn1) },
|
|
% We need to test that either the variable
|
|
% is live OR it occurs in the remaining arguments
|
|
% because of a bug in polymorphism.m which
|
|
% causes some compiler generated code to violate
|
|
% superhomogeneous form
|
|
(
|
|
code_info__variable_is_forward_live(V)
|
|
->
|
|
{ IsLive = yes }
|
|
;
|
|
{ IsLive = no }
|
|
),
|
|
{
|
|
list__member(Vtmp - _, Rest),
|
|
V = Vtmp
|
|
->
|
|
Occurs = yes
|
|
;
|
|
Occurs = no
|
|
},
|
|
(
|
|
% We can't simply use a disj here
|
|
% because of bugs in modes/det_analysis
|
|
{ bool__or(Occurs, IsLive, yes) }
|
|
->
|
|
{ code_exprn__lock_reg(Reg, Exprn1, Exprn2) },
|
|
code_info__set_exprn_info(Exprn2),
|
|
code_info__setup_call(Rest, Direction, Code1),
|
|
code_info__get_exprn_info(Exprn3),
|
|
{ code_exprn__unlock_reg(Reg, Exprn3, Exprn) },
|
|
code_info__set_exprn_info(Exprn),
|
|
{ Code = tree(Code0, Code1) }
|
|
;
|
|
{ code_exprn__lock_reg(Reg, Exprn1, Exprn2) },
|
|
code_info__set_exprn_info(Exprn2),
|
|
{ set__singleton_set(Vset, V) },
|
|
code_info__make_vars_forward_dead(Vset),
|
|
code_info__setup_call(Rest, Direction, Code1),
|
|
code_info__get_exprn_info(Exprn4),
|
|
{ code_exprn__unlock_reg(Reg, Exprn4, Exprn) },
|
|
code_info__set_exprn_info(Exprn),
|
|
{ Code = tree(Code0, Code1) }
|
|
)
|
|
;
|
|
code_info__setup_call(Rest, Direction, Code)
|
|
).
|
|
|
|
% XXX We could use the sanity checking mechanism...
|
|
code_info__clear_all_registers -->
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__clobber_regs([], Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__save_variable_on_stack(Var, Code) -->
|
|
code_info__get_variable_slot(Var, Slot),
|
|
code_info__get_exprn_info(Exprn0),
|
|
{ code_exprn__place_var(Var, Slot, Code, Exprn0, Exprn) },
|
|
code_info__set_exprn_info(Exprn).
|
|
|
|
code_info__save_variables_on_stack([], empty) --> [].
|
|
code_info__save_variables_on_stack([Var | Vars], Code) -->
|
|
code_info__save_variable_on_stack(Var, FirstCode),
|
|
code_info__save_variables_on_stack(Vars, RestCode),
|
|
{ Code = tree(FirstCode, RestCode) }.
|
|
|
|
code_info__max_reg_in_use(Max) -->
|
|
code_info__get_exprn_info(Exprn),
|
|
{ code_exprn__max_reg_in_use(Exprn, Max) }.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Submodule for dealing with information for garbage collection
|
|
% and value numbering.
|
|
|
|
:- interface.
|
|
|
|
:- pred code_info__generate_stack_livevals(set(var), set(lval),
|
|
code_info, code_info).
|
|
:- mode code_info__generate_stack_livevals(in, out, in, out) is det.
|
|
|
|
:- pred code_info__generate_stack_livelvals(set(var), instmap,
|
|
list(liveinfo), code_info, code_info).
|
|
:- mode code_info__generate_stack_livelvals(in, in, out, in, out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
code_info__generate_stack_livevals(Args, LiveVals) -->
|
|
code_info__get_known_variables(LiveVars),
|
|
{ set__list_to_set(LiveVars, Vars0) },
|
|
{ set__difference(Vars0, Args, Vars) },
|
|
{ set__to_sorted_list(Vars, VarList) },
|
|
{ set__init(LiveVals0) },
|
|
code_info__generate_var_livevals(VarList, LiveVals0, LiveVals1),
|
|
code_info__get_temps_in_use(TempsSet),
|
|
{ map__to_assoc_list(TempsSet, Temps) },
|
|
{ code_info__generate_temp_livevals(Temps, LiveVals1, LiveVals2) },
|
|
code_info__get_commit_triple_count(Triples),
|
|
{ code_info__generate_commit_livevals(Triples, LiveVals2, LiveVals) }.
|
|
|
|
:- pred code_info__generate_var_livevals(list(var), set(lval), set(lval),
|
|
code_info, code_info).
|
|
:- mode code_info__generate_var_livevals(in, in, out, in, out) is det.
|
|
|
|
code_info__generate_var_livevals([], Vals, Vals) --> [].
|
|
code_info__generate_var_livevals([V | Vs], Vals0, Vals) -->
|
|
code_info__get_variable_slot(V, Slot),
|
|
{ set__insert(Vals0, Slot, Vals1) },
|
|
code_info__generate_var_livevals(Vs, Vals1, Vals).
|
|
|
|
:- pred code_info__generate_temp_livevals(assoc_list(lval, slot_contents),
|
|
set(lval), set(lval)).
|
|
:- mode code_info__generate_temp_livevals(in, in, out) is det.
|
|
|
|
code_info__generate_temp_livevals([], Vals, Vals).
|
|
code_info__generate_temp_livevals([Slot - _ | Slots], Vals0, Vals) :-
|
|
set__insert(Vals0, Slot, Vals1),
|
|
code_info__generate_temp_livevals(Slots, Vals1, Vals).
|
|
|
|
:- pred code_info__generate_commit_livevals(int, set(lval), set(lval)).
|
|
:- mode code_info__generate_commit_livevals(in, in, out) is det.
|
|
|
|
code_info__generate_commit_livevals(Triples0, Vals0, Vals) :-
|
|
( Triples0 = 0 ->
|
|
Vals = Vals0
|
|
;
|
|
CurfrSlot is (Triples0 - 1) * 3 + 1,
|
|
MaxfrSlot is (Triples0 - 1) * 3 + 2,
|
|
RedoipSlot is (Triples0 - 1) * 3 + 3,
|
|
CurfrVar = stackvar(CurfrSlot),
|
|
MaxfrVar = stackvar(MaxfrSlot),
|
|
RedoipVar = stackvar(RedoipSlot),
|
|
set__insert(Vals0, CurfrVar, Vals1),
|
|
set__insert(Vals1, MaxfrVar, Vals2),
|
|
set__insert(Vals2, RedoipVar, Vals3),
|
|
Triples1 is Triples0 - 1,
|
|
code_info__generate_commit_livevals(Triples1, Vals3, Vals)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__generate_stack_livelvals(Args, AfterCallInstMap, LiveVals) -->
|
|
code_info__get_known_variables(LiveVars),
|
|
{ set__list_to_set(LiveVars, Vars0) },
|
|
{ set__difference(Vars0, Args, Vars) },
|
|
{ set__to_sorted_list(Vars, VarList) },
|
|
{ set__init(LiveVals0) },
|
|
code_info__generate_var_livelvals(VarList, LiveVals0, LiveVals1),
|
|
{ set__to_sorted_list(LiveVals1, LiveVals2) },
|
|
code_info__get_globals(Globals),
|
|
{ globals__get_gc_method(Globals, GC_Method) },
|
|
code_info__livevals_to_livelvals(LiveVals2, GC_Method,
|
|
AfterCallInstMap, LiveVals3),
|
|
code_info__get_temps_in_use(TempsSet),
|
|
{ map__to_assoc_list(TempsSet, Temps) },
|
|
{ code_info__generate_temp_livelvals(Temps, LiveVals3, LiveVals4) },
|
|
code_info__get_commit_triple_count(Triples),
|
|
{ code_info__generate_commit_livelvals(Triples, LiveVals4, LiveVals) }.
|
|
|
|
:- pred code_info__generate_var_livelvals(list(var),
|
|
set(pair(lval, var)), set(pair(lval, var)), code_info, code_info).
|
|
:- mode code_info__generate_var_livelvals(in, in, out, in, out) is det.
|
|
|
|
code_info__generate_var_livelvals([], Vals, Vals) --> [].
|
|
code_info__generate_var_livelvals([V | Vs], Vals0, Vals) -->
|
|
code_info__get_variable_slot(V, Slot),
|
|
{ set__insert(Vals0, Slot - V, Vals1) },
|
|
code_info__generate_var_livelvals(Vs, Vals1, Vals).
|
|
|
|
:- pred code_info__generate_temp_livelvals(assoc_list(lval, slot_contents),
|
|
list(liveinfo), list(liveinfo)).
|
|
:- mode code_info__generate_temp_livelvals(in, in, out) is det.
|
|
|
|
code_info__generate_temp_livelvals([], LiveInfo, LiveInfo).
|
|
code_info__generate_temp_livelvals([Slot - StoredLval | Slots], LiveInfo0,
|
|
[live_lvalue(Slot, LiveValueType, "", []) | LiveInfo1]) :-
|
|
code_info__get_live_value_type(StoredLval, LiveValueType),
|
|
code_info__generate_temp_livelvals(Slots, LiveInfo0, LiveInfo1).
|
|
|
|
:- pred code_info__generate_commit_livelvals(int,
|
|
list(liveinfo), list(liveinfo)).
|
|
:- mode code_info__generate_commit_livelvals(in, in, out) is det.
|
|
|
|
code_info__generate_commit_livelvals(Triples0, LiveInfo0, LiveInfo) :-
|
|
( Triples0 = 0 ->
|
|
LiveInfo = LiveInfo0
|
|
;
|
|
Triples1 is Triples0 - 1,
|
|
code_info__generate_commit_livelvals(Triples1,
|
|
LiveInfo0, LiveInfo1),
|
|
CurfrSlot is (Triples0 - 1) * 3 + 1,
|
|
MaxfrSlot is (Triples0 - 1) * 3 + 2,
|
|
RedoipSlot is (Triples0 - 1) * 3 + 3,
|
|
CurfrVar = stackvar(CurfrSlot),
|
|
MaxfrVar = stackvar(MaxfrSlot),
|
|
RedoipVar = stackvar(RedoipSlot),
|
|
code_info__get_live_value_type(lval(curfr), CurfrValueType),
|
|
code_info__get_live_value_type(lval(maxfr), MaxfrValueType),
|
|
code_info__get_live_value_type(lval(redoip(lval(maxfr))),
|
|
RedoipValueType),
|
|
LiveInfo2 = [live_lvalue(CurfrVar, CurfrValueType, "", []) |
|
|
LiveInfo1],
|
|
LiveInfo3 = [live_lvalue(MaxfrVar, MaxfrValueType, "", []) |
|
|
LiveInfo2],
|
|
LiveInfo = [live_lvalue(RedoipVar, RedoipValueType, "", []) |
|
|
LiveInfo3]
|
|
).
|
|
|
|
:- pred code_info__livevals_to_livelvals(assoc_list(lval, var), gc_method,
|
|
instmap, list(liveinfo), code_info, code_info).
|
|
:- mode code_info__livevals_to_livelvals(in, in, in, out, in, out) is det.
|
|
|
|
code_info__livevals_to_livelvals([], _GC_Method, _, []) --> [].
|
|
code_info__livevals_to_livelvals([Lval - Var | Ls], GC_Method, AfterCallInstMap,
|
|
[LiveLval | Lives]) -->
|
|
code_info__get_varset(VarSet),
|
|
{ varset__lookup_name(VarSet, Var, Name) },
|
|
(
|
|
{ GC_Method = accurate }
|
|
->
|
|
{ instmap__lookup_var(AfterCallInstMap, Var, Inst) },
|
|
|
|
code_info__variable_type(Var, Type),
|
|
{ type_util__vars(Type, TypeVars) },
|
|
code_info__find_type_infos(TypeVars, TypeParams),
|
|
{ LiveLval = live_lvalue(Lval, var(Type, Inst), Name,
|
|
TypeParams) }
|
|
;
|
|
{ LiveLval = live_lvalue(Lval, unwanted, Name, []) }
|
|
),
|
|
code_info__livevals_to_livelvals(Ls, GC_Method, AfterCallInstMap,
|
|
Lives).
|
|
|
|
:- pred code_info__get_live_value_type(slot_contents, live_value_type).
|
|
:- mode code_info__get_live_value_type(in, out) is det.
|
|
|
|
code_info__get_live_value_type(lval(succip), succip).
|
|
code_info__get_live_value_type(lval(hp), hp).
|
|
code_info__get_live_value_type(lval(maxfr), maxfr).
|
|
code_info__get_live_value_type(lval(curfr), curfr).
|
|
code_info__get_live_value_type(lval(succfr(_)), unwanted).
|
|
code_info__get_live_value_type(lval(prevfr(_)), unwanted).
|
|
code_info__get_live_value_type(lval(redoip(_)), unwanted).
|
|
code_info__get_live_value_type(lval(succip(_)), unwanted).
|
|
code_info__get_live_value_type(lval(sp), unwanted).
|
|
code_info__get_live_value_type(lval(lvar(_)), unwanted).
|
|
code_info__get_live_value_type(lval(field(_, _, _)), unwanted).
|
|
code_info__get_live_value_type(lval(temp(_, _)), unwanted).
|
|
code_info__get_live_value_type(lval(reg(_, _)), unwanted).
|
|
code_info__get_live_value_type(lval(stackvar(_)), unwanted).
|
|
code_info__get_live_value_type(lval(framevar(_)), unwanted).
|
|
code_info__get_live_value_type(lval(mem_ref(_)), unwanted). % XXX
|
|
code_info__get_live_value_type(ticket, unwanted). % XXX we may need to
|
|
% modify this, if the GC is going
|
|
% to garbage-collect the trail.
|
|
code_info__get_live_value_type(ticket_counter, unwanted).
|
|
code_info__get_live_value_type(trace_data, unwanted).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Submodule for managing stack slots.
|
|
|
|
% The det stack frame is organized as follows.
|
|
%
|
|
% ... unused ...
|
|
% sp ---> <first unused slot>
|
|
% <space for local var 1>
|
|
% ... local vars ...
|
|
% <space for local var n>
|
|
% <space for temporary reg save 1>
|
|
% ... temporary reg saves ...
|
|
% <space for temporary reg save n>
|
|
% <space for succip>
|
|
%
|
|
% The stack pointer points to the first free location at the
|
|
% top of the stack.
|
|
%
|
|
% `code_info__num_stackslots' counts the number of slots reserved
|
|
% for saving local variables. XXX
|
|
%
|
|
% `code_info__max_push_count' counts the number of slots reserved
|
|
% for saving and restoring registers (hp, redoip, etc.)
|
|
%
|
|
% `code_info__succip_used' determines whether we need a slot to
|
|
% hold the succip.
|
|
%
|
|
% The variable part of the nondet stack is organized in the same way
|
|
% as the det stack (but the nondet stack also contains several other
|
|
% fixed fields.)
|
|
|
|
:- interface.
|
|
|
|
% Returns the total stackslot count, but not including space for
|
|
% succip.
|
|
:- pred code_info__get_total_stackslot_count(int, code_info, code_info).
|
|
:- mode code_info__get_total_stackslot_count(out, in, out) is det.
|
|
|
|
:- pred code_info__get_trace_slot(lval, code_info, code_info).
|
|
:- mode code_info__get_trace_slot(out, in, out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- pred code_info__acquire_temp_slot(slot_contents, lval,
|
|
code_info, code_info).
|
|
:- mode code_info__acquire_temp_slot(in, out, in, out) is det.
|
|
|
|
:- pred code_info__release_temp_slot(lval, code_info, code_info).
|
|
:- mode code_info__release_temp_slot(in, in, out) is det.
|
|
|
|
:- pred code_info__get_variable_slot(var, lval, code_info, code_info).
|
|
:- mode code_info__get_variable_slot(in, out, in, out) is det.
|
|
|
|
:- pred code_info__max_var_slot(stack_slots, int).
|
|
:- mode code_info__max_var_slot(in, out) is det.
|
|
|
|
:- pred code_info__stack_variable(int, lval, code_info, code_info).
|
|
:- mode code_info__stack_variable(in, out, in, out) is det.
|
|
|
|
code_info__get_trace_slot(StackVar) -->
|
|
code_info__acquire_temp_slot(trace_data, StackVar).
|
|
|
|
code_info__acquire_temp_slot(Item, StackVar) -->
|
|
code_info__get_avail_temp_slots(AvailSlots0),
|
|
( { set__remove_least(AvailSlots0, StackVarPrime, AvailSlots) } ->
|
|
{ StackVar = StackVarPrime },
|
|
code_info__set_avail_temp_slots(AvailSlots)
|
|
;
|
|
code_info__get_var_slot_count(VarSlots),
|
|
code_info__get_max_temp_slot_count(TempSlots0),
|
|
{ TempSlots is TempSlots0 + 1 },
|
|
{ Slot is VarSlots + TempSlots },
|
|
code_info__stack_variable(Slot, StackVar),
|
|
code_info__set_max_temp_slot_count(TempSlots)
|
|
),
|
|
code_info__get_temps_in_use(TempsInUse0),
|
|
{ map__det_insert(TempsInUse0, StackVar, Item, TempsInUse) },
|
|
code_info__set_temps_in_use(TempsInUse).
|
|
|
|
code_info__release_temp_slot(StackVar) -->
|
|
code_info__get_avail_temp_slots(AvailSlots0),
|
|
{ set__insert(AvailSlots0, StackVar, AvailSlots) },
|
|
code_info__set_avail_temp_slots(AvailSlots),
|
|
code_info__get_temps_in_use(TempsInUse0),
|
|
{ map__delete(TempsInUse0, StackVar, TempsInUse) },
|
|
code_info__set_temps_in_use(TempsInUse).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
code_info__get_variable_slot(Var, Slot) -->
|
|
code_info__get_stack_slots(StackSlots),
|
|
( { map__search(StackSlots, Var, SlotPrime) } ->
|
|
{ Slot = SlotPrime }
|
|
;
|
|
code_info__variable_to_string(Var, Name),
|
|
{ term__var_to_int(Var, Num) },
|
|
{ string__int_to_string(Num, NumStr) },
|
|
{ string__append_list([
|
|
"code_info__get_variable_slot: variable `",
|
|
Name, "' (", NumStr, ") not found"], Str) },
|
|
{ error(Str) }
|
|
).
|
|
|
|
code_info__max_var_slot(StackSlots, SlotCount) :-
|
|
map__values(StackSlots, StackSlotList),
|
|
code_info__max_var_slot_2(StackSlotList, 0, SlotCount).
|
|
|
|
:- pred code_info__max_var_slot_2(list(lval), int, int).
|
|
:- mode code_info__max_var_slot_2(in, in, out) is det.
|
|
|
|
code_info__max_var_slot_2([], Max, Max).
|
|
code_info__max_var_slot_2([L | Ls], Max0, Max) :-
|
|
( L = stackvar(N) ->
|
|
int__max(N, Max0, Max1)
|
|
; L = framevar(N) ->
|
|
int__max(N, Max0, Max1)
|
|
;
|
|
Max1 = Max0
|
|
),
|
|
code_info__max_var_slot_2(Ls, Max1, Max).
|
|
|
|
code_info__get_total_stackslot_count(NumSlots) -->
|
|
code_info__get_var_slot_count(SlotsForVars),
|
|
code_info__get_max_temp_slot_count(SlotsForTemps),
|
|
{ NumSlots is SlotsForVars + SlotsForTemps }.
|
|
|
|
code_info__stack_variable(Num, Lval) -->
|
|
code_info__get_proc_model(CodeModel),
|
|
( { CodeModel = model_non } ->
|
|
{ Num1 is Num - 1 }, % framevars start at zero
|
|
{ Lval = framevar(Num1) }
|
|
;
|
|
{ Lval = stackvar(Num) } % stackvars start at one
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|