[m-rev.] for review: dependent parallel conjunctions (1/2)

Peter Wang wangp at students.cs.mu.OZ.AU
Thu Jun 22 14:28:57 AEST 2006


Estimated hours taken: 40
Branches: main

This patch adds preliminary support for deterministic, dependent
parallel conjunctions to the low-level backend.  In other backends
dependent parallel conjunctions are converted into plain conjunctions.

For a parallel conjunction (A & B), if the goal B is dependent on a variable
X which is bound by goal A, we transform the conjunction such that
goal B must wait for the value to be produced by A before it begins
executing.  This transformation is not yet useful in practice (you might as
well use a sequential conjunction).  A later version of this transformation
will move the synchronisation deeper into the goals so that B can execute as
much as possible before it waits for the value from A.

There is no coroutining support yet so if there are not enough threads
available then dependent parallel conjunctions can cause the program to
deadlock.


configure.in:
runtime/mercury_conf.h.in:
	Check for existence of semaphore.h and #define MR_HAVE_SEMAPHORE_H
	if it does.

library/library.m:
library/par_builtin.m:
library/private_builtin.m:
mdbcomp/prim_data.m:
mdbcomp/program_representation.m:
	Add a new module `par_builtin' to hold synchronisation primitives.

compiler/modules.m:
	Import `par_builtin' module in parallel grades.

compiler/dep_par_conj.m:
compiler/transform_hlds.m:
compiler/mercury_compile.m:
	Add a transformation to detect dependent parallel conjunctions
	and insert the necessary synchronisation code.

compiler/hlds_goal.m:
	Consider empty parallel conjunctions as atomic, the same as plain
	conjunctions.

compiler/inlining.m:
	Flatten parallel conjunctions when inlining, as for plain conjunctions.

compiler/live_vars.m:
	Fix build_live_sets_in_par_conj to handle dependent parallel
	conjunctions.

compiler/liveness.m:
	Delay deaths in parallel conjunctions the same way as for plain
	conjunctions.

	Update detect_resume_points_in_par_conj for dependent parallel
	conjunctions.

compiler/mode_util.m:
compiler/modes.m:
compiler/unique_modes.m:
	Update mode, uniqueness checking for dependent parallel conjunctions.

compiler/simplify.m:
	Don't reset instmaps and seen calls after each conjunct of a parallel
	conjunction.

compiler/store_alloc.m:
	Update allocation for dependent parallel conjunctions.

compiler/switch_detection.m:
	Detect switches in parallel conjunctions the same as plain
	conjunctions.

compiler/par_conj_gen.m:
	Add a todo comment.

tests/Mmakefile:
tests/par_conj/.cvsignore:
tests/par_conj/Mmakefile:
tests/par_conj/dep_par_1.m:
tests/par_conj/dep_par_10.m:
tests/par_conj/dep_par_11.m:
tests/par_conj/dep_par_11b.m:
tests/par_conj/dep_par_11c.m:
tests/par_conj/dep_par_12.m:
tests/par_conj/dep_par_13.m:
tests/par_conj/dep_par_14.m:
tests/par_conj/dep_par_14b.m:
tests/par_conj/dep_par_14c.m:
tests/par_conj/dep_par_14d.m:
tests/par_conj/dep_par_16.m:
tests/par_conj/dep_par_17.m:
tests/par_conj/dep_par_18.m:
tests/par_conj/dep_par_2.m:
tests/par_conj/dep_par_20.m:
tests/par_conj/dep_par_21.m:
tests/par_conj/dep_par_22.m:
tests/par_conj/dep_par_23.m:
tests/par_conj/dep_par_3.m:
tests/par_conj/dep_par_3b.m:
tests/par_conj/dep_par_3c.m:
tests/par_conj/dep_par_4.m:
tests/par_conj/dep_par_5.m:
tests/par_conj/dep_par_5b.m:
tests/par_conj/dep_par_5c.m:
tests/par_conj/dep_par_5d.m:
tests/par_conj/dep_par_6.m:
tests/par_conj/dep_par_7.m:
tests/par_conj/dep_par_8.m:
tests/par_conj/dep_par_9.m:
tests/par_conj/indep_par_append.exp:
tests/par_conj/indep_par_append.m:
tests/par_conj/indep_par_nested.exp:
tests/par_conj/indep_par_nested.m:
	Add some parallel conjunction test cases.  The dependent parallel
	conjunction tests are not yet executed as they can deadlock if there
	are not enough threads available.

browser/RESERVED_MACRO_NAMES:
library/RESERVED_MACRO_NAMES:
runtime/RESERVED_MACRO_NAMES:
trace/RESERVED_MACRO_NAMES:
	Add LINUX_THREADS, _REENTRANT and _THREAD_SAFE.


Index: configure.in
===================================================================
RCS file: /home/mercury1/repository/mercury/configure.in,v
retrieving revision 1.453
diff -u -r1.453 configure.in
--- configure.in	1 May 2006 06:00:45 -0000	1.453
+++ configure.in	18 Jun 2006 09:19:06 -0000
@@ -927,7 +927,8 @@
 		unistd.h sys/wait.h sys/siginfo.h sys/signal.h ucontext.h \
 		asm/sigcontext.h sys/param.h sys/time.h sys/times.h \
 		sys/types.h sys/stat.h fcntl.h termios.h sys/ioctl.h \
-		sys/stropts.h windows.h dirent.h getopt.h malloc.h)
+		sys/stropts.h windows.h dirent.h getopt.h malloc.h \
+		semaphore.h)
 
 if test "$MR_HAVE_GETOPT_H" = 1; then
 	GETOPT_H_AVAILABLE=yes
Index: browser/RESERVED_MACRO_NAMES
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/RESERVED_MACRO_NAMES,v
retrieving revision 1.4
diff -u -r1.4 RESERVED_MACRO_NAMES
--- browser/RESERVED_MACRO_NAMES	6 Jun 2006 07:37:36 -0000	1.4
+++ browser/RESERVED_MACRO_NAMES	21 Jun 2006 11:51:36 -0000
@@ -31,6 +31,7 @@
 __GC
 _GC_H
 HIDE_POINTER
+LINUX_THREADS
 REVEAL_POINTER
 #-----------------------------------------------------------------------------#
 # This is defined by mps_gc/code/mercury_mps.h,
@@ -55,3 +56,7 @@
 __OPTIMIZE__
 __STRICT_ANSI__
 #-----------------------------------------------------------------------------#
