Files
mercury/tests/par_conj/consume_wait.m
Zoltan Somogyi 8424003542 Fix an old bug in the transformation that implements dependent parallel
Estimated hours taken: 20
Branches: main

Fix an old bug in the transformation that implements dependent parallel
conjunctions. The bug occurred when some arms of a branched control structure
consumed a shared variable, and some arms didn't. For code like this

	q(X::in, Y::in, Z::out) :-
	    ( Y = 2 ->
		A = Y
	    ;
		A = X
	    ),
	    Z = X + A

where X is a shared variable in a conjunction that calls q, the transformation
yielded code that waited for the future version of X only in the else branch,
not in the then branch. Since each wait was the producer of X from FutureX,
this led directly to a mode inconsistency between the branches, and hence
to a compiler crash.

The main part of the fix is to make sure that the code that inserts waits into
branched goals always inserts the wait either into every branch (if the
variable is consumed by at least one branch), or into no branch (if no branch
consumes the variable).

The other part of the fix is to replace the code which tried to ensure,
in a general sort of way, the invariant that the conjuncts of a parallel
conjunction should not have any of their shared variables in their nonlocal
set, with code that directly ensures that shared variables are always renamed
in their consuming conjuncts. Unlike the earlier approach, this approach
generates code that is obviously correct by construction. It also takes
much less code to implement, and should take less compilation time.

compiler/dep_par_conj.m:
	Implement the fixes above.

	Separate out the different parts of the transformation. For each
	part, pass around only the information that part requires, document
	which parts of this information are read-only. Give more descriptive
	names to each function, including using a distinct set of prefixes
	for different parts of the transformation.

	Improve the documentation.

	Remove the code that used to handle the case of grades that do not
	support parallel conjunctions, since it cluttered up other code.

compiler/mercury_compile.m:
	Check just once whether the grade supports parallel conjunctions.
	If not, call the code in a new module parallel_to_plain_conj.

	The dep_par_conj pass creates specialized versions of procedures
	and redirects calls to them, so it may leave the original versions
	without any calls and thus dead, so invoke the dead procedure
	elimination pass immediately after it.

	Move the final dead procedure elimination pass *after* the dep_par_conj
	pass, and after some some other passes (that may also create dead
	procedures).

compiler/parallel_to_plain_conj.m:
	Downgrade all parallel conjunctions to plain conjunctions.

compiler/transform_hlds.m:
compiler/notes/compiler_design.m:
	Add the new module.

compiler/dead_proc_elim.m:
	Rename the parameter of the main procedure of this module to avoid
	a false dichotomy (the invocation of dead_proc_elim after the
	dep_par_conj pass is neither for warnings nor a final optimization).

compiler/goal_util.m:
	Give a predicate a more meaningful name. Export a predicate for use by
	dep_par_conj.

compiler/pd_util.m:
	Rename some predicates to avoid ambiguity.

compiler/deforest.m:
compiler/delay_partial_inst.m:
compiler/inlining.m:
compiler/quantification.m:
	Conform to the change to goal_util and/or pd_util.

compiler/simplify.m:
	Rename some predicates to avoid ambiguity.

	Use state variables to reduce the apparent complexity of some code.

tests/par_conj/consume_in_some_branches.{m,exp}:
tests/par_conj/consume_in_some_branches_and_after.{m,exp}:
tests/par_conj/consume_wait.{m,exp}:
	New test cases to test for the bug.

tests/par_conj/Mmakefile:
	Enable the new test cases.
2008-10-15 04:06:17 +00:00

100 lines
1.4 KiB
Mathematica

% vim: ft=mercury ts=4 sw=4 et
:- module consume_wait.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module int.
main(!IO) :-
(
X1 = 1
&
Y1 = 2,
q(X1, Y1, Z1)
),
io.write_int(Z1, !IO),
io.nl(!IO),
(
X2 = 1
&
Y2 = 2,
r(X2, Y2, Z2)
),
io.write_int(Z2, !IO),
io.nl(!IO),
(
X3 = t2
&
Y3 = t3,
s(X3, Y3, Z3)
),
io.write_int(Z3, !IO),
io.nl(!IO).
:- pred q(int::in, int::in, int::out) is det.
:- pragma no_inline(q/3).
q(X, Y, Z) :-
( X = 2 ->
Z = Y
;
Z = X
).
:- pred r(int::in, int::in, int::out) is det.
:- pragma no_inline(r/3).
r(X, Y, Z) :-
(
not (X = Y)
;
true
),
Z = Y.
:- type t
---> t1
; t2
; t3.
:- pred s(t::in, t::in, int::out) is det.
:- pragma no_inline(s/3).
s(X, Y, Z) :-
( not (X = Y) ->
(
X = t1,
Z = val(Y)
;
X = t2,
Z = val(X) + val(Y)
;
X = t3,
(
Y = t1,
Z = 10 * val(X)
;
Y = t2,
Z = 20 * val(X)
;
Y = t3,
Z = 30 * val(X)
)
)
;
Z = val(X)
).
:- func val(t) = int.
val(t1) = 1.
val(t2) = 2.
val(t3) = 3.