[m-rev.] for review: fix bug in dep_par_conj

Zoltan Somogyi zs at csse.unimelb.edu.au
Tue Oct 14 16:12:53 AEDT 2008


On 13-Oct-2008, Zoltan Somogyi <zs at csse.unimelb.edu.au> wrote:
> Actually, I found a bug when trying to describe the algorithm in the paper,
> so there is no point in a review until I fix that bug.

Here is the updated diff and log message.

Zoltan.

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.

cvs diff: Diffing .
cvs diff: Diffing analysis
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/doc
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing boehm_gc/libatomic_ops-1.2
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/doc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/hpc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ibmc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/icc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/sunc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/tests
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing boehm_gc/windows-untested
cvs diff: Diffing boehm_gc/windows-untested/vc60
cvs diff: Diffing boehm_gc/windows-untested/vc70
cvs diff: Diffing boehm_gc/windows-untested/vc71
cvs diff: Diffing browser
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
Index: compiler/dead_proc_elim.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/dead_proc_elim.m,v
retrieving revision 1.128
diff -u -b -r1.128 dead_proc_elim.m
--- compiler/dead_proc_elim.m	3 Apr 2008 05:26:42 -0000	1.128
+++ compiler/dead_proc_elim.m	14 Oct 2008 04:57:09 -0000
@@ -32,17 +32,29 @@
 
 %-----------------------------------------------------------------------------%
 
