Files
mercury/compiler/store_alloc.m
Zoltan Somogyi d344165793 Add a new option, --branch-delay-slot, intended for use by mc on
Estimated hours taken: 3

options:
	Add a new option, --branch-delay-slot, intended for use by mc on
	the basis of the configuattion script. It says whether the machine
	architecture has delays slots on branches.

	The setting of option should affect whether we set
	--optimize-delay-slots at -O2, but this doesn't work yet.

hlds_goal:
	Add an extra field to hold follow_vars infromation to disjunctions,
	switches and if-then-elses. I intend to use this information to
	generate better code.

*.m:
	Changes to accommodate the extra field.
1996-04-20 08:37:36 +00:00

335 lines
12 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1995 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.
%-----------------------------------------------------------------------------%
% Main author: conway.
% Allocates the storage location for each variable
% at the end of branched structures, so that the code generator
% will generate code which puts the variable in the same place
% in each branch.
% This module requires arg_info, liveness, and follow_vars to have
% already been computed.
%-----------------------------------------------------------------------------%
:- module store_alloc.
:- interface.
:- import_module hlds_module, hlds_pred, llds.
:- pred store_alloc(module_info, module_info).
:- mode store_alloc(in, out) is det.
:- pred store_alloc_in_proc(proc_info, module_info, proc_info).
% :- mode store_alloc_in_proc(di, in, uo) is det.
:- mode store_alloc_in_proc(in, in, out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds_goal, goal_util, mode_util.
:- import_module list, map, set, std_util, assoc_list.
:- import_module int, term, require.
%-----------------------------------------------------------------------------%
% Traverse the module structure, calling `store_alloc_in_goal'
% for each procedure body.
store_alloc(ModuleInfo0, ModuleInfo1) :-
module_info_predids(ModuleInfo0, PredIds),
store_alloc_in_preds(PredIds, ModuleInfo0, ModuleInfo1).
:- pred store_alloc_in_preds(list(pred_id), module_info, module_info).
:- mode store_alloc_in_preds(in, in, out) is det.
store_alloc_in_preds([], ModuleInfo, ModuleInfo).
store_alloc_in_preds([PredId | PredIds], ModuleInfo0, ModuleInfo) :-
module_info_preds(ModuleInfo0, PredTable),
map__lookup(PredTable, PredId, PredInfo),
pred_info_non_imported_procids(PredInfo, ProcIds),
store_alloc_in_procs(ProcIds, PredId, ModuleInfo0, ModuleInfo1),
store_alloc_in_preds(PredIds, ModuleInfo1, ModuleInfo).
:- pred store_alloc_in_procs(list(proc_id), pred_id, module_info,
module_info).
:- mode store_alloc_in_procs(in, in, in, out) is det.
store_alloc_in_procs([], _PredId, ModuleInfo, ModuleInfo).
store_alloc_in_procs([ProcId | ProcIds], PredId, ModuleInfo0, ModuleInfo) :-
module_info_preds(ModuleInfo0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo0),
pred_info_procedures(PredInfo0, ProcTable0),
map__lookup(ProcTable0, ProcId, ProcInfo0),
store_alloc_in_proc(ProcInfo0, ModuleInfo0, ProcInfo),
map__set(ProcTable0, ProcId, ProcInfo, ProcTable),
pred_info_set_procedures(PredInfo0, ProcTable, PredInfo),
map__set(PredTable0, PredId, PredInfo, PredTable),
module_info_set_preds(ModuleInfo0, PredTable, ModuleInfo1),
store_alloc_in_procs(ProcIds, PredId, ModuleInfo1, ModuleInfo).
store_alloc_in_proc(ProcInfo0, ModuleInfo, ProcInfo) :-
proc_info_goal(ProcInfo0, Goal0),
proc_info_follow_vars(ProcInfo0, Follow0),
initial_liveness(ProcInfo0, ModuleInfo, Liveness0),
store_alloc_in_goal(Goal0, Liveness0, Follow0, ModuleInfo,
Goal, _Liveness, _Follow),
proc_info_set_goal(ProcInfo0, Goal, ProcInfo).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- pred store_alloc_in_goal(hlds__goal, liveness_info, follow_vars, module_info,
hlds__goal, liveness_info, follow_vars).
:- mode store_alloc_in_goal(in, in, in, in, out, out, out) is det.
store_alloc_in_goal(Goal0 - GoalInfo0, Liveness0, Follow0, ModuleInfo,
Goal - GoalInfo, Liveness, Follow) :-
goal_info_pre_delta_liveness(GoalInfo0, PreDelta),
PreDelta = PreBirths - PreDeaths,
goal_info_post_delta_liveness(GoalInfo0, PostDelta),
PostDelta = PostBirths - PostDeaths,
set__difference(Liveness0, PreDeaths, Liveness1),
set__union(Liveness1, PreBirths, Liveness2),
goal_info_nondet_lives(GoalInfo0, NondetLives0),
store_alloc_in_goal_2(Goal0, Liveness2, Follow0, NondetLives0,
ModuleInfo, Goal, Liveness3, Follow),
set__difference(Liveness3, PostDeaths, Liveness4),
% If any variables magically become live in the PostBirths,
% then they have to mundanely become live somewhere else,
% so we don't need to allocate anything for them.
set__union(Liveness4, PostBirths, Liveness),
(
Goal = disj(_, _)
->
% For disjunctions, we only want to allocate registers
% for the variables that are generated by the disjunction
% (the outputs). For the inputs, the first disjunct will
% use whichever registers they happen to be in,
% and for subsequent disjuncts these variables need to be
% put in framevars.
set__difference(Liveness, Liveness0, OutputVars),
set__to_sorted_list(OutputVars, LiveVarList),
store_alloc_allocate_storage(LiveVarList, 1, Follow, StoreMap),
goal_info_set_store_map(GoalInfo0, yes(StoreMap), GoalInfo)
;
goal_util__goal_is_branched(Goal)
->
set__to_sorted_list(Liveness, LiveVarList),
store_alloc_allocate_storage(LiveVarList, 1, Follow, StoreMap),
goal_info_set_store_map(GoalInfo0, yes(StoreMap), GoalInfo)
;
goal_info_set_store_map(GoalInfo0, no, GoalInfo)
).
%-----------------------------------------------------------------------------%
% Here we process each of the different sorts of goals.
:- pred store_alloc_in_goal_2(hlds__goal_expr, liveness_info, follow_vars,
set(var), module_info, hlds__goal_expr,
liveness_info, follow_vars).
:- mode store_alloc_in_goal_2(in, in, in, in, in, out, out, out) is det.
store_alloc_in_goal_2(conj(Goals0), Liveness0, Follow0, _NondetLives,
ModuleInfo, conj(Goals), Liveness, Follow) :-
store_alloc_in_conj(Goals0, Liveness0, Follow0, ModuleInfo,
Goals, Liveness, Follow).
store_alloc_in_goal_2(disj(Goals0, FV), Liveness0, Follow0, _NondetLives,
ModuleInfo, disj(Goals, FV), Liveness, Follow) :-
store_alloc_in_disj(Goals0, Liveness0, Follow0, ModuleInfo,
Goals, Liveness, Follow).
store_alloc_in_goal_2(not(Goal0), Liveness0, Follow0, NondetLives, ModuleInfo,
not(Goal), Liveness, Follow) :-
store_alloc_in_goal(Goal0, Liveness0, Follow0, ModuleInfo,
Goal1, Liveness, Follow),
Goal1 = GoalGoal - GoalInfo0,
set__union(Liveness, NondetLives, ContLives),
goal_info_set_cont_lives(GoalInfo0, yes(ContLives), GoalInfo),
Goal = GoalGoal - GoalInfo.
store_alloc_in_goal_2(switch(Var, Det, Cases0, FV), Liveness0, Follow0,
_NondetLives, ModuleInfo, switch(Var, Det, Cases, FV),
Liveness, Follow) :-
store_alloc_in_cases(Cases0, Liveness0, Follow0, ModuleInfo,
Cases, Liveness, Follow).
store_alloc_in_goal_2(if_then_else(Vars, Cond0, Then0, Else0, FV),
Liveness0, Follow0, NondetLives, ModuleInfo,
if_then_else(Vars, Cond, Then, Else, FV), Liveness, Follow) :-
store_alloc_in_goal(Cond0, Liveness0, Follow0, ModuleInfo,
Cond1, Liveness1, Follow1),
Cond1 = CondGoal - GoalInfo0,
Else0 = _ElseGoal - ElseGoalInfo,
goal_info_pre_delta_liveness(ElseGoalInfo, ElseDelta),
ElseDelta = _Births - Deaths,
set__intersect(Liveness0, Liveness1, ContLiveness0),
set__difference(ContLiveness0, Deaths, ContLiveness),
set__union(ContLiveness, NondetLives, ContLives),
goal_info_set_cont_lives(GoalInfo0, yes(ContLives), GoalInfo),
Cond = CondGoal - GoalInfo,
store_alloc_in_goal(Then0, Liveness1, Follow1, ModuleInfo,
Then, Liveness, Follow),
% We ignore the resulting liveness and follow-vars
% from the else branch because this is the behaviour
% used in follow_vars.m
store_alloc_in_goal(Else0, Liveness1, Follow1, ModuleInfo,
Else, _Liveness2, _Follow2).
store_alloc_in_goal_2(some(Vars, Goal0), Liveness0, Follow0, _NondetLives,
ModuleInfo, some(Vars, Goal), Liveness, Follow) :-
store_alloc_in_goal(Goal0, Liveness0, Follow0, ModuleInfo,
Goal, Liveness, Follow).
store_alloc_in_goal_2(call(A, B, C, D, E, F, G), Liveness, _Follow0,
_NondetLives, _ModuleInfo, call(A, B, C, D, E, F, G),
Liveness, Follow) :-
Follow = G.
store_alloc_in_goal_2(unify(A,B,C,D,E), Liveness, Follow0, _NondetLives,
_ModuleInfo, unify(A,B,C,D,E), Liveness, Follow) :-
(
D = complicated_unify(_, _, F)
->
Follow = F
;
Follow = Follow0
).
store_alloc_in_goal_2(pragma_c_code(A, B, C, D, E), Liveness, Follow,
_NondetLives, _ModInfo,
pragma_c_code(A, B, C, D, E), Liveness, Follow).
%-----------------------------------------------------------------------------%
:- pred store_alloc_in_conj(list(hlds__goal), liveness_info, follow_vars,
module_info, list(hlds__goal), liveness_info, follow_vars).
:- mode store_alloc_in_conj(in, in, in, in, out, out, out) is det.
store_alloc_in_conj([], Liveness, Follow, _M, [], Liveness, Follow).
store_alloc_in_conj([Goal0|Goals0], Liveness0, Follow0, ModuleInfo,
[Goal|Goals], Liveness, Follow) :-
(
% XXX should be threading the instmap
Goal0 = _ - GoalInfo,
goal_info_get_instmap_delta(GoalInfo, unreachable)
->
store_alloc_in_goal(Goal0, Liveness0, Follow0,
ModuleInfo, Goal, Liveness, Follow),
Goals = Goals0
;
store_alloc_in_goal(Goal0, Liveness0, Follow0, ModuleInfo,
Goal, Liveness1, Follow1),
store_alloc_in_conj(Goals0, Liveness1, Follow1, ModuleInfo,
Goals, Liveness, Follow)
).
%-----------------------------------------------------------------------------%
:- pred store_alloc_in_disj(list(hlds__goal), liveness_info, follow_vars,
module_info, list(hlds__goal),
liveness_info, follow_vars).
:- mode store_alloc_in_disj(in, in, in, in, out, out, out) is det.
store_alloc_in_disj([], Liveness, Follow, _ModuleInfo, [], Liveness, Follow).
store_alloc_in_disj([Goal0|Goals0], Liveness0, Follow0, ModuleInfo,
[Goal|Goals], Liveness, Follow) :-
store_alloc_in_goal(Goal0, Liveness0, Follow0, ModuleInfo,
Goal, Liveness, Follow),
store_alloc_in_disj(Goals0, Liveness0, Follow0, ModuleInfo,
Goals, _Liveness1, _Follow1).
%-----------------------------------------------------------------------------%
:- pred store_alloc_in_cases(list(case), liveness_info, follow_vars,
module_info, list(case), liveness_info, follow_vars).
:- mode store_alloc_in_cases(in, in, in, in, out, out, out) is det.
store_alloc_in_cases([], Liveness, Follow, _ModuleInfo, [], Liveness, Follow).
store_alloc_in_cases([case(Cons, Goal0)|Goals0], Liveness0, Follow0,
ModuleInfo, [case(Cons, Goal)|Goals],
Liveness, Follow) :-
store_alloc_in_goal(Goal0, Liveness0, Follow0, ModuleInfo,
Goal, Liveness, Follow),
store_alloc_in_cases(Goals0, Liveness0, Follow0, ModuleInfo,
Goals, _Liveness1, _Follow1).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- pred initial_liveness(proc_info, module_info, set(var)).
:- mode initial_liveness(in, in, out) is det.
initial_liveness(ProcInfo, ModuleInfo, Liveness) :-
proc_info_headvars(ProcInfo, Vars),
proc_info_argmodes(ProcInfo, Args),
assoc_list__from_corresponding_lists(Vars, Args, VarArgs),
set__init(Liveness0),
initial_liveness_2(VarArgs, ModuleInfo, Liveness0, Liveness).
:- pred initial_liveness_2(assoc_list(var,mode), module_info,
set(var), set(var)).
:- mode initial_liveness_2(in, in, in, out) is det.
initial_liveness_2([], _ModuleInfo, Liveness, Liveness).
initial_liveness_2([V - M|VAs], ModuleInfo, Liveness0, Liveness) :-
(
mode_is_input(ModuleInfo, M)
->
set__insert(Liveness0, V, Liveness1)
;
Liveness1 = Liveness0
),
initial_liveness_2(VAs, ModuleInfo, Liveness1, Liveness).
%-----------------------------------------------------------------------------%
:- pred store_alloc_allocate_storage(list(var), int,
map(var, lval), map(var, lval)).
:- mode store_alloc_allocate_storage(in, in, in, out) is det.
store_alloc_allocate_storage([], _N, StoreMap, StoreMap).
store_alloc_allocate_storage([Var|Vars], N0, StoreMap0, StoreMap) :-
(
map__contains(StoreMap0, Var)
->
N1 = N0,
StoreMap1 = StoreMap0
;
map__values(StoreMap0, Values),
next_free_reg(N0, Values, N1),
map__set(StoreMap0, Var, reg(r(N1)), StoreMap1)
),
store_alloc_allocate_storage(Vars, N1, StoreMap1, StoreMap).
%-----------------------------------------------------------------------------%
:- pred next_free_reg(int, list(lval), int).
:- mode next_free_reg(in, in, out) is det.
next_free_reg(N0, Values, N) :-
(
list__member(reg(r(N0)), Values)
->
N1 is N0 + 1,
next_free_reg(N1, Values, N)
;
N = N0
).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%