Revised diff for parallel conjunction

Thomas Charles CONWAY conway at cs.mu.oz.au
Mon Oct 27 12:03:03 AEDT 1997


Hi

Here is a revised diff that addresses the concerns that fjh mentioned
in response to the earlier diff.

Note that the op declarations are ones that *should* have been part
of the diff that added '&' as an operator (comitted about 1000 years
ago).

Thomas
-- 
ZZ:wq!
^X^C
Thomas Conway               				      conway at cs.mu.oz.au
AD DEUM ET VINUM	  			      Every sword has two edges.


Add parallel conjunction to the compiler.
New syntax: "Goal1 & Goal2".
Status: experemental, very alpha. (Currently there is no runtime
support.)

compiler/prog_data.m:
	Add `&' as a constructor for a goal.
compiler/prog_*.m:
	Parse parallel conjunction.

compiler/hlds_goal.m:
	Add par_conj as a constructor for goal_exprn.

compiler/llds.m:
	Add "fork", "join_and_terminate", and "join_and_continue"
	as llds instructions.

compiler/instmap.m:
	add a couple of new predicates:
		instmap__unify which unifies the bindings of a set
			of variables from a list of instmaps
		merge_instmap_deltas which merges a list of instmap
			deltas.

compiler/modes_info.m, mode_errors.m:
	add a 'lock_context' to locked variables that specifies
	whether they were locked in a negation, if-then-else or
	parallel conjunction. Use this information for reporting
	mode errors.
	add a 'parallel vars' field to the mode_info to track which
	variables that are nonlocal to the current parallel conjunct
	have been bound (even if the conjunct as a whole is
	erroneous or failure).

compiler/modes.m:
	modecheck parallel conjunctions.

compiler/*.m:
	Bits and pieces to handle parallel conjunction and
	the fork/join llds instructions.

cvs diff: Diffing .
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/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing bytecode
cvs diff: Diffing bytecode/test
cvs diff: Diffing compiler
Index: compiler/bytecode_gen.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/bytecode_gen.m,v
retrieving revision 1.30
diff -u -r1.30 bytecode_gen.m
--- bytecode_gen.m	1997/09/01 14:00:22	1.30
+++ bytecode_gen.m	1997/09/08 22:43:24
@@ -193,6 +193,9 @@
 		GoalExpr = conj(GoalList),
 		bytecode_gen__conj(GoalList, ByteInfo0, ByteInfo, Code)
 	;
+		GoalExpr = par_conj(_GoalList, _SM),
+		error("sorry, bytecode_gen of parallel conj not implemented")
+	;
 		GoalExpr = disj(GoalList, _),
 		( GoalList = [] ->
 			Code = node([fail]),
Index: compiler/code_gen.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/code_gen.m,v
retrieving revision 1.38
diff -u -r1.38 code_gen.m
--- code_gen.m	1997/10/11 15:42:40	1.38
+++ code_gen.m	1997/10/17 04:20:09
@@ -58,7 +58,7 @@
 :- implementation.
 
 :- import_module call_gen, unify_gen, ite_gen, switch_gen, disj_gen.
-:- import_module pragma_c_gen, trace, globals, options, hlds_out.
+:- import_module par_conj_gen, pragma_c_gen, trace, globals, options, hlds_out.
 :- import_module code_aux, middle_rec, passes_aux, llds_out.
 :- import_module code_util, type_util, mode_util.
 :- import_module prog_data, instmap.
@@ -672,6 +672,8 @@
 
 code_gen__generate_det_goal_2(conj(Goals), _GoalInfo, Instr) -->
 	code_gen__generate_goals(Goals, model_det, Instr).
+code_gen__generate_det_goal_2(par_conj(Goals, _StoreMap), GoalInfo, Instr) -->
+	par_conj_gen__generate_det_par_conj(Goals, GoalInfo, Instr).
 code_gen__generate_det_goal_2(some(_Vars, Goal), _GoalInfo, Instr) -->
 	{ Goal = _ - InnerGoalInfo },
 	{ goal_info_get_code_model(InnerGoalInfo, CodeModel) },
@@ -760,6 +762,10 @@
 
 code_gen__generate_semi_goal_2(conj(Goals), _GoalInfo, Code) -->
 	code_gen__generate_goals(Goals, model_semi, Code).
+code_gen__generate_semi_goal_2(par_conj(_Goals, _SM), _GoalInfo, _Code) -->
+	% Determinism analysis will report a determinism error if the
+	% parallel conj is not det.
+	{ error("sorry, semidet parallel conjunction not implemented") }.
 code_gen__generate_semi_goal_2(some(_Vars, Goal), _GoalInfo, Code) -->
 	{ Goal = _ - InnerGoalInfo },
 	{ goal_info_get_code_model(InnerGoalInfo, CodeModel) },
@@ -972,6 +978,10 @@
 
 code_gen__generate_non_goal_2(conj(Goals), _GoalInfo, Code) -->
 	code_gen__generate_goals(Goals, model_non, Code).
+code_gen__generate_non_goal_2(par_conj(_Goals, _SM), _GoalInfo, _Code) -->
+		% Determinism analysis will report a determinism error if the
+		% parallel conj is not det.
+	{ error("sorry, nondet parallel conjunction not implemented") }.
 code_gen__generate_non_goal_2(some(_Vars, Goal), _GoalInfo, Code) -->
 	{ Goal = _ - InnerGoalInfo },
 	{ goal_info_get_code_model(InnerGoalInfo, CodeModel) },
Index: compiler/code_info.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/code_info.m,v
retrieving revision 1.213
diff -u -r1.213 code_info.m
--- code_info.m	1997/10/03 04:55:31	1.213
+++ code_info.m	1997/10/20 22:44:01
@@ -275,12 +275,6 @@
 					% switched on.
 	).
 
-:- type slot_contents 
-	--->	ticket			% a ticket (trail pointer)
-	;	ticket_counter		% a copy of the ticket counter
-	;	trace_data
-	;	lval(lval).
-
 %---------------------------------------------------------------------------%
 
 code_info__init(Varset, Liveness, StackSlots, SaveSuccip, Globals,
@@ -2969,6 +2963,7 @@
 					% modify this, if the GC is going
 					% to garbage-collect the trail.
 code_info__get_live_value_type(ticket_counter, unwanted).
+code_info__get_live_value_type(sync_term, unwanted).
 code_info__get_live_value_type(trace_data, unwanted).
 
 %---------------------------------------------------------------------------%
@@ -3006,6 +3001,15 @@
 
 :- interface.
 
+:- type slot_contents 
+	--->	ticket			% a ticket (trail pointer)
+	;	ticket_counter		% a copy of the ticket counter
+	;	trace_data
+	;	sync_term		% a syncronization term used
+					% at the end of par_conjs.
+					% see par_conj_gen.m for details.
+	;	lval(lval).
+
 	% Returns the total stackslot count, but not including space for
 	% succip.
 :- pred code_info__get_total_stackslot_count(int, code_info, code_info).
@@ -3014,11 +3018,6 @@
 :- pred code_info__get_trace_slot(lval, code_info, code_info).
 :- mode code_info__get_trace_slot(out, in, out) is det.
 
-%---------------------------------------------------------------------------%
-%---------------------------------------------------------------------------%
-
-:- implementation.
-
 :- pred code_info__acquire_temp_slot(slot_contents, lval,
 	code_info, code_info).
 :- mode code_info__acquire_temp_slot(in, out, in, out) is det.
@@ -3029,12 +3028,20 @@
 :- pred code_info__get_variable_slot(var, lval, code_info, code_info).
 :- mode code_info__get_variable_slot(in, out, in, out) is det.
 
-:- pred code_info__max_var_slot(stack_slots, int).
-:- mode code_info__max_var_slot(in, out) is det.
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
 
 :- pred code_info__stack_variable(int, lval, code_info, code_info).
 :- mode code_info__stack_variable(in, out, in, out) is det.
 
+:- pred code_info__stack_variable_reference(int, rval, code_info, code_info).
+:- mode code_info__stack_variable_reference(in, out, in, out) is det.
+
+:- pred code_info__max_var_slot(stack_slots, int).
+:- mode code_info__max_var_slot(in, out) is det.
+
 code_info__get_trace_slot(StackVar) -->
 	code_info__acquire_temp_slot(trace_data, StackVar).
 
@@ -3109,6 +3116,15 @@
 		{ Lval = framevar(Num1) }
 	;
 		{ Lval = stackvar(Num) }	% stackvars start at one
+	).
+
+code_info__stack_variable_reference(Num, mem_addr(Ref)) -->
+	code_info__get_proc_model(CodeModel),
+	( { CodeModel = model_non } ->
+		{ Num1 is Num - 1 },		% framevars start at zero
+		{ Ref = framevar_ref(Num1) }
+	;
+		{ Ref = stackvar_ref(Num) }	% stackvars start at one
 	).
 
 %---------------------------------------------------------------------------%
Index: compiler/code_util.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/code_util.m,v
retrieving revision 1.89
diff -u -r1.89 code_util.m
--- code_util.m	1997/09/01 14:00:37	1.89
+++ code_util.m	1997/09/08 22:43:24
@@ -786,6 +786,8 @@
 code_util__count_recursive_calls_2(conj(Goals), PredId, ProcId, Min, Max) :-
 	code_util__count_recursive_calls_conj(Goals, PredId, ProcId, 0, 0,
 		Min, Max).
+code_util__count_recursive_calls_2(par_conj(Goals, _), PredId, ProcId, Min, Max) :-
+	code_util__count_recursive_calls_conj(Goals, PredId, ProcId, 0, 0, Min, Max).
 code_util__count_recursive_calls_2(disj(Goals, _), PredId, ProcId, Min, Max) :-
 	code_util__count_recursive_calls_disj(Goals, PredId, ProcId, Min, Max).
 code_util__count_recursive_calls_2(switch(_, _, Cases, _), PredId, ProcId,
Index: compiler/constraint.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/constraint.m,v
retrieving revision 1.35
diff -u -r1.35 constraint.m
--- constraint.m	1997/09/01 14:00:47	1.35
+++ constraint.m	1997/09/08 22:43:24
@@ -140,6 +140,9 @@
 	constraint__propagate_conj(Goals0, Goals),
 	mode_checkpoint(exit, "conj").
 
+constraint__propagate_goal_2(par_conj(_, _), par_conj(_, _)) -->
+	{ error("constraint__propagate_goal_2: par_conj not supported") }.
+
 constraint__propagate_goal_2(disj(Goals0, SM), disj(Goals, SM)) -->
 	mode_checkpoint(enter, "disj"),
 	constraint__propagate_disj(Goals0, Goals),
Index: compiler/cse_detection.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/cse_detection.m,v
retrieving revision 1.48
diff -u -r1.48 cse_detection.m
--- cse_detection.m	1997/09/01 14:00:51	1.48
+++ cse_detection.m	1997/09/08 22:43:24
@@ -236,6 +236,10 @@
 		Redo, conj(Goals)) :-
 	detect_cse_in_conj(Goals0, InstMap, CseInfo0, CseInfo, Redo, Goals).
 
+detect_cse_in_goal_2(par_conj(Goals0, SM), _, InstMap, CseInfo0, CseInfo, Redo,
+		par_conj(Goals, SM)) :-
+	detect_cse_in_par_conj(Goals0, InstMap, CseInfo0, CseInfo, Redo, Goals).
+
 detect_cse_in_goal_2(disj(Goals0, SM), GoalInfo, InstMap, CseInfo0, CseInfo,
 		Redo, Goal) :-
 	( Goals0 = [] ->
@@ -280,6 +284,20 @@
 	;
 		Goals = [Goal1 | Goals1]
 	),
+	bool__or(Redo1, Redo2, Redo).
+
+%-----------------------------------------------------------------------------%
+
+:- pred detect_cse_in_par_conj(list(hlds_goal), instmap, cse_info, cse_info,
+	bool, list(hlds_goal)).
+:- mode detect_cse_in_par_conj(in, in, in, out, out, out) is det.
+
+detect_cse_in_par_conj([], _InstMap, CseInfo, CseInfo, no, []).
+detect_cse_in_par_conj([Goal0 | Goals0], InstMap0, CseInfo0, CseInfo,
+		Redo, [Goal | Goals]) :-
+	detect_cse_in_goal(Goal0, InstMap0, CseInfo0, CseInfo1, Redo1, Goal),
+	detect_cse_in_par_conj(Goals0, InstMap0, CseInfo1, CseInfo,
+		Redo2, Goals),
 	bool__or(Redo1, Redo2, Redo).
 
 %-----------------------------------------------------------------------------%
Index: compiler/dead_proc_elim.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/dead_proc_elim.m,v
retrieving revision 1.32
diff -u -r1.32 dead_proc_elim.m
--- dead_proc_elim.m	1997/09/01 14:00:56	1.32
+++ dead_proc_elim.m	1997/09/09 02:13:39
@@ -350,6 +350,10 @@
 		Needed0, Needed) :-
 	dead_proc_elim__examine_goals(Goals, CurrProc, Queue0, Queue,
 		Needed0, Needed).
+dead_proc_elim__examine_expr(par_conj(Goals, _SM), CurrProc, Queue0, Queue,
+		Needed0, Needed) :-
+	dead_proc_elim__examine_goals(Goals, CurrProc, Queue0, Queue,
+		Needed0, Needed).
 dead_proc_elim__examine_expr(not(Goal), CurrProc, Queue0, Queue,
 		Needed0, Needed) :-
 	dead_proc_elim__examine_goal(Goal, CurrProc, Queue0, Queue,
@@ -681,6 +685,8 @@
 		dead_pred_info::in, dead_pred_info::out) is det.
 
 pre_modecheck_examine_goal(conj(Goals) - _) -->
+	list__foldl(pre_modecheck_examine_goal, Goals).
+pre_modecheck_examine_goal(par_conj(Goals, _) - _) -->
 	list__foldl(pre_modecheck_examine_goal, Goals).
 pre_modecheck_examine_goal(disj(Goals, _) - _) -->
 	list__foldl(pre_modecheck_examine_goal, Goals).
Index: compiler/dependency_graph.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/dependency_graph.m,v
retrieving revision 1.30
diff -u -r1.30 dependency_graph.m
--- dependency_graph.m	1997/09/01 14:00:59	1.30
+++ dependency_graph.m	1997/09/08 22:43:25
@@ -195,6 +195,10 @@
 					DepGraph0, DepGraph) :-
 	dependency_graph__add_arcs_in_list(Goals, Caller, DepGraph0, DepGraph).
 
+dependency_graph__add_arcs_in_goal_2(par_conj(Goals, _SM), Caller, 
+					DepGraph0, DepGraph) :-
+	dependency_graph__add_arcs_in_list(Goals, Caller, DepGraph0, DepGraph).
+
 dependency_graph__add_arcs_in_goal_2(disj(Goals, _), Caller, 
 					DepGraph0, DepGraph) :-
 	dependency_graph__add_arcs_in_list(Goals, Caller, DepGraph0, DepGraph).
Index: compiler/det_analysis.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/det_analysis.m,v
retrieving revision 1.122
diff -u -r1.122 det_analysis.m
--- det_analysis.m	1997/09/01 14:01:06	1.122
+++ det_analysis.m	1997/10/21 02:15:48
@@ -378,6 +378,23 @@
 	det_infer_conj(Goals0, InstMap0, SolnContext, DetInfo,
 		Goals, Detism, Msgs).
 
+det_infer_goal_2(par_conj(Goals0, SM), GoalInfo, InstMap0, SolnContext,
+		DetInfo, _, _, par_conj(Goals, SM), Detism, Msgs) :-
+	det_infer_par_conj(Goals0, InstMap0, SolnContext, DetInfo,
+		Goals, Detism, Msgs0),
+	(
+		determinism_components(Detism, CanFail, Solns),
+		CanFail = cannot_fail,
+		Solns \= at_most_many
+	->
+		Msgs = Msgs0
+	;
+		det_info_get_pred_id(DetInfo, PredId),
+		det_info_get_proc_id(DetInfo, ProcId),
+		Msg = par_conj_not_det(Detism, PredId, ProcId, GoalInfo, Goals),
+		Msgs = [Msg|Msgs0]
+	).
+
 det_infer_goal_2(disj(Goals0, SM), _, InstMap0, SolnContext, DetInfo, _, _,
 		disj(Goals, SM), Detism, Msgs) :-
 	det_infer_disj(Goals0, InstMap0, SolnContext, DetInfo,
@@ -659,6 +676,27 @@
 	% Finally combine the results computed above.
 	%
 	det_conjunction_detism(DetismA, DetismB, Detism),
+	list__append(MsgsA, MsgsB, Msgs).
+
+:- pred det_infer_par_conj(list(hlds_goal), instmap, soln_context, det_info,
+		list(hlds_goal), determinism, list(det_msg)).
+:- mode det_infer_par_conj(in, in, in, in, out, out, out) is det.
+
+det_infer_par_conj([], _InstMap0, _SolnContext, _DetInfo, [], det, []).
+det_infer_par_conj([Goal0 | Goals0], InstMap0, SolnContext, DetInfo, 
+		[Goal | Goals], Detism, Msgs) :-
+
+	det_infer_goal(Goal0, InstMap0, SolnContext, DetInfo,
+			Goal, DetismA, MsgsA),
+	determinism_components(DetismA, CanFailA, MaxSolnsA),
+	
+	det_infer_par_conj(Goals0, InstMap0, SolnContext, DetInfo,
+			Goals, DetismB, MsgsB),
+	determinism_components(DetismB, CanFailB, MaxSolnsB),
+
+	det_conjunction_maxsoln(MaxSolnsA, MaxSolnsB, MaxSolns),
+	det_conjunction_canfail(CanFailA, CanFailB, CanFail),
+	determinism_components(Detism, CanFail, MaxSolns),
 	list__append(MsgsA, MsgsB, Msgs).
 
 :- pred det_infer_disj(list(hlds_goal), instmap, soln_context, det_info,
Index: compiler/det_report.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/det_report.m,v
retrieving revision 1.42
diff -u -r1.42 det_report.m
--- det_report.m	1997/10/15 07:39:42	1.42
+++ det_report.m	1997/10/21 02:10:18
@@ -49,7 +49,10 @@
 				determinism)
 		;	error_in_lambda(
 				determinism, determinism, % declared, inferred
-				hlds_goal, hlds_goal_info, pred_id, proc_id).
+				hlds_goal, hlds_goal_info, pred_id, proc_id)
+		;	par_conj_not_det(determinism, pred_id, proc_id,
+				hlds_goal_info, list(hlds_goal))
+		.
 
 :- type seen_call_id
 	--->	seen_call(pred_id, proc_id)
@@ -383,6 +386,10 @@
 		Diagnosed) -->
 	det_diagnose_conj(Goals, Desired, Context, DetInfo, Diagnosed).
 
+det_diagnose_goal_2(par_conj(Goals, _SM), _GoalInfo, Desired, _Actual,
+		Context, DetInfo, Diagnosed) -->
+	det_diagnose_conj(Goals, Desired, Context, DetInfo, Diagnosed).
+
 det_diagnose_goal_2(disj(Goals, _), GoalInfo, Desired, Actual, SwitchContext,
 		DetInfo, Diagnosed) -->
 	det_diagnose_disj(Goals, Desired, Actual, SwitchContext, DetInfo, 0,
@@ -598,6 +605,9 @@
 		io__write_string(".\n")
 	).
 
+	% det_diagnose_conj is used for both normal [sequential]
+	% conjunction and parallel conjunction.
+
 :- pred det_diagnose_conj(list(hlds_goal), determinism,
 	list(switch_context), det_info, bool, io__state, io__state).
 :- mode det_diagnose_conj(in, in, in, in, out, di, uo) is det.
@@ -891,6 +901,7 @@
 det_msg_get_type(cc_pred_in_wrong_context(_, _, _, _), error).
 det_msg_get_type(higher_order_cc_pred_in_wrong_context(_, _), error).
 det_msg_get_type(error_in_lambda(_, _, _, _, _, _), error).
+det_msg_get_type(par_conj_not_det(_, _, _, _, _), error).
 
 :- pred det_report_msg(det_msg, module_info, io__state, io__state).
 :- mode det_report_msg(in, in, di, uo) is det.
@@ -1104,6 +1115,33 @@
 	globals__io_get_globals(Globals),
 	{ det_info_init(ModuleInfo, PredId, ProcId, Globals, DetInfo) },
 	det_diagnose_goal(Goal, DeclaredDetism, [], DetInfo, _),
+	io__set_exit_status(1).
+det_report_msg(par_conj_not_det(InferredDetism, PredId,
+			ProcId, GoalInfo, Goals), ModuleInfo) -->
+	{ goal_info_get_context(GoalInfo, Context) },
+	prog_out__write_context(Context),
+	{ determinism_components(InferredDetism, CanFail, MaxSoln) },
+	(
+		{ CanFail \= cannot_fail }
+	->
+		io__write_string("Error: parallel conjunct may fail.\n")
+	;
+		{ MaxSoln = at_most_many }
+	->
+		prog_out__write_context(Context),
+		io__write_string("Error: parallel conjunct may have multiple solutions.\n")
+	;
+		{ error("strange determinism error for parallel conjunction") }
+	),
+	prog_out__write_context(Context),
+	io__write_string(
+		"  The current implementation supports only single-solution\n"
+	),
+	prog_out__write_context(Context),
+	io__write_string("  non-failing parallel conjunctions.\n"),
+	globals__io_get_globals(Globals),
+	{ det_info_init(ModuleInfo, PredId, ProcId, Globals, DetInfo) },
+	det_diagnose_conj(Goals, det, [], DetInfo, _),
 	io__set_exit_status(1).
 
 %-----------------------------------------------------------------------------%
Index: compiler/dnf.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/dnf.m,v
retrieving revision 1.22
diff -u -r1.22 dnf.m
--- dnf.m	1997/09/01 14:01:21	1.22
+++ dnf.m	1997/09/08 23:03:03
@@ -184,6 +184,9 @@
 			Goals, NewPredIds0, NewPredIds),
 		Goal = conj(Goals) - GoalInfo
 	;
+		GoalExpr0 = par_conj(_Goals0, _SM),
+		error("sorry, dnf of parallel conjunction not implemented")
+	;
 		GoalExpr0 = some(_, _),
 		dnf__transform_conj([Goal0], InstMap0, MaybeNonAtomic,
 			ModuleInfo0, ModuleInfo, Base, 0, _, DnfInfo,
@@ -441,6 +444,7 @@
 :- pred dnf__is_atomic_expr(hlds_goal_expr::in, bool::out) is det.
 
 dnf__is_atomic_expr(conj(_), no).
+dnf__is_atomic_expr(par_conj(_, _), no).
 dnf__is_atomic_expr(higher_order_call(_, _, _, _, _, _), yes).
 dnf__is_atomic_expr(call(_, _, _, _, _, _), yes).
 dnf__is_atomic_expr(switch(_, _, _, _), no).
Index: compiler/dupelim.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/dupelim.m,v
retrieving revision 1.22
diff -u -r1.22 dupelim.m
--- dupelim.m	1997/08/25 17:48:09	1.22
+++ dupelim.m	1997/09/08 22:43:25
@@ -190,6 +190,16 @@
 dupelim__replace_labels_instr(incr_sp(Size, Msg), _, incr_sp(Size, Msg)).
 dupelim__replace_labels_instr(decr_sp(Size), _, decr_sp(Size)).
 dupelim__replace_labels_instr(pragma_c(A,B,C,D,E), _, pragma_c(A,B,C,D,E)).
+dupelim__replace_labels_instr(fork(Child0, Parent0, SlotCount), Replmap,
+		fork(Child, Parent, SlotCount)) :-
+	dupelim__replace_labels_label(Child0, Replmap, Child),
+	dupelim__replace_labels_label(Parent0, Replmap, Parent).
+dupelim__replace_labels_instr(join_and_terminate(Lval0), Replmap, join_and_terminate(Lval)) :-
+	dupelim__replace_labels_lval(Lval0, Replmap, Lval).
+dupelim__replace_labels_instr(join_and_continue(Lval0, Label0),
+		Replmap, join_and_continue(Lval, Label)) :-
+	dupelim__replace_labels_label(Label0, Replmap, Label),
+	dupelim__replace_labels_lval(Lval0, Replmap, Lval).
 
 :- pred dupelim__replace_labels_lval(lval, map(label, label), lval).
 % :- mode dupelim__replace_labels_lval(di, in, uo) is det.
Index: compiler/excess.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/excess.m,v
retrieving revision 1.24
diff -u -r1.24 excess.m
--- excess.m	1997/09/01 14:01:24	1.24
+++ excess.m	1997/09/08 23:03:11
@@ -91,6 +91,12 @@
 					Goals, ElimVars),
 		conj_list_to_goal(Goals, GoalInfo0, Goal)
 	;
+		GoalExpr0 = par_conj(Goals0, _SM),
+		goal_info_get_nonlocals(GoalInfo0, NonLocals),
+		excess_assignments_in_conj(Goals0, [], ElimVars0, NonLocals,
+					Goals, ElimVars),
+		par_conj_list_to_goal(Goals, GoalInfo0, Goal)
+	;
 		GoalExpr0 = disj(Goals0, SM),
 		excess_assignments_in_disj(Goals0, ElimVars0, Goals, ElimVars),
 		Goal = disj(Goals, SM) - GoalInfo0
@@ -142,6 +148,9 @@
 	% If (say) V_4 and V_6 are nonlocal, then after the V_5 => V_4
 	% substitution has been made, the second assignment V_4 = V_6
 	% is left alone.
+	%
+	% This code is used for both sequential conjunction (conj/1) and
+	% parallel conjunction (par_conj/2).
 
 :- pred excess_assignments_in_conj(list(hlds_goal), list(hlds_goal),
 	list(var), set(var), list(hlds_goal), list(var)).
Index: compiler/follow_code.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/follow_code.m,v
retrieving revision 1.43
diff -u -r1.43 follow_code.m
--- follow_code.m	1997/09/01 14:01:28	1.43
+++ follow_code.m	1997/09/08 22:43:25
@@ -88,6 +88,13 @@
 move_follow_code_in_goal_2(conj(Goals0), conj(Goals), Flags, R0, R) :-
 	move_follow_code_in_conj(Goals0, Goals, Flags, R0, R).
 
+move_follow_code_in_goal_2(par_conj(Goals0, SM), par_conj(Goals, SM),
+		Flags, R0, R) :-
+		% move_follow_code_in_disj treats its list of goals as
+		% independent goals, so we can use it to process the
+		% independent parallel conjuncts.
+	move_follow_code_in_disj(Goals0, Goals, Flags, R0, R).
+
 move_follow_code_in_goal_2(disj(Goals0, SM), disj(Goals, SM), Flags, R0, R) :-
 	move_follow_code_in_disj(Goals0, Goals, Flags, R0, R).
 
@@ -118,6 +125,9 @@
 			pragma_c_code(A,B,C,D,E,F,G,H), _, R, R).
 
 %-----------------------------------------------------------------------------%
+
+	% move_follow_code_in_disj is used both for disjunction and
+	% parallel conjunction.
 
 :- pred move_follow_code_in_disj(list(hlds_goal), list(hlds_goal),
 	pair(bool), bool, bool).
Index: compiler/follow_vars.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/follow_vars.m,v
retrieving revision 1.43
diff -u -r1.43 follow_vars.m
--- follow_vars.m	1997/09/01 14:01:32	1.43
+++ follow_vars.m	1997/09/08 22:43:25
@@ -95,6 +95,14 @@
 	find_follow_vars_in_conj(Goals0, ArgsMethod, ModuleInfo, FollowVars0,
 		no, Goals, FollowVars).
 
+find_follow_vars_in_goal_2(par_conj(Goals0, SM), ArgsMethod, ModuleInfo,
+		FollowVars0, par_conj(Goals, SM), FollowVars) :-
+		% find_follow_vars_in_disj treats its list of goals as a
+		% series of independent goals, so we can use it to process
+		% independent parallel conjunction.
+	find_follow_vars_in_disj(Goals0, ArgsMethod, ModuleInfo, FollowVars0,
+		Goals, FollowVars).
+
 	% We record that at the end of each disjunct, live variables should
 	% be in the locations given by the initial follow_vars, which reflects
 	% the requirements of the code following the disjunction.
@@ -263,6 +271,8 @@
 	% they can only be entered with everything in stack slots; for
 	% model_det and model_semi disjunctions, they will never be
 	% entered at all.)
+	%
+	% This code is used both for disjunction and parallel conjunction.
 
 :- pred find_follow_vars_in_disj(list(hlds_goal), args_method, module_info,
 				follow_vars, list(hlds_goal), follow_vars).
Index: compiler/frameopt.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/frameopt.m,v
retrieving revision 1.63
diff -u -r1.63 frameopt.m
--- frameopt.m	1997/08/25 17:48:12	1.63
+++ frameopt.m	1997/09/08 22:43:25
@@ -688,6 +688,9 @@
 possible_targets(incr_sp(_, _), []).
 possible_targets(decr_sp(_), []).
 possible_targets(pragma_c(_, _, _, _, _), []).
+possible_targets(fork(Child, Parent, _), [Child, Parent]).
+possible_targets(join_and_terminate(_), []).
+possible_targets(join_and_continue(_, Label), [Label]).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -1301,18 +1304,33 @@
 substitute_labels_instr(decr_sp(Size), _, decr_sp(Size)).
 substitute_labels_instr(pragma_c(Decl, In, Code, Out, Context), _,
 		pragma_c(Decl, In, Code, Out, Context)).
+substitute_labels_instr(fork(Child0, Parent0, Lval), LabelMap,
+		fork(Child, Parent, Lval)) :-
+	substitute_label(LabelMap, Child0, Child),
+	substitute_label(LabelMap, Parent0, Parent).
+substitute_labels_instr(join_and_terminate(Lval), _LabelMap, join_and_terminate(Lval)).
+substitute_labels_instr(join_and_continue(Lval, Label0), LabelMap,
+		join_and_continue(Lval, Label)) :-
+	substitute_label(LabelMap, Label0, Label).
 
 :- pred substitute_labels_list(list(label)::in, assoc_list(label)::in,
 	list(label)::out) is det.
 
 substitute_labels_list([], _, []).
 substitute_labels_list([Label0 | Labels0], LabelMap, [Label | Labels]) :-
-	( assoc_list__search(LabelMap, Label0, Label1) ->
+	substitute_label(LabelMap, Label0, Label),
+	substitute_labels_list(Labels0, LabelMap, Labels).
+
+:- pred substitute_label(assoc_list(label)::in, label::in, label::out) is det.
+
+substitute_label(LabelMap, Label0, Label) :-
+	(
+		assoc_list__search(LabelMap, Label0, Label1)
+	->
 		Label = Label1
 	;
 		Label = Label0
-	),
-	substitute_labels_list(Labels0, LabelMap, Labels).
+	).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/goal_path.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/goal_path.m,v
retrieving revision 1.1
diff -u -r1.1 goal_path.m
--- goal_path.m	1997/10/13 08:09:39	1.1
+++ goal_path.m	1997/10/20 02:24:17
@@ -40,6 +40,8 @@
 
 fill_expr_slots(conj(Goals0), Path0, conj(Goals)) :-
 	fill_conj_slots(Goals0, Path0, 0, Goals).
+fill_expr_slots(par_conj(Goals0, SM), Path0, par_conj(Goals, SM)) :-
+	fill_conj_slots(Goals0, Path0, 0, Goals).
 fill_expr_slots(disj(Goals0, B), Path0, disj(Goals, B)) :-
 	fill_disj_slots(Goals0, Path0, 0, Goals).
 fill_expr_slots(switch(A, B, Cases0, D), Path0, switch(A, B, Cases, D)) :-
Index: compiler/goal_util.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/goal_util.m,v
retrieving revision 1.38
diff -u -r1.38 goal_util.m
--- goal_util.m	1997/09/01 14:01:36	1.38
+++ goal_util.m	1997/09/08 22:43:25
@@ -191,6 +191,11 @@
 goal_util__name_apart_2(conj(Goals0), Must, Subn, conj(Goals)) :-
 	goal_util__name_apart_list(Goals0, Must, Subn, Goals).
 
+goal_util__name_apart_2(par_conj(Goals0, SM0), Must, Subn,
+		par_conj(Goals, SM)) :-
+	goal_util__name_apart_list(Goals0, Must, Subn, Goals),
+	goal_util__rename_var_maps(SM0, Must, Subn, SM).
+
 goal_util__name_apart_2(disj(Goals0, SM0), Must, Subn, disj(Goals, SM)) :-
 	goal_util__name_apart_list(Goals0, Must, Subn, Goals),
 	goal_util__rename_var_maps(SM0, Must, Subn, SM).
@@ -424,6 +429,9 @@
 goal_util__goal_vars_2(conj(Goals), Set0, Set) :-
 	goal_util__goals_goal_vars(Goals, Set0, Set).
 
+goal_util__goal_vars_2(par_conj(Goals, _SM), Set0, Set) :-
+	goal_util__goals_goal_vars(Goals, Set0, Set).
+
 goal_util__goal_vars_2(disj(Goals, _), Set0, Set) :-
 	goal_util__goals_goal_vars(Goals, Set0, Set).
 
@@ -518,6 +526,9 @@
 
 goal_expr_size(conj(Goals), Size) :-
 	goals_size(Goals, Size).
+goal_expr_size(par_conj(Goals, _SM), Size) :-
+	goals_size(Goals, Size1),
+	Size is Size1 + 1.
 goal_expr_size(disj(Goals, _), Size) :-
 	goals_size(Goals, Size1),
 	Size is Size1 + 1.
Index: compiler/higher_order.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/higher_order.m,v
retrieving revision 1.33
diff -u -r1.33 higher_order.m
--- higher_order.m	1997/09/01 14:01:46	1.33
+++ higher_order.m	1997/09/08 22:43:25
@@ -280,6 +280,13 @@
 	traverse_conj(Goals0, Goals, PredProcId, unchanged, Changed,
 					0, GoalSize).
 
+traverse_goal(par_conj(Goals0, SM) - Info, par_conj(Goals, SM) - Info,
+			PredProcId, Changed, GoalSize) -->
+		% traverse_disj treats its list of goals as independent
+		% rather than specifically disjoint, so we can use it
+		% to process a list of independent parallel conjuncts.
+	traverse_disj(Goals0, Goals, PredProcId, Changed, GoalSize).
+
 traverse_goal(disj(Goals0, SM) - Info, disj(Goals, SM) - Info,
 				PredProcId, Changed, GoalSize) -->
 	traverse_disj(Goals0, Goals, PredProcId, Changed, GoalSize).
@@ -348,6 +355,10 @@
 		% specialization information before the goal, then merge the
 		% results to give the specialization information after the
 		% disjunction.
+		%
+		% This code is used both for disjunction and parallel
+		% conjunction.
+
 :- pred traverse_disj(hlds_goals::in, hlds_goals::out, pred_proc_id::in,
 		changed::out, int::out, higher_order_info::in,
 		higher_order_info::out) is det.
Index: compiler/hlds_goal.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/hlds_goal.m,v
retrieving revision 1.42
diff -u -r1.42 hlds_goal.m
--- hlds_goal.m	1997/10/13 08:09:41	1.42
+++ hlds_goal.m	1997/10/17 04:20:17
@@ -166,7 +166,15 @@
 			extra_pragma_info
 					% Extra information for model_non
 					% pragma_c_codes; none for others.
-		).
+		)
+
+	;	par_conj(hlds_goals, store_map)
+					% parallel conjunction
+					% The store_map specifies the locations
+					% in which live variables should be
+					% stored at the start of the parallel
+					% conjunction.
+	.
 
 :- type extra_pragma_info
 	--->	none
@@ -622,6 +630,13 @@
 :- pred goal_to_conj_list(hlds_goal, list(hlds_goal)).
 :- mode goal_to_conj_list(in, out) is det.
 
+	% Convert a goal to a list of parallel conjuncts.
+	% If the goal is a parallel conjunction, then return its conjuncts,
+	% otherwise return the goal as a singleton list.
+
+:- pred goal_to_par_conj_list(hlds_goal, list(hlds_goal)).
+:- mode goal_to_par_conj_list(in, out) is det.
+
 	% Convert a goal to a list of disjuncts.
 	% If the goal is a disjunction, then return its disjuncts,
 	% otherwise return the goal as a singleton list.
@@ -637,6 +652,14 @@
 :- pred conj_list_to_goal(list(hlds_goal), hlds_goal_info, hlds_goal).
 :- mode conj_list_to_goal(in, in, out) is det.
 
+	% Convert a list of parallel conjuncts to a goal.
+	% If the list contains only one goal, then return that goal,
+	% otherwise return the parallel conjunction of the conjuncts,
+	% with the specified goal_info.
+
+:- pred par_conj_list_to_goal(list(hlds_goal), hlds_goal_info, hlds_goal).
+:- mode par_conj_list_to_goal(in, in, out) is det.
+
 	% Convert a list of disjuncts to a goal.
 	% If the list contains only one goal, then return that goal,
 	% otherwise return the disjunction of the disjuncts,
@@ -846,6 +869,17 @@
 		ConjList = [Goal]
 	).
 
+	% Convert a goal to a list of parallel conjuncts.
+	% If the goal is a conjunction, then return its conjuncts,
+	% otherwise return the goal as a singleton list.
+
+goal_to_par_conj_list(Goal, ConjList) :-
+	( Goal = (par_conj(List, _) - _) ->
+		ConjList = List
+	;
+		ConjList = [Goal]
+	).
+
 	% Convert a goal to a list of disjuncts.
 	% If the goal is a disjunction, then return its disjuncts
 	% otherwise return the goal as a singleton list.
@@ -867,6 +901,19 @@
 		Goal = Goal0
 	;
 		Goal = conj(ConjList) - GoalInfo
+	).
+
+	% Convert a list of parallel conjuncts to a goal.
+	% If the list contains only one goal, then return that goal,
+	% otherwise return the parallel conjunction of the conjuncts,
+	% with the specified goal_info.
+
+par_conj_list_to_goal(ConjList, GoalInfo, Goal) :-
+	( ConjList = [Goal0] ->
+		Goal = Goal0
+	;
+		map__init(StoreMap),
+		Goal = par_conj(ConjList, StoreMap) - GoalInfo
 	).
 
 	% Convert a list of disjuncts to a goal.
Index: compiler/hlds_out.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/hlds_out.m,v
retrieving revision 1.174
diff -u -r1.174 hlds_out.m
--- hlds_out.m	1997/10/13 08:09:43	1.174
+++ hlds_out.m	1997/10/21 02:28:30
@@ -919,14 +919,15 @@
 			hlds_out__write_indent(Indent),
 			io__write_string("( % conjunction\n"),
 			hlds_out__write_conj(Goal, Goals, ModuleInfo, VarSet,
-				AppendVarnums, Indent1, "", Verbose, TypeQual),
+				AppendVarnums, Indent1, "", Verbose, ",\n",
+				TypeQual),
 			hlds_out__write_indent(Indent),
 			io__write_string(")"),
 			io__write_string(Follow),
 			io__write_string("\n")
 		;
 			hlds_out__write_conj(Goal, Goals, ModuleInfo, VarSet,
-				AppendVarnums, Indent, Follow, Verbose,
+				AppendVarnums, Indent, Follow, Verbose, ",\n",
 				TypeQual)
 		)
 	;
@@ -936,6 +937,27 @@
 		io__write_string("\n")
 	).
 
+hlds_out__write_goal_2(par_conj(List, _), ModuleInfo, VarSet, AppendVarnums,
+		Indent, Follow, TypeQual) -->
+	hlds_out__write_indent(Indent),
+	( { List = [Goal | Goals] } ->
+		io__write_string("( % parallel conjunction\n"),
+		{ Indent1 is Indent + 1 },
+		hlds_out__write_goal_a(Goal, ModuleInfo, VarSet, AppendVarnums,
+			Indent1, "", TypeQual),
+			% See comments at hlds_out__write_goal_list.
+		hlds_out__write_goal_list(Goals, ModuleInfo, VarSet,
+			AppendVarnums, Indent, "&", TypeQual),
+		hlds_out__write_indent(Indent),
+		io__write_string(")"),
+		io__write_string(Follow),
+		io__write_string("\n")
+	;
+		io__write_string("fail"),
+		io__write_string(Follow),
+		io__write_string("\n")
+	).
+
 hlds_out__write_goal_2(disj(List, _), ModuleInfo, VarSet, AppendVarnums,
 		Indent, Follow, TypeQual) -->
 	hlds_out__write_indent(Indent),
@@ -944,8 +966,8 @@
 		{ Indent1 is Indent + 1 },
 		hlds_out__write_goal_a(Goal, ModuleInfo, VarSet, AppendVarnums,
 			Indent1, "", TypeQual),
-		hlds_out__write_disj(Goals, ModuleInfo, VarSet, AppendVarnums,
-			Indent, TypeQual),
+		hlds_out__write_goal_list(Goals, ModuleInfo, VarSet,
+			AppendVarnums, Indent, ";", TypeQual),
 		hlds_out__write_indent(Indent),
 		io__write_string(")"),
 		io__write_string(Follow),
@@ -1383,11 +1405,12 @@
 	mercury_output_mode(Mode, VarSet).
 
 :- pred hlds_out__write_conj(hlds_goal, list(hlds_goal), module_info, varset,
-	bool, int, string, string, vartypes, io__state, io__state).
-:- mode hlds_out__write_conj(in, in, in, in, in, in, in, in, in, di, uo) is det.
+	bool, int, string, string, string, vartypes, io__state, io__state).
+:- mode hlds_out__write_conj(in, in, in, in, in, in, in, in, in, in,
+	di, uo) is det.
 
 hlds_out__write_conj(Goal1, Goals1, ModuleInfo, VarSet, AppendVarnums,
-		Indent, Follow, Verbose, TypeQual) -->
+		Indent, Follow, Verbose, Separator, TypeQual) -->
 	(
 		{ Goals1 = [Goal2 | Goals2] }
 	->
@@ -1400,34 +1423,39 @@
 			hlds_out__write_goal_a(Goal1, ModuleInfo, VarSet,
 				AppendVarnums, Indent, "", TypeQual),
 			hlds_out__write_indent(Indent),
-			io__write_string(",\n")
+			io__write_string(Separator)
 		;
 			hlds_out__write_goal_a(Goal1, ModuleInfo, VarSet,
-				AppendVarnums, Indent, ",", TypeQual)
+				AppendVarnums, Indent, Separator, TypeQual)
 		),
 		hlds_out__write_conj(Goal2, Goals2, ModuleInfo, VarSet,
-			AppendVarnums, Indent, Follow, Verbose, TypeQual)
+			AppendVarnums, Indent, Follow, Verbose, Separator,
+			TypeQual)
 	;
 		hlds_out__write_goal_a(Goal1, ModuleInfo, VarSet,
 			AppendVarnums, Indent, Follow, TypeQual)
 	).
 
-:- pred hlds_out__write_disj(list(hlds_goal), module_info, varset, bool, int,
-	vartypes, io__state, io__state).
-:- mode hlds_out__write_disj(in, in, in, in, in, in, di, uo) is det.
+	% hlds_out__write_goal_list is used to write both disjunctions and
+	% parallel conjunctions.
+
+:- pred hlds_out__write_goal_list(list(hlds_goal), module_info, varset, bool,
+		int, string, vartypes, io__state, io__state).
+:- mode hlds_out__write_goal_list(in, in, in, in, in, in, in, di, uo) is det.
 
-hlds_out__write_disj(GoalList, ModuleInfo, VarSet, AppendVarnums, Indent,
-		TypeQual) -->
+hlds_out__write_goal_list(GoalList, ModuleInfo, VarSet, AppendVarnums, Indent,
+		Separator, TypeQual) -->
 	(
 		{ GoalList = [Goal | Goals] }
 	->
 		hlds_out__write_indent(Indent),
-		io__write_string(";\n"),
+		io__write_string(Separator),
+		io__write_string("\n"),
 		{ Indent1 is Indent + 1 },
 		hlds_out__write_goal_a(Goal, ModuleInfo, VarSet,
 			AppendVarnums, Indent1, "", TypeQual),
-		hlds_out__write_disj(Goals, ModuleInfo, VarSet,
-			AppendVarnums, Indent, TypeQual)
+		hlds_out__write_goal_list(Goals, ModuleInfo, VarSet,
+			AppendVarnums, Indent, Separator, TypeQual)
 	;
 		[]
 	).
Index: compiler/inlining.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/inlining.m,v
retrieving revision 1.69
diff -u -r1.69 inlining.m
--- inlining.m	1997/09/01 14:02:31	1.69
+++ inlining.m	1997/09/09 02:19:04
@@ -386,6 +386,10 @@
 inlining__inlining_in_goal(conj(Goals0) - GoalInfo, conj(Goals) - GoalInfo) -->
 	inlining__inlining_in_conj(Goals0, Goals).
 
+inlining__inlining_in_goal(par_conj(Goals0, SM) - GoalInfo,
+		par_conj(Goals, SM) - GoalInfo) -->
+	inlining__inlining_in_disj(Goals0, Goals).
+
 inlining__inlining_in_goal(disj(Goals0, SM) - GoalInfo,
 		disj(Goals, SM) - GoalInfo) -->
 	inlining__inlining_in_disj(Goals0, Goals).
@@ -528,6 +532,9 @@
 		pragma_c_code(A, B, C, D, E, F, G, H) - GoalInfo) --> [].
 
 %-----------------------------------------------------------------------------%
+
+	% inlining__inlining_in_disj is used for both disjunctions and
+	% parallel conjunctions.
 
 :- pred inlining__inlining_in_disj(list(hlds_goal), list(hlds_goal), 
 		inline_info, inline_info).
Index: compiler/instmap.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/instmap.m,v
retrieving revision 1.16
diff -u -r1.16 instmap.m
--- instmap.m	1997/09/30 14:53:49	1.16
+++ instmap.m	1997/10/21 05:18:35
@@ -185,6 +185,18 @@
 		mode_info, mode_info).
 :- mode instmap__merge(in, in, in, mode_info_di, mode_info_uo) is det.
 
+	% instmap__unify(NonLocalVars, InstMapNonlocalvarPairss):
+	%       Unify the `InstMaps' in the list of pairs resulting
+	%	from different branches of a parallel conjunction and
+	%	update the instantiatedness of all the nonlocal variables.
+	%	The variable locking that is done when modechecking
+	%	the individual conjuncts ensures that variables have
+	%	at most one producer.
+	%
+:- pred instmap__unify(set(var), list(pair(instmap, set(var))),
+		mode_info, mode_info).
+:- mode instmap__unify(in, in, mode_info_di, mode_info_uo) is det.
+
 	% instmap__restrict takes an instmap and a set of vars and
 	% returns an instmap with its domain restricted to those
 	% vars.