+# These are defined in when threads are enabled.
+_REENTRANT
+_THREAD_SAFE
+#-----------------------------------------------------------------------------#
Index: compiler/dep_par_conj.m
===================================================================
RCS file: compiler/dep_par_conj.m
diff -N compiler/dep_par_conj.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ compiler/dep_par_conj.m	22 Jun 2006 04:04:20 -0000
@@ -0,0 +1,544 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sw=4 et
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2005-2006 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: dep_par_conj.m.
+% Author: wangp.
+
+% For a parallel conjunction (A & B), if the goal B is dependent on a variable
+% X which is bound by goal A, we transform the conjunction into the following:
+%
+%    par_builtin.new_promise(PromiseX),
+%    (
+%        (
+%            A(X),  % binds X
+%            impure par_builtin.signal(PromiseX, X)
+%        )
+%    &
+%        (
+%            par_builtin.wait(PromiseX, X1),
+%            B(X1)  % uses X
+%        )
+%    )
+%
+% That is, goal B must wait for the value to be produced by A before it begins
+% executing.  This transformation is not just useful in practice (you might as
+% well use a sequential conjunction).  A later version of this transformation
+% will move signal and wait calls into goals to, hopefully, actually allow
+% parallelism.
+%
+% If building in a non-parallel grade then dependent parallel conjunctions
+% are simply converted into sequential conjunctions.
+
+%-----------------------------------------------------------------------------%
+
+:- module transform_hlds.dep_par_conj.
+:- interface.
+
+:- import_module hlds.hlds_module.
+
+:- import_module io.
+
+%-----------------------------------------------------------------------------%
+
+:- pred dependent_par_conj(module_info::in, module_info::out, io::di, io::uo)
+    is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module check_hlds.inst_match.
+:- import_module check_hlds.mode_util.
+:- import_module check_hlds.purity.
+:- import_module hlds.goal_util.
+:- import_module hlds.hlds_goal.
+:- import_module hlds.hlds_pred.
+:- import_module hlds.instmap.
+:- import_module hlds.pred_table.
+:- import_module hlds.quantification.
+:- import_module libs.compiler_util.
+:- import_module libs.globals.
+:- import_module libs.options.
+:- import_module mdbcomp.prim_data.
+:- import_module parse_tree.prog_data.
+:- import_module parse_tree.prog_type.
+:- import_module transform_hlds.dependency_graph.
+
+:- import_module bool.
+:- import_module int.
+:- import_module list.
+:- import_module map.
+:- import_module pair.
+:- import_module set.
+:- import_module string.
+:- import_module svmap.
+:- import_module svset.
+:- import_module svvarset.
+:- import_module term.
+:- import_module varset.
+
+%-----------------------------------------------------------------------------%
+
+dependent_par_conj(!ModuleInfo, !IO) :-
+    module_info_predids(!.ModuleInfo, PredIds),
+    list.foldl2(dependent_par_conj_2, PredIds, !ModuleInfo, !IO).
+
+:- pred dependent_par_conj_2(pred_id::in, module_info::in, module_info::out,
+    io::di, io::uo) is det.
+
+dependent_par_conj_2(PredId, !ModuleInfo, !IO) :-
+    module_info_pred_info(!.ModuleInfo, PredId, PredInfo),
+    ProcIds = pred_info_non_imported_procids(PredInfo),
+    list.foldl2(search_proc_for_par_conj(PredId), ProcIds, !ModuleInfo, !IO).
+
+:- pred search_proc_for_par_conj(pred_id::in, proc_id::in,
+    module_info::in, module_info::out, io::di, io::uo) is det.
+
+search_proc_for_par_conj(PredId, ProcId, !ModuleInfo, !IO) :-
+    some [!PredInfo, !ProcInfo] (
+        module_info_preds(!.ModuleInfo, PredTable0),
+        map.lookup(PredTable0, PredId, !:PredInfo),
+        pred_info_get_procedures(!.PredInfo, ProcTable0),
+        map.lookup(ProcTable0, ProcId, !:ProcInfo),
+
+        proc_info_get_goal(!.ProcInfo, Body0),
+        proc_info_get_varset(!.ProcInfo, VarSet0),
+        proc_info_get_vartypes(!.ProcInfo, VarTypes0),
+        proc_info_get_initial_instmap(!.ProcInfo, !.ModuleInfo, InstMap),
+
+        search_goal_for_par_conj(!.ModuleInfo, 
+            VarSet0, VarSet, VarTypes0, VarTypes,
+            InstMap, _, Body0, Body, !IO),
+
+        proc_info_set_varset(VarSet, !ProcInfo),
+        proc_info_set_vartypes(VarTypes, !ProcInfo),
+        proc_info_set_goal(Body, !ProcInfo),
+
+        requantify_proc(!ProcInfo),
+
+        RecomputeAtomic = no,
+        recompute_instmap_delta_proc(RecomputeAtomic, !ProcInfo, !ModuleInfo),
+
+        map.det_update(ProcTable0, ProcId, !.ProcInfo, ProcTable),
+        pred_info_set_procedures(ProcTable, !PredInfo),
+
+        map.det_update(PredTable0, PredId, !.PredInfo, PredTable),
+        module_info_set_preds(PredTable, !ModuleInfo)
+    ).
+
+:- pred search_goal_for_par_conj(module_info::in,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
+    instmap::in, instmap::out, hlds_goal::in, hlds_goal::out,
+    io::di, io::uo) is det.
+
+search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap0, InstMap,
+        Goal0, Goal, !IO) :-
+    search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap0,
+        Goal0, Goal, !IO),
+    update_instmap(Goal0, InstMap0, InstMap).
+
+:- pred search_goal_for_par_conj_2(module_info::in,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
+    instmap::in, hlds_goal::in, hlds_goal::out, io::di, io::uo) is det.
+
+search_goal_for_par_conj_2(_ModuleInfo, !VarSet, !VarTypes, _InstMap,
+        G @ (Goal - _), G, !IO) :-
+    Goal = unify(_, _, _, _Kind, _).
+search_goal_for_par_conj_2(_ModuleInfo, !VarSet, !VarTypes, _InstMap,
+        G @ (Goal - _), G, !IO) :-
+    Goal = call(_CallPredId, _CallProcId, _CallArgs, _, _, _).
+search_goal_for_par_conj_2(_ModuleInfo, !VarSet, !VarTypes, _InstMap,
+        G @ (Goal - _), G, !IO) :-
+    Goal = generic_call(_Details, _Args, _ArgModes, _).
+search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap,
+        not(Goal0) - GI, not(Goal) - GI, !IO) :-
+    search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap, _,
+        Goal0, Goal, !IO).
+search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap,
+        Goal0 - GI, Goal - GI, !IO) :-
+    Goal0 = scope(Reason, ScopeGoal0),
+    search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap, _,
+        ScopeGoal0, ScopeGoal, !IO),
+    Goal = scope(Reason, ScopeGoal).
+search_goal_for_par_conj_2(_ModuleInfo, !VarSet, !VarTypes, _InstMap,
+        G @ (Goal - _), G, !IO) :-
+    Goal = foreign_proc(_Attributes, _, _, _, _, _).
+search_goal_for_par_conj_2(_, _,_, _,_, _, shorthand(_) - _, _, _,_) :-
+    unexpected(this_file,
+        "shorthand goal encountered during dependent parallel " ++
+        "conjunction transformation.").
+search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap,
+        Goal0 - GI, Goal - GI, !IO) :-
+    Goal0 = switch(Var, CanFail, Cases0),
+    search_cases_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
+        Cases0, Cases, !IO),
+    Goal = switch(Var, CanFail, Cases).
+search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap0,
+        Goal0 - GI, Goal - GI, !IO) :-
+    Goal0 = if_then_else(Quant, If0, Then0, Else0),
+    search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes,
+        InstMap0, InstMap1, If0, If, !IO),
+    search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes,
+        InstMap1, _InstMap2, Then0, Then, !IO),
+    search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes,
+        InstMap0, _InstMap3, Else0, Else, !IO),
+    Goal = if_then_else(Quant, If, Then, Else).
+search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap,
+        Goal0 - GI, Goal - GI, !IO) :-
+    Goal0 = disj(Goals0),
+    search_goals_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
+        Goals0, Goals, !IO),
+    Goal = disj(Goals).
+search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap,
+        Goal0 - GI, Goal, !IO) :-
+    Goal0 = conj(ConjType, Goals0),
+    (
+        ConjType = plain_conj,
+        search_goals_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
+            Goals0, Goals, !IO),
+        conj_list_to_goal(Goals, GI, Goal)
+    ;
+	ConjType = parallel_conj,
+	munge_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
+            Goals0, GI, Goal, !IO)
+    ).
+
+:- pred search_cases_for_par_conj(module_info::in, 
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
+    instmap::in, list(case)::in, list(case)::out, io::di, io::uo) is det.
+
+search_cases_for_par_conj(_ModuleInfo, !VarSet, !VarTypes, _InstMap,
+        [], [], !IO).
+search_cases_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
+        [Case0 | Cases0], [Case | Cases], !IO) :-
+    Case0 = case(Functor, Goal0),
+    search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap, _,
+        Goal0, Goal, !IO),
+    Case = case(Functor, Goal),
+    search_cases_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
+        Cases0, Cases, !IO).
+
+:- pred search_goals_for_par_conj(module_info::in,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
+    instmap::in, hlds_goals::in, hlds_goals::out, io::di, io::uo) is det.
+
+search_goals_for_par_conj(_ModuleInfo, !VarSet, !VarTypes, _InstMap0,
+        [], [], !IO).
+search_goals_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap0,
+        [Goal0 | Goals0], [Goal | Goals], !IO) :-
+    search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap0, InstMap,
+        Goal0, Goal, !IO),
+    search_goals_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
+        Goals0, Goals, !IO).
+
+%-----------------------------------------------------------------------------%
+
+    % We found a parallel conjunction.  We have to check if there are
+    % dependencies between the conjuncts and insert the synchronisation.
+    %
+:- pred munge_par_conj(module_info::in, prog_varset::in, prog_varset::out,
+    vartypes::in, vartypes::out, instmap::in,
+    hlds_goals::in, hlds_goal_info::in, hlds_goal::out, io::di, io::uo) is det.
+
+munge_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
+        Conjuncts0, GoalInfo, NewGoal, !IO) :-
+    % Search subgoals for nested parallel conjunctions.
+    search_goals_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
+        Conjuncts0, Conjuncts, !IO),
+
+    % Find the variables that are shared between conjunctions.
+    find_shared_variables(ModuleInfo, InstMap, Conjuncts, SharedVars),
+
+    % Dependent parallel conjunctions only supported on lowlevel C parallel
+    % grades.  For other grades convert any dependent parallel conjunctions
+    % into plain conjunctions.
+    globals.io_get_target(Target, !IO),
+    globals.io_lookup_bool_option(highlevel_code, HighLevelCode, !IO),
+    globals.io_lookup_bool_option(parallel, Parallel, !IO),
+    (if
+        set.non_empty(SharedVars),
+        Target = target_c,
+        HighLevelCode = no,
+        Parallel = yes
+    then
+        transform_conjunction(ModuleInfo, SharedVars,
+            Conjuncts, GoalInfo, NewGoal, InstMap, !VarSet, !VarTypes)
+    else
+        conj_list_to_goal(Conjuncts, GoalInfo, NewGoal)
+    ).
+
+    % Transforming the parallel conjunction.
+    %
+    % As a simple first step, all we do is insert waits and signals directly
+    % into the conjunction.  If a conjunct produces a shared variable we turn
+    % that conjunct into a sequential conjunction:
+    %
+    %   prod(Y)  ==>  ( prod(Y), impure signal(PrY, Y) )
+    %
+    % If the conjunct consumes a shared variable we will turn that conjunct
+    % into a sequential conjunction:
+    %
+    %   consume(Y)  ==>  ( wait(PrY, Y), consume(Y) )
+    %
+    % References to shared variables need to be renamed apart so that the
+    % conjuncts only share promises.
+    %
+:- pred transform_conjunction(module_info::in, 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) is det.
+
+transform_conjunction(ModuleInfo, SharedVars, Goals, GoalInfo, NewGoal,
+        InstMap, !VarSet, !VarTypes) :-
+    allocate_promises(ModuleInfo, SharedVars, !VarTypes, !VarSet,
+        AllocatePromises, PromiseMap),
+    list.map_foldl3(transform_conjunct(ModuleInfo, SharedVars, PromiseMap),
+        Goals, NewGoals, InstMap, _, !VarSet, !VarTypes),
+    % XXX not sure about GoalInfo
+    Conj = AllocatePromises ++ [conj(parallel_conj, NewGoals) - GoalInfo],
+    conj_list_to_goal(Conj, GoalInfo, NewGoal).
+
+:- pred transform_conjunct(module_info::in, set(prog_var)::in,
+    promise_map::in, hlds_goal::in, hlds_goal::out,
+    instmap::in, instmap::out, prog_varset::in, prog_varset::out,
+    vartypes::in, vartypes::out) is det.
+
+transform_conjunct(ModuleInfo, SharedVars, PromiseMap, Goal0, Goal,
+        !InstMap, !VarSet, !VarTypes) :-
+    goal_get_nonlocals(Goal0, Nonlocals),
+    set.intersect(Nonlocals, SharedVars, Intersect),
+    (if set.empty(Intersect) then
+        Goal = Goal0,
+        update_instmap(Goal, !InstMap)
+    else
+        Goal0 = (_ - GoalInfo0),
+        goal_info_get_instmap_delta(GoalInfo0, InstMapDelta0),
+
+        % Divide shared variables into those that are produced by this
+        % conjunction, and those that are consumed.
+        set.divide(produced_variable(ModuleInfo, !.InstMap, InstMapDelta0),
+            Intersect, ProducedVars, ConsumedVars),
+
+        % Rename references to consumed variables.  We let the producer keep
+        % the original name.  This helps because there may be references to
+        % the original name following the parallel conjunction.
+        create_variables(set.to_sorted_list(ConsumedVars),
+            !.VarSet, !.VarTypes,
+            !VarSet, !VarTypes, map.init, Renaming),
+        rename_vars_in_goal(Renaming, Goal0, Goal1),
+
+        % Make wait and signal goals.
+        list.map(make_wait(ModuleInfo, PromiseMap, Renaming),
+            set.to_sorted_list(ConsumedVars), WaitGoals),
+        list.map(make_signal(ModuleInfo, PromiseMap),
+            set.to_sorted_list(ProducedVars), SignalGoals),
+
+        % Insert signal goals after the conjunct and waits before the conjunct.
+        Goal1 = _ - GoalInfo,
+        conj_list_to_goal(WaitGoals, GoalInfo, WaitGoalsConj),
+        conjoin_goal_and_goal_list(Goal1, SignalGoals, Goal2),
+        conjoin_goals(WaitGoalsConj, Goal2, Goal),
+
+        % Use the goal_info from _before_ the renaming of variables to update
+        % the instmap, as the rest of the conjuncts won't know anything about
+        % the new names.
+        update_instmap(Goal0, !InstMap)
+    ).
+
+    % Make a goal to wait on a promise for a consumed variable to be produced.
+    %
+:- pred make_wait(module_info::in, promise_map::in,
+    prog_var_renaming::in, prog_var::in, hlds_goal::out) is det.
+
+make_wait(ModuleInfo, PromiseMap, Renaming, ConsumedVar, WaitGoal) :-
+    map.lookup(PromiseMap, ConsumedVar, PromiseVar),
+    map.lookup(Renaming, ConsumedVar, WaitVar),
+
+    ModuleName = mercury_par_builtin_module,
+    PredName = "wait",
+    Args = [PromiseVar, WaitVar],
+    Features = [],
+    InstMapSrc = [WaitVar - ground(shared, none)],
+    Context = term.context_init,
+    goal_util.generate_simple_call(ModuleName, PredName, predicate,
+        only_mode, det, Args, Features, InstMapSrc, ModuleInfo,
+        Context, WaitGoal).
+
+    % Make a goal to signal that a variable is produced.
+    %
+:- pred make_signal(module_info::in, promise_map::in,
+    prog_var::in, hlds_goal::out) is det.
+
+make_signal(ModuleInfo, PromiseMap, ProducedVar, SignalGoal) :-
+    map.lookup(PromiseMap, ProducedVar, PromiseVar),
+
+    ModuleName = mercury_par_builtin_module,
+    PredName = "signal",
+    Args = [PromiseVar, ProducedVar],
+    Features = [],
+    InstMapSrc = [],
+    Context = term.context_init,
+    goal_util.generate_simple_call(ModuleName, PredName, predicate,
+        only_mode, det, Args, Features, InstMapSrc, ModuleInfo,
+        Context, SignalGoal).
+
+    % Succeed if Var is a variable bound between InstMap and
+    % InstMap+InstMapDelta.
+    %
+:- pred produced_variable(module_info::in, instmap::in, instmap_delta::in,
+    prog_var::in) is semidet.
+
+produced_variable(ModuleInfo, InstMap, InstMapDelta, Var) :-
+    instmap.lookup_var(InstMap, Var, OldVarInst),
+    inst_is_free(ModuleInfo, OldVarInst),
+    instmap_delta_search_var(InstMapDelta, Var, VarInst),
+    inst_is_bound(ModuleInfo, VarInst).
+
+%-----------------------------------------------------------------------------%
+
+    % If a variable is nonlocal to a conjunct, and appears in the
+    % instmap_delta of a _different_ conjunct, then we say that variable is
+    % shared.
+    %
+    % (1) A variable must be nonlocal to a conjunct if it is shared.
+    % (2) If the variable does not appear in the instmap_delta
+    %     of any of the conjuncts of the parallel conjunction
+    %     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
+    % more elegant way to find the shared variables somewhere, using multisets.
+    %
+:- pred find_shared_variables(module_info::in, instmap::in, hlds_goals::in,
+    set(prog_var)::out) is det.
+
+find_shared_variables(ModuleInfo, InstMap, Goals, SharedVars) :-
+    list.map2(get_nonlocals_and_instmaps, Goals, Nonlocals, InstMapDeltas),
+    find_shared_variables_2(ModuleInfo, 0, Nonlocals, InstMap, InstMapDeltas,
+        set.init, SharedVars).
+
+:- pred get_nonlocals_and_instmaps(hlds_goal::in,
+    set(prog_var)::out, instmap_delta::out) is det.
+
+get_nonlocals_and_instmaps(_Goal - GoalInfo, Nonlocals, InstMapDelta) :-
+    goal_info_get_nonlocals(GoalInfo, Nonlocals),
+    goal_info_get_instmap_delta(GoalInfo, InstMapDelta).
+
+:- pred find_shared_variables_2(module_info::in, int::in,
+    list(set(prog_var))::in, instmap::in, list(instmap_delta)::in,
+    set(prog_var)::in, set(prog_var)::out) is det.
+
+find_shared_variables_2(_ModuleInfo, _ConjunctIndex,
+        [], _InstMap, _InstMapDeltas, !SharedVars).
+find_shared_variables_2(ModuleInfo, ConjunctIndex,
+        [Nonlocals | MoreNonlocals], InstMap, InstMapDeltas, !SharedVars) :-
+    det_delete_nth(ConjunctIndex, InstMapDeltas, InstMapDeltasB),
+    % Keep only nonlocals which were not already bound at the start of the
+    % parallel conjunction.
+    Filter = (pred(Var::in) is semidet :-
+        not (
+            instmap.lookup_var(InstMap, Var, VarInst),
+            inst_is_bound(ModuleInfo, VarInst)
+        )
+    ),
+    set.filter(Filter, Nonlocals) = UnboundNonlocals,
+    set.fold(find_changed_vars(ModuleInfo, InstMapDeltasB),
+        UnboundNonlocals, !SharedVars),
+    find_shared_variables_2(ModuleInfo, ConjunctIndex+1, MoreNonlocals,
+        InstMap, InstMapDeltas, !SharedVars).
+
+:- pred find_changed_vars(module_info::in, list(instmap_delta)::in,
+    prog_var::in, set(prog_var)::in, set(prog_var)::out) is det.
+
+find_changed_vars(ModuleInfo, InstMapDeltas, UnboundVar, !SharedVars) :-
+    (if
+        % Is the unbound nonlocal bound in one of the conjuncts?
+        InstMapDelta `member` InstMapDeltas,
+        instmap_delta_search_var(InstMapDelta, UnboundVar, Inst),
+        inst_is_bound(ModuleInfo, Inst)
+    then
+        svset.insert(UnboundVar, !SharedVars)
+    else
+        true
+    ).
+
+%-----------------------------------------------------------------------------%
+
+:- type promise_map == map(prog_var, prog_var).
+
+    % Make goals to allocate promise objects for variables shared
+    % between two parallel conjuncts (a producer and one or more consumers).
+    %
+:- pred allocate_promises(module_info::in, set(prog_var)::in,
+    vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
+    hlds_goals::out, promise_map::out) is det.
+
+allocate_promises(ModuleInfo, SharedVars, !VarTypes, !VarSet,
+        AllocGoals, PromiseMap) :-
+    set.fold4(allocate_promise(ModuleInfo), SharedVars,
+        !VarTypes, !VarSet, [], AllocGoals, map.init, PromiseMap).
+
+:- pred allocate_promise(module_info::in, prog_var::in,
+    vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
+    hlds_goals::in, hlds_goals::out, promise_map::in, promise_map::out) is det.
+
+allocate_promise(ModuleInfo, SharedVar, !VarTypes, !VarSet,
+        !AllocGoals, !PromiseMap) :-
+    map.lookup(!.VarTypes, SharedVar, SharedVarType),
+    make_promise(ModuleInfo, SharedVarType, SharedVar, !VarTypes, !VarSet,
+        AllocGoal, PromiseVar),
+    list.cons(AllocGoal, !AllocGoals),
+    svmap.det_insert(SharedVar, PromiseVar, !PromiseMap).
+
+:- pred make_promise(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.
+
+make_promise(ModuleInfo, SharedVarType, SharedVar, !VarTypes, !VarSet,
+        AllocGoal, PromiseVar) :-
+    construct_promise_type(SharedVarType, PromiseType),
+    varset.lookup_name(!.VarSet, SharedVar, SharedVarName),
+    svvarset.new_named_var("Promise" ++ SharedVarName, PromiseVar, !VarSet),
+    svmap.det_insert(PromiseVar, PromiseType, !VarTypes),
+
+    ModuleName = mercury_par_builtin_module,
+    PredName = "new_promise",
+    Args = [PromiseVar],
+    Features = [],
+    InstMapSrc = [PromiseVar - ground(shared, none)],
+    Context = term.context_init,
+    goal_util.generate_simple_call(ModuleName, PredName, predicate,
+        only_mode, det, Args, Features, InstMapSrc, ModuleInfo,
+        Context, AllocGoal).
+
+    % Construct type promise(T) given type T.
+    %
+:- pred construct_promise_type(mer_type::in, mer_type::out) is det.
+
+construct_promise_type(T, PromiseT) :-
+    Prom = qualified(mercury_private_builtin_module, "prom"),
+    PromiseCtor = type_ctor(Prom, 1),
+    construct_type(PromiseCtor, [T], PromiseT).
+
+%-----------------------------------------------------------------------------%
+
+:- pred det_delete_nth(int::in, list(T)::in, list(T)::out) is det.
+
+det_delete_nth(N, List0, List) :-
+    list.det_split_list(N, List0, Left, Right),
+    List = Left ++ det_tail(Right).
+
+%-----------------------------------------------------------------------------%
+
+:- func this_file = string.
+
+this_file = "dep_par_conj.m".
+
+%-----------------------------------------------------------------------------%
+:- end_module dep_par_conj.
+%-----------------------------------------------------------------------------%
Index: compiler/hlds_goal.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_goal.m,v
retrieving revision 1.159
diff -u -r1.159 hlds_goal.m
--- compiler/hlds_goal.m	8 Jun 2006 08:19:13 -0000	1.159
+++ compiler/hlds_goal.m	19 Jun 2006 04:14:04 -0000
@@ -2048,9 +2048,8 @@
 goal_is_atomic(generic_call(_, _, _, _)) = yes.
 goal_is_atomic(call(_, _, _, _, _, _)) = yes.
 goal_is_atomic(foreign_proc(_, _, _, _, _,  _)) = yes.
-goal_is_atomic(conj(plain_conj, Conj)) =
+goal_is_atomic(conj(_, Conj)) =
     ( Conj = [] -> yes ; no ).
-goal_is_atomic(conj(parallel_conj, _)) = no.
 goal_is_atomic(disj(Disj)) =
     ( Disj = [] -> yes ; no ).
 goal_is_atomic(if_then_else(_, _, _, _)) = no.
Index: compiler/inlining.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/inlining.m,v
retrieving revision 1.139
diff -u -r1.139 inlining.m
--- compiler/inlining.m	8 Jun 2006 08:19:15 -0000	1.139
+++ compiler/inlining.m	18 Jun 2006 08:12:22 -0000
@@ -540,7 +540,7 @@
             inlining_in_conj(Goals0, Goals, !Info)
         ;
             ConjType = parallel_conj,
-            inlining_in_goals(Goals0, Goals, !Info)
+            inlining_in_par_conj(Goals0, Goals, !Info)
         ),
         Goal = conj(ConjType, Goals),
         GoalInfo = GoalInfo0
