Files
mercury/compiler/liveness.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

726 lines
28 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.
% This module traverses the goal for each procedure, and adds
% liveness annotations to the goal_info for each sub-goal.
% Note - the concept of `liveness' here is different to that
% used in the mode analysis. The mode analysis is concerned
% with the liveness of what is *pointed* to by a variable, for
% the purpose of avoiding aliasing and for structure re-use
% optimization, whereas here we are concerned with the liveness
% of the variable itself, for the purposes of minimizing stack
% slot usage and for register re-use.
%-----------------------------------------------------------------------------%
:- module liveness.
:- interface.
:- import_module hlds_module, hlds_pred, llds.
:- pred detect_liveness(module_info, module_info).
:- mode detect_liveness(in, out) is det.
:- pred detect_liveness_proc(proc_info, module_info, proc_info).
% :- mode detect_liveness_proc(di, in, uo) is det.
:- mode detect_liveness_proc(in, in, out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds_goal, mode_util, term, quantification.
:- import_module list, map, set, std_util, assoc_list.
%-----------------------------------------------------------------------------%
% Traverse the module structure, calling `detect_liveness_in_goal'
% for each procedure body.
detect_liveness(ModuleInfo0, ModuleInfo1) :-
module_info_predids(ModuleInfo0, PredIds),
detect_liveness_in_preds(PredIds, ModuleInfo0, ModuleInfo1).
:- pred detect_liveness_in_preds(list(pred_id), module_info, module_info).
:- mode detect_liveness_in_preds(in, in, out) is det.
detect_liveness_in_preds([], ModuleInfo, ModuleInfo).
detect_liveness_in_preds([PredId | PredIds], ModuleInfo0, ModuleInfo) :-
module_info_preds(ModuleInfo0, PredTable),
map__lookup(PredTable, PredId, PredInfo),
pred_info_non_imported_procids(PredInfo, ProcIds),
detect_liveness_in_procs(ProcIds, PredId, ModuleInfo0, ModuleInfo1),
detect_liveness_in_preds(PredIds, ModuleInfo1, ModuleInfo).
:- pred detect_liveness_in_procs(list(proc_id), pred_id,
module_info, module_info).
:- mode detect_liveness_in_procs(in, in, in, out) is det.
detect_liveness_in_procs([], _PredId, ModuleInfo, ModuleInfo).
detect_liveness_in_procs([ProcId | ProcIds], PredId, ModuleInfo0, ModuleInfo) :-
detect_liveness_in_proc(ProcId, PredId, ModuleInfo0, ModuleInfo1),
detect_liveness_in_procs(ProcIds, PredId, ModuleInfo1, ModuleInfo).
:- pred detect_liveness_in_proc(proc_id, pred_id, module_info, module_info).
:- mode detect_liveness_in_proc(in, in, in, out) is det.
detect_liveness_in_proc(ProcId, PredId, ModuleInfo0, ModuleInfo) :-
module_info_preds(ModuleInfo0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo0),
pred_info_procedures(PredInfo0, ProcTable0),
map__lookup(ProcTable0, ProcId, ProcInfo0),
detect_liveness_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, ModuleInfo).
% To process each ProcInfo, we get the goal,
% initialize the instmap based on the modes of the head vars,
% and pass these to `detect_liveness_in_goal'.
detect_liveness_proc(ProcInfo0, ModuleInfo, ProcInfo) :-
proc_info_goal(ProcInfo0, Goal0),
detect_initial_liveness(ProcInfo0, ModuleInfo, Liveness0),
detect_liveness_in_goal(Goal0, Liveness0, ModuleInfo, Goal1),
detect_initial_deadness(ProcInfo0, ModuleInfo, Deadness0),
detect_deadness_in_goal(Goal1, Deadness0, ModuleInfo, Goal2),
set__init(Extras0),
add_nondet_lives_to_goal(Goal2, Liveness0, Extras0, Goal, _, _),
proc_info_set_goal(ProcInfo0, Goal, ProcInfo1),
proc_info_set_liveness_info(ProcInfo1, Liveness0, ProcInfo).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- pred detect_liveness_in_goal(hlds__goal, liveness_info, module_info,
liveness_info, hlds__goal).
:- mode detect_liveness_in_goal(in, in, in, out, out) is det.
detect_liveness_in_goal(Goal0 - GoalInfo0, Liveness0, ModuleInfo,
Liveness, Goal - GoalInfo) :-
goal_info_pre_delta_liveness(GoalInfo0, PreDelta0),
goal_info_post_delta_liveness(GoalInfo0, PostDelta0),
goal_info_get_nonlocals(GoalInfo0, NonLocals),
PreDelta0 = _PreBirths0 - PreDeaths,
PostDelta0 = _PostBirths0 - PostDeaths,
% work out which variables get born in this goal
set__difference(NonLocals, Liveness0, NewVarsSet),
set__to_sorted_list(NewVarsSet, NewVarsList),
goal_info_get_instmap_delta(GoalInfo0, InstMapDelta),
set__init(Births0),
find_binding_occurrences(NewVarsList, ModuleInfo, InstMapDelta,
Births0, Births),
set__union(Liveness0, Births, Liveness),
(
goal_is_atomic(Goal0)
->
PreBirths = Births,
Goal = Goal0,
PostDelta = PostDelta0
;
set__init(PreBirths),
detect_liveness_in_goal_2(Goal0, Liveness0,
ModuleInfo, Liveness1, Goal),
set__difference(Births, Liveness1, PostBirths),
PostDelta = PostBirths - PostDeaths
),
PreDelta = PreBirths - PreDeaths,
goal_info_set_pre_delta_liveness(GoalInfo0, PreDelta, GoalInfo1),
goal_info_set_post_delta_liveness(GoalInfo1, PostDelta, GoalInfo).
:- pred detect_liveness_in_goal(hlds__goal, liveness_info, module_info,
hlds__goal).
:- mode detect_liveness_in_goal(in, in, in, out) is det.
detect_liveness_in_goal(Goal0, Liveness0, ModuleInfo, Goal) :-
detect_liveness_in_goal(Goal0, Liveness0, ModuleInfo, _, Goal).
% Here we process each of the different sorts of goals.
%-----------------------------------------------------------------------------%
% Given a list of variables and an instmap delta, determine
% which of those variables become bound (according to the instmap
% delta) and insert them into the accumulated set of bound vars.
:- pred find_binding_occurrences(list(var), module_info, instmap_delta,
set(var), set(var)).
:- mode find_binding_occurrences(in, in, in, in, out) is det.
find_binding_occurrences([], _, _, BoundVars, BoundVars).
find_binding_occurrences([Var | Vars], ModuleInfo, InstMapDelta, BoundVars0,
BoundVars) :-
instmap_lookup_var(InstMapDelta, Var, Inst),
( inst_is_bound(ModuleInfo, Inst) ->
set__insert(BoundVars0, Var, BoundVars1)
;
BoundVars1 = BoundVars0
),
find_binding_occurrences(Vars, ModuleInfo, InstMapDelta, BoundVars1,
BoundVars).
%-----------------------------------------------------------------------------%
:- pred detect_liveness_in_goal_2(hlds__goal_expr, liveness_info,
module_info, liveness_info, hlds__goal_expr).
:- mode detect_liveness_in_goal_2(in, in, in, out, out) is det.
detect_liveness_in_goal_2(conj(Goals0), Liveness0, ModuleInfo,
Liveness, conj(Goals)) :-
detect_liveness_in_conj(Goals0, Liveness0, ModuleInfo, Liveness, Goals).
detect_liveness_in_goal_2(disj(Goals0, FV), Liveness0, ModuleInfo,
Liveness, disj(Goals, FV)) :-
set__init(Union0),
detect_liveness_in_disj(Goals0, Liveness0, ModuleInfo,
Union0, Union, Goals),
set__union(Liveness0, Union, Liveness).
detect_liveness_in_goal_2(not(Goal0), Liveness0, ModuleInfo,
Liveness, not(Goal)) :-
detect_liveness_in_goal(Goal0, Liveness0, ModuleInfo, Liveness, Goal).
detect_liveness_in_goal_2(switch(Var, Det, Cases0, FV), Liveness0,
ModuleInfo, Liveness, switch(Var, Det, Cases, FV)) :-
set__init(Union0),
detect_liveness_in_cases(Cases0, Liveness0, ModuleInfo,
Union0, Union, Cases),
set__union(Liveness0, Union, Liveness).
detect_liveness_in_goal_2(if_then_else(Vars, Cond0, Then0, Else0, FV),
Liveness0, M, Liveness,
if_then_else(Vars, Cond, Then, Else, FV)) :-
detect_liveness_in_goal(Cond0, Liveness0, M, LivenessCond, Cond),
detect_liveness_in_goal(Then0, LivenessCond, M, LivenessThen, Then1),
detect_liveness_in_goal(Else0, Liveness0, M, LivenessElse, Else1),
set__difference(LivenessThen, LivenessCond, ProducedInThen),
set__difference(LivenessElse, Liveness0, ProducedInElse),
set__difference(ProducedInElse, ProducedInThen, ResidueThen),
set__difference(ProducedInThen, ProducedInElse, ResidueElse),
stuff_liveness_residue_into_goal(Then1, ResidueThen, Then),
stuff_liveness_residue_into_goal(Else1, ResidueElse, Else),
set__union(LivenessThen, LivenessElse, Liveness).
detect_liveness_in_goal_2(some(Vars, Goal0), Liveness0, ModuleInfo,
Liveness, some(Vars, Goal)) :-
detect_liveness_in_goal(Goal0, Liveness0, ModuleInfo, Liveness, Goal).
detect_liveness_in_goal_2(call(A,B,C,D,E,F,G), L, _, L, call(A,B,C,D,E,F,G)).
detect_liveness_in_goal_2(unify(A,B,C,D,E), L, _, L, unify(A,B,C,D,E)).
detect_liveness_in_goal_2(pragma_c_code(A,B,C,D,E), L, _, L,
pragma_c_code(A,B,C,D,E)).
%-----------------------------------------------------------------------------%
:- pred detect_liveness_in_conj(list(hlds__goal), set(var), module_info,
set(var), list(hlds__goal)).
:- mode detect_liveness_in_conj(in, in, in, out, out) is det.
detect_liveness_in_conj([], Liveness, _ModuleInfo, Liveness, []).
detect_liveness_in_conj([Goal0|Goals0], Liveness0,
ModuleInfo, Liveness, [Goal|Goals]) :-
detect_liveness_in_goal(Goal0, Liveness0, ModuleInfo, Liveness1, Goal),
(
Goal0 = _ - GoalInfo,
goal_info_get_instmap_delta(GoalInfo, unreachable)
->
Goals = Goals0,
Liveness = Liveness1
;
detect_liveness_in_conj(Goals0, Liveness1,
ModuleInfo, Liveness, Goals)
).
%-----------------------------------------------------------------------------%
:- pred detect_liveness_in_disj(list(hlds__goal), set(var), module_info,
set(var), set(var), list(hlds__goal)).
:- mode detect_liveness_in_disj(in, in, in, in, out, out) is det.
detect_liveness_in_disj([], _Liveness, _ModuleInfo, Union, Union, []).
detect_liveness_in_disj([Goal0|Goals0], Liveness, ModuleInfo,
Union0, Union, [Goal|Goals]) :-
detect_liveness_in_goal(Goal0, Liveness, ModuleInfo, Liveness1, Goal1),
set__union(Union0, Liveness1, Union1),
detect_liveness_in_disj(Goals0, Liveness, ModuleInfo,
Union1, Union, Goals),
set__difference(Union, Liveness1, Residue),
stuff_liveness_residue_into_goal(Goal1, Residue, Goal).
%-----------------------------------------------------------------------------%
:- pred detect_liveness_in_cases(list(case), set(var), module_info,
set(var), set(var), list(case)).
:- mode detect_liveness_in_cases(in, in, in, in, out, out) is det.
detect_liveness_in_cases([], _Liveness, _ModuleInfo, Union, Union, []).
detect_liveness_in_cases([case(Cons, Goal0)|Goals0], Liveness, ModuleInfo,
Union0, Union, [case(Cons, Goal)|Goals]) :-
detect_liveness_in_goal(Goal0, Liveness, ModuleInfo, Liveness1, Goal1),
set__union(Union0, Liveness1, Union1),
detect_liveness_in_cases(Goals0, Liveness, ModuleInfo,
Union1, Union, Goals),
set__difference(Union, Liveness1, Residue),
stuff_liveness_residue_into_goal(Goal1, Residue, Goal).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- pred detect_deadness_in_goal(hlds__goal, liveness_info, module_info,
liveness_info, hlds__goal).
:- mode detect_deadness_in_goal(in, in, in, out, out) is det.
detect_deadness_in_goal(Goal0 - GoalInfo0, Deadness0, ModuleInfo,
Deadness, Goal - GoalInfo) :-
goal_info_post_delta_liveness(GoalInfo0, PostDelta0),
goal_info_pre_delta_liveness(GoalInfo0, PreDelta0),
goal_info_get_nonlocals(GoalInfo0, NonLocals),
PostDelta0 = PostBirths - _PostDeaths0,
PreDelta0 = PreBirths - _PreDeaths0,
(
goal_is_atomic(Goal0)
->
set__difference(NonLocals, Deadness0, PostDeaths),
set__union(Deadness0, PostDeaths, Deadness),
Goal = Goal0,
PreDelta = PreDelta0
;
set__union(Deadness0, NonLocals, Deadness),
set__init(PostDeaths),
detect_deadness_in_goal_2(Goal0, Deadness0,
ModuleInfo, Deadness1, Goal),
set__difference(Deadness, Deadness1, PreDeaths),
PreDelta = PreBirths - PreDeaths
),
PostDelta = PostBirths - PostDeaths,
goal_info_set_post_delta_liveness(GoalInfo0, PostDelta, GoalInfo1),
goal_info_set_pre_delta_liveness(GoalInfo1, PreDelta, GoalInfo).
:- pred detect_deadness_in_goal(hlds__goal, liveness_info, module_info,
hlds__goal).
:- mode detect_deadness_in_goal(in, in, in, out) is det.
detect_deadness_in_goal(Goal0, Deadness, ModuleInfo, Goal) :-
detect_deadness_in_goal(Goal0, Deadness, ModuleInfo, _, Goal).
% Here we process each of the different sorts of goals.
:- pred detect_deadness_in_goal_2(hlds__goal_expr, liveness_info,
module_info, liveness_info, hlds__goal_expr).
:- mode detect_deadness_in_goal_2(in, in, in, out, out) is det.
detect_deadness_in_goal_2(conj(Goals0), Deadness0, ModuleInfo, Deadness,
conj(Goals)) :-
detect_deadness_in_conj(Goals0, Deadness0, ModuleInfo,
Goals, Deadness).
detect_deadness_in_goal_2(disj(Goals0, FV), Deadness0, ModuleInfo, Deadness,
disj(Goals, FV)) :-
set__init(Union0),
detect_deadness_in_disj(Goals0, Deadness0, ModuleInfo, Union0, Union,
Goals),
set__union(Deadness0, Union, Deadness).
detect_deadness_in_goal_2(not(Goal0), Deadness0, ModuleInfo, Deadness,
not(Goal)) :-
detect_deadness_in_goal(Goal0, Deadness0, ModuleInfo, Deadness, Goal).
detect_deadness_in_goal_2(if_then_else(Vars, Cond0, Then0, Else0, FV),
Deadness0, ModuleInfo, Deadness,
if_then_else(Vars, Cond, Then, Else, FV)) :-
detect_deadness_in_goal(Then0, Deadness0, ModuleInfo,
DeadnessThen, Then1),
detect_deadness_in_goal(Else0, Deadness0, ModuleInfo,
DeadnessElse, Else1),
set__union(DeadnessThen, DeadnessElse, DeadnessThenElse),
detect_deadness_in_goal(Cond0, DeadnessThenElse, ModuleInfo,
Deadness, Cond),
set__difference(DeadnessElse, DeadnessThen, ResidueThen),
stuff_deadness_residue_into_goal(Then1, ResidueThen, Then),
set__difference(DeadnessThen, DeadnessElse, ResidueElse),
stuff_deadness_residue_into_goal(Else1, ResidueElse, Else).
detect_deadness_in_goal_2(switch(Var, Det, Cases0, FV), Deadness0, ModuleInfo,
Deadness, switch(Var, Det, Cases, FV)) :-
set__init(Union0),
detect_deadness_in_cases(Var, Cases0, Deadness0, ModuleInfo, Union0,
Union, Cases),
set__union(Deadness0, Union, Deadness).
detect_deadness_in_goal_2(some(Vars, Goal0), Deadness0, ModuleInfo, Deadness,
some(Vars, Goal)) :-
detect_deadness_in_goal(Goal0, Deadness0, ModuleInfo, Deadness, Goal).
detect_deadness_in_goal_2(call(A,B,C,D,E,F,G), Dn, _, Dn, call(A,B,C,D,E,F,G)).
detect_deadness_in_goal_2(unify(A,B,C,D,E), Dn, _, Dn, unify(A,B,C,D,E)).
detect_deadness_in_goal_2(pragma_c_code(A,B,C,D,E), Dn, _, Dn,
pragma_c_code(A,B,C,D,E)).
%-----------------------------------------------------------------------------%
:- pred detect_deadness_in_conj(list(hlds__goal), set(var), module_info,
list(hlds__goal), set(var)).
:- mode detect_deadness_in_conj(in, in, in, out, out) is det.
detect_deadness_in_conj([], Deadness, _ModuleInfo, [], Deadness).
detect_deadness_in_conj([Goal0|Goals0], Deadness0, ModuleInfo,
[Goal|Goals], Deadness) :-
(
Goal0 = _ - GoalInfo,
goal_info_get_instmap_delta(GoalInfo, unreachable)
->
Goals = Goals0,
detect_deadness_in_goal(Goal0, Deadness0,
ModuleInfo, Deadness, Goal)
;
detect_deadness_in_conj(Goals0, Deadness0,
ModuleInfo, Goals, Deadness1),
detect_deadness_in_goal(Goal0, Deadness1,
ModuleInfo, Deadness, Goal)
).
%-----------------------------------------------------------------------------%
:- pred detect_deadness_in_disj(list(hlds__goal), set(var), module_info,
set(var), set(var), list(hlds__goal)).
:- mode detect_deadness_in_disj(in, in, in, in, out, out) is det.
detect_deadness_in_disj([], _Deadness, _ModuleInfo, Union, Union, []).
detect_deadness_in_disj([Goal0|Goals0], Deadness, ModuleInfo,
Union0, Union, [Goal|Goals]) :-
detect_deadness_in_goal(Goal0, Deadness, ModuleInfo, Deadness1, Goal1),
set__union(Union0, Deadness1, Union1),
detect_deadness_in_disj(Goals0, Deadness, ModuleInfo,
Union1, Union, Goals),
set__difference(Union, Deadness1, Residue),
stuff_deadness_residue_into_goal(Goal1, Residue, Goal).
%-----------------------------------------------------------------------------%
:- pred detect_deadness_in_cases(var, list(case), set(var), module_info,
set(var), set(var), list(case)).
:- mode detect_deadness_in_cases(in, in, in, in, in, out, out) is det.
detect_deadness_in_cases(_Var, [], _Deadness, _ModuleInfo, Union, Union, []).
detect_deadness_in_cases(SwitchVar, [case(Cons, Goal0)|Goals0], Deadness0,
ModuleInfo, Union0, Union, [case(Cons, Goal)|Goals]) :-
detect_deadness_in_goal(Goal0, Deadness0, ModuleInfo, Deadness1, Goal1),
set__union(Union0, Deadness1, Union1),
detect_deadness_in_cases(SwitchVar, Goals0, Deadness0, ModuleInfo,
Union1, Union2, Goals),
% If the switch variable does not become dead in a case
% it must be put in the pre-death set of that case.
set__insert(Union2, SwitchVar, Union),
set__difference(Union, Deadness1, Residue),
stuff_deadness_residue_into_goal(Goal1, Residue, Goal).
%-----------------------------------------------------------------------------%
:- pred detect_initial_liveness(proc_info, module_info, set(var)).
:- mode detect_initial_liveness(in, in, out) is det.
detect_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),
detect_initial_liveness_2(VarArgs, ModuleInfo, Liveness0, Liveness).
:- pred detect_initial_liveness_2(assoc_list(var,mode), module_info,
set(var), set(var)).
:- mode detect_initial_liveness_2(in, in, in, out) is det.
detect_initial_liveness_2([], _ModuleInfo, Liveness, Liveness).
detect_initial_liveness_2([V - M|VAs], ModuleInfo,
Liveness0, Liveness) :-
(
mode_is_input(ModuleInfo, M)
->
set__insert(Liveness0, V, Liveness1)
;
Liveness1 = Liveness0
),
detect_initial_liveness_2(VAs, ModuleInfo, Liveness1, Liveness).
%-----------------------------------------------------------------------------%
:- pred detect_initial_deadness(proc_info, module_info, set(var)).
:- mode detect_initial_deadness(in, in, out) is det.
detect_initial_deadness(ProcInfo, ModuleInfo, Deadness) :-
proc_info_headvars(ProcInfo, Vars),
proc_info_argmodes(ProcInfo, Args),
assoc_list__from_corresponding_lists(Vars, Args, VarArgs),
set__init(Deadness0),
detect_initial_deadness_2(VarArgs, ModuleInfo, Deadness0, Deadness).
:- pred detect_initial_deadness_2(assoc_list(var,mode), module_info,
set(var), set(var)).
:- mode detect_initial_deadness_2(in, in, in, out) is det.
detect_initial_deadness_2([], _ModuleInfo, Deadness, Deadness).
detect_initial_deadness_2([V - M|VAs], ModuleInfo, Deadness0, Deadness) :-
(
mode_is_output(ModuleInfo, M)
->
set__insert(Deadness0, V, Deadness1)
;
Deadness1 = Deadness0
),
detect_initial_deadness_2(VAs, ModuleInfo, Deadness1, Deadness).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- pred stuff_liveness_residue_into_goal(hlds__goal, liveness_info, hlds__goal).
:- mode stuff_liveness_residue_into_goal(in, in, out) is det.
stuff_liveness_residue_into_goal(Goal - GoalInfo0, Residue, Goal - GoalInfo) :-
goal_info_post_delta_liveness(GoalInfo0, Births0 - Deaths),
set__union(Births0, Residue, Births),
goal_info_set_post_delta_liveness(GoalInfo0, Births - Deaths, GoalInfo).
%-----------------------------------------------------------------------------%
:- pred stuff_deadness_residue_into_goal(hlds__goal, liveness_info, hlds__goal).
:- mode stuff_deadness_residue_into_goal(in, in, out) is det.
stuff_deadness_residue_into_goal(Goal - GoalInfo0, Residue, Goal - GoalInfo) :-
goal_info_pre_delta_liveness(GoalInfo0, Births - Deaths0),
set__union(Deaths0, Residue, Deaths),
goal_info_set_pre_delta_liveness(GoalInfo0, Births - Deaths, GoalInfo).
%-----------------------------------------------------------------------------%
% traverses a goal, annotating it with information about which vars
% are live on backtracking. `Liveness' is the variables that are
% are live for the purposes of forward execution, i.e. they have
% been bound and may be referenced again (during forward execution).
% `Extras' is the variables that may be referenced on backtracking.
% Each goal is annotated with the variables that will be live on
% backtracking.
:- pred add_nondet_lives_to_goal(hlds__goal, set(var),
set(var), hlds__goal, set(var), set(var)).
:- mode add_nondet_lives_to_goal(in, in, in, out, out, out) is det.
add_nondet_lives_to_goal(Goal0 - GoalInfo0, Liveness0,
Extras0, Goal - GoalInfo, Liveness, Extras) :-
goal_info_pre_delta_liveness(GoalInfo0, PreDelta0),
goal_info_post_delta_liveness(GoalInfo0, PostDelta0),
PreDelta0 = PreBirths0 - PreDeaths0,
PostDelta0 = PostBirths0 - PostDeaths0,
set__difference(Liveness0, PreDeaths0, Liveness1),
goal_info_get_code_model(GoalInfo0, GoalModel),
(
GoalModel = model_non,
Goal0 = disj(_, _)
->
% If the goal is a nondet disj then all the variables
% that are live at the start of the disj will be
% needed at later disjuncts (a conservative approximation)
set__union(Extras0, Liveness1, Extras1)
;
GoalModel = model_non,
Goal0 = call(_,_,_,_,_,_,_)
->
% If the goal is a nondet call then all the variables
% that are live across the call become nondet live.
set__difference(Liveness1, PostDeaths0, LivenessAcross),
set__union(Extras0, LivenessAcross, Extras1)
;
Extras1 = Extras0
),
set__union(Liveness1, PreBirths0, Liveness2),
add_nondet_lives_to_goal_2(Goal0, Liveness2, Extras1,
Goal, Liveness3, Extras),
set__difference(Liveness3, PostDeaths0, Liveness4),
set__union(Liveness4, PostBirths0, Liveness),
goal_info_set_nondet_lives(GoalInfo0, Extras1, GoalInfo).
:- pred add_nondet_lives_to_goal_2(hlds__goal_expr, set(var), set(var),
hlds__goal_expr, set(var), set(var)).
:- mode add_nondet_lives_to_goal_2(in, in, in, out, out, out) is det.
add_nondet_lives_to_goal_2(conj(Goals0), Liveness0, Extras0,
conj(Goals), Liveness, Extras) :-
add_nondet_lives_to_conj(Goals0, Liveness0, Extras0,
Goals, Liveness, Extras).
add_nondet_lives_to_goal_2(disj(Goals0, FV), Liveness0, Extras0,
disj(Goals, FV), Liveness, Extras) :-
ExtrasAcc = Extras0,
add_nondet_lives_to_disj(Goals0, Liveness0, Extras0,
Goals, Liveness, ExtrasAcc, Extras).
add_nondet_lives_to_goal_2(switch(Var, CF, Goals0, FV), Liveness0, Extras0,
switch(Var, CF, Goals, FV), Liveness, Extras) :-
ExtrasAcc = Extras0,
add_nondet_lives_to_switch(Goals0, Liveness0, Extras0,
Goals, Liveness, ExtrasAcc, Extras).
add_nondet_lives_to_goal_2(if_then_else(Vars, Cond0, Then0, Else0, FV),
Liveness0, Extras0, if_then_else(Vars, Cond, Then, Else, FV),
Liveness, Extras) :-
add_nondet_lives_to_goal(Cond0, Liveness0, Extras0,
Cond, Liveness1, Extras1),
add_nondet_lives_to_goal(Then0, Liveness1, Extras1,
Then1, _Liveness2, Extras2),
add_nondet_lives_to_goal(Else0, Liveness1, Extras0,
Else1, Liveness, Extras3),
set__union(Extras2, Extras3, Extras),
% things that become nondet live in the Else
% but not the Then have to become automagically
% live at the end of the Then.
set__difference(Extras, Extras2, ElseOnlyExtras),
stuff_liveness_residue_into_goal(Then1, ElseOnlyExtras, Then),
% things that become nondet live in the Then
% but not the Else have to become automagically
% live at the end of the Else.
set__difference(Extras, Extras3, ThenOnlyExtras),
stuff_liveness_residue_into_goal(Else1, ThenOnlyExtras, Else).
% Nondet lives cannot escape from a some if they
% are quantified to that quantifier.
add_nondet_lives_to_goal_2(some(Vars, Goal0), Liveness0, Extras0,
some(Vars, Goal), Liveness, Extras0) :-
add_nondet_lives_to_goal(Goal0, Liveness0, Extras0,
Goal, Liveness, _Extras).
% Nondet lives cannot escape from a negation
add_nondet_lives_to_goal_2(not(Goal0), Liveness0, Extras0,
not(Goal), Liveness, Extras0) :-
add_nondet_lives_to_goal(Goal0, Liveness0, Extras0,
Goal, Liveness, _).
add_nondet_lives_to_goal_2(call(A,B,C,D,E,F,G), Liveness, Extras,
call(A,B,C,D,E,F,G), Liveness, Extras).
add_nondet_lives_to_goal_2(unify(A,B,C,D,E), Liveness, Extras,
unify(A,B,C,D,E), Liveness, Extras).
add_nondet_lives_to_goal_2(pragma_c_code(A,B,C,D,E), Liveness, Extras,
pragma_c_code(A,B,C,D,E), Liveness, Extras).
:- pred add_nondet_lives_to_conj(list(hlds__goal), set(var), set(var),
list(hlds__goal), set(var), set(var)).
:- mode add_nondet_lives_to_conj(in, in, in, out, out, out) is det.
add_nondet_lives_to_conj([], Liveness, Extras, [], Liveness, Extras).
add_nondet_lives_to_conj([G0|Gs0], Liveness0, Extras0,
[G|Gs], Liveness, Extras) :-
add_nondet_lives_to_goal(G0, Liveness0, Extras0, G, Liveness1, Extras1),
(
G0 = _ - GoalInfo,
goal_info_get_instmap_delta(GoalInfo, unreachable)
->
Gs = Gs0,
Liveness = Liveness1,
Extras = Extras1
;
add_nondet_lives_to_conj(Gs0, Liveness1, Extras1,
Gs, Liveness, Extras)
).
:- pred add_nondet_lives_to_disj(list(hlds__goal), set(var), set(var),
list(hlds__goal), set(var), set(var), set(var)).
:- mode add_nondet_lives_to_disj(in, in, in, out, out, in, out) is det.
% We have to add post-births of variables that become nondet
% live in some disjuncts but are neither live nor nondet live at
% the end of others.
add_nondet_lives_to_disj([], Liveness, _Extras0, [], Liveness, Extras, Extras).
% For the last disjunct, we optimize what variables are nondet-
% live by observing that in the last disjunct we no longer need
% to save the inputs onto the stack for later disjuncts (since
% there aren't any.
add_nondet_lives_to_disj([G0], Liveness0, Extras0,
[G], Liveness, ExtrasAcc, Extras) :-
add_nondet_lives_to_goal(G0, Liveness0, Extras0,
G1, Liveness, Extras1),
set__union(ExtrasAcc, Extras1, Extras),
set__difference(ExtrasAcc, Extras1, OtherGoalExtras),
% optimized Extras -> ExtrasAcc
stuff_liveness_residue_into_goal(G1, OtherGoalExtras, G).
add_nondet_lives_to_disj([G0|Gs0], Liveness0, Extras0,
[G|Gs], Liveness, ExtrasAcc0, Extras) :-
% make this clause mutually exclusive with the previous one
Gs0 = [_|_],
add_nondet_lives_to_goal(G0, Liveness0, Extras0, G1, Liveness, Extras2),
set__union(ExtrasAcc0, Extras2, ExtrasAcc),
add_nondet_lives_to_disj(Gs0, Liveness0, Extras0,
Gs, _Liveness1, ExtrasAcc, Extras),
set__difference(Extras, Extras2, OtherGoalExtras),
stuff_liveness_residue_into_goal(G1, OtherGoalExtras, G).
:- pred add_nondet_lives_to_switch(list(case), set(var), set(var),
list(case), set(var),set(var), set(var)).
:- mode add_nondet_lives_to_switch(in, in, in, out, out, in, out) is det.
add_nondet_lives_to_switch([], Liveness, _Extras0,
[], Liveness, Extras, Extras).
add_nondet_lives_to_switch([case(ConsId, G0)|Gs0], Liveness0, Extras0,
[case(ConsId, G)|Gs], Liveness, ExtrasAcc0, Extras) :-
add_nondet_lives_to_goal(G0, Liveness0, Extras0, G1, Liveness, Extras2),
set__union(ExtrasAcc0, Extras2, ExtrasAcc),
add_nondet_lives_to_switch(Gs0, Liveness0, Extras0,
Gs, _Liveness1, ExtrasAcc, Extras),
set__difference(Extras, Extras2, OtherGoalExtras),
stuff_liveness_residue_into_goal(G1, OtherGoalExtras, G).
%------------------------------------------------------------------------------%
:- pred add_deadness_to_goal(hlds__goal, set(var), hlds__goal).
:- mode add_deadness_to_goal(in, in, out) is det.
add_deadness_to_goal(Goal - GoalInfo0, Vars, Goal - GoalInfo) :-
goal_info_nondet_lives(GoalInfo0, NondetLives0),
goal_info_post_delta_liveness(GoalInfo0, PostDelta0),
PostDelta0 = PostBirths - PostDeaths0,
set__union(NondetLives0, Vars, NondetLives),
set__union(PostDeaths0, Vars, PostDeaths),
PostDelta = PostBirths - PostDeaths,
goal_info_set_nondet_lives(GoalInfo0, NondetLives, GoalInfo1),
goal_info_set_post_delta_liveness(GoalInfo1, PostDelta, GoalInfo).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%