@@ -214,8 +226,8 @@
 
 	% merge_instmap_delta(InitialInstMap, NonLocals,
 	%	InstMapDeltaA, InstMapDeltaB, ModuleInfo0, ModuleInfo)
-	% Merge the instmap_deltas of different branches of an ite, disj
-	% or switch.
+	% Merge the instmap_deltas of different branches of an if-then-else,
+	% disj or switch.
 :- pred merge_instmap_delta(instmap, set(var), instmap_delta, instmap_delta,
 		instmap_delta, module_info, module_info).
 :- mode merge_instmap_delta(in, in, in, in, out, in, out) is det.
@@ -229,6 +241,14 @@
 		instmap_delta, module_info, module_info).
 :- mode merge_instmap_deltas(in, in, in, out, in, out) is det.
 
+	% unify_instmap_delta(InitialInstMap, NonLocals,
+	%	InstMapDeltaA, InstMapDeltaB, ModuleInfo0, ModuleInfo)
+	% Unify the instmap_deltas of different branches of a parallel
+	% conjunction.
+:- pred unify_instmap_delta(instmap, set(var), instmap_delta, instmap_delta,
+		instmap_delta, module_info, module_info).
+:- mode unify_instmap_delta(in, in, in, in, out, in, out) is det.
+
 %-----------------------------------------------------------------------------%
 
 	% `instmap_delta_apply_sub(InstmapDelta0, Must, Sub, InstmapDelta)'
@@ -635,6 +655,127 @@
 		MergedDelta, ModuleInfo1, ModuleInfo).
 
 %-----------------------------------------------------------------------------%
+
+instmap__unify(NonLocals, InstMapList, ModeInfo0, ModeInfo) :-
+	(
+			% If any of the instmaps is unreachable, then
+			% the final instmap is unreachable.
+		list__member(unreachable - _, InstMapList)
+	->
+		mode_info_set_instmap(unreachable, ModeInfo0, ModeInfo)
+	;
+			% If there is only one instmap, then we just
+			% stick it in the mode_info.
+		InstMapList = [InstMap - _]
+	->
+		mode_info_set_instmap(InstMap, ModeInfo0, ModeInfo)
+	;
+		InstMapList = [InstMap0 - _|InstMapList1],
+		InstMap0 = reachable(InstMapping0)
+	->
+			% having got the first instmapping, to use as
+			% an accumulator, all instmap__unify_2 which
+			% unifies each of the nonlocals from each instmap
+			% with the corresponding inst in the accumulator.
+		mode_info_get_module_info(ModeInfo0, ModuleInfo0),
+		set__to_sorted_list(NonLocals, NonLocalsList),
+		instmap__unify_2(NonLocalsList, InstMap0, InstMapList1,
+			ModuleInfo0, InstMapping0, ModuleInfo,
+			InstMapping, ErrorList),
+		mode_info_set_module_info(ModeInfo0, ModuleInfo, ModeInfo1),
+			
+			% If there were any errors, then add the error
+			% to the list of possible errors in the mode_info.
+		( ErrorList = [FirstError | _] ->
+			FirstError = Var - _,
+			set__singleton_set(WaitingVars, Var),
+			mode_info_error(WaitingVars,
+				mode_error_par_conj(ErrorList),
+				ModeInfo1, ModeInfo2)
+		;
+			ModeInfo2 = ModeInfo1
+		),
+		mode_info_set_instmap(reachable(InstMapping),
+			ModeInfo2, ModeInfo)
+	;
+		ModeInfo = ModeInfo0
+	).
+
+%-----------------------------------------------------------------------------%
+
+	% instmap__unify_2(Vars, InitialInstMap, InstMaps, ModuleInfo,
+	%		ErrorList):
+	%       Let `ErrorList' be the list of variables in `Vars' for
+	%       which there are two instmaps in `InstMaps' for which the insts
+	%       of the variable is incompatible.
+:- pred instmap__unify_2(list(var), instmap, list(pair(instmap, set(var))),
+		module_info, map(var, inst), module_info,
+		map(var, inst), merge_errors).
+:- mode instmap__unify_2(in, in, in, in, in, out, out, out) is det.
+
+instmap__unify_2([], _, _, ModuleInfo, InstMap, ModuleInfo, InstMap, []).
+instmap__unify_2([Var|Vars], InitialInstMap, InstMapList, ModuleInfo0, InstMap0,
+			ModuleInfo, InstMap, ErrorList) :-
+	instmap__unify_2(Vars, InitialInstMap, InstMapList, ModuleInfo0,
+			InstMap0, ModuleInfo1, InstMap1, ErrorList1),
+	instmap__lookup_var(InitialInstMap, Var, InitialVarInst),
+	instmap__unify_var(InstMapList, Var, [], Insts, InitialVarInst, Inst,
+		ModuleInfo1, ModuleInfo, no, Error),
+	( Error = yes ->
+		ErrorList = [Var - Insts | ErrorList1]
+	;
+		ErrorList = ErrorList1
+	),
+	map__set(InstMap1, Var, Inst, InstMap).
+
+	% instmap__unify_var(InstMaps, Var, InitialInstMap, ModuleInfo,
+	%		Insts, Error):
+	%       Let `Insts' be the list of the inst of `Var' in
+	%       each of the corresponding `InstMaps'.  Let `Error' be yes
+	%	iff there are two instmaps for which the inst of `Var'
+	%       is incompatible.
+
+:- pred instmap__unify_var(list(pair(instmap, set(var))), var,
+		list(inst), list(inst), inst, inst, module_info, module_info,
+		bool, bool).
+:- mode instmap__unify_var(in, in, in, out, in, out, in, out, in, out) is det.
+
+instmap__unify_var([], _, Insts, Insts, Inst, Inst, ModuleInfo, ModuleInfo,
+		Error, Error).
+instmap__unify_var([InstMap - Nonlocals| Rest], Var, InstList0, InstList,
+		Inst0, Inst, ModuleInfo0, ModuleInfo, Error0, Error) :-
+	(
+		set__member(Var, Nonlocals)
+	->
+		instmap__lookup_var(InstMap, Var, VarInst),
+		(
+			% We unify the accumulated inst and the inst from the
+			% given instmap - we don't care about the determinism.
+			% Variable locking during mode analysis ensures that
+			% there is a unique producer for each variable - whether
+			% or not the unification may fail is up to determinism
+			% analysis.
+
+			abstractly_unify_inst(live, Inst0, VarInst, fake_unify,
+				ModuleInfo0, Inst1, _Det, ModuleInfo1)
+		->
+			Inst2 = Inst1,
+			ModuleInfo2 = ModuleInfo1,
+			Error1 = Error0
+		;
+			Error1 = yes,
+			ModuleInfo2 = ModuleInfo0,
+			Inst2 = not_reached
+		)
+	;
+		VarInst = free,
+		Inst2 = Inst0,
+		Error1 = Error0,
+		ModuleInfo2 = ModuleInfo0
+	),
+	instmap__unify_var(Rest, Var, [VarInst | InstList0], InstList,
+		Inst2, Inst, ModuleInfo2, ModuleInfo, Error1, Error).
+
 %-----------------------------------------------------------------------------%
 
 	% Given two instmaps and a set of variables, compute an instmap delta
@@ -751,6 +892,75 @@
 		error("merge_instmapping_delta_2: unexpected mode error")
 	),
 	merge_instmapping_delta_2(Vars, InstMap, InstMappingA, InstMappingB,
+		InstMapping1, InstMapping, ModuleInfo1, ModuleInfo).
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+	% Given two instmap deltas, unify them to produce a new instmap_delta.
+
+unify_instmap_delta(_, _, unreachable, InstMapDelta, InstMapDelta) --> [].
+unify_instmap_delta(_, _, reachable(InstMapping), unreachable,
+				reachable(InstMapping)) --> [].
+unify_instmap_delta(InstMap, NonLocals, reachable(InstMappingA),
+		reachable(InstMappingB), reachable(InstMapping)) -->
+	unify_instmapping_delta(InstMap, NonLocals, InstMappingA,
+		InstMappingB, InstMapping).
+
+:- pred unify_instmapping_delta(instmap, set(var), instmapping, instmapping,
+		instmapping, module_info, module_info).
+:- mode unify_instmapping_delta(in, in, in, in, out, in, out) is det.
+
+unify_instmapping_delta(InstMap, NonLocals, InstMappingA,
+		InstMappingB, InstMapping) -->
+	{ map__keys(InstMappingA, VarsInA) },
+	{ map__keys(InstMappingB, VarsInB) },
+	{ set__sorted_list_to_set(VarsInA, SetofVarsInA) },
+	{ set__insert_list(SetofVarsInA, VarsInB, SetofVars0) },
+	{ set__intersect(SetofVars0, NonLocals, SetofVars) },
+	{ map__init(InstMapping0) },
+	{ set__to_sorted_list(SetofVars, ListofVars) },
+	unify_instmapping_delta_2(ListofVars, InstMap, InstMappingA,
+		InstMappingB, InstMapping0, InstMapping).
+
+:- pred unify_instmapping_delta_2(list(var), instmap, instmapping, instmapping,
+			instmapping, instmapping, module_info, module_info).
+:- mode unify_instmapping_delta_2(in, in, in, in, in, out, in, out) is det.
+
+unify_instmapping_delta_2([], _, _, _, InstMapping, InstMapping,
+		ModInfo, ModInfo).
+unify_instmapping_delta_2([Var | Vars], InstMap, InstMappingA, InstMappingB,
+			InstMapping0, InstMapping, ModuleInfo0, ModuleInfo) :-
+	( map__search(InstMappingA, Var, InstA) ->
+		( map__search(InstMappingB, Var, InstB) ->
+			(
+			% We unify the accumulated inst and the inst from the
+			% given instmap - we don't care about the determinism.
+			% Variable locking during mode analysis ensures that
+			% there is a unique producer for each variable - whether
+			% or not the unification may fail is up to determinism
+			% analysis.
+
+				abstractly_unify_inst(live, InstA, InstB,
+					fake_unify, ModuleInfo0, Inst, _Det,
+					ModuleInfoPrime)
+			->
+				ModuleInfo1 = ModuleInfoPrime,
+				map__det_insert(InstMapping0, Var, Inst,
+					InstMapping1)
+			;
+				error(
+				"unify_instmapping_delta_2: unexpected error")
+			)
+		;
+			ModuleInfo1 = ModuleInfo0,
+			map__det_insert(InstMapping0, Var, InstA, InstMapping1)
+		)
+	;
+		ModuleInfo1 = ModuleInfo0,
+		InstMapping1 = InstMapping0
+	),
+	unify_instmapping_delta_2(Vars, InstMap, InstMappingA, InstMappingB,
 		InstMapping1, InstMapping, ModuleInfo1, ModuleInfo).
 
 %-----------------------------------------------------------------------------%
Index: compiler/intermod.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/intermod.m,v
retrieving revision 1.34
diff -u -r1.34 intermod.m
--- intermod.m	1997/10/26 23:05:36	1.34
+++ intermod.m	1997/10/26 23:31:56
@@ -346,6 +346,10 @@
 intermod__traverse_goal(conj(Goals0) - Info, conj(Goals) - Info, DoWrite) -->
 	intermod__traverse_list_of_goals(Goals0, Goals, DoWrite).
 
+intermod__traverse_goal(par_conj(Goals0, SM) - Info, par_conj(Goals, SM) - Info,
+		DoWrite) -->
+	intermod__traverse_list_of_goals(Goals0, Goals, DoWrite).
+
 intermod__traverse_goal(disj(Goals0, SM) - Info, disj(Goals, SM) - Info,
 		DoWrite) -->
 	intermod__traverse_list_of_goals(Goals0, Goals, DoWrite).
Index: compiler/lambda.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/lambda.m,v
retrieving revision 1.32
diff -u -r1.32 lambda.m
--- lambda.m	1997/09/01 14:02:47	1.32
+++ lambda.m	1997/09/08 22:43:25
@@ -171,6 +171,9 @@
 
 lambda__process_goal_2(conj(Goals0), GoalInfo, conj(Goals) - GoalInfo) -->
 	lambda__process_goal_list(Goals0, Goals).
+lambda__process_goal_2(par_conj(Goals0, SM), GoalInfo,
+		par_conj(Goals, SM) - GoalInfo) -->
+	lambda__process_goal_list(Goals0, Goals).
 lambda__process_goal_2(disj(Goals0, SM), GoalInfo, disj(Goals, SM) - GoalInfo)
 		-->
 	lambda__process_goal_list(Goals0, Goals).
Index: compiler/lco.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/lco.m,v
retrieving revision 1.7
diff -u -r1.7 lco.m
--- lco.m	1997/09/01 14:02:49	1.7
+++ lco.m	1997/09/08 22:43:25
@@ -28,7 +28,7 @@
 :- implementation.
 
 :- import_module hlds_goal, passes_aux, hlds_out.
-:- import_module list, std_util.
+:- import_module list, require, std_util.
 
 %-----------------------------------------------------------------------------%
 
@@ -62,6 +62,10 @@
 lco_in_goal_2(conj(Goals0), ModuleInfo, conj(Goals)) :-
 	list__reverse(Goals0, RevGoals0),
 	lco_in_conj(RevGoals0, [], ModuleInfo, Goals).
+
+	% XXX Some execution algorithm issues here.
+lco_in_goal_2(par_conj(_Goals0, SM), _ModuleInfo, par_conj(_Goals, SM)) :-
+	error("sorry: lco of parallel conjunction not implemented").
 
 lco_in_goal_2(disj(Goals0, SM), ModuleInfo, disj(Goals, SM)) :-
 	lco_in_disj(Goals0, ModuleInfo, Goals).
Index: compiler/live_vars.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/live_vars.m,v
retrieving revision 1.67
diff -u -r1.67 live_vars.m
--- live_vars.m	1997/09/01 14:02:55	1.67
+++ live_vars.m	1997/10/21 04:56:24
@@ -135,7 +135,7 @@
 	(
 /*******
 		% goal_is_atomic(Goal0)
-		fail
+		semidet_fail
 		% NB: `fail' is a conservative approximation
 		% We could do better, but `goal_is_atomic' is not
 		% quite right
@@ -170,6 +170,25 @@
 	build_live_sets_in_conj(Goals0, Liveness0, ResumeVars0, LiveSets0,
 		ModuleInfo, ProcInfo, Liveness, ResumeVars, LiveSets).
 
+build_live_sets_in_goal_2(par_conj(Goals0, _SM), Liveness0, ResumeVars0,
+		LiveSets0, GoalInfo, ModuleInfo, ProcInfo, Liveness,
+		ResumeVars, LiveSets) :-
+	goal_info_get_nonlocals(GoalInfo, NonLocals),
+	set__union(NonLocals, Liveness0, LiveSet),
+		% We insert all the union of the live vars and the nonlocals.
+		% Since each parallel conjunct may be run on a different
+		% Mercury engine to the current engine, we must save all
+		% the variables that are live or nonlocal to the parallel
+		% conjunction. Nonlocal variables that are currently free, but
+		% are bound inside one of the conjuncts need a stackslot
+		% because they are passed out by reference to that stackslot.
+	set__insert(LiveSets0, LiveSet, LiveSets1),
+		% build_live_sets_in_disj treats its list of goals as a list
+		% of independent goals, so we can use it for parallel conj's
+		% too.
+	build_live_sets_in_disj(Goals0, Liveness0, ResumeVars0, LiveSets1,
+		GoalInfo, ModuleInfo, ProcInfo, Liveness, ResumeVars, LiveSets).
+
 build_live_sets_in_goal_2(disj(Goals0, _), Liveness0, ResumeVars0, LiveSets0,
 		GoalInfo, ModuleInfo, ProcInfo, Liveness, ResumeVars, LiveSets)
 		:-
@@ -386,6 +405,9 @@
 	).
 
 %-----------------------------------------------------------------------------%
+
+	% build_live_sets_in_disj is used for both disjunctions and
+	% parallel conjunctions.
 
 :- pred build_live_sets_in_disj(list(hlds_goal), set(var), set(var),
 	set(set(var)), hlds_goal_info, module_info, proc_info,
Index: compiler/livemap.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/livemap.m,v
retrieving revision 1.27
diff -u -r1.27 livemap.m
--- livemap.m	1997/08/25 17:48:18	1.27
+++ livemap.m	1997/09/09 02:19:23
@@ -60,9 +60,9 @@
 
 livemap__build_2(Backinstrs, Livemap0, MaybeLivemap) :-
 	set__init(Livevals0),
-	livemap__build_livemap(Backinstrs, Livevals0, no, Ccode1,
+	livemap__build_livemap(Backinstrs, Livevals0, no, DontValueNumber1,
 		Livemap0, Livemap1),
-	( Ccode1 = yes ->
+	( DontValueNumber1 = yes ->
 		MaybeLivemap = no
 	; livemap__equal_livemaps(Livemap0, Livemap1) ->
 		MaybeLivemap = yes(Livemap1)
@@ -105,13 +105,15 @@
 	livemap, livemap).
 :- mode livemap__build_livemap(in, in, in, out, in, out) is det.
 
-livemap__build_livemap([], _, Ccode, Ccode, Livemap, Livemap).
-livemap__build_livemap([Instr0 | Instrs0], Livevals0, Ccode0, Ccode,
-		Livemap0, Livemap) :-
+livemap__build_livemap([], _, DontValueNumber, DontValueNumber,
+		Livemap, Livemap).
+livemap__build_livemap([Instr0 | Instrs0], Livevals0,
+		DontValueNumber0, DontValueNumber, Livemap0, Livemap) :-
 	livemap__build_livemap_instr(Instr0, Instrs0, Instrs1,
-		Livevals0, Livevals1, Ccode0, Ccode1, Livemap0, Livemap1),
+		Livevals0, Livevals1, DontValueNumber0, DontValueNumber1,
+		Livemap0, Livemap1),
 	livemap__build_livemap(Instrs1, Livevals1,
-		Ccode1, Ccode, Livemap1, Livemap).
+		DontValueNumber1, DontValueNumber, Livemap1, Livemap).
 
 :- pred livemap__build_livemap_instr(instruction, list(instruction),
 	list(instruction), lvalset, lvalset, bool, bool, livemap, livemap).
@@ -119,14 +121,15 @@
 	is det.
 
 livemap__build_livemap_instr(Instr0, Instrs0, Instrs,
-		Livevals0, Livevals, Ccode0, Ccode, Livemap0, Livemap) :-
+		Livevals0, Livevals, DontValueNumber0, DontValueNumber,
+		Livemap0, Livemap) :-
 	Instr0 = Uinstr0 - _,
 	(
 		Uinstr0 = comment(_),
 		Livemap = Livemap0,
 		Livevals = Livevals0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = livevals(_),
 		error("livevals found in backward scan in build_livemap")
@@ -148,31 +151,31 @@
 		livemap__make_live_in_rvals([Rval | Rvals], Livevals1, Livevals),
 		Livemap = Livemap0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = call(_, _, _, _),
 		livemap__look_for_livevals(Instrs0, Instrs,
 			Livevals0, Livevals, "call", yes, _),
 		Livemap = Livemap0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = mkframe(_, _, _),
 		Livemap = Livemap0,
 		Livevals = Livevals0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = modframe(_),
 		Livemap = Livemap0,
 		Livevals = Livevals0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = label(Label),
 		map__set(Livemap0, Label, Livevals0, Livemap),
 		Livevals = Livevals0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = goto(CodeAddr),
 		opt_util__livevals_addr(CodeAddr, LivevalsNeeded),
@@ -201,7 +204,7 @@
 			Livevals = Livevals3
 		),
 		Livemap = Livemap0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = computed_goto(Rval, Labels),
 		set__init(Livevals1),
@@ -210,13 +213,13 @@
 			Livevals2, Livevals),
 		Livemap = Livemap0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = c_code(_),
 		Livemap = Livemap0,
 		Livevals = Livevals0,
 		Instrs = Instrs0,
-		Ccode = yes
+		DontValueNumber = yes
 	;
 		Uinstr0 = if_val(Rval, CodeAddr),
 		livemap__look_for_livevals(Instrs0, Instrs,
@@ -242,7 +245,7 @@
 			Livevals = Livevals3
 		),
 		Livemap = Livemap0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = incr_hp(Lval, _Tag, Rval),
 
@@ -258,7 +261,7 @@
 		livemap__make_live_in_rvals([Rval | Rvals], Livevals1, Livevals),
 		Livemap = Livemap0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = mark_hp(Lval),
 		set__delete(Livevals0, Lval, Livevals1),
@@ -266,13 +269,13 @@
 		livemap__make_live_in_rvals(Rvals, Livevals1, Livevals),
 		Livemap = Livemap0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = restore_hp(Rval),
 		livemap__make_live_in_rvals([Rval], Livevals0, Livevals),
 		Livemap = Livemap0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = store_ticket(Lval),
 		set__delete(Livevals0, Lval, Livevals1),
@@ -280,19 +283,19 @@
 		livemap__make_live_in_rvals(Rvals, Livevals1, Livevals),
 		Livemap = Livemap0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = reset_ticket(Rval, _Reason),
 		livemap__make_live_in_rval(Rval, Livevals0, Livevals),
 		Livemap = Livemap0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = discard_ticket,
 		Livevals = Livevals0,
 		Livemap = Livemap0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = mark_ticket_stack(Lval),
 		set__delete(Livevals0, Lval, Livevals1),
@@ -300,32 +303,56 @@
 		livemap__make_live_in_rvals(Rvals, Livevals1, Livevals),
 		Livemap = Livemap0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = discard_tickets_to(Rval),
 		livemap__make_live_in_rval(Rval, Livevals0, Livevals),
 		Livemap = Livemap0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = incr_sp(_, _),
-		Livevals = Livevals0,
 		Livemap = Livemap0,
+		Livevals = Livevals0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = DontValueNumber0
 	;
 		Uinstr0 = decr_sp(_),
+		Livemap = Livemap0,
 		Livevals = Livevals0,
+		Instrs = Instrs0,
+		DontValueNumber = DontValueNumber0
+	;
+		% XXX Value numbering doesn't handle fork [yet] so
+		% set DontValueNumber to yes.
+		Uinstr0 = fork(_, _, _),
 		Livemap = Livemap0,
+		Livevals = Livevals0,
+		Instrs = Instrs0,
+		DontValueNumber = yes
+	;
+		% XXX Value numbering doesn't handle join_and_terminate [yet] so
+		% set DontValueNumber to yes.
+		Uinstr0 = join_and_terminate(_),
+		Livemap = Livemap0,
+		Livevals = Livevals0,
+		Instrs = Instrs0,
+		DontValueNumber = yes
+	;
+		% XXX Value numbering doesn't handle join_and_continue [yet] so
+		% set DontValueNumber to yes.
+		Uinstr0 = join_and_continue(_, _),
+		Livemap = Livemap0,
+		Livevals = Livevals0,
 		Instrs = Instrs0,
-		Ccode = Ccode0
+		DontValueNumber = yes
 	;
 		% XXX we shouldn't just give up here
 		Uinstr0 = pragma_c(_, _, _, _, _),
 		Livemap = Livemap0,
 		Livevals = Livevals0,
 		Instrs = Instrs0,
-		Ccode = yes
+		DontValueNumber = yes
 	).
 
 :- pred livemap__look_for_livevals(list(instruction), list(instruction),
Index: compiler/liveness.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/liveness.m,v
retrieving revision 1.84
diff -u -r1.84 liveness.m
--- liveness.m	1997/10/20 07:35:22	1.84
+++ liveness.m	1997/10/20 22:35:23
@@ -233,6 +233,13 @@
 		Liveness, conj(Goals)) :-
 	detect_liveness_in_conj(Goals0, Liveness0, LiveInfo, Liveness, Goals).
 
+detect_liveness_in_goal_2(par_conj(Goals0, SM), Liveness0, NonLocals, LiveInfo,
+		Liveness, par_conj(Goals, SM)) :-
+	set__init(Union0),
+	detect_liveness_in_par_conj(Goals0, Liveness0, NonLocals, LiveInfo,
+		Union0, Union, Goals),
+	set__union(Liveness0, Union, Liveness).
+
 detect_liveness_in_goal_2(disj(Goals0, SM), Liveness0, NonLocals, LiveInfo,
 		Liveness, disj(Goals, SM)) :-
 	set__init(Union0),
@@ -357,6 +364,21 @@
 	add_liveness_after_goal(Goal1, Residue, Goal).
 
 %-----------------------------------------------------------------------------%
+
+:- pred detect_liveness_in_par_conj(list(hlds_goal), set(var), set(var),
+	live_info, set(var), set(var), list(hlds_goal)).
+:- mode detect_liveness_in_par_conj(in, in, in, in, in, out, out) is det.
+
+detect_liveness_in_par_conj([], _Liveness, _NonLocals, _LiveInfo,
+		Union, Union, []).
+detect_liveness_in_par_conj([Goal0 | Goals0], Liveness, NonLocals, LiveInfo,
+		Union0, Union, [Goal | Goals]) :-
+	detect_liveness_in_goal(Goal0, Liveness, LiveInfo, Liveness1, Goal),
+	set__union(Union0, Liveness1, Union1),
+	detect_liveness_in_par_conj(Goals0, Liveness, NonLocals, LiveInfo,
+		Union1, Union, Goals).
+
+%-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
 :- pred detect_deadness_in_goal(hlds_goal, set(var), live_info,
@@ -420,6 +442,14 @@
 	detect_deadness_in_conj(Goals0, Deadness0, LiveInfo,
 		Goals, Deadness).
 
+detect_deadness_in_goal_2(par_conj(Goals0, SM), GoalInfo, Deadness0, LiveInfo,
+		Deadness, par_conj(Goals, SM)) :-
+	set__init(Union0),
+	goal_info_get_nonlocals(GoalInfo, NonLocals),
+	detect_deadness_in_par_conj(Goals0, Deadness0, NonLocals,
+		LiveInfo, Union0, Union, Goals),
+	set__union(Union, Deadness0, Deadness).
+
 detect_deadness_in_goal_2(disj(Goals0, SM), GoalInfo, Deadness0,
 		LiveInfo, Deadness, disj(Goals, SM)) :-
 	set__init(Union0),
@@ -539,6 +569,24 @@
 	add_deadness_before_goal(Goal1, Residue, Goal).
 
 %-----------------------------------------------------------------------------%
+
+:- pred detect_deadness_in_par_conj(list(hlds_goal), set(var), set(var),
+	live_info, set(var), set(var), list(hlds_goal)).
+:- mode detect_deadness_in_par_conj(in, in, in, in, in, out, out) is det.
+
+detect_deadness_in_par_conj([], _Deadness, _NonLocals, _LiveInfo,
+		Union, Union, []).
+detect_deadness_in_par_conj([Goal0 | Goals0], Deadness, NonLocals, LiveInfo,
+		Union0, Union, [Goal | Goals]) :-
+	detect_deadness_in_goal(Goal0, Deadness, LiveInfo, Deadness1, Goal1),
+	set__union(Union0, Deadness1, Union1),
+	detect_deadness_in_par_conj(Goals0, Deadness, NonLocals, LiveInfo,
+		Union1, Union, Goals),
+	set__intersect(Union, NonLocals, NonLocalUnion),
+	set__difference(NonLocalUnion, Deadness1, Residue),
+	add_deadness_before_goal(Goal1, Residue, Goal).
+
+%-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
 :- pred detect_resume_points_in_goal(hlds_goal, set(var), live_info, set(var),
@@ -570,6 +618,11 @@
 	detect_resume_points_in_conj(Goals0, Liveness0, LiveInfo, ResumeVars0,
 		Goals, Liveness).
 
+detect_resume_points_in_goal_2(par_conj(Goals0, SM), _, Liveness0, LiveInfo,
+		ResumeVars0, par_conj(Goals, SM), Liveness) :-
+	detect_resume_points_in_par_conj(Goals0, Liveness0, LiveInfo,
+		ResumeVars0, Goals, Liveness).
+
 detect_resume_points_in_goal_2(disj(Goals0, SM), GoalInfo, Liveness0, LiveInfo,
 		ResumeVars0, disj(Goals, SM), Liveness) :-
 	goal_info_get_code_model(GoalInfo, CodeModel),
@@ -820,6 +873,18 @@
 	;
 		Cases = Cases0
 	).
+
+:- pred detect_resume_points_in_par_conj(list(hlds_goal), set(var), live_info,
+	set(var), list(hlds_goal), set(var)).
+:- mode detect_resume_points_in_par_conj(in, in, in, in, out, out) is det.
+
+detect_resume_points_in_par_conj([], Liveness, _, _, [], Liveness).
+detect_resume_points_in_par_conj([Goal0 | Goals0], Liveness0, LiveInfo,
+		ResumeVars0, [Goal | Goals], LivenessFirst) :-
+	detect_resume_points_in_goal(Goal0, Liveness0, LiveInfo, ResumeVars0,
+		Goal, LivenessFirst),
+	detect_resume_points_in_par_conj(Goals0, Liveness0, LiveInfo,
+		ResumeVars0, Goals, _LivenessRest).
 
 :- pred require_equal(set(var), set(var), string, live_info).
 :- mode require_equal(in, in, in, in) is det.
Index: compiler/llds.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/llds.m,v
retrieving revision 1.211
diff -u -r1.211 llds.m
--- llds.m	1997/10/12 13:32:31	1.211
+++ llds.m	1997/10/21 04:57:34
@@ -221,7 +221,7 @@
 			% Decrement the det stack pointer.
 
 	;	pragma_c(list(pragma_c_decl), list(pragma_c_input),
-			string, list(pragma_c_output), term__context).
+			string, list(pragma_c_output), term__context)
 			% The local variable declarations, the info required
 			% for placing the inputs in the variables, the c code,
 			% the info required for picking up the outputs, and
@@ -234,6 +234,30 @@
 %			% in LABEL_1 and DEFINE_LABEL_1 style macros.
 %			% For use in model_non pragma_c_codes, where it
 %			% should be preceded by a mkframe.
+
+	;	fork(label, label, int)
+			% Create a new context.
+			% fork(Child, Parent, NumSlots) creates a new thread
+			% which will start executing at Child, then execution
+			% in the current context branches to Parent.
+			% NumSlots is the number of stack slots that need to
+			% be copied to the child's stack (see comments in
+			% runtime/context.{h,mod}).
+
+	;	join_and_terminate(lval)
+			% Signal that this thread of execution has finished in
+			% the current parallel conjunction, then terminate it.
+			% The synchronisation term specified by the
+			% given lval. (See the documentation in par_conj_gen.m
+			% and runtime/context.mod for further information about
+			% synchronisation terms.)
+
+	;	join_and_continue(lval, label)
+			% Signal that this thread of execution has finished
+			% in the current parallel conjunction, then branch to
+			% the given label. The synchronisation
+			% term specified by the given lval.
+	.
 
 	% pragma_c_decl holds the information needed for a variable
 	% declaration for a pragma_c instruction.
Index: compiler/llds_common.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/llds_common.m,v
retrieving revision 1.10
diff -u -r1.10 llds_common.m
--- llds_common.m	1997/08/25 17:48:23	1.10
+++ llds_common.m	1997/09/08 23:17:54
@@ -253,6 +253,18 @@
 		Instr0 = pragma_c(_, _, _, _, _),
 		Instr = Instr0,
 		Info = Info0
+	;
+		Instr0 = fork(_, _, _),
+		Instr = Instr0,
+		Info = Info0
+	;
+		Instr0 = join_and_terminate(_),
+		Instr = Instr0,
+		Info = Info0
+	;
+		Instr0 = join_and_continue(_, _),
+		Instr = Instr0,
+		Info = Info0
 	).
 
 :- pred llds_common__process_rval(rval, common_info, common_info, rval).
Index: compiler/llds_out.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/llds_out.m,v
retrieving revision 1.59
diff -u -r1.59 llds_out.m
--- llds_out.m	1997/10/12 13:32:34	1.59
+++ llds_out.m	1997/10/21 04:59:00
@@ -650,8 +650,8 @@
 		llds_out__find_caller_label(Instrs, CallerLabel)
 	).
 
-	% Locate all the labels which are the continutation labels for calls
-	% or nondet disjunctions, and store them in ContLabelSet.
+	% Locate all the labels which are the continuation labels for calls,
+	% nondet disjunctions, forks or joins, and store them in ContLabelSet.
 
 :- pred llds_out__find_cont_labels(list(instruction), set(label), set(label)).
 :- mode llds_out__find_cont_labels(in, in, out) is det.
@@ -667,12 +667,18 @@
 		;
 			Instr = modframe(label(ContLabel))
 		;
+			Instr = join_and_continue(_, ContLabel)
+		;
 			Instr = assign(redoip(lval(maxfr)), 
 				const(code_addr_const(label(ContLabel))))
 		)
 	->
 		set__insert(ContLabelSet0, ContLabel, ContLabelSet1)
 	;
+		Instr = fork(Label1, Label2, _)
+	->
+		set__insert_list(ContLabelSet0, [Label1, Label2], ContLabelSet1)
+	;
 		Instr = block(_, _, Block)
 	->
 		llds_out__find_cont_labels(Block, ContLabelSet0, ContLabelSet1)
@@ -800,6 +806,14 @@
 		DeclSet0, DeclSet) -->
 	output_pragma_input_rval_decls(Inputs, DeclSet0, DeclSet1),
 	output_pragma_output_lval_decls(Outputs, DeclSet1, DeclSet).
+output_instruction_decls(fork(Child, Parent, _), DeclSet0, DeclSet) -->
+	output_code_addr_decls(label(Child), "", "", 0, _, DeclSet0, DeclSet2),
+	output_code_addr_decls(label(Parent), "", "", 0, _, DeclSet2, DeclSet).
+output_instruction_decls(join_and_terminate(Lval), DeclSet0, DeclSet) -->
+	output_lval_decls(Lval, "", "", 0, _, DeclSet0, DeclSet).
+output_instruction_decls(join_and_continue(Lval, Label), DeclSet0, DeclSet) -->
+	output_lval_decls(Lval, "", "", 0, _, DeclSet0, DeclSet1),
+	output_code_addr_decls(label(Label), "", "", 0, _, DeclSet1, DeclSet).
 
 %-----------------------------------------------------------------------------%
 
@@ -1063,6 +1077,27 @@
 	output_reset_line_num,
 	output_pragma_outputs(Outputs),
 	io__write_string("\n\t}\n").
+
+output_instruction(fork(Child, Parent, Lval), _) -->
+	io__write_string("\tfork_new_context("),
+	output_label_as_code_addr(Child),
+	io__write_string(", "),
+	output_label_as_code_addr(Parent),
+	io__write_string(", "),
+	io__write_int(Lval),
+	io__write_string(");\n").
+
+output_instruction(join_and_terminate(Lval), _) -->
+	io__write_string("\tjoin_and_terminate("),
+	output_lval(Lval),
+	io__write_string(");\n").
+
+output_instruction(join_and_continue(Lval, Label), _) -->
+	io__write_string("\tjoin_and_continue("),
+	output_lval(Lval),
+	io__write_string(", "),
+	output_label_as_code_addr(Label),
+	io__write_string(");\n").
 
 :- pred output_set_line_num(term__context, io__state, io__state).
 :- mode output_set_line_num(in, di, uo) is det.
Index: compiler/make_hlds.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/make_hlds.m,v
retrieving revision 1.242
diff -u -r1.242 make_hlds.m
--- make_hlds.m	1997/10/09 09:38:48	1.242
+++ make_hlds.m	1997/10/17 04:20:26
@@ -2035,6 +2035,10 @@
 		PredCallId) -->
 	warn_singletons_in_goal_list(Goals, QuantVars, VarSet, PredCallId).
 
+warn_singletons_in_goal_2(par_conj(Goals, _SM), _GoalInfo, QuantVars, VarSet,
+		PredCallId) -->
+	warn_singletons_in_goal_list(Goals, QuantVars, VarSet, PredCallId).
+
 warn_singletons_in_goal_2(disj(Goals, _), _GoalInfo, QuantVars, VarSet,
 		PredCallId) -->
 	warn_singletons_in_goal_list(Goals, QuantVars, VarSet, PredCallId).
@@ -2580,6 +2584,12 @@
 	{ goal_info_init(GoalInfo) },
 	{ conj_list_to_goal(L, GoalInfo, Goal) }.
 
+transform_goal_2((A0 & B0), _, VarSet0, Subst, Goal, VarSet, Info0, Info) -->
+	get_par_conj(B0, Subst, [], VarSet0, L0, VarSet1, Info0, Info1),
+	get_par_conj(A0, Subst, L0, VarSet1, L, VarSet, Info1, Info),
+	{ goal_info_init(GoalInfo) },
+	{ par_conj_list_to_goal(L, GoalInfo, Goal) }.
+
 transform_goal_2((A0;B0), _, VarSet0, Subst, Goal, VarSet, Info0, Info) -->
 	get_disj(B0, Subst, [], VarSet0, L0, VarSet1, Info0, Info1),
 	get_disj(A0, Subst, L0, VarSet1, L, VarSet, Info1, Info),
@@ -3200,6 +3210,29 @@
 						Info0, Info),
 		{ goal_to_conj_list(Goal1, ConjList) },
 		{ list__append(ConjList, Conj0, Conj) }
+	).
+
+% get_par_conj(Goal, ParConj0, Subst, ParConj) :
+% 	Goal is a tree of conjuncts.  Flatten it into a list (applying Subst),
+%	append ParConj0, and return the result in ParConj.
+
+:- pred get_par_conj(goal, substitution, list(hlds_goal), varset,
+	list(hlds_goal), varset, qual_info, qual_info, io__state, io__state).
+:- mode get_par_conj(in, in, in, in, out, out, in, out, di, uo) is det.
+
+get_par_conj(Goal, Subst, ParConj0, VarSet0, ParConj, VarSet, Info0, Info) -->
+	(
+		{ Goal = (A & B) - _Context }
+	->
+		get_par_conj(B, Subst, ParConj0, VarSet0, ParConj1, VarSet1,
+						Info0, Info1),
+		get_par_conj(A, Subst, ParConj1, VarSet1, ParConj, VarSet,
+						Info1, Info)
+	;
+		transform_goal(Goal, VarSet0, Subst, Goal1, VarSet,
+						Info0, Info),
+		{ goal_to_par_conj_list(Goal1, ParConjList) },
+		{ list__append(ParConjList, ParConj0, ParConj) }
 	).
 
 % get_disj(Goal, Subst, Disj0, Disj) :
Index: compiler/mercury_to_c.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mercury_to_c.m,v
retrieving revision 1.27
diff -u -r1.27 mercury_to_c.m
--- mercury_to_c.m	1997/09/01 14:03:37	1.27
+++ mercury_to_c.m	1997/09/08 22:43:25
@@ -603,6 +603,9 @@
 c_gen_goal_2(conj(Goals), Indent, CGenInfo0, CGenInfo) -->
 	c_gen_conj(Goals, Indent, CGenInfo0, CGenInfo).
 
+c_gen_goal_2(par_conj(_Goals, _SM), _Indent, _CGenInfo0, _CGenInfo) -->
+	{ error("sorry, c_gen of parallel conjunction not implemented") }.
+
 c_gen_goal_2(disj(List, _), Indent, CGenInfo0, CGenInfo) -->
 	{ c_gen_info_get_code_model(CGenInfo0, CodeModel) },
 	( { CodeModel = model_non } ->
Index: compiler/mercury_to_goedel.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mercury_to_goedel.m,v
retrieving revision 1.60
diff -u -r1.60 mercury_to_goedel.m
--- mercury_to_goedel.m	1997/08/22 13:55:25	1.60
+++ mercury_to_goedel.m	1997/09/08 22:43:25
@@ -596,6 +596,14 @@
 	goedel_output_newline(Indent),
 	goedel_output_goal(B, VarSet, Indent).
 
+	% Goedel doesn't have parallel conjunction,
+	% but we can use sequential conjunction instead.
+goedel_output_goal_2((A & B), VarSet, Indent) -->
+	goedel_output_goal(A, VarSet, Indent),
+	io__write_string(" &"),
+	goedel_output_newline(Indent),
+	goedel_output_goal(B, VarSet, Indent).
+
 goedel_output_goal_2((A;B), VarSet, Indent) -->
 	io__write_string("("),
 	{ Indent1 is Indent + 1 },
Index: compiler/mercury_to_mercury.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mercury_to_mercury.m,v
retrieving revision 1.119
diff -u -r1.119 mercury_to_mercury.m
--- mercury_to_mercury.m	1997/10/09 09:38:54	1.119
+++ mercury_to_mercury.m	1997/10/17 04:20:28
@@ -1434,6 +1434,16 @@
 	mercury_output_newline(Indent),
 	mercury_output_goal(B, VarSet, Indent).
 
+mercury_output_goal_2((A & B), VarSet, Indent) -->
+	io__write_string("("),
+	{ Indent1 is Indent + 1 },
+	mercury_output_newline(Indent1),
+	mercury_output_goal(A, VarSet, Indent1),
+	mercury_output_par_conj(B, VarSet, Indent),
+	mercury_output_newline(Indent),
+	io__write_string(")").
+
+
 mercury_output_goal_2((A;B), VarSet, Indent) -->
 	io__write_string("("),
 	{ Indent1 is Indent + 1 },
@@ -1480,6 +1490,23 @@
 	->
 		mercury_output_goal(A, VarSet, Indent1),
 		mercury_output_disj(B, VarSet, Indent)
+	;
+		mercury_output_goal(Goal, VarSet, Indent1)
+	).
+
+:- pred mercury_output_par_conj(goal, varset, int, io__state, io__state).
+:- mode mercury_output_par_conj(in, in, in, di, uo) is det.
+
+mercury_output_par_conj(Goal, VarSet, Indent) -->
+	mercury_output_newline(Indent),
+	io__write_string("&"),
+	{ Indent1 is Indent + 1 },
+	mercury_output_newline(Indent1),
+	(
+		{ Goal = (A & B) - _Context }
+	->
+		mercury_output_goal(A, VarSet, Indent1),
+		mercury_output_par_conj(B, VarSet, Indent)
 	;
 		mercury_output_goal(Goal, VarSet, Indent1)
 	).
Index: compiler/middle_rec.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/middle_rec.m,v
retrieving revision 1.66
diff -u -r1.66 middle_rec.m
--- middle_rec.m	1997/08/25 17:48:28	1.66
+++ middle_rec.m	1997/09/08 22:43:25
@@ -418,6 +418,11 @@
 		Used0, Used) :-
 	insert_pragma_c_input_registers(Ins, Used0, Used1),
 	insert_pragma_c_output_registers(Outs, Used1, Used).
+middle_rec__find_used_registers_instr(fork(_, _, _), Used, Used).
+middle_rec__find_used_registers_instr(join_and_terminate(Lval), Used0, Used) :-
+	middle_rec__find_used_registers_lval(Lval, Used0, Used).
+middle_rec__find_used_registers_instr(join_and_continue(Lval,_), Used0, Used) :-
+	middle_rec__find_used_registers_lval(Lval, Used0, Used).
 
 :- pred middle_rec__find_used_registers_lvals(list(lval), set(int), set(int)).
 :- mode middle_rec__find_used_registers_lvals(in, di, uo) is det.
Index: compiler/mode_errors.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mode_errors.m,v
retrieving revision 1.47
diff -u -r1.47 mode_errors.m
--- mode_errors.m	1997/07/27 15:01:04	1.47
+++ mode_errors.m	1997/10/23 00:59:55
@@ -39,6 +39,9 @@
 	--->	mode_error_disj(merge_context, merge_errors)
 			% different arms of a disjunction result in
 			% different insts for some non-local variables
+	;	mode_error_par_conj(merge_errors)
+			% different arms of a parallel conj result in
+			% mutually exclusive bindings
 	;	mode_error_higher_order_pred_var(pred_or_func, var, inst, arity)
 			% the predicate variable in a higher-order predicate
 			% or function call didn't have a higher-order
@@ -65,9 +68,10 @@
 	;	mode_error_no_matching_mode(list(var), list(inst))
 			% call to a predicate with an insufficiently
 			% instantiated variable (for preds with >1 mode)
-	;	mode_error_bind_var(var, inst, inst)
+	;	mode_error_bind_var(var, inst, inst, lock_context)
 			% attempt to bind a non-local variable inside
-			% a negated context
+			% a negated context, or attempt to re-bind a variable
+			% in a parallel conjunct
 	;	mode_error_unify_var_var(var, var, inst, inst)
 			% attempt to unify two free variables
 	;	mode_error_unify_var_functor(var, cons_id, list(var),
@@ -83,9 +87,13 @@
 	;	mode_error_final_inst(int, var, inst, inst, final_inst_error)
 			% one of the head variables did not have the
 			% expected final inst on exit from the proc
-	;	mode_error_undefined_mode_in_lambda.
+	;	mode_error_undefined_mode_in_lambda
 			% This is a dummy error - the actual message
 			% is output by module_qual.m.
+	;	mode_error_parallel_var(var, inst, inst)
+			% attempt to bind a non-local variable that has already
+			% been bound in another parallel conjunct.
+	.
 
 :- type final_inst_error
 	--->	too_instantiated
@@ -156,6 +164,8 @@
 
 report_mode_error(mode_error_disj(MergeContext, ErrorList), ModeInfo) -->
 	report_mode_error_disj(ModeInfo, MergeContext, ErrorList).
+report_mode_error(mode_error_par_conj(ErrorList), ModeInfo) -->
+	report_mode_error_par_conj(ModeInfo, ErrorList).
 report_mode_error(mode_error_higher_order_pred_var(PredOrFunc, Var, Inst,
 		Arity), ModeInfo) -->
 	report_mode_error_higher_order_pred_var(ModeInfo, PredOrFunc, Var,
@@ -171,8 +181,8 @@
 	report_mode_error_implied_mode(ModeInfo, Var, InstA, InstB).
 report_mode_error(mode_error_no_mode_decl, ModeInfo) -->
 	report_mode_error_no_mode_decl(ModeInfo).
-report_mode_error(mode_error_bind_var(Var, InstA, InstB), ModeInfo) -->
-	report_mode_error_bind_var(ModeInfo, Var, InstA, InstB).
+report_mode_error(mode_error_bind_var(Var, InstA, InstB, Ctxt), ModeInfo) -->
+	report_mode_error_bind_var(ModeInfo, Var, InstA, InstB, Ctxt).
 report_mode_error(mode_error_unify_var_var(VarA, VarB, InstA, InstB),
 		ModeInfo) -->
 	report_mode_error_unify_var_var(ModeInfo, VarA, VarB, InstA, InstB).
@@ -192,6 +202,8 @@
 	report_mode_error_final_inst(ModeInfo, ArgNum, Var, VarInst, Inst,
 		Reason).
 report_mode_error(mode_error_undefined_mode_in_lambda, _ModeInfo) --> [].
+report_mode_error(mode_error_parallel_var(Var, InstA, InstB), ModeInfo) -->
+	report_mode_error_parallel_var(ModeInfo, Var, InstA, InstB).
 
 %-----------------------------------------------------------------------------%
 
@@ -299,6 +311,17 @@
 	io__write_string(".\n"),
 	write_merge_error_list(ErrorList, ModeInfo).
 
+:- pred report_mode_error_par_conj(mode_info, merge_errors,
+				io__state, io__state).
+:- mode report_mode_error_par_conj(mode_info_no_io, in, di, uo) is det.
+
+report_mode_error_par_conj(ModeInfo, ErrorList) -->
+	{ mode_info_get_context(ModeInfo, Context) },
+	mode_info_write_context(ModeInfo),
+	prog_out__write_context(Context),
+	io__write_string("  mode error: mutually exclusive bindings in parallel conjunction.\n"),
+	write_merge_error_list(ErrorList, ModeInfo).
+
 :- pred write_merge_error_list(merge_errors, mode_info, io__state, io__state).
 :- mode write_merge_error_list(in, mode_info_no_io, di, uo) is det.
 
@@ -326,17 +349,42 @@
 %-----------------------------------------------------------------------------%
 
 :- pred report_mode_error_bind_var(mode_info, var, inst, inst,
-					io__state, io__state).
-:- mode report_mode_error_bind_var(mode_info_ui, in, in, in, di, uo) is det.
+		lock_context, io__state, io__state).
+:- mode report_mode_error_bind_var(mode_info_ui, in, in, in, in, di, uo) is det.
 
-report_mode_error_bind_var(ModeInfo, Var, VarInst, Inst) -->
+report_mode_error_bind_var(ModeInfo, Var, VarInst, Inst, LockContext) -->
 	{ mode_info_get_context(ModeInfo, Context) },
 	{ mode_info_get_varset(ModeInfo, VarSet) },
 	{ mode_info_get_instvarset(ModeInfo, InstVarSet) },
 	mode_info_write_context(ModeInfo),
-	prog_out__write_context(Context),
-	io__write_string(
-		"  scope error: attempt to bind variable inside a negation.\n"),
+	(
+		{ LockContext = negation },
+		prog_out__write_context(Context),
+		io__write_string(
+		"  scope error: attempt to bind variable inside a negation.\n")
+	;
+		{ LockContext = if_then_else },
+		prog_out__write_context(Context),
+		io__write_string(
+		"  scope error: attempt to bind nonlocal variable inside \n"),
+		prog_out__write_context(Context),
+		io__write_string(
+		"  the condition of an if-then-else.\n")
+	;
+		{ LockContext = par_conj },
+		prog_out__write_context(Context),
+		io__write_string(
+		"  mode error: attempt to bind variable inside more than one\n"),
+		prog_out__write_context(Context),
+		io__write_string("  parallel conjunct.\n")
+	;
+		{ LockContext = lambda_goal },
+		prog_out__write_context(Context),
+		io__write_string(
+		"  scope error: attempt to bind a nonlocal variable inside\n"),
+		prog_out__write_context(Context),
+		io__write_string("  a pred/lambda goal.\n")
+	),
 	prog_out__write_context(Context),
 	io__write_string("  Variable `"),
 	mercury_output_var(Var, VarSet, no),
