[m-dev.] for review: fix bug in unique mode checking
Fergus Henderson
fjh at cs.mu.OZ.AU
Fri Apr 16 17:50:07 AEST 1999
Since no-one has raised any objections, I will go ahead and commit this one.
On 09-Apr-1999, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> Hi,
>
> Could someone please review this one?
>
> --------------------
>
> Estimated hours taken: 4
>
> compiler/unique_modes.m:
> Fix a bug reported by Serge Varennes
> <serge.varennes at detexis.thomson-csf.com>:
> we need to mark variables as `mostly_unique' rather
> than `unique' at all disjunctions, not just at model_non
> disjunctions, because model_semi and even model_det
> disjunctions can still have backtracking from one failing
> disjunct into the next disjunct.
>
> Also add a couple of comments.
>
> tests/invalid/Mmakefile:
> tests/invalid/uniq_modes.m:
> tests/invalid/uniq_modes.err_exp:
> Add a regression test for this change.
>
> tests/hard_coded/purity.m:
> tests/hard_coded/cc_nondet_disj.m:
> Fix code that the compiler now rejects, due to the above change.
> The compiler is being a bit conservative to reject these cases,
> because the code won't actually violate unique-mode-correctness,
> but the conservatism here with disjunctions is similar to unique
> mode analysis's already existing conservatism with regard to
> if-then-elses, and the work-around for cases like this is easy,
> so I don't consider that to be a significant problem.
>
> The conservatism in question is that if it sees
> `{ test }, io__write_string("blah")' in a model_det/model_semi
> disjunct or in the condition of an if-then-else, it will report
> a unique mode error, since it doesn't realize that destructive
> update only occurs _after_ we have committed to this branch.
>
> tests/hard_coded/Mmakefile:
> Disable the test case bidirectional.m, since the compiler now
> rejects it, due to the above change to unique_modes.m.
> The compiler is again being overly conservative in its analysis.
> The problem is similar to that in the two test cases above,
> unfortunately there is no easy work-around in this case.
> The compiler really ought to support this style of bidirectional
> code using unique modes, so I do consider this to be a significant
> problem, but the fix is a fair bit of work, so I will deal with
> that as a separate change.
>
> Index: compiler/unique_modes.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/compiler/unique_modes.m,v
> retrieving revision 1.50
> diff -u -r1.50 unique_modes.m
> --- unique_modes.m 1998/11/20 04:09:38 1.50
> +++ unique_modes.m 1999/04/08 16:42:07
> @@ -10,6 +10,10 @@
> % This module checks that variables with a unique mode (as opposed to
> % a mostly-unique mode) really are unique, and not nondet live - i.e.,
> % that they cannot be referenced on backtracking.
> +% (Actually the term "nondet live" is a bit of a misnomer, because
> +% really we are just interested in whether something can be referenced
> +% on backtracking, and this can occur after backtracking in semidet
> +% code too, not just in nondet code.)
>
> % Basically we just traverse each goal, keeping track of which variables
> % are nondet live. At each procedure call, we check that any arguments
> @@ -19,7 +23,9 @@
>
> % Variables can become nondet live in several places:
> % in negations, in the conditions of if-then-elses,
> -% and in disjunctions, and at nondet calls.
> +% in disjunctions, and at nondet calls.
> +% These are the only places at which we can resume execution
> +% after backtracking.
>
> % XXX we currently make the conservative assumption that
> % any non-local variable in a disjunction or nondet call
> @@ -245,10 +251,10 @@
>
> unique_modes__check_goal_2(conj(List0), _GoalInfo0, conj(List)) -->
> mode_checkpoint(enter, "conj"),
> - mode_info_add_goals_live_vars(List0),
> ( { List0 = [] } -> % for efficiency, optimize common case
> { List = [] }
> ;
> + mode_info_add_goals_live_vars(List0),
> unique_modes__check_conj(List0, List)
> ),
> mode_checkpoint(exit, "conj").
> @@ -270,21 +276,15 @@
> { instmap__init_unreachable(InstMap) },
> mode_info_set_instmap(InstMap)
> ;
> + %
> + % Mark all the variables which are nondet-live at the
> + % start of the disjunction and whose inst is `unique'
> + % as instead being only `mostly_unique'.
> + %
> { goal_info_get_nonlocals(GoalInfo0, NonLocals) },
> - { goal_info_get_code_model(GoalInfo0, CodeModel) },
> - % does this disjunction create a choice point?
> - ( { CodeModel = model_non } ->
> - %
> - % Mark all the variables which are nondet-live at the
> - % start of the disjunction and whose inst is `unique'
> - % as instead being only `mostly_unique'.
> - %
> - mode_info_add_live_vars(NonLocals),
> - make_all_nondet_live_vars_mostly_uniq,
> - mode_info_remove_live_vars(NonLocals)
> - ;
> - []
> - ),
> + mode_info_add_live_vars(NonLocals),
> + make_all_nondet_live_vars_mostly_uniq,
> + mode_info_remove_live_vars(NonLocals),
>
> %
> % Now just modecheck each disjunct in turn, and then
> @@ -314,6 +314,23 @@
> % safe to leave it as `unique' on entry to the condition.
> % The only case we need to set it to `mostly_unique' is
> % if the condition would clobber it.
> + %
> + % XXX actually that is not true; the code below does
> + % the wrong thing for examples such as this one:
> + %
> + % :- mode p(di).
> + % p(Var) :-
> + % (if
> + % (if semidet_succeed then
> + % clobber(Var), fail
> + % else
> + % true
> + % )
> + % then
> + % blah
> + % else
> + % use(Var)
> + % ).
> %
> mode_info_add_live_vars(C_Vars),
> =(ModeInfo),
> Index: tests/hard_coded/Mmakefile
> ===================================================================
> RCS file: /home/mercury1/repository/tests/hard_coded/Mmakefile,v
> retrieving revision 1.54
> diff -u -r1.54 Mmakefile
> --- Mmakefile 1999/03/26 04:34:14 1.54
> +++ Mmakefile 1999/04/08 17:18:29
> @@ -9,7 +9,6 @@
> PROGS= \
> address_of_builtins \
> agg \
> - bidirectional \
> bigtest \
> boyer \
> c_write_string \
> @@ -94,6 +93,8 @@
>
> # we do no pass the following tests
> # var_not_found -- "sorry, not implemented" in polymorphism.m.
> +# bidirectional -- unique mode analysis is overly conservative
> +# and thus rejects this test case.
>
> #-----------------------------------------------------------------------------#
>
> Index: tests/hard_coded/cc_nondet_disj.m
> ===================================================================
> RCS file: /home/mercury1/repository/tests/hard_coded/cc_nondet_disj.m,v
> retrieving revision 1.4
> diff -u -r1.4 cc_nondet_disj.m
> --- cc_nondet_disj.m 1997/05/20 02:08:16 1.4
> +++ cc_nondet_disj.m 1999/04/08 17:03:01
> @@ -9,7 +9,20 @@
> :- import_module list.
>
> main --> io__read_line(Res),
> + ( { Res = ok(['y'|_]), Message = "Yes\n" }
> + ; { Res = ok(['n'|_]), Message = "No\n" }
> + ; { Message = "Huh?\n" }
> + ),
> + io__write_string(Message).
> +
> +/***
> +% This test used to be written as follows, but currently
> +% the unique mode analysis is not smart enough to realize
> +% that the disjuncts which update the I/O state won't
> +% backtrack over I/O if the code is written like that.
> +main --> io__read_line(Res),
> ( { Res = ok(['y'|_]) }, io__write_string("Yes\n")
> ; { Res = ok(['n'|_]) }, io__write_string("No\n")
> ; io__write_string("Huh?\n")
> ).
> +***/
> Index: tests/hard_coded/purity.m
> ===================================================================
> RCS file: /home/mercury1/repository/tests/hard_coded/purity.m,v
> retrieving revision 1.3
> diff -u -r1.3 purity.m
> --- purity.m 1998/01/06 06:31:40 1.3
> +++ purity.m 1999/04/08 17:03:58
> @@ -80,9 +80,24 @@
> test3 -->
> ( { impure incr_x },
> { fail }
> + ; { semipure get_x(Y) }
> + ),
> + io__format("%d\n", [i(Y)]).
> +
> +/***
> +% This test used to be written as follows, but currently
> +% the unique mode analysis is not smart enough to realize
> +% that the disjuncts which update the I/O state won't
> +% backtrack over I/O if the code is written like that.
> +
> +% tempt compiler to optimize away impure goal in branch that cannot succeed.
> +test3 -->
> + ( { impure incr_x },
> + { fail }
> ; { semipure get_x(Y) },
> io__format("%d\n", [i(Y)])
> ).
> +***/
>
> % regression test for problem with calls to implied modes of impure/semipure
> % preds reporting spurious warnings about impurity markers in the wrong place.
> @@ -118,9 +133,24 @@
> test3_inline -->
> ( { impure incr_x_inline },
> { fail }
> + ; { semipure get_x_inline(Y) }
> + ),
> + io__format("%d\n", [i(Y)]).
> +
> +/***
> +% This test used to be written as follows, but currently
> +% the unique mode analysis is not smart enough to realize
> +% that the disjuncts which update the I/O state won't
> +% backtrack over I/O if the code is written like that.
> +
> +% tempt compiler to optimize away impure goal in branch that cannot succeed.
> +test3_inline -->
> + ( { impure incr_x_inline },
> + { fail }
> ; { semipure get_x_inline(Y) },
> io__format("%d\n", [i(Y)])
> ).
> +***/
>
> % regression test for problem with calls to implied modes of impure/semipure
> % preds reporting spurious warnings about impurity markers in the wrong place.
> Index: tests/hard_coded/uniq_modes.m
> ===================================================================
> RCS file: uniq_modes.m
> diff -N uniq_modes.m
> --- /dev/null Fri Apr 9 04:28:35 1999
> +++ uniq_modes.m Fri Apr 9 04:03:24 1999
> @@ -0,0 +1,18 @@
> +:- module uniq_modes.
> +:- interface.
> +:- import_module io.
> +
> +:- pred main(io__state, io__state).
> +:- mode main(di, uo) is det.
> +
> +:- implementation.
> +:- import_module list,std_util.
> +
> +main(In, _Out) :-
> + io__write("looking for", In, Int1),
> + io__nl(Int1, _Int2),
> + fail.
> +main(In, Out) :-
> + io__write("not found", In, Int),
> + io__nl(Int, Out).
> +
> Index: tests/hard_coded/uniq_modes.err_exp
> ===================================================================
> RCS file: uniq_modes.err_exp
> diff -N uniq_modes.err_exp
> --- /dev/null Fri Apr 9 04:28:37 1999
> +++ uniq_modes.err_exp Fri Apr 9 04:06:46 1999
> @@ -0,0 +1,5 @@
> +uniq_modes.m:012: In clause for `main(di, uo)':
> +uniq_modes.m:012: in argument 2 of call to predicate `io:write/3':
> +uniq_modes.m:012: mode error: variable `In' has instantiatedness `mostly_unique',
> +uniq_modes.m:012: expected instantiatedness was `unique'.
> +For more information, try recompiling with `-E'.
> Index: tests/hard_coded/Mmakefile
> ===================================================================
> RCS file: /home/mercury1/repository/tests/invalid/Mmakefile,v
> retrieving revision 1.37
> diff -u -r1.37 Mmakefile
> --- Mmakefile 1999/02/12 04:19:30 1.37
> +++ Mmakefile 1999/04/08 18:00:44
> @@ -61,6 +61,7 @@
> undef_mode.m \
> undef_symbol.m \
> undef_type.m \
> + uniq_modes.m \
> uu_type.m \
> vars_in_wrong_places.m
>
>
> --
> 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.
> --------------------------------------------------------------------------
> mercury-developers mailing list
> Post messages to: mercury-developers at cs.mu.oz.au
> Administrative Queries: owner-mercury-developers at cs.mu.oz.au
> Subscriptions: mercury-developers-request at cs.mu.oz.au
> --------------------------------------------------------------------------
>
--
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