-:- type dead_proc_pass
-    --->    dead_proc_warning_pass
-    ;       dead_proc_final_optimization_pass.
-
-    % Eliminate dead procedures. If the first argument is `warning_pass',
-    % also warn about any user-defined procedures that are dead.
-    % If the first argument is `final_optimization_pass', also eliminate
-    % any opt_imported procedures.
+:- type maybe_elim_opt_imported
+    --->    elim_opt_imported
+    ;       do_not_elim_opt_imported.
+
+    % Eliminate dead procedures. If the first argument is `elim_opt_imported',
+    % also eliminate any opt_imported procedures.
+    %
+    % The last argument will be a list of warnings about any user-defined
+    % procedures that are dead, but the caller is free to ignore this list.
     %
-:- pred dead_proc_elim(dead_proc_pass::in, module_info::in, module_info::out,
-    list(error_spec)::out) is det.
+:- pred dead_proc_elim(maybe_elim_opt_imported::in,
+    module_info::in, module_info::out, list(error_spec)::out) is det.
+
+:- type needed_map == map(entity, maybe_needed).
+
+:- type entity
+    --->    entity_proc(pred_id, proc_id)
+    ;       entity_table_struct(pred_id, proc_id)
+    ;       entity_type_ctor(module_name, string, int).
+
+:- type maybe_needed
+    --->    not_eliminable
+    ;       maybe_eliminable(num_references :: int).
 
     % Analyze which entities are needed, and for those entities which are
     % needed, record how many times they are referenced (this information
@@ -59,17 +71,6 @@
     %
 :- pred dead_pred_elim(module_info::in, module_info::out) is det.
 
-:- type entity
-    --->    entity_proc(pred_id, proc_id)
-    ;       entity_table_struct(pred_id, proc_id)
-    ;       entity_type_ctor(module_name, string, int).
-
-:- type needed_map == map(entity, maybe_needed).
-
-:- type maybe_needed
-    --->    not_eliminable
-    ;       maybe_eliminable(num_references :: int).
-
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -127,9 +128,9 @@
 :- type entity_queue    ==  queue(entity).
 :- type examined_set    ==  set(entity).
 
-dead_proc_elim(Pass, !ModuleInfo, Specs) :-
+dead_proc_elim(ElimOptImported, !ModuleInfo, Specs) :-
     dead_proc_analyze(!ModuleInfo, Needed),
-    dead_proc_eliminate(Pass, Needed, !ModuleInfo, Specs).
+    dead_proc_eliminate(ElimOptImported, Needed, !ModuleInfo, Specs).
 
 %-----------------------------------------------------------------------------%
 
@@ -622,33 +623,36 @@
 
 :- type proc_elim_info
     --->    proc_elim_info(
-                proc_elim_needed_map    :: needed_map,
                                         % Collected usage counts.
+                proc_elim_needed_map    :: needed_map,
+
                 proc_elim_module_info   :: module_info,
+
+                % Table of predicates in this module: preds and procs
+                % in this table may be eliminated.
                 proc_elim_pred_table    :: pred_table,
-                                        % Table of predicates in this module:
-                                        % preds and procs in this table
-                                        % may be eliminated.
-                proc_elim_changed       :: bool,
+
                                         % Has anything changed.
-                proc_elim_warnings      :: list(error_spec)
+                proc_elim_changed       :: bool,
+
                                         % A list of warning messages.
+                proc_elim_warnings      :: list(error_spec)
             ).
 
     % Given the information about which entities are needed,
     % eliminate procedures which are not needed.
     %
-:- pred dead_proc_eliminate(dead_proc_pass::in, needed_map::in,
+:- pred dead_proc_eliminate(maybe_elim_opt_imported::in, needed_map::in,
     module_info::in, module_info::out, list(error_spec)::out) is det.
 
-dead_proc_eliminate(Pass, !.Needed, !ModuleInfo, Specs) :-
+dead_proc_eliminate(ElimOptImported, !.Needed, !ModuleInfo, Specs) :-
     module_info_predids(PredIds, !ModuleInfo),
     module_info_preds(!.ModuleInfo, PredTable0),
 
     Changed0 = no,
     ProcElimInfo0 = proc_elim_info(!.Needed, !.ModuleInfo, PredTable0,
         Changed0, []),
-    list.foldl(dead_proc_eliminate_pred(Pass), PredIds,
+    list.foldl(dead_proc_eliminate_pred(ElimOptImported), PredIds,
         ProcElimInfo0, ProcElimInfo),
     ProcElimInfo = proc_elim_info(!:Needed, !:ModuleInfo, PredTable,
         Changed, Specs),
@@ -675,10 +679,10 @@
 
     % Eliminate any unused procedures for this pred.
     %
-:- pred dead_proc_eliminate_pred(dead_proc_pass::in, pred_id::in,
+:- pred dead_proc_eliminate_pred(maybe_elim_opt_imported::in, pred_id::in,
     proc_elim_info::in, proc_elim_info::out) is det.
 
-dead_proc_eliminate_pred(Pass, PredId, !ProcElimInfo) :-
+dead_proc_eliminate_pred(ElimOptImported, PredId, !ProcElimInfo) :-
     !.ProcElimInfo = proc_elim_info(Needed, ModuleInfo, PredTable0, Changed0,
         Specs0),
     map.lookup(PredTable0, PredId, PredInfo0),
@@ -735,9 +739,9 @@
         % Don't generate code in the current module for unoptimized
         % opt_imported preds (that is, for opt_imported preds which we have not
         % by this point managed to inline or specialize; this code should be
-        % called with `Pass = final_optimization_pass' only after inlining
+        % called with `ElimOptImported = elim_opt_imported' only after inlining
         % and specialization is complete).
-        Pass = dead_proc_final_optimization_pass,
+        ElimOptImported = elim_opt_imported,
         Status = status_opt_imported
     ->
         Changed = yes,
Index: compiler/deforest.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/deforest.m,v
retrieving revision 1.85
diff -u -b -r1.85 deforest.m
--- compiler/deforest.m	27 Feb 2008 07:23:04 -0000	1.85
+++ compiler/deforest.m	9 Oct 2008 04:02:40 -0000
@@ -1440,7 +1440,7 @@
     proc_info_get_varset(FirstProcInfo, FirstVersionVarSet),
     proc_info_get_vartypes(FirstProcInfo, FirstVersionVarTypes),
 
-    goal_util.create_variables(FirstVersionVars,
+    clone_variables(FirstVersionVars,
         FirstVersionVarSet, FirstVersionVarTypes,
         !VarSet, !VarTypes, FirstRenaming0, FirstRenaming),
     must_rename_vars_in_goal(FirstRenaming,
@@ -1899,7 +1899,7 @@
         ( set.equal(NonLocals1, NonLocals) ->
             Goal2 = Goal1
         ;
-            pd_util.requantify_goal(NonLocals, Goal1, Goal2, !PDInfo)
+            pd_requantify_goal(NonLocals, Goal1, Goal2, !PDInfo)
         ),
 
         % Push the extra information from the call through the goal.
Index: compiler/delay_partial_inst.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/delay_partial_inst.m,v
retrieving revision 1.8
diff -u -b -r1.8 delay_partial_inst.m
--- compiler/delay_partial_inst.m	29 Feb 2008 02:51:55 -0000	1.8
+++ compiler/delay_partial_inst.m	9 Oct 2008 04:03:02 -0000
@@ -452,9 +452,9 @@
 create_canonical_variables(OrigVars, CanonVars, !DelayInfo) :-
     VarSet0 = !.DelayInfo ^ dpi_varset,
     VarTypes0 = !.DelayInfo ^ dpi_vartypes,
-    create_variables(OrigVars, VarSet0, VarTypes0,
-        VarSet0, VarSet, VarTypes0, VarTypes, map.init, Subn),
-    rename_var_list(must_rename, Subn, OrigVars, CanonVars),
+    clone_variables(OrigVars, VarSet0, VarTypes0,
+        VarSet0, VarSet, VarTypes0, VarTypes, map.init, Renaming),
+    rename_var_list(must_rename, Renaming, OrigVars, CanonVars),
     !DelayInfo ^ dpi_varset := VarSet,
     !DelayInfo ^ dpi_vartypes := VarTypes.
 
Index: compiler/dep_par_conj.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/dep_par_conj.m,v
retrieving revision 1.25
diff -u -b -r1.25 dep_par_conj.m
--- compiler/dep_par_conj.m	27 Feb 2008 07:23:04 -0000	1.25
+++ compiler/dep_par_conj.m	13 Oct 2008 10:35:52 -0000
@@ -1,5 +1,5 @@
-%-----------------------------------------------------------------------------%
-% vim: ft=mercury ts=8 sw=4 et
+%-----------------------------------------------------------------------------%,
+% vim: ft=mercury ts=4 sw=4 et
 %-----------------------------------------------------------------------------%
 % Copyright (C) 2006-2008 The University of Melbourne.
 % This file may only be copied under the terms of the GNU General
@@ -10,36 +10,78 @@
 % Author: wangp.
 %
 % This module implements dependent parallel conjunction using a HLDS->HLDS
-% transformation.  The transformation adds calls to the synchronisation
-% predicates defined in library/par_builtin.m.
+% transformation. The transformation has two main components: a synchronization
+% transformation and a specialization transformation.
 %
-% For a parallel conjunction (A & B), if the goal B is dependent on a variable
-% X which is bound by goal A, we first transform the conjunction into the
-% following:
+% 1 The synchronization transformation ensures that consumers do not access
+%   shared variables before producers generate them. We do this by adding calls
+%   to the synchronisation primitives defined in library/par_builtin.m.
+%   In general, we make producers signal the availability of shared variables
+%   as soon as possible and we make consumers wait for the shared variables
+%   as late as possible.
 %
-%    par_builtin.new_future(FutureX),
+% 2 The specialization transformation spots the need for and creates new
+%   versions of procedures. If some shared variables in a parallel conjunction
+%   are produced and/or consumed inside a call, we create a specialized version
+%   of the called procedure that does the signalling of the produced variables
+%   (as early as possible) and/or the waiting for the consumed variables (as
+%   late as possible). In the absence of these specialized procedures, we would
+%   have to assume that all calls consume their inputs immediately and generate
+%   their outputs only when they return, which in many cases is an excessively
+%   optimistic assumption.
+%
+% To see how the synchronization transformation works, consider this example:
+%
+% p(A::in, B::in, C::out) :-
+%   (
+%       q(A, X),
+%       r(X, Y)
+%   )
+%   &
 %    (
+%       s(B, W),
+%       t(X, W, Z)
+%   ),
+%   C = X + Y + Z.
+%
+% The only variable shared between the parallel conjuncts is X, which is
+% produced by the call to q and is used in the call to t. We transform this
+% code to
+%
+% p(A::in, B::in, C::out) :-
+%   promise_pure(
+%       par_builtin.new_future(FutureX),
 %        (
-%            A(X),  % binds X
+%           q(A, X),
 %            impure par_builtin.signal(FutureX, X)
+%           r(X, Y)
 %        )
 %    &
 %        (
-%            par_builtin.wait(FutureX, X1),
-%            B(X1)  % uses X
-%        )
+%           s(B, W),
+%           par_builtin.wait(FutureX, X')
+%           t(X', W, Z)
 %    )
+%   ),
+%   C = X + Y + Z.
 %
-% That is, goal B must wait for the value to be produced by A before it begins
-% executing.  If B is a compound goal then the wait call is moved as late
-% into B as possible.  Signal calls will be moved to as early as possible.
-% Future variables become the only variables shared by parallel conjuncts.
+% For each shared variable, we create a new future variable, which serves as
+% the conduit between the producer and the consumers both for synchronization
+% and for the transmission of the shared variable's value. Note that we
+% create a new, distinct name for each shared variable in each consumer,
+% so that after the transformation, the only variables that occur in more than
+% one conjunct of the parallel conjunction are the variables that were already
+% ground before the parallel conjunction is entered (these include the future
+% variables).
 %
-% A subsequent pass looks for contiguous sequences of waits, a call to a
-% predicate P, followed by signals in a conjunction (there must be at least one
-% wait or one signal).  If the code of P is available then a specialised
-% ("parallel") version of P is produced, taking futures in place of any
-% arguments which need to be waited on or signalled.  For example:
+% The specialization transformation looks for calls preceded by a contiguous
+% sequence of one or more calls to par_builtin.wait and/or followed by a
+% contiguous sequence of one or more calls to par_builtin.signal. When it finds
+% one, it (a) replaces the sequence with a call to a specialized version of
+% the called procedure, a version which will do all the waits and/or signals
+% internally, and (b) creates that specialized version of the called procedure,
+% pushing the waits as late as possible and the signals as early as possible.
+% For example,
 %
 %   wait(FutureX, X),
 %   p(X, Y),
@@ -51,9 +93,13 @@
 %
 % where the wait and signal calls are now in the body of Parallel__p.
 %
-%
-% In non-parallel grades dependent parallel conjunctions are converted
-% into sequential conjunctions.
+% - The predicates and functions in this module whose names start with the
+%   prefixes "sync_dep_par_conjs", "insert_wait_in" and "insert_signal_in"
+%   implement the synchronization transformation
+% - Those whose names start with "find_specialization_requests" or include
+%   "specialization" implement part (a) of the specialization transformation.
+% - Those whose names start with "add_requested_specialized" implement part (b)
+%   of the specialization transformation.
 %
 % TODO:
 % - reconsider when this pass is run; in particular par_builtin primitives
@@ -69,16 +115,25 @@
 :- import_module hlds.instmap.
 :- import_module parse_tree.prog_data.
 
-:- import_module io.
+:- import_module list.
 :- import_module set.
 
 %-----------------------------------------------------------------------------%
 
-:- pred dependent_par_conj(module_info::in, module_info::out, io::di, io::uo)
+    % Transform all the parallel conjunctions in the procedures of this module
+    % according to the scheme shown above.
+    %
+:- pred impl_dep_par_conjs_in_module(module_info::in, module_info::out)
     is det.
 
-    % Exported for use by the implicit_parallelism pass.
-:- func find_shared_variables(module_info, instmap, hlds_goals)
+    % Given the conjunct goals in a parallel conjunction and the instmap before
+    % it, return the set of variables that need synchronization, i.e. the
+    % variables that are produced in one conjunct and consumed in one or more
+    % other conjuncts.
+    %
+    % This function is exported for use by the implicit_parallelism pass.
+    %
+:- func find_shared_variables(module_info, instmap, list(hlds_goal))
     = set(prog_var).
 
 %-----------------------------------------------------------------------------%
@@ -103,7 +158,6 @@
 :- import_module assoc_list.
 :- import_module bool.
 :- import_module int.
-:- import_module list.
 :- import_module map.
 :- import_module maybe.
 :- import_module pair.
@@ -116,32 +170,48 @@
 
 %-----------------------------------------------------------------------------%
 
-    % This type holds information relevant to the dependent parallel
-    % conjunction transformation.
+    % This type holds information relevant to the synchronization
+    % transformation.
     %
-:- type dep_par_info
-    --->    dep_par_info(
-                dp_par_procs    :: par_procs,
-                % Parallelised procedures added or waiting to be added.
+:- type sync_info
+    --->    sync_info(
+                % The current module. This field is read only.
+                sync_module_info            :: module_info,
 
-                dp_module_info  :: module_info,
-                % The current module.
+                % Variables which should not be replaced by futures in this
+                % pass because it has already been done. This field is
+                % read only.
+                sync_ignore_vars            :: set(prog_var),
 
-                dp_varset       :: prog_varset,
-                dp_vartypes     :: vartypes,
                 % The varset and vartypes for the procedure being analysed.
-
-                dp_ignore_vars  :: set(prog_var)
-                % Variables which should not be replaced by futures in this
-                % pass because it has already been done.
+                % These fields are updated when we add new variables.
+                sync_varset                 :: prog_varset,
+                sync_vartypes               :: vartypes
+
+                % XXX We may also need the rtti_var_maps.
+            ).
+
+    % This type holds information relevant to the specialization
+    % transformation.
+    %
+:- type spec_info
+    --->    spec_info(
+                % The set of parallelised procedures that we have already
+                % created. This field is constant: it should never be updated.
+                % (The set of done procs is updated only between the lifetimes
+                % of values of this type.)
+                spec_done_procs             :: done_par_procs,
+
+                % The current module. Updated when requesting a new
+                % specialization, since to get the pred_id for the specialized
+                % predicate we need to update the module_info.
+                spec_module_info            :: module_info,
+
+                % Parallelised procedures waiting to be added. Updated when
+                % requesting a new specialization.
+                spec_pending_procs          :: pending_par_procs
             ).
 
-    % Parallelised versions of procedures that have been added to the module,
-    % or are scheduled to be added.
-    %
-:- type par_procs
-    --->    par_procs(done_par_procs, pending_par_procs).
-
     % Parallelised procedures that have been added to the module already.
     % The calling pattern is the original pred_proc_id of the procedure
     % being called, plus the list of arguments which have been replaced
@@ -170,102 +240,93 @@
 :- type arg_pos == int.
 
     % A map from a variable to the future object created for that variable.
-    % i.e. for variable X with future F, when X is bound to a value then F is
-    % signalled.  A consumer of X waits (blocks) on F until that happens.
+    % If it maps e.g. X to FutureX, then
+    %
+    % - after a producer binds X to a value, it will signal FutureX, and
+    % - before a consumer needs X, it will wait on FutureX.
     %
 :- type future_map == map(prog_var, prog_var).
 
 %-----------------------------------------------------------------------------%
 
-dependent_par_conj(!ModuleInfo, !IO) :-
-    ModuleInfo0 = !.ModuleInfo,
+impl_dep_par_conjs_in_module(!ModuleInfo) :-
+    InitialModuleInfo = !.ModuleInfo,
 
-    % First process all parallel conjunctions in user-defined procedures.
+    % Phase one: insert synchronization code into all parallel conjunctions
+    % in the module.
     module_info_predids(PredIds, !ModuleInfo),
-    ParProcs0 = par_procs(map.init, []),
-    list.foldl3(process_pred_for_dep_par_conj, PredIds,
-        !ModuleInfo, ParProcs0, ParProcs, !IO),
-    ParProcs = par_procs(DoneParProcs, PendingProcs),
-
-    expect(map.is_empty(DoneParProcs), this_file, "DoneParProcs non empty"),
+    list.foldl2(maybe_sync_dep_par_conjs_in_pred, PredIds,
+        !ModuleInfo, [], ProcsToScan),
 
-    % Create the pending parallelised versions of procedures.
-    % These may in turn create more parallelised versions.
-    add_pending_par_procs(DoneParProcs, PendingProcs,
-        ModuleInfo0, !ModuleInfo, !IO).
+    % Phase two: attempt to push the synchronization code inside procedures
+    % as far as we can. We do this by creating specialized versions of
+    % procedures. We do this to a fixpoint, since creating a specialized
+    % version of a procedure may require us to create more specialized versions
+    % of the other procedures.
 
-:- pred handle_par_conj(module_info::in) is semidet.
-
-handle_par_conj(ModuleInfo) :-
-    module_info_get_globals(ModuleInfo, Globals),
-    current_grade_supports_par_conj(Globals, yes).
+    PendingParProcs0 = [],
+    DoneParProcs0 = map.init,
+    list.foldl2(find_specialization_requests_in_proc(DoneParProcs0),
+        ProcsToScan, !ModuleInfo, PendingParProcs0, PendingParProcs),
+    add_requested_specialized_par_procs(PendingParProcs, DoneParProcs0,
+        InitialModuleInfo, !ModuleInfo).
 
 %-----------------------------------------------------------------------------%
 
-:- pred process_pred_for_dep_par_conj(pred_id::in,
-    module_info::in, module_info::out, par_procs::in, par_procs::out,
-    io::di, io::uo) is det.
+:- pred maybe_sync_dep_par_conjs_in_pred(pred_id::in,
+    module_info::in, module_info::out,
+    list(pred_proc_id)::in, list(pred_proc_id)::out) is det.
 
-process_pred_for_dep_par_conj(PredId, !ModuleInfo, !ParProcs, !IO) :-
+maybe_sync_dep_par_conjs_in_pred(PredId, !ModuleInfo, !ProcsToScan) :-
     module_info_pred_info(!.ModuleInfo, PredId, PredInfo),
     ProcIds = pred_info_non_imported_procids(PredInfo),
-    list.foldl3(process_proc_for_dep_par_conj(PredId), ProcIds,
-        !ModuleInfo, !ParProcs, !IO).
+    list.foldl2(maybe_sync_dep_par_conjs_in_proc(PredId), ProcIds,
+        !ModuleInfo, !ProcsToScan).
 
-:- pred process_proc_for_dep_par_conj(pred_id::in, proc_id::in,
-    module_info::in, module_info::out, par_procs::in, par_procs::out,
-    io::di, io::uo) is det.
+:- pred maybe_sync_dep_par_conjs_in_proc(pred_id::in, proc_id::in,
+    module_info::in, module_info::out,
+    list(pred_proc_id)::in, list(pred_proc_id)::out) is det.
 
-process_proc_for_dep_par_conj(PredId, ProcId, !ModuleInfo, !ParProcs, !IO) :-
+maybe_sync_dep_par_conjs_in_proc(PredId, ProcId, !ModuleInfo, !ProcsToScan) :-
     module_info_proc_info(!.ModuleInfo, PredId, ProcId, ProcInfo),
     proc_info_get_has_parallel_conj(ProcInfo, HasParallelConj),
     (
         HasParallelConj = no
     ;
         HasParallelConj = yes,
-        process_proc_for_dep_par_conj_with_ignores(PredId, ProcId, set.init,
-            !ModuleInfo, !ParProcs, !IO)
+        sync_dep_par_conjs_in_proc(PredId, ProcId, set.init,
+            !ModuleInfo, !ProcsToScan)
     ).
 
-:- pred process_proc_for_dep_par_conj_with_ignores(pred_id::in, proc_id::in,
-    set(prog_var)::in, module_info::in, module_info::out,
-    par_procs::in, par_procs::out, io::di, io::uo) is det.
+:- pred sync_dep_par_conjs_in_proc(pred_id::in, proc_id::in, set(prog_var)::in,
+    module_info::in, module_info::out,
+    list(pred_proc_id)::in, list(pred_proc_id)::out) is det.
 
-process_proc_for_dep_par_conj_with_ignores(PredId, ProcId, IgnoreVars,
-        !ModuleInfo, !ParProcs, !IO) :-
-    some [!PredInfo, !ProcInfo, !Body, !VarSet, !VarTypes] (
+sync_dep_par_conjs_in_proc(PredId, ProcId, IgnoreVars, !ModuleInfo,
+        !ProcsToScan) :-
+    some [!PredInfo, !ProcInfo, !Goal, !VarSet, !VarTypes, !SyncInfo] (
         module_info_pred_proc_info(!.ModuleInfo, PredId, ProcId,
             !:PredInfo, !:ProcInfo),
-        proc_info_get_goal(!.ProcInfo, !:Body),
+        proc_info_get_goal(!.ProcInfo, !:Goal),
         proc_info_get_varset(!.ProcInfo, !:VarSet),
         proc_info_get_vartypes(!.ProcInfo, !:VarTypes),
         proc_info_get_initial_instmap(!.ProcInfo, !.ModuleInfo, InstMap0),
 
-        Info0 = dep_par_info(!.ParProcs, !.ModuleInfo,
-            !.VarSet, !.VarTypes, IgnoreVars),
-
-        search_goal_for_par_conj(!Body, InstMap0, _, Info0, Info1),
-
-        (if handle_par_conj(!.ModuleInfo) then
-            replace_sequences_in_goal(!Body, Info1, Info2),
-            Info2 = dep_par_info(!:ParProcs, !:ModuleInfo,
-                !:VarSet, !:VarTypes, _IgnoreVars),
+        !:SyncInfo = sync_info(!.ModuleInfo, IgnoreVars, !.VarSet, !.VarTypes),
+        sync_dep_par_conjs_in_goal(!Goal, InstMap0, _, !SyncInfo),
+        !.SyncInfo = sync_info(_, _, !:VarSet, !:VarTypes),
             % XXX RTTI varmaps may need to be updated
-            rename_apart_in_goal(!.ModuleInfo, !Body, InstMap0,
-                !VarSet, !VarTypes)
-        else
-            Info1 = dep_par_info(!:ParProcs, !:ModuleInfo,
-                !:VarSet, !:VarTypes, _IgnoreVars)
-        ),
 
         % We really only need to run this part if something changed, but we
         % only run this predicate on procedures which are likely to have
         % parallel conjunctions.
         proc_info_set_varset(!.VarSet, !ProcInfo),
         proc_info_set_vartypes(!.VarTypes, !ProcInfo),
-        proc_info_set_goal(!.Body, !ProcInfo),
+        proc_info_set_goal(!.Goal, !ProcInfo),
         fixup_and_reinsert_proc(PredId, ProcId, !.PredInfo, !.ProcInfo,
-            !ModuleInfo)
+            !ModuleInfo),
+        PredProcId = proc(PredId, ProcId),
+        !:ProcsToScan = [PredProcId | !.ProcsToScan]
     ).
 
 :- pred fixup_and_reinsert_proc(pred_id::in, proc_id::in,
@@ -281,107 +342,128 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred add_pending_par_procs(done_par_procs::in, pending_par_procs::in,
-    module_info::in, module_info::in, module_info::out, io::di, io::uo) is det.
+:- pred find_specialization_requests_in_proc(done_par_procs::in,
+    pred_proc_id::in, module_info::in, module_info::out,
+    pending_par_procs::in, pending_par_procs::out) is det.
+
+find_specialization_requests_in_proc(DoneProcs, PredProcId, !ModuleInfo,
+        !PendingParProcs) :-
+    PredProcId = proc(PredId, ProcId),
+    some [!PredInfo, !ProcInfo, !Goal, !SpecInfo] (
+        module_info_pred_proc_info(!.ModuleInfo, PredId, ProcId,
+            !:PredInfo, !:ProcInfo),
+        proc_info_get_goal(!.ProcInfo, !:Goal),
+        !:SpecInfo = spec_info(DoneProcs, !.ModuleInfo, !.PendingParProcs),
+        specialize_sequences_in_goal(!Goal, !SpecInfo),
+        !.SpecInfo = spec_info(_, !:ModuleInfo, !:PendingParProcs),
+        proc_info_set_goal(!.Goal, !ProcInfo),
+        % Optimization oppotunity: we should not fix up the same procedure
+        % twice, i.e. in sync_dep_par_conjs_in_proc and here.
+        fixup_and_reinsert_proc(PredId, ProcId, !.PredInfo, !.ProcInfo,
+            !ModuleInfo)
+    ).
+
+:- pred add_requested_specialized_par_procs(pending_par_procs::in,
+    done_par_procs::in, module_info::in, module_info::in, module_info::out)
+    is det.
 
-add_pending_par_procs(_DoneParProcs, [], _ModuleInfo0, !ModuleInfo, !IO).
-add_pending_par_procs(DoneParProcs0, [CallPattern - NewProc | Pending0],
-        ModuleInfo0, !ModuleInfo, !IO) :-
+add_requested_specialized_par_procs(!.PendingParProcs, !.DoneParProcs,
+        InitialModuleInfo, !ModuleInfo) :-
+    (
+        !.PendingParProcs = []
+    ;
+        !.PendingParProcs = [CallPattern - NewProc | !:PendingParProcs],
     % Move the procedure we are about to parallelise into the list of
     % done procedures, in case of recursive calls.
-    map.det_insert(DoneParProcs0, CallPattern, NewProc, DoneParProcs),
-    add_pending_par_proc(CallPattern, NewProc, DoneParProcs,
-        Pending0, Pending, ModuleInfo0, !ModuleInfo, !IO),
-    add_pending_par_procs(DoneParProcs, Pending,
-        ModuleInfo0, !ModuleInfo, !IO).
-
-:- pred add_pending_par_proc(par_proc_call_pattern::in, new_par_proc::in,
-    done_par_procs::in, pending_par_procs::in, pending_par_procs::out,
-    module_info::in, module_info::in, module_info::out, io::di, io::uo)
+        svmap.det_insert(CallPattern, NewProc, !DoneParProcs),
+        add_requested_specialized_par_proc(CallPattern, NewProc,
+            !PendingParProcs, !.DoneParProcs, InitialModuleInfo, !ModuleInfo),
+        add_requested_specialized_par_procs(!.PendingParProcs, !.DoneParProcs,
+            InitialModuleInfo, !ModuleInfo)
+    ).
+
+:- pred add_requested_specialized_par_proc(par_proc_call_pattern::in,
+    new_par_proc::in, pending_par_procs::in, pending_par_procs::out,
+    done_par_procs::in, module_info::in, module_info::in, module_info::out)
     is det.
 
-add_pending_par_proc(CallPattern, NewProc, DoneParProcs, PendingProcs0,
-        PendingProcs, ModuleInfo0, !ModuleInfo, !IO) :-
+add_requested_specialized_par_proc(CallPattern, NewProc, !PendingParProcs,
+        DoneParProcs, InitialModuleInfo, !ModuleInfo) :-
     CallPattern = par_proc_call_pattern(OldPredProcId, FutureArgs),
     NewProc     = new_par_proc(NewPredProcId, _Name),
-    ParProcs0   = par_procs(DoneParProcs, PendingProcs0),
-    ParProcs    = par_procs(_DoneParProcs, PendingProcs),
-    add_pending_par_proc_2(OldPredProcId, NewPredProcId, FutureArgs,
-        ModuleInfo0, !ModuleInfo, ParProcs0, ParProcs, !IO).
-
-:- pred add_pending_par_proc_2(pred_proc_id::in, pred_proc_id::in,
-    list(arg_pos)::in, module_info::in, module_info::in, module_info::out,
-    par_procs::in, par_procs::out, io::di, io::uo) is det.
-
-add_pending_par_proc_2(proc(OldPredId, OldProcId), proc(PredId, ProcId),
-        FutureArgs, ModuleInfo0, !ModuleInfo, !ParProcs, !IO) :-
-    some [!VarSet, !VarTypes, !ProcInfo] (
+    OldPredProcId = proc(OldPredId, OldProcId),
+    NewPredProcId = proc(NewPredId, NewProcId),
+
+    some [!VarSet, !VarTypes, !NewProcInfo] (
         % Get the proc_info from _before_ the dependent parallel conjunction
         % pass was ever run, so we get untransformed procedure bodies.
         % Our transformation does not attempt to handle already transformed
         % parallel conjunctions.
-        module_info_proc_info(ModuleInfo0, OldPredId, OldProcId, !:ProcInfo),
-        proc_info_get_varset(!.ProcInfo, !:VarSet),
-        proc_info_get_vartypes(!.ProcInfo, !:VarTypes),
-        proc_info_get_headvars(!.ProcInfo, HeadVars0),
-        proc_info_get_argmodes(!.ProcInfo, ArgModes0),
-        proc_info_get_goal(!.ProcInfo, Goal0),
-        proc_info_get_initial_instmap(!.ProcInfo, ModuleInfo0, InstMap0),
+        module_info_proc_info(InitialModuleInfo, OldPredId, OldProcId,
+            !:NewProcInfo),
+        proc_info_get_varset(!.NewProcInfo, !:VarSet),
+        proc_info_get_vartypes(!.NewProcInfo, !:VarTypes),
+        proc_info_get_headvars(!.NewProcInfo, HeadVars0),
+        proc_info_get_argmodes(!.NewProcInfo, ArgModes0),
+        proc_info_get_goal(!.NewProcInfo, Goal0),
+        proc_info_get_initial_instmap(!.NewProcInfo, InitialModuleInfo,
+            InstMap0),
 
         % Set up the mapping from head variables to futures.
-        list.foldl4(reproduce_future_map(HeadVars0), FutureArgs,
-            map.init, FutureMap, !VarSet, !VarTypes, !ModuleInfo),
+        list.foldl3(map_arg_to_new_future(HeadVars0), FutureArgs,
+            map.init, FutureMap, !VarSet, !VarTypes),
 
         % Replace head variables by their futures.
         replace_head_vars(!.ModuleInfo, FutureMap,
             HeadVars0, HeadVars, ArgModes0, ArgModes),
 
-        % Insert signals and waits into procedure body as a conjunct of a
-        % parallel conjunction.
+        % Insert signals and waits into the procedure body. We treat the body
+        % as it were a conjunct of a parallel conjunction, since it is.
         SharedVars = set.from_list(map.keys(FutureMap)),
-        transform_conjunct(SharedVars, FutureMap, Goal0, Goal, InstMap0, _,
-            !VarSet, !VarTypes, !ModuleInfo, !ParProcs),
+        sync_dep_par_conjunct(!.ModuleInfo, par_conjunct_is_proc_body,
+            SharedVars, FutureMap, Goal0, Goal, InstMap0, _,
+            !VarSet, !VarTypes),
+
+        proc_info_set_varset(!.VarSet, !NewProcInfo),
+        proc_info_set_vartypes(!.VarTypes, !NewProcInfo),
+        proc_info_set_headvars(HeadVars, !NewProcInfo),
+        proc_info_set_argmodes(ArgModes, !NewProcInfo),
+        proc_info_set_goal(Goal, !NewProcInfo),
 
-        proc_info_set_varset(!.VarSet, !ProcInfo),
-        proc_info_set_vartypes(!.VarTypes, !ProcInfo),
-        proc_info_set_headvars(HeadVars, !ProcInfo),
-        proc_info_set_argmodes(ArgModes, !ProcInfo),
-        proc_info_set_goal(Goal, !ProcInfo),
-
-        module_info_pred_info(!.ModuleInfo, PredId, PredInfo0),
+        module_info_pred_info(!.ModuleInfo, NewPredId, NewPredInfo0),
 
         % Mark this predicate impure if it no longer has any output arguments
         % (having been replaced by a future, which is an input argument which
         % is destructively updated).
-        (if any_output_arguments(!.ModuleInfo, ArgModes) then
-            PredInfo = PredInfo0
-        else
-            pred_info_get_markers(PredInfo0, Markers0),
+        ( any_output_arguments(!.ModuleInfo, ArgModes) ->
+            NewPredInfo = NewPredInfo0
+        ;
+            pred_info_get_markers(NewPredInfo0, Markers0),
             add_marker(marker_is_impure, Markers0, Markers),
-            pred_info_set_markers(Markers, PredInfo0, PredInfo)
+            pred_info_set_markers(Markers, NewPredInfo0, NewPredInfo)
         ),
 
-        fixup_and_reinsert_proc(PredId, ProcId, PredInfo, !.ProcInfo,
-            !ModuleInfo),
+        fixup_and_reinsert_proc(NewPredId, NewProcId, NewPredInfo,
+            !.NewProcInfo, !ModuleInfo),
 
-        % Continue processing the procedure and look for further dependent
-        % parallel conjunctions.
+        % Look for and process any dependent parallel conjunctions inside
+        % the newly created (sort of; the previous version was only a
+        % placeholder) specialized procedure.
         IgnoreVars = set.from_list(map.keys(FutureMap)),
-        process_proc_for_dep_par_conj_with_ignores(PredId, ProcId, IgnoreVars,
-            !ModuleInfo, !ParProcs, !IO)
+        sync_dep_par_conjs_in_proc(NewPredId, NewProcId, IgnoreVars,
+            !ModuleInfo, [], _ProcsToScan),
+        find_specialization_requests_in_proc(DoneParProcs, NewPredProcId,
+            !ModuleInfo, !PendingParProcs)
     ).
 
-:- pred reproduce_future_map(list(prog_var)::in,
-    arg_pos::in, future_map::in, future_map::out,
-    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
-    module_info::in, module_info::out) is det.
+:- pred map_arg_to_new_future(list(prog_var)::in, arg_pos::in,
+    future_map::in, future_map::out,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
 
-reproduce_future_map(HeadVars, FutureArg, !FutureMap,
-        !VarSet, !VarTypes, !ModuleInfo) :-
+map_arg_to_new_future(HeadVars, FutureArg, !FutureMap, !VarSet, !VarTypes) :-
     HeadVar = list.det_index1(HeadVars, FutureArg),
     map.lookup(!.VarTypes, HeadVar, VarType),
-    make_future(!.ModuleInfo, VarType, HeadVar, !VarTypes, !VarSet,
-        _AllocGoal, FutureVar),
+    make_future_var(HeadVar, VarType, !VarSet, !VarTypes, FutureVar),
     svmap.det_insert(HeadVar, FutureVar, !FutureMap).
 
 :- pred replace_head_vars(module_info::in, future_map::in,
@@ -391,8 +473,8 @@
 replace_head_vars(_ModuleInfo, _FutureMap, [], [], [], []).
 replace_head_vars(ModuleInfo, FutureMap,
         [Var0 | Vars0], [Var | Vars], [Mode0 | Modes0], [Mode | Modes]) :-
-    ( map.search(FutureMap, Var0, Var1) ->
-        Var = Var1,
+    ( map.search(FutureMap, Var0, FutureVar) ->
+        Var = FutureVar,
         ( mode_is_input(ModuleInfo, Mode0) ->
             Mode = Mode0
         ; mode_is_output(ModuleInfo, Mode0) ->
@@ -407,9 +489,9 @@
         Mode = Mode0
     ),
     replace_head_vars(ModuleInfo, FutureMap, Vars0, Vars, Modes0, Modes).
-replace_head_vars(_, _, [_|_], _, [], _) :-
+replace_head_vars(_, _, [_ | _], _, [], _) :-
     unexpected(this_file, "replace_head_vars: length mismatch").
-replace_head_vars(_, _, [], _, [_|_], _) :-
+replace_head_vars(_, _, [], _, [_ | _], _) :-
     unexpected(this_file, "replace_head_vars: length mismatch").
 
 :- pred any_output_arguments(module_info::in, list(mer_mode)::in) is semidet.
@@ -426,140 +508,122 @@
     % If so, allocate futures for variables shared between conjuncts.
     % Insert wait and signal calls for those futures into the conjuncts.
     %
-:- pred search_goal_for_par_conj(hlds_goal::in, hlds_goal::out,
-    instmap::in, instmap::out, dep_par_info::in, dep_par_info::out) is det.
-
-search_goal_for_par_conj(Goal0, Goal, InstMap0, InstMap, !Info) :-
-    search_goal_for_par_conj_2(Goal0, Goal, InstMap0, !Info),
-    update_instmap(Goal, InstMap0, InstMap).
-
-:- pred search_goal_for_par_conj_2(hlds_goal::in, hlds_goal::out,
-    instmap::in, dep_par_info::in, dep_par_info::out) is det.
+:- pred sync_dep_par_conjs_in_goal(hlds_goal::in, hlds_goal::out,
+    instmap::in, instmap::out, sync_info::in, sync_info::out)
+    is det.
 
-search_goal_for_par_conj_2(Goal0, Goal, InstMap0, !Info) :-
+sync_dep_par_conjs_in_goal(Goal0, Goal, InstMap0, InstMap, !SyncInfo) :-
     Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
     (
         GoalExpr0 = conj(ConjType, Goals0),
+        sync_dep_par_conjs_in_conj(Goals0, Goals, InstMap0, !SyncInfo),
         (
             ConjType = plain_conj,
-            search_goals_for_par_conj(Goals0, Goals, InstMap0, !Info),
             conj_list_to_goal(Goals, GoalInfo0, Goal)
         ;
             ConjType = parallel_conj,
-            maybe_transform_par_conj(Goals0, GoalInfo0, Goal, InstMap0, !Info)
+            maybe_sync_dep_par_conj(Goals, GoalInfo0, Goal, InstMap0,
+                !SyncInfo)
         )
     ;
         GoalExpr0 = disj(Goals0),
-        search_disj_for_par_conj(Goals0, Goals, InstMap0, !Info),
+        sync_dep_par_conjs_in_disj(Goals0, Goals, InstMap0, !SyncInfo),
         GoalExpr = disj(Goals),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
         GoalExpr0 = switch(Var, CanFail, Cases0),
-        search_cases_for_par_conj(Cases0, Cases, InstMap0, !Info),
+        sync_dep_par_conjs_in_cases(Cases0, Cases, InstMap0, !SyncInfo),
         GoalExpr = switch(Var, CanFail, Cases),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
-        GoalExpr0 = if_then_else(Quant, If0, Then0, Else0),
-        search_goal_for_par_conj(If0, If, InstMap0, InstMap1, !Info),
-        search_goal_for_par_conj(Then0, Then, InstMap1, _InstMap2, !Info),
-        search_goal_for_par_conj(Else0, Else, InstMap0, _InstMap3, !Info),
-        GoalExpr = if_then_else(Quant, If, Then, Else),
+        GoalExpr0 = if_then_else(QuantVars, Cond0, Then0, Else0),
+        sync_dep_par_conjs_in_goal(Cond0, Cond, InstMap0, InstMap1,
+            !SyncInfo),
+        sync_dep_par_conjs_in_goal(Then0, Then, InstMap1, _, !SyncInfo),
+        sync_dep_par_conjs_in_goal(Else0, Else, InstMap0, _, !SyncInfo),
+        GoalExpr = if_then_else(QuantVars, Cond, Then, Else),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
         GoalExpr0 = negation(SubGoal0),
-        search_goal_for_par_conj(SubGoal0, SubGoal, InstMap0, _, !Info),
+        sync_dep_par_conjs_in_goal(SubGoal0, SubGoal, InstMap0, _,
+            !SyncInfo),
         GoalExpr = negation(SubGoal),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
-        GoalExpr0 = scope(Reason, ScopeGoal0),
-        search_goal_for_par_conj(ScopeGoal0, ScopeGoal, InstMap0, _, !Info),
-        GoalExpr = scope(Reason, ScopeGoal),
+        GoalExpr0 = scope(Reason, SubGoal0),
+        sync_dep_par_conjs_in_goal(SubGoal0, SubGoal, InstMap0, _,
+            !SyncInfo),
+        GoalExpr = scope(Reason, SubGoal),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
-        ( GoalExpr0 = unify(_, _, _, _Kind, _)
-        ; GoalExpr0 = plain_call(_CallPredId, _CallProcId, _CallArgs, _, _, _)
-        ; GoalExpr0 = generic_call(_Details, _Args, _ArgModes, _)
+        ( GoalExpr0 = unify(_, _, _, _, _)
+        ; GoalExpr0 = plain_call(_, _, _, _, _, _)
+        ; GoalExpr0 = generic_call(_, _, _, _)
         ; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _)
         ),
         Goal = Goal0
     ;
         GoalExpr0 = shorthand(_),
         % These should have been expanded out by now.
-        unexpected(this_file,
-            "shorthand goal encountered during dependent parallel " ++
-            "conjunction transformation.")
-    ).
-
-:- pred search_goals_for_par_conj(hlds_goals::in, hlds_goals::out,
-    instmap::in, dep_par_info::in, dep_par_info::out) is det.
-
-search_goals_for_par_conj([], [], _InstMap0, !Info).
-search_goals_for_par_conj([Goal0 | Goals0], [Goal | Goals], InstMap0, !Info) :-
-    search_goal_for_par_conj(Goal0, Goal, InstMap0, InstMap, !Info),
-    search_goals_for_par_conj(Goals0, Goals, InstMap, !Info).
-
-:- pred search_disj_for_par_conj(hlds_goals::in, hlds_goals::out,
-    instmap::in, dep_par_info::in, dep_par_info::out) is det.
-
-search_disj_for_par_conj([], [], _InstMap0, !Info).
-search_disj_for_par_conj([Goal0 | Goals0], [Goal | Goals], InstMap0, !Info) :-
-    search_goal_for_par_conj(Goal0, Goal, InstMap0, _InstMap, !Info),
-    search_disj_for_par_conj(Goals0, Goals, InstMap0, !Info).
+        unexpected(this_file, "sync_dep_par_conjs_in_goal: shorthand")
+    ),
+    update_instmap(Goal, InstMap0, InstMap).
 
-:- pred search_cases_for_par_conj(list(case)::in, list(case)::out, instmap::in,
-    dep_par_info::in, dep_par_info::out) is det.
+:- pred sync_dep_par_conjs_in_conj(list(hlds_goal)::in, list(hlds_goal)::out,
+    instmap::in, sync_info::in, sync_info::out) is det.
 
-search_cases_for_par_conj([], [], _InstMap0, !Info).
-search_cases_for_par_conj([Case0 | Cases0], [Case | Cases], InstMap0, !Info) :-
+sync_dep_par_conjs_in_conj([], [], _, !SyncInfo).
+sync_dep_par_conjs_in_conj([Goal0 | Goals0], [Goal | Goals], !.InstMap,
+        !SyncInfo) :-
+    sync_dep_par_conjs_in_goal(Goal0, Goal, !InstMap, !SyncInfo),
+    sync_dep_par_conjs_in_conj(Goals0, Goals, !.InstMap, !SyncInfo).
+
+:- pred sync_dep_par_conjs_in_disj(list(hlds_goal)::in, list(hlds_goal)::out,
+    instmap::in, sync_info::in, sync_info::out) is det.
+
+sync_dep_par_conjs_in_disj([], [], _InstMap0, !SyncInfo).
+sync_dep_par_conjs_in_disj([Goal0 | Goals0], [Goal | Goals], InstMap0,
+        !SyncInfo) :-
+    sync_dep_par_conjs_in_goal(Goal0, Goal, InstMap0, _InstMap, !SyncInfo),
+    sync_dep_par_conjs_in_disj(Goals0, Goals, InstMap0, !SyncInfo).
+
+:- pred sync_dep_par_conjs_in_cases(list(case)::in, list(case)::out,
+    instmap::in, sync_info::in, sync_info::out) is det.
+
+sync_dep_par_conjs_in_cases([], [], _InstMap0, !SyncInfo).
+sync_dep_par_conjs_in_cases([Case0 | Cases0], [Case | Cases], InstMap0,
+        !SyncInfo) :-
     Case0 = case(MainConsId, OtherConsIds, Goal0),
-    search_goal_for_par_conj(Goal0, Goal, InstMap0, _, !Info),
+    sync_dep_par_conjs_in_goal(Goal0, Goal, InstMap0, _, !SyncInfo),
     Case = case(MainConsId, OtherConsIds, Goal),
-    search_cases_for_par_conj(Cases0, Cases, InstMap0, !Info).
+    sync_dep_par_conjs_in_cases(Cases0, Cases, InstMap0, !SyncInfo).
 
 %-----------------------------------------------------------------------------%
 
-    % We found a parallel conjunction.  Check for any dependencies
-    % between the conjuncts and, if so, insert sychronisation primitives.
+    % We found a parallel conjunction. Check for any dependencies between
+    % the conjuncts and, if we find som, insert sychronisation primitives.
     %
-:- pred maybe_transform_par_conj(hlds_goals::in, hlds_goal_info::in,
-    hlds_goal::out, instmap::in, dep_par_info::in, dep_par_info::out)
+:- pred maybe_sync_dep_par_conj(list(hlds_goal)::in, hlds_goal_info::in,
+    hlds_goal::out, instmap::in, sync_info::in, sync_info::out)
     is det.
 
-maybe_transform_par_conj(Conjuncts0, GoalInfo, NewGoal, InstMap,
-        !Info) :-
-    % Search subgoals for nested parallel conjunctions.
-    search_goals_for_par_conj(Conjuncts0, Conjuncts, InstMap, !Info),
-
+maybe_sync_dep_par_conj(Conjuncts, GoalInfo, NewGoal, InstMap, !SyncInfo) :-
+    !.SyncInfo = sync_info(ModuleInfo, IgnoreVars, VarSet0, VarTypes0),
     % Find the variables that are shared between conjuncts.
-    SharedVars0 = find_shared_variables(!.Info ^ dp_module_info,
-        InstMap, Conjuncts),
+    SharedVars0 = find_shared_variables(ModuleInfo, InstMap, Conjuncts),
 
     % Filter out all the variables which have already have associated futures,
     % i.e. they were head variables which were replaced by futures; signal and
     % wait calls will already have been inserted for them.
-    SharedVars = set.filter(isnt(set.contains(!.Info ^ dp_ignore_vars)),
-        SharedVars0),
+    SharedVars = set.filter(isnt(set.contains(IgnoreVars)), SharedVars0),
 
-    !.Info = dep_par_info(ParProcs0, ModuleInfo0,
-        VarSet0, VarTypes0, IgnoreVars),
-    (if
-        handle_par_conj(ModuleInfo0)
-    then
-        (if
-            set.empty(SharedVars)
-        then
+    ( set.empty(SharedVars) ->
             % Independent parallel conjunctions need no transformation.
             par_conj_list_to_goal(Conjuncts, GoalInfo, NewGoal)
-        else
-            transform_conjunction(SharedVars, Conjuncts, GoalInfo, NewGoal,
-                InstMap, VarSet0, VarSet, VarTypes0, VarTypes,
-                ModuleInfo0, ModuleInfo, ParProcs0, ParProcs),
-            !:Info = dep_par_info(ParProcs, ModuleInfo,
-                VarSet, VarTypes, IgnoreVars)
-        )
-    else
-        % Replace all parallel conjunctions by sequential conjunctions.
-        conj_list_to_goal(Conjuncts, GoalInfo, NewGoal)
+    ;
+        sync_dep_par_conj(ModuleInfo, SharedVars, Conjuncts, GoalInfo, NewGoal,
+            InstMap, VarSet0, VarSet, VarTypes0, VarTypes),
+        !:SyncInfo = sync_info(ModuleInfo, IgnoreVars, VarSet, VarTypes)
     ).
 
     % Transforming the parallel conjunction.
@@ -586,20 +650,19 @@
     %           append(AB_10, A, ABA)
     %       ).
     %
-:- pred transform_conjunction(set(prog_var)::in,
-    hlds_goals::in, hlds_goal_info::in, hlds_goal::out, instmap::in,
-    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
-    module_info::in, module_info::out,
-    par_procs::in, par_procs::out) is det.
+:- pred sync_dep_par_conj(module_info::in, set(prog_var)::in,
+    list(hlds_goal)::in, hlds_goal_info::in, hlds_goal::out, instmap::in,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
 
-transform_conjunction(SharedVars, Goals, GoalInfo, NewGoal, InstMap,
-        !VarSet, !VarTypes, !ModuleInfo, !ParProcs) :-
+sync_dep_par_conj(ModuleInfo, SharedVars, Goals, GoalInfo, NewGoal, InstMap,
+        !VarSet, !VarTypes) :-
     SharedVarsList = set.to_sorted_list(SharedVars),
-    list.map_foldl3(allocate_future(!.ModuleInfo), SharedVarsList,
-        AllocateFutures, !VarTypes, !VarSet, map.init, FutureMap),
-    list.map_foldl5(transform_conjunct(SharedVars, FutureMap),
-        Goals, NewGoals,
-        InstMap, _, !VarSet, !VarTypes, !ModuleInfo, !ParProcs),
+    list.map_foldl3(allocate_future(ModuleInfo), SharedVarsList,
+        AllocateFutures, !VarSet, !VarTypes, map.init, FutureMap),
+    list.map_foldl3(
+        sync_dep_par_conjunct(ModuleInfo, par_conjunct_is_in_conjunction,
+            SharedVars, FutureMap),
+        Goals, NewGoals, InstMap, _, !VarSet, !VarTypes),
 
     LastGoal = hlds_goal(conj(parallel_conj, NewGoals), GoalInfo),
     Conj = AllocateFutures ++ [LastGoal],
@@ -620,50 +683,58 @@
         NewGoal = hlds_goal(scope(Reason, NewGoal0), GoalInfo)
     ).
 
-:- pred allocate_future(module_info::in, prog_var::in, hlds_goal::out,
-    vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
-    future_map::in, future_map::out) is det.
+:- type par_conjunct_status
+    --->    par_conjunct_is_in_conjunction
+    ;       par_conjunct_is_proc_body.
 
-allocate_future(ModuleInfo, SharedVar, AllocGoal,
-        !VarTypes, !VarSet, !FutureMap) :-
-    map.lookup(!.VarTypes, SharedVar, SharedVarType),
-    make_future(ModuleInfo, SharedVarType, SharedVar, !VarTypes, !VarSet,
-        AllocGoal, FutureVar),
-    svmap.det_insert(SharedVar, FutureVar, !FutureMap).
-
-:- pred transform_conjunct(set(prog_var)::in, future_map::in,
+:- pred sync_dep_par_conjunct(module_info::in, par_conjunct_status::in,
+    set(prog_var)::in, future_map::in,
     hlds_goal::in, hlds_goal::out, instmap::in, instmap::out,
-    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
-    module_info::in, module_info::out,
-    par_procs::in, par_procs::out) is det.
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
 
-transform_conjunct(SharedVars, FutureMap, Goal0, Goal, !InstMap,
-        !VarSet, !VarTypes, !ModuleInfo, !ParProcs) :-
-    Nonlocals = goal_get_nonlocals(Goal0),
-    set.intersect(Nonlocals, SharedVars, Intersect),
-    ( set.empty(Intersect) ->
-        Goal = Goal0
+sync_dep_par_conjunct(ModuleInfo, ParConjunctStatus, SharedVars, FutureMap,
+        !Goal, !InstMap, !VarSet, !VarTypes) :-
+    Nonlocals = goal_get_nonlocals(!.Goal),
+    set.intersect(Nonlocals, SharedVars, NonlocalSharedVars),
+    ( set.empty(NonlocalSharedVars) ->
+        true
     ;
-        Goal0 = hlds_goal(_, GoalInfo0),
+        GoalInfo0 = !.Goal ^ hlds_goal_info,
         InstMapDelta0 = goal_info_get_instmap_delta(GoalInfo0),
 
-        % Divide shared variables into those that are produced by this
+        % Divide the shared variables into those that are produced by this
         % conjunct, and those that are consumed by it.
-        IsProducedVar = var_is_bound_in_instmap_delta(!.ModuleInfo,
+        % XXX We should check that the initial instantiation of each variable
+        % in ProducedVars in !.InstMap is free. However, at the moment, there
+        % is nothing useful we can do if it isn't.
+        IsProducedVar = var_is_bound_in_instmap_delta(ModuleInfo,
             !.InstMap, InstMapDelta0),
-        set.divide(IsProducedVar, Intersect, ProducedVars, ConsumedVars),
+        set.divide(IsProducedVar, NonlocalSharedVars,
+            ProducedVars, ConsumedVars),
+        ConsumedVarsList = set.to_sorted_list(ConsumedVars),
+        ProducedVarsList = set.to_sorted_list(ProducedVars),
+
+        % Insert waits into the conjunct, as late as possible.
+        list.foldl3(insert_wait_in_goal(ModuleInfo, FutureMap),
+            ConsumedVarsList, !Goal, !VarSet, !VarTypes),
+
+        % Insert signals into the conjunct, as early as possible.
+        list.foldl3(insert_signal_in_goal(ModuleInfo, FutureMap),
+            ProducedVarsList, !Goal, !VarSet, !VarTypes),
 
-        % Insert waits into the conjunct as deeply as possible.
-        list.foldl3(insert_wait_in_goal(!.ModuleInfo, FutureMap),
-            set.to_sorted_list(ConsumedVars),
-            Goal0, Goal1, !VarSet, !VarTypes),
-
-        % Insert signals into the conjunct as early as possible.
-        list.foldl3(insert_signal_in_goal(!.ModuleInfo, FutureMap),
-            set.to_sorted_list(ProducedVars),
-            Goal1, Goal, !VarSet, !VarTypes)
+        % Each consumer will have its own local name for the consumed variable,
+        % so they can each wait for it when they need to.
+        (
+            ParConjunctStatus = par_conjunct_is_in_conjunction,
+            clone_variables(ConsumedVarsList, !.VarSet, !.VarTypes,
+                !VarSet, !VarTypes, map.init, Renaming),
+            rename_some_vars_in_goal(Renaming, !Goal)
+        ;
+            ParConjunctStatus = par_conjunct_is_proc_body
+            % We don't need to rename anything, XXX.
+        )
     ),
-    update_instmap(Goal, !InstMap).
+    update_instmap(!.Goal, !InstMap).
 
 %-----------------------------------------------------------------------------%
 
@@ -677,7 +748,7 @@
     %     then it could not have been further instantiated within
     %     by the conjunction as a whole.
     %
-    % XXX this code is probably too complicated.  I think Thomas already had a
+    % XXX This code is probably too complicated.  I think Thomas already had a
     % more elegant way to find the shared variables somewhere, using multisets.
     %
 find_shared_variables(ModuleInfo, InstMap, Goals) = SharedVars :-
@@ -707,9 +778,9 @@
         instmap.lookup_var(InstMap, Var, VarInst),
         not inst_is_bound(ModuleInfo, VarInst)
     ),
-    set.filter(Filter, Nonlocals) = UnboundNonlocals,
-    set.filter(changed_var(ModuleInfo, InstMapDeltasB), UnboundNonlocals)
-        = Changed,
+    UnboundNonlocals = set.filter(Filter, Nonlocals),
+    Changed =
+        set.filter(changed_var(ModuleInfo, InstMapDeltasB), UnboundNonlocals),
     set.union(Changed, !SharedVars),
     find_shared_variables_2(ModuleInfo, ConjunctIndex+1, MoreNonlocals,
         InstMap, InstMapDeltas, !SharedVars).
@@ -719,54 +790,60 @@
 
 changed_var(ModuleInfo, InstMapDeltas, UnboundVar) :-
     % Is the unbound nonlocal bound in one of the conjuncts?
-    InstMapDelta `list.member` InstMapDeltas,
+    list.member(InstMapDelta, InstMapDeltas),
     instmap_delta_search_var(InstMapDelta, UnboundVar, Inst),
     inst_is_bound(ModuleInfo, Inst).
 
 %-----------------------------------------------------------------------------%
 
-    % Look for the first instance of the consumed variable down every
-    % computation path.  The first goal referring to the variable needs to
-    % have a wait call inserted right before it.
+    % insert_wait_in_goal(ModuleInfo, FutureMap, ConsumedVar, Goal0, Goal,
+    %   !VarSet, !VarTypes):
     %
-:- pred insert_wait_in_goal(module_info::in, future_map::in, prog_var::in,
-    hlds_goal::in, hlds_goal::out,
-    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
-
-insert_wait_in_goal(ModuleInfo, FutureMap, ConsumedVar,
-        Goal0, Goal, !VarSet, !VarTypes) :-
-    ( var_in_nonlocals(ConsumedVar, Goal0) ->
-        insert_wait_in_goal_2(ModuleInfo, FutureMap, ConsumedVar,
-            Goal0, Goal, !VarSet, !VarTypes)
-    ;
-        Goal = Goal0
-    ).
-
-    % ConsumedVar is nonlocal to Goal0.
+    % Insert a wait on the future version of ConsumedVar *just before*
+    % the first reference to it inside Goal0. If there is no reference to
+    % ConsumedVar inside Goal0, then insert a wait for ConsumedVar at the
+    % end of Goal0 (unless Goal0 cannot succeed, in which case the wait
+    % would never be reached.
+    %
+    % Call this predicate if either (a) Goal0 consumes ConsumedVar, or (b)
+    % some other goal that Goal0 is parallel to consumes ConsumedVar.
+    % (We must ensure that if one branch of a branched goal inserts a wait
+    % for a variable, then *all* branches of that goal insert a wait.)
     %
-:- pred insert_wait_in_goal_2(module_info::in, future_map::in, prog_var::in,
+:- pred insert_wait_in_goal(module_info::in, future_map::in, prog_var::in,
     hlds_goal::in, hlds_goal::out, prog_varset::in, prog_varset::out,
     vartypes::in, vartypes::out) is det.
 
-insert_wait_in_goal_2(ModuleInfo, FutureMap, ConsumedVar,
+insert_wait_in_goal(ModuleInfo, FutureMap, ConsumedVar,
         Goal0, Goal, !VarSet, !VarTypes) :-
+    ( var_in_nonlocals(ConsumedVar, Goal0) ->
     Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
     (
         GoalExpr0 = conj(ConjType, Goals0),
         (
             ConjType = plain_conj,
-            insert_wait_in_conj(ModuleInfo, FutureMap, ConsumedVar,
-                Goals0, Goal, !VarSet, !VarTypes)
+                insert_wait_in_plain_conj(ModuleInfo, FutureMap, ConsumedVar,
+                    have_not_waited_in_conjunct, Waited,
+                    Goals0, Goals, !VarSet, !VarTypes)
         ;
             ConjType = parallel_conj,
-            insert_wait_in_goals(ModuleInfo, FutureMap, ConsumedVar,
-                Goals0, Goals, !VarSet, !VarTypes),
+                insert_wait_in_par_conj(ModuleInfo, FutureMap, ConsumedVar,
+                    have_not_waited_in_conjunct, Waited,
+                    Goals0, Goals, !VarSet, !VarTypes)
+            ),
             GoalExpr = conj(ConjType, Goals),
-            Goal = hlds_goal(GoalExpr, GoalInfo0)
+            Goal1 = hlds_goal(GoalExpr, GoalInfo0),
+            (
+                Waited = waited_in_conjunct,
+                Goal = Goal1
+            ;
+                Waited = have_not_waited_in_conjunct,
+                insert_wait_after_goal(ModuleInfo, FutureMap, ConsumedVar,
+                    Goal1, Goal, !VarSet, !VarTypes)
         )
     ;
         GoalExpr0 = disj(Goals0),
-        insert_wait_in_goals(ModuleInfo, FutureMap, ConsumedVar,
+            insert_wait_in_disj(ModuleInfo, FutureMap, ConsumedVar,
             Goals0, Goals, !VarSet, !VarTypes),
         GoalExpr = disj(Goals),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
@@ -782,43 +859,56 @@
             Goal = hlds_goal(GoalExpr, GoalInfo0)
         )
     ;
-        GoalExpr0 = if_then_else(Quant, If, Then0, Else0),
-        ( var_in_nonlocals(ConsumedVar, If) ->
+            GoalExpr0 = if_then_else(Quant, Cond, Then0, Else0),
+            ( var_in_nonlocals(ConsumedVar, Cond) ->
+                % XXX We could try to wait for the shared variable only when
+                % the condition needs it. This would require also waiting
+                % for the shared variable somewhere in the else branch.
+                % However, the compiler requires that the conditions of
+                % if-then-elses bind no variable that is accessible from
+                % anywhere except the condition and the then-part of that
+                % if-then-else, so we would have to do tricks like renaming
+                % the variable waited-for by the condition, and then assigning
+                % the renamed variable to its original name in the then-part.
             insert_wait_before_goal(ModuleInfo, FutureMap, ConsumedVar,
                 Goal0, Goal, !VarSet, !VarTypes)
         ;
+                % If ConsumedVar is not in the nonlocals of Cond, then it
+                % must be in the nonlocals of at least one of Then0 and Else0.
             insert_wait_in_goal(ModuleInfo, FutureMap, ConsumedVar,
                 Then0, Then, !VarSet, !VarTypes),
             insert_wait_in_goal(ModuleInfo, FutureMap, ConsumedVar,
                 Else0, Else, !VarSet, !VarTypes),
-            GoalExpr = if_then_else(Quant, If, Then, Else),
+                GoalExpr = if_then_else(Quant, Cond, Then, Else),
             Goal = hlds_goal(GoalExpr, GoalInfo0)
         )
     ;
-        GoalExpr0 = negation(SubGoal0),
-        insert_wait_in_goal(ModuleInfo, FutureMap, ConsumedVar,
-            SubGoal0, SubGoal, !VarSet, !VarTypes),
-        GoalExpr = negation(SubGoal),
-        Goal = hlds_goal(GoalExpr, GoalInfo0)
-    ;
         GoalExpr0 = scope(Reason, SubGoal0),
         insert_wait_in_goal(ModuleInfo, FutureMap, ConsumedVar,
             SubGoal0, SubGoal, !VarSet, !VarTypes),
         GoalExpr = scope(Reason, SubGoal),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
-        ( GoalExpr0 = unify(_LHS, _RHS0, _C, _D, _UnifyContext)
-        ; GoalExpr0 = plain_call(_PredId, _ProcId, _Args, _, _, _)
-        ; GoalExpr0 = generic_call(_GenericCall, _Args, _Modes, _Detism)
-        ; GoalExpr0 = call_foreign_proc(_, _PredId, _, _Args, _, _, _)
+            GoalExpr0 = negation(_SubGoal0),
+            % We treat the negated goal just as we treat the condition of
+            % an if-then-else.
+            insert_wait_before_goal(ModuleInfo, FutureMap, ConsumedVar,
+                Goal0, Goal, !VarSet, !VarTypes)
+        ;
+            ( GoalExpr0 = unify(_, _, _, _, _)
+            ; GoalExpr0 = plain_call(_, _, _, _, _, _)
+            ; GoalExpr0 = generic_call(_, _, _, _)
+            ; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _)
         ),
         insert_wait_before_goal(ModuleInfo, FutureMap, ConsumedVar,
             Goal0, Goal, !VarSet, !VarTypes)
     ;
         GoalExpr0 = shorthand(_),
-        unexpected(this_file,
-            "shorthand goal encountered during dependent parallel " ++
-            "conjunction transformation.")
+            unexpected(this_file, "insert_wait_in_goal: shorthand")
+        )
+    ;
+        insert_wait_after_goal(ModuleInfo, FutureMap, ConsumedVar,
+            Goal0, Goal, !VarSet, !VarTypes)
     ).
 
 :- pred insert_wait_before_goal(module_info::in, future_map::in,
@@ -827,39 +917,105 @@
 
 insert_wait_before_goal(ModuleInfo, FutureMap, ConsumedVar,
         Goal0, Goal, !VarSet, !VarTypes) :-
-    FutureVar = map.lookup(FutureMap, ConsumedVar),
+    map.lookup(FutureMap, ConsumedVar, FutureVar),
     make_wait_goal(ModuleInfo, FutureVar, ConsumedVar, WaitGoal),
-    conjoin_goals_update_goal_infos(WaitGoal, Goal0, Goal).
+    conjoin_goals_update_goal_infos(Goal0 ^ hlds_goal_info, WaitGoal, Goal0,
+        Goal).
+
+:- pred insert_wait_after_goal(module_info::in, future_map::in,
+    prog_var::in, hlds_goal::in, hlds_goal::out,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
+
+insert_wait_after_goal(ModuleInfo, FutureMap, ConsumedVar,
+        Goal0, Goal, !VarSet, !VarTypes) :-
+    map.lookup(FutureMap, ConsumedVar, FutureVar),
+    make_wait_goal(ModuleInfo, FutureVar, ConsumedVar, WaitGoal),
+    conjoin_goals_update_goal_infos(Goal0 ^ hlds_goal_info, Goal0, WaitGoal,
+        Goal).
+
+:- type waited_in_conjunct
+    --->    waited_in_conjunct
+    ;       have_not_waited_in_conjunct.
+
+    % Insert a wait for ConsumedVar in the first goal in the conjunction
+    % that references it. Any later conjuncts will get the waited-for variable
+    % without having to call wait.
+    %
+:- pred insert_wait_in_plain_conj(module_info::in, future_map::in,
+    prog_var::in, waited_in_conjunct::in, waited_in_conjunct::out,
+    list(hlds_goal)::in, list(hlds_goal)::out,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
 
-:- pred insert_wait_in_conj(module_info::in, future_map::in, prog_var::in,
-    hlds_goals::in, hlds_goal::out,
+insert_wait_in_plain_conj(_ModuleInfo, _FutureMap, _ConsumedVar, !Waited,
+        [], [], !VarSet, !VarTypes).
+insert_wait_in_plain_conj(ModuleInfo, FutureMap, ConsumedVar, !Waited,
+        [Goal0 | Goals0], Goals, !VarSet, !VarTypes) :-
+    ( var_in_nonlocals(ConsumedVar, Goal0) ->
+        % ConsumedVar appears in Goal0, so wait for it in Goal0. The code
+        % in Goals0 will then be able to access ConsumedVar waiting any further
+        % waiting.
+        insert_wait_in_goal(ModuleInfo, FutureMap, ConsumedVar,
+            Goal0, Goal, !VarSet, !VarTypes),
+        ( Goal ^ hlds_goal_expr = conj(plain_conj, GoalConj) ->
+            Goals = GoalConj ++ Goals0
+        ;
+            Goals = [Goal | Goals0]
+        ),
+        !:Waited = waited_in_conjunct
+    ;
+        % ConsumedVar does not appear in Goal0, so wait for it in Goals0.
+        insert_wait_in_plain_conj(ModuleInfo, FutureMap, ConsumedVar, !Waited,
+            Goals0, Goals1, !VarSet, !VarTypes),
+        Goals = [Goal0 | Goals1]
+    ).
+
+    % Insert a wait for ConsumedVar in the *every* goal in the conjunction
+    % that references it. "Later" conjuncts cannot get the variable that
+    % "earlier" conjuncts waited for, since those waits may not have finished
+    % yet.
+    %
+:- pred insert_wait_in_par_conj(module_info::in, future_map::in, prog_var::in,
+    waited_in_conjunct::in, waited_in_conjunct::out,
+    list(hlds_goal)::in, list(hlds_goal)::out,
     prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
 
-insert_wait_in_conj(_ModuleInfo, _FutureMap, _ConsumedVar,
-        [], true_goal, !VarSet, !VarTypes).
-insert_wait_in_conj(ModuleInfo, FutureMap, ConsumedVar,
-        [Goal0 | Goals0], Goal, !VarSet, !VarTypes) :-
-    (if var_in_nonlocals(ConsumedVar, Goal0) then
+insert_wait_in_par_conj(_ModuleInfo, _FutureMap, _ConsumedVar, !Waited,
+        [], [], !VarSet, !VarTypes).
+insert_wait_in_par_conj(ModuleInfo, FutureMap, ConsumedVar, !Waited,
+        [Goal0 | Goals0], [Goal | Goals], !VarSet, !VarTypes) :-
+    ( var_in_nonlocals(ConsumedVar, Goal0) ->
+        % ConsumedVar appears in Goal0, so wait for it in Goal0, but the code
+        % in Goals0 will *not* be able to access ConsumedVar waiting, since the
+        % conjuncts are executed independently.
         insert_wait_in_goal(ModuleInfo, FutureMap, ConsumedVar,
             Goal0, Goal1, !VarSet, !VarTypes),
-        conjoin_goal_and_goal_list_update_goal_infos(Goal1, Goals0, Goal)
-    else
-        insert_wait_in_conj(ModuleInfo, FutureMap, ConsumedVar,
-            Goals0, Goal1, !VarSet, !VarTypes),
-        conjoin_goals_update_goal_infos(Goal0, Goal1, Goal)
-    ).
+        (
+            !.Waited = have_not_waited_in_conjunct,
+            Goal = Goal1
+        ;
+            !.Waited = waited_in_conjunct,
+            clone_variable(ConsumedVar, !.VarSet, !.VarTypes,
+                !VarSet, !VarTypes, map.init, Renaming, _CloneVar),
+            rename_some_vars_in_goal(Renaming, Goal1, Goal)
+        ),
+        !:Waited = waited_in_conjunct
+    ;
+        Goal = Goal0
+    ),
+    insert_wait_in_par_conj(ModuleInfo, FutureMap, ConsumedVar, !Waited,
+        Goals0, Goals, !VarSet, !VarTypes).
 
-:- pred insert_wait_in_goals(module_info::in, future_map::in, prog_var::in,
-    hlds_goals::in, hlds_goals::out,
+:- pred insert_wait_in_disj(module_info::in, future_map::in, prog_var::in,
+    list(hlds_goal)::in, list(hlds_goal)::out,
     prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
 
-insert_wait_in_goals(_ModuleInfo, _FutureMap, _ConsumedVar,
+insert_wait_in_disj(_ModuleInfo, _FutureMap, _ConsumedVar,
         [], [], !VarSet, !VarTypes).
-insert_wait_in_goals(ModuleInfo, FutureMap, ConsumedVar,
+insert_wait_in_disj(ModuleInfo, FutureMap, ConsumedVar,
         [Goal0 | Goals0], [Goal | Goals], !VarSet, !VarTypes) :-
     insert_wait_in_goal(ModuleInfo, FutureMap, ConsumedVar,
         Goal0, Goal, !VarSet, !VarTypes),
-    insert_wait_in_goals(ModuleInfo, FutureMap, ConsumedVar,
+    insert_wait_in_disj(ModuleInfo, FutureMap, ConsumedVar,
         Goals0, Goals, !VarSet, !VarTypes).
 
 :- pred insert_wait_in_cases(module_info::in, future_map::in, prog_var::in,
@@ -880,8 +1036,8 @@
 %-----------------------------------------------------------------------------%
 
     % Look for the first instance of the produced variable down every
-    % computation path.  The first goal referring to the variable must produce
-    % it, so insert a signal call right after that goal.
+    % branch. The first goal referring to the variable must produce it,
+    % so insert a signal call right after that goal.
     %
 :- pred insert_signal_in_goal(module_info::in, future_map::in, prog_var::in,
     hlds_goal::in, hlds_goal::out,
@@ -889,38 +1045,24 @@
 
 insert_signal_in_goal(ModuleInfo, FutureMap, ProducedVar,
         Goal0, Goal, !VarSet, !VarTypes) :-
-    (if var_in_nonlocals(ProducedVar, Goal0) then
-        insert_signal_in_goal_2(ModuleInfo, FutureMap, ProducedVar,
-            Goal0, Goal, !VarSet, !VarTypes)
-    else
-        Goal = Goal0
-    ).
-
-    % ProducedVar is nonlocal to Goal0.
-    %
-:- pred insert_signal_in_goal_2(module_info::in, future_map::in, prog_var::in,
-    hlds_goal::in, hlds_goal::out, prog_varset::in, prog_varset::out,
-    vartypes::in, vartypes::out) is det.
-
-insert_signal_in_goal_2(ModuleInfo, FutureMap, ProducedVar,
-        Goal0, Goal, !VarSet, !VarTypes) :-
     Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
+    ( var_in_nonlocals(ProducedVar, Goal0) ->
     (
         GoalExpr0 = conj(ConjType, Goals0),
         (
             ConjType = plain_conj,
-            insert_signal_in_conj(ModuleInfo, FutureMap, ProducedVar,
-                Goals0, Goal, !VarSet, !VarTypes)
+                insert_signal_in_plain_conj(ModuleInfo, FutureMap, ProducedVar,
+                    Goals0, Goals, !VarSet, !VarTypes)
         ;
             ConjType = parallel_conj,
-            insert_signal_in_goals(ModuleInfo, FutureMap, ProducedVar,
-                Goals0, Goals, !VarSet, !VarTypes),
+                insert_signal_in_par_conj(ModuleInfo, FutureMap, ProducedVar,
+                    Goals0, Goals, !VarSet, !VarTypes)
+            ),
             GoalExpr = conj(ConjType, Goals),
             Goal = hlds_goal(GoalExpr, GoalInfo0)
-        )
     ;
         GoalExpr0 = disj(Goals0),
-        insert_signal_in_goals(ModuleInfo, FutureMap, ProducedVar,
+            insert_signal_in_disj(ModuleInfo, FutureMap, ProducedVar,
             Goals0, Goals, !VarSet, !VarTypes),
         GoalExpr = disj(Goals),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
@@ -935,20 +1077,18 @@
             Goal = hlds_goal(GoalExpr, GoalInfo0)
         )
     ;
-        GoalExpr0 = if_then_else(Quant, If, Then0, Else0),
-        expect(var_not_in_nonlocals(ProducedVar, If),
+            GoalExpr0 = if_then_else(QuantVars, Cond, Then0, Else0),
+            expect(var_not_in_nonlocals(ProducedVar, Cond),
             this_file, "condition binds shared variable"),
         insert_signal_in_goal(ModuleInfo, FutureMap, ProducedVar,
             Then0, Then, !VarSet, !VarTypes),
         insert_signal_in_goal(ModuleInfo, FutureMap, ProducedVar,
             Else0, Else, !VarSet, !VarTypes),
-        GoalExpr = if_then_else(Quant, If, Then, Else),
+            GoalExpr = if_then_else(QuantVars, Cond, Then, Else),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
-        GoalExpr0 = negation(SubGoal0),
-        expect(var_not_in_nonlocals(ProducedVar, SubGoal0),
-            this_file, "negation binds shared variable"),
-        Goal = Goal0
+            GoalExpr0 = negation(_),
+            unexpected(this_file, "negation binds shared variable")
     ;
         GoalExpr0 = scope(Reason, SubGoal0),
         insert_signal_in_goal(ModuleInfo, FutureMap, ProducedVar,
@@ -956,18 +1096,30 @@
         GoalExpr = scope(Reason, SubGoal),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
-        ( GoalExpr0 = unify(_LHS, _RHS0, _C, _D, _UnifyContext)
-        ; GoalExpr0 = plain_call(_PredId, _ProcId, _Args, _, _, _)
-        ; GoalExpr0 = generic_call(_GenericCall, _Args, _Modes, _Detism)
-        ; GoalExpr0 = call_foreign_proc(_, _PredId, _, _Args, _, _, _)
+            ( GoalExpr0 = unify(_, _, _, _, _)
+            ; GoalExpr0 = plain_call(_, _, _, _, _, _)
+            ; GoalExpr0 = generic_call(_, _, _, _)
+            ; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _)
         ),
         insert_signal_after_goal(ModuleInfo, FutureMap, ProducedVar,
             Goal0, Goal, !VarSet, !VarTypes)
     ;
         GoalExpr0 = shorthand(_),
-        unexpected(this_file,
-            "shorthand goal encountered during dependent parallel " ++
-            "conjunction transformation.")
+            unexpected(this_file, "insert_signal_in_goal: shorthand")
+        )
+    ;
+        % When inserting waits into a goal, it is ok for the goal not to
+        % mention the consumed variable, but when inserting signals into a
+        % goal, the goal must produce the variable if it succeeds, so if
+        % the goal does not mention the variable, it cannot succeed.
+        Detism = goal_info_get_determinism(GoalInfo0),
+        determinism_components(Detism, _CanFail, SolnCount),
+        expect(unify(SolnCount, at_most_zero), this_file,
+            "insert_signal_in_goal: ProducedVar is not in nonlocals"),
+
+        % There would be no point in adding a signal to the end of Goal0,
+        % since execution cannot get their.
+        Goal = Goal0
     ).
 
 :- pred insert_signal_after_goal(module_info::in, future_map::in,
@@ -977,37 +1129,76 @@
 insert_signal_after_goal(ModuleInfo, FutureMap, ProducedVar,
         Goal0, Goal, !VarSet, !VarTypes) :-
     make_signal_goal(ModuleInfo, FutureMap, ProducedVar, SignalGoal),
-    conjoin_goals_update_goal_infos(Goal0, SignalGoal, Goal).
+    conjoin_goals_update_goal_infos(Goal0 ^ hlds_goal_info, Goal0, SignalGoal,
+        Goal).
 
-:- pred insert_signal_in_conj(module_info::in, future_map::in, prog_var::in,
-    hlds_goals::in, hlds_goal::out,
+:- pred insert_signal_in_plain_conj(module_info::in, future_map::in,
+    prog_var::in, list(hlds_goal)::in, list(hlds_goal)::out,
     prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
 
-insert_signal_in_conj(_ModuleInfo, _FutureMap, _ProducedVar,
-        [], true_goal, !VarSet, !VarTypes).
-insert_signal_in_conj(ModuleInfo, FutureMap, ProducedVar,
-        [Goal0 | Goals0], Goal, !VarSet, !VarTypes) :-
-    (if var_in_nonlocals(ProducedVar, Goal0) then
+insert_signal_in_plain_conj(_ModuleInfo, _FutureMap, _ProducedVar,
+        [], [], !VarSet, !VarTypes).
+insert_signal_in_plain_conj(ModuleInfo, FutureMap, ProducedVar,
+        [Goal0 | Goals0], Goals, !VarSet, !VarTypes) :-
+    ( var_in_nonlocals(ProducedVar, Goal0) ->
+        % The first conjunct that mentions ProducedVar should bind ProducedVar.
+        % Since we don't recurse in this case, we get here only for the first
+        % conjunct.
+        Goal0 = hlds_goal(_, GoalInfo0),
+        InstMapDelta = goal_info_get_instmap_delta(GoalInfo0),
+        instmap_delta_changed_vars(InstMapDelta, ChangedVars),
+        expect(set.contains(ChangedVars, ProducedVar), this_file,
+            "insert_signal_in_plain_conj: ProducedVar not in ChangedVars"),
         insert_signal_in_goal(ModuleInfo, FutureMap, ProducedVar,
             Goal0, Goal1, !VarSet, !VarTypes),
-        conjoin_goal_and_goal_list_update_goal_infos(Goal1, Goals0, Goal)
-    else
-        insert_signal_in_conj(ModuleInfo, FutureMap, ProducedVar,
-            Goals0, Goal1, !VarSet, !VarTypes),
-        conjoin_goals_update_goal_infos(Goal0, Goal1, Goal)
+        ( Goal1 ^ hlds_goal_expr = conj(plain_conj, GoalConjs1) ->
+            Goals = GoalConjs1 ++ Goals0
+        ;
+            Goals = [Goal1 | Goals0]
+        )
+    ;
+        insert_signal_in_plain_conj(ModuleInfo, FutureMap, ProducedVar,
+            Goals0, Goals1, !VarSet, !VarTypes),
+        Goals = [Goal0 | Goals1]
     ).
 
-:- pred insert_signal_in_goals(module_info::in, future_map::in, prog_var::in,
-    hlds_goals::in, hlds_goals::out,
+:- pred insert_signal_in_par_conj(module_info::in, future_map::in, prog_var::in,
+    list(hlds_goal)::in, list(hlds_goal)::out,
     prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
 
-insert_signal_in_goals(_ModuleInfo, _FutureMap, _ProducedVar,
+insert_signal_in_par_conj(_ModuleInfo, _FutureMap, _ProducedVar,
         [], [], !VarSet, !VarTypes).
-insert_signal_in_goals(ModuleInfo, FutureMap, ProducedVar,
+insert_signal_in_par_conj(ModuleInfo, FutureMap, ProducedVar,
+        [Goal0 | Goals0], [Goal | Goals], !VarSet, !VarTypes) :-
+    ( var_in_nonlocals(ProducedVar, Goal0) ->
+        % The first conjunct that mentions ProducedVar should bind ProducedVar.
+        % Since we don't recurse in this case, we get here only for the first
+        % conjunct.
+        Goal0 = hlds_goal(_, GoalInfo0),
+        InstMapDelta = goal_info_get_instmap_delta(GoalInfo0),
+        instmap_delta_changed_vars(InstMapDelta, ChangedVars),
+        expect(set.contains(ChangedVars, ProducedVar), this_file,
+            "insert_signal_in_plain_conj: ProducedVar not in ChangedVars"),
+        insert_signal_in_goal(ModuleInfo, FutureMap, ProducedVar,
+            Goal0, Goal, !VarSet, !VarTypes),
+        Goals = Goals0
+    ;
+        Goal = Goal0,
+        insert_signal_in_par_conj(ModuleInfo, FutureMap, ProducedVar,
+            Goals0, Goals, !VarSet, !VarTypes)
+    ).
+
+:- pred insert_signal_in_disj(module_info::in, future_map::in, prog_var::in,
+    list(hlds_goal)::in, list(hlds_goal)::out,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
+
+insert_signal_in_disj(_ModuleInfo, _FutureMap, _ProducedVar,
+        [], [], !VarSet, !VarTypes).
+insert_signal_in_disj(ModuleInfo, FutureMap, ProducedVar,
         [Goal0 | Goals0], [Goal | Goals], !VarSet, !VarTypes) :-
     insert_signal_in_goal(ModuleInfo, FutureMap, ProducedVar,
         Goal0, Goal, !VarSet, !VarTypes),
-    insert_signal_in_goals(ModuleInfo, FutureMap, ProducedVar,
+    insert_signal_in_disj(ModuleInfo, FutureMap, ProducedVar,
         Goals0, Goals, !VarSet, !VarTypes).
 
 :- pred insert_signal_in_cases(module_info::in, future_map::in, prog_var::in,
@@ -1043,78 +1234,79 @@
     % call to a parallelised procedure P'.  Queue P' to be created later,
     % if it has not been created already.
     %
-:- pred replace_sequences_in_goal(hlds_goal::in, hlds_goal::out,
-    dep_par_info::in, dep_par_info::out) is det.
+:- pred specialize_sequences_in_goal(hlds_goal::in, hlds_goal::out,
+    spec_info::in, spec_info::out) is det.
 
-replace_sequences_in_goal(Goal0, Goal, !Info) :-
+specialize_sequences_in_goal(Goal0, Goal, !SpecInfo) :-
     Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
     (
         GoalExpr0 = conj(ConjType, Goals0),
         (
             ConjType = plain_conj,
-            replace_sequences_in_conj(Goals0, Goals, !Info),
+            specialize_sequences_in_conj(Goals0, Goals, !SpecInfo),
             conj_list_to_goal(Goals, GoalInfo0, Goal)
         ;
             ConjType = parallel_conj,
-            replace_sequences_in_goals(Goals0, Goals, !Info),
+            specialize_sequences_in_goals(Goals0, Goals, !SpecInfo),
             GoalExpr = conj(ConjType, Goals),
             Goal = hlds_goal(GoalExpr, GoalInfo0)
         )
     ;
         GoalExpr0 = disj(Goals0),
-        replace_sequences_in_goals(Goals0, Goals, !Info),
+        specialize_sequences_in_goals(Goals0, Goals, !SpecInfo),
         GoalExpr = disj(Goals),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
         GoalExpr0 = switch(SwitchVar, CanFail, Cases0),
-        replace_sequences_in_cases(Cases0, Cases, !Info),
+        specialize_sequences_in_cases(Cases0, Cases, !SpecInfo),
         GoalExpr = switch(SwitchVar, CanFail, Cases),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
-        GoalExpr0 = if_then_else(Quant, If0, Then0, Else0),
-        replace_sequences_in_goal(If0, If, !Info),
-        replace_sequences_in_goal(Then0, Then, !Info),
-        replace_sequences_in_goal(Else0, Else, !Info),
-        GoalExpr = if_then_else(Quant, If, Then, Else),
+        GoalExpr0 = if_then_else(Quant, Cond0, Then0, Else0),
+        specialize_sequences_in_goal(Cond0, Cond, !SpecInfo),
+        specialize_sequences_in_goal(Then0, Then, !SpecInfo),
+        specialize_sequences_in_goal(Else0, Else, !SpecInfo),
+        GoalExpr = if_then_else(Quant, Cond, Then, Else),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
         GoalExpr0 = negation(SubGoal0),
-        replace_sequences_in_goal(SubGoal0, SubGoal, !Info),
+        specialize_sequences_in_goal(SubGoal0, SubGoal, !SpecInfo),
         GoalExpr = negation(SubGoal),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
         GoalExpr0 = scope(Reason, SubGoal0),
-        replace_sequences_in_goal(SubGoal0, SubGoal, !Info),
+        specialize_sequences_in_goal(SubGoal0, SubGoal, !SpecInfo),
         GoalExpr = scope(Reason, SubGoal),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
     ;
-        ( GoalExpr0 = unify(_LHS, _RHS0, _C, _D, _UnifyContext)
-        ; GoalExpr0 = plain_call(_PredId, _ProcId, _Args, _, _, _)
-        ; GoalExpr0 = generic_call(_GenericCall, _Args, _Modes, _Detism)
+        ( GoalExpr0 = unify(_, _, _, _, _)
+        ; GoalExpr0 = plain_call(_, _, _, _, _, _)
+        ; GoalExpr0 = generic_call(_, _, _, _)
         ; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _)
         ),
         Goal = Goal0
     ;
         GoalExpr0 = shorthand(_),
-        unexpected(this_file,
-            "shorthand goal encountered during dependent parallel " ++
-            "conjunction transformation.")
+        unexpected(this_file, "shorthand")
     ).
 
-:- pred replace_sequences_in_conj(hlds_goals::in, hlds_goals::out,
-    dep_par_info::in, dep_par_info::out) is det.
+:- pred specialize_sequences_in_conj(list(hlds_goal)::in, list(hlds_goal)::out,
+    spec_info::in, spec_info::out) is det.
 
-replace_sequences_in_conj(Goals0, Goals, !Info) :-
-    % For each call goal, look backwards for as many wait calls
-    % as possible and forward for as many signal calls as possible.
-    % To look backwards maintain a stack of the preceding goals.
-    replace_sequences_in_conj_2([], Goals0, Goals, !Info).
+specialize_sequences_in_conj(Goals0, Goals, !SpecInfo) :-
+    % For each call goal, look backwards for as many wait calls as possible
+    % and forward for as many signal calls as possible. To allow us to look
+    % backwards, we maintain a stack of the preceding goals.
+    specialize_sequences_in_conj_2([], Goals0, Goals, !SpecInfo).
 
-:- pred replace_sequences_in_conj_2(hlds_goals::in, hlds_goals::in,
-    hlds_goals::out, dep_par_info::in, dep_par_info::out) is det.
+:- pred specialize_sequences_in_conj_2(list(hlds_goal)::in,
+    list(hlds_goal)::in, list(hlds_goal)::out, spec_info::in, spec_info::out)
+    is det.
 
-replace_sequences_in_conj_2(RevGoals, [], reverse(RevGoals), !Info).
-replace_sequences_in_conj_2(RevGoals0, [Goal0 | Goals0], Goals, !Info) :-
+specialize_sequences_in_conj_2(RevGoals, [], list.reverse(RevGoals),
+        !SpecInfo).
+specialize_sequences_in_conj_2(RevGoals0, [Goal0 | Goals0], Goals,
+        !SpecInfo) :-
     Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
     (
         GoalExpr0 = plain_call(_, _, _, _, _, _),
@@ -1122,31 +1314,32 @@
         not is_signal_goal(Goal0)
     ->
         CallGoal0 = hlds_goal(GoalExpr0, GoalInfo0),  % dumb mode system
-        maybe_replace_call(RevGoals0, CallGoal0, Goals0, RevGoals1, Goals1,
-            !Info),
-        replace_sequences_in_conj_2(RevGoals1, Goals1, Goals, !Info)
+        maybe_specialize_call_and_goals(RevGoals0, CallGoal0, Goals0,
+            RevGoals1, Goals1, !SpecInfo),
+        specialize_sequences_in_conj_2(RevGoals1, Goals1, Goals, !SpecInfo)
     ;
-        replace_sequences_in_goal(Goal0, Goal, !Info),
-        replace_sequences_in_conj_2([Goal | RevGoals0], Goals0, Goals, !Info)
+        specialize_sequences_in_goal(Goal0, Goal, !SpecInfo),
+        specialize_sequences_in_conj_2([Goal | RevGoals0], Goals0, Goals,
+            !SpecInfo)
     ).
 
-:- pred replace_sequences_in_goals(hlds_goals::in, hlds_goals::out,
-    dep_par_info::in, dep_par_info::out) is det.
+:- pred specialize_sequences_in_goals(list(hlds_goal)::in, list(hlds_goal)::out,
+    spec_info::in, spec_info::out) is det.
 
-replace_sequences_in_goals([], [], !Info).
-replace_sequences_in_goals([Goal0 | Goals0], [Goal | Goals], !Info) :-
-    replace_sequences_in_goal(Goal0, Goal, !Info),
-    replace_sequences_in_goals(Goals0, Goals, !Info).
+specialize_sequences_in_goals([], [], !SpecInfo).
+specialize_sequences_in_goals([Goal0 | Goals0], [Goal | Goals], !SpecInfo) :-
+    specialize_sequences_in_goal(Goal0, Goal, !SpecInfo),
+    specialize_sequences_in_goals(Goals0, Goals, !SpecInfo).
 
-:- pred replace_sequences_in_cases(list(case)::in, list(case)::out,
-    dep_par_info::in, dep_par_info::out) is det.
+:- pred specialize_sequences_in_cases(list(case)::in, list(case)::out,
+    spec_info::in, spec_info::out) is det.
 
-replace_sequences_in_cases([], [], !Info).
-replace_sequences_in_cases([Case0 | Cases0], [Case | Cases], !Info) :-
+specialize_sequences_in_cases([], [], !SpecInfo).
+specialize_sequences_in_cases([Case0 | Cases0], [Case | Cases], !SpecInfo) :-
     Case0 = case(MainConsId, OtherConsIds, Goal0),
-    replace_sequences_in_goal(Goal0, Goal, !Info),
+    specialize_sequences_in_goal(Goal0, Goal, !SpecInfo),
     Case = case(MainConsId, OtherConsIds, Goal),
-    replace_sequences_in_cases(Cases0, Cases, !Info).
+    specialize_sequences_in_cases(Cases0, Cases, !SpecInfo).
 
 :- inst call_goal_expr
     ==  bound(plain_call(ground, ground, ground, ground, ground, ground)).
@@ -1154,15 +1347,17 @@
 :- inst call_goal
     ==  bound(hlds_goal(call_goal_expr, ground)).
 
-:- pred maybe_replace_call(hlds_goals::in, hlds_goal::in(call_goal),
-    hlds_goals::in, hlds_goals::out, hlds_goals::out,
-    dep_par_info::in, dep_par_info::out) is det.
+:- pred maybe_specialize_call_and_goals(list(hlds_goal)::in,
+    hlds_goal::in(call_goal), list(hlds_goal)::in,
+    list(hlds_goal)::out, list(hlds_goal)::out,
+    spec_info::in, spec_info::out) is det.
 
-maybe_replace_call(RevGoals0, Goal0, FwdGoals0, RevGoals, FwdGoals, !Info) :-
+maybe_specialize_call_and_goals(RevGoals0, Goal0, FwdGoals0,
+        RevGoals, FwdGoals, !SpecInfo) :-
     Goal0 = hlds_goal(GoalExpr0, _),
     GoalExpr0 = plain_call(PredId, ProcId, CallVars, _, _, _),
 
-    module_info_pred_info(!.Info ^ dp_module_info, PredId, PredInfo),
+    module_info_pred_info(!.SpecInfo ^ spec_module_info, PredId, PredInfo),
     ( list.member(ProcId, pred_info_non_imported_procids(PredInfo)) ->
         % RevGoals0 = WaitGoals1   ++ RevGoals1
         % FwdGoals0 = SignalGoals1 ++ FwdGoals1
@@ -1170,9 +1365,8 @@
         list.takewhile(is_wait_goal,   RevGoals0, WaitGoals1,   RevGoals1),
         list.takewhile(is_signal_goal, FwdGoals0, SignalGoals1, FwdGoals1),
 
-        % Filter out relevant and irrelevant wait and signal goals
-        % i.e. wait and signal goals for variables that appear as call
-        % arguments or not.
+        % Partition the wait and signal goals into those that are relevant
+        % (i.e. they mention arguments of the call) and those that are not.
         %
         list.filter_map(relevant_wait_goal(CallVars), WaitGoals1,
             WaitPairs, IrrelevantWaitGoals),
@@ -1186,7 +1380,8 @@
             RevGoals = [Goal0 | RevGoals0],
             FwdGoals = FwdGoals0
         ;
-            replace_call(WaitPairs, SignalPairs, Goal0, Goal, !Info),
+            specialize_dep_par_call(WaitPairs, SignalPairs, Goal0, Goal,
+                !SpecInfo),
 
             % After the replaced call may be further references to a signalled
             % or waited variable.  Add `get' goals after the transformed goal
