For review: parallel conjunction

Thomas Charles CONWAY conway at cs.mu.oz.au
Wed Feb 19 14:21:28 AEDT 1997


Hi.

The following diff adds parallel conjunction to the compiler.
I have another diff for the runtime support, but this can be
done independently, and it is easier to review the changes in
the smaller bunches.

Changes to the compiler to support parallel conjunction (&).
At the moment the support is only for deterministic independent
and-parallel conjunctions.

Because parallel conjunction is explicit (using & instead of ,),
and the compiler doesn't use it, these changes won't lead to
bootstrapping problems (provided they compile, which they do ;-).

compiler/hlds_goal.m:
	Add parallel conjunction to the hlds__goal_exprn type.

compiler/llds.m:
	Add fork/3, join_and_terminate/1 and join_and_continue/2
	to llds__instruction.

compiler/prog_data.m:
	Add par/2 for parallel conjunction.

compiler/prog_io_{dcg,goal}.m:
	Recognise & as the parallel conjunction connective.

compiler/*.m:
	Lots of changes to handle the new goal, hlds__goal_exprn and
	llds__instruction types.

cvs diff: Diffing .
Index: bytecode_gen.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/bytecode_gen.m,v
retrieving revision 1.22
diff -u -r1.22 bytecode_gen.m
--- bytecode_gen.m	1997/01/27 07:44:49	1.22
+++ bytecode_gen.m	1997/01/27 22:38:23
@@ -182,6 +182,9 @@
 		GoalExpr = conj(GoalList),
 		bytecode_gen__conj(GoalList, ByteInfo0, ByteInfo, Code)
 	;
+		GoalExpr = par_conj(_GoalList, _SM),
+		error("bytecode_gen of parallel conjunction not implemented")
+	;
 		GoalExpr = disj(GoalList, _),
 		( GoalList = [] ->
 			Code = node([fail]),
Index: code_gen.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/code_gen.m,v
retrieving revision 1.20
diff -u -r1.20 code_gen.m
--- code_gen.m	1997/01/27 07:44:51	1.20
+++ code_gen.m	1997/01/27 22:16:03
@@ -58,7 +58,7 @@
 
 :- implementation.
 
-:- import_module call_gen, unify_gen, ite_gen, switch_gen.
+:- import_module call_gen, unify_gen, ite_gen, switch_gen, par_conj.
 :- import_module disj_gen, pragma_c_gen, globals, options, hlds_out.
 :- import_module code_aux, middle_rec, passes_aux.
 :- import_module code_util, type_util, mode_util.
@@ -667,6 +667,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__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) },
@@ -753,6 +755,8 @@
 
 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) -->
+	{ error("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) },
@@ -958,6 +962,8 @@
 
 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) -->
+	{ error("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: code_info.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/code_info.m,v
retrieving revision 1.196
diff -u -r1.196 code_info.m
--- code_info.m	1997/01/21 05:04:53	1.196
+++ code_info.m	1997/01/24 06:07:00
@@ -63,6 +63,8 @@
 
 :- type code_info.
 
+:- type lval_or_ticket  --->	ticket ; lval(lval).
+
 		% Create a new code_info structure.
 :- pred code_info__init(varset, set(var), stack_slots, bool, globals,
 	pred_id, proc_id, proc_info, instmap, follow_vars, module_info,
@@ -276,8 +278,6 @@
 					% these slots.
 	).
 
-:- type lval_or_ticket  --->	ticket ; lval(lval).
-
 %---------------------------------------------------------------------------%
 
 code_info__init(Varset, Liveness, StackSlots, SaveSuccip, Globals,
@@ -2833,11 +2833,6 @@
 :- pred code_info__get_total_stackslot_count(int, code_info, code_info).
 :- mode code_info__get_total_stackslot_count(out, in, out) is det.
 
-%---------------------------------------------------------------------------%
-%---------------------------------------------------------------------------%
-
-:- implementation.
-
 :- pred code_info__acquire_temp_slot(lval_or_ticket, lval,
 	code_info, code_info).
 :- mode code_info__acquire_temp_slot(in, out, in, out) is det.
@@ -2845,15 +2840,26 @@
 :- pred code_info__release_temp_slot(lval, code_info, code_info).
 :- mode code_info__release_temp_slot(in, in, out) is det.
 
+:- 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__get_variable_slot_num(var, int, code_info, code_info).
+:- mode code_info__get_variable_slot_num(in, out, in, out) is det.
+
 :- pred code_info__get_variable_slot(var, lval, code_info, code_info).
 :- mode code_info__get_variable_slot(in, out, in, out) is det.
 
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
 :- pred code_info__max_var_slot(stack_slots, int).
 :- mode code_info__max_var_slot(in, out) is det.
 
-:- pred code_info__stack_variable(int, lval, code_info, code_info).
-:- mode code_info__stack_variable(in, out, in, out) is det.
-
 code_info__acquire_temp_slot(Item, StackVar) -->
 	code_info__get_avail_temp_slots(AvailSlots0),
 	( { set__remove_least(AvailSlots0, StackVarPrime, AvailSlots) } ->
@@ -2895,6 +2901,28 @@
 		{ error(Str) }
 	).
 
+code_info__get_variable_slot_num(Var, SlotNum) -->
+	code_info__get_stack_slots(StackSlots),
+	(
+		{ map__search(StackSlots, Var, Slot) },
+		{
+			Slot = stackvar(N)
+		;
+			Slot = framevar(N)
+		}
+	->
+		{ SlotNum = N }
+	;
+		code_info__variable_to_string(Var, Name),
+		{ term__var_to_int(Var, Num) },
+		{ string__int_to_string(Num, NumStr) },
+		{ string__append_list([
+			"code_info__get_variable_slot_num: variable `",
+			Name, "' (", NumStr, ") not found or not a slot"],
+			Str) },
+		{ error(Str) }
+	).
+
 code_info__max_var_slot(StackSlots, SlotCount) :-
 	map__values(StackSlots, StackSlotList),
 	code_info__max_var_slot_2(StackSlotList, 0, SlotCount).
@@ -2925,6 +2953,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: code_util.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/code_util.m,v
retrieving revision 1.79
diff -u -r1.79 code_util.m
--- code_util.m	1997/02/17 01:26:27	1.79
+++ code_util.m	1997/02/17 23:35:33
@@ -779,6 +779,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: constraint.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/constraint.m,v
retrieving revision 1.30
diff -u -r1.30 constraint.m
--- constraint.m	1997/01/27 07:44:55	1.30
+++ constraint.m	1997/02/18 01:35:16
@@ -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: cse_detection.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/cse_detection.m,v
retrieving revision 1.39
diff -u -r1.39 cse_detection.m
--- cse_detection.m	1997/01/27 07:44:55	1.39
+++ cse_detection.m	1997/01/27 22:16:05
@@ -233,6 +233,9 @@
 		Redo, conj(Goals)) :-
 	detect_cse_in_conj(Goals0, InstMap, CseInfo0, CseInfo, Redo, Goals).
 
+detect_cse_in_goal_2(par_conj(Goals, SM), _, _, CseInfo, CseInfo, no,
+		par_conj(Goals, SM)).
+
 detect_cse_in_goal_2(disj(Goals0, SM), GoalInfo, InstMap, CseInfo0, CseInfo,
 		Redo, Goal) :-
 	( Goals0 = [] ->
Index: dead_proc_elim.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/dead_proc_elim.m,v
retrieving revision 1.23
diff -u -r1.23 dead_proc_elim.m
--- dead_proc_elim.m	1997/02/16 06:41:26	1.23
+++ dead_proc_elim.m	1997/02/16 21:10:43
@@ -342,6 +342,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,
Index: dependency_graph.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/dependency_graph.m,v
retrieving revision 1.26
diff -u -r1.26 dependency_graph.m
--- dependency_graph.m	1997/01/27 07:44:57	1.26
+++ dependency_graph.m	1997/01/27 22:16:07
@@ -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: det_analysis.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/det_analysis.m,v
retrieving revision 1.111
diff -u -r1.111 det_analysis.m
--- det_analysis.m	1997/01/27 07:44:58	1.111
+++ det_analysis.m	1997/02/18 01:08:07
@@ -374,6 +374,18 @@
 	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),
+	(
+		Detism \= det
+	->
+		Msgs = [par_conj_not_det(GoalInfo)|Msgs0]
+	;
+		Msgs = Msgs0
+	).
+
 det_infer_goal_2(disj(Goals0, SM), _, InstMap0, SolnContext, DetInfo, _, _,
 		disj(Goals, SM), Detism, Msgs) :-
 	det_infer_disj(Goals0, InstMap0, SolnContext, DetInfo,
@@ -626,6 +638,39 @@
 	% Process the first conjunct.
 	%
 	det_infer_goal(Goal0, InstMap0, SolnContextA, DetInfo,
+			Goal, DetismA, MsgsA),
+	determinism_components(DetismA, CanFailA, MaxSolnsA),
+
+	%
+	% Finally combine the results computed above.
+	%
+	det_conjunction_canfail(CanFailA, CanFailB, CanFail),
+	det_conjunction_maxsoln(MaxSolnsA, MaxSolnsB, MaxSolns),
+	determinism_components(Detism, CanFail, MaxSolns),
+	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) :-
+
+	% We should look to see when we get to a not_reached point
+	% and optimize away the remaining elements of the conjunction.
+	% But that optimization is done in the code generation anyway.
+
+	%
+	% First, process the second and subsequent conjuncts.
+	%
+	det_infer_par_conj(Goals0, InstMap0, SolnContext, DetInfo,
+			Goals, DetismB, MsgsB),
+	determinism_components(DetismB, CanFailB, MaxSolnsB),
+
+	% Process the first conjunct.
+	%
+	det_infer_goal(Goal0, InstMap0, SolnContext, DetInfo,
 			Goal, DetismA, MsgsA),
 	determinism_components(DetismA, CanFailA, MaxSolnsA),
 
Index: det_report.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/det_report.m,v
retrieving revision 1.31
diff -u -r1.31 det_report.m
--- det_report.m	1997/02/08 16:16:05	1.31
+++ det_report.m	1997/02/18 01:32:50
@@ -45,7 +45,9 @@
 				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(hlds__goal_info)
+		.
 
 :- type seen_call_id
 	--->	seen_call(pred_id, proc_id)
@@ -294,6 +296,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,
@@ -833,6 +839,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.
@@ -968,6 +975,10 @@
 	{ 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(GoalInfo), _) -->
+	{ goal_info_get_context(GoalInfo, Context) },
+	prog_out__write_context(Context),
+	io__write_string("Warning: parallel conjunction is not deterministic.\n").
 
 %-----------------------------------------------------------------------------%
 
Index: dnf.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/dnf.m,v
retrieving revision 1.16
diff -u -r1.16 dnf.m
--- dnf.m	1997/01/27 07:45:01	1.16
+++ dnf.m	1997/01/27 22:16:10
@@ -184,6 +184,9 @@
 			Goals, NewPredIds0, NewPredIds),
 		Goal = conj(Goals) - GoalInfo
 	;
+		GoalExpr0 = par_conj(_Goals0, _SM),
+		error("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: dupelim.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/dupelim.m,v
retrieving revision 1.17
diff -u -r1.17 dupelim.m
--- dupelim.m	1997/01/21 05:04:56	1.17
+++ dupelim.m	1997/02/07 04:41:00
@@ -184,6 +184,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: excess.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/excess.m,v
retrieving revision 1.18
diff -u -r1.18 excess.m
--- excess.m	1997/01/27 07:45:02	1.18
+++ excess.m	1997/02/19 03:05:12
@@ -43,7 +43,7 @@
 :- implementation.
 
 :- import_module hlds_goal, goal_util.
-:- import_module varset, list, bool, map, set, std_util.
+:- import_module require, varset, list, bool, map, set, std_util.
 
 %-----------------------------------------------------------------------------%
 
@@ -90,6 +90,12 @@
 		excess_assignments_in_conj(Goals0, [], ElimVars0, NonLocals,
 					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),
Index: follow_code.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/follow_code.m,v
retrieving revision 1.37
diff -u -r1.37 follow_code.m
--- follow_code.m	1997/01/27 07:45:03	1.37
+++ follow_code.m	1997/01/27 22:16:10
@@ -88,6 +88,9 @@
 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(Goals, SM), par_conj(Goals, SM),
+		_Flags, R, 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).
 
Index: follow_vars.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/follow_vars.m,v
retrieving revision 1.38
diff -u -r1.38 follow_vars.m
--- follow_vars.m	1997/01/27 07:45:04	1.38
+++ follow_vars.m	1997/01/27 22:16:11
@@ -95,6 +95,11 @@
 	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(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.
Index: frameopt.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/frameopt.m,v
retrieving revision 1.55
diff -u -r1.55 frameopt.m
--- frameopt.m	1997/01/15 01:10:17	1.55
+++ frameopt.m	1997/01/24 07:59:44
@@ -658,6 +658,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]).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -1237,6 +1240,32 @@
 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)) :-
+	(
+		assoc_list__search(LabelMap, Child0, Child1)
+	->
+		Child = Child1
+	;
+		Child = Child0
+	),
+	(
+		assoc_list__search(LabelMap, Parent0, Parent1)
+	->
+		Parent = Parent1
+	;
+		Parent = Parent0
+	).
+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)) :-
+	(
+		assoc_list__search(LabelMap, Label0, Label1)
+	->
+		Label = Label1
+	;
+		Label = Label0
+	).
 
 :- pred substitute_labels_list(list(label)::in, assoc_list(label)::in,
 	list(label)::out) is det.
Index: goal_util.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/goal_util.m,v
retrieving revision 1.33
diff -u -r1.33 goal_util.m
--- goal_util.m	1997/01/27 07:45:05	1.33
+++ goal_util.m	1997/01/27 22:16:11
@@ -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).
@@ -422,6 +427,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).
 
@@ -516,6 +524,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: higher_order.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/higher_order.m,v
retrieving revision 1.22
diff -u -r1.22 higher_order.m
--- higher_order.m	1997/01/27 07:45:07	1.22
+++ higher_order.m	1997/02/19 03:20:40
@@ -280,6 +280,10 @@
 	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(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).
Index: hlds_goal.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/hlds_goal.m,v
retrieving revision 1.28
diff -u -r1.28 hlds_goal.m
--- hlds_goal.m	1997/01/27 07:45:08	1.28
+++ hlds_goal.m	1997/01/27 22:39:16
@@ -158,7 +158,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
@@ -545,6 +553,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.
@@ -560,6 +575,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,
@@ -748,6 +771,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.
@@ -769,6 +803,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: hlds_out.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/hlds_out.m,v
retrieving revision 1.156
diff -u -r1.156 hlds_out.m
--- hlds_out.m	1997/02/16 06:41:28	1.156
+++ hlds_out.m	1997/02/16 21:10:49
@@ -899,6 +899,32 @@
 		io__write_string("\n")
 	).
 
+hlds_out__write_goal_2(par_conj(List, _), ModuleInfo, VarSet, AppendVarnums,
+		Indent, Follow, TypeQual) -->
+	( { List = [Goal | Goals] } ->
+		globals__io_lookup_string_option(verbose_dump_hlds, Verbose),
+		( { Verbose \= "" } ->
+			{ Indent1 is Indent + 1 },
+			hlds_out__write_indent(Indent),
+			io__write_string("( % parallel conjunction\n"),
+			hlds_out__write_conj(Goal, Goals, ModuleInfo, VarSet,
+				AppendVarnums, Indent1, "", Verbose, 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,
+				TypeQual)
+		)
+	;
+		hlds_out__write_indent(Indent),
+		io__write_string("true"),
+		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),
Index: inlining.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/inlining.m,v
retrieving revision 1.56
diff -u -r1.56 inlining.m
--- inlining.m	1997/01/27 07:45:10	1.56
+++ inlining.m	1997/01/27 22:16:14
@@ -336,10 +336,16 @@
 	inlining__inlining_in_conj(Goals0, Varset0, VarTypes0, TVarSet,
 		ModuleInfo, InlinedProcs, Thresh, Goals, Varset, VarTypes).
 
-inlining__inlining_in_goal_2(disj(Goals0, SM), Varset0, VarTypes0, TVarset,
+inlining__inlining_in_goal_2(par_conj(Goals0, SM), Varset0, VarTypes0, TVarSet,
+		ModuleInfo, InlinedProcs, Thresh,
+		par_conj(Goals, SM), Varset, VarTypes) :-
+	inlining__inlining_in_disj(Goals0, Varset0, VarTypes0, TVarSet,
+		ModuleInfo, InlinedProcs, Thresh, Goals, Varset, VarTypes).
+
+inlining__inlining_in_goal_2(disj(Goals0, SM), Varset0, VarTypes0, TVarSet,
 		ModuleInfo, InlinedProcs, Thresh,
 		disj(Goals, SM), Varset, VarTypes) :-
-	inlining__inlining_in_disj(Goals0, Varset0, VarTypes0, TVarset,
+	inlining__inlining_in_disj(Goals0, Varset0, VarTypes0, TVarSet,
 		ModuleInfo, InlinedProcs, Thresh, Goals, Varset, VarTypes).
 
 inlining__inlining_in_goal_2(switch(Var, Det, Cases0, SM),
Index: inst_match.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/inst_match.m,v
retrieving revision 1.27
diff -u -r1.27 inst_match.m
--- inst_match.m	1997/02/17 01:26:35	1.27
+++ inst_match.m	1997/02/17 23:35:42
@@ -875,6 +875,8 @@
 
 %-----------------------------------------------------------------------------%
 
+%-----------------------------------------------------------------------------%
+
 	% Abstractly unify two insts.
 
 abstractly_unify_inst(Live, InstA, InstB, UnifyIsReal, ModuleInfo0,
Index: instmap.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/instmap.m,v
retrieving revision 1.6
diff -u -r1.6 instmap.m
--- instmap.m	1997/02/17 01:26:38	1.6
+++ instmap.m	1997/02/17 23:35:44
@@ -179,6 +179,19 @@
 		mode_info, mode_info).
 :- mode instmap__merge(in, in, in, mode_info_di, mode_info_uo) is det.
 
+	% instmap_join(NonLocalVars, InstMaps):
+	%       Join the `InstMaps' resulting from different branches
+	%       of a parallel conjucntion and update the
+	%       instantiatedness of all the nonlocal variables,
+	%       checking that every branch binds an independent
+	%	set of variables, and that any bound variables for
+	%	which branch finds more specific binding information,
+	%	have bindings that are compatiable with any bindings
+	%	in other branches.
+	%
+:- pred instmap__join(set(var), list(instmap), mode_info, mode_info).
+:- mode instmap__join(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,6 +227,14 @@
 		instmap_delta, module_info, module_info).
 :- mode merge_instmap_delta(in, in, in, in, out, in, out) is det.
 
+	% join_instmap_delta(InitialInstMap, NonLocals,
+	%	InstMapDeltaA, InstMapDeltaB, ModuleInfo0, ModuleInfo)
+	% Merge the instmap_deltas of different branches of an ite, disj
+	% or switch.
+:- pred join_instmap_delta(instmap, set(var), instmap_delta, instmap_delta,
+		instmap_delta, module_info, module_info).
+:- mode join_instmap_delta(in, in, in, in, out, in, out) is det.
+
 %-----------------------------------------------------------------------------%
 
 	% `instmap_delta_apply_sub(InstmapDelta0, Must, Sub, InstmapDelta)'
@@ -242,9 +263,9 @@
 
 :- implementation.
 
-:- import_module mode_util, inst_match, prog_data, mode_errors, goal_util.
-:- import_module hlds_data.
-:- import_module list, std_util, bool, map, set, assoc_list, require.
+:- import_module mode_util, inst_match, prog_data.
+:- import_module mode_errors, goal_util, hlds_data.
+:- import_module std_util, bool, map, set, assoc_list, require, list.
 
 :- type instmap_delta	==	instmap.
 
@@ -566,6 +587,101 @@
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
+	% instmap__join(NonLocalVars, InstMaps):
+
+instmap__join(NonLocals, InstMapList, ModeInfo0, ModeInfo) :-
+	mode_info_get_instmap(ModeInfo0, InstMap0),
+	(
+		list__member(unreachable, InstMapList)
+	->
+		mode_info_set_instmap(unreachable, ModeInfo0, ModeInfo)
+	;
+		InstMap0 = reachable(InstMapping0)
+	->
+		mode_info_get_module_info(ModeInfo0, ModuleInfo0),
+		set__to_sorted_list(NonLocals, NonLocalsList),
+		instmap__join_2(NonLocalsList, InstMap0, InstMapList,
+			ModuleInfo0, InstMapping0, ModuleInfo,
+			InstMapping, ErrorList),
+		mode_info_set_module_info(ModeInfo0, ModuleInfo, ModeInfo1),
+		( 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__join_2(Vars, InitialInstMap, InstMaps, ModuleInfo,
+	%		ErrorList):
+	%       Let `ErrorList' be the list of variables in `Vars' for
+	%       there are two instmaps in `InstMaps' for which the inst
+	%       the variable is incompatible.
+:- pred instmap__join_2(list(var), instmap, list(instmap),
+		module_info, map(var, inst), module_info,
+		map(var, inst), merge_errors).
+:- mode instmap__join_2(in, in, in, in, in, out, out, out) is det.
+
+instmap__join_2([], _, _, ModuleInfo, InstMap, ModuleInfo, InstMap, []).
+instmap__join_2([Var|Vars], InitialInstMap, InstMapList, ModuleInfo0, InstMap0,
+			ModuleInfo, InstMap, ErrorList) :-
+	instmap__join_2(Vars, InitialInstMap, InstMapList, ModuleInfo0,
+			InstMap0, ModuleInfo1, InstMap1, ErrorList1),
+	instmap__lookup_var(InitialInstMap, Var, InitialVarInst),
+	instmap__join_var(InstMapList, Var, InitialVarInst, ModuleInfo1,
+			Insts, Inst, ModuleInfo, Error),
+	( Error = yes ->
+		ErrorList = [Var - Insts | ErrorList1],
+		map__set(InstMap1, Var, not_reached, InstMap)
+	;
+		ErrorList = ErrorList1,
+		map__set(InstMap1, Var, Inst, InstMap)
+	).
+
+	% instmap_merge_var(InstMaps, Var, InitialInstMap, ModuleInfo,
+	%		Insts, Error):
+	%       Let `Insts' be the list of the inst of `Var' in the
+	%       corresponding `InstMaps'.  Let `Error' be yes iff
+	%       there are two instmaps for which the inst of `Var'
+	%       is incompatible.
+
+:- pred instmap__join_var(list(instmap), var, (inst), module_info,
+				list(inst), inst, module_info, bool).
+:- mode instmap__join_var(in, in, in, in, out, out, out, out) is det.
+
+instmap__join_var([], _, InitialInst, ModuleInfo, [],
+		InitialInst, ModuleInfo, no).
+instmap__join_var([InstMap | InstMaps], Var, InitialVarInst, ModuleInfo0,
+		InstList, Inst, ModuleInfo, Error) :-
+	instmap__join_var(InstMaps, Var, InitialVarInst, ModuleInfo0,
+		InstList0, Inst0, ModuleInfo1, Error0),
+	instmap__lookup_var(InstMap, Var, VarInst),
+	InstList = [VarInst | InstList0],
+	(
+		abstractly_unify_inst(live, Inst0, VarInst, fake_unify,
+			ModuleInfo1, Inst1, _Det, ModuleInfo2)
+	->
+		Inst = Inst1,
+		ModuleInfo = ModuleInfo2,
+		Error = Error0
+	;
+		Error = yes,
+		ModuleInfo = ModuleInfo1,
+		Inst = not_reached
+	).
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
 	% Given two instmaps and a set of variables, compute an instmap delta
 	% which records the change in the instantiation state of those
 	% variables.
@@ -680,6 +796,65 @@
 		error("merge_instmapping_delta_2: unexpected mode error")
 	),
 	merge_instmapping_delta_2(Vars, InstMap, InstMappingA, InstMappingB,
+		InstMapping1, InstMapping, ModuleInfo1, ModuleInfo).
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+	% Given two instmap deltas, join them to produce a new instmap_delta.
+
+join_instmap_delta(_, _, unreachable, InstMapDelta, InstMapDelta) --> [].
+join_instmap_delta(_, _, reachable(InstMapping), unreachable,
+				reachable(InstMapping)) --> [].
+join_instmap_delta(InstMap, NonLocals, reachable(InstMappingA),
+		reachable(InstMappingB), reachable(InstMapping)) -->
+	join_instmapping_delta(InstMap, NonLocals, InstMappingA,
+		InstMappingB, InstMapping).
+
+:- pred join_instmapping_delta(instmap, set(var), instmapping, instmapping,
+		instmapping, module_info, module_info).
+:- mode join_instmapping_delta(in, in, in, in, out, in, out) is det.
+
+join_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) },
+	join_instmapping_delta_2(ListofVars, InstMap, InstMappingA,
+		InstMappingB, InstMapping0, InstMapping).
+
+:- pred join_instmapping_delta_2(list(var), instmap, instmapping, instmapping,
+			instmapping, instmapping, module_info, module_info).
+:- mode join_instmapping_delta_2(in, in, in, in, in, out, in, out) is det.
+
+join_instmapping_delta_2([], _, _, _, InstMapping, InstMapping,
+		ModInfo, ModInfo).
+join_instmapping_delta_2([Var | Vars], InstMap, InstMappingA, InstMappingB,
+			InstMapping0, InstMapping, ModuleInfo0, ModuleInfo) :-
+	( map__search(InstMappingA, Var, InstInA) ->
+		InstA = InstInA
+	;
+		instmap__lookup_var(InstMap, Var, InstA)
+	),
+	( map__search(InstMappingB, Var, InstInB) ->
+		InstB = InstInB
+	;
+		instmap__lookup_var(InstMap, Var, InstB)
+	),
+	(
+		abstractly_unify_inst(live, InstA, InstB, fake_unify,
+			ModuleInfo0, Inst, det, ModuleInfoPrime)
+	->
+		ModuleInfo1 = ModuleInfoPrime,
+		map__det_insert(InstMapping0, Var, Inst, InstMapping1)
+	;
+		error("join_instmapping_delta_2: unexpected mode error")
+	),
+	join_instmapping_delta_2(Vars, InstMap, InstMappingA, InstMappingB,
 		InstMapping1, InstMapping, ModuleInfo1, ModuleInfo).
 
 %-----------------------------------------------------------------------------%
Index: intermod.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/intermod.m,v
retrieving revision 1.15
diff -u -r1.15 intermod.m
--- intermod.m	1997/02/03 04:43:07	1.15
+++ intermod.m	1997/02/18 01:53:10
@@ -342,6 +342,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: lambda.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/lambda.m,v
retrieving revision 1.23
diff -u -r1.23 lambda.m
--- lambda.m	1997/01/27 07:45:12	1.23
+++ lambda.m	1997/01/27 22:16:16
@@ -160,6 +160,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: lco.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/lco.m,v
retrieving revision 1.3
diff -u -r1.3 lco.m
--- lco.m	1997/01/27 07:45:13	1.3
+++ lco.m	1997/01/27 22:16:17
@@ -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,9 @@
 lco_in_goal_2(conj(Goals0), ModuleInfo, conj(Goals)) :-
 	list__reverse(Goals0, RevGoals0),
 	lco_in_conj(RevGoals0, [], ModuleInfo, Goals).
+
+lco_in_goal_2(par_conj(_Goals0, SM), _ModuleInfo, par_conj(_Goals, SM)) :-
+	error("lco of parallel conjunction not implemented").
 
 lco_in_goal_2(disj(Goals0, SM), ModuleInfo, disj(Goals, SM)) :-
 	lco_in_disj(Goals0, ModuleInfo, Goals).
Index: live_vars.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/live_vars.m,v
retrieving revision 1.60
diff -u -r1.60 live_vars.m
--- live_vars.m	1997/01/27 07:45:14	1.60
+++ live_vars.m	1997/01/27 22:16:17
@@ -167,6 +167,13 @@
 	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) :-
+	set__insert(LiveSets0, Liveness0, LiveSets1),
+	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)
 		:-
Index: livemap.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/livemap.m,v
retrieving revision 1.22
diff -u -r1.22 livemap.m
--- livemap.m	1997/01/21 05:05:04	1.22
+++ livemap.m	1997/02/07 04:52:41
@@ -304,6 +304,29 @@
 		Livevals = Livevals0,
 		Instrs = Instrs0,
 		Ccode = yes
+	;
+		Uinstr0 = fork(Child, Parent, _),
+		livemap__insert_label_livevals([Child, Parent], Livemap0,
+				Livevals0, Livevals),
+		Livemap = Livemap0,
+		Instrs = Instrs0,
+		Ccode = Ccode0
+	;
+		Uinstr0 = join_and_terminate(Lval),
+		opt_util__lval_access_rvals(Lval, Rvals),
+		livemap__make_live_in_rvals(Rvals, Livevals0, Livevals),
+		Livemap = Livemap0,
+		Instrs = Instrs0,
+		Ccode = Ccode0
+	;
+		Uinstr0 = join_and_continue(Lval, Label),
+		livemap__insert_label_livevals([Label], Livemap0,
+				Livevals0, Livevals1),
+		opt_util__lval_access_rvals(Lval, Rvals),
+		livemap__make_live_in_rvals(Rvals, Livevals1, Livevals),
+		Livemap = Livemap0,
+		Instrs = Instrs0,
+		Ccode = Ccode0
 	).
 
 :- pred livemap__look_for_livevals(list(instruction), list(instruction),
Index: liveness.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/liveness.m,v
retrieving revision 1.68
diff -u -r1.68 liveness.m
--- liveness.m	1997/01/27 07:45:15	1.68
+++ liveness.m	1997/02/19 02:52:45
@@ -167,6 +167,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),
@@ -276,6 +283,24 @@
 	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, Goal1),
+	set__union(Union0, Liveness1, Union1),
+	detect_liveness_in_par_conj(Goals0, Liveness, NonLocals, LiveInfo,
+		Union1, Union, Goals),
+	set__intersect(Union, NonLocals, NonLocalUnion),
+	set__difference(NonLocalUnion, Liveness1, Residue),
+	add_liveness_after_goal(Goal1, Residue, Goal).
+
+%-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
 :- pred detect_deadness_in_goal(hlds__goal, set(var), live_info,
@@ -338,6 +363,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),
@@ -457,6 +490,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),
@@ -488,6 +539,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),
@@ -757,9 +813,22 @@
 			ResumeVars0, Cases, LivenessRest),
 		require(set__equal(LivenessFirst, LivenessRest),
 			"branches of switch disagree on liveness")
+		%true
 	;
 		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).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
Index: llds.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/llds.m,v
retrieving revision 1.199
diff -u -r1.199 llds.m
--- llds.m	1997/01/29 00:47:40	1.199
+++ llds.m	1997/02/18 01:26:02
@@ -197,7 +197,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
@@ -210,6 +210,26 @@
 %			% 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,
+			% then terminate it. The synchronisation term is
+			% pointed to by the given lval.
+
+	;	join_and_continue(lval, label)
+			% Signal that this thread of execution has finished,
+			% then branch to the given label. The synchronisation
+			% term is pointed to by the given lval.
+	.
 
 	% pragma_c_decl holds the information needed for a variable
 	% declaration for a pragma_c instruction.
Index: llds_common.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/llds_common.m,v
retrieving revision 1.6
diff -u -r1.6 llds_common.m
--- llds_common.m	1997/01/21 05:05:08	1.6
+++ llds_common.m	1997/01/24 07:38:14
@@ -245,6 +245,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: llds_out.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/llds_out.m,v
retrieving revision 1.37
diff -u -r1.37 llds_out.m
--- llds_out.m	1997/02/17 03:47:32	1.37
+++ llds_out.m	1997/02/17 23:35:50
@@ -660,12 +660,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)
@@ -789,6 +795,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).
 
 %-----------------------------------------------------------------------------%
 
@@ -1069,6 +1083,27 @@
 %	;
 %		[]
 %	).
+
+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").
 
 	% Output the local variable declarations at the top of the 
 	% pragma_c_code code.
Index: make_hlds.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/make_hlds.m,v
retrieving revision 1.220
diff -u -r1.220 make_hlds.m
--- make_hlds.m	1997/02/18 05:17:46	1.220
+++ make_hlds.m	1997/02/18 21:22:31
@@ -1868,6 +1868,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).
@@ -2419,6 +2423,12 @@
 	{ goal_info_init(GoalInfo) },
 	{ conj_list_to_goal(L, GoalInfo, Goal) }.
 
+transform_goal_2(par(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),
@@ -3011,6 +3021,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 = par(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: mercury_to_c.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mercury_to_c.m,v
retrieving revision 1.21
diff -u -r1.21 mercury_to_c.m
--- mercury_to_c.m	1997/01/27 07:45:20	1.21
+++ mercury_to_c.m	1997/01/27 22:16:21
@@ -602,6 +602,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("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: mercury_to_goedel.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mercury_to_goedel.m,v
retrieving revision 1.56
diff -u -r1.56 mercury_to_goedel.m
--- mercury_to_goedel.m	1996/11/04 06:26:06	1.56
+++ mercury_to_goedel.m	1997/01/15 04:49:31
@@ -587,6 +587,9 @@
 	goedel_output_newline(Indent),
 	goedel_output_goal(B, VarSet, Indent).
 
+goedel_output_goal_2(par(_A,_B), _VarSet, _Indent) -->
+	{ error("goedel of parallel conjunction not implemented") }.
+
 goedel_output_goal_2((A;B), VarSet, Indent) -->
 	io__write_string("("),
 	{ Indent1 is Indent + 1 },
Index: mercury_to_mercury.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mercury_to_mercury.m,v
retrieving revision 1.94
diff -u -r1.94 mercury_to_mercury.m
--- mercury_to_mercury.m	1997/02/17 01:26:44	1.94
+++ mercury_to_mercury.m	1997/02/17 23:35:59
@@ -1097,6 +1097,12 @@
 	mercury_output_newline(Indent),
 	mercury_output_goal(B, VarSet, Indent).
 
+mercury_output_goal_2(par(A,B), VarSet, Indent) -->
+	mercury_output_goal(A, VarSet, Indent),
+	io__write_string("&"),
+	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 },
Index: middle_rec.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/middle_rec.m,v
retrieving revision 1.60
diff -u -r1.60 middle_rec.m
--- middle_rec.m	1997/01/21 05:05:12	1.60
+++ middle_rec.m	1997/02/07 04:53:34
@@ -411,6 +411,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: mode_errors.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mode_errors.m,v
retrieving revision 1.42
diff -u -r1.42 mode_errors.m
--- mode_errors.m	1997/02/17 01:26:45	1.42
+++ mode_errors.m	1997/02/17 23:36:03
@@ -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
+			% overlapping 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
@@ -156,6 +159,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,
@@ -297,6 +302,17 @@
 	io__write_string("  mode mismatch in "),
 	write_merge_context(MergeContext),
 	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("  incompatible bindings in parallel conjunction.\n"),
 	write_merge_error_list(ErrorList, ModeInfo).
 
 :- pred write_merge_error_list(merge_errors, mode_info, io__state, io__state).
Index: mode_util.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mode_util.m,v
retrieving revision 1.81
diff -u -r1.81 mode_util.m
--- mode_util.m	1997/02/18 10:00:40	1.81
+++ mode_util.m	1997/02/18 21:22:32
@@ -1499,6 +1499,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) },
@@ -1586,6 +1592,25 @@
 	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),
+	join_instmap_delta(InstMap, NonLocals, InstMapDelta0,
 		InstMapDelta1, InstMapDelta).
 
 %-----------------------------------------------------------------------------%
Index: modes.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/modes.m,v
retrieving revision 1.194
diff -u -r1.194 modes.m
--- modes.m	1997/02/17 01:26:53	1.194
+++ modes.m	1997/02/17 23:36:08
@@ -697,6 +697,18 @@
 	),
 	mode_checkpoint(exit, "conj").
 
+	% To modecheck a parallel conjunction, we modecheck each
+	% conjunct independently (just like for disjunctions), and
+	% make sure that each conjunct binds an independent set of
+	% variables.
+modecheck_goal_expr(par_conj(List0, SM), GoalInfo0, par_conj(List, SM)) -->
+	mode_checkpoint(enter, "par_conj"),
+	{ goal_info_get_nonlocals(GoalInfo0, NonLocals) },
+	{ set__to_sorted_list(NonLocals, NonLocalList) },
+	modecheck_par_conj_list(List0, List, NonLocalList, InstMapList),
+	instmap__join(NonLocals, InstMapList),
+	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
@@ -1073,6 +1085,42 @@
 	{ fixup_switch_var(Var, InstMap0, InstMap, Goal1, Goal) },
 	mode_info_set_instmap(InstMap0),
 	modecheck_case_list(Cases0, Var, Cases, InstMaps).
+
+%-----------------------------------------------------------------------------%
+
+:- pred modecheck_par_conj_list(list(hlds__goal), list(hlds__goal),
+		list(var), list(instmap), 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|InstMaps]) -->
+	mode_info_dcg_get_instmap(InstMap0),
+	modecheck_goal(Goal0, Goal),
+	mode_info_dcg_get_instmap(InstMap),
+	mode_info_set_instmap(InstMap0),
+	=(ModeInfo),
+	{ mode_info_get_module_info(ModeInfo, ModuleInfo) },
+	{ find_bound_vars(NonLocals, InstMap0, InstMap, ModuleInfo, LockVars) },
+	mode_info_lock_vars(LockVars),
+	modecheck_par_conj_list(Goals0, Goals, NonLocals, InstMaps),
+	mode_info_unlock_vars(LockVars).
+
+:- pred find_bound_vars(list(var), instmap, instmap, module_info, set(var)).
+:- mode find_bound_vars(in, in, in, in, out) is det.
+
+find_bound_vars([], _, _, _, Empty) :-
+	set__init(Empty).
+find_bound_vars([Var|Vars], Initial, Final, ModuleInfo, LockVars) :-
+	find_bound_vars(Vars, Initial, Final, ModuleInfo, LockVars0),
+	instmap__lookup_var(Initial, Var, InitialInst),
+	instmap__lookup_var(Final, Var, FinalInst),
+	( \+ inst_matches_binding(InitialInst, FinalInst, ModuleInfo) ->
+		set__insert(LockVars0, Var, LockVars)
+	;
+		LockVars = LockVars0
+	).
 
 %-----------------------------------------------------------------------------%
 
Index: opt_debug.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/opt_debug.m,v
retrieving revision 1.65
diff -u -r1.65 opt_debug.m
--- opt_debug.m	1997/01/29 00:48:08	1.65
+++ opt_debug.m	1997/02/07 04:54:25
@@ -862,6 +862,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: opt_util.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/opt_util.m,v
retrieving revision 1.79
diff -u -r1.79 opt_util.m
--- opt_util.m	1997/01/29 00:48:02	1.79
+++ opt_util.m	1997/02/07 04:55:58
@@ -875,6 +875,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([], []).
@@ -972,6 +991,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).
@@ -995,6 +1017,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.
@@ -1034,6 +1059,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
 
@@ -1090,6 +1118,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.
@@ -1120,6 +1151,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)).
@@ -1210,6 +1244,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: polymorphism.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/polymorphism.m,v
retrieving revision 1.96
diff -u -r1.96 polymorphism.m
--- polymorphism.m	1997/02/18 02:50:55	1.96
+++ polymorphism.m	1997/02/18 21:22:33
@@ -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: prog_data.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_data.m,v
retrieving revision 1.16
diff -u -r1.16 prog_data.m
--- prog_data.m	1997/01/27 07:45:29	1.16
+++ prog_data.m	1997/01/27 22:16:27
@@ -155,6 +155,7 @@
 :- type goal_expr	--->	(goal,goal)
 			;	true	
 					% could use conj(goals) instead 
+			;	par(goal, goal)	% &/2 ie parallel-conj
 			;	{goal;goal}	% {...} quotes ';'/2.
 			;	fail	
 					% could use disj(goals) instead
Index: prog_io_dcg.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_io_dcg.m,v
retrieving revision 1.1
diff -u -r1.1 prog_io_dcg.m
--- prog_io_dcg.m	1997/01/27 07:45:31	1.1
+++ prog_io_dcg.m	1997/01/27 23:03:06
@@ -200,6 +200,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,
+		par(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: prog_io_goal.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_io_goal.m,v
retrieving revision 1.1
diff -u -r1.1 prog_io_goal.m
--- prog_io_goal.m	1997/01/27 07:45:32	1.1
+++ prog_io_goal.m	1997/01/27 23:02:28
@@ -159,6 +159,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, par(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: prog_util.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/prog_util.m,v
retrieving revision 1.33
diff -u -r1.33 prog_util.m
--- prog_util.m	1996/08/03 12:06:23	1.33
+++ prog_util.m	1997/01/08 03:58:13
@@ -139,6 +139,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(par(GoalA0, GoalB0), OldVar, NewVar,
+		par(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: quantification.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/quantification.m,v
retrieving revision 1.46
diff -u -r1.46 quantification.m
--- quantification.m	1997/01/27 07:45:33	1.46
+++ quantification.m	1997/01/27 22:16:30
@@ -208,6 +208,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).
 
@@ -548,6 +551,9 @@
 	set__insert_list(Set0, ArgVars, Set).
 
 goal_vars_2(conj(Goals), Set0, LambdaSet0, Set, LambdaSet) :-
+	goal_list_vars_2(Goals, Set0, LambdaSet0, Set, LambdaSet).
+
+goal_vars_2(par_conj(Goals, _SM), Set0, LambdaSet0, Set, LambdaSet) :-
 	goal_list_vars_2(Goals, Set0, LambdaSet0, Set, LambdaSet).
 
 goal_vars_2(disj(Goals, _), Set0, LambdaSet0, Set, LambdaSet) :-
Index: saved_vars.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/saved_vars.m,v
retrieving revision 1.4
diff -u -r1.4 saved_vars.m
--- saved_vars.m	1997/01/27 07:45:34	1.4
+++ saved_vars.m	1997/01/27 22:16:30
@@ -37,7 +37,7 @@
 :- implementation.
 
 :- import_module hlds_goal, hlds_out, goal_util, quantification, passes_aux.
-:- import_module bool, list, set, map, std_util, varset.
+:- import_module require, bool, list, set, map, std_util, varset.
 
 %-----------------------------------------------------------------------------%
 
@@ -79,6 +79,10 @@
 			Goals, SlotInfo),
 		conj_list_to_goal(Goals, GoalInfo0, Goal)
 	;
+		GoalExpr0 = par_conj(Goals0, SM),
+		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
@@ -282,6 +286,11 @@
 			list__append(Conj, Goals0, Goals1),
 			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),
Index: simplify.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/simplify.m,v
retrieving revision 1.25
diff -u -r1.25 simplify.m
--- simplify.m	1997/02/17 01:27:03	1.25
+++ simplify.m	1997/02/17 23:36:19
@@ -248,6 +248,10 @@
 		)
 	).
 
+simplify__goal_2(par_conj(Goals0, SM), GoalInfo, par_conj(Goals, SM),
+		GoalInfo, Info, Info) :-
+	simplify__goal_list(Goals0, Info, Goals).
+
 simplify__goal_2(disj(Disjuncts0, SM), GoalInfo,
 		Goal, GoalInfo, Info0, Info) :-
 	( Disjuncts0 = [] ->
@@ -673,6 +677,16 @@
 	;
 		RevGoals = [Goal | RevGoals0]
 	).
+
+%-----------------------------------------------------------------------------%
+
+:- pred simplify__goal_list(list(hlds__goal)::in, simplify_info::in,
+		list(hlds__goal)::out) is det.
+
+simplify__goal_list([], _, []).
+simplify__goal_list([Goal0|Goals0], Info, [Goal|Goals]) :-
+	simplify__goal(Goal0, Goal, Info, _),
+	simplify__goal_list(Goals0, Info, Goals).
 
 %-----------------------------------------------------------------------------%
 
Index: store_alloc.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/store_alloc.m,v
retrieving revision 1.48
diff -u -r1.48 store_alloc.m
--- store_alloc.m	1997/01/27 07:45:36	1.48
+++ store_alloc.m	1997/01/27 22:40:22
@@ -128,6 +128,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_disj(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,
Index: stratify.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/stratify.m,v
retrieving revision 1.4
diff -u -r1.4 stratify.m
--- stratify.m	1997/01/27 07:45:36	1.4
+++ stratify.m	1997/01/27 22:16:32
@@ -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,
Index: switch_detection.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/switch_detection.m,v
retrieving revision 1.64
diff -u -r1.64 switch_detection.m
--- switch_detection.m	1997/01/27 07:45:37	1.64
+++ switch_detection.m	1997/01/27 22:16:33
@@ -141,6 +141,12 @@
 		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).
@@ -289,6 +295,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: typecheck.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/typecheck.m,v
retrieving revision 1.186
diff -u -r1.186 typecheck.m
--- typecheck.m	1997/02/17 01:27:06	1.186
+++ typecheck.m	1997/02/17 23:42:49
@@ -576,6 +576,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: unique_modes.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/unique_modes.m,v
retrieving revision 1.31
diff -u -r1.31 unique_modes.m
--- unique_modes.m	1997/02/17 01:27:10	1.31
+++ unique_modes.m	1997/02/17 23:36:25
@@ -386,6 +386,14 @@
 	),
 	mode_checkpoint(exit, "conj").
 
+	% XXX
+unique_modes__check_goal_2(par_conj(List0, SM), _GoalInfo0,
+		par_conj(List, SM)) -->
+	mode_checkpoint(enter, "par_conj"),
+	mode_info_add_goals_live_vars(List0),
+	unique_modes__check_par_conj(List0, List),
+	mode_checkpoint(exit, "par_conj").
+
 unique_modes__check_goal_2(disj(List0, SM), GoalInfo0, disj(List, SM)) -->
 	mode_checkpoint(enter, "disj"),
 	( { List0 = [] } ->
@@ -647,6 +655,23 @@
 	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),
+		mode_info, mode_info).
+:- mode unique_modes__check_par_conj(in, out,
+		mode_info_di, mode_info_uo) is det.
+
+	% Just process each conjunct in turn.
+	% Note that we don't do any reordering of conjuncts here.
+
+unique_modes__check_par_conj([], []) --> [].
+unique_modes__check_par_conj([Goal0 | Goals0], [Goal | Goals]) -->
+	{ unique_modes__goal_get_nonlocals(Goal0, NonLocals) },
+	mode_info_remove_live_vars(NonLocals),
+	unique_modes__check_goal(Goal0, Goal),
+	unique_modes__check_par_conj(Goals0, Goals).
 
 %-----------------------------------------------------------------------------%
 
Index: unused_args.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/unused_args.m,v
retrieving revision 1.24
diff -u -r1.24 unused_args.m
--- unused_args.m	1997/01/27 07:45:40	1.24
+++ unused_args.m	1997/02/19 02:55:03
@@ -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).
@@ -1123,6 +1127,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: value_number.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/value_number.m,v
retrieving revision 1.80
diff -u -r1.80 value_number.m
--- value_number.m	1997/01/15 01:10:45	1.80
+++ value_number.m	1997/01/24 07:43:14
@@ -1069,6 +1069,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: vn_block.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/vn_block.m,v
retrieving revision 1.44
diff -u -r1.44 vn_block.m
--- vn_block.m	1997/01/15 01:10:47	1.44
+++ vn_block.m	1997/01/24 07:43:32
@@ -325,6 +325,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").
+vn_block__handle_instr(join_and_continue(_, _),
+		_Livemap, _Params, VnTables, VnTables, Liveset, Liveset,
+		SeenIncr, SeenIncr, Tuple, Tuple) :-
+	error("value numbering not supported for wait").
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -832,6 +844,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: vn_cost.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/vn_cost.m,v
retrieving revision 1.22
diff -u -r1.22 vn_cost.m
--- vn_cost.m	1997/01/21 05:05:21	1.22
+++ vn_cost.m	1997/01/24 07:43:40
@@ -167,6 +167,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 found in vn_block_cost")
+	;
+		Uinstr = join_and_continue(_, _),
+		error("wait found in vn_block_cost")
 	).
 
 vn_cost__lval_cost(Lval, Params, Cost) :-
Index: vn_filter.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/vn_filter.m,v
retrieving revision 1.8
diff -u -r1.8 vn_filter.m
--- vn_filter.m	1997/01/21 05:05:23	1.8
+++ vn_filter.m	1997/01/24 08:00:36
@@ -125,7 +125,13 @@
 vn_filter__user_instr(incr_sp(_, _), no).
 vn_filter__user_instr(decr_sp(_), no).
 vn_filter__user_instr(pragma_c(_, _, _, _, _), _):-
-	error("inappropriate instruction in vn__filter").
+	error("pragma_c instruction in vn__filter").
+vn_filter__user_instr(fork(_, _, _), _):-
+	error("fork instruction in vn__filter").
+vn_filter__user_instr(join_and_terminate(_), _):-
+	error("join instruction in vn__filter").
+vn_filter__user_instr(join_and_continue(_, _), _):-
+	error("wait instruction in vn__filter").
 
 :- pred vn_filter__replace_in_user_instr(instr, lval, rval, instr).
 :- mode vn_filter__replace_in_user_instr(in, in, in, out) is det.
@@ -178,6 +184,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 instruction in vn__filter").
+vn_filter__replace_in_user_instr(join_and_continue(_, _), _, _, _):-
+	error("wait instruction in vn__filter").
 
 :- pred vn_filter__defining_instr(instr, maybe(lval)).
 :- mode vn_filter__defining_instr(in, out) is det.
@@ -206,6 +218,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 instruction in vn__filter").
+vn_filter__defining_instr(join_and_continue(_, _), _):-
+	error("wait instruction in vn__filter").
 
 :- pred vn_filter__replace_in_defining_instr(instr, lval, rval, instr).
 :- mode vn_filter__replace_in_defining_instr(in, in, in, out) is det.
@@ -255,7 +273,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 instruction in vn_filter__replace_in_defining_instr").
+vn_filter__replace_in_defining_instr(join_and_continue(_, _), _, _, _):-
+	error("wait instruction in vn_filter__replace_in_defining_instr").
 
 :- pred vn_filter__replace_in_lval(lval, lval, rval, lval).
 :- mode vn_filter__replace_in_lval(in, in, in, out) is det.
cvs diff: Diffing notes
-- 
Thomas Conway               				      conway at cs.mu.oz.au
AD DEUM ET VINUM	  			      Every sword has two edges.



More information about the developers mailing list