for review: new method of handling failures, part 5 of 6

Zoltan Somogyi zs at cs.mu.OZ.AU
Thu Jul 2 16:24:16 AEST 1998


Index: compiler/code_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/code_util.m,v
retrieving revision 1.98
diff -u -r1.98 code_util.m
--- code_util.m	1998/06/09 02:12:10	1.98
+++ code_util.m	1998/06/09 05:48:45
@@ -18,7 +18,7 @@
 :- interface.
 
 :- import_module hlds_module, hlds_pred, hlds_goal, hlds_data, prog_data, llds.
-:- import_module list, std_util, term.
+:- import_module list, assoc_list, set, std_util, term.
 
 	% Create a code address which holds the address of the specified
 	% procedure.
@@ -147,6 +147,11 @@
 	int, int).
 :- mode code_util__count_recursive_calls(in, in, in, out, out) is det.
 
+	% Return the set of locations occupied by output arguments.
+
+:- pred code_util__output_args(assoc_list(var, arg_info), set(lval)).
+:- mode code_util__output_args(in, out) is det.
+
 	% These predicates return the set of lvals referenced in an rval
 	% and an lval respectively. Lvals referenced indirectly through
 	% lvals of the form var(_) are not counted.
@@ -160,8 +165,10 @@
 %---------------------------------------------------------------------------%
 
 :- implementation.
+
 :- import_module prog_data, type_util, special_pred.
-:- import_module bool, char, int, string, map, term, varset, require, std_util.
+:- import_module bool, char, int, string, set, map, term, varset.
+:- import_module require, std_util, assoc_list.
 
 %---------------------------------------------------------------------------%
 
@@ -353,7 +360,8 @@
 	% --- not yet:
 	% FullyQualifiedModule = qualified(unqualified("std"), ModuleName),
 	FullyQualifiedModule = unqualified(ModuleName),
-	code_util__translate_builtin_2(ModuleName, PredName, ProcId, Args, _, _).
+	code_util__translate_builtin_2(ModuleName, PredName, ProcId, Args,
+		_, _).
 
 code_util__translate_builtin(FullyQualifiedModule, PredName, ProcId, Args,
 		BinOp, AsgOp) :-
@@ -881,6 +889,19 @@
 		int__max(Max0, Max1, Max)
 	).
 
+code_util__output_args([], LiveVals) :-
+	set__init(LiveVals).
+code_util__output_args([_V - arg_info(Loc, Mode) | Args], Vs) :-
+	code_util__output_args(Args, Vs0),
+	(
+		Mode = top_out
+	->
+		code_util__arg_loc_to_register(Loc, Reg),
+		set__insert(Vs0, Reg, Vs)
+	;
+		Vs = Vs0
+	).
+
 %-----------------------------------------------------------------------------%
 
 code_util__lvals_in_rval(lval(Lval), [Lval | Lvals]) :-
@@ -906,6 +927,8 @@
 code_util__lvals_in_lval(maxfr, []).
 code_util__lvals_in_lval(curfr, []).
 code_util__lvals_in_lval(succip(Rval), Lvals) :-
+	code_util__lvals_in_rval(Rval, Lvals).
+code_util__lvals_in_lval(redofr(Rval), Lvals) :-
 	code_util__lvals_in_rval(Rval, Lvals).
 code_util__lvals_in_lval(redoip(Rval), Lvals) :-
 	code_util__lvals_in_rval(Rval, Lvals).
Index: compiler/dense_switch.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/dense_switch.m,v
retrieving revision 1.33
diff -u -r1.33 dense_switch.m
--- dense_switch.m	1998/04/08 11:31:31	1.33
+++ dense_switch.m	1998/05/17 03:40:20
@@ -34,9 +34,10 @@
 	% Generate code for a switch using a dense jump table.
 
 :- pred dense_switch__generate(cases_list, int, int, var, code_model,
-	can_fail, store_map, label, code_tree, code_info, code_info).
+	can_fail, store_map, label, branch_end, branch_end, code_tree,
+	code_info, code_info).
 :- mode dense_switch__generate(in, in, in, in, in, in, in, in,
-	out, in, out) is det.
+	in, out, out, in, out) is det.
 
 	% also used by lookup_switch
 :- pred dense_switch__calc_density(int, int, int).
@@ -138,7 +139,7 @@
 %---------------------------------------------------------------------------%
 
 dense_switch__generate(Cases, StartVal, EndVal, Var, CodeModel, CanFail,
-		StoreMap, EndLabel, Code) -->
+		StoreMap, EndLabel, MaybeEnd0, MaybeEnd, Code) -->
 		% Evaluate the variable which we are going to be switching on
 	code_info__produce_variable(Var, VarCode, Rval),
 		% If the case values start at some number other than 0,
@@ -163,20 +164,14 @@
 	),
 		% Now generate the jump table and the cases
 	dense_switch__generate_cases(Cases, StartVal, EndVal, CodeModel,
-			StoreMap, EndLabel, Labels, CasesCode, no,
-			MaybeFinalCodeInfo),
+			StoreMap, EndLabel, MaybeEnd0, MaybeEnd,
+			Labels, CasesCode),
+		% XXX
 		% We keep track of the code_info at the end of one of
 		% the non-fail cases.  We have to do this because 
 		% generating a `fail' slot last would yield the
 		% wrong liveness and would not unset the failure cont
 		% for a nondet switch.
-	(
-		{ MaybeFinalCodeInfo = yes(FinalCodeInfo) }
-	->
-		code_info__slap_code_info(FinalCodeInfo)
-	;
-		{ error("dense_switch__generate: no final code_info") }
-	),
 	{ DoJump = node([
 		computed_goto(Index, Labels)
 			- "switch (using dense jump table)"
@@ -185,51 +180,59 @@
 	{ Code = tree(VarCode, tree(RangeCheck, tree(DoJump, CasesCode))) }.
 
 :- pred dense_switch__generate_cases(cases_list, int, int,
-	code_model, store_map, label, list(label), code_tree, 
-	maybe(code_info), maybe(code_info), code_info, code_info).
-:- mode dense_switch__generate_cases(in, in, in, in, in, in, out, out,
-	in, out, in, out) is det.
+	code_model, store_map, label, branch_end, branch_end,
+	list(label), code_tree, code_info, code_info).
+:- mode dense_switch__generate_cases(in, in, in, in, in, in, in, out,
+	out, out, in, out) is det.
 
 dense_switch__generate_cases(Cases0, NextVal, EndVal, CodeModel, StoreMap,
-		EndLabel, Labels, Code, MaybeCodeInfo0, MaybeCodeInfo) -->
+		EndLabel, MaybeEnd0, MaybeEnd, Labels, Code) -->
 	(
 		{ NextVal > EndVal }
 	->
-		{ Code = node([ label(EndLabel) - "End of dense switch" ]) },
+		{ MaybeEnd = MaybeEnd0 },
 		{ Labels = [] },
-		{ MaybeCodeInfo = MaybeCodeInfo0 }
+		{ Code = node([
+			label(EndLabel)
+				- "End of dense switch"
+		]) }
 	;
 		code_info__get_next_label(ThisLabel),
 		dense_switch__generate_case(Cases0, NextVal, CodeModel,
-			StoreMap, Cases1, ThisCode, Comment, MaybeNewCodeInfo),
-		{ ThisCaseCode = tree(
-			node([ label(ThisLabel) - Comment ]),
-			tree(	ThisCode,
-				node([ goto(label(EndLabel))
-					- "branch to end of dense switch" ])
-			)
-		) },
-		{ dense_switch__merge_maybe_code_info(MaybeCodeInfo0,
-				MaybeNewCodeInfo, MaybeCodeInfo1) },
+			StoreMap, Cases1, MaybeEnd0, MaybeEnd1,
+			ThisCode, Comment),
+		{ LabelCode = node([
+			label(ThisLabel)
+				- Comment
+		]) },
+		{ JumpCode = node([
+			goto(label(EndLabel))
+				- "branch to end of dense switch"
+		]) },
 			% generate the rest of the cases.
 		{ NextVal1 is NextVal + 1 },
 		dense_switch__generate_cases(Cases1, NextVal1, EndVal,
-			CodeModel, StoreMap, EndLabel, Labels1, OtherCasesCode,
-			MaybeCodeInfo1, MaybeCodeInfo),
+			CodeModel, StoreMap, EndLabel, MaybeEnd1, MaybeEnd,
+			Labels1, OtherCasesCode),
 		{ Labels = [ThisLabel | Labels1] },
-		{ Code = tree(ThisCaseCode, OtherCasesCode) }
+		{ Code =
+			tree(LabelCode,
+			tree(ThisCode,
+			tree(JumpCode,
+			     OtherCasesCode)))
+		}
 	).
 
 %---------------------------------------------------------------------------%
 
 :- pred dense_switch__generate_case(cases_list, int, code_model, store_map,
-		cases_list, code_tree, string, maybe(code_info),
+		cases_list, branch_end, branch_end, code_tree, string,
 		code_info, code_info).
-:- mode dense_switch__generate_case(in, in, in, in, out, out, out, out,
+:- mode dense_switch__generate_case(in, in, in, in, out, in, out, out, out,
 		in, out) is det.
 
 dense_switch__generate_case(Cases0, NextVal, CodeModel, StoreMap, Cases,
-		Code, Comment, MaybeCodeInfo) -->
+		MaybeEnd0, MaybeEnd, Code, Comment) -->
 	(
 		{ Cases0 = [Case | Cases1] },
 		{ Case = case(_, int_constant(NextVal), _, Goal) }
@@ -237,38 +240,23 @@
 		{ Comment = "case of dense switch" },
 		% We need to save the expression cache, etc.,
 		% and restore them when we've finished.
-		code_info__grab_code_info(CodeInfoAtStart),
+		code_info__remember_position(BranchStart),
 		trace__maybe_generate_internal_event_code(Goal, TraceCode),
 		code_gen__generate_goal(CodeModel, Goal, GoalCode),
-		code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
+		code_info__generate_branch_end(StoreMap, MaybeEnd0, MaybeEnd,
+			SaveCode),
 		{ Code =
 			tree(TraceCode,
 			tree(GoalCode,
 			     SaveCode))
 		},
-		code_info__grab_code_info(CodeInfoAtEnd),
-		code_info__slap_code_info(CodeInfoAtStart),
-		{ Cases = Cases1 },
-		{ MaybeCodeInfo = yes(CodeInfoAtEnd) }
+		code_info__reset_to_position(BranchStart),
+		{ Cases = Cases1 }
 	;
-		% This case didn't occur in the original case list - just
-		% generate a `fail' for it.
+		% This case didn't occur in the original case list
+		% - just generate a `fail' for it.
 		{ Comment = "compiler-introduced `fail' case of dense switch" },
 		code_info__generate_failure(Code),
-		{ Cases = Cases0 },
-		{ MaybeCodeInfo = no }
-	).
-
-:- pred dense_switch__merge_maybe_code_info(maybe(code_info),
-				maybe(code_info), maybe(code_info)).
-:- mode dense_switch__merge_maybe_code_info(in, in, out) is det.
-
-dense_switch__merge_maybe_code_info(CodeInfo0, CodeInfo1, CodeInfo) :-
-	(
-		CodeInfo0 = no
-	->
-		CodeInfo = CodeInfo1
-	;
-		CodeInfo = CodeInfo0
+		{ MaybeEnd = MaybeEnd0 },
+		{ Cases = Cases0 }
 	).
-
Index: compiler/disj_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/disj_gen.m,v
retrieving revision 1.64
diff -u -r1.64 disj_gen.m
--- disj_gen.m	1998/06/02 05:31:36	1.64
+++ disj_gen.m	1998/06/23 02:21:40
@@ -10,9 +10,6 @@
 %
 % The predicates of this module generate code for disjunctions.
 %
-% The handling of model_det and model_semi disjunctions is almost identical.
-% The handling of model_non disjunctions is also quite similar.
-%
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
 
@@ -23,97 +20,143 @@
 :- import_module hlds_goal, llds, code_info.
 :- import_module list.
 
-:- pred disj_gen__generate_det_disj(list(hlds_goal), store_map,
-					code_tree, code_info, code_info).
-:- mode disj_gen__generate_det_disj(in, in, out, in, out) is det.
-
-:- pred disj_gen__generate_semi_disj(list(hlds_goal), store_map,
-					code_tree, code_info, code_info).
-:- mode disj_gen__generate_semi_disj(in, in, out, in, out) is det.
-
-:- pred disj_gen__generate_non_disj(list(hlds_goal), store_map,
-					code_tree, code_info, code_info).
-:- mode disj_gen__generate_non_disj(in, in, out, in, out) is det.
+:- pred disj_gen__generate_disj(code_model::in, list(hlds_goal)::in,
+	store_map::in, code_tree::out, code_info::in, code_info::out) is det.
 
 %---------------------------------------------------------------------------%
 
 :- implementation.
 
 :- import_module hlds_data, code_gen, code_util, trace, options, globals.
-:- import_module bool, set, tree, map, std_util, require.
+:- import_module bool, set, tree, map, std_util, term, require.
 
