Files
mercury/compiler/store_alloc.m
Fergus Henderson 5fe0f4f82c A bunch of changes required to fix problems in code generation for
Estimated hours taken: 24

A bunch of changes required to fix problems in code generation for
model_det and model_semi disjunctions.

simplify.m:
	Don't convert all model_det and model_semi disjunctions into
	if-then-elses, because that doesn't work if the disjuncts
	have output variables, which can happen (e.g. with cc_nondet
	disjunctions)

disj_gen.m:
	Fix a bug in the code generation for semidet disjunctions:
	don't forget to jump to the end of the disjunction after
	each disjunct!

liveness.m, live_vars.m, store_alloc.m, disj_gen.m:
	Treat backtracking in model_det and model_semi disjunctions
	as shallow backtracking rather than deep backtracking.
	This means that rather than pushing all live variables
	onto the stack at the start of a model_det/semi disjunction,
	and using the nondet_lives to keep track of them, we instead
	treat these disjunctions a bit more like an if-then-else and
	use the ordinary liveness/deadness to keep track of them.

code_aux.m:
	Change code_aux__pre_goal_update so that it only applies
	the post-deaths if the goal is atomic.  Applying the
	*post*-deaths to the set of live variables in the *pre*-goal
	update only makes sense for atomic goals.
	(I think previously we only ever generated post-deaths
	for atomic goals, but now we generate them also for
	goals inside model_det or model_semi disjunctions.)

code_gen.pp, middle_rec.m:
	Pass an is-atomic flag to code_aux__pre_goal_update.

hlds_goal.m:
	Add some comments.

goal_util.m:
	Fix bugs in goal_util__name_apart_goalinfo.
	It wasn't applying the substitution to all the
	appropriate fields.

code_exprn.m:
	Improve the error message for one of the internal errors.

hlds_out.m:
	Print the stack slot allocations in the HLDS dump again.
1996-10-29 20:10:17 +00:00