@@ -832,6 +832,18 @@
     inlining_in_conj(Goals0, Goals1, !Info),
     list.append(Goal1List, Goals1, Goals).
 
+:- pred inlining_in_par_conj(list(hlds_goal)::in, list(hlds_goal)::out,
+    inline_info::in, inline_info::out) is det.
+
+inlining_in_par_conj([], [], !Info).
+inlining_in_par_conj([Goal0 | Goals0], Goals, !Info) :-
+    % Since a single goal may become a parallel conjunction,
+    % we flatten the conjunction as we go.
+    inlining_in_goal(Goal0, Goal1, !Info),
+    goal_to_par_conj_list(Goal1, Goal1List),
+    inlining_in_par_conj(Goals0, Goals1, !Info),
+    list.append(Goal1List, Goals1, Goals).
+
 %-----------------------------------------------------------------------------%
 
     % Check to see if we should inline a call.
Index: compiler/live_vars.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/live_vars.m,v
retrieving revision 1.119
diff -u -r1.119 live_vars.m
--- compiler/live_vars.m	29 Mar 2006 08:06:53 -0000	1.119
+++ compiler/live_vars.m	18 Jun 2006 08:17:12 -0000
@@ -149,7 +149,7 @@
     % set of live variables, i.e. vars which have been referenced and may be
     % referenced again (during forward execution). `ResumeVars' is the set
     % of variables that may or may not be `live' during the current forward