-%---------------------------------------------------------------------------%
-
-disj_gen__generate_det_disj(Goals, StoreMap, Code) -->
-	disj_gen__generate_pruned_disj(Goals, StoreMap, Code).
-
-disj_gen__generate_semi_disj(Goals, StoreMap, Code) -->
-	( { Goals = [] } ->
-		code_info__generate_failure(Code)
+disj_gen__generate_disj(CodeModel, Goals, StoreMap, Code) -->
+	(
+		{ Goals = [] },
+		( { CodeModel = model_semi } ->
+			code_info__generate_failure(Code)
+		;
+			{ error("empty disjunction") }
+		)
 	;
-		disj_gen__generate_pruned_disj(Goals, StoreMap, Code)
+		{ Goals = [Goal | _] },
+		{ Goal = _ - GoalInfo },
+		{ goal_info_get_resume_point(GoalInfo, Resume) },
+		{ Resume = resume_point(ResumeVarsPrime, _) ->
+			ResumeVars = ResumeVarsPrime
+		;
+			set__init(ResumeVars)
+		},
+		disj_gen__generate_real_disj(CodeModel, ResumeVars,
+			Goals, StoreMap, Code)
 	).
 
 %---------------------------------------------------------------------------%
 
-:- pred disj_gen__generate_pruned_disj(list(hlds_goal), store_map,
-	code_tree, code_info, code_info).
-:- mode disj_gen__generate_pruned_disj(in, in, out, in, out) is det.
+:- pred disj_gen__generate_real_disj(code_model::in, set(var)::in,
+	list(hlds_goal)::in, store_map::in, code_tree::out,
+	code_info::in, code_info::out) is det.
+
+disj_gen__generate_real_disj(CodeModel, ResumeVars, Goals, StoreMap, Code) -->
+		% Make sure that the variables whose values will be needed
+		% on backtracking to any disjunct are materialized into
+		% registers or stack slots. Their locations are recorded
+		% in ResumeMap.
+	code_info__produce_vars(ResumeVars, ResumeMap, FlushCode),
 
-disj_gen__generate_pruned_disj(Goals, StoreMap, Code) -->
 		% If we are using a trail, save the current trail state
 		% before the first disjunct.
+		% XXX We should use a scheme such as the one we use for heap
+		% recovery for semi and det disjunctions, and delay saving
+		% the ticket until necessary.
 	code_info__get_globals(Globals),
-	{ globals__lookup_bool_option(Globals, reclaim_heap_on_semidet_failure,
-		ReclaimHeap) },
 	{ globals__lookup_bool_option(Globals, use_trail, UseTrail) },
 	code_info__maybe_save_ticket(UseTrail, SaveTicketCode,
 		MaybeTicketSlot),
 
-		% Rather than saving the heap pointer here,
-		% we delay saving it until we get to the first
-		% disjunct that might allocate some heap space.
-	{ MaybeHpSlot = no },
+		% If we are using a grade in which we can recover memory
+		% by saving and restoring the heap pointer, set up for
+		% doing so if necessary.
+	( { CodeModel = model_non } ->
+			% With nondet disjunctions, we must recover memory
+			% across all disjuncts, even disjuncts that cannot
+			% themselves allocate memory, since we can backtrack
+			% to disjunct N after control leaves disjunct N-1.
+		{ globals__lookup_bool_option(Globals,
+			reclaim_heap_on_nondet_failure, ReclaimHeap) },
+		code_info__maybe_save_hp(ReclaimHeap, SaveHpCode,
+			MaybeHpSlot)
+	;
+			% With other disjunctions, we can backtrack to
+			% disjunct N only from disjunct N-1, so if disjunct
+			% N-1 does not allocate memory, we need not recover
+			% memory across it. Since it is possible (and common)
+			% for no disjunct to allocate memory, we delay saving
+			% the heap pointer and allocating a stack slot for
+			% the saved hp as long as possible.
+		{ globals__lookup_bool_option(Globals,
+			reclaim_heap_on_semidet_failure, ReclaimHeap) },
+		{ SaveHpCode = empty },
+		{ MaybeHpSlot = no }
+	),
+
+		% Save the values of any stack slots we may hijack,
+		% and if necessary, set the redofr slot of the top frame
+		% to point to this frame.
+	code_info__prepare_for_disj_hijack(CodeModel,
+		HijackInfo, PrepareHijackCode),
 
-		% Generate all the disjuncts.
 	code_info__get_next_label(EndLabel),
-	disj_gen__generate_pruned_disjuncts(Goals, StoreMap, EndLabel,
-		ReclaimHeap, MaybeHpSlot, MaybeTicketSlot, no, GoalsCode),
-
-		% Remake the code_info using the store map for the
-		% variable locations at the end of the disjunction.
-	code_info__remake_with_store_map(StoreMap),
 
-	{ Code = tree(SaveTicketCode, GoalsCode) }.
+	code_info__remember_position(BranchStart),
+	disj_gen__generate_disjuncts(Goals, CodeModel, ResumeMap, no,
+		HijackInfo, StoreMap, EndLabel,
+		ReclaimHeap, MaybeHpSlot, MaybeTicketSlot,
+		BranchStart, no, MaybeEnd, GoalsCode),
+
+	code_info__after_all_branches(StoreMap, MaybeEnd),
+	( { CodeModel = model_non } ->
+		code_info__set_resume_point_to_unknown
+	;
+		[]
+	),
+		% XXX release any temp slots holding heap or trail pointers
+	{ Code =
+		tree(FlushCode,
+		tree(SaveTicketCode,
+		tree(SaveHpCode,
+		tree(PrepareHijackCode,
+		     GoalsCode))))
+	}.
 
 %---------------------------------------------------------------------------%
 
-:- pred disj_gen__generate_pruned_disjuncts(list(hlds_goal), store_map,
-	label, bool, maybe(lval), maybe(lval), bool, code_tree,
-	code_info, code_info).
-:- mode disj_gen__generate_pruned_disjuncts(in, in, in, in, in, in, in,
-	out, in, out) is det.
-
-	% To generate code for a det or semidet disjunction,
-	% we generate a chain of goals if-then-else style
-	% until we come to a goal without a resume point.
-	% That goal is the last in the chain that we need to
-	% generate code for. (This is figured out by the liveness pass.)
-	%
-	% For a semidet disj, this goal will be semidet,
-	% and will be followed by no other goal.
-	% For a det disj, this goal will be det,
-	% and may be followed by other goals.
-	%
-	% XXX For efficiency, we ought not to restore anything in the
-	% first disjunct.
-
-disj_gen__generate_pruned_disjuncts([], _, _, _, _, _, _, _) -->
-	{ error("Empty pruned disjunction!") }.
-disj_gen__generate_pruned_disjuncts([Goal0 | Goals], StoreMap, EndLabel,
-		ReclaimHeap, MaybeHpSlot0, MaybeTicketSlot, First, Code) -->
+:- pred disj_gen__generate_disjuncts(list(hlds_goal)::in,
+	code_model::in, resume_map::in, maybe(resume_point_info)::in,
+	disj_hijack_info::in, store_map::in, label::in,
+	bool::in, maybe(lval)::in, maybe(lval)::in, position_info::in,
+	maybe(branch_end_info)::in, maybe(branch_end_info)::out,
+	code_tree::out, code_info::in, code_info::out) is det.
+
+disj_gen__generate_disjuncts([], _, _, _, _, _, _, _, _, _, _, _, _, _) -->
+	{ error("empty disjunction!") }.
+disj_gen__generate_disjuncts([Goal0 | Goals], CodeModel, FullResumeMap,
+		MaybeEntryResumePoint, HijackInfo, StoreMap, EndLabel,
+		ReclaimHeap, MaybeHpSlot0, MaybeTicketSlot,
+		BranchStart, MaybeEnd0, MaybeEnd, Code) -->
+
+	code_info__reset_to_position(BranchStart),
+
+		% If this is not the first disjunct, generate the
+		% resume point by which arrive at this disjunct.
+	( { MaybeEntryResumePoint = yes(EntryResumePoint) } ->
+		code_info__generate_resume_point(EntryResumePoint,
+			EntryResumePointCode)
+	;
+		{ EntryResumePointCode = empty }
+	),
+
 	{ Goal0 = GoalExpr0 - GoalInfo0 },
-	{ goal_info_get_code_model(GoalInfo0, CodeModel) },
 	{ goal_info_get_resume_point(GoalInfo0, Resume) },
 	(
 		{ Resume = resume_point(ResumeVars, ResumeLocs) }
@@ -121,30 +164,28 @@
 		% Emit code for a non-last disjunct, including setting things
 		% up for the execution of the next disjunct.
 
-		code_info__push_resume_point_vars(ResumeVars),
-		code_info__make_known_failure_cont(ResumeVars, ResumeLocs, no,
-			ModContCode),
-			% The next line is to enable Goal to pass the
-			% pre_goal_update sanity check.
-		{ goal_info_set_resume_point(GoalInfo0, no_resume_point,
-			GoalInfo) },
-		{ Goal = GoalExpr0 - GoalInfo },
-
-		( { First = no } ->
+		( { MaybeEntryResumePoint = yes(_) } ->
 				% Reset the heap pointer to recover memory
 				% allocated by the previous disjunct(s),
 				% if necessary.
 			code_info__maybe_restore_hp(MaybeHpSlot0,
-				RestoreHPCode),
+				RestoreHpCode),
 
 				% Reset the solver state if necessary.
 			code_info__maybe_reset_ticket(MaybeTicketSlot, undo,
 				RestoreTicketCode)
 		;
-			{ RestoreHPCode = empty },
+			{ RestoreHpCode = empty },
 			{ RestoreTicketCode = empty }
 		),
 
+			% The pre_goal_update sanity check insist on
+			% no_resume_point, to make sure that all resume
+			% points have been handled by surrounding code.
+		{ goal_info_set_resume_point(GoalInfo0, no_resume_point,
+			GoalInfo) },
+		{ Goal = GoalExpr0 - GoalInfo },
+
 			% Save hp if it needs to be saved and hasn't been
 			% saved previously.
 		(
@@ -152,244 +193,109 @@
 			{ code_util__goal_may_allocate_heap(Goal) },
 			{ MaybeHpSlot0 = no }
 		->
-			code_info__save_hp(SaveHPCode, HpSlot),
+			code_info__save_hp(SaveHpCode, HpSlot),
 			{ MaybeHpSlot = yes(HpSlot) }
 		;
-			{ SaveHPCode = empty },
+			{ SaveHpCode = empty },
 			{ MaybeHpSlot = MaybeHpSlot0 }
 		),
 
-		code_info__grab_code_info(CodeInfo),
-
-			% Generate the disjunct as a semi-deterministic goal.
-		{ CodeModel = model_semi ->
-			true
-		;
-			error("pruned disj non-last goal is not semidet")
-		},
-		trace__maybe_generate_internal_event_code(Goal, TraceCode),
-		code_gen__generate_goal(CodeModel, Goal, GoalCode),
-		code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
-
-		{ BranchCode = node([
-			goto(label(EndLabel)) -
-				"skip to end of pruned disj"
-		]) },
-
-		code_info__slap_code_info(CodeInfo),
-		code_info__pop_resume_point_vars,
-		code_info__restore_failure_cont(RestoreContCode),
-
-		disj_gen__generate_pruned_disjuncts(Goals, StoreMap, EndLabel,
-			ReclaimHeap, MaybeHpSlot, MaybeTicketSlot, no,
-			RestCode),
-
-		{ Code = tree(ModContCode, 
-			 tree(RestoreHPCode,
-			 tree(SaveHPCode,
-			 tree(RestoreTicketCode,
-			 tree(TraceCode,
-			 tree(GoalCode,
-			 tree(SaveCode,
-			 tree(BranchCode,
-			 tree(RestoreContCode,
-			      RestCode)))))))))
-		}
-	;
-		% Emit code for the last disjunct.
-
-			% Restore the heap pointer if necessary.
-		code_info__maybe_restore_and_discard_hp(MaybeHpSlot0,
-			RestoreHPCode),
-
-			% Restore the solver state if necessary.
-		code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot, 
-			undo, RestorePopTicketCode),
-
-			% Generate the goal.
-		trace__maybe_generate_internal_event_code(Goal0, TraceCode),
-		code_gen__generate_goal(CodeModel, Goal0, GoalCode),
-		code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
-
-		{ EndCode = node([
-			label(EndLabel) - "End of pruned disj"
-		]) },
-		{ Code = tree(RestoreHPCode,
-			 tree(RestorePopTicketCode,
-			 tree(TraceCode,
-			 tree(GoalCode,
-			 tree(SaveCode,
-			      EndCode)))))
-		}
-	).
-
-%---------------------------------------------------------------------------%
-
-disj_gen__generate_non_disj(Goals, StoreMap, Code) -->
-
-		% Sanity check
-	{
-		Goals = [],
-		error("empty disjunction shouldn't be nondet")
-	;
-		Goals = [_],
-		error("singleton disjunction")
-	;
-		Goals = [_, _ | _]
-	},
-
-		% If we are using a trail, save the current trail state
-		% before the first disjunct.
-	code_info__get_globals(Globals),
-	{ globals__lookup_bool_option(Globals, use_trail, UseTrail) },
-	code_info__maybe_save_ticket(UseTrail, SaveTicketCode,
-		MaybeTicketSlot),
-
-		% With nondet disjunctions, we must recover memory across
-		% all disjuncts, since we can backtract to disjunct N
-		% even after control leaves disjunct N-1.
-	{ globals__lookup_bool_option(Globals, reclaim_heap_on_nondet_failure,
-		ReclaimHeap) },
-	code_info__maybe_save_hp(ReclaimHeap, SaveHeapCode, MaybeHpSlot),
-
-	code_info__get_next_label(EndLabel),
-	disj_gen__generate_non_disjuncts(Goals, StoreMap, EndLabel,
-		MaybeHpSlot, MaybeTicketSlot, no, GoalsCode),
-
-		% since we don't know which disjunct we have come from
-		% we must set the current failure continuation to unknown.
-
-	code_info__unset_failure_cont(FlushResumeVarsCode),
-	code_info__remake_with_store_map(StoreMap),
-	{ Code = tree(SaveTicketCode,
-		 tree(SaveHeapCode,
-		 tree(GoalsCode,
-		      FlushResumeVarsCode))) }.
-
-%---------------------------------------------------------------------------%
-
-	% XXX For efficiency, we ought not to restore anything in the
-	% first disjunct.
-
-:- pred disj_gen__generate_non_disjuncts(list(hlds_goal), store_map, label,
-	maybe(lval), maybe(lval), bool, code_tree, code_info, code_info).
-:- mode disj_gen__generate_non_disjuncts(in, in, in, in, in, in,
-	out, in, out) is det.
-
-disj_gen__generate_non_disjuncts([], _, _, _, _, _, _) -->
-	{ error("empty nondet disjunction!") }.
-disj_gen__generate_non_disjuncts([Goal0 | Goals], StoreMap, EndLabel,
-		MaybeHpSlot, MaybeTicketSlot, First, Code) -->
-
-	{ Goal0 = GoalExpr0 - GoalInfo0 },
-	{ goal_info_get_resume_point(GoalInfo0, Resume) },
-	(
-		{ Resume = resume_point(ResumeVars, ResumeLocs) }
-	->
-		% Emit code for a non-last disjunct, including setting things
-		% up for the execution of the next disjunct.
-
-		code_info__push_resume_point_vars(ResumeVars),
-		code_info__make_known_failure_cont(ResumeVars, ResumeLocs, yes,
+		code_info__make_resume_point(ResumeVars, ResumeLocs,
+			FullResumeMap, NextResumePoint),
+		code_info__effect_resume_point(NextResumePoint, CodeModel,
 			ModContCode),
-			% The next line is to enable Goal to pass the
-			% pre_goal_update sanity check.
-		{ goal_info_set_resume_point(GoalInfo0, no_resume_point,
-			GoalInfo) },
-		{ Goal = GoalExpr0 - GoalInfo },
 
-		( { First = no } ->
-				% Reset the heap pointer to recover memory
-				% allocated by the previous disjunct(s),
-				% if necessary.
-			code_info__maybe_restore_hp(MaybeHpSlot,
-				RestoreHPCode),
+		trace__maybe_generate_internal_event_code(Goal, TraceCode),
+		{ goal_info_get_code_model(GoalInfo, GoalCodeModel) },
+		code_gen__generate_goal(GoalCodeModel, Goal, GoalCode),
 
-				% Reset the solver state if necessary.
-			code_info__maybe_reset_ticket(MaybeTicketSlot, undo,
-				RestoreTicketCode)
+		( { CodeModel = model_non } ->
+			% We can backtrack to the next disjunct from outside,
+			% so we make sure every variable in the resume set
+			% is in its stack slot.
+			code_info__flush_resume_vars_to_stack(ResumeVarsCode)
 		;
-			{ RestoreHPCode = empty },
-			{ RestoreTicketCode = empty }
+			{ ResumeVarsCode = empty }
 		),
 
-		code_info__grab_code_info(CodeInfo),
-
-		trace__maybe_generate_internal_event_code(Goal, TraceCode),
-		code_gen__generate_goal(model_non, Goal, GoalCode),
-		code_info__generate_branch_end(model_non, StoreMap, SaveCode),
-
-			% Make sure every variable in the resume set is in its
-			% stack slot.
-		code_info__flush_resume_vars_to_stack(FlushResumeVarsCode),
+			% Put every variable whose value is needed after
+			% the disjunction to the place indicated by StoreMap,
+			% and accumulate information about the code_info state
+			% at the ends of the branches so far.
+		code_info__generate_branch_end(StoreMap, MaybeEnd0, MaybeEnd1,
+			SaveCode),
 
 		{ BranchCode = node([
 			goto(label(EndLabel)) -
 				"skip to end of nondet disj"
 		]) },
 
-		code_info__slap_code_info(CodeInfo),
-		code_info__pop_resume_point_vars,
-
-			% Make sure that the redoip of the top nondet frame
-			% points to the right label, and set up the start of
-			% the next disjunct.
-		code_info__restore_failure_cont(RestoreContCode),
-
-		disj_gen__generate_non_disjuncts(Goals, StoreMap, EndLabel,
-			MaybeHpSlot, MaybeTicketSlot, no, RestCode),
-
-		{ Code = tree(ModContCode, 
-			 tree(RestoreHPCode,
-			 tree(RestoreTicketCode,
-			 tree(TraceCode,
-			 tree(GoalCode,
-			 tree(SaveCode,
-			 tree(FlushResumeVarsCode,
-			 tree(BranchCode,
-			 tree(RestoreContCode,
-			      RestCode)))))))))
+		disj_gen__generate_disjuncts(Goals, CodeModel, FullResumeMap,
+			yes(NextResumePoint), HijackInfo, StoreMap, EndLabel,
+			ReclaimHeap, MaybeHpSlot, MaybeTicketSlot,
+			BranchStart, MaybeEnd1, MaybeEnd, RestCode),
+
+		{ Code =
+			tree(EntryResumePointCode, 
+			tree(RestoreHpCode,
+			tree(RestoreTicketCode,
+			tree(SaveHpCode,
+			tree(ModContCode, 
+			tree(TraceCode,
+			tree(GoalCode,
+			tree(ResumeVarsCode,
+			tree(SaveCode,
+			tree(BranchCode,
+			     RestCode))))))))))
 		}
 	;
-		% Emit code for the last disjunct.
+		% Emit code for the last disjunct
 
-		{ Goals = [] ->
-			true
+			% Restore the heap pointer and solver state
+			% if necessary.
+		( { CodeModel = model_non } ->
+
+			% Note that we can't release the temps used for the
+			% heap pointer and ticket, because those values may be
+			% required again after backtracking after control
+			% leaves the disjunction. If we were to reuse either
+			% of their stack slots for something else when
+			% generating the code that follows this goal,
+			% then the values that earlier disjuncts need on
+			% backtracking would get clobbered.
+			% Thus we must not use the `_discard' versions
+			% of the two predicates below.
+
+			code_info__maybe_restore_hp(MaybeHpSlot0,
+				RestoreHpCode),
+			code_info__maybe_reset_and_pop_ticket(
+				MaybeTicketSlot, undo, RestoreTicketCode)
 		;
-			error("disj_gen__generate_non_disjuncts: last disjunct followed by others")
-		},
+			code_info__maybe_restore_and_discard_hp(MaybeHpSlot0,
+				RestoreHpCode),
+			code_info__maybe_reset_and_discard_ticket(
+				MaybeTicketSlot, undo, RestoreTicketCode)
+		),
 
-		% Note that we can't release the temps used for the heap
-		% pointer and ticket, because those values may be required
-		% again after backtracking from goals that following
-		% the disjunction.
-		% If we were to reuse the same stack slot for something
-		% else when generating the code that follows this goal,
-		% then the values that earlier disjuncts need on
-		% backtracking would get clobbered.
-		% Thus we must not use the `_discard' versions of the two
-		% predicates below.
-
-			% Restore the heap pointer if necessary.
-		code_info__maybe_restore_hp(MaybeHpSlot, RestoreHPCode),
-
-			% Restore the solver state if necessary.
-		code_info__maybe_reset_and_pop_ticket(
-			MaybeTicketSlot, undo, RestorePopTicketCode),
+		code_info__undo_disj_hijack(HijackInfo, UndoCode),
 
 		trace__maybe_generate_internal_event_code(Goal0, TraceCode),
-		code_gen__generate_goal(model_non, Goal0, GoalCode),
-		code_info__generate_branch_end(model_non, StoreMap, SaveCode),
+		code_gen__generate_goal(CodeModel, Goal0, GoalCode),
+		code_info__generate_branch_end(StoreMap, MaybeEnd0, MaybeEnd,
+			SaveCode),
 
 		{ EndCode = node([
 			label(EndLabel) - "End of nondet disj"
 		]) },
-		{ Code = tree(RestoreHPCode,
-			 tree(RestorePopTicketCode,
-			 tree(TraceCode,
-			 tree(GoalCode,
-			 tree(SaveCode,
-			      EndCode)))))
+		{ Code =
+			tree(EntryResumePointCode,
+			tree(TraceCode,
+			tree(RestoreHpCode,
+			tree(RestoreTicketCode,
+			tree(UndoCode,
+			tree(GoalCode,
+			tree(SaveCode,
+			     EndCode)))))))
 		}
 	).
 
Index: compiler/dupelim.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/dupelim.m,v
retrieving revision 1.33
diff -u -r1.33 dupelim.m
--- dupelim.m	1998/06/09 02:12:32	1.33
+++ dupelim.m	1998/06/29 08:26:46
@@ -294,7 +294,7 @@
 		Instr1 = call(_, _, _, _),
 		Instr = Instr1
 	;
-		Instr1 = mkframe(_, _, _, _),
+		Instr1 = mkframe(_, _),
 		Instr = Instr1
 	;
 		Instr1 = modframe(_),
@@ -415,6 +415,9 @@
 		Lval1 = succfr(_),
 		Lval = Lval1
 	;
+		Lval1 = redofr(_),
+		Lval = Lval1
+	;
 		Lval1 = prevfr(_),
 		Lval = Lval1
 	;
@@ -562,7 +565,7 @@
 		Instr2 = Instr1,
 		Instr = Instr1
 	;
-		Instr1 = mkframe(_, _, _, _),
+		Instr1 = mkframe(_, _),
 		Instr2 = Instr1,
 		Instr = Instr1
 	;
@@ -695,6 +698,10 @@
 		Lval2 = Lval1,
 		Lval = Lval1
 	;
+		Lval1 = redofr(_),
+		Lval2 = Lval1,
+		Lval = Lval1
+	;
 		Lval1 = succfr(_),
 		Lval2 = Lval1,
 		Lval = Lval1
@@ -793,8 +800,8 @@
 dupelim__replace_labels_instr(call(Target, Return0, LiveInfo, CM),
 		ReplMap, call(Target, Return, LiveInfo, CM)) :-
 	dupelim__replace_labels_code_addr(Return0, ReplMap, Return).
-dupelim__replace_labels_instr(mkframe(Name, Size, Pragma, Redoip0), ReplMap,
-		mkframe(Name, Size, Pragma, Redoip)) :-
+dupelim__replace_labels_instr(mkframe(NondetFrameInfo, Redoip0), ReplMap,
+		mkframe(NondetFrameInfo, Redoip)) :-
 	dupelim__replace_labels_code_addr(Redoip0, ReplMap, Redoip).
 dupelim__replace_labels_instr(modframe(Redoip0), ReplMap, modframe(Redoip)) :-
 	dupelim__replace_labels_code_addr(Redoip0, ReplMap, Redoip).
@@ -874,6 +881,8 @@
 dupelim__replace_labels_lval(succip(Rval0), ReplMap, succip(Rval)) :-
 	dupelim__replace_labels_rval(Rval0, ReplMap, Rval).
 dupelim__replace_labels_lval(redoip(Rval0), ReplMap, redoip(Rval)) :-
+	dupelim__replace_labels_rval(Rval0, ReplMap, Rval).
+dupelim__replace_labels_lval(redofr(Rval0), ReplMap, redofr(Rval)) :-
 	dupelim__replace_labels_rval(Rval0, ReplMap, Rval).
 dupelim__replace_labels_lval(succfr(Rval0), ReplMap, succfr(Rval)) :-
 	dupelim__replace_labels_rval(Rval0, ReplMap, Rval).
Index: compiler/exprn_aux.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/exprn_aux.m,v
retrieving revision 1.28
diff -u -r1.28 exprn_aux.m
--- exprn_aux.m	1998/01/23 12:56:29	1.28
+++ exprn_aux.m	1998/02/27 02:24:10
@@ -319,6 +319,8 @@
 	exprn_aux__vars_in_rval(Rval, Vars).
 exprn_aux__vars_in_lval(redoip(Rval), Vars) :-
 	exprn_aux__vars_in_rval(Rval, Vars).
+exprn_aux__vars_in_lval(redofr(Rval), Vars) :-
+	exprn_aux__vars_in_rval(Rval, Vars).
 exprn_aux__vars_in_lval(succfr(Rval), Vars) :-
 	exprn_aux__vars_in_rval(Rval, Vars).
 exprn_aux__vars_in_lval(prevfr(Rval), Vars) :-
@@ -469,6 +471,11 @@
 			Rval0, Rval),
 		Lval = redoip(Rval)
 	;
+		Lval0 = redofr(Rval0),
+		exprn_aux__substitute_lval_in_rval(OldLval, NewLval,
+			Rval0, Rval),
+		Lval = redofr(Rval)
+	;
 		Lval0 = succfr(Rval0),
 		exprn_aux__substitute_lval_in_rval(OldLval, NewLval,
 			Rval0, Rval),
@@ -618,6 +625,11 @@
 			Rval0, Rval),
 		Lval = redoip(Rval)
 	;
+		Lval0 = redofr(Rval0),
+		exprn_aux__substitute_rval_in_rval(OldRval, NewRval,
+			Rval0, Rval),
+		Lval = redofr(Rval)
+	;
 		Lval0 = succfr(Rval0),
 		exprn_aux__substitute_rval_in_rval(OldRval, NewRval,
 			Rval0, Rval),
@@ -817,6 +829,8 @@
 exprn_aux__lval_addrs(prevfr(Rval), CodeAddrs, DataAddrs) :-
 	exprn_aux__rval_addrs(Rval, CodeAddrs, DataAddrs).
 exprn_aux__lval_addrs(succfr(Rval), CodeAddrs, DataAddrs) :-
+	exprn_aux__rval_addrs(Rval, CodeAddrs, DataAddrs).
+exprn_aux__lval_addrs(redofr(Rval), CodeAddrs, DataAddrs) :-
 	exprn_aux__rval_addrs(Rval, CodeAddrs, DataAddrs).
 exprn_aux__lval_addrs(redoip(Rval), CodeAddrs, DataAddrs) :-
 	exprn_aux__rval_addrs(Rval, CodeAddrs, DataAddrs).
Index: compiler/frameopt.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/frameopt.m,v
retrieving revision 1.70
diff -u -r1.70 frameopt.m
--- frameopt.m	1998/06/09 02:12:40	1.70
+++ frameopt.m	1998/06/29 08:19:37
@@ -533,7 +533,7 @@
 			(
 				Uinstr = call(_, _, _, _)
 			;
-				Uinstr = mkframe(_, _, _, _)
+				Uinstr = mkframe(_, _)
 			;
 				Uinstr = c_code(_)
 			;
@@ -666,7 +666,7 @@
 	;
 		Labels = []
 	).
-possible_targets(mkframe(_, _, _, _), []).
+possible_targets(mkframe(_, _), []).
 possible_targets(modframe(_), []).
 possible_targets(label(_), []).
 possible_targets(goto(CodeAddr), Targets) :-
@@ -1274,8 +1274,8 @@
 	;
 		ReturnAddr = ReturnAddr0
 	).
-substitute_labels_instr(mkframe(Name, Size, Pragma, Redoip), _,
-		mkframe(Name, Size, Pragma, Redoip)).
+substitute_labels_instr(mkframe(NondetFrameInfo, Redoip), _,
+		mkframe(NondetFrameInfo, Redoip)).
 substitute_labels_instr(modframe(Redoip), _, modframe(Redoip)).
 substitute_labels_instr(label(_), _, _) :-
 	error("label in substitute_labels_instr").
Index: compiler/handle_options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.58
diff -u -r1.58 handle_options.m
--- handle_options.m	1998/07/01 06:08:24	1.58
+++ handle_options.m	1998/07/01 12:36:09
@@ -135,14 +135,14 @@
                 ->
                     { map__lookup(OptionTable,
                         fact_table_hash_percent_full, PercentFull) },
-                    ( 
+                    (
                         { PercentFull = int(Percent) },
                         { Percent >= 1 },
                         { Percent =< 100 }
                     ->
                         { map__lookup(OptionTable, termination_norm,
                                 TermNorm0) },
-                        ( 
+                        (
                             { TermNorm0 = string(TermNormStr) },
                             { convert_termination_norm(TermNormStr, TermNorm) }
                         ->
@@ -181,7 +181,7 @@
         { Error = yes("Invalid GC option (must be `none', `conservative' or `accurate')") }
     ).
 
-:- pred postprocess_options_2(option_table, gc_method, tags_method, 
+:- pred postprocess_options_2(option_table, gc_method, tags_method,
 	args_method, prolog_dialect, termination_norm, trace_level,
 	io__state, io__state).
 :- mode postprocess_options_2(in, in, in, in, in, in, in, di, uo) is det.
@@ -225,7 +225,7 @@
 		{ NumTagBits0 = -1 }
 	->
 		globals__io_lookup_int_option(conf_low_tag_bits, NumTagBits1)
-	;	
+	;
 		{ NumTagBits1 = NumTagBits0 }
 	),
 
@@ -264,12 +264,12 @@
 	% --split-c-files implies --procs-per-c-function 1
 	option_implies(split_c_files, procs_per_c_function, int(1)),
 
-	% -D all is really -D "abcdefghijklmnopqrstuvwxyz"
+	% -D all is really "all possible flag chars are in VerboseDump"
 	globals__io_lookup_string_option(verbose_dump_hlds, VerboseDump),
 	( { VerboseDump = "all" } ->
 		globals__io_set_option(verbose_dump_hlds,
 			string("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"))
-	;	
+	;
 		[]
 	),
 
@@ -290,8 +290,8 @@
 		[]
 	),
 
-	% Tracing requires 
-	% 	- disabling optimizations that would change 
+	% Execution tracing requires
+	% 	- disabling optimizations that would change
 	% 	  the trace being generated
 	%	- enabling some low level optimizations to ensure consistent
 	%	  paths across optimization levels
@@ -350,11 +350,12 @@
 	option_implies(trace_stack_layout, procid_stack_layout, bool(yes)),
 
 	% --gc accurate requires `agc' stack layouts, typeinfo liveness,
-	% and needs frameopt to be switched off.
+	% and needs hijacks and frameopt to be switched off.
 	( { GC_Method = accurate } ->
 		globals__io_set_option(agc_stack_layout, bool(yes)),
 		globals__io_set_option(typeinfo_liveness, bool(yes)),
-		globals__io_set_option(optimize_frames, bool(no)) 
+		globals__io_set_option(allow_hijacks, bool(no)),
+		globals__io_set_option(optimize_frames, bool(no))
 	;
 		[]
 	),
@@ -384,7 +385,7 @@
 
 	% --intermod-unused-args implies --intermodule-optimization and
 	% --optimize-unused-args.
-	option_implies(intermod_unused_args, intermodule_optimization, 
+	option_implies(intermod_unused_args, intermodule_optimization,
 		bool(yes)),
 	option_implies(intermod_unused_args, optimize_unused_args, bool(yes)),
 
@@ -426,8 +427,9 @@
 % option_implies(SourceBoolOption, ImpliedOption, ImpliedOptionValue, IO0, IO).
 % If the SourceBoolOption is set to yes, then the ImpliedOption is set
 % to ImpliedOptionValue.
-:- pred option_implies(option::in, option::in, option_data::in, 
+:- pred option_implies(option::in, option::in, option_data::in,
 	io__state::di, io__state::uo) is det.
+
 option_implies(SourceOption, ImpliedOption, ImpliedOptionValue) -->
 	globals__io_lookup_bool_option(SourceOption, SourceOptionValue),
 	( { SourceOptionValue = yes } ->
@@ -436,12 +438,13 @@
 		[]
 	).
 
-% option_neg_implies(SourceBoolOption, ImpliedOption, 
+% option_neg_implies(SourceBoolOption, ImpliedOption,
 %	ImpliedOptionValue, IO0, IO).
 % If the SourceBoolOption is set to no, then the ImpliedOption is set
 % to ImpliedOptionValue.
-:- pred option_neg_implies(option::in, option::in, option_data::in, 
+:- pred option_neg_implies(option::in, option::in, option_data::in,
 	io__state::di, io__state::uo) is det.
+
 option_neg_implies(SourceOption, ImpliedOption, ImpliedOptionValue) -->
 	globals__io_lookup_bool_option(SourceOption, SourceOptionValue),
 	( { SourceOptionValue = no } ->
@@ -509,14 +512,14 @@
 		( ProfileCalls = yes ->
 			( ProfileMemory = yes ->
 				Part4 = ".profall"
-			; 
+			;
 				Part4 = ".prof"
 			)
 		;
 			( ProfileMemory = yes ->
 				Part4 = ".profmemtime" /* not allowed */
 					/* `ml' will catch the error */
-			; 
+			;
 				Part4 = ".proftime" /* currently useless */
 			)
 		)
@@ -524,14 +527,14 @@
 		( ProfileCalls = yes ->
 			( ProfileMemory = yes ->
 				Part4 = ".memprof"
-			; 
+			;
 				Part4 = ".profcalls"
 			)
-		; 
+		;
 			( ProfileMemory = yes ->
 				Part4 = ".profmem" /* not allowed */
 					/* `ml' will catch the error */
-			; 
+			;
 				Part4 = ""
 			)
 		)
@@ -550,8 +553,6 @@
 		string__format(".hightags%d", [i(TagBits)], Part6)
 	;
 		string__format(".tags%d", [i(TagBits)], Part6)
-	;
-		
 	),
 	( UnboxedFloat = yes ->
 		Part7 = ".ubf"
@@ -688,10 +689,10 @@
 	),
 	% Set the type of gc that the grade option implies.
 	% 'accurate' is now set in the grade, so we can override it here.
-	( 
-		{ GC = accurate }, 
+	(
+		{ GC = accurate },
 		set_string_opt(gc, "accurate")
-	; 
+	;
 		{ GC = conservative },
 		set_string_opt(gc, "conservative")
 	;
Index: compiler/hlds_module.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_module.m,v
retrieving revision 1.34
diff -u -r1.34 hlds_module.m
--- hlds_module.m	1998/05/07 06:41:03	1.34
+++ hlds_module.m	1998/07/01 05:57:10
@@ -162,7 +162,7 @@
 	module_info).
 :- mode module_info_set_superclasses(in, in, out) is det.
 
-	% The cell count is used as a unique label number for
+	% The cell count is used as a unique cell number for
 	% constants in the generated C code.
 :- pred module_info_get_cell_count(module_info, int).
 :- mode module_info_get_cell_count(in, out) is det.
Index: compiler/ite_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ite_gen.m,v
retrieving revision 1.55
diff -u -r1.55 ite_gen.m
--- ite_gen.m	1998/06/02 05:31:39	1.55
+++ ite_gen.m	1998/07/01 12:16:39
@@ -3,19 +3,16 @@
 % This file may only be copied under the terms of the GNU General
 % Public License - see the file COPYING in the Mercury distribution.
 %---------------------------------------------------------------------------%
-%---------------------------------------------------------------------------%
 %
 % File: ite_gen.m
 %
 % Main authors: conway, fjh, zs.
 %
-% The predicates of this module generate code for if-then-elses.
-%
-% The handling of model_det and model_semi if-then-elses is almost identical.
-% The handling of model_non if-then-elses is also quite similar.
+% The predicates of this module generate code for if-then-elses, and for
+% negations (which are cut-down versions of if-then-elses, since not(G)
+% is equivalent to (G -> fail ; true).
 %
 %---------------------------------------------------------------------------%
-%---------------------------------------------------------------------------%
 
 :- module ite_gen.
 
@@ -23,63 +20,58 @@
 
 :- import_module hlds_goal, llds, code_info.
 
-:- pred ite_gen__generate_det_ite(hlds_goal, hlds_goal, hlds_goal,
-	store_map, code_tree, code_info, code_info).
-:- mode ite_gen__generate_det_ite(in, in, in, in, out, in, out) is det.
-
-:- pred ite_gen__generate_semidet_ite(hlds_goal, hlds_goal, hlds_goal,
-	store_map, code_tree, code_info, code_info).
-:- mode ite_gen__generate_semidet_ite(in, in, in, in, out, in, out) is det.
-
-:- pred ite_gen__generate_nondet_ite(hlds_goal, hlds_goal, hlds_goal,
-	store_map, code_tree, code_info, code_info).
-:- mode ite_gen__generate_nondet_ite(in, in, in, in, out, in, out) is det.
+:- pred ite_gen__generate_ite(code_model::in, hlds_goal::in, hlds_goal::in,
+	hlds_goal::in, store_map::in, code_tree::out,
+	code_info::in, code_info::out) is det.
+
+:- pred ite_gen__generate_negation(code_model::in, hlds_goal::in,
+	code_tree::out, code_info::in, code_info::out) is det.
 
 %---------------------------------------------------------------------------%
 
 :- implementation.
 
 :- import_module code_gen, code_util, trace, options, globals.
-:- import_module bool, set, tree, list, map, std_util, require.
-
-ite_gen__generate_det_ite(CondGoal, ThenGoal, ElseGoal, StoreMap, Code) -->
-	ite_gen__generate_basic_ite(CondGoal, ThenGoal, ElseGoal, StoreMap,
-		model_det, Code).
-
-ite_gen__generate_semidet_ite(CondGoal, ThenGoal, ElseGoal, StoreMap, Code) -->
-	ite_gen__generate_basic_ite(CondGoal, ThenGoal, ElseGoal, StoreMap,
-		model_semi, Code).
-
-%---------------------------------------------------------------------------%
+:- import_module bool, set, tree, list, map, std_util, term, require.
 
-:- pred ite_gen__generate_basic_ite(hlds_goal, hlds_goal, hlds_goal,
-	store_map, code_model, code_tree, code_info, code_info).
-:- mode ite_gen__generate_basic_ite(in, in, in, in, in, out, in, out) is det.
-
-ite_gen__generate_basic_ite(CondGoal0, ThenGoal, ElseGoal, StoreMap, CodeModel,
-		Code) -->
-
-		% Set up for the possible failure of the condition
+ite_gen__generate_ite(CodeModel, CondGoal0, ThenGoal, ElseGoal, StoreMap, Code)
+		-->
 	{ CondGoal0 = CondExpr - CondInfo0 },
+	{ goal_info_get_code_model(CondInfo0, CondCodeModel) },
+	{
+		CodeModel = model_non,
+		CondCodeModel \= model_non
+	->
+		EffCodeModel = model_semi
+	;
+		EffCodeModel = CodeModel
+	},
+
 	{ goal_info_get_resume_point(CondInfo0, Resume) },
-	(
-		{ Resume = resume_point(ResumeVarsPrime, ResumeLocsPrime) }
+	{
+		Resume = resume_point(ResumeVarsPrime, ResumeLocsPrime)
 	->
-		{ ResumeVars = ResumeVarsPrime },
-		{ ResumeLocs = ResumeLocsPrime }
+		ResumeVars = ResumeVarsPrime,
+		ResumeLocs = ResumeLocsPrime,
+			% The pre_goal_update sanity check insists on
+			% no_resume_point, to make sure that all resume
+			% points have been handled by surrounding code.
+		goal_info_set_resume_point(CondInfo0, no_resume_point,
+			CondInfo),
+		CondGoal = CondExpr - CondInfo
 	;
-		{ error("condition of an if-then-else has no resume point") }
-	),
-	code_info__make_known_failure_cont(ResumeVars, ResumeLocs, no,
-		ModContCode),
-		% The next line is to enable Cond to pass the
-		% pre_goal_update sanity check
-	{ goal_info_set_resume_point(CondInfo0, no_resume_point, CondInfo) },
-	{ CondGoal = CondExpr - CondInfo },
+		error("condition of an if-then-else has no resume point")
+	},
 
-		% Maybe save the heap state current before the condition;
-		% this ought to be after we make the failure continuation
-		% because that causes the cache to get flushed
+		% Make sure that the variables whose values will be needed
+		% on backtracking to the else part are materialized into
+		% registers or stack slots. Their locations are recorded
+		% in ResumeMap.
+	code_info__produce_vars(ResumeVars, ResumeMap, FlushCode),
+
+		% Maybe save the heap state current before the condition.
+		% This is after code_info__produce_vars since code that
+		% flushes the cache may allocate memory we must not "recover".
 	code_info__get_globals(Globals),
 	{ 
 		globals__lookup_bool_option(Globals,
@@ -90,225 +82,338 @@
 	;
 		ReclaimHeap = no
 	},
-	code_info__maybe_save_hp(ReclaimHeap, SaveHPCode, MaybeHpSlot),
+	code_info__maybe_save_hp(ReclaimHeap, SaveHpCode, MaybeHpSlot),
 
 		% Maybe save the current trail state before the condition
 	{ globals__lookup_bool_option(Globals, use_trail, UseTrail) },
-	code_info__maybe_save_ticket(UseTrail, SaveTicketCode, MaybeTicketSlot),
+	code_info__maybe_save_ticket(UseTrail, SaveTicketCode,
+		MaybeTicketSlot),
 
-	code_info__grab_code_info(CodeInfo),
+	code_info__remember_position(BranchStart),
 
-		% Generate the condition as a semi-deterministic goal
-	code_info__push_resume_point_vars(ResumeVars),
-	code_gen__generate_goal(model_semi, CondGoal, CondCode),
-	code_info__pop_resume_point_vars,
+	code_info__prepare_for_ite_hijack(EffCodeModel, HijackInfo,
+		PrepareHijackCode),
+
+	code_info__make_resume_point(ResumeVars, ResumeLocs, ResumeMap,
+		ResumePoint),
+	code_info__effect_resume_point(ResumePoint, EffCodeModel,
+		EffectResumeCode),
+
+	{ goal_may_hijack_top_redoip(CondGoal, CondMayHijack) },
+	code_info__maybe_push_temp_frame(EffCodeModel, CondMayHijack,
+		HijackInfo, CurFrameLval, TempFrameCode),
+
+		% Generate the condition
+	code_gen__generate_goal(CondCodeModel, CondGoal, CondCode),
+
+	code_info__ite_enter_then(HijackInfo, CurFrameLval,
+		ThenNeckCode, ElseNeckCode),
 
 		% Kill again any variables that have become zombies
 	code_info__pickup_zombies(Zombies),
 	code_info__make_vars_forward_dead(Zombies),
 
-	code_info__pop_failure_cont,
-
 		% Discard hp and trail ticket if the condition succeeded
+		% XXX is this the right thing to do?
 	code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot, commit,
 		DiscardTicketCode),
 	code_info__maybe_discard_hp(MaybeHpSlot),
 
+		% XXX release any temp slots holding heap or trail pointers
+
+		% XXX If instmap indicates we cannot reach then part,
+		% do not attempt to generate it (may cause aborts)
+
 		% Generate the then branch
 	trace__maybe_generate_internal_event_code(ThenGoal, ThenTraceCode),
 	code_gen__generate_goal(CodeModel, ThenGoal, ThenCode),
-	code_info__generate_branch_end(CodeModel, StoreMap, ThenSaveCode),
+	code_info__generate_branch_end(StoreMap, no, MaybeEnd0, ThenSaveCode),
 
 		% Generate the entry to the else branch
-	code_info__slap_code_info(CodeInfo),
-	code_info__restore_failure_cont(RestoreContCode),
-	code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot, undo,
-		RestoreTicketCode),
-	code_info__maybe_restore_and_discard_hp(MaybeHpSlot, RestoreHPCode),
+	code_info__reset_to_position(BranchStart),
+	code_info__generate_resume_point(ResumePoint, ResumeCode),
+
+	( { CondCodeModel = model_non } ->
+			% We cannot release the stack slots used for
+			% the trail ticket and heap pointer if the
+			% condition can be backtracked into.
+		code_info__maybe_restore_hp(MaybeHpSlot, RestoreHpCode),
+		code_info__maybe_reset_and_pop_ticket(MaybeTicketSlot,
+			undo, RestoreTicketCode)
+	;
+		code_info__maybe_restore_and_discard_hp(MaybeHpSlot,
+			RestoreHpCode),
+		code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot,
+			undo, RestoreTicketCode)
+	),
 
 		% Generate the else branch
 	trace__maybe_generate_internal_event_code(ElseGoal, ElseTraceCode),
 	code_gen__generate_goal(CodeModel, ElseGoal, ElseCode),
-	code_info__generate_branch_end(CodeModel, StoreMap, ElseSaveCode),
+	code_info__generate_branch_end(StoreMap, MaybeEnd0, MaybeEnd,
+		ElseSaveCode),
 
-	code_info__get_next_label(EndLab),
-	{ JumpToEndCode = node([goto(label(EndLab))
-		- "Jump to the end of if-then-else"]) },
-	{ EndLabelCode = node([label(EndLab) - "end of if-then-else"]) },
-	{ Code = tree(ModContCode,
-		 tree(SaveHPCode,
-		 tree(SaveTicketCode,
-		 tree(CondCode,
-		 tree(DiscardTicketCode,
-		 tree(ThenTraceCode,
-		 tree(ThenCode,
-		 tree(ThenSaveCode,
-		 tree(JumpToEndCode,
-		 tree(RestoreContCode,
-		 tree(RestoreHPCode,
-		 tree(RestoreTicketCode,
-		 tree(ElseTraceCode,
-		 tree(ElseCode,
-		 tree(ElseSaveCode,
-		      EndLabelCode)))))))))))))))
+	code_info__get_next_label(EndLabel),
+	{ JumpToEndCode = node([
+		goto(label(EndLabel))
+			- "Jump to the end of if-then-else"
+	]) },
+	{ EndLabelCode = node([
+		label(EndLabel)
+			- "end of if-then-else"
+	]) },
+	{ Code =
+		tree(FlushCode,
+		tree(SaveHpCode,
+		tree(SaveTicketCode,
+		tree(PrepareHijackCode,
+		tree(EffectResumeCode,
+		tree(TempFrameCode,
+		tree(CondCode,
+		tree(ThenNeckCode,
+		tree(DiscardTicketCode,
+		tree(ThenTraceCode,
+		tree(ThenCode,
+		tree(ThenSaveCode,
+		tree(JumpToEndCode,
+		tree(ResumeCode,
+		tree(ElseNeckCode,
+		tree(RestoreHpCode,
+		tree(RestoreTicketCode,
+		tree(ElseTraceCode,
+		tree(ElseCode,
+		tree(ElseSaveCode,
+		     EndLabelCode))))))))))))))))))))
 	},
-	code_info__remake_with_store_map(StoreMap).
+	code_info__after_all_branches(StoreMap, MaybeEnd).
 
 %---------------------------------------------------------------------------%
 
-ite_gen__generate_nondet_ite(CondGoal0, ThenGoal, ElseGoal, StoreMap, Code) -->
+ite_gen__generate_negation(CodeModel, Goal0, Code) -->
+	{ CodeModel = model_non ->
+		error("nondet negation")
+	;
+		true
+	},
 
-		% Set up for the possible failure of the condition
-	{ CondGoal0 = CondExpr - CondInfo0 },
-	{ goal_info_get_code_model(CondInfo0, CondCodeModel) },
-	( { CondCodeModel = model_non } ->
-		{ NondetCond = yes }
+	{ Goal0 = GoalExpr - GoalInfo0 },
+	{ goal_info_get_resume_point(GoalInfo0, Resume) },
+	{
+		Resume = resume_point(ResumeVarsPrime, ResumeLocsPrime)
+	->
+		ResumeVars = ResumeVarsPrime,
+		ResumeLocs = ResumeLocsPrime,
+		goal_info_set_resume_point(GoalInfo0, no_resume_point,
+			GoalInfo),
+		Goal = GoalExpr - GoalInfo
 	;
-		{ NondetCond = no }
-	),
-	{ goal_info_get_resume_point(CondInfo0, Resume) },
+		error("negated goal has no resume point")
+	},
+
+		% For a negated simple test, we can generate better code
+		% than the general mechanism, because we don't have to
+		% flush the cache.
 	(
-		{ Resume = resume_point(ResumeVarsPrime, ResumeLocsPrime) }
+		{ CodeModel = model_semi },
+		{ GoalExpr = unify(_, _, _, simple_test(L, R), _) },
+		code_info__failure_is_direct_branch(CodeAddr),
+		code_info__get_globals(Globals),
+		{ globals__lookup_bool_option(Globals, simple_neg, yes) }
 	->
-		{ ResumeVars = ResumeVarsPrime},
-		{ ResumeLocs = ResumeLocsPrime}
+			% Because we are generating the negated goal ourselves,
+			% we need to apply the pre- and post-goal updates
+			% that would normally be applied by
+			% code_gen__generate_goal.
+
+		code_info__enter_simple_neg(ResumeVars, GoalInfo, SimpleNeg),
+		code_info__produce_variable(L, CodeL, ValL),
+		code_info__produce_variable(R, CodeR, ValR),
+		code_info__variable_type(L, Type),
+		{ Type = term__functor(term__atom("string"), [], _) ->
+			Op = str_eq
+		; Type = term__functor(term__atom("float"), [], _) ->
+			Op = float_eq
+		;
+			Op = eq
+		},
+		{ TestCode = node([
+			if_val(binop(Op, ValL, ValR), CodeAddr) -
+				"test inequality"
+		]) },
+		code_info__leave_simple_neg(GoalInfo, SimpleNeg),
+		{ Code = tree(tree(CodeL, CodeR), TestCode) }
 	;
-		{ error("condition of an if-then-else has no resume point") }
-	),
-	code_info__make_known_failure_cont(ResumeVars, ResumeLocs, NondetCond,
-		ModContCode),
-		% The next line is to enable Cond to pass the
-		% pre_goal_update sanity check
-	{ goal_info_set_resume_point(CondInfo0, no_resume_point, CondInfo) },
-	{ CondGoal = CondExpr - CondInfo },
-
-		% Prevent a nondet condition from hijacking the redoip slot
-		% We could improve the efficiency of this
-	( { NondetCond = yes } ->
-		code_info__unset_failure_cont(FlushEnclosingResumeVarsCode),
-		code_info__save_maxfr(MaxfrLval0, SaveMaxfrCode),
-		{ MaybeMaxfrLval = yes(MaxfrLval0) }
-	;
-		{ FlushEnclosingResumeVarsCode = empty },
-		{ SaveMaxfrCode = empty },
-		{ MaybeMaxfrLval = no }
-	),
+		generate_negation_general(CodeModel, Goal,
+			ResumeVars, ResumeLocs, Code)
+	).
+
+	% The code of generate_negation_general is a cut-down version
+	% of the code for if-then-elses.
+
+:- pred generate_negation_general(code_model::in, hlds_goal::in,
+	set(var)::in, resume_locs::in, code_tree::out,
+	code_info::in, code_info::out) is det.
+
+generate_negation_general(CodeModel, Goal, ResumeVars, ResumeLocs, Code) -->
+
+	code_info__produce_vars(ResumeVars, ResumeMap, FlushCode),
 
 		% Maybe save the heap state current before the condition;
 		% this ought to be after we make the failure continuation
 		% because that causes the cache to get flushed
 	code_info__get_globals(Globals),
-	{ 
+	{
 		globals__lookup_bool_option(Globals,
 			reclaim_heap_on_semidet_failure, yes),
-		code_util__goal_may_allocate_heap(CondGoal)
+		code_util__goal_may_allocate_heap(Goal)
 	->
 		ReclaimHeap = yes
 	;
 		ReclaimHeap = no
 	},
-	code_info__maybe_save_hp(ReclaimHeap, SaveHPCode, MaybeHpSlot),
+	code_info__maybe_save_hp(ReclaimHeap, SaveHpCode, MaybeHpSlot),
 
-		% Maybe save the current trail state before the condition
 	{ globals__lookup_bool_option(Globals, use_trail, UseTrail) },
-	code_info__maybe_save_ticket(UseTrail, SaveTicketCode, MaybeTicketSlot),
+	code_info__maybe_save_ticket(UseTrail, SaveTicketCode,
+		MaybeTicketSlot),
 
-	code_info__grab_code_info(CodeInfo),
+	code_info__prepare_for_ite_hijack(CodeModel, HijackInfo,
+		PrepareHijackCode),
 
-		% Generate the condition as either a semi-deterministic
-		% or as a non-deterministic goal (the failure continuation
-		% must be set up the same way)
-	code_info__push_resume_point_vars(ResumeVars),
-	code_gen__generate_goal(CondCodeModel, CondGoal, CondCode),
-	code_info__pop_resume_point_vars,
+	code_info__make_resume_point(ResumeVars, ResumeLocs, ResumeMap,
+		ResumePoint),
+	code_info__effect_resume_point(ResumePoint, CodeModel,
+		EffectResumeCode),
+
+	{ goal_may_hijack_top_redoip(Goal, MayHijack) },
+	code_info__maybe_push_temp_frame(CodeModel, MayHijack,
+		HijackInfo, CurFrameLval, TempFrameCode),
 
-	code_info__pop_failure_cont,
-	( { MaybeMaxfrLval = yes(MaxfrLval) } ->
-		code_info__do_soft_cut(MaxfrLval, SoftCutCode, SoftCutContCode),
-		code_info__unset_failure_cont(FlushCode)
-			% XXX why call unset_failure_cont here?
-			% We're going to call it from branch_end at the
-			% end of the `then' anyway, so is this
-			% one really necessary?
-	;
-		{ SoftCutCode = empty },
-		{ SoftCutContCode = empty },
-		{ FlushCode = empty }
-	),
+		% Generate the negated goal.
+	code_gen__generate_goal(CodeModel, Goal, GoalCode),
+
+	code_info__ite_enter_then(HijackInfo, CurFrameLval,
+		ThenNeckCode, ElseNeckCode),
 
 		% Kill again any variables that have become zombies
 	code_info__pickup_zombies(Zombies),
 	code_info__make_vars_forward_dead(Zombies),
 
-		% Discard hp and maybe trail ticket if the condition succeeded
-	code_info__maybe_discard_hp(MaybeHpSlot),
-	( { NondetCond = yes } ->
-			% We cannot discard the trail ticket if the 
-			% condition can be backtracked into.
-			% But we do need to call reset_ticket(..., solve)
-			% to check for floundering.
-		code_info__maybe_reset_ticket(MaybeTicketSlot,
-			solve, DiscardTicketCode)
+	code_info__get_forward_live_vars(LiveVars),
+
+	( { CodeModel = model_det } ->
+			% the then branch will never be reached
+		{ DiscardTicketCode = empty },
+		{ FailCode = empty }
 	;
-			% Discard the trail ticket if the condition succeeded
-			% and we will not backtrack into the condition
+		code_info__remember_position(AfterNegatedGoal),
+		% The call to reset_ticket(..., commit) here is necessary
+		% in order to properly detect floundering.
 		code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot,
-			commit, DiscardTicketCode)
+			commit, DiscardTicketCode),
+		code_info__generate_failure(FailCode),
+			% We want liveness after not(G) to be the same as
+			% after G. Information about what variables are where
+			% will be set by code_info__generate_resume_point.
+		code_info__reset_to_position(AfterNegatedGoal)
 	),
 
-		% Generate the then branch
-	trace__maybe_generate_internal_event_code(ThenGoal, ThenTraceCode),
-	code_gen__generate_goal(model_non, ThenGoal, ThenCode),
-	code_info__generate_branch_end(model_non, StoreMap, ThenSaveCode),
-
 		% Generate the entry to the else branch
-	code_info__slap_code_info(CodeInfo),
-	code_info__restore_failure_cont(RestoreContCode),
-	( { NondetCond = yes } ->
-			% We cannot release the stack slots used for
-			% the trail ticket and heap pointer if the
-			% condition can be backtracked into.
-		code_info__maybe_restore_hp(MaybeHpSlot, RestoreHPCode),
-		code_info__maybe_reset_and_pop_ticket(MaybeTicketSlot,
-			undo, RestoreTicketCode)
+	code_info__generate_resume_point(ResumePoint, ResumeCode),
+
+	code_info__set_forward_live_vars(LiveVars),
+
+	code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot, undo,
+		RestoreTicketCode),
+	code_info__maybe_restore_and_discard_hp(MaybeHpSlot, RestoreHpCode),
+
+	{ Code =
+		tree(FlushCode,
+		tree(PrepareHijackCode,
+		tree(EffectResumeCode,
+		tree(TempFrameCode,
+		tree(SaveHpCode,
+		tree(SaveTicketCode,
+		tree(GoalCode,
+		tree(ThenNeckCode,
+		tree(DiscardTicketCode,
+		tree(FailCode,
+		tree(ResumeCode,
+		tree(ElseNeckCode,
+		tree(RestoreTicketCode,
+		     RestoreHpCode)))))))))))))
+	}.
+
+%---------------------------------------------------------------------------%
+
+:- pred goal_may_hijack_top_redoip(hlds_goal::in, bool::out) is det.
+
+goal_may_hijack_top_redoip(GoalExpr - GoalInfo, MayHijack) :-
+	(
+		GoalExpr = conj(Conj),
+		goals_may_hijack_top_redoip(Conj, MayHijack)
 	;
-		code_info__maybe_restore_and_discard_hp(MaybeHpSlot,
-			RestoreHPCode),
-		code_info__maybe_reset_and_discard_ticket(MaybeTicketSlot,
-			undo, RestoreTicketCode)
-	),
+		GoalExpr = par_conj(Conj, _),
+		goals_may_hijack_top_redoip(Conj, MayHijack)
+	;
+		GoalExpr = call(_, _, _, _, _, _),
+		MayHijack = yes
+	;
+		GoalExpr = higher_order_call(_, _, _, _, _, _),
+		MayHijack = yes
+	;
+		GoalExpr = class_method_call(_, _, _, _, _, _),
+		MayHijack = yes
+	;
+		GoalExpr = switch(_, _, Cases, _),
+		cases_may_hijack_top_redoip(Cases, MayHijack)
+	;
+		GoalExpr = unify(_, _, _, _, _),
+		MayHijack = no
+	;
+		GoalExpr = disj(Disj, _),
+		(
+			goal_info_get_code_model(GoalInfo, CodeModel),
+			CodeModel = model_non
+		->
+			MayHijack = yes
+		;
+			goals_may_hijack_top_redoip(Disj, MayHijack)
+		)
+	;
+		GoalExpr = not(_SubGoal),
+		MayHijack = yes
+	;
+		GoalExpr = some(_, _SubGoal),
+		MayHijack = yes
+	;
+		GoalExpr = if_then_else(_, _, _, _, _),
+		MayHijack = yes
+	;
+		GoalExpr = pragma_c_code(_, _, _, _, _, _, _),
+		MayHijack = yes
+	).
+
+:- pred goals_may_hijack_top_redoip(list(hlds_goal)::in, bool::out) is det.
+
+goals_may_hijack_top_redoip([], no).
+goals_may_hijack_top_redoip([Goal | Goals], MayHijack) :-
+	goal_may_hijack_top_redoip(Goal, MayHijack0),
+	( MayHijack0 = yes ->
+		MayHijack = yes
+	;
+		goals_may_hijack_top_redoip(Goals, MayHijack)
+	).
 
-		% Generate the else branch
-	trace__maybe_generate_internal_event_code(ElseGoal, ElseTraceCode),
-	code_gen__generate_goal(model_non, ElseGoal, ElseCode),
-	code_info__generate_branch_end(model_non, StoreMap, ElseSaveCode),
+:- pred cases_may_hijack_top_redoip(list(case)::in, bool::out) is det.
 
-	code_info__get_next_label(EndLab),
-	{ JumpToEndCode = node([goto(label(EndLab))
-		- "Jump to the end of if-then-else"]) },
-	{ EndLabelCode = node([label(EndLab) - "end of if-then-else"]) },
-	{ Code = tree(ModContCode,
-		 tree(FlushEnclosingResumeVarsCode,
-		 tree(SaveMaxfrCode,
-		 tree(SaveHPCode,
-		 tree(SaveTicketCode,
-		 tree(CondCode,
-		 tree(SoftCutCode,
-		 tree(FlushCode,
-		 tree(DiscardTicketCode,
-		 tree(ThenTraceCode,
-		 tree(ThenCode,
-		 tree(ThenSaveCode,
-		 tree(JumpToEndCode,
-		 tree(SoftCutContCode,
-		 tree(RestoreContCode,
-		 tree(RestoreHPCode,
-		 tree(RestoreTicketCode,
-		 tree(ElseTraceCode,
-		 tree(ElseCode,
-		 tree(ElseSaveCode,
-		      EndLabelCode))))))))))))))))))))
-	},
-	code_info__remake_with_store_map(StoreMap).
+cases_may_hijack_top_redoip([], no).
+cases_may_hijack_top_redoip([case(_, Goal) | Goals], MayHijack) :-
+	goal_may_hijack_top_redoip(Goal, MayHijack0),
+	( MayHijack0 = yes ->
+		MayHijack = yes
+	;
+		cases_may_hijack_top_redoip(Goals, MayHijack)
+	).
 
 %---------------------------------------------------------------------------%
Index: compiler/jumpopt.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/jumpopt.m,v
retrieving revision 1.43
diff -u -r1.43 jumpopt.m
--- jumpopt.m	1998/01/23 12:56:39	1.43
+++ jumpopt.m	1998/02/27 02:24:17
@@ -66,8 +66,13 @@
 	map__init(Forkmap0),
 	jumpopt__build_forkmap(Instrs0, Sdprocmap, Forkmap0, Forkmap),
 	jumpopt__instr_list(Instrs0, comment(""), Instrmap, Blockmap, Lvalmap,
-		Procmap, Sdprocmap, Forkmap, Succmap, Instrs1, Mod),
-	opt_util__filter_out_bad_livevals(Instrs1, Instrs).
+		Procmap, Sdprocmap, Forkmap, Succmap, Instrs1),
+	opt_util__filter_out_bad_livevals(Instrs1, Instrs),
+	( Instrs = Instrs0 ->
+		Mod = no
+	;
+		Mod = yes
+	).
 
 %-----------------------------------------------------------------------------%
 
@@ -179,14 +184,14 @@
 	% between the if-val and the goto.
 
 :- pred jumpopt__instr_list(list(instruction), instr, instrmap, tailmap,
-	lvalmap, tailmap, tailmap, tailmap, tailmap, list(instruction), bool).
-:- mode jumpopt__instr_list(in, in, in, in, in, in, in, in, in, out, out)
+	lvalmap, tailmap, tailmap, tailmap, tailmap, list(instruction)).
+:- mode jumpopt__instr_list(in, in, in, in, in, in, in, in, in, out)
 	is det.
 
 jumpopt__instr_list([], _PrevInstr, _Instrmap, _Blockmap,
-		_Lvalmap, _Procmap, _Sdprocmap, _Forkmap, _Succmap, [], no).
+		_Lvalmap, _Procmap, _Sdprocmap, _Forkmap, _Succmap, []).
 jumpopt__instr_list([Instr0 | Instrs0], PrevInstr, Instrmap, Blockmap,
-		Lvalmap, Procmap, Sdprocmap, Forkmap, Succmap, Instrs, Mod) :-
+		Lvalmap, Procmap, Sdprocmap, Forkmap, Succmap, Instrs) :-
 	Instr0 = Uinstr0 - Comment0,
 	string__append(Comment0, " (redirected return)", Redirect),
 	(
@@ -204,8 +209,7 @@
 			opt_util__filter_out_livevals(Between0, Between1),
 			list__append(Between1, [livevals(Livevals) - "",
 				goto(Proc) - Redirect], NewInstrs),
-			RemainInstrs = Instrs0,
-			Mod0 = yes
+			RemainInstrs = Instrs0
 		;
 			% Look for semidet style tailcalls.
 			CallModel = semidet,
@@ -214,8 +218,7 @@
 		->
 			list__append(Between, [livevals(Livevals) - "",
 				goto(Proc) - Redirect], NewInstrs),
-			RemainInstrs = Instrs0,
-			Mod0 = yes
+			RemainInstrs = Instrs0
 		;
 			% Look for nondet style tailcalls.
 			CallModel = nondet(yes),
@@ -233,8 +236,7 @@
 				livevals(Livevals) - "",
 				goto(Proc) - Redirect
 			],
-			RemainInstrs = Instrs0,
-			Mod0 = yes
+			RemainInstrs = Instrs0
 		;
 			% Short circuit the return label if possible.
 			map__search(Instrmap, RetLabel, RetInstr)
@@ -243,18 +245,15 @@
 				DestLabel, _DestInstr),
 			( RetLabel = DestLabel ->
 				NewInstrs = [Instr0],
-				RemainInstrs = Instrs0,
-				Mod0 = no
+				RemainInstrs = Instrs0
 			;
 				NewInstrs = [call(Proc, label(DestLabel),
 					GC, CallModel) - Redirect],
-				RemainInstrs = Instrs0,
-				Mod0 = yes
+				RemainInstrs = Instrs0
 			)
 		;
 			NewInstrs = [Instr0],
-			RemainInstrs = Instrs0,
-			Mod0 = no
+			RemainInstrs = Instrs0
 		)
 	;
 		Uinstr0 = goto(label(TargetLabel))
@@ -264,8 +263,7 @@
 			opt_util__is_this_label_next(TargetLabel, Instrs0, _)
 		->
 			NewInstrs = [],
-			RemainInstrs = Instrs0,
-			Mod0 = yes
+			RemainInstrs = Instrs0
 		;
 			PrevInstr = if_val(_, label(IfTargetLabel)),
 			opt_util__is_this_label_next(IfTargetLabel, Instrs0, _)
@@ -277,8 +275,7 @@
 			% We cannot eliminate the instruction here because
 			% that would require altering the if_val instruction.
 			NewInstrs = [Instr0],
-			RemainInstrs = Instrs0,
-			Mod0 = no
+			RemainInstrs = Instrs0
 		;
 			% Replace a jump to a det epilog with the epilog.
 			map__search(Procmap, TargetLabel, Between0)
@@ -286,8 +283,7 @@
 			jumpopt__adjust_livevals(PrevInstr, Between0, Between),
 			list__append(Between, [goto(succip) - "shortcircuit"],
 				NewInstrs),
-			RemainInstrs = Instrs0,
-			Mod0 = yes
+			RemainInstrs = Instrs0
 		;
 			% Replace a jump to a semidet epilog with the epilog.
 			map__search(Sdprocmap, TargetLabel, Between0)
@@ -295,16 +291,14 @@
 			jumpopt__adjust_livevals(PrevInstr, Between0, Between),
 			list__append(Between, [goto(succip) - "shortcircuit"],
 				NewInstrs),
-			RemainInstrs = Instrs0,
-			Mod0 = yes
+			RemainInstrs = Instrs0
 		;
 			% Replace a jump to a nondet epilog with the epilog.
 			map__search(Succmap, TargetLabel, BetweenIncl0)
 		->
 			jumpopt__adjust_livevals(PrevInstr, BetweenIncl0,
 				NewInstrs),
-			RemainInstrs = Instrs0,
-			Mod0 = yes
+			RemainInstrs = Instrs0
 		;
 			% Replace a jump to a non-epilog block with the
 			% block itself. These jumps are treated separately
@@ -336,9 +330,8 @@
 			map__delete(Blockmap, DestLabel, CrippledBlockmap),
 			jumpopt__instr_list(AdjustedBlock, comment(""),
 				Instrmap, CrippledBlockmap, Lvalmap, Procmap,
-				Sdprocmap, Forkmap, Succmap, NewInstrs, _),
-			RemainInstrs = Instrs0,
-			Mod0 = yes
+				Sdprocmap, Forkmap, Succmap, NewInstrs),
+			RemainInstrs = Instrs0
 		;
 			% Short-circuit the goto.
 			map__search(Instrmap, TargetLabel, TargetInstr)
@@ -352,18 +345,15 @@
 				Canfallthrough),
 			( Canfallthrough = no ->
 				NewInstrs0 = [UdestInstr - Shorted],
-				RemainInstrs = Instrs0,
-				Mod0 = yes
+				RemainInstrs = Instrs0
 			;
 				( TargetLabel = DestLabel ->
 					NewInstrs0 = [Instr0],
-					RemainInstrs = Instrs0,
-					Mod0 = no
+					RemainInstrs = Instrs0
 				;
 					NewInstrs0 = [goto(label(DestLabel))
 						- Shorted],
-					RemainInstrs = Instrs0,
-					Mod0 = yes
+					RemainInstrs = Instrs0
 				)
 			),
 			( map__search(Lvalmap, DestLabel, yes(Lvalinstr)) ->
@@ -374,19 +364,18 @@
 			)
 		;
 			NewInstrs = [Instr0],
-			RemainInstrs = Instrs0,
-			Mod0 = no
+			RemainInstrs = Instrs0
 		)
 	; Uinstr0 = computed_goto(Index, LabelList0) ->
 		% Short-circuit all the destination labels.
-		jumpopt__short_labels(LabelList0, Instrmap, LabelList, Mod0),
+		jumpopt__short_labels(LabelList0, Instrmap, LabelList),
 		RemainInstrs = Instrs0,
-		( Mod0 = yes ->
+		( LabelList = LabelList0 ->
+			NewInstrs = [Instr0]
+		;
 			string__append(Comment0, " (some shortcircuits)",
 				Shorted),
 			NewInstrs = [computed_goto(Index, LabelList) - Shorted]
-		;
-			NewInstrs = [Instr0]
 		)
 	; Uinstr0 = if_val(Cond, label(TargetLabel)) ->
 		(
@@ -435,8 +424,7 @@
 			% the recursive call. We can't go into an infinite
 			% loop because each application of the transformation
 			% strictly reduces the size of the code.
-			RemainInstrs = [NewInstr | AfterGoto],
-			Mod0 = yes
+			RemainInstrs = [NewInstr | AfterGoto]
 		;
 			map__search(Instrmap, TargetLabel, TargetInstr)
 		->
@@ -486,8 +474,7 @@
 				Proceed = goto(succip) - "shortcircuit",
 				list__append([NewAssign | Between], [Proceed],
 					NewInstrs),
-				RemainInstrs = Instrs0,
-				Mod0 = yes
+				RemainInstrs = Instrs0
 			;
 				% Try to short-circuit the destination.
 
@@ -497,22 +484,29 @@
 					Comment0, Shorted),
 				NewInstrs = [if_val(Cond, label(DestLabel))
 					- Shorted],
-				RemainInstrs = Instrs0,
-				Mod0 = yes
+				RemainInstrs = Instrs0
 			;
 				NewInstrs = [Instr0],
-				RemainInstrs = Instrs0,
-				Mod0 = no
+				RemainInstrs = Instrs0
 			)
 		;
 			NewInstrs = [Instr0],
-			RemainInstrs = Instrs0,
-			Mod0 = no
+			RemainInstrs = Instrs0
+		)
+	; Uinstr0 = assign(Lval, Rval0) ->
+		% Any labels mentioned in Rval0 should be short-circuited.
+		jumpopt__short_labels_rval(Rval0, Instrmap, Rval),
+		RemainInstrs = Instrs0,
+		( Rval = Rval0 ->
+			NewInstrs = [Instr0]
+		;
+			string__append(Comment0, " (some shortcircuits)",
+				Shorted),
+			NewInstrs = [assign(Lval, Rval) - Shorted]
 		)
 	;
 		NewInstrs = [Instr0],
-		RemainInstrs = Instrs0,
-		Mod0 = no
+		RemainInstrs = Instrs0
 	),
 	( ( Uinstr0 = comment(_) ; NewInstrs = [] ) ->
 		NewPrevInstr = PrevInstr
@@ -520,13 +514,8 @@
 		NewPrevInstr = Uinstr0
 	),
 	jumpopt__instr_list(RemainInstrs, NewPrevInstr, Instrmap, Blockmap,
-		Lvalmap, Procmap, Sdprocmap, Forkmap, Succmap, Instrs9, Mod1),
-	list__append(NewInstrs, Instrs9, Instrs),
-	( Mod0 = no, Mod1 = no ->
-		Mod = no
-	;
-		Mod = yes
-	).
+		Lvalmap, Procmap, Sdprocmap, Forkmap, Succmap, Instrs9),
+	list__append(NewInstrs, Instrs9, Instrs).
 
 % We avoid generating statements that redefine the value of a location
 % by comparing its old contents for non-equality with zero.
@@ -588,32 +577,25 @@
 	% Short-circuit the given label by following any gotos at the
 	% labelled instruction or by falling through consecutive labels.
 
-:- pred jumpopt__short_label(label, instrmap, label, bool).
-:- mode jumpopt__short_label(in, in, out, out) is det.
+:- pred jumpopt__short_label(label, instrmap, label).
+:- mode jumpopt__short_label(in, in, out) is det.
 
-jumpopt__short_label(Label0, Instrmap, Label, Mod) :-
-	map__lookup(Instrmap, Label0, Instr0),
-	jumpopt__final_dest(Label0, Instr0, Instrmap, Label, _Instr),
-	( Label = Label0 ->
-		Mod = no
+jumpopt__short_label(Label0, Instrmap, Label) :-
+	( map__search(Instrmap, Label0, Instr0) ->
+		jumpopt__final_dest(Label0, Instr0, Instrmap, Label, _Instr)
 	;
-		Mod = yes
+		Label = Label0
 	).
 
-:- pred jumpopt__short_labels(list(label), instrmap, list(label), bool).
-:- mode jumpopt__short_labels(in, in, out, out) is det.
+:- pred jumpopt__short_labels(list(label), instrmap, list(label)).
+:- mode jumpopt__short_labels(in, in, out) is det.
 
 % XXX these uses of the Mod argument should be replaced by accumulator passing
 
-jumpopt__short_labels([], _Instrmap, [], no).
-jumpopt__short_labels([Label0 | Labels0], Instrmap, [Label | Labels], Mod) :-
-	jumpopt__short_label(Label0, Instrmap, Label, Mod1),
-	jumpopt__short_labels(Labels0, Instrmap, Labels, Mod2),
-	( Mod1 = no, Mod2 = no ->
-		Mod = no
-	;
-		Mod = yes
-	).
+jumpopt__short_labels([], _Instrmap, []).
+jumpopt__short_labels([Label0 | Labels0], Instrmap, [Label | Labels]) :-
+	jumpopt__short_label(Label0, Instrmap, Label),
+	jumpopt__short_labels(Labels0, Instrmap, Labels).
 
 %-----------------------------------------------------------------------------%
 
@@ -649,5 +631,99 @@
 		DestLabel = SrcLabel,
 		DestInstr = SrcInstr
 	).
+
+%-----------------------------------------------------------------------------%
+
+:- pred jumpopt__short_labels_rval(rval, instrmap, rval).
+:- mode jumpopt__short_labels_rval(in, in, out) is det.
+
+jumpopt__short_labels_rval(lval(Lval0), Instrmap, lval(Lval)) :-
+	jumpopt__short_labels_lval(Lval0, Instrmap, Lval).
+jumpopt__short_labels_rval(var(_), _, _) :-
+	error("var rval in jumpopt__short_labels_rval").
+jumpopt__short_labels_rval(create(Tag, Rvals0, Unique, Cell, Type), Instrmap,
+		create(Tag, Rvals, Unique, Cell, Type)) :-
+	jumpopt__short_labels_maybe_rvals(Rvals0, Instrmap, Rvals).
+jumpopt__short_labels_rval(mkword(Tag, Rval0), Instrmap,
+		mkword(Tag, Rval)) :-
+	jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_rval(const(Const0), Instrmap, const(Const)) :-
+	jumpopt__short_labels_const(Const0, Instrmap, Const).
+jumpopt__short_labels_rval(unop(Op, Rval0), Instrmap, unop(Op, Rval)) :-
+	jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_rval(binop(Op, LRval0, RRval0), Instrmap,
+		binop(Op, LRval, RRval)) :-
+	jumpopt__short_labels_rval(LRval0, Instrmap, LRval),
+	jumpopt__short_labels_rval(RRval0, Instrmap, RRval).
+jumpopt__short_labels_rval(mem_addr(MemRef), _, mem_addr(MemRef)).
+
+:- pred jumpopt__short_labels_const(rval_const, instrmap, rval_const).
+:- mode jumpopt__short_labels_const(in, in, out) is det.
+
+jumpopt__short_labels_const(true, _, true).
+jumpopt__short_labels_const(false, _, false).
+jumpopt__short_labels_const(int_const(I), _, int_const(I)).
+jumpopt__short_labels_const(float_const(F), _, float_const(F)).
+jumpopt__short_labels_const(string_const(S), _, string_const(S)).
+jumpopt__short_labels_const(label_entry(Label0), Instrmap,
+		label_entry(Label)) :-
+	jumpopt__short_label(Label0, Instrmap, Label).
+jumpopt__short_labels_const(code_addr_const(CodeAddr0), Instrmap,
+		code_addr_const(CodeAddr)) :-
+	( CodeAddr0 = label(Label0) ->
+		jumpopt__short_label(Label0, Instrmap, Label),
+		CodeAddr = label(Label)
+	;
+		CodeAddr = CodeAddr0
+	).
+jumpopt__short_labels_const(data_addr_const(D), _, data_addr_const(D)).
+
+:- pred jumpopt__short_labels_maybe_rvals(list(maybe(rval)), instrmap,
+	list(maybe(rval))).
+:- mode jumpopt__short_labels_maybe_rvals(in, in, out) is det.
+
+jumpopt__short_labels_maybe_rvals([], _, []).
+jumpopt__short_labels_maybe_rvals([MaybeRval0 | MaybeRvals0], Instrmap,
+		[MaybeRval | MaybeRvals]) :-
+	(
+		MaybeRval0 = no,
+		MaybeRval = no
+	;
+		MaybeRval0 = yes(Rval0),
+		jumpopt__short_labels_rval(Rval0, Instrmap, Rval),
+		MaybeRval = yes(Rval)
+	),
+	jumpopt__short_labels_maybe_rvals(MaybeRvals0, Instrmap, MaybeRvals).
+
+:- pred jumpopt__short_labels_lval(lval, instrmap, lval).
+:- mode jumpopt__short_labels_lval(in, in, out) is det.
+
+jumpopt__short_labels_lval(reg(T, N), _, reg(T, N)).
+jumpopt__short_labels_lval(succip, _, succip).
+jumpopt__short_labels_lval(maxfr, _, maxfr).
+jumpopt__short_labels_lval(curfr, _, curfr).
+jumpopt__short_labels_lval(hp, _, hp).
+jumpopt__short_labels_lval(sp, _, sp).
+jumpopt__short_labels_lval(temp(T, N), _, temp(T, N)).
+jumpopt__short_labels_lval(stackvar(N), _, stackvar(N)).
+jumpopt__short_labels_lval(framevar(N), _, framevar(N)).
+jumpopt__short_labels_lval(succip(Rval0), Instrmap, succip(Rval)) :-
+	jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_lval(redoip(Rval0), Instrmap, redoip(Rval)) :-
+	jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_lval(redofr(Rval0), Instrmap, redofr(Rval)) :-
+	jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_lval(succfr(Rval0), Instrmap, succfr(Rval)) :-
+	jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_lval(prevfr(Rval0), Instrmap, prevfr(Rval)) :-
+	jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_lval(field(Tag, Rval0, Field0), Instrmap,
+		field(Tag, Rval, Field)) :-
+	jumpopt__short_labels_rval(Rval0, Instrmap, Rval),
+	jumpopt__short_labels_rval(Field0, Instrmap, Field).
+jumpopt__short_labels_lval(mem_ref(Rval0), Instrmap, mem_ref(Rval)) :-
+	jumpopt__short_labels_rval(Rval0, Instrmap, Rval).
+jumpopt__short_labels_lval(lvar(_), _, _) :-
+	error("lvar lval in jumpopt__short_labels_lval").
 
 %-----------------------------------------------------------------------------%
Index: compiler/livemap.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/livemap.m,v
retrieving revision 1.35
diff -u -r1.35 livemap.m
--- livemap.m	1998/06/09 02:13:13	1.35
+++ livemap.m	1998/06/29 08:00:26
@@ -160,7 +160,7 @@
 		Livemap = Livemap0,
 		DontValueNumber = DontValueNumber0
 	;
-		Uinstr0 = mkframe(_, _, _, _),
+		Uinstr0 = mkframe(_, _),
 		Livemap = Livemap0,
 		Livevals = Livevals0,
 		Instrs = Instrs0,
Index: compiler/llds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/llds.m,v
retrieving revision 1.225
diff -u -r1.225 llds.m
--- llds.m	1998/06/09 02:13:21	1.225
+++ llds.m	1998/06/29 07:24:49
@@ -152,16 +152,16 @@
 			% says whether tail recursion elimination is
 			% potentially applicable to the call.
 
-	;	mkframe(string, int, maybe(pragma_c_struct), code_addr)
-			% mkframe(Comment, SlotCount, MaybePragmaStruct,
-			% FailureContinuation) creates a nondet stack frame.
-			% Comment says what predicate creates the frame.
-			% SlotCount says how many ordinary framevar slots
-			% it ought to have. If MaybePragmaStruct is yes,
-			% the argument gives the details of the structure
-			% which occupies the rest of the framevar slots.
-			% CodeAddr is the code address to branch to when
-			% trying to generate the next solution from this
+	;	mkframe(nondet_frame_info, code_addr)
+			% mkframe(NondetFrameInfo, CodeAddr) creates a nondet
+			% stack frame. NondetFrameInfo says whether the frame
+			% is an ordinary frame, containing the variables of a
+			% model_non procedure, or a temp frame used only for
+			% its redoip/redofr slots. If the former, it also
+			% gives the details of the size of the variable parts
+			% of the frame (temp frames have no variable sized
+			% parts). CodeAddr is the code address to branch to
+			% when trying to generate the next solution from this
 			% choice point.
 
 	;	modframe(code_addr)
@@ -322,6 +322,17 @@
 			% term is specified by the given lval.
 	.
 
+:- type nondet_frame_info
+	--->	temp_frame
+	;	ordinary_frame(
+			string, 		% Name of the predicate.
+			int,			% Number of framevar slots.
+			maybe(pragma_c_struct)	% If yes, the frame should
+						% also contain this struct
+						% (for use by a model_non
+						% pragma C code).
+		).
+
 	% Procedures defined by nondet pragma C codes must have some way of
 	% preserving information after a success, so that when control
 	% backtracks to the procedure, the C code knows what to do.
@@ -420,6 +431,7 @@
 	;	curfr		% a stored curfr
 	;	maxfr		% a stored maxfr
 	;	redoip
+	;	redofr
 	;	hp
 	;	var(type, inst)	% a variable
 	;	unwanted.	% something we don't need, or used as
@@ -485,6 +497,12 @@
 				% nondet stack frame; holds the code address
 				% to jump to on failure.
 
+	;	redofr(rval)	% the redofr slot of the specified
+				% nondet stack frame; holds the address of
+				% the frame that the curfr register should be
+				% set to when backtracking through the redoip
+				% slot.
+
 	;	succfr(rval)	% The succfr slot of the specified
 				% nondet stack frame; holds the address of
 				% caller's nondet stack frame.  On successful
@@ -774,6 +792,7 @@
 llds__lval_type(framevar(_), word).
 llds__lval_type(succip(_), code_ptr).
 llds__lval_type(redoip(_), code_ptr).
+llds__lval_type(redofr(_), data_ptr).
 llds__lval_type(succfr(_), data_ptr).
 llds__lval_type(prevfr(_), data_ptr).
 llds__lval_type(field(_, _, _), word).
Index: compiler/llds_common.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/llds_common.m,v
retrieving revision 1.18
diff -u -r1.18 llds_common.m
--- llds_common.m	1998/06/09 02:13:23	1.18
+++ llds_common.m	1998/06/29 08:00:32
@@ -180,7 +180,7 @@
 		Instr = Instr0,
 		Info = Info0
 	;
-		Instr0 = mkframe(_, _, _, _),
+		Instr0 = mkframe(_, _),
 		Instr = Instr0,
 		Info = Info0
 	;
Index: compiler/llds_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/llds_out.m,v
retrieving revision 1.84
diff -u -r1.84 llds_out.m
--- llds_out.m	1998/06/18 06:06:32	1.84
+++ llds_out.m	1998/07/01 12:43:19
@@ -215,6 +215,11 @@
 :- mode output_c_file_mercury_headers(di, uo) is det.
 
 output_c_file_mercury_headers -->
+		% The next two lines are only until MR_USE_REDOFR is default.
+		% The #undef avoids a warning if the invocation of mgnuc
+		% also supplies a definition on the command line.
+	io__write_string("#undef MR_USE_REDOFR\n"),
+	io__write_string("#define MR_USE_REDOFR\n"),
 	globals__io_get_trace_level(TraceLevel),
 	( { trace_level_trace_interface(TraceLevel, yes) } ->
 		io__write_string("#define MR_STACK_TRACE_THIS_MODULE\n"),
@@ -737,7 +742,7 @@
 		(
 			Instr = call(_, label(ContLabel), _, _)
 		;
-			Instr = mkframe(_, _, _, label(ContLabel))
+			Instr = mkframe(_, label(ContLabel))
 		;
 			Instr = modframe(label(ContLabel))
 		;
@@ -845,14 +850,19 @@
 	output_code_addr_decls(Target, "", "", 0, _, DeclSet0, DeclSet1),
 	output_code_addr_decls(ContLabel, "", "", 0, _, DeclSet1, DeclSet).
 output_instruction_decls(c_code(_), DeclSet, DeclSet) --> [].
-output_instruction_decls(mkframe(_, _, MaybeStruct, FailureContinuation),
+output_instruction_decls(mkframe(FrameInfo, FailureContinuation),
 		DeclSet0, DeclSet) -->
 	(
-		{ MaybeStruct = yes(pragma_c_struct(StructName,
-			StructFields, MaybeStructFieldsContext)) }
-	->
-		{ bintree_set__is_member(pragma_c_struct(StructName), DeclSet0) ->
-			string__append_list(["struct ", StructName, " has been declared already"], Msg),
+		{ FrameInfo = ordinary_frame(_, _, yes(Struct)) },
+		{ Struct = pragma_c_struct(StructName, StructFields,
+				MaybeStructFieldsContext) }
+	->
+		{
+			bintree_set__is_member(pragma_c_struct(StructName),
+				DeclSet0)
+		->
+			string__append_list(["struct ", StructName,
+				" has been declared already"], Msg),
 			error(Msg)
 		;
 			true
@@ -868,7 +878,8 @@
 			io__write_string(StructFields)
 		),
 		io__write_string("\n};\n"),
-		{ bintree_set__insert(DeclSet0, pragma_c_struct(StructName), DeclSet1) }
+		{ bintree_set__insert(DeclSet0, pragma_c_struct(StructName),
+			DeclSet1) }
 	;
 		{ DeclSet1 = DeclSet0 }
 	),
@@ -1097,23 +1108,31 @@
 	io__write_string("\t"),
 	io__write_string(C_Code_String).
 
-output_instruction(mkframe(Msg, Num, MaybePragmaStructName, FailCont), _) -->
-	( { MaybePragmaStructName = yes(pragma_c_struct(StructName, _, _)) } ->
-		io__write_string("\tmkpragmaframe("""),
-		io__write_string(Msg),
-		io__write_string(""", "),
-		io__write_int(Num),
-		io__write_string(", "),
-		io__write_string(StructName),
-		io__write_string(", "),
-		output_code_addr(FailCont),
-		io__write_string(");\n")
+output_instruction(mkframe(FrameInfo, FailCont), _) -->
+	(
+		{ FrameInfo = ordinary_frame(Msg, Num, MaybeStruct) },
+		( { MaybeStruct = yes(pragma_c_struct(StructName, _, _)) } ->
+			io__write_string("\tmkpragmaframe("""),
+			io__write_string(Msg),
+			io__write_string(""", "),
+			io__write_int(Num),
+			io__write_string(", "),
+			io__write_string(StructName),
+			io__write_string(", "),
+			output_code_addr(FailCont),
+			io__write_string(");\n")
+		;
+			io__write_string("\tmkframe("""),
+			io__write_string(Msg),
+			io__write_string(""", "),
+			io__write_int(Num),
+			io__write_string(", "),
+			output_code_addr(FailCont),
+			io__write_string(");\n")
+		)
 	;
-		io__write_string("\tmkframe("""),
-		io__write_string(Msg),
-		io__write_string(""", "),
-		io__write_int(Num),
-		io__write_string(", "),
+		{ FrameInfo = temp_frame },
+		io__write_string("\tmktempframe("),
 		output_code_addr(FailCont),
 		io__write_string(");\n")
 	).
@@ -1503,6 +1522,7 @@
 output_live_value_type(succip) --> io__write_string("MR_succip").
 output_live_value_type(curfr) --> io__write_string("MR_curfr").
 output_live_value_type(maxfr) --> io__write_string("MR_maxfr").
+output_live_value_type(redofr) --> io__write_string("MR_redofr").
 output_live_value_type(redoip) --> io__write_string("MR_redoip").
 output_live_value_type(hp) --> io__write_string("MR_hp").
 output_live_value_type(unwanted) --> io__write_string("unwanted").
@@ -1949,6 +1969,10 @@
 		DeclSet0, DeclSet) -->
 	output_rval_decls(Rval, FirstIndent, LaterIndent, N0, N,
 		DeclSet0, DeclSet).
+output_lval_decls(redofr(Rval), FirstIndent, LaterIndent, N0, N,
+		DeclSet0, DeclSet) -->
+	output_rval_decls(Rval, FirstIndent, LaterIndent, N0, N,
+		DeclSet0, DeclSet).
 output_lval_decls(redoip(Rval), FirstIndent, LaterIndent, N0, N,
 		DeclSet0, DeclSet) -->
 	output_rval_decls(Rval, FirstIndent, LaterIndent, N0, N,
@@ -3034,6 +3058,10 @@
 	io__write_string(")").
 output_lval(prevfr(Rval)) -->
 	io__write_string("bt_prevfr("),
+	output_rval(Rval),
+	io__write_string(")").
+output_lval(redofr(Rval)) -->
+	io__write_string("bt_redofr("),
 	output_rval(Rval),
 	io__write_string(")").
 output_lval(redoip(Rval)) -->



More information about the developers mailing list