278 lines
10 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.
%-----------------------------------------------------------------------------%
% Original author: conway.
% Extensive modification by zs.
% 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_in_proc(proc_info, module_info, proc_info).
:- mode store_alloc_in_proc(in, in, out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds_goal, goal_util, mode_util, instmap.
:- import_module list, map, set, std_util, assoc_list.
:- import_module int, term, require.
%-----------------------------------------------------------------------------%
store_alloc_in_proc(ProcInfo0, ModuleInfo, ProcInfo) :-
proc_info_goal(ProcInfo0, Goal0),
initial_liveness(ProcInfo0, ModuleInfo, Liveness0),
store_alloc_in_goal(Goal0, Liveness0, ModuleInfo, Goal, _Liveness),
proc_info_set_goal(ProcInfo0, Goal, ProcInfo).
%-----------------------------------------------------------------------------%
:- pred store_alloc_in_goal(hlds__goal, liveness_info, module_info,
hlds__goal, liveness_info).
:- mode store_alloc_in_goal(in, in, in, out, out) is det.
store_alloc_in_goal(Goal0 - GoalInfo0, Liveness0, ModuleInfo,
Goal - GoalInfo0, Liveness) :-
goal_info_get_code_model(GoalInfo0, CodeModel),
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, NondetLives0,
ModuleInfo, Goal1, Liveness3),
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 here.
set__union(Liveness4, PostBirths, Liveness),
(
Goal1 = disj(Disjuncts, FollowVars)
->
% For nondet 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.
( CodeModel = model_non ->
set__difference(Liveness, Liveness0, OutputVars),
set__to_sorted_list(OutputVars, LiveVarList)
;
set__to_sorted_list(Liveness, LiveVarList)
),
store_alloc_allocate_storage(LiveVarList, 1, FollowVars,
StoreMap),
Goal = disj(Disjuncts, StoreMap)
;
Goal1 = switch(Var, CanFail, Cases, FollowVars)
->
set__to_sorted_list(Liveness, LiveVarList),
store_alloc_allocate_storage(LiveVarList, 1, FollowVars,
StoreMap),
Goal = switch(Var, CanFail, Cases, StoreMap)
;
Goal1 = if_then_else(Vars, Cond, Then, Else, FollowVars)
->
set__to_sorted_list(Liveness, LiveVarList),
store_alloc_allocate_storage(LiveVarList, 1, FollowVars,
StoreMap),
Goal = if_then_else(Vars, Cond, Then, Else, StoreMap)
;
Goal = Goal1
).
%-----------------------------------------------------------------------------%
% Here we process each of the different sorts of goals.
:- pred store_alloc_in_goal_2(hlds__goal_expr, liveness_info,
set(var), module_info, hlds__goal_expr, liveness_info).
:- mode store_alloc_in_goal_2(in, in, in, in, out, out) is det.
store_alloc_in_goal_2(conj(Goals0), Liveness0, _NondetLives, ModuleInfo,
conj(Goals), Liveness) :-
store_alloc_in_conj(Goals0, Liveness0, ModuleInfo, Goals, Liveness).
store_alloc_in_goal_2(disj(Goals0, FV), Liveness0, _NondetLives, ModuleInfo,
disj(Goals, FV), Liveness) :-
store_alloc_in_disj(Goals0, Liveness0, ModuleInfo, Goals, Liveness).
store_alloc_in_goal_2(not(Goal0), Liveness0, NondetLives, ModuleInfo,
not(Goal), Liveness) :-
store_alloc_in_goal(Goal0, Liveness0, ModuleInfo, Goal1, Liveness),
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, _NondetLives,
ModuleInfo, switch(Var, Det, Cases, FV), Liveness) :-
store_alloc_in_cases(Cases0, Liveness0, ModuleInfo, Cases, Liveness).
store_alloc_in_goal_2(if_then_else(Vars, Cond0, Then0, Else0, FV),
Liveness0, NondetLives, ModuleInfo,
if_then_else(Vars, Cond, Then, Else, FV), Liveness) :-
store_alloc_in_goal(Cond0, Liveness0, ModuleInfo, Cond1, Liveness1),
Cond1 = CondGoal - GoalInfo0,
Else0 = _ElseGoal - ElseGoalInfo,
goal_info_pre_delta_liveness(ElseGoalInfo, ElseDelta),
ElseDelta = _Births - Deaths,
set__intersect(Liveness1, Liveness0, 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, ModuleInfo, Then, Liveness),
store_alloc_in_goal(Else0, Liveness1, ModuleInfo, Else, _Liveness2).
store_alloc_in_goal_2(some(Vars, Goal0), Liveness0, _, ModuleInfo,
some(Vars, Goal), Liveness) :-
store_alloc_in_goal(Goal0, Liveness0, ModuleInfo, Goal, Liveness).
store_alloc_in_goal_2(higher_order_call(A, B, C, D, E, F), Liveness, _, _,
higher_order_call(A, B, C, D, E, F), Liveness).
store_alloc_in_goal_2(call(A, B, C, D, E, F, G), Liveness, _, _,
call(A, B, C, D, E, F, G), Liveness).
store_alloc_in_goal_2(unify(A,B,C,D,E), Liveness, _, _,
unify(A,B,C,D,E), Liveness).
store_alloc_in_goal_2(pragma_c_code(A, B, C, D, E, F), Liveness, _, _,
pragma_c_code(A, B, C, D, E, F), Liveness).
%-----------------------------------------------------------------------------%
:- pred store_alloc_in_conj(list(hlds__goal), liveness_info,
module_info, list(hlds__goal), liveness_info).
:- mode store_alloc_in_conj(in, in, in, out, out) is det.
store_alloc_in_conj([], Liveness, _M, [], Liveness).
store_alloc_in_conj([Goal0 | Goals0], Liveness0, ModuleInfo,
[Goal | Goals], Liveness) :-
(
% XXX should be threading the instmap
Goal0 = _ - GoalInfo,
goal_info_get_instmap_delta(GoalInfo, unreachable)
->
store_alloc_in_goal(Goal0, Liveness0, ModuleInfo,
Goal, Liveness),
Goals = Goals0
;
store_alloc_in_goal(Goal0, Liveness0, ModuleInfo,
Goal, Liveness1),
store_alloc_in_conj(Goals0, Liveness1, ModuleInfo,
Goals, Liveness)
).
%-----------------------------------------------------------------------------%
:- pred store_alloc_in_disj(list(hlds__goal), liveness_info, module_info,
list(hlds__goal), liveness_info).
:- mode store_alloc_in_disj(in, in, in, out, out) is det.
store_alloc_in_disj([], Liveness, _ModuleInfo, [], Liveness).
store_alloc_in_disj([Goal0 | Goals0], Liveness0, ModuleInfo,
[Goal | Goals], Liveness) :-
store_alloc_in_goal(Goal0, Liveness0, ModuleInfo, Goal, Liveness),
store_alloc_in_disj(Goals0, Liveness0, ModuleInfo, Goals, _Liveness1).
%-----------------------------------------------------------------------------%
:- pred store_alloc_in_cases(list(case), liveness_info, module_info,
list(case), liveness_info).
:- mode store_alloc_in_cases(in, in, in, out, out) is det.
store_alloc_in_cases([], Liveness, _ModuleInfo, [], Liveness).
store_alloc_in_cases([case(Cons, Goal0) | Goals0], Liveness0,
ModuleInfo, [case(Cons, Goal) | Goals], Liveness) :-
store_alloc_in_goal(Goal0, Liveness0, ModuleInfo, Goal, Liveness),
store_alloc_in_cases(Goals0, Liveness0, ModuleInfo, Goals, _Liveness1).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- 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([Var - Mode | VarModes], ModuleInfo, Liveness0, Liveness) :-
(
mode_is_input(ModuleInfo, Mode)
->
set__insert(Liveness0, Var, Liveness1)
;
Liveness1 = Liveness0
),
initial_liveness_2(VarModes, 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
).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%