-    % execution but will become live again on backtracking. `SaveInfo' is the
+    % execution but will become live again on backtracking. `StackAlloc' is the
     % interference graph, i.e. the set of sets of variables which need to be
     % on the stack at the same time.
     %
@@ -179,7 +179,7 @@
         NeedInParConj = need_in_par_conj(LiveSet),
         record_par_conj(NeedInParConj, GoalInfo0, GoalInfo, !StackAlloc),
         build_live_sets_in_par_conj(Goals0, Goals, ResumeVars0, AllocData,
-            !StackAlloc, !Liveness, !NondetLiveness)
+            !StackAlloc, !.Liveness, !Liveness, !NondetLiveness)
     ).
 
 build_live_sets_in_goal_2(disj(Goals0), disj(Goals), GoalInfo, GoalInfo,
@@ -423,17 +423,18 @@
 
 :- pred build_live_sets_in_par_conj(list(hlds_goal)::in, list(hlds_goal)::out,
     set(prog_var)::in, alloc_data::in, T::in, T::out,
-    set(prog_var)::in, set(prog_var)::out,
+    set(prog_var)::in, set(prog_var)::in, set(prog_var)::out,
     set(prog_var)::in, set(prog_var)::out) is det <= stack_alloc_info(T).
 
 build_live_sets_in_par_conj([], [], _, _,
-        !StackAlloc, !Liveness, !NondetLiveness).
+        !StackAlloc, _Liveness0, !Liveness, !NondetLiveness).
 build_live_sets_in_par_conj([Goal0 | Goals0], [Goal | Goals], ResumeVars0,
-        AllocData, !StackAlloc, !Liveness, !NondetLiveness) :-
+        AllocData, !StackAlloc, Liveness0, !Liveness, !NondetLiveness) :-
     build_live_sets_in_goal(Goal0, Goal, ResumeVars0, AllocData,
-        !StackAlloc, !Liveness, !NondetLiveness),
+        !StackAlloc, Liveness0, Liveness1, !NondetLiveness),
+    set.union(Liveness1, !Liveness),
     build_live_sets_in_par_conj(Goals0, Goals, ResumeVars0, AllocData,
-        !StackAlloc, !Liveness, !NondetLiveness).
+        !StackAlloc, Liveness0, !Liveness, !NondetLiveness).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/liveness.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/liveness.m,v
retrieving revision 1.145
diff -u -r1.145 liveness.m
--- compiler/liveness.m	29 Mar 2006 08:06:54 -0000	1.145
+++ compiler/liveness.m	19 Jun 2006 04:24:57 -0000
@@ -995,14 +995,7 @@
         !.GoalExpr = foreign_proc(_, _, _, _, _, _)
     ;
         !.GoalExpr = conj(ConjType, Goals0),
-        (
-            ConjType = plain_conj,
-            delay_death_conj(Goals0, Goals, !BornVars, !DelayedDead, VarSet)
-        ;
-            ConjType = parallel_conj,
-            delay_death_par_conj(Goals0, Goals, !BornVars, !DelayedDead,
-                VarSet)
-        ),
+        delay_death_conj(Goals0, Goals, !BornVars, !DelayedDead, VarSet),
         !:GoalExpr = conj(ConjType, Goals)
     ;
         !.GoalExpr = disj(Goals0),
@@ -1073,20 +1066,6 @@
     delay_death_goal(Goal0, Goal, !BornVars, !DelayedDead, VarSet),
     delay_death_conj(Goals0, Goals, !BornVars, !DelayedDead, VarSet).
 
