diff: liveness bug fix
Fergus Henderson
fjh at cs.mu.oz.au
Mon Aug 25 17:53:15 AEST 1997
Here's the diff I forgot for this one.
> Fix a bug which caused the code generator to fail on certain
> examples involving predicates with determinism `erroneous'.
>
> compiler/inst_match.m:
> Change `inst_is_bound' so that it succeeds for `not_reached' insts.
> This change is so that the behaviour of the predicate matches
> the documentation, and so that it is consistent with the behaviour
> of `inst_is_ground'.
>
> compiler/liveness.m:
> When computing the value-giving occurrences, check explicitly
> for unreachable instmaps. This is necessary to handle the above
> change to `inst_is_bound'.
>
> Fix a bug in detect_deadness: it was applying the deaths before
> the births, but it should be done in the other order.
> Normally deaths must be applied before births, but in detect_deadness
> we are traversing the goal backwards, so we must apply births first
> and then deaths.
>
> The old solution of just cancelling out any vars that occur in
> both the post-death and post-birth set was not quite right;
> instead we just need to apply them in the correct order.
>
> compiler/code_info.m:
> Change the code so that it applies the pre/post deaths
> before applying the corresponding births.
>
> compiler/live_vars.m:
> compiler/store_alloc.m:
> compiler/hlds_goal.m:
> Add some comments about making sure we always apply the deaths
> before applying the births. (The code here was already correct,
> I just added some documentation.)
>
> compiler/hlds_out.m:
> Print out the pre/post deaths before the pre/post births, so
> that the order that they are printed out in matches the order
> in which they should be applied.
>
> tests/hard_coded/Mmake:
> tests/hard_coded/erroneous_liveness.m:
> tests/hard_coded/erroneous_liveness.exp:
> tests/hard_coded/erroneous_liveness.inp:
> Regression test for the above-mentioned bug fix.
Index: inst_match.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/inst_match.m,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -u -r1.33 -r1.34
--- inst_match.m 1997/07/27 15:00:36 1.33
+++ inst_match.m 1997/08/23 20:32:58 1.34
@@ -741,6 +741,7 @@
% or is a user-defined inst which is not defined as `free'.
% Abstract insts must be bound.
+inst_is_bound(_, not_reached).
inst_is_bound(_, any(_)).
inst_is_bound(_, ground(_, _)).
inst_is_bound(_, bound(_, _)).
Index: liveness.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/liveness.m,v
retrieving revision 1.78
retrieving revision 1.79
diff -u -u -r1.78 -r1.79
--- liveness.m 1997/07/27 15:00:49 1.78
+++ liveness.m 1997/08/23 20:33:02 1.79
@@ -23,6 +23,10 @@
% track of aliasing and for structure re-use optimization, whereas here
% we are concerned with the liveness of the variable itself, for the
% purposes of optimizing stack slot and register usage.
+% Variables have a lifetime: each variable is born, gets used, and then dies.
+% To minimize stack slot and register usage, the birth should be
+% as late as possible (but before the first possible use), and the
+% death should be as early as possible (but after the last possible use).
%
% We compute liveness related information in three distinct passes.
%
@@ -154,35 +158,39 @@
set__difference(NonLocals, Liveness0, NewVarsSet),
set__to_sorted_list(NewVarsSet, NewVarsList),
goal_info_get_instmap_delta(GoalInfo0, InstMapDelta),
- set__init(Births0),
- find_value_giving_occurrences(NewVarsList, LiveInfo, InstMapDelta,
- Births0, Births),
- set__union(Liveness0, Births, Liveness),
set__init(Empty),
+ ( instmap_delta_is_unreachable(InstMapDelta) ->
+ Births = Empty
+ ;
+ set__init(Births0),
+ find_value_giving_occurrences(NewVarsList, LiveInfo,
+ InstMapDelta, Births0, Births)
+ ),
+ set__union(Liveness0, Births, Liveness),
(
goal_is_atomic(Goal0)
->
- PreBirths = Births,
PreDeaths = Empty,
- PostBirths = Empty,
+ PreBirths = Births,
PostDeaths = Empty,
+ PostBirths = Empty,
Goal = Goal0
;
- PreBirths = Empty,
PreDeaths = Empty,
+ PreBirths = Empty,
detect_liveness_in_goal_2(Goal0, Liveness0, NonLocals,
LiveInfo, ActualLiveness, Goal),
set__intersect(NonLocals, ActualLiveness, NonLocalLiveness),
set__union(NonLocalLiveness, Liveness0, FinalLiveness),
- set__difference(Liveness, FinalLiveness, PostBirths),
- set__difference(FinalLiveness, Liveness, PostDeaths)
+ set__difference(FinalLiveness, Liveness, PostDeaths),
+ set__difference(Liveness, FinalLiveness, PostBirths)
),
% We initialize all the fields in order to obliterate any
% annotations left by a previous invocation of this module.
- goal_info_set_pre_births(GoalInfo0, PreBirths, GoalInfo1),
- goal_info_set_post_births(GoalInfo1, PostBirths, GoalInfo2),
- goal_info_set_pre_deaths(GoalInfo2, PreDeaths, GoalInfo3),
- goal_info_set_post_deaths(GoalInfo3, PostDeaths, GoalInfo4),
+ goal_info_set_pre_deaths(GoalInfo0, PreDeaths, GoalInfo1),
+ goal_info_set_pre_births(GoalInfo1, PreBirths, GoalInfo2),
+ goal_info_set_post_deaths(GoalInfo2, PostDeaths, GoalInfo3),
+ goal_info_set_post_births(GoalInfo3, PostBirths, GoalInfo4),
goal_info_set_resume_point(GoalInfo4, no_resume_point, GoalInfo).
%-----------------------------------------------------------------------------%
@@ -329,35 +337,49 @@
detect_deadness_in_goal(Goal0 - GoalInfo0, Deadness0, LiveInfo, Deadness,
Goal - GoalInfo) :-
- goal_info_get_pre_births(GoalInfo0, PreBirths0),
- goal_info_get_post_births(GoalInfo0, PostBirths0),
goal_info_get_pre_deaths(GoalInfo0, PreDeaths0),
+ goal_info_get_pre_births(GoalInfo0, PreBirths0),
goal_info_get_post_deaths(GoalInfo0, PostDeaths0),
- set__union(Deadness0, PostDeaths0, Deadness1),
- set__difference(Deadness1, PostBirths0, Deadness2),
+ goal_info_get_post_births(GoalInfo0, PostBirths0),
+
+ set__difference(Deadness0, PostBirths0, Deadness1),
+ set__union(Deadness1, PostDeaths0, Deadness2),
liveness__get_nonlocals_and_typeinfos(LiveInfo, GoalInfo0, NonLocals),
set__init(Empty),
(
goal_is_atomic(Goal0)
->
- NewPreDeaths = Empty,
+ %
+ % The code below is slightly dodgy: the new postdeaths really
+ % ought to be computed as the difference between the liveness
+ % immediately before goal and the deadness immediately after
+ % goal. But we don't have liveness available here, and
+ % computing it would be complicated and perhaps costly. So
+ % instead we use the non-locals. The effect of this is that a
+ % variable will die after its last occurence, even if it has
+ % never been born. (This can occur in the case of variables
+ % with `free->free' modes, or for goals with determinism
+ % erroneous.) Thus the code generator must be willing to
+ % handle that -- it is not considered an error for a variable
+ % that is not yet live to die. [If we ever wanted to
+ % change this, the easiest thing to do would be to put
+ % some extra code in the third pass (detect_resume_points)
+ % to delete any such untimely deaths.]
+ %
set__difference(NonLocals, Deadness2, NewPostDeaths),
set__union(Deadness2, NewPostDeaths, Deadness3),
Goal = Goal0
;
- NewPreDeaths = Empty,
NewPostDeaths = Empty,
detect_deadness_in_goal_2(Goal0, GoalInfo0, Deadness2,
LiveInfo, Deadness3, Goal)
),
- set__union(PreDeaths0, NewPreDeaths, PreDeaths),
set__union(PostDeaths0, NewPostDeaths, PostDeaths),
- goal_info_set_pre_deaths(GoalInfo0, PreDeaths, GoalInfo1),
- goal_info_set_post_deaths(GoalInfo1, PostDeaths, GoalInfo),
+ goal_info_set_post_deaths(GoalInfo0, PostDeaths, GoalInfo),
- set__union(Deadness3, PreDeaths0, Deadness4),
- set__difference(Deadness4, PreBirths0, Deadness).
+ set__difference(Deadness3, PreBirths0, Deadness4),
+ set__union(Deadness4, PreDeaths0, Deadness).
% Here we process each of the different sorts of goals.
@@ -497,10 +519,10 @@
detect_resume_points_in_goal(Goal0 - GoalInfo0, Liveness0, LiveInfo,
ResumeVars0, Goal - GoalInfo0, Liveness) :-
- goal_info_get_pre_births(GoalInfo0, PreBirths0),
- goal_info_get_post_births(GoalInfo0, PostBirths0),
goal_info_get_pre_deaths(GoalInfo0, PreDeaths0),
+ goal_info_get_pre_births(GoalInfo0, PreBirths0),
goal_info_get_post_deaths(GoalInfo0, PostDeaths0),
+ goal_info_get_post_births(GoalInfo0, PostBirths0),
set__difference(Liveness0, PreDeaths0, Liveness1),
set__union(Liveness1, PreBirths0, Liveness2),
@@ -576,29 +598,7 @@
CondResume = resume_point(CondResumeVars, CondResumeLocs),
goal_set_resume_point(Cond1, CondResume, Cond),
- (
- set__equal(LivenessThen, LivenessElse)
- ->
- true
- ;
- live_info_get_varset(LiveInfo, Varset),
- set__to_sorted_list(LivenessThen, ThenVarsList),
- set__to_sorted_list(LivenessElse, ElseVarsList),
- list__map(varset__lookup_name(Varset),
- ThenVarsList, ThenVarNames),
- list__map(varset__lookup_name(Varset),
- ElseVarsList, ElseVarNames),
- Pad = lambda([S0::in, S::out] is det,
- string__append(S0, " ", S)),
- list__map(Pad, ThenVarNames, PaddedThenNames),
- list__map(Pad, ElseVarNames, PaddedElseNames),
- string__append_list(PaddedThenNames, ThenNames),
- string__append_list(PaddedElseNames, ElseNames),
- string__append_list([
- "branches of if-then-else disagree on liveness\nThen: ",
- ThenNames, "\nElse: ", ElseNames], Msg),
- error(Msg)
- ).
+ require_equal(LivenessThen, LivenessElse, "if-then-else", LiveInfo).
detect_resume_points_in_goal_2(some(Vars, Goal0), _, Liveness0, LiveInfo,
ResumeVars0, some(Vars, Goal), Liveness) :-
@@ -759,8 +759,7 @@
set__difference(Liveness0, PreDeaths, NeededFirst),
set__union(NeededFirst, NeededRest, Needed),
- require(set__equal(Liveness, LivenessRest),
- "branches of disjunction disagree on liveness").
+ require_equal(Liveness, LivenessRest, "disjunction", LiveInfo).
:- pred detect_resume_points_in_last_disjunct(hlds_goal, set(var), live_info,
set(var), hlds_goal, set(var), set(var)).
@@ -788,12 +787,44 @@
( Cases0 = [_ | _] ->
detect_resume_points_in_cases(Cases0, Liveness0, LiveInfo,
ResumeVars0, Cases, LivenessRest),
- require(set__equal(LivenessFirst, LivenessRest),
- "branches of switch disagree on liveness")
+ require_equal(LivenessFirst, LivenessRest, "switch",
+ LiveInfo)
;
Cases = Cases0
).
+:- pred require_equal(set(var), set(var), string, live_info).
+:- mode require_equal(in, in, in, in) is det.
+
+require_equal(LivenessFirst, LivenessRest, GoalType, LiveInfo) :-
+ (
+ set__equal(LivenessFirst, LivenessRest)
+ ->
+ true
+ ;
+ live_info_get_varset(LiveInfo, Varset),
+ set__to_sorted_list(LivenessFirst, FirstVarsList),
+ set__to_sorted_list(LivenessRest, RestVarsList),
+ list__map(varset__lookup_name(Varset),
+ FirstVarsList, FirstVarNames),
+ list__map(varset__lookup_name(Varset),
+ RestVarsList, RestVarNames),
+ Pad = lambda([S0::in, S::out] is det,
+ string__append(S0, " ", S)),
+ list__map(Pad, FirstVarNames, PaddedFirstNames),
+ list__map(Pad, RestVarNames, PaddedRestNames),
+ string__append_list(PaddedFirstNames, FirstNames),
+ string__append_list(PaddedRestNames, RestNames),
+ string__append_list(["branches of ", GoalType,
+ " disagree on liveness\nFirst: ",
+ FirstNames, "\nRest: ", RestNames], Msg),
+ % error(Msg)
+ dump(Msg) % XXX temporary debugging hack
+ ).
+
+:- pred dump(string::in) is det.
+:- pragma c_code(dump(S::in), "puts(S);").
+
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
@@ -902,47 +933,13 @@
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
- % Consider a goal such as
- %
- % ( Cond ->
- % DCG = value1
- % error
- % ;
- % ...
- % DCG = value2
- % )
- %
- % When working working on the goal representing the then-part,
- % detect_liveness_in_goal will put DCG into its post-death set,
- % because the then-part cannot succeed and thus the lifetime of DCG
- % is over at the end of the then-part.
- %
- % Later, at the end of the processing of the if-then-else, we will
- % then put DCG into the post-birth set of the then-part, since it
- % would have to be produced by the then-part if it ever terminated.
- %
- % Rather than end up with DCG in both the post-death and post-birth
- % sets, which can cause problems if they are applied in the wrong
- % order, we instead put into neither. This is fine; the intended
- % result is that DCG should be live after the then-part, and it must
- % have been born during the then-part (otherwise it would not have
- % been put into the post-death set).
-
:- pred add_liveness_after_goal(hlds_goal, set(var), hlds_goal).
:- mode add_liveness_after_goal(in, in, out) is det.
add_liveness_after_goal(Goal - GoalInfo0, Residue, Goal - GoalInfo) :-
- goal_info_get_post_deaths(GoalInfo0, PostDeaths0),
goal_info_get_post_births(GoalInfo0, PostBirths0),
-
- set__intersect(Residue, PostDeaths0, CancelledDeaths),
- set__difference(Residue, CancelledDeaths, NewBirths),
-
- set__difference(PostDeaths0, CancelledDeaths, PostDeaths),
- set__union(PostBirths0, NewBirths, PostBirths),
-
- goal_info_set_post_births(GoalInfo0, PostBirths, GoalInfo1),
- goal_info_set_post_deaths(GoalInfo1, PostDeaths, GoalInfo).
+ set__union(PostBirths0, Residue, PostBirths),
+ goal_info_set_post_births(GoalInfo0, PostBirths, GoalInfo).
:- pred add_deadness_before_goal(hlds_goal, set(var), hlds_goal).
:- mode add_deadness_before_goal(in, in, out) is det.
Index: code_info.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/code_info.m,v
retrieving revision 1.207
retrieving revision 1.208
diff -u -u -r1.207 -r1.208
--- code_info.m 1997/07/27 14:59:57 1.207
+++ code_info.m 1997/08/23 20:33:07 1.208
@@ -752,11 +752,12 @@
;
{ MaybeFollowVars = no }
),
- { goal_info_get_pre_births(GoalInfo, PreBirths) },
+ % note: we must be careful to apply deaths before births
{ goal_info_get_pre_deaths(GoalInfo, PreDeaths) },
- code_info__add_forward_live_vars(PreBirths),
code_info__rem_forward_live_vars(PreDeaths),
code_info__make_vars_forward_dead(PreDeaths),
+ { goal_info_get_pre_births(GoalInfo, PreBirths) },
+ code_info__add_forward_live_vars(PreBirths),
( { Atomic = yes } ->
{ goal_info_get_post_deaths(GoalInfo, PostDeaths) },
code_info__rem_forward_live_vars(PostDeaths)
@@ -767,11 +768,12 @@
% Update the code info structure to be consistent
% immediately after generating a goal
code_info__post_goal_update(GoalInfo) -->
- { goal_info_get_post_births(GoalInfo, PostBirths) },
+ % note: we must be careful to apply deaths before births
{ goal_info_get_post_deaths(GoalInfo, PostDeaths) },
- code_info__add_forward_live_vars(PostBirths),
code_info__rem_forward_live_vars(PostDeaths),
code_info__make_vars_forward_dead(PostDeaths),
+ { goal_info_get_post_births(GoalInfo, PostBirths) },
+ code_info__add_forward_live_vars(PostBirths),
code_info__make_vars_forward_live(PostBirths),
{ goal_info_get_instmap_delta(GoalInfo, InstMapDelta) },
code_info__apply_instmap_delta(InstMapDelta).
@@ -2090,7 +2092,8 @@
code_info__get_stack_slots(StackSlots),
code_info__get_exprn_info(Exprn0),
{ set__to_sorted_list(Vars, VarList) },
- { code_info__make_vars_forward_live_2(VarList, StackSlots, 1, Exprn0, Exprn) },
+ { code_info__make_vars_forward_live_2(VarList, StackSlots, 1,
+ Exprn0, Exprn) },
code_info__set_exprn_info(Exprn).
:- pred code_info__make_vars_forward_live_2(list(var), stack_slots, int,
Index: live_vars.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/live_vars.m,v
retrieving revision 1.65
retrieving revision 1.66
diff -u -u -r1.65 -r1.66
--- live_vars.m 1997/07/27 15:00:46 1.65
+++ live_vars.m 1997/08/23 20:33:12 1.66
@@ -69,10 +69,11 @@
build_live_sets_in_goal(Goal0 - GoalInfo, Liveness0, ResumeVars0, LiveSets0,
ModuleInfo, ProcInfo, Liveness, ResumeVars, LiveSets) :-
- goal_info_get_pre_births(GoalInfo, PreBirths),
+ % note: we must be careful to apply deaths before births
goal_info_get_pre_deaths(GoalInfo, PreDeaths),
- goal_info_get_post_births(GoalInfo, PostBirths),
+ goal_info_get_pre_births(GoalInfo, PreBirths),
goal_info_get_post_deaths(GoalInfo, PostDeaths),
+ goal_info_get_post_births(GoalInfo, PostBirths),
set__difference(Liveness0, PreDeaths, Liveness1),
set__union(Liveness1, PreBirths, Liveness2),
Index: store_alloc.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/store_alloc.m,v
retrieving revision 1.53
retrieving revision 1.54
diff -u -u -r1.53 -r1.54
--- store_alloc.m 1997/07/27 15:01:40 1.53
+++ store_alloc.m 1997/08/23 20:33:14 1.54
@@ -73,10 +73,11 @@
store_alloc_in_goal(Goal0 - GoalInfo0, Liveness0, ResumeVars0, ModuleInfo,
Goal - GoalInfo0, Liveness) :-
- goal_info_get_pre_births(GoalInfo0, PreBirths),
+ % note: we must be careful to apply deaths before births
goal_info_get_pre_deaths(GoalInfo0, PreDeaths),
- goal_info_get_post_births(GoalInfo0, PostBirths),
+ goal_info_get_pre_births(GoalInfo0, PreBirths),
goal_info_get_post_deaths(GoalInfo0, PostDeaths),
+ goal_info_get_post_births(GoalInfo0, PostBirths),
set__difference(Liveness0, PreDeaths, Liveness1),
set__union(Liveness1, PreBirths, Liveness2),
Index: hlds_goal.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/hlds_goal.m,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -u -r1.38 -r1.39
--- hlds_goal.m 1997/07/27 15:00:28 1.38
+++ hlds_goal.m 1997/08/23 20:33:23 1.39
@@ -478,7 +478,11 @@
% Instead of recording the liveness of every variable at every
% part of the goal, we just keep track of the initial liveness
-% and the changes in liveness.
+% and the changes in liveness. Note that when traversing forwards
+% through a goal, deaths must be applied before births;
+% this is necessary to handle certain circumstances where a
+% variable can occur in both the post-death and post-birth sets,
+% or in both the pre-death and pre-birth sets.
:- pred goal_info_get_pre_births(hlds_goal_info, set(var)).
:- mode goal_info_get_pre_births(in, out) is det.
Index: hlds_out.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/hlds_out.m,v
retrieving revision 1.170
retrieving revision 1.171
diff -u -u -r1.170 -r1.171
--- hlds_out.m 1997/08/22 13:55:01 1.170
+++ hlds_out.m 1997/08/23 20:33:31 1.171
@@ -660,23 +660,23 @@
[]
),
( { string__contains_char(Verbose, 'p') } ->
- { goal_info_get_pre_births(GoalInfo, PreBirths) },
- { set__to_sorted_list(PreBirths, PreBirthList) },
- ( { PreBirthList \= [] } ->
+ { goal_info_get_pre_deaths(GoalInfo, PreDeaths) },
+ { set__to_sorted_list(PreDeaths, PreDeathList) },
+ ( { PreDeathList \= [] } ->
hlds_out__write_indent(Indent),
- io__write_string("% pre-births: "),
- mercury_output_vars(PreBirthList, VarSet,
+ io__write_string("% pre-deaths: "),
+ mercury_output_vars(PreDeathList, VarSet,
AppendVarnums),
io__write_string("\n")
;
[]
),
- { goal_info_get_pre_deaths(GoalInfo, PreDeaths) },
- { set__to_sorted_list(PreDeaths, PreDeathList) },
- ( { PreDeathList \= [] } ->
+ { goal_info_get_pre_births(GoalInfo, PreBirths) },
+ { set__to_sorted_list(PreBirths, PreBirthList) },
+ ( { PreBirthList \= [] } ->
hlds_out__write_indent(Indent),
- io__write_string("% pre-deaths: "),
- mercury_output_vars(PreDeathList, VarSet,
+ io__write_string("% pre-births: "),
+ mercury_output_vars(PreBirthList, VarSet,
AppendVarnums),
io__write_string("\n")
;
@@ -731,23 +731,23 @@
[]
),
( { string__contains_char(Verbose, 'p') } ->
- { goal_info_get_post_births(GoalInfo, PostBirths) },
- { set__to_sorted_list(PostBirths, PostBirthList) },
- ( { PostBirthList \= [] } ->
+ { goal_info_get_post_deaths(GoalInfo, PostDeaths) },
+ { set__to_sorted_list(PostDeaths, PostDeathList) },
+ ( { PostDeathList \= [] } ->
hlds_out__write_indent(Indent),
- io__write_string("% post-births: "),
- mercury_output_vars(PostBirthList, VarSet,
+ io__write_string("% post-deaths: "),
+ mercury_output_vars(PostDeathList, VarSet,
AppendVarnums),
io__write_string("\n")
;
[]
),
- { goal_info_get_post_deaths(GoalInfo, PostDeaths) },
- { set__to_sorted_list(PostDeaths, PostDeathList) },
- ( { PostDeathList \= [] } ->
+ { goal_info_get_post_births(GoalInfo, PostBirths) },
+ { set__to_sorted_list(PostBirths, PostBirthList) },
+ ( { PostBirthList \= [] } ->
hlds_out__write_indent(Indent),
- io__write_string("% post-deaths: "),
- mercury_output_vars(PostDeathList, VarSet,
+ io__write_string("% post-births: "),
+ mercury_output_vars(PostBirthList, VarSet,
AppendVarnums),
io__write_string("\n")
;
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3 | -- the last words of T. S. Garp.
More information about the developers
mailing list