@@ -348,7 +396,9 @@
 	output_inst(Inst, InstVarSet),
 	io__write_string("'.\n"),
 	globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
-	( { VerboseErrors = yes } ->
+	(
+		{ VerboseErrors = yes }
+	->
 		io__write_string("\tA negation is only allowed to bind variables which are local to the\n"),
 		io__write_string("\tnegation, i.e. those which are implicitly existentially quantified\n"),
 		io__write_string("\tinside the scope of the negation.\n"),
@@ -718,6 +768,24 @@
 
 
 %-----------------------------------------------------------------------------%
+
+:- pred report_mode_error_parallel_var(mode_info, var, inst, inst,
+		io__state, io__state).
+:- mode report_mode_error_parallel_var(mode_info_ui, in, in, in, di, uo) is det.
+
+report_mode_error_parallel_var(ModeInfo, Var, _VarInst, _Inst) -->
+	{ mode_info_get_context(ModeInfo, Context) },
+	{ mode_info_get_varset(ModeInfo, VarSet) },
+	mode_info_write_context(ModeInfo),
+	prog_out__write_context(Context),
+	io__write_string("  mode error: attempt to bind a variable already bound\n"),
+	prog_out__write_context(Context),
+	io__write_string("  in anonther parallel conjunct.\n"),
+	prog_out__write_context(Context),
+	io__write_string("  The variable concerned was `"),
+	mercury_output_var(Var, VarSet, no),
+	io__write_string("'.\n").
+
 %-----------------------------------------------------------------------------%
 
 mode_context_init(uninitialized).
Index: compiler/mode_info.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mode_info.m,v
retrieving revision 1.40
diff -u -r1.40 mode_info.m
--- mode_info.m	1997/10/14 09:18:44	1.40
+++ mode_info.m	1997/10/23 00:13:00
@@ -119,10 +119,12 @@
 :- pred mode_info_set_instmap(instmap, mode_info, mode_info).
 :- mode mode_info_set_instmap(in, mode_info_di, mode_info_uo) is det.
 
-:- pred mode_info_get_locked_vars(mode_info, list(set(var))).
+:- type locked_vars	==	pair(set(var), lock_context).
+
+:- pred mode_info_get_locked_vars(mode_info, list(locked_vars)).
 :- mode mode_info_get_locked_vars(mode_info_ui, out) is det.
 
-:- pred mode_info_set_locked_vars(mode_info, list(set(var)), mode_info).
+:- pred mode_info_set_locked_vars(mode_info, list(locked_vars), mode_info).
 :- mode mode_info_set_locked_vars(mode_info_di, in, mode_info_uo) is det.
 
 :- pred mode_info_get_errors(mode_info, list(mode_error_info)).
@@ -173,17 +175,24 @@
 :- pred mode_info_get_types_of_vars(mode_info, list(var), list(type)).
 :- mode mode_info_get_types_of_vars(mode_info_ui, in, out) is det.
 
-:- pred mode_info_lock_vars(set(var), mode_info, mode_info).
-:- mode mode_info_lock_vars(in, mode_info_di, mode_info_uo) is det.
+:- type lock_context
+		--->	negation
+		;	if_then_else
+		;	par_conj
+		;	lambda_goal
+		.
+
+:- pred mode_info_lock_vars(set(var), lock_context, mode_info, mode_info).
+:- mode mode_info_lock_vars(in, in, mode_info_di, mode_info_uo) is det.
 
 :- pred mode_info_unlock_vars(set(var), mode_info, mode_info).
 :- mode mode_info_unlock_vars(in, mode_info_di, mode_info_uo) is det.
 
-:- pred mode_info_var_is_locked(mode_info, var).
-:- mode mode_info_var_is_locked(mode_info_ui, in) is semidet.
+:- pred mode_info_var_is_locked(mode_info, var, lock_context).
+:- mode mode_info_var_is_locked(mode_info_ui, in, out) is semidet.
 
-:- pred mode_info_var_is_locked_2(list(set(var)), var).
-:- mode mode_info_var_is_locked_2(in, in) is semidet.
+:- pred mode_info_var_is_locked_2(list(locked_vars), var, lock_context).
+:- mode mode_info_var_is_locked_2(in, in, out) is semidet.
 
 :- pred mode_info_get_delay_info(mode_info, delay_info).
 :- mode mode_info_get_delay_info(mode_info_no_io, out) is det.
@@ -205,6 +214,14 @@
 :- mode mode_info_set_last_checkpoint_insts(in, mode_info_di, mode_info_uo)
 	is det.
 
+:- pred mode_info_get_parallel_vars(list(pair(set(var))), mode_info,
+		mode_info).
+:- mode mode_info_get_parallel_vars(out, mode_info_di, mode_info_uo) is det.
+
+:- pred mode_info_set_parallel_vars(list(pair(set(var))), mode_info,
+		mode_info).
+:- mode mode_info_set_parallel_vars(in, mode_info_di, mode_info_uo) is det.
+
 :- pred mode_info_get_changed_flag(mode_info, bool).
 :- mode mode_info_get_changed_flag(mode_info_no_io, out) is det.
 
@@ -218,7 +235,7 @@
 						ground, ground, ground,
 						ground, ground, ground, ground,
 						ground, ground, ground, ground,
-						ground, ground, ground
+						ground, ground, ground, ground
 					)
 				).
 */
