Files
mercury/compiler/liveness.m
Thomas Conway 1661289197 Bugfix: unreachable inst problem.
liveness.nl:
	Bugfix: unreachable inst problem.
1995-02-08 04:55:12 +00:00

492 lines
19 KiB
Mathematica

%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module liveness.
% 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.
%-----------------------------------------------------------------------------%
:- interface.
:- import_module hlds, llds.
:- pred detect_liveness(module_info, module_info).
:- mode detect_liveness(in, out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module list, map, set, std_util.
:- import_module mode_util, term.
%-----------------------------------------------------------------------------%
% 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_is_imported(PredInfo) ->
ModuleInfo1 = ModuleInfo0
;
pred_info_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) :-
module_info_preds(ModuleInfo0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo0),
pred_info_procedures(PredInfo0, ProcTable0),
map__lookup(ProcTable0, ProcId, ProcInfo0),
% 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'.
proc_info_goal(ProcInfo0, Goal0),
detect_initial_liveness(ProcInfo0, ModuleInfo0, Liveness0),
detect_liveness_in_goal(Goal0, Liveness0, ModuleInfo0, Goal1),
detect_initial_deadness(ProcInfo0, ModuleInfo0, Deadness0),
detect_deadness_in_goal(Goal1, Deadness0, ModuleInfo0, Goal),
proc_info_set_goal(ProcInfo0, Goal, ProcInfo1),
proc_info_set_liveness_info(ProcInfo1, Liveness0, 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),
detect_liveness_in_procs(ProcIds, PredId, ModuleInfo1, ModuleInfo).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- 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), Liveness0, ModuleInfo,
Liveness, disj(Goals)) :-
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), Liveness0,
ModuleInfo, Liveness, switch(Var, Det, Cases)) :-
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), Liveness0,
M, Liveness, if_then_else(Vars, Cond, Then, Else)) :-
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), L, _, L, call(A,B,C,D,E,F)).
detect_liveness_in_goal_2(unify(A,B,C,D,E), L, _, L, unify(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]) :-
% (
% Goal0 = _ - GoalInfo,
% goal_info_get_instmap_delta(GoalInfo, unreachable)
% ->
% Goal = Goal0,
% Goals = Goals0,
% Liveness = Liveness0
% ;
detect_liveness_in_goal(Goal0, Liveness0,
ModuleInfo, Liveness1, Goal),
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), Deadness0,
ModuleInfo, Deadness, disj(Goals)) :-
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), Deadness0,
ModuleInfo, Deadness, if_then_else(Vars, Cond, Then, Else)) :-
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), Deadness0,
ModuleInfo, Deadness, switch(Var, Det, Cases)) :-
set__init(Union0),
detect_deadness_in_cases(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), Dn, _, Dn, call(A,B,C,D,E,F)).
detect_deadness_in_goal_2(unify(A,B,C,D,E), Dn, _, Dn, unify(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)
->
detect_deadness_in_conj(Goals0, Deadness0,
ModuleInfo, Goals, Deadness2),
detect_deadness_in_goal(Goal0, Deadness2,
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(list(case), set(var), module_info, set(var),
set(var), list(case)).
:- mode detect_deadness_in_cases(in, in, in, in, out, out) is det.
detect_deadness_in_cases([], _Deadness, _ModuleInfo, Union, Union, []).
detect_deadness_in_cases([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(Goals0, Deadness0, ModuleInfo,
Union1, Union, Goals),
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).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%