@@ -1196,7 +1391,7 @@
             % XXX the simplify pass that comes later doesn't always remove
             %     these calls even if they're unnecessary
             %
-            list.map(make_get_goal(!.Info ^ dp_module_info),
+            list.map(make_get_goal(!.SpecInfo ^ spec_module_info),
                 SignalPairs ++ WaitPairs, GetGoals),
 
             RevGoals = GetGoals ++ [Goal] ++ IrrelevantWaitGoals ++ RevGoals1,
@@ -1231,11 +1426,12 @@
     GoalExpr = plain_call(_, _, [Future, SignalVar], _, _, _),
     list.member(SignalVar, CallVars).
 
-:- pred replace_call(list(future_var_pair)::in, list(future_var_pair)::in,
+:- pred specialize_dep_par_call(
+    list(future_var_pair)::in, list(future_var_pair)::in,
     hlds_goal::in(call_goal), hlds_goal::out,
-    dep_par_info::in, dep_par_info::out) is det.
+    spec_info::in, spec_info::out) is det.
 
-replace_call(WaitPairs, SignalPairs, Goal0, Goal, !Info) :-
+specialize_dep_par_call(WaitPairs, SignalPairs, Goal0, Goal, !SpecInfo) :-
     Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
     GoalExpr0 = plain_call(PredId, ProcId, CallVars, _Builtin, Context, _Name),
     OrigPPId = proc(PredId, ProcId),
@@ -1246,53 +1442,53 @@
 
     CallPattern = par_proc_call_pattern(OrigPPId, FutureArgs),
     (
-        find_par_proc_for_call_pattern(!.Info ^ dp_par_procs,
-            CallPattern, ParProc)
+        find_spec_par_proc_for_call_pattern(!.SpecInfo ^ spec_done_procs,
+            !.SpecInfo ^ spec_pending_procs, CallPattern, SpecNewParProc)
     ->
-        ParProc = new_par_proc(ParPPId, ParName)
+        SpecNewParProc = new_par_proc(SpecPPId, SpecSymName)
     ;
-        % Queue a new parallel procedure to be made.
-        !.Info = dep_par_info(ParProcs0, ModuleInfo0,
-            VarSet, VarTypes, IgnoreVars),
-
-        create_new_pred(FutureArgs, OrigPPId, ParPPId, NewName,
+        % Queue a new parallel procedure to be made. We add the new specialized
+        % predicate and procedure to the module_info now; its final body
+        % will be set later.
+        ModuleInfo0 = !.SpecInfo ^ spec_module_info,
+        PendingParProcs0 = !.SpecInfo ^ spec_pending_procs,
+        create_new_spec_parallel_pred(FutureArgs, OrigPPId, SpecPPId, SpecName,
             ModuleInfo0, ModuleInfo),
         module_info_get_name(ModuleInfo, ModuleName),
-        ParName = qualified(ModuleName, NewName),
-        queue_par_proc(CallPattern, new_par_proc(ParPPId, ParName),
-            ParProcs0, ParProcs),
-
-        !:Info = dep_par_info(ParProcs, ModuleInfo,
-            VarSet, VarTypes, IgnoreVars)
+        SpecSymName = qualified(ModuleName, SpecName),
+        queue_par_proc(CallPattern, new_par_proc(SpecPPId, SpecSymName),
+            PendingParProcs0, PendingParProcs),
+        !SpecInfo ^ spec_module_info := ModuleInfo,
+        !SpecInfo ^ spec_pending_procs := PendingParProcs
     ),
 
     % Replace the call with a call to the parallelised procedure.
-    ParPPId = proc(ParPredId, ParProcId),
     list.map(replace_args_with_futures(WaitPairs ++ SignalPairs),
         CallVars, NewCallVars),
-    GoalExpr = plain_call(ParPredId, ParProcId, NewCallVars, not_builtin,
-        Context, ParName),
+    SpecPPId = proc(SpecPredId, SpecProcId),
+    GoalExpr = plain_call(SpecPredId, SpecProcId, NewCallVars, not_builtin,
+        Context, SpecSymName),
     Goal = hlds_goal(GoalExpr, GoalInfo0).
 
-:- pred find_par_proc_for_call_pattern(par_procs::in,
-    par_proc_call_pattern::in, new_par_proc::out) is semidet.
-
-find_par_proc_for_call_pattern(par_procs(DoneParProcs, PendingProcs),
-        CallPattern, NewProc) :-
-    ( search(DoneParProcs, CallPattern, NewProc0) ->
-        NewProc = NewProc0
-    ; search(PendingProcs, CallPattern, NewProc0) ->
-        NewProc = NewProc0
+:- pred find_spec_par_proc_for_call_pattern(done_par_procs::in,
+    pending_par_procs::in, par_proc_call_pattern::in,
+    new_par_proc::out) is semidet.
+
+find_spec_par_proc_for_call_pattern(DoneParProcs, PendingProcs, CallPattern,
+        SpecProc) :-
+    ( search(DoneParProcs, CallPattern, SpecProcPrime) ->
+        SpecProc = SpecProcPrime
+    ; search(PendingProcs, CallPattern, SpecProcPrime) ->
+        SpecProc = SpecProcPrime
     ;
         fail
     ).
 
 :- pred queue_par_proc(par_proc_call_pattern::in, new_par_proc::in,
-    par_procs::in, par_procs::out) is det.
+    pending_par_procs::in, pending_par_procs::out) is det.
 
-queue_par_proc(CallPattern, NewProc,
-        par_procs(Done, Pending),
-        par_procs(Done, [CallPattern - NewProc | Pending])).
+queue_par_proc(CallPattern, NewProc, !PendingParProcs) :-
+    !:PendingParProcs = [CallPattern - NewProc | !.PendingParProcs].
 
 :- pred replace_args_with_futures(list(future_var_pair)::in,
     prog_var::in, prog_var::out) is det.
@@ -1311,30 +1507,28 @@
 
 number_future_args(_, [], _, RevAcc, reverse(RevAcc)).
 number_future_args(ArgNo, [Arg | Args], WaitSignalVars, !RevAcc) :-
-    ( Arg `list.member` WaitSignalVars ->
+    ( list.member(Arg, WaitSignalVars) ->
         list.cons(ArgNo, !RevAcc)
     ;
         true
     ),
     number_future_args(ArgNo+1, Args, WaitSignalVars, !RevAcc).
 
-:- pred create_new_pred(list(arg_pos)::in, pred_proc_id::in,
-    pred_proc_id::out, string::out, module_info::in, module_info::out)
-    is det.
+:- pred create_new_spec_parallel_pred(list(arg_pos)::in, pred_proc_id::in,
+    pred_proc_id::out, string::out, module_info::in, module_info::out) is det.
 
-create_new_pred(FutureArgs, OrigPPId, proc(NewPredId, ProcId), NewPredName,
-        !ModuleInfo) :-
-    OrigPPId = proc(_, ProcId),
+create_new_spec_parallel_pred(FutureArgs, OrigPPId, NewPPId,
+        NewPredName, !ModuleInfo) :-
     module_info_pred_proc_info(!.ModuleInfo, OrigPPId,
         OrigPredInfo, OrigProcInfo),
-
     Status = status_local,
-    make_new_pred_info(FutureArgs, Status, OrigPPId, OrigPredInfo,
-        NewPredInfo0),
+    make_new_spec_parallel_pred_info(FutureArgs, Status, OrigPPId,
+        OrigPredInfo, NewPredInfo0),
     NewPredName = pred_info_name(NewPredInfo0),
 
     % Assign the old procedure to a new predicate, which will be modified
     % in a later pass.
+    OrigPPId = proc(_, ProcId),
     pred_info_get_procedures(NewPredInfo0, NewProcs0),
     map.set(NewProcs0, ProcId, OrigProcInfo, NewProcs),
     pred_info_set_procedures(NewProcs, NewPredInfo0, NewPredInfo),
@@ -1342,14 +1536,16 @@
     % Add the new predicate to the pred table.
     module_info_get_predicate_table(!.ModuleInfo, PredTable0),
     predicate_table_insert(NewPredInfo, NewPredId, PredTable0, PredTable),
-    module_info_set_predicate_table(PredTable, !ModuleInfo).
+    module_info_set_predicate_table(PredTable, !ModuleInfo),
+    NewPPId = proc(NewPredId, ProcId).
 
     % The comments in this predicate are from unused_args.m
     %
-:- pred make_new_pred_info(list(arg_pos)::in, import_status::in,
+:- pred make_new_spec_parallel_pred_info(list(arg_pos)::in, import_status::in,
     pred_proc_id::in, pred_info::in, pred_info::out) is det.
 
-make_new_pred_info(FutureArgs, Status, proc(PredId, ProcId), !PredInfo) :-
+make_new_spec_parallel_pred_info(FutureArgs, Status, PPId, !PredInfo) :-
+    PPId = proc(PredId, ProcId),
     PredModule = pred_info_module(!.PredInfo),
     Name0 = pred_info_name(!.PredInfo),
     PredOrFunc = pred_info_is_pred_or_func(!.PredInfo),
@@ -1396,187 +1592,39 @@
 futurise_argtypes(_, [], ArgTypes, ArgTypes).
 futurise_argtypes(ArgNo, [FutureArg | FutureArgs], [ArgType0 | ArgTypes0],
         [ArgType | ArgTypes]) :-
-    (if ArgNo = FutureArg then
+    ( ArgNo = FutureArg ->
         construct_future_type(ArgType0, ArgType),
         futurise_argtypes(ArgNo+1, FutureArgs,
             ArgTypes0, ArgTypes)
-    else
+    ;
         ArgType = ArgType0,
         futurise_argtypes(ArgNo+1, [FutureArg | FutureArgs],
             ArgTypes0, ArgTypes)
     ).
-futurise_argtypes(_, [_|_], [], _) :-
+futurise_argtypes(_, [_ | _], [], _) :-
     unexpected(this_file,
         "futurise_argtypes: more future arguments than argument types").
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
-
-    % Rename apart variables so that parallel conjuncts do not share
-    % the names of any variables except for futures.
-    % In exactly one conjunct the name of a shared variable is left
-    % unchanged, so that code following the parallel conjunction
-    % can refer to the old name.
-    %
-    % We do this as a separate pass to keep the code introducing futures,
-    % waits and signals simpler.  Also that pass works inside out, whereas
-    % this pass works from the outside in.
-    %
-:- pred rename_apart_in_goal(module_info::in,
-    hlds_goal::in, hlds_goal::out, instmap::in,
-    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
-
-rename_apart_in_goal(ModuleInfo, Goal0, Goal, InstMap,
-        !VarSet, !VarTypes) :-
-    Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
-    (
-        GoalExpr0 = conj(ConjType, Goals0),
-        (
-            ConjType = plain_conj,
-            rename_apart_in_conj(ModuleInfo, Goals0, Goals, InstMap,
-                !VarSet, !VarTypes)
-        ;
-            ConjType = parallel_conj,
-
-            % Get nonlocal variables which are not futures.
-            SharedVars0 = find_shared_variables(ModuleInfo, InstMap, Goals0),
-            NonFutureVar = (pred(Var::in) is semidet :-
-                map.lookup(!.VarTypes, Var, Type),
-                not is_future_type(Type)
-            ),
-            SharedVars = set.filter(NonFutureVar, SharedVars0),
-
-            list.map_foldl3(rename_apart_in_par_conjunct(SharedVars),
-                Goals0, Goals1,
-                SharedVars, _, !VarSet, !VarTypes),
-            rename_apart_in_goals(ModuleInfo,
-                Goals1, Goals, InstMap, !VarSet, !VarTypes)
-        ),
-        GoalExpr = conj(ConjType, Goals),
-        Goal = hlds_goal(GoalExpr, GoalInfo0)
-    ;
-        GoalExpr0 = disj(Goals0),
-        rename_apart_in_goals(ModuleInfo,
-            Goals0, Goals, InstMap, !VarSet, !VarTypes),
-        GoalExpr = disj(Goals),
-        Goal = hlds_goal(GoalExpr, GoalInfo0)
-    ;
-        GoalExpr0 = switch(SwitchVar, CanFail, Cases0),
-        rename_apart_in_cases(ModuleInfo,
-            Cases0, Cases, InstMap, !VarSet, !VarTypes),
-        GoalExpr = switch(SwitchVar, CanFail, Cases),
-        Goal = hlds_goal(GoalExpr, GoalInfo0)
-    ;
-        GoalExpr0 = if_then_else(Quant, If0, Then0, Else0),
-        rename_apart_in_goal(ModuleInfo,
-            If0, If, InstMap, !VarSet, !VarTypes),
-        rename_apart_in_goal(ModuleInfo,
-            Then0, Then, InstMap, !VarSet, !VarTypes),
-        rename_apart_in_goal(ModuleInfo,
-            Else0, Else, InstMap, !VarSet, !VarTypes),
-        GoalExpr = if_then_else(Quant, If, Then, Else),
-        Goal = hlds_goal(GoalExpr, GoalInfo0)
-    ;
-        GoalExpr0 = negation(SubGoal0),
-        rename_apart_in_goal(ModuleInfo,
-            SubGoal0, SubGoal, InstMap, !VarSet, !VarTypes),
-        GoalExpr = negation(SubGoal),
-        Goal = hlds_goal(GoalExpr, GoalInfo0)
-    ;
-        GoalExpr0 = scope(Reason, SubGoal0),
-        rename_apart_in_goal(ModuleInfo,
-            SubGoal0, SubGoal, InstMap, !VarSet, !VarTypes),
-        GoalExpr = scope(Reason, SubGoal),
-        Goal = hlds_goal(GoalExpr, GoalInfo0)
-    ;
-        ( GoalExpr0 = unify(_LHS, _RHS0, _C, _D, _UnifyContext)
-        ; GoalExpr0 = plain_call(_, _, _, _, _, _)
-        ; GoalExpr0 = generic_call(_, _, _, _)
-        ; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _)
-        ; GoalExpr0 = shorthand(_)
-        ),
-        Goal = Goal0
-    ).
-
-:- pred rename_apart_in_conj(module_info::in,
-    hlds_goals::in, hlds_goals::out, instmap::in,
-    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
-
-rename_apart_in_conj(_ModuleInfo,
-        [], [], _InstMap, !VarSet, !VarTypes).
-rename_apart_in_conj(ModuleInfo,
-        [Goal0 | Goals0], [Goal | Goals], InstMap0, !VarSet, !VarTypes) :-
-    rename_apart_in_goal(ModuleInfo,
-        Goal0, Goal, InstMap0, !VarSet, !VarTypes),
-    update_instmap(Goal, InstMap0, InstMap),
-    rename_apart_in_conj(ModuleInfo,
-        Goals0, Goals, InstMap, !VarSet, !VarTypes).
-
-:- pred rename_apart_in_goals(module_info::in,
-    hlds_goals::in, hlds_goals::out, instmap::in,
-    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
-
-rename_apart_in_goals(_ModuleInfo,
-        [], [], _InstMap, !VarSet, !VarTypes).
-rename_apart_in_goals(ModuleInfo,
-        [Goal0 | Goals0], [Goal | Goals], InstMap0, !VarSet, !VarTypes) :-
-    rename_apart_in_goal(ModuleInfo,
-        Goal0, Goal, InstMap0, !VarSet, !VarTypes),
-    rename_apart_in_goals(ModuleInfo,
-        Goals0, Goals, InstMap0, !VarSet, !VarTypes).
-
-:- pred rename_apart_in_cases(module_info::in,
-    list(case)::in, list(case)::out, instmap::in,
-    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
-
-rename_apart_in_cases(_ModuleInfo,
-        [], [], _InstMap0, !VarSet, !VarTypes).
-rename_apart_in_cases(ModuleInfo,
-        [Case0 | Cases0], [Case | Cases], InstMap0, !VarSet, !VarTypes) :-
-    Case0 = case(MainConsId, OtherConsIds, Goal0),
-    rename_apart_in_goal(ModuleInfo,
-        Goal0, Goal, InstMap0, !VarSet, !VarTypes),
-    Case = case(MainConsId, OtherConsIds, Goal),
-    rename_apart_in_cases(ModuleInfo,
-        Cases0, Cases, InstMap0, !VarSet, !VarTypes).
-
-:- pred rename_apart_in_par_conjunct(set(prog_var)::in,
-    hlds_goal::in, hlds_goal::out, set(prog_var)::in, set(prog_var)::out,
-    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
-
-rename_apart_in_par_conjunct(AllNonLocals, Goal0, Goal,
-        DontRename0, DontRename, !VarSet, !VarTypes) :-
-    free_goal_vars(Goal0) = GoalVars,
-    set.intersect(GoalVars, AllNonLocals, Intersect),
-
-    set.difference(Intersect, DontRename0) = DoRename,
-    set.difference(DontRename0, Intersect) = DontRename,
-
-    create_variables(set.to_sorted_list(DoRename),
-        !.VarSet, !.VarTypes, !VarSet, !VarTypes, map.init, Renaming),
-    rename_some_vars_in_goal(Renaming, Goal0, Goal).
-
-%-----------------------------------------------------------------------------%
-%-----------------------------------------------------------------------------%
 %
 % Utilities for working with par_builtin.
 %
 
     % Given a variable SharedVar of type SharedVarType, add a new variable
-    % FutureVar of type future(SharedVarType).
-    % Also make a goal AllocGoal that calls `par_builtin.new_future/1' to
-    % allocate FutureVar.
+    % FutureVar of type future(SharedVarType), add the mapping from SharedVar
+    % to FutureVar to FutureMap, and generate the goal AllocGoal that calls
+    % `par_builtin.new_future/1' to allocate FutureVar.
     %
-:- pred make_future(module_info::in, mer_type::in, prog_var::in, vartypes::in,
-    vartypes::out, prog_varset::in, prog_varset::out, hlds_goal::out,
-    prog_var::out) is det.
+:- pred allocate_future(module_info::in, prog_var::in, hlds_goal::out,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
+    future_map::in, future_map::out) is det.
 
-make_future(ModuleInfo, SharedVarType, SharedVar, !VarTypes, !VarSet,
-        AllocGoal, FutureVar) :-
-    construct_future_type(SharedVarType, FutureType),
-    varset.lookup_name(!.VarSet, SharedVar, SharedVarName),
-    svvarset.new_named_var("Future" ++ SharedVarName, FutureVar, !VarSet),
-    svmap.det_insert(FutureVar, FutureType, !VarTypes),
+allocate_future(ModuleInfo, SharedVar, AllocGoal, !VarSet, !VarTypes,
+        !FutureMap) :-
+    map.lookup(!.VarTypes, SharedVar, SharedVarType),
+    make_future_var(SharedVar, SharedVarType, !VarSet, !VarTypes, FutureVar),
+    svmap.det_insert(SharedVar, FutureVar, !FutureMap),
 
     ModuleName = mercury_par_builtin_module,
     PredName = "new_future",
@@ -1588,6 +1636,19 @@
         only_mode, detism_det, purity_pure, Args, Features, InstMapSrc,
         ModuleInfo, Context, AllocGoal).
 
+    % Given a variable SharedVar of type SharedVarType, add a new variable
+    % FutureVar of type future(SharedVarType).
+    %
+:- pred make_future_var(prog_var::in, mer_type::in,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
+    prog_var::out) is det.
+
+make_future_var(SharedVar, SharedVarType, !VarSet, !VarTypes, FutureVar) :-
+    construct_future_type(SharedVarType, FutureType),
+    varset.lookup_name(!.VarSet, SharedVar, SharedVarName),
+    svvarset.new_named_var("Future" ++ SharedVarName, FutureVar, !VarSet),
+    svmap.det_insert(FutureVar, FutureType, !VarTypes).
+
     % Construct type future(T) given type T.
     %
 :- pred construct_future_type(mer_type::in, mer_type::out) is det.
@@ -1597,13 +1658,6 @@
     FutureCtor = type_ctor(Future, 1),
     construct_type(FutureCtor, [T], FutureT).
 
-:- pred is_future_type(mer_type::in) is semidet.
-
-is_future_type(T) :-
-    Future = qualified(mercury_par_builtin_module, "future"),
-    FutureCtor = type_ctor(Future, 1),
-    type_to_ctor_and_args(T, FutureCtor, _Args).
-
 :- pred make_wait_goal(module_info::in, prog_var::in, prog_var::in,
     hlds_goal::out) is det.
 
@@ -1656,35 +1710,41 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred conjoin_goal_and_goal_list_update_goal_infos(hlds_goal::in,
-    list(hlds_goal)::in, hlds_goal::out) is det.
+:- pred conjoin_goal_and_goal_list_update_goal_infos(hlds_goal_info::in,
+    hlds_goal::in, list(hlds_goal)::in, hlds_goal::out) is det.
 
-conjoin_goal_and_goal_list_update_goal_infos(Goal0, Goals, Goal) :-
-    Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
-    ( GoalExpr0 = conj(plain_conj, GoalList0) ->
-        list.append(GoalList0, Goals, GoalList)
+conjoin_goal_and_goal_list_update_goal_infos(!.GoalInfo, GoalA, GoalsB,
+        Goal) :-
+    GoalA = hlds_goal(GoalExprA, _),
+
+    ( GoalExprA = conj(plain_conj, GoalListA) ->
+        GoalList = GoalListA ++ GoalsB
     ;
-        GoalList = [Goal0 | Goals]
+        GoalList = [GoalA | GoalsB]
     ),
     GoalExpr = conj(plain_conj, GoalList),
+
     goal_list_determinism(GoalList, Detism),
     goal_list_instmap_delta(GoalList, InstMapDelta),
     goal_list_nonlocals(GoalList, NonLocals),
-    goal_info_set_determinism(Detism, GoalInfo1, GoalInfo2),
-    goal_info_set_instmap_delta(InstMapDelta, GoalInfo2, GoalInfo),
-    goal_info_set_nonlocals(NonLocals, GoalInfo0, GoalInfo1),
-    Goal = hlds_goal(GoalExpr, GoalInfo).
 
-:- pred conjoin_goals_update_goal_infos(hlds_goal::in, hlds_goal::in,
-    hlds_goal::out) is det.
+    goal_info_set_nonlocals(NonLocals, !GoalInfo),
+    goal_info_set_determinism(Detism, !GoalInfo),
+    goal_info_set_instmap_delta(InstMapDelta, !GoalInfo),
+
+    Goal = hlds_goal(GoalExpr, !.GoalInfo).
+
+:- pred conjoin_goals_update_goal_infos(hlds_goal_info::in,
+    hlds_goal::in, hlds_goal::in, hlds_goal::out) is det.
 
-conjoin_goals_update_goal_infos(Goal1, Goal2, Goal) :-
-    ( Goal2 = hlds_goal(conj(plain_conj, Goals2), _) ->
-        GoalList = Goals2
+conjoin_goals_update_goal_infos(!.GoalInfo, GoalA, GoalB, Goal) :-
+    ( GoalB = hlds_goal(conj(plain_conj, GoalsB), _) ->
+        GoalListB = GoalsB
     ;
-        GoalList = [Goal2]
+        GoalListB = [GoalB]
     ),
-    conjoin_goal_and_goal_list_update_goal_infos(Goal1, GoalList, Goal).
+    conjoin_goal_and_goal_list_update_goal_infos(!.GoalInfo, GoalA, GoalListB,
+        Goal).
 
 :- pred det_delete_nth(int::in, list(T)::in, list(T)::out) is det.
 
Index: compiler/goal_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/goal_util.m,v
retrieving revision 1.159
diff -u -b -r1.159 goal_util.m
--- compiler/goal_util.m	29 Jul 2008 23:57:57 -0000	1.159
+++ compiler/goal_util.m	9 Oct 2008 04:07:56 -0000
@@ -50,27 +50,41 @@
     % ( Goal' -> UnifyGoals, ... ; ...), where Goal' has its output
     % variables (OutputVars) replaced with new variables (NewVars),
     % with the mapping from OutputVars to NewVars being Renaming.
-    % VarTypes and Varset are updated for the new variables. The final
+    % VarTypes and VarSet are updated for the new variables. The final
     % insts of NewVar are taken from the insts of the corresponding
     % OutputVar in InstMapDelta (the initial inst is free).
     %
-:- pred create_renaming(prog_vars::in, instmap_delta::in,
+:- pred create_renaming(list(prog_var)::in, instmap_delta::in,
     prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
-    hlds_goals::out, prog_vars::out, prog_var_renaming::out) is det.
+    list(hlds_goal)::out, list(prog_var)::out, prog_var_renaming::out) is det.
 
-    % create_variables(OldVariables, OldVarNames, OldVarTypes,
-    %   !Varset, !VarTypes, !Subn):
+    % clone_variable(OldVar, OldVarSet, OldVarTypes,
+    %   !VarSet, !VarTypes, !Renaming, CloneVar):
     %
-    % create_variables takes a list of variables, a varset, and map
-    % from vars to types and an initial substitution, and creates new instances
-    % of each of the source variables in the substitution, adding each new
-    % variable to the varset and the var types map. The name and type of each
-    % new variable is found by looking up in the type map given in the 5th
-    % argument - the last input. (This interface will not easily admit
-    % uniqueness in the type map for this reason - such is the sacrifice
-    % for generality.)
+    % clone_variable typically takes an old variable OldVar, and creates a
+    % clone of it, adding the clone variable to !VarSet and !VarType, and
+    % adding a mapping from the old variable to its clone in !Renaming.
+    % The name and type of the clone are taken from OldVarSet and OldVarTypes.
+    % However, if OldVar already has a clone, as shown by it already being a
+    % key in !.Renaming, clone_variable does nothing. Either way, the identity
+    % of the clone variable is returned in CloneVar.
     %
-:- pred create_variables(prog_vars::in, prog_varset::in, vartypes::in,
+    % (This interface will not easily admit uniqueness in the varset and
+    % vartypes arguments; such is the sacrifice for generality.)
+    %
+:- pred clone_variable(prog_var::in, prog_varset::in, vartypes::in,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
+    prog_var_renaming::in, prog_var_renaming::out, prog_var::out) is det.
+
+    % clone_variables(OldVars, OldVarSet, OldVarTypes,
+    %   !VarSet, !VarTypes, !Renaming):
+    %
+    % Invoke clone_variable on each variable in OldVars.
+    %
+    % The caller can find the identity of the clone of each variable in OldVars
+    % by looking it up in !:Renaming.
+    %
+:- pred clone_variables(list(prog_var)::in, prog_varset::in, vartypes::in,
     prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
     prog_var_renaming::in, prog_var_renaming::out) is det.
 
@@ -84,12 +98,12 @@
     % Unlike quantification.goal_vars, this predicate returns
     % even the explicitly quantified variables.
     %
-:- pred goals_goal_vars(hlds_goals::in,
+:- pred goals_goal_vars(list(hlds_goal)::in,
     set(prog_var)::in, set(prog_var)::out) is det.
 
     % Return all the variables in a generic call.
     %
-:- pred generic_call_vars(generic_call::in, prog_vars::out) is det.
+:- pred generic_call_vars(generic_call::in, list(prog_var)::out) is det.
 
     % Attach the given goal features to the given goal and all its subgoals.
     %
@@ -135,7 +149,7 @@
 
     % Return an indication of the size of the list of goals.
     %
-:- pred goals_size(hlds_goals::in, int::out) is det.
+:- pred goals_size(list(hlds_goal)::in, int::out) is det.
 
     % Return an indication of the size of the list of clauses.
     %
@@ -194,11 +208,11 @@
     % Returns all the predids that are called along with the list of
     % arguments.
 :- pred predids_with_args_from_goal(hlds_goal::in,
-    list({pred_id, prog_vars})::out) is det.
+    list({pred_id, list(prog_var)})::out) is det.
 
     % Returns all the predids that are used in a list of goals.
     %
-:- pred predids_from_goals(hlds_goals::in, list(pred_id)::out) is det.
+:- pred predids_from_goals(list(hlds_goal)::in, list(pred_id)::out) is det.
 
     % Returns all the procedures that are used within a goal.
     %
@@ -211,7 +225,7 @@
     % This aborts if any of the constructors are existentially typed.
     %
 :- pred switch_to_disjunction(prog_var::in, list(case)::in,
-    instmap::in, hlds_goals::out, prog_varset::in, prog_varset::out,
+    instmap::in, list(hlds_goal)::out, prog_varset::in, prog_varset::out,
     vartypes::in, vartypes::out, module_info::in, module_info::out) is det.
 
     % Convert a case into a conjunction by adding a tag test
@@ -232,7 +246,7 @@
 
     % Flatten a list of goals of a conjunction.
     %
-:- pred flatten_conj(hlds_goals::in, hlds_goals::out) is det.
+:- pred flatten_conj(list(hlds_goal)::in, list(hlds_goal)::out) is det.
 
     % Create a conjunction of the specified type using the specified goals,
     % This fills in the hlds_goal_info.
@@ -320,8 +334,8 @@
     % If ModeNo = mode_no(N) then the Nth procedure is used, counting
     % from 0.
     %
-:- pred generate_simple_call(module_name::in, string::in,
-    pred_or_func::in, mode_no::in, determinism::in, purity::in, prog_vars::in,
+:- pred generate_simple_call(module_name::in, string::in, pred_or_func::in,
+    mode_no::in, determinism::in, purity::in, list(prog_var)::in,
     list(goal_feature)::in, assoc_list(prog_var, mer_inst)::in,
     module_info::in, term.context::in, hlds_goal::out) is det.
 
@@ -406,9 +420,10 @@
     list.reverse(RevNewVars, NewVars),
     list.reverse(RevUnifies, Unifies).
 
-:- pred create_renaming_2(prog_vars::in, instmap_delta::in,
+:- pred create_renaming_2(list(prog_var)::in, instmap_delta::in,
     prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
-    hlds_goals::in, hlds_goals::out, prog_vars::in, prog_vars::out,
+    list(hlds_goal)::in, list(hlds_goal)::out,
+    list(prog_var)::in, list(prog_var)::out,
     prog_var_renaming::in, prog_var_renaming::out) is det.
 
 create_renaming_2([], _, !VarSet, !VarTypes, !RevUnifies, !RevNewVars,
@@ -440,26 +455,33 @@
 
 %-----------------------------------------------------------------------------%
 
-create_variables([], _OldVarNames, _OldVarTypes, !Varset, !VarTypes, !Subn).
-create_variables([V | Vs], OldVarNames, OldVarTypes, !Varset, !VarTypes,
-        !Subn) :-
-    ( map.contains(!.Subn, V) ->
-        true
-    ;
-        svvarset.new_var(NV, !Varset),
-        ( varset.search_name(OldVarNames, V, Name) ->
-            svvarset.name_var(NV, Name, !Varset)
+clone_variable(Var, OldVarNames, OldVarTypes, !VarSet, !VarTypes, !Renaming,
+        CloneVar) :-
+    ( map.search(!.Renaming, Var, CloneVarPrime) ->
+        CloneVar = CloneVarPrime
+    ;
+        svvarset.new_var(CloneVar, !VarSet),
+        ( varset.search_name(OldVarNames, Var, Name) ->
+            svvarset.name_var(CloneVar, Name, !VarSet)
         ;
             true
         ),
-        svmap.det_insert(V, NV, !Subn),
-        ( map.search(OldVarTypes, V, VT) ->
-            svmap.set(NV, VT, !VarTypes)
+        svmap.det_insert(Var, CloneVar, !Renaming),
+        ( map.search(OldVarTypes, Var, VarType) ->
+            svmap.set(CloneVar, VarType, !VarTypes)
         ;
+            % XXX This should never happen after typechecking.
             true
         )
-    ),
-    create_variables(Vs, OldVarNames, OldVarTypes, !Varset, !VarTypes, !Subn).
+    ).
+
+clone_variables([], _, _, !VarSet, !VarTypes, !Renaming).
+clone_variables([Var | Vars], OldVarNames, OldVarTypes, !VarSet, !VarTypes,
+        !Renaming) :-
+    clone_variable(Var, OldVarNames, OldVarTypes, !VarSet, !VarTypes,
+        !Renaming, _CloneVar),
+    clone_variables(Vars, OldVarNames, OldVarTypes, !VarSet, !VarTypes,
+        !Renaming).
 
 %-----------------------------------------------------------------------------%
 
@@ -928,7 +950,7 @@
 goal_calls(hlds_goal(GoalExpr, _), PredProcId) :-
     goal_expr_calls(GoalExpr, PredProcId).
 
-:- pred goals_calls(hlds_goals, pred_proc_id).
+:- pred goals_calls(list(hlds_goal), pred_proc_id).
 :- mode goals_calls(in, in) is semidet.
 :- mode goals_calls(in, out) is nondet.
 
@@ -986,7 +1008,7 @@
 goal_calls_pred_id(hlds_goal(GoalExpr, _), PredId) :-
     goal_expr_calls_pred_id(GoalExpr, PredId).
 
-:- pred goals_calls_pred_id(hlds_goals, pred_id).
+:- pred goals_calls_pred_id(list(hlds_goal), pred_id).
 :- mode goals_calls_pred_id(in, in) is semidet.
 :- mode goals_calls_pred_id(in, out) is nondet.
 
@@ -1136,7 +1158,7 @@
     Unify = construct(_, _, _, _, HowToConstruct, _, _),
     HowToConstruct = reuse_cell(_).
 
-:- pred goals_contain_reconstruction(hlds_goals::in) is semidet.
+:- pred goals_contain_reconstruction(list(hlds_goal)::in) is semidet.
 
 goals_contain_reconstruction(Goals) :-
     list.member(Goal, Goals),
Index: compiler/inlining.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/inlining.m,v
retrieving revision 1.159
diff -u -b -r1.159 inlining.m
--- compiler/inlining.m	27 Feb 2008 07:23:07 -0000	1.159
+++ compiler/inlining.m	9 Oct 2008 04:12:18 -0000
@@ -809,13 +809,12 @@
     ).
 
 rename_goal(HeadVars, ArgVars, VarSet0, CalleeVarSet, VarSet, VarTypes1,
-        CalleeVarTypes, VarTypes, Subn, CalledGoal, Goal) :-
-    map.from_corresponding_lists(HeadVars, ArgVars, Subn0),
+        CalleeVarTypes, VarTypes, Renaming, CalledGoal, Goal) :-
+    map.from_corresponding_lists(HeadVars, ArgVars, Renaming0),
     varset.vars(CalleeVarSet, CalleeListOfVars),
-    goal_util.create_variables(CalleeListOfVars,
-        CalleeVarSet, CalleeVarTypes,
-        VarSet0, VarSet, VarTypes1, VarTypes, Subn0, Subn),
-    must_rename_vars_in_goal(Subn, CalledGoal, Goal).
+    clone_variables(CalleeListOfVars, CalleeVarSet, CalleeVarTypes,
+        VarSet0, VarSet, VarTypes1, VarTypes, Renaming0, Renaming),
+    must_rename_vars_in_goal(Renaming, CalledGoal, Goal).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.481
diff -u -b -r1.481 mercury_compile.m
--- compiler/mercury_compile.m	8 Oct 2008 02:28:41 -0000	1.481
+++ compiler/mercury_compile.m	13 Oct 2008 11:01:58 -0000
@@ -103,6 +103,7 @@
 :- import_module transform_hlds.ctgc.structure_sharing.analysis.
 :- import_module transform_hlds.granularity.
 :- import_module transform_hlds.dep_par_conj.
+:- import_module transform_hlds.parallel_to_plain_conj.
 :- import_module transform_hlds.size_prof.
 :- import_module ll_backend.deep_profiling.
 
@@ -2744,9 +2745,6 @@
     maybe_lco(Verbose, Stats, !HLDS, !IO),
     maybe_dump_hlds(!.HLDS, 175, "lco", !DumpInfo, !IO),
 
-    maybe_eliminate_dead_procs(Verbose, Stats, !HLDS, !IO),
-    maybe_dump_hlds(!.HLDS, 180, "dead_procs", !DumpInfo, !IO),
-
     maybe_analyse_mm_tabling(Verbose, Stats, !HLDS, !IO),
     maybe_dump_hlds(!.HLDS, 185, "mm_tabling_analysis", !DumpInfo, !IO),
 
@@ -2756,7 +2754,7 @@
     maybe_control_distance_granularity(Verbose, Stats, !HLDS, !IO),
     maybe_dump_hlds(!.HLDS, 201, "distance_granularity", !DumpInfo, !IO),
 
-    maybe_dependent_par_conj(Verbose, Stats, !HLDS, !IO),
+    maybe_impl_dependent_par_conjs(Verbose, Stats, !HLDS, !IO),
     maybe_dump_hlds(!.HLDS, 205, "dependent_par_conj", !DumpInfo, !IO),
 
     % If we are compiling in a deep profiling grade then now rerun simplify.
@@ -2793,6 +2791,9 @@
     maybe_region_analysis(Verbose, Stats, !HLDS, !IO),
     maybe_dump_hlds(!.HLDS, 240, "region_analysis", !DumpInfo, !IO),
 
+    maybe_eliminate_dead_procs(Verbose, Stats, !HLDS, !IO),
+    maybe_dump_hlds(!.HLDS, 250, "dead_procs", !DumpInfo, !IO),
+
     maybe_dump_hlds(!.HLDS, 299, "middle_pass", !DumpInfo, !IO).
 
 %-----------------------------------------------------------------------------%
@@ -3400,7 +3401,7 @@
         maybe_write_string(Verbose, "% Warning about dead procedures...\n",
             !IO),
         maybe_flush_output(Verbose, !IO),
-        dead_proc_elim(dead_proc_warning_pass, !.HLDS, _HLDS1, Specs),
+        dead_proc_elim(do_not_elim_opt_imported, !.HLDS, _HLDS1, Specs),
         maybe_write_string(Verbose, "% done.\n", !IO),
         maybe_report_stats(Stats, !IO),
         module_info_get_globals(!.HLDS, Globals),
@@ -4109,7 +4110,7 @@
         maybe_write_string(Verbose, "% Eliminating dead procedures...\n", !IO),
         maybe_flush_output(Verbose, !IO),
         % Ignore any warning messages generated.
-        dead_proc_elim(dead_proc_final_optimization_pass, !HLDS, _Specs),
+        dead_proc_elim(elim_opt_imported, !HLDS, _ElimSpecs),
         maybe_write_string(Verbose, "% done.\n", !IO),
         maybe_report_stats(Stats, !IO)
     ;
@@ -4252,21 +4253,29 @@
         true
     ).
 
-:- pred maybe_dependent_par_conj(bool::in, bool::in,
+:- pred maybe_impl_dependent_par_conjs(bool::in, bool::in,
     module_info::in, module_info::out, io::di, io::uo) is det.
 
-maybe_dependent_par_conj(Verbose, Stats, !HLDS, !IO) :-
+maybe_impl_dependent_par_conjs(Verbose, Stats, !HLDS, !IO) :-
     module_info_get_contains_par_conj(!.HLDS, ContainsParConj),
     (
         ContainsParConj = yes,
-        % This pass also converts dependent parallel conjunctions into
-        % plain conjunctions if we are not building in a parallel grade.
+        module_info_get_globals(!.HLDS, Globals),
+        current_grade_supports_par_conj(Globals, SupportsParConj),
+        (
+            SupportsParConj = no,
+            process_all_nonimported_procs(update_proc(parallel_to_plain_conjs),
+                !HLDS, !IO)
+        ;
+            SupportsParConj = yes,
         maybe_write_string(Verbose,
             "% Dependent parallel conjunction transformation...\n", !IO),
         maybe_flush_output(Verbose, !IO),
-        dependent_par_conj(!HLDS, !IO),
+            impl_dep_par_conjs_in_module(!HLDS),
+            dead_proc_elim(do_not_elim_opt_imported, !HLDS, _ElimSpecs),
         maybe_write_string(Verbose, "% done.\n", !IO),
         maybe_report_stats(Stats, !IO)
+        )
     ;
         ContainsParConj = no
     ).
Index: compiler/parallel_to_plain_conj.m
===================================================================
RCS file: compiler/parallel_to_plain_conj.m
diff -N compiler/parallel_to_plain_conj.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ compiler/parallel_to_plain_conj.m	7 Oct 2008 03:34:57 -0000
@@ -0,0 +1,123 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sw=4 et
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2008 The 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.
+%-----------------------------------------------------------------------------%
+%
+% File: parallel_to_plain_conj.m.
+%
+% This module converts parallel conjunction to plain conjunctions,
+% for use in grades that do not allow parallelism.
+%
+%-----------------------------------------------------------------------------%
+
+:- module transform_hlds.parallel_to_plain_conj.
+:- interface.
+
+:- import_module hlds.hlds_module.
+:- import_module hlds.hlds_pred.
+
+%-----------------------------------------------------------------------------%
+
+    % Transform all parallel conjunctions in the procedure into sequential
+    % conjunctions.
+    %
+:- pred parallel_to_plain_conjs(module_info::in, proc_info::in, proc_info::out)
+    is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module hlds.hlds_goal.
+:- import_module libs.compiler_util.
+
+:- import_module bool.
+:- import_module list.
+
+%-----------------------------------------------------------------------------%
+
+parallel_to_plain_conjs(_ModuleInfo, !ProcInfo) :-
+    proc_info_get_has_parallel_conj(!.ProcInfo, HasParallelConj),
+    (
+        HasParallelConj = no
+    ;
+        HasParallelConj = yes,
+        proc_info_get_goal(!.ProcInfo, Goal0),
+        parallel_to_plain_conjs_goal(Goal0, Goal),
+        proc_info_set_goal(Goal, !ProcInfo)
+    ).
+
+:- pred parallel_to_plain_conjs_goal(hlds_goal::in, hlds_goal::out) is det.
+
+parallel_to_plain_conjs_goal(Goal0, Goal) :-
+    Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
+    (
+        GoalExpr0 = conj(_ConjType, Goals0),
+        parallel_to_plain_conjs_goals(Goals0, Goals),
+        GoalExpr = conj(plain_conj, Goals)
+    ;
+        GoalExpr0 = disj(Goals0),
+        parallel_to_plain_conjs_goals(Goals0, Goals),
+        GoalExpr = disj(Goals)
+    ;
+        GoalExpr0 = switch(Var, CanFail, Cases0),
+        parallel_to_plain_conjs_cases(Cases0, Cases),
+        GoalExpr = switch(Var, CanFail, Cases)
+    ;
+        GoalExpr0 = if_then_else(QuantVars, Cond0, Then0, Else0),
+        parallel_to_plain_conjs_goal(Cond0, Cond),
+        parallel_to_plain_conjs_goal(Then0, Then),
+        parallel_to_plain_conjs_goal(Else0, Else),
+        GoalExpr = if_then_else(QuantVars, Cond, Then, Else)
+    ;
+        GoalExpr0 = negation(SubGoal0),
+        parallel_to_plain_conjs_goal(SubGoal0, SubGoal),
+        GoalExpr = negation(SubGoal)
+    ;
+        GoalExpr0 = scope(Reason, SubGoal0),
+        parallel_to_plain_conjs_goal(SubGoal0, SubGoal),
+        GoalExpr = scope(Reason, SubGoal)
+    ;
+        ( GoalExpr0 = unify(_, _, _, _, _)
+        ; GoalExpr0 = plain_call(_, _, _, _, _, _)
+        ; GoalExpr0 = generic_call(_, _, _, _)
+        ; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _)
+        ),
+        GoalExpr = GoalExpr0
+    ;
+        GoalExpr0 = shorthand(_),
+        % These should have been expanded out by now.
+        unexpected(this_file, "shorthand")
+    ),
+    Goal = hlds_goal(GoalExpr, GoalInfo0).
+
+:- pred parallel_to_plain_conjs_goals(
+    list(hlds_goal)::in, list(hlds_goal)::out) is det.
+
+parallel_to_plain_conjs_goals([], []).
+parallel_to_plain_conjs_goals([Goal0 | Goals0], [Goal | Goals]) :-
+    parallel_to_plain_conjs_goal(Goal0, Goal),
+    parallel_to_plain_conjs_goals(Goals0, Goals).
+
+:- pred parallel_to_plain_conjs_cases(list(case)::in, list(case)::out) is det.
+
+parallel_to_plain_conjs_cases([], []).
+parallel_to_plain_conjs_cases([Case0 | Cases0], [Case | Cases]) :-
+    Case0 = case(MainConsId, OtherConsIds, Goal0),
+    parallel_to_plain_conjs_goal(Goal0, Goal),
+    Case = case(MainConsId, OtherConsIds, Goal),
+    parallel_to_plain_conjs_cases(Cases0, Cases).
+
+%-----------------------------------------------------------------------------%
+
+:- func this_file = string.
+
+this_file = "parallel_to_plain_conj.m".
+
+%-----------------------------------------------------------------------------%
+:- end_module parallel_to_plain_conj.
+%-----------------------------------------------------------------------------%
Index: compiler/pd_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/pd_util.m,v
retrieving revision 1.69
diff -u -b -r1.69 pd_util.m
--- compiler/pd_util.m	27 Feb 2008 07:23:12 -0000	1.69
+++ compiler/pd_util.m	9 Oct 2008 03:29:01 -0000
@@ -76,12 +76,12 @@
 
     % Recompute the non-locals of the goal.
     %
-:- pred requantify_goal(set(prog_var)::in,
+:- pred pd_requantify_goal(set(prog_var)::in,
     hlds_goal::in, hlds_goal::out, pd_info::in, pd_info::out) is det.
 
     % Apply mode_util.recompute_instmap_delta to the goal.
     %
-:- pred recompute_instmap_delta(hlds_goal::in, hlds_goal::out,
+:- pred pd_recompute_instmap_delta(hlds_goal::in, hlds_goal::out,
     pd_info::in, pd_info::out) is det.
 
     % Convert from information about the argument positions to
@@ -219,8 +219,8 @@
             Changed = yes,
             pd_debug_output_goal(!.PDInfo,
                 "after constraints, before recompute\n", !.Goal, !IO),
-            requantify_goal(NonLocals, !Goal, !PDInfo),
-            recompute_instmap_delta(!Goal, !PDInfo),
+            pd_requantify_goal(NonLocals, !Goal, !PDInfo),
+            pd_recompute_instmap_delta(!Goal, !PDInfo),
             rerun_det_analysis(!Goal, !PDInfo, !IO),
             module_info_get_globals(ModuleInfo, Globals),
             simplify.find_simplifications(no, Globals, Simplifications),
@@ -781,7 +781,7 @@
 
 %-----------------------------------------------------------------------------%
 
-requantify_goal(NonLocals, Goal0, Goal, !PDInfo) :-
+pd_requantify_goal(NonLocals, Goal0, Goal, !PDInfo) :-
     some [!ProcInfo] (
         pd_info_get_proc_info(!.PDInfo, !:ProcInfo),
         proc_info_get_varset(!.ProcInfo, VarSet0),
@@ -795,7 +795,7 @@
         pd_info_set_proc_info(!.ProcInfo, !PDInfo)
     ).
 
-recompute_instmap_delta(Goal0, Goal, !PDInfo) :-
+pd_recompute_instmap_delta(Goal0, Goal, !PDInfo) :-
     pd_info_get_module_info(!.PDInfo, ModuleInfo0),
     pd_info_get_instmap(!.PDInfo, InstMap),
     pd_info_get_proc_info(!.PDInfo, ProcInfo),
Index: compiler/quantification.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/quantification.m,v
retrieving revision 1.126
diff -u -b -r1.126 quantification.m
--- compiler/quantification.m	27 Feb 2008 07:23:13 -0000	1.126
+++ compiler/quantification.m	9 Oct 2008 04:08:40 -0000
@@ -1434,7 +1434,7 @@
         get_varset(!.Info, Varset0),
         get_vartypes(!.Info, VarTypes0),
         map.init(RenameMap0),
-        goal_util.create_variables(RenameList, Varset0, VarTypes0,
+        clone_variables(RenameList, Varset0, VarTypes0,
             Varset0, Varset, VarTypes0, VarTypes, RenameMap0, RenameMap),
         rename_some_vars_in_goal(RenameMap, !Goal),
         set_varset(Varset, !Info),
Index: compiler/simplify.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/simplify.m,v
retrieving revision 1.233
diff -u -b -r1.233 simplify.m
--- compiler/simplify.m	21 Jul 2008 03:10:14 -0000	1.233
+++ compiler/simplify.m	9 Oct 2008 03:27:26 -0000
@@ -567,64 +567,71 @@
 :- pred do_process_clause_body_goal(hlds_goal::in, hlds_goal::out,
     simplify_info::in, simplify_info::out) is det.
 
-do_process_clause_body_goal(Goal0, Goal, !Info) :-
+do_process_clause_body_goal(!Goal, !Info) :-
+    !.Goal = hlds_goal(_, GoalInfo0),
+    Detism = goal_info_get_determinism(GoalInfo0),
+    NonLocals = goal_info_get_nonlocals(GoalInfo0),
     simplify_info_get_instmap(!.Info, InstMap0),
-    simplify_goal(Goal0, Goal1, !Info),
-    simplify_info_get_varset(!.Info, VarSet0),
-    simplify_info_get_var_types(!.Info, VarTypes0),
-    simplify_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
-    ( simplify_info_requantify(!.Info) ->
-        Goal1 = hlds_goal(_, GoalInfo1),
-        NonLocals = goal_info_get_nonlocals(GoalInfo1),
-        implicitly_quantify_goal(NonLocals, _, Goal1, Goal2,
-            VarSet0, VarSet1, VarTypes0, VarTypes1,
-            RttiVarMaps0, RttiVarMaps1),
 
-        simplify_info_set_varset(VarSet1, !Info),
-        simplify_info_set_var_types(VarTypes1, !Info),
-        simplify_info_set_rtti_varmaps(RttiVarMaps1, !Info),
+    simplify_goal(!Goal, !Info),
+
+    ( simplify_info_requantify(!.Info) ->
+        some [!VarSet, !VarTypes, !RttiVarMaps, !ModuleInfo] (
+            simplify_info_get_varset(!.Info, !:VarSet),
+            simplify_info_get_var_types(!.Info, !:VarTypes),
+            simplify_info_get_rtti_varmaps(!.Info, !:RttiVarMaps),
+            implicitly_quantify_goal(NonLocals, _, !Goal,
+                !VarSet, !VarTypes, !RttiVarMaps),
+
+            simplify_info_set_varset(!.VarSet, !Info),
+            simplify_info_set_var_types(!.VarTypes, !Info),
+            simplify_info_set_rtti_varmaps(!.RttiVarMaps, !Info),
 
         % Always recompute instmap_deltas for atomic goals - this is safer
         % in the case where unused variables should no longer be included
         % in the instmap_delta for a goal.
         % In the alias branch this is necessary anyway.
-        simplify_info_get_module_info(!.Info, ModuleInfo0),
-        recompute_instmap_delta(recompute_atomic_instmap_deltas, Goal2, Goal3,
-            VarTypes1, !.Info ^ simp_inst_varset, InstMap0,
-            ModuleInfo0, ModuleInfo1),
-        simplify_info_set_module_info(ModuleInfo1, !Info)
+            simplify_info_get_module_info(!.Info, !:ModuleInfo),
+            InstVarSet = !.Info ^ simp_inst_varset,
+            recompute_instmap_delta(recompute_atomic_instmap_deltas, !Goal,
+                !.VarTypes, InstVarSet, InstMap0, !ModuleInfo),
+            simplify_info_set_module_info(!.ModuleInfo, !Info)
+        )
     ;
-        Goal3 = Goal1
+        true
     ),
     ( simplify_info_rerun_det(!.Info) ->
-        Goal0 = hlds_goal(_, GoalInfo0),
-        Detism = goal_info_get_determinism(GoalInfo0),
+        some [!VarSet, !VarTypes, !RttiVarMaps, !ModuleInfo, !ProcInfo,
+            !DetInfo]
+        (
         det_get_soln_context(Detism, SolnContext),
 
-        % det_infer_goal looks up the proc_info in the module_info
-        % for the vartypes, so we'd better stick them back in the module_info.
-        simplify_info_get_module_info(!.Info, ModuleInfo2),
-        simplify_info_get_varset(!.Info, VarSet2),
-        simplify_info_get_var_types(!.Info, VarTypes2),
-        simplify_info_get_det_info(!.Info, DetInfo2),
-        simplify_info_get_rtti_varmaps(!.Info, RttiVarMaps2),
-        det_info_get_pred_id(DetInfo2, PredId),
-        det_info_get_proc_id(DetInfo2, ProcId),
-        module_info_pred_proc_info(ModuleInfo2, PredId, ProcId,
-            PredInfo, ProcInfo0),
-        proc_info_set_vartypes(VarTypes2, ProcInfo0, ProcInfo1),
-        proc_info_set_varset(VarSet2, ProcInfo1, ProcInfo2),
-        proc_info_set_rtti_varmaps(RttiVarMaps2, ProcInfo2, ProcInfo),
+            % Det_infer_goal looks up the proc_info in the module_info
+            % for the vartypes, so we'd better stick them back in the
+            % module_info.
+            simplify_info_get_module_info(!.Info, !:ModuleInfo),
+            simplify_info_get_varset(!.Info, !:VarSet),
+            simplify_info_get_var_types(!.Info, !:VarTypes),
+            simplify_info_get_rtti_varmaps(!.Info, !:RttiVarMaps),
+            simplify_info_get_det_info(!.Info, !:DetInfo),
+            det_info_get_pred_id(!.DetInfo, PredId),
+            det_info_get_proc_id(!.DetInfo, ProcId),
+            module_info_pred_proc_info(!.ModuleInfo, PredId, ProcId,
+                PredInfo, !:ProcInfo),
+            proc_info_set_vartypes(!.VarTypes, !ProcInfo),
+            proc_info_set_varset(!.VarSet, !ProcInfo),
+            proc_info_set_rtti_varmaps(!.RttiVarMaps, !ProcInfo),
         module_info_set_pred_proc_info(PredId, ProcId,
-            PredInfo, ProcInfo, ModuleInfo2, ModuleInfo3),
-        simplify_info_set_module_info(ModuleInfo3, !Info),
+                PredInfo, !.ProcInfo, !ModuleInfo),
+            simplify_info_set_module_info(!.ModuleInfo, !Info),
 
-        simplify_info_get_det_info(!.Info, DetInfo0),
-        det_infer_goal(Goal3, Goal, InstMap0, SolnContext, [], no,
-            _, _, DetInfo0, DetInfo, [], _),
-        simplify_info_set_det_info(DetInfo, !Info)
+            simplify_info_get_det_info(!.Info, !:DetInfo),
+            det_infer_goal(!Goal, InstMap0, SolnContext, [], no,
+                _, _, !DetInfo, [], _),
+            simplify_info_set_det_info(!.DetInfo, !Info)
+        )
     ;
-        Goal = Goal3
+        true
     ).
 
 %-----------------------------------------------------------------------------%
@@ -1221,8 +1228,8 @@
         inequality_goal(TI, X, Y, Inequality, Invert, GoalInfo0,
             GoalExpr, GoalInfo, !Info)
     ;
-        call_goal(PredId, ProcId, Args, IsBuiltin, GoalExpr0, GoalExpr,
-            GoalInfo0, GoalInfo, !Info)
+        simplify_call_goal(PredId, ProcId, Args, IsBuiltin,
+            GoalExpr0, GoalExpr, GoalInfo0, GoalInfo, !Info)
     ).
 
 :- pred simplify_goal_2_unify(
@@ -2126,12 +2133,13 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred call_goal(pred_id::in, proc_id::in, list(prog_var)::in,
+:- pred simplify_call_goal(pred_id::in, proc_id::in, list(prog_var)::in,
     builtin_state::in, hlds_goal_expr::in, hlds_goal_expr::out,
     hlds_goal_info::in, hlds_goal_info::out,
     simplify_info::in, simplify_info::out) is det.
 
-call_goal(PredId, ProcId, Args, IsBuiltin, !GoalExpr, !GoalInfo, !Info) :-
+simplify_call_goal(PredId, ProcId, Args, IsBuiltin, !GoalExpr, !GoalInfo,
+        !Info) :-
     simplify_info_get_module_info(!.Info, ModuleInfo0),
     module_info_pred_proc_info(ModuleInfo0, PredId, ProcId,
         PredInfo, ProcInfo),
Index: compiler/transform_hlds.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/transform_hlds.m,v
retrieving revision 1.29
diff -u -b -r1.29 transform_hlds.m
--- compiler/transform_hlds.m	27 Feb 2008 07:23:16 -0000	1.29
+++ compiler/transform_hlds.m	7 Oct 2008 03:29:26 -0000
@@ -95,6 +95,7 @@
 :- include_module distance_granularity.
 :- include_module granularity.
 :- include_module dep_par_conj.
+:- include_module parallel_to_plain_conj.
 :- include_module implicit_parallelism.
 
 :- include_module mmc_analysis.
cvs diff: Diffing compiler/notes
Index: compiler/notes/compiler_design.html
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/notes/compiler_design.html,v
retrieving revision 1.135
diff -u -b -r1.135 compiler_design.html
--- compiler/notes/compiler_design.html	21 Jul 2008 03:10:25 -0000	1.135
+++ compiler/notes/compiler_design.html	13 Oct 2008 04:51:58 -0000
@@ -1138,6 +1138,9 @@
   in producers and the waits as late as possible in the consumers, creating
   specialized versions of predicates as needed.
 
+<li> parallel_to_plain_conj.m transforms parallel conjunctions to plain
+  conjunctions, for use in grades that do not support AND-parallelism.
+
 <li> granularity.m tries to ensure that programs do not generate too much
   parallelism. Its goal is to minimize parallelism's overhead while still
   gaining all the parallelism the machine can actually exploit.
cvs diff: Diffing debian
cvs diff: Diffing debian/patches
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
cvs diff: Diffing extras
cvs diff: Diffing extras/base64
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/concurrency
cvs diff: Diffing extras/curs
cvs diff: Diffing extras/curs/samples
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/error
cvs diff: Diffing extras/fixed
cvs diff: Diffing extras/gator
cvs diff: Diffing extras/gator/generations
cvs diff: Diffing extras/gator/generations/1
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/easyx
cvs diff: Diffing extras/graphics/easyx/samples
cvs diff: Diffing extras/graphics/mercury_allegro
cvs diff: Diffing extras/graphics/mercury_allegro/examples
cvs diff: Diffing extras/graphics/mercury_allegro/samples
cvs diff: Diffing extras/graphics/mercury_allegro/samples/demo
cvs diff: Diffing extras/graphics/mercury_allegro/samples/mandel
cvs diff: Diffing extras/graphics/mercury_allegro/samples/pendulum2
cvs diff: Diffing extras/graphics/mercury_allegro/samples/speed
cvs diff: Diffing extras/graphics/mercury_glut
cvs diff: Diffing extras/graphics/mercury_opengl
cvs diff: Diffing extras/graphics/mercury_tcltk
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/gears
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/graphics/samples/pent
cvs diff: Diffing extras/lazy_evaluation
cvs diff: Diffing extras/lex
cvs diff: Diffing extras/lex/samples
cvs diff: Diffing extras/lex/tests
cvs diff: Diffing extras/log4m
cvs diff: Diffing extras/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
cvs diff: Diffing extras/moose/tests
cvs diff: Diffing extras/mopenssl
cvs diff: Diffing extras/morphine
cvs diff: Diffing extras/morphine/non-regression-tests
cvs diff: Diffing extras/morphine/scripts
cvs diff: Diffing extras/morphine/source
cvs diff: Diffing extras/net
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/posix/samples
cvs diff: Diffing extras/quickcheck
cvs diff: Diffing extras/quickcheck/tutes
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/solver_types
cvs diff: Diffing extras/solver_types/library
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing extras/windows_installer_generator
cvs diff: Diffing extras/windows_installer_generator/sample
cvs diff: Diffing extras/windows_installer_generator/sample/images
cvs diff: Diffing extras/xml
cvs diff: Diffing extras/xml/samples
cvs diff: Diffing extras/xml_stylesheets
cvs diff: Diffing java
cvs diff: Diffing java/runtime
cvs diff: Diffing library
cvs diff: Diffing mdbcomp
cvs diff: Diffing profiler
cvs diff: Diffing robdd
cvs diff: Diffing runtime
cvs diff: Diffing runtime/GETOPT
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/standalone_c
cvs diff: Diffing samples/diff
cvs diff: Diffing samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing samples/solver_types
cvs diff: Diffing samples/tests
cvs diff: Diffing samples/tests/c_interface
cvs diff: Diffing samples/tests/c_interface/c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/tests/c_interface/mercury_calls_c
cvs diff: Diffing samples/tests/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/tests/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/tests/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/tests/diff
cvs diff: Diffing samples/tests/muz
cvs diff: Diffing samples/tests/rot13
cvs diff: Diffing samples/tests/solutions
cvs diff: Diffing samples/tests/toplevel
cvs diff: Diffing scripts
cvs diff: Diffing slice
cvs diff: Diffing ssdb
cvs diff: Diffing tests
cvs diff: Diffing tests/analysis
cvs diff: Diffing tests/analysis/ctgc
cvs diff: Diffing tests/analysis/excp
cvs diff: Diffing tests/analysis/ext
cvs diff: Diffing tests/analysis/sharing
cvs diff: Diffing tests/analysis/table
cvs diff: Diffing tests/analysis/trail
cvs diff: Diffing tests/analysis/unused_args
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
cvs diff: Diffing tests/debugger/declarative
cvs diff: Diffing tests/dppd
cvs diff: Diffing tests/general
cvs diff: Diffing tests/general/accumulator
cvs diff: Diffing tests/general/string_format
cvs diff: Diffing tests/general/structure_reuse
cvs diff: Diffing tests/grade_subdirs
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/purity
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/mmc_make
cvs diff: Diffing tests/mmc_make/lib
cvs diff: Diffing tests/par_conj
Index: tests/par_conj/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/par_conj/Mmakefile,v
retrieving revision 1.15
diff -u -b -r1.15 Mmakefile
--- tests/par_conj/Mmakefile	6 Jun 2007 01:48:13 -0000	1.15
+++ tests/par_conj/Mmakefile	13 Oct 2008 16:32:08 -0000
@@ -6,6 +6,9 @@
 
 # please keep these lists sorted
 DEP_PAR_CONJ_PROGS= \
+	consume_in_some_branches \
+	consume_in_some_branches_and_after \
+	consume_wait \
 	dep_par_1 \
 	dep_par_2 \
 	dep_par_3 \
@@ -149,8 +152,11 @@
 # threads to see the bug.
 spawn_many.out: spawn_many
 	ulimit -s 256 && \
-		MERCURY_OPTIONS='-P2 --detstack-size 32 --small-detstack-size 32 \
-			--nondetstack-size 16 --small-nondetstack-size 16' \
+		MERCURY_OPTIONS="-P2 \
+			--detstack-size 32 \
+			--small-detstack-size 32 \
+			--nondetstack-size 16 \
+			--small-nondetstack-size 16" \
 		./spawn_many 2>&1 > spawn_many.out || \
 		{ grep . $@ /dev/null; exit 1; }
 
Index: tests/par_conj/consume_in_some_branches.exp
===================================================================
RCS file: tests/par_conj/consume_in_some_branches.exp
diff -N tests/par_conj/consume_in_some_branches.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/par_conj/consume_in_some_branches.exp	13 Oct 2008 13:55:00 -0000
@@ -0,0 +1,3 @@
+2
+2
+5
Index: tests/par_conj/consume_in_some_branches.m
===================================================================
RCS file: tests/par_conj/consume_in_some_branches.m
diff -N tests/par_conj/consume_in_some_branches.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/par_conj/consume_in_some_branches.m	13 Oct 2008 13:55:01 -0000
@@ -0,0 +1,82 @@
+% vim: ft=mercury ts=4 sw=4 et
+
+:- module consume_in_some_branches.
+
+:- 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 = 1
+    &
+        Y3 = 3,
+        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) :-
+    ( Y = 2 ->
+        Z = Y
+    ;
+        Z = X
+    ).
+
+:- pred r(int::in, int::in, int::out) is det.
+:- pragma no_inline(r/3).
+
+r(X, Y, Z) :-
+    ( Y = 2 ->
+        A = Y,
+        Z = A
+    ;
+        A = X,
+        Z = A
+    ).
+
+:- pred s(int::in, int::in, int::out) is det.
+:- pragma no_inline(s/3).
+
+s(X, Y, Z) :-
+    ( Y = 2 ->
+        (
+            A = Y
+        &
+            Z = A
+        )
+    ;
+        (
+            A = X
+        &
+            B = X
+        &
+            C = Y
+        ),
+        Z = A + B + C
+    ).
Index: tests/par_conj/consume_in_some_branches_and_after.exp
===================================================================
RCS file: tests/par_conj/consume_in_some_branches_and_after.exp
diff -N tests/par_conj/consume_in_some_branches_and_after.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/par_conj/consume_in_some_branches_and_after.exp	13 Oct 2008 13:55:21 -0000
@@ -0,0 +1,3 @@
+3
+3
+6
Index: tests/par_conj/consume_in_some_branches_and_after.m
===================================================================
RCS file: tests/par_conj/consume_in_some_branches_and_after.m
diff -N tests/par_conj/consume_in_some_branches_and_after.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/par_conj/consume_in_some_branches_and_after.m	13 Oct 2008 16:10:18 -0000
@@ -0,0 +1,90 @@
+% vim: ft=mercury ts=4 sw=4 et
+%
+% This is a regression test. The version of the compiler before Oct 7, 2008
+% used to abort on this code with the error message
+%
+%   instmap.m: Unexpected: merge_instmapping_delta_2: error merging var 17
+
+:- module consume_in_some_branches_and_after.
+
+:- 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 = 1
+    &
+        Y3 = 3,
+        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) :-
+    ( Y = 2 ->
+        A = Y
+    ;
+        A = X
+    ),
+    Z = X + A.
+
+:- pred r(int::in, int::in, int::out) is det.
+:- pragma no_inline(r/3).
+
+r(X, Y, Z) :-
+    ( Y = 2 ->
+        A = Y,
+        W = A
+    ;
+        A = X,
+        W = A
+    ),
+    Z = X + W.
+
+:- pred s(int::in, int::in, int::out) is det.
+:- pragma no_inline(s/3).
+
+s(X, Y, Z) :-
+    ( Y = 2 ->
+        (
+            A = Y
+        &
+            W = A
+        )
+    ;
+        (
+            A = X
+        &
+            B = X
+        &
+            C = Y
+        ),
+        W = A + B + C
+    ),
+    Z = X + W.
Index: tests/par_conj/consume_wait.exp
===================================================================
RCS file: tests/par_conj/consume_wait.exp
diff -N tests/par_conj/consume_wait.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/par_conj/consume_wait.exp	14 Oct 2008 03:28:35 -0000
@@ -0,0 +1,3 @@
+1
+2
+5
Index: tests/par_conj/consume_wait.m
===================================================================
RCS file: tests/par_conj/consume_wait.m
diff -N tests/par_conj/consume_wait.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/par_conj/consume_wait.m	13 Oct 2008 16:56:28 -0000
@@ -0,0 +1,99 @@
+% 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.
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/trailing
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
cvs diff: Diffing util
cvs diff: Diffing vim
cvs diff: Diffing vim/after
cvs diff: Diffing vim/ftplugin
cvs diff: Diffing vim/syntax
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list