@@ -237,7 +254,7 @@
 						dead, ground, ground, ground,
 						ground, ground, ground, ground,
 						ground, ground, ground, ground,
-						ground, ground, ground
+						ground, ground, ground, ground
 					)
 				).
 */
@@ -279,7 +296,7 @@
 					% goal the error occurred
 			instmap,	% The current instantiatedness
 					% of the variables
-			list(set(var)),	% The "locked" variables,
+			list(locked_vars),	% The "locked" variables,
 					% i.e. variables which cannot be
 					% further instantiated inside a
 					% negated context
@@ -312,6 +329,14 @@
 	% This field will always contain an empty list if debug_modes is off,
 	% since its information is not needed then.
 
+			list(pair(set(var), set(var))),
+	% A stack of pairs of sets of variables used to mode-check
+	% parallel conjunctions. The first set is the nonlocals of
+	% the parallel conjunction. The second set is a subset of the
+	% first, and is the set of variables that have been [further]
+	% bound inside the current parallel conjunct - the stack is for
+	% the correct handling of nested parallel conjunctions.
+
 			bool		% Changed flag
 					% If `yes', then we may need
 					% to repeat mode inference.
@@ -347,7 +372,7 @@
 	ModeInfo = mode_info(
 		IOState, ModuleInfo, PredId, ProcId, VarSet, VarTypes,
 		Context, ModeContext, InstMapping0, LockedVars, DelayInfo,
-		ErrorList, LiveVarsList, NondetLiveVarsList, [],
+		ErrorList, LiveVarsList, NondetLiveVarsList, [], [],
 		Changed
 	).
 
@@ -355,89 +380,95 @@
 
 	% Lots of very boring access predicates.
 
-mode_info_get_io_state(mode_info(IOState0,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
+mode_info_get_io_state(mode_info(IOState0,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
 		IOState) :-
 	% XXX
 	unsafe_promise_unique(IOState0, IOState).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_io_state( mode_info(_,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P), IOState0,
-			mode_info(IOState,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P)) :-
+mode_info_set_io_state( mode_info(_,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q), IOState0,
+			mode_info(IOState,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q)) :-
 	% XXX
 	unsafe_promise_unique(IOState0, IOState).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_module_info(mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
+mode_info_get_module_info(mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
 				ModuleInfo).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_module_info(mode_info(A,_,C,D,E,F,G,H,I,J,K,L,M,N,O,P), ModuleInfo,
-			mode_info(A,ModuleInfo,C,D,E,F,G,H,I,J,K,L,M,N,O,P)).
+mode_info_set_module_info(mode_info(A,_,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q),
+			ModuleInfo,
+			mode_info(A,ModuleInfo,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q)).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_preds(mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_), Preds) :-
+mode_info_get_preds(mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
+		Preds) :-
 	module_info_preds(ModuleInfo, Preds).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_modes(mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_), Modes) :-
+mode_info_get_modes(mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
+		Modes) :-
 	module_info_modes(ModuleInfo, Modes).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_insts(mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_), Insts) :-
+mode_info_get_insts(mode_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_),
+		Insts) :-
 	module_info_insts(ModuleInfo, Insts).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_predid(mode_info(_,_,PredId,_,_,_,_,_,_,_,_,_,_,_,_,_), PredId).
+mode_info_get_predid(mode_info(_,_,PredId,_,_,_,_,_,_,_,_,_,_,_,_,_,_), PredId).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_procid(mode_info(_,_,_,ProcId,_,_,_,_,_,_,_,_,_,_,_,_), ProcId).
+mode_info_get_procid(mode_info(_,_,_,ProcId,_,_,_,_,_,_,_,_,_,_,_,_,_), ProcId).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_varset(mode_info(_,_,_,_,VarSet,_,_,_,_,_,_,_,_,_,_,_), VarSet).
+mode_info_get_varset(mode_info(_,_,_,_,VarSet,_,_,_,_,_,_,_,_,_,_,_,_), VarSet).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_varset(VarSet, mode_info(A,B,C,D,_,F,G,H,I,J,K,L,M,N,O,P),
-				mode_info(A,B,C,D,VarSet,F,G,H,I,J,K,L,M,N,O,P)).
+mode_info_set_varset(VarSet, mode_info(A,B,C,D,_,F,G,H,I,J,K,L,M,N,O,P,Q),
+			mode_info(A,B,C,D,VarSet,F,G,H,I,J,K,L,M,N,O,P,Q)).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_var_types(mode_info(_,_,_,_,_,VarTypes,_,_,_,_,_,_,_,_,_,_),
+mode_info_get_var_types(mode_info(_,_,_,_,_,VarTypes,_,_,_,_,_,_,_,_,_,_,_),
 				VarTypes).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_var_types(VarTypes, mode_info(A,B,C,D,E,_,G,H,I,J,K,L,M,N,O,P),
-			mode_info(A,B,C,D,E,VarTypes,G,H,I,J,K,L,M,N,O,P)).
+mode_info_set_var_types(VarTypes, mode_info(A,B,C,D,E,_,G,H,I,J,K,L,M,N,O,P,Q),
+			mode_info(A,B,C,D,E,VarTypes,G,H,I,J,K,L,M,N,O,P,Q)).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_context(mode_info(_,_,_,_,_,_,Context,_,_,_,_,_,_,_,_,_), Context).
+mode_info_get_context(mode_info(_,_,_,_,_,_,Context,_,_,_,_,_,_,_,_,_,_),
+		Context).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_context(Context, mode_info(A,B,C,D,E,F,_,H,I,J,K,L,M,N,O,P),
-			mode_info(A,B,C,D,E,F,Context,H,I,J,K,L,M,N,O,P)).
+mode_info_set_context(Context, mode_info(A,B,C,D,E,F,_,H,I,J,K,L,M,N,O,P,Q),
+			mode_info(A,B,C,D,E,F,Context,H,I,J,K,L,M,N,O,P,Q)).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_mode_context(mode_info(_,_,_,_,_,_,_,ModeContext,_,_,_,_,_,_,_,_),
-				ModeContext).
+mode_info_get_mode_context(
+		mode_info(_,_,_,_,_,_,_,ModeContext,_,_,_,_,_,_,_,_,_),
+		ModeContext).
 
 %-----------------------------------------------------------------------------%
 
 mode_info_set_mode_context(ModeContext,
-		mode_info(A,B,C,D,E,F,G,_,I,J,K,L,M,N,O,P),
-		mode_info(A,B,C,D,E,F,G,ModeContext,I,J,K,L,M,N,O,P)).
+		mode_info(A,B,C,D,E,F,G,_,I,J,K,L,M,N,O,P,Q),
+		mode_info(A,B,C,D,E,F,G,ModeContext,I,J,K,L,M,N,O,P,Q)).
 
 %-----------------------------------------------------------------------------%
 
@@ -466,7 +497,8 @@
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_instmap(mode_info(_,_,_,_,_,_,_,_,InstMap,_,_,_,_,_,_,_), InstMap).
+mode_info_get_instmap(mode_info(_,_,_,_,_,_,_,_,InstMap,_,_,_,_,_,_,_,_),
+		InstMap).
 
 	% mode_info_dcg_get_instmap/3 is the same as mode_info_get_instmap/2
 	% except that it's easier to use inside a DCG.
@@ -477,8 +509,8 @@
 %-----------------------------------------------------------------------------%
 
 mode_info_set_instmap( InstMap,
-		mode_info(A,B,C,D,E,F,G,H,InstMap0,J,DelayInfo0,L,M,N,O,P),
-		mode_info(A,B,C,D,E,F,G,H,InstMap,J,DelayInfo,L,M,N,O,P)) :-
+		mode_info(A,B,C,D,E,F,G,H,InstMap0,J,DelayInfo0,L,M,N,O,P,Q),
+		mode_info(A,B,C,D,E,F,G,H,InstMap,J,DelayInfo,L,M,N,O,P,Q)) :-
 	( instmap__is_unreachable(InstMap), instmap__is_reachable(InstMap0) ->
 		delay_info__bind_all_vars(DelayInfo0, DelayInfo)
 	;
@@ -487,28 +519,29 @@
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_locked_vars(mode_info(_,_,_,_,_,_,_,_,_,LockedVars,_,_,_,_,_,_),
+mode_info_get_locked_vars(mode_info(_,_,_,_,_,_,_,_,_,LockedVars,_,_,_,_,_,_,_),
 		LockedVars).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_locked_vars( mode_info(A,B,C,D,E,F,G,H,I,_,K,L,M,N,O,P), LockedVars,
-			mode_info(A,B,C,D,E,F,G,H,I,LockedVars,K,L,M,N,O,P)).
+mode_info_set_locked_vars( mode_info(A,B,C,D,E,F,G,H,I,_,K,L,M,N,O,P,Q),
+		LockedVars,
+		mode_info(A,B,C,D,E,F,G,H,I,LockedVars,K,L,M,N,O,P,Q)).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_errors(mode_info(_,_,_,_,_,_,_,_,_,_,_,Errors,_,_,_,_), Errors).
+mode_info_get_errors(mode_info(_,_,_,_,_,_,_,_,_,_,_,Errors,_,_,_,_,_), Errors).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_get_num_errors(mode_info(_,_,_,_,_,_,_,_,_,_,_,Errors,_,_,_,_),
+mode_info_get_num_errors(mode_info(_,_,_,_,_,_,_,_,_,_,_,Errors,_,_,_,_,_),
 		NumErrors) :-
 	list__length(Errors, NumErrors).
 
 %-----------------------------------------------------------------------------%
 
-mode_info_set_errors( Errors, mode_info(A,B,C,D,E,F,G,H,I,J,K,_,M,N,O,P), 
-			mode_info(A,B,C,D,E,F,G,H,I,J,K,Errors,M,N,O,P)).
+mode_info_set_errors( Errors, mode_info(A,B,C,D,E,F,G,H,I,J,K,_,M,N,O,P,Q),
+			mode_info(A,B,C,D,E,F,G,H,I,J,K,Errors,M,N,O,P,Q)).
 
 %-----------------------------------------------------------------------------%
 
@@ -522,9 +555,9 @@
 
 mode_info_add_live_vars(NewLiveVars,
 		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,
-			LiveVars0,NondetLiveVars0,O,P),
+			LiveVars0,NondetLiveVars0,O,P,Q),
 		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,
-			LiveVars,NondetLiveVars,O,P)) :-
+			LiveVars,NondetLiveVars,O,P,Q)) :-
 
 	LiveVars = [NewLiveVars | LiveVars0],
 	NondetLiveVars = [NewLiveVars | NondetLiveVars0].
@@ -534,9 +567,9 @@
 
 mode_info_remove_live_vars(OldLiveVars, ModeInfo0, ModeInfo) :-
 	ModeInfo0 = mode_info(A,B,C,D,E,F,G,H,I,J,K,L,
-				LiveVars0, NondetLiveVars0,O,P),
+				LiveVars0, NondetLiveVars0,O,P,Q),
 	ModeInfo1 = mode_info(A,B,C,D,E,F,G,H,I,J,K,L,
-				LiveVars, NondetLiveVars,O,P),
+				LiveVars, NondetLiveVars,O,P,Q),
 	(
 		list__delete_first(LiveVars0, OldLiveVars, LiveVars1),
 		list__delete_first(NondetLiveVars0, OldLiveVars,
@@ -563,8 +596,8 @@
 
 	% Check whether a variable is live or not
 
-mode_info_var_is_live(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,LiveVarsList,_,_,_), Var,
-		Result) :-
+mode_info_var_is_live(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,LiveVarsList,_,_,_,_),
+		Var, Result) :-
 	(
 		% some [LiveVars] 
 		list__member(LiveVars, LiveVarsList),
@@ -578,7 +611,7 @@
 	% Check whether a variable is nondet_live or not.
 
 mode_info_var_is_nondet_live(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,
-		NondetLiveVarsList,_,_), Var, Result) :-
+		NondetLiveVarsList,_,_,_), Var, Result) :-
 	(
 		% some [LiveVars] 
 		list__member(LiveVars, NondetLiveVarsList),
@@ -589,7 +622,7 @@
 		Result = dead
 	).
 
-mode_info_get_liveness(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,LiveVarsList,_,_,_),
+mode_info_get_liveness(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,LiveVarsList,_,_,_,_),
 		LiveVars) :-
 	set__init(LiveVars0),
 	mode_info_get_liveness_2(LiveVarsList, LiveVars0, LiveVars).
@@ -620,9 +653,9 @@
 	% push them on the stack, and to unlock a set of vars, we just
 	% pop them off the stack.  The stack is implemented as a list.
 
-mode_info_lock_vars(Vars, ModeInfo0, ModeInfo) :-
+mode_info_lock_vars(Vars, Context, ModeInfo0, ModeInfo) :-
 	mode_info_get_locked_vars(ModeInfo0, LockedVars),
-	mode_info_set_locked_vars(ModeInfo0, [Vars | LockedVars], ModeInfo).
+	mode_info_set_locked_vars(ModeInfo0, [Vars - Context | LockedVars], ModeInfo).
 
 mode_info_unlock_vars(_, ModeInfo0, ModeInfo) :-
 	mode_info_get_locked_vars(ModeInfo0, LockedVars0),
@@ -633,46 +666,54 @@
 	),
 	mode_info_set_locked_vars(ModeInfo0, LockedVars, ModeInfo).
 
-mode_info_var_is_locked(ModeInfo, Var) :-
+mode_info_var_is_locked(ModeInfo, Var, Context) :-
 	mode_info_get_locked_vars(ModeInfo, LockedVarsList),
-	mode_info_var_is_locked_2(LockedVarsList, Var).
+	mode_info_var_is_locked_2(LockedVarsList, Var, Context).
 
-mode_info_var_is_locked_2([Set | Sets], Var) :-
+mode_info_var_is_locked_2([Set - Context0| Sets], Var, Context) :-
 	(
 		set__member(Var, Set)
 	->
-		true
+		Context = Context0
 	;
-		mode_info_var_is_locked_2(Sets, Var)
+		mode_info_var_is_locked_2(Sets, Var, Context)
 	).
 
-mode_info_get_delay_info(mode_info(_,_,_,_,_,_,_,_,_,_,DelayInfo,_,_,_,_,_),
+mode_info_get_delay_info(mode_info(_,_,_,_,_,_,_,_,_,_,DelayInfo,_,_,_,_,_,_),
 	DelayInfo).
 
-mode_info_set_delay_info(DelayInfo, mode_info(A,B,C,D,E,F,G,H,I,J,_,L,M,N,O,P),
-			mode_info(A,B,C,D,E,F,G,H,I,J,DelayInfo,L,M,N,O,P)).
+mode_info_set_delay_info(DelayInfo,
+		mode_info(A,B,C,D,E,F,G,H,I,J,_,L,M,N,O,P,Q),
+		mode_info(A,B,C,D,E,F,G,H,I,J,DelayInfo,L,M,N,O,P,Q)).
 
 mode_info_get_nondet_live_vars(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,
-			NondetLiveVars,_,_), NondetLiveVars).
+			NondetLiveVars,_,_,_), NondetLiveVars).
 
 mode_info_set_nondet_live_vars(NondetLiveVars,
-		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,_,O,P),
-		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,NondetLiveVars,O,P)).
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,_,O,P,Q),
+		mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,NondetLiveVars,O,P,Q)).
 
 mode_info_get_last_checkpoint_insts(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,_,
-		LastCheckpointInsts,_), LastCheckpointInsts).
+		LastCheckpointInsts,_,_), LastCheckpointInsts).
 
 mode_info_set_last_checkpoint_insts(LastCheckpointInsts,
-			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,_,P),
+			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,_,P,Q),
 			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,
-				LastCheckpointInsts,P)).
+				LastCheckpointInsts,P,Q)).
+
+mode_info_get_parallel_vars(PVars, ModeInfo, ModeInfo) :-
+	ModeInfo = mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,PVars,_).
+
+mode_info_set_parallel_vars(PVars,
+			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,_,Q),
+			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,PVars,Q)).
 
-mode_info_get_changed_flag(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,Changed),
+mode_info_get_changed_flag(mode_info(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,Changed),
 				Changed).
 
 mode_info_set_changed_flag(Changed,
-			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,_),
-			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,Changed)).
+			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,_),
+			mode_info(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Changed)).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/mode_util.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mode_util.m,v
retrieving revision 1.101
diff -u -r1.101 mode_util.m
--- mode_util.m	1997/09/29 06:45:48	1.101
+++ mode_util.m	1997/10/02 00:26:20
@@ -1092,6 +1092,12 @@
 	recompute_instmap_delta_conj(Atomic, Goals0, Goals,
 		InstMap, InstMapDelta).
 
+recompute_instmap_delta_2(Atomic, par_conj(Goals0, SM), GoalInfo,
+		par_conj(Goals, SM), InstMap, InstMapDelta) -->
+	{ goal_info_get_nonlocals(GoalInfo, NonLocals) },
+	recompute_instmap_delta_par_conj(Atomic, Goals0, Goals,
+		InstMap, NonLocals, InstMapDelta).
+
 recompute_instmap_delta_2(Atomic, disj(Goals0, SM), GoalInfo, disj(Goals, SM),
 		InstMap, InstMapDelta) -->
 	{ goal_info_get_nonlocals(GoalInfo, NonLocals) },
@@ -1179,6 +1185,27 @@
 	recompute_instmap_delta_disj(Atomic, Goals0, Goals,
 		InstMap, NonLocals, InstMapDelta1),
 	merge_instmap_delta(InstMap, NonLocals, InstMapDelta0,
+		InstMapDelta1, InstMapDelta).
+
+:- pred recompute_instmap_delta_par_conj(bool, list(hlds_goal),
+		list(hlds_goal), instmap, set(var), instmap_delta,
+		module_info, module_info).
+:- mode recompute_instmap_delta_par_conj(in, in, out, in, in, out,
+		in, out) is det.
+
+recompute_instmap_delta_par_conj(_, [], [], _, _, InstMapDelta) -->
+	{ instmap_delta_init_unreachable(InstMapDelta) }.
+recompute_instmap_delta_par_conj(Atomic, [Goal0], [Goal],
+		InstMap, _, InstMapDelta) -->
+	recompute_instmap_delta(Atomic, Goal0, Goal, InstMap, InstMapDelta).
+recompute_instmap_delta_par_conj(Atomic, [Goal0 | Goals0], [Goal | Goals],
+		InstMap, NonLocals, InstMapDelta) -->
+	{ Goals0 = [_|_] },
+	recompute_instmap_delta(Atomic, Goal0, Goal,
+		InstMap, InstMapDelta0),
+	recompute_instmap_delta_par_conj(Atomic, Goals0, Goals,
+		InstMap, NonLocals, InstMapDelta1),
+	unify_instmap_delta(InstMap, NonLocals, InstMapDelta0,
 		InstMapDelta1, InstMapDelta).
 
 %-----------------------------------------------------------------------------%
Index: compiler/modecheck_unify.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/modecheck_unify.m,v
retrieving revision 1.24
diff -u -r1.24 modecheck_unify.m
--- modecheck_unify.m	1997/10/13 10:24:18	1.24
+++ modecheck_unify.m	1997/10/21 05:28:13
@@ -381,10 +381,11 @@
 	% lock the non-locals
 	% (a lambda goal is not allowed to bind any of the non-local
 	% variables, since it could get called more than once)
+	% `negation' as the locked_var_context is a place holder.
 	Goal0 = _ - GoalInfo0,
 	goal_info_get_nonlocals(GoalInfo0, NonLocals0),
 	set__delete_list(NonLocals0, Vars, NonLocals),