-:- pred delay_death_par_conj(list(hlds_goal)::in, list(hlds_goal)::out,
-    set(prog_var)::in, set(prog_var)::out,
-    set(prog_var)::in, set(prog_var)::out, prog_varset::in) is det.
-
-delay_death_par_conj([], [], !BornVars, !DelayedDead, _).
-delay_death_par_conj([Goal0 | Goals0], [Goal | Goals],
-        BornVars0, BornVars, DelayedDead0, DelayedDead, VarSet) :-
-    delay_death_goal(Goal0, Goal, BornVars0, BornVarsGoal,
-        DelayedDead0, DelayedDeadGoal, VarSet),
-    delay_death_par_conj(Goals0, Goals, BornVars0, BornVarsGoals,
-        DelayedDead0, DelayedDeadGoals, VarSet),
-    set.union(BornVarsGoal, BornVarsGoals, BornVars),
-    set.union(DelayedDeadGoal, DelayedDeadGoals, DelayedDead).
-
 :- pred delay_death_disj(list(hlds_goal)::in,
     assoc_list(hlds_goal, set(prog_var))::out,
     set(prog_var)::in, set(prog_var)::in, prog_varset::in,
@@ -1481,8 +1460,8 @@
 
 detect_resume_points_in_par_conj([], [], !Liveness, _, _).
 detect_resume_points_in_par_conj([Goal0 | Goals0], [Goal | Goals],
-        Liveness0, LivenessFirst, LiveInfo, ResumeVars0) :-
-    detect_resume_points_in_goal(Goal0, Goal, Liveness0, LivenessFirst,
+        Liveness0, Liveness, LiveInfo, ResumeVars0) :-
+    detect_resume_points_in_goal(Goal0, Goal, Liveness0, Liveness,
         LiveInfo, ResumeVars0),
     detect_resume_points_in_par_conj(Goals0, Goals,
         Liveness0, _LivenessRest, LiveInfo, ResumeVars0).
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.391
diff -u -r1.391 mercury_compile.m
--- compiler/mercury_compile.m	14 Jun 2006 08:14:49 -0000	1.391
+++ compiler/mercury_compile.m	21 Jun 2006 07:04:21 -0000
@@ -94,6 +94,7 @@
 :- import_module transform_hlds.ctgc.structure_reuse.analysis.
 :- import_module transform_hlds.ctgc.structure_sharing.
 :- import_module transform_hlds.ctgc.structure_sharing.analysis.
+:- import_module transform_hlds.dep_par_conj.
 :- import_module transform_hlds.size_prof.
 :- import_module ll_backend.deep_profiling.
 
@@ -2431,6 +2432,9 @@
 
     maybe_structure_reuse_analysis(Verbose, Stats, !HLDS, !IO), 
     maybe_dump_hlds(!.HLDS, 212, "structure_reuse", !DumpInfo, !IO), 
+
+    maybe_dependent_par_conj(Verbose, Stats, !HLDS, !IO),
+    maybe_dump_hlds(!.HLDS, 214, "dependent_par_conj", !DumpInfo, !IO), 
     
     % If we are compiling in a deep profiling grade then now rerun simplify.
     % The reason for doing this now is that we want to take advantage of any
@@ -3688,6 +3692,20 @@
         Sharing = no
     ).
 
+:- pred maybe_dependent_par_conj(bool::in, bool::in,
+    module_info::in, module_info::out, io::di, io::uo) is det.
+
+maybe_dependent_par_conj(Verbose, Stats, !HLDS, !IO) :- 
+    % XXX only do this if the module actually has parallel conjunctions
+    % This pass also converts dependent parallel conjunctions into
+    % plain conjunctions if we are not building in a parallel grade.
+    maybe_write_string(Verbose,
+        "% Dependent parallel conjunction transformation...\n", !IO), 
+    maybe_flush_output(Verbose, !IO), 
+    dependent_par_conj(!HLDS, !IO), 
+    maybe_write_string(Verbose, "% done.\n", !IO),
+    maybe_report_stats(Stats, !IO).
+
 :- pred maybe_structure_reuse_analysis(bool::in, bool::in,
     module_info::in, module_info::out, io::di, io::uo) is det.
 
Index: compiler/mode_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mode_util.m,v
retrieving revision 1.186
diff -u -r1.186 mode_util.m
--- compiler/mode_util.m	20 Apr 2006 05:36:56 -0000	1.186
+++ compiler/mode_util.m	18 Jun 2006 08:19:48 -0000
@@ -1156,14 +1156,15 @@
     recompute_instmap_delta_1(Atomic, Goal0, Goal, VarTypes, InstMap,
         InstMapDelta, !RI).
 recompute_instmap_delta_par_conj(Atomic, [Goal0 | Goals0], [Goal | Goals],
-        VarTypes, InstMap, NonLocals, InstMapDelta, !RI) :-
+        VarTypes, InstMap0, NonLocals, InstMapDelta, !RI) :-
     Goals0 = [_ | _],
     recompute_instmap_delta_1(Atomic, Goal0, Goal,
-        VarTypes, InstMap, InstMapDelta0, !RI),
+        VarTypes, InstMap0, InstMapDelta0, !RI),
+    instmap.apply_instmap_delta(InstMap0, InstMapDelta0, InstMap1),
     recompute_instmap_delta_par_conj(Atomic, Goals0, Goals,
-        VarTypes, InstMap, NonLocals, InstMapDelta1, !RI),
-    update_module_info(unify_instmap_delta(InstMap, NonLocals,
-        InstMapDelta0, InstMapDelta1), InstMapDelta, !RI).
+        VarTypes, InstMap1, NonLocals, InstMapDelta1, !RI),
+    instmap_delta_apply_instmap_delta(InstMapDelta0, InstMapDelta1,
+        large_overlay, InstMapDelta).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/modes.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modes.m,v
retrieving revision 1.334
diff -u -r1.334 modes.m
--- compiler/modes.m	8 Jun 2006 08:19:24 -0000	1.334
+++ compiler/modes.m	19 Jun 2006 04:19:03 -0000
@@ -251,7 +251,7 @@
 :- pred modecheck_lambda_final_insts(list(prog_var)::in, list(mer_inst)::in,
     hlds_goal::in, hlds_goal::out, mode_info::in, mode_info::out) is det.
 
