Files
mercury/compiler/stack_alloc.m
Zoltan Somogyi 3c60c0e485 Change a bunch of modules to import only one module per line, even
Estimated hours taken: 4
Branches: main

compiler/*.m:
	Change a bunch of modules to import only one module per line, even
	from the library.

compiler/mlds_to_il.m:
compiler/mlds_to_managed.m:
	Convert these modules to our current coding style. Use state variables
	where appropriate. Use predmode declarations where possible.
2005-03-22 06:40:32 +00:00

270 lines
9.9 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 2002-2005 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 stack_alloc.m
%
% Authors: zs, conway.
%
% This module allocates stack slots to the variables that need to be saved
% across a call, across a goal that may fail, or in a parallel conjunction.
%
% The jobs is done in two steps. First we traverse the predicate definition
% looking for sets of variables that must be saved on the stack at the same
% time. If --optimize-stack-slots is set, then this phase is done by
% stack_opt.m; if --optimize-stack-slots is not set, then it is done by
% this module. Then we use a graph colouring algorithm to find an allocation
% of stack slots (colours) to variables such that in each set of variables
% that must be saved at the same time, each variable has a different colour.
%-----------------------------------------------------------------------------%
:- module ll_backend__stack_alloc.
:- interface.
:- import_module hlds__hlds_module.
:- import_module hlds__hlds_pred.
:- import_module io.
:- pred allocate_stack_slots_in_proc(pred_id::in, proc_id::in, module_info::in,
proc_info::in, proc_info::out, io::di, io::uo) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module check_hlds__goal_path.
:- import_module check_hlds__type_util.
:- import_module hlds__code_model.
:- import_module hlds__hlds_data.
:- import_module hlds__hlds_goal.
:- import_module hlds__hlds_llds.
:- import_module libs__globals.
:- import_module libs__graph_colour.
:- import_module libs__options.
:- import_module libs__trace_params.
:- import_module ll_backend__live_vars.
:- import_module ll_backend__liveness.
:- import_module ll_backend__llds.
:- import_module ll_backend__stack_opt.
:- import_module ll_backend__trace.
:- import_module parse_tree__prog_data.
:- import_module assoc_list.
:- import_module bool.
:- import_module int.
:- import_module list.
:- import_module map.
:- import_module require.
:- import_module set.
:- import_module std_util.
%-----------------------------------------------------------------------------%
allocate_stack_slots_in_proc(PredId, _ProcId, ModuleInfo, !ProcInfo, !IO) :-
initial_liveness(!.ProcInfo, PredId, ModuleInfo, Liveness0),
module_info_pred_info(ModuleInfo, PredId, PredInfo),
module_info_globals(ModuleInfo, Globals),
globals__get_trace_level(Globals, TraceLevel),
(
eff_trace_level_needs_input_vars(PredInfo, !.ProcInfo,
TraceLevel) = yes
->
trace__fail_vars(ModuleInfo, !.ProcInfo, FailVars)
;
set__init(FailVars)
),
body_should_use_typeinfo_liveness(PredInfo, Globals, TypeInfoLiveness),
globals__lookup_bool_option(Globals, opt_no_return_calls,
OptNoReturnCalls),
AllocData = alloc_data(ModuleInfo, !.ProcInfo, TypeInfoLiveness,
OptNoReturnCalls),
set__init(NondetLiveness0),
SimpleStackAlloc0 = stack_alloc(set__make_singleton_set(FailVars)),
proc_info_goal(!.ProcInfo, Goal0),
build_live_sets_in_goal(Goal0, Goal, FailVars, AllocData,
SimpleStackAlloc0, SimpleStackAlloc, Liveness0, _Liveness,
NondetLiveness0, _NondetLiveness),
proc_info_set_goal(Goal, !ProcInfo),
SimpleStackAlloc = stack_alloc(LiveSets0),
trace__do_we_need_maxfr_slot(Globals, PredInfo, !ProcInfo),
trace__reserved_slots(ModuleInfo, PredInfo, !.ProcInfo, Globals,
NumReservedSlots, MaybeReservedVarInfo),
(
MaybeReservedVarInfo = yes(ResVar - _),
set__singleton_set(ResVarSet, ResVar),
set__insert(LiveSets0, ResVarSet, LiveSets1)
;
MaybeReservedVarInfo = no,
LiveSets1 = LiveSets0
),
proc_info_vartypes(!.ProcInfo, VarTypes),
filter_out_dummy_values(VarTypes, LiveSets1, LiveSets, DummyVars),
graph_colour__group_elements(LiveSets, ColourSets),
set__to_sorted_list(ColourSets, ColourList),
proc_info_interface_code_model(!.ProcInfo, CodeModel),
allocate_stack_slots(ColourList, CodeModel, NumReservedSlots,
MaybeReservedVarInfo, StackSlots1),
allocate_dummy_stack_slots(DummyVars, CodeModel, -1,
StackSlots1, StackSlots),
proc_info_set_stack_slots(StackSlots, !ProcInfo).
:- pred filter_out_dummy_values(vartypes::in,
set(set(prog_var))::in, set(set(prog_var))::out,
list(prog_var)::out) is det.
filter_out_dummy_values(VarTypes, LiveSet0, LiveSet, DummyVars) :-
set__to_sorted_list(LiveSet0, LiveList0),
filter_out_dummy_values_2(VarTypes, LiveList0, LiveList,
set__init, Dummies),
set__list_to_set(LiveList, LiveSet),
set__to_sorted_list(Dummies, DummyVars).
:- pred filter_out_dummy_values_2(vartypes::in,
list(set(prog_var))::in, list(set(prog_var))::out,
set(prog_var)::in, set(prog_var)::out) is det.
filter_out_dummy_values_2(_VarTypes, [], [], !Dummies).
filter_out_dummy_values_2(VarTypes, [LiveSet0 | LiveSets0], LiveSets,
!Dummies) :-
filter_out_dummy_values_2(VarTypes, LiveSets0, LiveSets1, !Dummies),
set__to_sorted_list(LiveSet0, LiveList0),
list__filter(var_is_of_dummy_type(VarTypes), LiveList0,
DummyVars, NonDummyVars),
set__insert_list(!.Dummies, DummyVars, !:Dummies),
(
NonDummyVars = [],
LiveSets = LiveSets1
;
NonDummyVars = [_ | _],
LiveSets = [list_to_set(NonDummyVars) | LiveSets1]
).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- type stack_alloc
---> stack_alloc(
set(set(prog_var)) % The sets of vars that need to
% be on the stack at the same
% time.
).
:- instance stack_alloc_info(stack_alloc) where [
pred(at_call_site/4) is alloc_at_call_site,
pred(at_resume_site/4) is alloc_at_resume_site,
pred(at_par_conj/4) is alloc_at_par_conj
].
:- pred alloc_at_call_site(need_across_call::in, hlds_goal_info::in,
stack_alloc::in, stack_alloc::out) is det.
alloc_at_call_site(NeedAtCall, _GoalInfo, StackAlloc0, StackAlloc) :-
NeedAtCall = need_across_call(ForwardVars, ResumeVars, NondetLiveVars),
LiveSet = set__union_list([ForwardVars, ResumeVars, NondetLiveVars]),
StackAlloc0 = stack_alloc(LiveSets0),
LiveSets = set__insert(LiveSets0, LiveSet),
StackAlloc = stack_alloc(LiveSets).
:- pred alloc_at_resume_site(need_in_resume::in, hlds_goal_info::in,
stack_alloc::in, stack_alloc::out) is det.
alloc_at_resume_site(NeedAtResume, _GoalInfo, StackAlloc0, StackAlloc) :-
NeedAtResume = need_in_resume(ResumeOnStack, ResumeVars,
NondetLiveVars),
(
ResumeOnStack = no,
StackAlloc = StackAlloc0
;
ResumeOnStack = yes,
LiveSet = set__union(ResumeVars, NondetLiveVars),
StackAlloc0 = stack_alloc(LiveSets0),
LiveSets = set__insert(LiveSets0, LiveSet),
StackAlloc = stack_alloc(LiveSets)
).
:- pred alloc_at_par_conj(need_in_par_conj::in, hlds_goal_info::in,
stack_alloc::in, stack_alloc::out) is det.
alloc_at_par_conj(NeedParConj, _GoalInfo, StackAlloc0, StackAlloc) :-
NeedParConj = need_in_par_conj(StackVars),
StackAlloc0 = stack_alloc(LiveSets0),
LiveSets = set__insert(LiveSets0, StackVars),
StackAlloc = stack_alloc(LiveSets).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- pred allocate_stack_slots(list(set(prog_var))::in, code_model::in, int::in,
maybe(pair(prog_var, int))::in, stack_slots::out) is det.
allocate_stack_slots(ColourList, CodeModel, NumReservedSlots,
MaybeReservedVarInfo, StackSlots) :-
% The reserved slots are referred to by fixed number
% (e.g. framevar(1)) in trace__setup.
FirstVarSlot = NumReservedSlots + 1,
allocate_stack_slots_2(ColourList, CodeModel, FirstVarSlot,
MaybeReservedVarInfo, map__init, StackSlots).
:- pred allocate_stack_slots_2(list(set(prog_var))::in, code_model::in,
int::in, maybe(pair(prog_var, int))::in,
stack_slots::in, stack_slots::out) is det.
allocate_stack_slots_2([], _, _, _, !StackSlots).
allocate_stack_slots_2([Vars | VarSets], CodeModel, N0, MaybeReservedVarInfo,
!StackSlots) :-
(
MaybeReservedVarInfo = yes(ResVar - ResSlotNum),
set__member(ResVar, Vars)
->
SlotNum = ResSlotNum,
N1 = N0
;
SlotNum = N0,
N1 = N0 + 1
),
set__to_sorted_list(Vars, VarList),
allocate_same_stack_slot(VarList, CodeModel, SlotNum, !StackSlots),
allocate_stack_slots_2(VarSets, CodeModel, N1, MaybeReservedVarInfo,
!StackSlots).
:- pred allocate_same_stack_slot(list(prog_var)::in, code_model::in, int::in,
stack_slots::in, stack_slots::out) is det.
allocate_same_stack_slot([], _CodeModel, _Slot, !StackSlots).
allocate_same_stack_slot([Var | Vars], CodeModel, Slot, !StackSlots) :-
( CodeModel = model_non ->
Locn = nondet_slot(Slot)
;
Locn = det_slot(Slot)
),
map__det_insert(!.StackSlots, Var, Locn, !:StackSlots),
allocate_same_stack_slot(Vars, CodeModel, Slot, !StackSlots).
% We must not allocate the same stack slot to dummy variables. If we do,
% then the code that saves variables on the stack at calls will get confused.
% After saving one dummy variable on the stack, it will try to save the next
% in the same stack slot; believing the first variable to still be live, it
% will move it away.
%
% In ordinary grades, it is possible to have one value of type io__state
% and another of type store__store live at the same time; in debugging grades,
% due to our policy of extending variable lifetimes, more than one io__state
% may be live at the same time.
:- pred allocate_dummy_stack_slots(list(prog_var)::in, code_model::in,
int::in, stack_slots::in, stack_slots::out) is det.
allocate_dummy_stack_slots([], _, _, !StackSlots).
allocate_dummy_stack_slots([Var | Vars], CodeModel, N0, !StackSlots) :-
allocate_same_stack_slot([Var], CodeModel, N0, !StackSlots),
allocate_dummy_stack_slots(Vars, CodeModel, N0 - 1, !StackSlots).
%-----------------------------------------------------------------------------%