-	mode_info_lock_vars(NonLocals, ModeInfo2, ModeInfo3),
+	mode_info_lock_vars(NonLocals, lambda_goal, ModeInfo2, ModeInfo3),
  
 	mode_checkpoint(enter, "lambda goal", ModeInfo3, ModeInfo4),
 	% if we're being called from unique_modes.m, then we need to 
Index: compiler/modes.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/modes.m,v
retrieving revision 1.205
diff -u -r1.205 modes.m
--- modes.m	1997/09/15 21:12:24	1.205
+++ modes.m	1997/10/23 00:52:28
@@ -711,6 +711,33 @@
 	),
 	mode_checkpoint(exit, "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.
+modecheck_goal_expr(par_conj(List0, SM), GoalInfo0, par_conj(List, SM)) -->
+	mode_checkpoint(enter, "par_conj"),
+	{ goal_info_get_nonlocals(GoalInfo0, NonLocals) },
+	modecheck_par_conj_list(List0, List, NonLocals, InstMapNonlocalList),
+	instmap__unify(NonLocals, InstMapNonlocalList),
+	mode_checkpoint(exit, "par_conj").
+
 modecheck_goal_expr(disj(List0, SM), GoalInfo0, disj(List, SM)) -->
 	mode_checkpoint(enter, "disj"),
 	( { List0 = [] } ->	% for efficiency, optimize common case
@@ -729,7 +756,7 @@
 	{ goal_info_get_nonlocals(GoalInfo0, NonLocals) },
 	{ goal_get_nonlocals(B0, B_Vars) },
 	mode_info_dcg_get_instmap(InstMap0),
-	mode_info_lock_vars(NonLocals),
+	mode_info_lock_vars(NonLocals, if_then_else),
 	mode_info_add_live_vars(B_Vars),
 	modecheck_goal(A0, A),
 	mode_info_remove_live_vars(B_Vars),
@@ -748,7 +775,7 @@
 	mode_checkpoint(enter, "not"),
 	{ goal_info_get_nonlocals(GoalInfo0, NonLocals) },
 	mode_info_dcg_get_instmap(InstMap0),
-	mode_info_lock_vars(NonLocals),
+	mode_info_lock_vars(NonLocals, negation),
 	modecheck_goal(A0, A),
 	mode_info_unlock_vars(NonLocals),
 	mode_info_set_instmap(InstMap0),
@@ -985,8 +1012,8 @@
 
 		% Now see whether the goal was successfully scheduled.
 		% If we didn't manage to schedule the goal, then we
-		% restore the original instmap, delay_info & livevars here,
-		% and delay the goal.
+		% restore the original instmap, delay_info and livevars
+		% here, and delay the goal.
 	=(ModeInfo1),
 	{ mode_info_get_errors(ModeInfo1, Errors) },
 	( { Errors = [ FirstError | _] } ->
@@ -1089,6 +1116,58 @@
 
 %-----------------------------------------------------------------------------%
 
+:- pred modecheck_par_conj_list(list(hlds_goal), list(hlds_goal),
+		set(var), list(pair(instmap, set(var))), mode_info, mode_info).
+:- mode modecheck_par_conj_list(in, out, in, out,
+		mode_info_di, mode_info_uo) is det.
+
+modecheck_par_conj_list([], [], _NonLocals, []) --> [].
+modecheck_par_conj_list([Goal0|Goals0], [Goal|Goals], NonLocals, 
+		[InstMap - GoalNonLocals|InstMaps]) -->
+	mode_info_dcg_get_instmap(InstMap0),
+	{ Goal0 = _ - GoalInfo },
+	{ goal_info_get_nonlocals(GoalInfo, GoalNonLocals) },
+	mode_info_get_parallel_vars(PVars0),
+	{ set__init(Bound0) },
+	mode_info_set_parallel_vars([NonLocals - Bound0|PVars0]),
+
+	modecheck_goal(Goal0, Goal),
+	mode_info_get_parallel_vars(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)
+		;
+			{ PVars2 = [] },
+			mode_info_set_parallel_vars(PVars2)
+		)
+	;
+		{ PVars1 = [] },
+		{ error("lost parallel vars") }
+	),
+	mode_info_dcg_get_instmap(InstMap),
+	mode_info_set_instmap(InstMap0),
+	mode_info_lock_vars(Bound1, par_conj),
+	modecheck_par_conj_list(Goals0, Goals, NonLocals, InstMaps),
+	mode_info_unlock_vars(Bound1).
+
+:- pred get_all_conjunct_nonlocals(list(hlds_goal), set(var), set(var)).
+:- mode get_all_conjunct_nonlocals(in, in, out) is det.
+
+get_all_conjunct_nonlocals([], NonLocals, NonLocals).
+get_all_conjunct_nonlocals([G|Gs], NonLocals0, NonLocals) :-
+	G = _ - GoalInfo,
+	goal_info_get_nonlocals(GoalInfo, GoalNonLocals),
+	set__union(GoalNonLocals, NonLocals0, NonLocals1),
+	get_all_conjunct_nonlocals(Gs, NonLocals1, NonLocals).
+
+
+%-----------------------------------------------------------------------------%
+
 	% Given a list of variables and a list of expected livenesses,
 	% ensure the liveness of each variable satisfies the corresponding
 	% expected liveness.
@@ -1227,8 +1306,9 @@
 	% The former is used for predicate calls, where we may need
 	% to introduce unifications to handle calls to implied modes.
 
-modecheck_set_var_inst(Var0, FinalInst, ModeInfo0, ModeInfo) :-
+modecheck_set_var_inst(Var0, FinalInst, ModeInfo00, ModeInfo) :-
 	mode_info_get_instmap(ModeInfo0, InstMap0),
+	mode_info_get_parallel_vars(PVars0, ModeInfo00, ModeInfo0),
 	( instmap__is_reachable(InstMap0) ->
 		% The new inst must be computed by unifying the
 		% old inst and the proc's final inst
@@ -1251,7 +1331,7 @@
 			inst_expand(ModuleInfo, Inst, not_reached)
 		->
 			instmap__init_unreachable(InstMap),
-			mode_info_set_instmap(InstMap, ModeInfo1, ModeInfo)
+			mode_info_set_instmap(InstMap, ModeInfo1, ModeInfo3)
 		;
 			% If we haven't added any information and
 			% we haven't bound any part of the var, then
@@ -1259,7 +1339,7 @@
 			inst_matches_initial(Inst0, Inst, ModuleInfo)
 		->
 			instmap__set(InstMap0, Var0, Inst, InstMap),
-			mode_info_set_instmap(InstMap, ModeInfo1, ModeInfo)
+			mode_info_set_instmap(InstMap, ModeInfo1, ModeInfo3)
 		;
 			% We must have either added some information,
 			% lost some uniqueness, or bound part of the var.
@@ -1273,26 +1353,40 @@
 			mode_info_set_instmap(InstMap, ModeInfo1, ModeInfo2),
 			mode_info_get_delay_info(ModeInfo2, DelayInfo0),
 			delay_info__bind_var(DelayInfo0, Var0, DelayInfo),
-			mode_info_set_delay_info(DelayInfo, ModeInfo2, ModeInfo)
+			mode_info_set_delay_info(DelayInfo,
+				ModeInfo2, ModeInfo3)
 		;
 			% We've bound part of the var.  If the var was locked,
 			% then we need to report an error.
-			mode_info_var_is_locked(ModeInfo1, Var0)
+			mode_info_var_is_locked(ModeInfo1, Var0, LockContext)
 		->
 			set__singleton_set(WaitingVars, Var0),
 			mode_info_error(WaitingVars,
-					mode_error_bind_var(Var0, Inst0, Inst),
-					ModeInfo1, ModeInfo
-			)
+				mode_error_bind_var(Var0, Inst0, Inst,
+				LockContext), ModeInfo1, ModeInfo3)
 		;
 			instmap__set(InstMap0, Var0, Inst, InstMap),
 			mode_info_set_instmap(InstMap, ModeInfo1, ModeInfo2),
 			mode_info_get_delay_info(ModeInfo2, DelayInfo0),
 			delay_info__bind_var(DelayInfo0, Var0, DelayInfo),
-			mode_info_set_delay_info(DelayInfo, ModeInfo2, ModeInfo)
+			mode_info_set_delay_info(DelayInfo,
+						ModeInfo2, ModeInfo3)
 		)
 	;