-:- pred mode_info_add_goals_live_vars(list(hlds_goal)::in,
+:- pred mode_info_add_goals_live_vars(conj_type::in, list(hlds_goal)::in,
     mode_info::in, mode_info::out) is det.
 
 :- pred mode_info_remove_goals_live_vars(list(hlds_goal)::in,
@@ -1261,7 +1261,7 @@
     mode_info_set_in_dupl_for_switch(InDuplForSwitch, !ModeInfo).
 
 compute_goal_instmap_delta(InstMap0, Goal, !GoalInfo, !ModeInfo) :-
-    ( Goal = conj(plain_conj, []) ->
+    ( Goal = conj(_, []) ->
         % When modecheck_unify.m replaces a unification with a dead variable
         % with `true', make sure the instmap_delta of the goal is empty.
         % The code generator and mode_util.recompute_instmap_delta can be
@@ -1286,43 +1286,16 @@
             Goal = conj(plain_conj, [])
         ;
             Goals0 = [_ | _],
-            modecheck_conj_list(Goals0, Goals, !ModeInfo, !IO),
+            modecheck_conj_list(ConjType, Goals0, Goals, !ModeInfo, !IO),
             conj_list_to_goal(Goals, GoalInfo0, Goal - _GoalInfo)
         ),
         mode_checkpoint(exit, "conj", !ModeInfo, !IO)
     ;
         ConjType = parallel_conj,
-        % To modecheck a parallel conjunction, we modecheck each
-        % conjunct independently (just like for disjunctions).
-        % To make sure that we don't try to bind a variable more than
-        % once (by binding it in more than one conjunct), we maintain a
-        % datastructure that keeps track of three things:
-        %
-        % - the set of variables that are nonlocal to the conjuncts
-        %   (which may be a superset of the nonlocals of the par_conj
-        %   as a whole);
-        % - the set of nonlocal variables that have been bound in the
-        %   current conjunct; and
-        % - the set of variables that were bound in previous conjuncts.
-        %
-        % When binding a variable, we check that it wasn't in the set of
-        % variables bound in other conjuncts, and we add it to the set of
-        % variables bound in this conjunct.
-        %
-        % At the end of the conjunct, we add the set of variables bound in
-        % this conjunct to the set of variables bound in previous conjuncts
-        % and set the set of variables bound in the current conjunct to
-        % empty.
-        %
-        % A stack of these structures is maintained to handle nested parallel
-        % conjunctions properly.
-        %
         mode_checkpoint(enter, "par_conj", !ModeInfo, !IO),
-        goal_info_get_nonlocals(GoalInfo0, NonLocals),
-        modecheck_par_conj_list(Goals0, Goals, NonLocals, InstMapNonlocalList,
-            !ModeInfo, !IO),
-        Goal = conj(parallel_conj, Goals),
-        instmap_unify(NonLocals, InstMapNonlocalList, !ModeInfo),
+        % empty parallel conjunction should not be a common case
+        modecheck_conj_list(ConjType, Goals0, Goals, !ModeInfo, !IO),
+        par_conj_list_to_goal(Goals, GoalInfo0, Goal - _GoalInfo),
         mode_checkpoint(exit, "par_conj", !ModeInfo, !IO)
     ).
 
@@ -1750,7 +1723,7 @@
         % is not, the main unification will be delayed until after the
         % argument unifications, which turns them into assignments,
         % and we end up repeating the process forever.
-        mode_info_add_goals_live_vars(GoalList0, !ModeInfo),
+        mode_info_add_goals_live_vars(plain_conj, GoalList0, !ModeInfo),
         modecheck_conj_list_no_delay(GoalList0, GoalList, !ModeInfo, !IO),
         Goal = conj(plain_conj, GoalList),
         mode_info_set_checking_extra_goals(no, !ModeInfo),
@@ -1934,10 +1907,11 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred modecheck_conj_list(list(hlds_goal)::in, list(hlds_goal)::out,
+:- pred modecheck_conj_list(conj_type::in,
+    list(hlds_goal)::in, list(hlds_goal)::out,
     mode_info::in, mode_info::out, io::di, io::uo) is det.
 
-modecheck_conj_list(Goals0, Goals, !ModeInfo, !IO) :-
+modecheck_conj_list(ConjType, Goals0, Goals, !ModeInfo, !IO) :-
     mode_info_get_errors(!.ModeInfo, OldErrors),
     mode_info_set_errors([], !ModeInfo),
 
@@ -1948,14 +1922,14 @@
     mode_info_set_delay_info(DelayInfo1, !ModeInfo),
 
     mode_info_get_live_vars(!.ModeInfo, LiveVars1),
-    mode_info_add_goals_live_vars(Goals0, !ModeInfo),
+    mode_info_add_goals_live_vars(ConjType, Goals0, !ModeInfo),
 
         % Try to schedule goals without inserting any solver
         % initialisation calls by setting the mode_info flag
         % may_initialise_solver_vars to no.
     mode_info_set_may_initialise_solver_vars(no, !ModeInfo),
 
-    modecheck_conj_list_2(Goals0, Goals1,
+    modecheck_conj_list_2(ConjType, Goals0, Goals1,
         [], RevImpurityErrors0, !ModeInfo, !IO),
 
     mode_info_get_delay_info(!.ModeInfo, DelayInfo2),
@@ -1964,8 +1938,9 @@
 
         % Otherwise try scheduling by inserting solver
         % initialisation calls where necessary.
-    modecheck_delayed_solver_goals(Goals2, DelayedGoals0, DelayedGoals,
-        RevImpurityErrors0, RevImpurityErrors, !ModeInfo, !IO),
+    modecheck_delayed_solver_goals(ConjType, Goals2,
+        DelayedGoals0, DelayedGoals, RevImpurityErrors0, RevImpurityErrors,
+        !ModeInfo, !IO),
 
     Goals = Goals1 ++ Goals2,
 
@@ -2004,8 +1979,8 @@
         % Restore the value of the may_initialise_solver_vars flag.
     mode_info_set_may_initialise_solver_vars(MayInitEntryValue, !ModeInfo).
 
-mode_info_add_goals_live_vars([], !ModeInfo).
-mode_info_add_goals_live_vars([Goal | Goals], !ModeInfo) :-
+mode_info_add_goals_live_vars(_ConjType, [], !ModeInfo).
+mode_info_add_goals_live_vars(ConjType, [Goal | Goals], !ModeInfo) :-
     % We add the live vars for the goals in the goal list
     % in reverse order, because this ensures that in the
     % common case (where there is no delaying), when we come
@@ -2013,13 +1988,13 @@
     % they will have been added last and will thus be
     % at the start of the list of live vars sets, which
     % makes them cheaper to remove.
-    mode_info_add_goals_live_vars(Goals, !ModeInfo),
+    mode_info_add_goals_live_vars(ConjType, Goals, !ModeInfo),
     (
         % Recurse into conjunctions, in case there are any conjunctions
         % that have not been flattened.
-        Goal = conj(plain_conj, ConjGoals) - _
+        Goal = conj(ConjType, ConjGoals) - _
     ->
-        mode_info_add_goals_live_vars(ConjGoals, !ModeInfo)
+        mode_info_add_goals_live_vars(ConjType, ConjGoals, !ModeInfo)
     ;
         goal_get_nonlocals(Goal, NonLocals),
         mode_info_add_live_vars(NonLocals, !ModeInfo)
@@ -2041,28 +2016,32 @@
 
 :- type impurity_errors == list(mode_error_info).
 
-    % Flatten conjunctions as we go.  Call modecheck_conj_list_3 to do
-    % the actual scheduling.
+    % Flatten conjunctions as we go, as long as they are of the same type).
+    % Call modecheck_conj_list_3 to do the actual scheduling.
     %
-:- pred modecheck_conj_list_2(list(hlds_goal)::in, list(hlds_goal)::out,
+:- pred modecheck_conj_list_2(conj_type::in,
+    list(hlds_goal)::in, list(hlds_goal)::out,
     impurity_errors::in, impurity_errors::out,
     mode_info::in, mode_info::out, io::di, io::uo) is det.
 
-modecheck_conj_list_2([], [], !ImpurityErrors, !ModeInfo, !IO).
-modecheck_conj_list_2([Goal0 | Goals0], Goals, !ImpurityErrors, !ModeInfo,
-        !IO) :-
+modecheck_conj_list_2(_ConjType, [], [], !ImpurityErrors, !ModeInfo, !IO).
+modecheck_conj_list_2(ConjType, [Goal0 | Goals0], Goals, !ImpurityErrors,
+        !ModeInfo, !IO) :-
     (
-        Goal0 = conj(plain_conj, ConjGoals) - _
+        Goal0 = conj(ConjType, ConjGoals) - _,
+        ConjType = plain_conj
     ->
         list.append(ConjGoals, Goals0, Goals1),
-        modecheck_conj_list_2(Goals1, Goals, !ImpurityErrors, !ModeInfo, !IO)
+        modecheck_conj_list_2(ConjType, Goals1, Goals, !ImpurityErrors,
+            !ModeInfo, !IO)
     ;
-        modecheck_conj_list_3(Goal0, Goals0, Goals, !ImpurityErrors,
+        modecheck_conj_list_3(ConjType, Goal0, Goals0, Goals, !ImpurityErrors,
             !ModeInfo, !IO)
     ).
 
-:- pred modecheck_conj_list_3(hlds_goal::in, list(hlds_goal)::in,
-    list(hlds_goal)::out, impurity_errors::in, impurity_errors::out,
+:- pred modecheck_conj_list_3(conj_type::in, hlds_goal::in,
+    list(hlds_goal)::in, list(hlds_goal)::out,
+    impurity_errors::in, impurity_errors::out,
     mode_info::in, mode_info::out, io::di, io::uo) is det.
 
     % Schedule a conjunction. If it is empty, then there is nothing to do.
@@ -2071,7 +2050,8 @@
     % (if any), and if not, we delay the goal. Then we continue attempting
     % to schedule all the rest of the goals.
     %
-modecheck_conj_list_3(Goal0, Goals0, Goals, !ImpurityErrors, !ModeInfo, !IO) :-
+modecheck_conj_list_3(ConjType, Goal0, Goals0, Goals, !ImpurityErrors,
+        !ModeInfo, !IO) :-
     Goal0 = _GoalExpr - GoalInfo0,
     ( goal_info_is_impure(GoalInfo0) ->
         Impure = yes,
@@ -2146,7 +2126,8 @@
         Goals2  = []
     ;
         % The remaining goals may still need to be flattened.
-        modecheck_conj_list_2(Goals1, Goals2, !ImpurityErrors, !ModeInfo, !IO)
+        modecheck_conj_list_2(ConjType, Goals1, Goals2, !ImpurityErrors,
+            !ModeInfo, !IO)
     ),
     (
         Errors = [_ | _],
@@ -2158,7 +2139,7 @@
         % in the list of successfully scheduled goals.
         % We flatten out conjunctions if we can. They can arise
         % when Goal0 was a scope(from_ground_term, _) goal.
-        ( Goal = conj(plain_conj, SubGoals) - _ ->
+        ( Goal = conj(ConjType, SubGoals) - _ ->
             Goals = ScheduledSolverGoals ++ SubGoals ++ Goals2
         ;
             Goals = ScheduledSolverGoals ++ [Goal | Goals2]
@@ -2170,25 +2151,25 @@
     % from inst free to inst any. This predicate attempts to schedule
     % such goals.
     %
-:- pred modecheck_delayed_solver_goals(list(hlds_goal)::out,
+:- pred modecheck_delayed_solver_goals(conj_type::in, list(hlds_goal)::out,
     list(delayed_goal)::in, list(delayed_goal)::out,
     impurity_errors::in, impurity_errors::out,
     mode_info::in, mode_info::out, io::di, io::uo) is det.
 
-modecheck_delayed_solver_goals(Goals, DelayedGoals0, DelayedGoals,
+modecheck_delayed_solver_goals(ConjType, Goals, DelayedGoals0, DelayedGoals,
         !ImpurityErrors, !ModeInfo, !IO) :-
 
         % Try to handle any unscheduled goals by inserting solver
         % initialisation calls, aiming for a deterministic schedule.
         %
-    modecheck_delayed_goals_try_det(DelayedGoals0, DelayedGoals1, Goals0,
-        !ImpurityErrors, !ModeInfo, !IO),
+    modecheck_delayed_goals_try_det(ConjType, DelayedGoals0, DelayedGoals1,
+        Goals0, !ImpurityErrors, !ModeInfo, !IO),
 
         % Try to handle any unscheduled goals by inserting solver
         % initialisation calls, aiming for *any* workable schedule.
         %
-    modecheck_delayed_goals_eager(DelayedGoals1, DelayedGoals, Goals1,
-        !ImpurityErrors, !ModeInfo, !IO),
+    modecheck_delayed_goals_eager(ConjType, DelayedGoals1, DelayedGoals,
+        Goals1, !ImpurityErrors, !ModeInfo, !IO),
     Goals = Goals0 ++ Goals1.
 
     % We may still have some unscheduled goals.  This may be because some
@@ -2219,12 +2200,12 @@
     % XXX At some point we should extend this analysis to handle
     % disjunction, if-then-else goals, and negation.
     %
-:- pred modecheck_delayed_goals_try_det(list(delayed_goal)::in,
+:- pred modecheck_delayed_goals_try_det(conj_type::in, list(delayed_goal)::in,
     list(delayed_goal)::out, list(hlds_goal)::out,
     impurity_errors::in, impurity_errors::out,
     mode_info::in, mode_info::out, io::di, io::uo) is det.
 
-modecheck_delayed_goals_try_det(DelayedGoals0, DelayedGoals, Goals,
+modecheck_delayed_goals_try_det(ConjType, DelayedGoals0, DelayedGoals, Goals,
         !ImpurityErrors, !ModeInfo, !IO) :-
     (
         % There are no unscheduled goals, so we don't need to do anything.
@@ -2279,10 +2260,10 @@
             delay_info_enter_conj(DelayInfo0, DelayInfo1),
             mode_info_set_delay_info(DelayInfo1, !ModeInfo),
 
-            mode_info_add_goals_live_vars(InitGoals, !ModeInfo),
+            mode_info_add_goals_live_vars(ConjType, InitGoals, !ModeInfo),
 
-            modecheck_conj_list_2(Goals1, Goals, !ImpurityErrors, !ModeInfo,
-                !IO),
+            modecheck_conj_list_2(ConjType, Goals1, Goals, !ImpurityErrors,
+                !ModeInfo, !IO),
 
             mode_info_get_delay_info(!.ModeInfo, DelayInfo2),
             delay_info_leave_conj(DelayInfo2, DelayedGoals, DelayInfo3),
@@ -2539,12 +2520,12 @@
     % It is "eager" in the sense that as soon as it encounters a sub-goal
     % that may be unblocked this way it tries to do so.
     %
-:- pred modecheck_delayed_goals_eager(list(delayed_goal)::in,
+:- pred modecheck_delayed_goals_eager(conj_type::in, list(delayed_goal)::in,
     list(delayed_goal)::out, list(hlds_goal)::out,
     impurity_errors::in, impurity_errors::out,
     mode_info::in, mode_info::out, io::di, io::uo) is det.
 
-modecheck_delayed_goals_eager(DelayedGoals0, DelayedGoals, Goals,
+modecheck_delayed_goals_eager(ConjType, DelayedGoals0, DelayedGoals, Goals,
         !ImpurityErrors, !ModeInfo, !IO) :-
     (
             % There are no unscheduled goals, so we don't need to do anything.
@@ -2565,7 +2546,7 @@
         mode_info_set_delay_info(DelayInfo1, !ModeInfo),
 
         mode_info_set_may_initialise_solver_vars(yes, !ModeInfo),
-        modecheck_conj_list_2(Goals0, Goals1, !ImpurityErrors,
+        modecheck_conj_list_2(ConjType, Goals0, Goals1, !ImpurityErrors,
             !ModeInfo, !IO),
         mode_info_set_may_initialise_solver_vars(no, !ModeInfo),
 
@@ -2581,8 +2562,9 @@
                 % We scheduled some goals. Keep going until we either
                 % flounder or succeed.
                 %
-            modecheck_delayed_goals_eager(DelayedGoals1, DelayedGoals,
-                Goals2, !ImpurityErrors, !ModeInfo, !IO),
+            modecheck_delayed_goals_eager(ConjType,
+                DelayedGoals1, DelayedGoals, Goals2,
+                !ImpurityErrors, !ModeInfo, !IO),
             Goals = Goals1 ++ Goals2
         ;
             DelayedGoals = DelayedGoals1,
@@ -2619,7 +2601,7 @@
     clauses_info_get_headvars(ClausesInfo, HeadVars),
     filter_headvar_unification_goals(HeadVars, DelayedGoals0,
         HeadVarUnificationGoals, NonHeadVarUnificationGoals0),
-    modecheck_delayed_solver_goals(Goals,
+    modecheck_delayed_solver_goals(plain_conj, Goals,
         NonHeadVarUnificationGoals0, NonHeadVarUnificationGoals,
         !ImpurityErrors, !ModeInfo, !IO),
     mode_info_get_delay_info(!.ModeInfo, DelayInfo2),
@@ -2756,47 +2738,6 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred modecheck_par_conj_list(list(hlds_goal)::in, list(hlds_goal)::out,
-    set(prog_var)::in, list(pair(instmap, set(prog_var)))::out,
-    mode_info::in, mode_info::out, io::di, io::uo) is det.
-
-modecheck_par_conj_list([], [], _NonLocals, [], !ModeInfo, !IO).
-modecheck_par_conj_list([Goal0 | Goals0], [Goal | Goals], NonLocals,
-        [InstMap - GoalNonLocals | InstMaps], !ModeInfo, !IO) :-
-    mode_info_get_instmap(!.ModeInfo, InstMap0),
-    Goal0 = _ - GoalInfo,
-    goal_info_get_nonlocals(GoalInfo, GoalNonLocals),
-    mode_info_get_parallel_vars(!.ModeInfo, PVars0),
-    set.init(Bound0),
-    mode_info_set_parallel_vars([NonLocals - Bound0 | PVars0], !ModeInfo),
-
-    modecheck_goal(Goal0, Goal, !ModeInfo, !IO),
-    mode_info_get_parallel_vars(!.ModeInfo, PVars1),
-    (
-        PVars1 = [_ - Bound1 | PVars2],
-        (
-            PVars2 = [OuterNonLocals - OuterBound0 | PVars3],
-            set.intersect(OuterNonLocals, Bound1, Bound),
-            set.union(OuterBound0, Bound, OuterBound),
-            PVars = [OuterNonLocals - OuterBound | PVars3],
-            mode_info_set_parallel_vars(PVars, !ModeInfo)
-        ;
-            PVars2 = [],
-            mode_info_set_parallel_vars(PVars2, !ModeInfo)
-        )
-    ;
-        PVars1 = [],
-        unexpected(this_file, "modecheck_par_conj_list: lost parallel vars")
-    ),
-    mode_info_get_instmap(!.ModeInfo, InstMap),
-    mode_info_set_instmap(InstMap0, !ModeInfo),
-    mode_info_lock_vars(par_conj, Bound1, !ModeInfo),
-    modecheck_par_conj_list(Goals0, Goals, NonLocals, InstMaps, !ModeInfo,
-        !IO),
-    mode_info_unlock_vars(par_conj, Bound1, !ModeInfo).
-
-%-----------------------------------------------------------------------------%
-
     % Calculate the argument number offset that needs to be passed to
     % modecheck_var_list_is_live, modecheck_var_has_inst_list, and
     % modecheck_set_var_inst_list.  This offset number is calculated
Index: compiler/modules.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.394
diff -u -r1.394 modules.m
--- compiler/modules.m	15 Jun 2006 19:37:05 -0000	1.394
+++ compiler/modules.m	21 Jun 2006 06:35:35 -0000
@@ -2754,6 +2754,7 @@
     mercury_table_builtin_module(MercuryTableBuiltin),
     mercury_profiling_builtin_module(MercuryProfilingBuiltin),
     mercury_term_size_prof_builtin_module(MercuryTermSizeProfBuiltin),
+    mercury_par_builtin_module(MercuryParBuiltin),
     !:ImportDeps = [MercuryPublicBuiltin | !.ImportDeps],
     !:UseDeps = [MercuryPrivateBuiltin | !.UseDeps],
     (
@@ -2793,6 +2794,13 @@
         !:UseDeps = [MercuryTermSizeProfBuiltin | !.UseDeps]
     ;
         true
+    ),
+    globals.lookup_bool_option(Globals, parallel, Parallel),
+    (
+        Parallel = yes,
+        !:UseDeps = [MercuryParBuiltin | !.UseDeps]
+    ;
+        Parallel = no
     ).
 
 :- pred contains_tabling_pragma(item_list::in) is semidet.
Index: compiler/par_conj_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/par_conj_gen.m,v
retrieving revision 1.25
diff -u -r1.25 par_conj_gen.m
--- compiler/par_conj_gen.m	18 Apr 2006 05:47:33 -0000	1.25
+++ compiler/par_conj_gen.m	19 Jun 2006 12:26:13 -0000
@@ -259,6 +259,14 @@
     ),
     find_outputs(Vars, Initial, Final, ModuleInfo, !Outputs).
 
+    % XXX at the moment we are copying back too much.  Conjuncts which
+    % are only consumers of variable X should not be copying it back.
+    %
+    % Also, variables which are shared (i.e. we allocate a promise for
+    % it) do not need copying back if we take the address of the
+    % shared variable and store it in the promise, then write
+    % to that address on `signal' or the last `wait'.
+    %
 :- pred copy_outputs(code_info::in, list(prog_var)::in, lval::in,
     code_tree::out) is det.
 
Index: compiler/simplify.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/simplify.m,v
retrieving revision 1.177
diff -u -r1.177 simplify.m
--- compiler/simplify.m	26 May 2006 04:03:03 -0000	1.177
+++ compiler/simplify.m	20 Jun 2006 08:48:21 -0000
@@ -2010,7 +2010,7 @@
 simplify_par_conj([], [], _, !Info, !IO).
 simplify_par_conj([Goal0 |Goals0], [Goal | Goals], Info0, !Info, !IO) :-
     simplify_goal(Goal0, Goal, !Info, !IO),
-    simplify_info_post_branch_update(Info0, !Info),
+    simplify_info_update_instmap(Goal, !Info),
     simplify_par_conj(Goals0, Goals, Info0, !Info, !IO).
 
 %-----------------------------------------------------------------------------%
Index: compiler/store_alloc.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/store_alloc.m,v
retrieving revision 1.98
diff -u -r1.98 store_alloc.m
--- compiler/store_alloc.m	29 Mar 2006 08:07:22 -0000	1.98
+++ compiler/store_alloc.m	18 Jun 2006 11:32:19 -0000
@@ -272,14 +272,14 @@
     liveness_info::in, liveness_info::out, last_locns::in, last_locns::out,
     set(prog_var)::in, store_alloc_info::in) is det.
 
-store_alloc_in_par_conj([], [], !Liveness, !LastLocns, _, _).
+store_alloc_in_par_conj([], [], _Liveness0, set.init, !LastLocns, _, _).
 store_alloc_in_par_conj([Goal0 | Goals0], [Goal | Goals], Liveness0, Liveness,
         !LastLocns, ResumeVars0, StoreAllocInfo) :-
-    % XXX ignoring _Liveness1 looks fishy
-    store_alloc_in_goal(Goal0, Goal, Liveness0, Liveness,
+    store_alloc_in_goal(Goal0, Goal, Liveness0, Liveness1,
+        !LastLocns, ResumeVars0, StoreAllocInfo),
+    store_alloc_in_par_conj(Goals0, Goals, Liveness0, Liveness2,
         !LastLocns, ResumeVars0, StoreAllocInfo),
-    store_alloc_in_par_conj(Goals0, Goals, Liveness0, _Liveness1,
-        !LastLocns, ResumeVars0, StoreAllocInfo).
+    Liveness = set.union(Liveness1, Liveness2).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/switch_detection.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/switch_detection.m,v
retrieving revision 1.124
diff -u -r1.124 switch_detection.m
--- compiler/switch_detection.m	26 May 2006 04:03:04 -0000	1.124
+++ compiler/switch_detection.m	18 Jun 2006 08:29:25 -0000
@@ -199,15 +199,8 @@
         )
     ;
         Goal0 = conj(ConjType, Goals0),
-        (
-            ConjType = plain_conj,
-            detect_switches_in_conj(ModuleInfo, VarTypes, InstMap0,
-                Goals0, Goals, !Requant)
-        ;
-            ConjType = parallel_conj,
-            detect_switches_in_par_conj(ModuleInfo, VarTypes, InstMap0,
-                Goals0, Goals, !Requant)
-        ),
+        detect_switches_in_conj(ModuleInfo, VarTypes, InstMap0,
+            Goals0, Goals, !Requant),
         Goal = conj(ConjType, Goals)
     ;
         Goal0 = not(SubGoal0),
@@ -388,17 +381,6 @@
     detect_switches_in_cases(ModuleInfo, VarTypes, InstMap, Cases0, Cases,
         !Requant).
 
-:- pred detect_switches_in_par_conj(module_info::in, vartypes::in, instmap::in,
-    list(hlds_goal)::in, list(hlds_goal)::out, bool::in, bool::out) is det.
-
-detect_switches_in_par_conj(_, _, _, [], [], !Requant).
-detect_switches_in_par_conj(ModuleInfo, VarTypes, InstMap,
-        [Goal0 | Goals0], [Goal | Goals], !Requant) :-
-    detect_switches_in_goal(ModuleInfo, VarTypes, InstMap, Goal0, Goal,
-        !Requant),
-    detect_switches_in_par_conj(ModuleInfo, VarTypes, InstMap,
-        Goals0, Goals, !Requant).
-
 :- pred detect_switches_in_conj(module_info::in, vartypes::in, instmap::in,
     list(hlds_goal)::in, list(hlds_goal)::out, bool::in, bool::out) is det.
 
Index: compiler/transform_hlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/transform_hlds.m,v
retrieving revision 1.23
diff -u -r1.23 transform_hlds.m
--- compiler/transform_hlds.m	5 Jun 2006 02:26:11 -0000	1.23
+++ compiler/transform_hlds.m	13 Jun 2006 15:46:30 -0000
@@ -83,6 +83,7 @@
 :- include_module size_prof.
 :- include_module tupling.
 :- include_module untupling.
+:- include_module dep_par_conj.
 
 :- include_module mmc_analysis.
 
Index: compiler/unique_modes.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/unique_modes.m,v
retrieving revision 1.110
diff -u -r1.110 unique_modes.m
--- compiler/unique_modes.m	26 May 2006 04:03:04 -0000	1.110
+++ compiler/unique_modes.m	18 Jun 2006 11:36:03 -0000
@@ -258,35 +258,19 @@
     hlds_goal_expr::out, mode_info::in, mode_info::out,
     io::di, io::uo) is det.
 
-check_goal_2(conj(ConjType, List0), GoalInfo0, conj(ConjType, List),
+check_goal_2(conj(ConjType, List0), _GoalInfo0, conj(ConjType, List),
         !ModeInfo, !IO) :-
+    mode_checkpoint(enter, "*conj", !ModeInfo, !IO),
     (
-        ConjType = plain_conj,
-        mode_checkpoint(enter, "conj", !ModeInfo, !IO),
-        (
-            List0 = [],
-            % For efficiency, optimize common case.
-            List = []
-        ;
-            List0 = [_ | _],
-            mode_info_add_goals_live_vars(List0, !ModeInfo),
-            check_conj(List0, List, !ModeInfo, !IO)
-        ),
-        mode_checkpoint(exit, "conj", !ModeInfo, !IO)
+        List0 = [],
+        % For efficiency, optimize common case.
+        List = []
     ;
-        ConjType = parallel_conj,
-        mode_checkpoint(enter, "par_conj", !ModeInfo, !IO),
-        goal_info_get_nonlocals(GoalInfo0, NonLocals),
-        mode_info_add_live_vars(NonLocals, !ModeInfo),
-        % Build a multiset of the nonlocals of the conjuncts so that we can
-        % figure out which variables must be made shared at the start of the
-        % parallel conjunction.
-        make_par_conj_nonlocal_multiset(List0, NonLocalsBag),
-        check_par_conj(List0, NonLocalsBag, List, InstMapList, !ModeInfo, !IO),
-        instmap_unify(NonLocals, InstMapList, !ModeInfo),
-        mode_info_remove_live_vars(NonLocals, !ModeInfo),
-        mode_checkpoint(exit, "par_conj", !ModeInfo, !IO)
-    ).
+        List0 = [_ | _],
+        mode_info_add_goals_live_vars(ConjType, List0, !ModeInfo),
+        check_conj(ConjType, List0, List, !ModeInfo, !IO)
+    ),
+    mode_checkpoint(exit, "*conj", !ModeInfo, !IO).
 
 check_goal_2(disj(List0), GoalInfo0, disj(List), !ModeInfo, !IO) :-
     mode_checkpoint(enter, "disj", !ModeInfo, !IO),
@@ -642,27 +626,28 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred check_conj(list(hlds_goal)::in, list(hlds_goal)::out,
+:- pred check_conj(conj_type::in, list(hlds_goal)::in, list(hlds_goal)::out,
     mode_info::in, mode_info::out, io::di, io::uo) is det.
 
     % Just process each conjunct in turn.  Note that we don't do any
     % reordering of conjuncts here, although we do flatten conjunctions.
     %
-check_conj([], [], !ModeInfo, !IO).
-check_conj([Goal0 | Goals0], Goals, !ModeInfo, !IO) :-
+check_conj(_ConjType, [], [], !ModeInfo, !IO).
+check_conj(ConjType, [Goal0 | Goals0], Goals, !ModeInfo, !IO) :-
     (
-        Goal0 = conj(plain_conj, ConjGoals) - _
+        Goal0 = conj(ConjType, ConjGoals) - _
     ->
         list.append(ConjGoals, Goals0, Goals1),
-        check_conj(Goals1, Goals, !ModeInfo, !IO)
+        check_conj(ConjType, Goals1, Goals, !ModeInfo, !IO)
     ;
-        check_conj_2(Goal0, Goals0, Goals, !ModeInfo, !IO)
+        check_conj_2(ConjType, Goal0, Goals0, Goals, !ModeInfo, !IO)
     ).
 
-:- pred check_conj_2(hlds_goal::in, list(hlds_goal)::in, list(hlds_goal)::out,
+:- pred check_conj_2(conj_type::in,
+    hlds_goal::in, list(hlds_goal)::in, list(hlds_goal)::out,
     mode_info::in, mode_info::out, io::di, io::uo) is det.
 
-check_conj_2(Goal0, Goals0, [Goal | Goals], !ModeInfo, !IO) :-
+check_conj_2(ConjType, Goal0, Goals0, [Goal | Goals], !ModeInfo, !IO) :-
     goal_get_nonlocals(Goal0, NonLocals),
     mode_info_remove_live_vars(NonLocals, !ModeInfo),
     check_goal(Goal0, Goal, !ModeInfo, !IO),
@@ -674,7 +659,7 @@
         mode_info_remove_goals_live_vars(Goals0, !ModeInfo),
         Goals = []
     ;
-        check_conj(Goals0, Goals, !ModeInfo, !IO)
+        check_conj(ConjType, Goals0, Goals, !ModeInfo, !IO)
     ).
 
 %-----------------------------------------------------------------------------%
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list