-		ModeInfo = ModeInfo0
+		ModeInfo3 = ModeInfo0
+	),
+	(
+		PVars0 = [],
+		ModeInfo = ModeInfo3
+	;
+		PVars0 = [NonLocals - Bound0|PVars1],
+		( set__member(Var0, NonLocals) ->
+			set__insert(Bound0, Var0, Bound),
+			PVars = [NonLocals - Bound|PVars1]
+		;
+			PVars = PVars0
+		),
+		mode_info_set_parallel_vars(PVars, ModeInfo3, ModeInfo)
 	).
 
 
Index: compiler/opt_debug.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/opt_debug.m,v
retrieving revision 1.72
diff -u -r1.72 opt_debug.m
--- opt_debug.m	1997/08/25 17:48:31	1.72
+++ opt_debug.m	1997/09/08 22:43:25
@@ -873,6 +873,19 @@
 % XXX  should probably give more info than this
 opt_debug__dump_instr(pragma_c(_, _, Code, _, _), Str) :-
 	string__append_list(["pragma_c(", Code, ")"], Str).
+opt_debug__dump_instr(fork(Child, Parent, Lval), Str) :-
+	opt_debug__dump_label(Child, ChildStr),
+	opt_debug__dump_label(Parent, ParentStr),
+	string__int_to_string(Lval, LvalStr),
+	string__append_list(["fork(", ChildStr, ", ", ParentStr, ", ",
+		LvalStr, ")"], Str).
+opt_debug__dump_instr(join_and_terminate(Lval), Str) :-
+	opt_debug__dump_lval(Lval, LvalStr),
+	string__append_list(["join_and_terminate(", LvalStr, ")"], Str).
+opt_debug__dump_instr(join_and_continue(Lval, Label), Str) :-
+	opt_debug__dump_lval(Lval, LvalStr),
+	opt_debug__dump_label(Label, LabelStr),
+	string__append_list(["join(", LvalStr, ", ", LabelStr, ")"], Str).
 
 opt_debug__dump_fullinstr(Uinstr - Comment, Str) :-
 	opt_debug__dump_instr(Uinstr, U_str),
Index: compiler/opt_util.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/opt_util.m,v
retrieving revision 1.84
diff -u -r1.84 opt_util.m
--- opt_util.m	1997/08/25 17:48:34	1.84
+++ opt_util.m	1997/09/08 23:18:30
@@ -891,6 +891,25 @@
 	;
 		Uinstr0 = pragma_c(_, _, _, _, _),
 		Need = no
+	;
+		Uinstr0 = fork(_, _, _),
+		Need = no
+	;
+		Uinstr0 = join_and_terminate(Lval),
+		opt_util__lval_refers_stackvars(Lval, Use),
+		( Use = yes ->
+			Need = yes
+		;
+			opt_util__block_refers_stackvars(Instrs0, Need)
+		)
+	;
+		Uinstr0 = join_and_continue(Lval, _),
+		opt_util__lval_refers_stackvars(Lval, Use),
+		( Use = yes ->
+			Need = yes
+		;
+			opt_util__block_refers_stackvars(Instrs0, Need)
+		)
 	).
 
 opt_util__filter_out_labels([], []).
@@ -990,6 +1009,9 @@
 opt_util__can_instr_branch_away(incr_sp(_, _), no).
 opt_util__can_instr_branch_away(decr_sp(_), no).
 opt_util__can_instr_branch_away(pragma_c(_, _, _, _, _), no).
+opt_util__can_instr_branch_away(fork(_, _, _), yes).
+opt_util__can_instr_branch_away(join_and_terminate(_), no).
+opt_util__can_instr_branch_away(join_and_continue(_, _), yes).
 
 opt_util__can_instr_fall_through(comment(_), yes).
 opt_util__can_instr_fall_through(livevals(_), yes).
@@ -1015,6 +1037,9 @@
 opt_util__can_instr_fall_through(incr_sp(_, _), yes).
 opt_util__can_instr_fall_through(decr_sp(_), yes).
 opt_util__can_instr_fall_through(pragma_c(_, _, _, _, _), yes).
+opt_util__can_instr_fall_through(fork(_, _, _), no).
+opt_util__can_instr_fall_through(join_and_terminate(_), no).
+opt_util__can_instr_fall_through(join_and_continue(_, _), no).
 
 	% Check whether an instruction sequence can possibly fall through
 	% to the next instruction without using its label.
@@ -1056,6 +1081,9 @@
 opt_util__can_use_livevals(incr_sp(_, _), no).
 opt_util__can_use_livevals(decr_sp(_), no).
 opt_util__can_use_livevals(pragma_c(_, _, _, _, _), no).
+opt_util__can_use_livevals(fork(_, _, _), no).
+opt_util__can_use_livevals(join_and_terminate(_), no).
+opt_util__can_use_livevals(join_and_continue(_, _), no).
 
 % determine all the labels and code_addresses that are referenced by Instr
 
@@ -1114,6 +1142,9 @@
 opt_util__instr_labels_2(incr_sp(_, _), [], []).
 opt_util__instr_labels_2(decr_sp(_), [], []).
 opt_util__instr_labels_2(pragma_c(_, _, _, _, _), [], []).
+opt_util__instr_labels_2(fork(Child, Parent, _), [Child, Parent], []).
+opt_util__instr_labels_2(join_and_terminate(_), [], []).
+opt_util__instr_labels_2(join_and_continue(_, Label), [Label], []).
 
 :- pred opt_util__instr_rvals_and_lvals(instr, list(rval), list(lval)).
 :- mode opt_util__instr_rvals_and_lvals(in, out, out) is det.
@@ -1146,6 +1177,9 @@
 opt_util__instr_rvals_and_lvals(pragma_c(_, In, _, Out, _), Rvals, Lvals) :-
 	pragma_c_inputs_get_rvals(In, Rvals),
 	pragma_c_outputs_get_lvals(Out, Lvals).
+opt_util__instr_rvals_and_lvals(fork(_, _, _), [], []).
+opt_util__instr_rvals_and_lvals(join_and_terminate(Lval), [], [Lval]).
+opt_util__instr_rvals_and_lvals(join_and_continue(Lval, _), [], [Lval]).
 
 	% extract the rvals from the pragma_c_input
 :- pred pragma_c_inputs_get_rvals(list(pragma_c_input), list(rval)).
@@ -1241,6 +1275,11 @@
 opt_util__count_temps_instr(incr_sp(_, _), R, R, F, F).
 opt_util__count_temps_instr(decr_sp(_), R, R, F, F).
 opt_util__count_temps_instr(pragma_c(_, _, _, _, _), R, R, F, F).
+opt_util__count_temps_instr(fork(_, _, _), R, R, F, F).
+opt_util__count_temps_instr(join_and_terminate(Lval), R0, R, F0, F) :-
+	opt_util__count_temps_lval(Lval, R0, R, F0, F).
+opt_util__count_temps_instr(join_and_continue(Lval, _), R0, R, F0, F) :-
+	opt_util__count_temps_lval(Lval, R0, R, F0, F).
 
 :- pred opt_util__count_temps_lval(lval, int, int, int, int).
 :- mode opt_util__count_temps_lval(in, in, out, in, out) is det.
Index: compiler/polymorphism.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/polymorphism.m,v
retrieving revision 1.118
diff -u -r1.118 polymorphism.m
--- polymorphism.m	1997/10/14 09:27:53	1.118
+++ polymorphism.m	1997/10/17 04:20:34
@@ -503,6 +503,9 @@
 polymorphism__process_goal_expr(conj(Goals0), GoalInfo,
 		conj(Goals) - GoalInfo) -->
 	polymorphism__process_goal_list(Goals0, Goals).
+polymorphism__process_goal_expr(par_conj(Goals0, SM), GoalInfo,
+		par_conj(Goals, SM) - GoalInfo) -->
+	polymorphism__process_goal_list(Goals0, Goals).
 polymorphism__process_goal_expr(disj(Goals0, SM), GoalInfo,
 		disj(Goals, SM) - GoalInfo) -->
 	polymorphism__process_goal_list(Goals0, Goals).
Index: compiler/prog_data.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_data.m,v
retrieving revision 1.26
diff -u -r1.26 prog_data.m
--- prog_data.m	1997/10/09 09:39:05	1.26
+++ prog_data.m	1997/10/20 01:21:52
@@ -176,10 +176,12 @@
 % clause/4 defined above
 
 :- type goal		==	pair(goal_expr, term__context).
+
 :- type goal_expr	
 	--->	(goal,goal)
 	;	true	
 			% could use conj(goals) instead 
+	;	(goal &  goal)	% &/2 ie parallel-conj
 	;	{goal;goal}	% {...} quotes ';'/2.
 	;	fail	
 			% could use disj(goals) instead
Index: compiler/prog_io_dcg.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_io_dcg.m,v
retrieving revision 1.6
diff -u -r1.6 prog_io_dcg.m
--- prog_io_dcg.m	1997/10/06 22:18:13	1.6
+++ prog_io_dcg.m	1997/10/07 22:35:02
@@ -199,6 +199,11 @@
 	parse_dcg_goal(A0, VarSet0, N0, Var0, A, VarSet1, N1, Var1),
 	parse_dcg_goal(B0, VarSet1, N1, Var1, B, VarSet, N, Var).
 
+parse_dcg_goal_2("&", [A0, B0], Context, VarSet0, N0, Var0,
+		(A & B) - Context, VarSet, N, Var) :-
+	parse_dcg_goal(A0, VarSet0, N0, Var0, A, VarSet1, N1, Var1),
+	parse_dcg_goal(B0, VarSet1, N1, Var1, B, VarSet, N, Var).
+
 	% Disjunction or if-then-else (Prolog syntax).
 parse_dcg_goal_2(";", [A0, B0], Context, VarSet0, N0, Var0,
 		Goal, VarSet, N, Var) :-
Index: compiler/prog_io_goal.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_io_goal.m,v
retrieving revision 1.6
diff -u -r1.6 prog_io_goal.m
--- prog_io_goal.m	1997/10/06 22:18:16	1.6
+++ prog_io_goal.m	1997/10/07 22:35:02
@@ -168,6 +168,9 @@
 parse_goal_2(",", [A0, B0], V0, (A, B), V) :-
 	parse_goal(A0, V0, A, V1),
 	parse_goal(B0, V1, B, V).
+parse_goal_2("&", [A0, B0], V0, (A & B), V) :-
+	parse_goal(A0, V0, A, V1),
+	parse_goal(B0, V1, B, V).
 parse_goal_2(";", [A0, B0], V0, R, V) :-
 	(
 		A0 = term__functor(term__atom("->"), [X0, Y0], _Context)
Index: compiler/prog_util.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_util.m,v
retrieving revision 1.35
diff -u -r1.35 prog_util.m
--- prog_util.m	1997/07/27 15:01:32	1.35
+++ prog_util.m	1997/09/08 22:43:25
@@ -140,6 +140,10 @@
 		(GoalA, GoalB)) :-
 	prog_util__rename_in_goal(GoalA0, OldVar, NewVar, GoalA),
 	prog_util__rename_in_goal(GoalB0, OldVar, NewVar, GoalB).
+prog_util__rename_in_goal_expr((GoalA0 & GoalB0), OldVar, NewVar,
+		(GoalA & GoalB)) :-
+	prog_util__rename_in_goal(GoalA0, OldVar, NewVar, GoalA),
+	prog_util__rename_in_goal(GoalB0, OldVar, NewVar, GoalB).
 prog_util__rename_in_goal_expr(true, _Var, _NewVar, true).
 prog_util__rename_in_goal_expr((GoalA0; GoalB0), OldVar, NewVar,
 		(GoalA; GoalB)) :-
Index: compiler/quantification.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/quantification.m,v
retrieving revision 1.53
diff -u -r1.53 quantification.m
--- quantification.m	1997/09/01 14:04:33	1.53
+++ quantification.m	1997/09/08 22:43:25
@@ -209,6 +209,9 @@
 implicitly_quantify_goal_2(conj(List0), _, conj(List)) -->
 	implicitly_quantify_conj(List0, List).
 
+implicitly_quantify_goal_2(par_conj(List0, SM), _, par_conj(List, SM)) -->
+	implicitly_quantify_conj(List0, List).
+
 implicitly_quantify_goal_2(disj(Goals0, SM), _, disj(Goals, SM)) -->
 	implicitly_quantify_disj(Goals0, Goals).
 
@@ -595,6 +598,9 @@
 	set__insert_list(Set0, ArgVars, Set).
 
 quantification__goal_vars_2(conj(Goals), Set0, LambdaSet0, Set, LambdaSet) :-
+	goal_list_vars_2(Goals, Set0, LambdaSet0, Set, LambdaSet).
+
+quantification__goal_vars_2(par_conj(Goals, _SM), Set0, LambdaSet0, Set, LambdaSet) :-
 	goal_list_vars_2(Goals, Set0, LambdaSet0, Set, LambdaSet).
 
 quantification__goal_vars_2(disj(Goals, _), Set0, LambdaSet0, Set, LambdaSet) :-
Index: compiler/saved_vars.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/saved_vars.m,v
retrieving revision 1.11
diff -u -r1.11 saved_vars.m
--- saved_vars.m	1997/09/01 14:04:35	1.11
+++ saved_vars.m	1997/09/08 23:18:36
@@ -84,6 +84,13 @@
 			Goals, SlotInfo),
 		conj_list_to_goal(Goals, GoalInfo0, Goal)
 	;
+		GoalExpr0 = par_conj(Goals0, SM),
+			% saved_vars_in_disj treats its goal list as
+			% an independent list of goals, so we can use
+			% it to process the list of parallel conjuncts too.
+		saved_vars_in_disj(Goals0, SlotInfo0, Goals, SlotInfo),
+		Goal = par_conj(Goals, SM) - GoalInfo0
+	;
 		GoalExpr0 = disj(Goals0, SM),
 		saved_vars_in_disj(Goals0, SlotInfo0, Goals, SlotInfo),
 		Goal = disj(Goals, SM) - GoalInfo0
@@ -288,6 +295,11 @@
 			saved_vars_delay_goal(Goals1, Construct, Var,
 				IsNonLocal, SlotInfo0, Goals, SlotInfo)
 		;
+			Goal0Expr = par_conj(_ParConj, _SM),
+			saved_vars_delay_goal(Goals0, Construct, Var,
+				IsNonLocal, SlotInfo0, Goals1, SlotInfo),
+			Goals = [Goal0|Goals1]
+		;
 			Goal0Expr = some(SomeVars, SomeGoal0),
 			rename_var(SlotInfo0, Var, NewVar, Subst, SlotInfo1),
 			goal_util__rename_vars_in_goal(Construct, Subst,
@@ -424,6 +436,9 @@
 		Cases, SlotInfo).
 
 %-----------------------------------------------------------------------------%
+
+	% saved_vars_in_disj does a saved_vars_in_goal on an list of independent
+	% goals, and is used to process disjunctions and parallel conjunctions.
 
 :- pred saved_vars_in_disj(list(hlds_goal), slot_info,
 	list(hlds_goal), slot_info).
Index: compiler/simplify.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/simplify.m,v
retrieving revision 1.46
diff -u -r1.46 simplify.m
--- simplify.m	1997/09/01 14:04:39	1.46
+++ simplify.m	1997/09/08 22:43:25
@@ -275,6 +275,21 @@
 		)
 	).
 
+simplify__goal_2(par_conj(Goals0, SM), GoalInfo, Goal, GoalInfo, Info0, Info) :-
+	(
+		Goals0 = []
+	->
+		Goal = conj([]),
+		Info = Info0
+	;
+		Goals0 = [Goal0]
+	->
+		simplify__goal(Goal0, Goal - _, Info0, Info)
+	;
+		simplify__par_conj(Goals0, Goals, Info0, Info0, Info),
+		Goal = par_conj(Goals, SM)
+	).
+
 simplify__goal_2(disj(Disjuncts0, SM), GoalInfo0,
 		Goal, GoalInfo, Info0, Info) :-
 	( Disjuncts0 = [] ->
@@ -905,6 +920,18 @@
 	;
 		RevGoals = [Goal | RevGoals0]
 	).
+
+%-----------------------------------------------------------------------------%
+
+:- pred simplify__par_conj(list(hlds_goal), list(hlds_goal),
+		simplify_info, simplify_info, simplify_info).
+:- mode simplify__par_conj(in, out, in, in, out) is det.
+
+simplify__par_conj([], [], _, Info, Info).
+simplify__par_conj([Goal0 |Goals0], [Goal | Goals], Info0, Info1, Info) :-
+	simplify__goal(Goal0, Goal, Info1, Info2),
+	simplify_info_post_branch_update(Info0, Info2, Info3),
+	simplify__par_conj(Goals0, Goals, Info0, Info3, Info).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/store_alloc.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/store_alloc.m,v
retrieving revision 1.55
diff -u -r1.55 store_alloc.m
--- store_alloc.m	1997/09/01 14:04:44	1.55
+++ store_alloc.m	1997/09/08 22:43:25
@@ -129,6 +129,11 @@
 	store_alloc_in_conj(Goals0, Liveness0, ResumeVars0, ModuleInfo,
 		Goals, Liveness).
 
+store_alloc_in_goal_2(par_conj(Goals0, SM), Liveness0, ResumeVars0, ModuleInfo,
+		par_conj(Goals, SM), Liveness) :-
+	store_alloc_in_par_conj(Goals0, Liveness0, ResumeVars0, ModuleInfo,
+		Goals, Liveness).
+
 store_alloc_in_goal_2(disj(Goals0, FV), Liveness0, ResumeVars0, ModuleInfo,
 		disj(Goals, FV), Liveness) :-
 	store_alloc_in_disj(Goals0, Liveness0, ResumeVars0, ModuleInfo,
@@ -201,6 +206,20 @@
 		store_alloc_in_conj(Goals0, Liveness1, ResumeVars0, ModuleInfo,
 			Goals, Liveness)
 	).
+
+%-----------------------------------------------------------------------------%
+
+:- pred store_alloc_in_par_conj(list(hlds_goal), liveness_info, set(var),
+	module_info, list(hlds_goal), liveness_info).
+:- mode store_alloc_in_par_conj(in, in, in, in, out, out) is det.
+
+store_alloc_in_par_conj([], Liveness, _ResumeVars0, _ModuleInfo, [], Liveness).
+store_alloc_in_par_conj([Goal0 | Goals0], Liveness0, ResumeVars0, ModuleInfo,
+		[Goal | Goals], Liveness) :-
+	store_alloc_in_goal(Goal0, Liveness0, ResumeVars0, ModuleInfo,
+		Goal, Liveness),
+	store_alloc_in_par_conj(Goals0, Liveness0, ResumeVars0, ModuleInfo,
+		Goals, _Liveness1).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/stratify.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/stratify.m,v
retrieving revision 1.10
diff -u -r1.10 stratify.m
--- stratify.m	1997/09/01 14:04:49	1.10
+++ stratify.m	1997/09/08 22:43:25
@@ -161,6 +161,10 @@
 		ThisPredProcId, Error, Module0, Module) -->
 	first_order_check_goal_list(Goals, Negated, WholeScc, ThisPredProcId,
 		Error, Module0, Module).
+first_order_check_goal(par_conj(Goals, _SM), _GoalInfo, Negated, WholeScc, 
+		ThisPredProcId, Error, Module0, Module) -->
+	first_order_check_goal_list(Goals, Negated, WholeScc, ThisPredProcId,
+		Error, Module0, Module).
 first_order_check_goal(disj(Goals, _Follow), _GoalInfo, Negated, 
 		WholeScc, ThisPredProcId, Error, Module0, Module) -->
 	first_order_check_goal_list(Goals, Negated, WholeScc, ThisPredProcId,
@@ -337,6 +341,10 @@
 		ThisPredProcId, HighOrderLoops, Error, Module0, Module) -->
 	higher_order_check_goal_list(Goals, Negated, WholeScc, ThisPredProcId,
 		HighOrderLoops, Error, Module0, Module).
+higher_order_check_goal(par_conj(Goals, _), _GoalInfo, Negated, WholeScc, 
+		ThisPredProcId, HighOrderLoops, Error, Module0, Module) -->
+	higher_order_check_goal_list(Goals, Negated, WholeScc, ThisPredProcId,
+		HighOrderLoops, Error, Module0, Module).
 higher_order_check_goal(disj(Goals, _Follow), _GoalInfo, Negated, WholeScc, 
 		ThisPredProcId, HighOrderLoops, Error, Module0, Module) -->
 	higher_order_check_goal_list(Goals, Negated, WholeScc, ThisPredProcId,
@@ -830,6 +838,9 @@
 
 check_goal1(conj(Goals), Calls0, Calls, HasAT0, HasAT, CallsHO0, CallsHO) :-
 	check_goal_list(Goals, Calls0, Calls, HasAT0, HasAT, CallsHO0, CallsHO).
+check_goal1(par_conj(Goals, _), Calls0, Calls, HasAT0, HasAT,
+		CallsHO0, CallsHO) :-
+	check_goal_list(Goals, Calls0, Calls, HasAT0, HasAT, CallsHO0, CallsHO).
 check_goal1(disj(Goals, _Follow), Calls0, Calls, HasAT0, HasAT, CallsHO0, 
 		CallsHO) :-
 	check_goal_list(Goals, Calls0, Calls, HasAT0, HasAT, CallsHO0, CallsHO).
@@ -926,6 +937,8 @@
 
 
 get_called_procs(conj(Goals), Calls0, Calls) :-
+	check_goal_list(Goals, Calls0, Calls).
+get_called_procs(par_conj(Goals, _), Calls0, Calls) :-
 	check_goal_list(Goals, Calls0, Calls).
 get_called_procs(disj(Goals, _Follow), Calls0, Calls) :-
 	check_goal_list(Goals, Calls0, Calls).
Index: compiler/switch_detection.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/switch_detection.m,v
retrieving revision 1.76
diff -u -r1.76 switch_detection.m
--- switch_detection.m	1997/09/01 14:04:54	1.76
+++ switch_detection.m	1997/09/08 22:43:25
@@ -147,6 +147,11 @@
 		VarTypes, ModuleInfo, conj(Goals)) :-
 	detect_switches_in_conj(Goals0, InstMap0, VarTypes, ModuleInfo, Goals).
 
+detect_switches_in_goal_2(par_conj(Goals0, SM), _GoalInfo, InstMap0,
+		VarTypes, ModuleInfo, par_conj(Goals, SM)) :-
+	detect_switches_in_par_conj(Goals0, InstMap0, VarTypes,
+		ModuleInfo, Goals).
+
 detect_switches_in_goal_2(not(Goal0), _GoalInfo, InstMap0,
 		VarTypes, ModuleInfo, not(Goal)) :-
 	detect_switches_in_goal(Goal0, InstMap0, VarTypes, ModuleInfo, Goal).
@@ -321,6 +326,17 @@
 	detect_switches_in_goal(Goal0, InstMap, VarTypes, ModuleInfo, Goal),
 	Case = case(Functor, Goal),
 	detect_switches_in_cases(Cases0, InstMap, VarTypes, ModuleInfo, Cases).
+
+:- pred detect_switches_in_par_conj(list(hlds_goal), instmap, map(var, type),
+	module_info, list(hlds_goal)).
+:- mode detect_switches_in_par_conj(in, in, in, in, out) is det.
+
+detect_switches_in_par_conj([], _InstMap, _VarTypes, _ModuleInfo, []).
+detect_switches_in_par_conj([Goal0 | Goals0], InstMap, VarTypes, ModuleInfo,
+		[Goal | Goals]) :-
+	detect_switches_in_goal(Goal0, InstMap, VarTypes, ModuleInfo, Goal),
+	detect_switches_in_par_conj(Goals0, InstMap, VarTypes,
+		ModuleInfo, Goals).
 
 :- pred detect_switches_in_conj(list(hlds_goal), instmap, map(var, type),
 	module_info, list(hlds_goal)).
Index: compiler/term_pass1.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/term_pass1.m,v
retrieving revision 1.3
diff -u -r1.3 term_pass1.m
--- term_pass1.m	1997/10/20 04:12:41	1.3
+++ term_pass1.m	1997/10/20 04:49:20
@@ -402,6 +402,17 @@
 			Res, Offs0, Offs)
 	).
 
+proc_inequalities_goal(par_conj([], _), _, _Module, _, _PPId, ok, Offs, Offs).
+proc_inequalities_goal(par_conj([ Goal | Goals ], _), GoalInfo, Module, Info, 
+		PPId, Res, Offs0, Offs) :-
+	( goal_will_fail(GoalInfo) ->
+		Res = ok,
+		Offs = []
+	;
+		proc_inequalities_conj(Goal, Goals, Module, Info, PPId, 
+			Res, Offs0, Offs)
+	).
+
 % This clause fails (returns Res=error()) if:
 %	The called predicate contains higher order arguments
 %	The terminates value of the called predicate is 'dont_know'
Index: compiler/term_pass2.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/term_pass2.m,v
retrieving revision 1.2
diff -u -r1.2 term_pass2.m
--- term_pass2.m	1997/10/09 09:39:18	1.2
+++ term_pass2.m	1997/10/20 02:08:42
@@ -474,6 +474,11 @@
 	termination_conj(Goals, Module, UnifyInfo, CallInfo, Res, 
 		Out0, Out).
 
+termination_goal(par_conj(Goals, _), 
+		_GoalInfo, Module, UnifyInfo, CallInfo, Res, Out0, Out) :-
+	termination_conj(Goals, Module, UnifyInfo, CallInfo, Res, 
+		Out0, Out).
+
 % This processes calls when doing normal termination analysis (as opposed
 % to single argument analysis).
 termination_goal(call(CallPredId, CallProcId, Args, _IsBuiltin, _, _), 
Index: compiler/typecheck.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/typecheck.m,v
retrieving revision 1.217
diff -u -r1.217 typecheck.m
--- typecheck.m	1997/10/14 09:18:50	1.217
+++ typecheck.m	1997/10/17 04:20:42
@@ -807,6 +807,9 @@
 typecheck_goal_2(conj(List0), conj(List)) -->
 	checkpoint("conj"),
 	typecheck_goal_list(List0, List).
+typecheck_goal_2(par_conj(List0, SM), par_conj(List, SM)) -->
+	checkpoint("par_conj"),
+	typecheck_goal_list(List0, List).
 typecheck_goal_2(disj(List0, SM), disj(List, SM)) -->
 	checkpoint("disj"),
 	typecheck_goal_list(List0, List).
Index: compiler/unique_modes.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/unique_modes.m,v
retrieving revision 1.40
diff -u -r1.40 unique_modes.m
--- unique_modes.m	1997/09/15 21:12:50	1.40
+++ unique_modes.m	1997/09/16 00:14:39
@@ -382,6 +382,16 @@
 	),
 	mode_checkpoint(exit, "conj").
 
+unique_modes__check_goal_2(par_conj(List0, SM), GoalInfo0,
+		par_conj(List, SM)) -->
+	mode_checkpoint(enter, "par_conj"),
+	{ goal_info_get_nonlocals(GoalInfo0, NonLocals) },
+	mode_info_add_live_vars(NonLocals),
+	unique_modes__check_par_conj(List0, List, InstMapList),
+	instmap__unify(NonLocals, InstMapList),
+	mode_info_remove_live_vars(NonLocals),
+	mode_checkpoint(exit, "par_conj").
+
 unique_modes__check_goal_2(disj(List0, SM), GoalInfo0, disj(List, SM)) -->
 	mode_checkpoint(enter, "disj"),
 	( { List0 = [] } ->
@@ -422,7 +432,7 @@
 	{ unique_modes__goal_get_nonlocals(B0, B_Vars) },
 	{ unique_modes__goal_get_nonlocals(C0, C_Vars) },
 	mode_info_dcg_get_instmap(InstMap0),
-	mode_info_lock_vars(NonLocals),
+	mode_info_lock_vars(NonLocals, if_then_else),
 
 	%
 	% At this point, we should set the inst of any `unique'
@@ -468,7 +478,7 @@
 	=(ModeInfo),
 	{ select_live_vars(NonLocalsList, ModeInfo, LiveNonLocals) },
 	make_var_list_mostly_uniq(LiveNonLocals),
-	mode_info_lock_vars(NonLocals),
+	mode_info_lock_vars(NonLocals, negation),
 	unique_modes__check_goal(A0, A),
 	mode_info_unlock_vars(NonLocals),
 	mode_info_set_instmap(InstMap0),
@@ -615,6 +625,28 @@
 	mode_info_remove_live_vars(NonLocals),
 	unique_modes__check_goal(Goal0, Goal),
 	unique_modes__check_conj(Goals0, Goals).
+
+%-----------------------------------------------------------------------------%
+
+:- pred unique_modes__check_par_conj(list(hlds_goal), list(hlds_goal),
+		list(pair(instmap, set(var))), mode_info, mode_info).
+:- mode unique_modes__check_par_conj(in, out, out,
+		mode_info_di, mode_info_uo) is det.
+
+	% Just process each conjunct in turn.
+	% Because we have already done modechecking, we know that
+	% there are no attempts to bind a variable in multiple
+	% parallel conjuncts, so we don't need to lock/unlock variables.
+
+unique_modes__check_par_conj([], [], []) --> [].
+unique_modes__check_par_conj([Goal0 | Goals0], [Goal | Goals],
+		[InstMap - NonLocals|InstMaps]) -->
+	{ unique_modes__goal_get_nonlocals(Goal0, NonLocals) },
+	mode_info_dcg_get_instmap(InstMap0),
+	unique_modes__check_goal(Goal0, Goal),
+	mode_info_dcg_get_instmap(InstMap),
+	mode_info_set_instmap(InstMap0),
+	unique_modes__check_par_conj(Goals0, Goals, InstMaps).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/unused_args.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/unused_args.m,v
retrieving revision 1.35
diff -u -r1.35 unused_args.m
--- unused_args.m	1997/09/01 14:05:44	1.35
+++ unused_args.m	1997/09/08 22:43:25
@@ -356,6 +356,10 @@
 traverse_goal(ModuleInfo, conj(Goals), UseInf0, UseInf) :-
 	traverse_list_of_goals(ModuleInfo, Goals, UseInf0, UseInf).
 
+% handle parallel conjunction
+traverse_goal(ModuleInfo, par_conj(Goals, _SM), UseInf0, UseInf) :-
+	traverse_list_of_goals(ModuleInfo, Goals, UseInf0, UseInf).
+
 % handle disjunction
 traverse_goal(ModuleInfo, disj(Goals, _), UseInf0, UseInf) :-
 	traverse_list_of_goals(ModuleInfo, Goals, UseInf0, UseInf).
@@ -1119,6 +1123,12 @@
 
 fixup_goal_expr(ModuleInfo, UnusedVars, ProcCallInfo, Changed,
 		conj(Goals0) - GoalInfo, conj(Goals) - GoalInfo) :-
+	fixup_conjuncts(ModuleInfo, UnusedVars, ProcCallInfo, no,
+						Changed, Goals0, Goals).
+
+fixup_goal_expr(ModuleInfo, UnusedVars, ProcCallInfo, Changed,
+		par_conj(Goals0, SM) - GoalInfo,
+		par_conj(Goals, SM) - GoalInfo) :-
 	fixup_conjuncts(ModuleInfo, UnusedVars, ProcCallInfo, no,
 						Changed, Goals0, Goals).
 
Index: compiler/value_number.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/value_number.m,v
retrieving revision 1.86
diff -u -r1.86 value_number.m
--- value_number.m	1997/08/27 07:35:15	1.86
+++ value_number.m	1997/09/08 22:43:25
@@ -1093,6 +1093,9 @@
 value_number__boundary_instr(incr_sp(_, _), yes).
 value_number__boundary_instr(decr_sp(_), yes).
 value_number__boundary_instr(pragma_c(_, _, _, _, _), yes).
+value_number__boundary_instr(fork(_, _, _), yes).
+value_number__boundary_instr(join_and_terminate(_), yes).
+value_number__boundary_instr(join_and_continue(_, _), yes).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/vn_block.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/vn_block.m,v
retrieving revision 1.49
diff -u -r1.49 vn_block.m
--- vn_block.m	1997/08/27 07:35:20	1.49
+++ vn_block.m	1997/09/08 22:43:25
@@ -357,6 +357,18 @@
 		_Livemap, _Params, VnTables, VnTables, Liveset, Liveset,
 		SeenIncr, SeenIncr, Tuple, Tuple) :-
 	error("value numbering not supported for pragma_c").
+vn_block__handle_instr(fork(_, _, _),
+		_Livemap, _Params, VnTables, VnTables, Liveset, Liveset,
+		SeenIncr, SeenIncr, Tuple, Tuple) :-
+	error("value numbering not supported for fork").
+vn_block__handle_instr(join_and_terminate(_),
+		_Livemap, _Params, VnTables, VnTables, Liveset, Liveset,
+		SeenIncr, SeenIncr, Tuple, Tuple) :-
+	error("value numbering not supported for join_and_terminate").
+vn_block__handle_instr(join_and_continue(_, _),
+		_Livemap, _Params, VnTables, VnTables, Liveset, Liveset,
+		SeenIncr, SeenIncr, Tuple, Tuple) :-
+	error("value numbering not supported for join_and_continue").
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -892,6 +904,9 @@
 vn_block__is_ctrl_instr(incr_sp(_, _), yes).
 vn_block__is_ctrl_instr(decr_sp(_), yes).
 vn_block__is_ctrl_instr(pragma_c(_, _, _, _, _), no).
+vn_block__is_ctrl_instr(fork(_, _, _), yes).
+vn_block__is_ctrl_instr(join_and_terminate(_), yes).
+vn_block__is_ctrl_instr(join_and_continue(_, _), yes).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
Index: compiler/vn_cost.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/vn_cost.m,v
retrieving revision 1.28
diff -u -r1.28 vn_cost.m
--- vn_cost.m	1997/08/25 17:48:42	1.28
+++ vn_cost.m	1997/09/08 22:43:25
@@ -183,6 +183,15 @@
 	;
 		Uinstr = pragma_c(_, _, _, _, _),
 		error("pragma_c found in vn_block_cost")
+	;
+		Uinstr = fork(_, _, _),
+		error("fork found in vn_block_cost")
+	;
+		Uinstr = join_and_terminate(_),
+		error("join_and_terminate found in vn_block_cost")
+	;
+		Uinstr = join_and_continue(_, _),
+		error("join_and_continue found in vn_block_cost")
 	).
 
 vn_cost__lval_cost(Lval, Params, Cost) :-
Index: compiler/vn_filter.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/vn_filter.m,v
retrieving revision 1.12
diff -u -r1.12 vn_filter.m
--- vn_filter.m	1997/08/27 07:35:21	1.12
+++ vn_filter.m	1997/09/09 00:46:27
@@ -156,6 +156,12 @@
 vn_filter__user_instr(decr_sp(_), no).
 vn_filter__user_instr(pragma_c(_, _, _, _, _), _):-
 	error("inappropriate instruction in vn__filter").
+vn_filter__user_instr(fork(_, _, _), _):-
+	error("fork instruction in vn__filter").
+vn_filter__user_instr(join_and_terminate(_), _):-
+	error("join_and_terminate instruction in vn__filter").
+vn_filter__user_instr(join_and_continue(_, _), _):-
+	error("join_and_continue instruction in vn__filter").
 
 	% vn_filter__replace_in_user_instr(Instr0, Old, New, Instr):
 	% Given that Instr0 refers to the values of some locations,
@@ -218,6 +224,12 @@
 	error("non-user instruction in vn_filter__replace_in_user_instr").
 vn_filter__replace_in_user_instr(pragma_c(_, _, _, _, _), _, _, _):-
 	error("inappropriate instruction in vn__filter").
+vn_filter__replace_in_user_instr(fork(_, _, _), _, _, _):-
+	error("fork instruction in vn__filter").
+vn_filter__replace_in_user_instr(join_and_terminate(_), _, _, _):-
+	error("join_and_terminate instruction in vn__filter").
+vn_filter__replace_in_user_instr(join_and_continue(_, _), _, _, _):-
+	error("join_and_continue instruction in vn__filter").
 
 	% Check whether this instruction defines the value of any lval.
 
@@ -250,6 +262,12 @@
 vn_filter__defining_instr(decr_sp(_), no).
 vn_filter__defining_instr(pragma_c(_, _, _, _, _), _):-
 	error("inappropriate instruction in vn__filter").
+vn_filter__defining_instr(fork(_, _, _), _):-
+	error("fork instruction in vn__filter").
+vn_filter__defining_instr(join_and_terminate(_), _):-
+	error("join_and_terminate instruction in vn__filter").
+vn_filter__defining_instr(join_and_continue(_, _), _):-
+	error("join_and_continue instruction in vn__filter").
 
 	% vn_filter__replace_in_defining_instr(Instr0, Old, New, Instr):
 	% Given that Instr0 defines the value of a location,
@@ -309,7 +327,13 @@
 vn_filter__replace_in_defining_instr(decr_sp(_), _, _, _) :-
 	error("non-def instruction in vn_filter__replace_in_defining_instr").
 vn_filter__replace_in_defining_instr(pragma_c(_, _, _, _, _), _, _, _):-
-	error("inappropriate instruction in vn__filter").
+	error("inappropriate instruction in vn_filter__replace_in_defining_instr").
+vn_filter__replace_in_defining_instr(fork(_, _, _), _, _, _):-
+	error("fork instruction in vn_filter__replace_in_defining_instr").
+vn_filter__replace_in_defining_instr(join_and_terminate(_), _, _, _):-
+	error("join_and_terminate instruction in vn_filter__replace_in_defining_instr").
+vn_filter__replace_in_defining_instr(join_and_continue(_, _), _, _, _):-
+	error("join_and_continue instruction in vn_filter__replace_in_defining_instr").
 
 	% vn_filter__replace_in_lval(Lval0, Old, New, Lval):
 	% Replace all occurrences of Old with New in Lval0,
cvs diff: Diffing compiler/notes
cvs diff: Diffing doc
cvs diff: Diffing extras
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/graphics
cvs diff: Diffing extras/graphics/Togl-1.2
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing library
Index: library/nc_builtin.nl
===================================================================
RCS file: /home/staff/zs/imp/mercury/library/nc_builtin.nl,v
retrieving revision 1.15
diff -u -r1.15 nc_builtin.nl
--- nc_builtin.nl	1997/07/27 15:06:59	1.15
+++ nc_builtin.nl	1997/09/08 22:54:57
@@ -50,6 +50,8 @@
 :- op(1179, xfy, (--->)).
 :- op(1175, xfx, (::)).
 
+:- op(1025, xfy, (&)).
+
 :- op(950, fxy, (lambda)).
 
 :- op(400, yfx, (rem)).
Index: library/sp_builtin.nl
===================================================================
RCS file: /home/staff/zs/imp/mercury/library/sp_builtin.nl,v
retrieving revision 1.13
diff -u -r1.13 sp_builtin.nl
--- sp_builtin.nl	1997/07/27 15:07:13	1.13
+++ sp_builtin.nl	1997/09/08 22:54:57
@@ -53,6 +53,7 @@
 :- op(1199, fx, (mode)).
 :- op(1199, fx, (inst)).
 :- op(1179, xfy, (--->)).
+:- op(1025, xfy, (&)).
 :- op(975, xfx, ('::')).
 :- op(700, xfx, ( \= ) ).
 :- op(500, fx, ( \ ) ).
cvs diff: Diffing lp_solve
cvs diff: Diffing lp_solve/lp_examples
cvs diff: Diffing profiler
cvs diff: Diffing runtime
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/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing scripts
cvs diff: Diffing tools
cvs diff: Diffing trial
cvs diff: Diffing util



More information about the developers mailing list