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

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


Index: compiler/code_info.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/code_info.m,v
retrieving revision 1.223
diff -u -r1.223 code_info.m
--- code_info.m	1998/06/18 06:05:53	1.223
+++ code_info.m	1998/07/01 11:58:48
@@ -11,10 +11,11 @@
 % This file defines the code_info type and various operations on it.
 % The code_info structure is the 'state' of the code generator.
 %
-% This file is organized into eight submodules:
+% This file is organized into nine submodules:
 %
 %	- the code_info structure and its access predicates
 %	- simple wrappers around access predicates
+%	- handling branched control structures
 %	- handling failure continuations
 %	- handling liveness issues
 %	- saving and restoring heap pointers, trail tickets etc
@@ -22,11 +23,6 @@
 %	- managing the info required by garbage collection and value numbering
 %	- managing stack slots
 %
-% Note: Any new "state" arguments (eg counters) that should be strictly
-% threaded (for example the counter used for allocating new labels) will
-% require changes to code_info__slap_code_info/3.
-%
-%---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
 
 :- module code_info.
@@ -45,6 +41,7 @@
 
 :- import_module set, varset, stack.
 :- import_module string, require, char, bimap, tree, int.
+:- import_module unsafe, io.
 
 %---------------------------------------------------------------------------%
 
@@ -68,13 +65,17 @@
 		% 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,
-	int /* cell number */, code_info).
+	int, resume_point_info, code_info).
 :- mode code_info__init(in, in, in, in, in, in, in, in, in, in, in, in,
-	out) is det.
+	out, out) is det.
 
-		% Get the variables for the current procedure.
-:- pred code_info__get_varset(varset, code_info, code_info).
-:- mode code_info__get_varset(out, in, out) is det.
+		% Get the globals table.
+:- pred code_info__get_globals(globals, code_info, code_info).
+:- mode code_info__get_globals(out, in, out) is det.
+
+		% Get the HLDS of the entire module.
+:- pred code_info__get_module_info(module_info, code_info, code_info).
+:- mode code_info__get_module_info(out, in, out) is det.
 
 		% Get the id of the predicate we are generating code for.
 :- pred code_info__get_pred_id(pred_id, code_info, code_info).
@@ -88,13 +89,13 @@
 :- pred code_info__get_proc_info(proc_info, code_info, code_info).
 :- mode code_info__get_proc_info(out, in, out) is det.
 
-		% Get the flag that indicates whether succip is used or not.
-:- pred code_info__get_succip_used(bool, code_info, code_info).
-:- mode code_info__get_succip_used(out, in, out) is det.
+		% Get the variables for the current procedure.
+:- pred code_info__get_varset(varset, code_info, code_info).
+:- mode code_info__get_varset(out, in, out) is det.
 
-		% Get the HLDS of the entire module.
-:- pred code_info__get_module_info(module_info, code_info, code_info).
-:- mode code_info__get_module_info(out, in, out) is det.
+:- pred code_info__get_maybe_trace_info(maybe(trace_info),
+	code_info, code_info).
+:- mode code_info__get_maybe_trace_info(out, in, out) is det.
 
 		% Get the set of currently forward-live variables.
 :- pred code_info__get_forward_live_vars(set(var), code_info, code_info).
@@ -114,22 +115,17 @@
 :- pred code_info__set_instmap(instmap, code_info, code_info).
 :- mode code_info__set_instmap(in, in, out) is det.
 
-		% Get the globals table.
-:- pred code_info__get_globals(globals, code_info, code_info).
-:- mode code_info__get_globals(out, in, out) is det.
+:- pred code_info__get_cell_count(int, code_info, code_info).
+:- mode code_info__get_cell_count(out, in, out) is det.
+
+		% Get the flag that indicates whether succip is used or not.
+:- pred code_info__get_succip_used(bool, code_info, code_info).
+:- mode code_info__get_succip_used(out, in, out) is det.
 
 :- pred code_info__get_layout_info(map(label, internal_layout_info), 
-		code_info, code_info).
+	code_info, code_info).
 :- mode code_info__get_layout_info(out, in, out) is det.
 
-:- pred code_info__get_maybe_trace_info(maybe(trace_info),
-		code_info, code_info).
-:- mode code_info__get_maybe_trace_info(out, in, out) is det.
-
-:- pred code_info__set_maybe_trace_info(maybe(trace_info), 
-		code_info, code_info).
-:- mode code_info__set_maybe_trace_info(in, in, out) is det.
-
 %---------------------------------------------------------------------------%
 
 :- implementation.
@@ -137,14 +133,15 @@
 :- pred code_info__get_var_slot_count(int, code_info, code_info).
 :- mode code_info__get_var_slot_count(out, in, out) is det.
 
-:- pred code_info__get_label_count(int, code_info, code_info).
-:- mode code_info__get_label_count(out, in, out) is det.
+:- pred code_info__set_maybe_trace_info(maybe(trace_info),
+	code_info, code_info).
+:- mode code_info__set_maybe_trace_info(in, in, out) is det.
 
-:- pred code_info__set_label_count(int, code_info, code_info).
-:- mode code_info__set_label_count(in, in, out) is det.
+:- pred code_info__get_zombies(set(var), code_info, code_info).
+:- mode code_info__get_zombies(out, in, out) is det.
 
-:- pred code_info__set_cell_count(int, code_info, code_info).
-:- mode code_info__set_cell_count(in, in, out) is det.
+:- pred code_info__set_zombies(set(var), code_info, code_info).
+:- mode code_info__set_zombies(in, in, out) is det.
 
 :- pred code_info__get_exprn_info(exprn_info, code_info, code_info).
 :- mode code_info__get_exprn_info(out, in, out) is det.
@@ -152,27 +149,6 @@
 :- pred code_info__set_exprn_info(exprn_info, code_info, code_info).
 :- mode code_info__set_exprn_info(in, in, out) is det.
 
-:- pred code_info__set_succip_used(bool, code_info, code_info).
-:- mode code_info__set_succip_used(in, in, out) is det.
-
-:- pred code_info__get_fail_stack(fail_stack, code_info, code_info).
-:- mode code_info__get_fail_stack(out, in, out) is det.
-
-:- pred code_info__set_fail_stack(fail_stack, code_info, code_info).
-:- mode code_info__set_fail_stack(in, in, out) is det.
-
-:- pred code_info__get_avail_temp_slots(set(lval), code_info, code_info).
-:- mode code_info__get_avail_temp_slots(out, in, out) is det.
-
-:- pred code_info__set_avail_temp_slots(set(lval), code_info, code_info).
-:- mode code_info__set_avail_temp_slots(in, in, out) is det.
-
-:- pred code_info__get_max_temp_slot_count(int, code_info, code_info).
-:- mode code_info__get_max_temp_slot_count(out, in, out) is det.
-
-:- pred code_info__set_max_temp_slot_count(int, code_info, code_info).
-:- mode code_info__set_max_temp_slot_count(in, in, out) is det.
-
 :- pred code_info__get_temps_in_use(map(lval, slot_contents),
 	code_info, code_info).
 :- mode code_info__get_temps_in_use(out, in, out) is det.
@@ -181,107 +157,114 @@
 	code_info, code_info).
 :- mode code_info__set_temps_in_use(in, in, out) is det.
 
-:- pred code_info__set_layout_info(map(label, internal_layout_info), 
-		code_info, code_info).
-:- mode code_info__set_layout_info(in, in, out) is det.
+:- pred code_info__get_fail_info(fail_info, code_info, code_info).
+:- mode code_info__get_fail_info(out, in, out) is det.
 
-:- pred code_info__get_zombies(set(var), code_info, code_info).
-:- mode code_info__get_zombies(out, in, out) is det.
+:- pred code_info__set_fail_info(fail_info, code_info, code_info).
+:- mode code_info__set_fail_info(in, in, out) is det.
 
-:- pred code_info__set_zombies(set(var), code_info, code_info).
-:- mode code_info__set_zombies(in, in, out) is det.
+:- pred code_info__get_label_count(int, code_info, code_info).
+:- mode code_info__get_label_count(out, in, out) is det.
 
-:- pred code_info__get_resume_point_stack(stack(set(var)),
-	code_info, code_info).
-:- mode code_info__get_resume_point_stack(out, in, out) is det.
+:- pred code_info__set_label_count(int, code_info, code_info).
+:- mode code_info__set_label_count(in, in, out) is det.
+
+:- pred code_info__set_cell_count(int, code_info, code_info).
+:- mode code_info__set_cell_count(in, in, out) is det.
+
+:- pred code_info__set_succip_used(bool, code_info, code_info).
+:- mode code_info__set_succip_used(in, in, out) is det.
 
-:- pred code_info__set_resume_point_stack(stack(set(var)),
+:- pred code_info__set_layout_info(map(label, internal_layout_info), 
 	code_info, code_info).
-:- mode code_info__set_resume_point_stack(in, in, out) is det.
+:- mode code_info__set_layout_info(in, in, out) is det.
+
+:- pred code_info__get_max_temp_slot_count(int, code_info, code_info).
+:- mode code_info__get_max_temp_slot_count(out, in, out) is det.
+
+:- pred code_info__set_max_temp_slot_count(int, code_info, code_info).
+:- mode code_info__set_max_temp_slot_count(in, in, out) is det.
 
-:- pred code_info__get_commit_triple_count(int, code_info, code_info).
-:- mode code_info__get_commit_triple_count(out, in, out) is det.
+:- pred code_info__get_avail_temp_slots(set(lval), code_info, code_info).
+:- mode code_info__get_avail_temp_slots(out, in, out) is det.
 
-:- pred code_info__set_commit_triple_count(int, code_info, code_info).
-:- mode code_info__set_commit_triple_count(in, in, out) is det.
+:- pred code_info__set_avail_temp_slots(set(lval), code_info, code_info).
+:- mode code_info__set_avail_temp_slots(in, in, out) is det.
 
 %---------------------------------------------------------------------------%
 
+	% The code_info structure has three groups of fields.
+	%
+	% Some fields are static; they are set when the code_info structure
+	% is initialized, and never changed afterwards.
+	%
+	% Some fields record information about the state of the code generator
+	% at a particular location in the HLDS code of the current procedure.
+	% At the start of the branched control structure, the code generator
+	% remembers the values of these fields, and starts generating code
+	% for each branch from the same location-dependent state.
+	%
+	% Some fields record persistent information that does not depend
+	% on a code location. Updates to these fields must remain effective
+	% even when the code generator resets its location-dependent state.
+
 :- type code_info	--->
-		code_info(
-			int,		% The number of stack slots allocated.
-					% for storing variables.
-					% (Some extra stack slots are used
-					% for saving and restoring registers.)
-			int,		% Counter for the local labels used
-					% by this procedure.
-			varset,		% The variables in this procedure.
-			pred_id,	% The label of the current predicate.
-			proc_id,	% The label of the current procedure.
-			int,		% Counter for cells in this proc.
-			exprn_info,	% A map storing the information about
-					% the status of each variable.
-			proc_info,	% The proc_info for the this procedure.
-			bool,		% do we need to store succip?
-			fail_stack,	% The failure continuation stack
-			module_info,	% The module_info structure - you just
-					% never know when you might need it.
-					% It should be read-only.
-			set(var),	% Variables that are forward live
-					% after this goal
-			instmap,	% insts of variables
-			set(lval),	% Stack variables that have been used
-					% for temporaries and are now again
-					% available for reuse.
-			int,		% The maximum number of extra
-					% temporary stackslots that have been
-					% used during the procedure
-			globals,	% code generation options
-			map(lval, slot_contents),
-					% The temp locations in use on the stack
-					% and what they contain (for gc).
-			map(label, internal_layout_info),	
-					% Information on which values
-					% are live and where at which labels,
-					% for tracing and/or accurate gc.
-			set(var),	% Zombie variables; variables that have
-					% been killed but are protected by a
-					% resume point.
-			stack(set(var)),
-					% Each resumption point has an
-					% associated set of variables
-					% whose values may be needed on
-					% resumption at that point.
-					% This field gives those variables
-					% for a nested set of resumption
-					% points. Each element must be
-					% a superset of the ones below.
-					% When a variable included in the top
-					% set becomes no longer forward live,
-					% we must save its value to the stack.
-			int,
-					% A count of how many triples of
-					% curfr, maxfr and redoip are live on
-					% the det stack. These triples are
-					% pushed onto the det stack when
-					% generating code for commits within
-					% model_non procedures. The value
-					% numbering pass and the accurate
-					% garbage collector need to know about
-					% these slots.  (Triple is a misnomer:
-					% in grades with trailing, it is four.)
-			maybe(trace_info)
-					% Information about which stack slots
-					% the call sequence number and depth
-					% are stored, provided tracing is
-					% switched on.
+	code_info(
+		% STATIC fields
+		globals,	% For the code generation options.
+		module_info,	% The module_info structure - you just
+				% never know when you might need it.
+		pred_id,	% The id of the current predicate.
+		proc_id,	% The id of the current procedure.
+		proc_info,	% The proc_info for the this procedure.
+		varset,		% The variables in this procedure.
+		int,		% The number of stack slots allocated.
+				% for storing variables.
+				% (Some extra stack slots are used
+				% for saving and restoring registers.)
+		maybe(trace_info),
+				% Information about which stack slots
+				% the call sequence number and depth
+				% are stored, provided tracing is
+				% switched on.
+
+		% LOCATION DEPENDENT fields
+		set(var),	% Variables that are forward live
+				% after this goal.
+ 		instmap,	% Current insts of the live variables.
+		set(var),	% Zombie variables; variables that are not
+				% forward live but which are protected by
+				% an enclosing resume point.
+		exprn_info,	% A map storing the information about
+				% the status of each known variable.
+				% (Known vars = forward live vars + zombies)
+		map(lval, slot_contents),
+				% The temp locations in use on the stack
+				% and what they contain (for gc).
+		fail_info,	% Information about how to manage failures.
+
+		% PERSISTENT fields
+ 		int,		% Counter for the local labels used
+				% by this procedure.
+		int,		% Counter for cells in this proc.
+		bool,		% do we need to store succip?
+		map(label, internal_layout_info),
+				% Information on which values
+				% are live and where at which labels,
+				% for tracing. Accurate gc 
+		int,		% The maximum number of extra
+				% temporary stackslots that have been
+				% used during the procedure.
+		set(lval)	% Stack variables that have been used
+				% for temporaries and are now again
+				% available for reuse.
 	).
 
 %---------------------------------------------------------------------------%
 
 code_info__init(Varset, Liveness, StackSlots, SaveSuccip, Globals,
-		PredId, ProcId, ProcInfo, Requests, FollowVars,
-		ModuleInfo, CellCount, C) :-
+		PredId, ProcId, ProcInfo, Instmap, FollowVars,
+		ModuleInfo, CellCount, ResumePoint, CodeInfo) :-
 	proc_info_headvars(ProcInfo, HeadVars),
 	proc_info_arg_info(ProcInfo, ArgInfos),
 	assoc_list__from_corresponding_lists(HeadVars, ArgInfos, Args),
@@ -289,12 +272,13 @@
 	globals__get_options(Globals, Options),
 	code_exprn__init_state(ArgList, Varset, StackSlots, FollowVars,
 		Options, ExprnInfo),
-	stack__init(Continue),
-	stack__init(ResumeSetStack0),
-	set__init(AvailSlots0),
-	map__init(TempsInUse0),
-	set__init(Zombies0),
-	map__init(Shapes),
+	stack__init(ResumePoints),
+	DummyFailInfo = fail_info(ResumePoints, resume_point_unknown,
+		may_be_different),
+	set__init(AvailSlots),
+	map__init(TempsInUse),
+	set__init(Zombies),
+	map__init(LayoutMap),
 	code_info__max_var_slot(StackSlots, VarSlotCount0),
 	proc_info_interface_code_model(ProcInfo, CodeModel),
 	(
@@ -304,289 +288,212 @@
 	;
 		VarSlotCount = VarSlotCount0
 	),
-	C = code_info(
-		VarSlotCount,
-		0,
-		Varset,
+	CodeInfo0 = code_info(
+		Globals,
+		ModuleInfo,
 		PredId,
 		ProcId,
-		CellCount,
-		ExprnInfo,
 		ProcInfo,
-		SaveSuccip,
-		Continue,
-		ModuleInfo,
+		Varset,
+		VarSlotCount,
+		no,
+
 		Liveness,
-		Requests,
-		AvailSlots0,
+		Instmap,
+		Zombies,
+		ExprnInfo,
+		TempsInUse,
+		DummyFailInfo,		% code_info__init_fail_info
+					% will override this dummy value
 		0,
-		Globals,
-		TempsInUse0,
-		Shapes,
-		Zombies0,
-		ResumeSetStack0,
+		CellCount,
+		SaveSuccip,
+		LayoutMap,
 		0,
-		no
-	).
-
-%---------------------------------------------------------------------------%
-
-code_info__get_var_slot_count(A, CI, CI) :-
-	CI = code_info(A, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_label_count(B, CI, CI) :-
-	CI = code_info(_, B, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_varset(C, CI, CI) :-
-	CI = code_info(_, _, C, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_pred_id(D, CI, CI) :-
-	CI = code_info(_, _, _, D, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_proc_id(E, CI, CI) :-
-	CI = code_info(_, _, _, _, E, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_cell_count(F, CI, CI) :-
-	CI = code_info(_, _, _, _, _, F, _, _, _, _, _, _, _, _, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_exprn_info(G, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, G, _, _, _, _, _, _, _, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_proc_info(H, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, H, _, _, _, _, _, _, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_succip_used(I, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, I, _, _, _, _, _, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_fail_stack(J, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, _, J, _, _, _, _, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_module_info(K, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, _, _, K, _, _, _, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_forward_live_vars(L, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, _, _, _, L, _, _, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_instmap(M, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, M, _, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_avail_temp_slots(N, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, N, _, _, _, _, _,
-		_, _, _).
-
-code_info__get_max_temp_slot_count(O, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, O, _, _, _, _,
-		_, _, _).
-
-code_info__get_globals(P, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, P, _, _, _,
-		_, _, _).
-
-code_info__get_temps_in_use(Q, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, Q, _, _,
-		_, _, _).
-
-code_info__get_layout_info(R, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, R, _,
-		_, _, _).
-
-code_info__get_zombies(S, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, S,
-		_, _, _).
-
-code_info__get_resume_point_stack(T, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
-		T, _, _).
-
-code_info__get_commit_triple_count(U, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
-		_, U, _).
-
-code_info__get_maybe_trace_info(V, CI, CI) :-
-	CI = code_info(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
-		_, _, V).
-
-% :- type code_info	--->
-%		code_info(
-%	A		int,		% The number of stack slots allocated.
-%					% for storing variables.
-%					% (Some extra stack slots are used
-%					% for saving and restoring registers.)
-%	B		int,		% Counter for the local labels used
-%					% by this procedure.
-%	C		varset,		% The variables in this procedure.
-%	D		pred_id,	% The label of the current predicate.
-%	E		proc_id,	% The label of the current procedure.
-%	F		int,		% Counter for cells in this proc.
-%	G		exprn_info,	% A map storing the information about
-%					% the status of each variable.
-%	H		proc_info,	% The proc_info for the this procedure.
-%	I		bool,		% do we need to store succip?
-%	J		fail_stack,	% The failure continuation stack
-%	K		module_info,	% The module_info structure - you just
-%					% never know when you might need it.
-%					% It should be read-only.
-%	L		set(var),	% Variables that are forward live
-%					% after this goal
-%	M		instmap,	% insts of variables
-%	N		set(lval),	% Stack variables that have been used
-%					% for temporaries and are now again
-%					% available for reuse.
-%	O		int,		% The maximum number of extra
-%					% temporary stackslots that have been
-%					% used during the procedure
-%	P		globals,	% code generation options
-%	Q		map(lval, slot_contents),
-%					% The temp locations in use on the stack
-%					% and what they contain (for gc).
-%	R		map(label, internal_layout_info),	
-%					% Information on which values
-%					% are live and where at which labels,
-%					% for tracing and/or accurate gc.
-%	S		set(var),	% Zombie variables; variables that have
-%					% been killed but are protected by a
-%					% resume point.
-%	T		stack(set(var)),
-%					% Each resumption point has an
-%					% associated set of variables
-%					% whose values may be needed on
-%					% resumption at that point.
-%					% This field gives those variables
-%					% for a nested set of resumption
-%					% points. Each element must be
-%					% a superset of the ones below.
-%					% When a variable included in the top
-%					% set becomes no longer forward live,
-%					% we must save its value to the stack.
-%	U		int,
-%					% A count of how many triples of
-%					% curfr, maxfr and redoip are live on
-%					% the det stack. These triples are
-%					% pushed onto the det stack when
-%					% generating code for commits within
-%					% model_non procedures. The value
-%					% numbering pass and the accurate
-%					% garbage collector need to know about
-%					% these slots.  (Triple is a misnomer:
-%					% in grades with trailing, it is four.)
-%	V		maybe(trace_info)
-%					% Information about which stack slots
-%					% the call sequence number and depth
-%					% are stored, provided tracing is
-%					% switched on.
-%	).
-%
-% we don't need
-% code_info__set_var_slot_count
-% code_info__set_varset
-% code_info__set_pred_id
-% code_info__set_proc_id
-% code_info__set_module_info
-% code_info__set_globals
-% code_info__set_code_model
-
-code_info__set_label_count(B, CI0, CI) :-
-	CI0 = code_info(A, _, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_cell_count(F, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, _, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_exprn_info(G, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, F, _, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_succip_used(I, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, F, G, H, _, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_fail_stack(J, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, F, G, H, I, _, K, L, M, N, O, P, Q,
-		R, S, T, U, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_forward_live_vars(L, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, _, M, N, O, P, Q,
-		R, S, T, U, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_instmap(M, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, _, N, O, P, Q,
-		R, S, T, U, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_avail_temp_slots(N, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, _, O, P, Q,
-		R, S, T, U, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_max_temp_slot_count(O, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, _, P, Q,
-		R, S, T, U, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_temps_in_use(Q, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, _,
-		R, S, T, U, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_layout_info(R, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		_, S, T, U, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_zombies(S, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, _, T, U, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_resume_point_stack(T, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, _, U, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_commit_triple_count(U, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, _, V),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
-
-code_info__set_maybe_trace_info(V, CI0, CI) :-
-	CI0 = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, _),
-	CI = code_info(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q,
-		R, S, T, U, V).
+		AvailSlots
+	),
+	globals__get_trace_level(Globals, TraceLevel),
+	code_info__init_maybe_trace_info(TraceLevel, ModuleInfo, ProcInfo,
+		MaybeFailVars, CodeInfo0, CodeInfo1),
+	code_info__init_fail_info(CodeModel, MaybeFailVars, ResumePoint,
+		CodeInfo1, CodeInfo).
+
+:- pred code_info__init_maybe_trace_info(trace_level, module_info, proc_info,
+	maybe(set(var)), code_info, code_info).
+:- mode code_info__init_maybe_trace_info(in, in, in, out, in, out) is det.
+
+code_info__init_maybe_trace_info(TraceLevel, ModuleInfo, ProcInfo,
+		MaybeFailVars) -->
+	( { trace_level_trace_interface(TraceLevel, yes) } ->
+		trace__setup(TraceLevel, TraceInfo),
+		code_info__set_maybe_trace_info(yes(TraceInfo)),
+		{ trace__fail_vars(ModuleInfo, ProcInfo, FailVars) },
+		{ MaybeFailVars = yes(FailVars) }
+	;
+		{ MaybeFailVars = no }
+	).
+
+%---------------------------------------------------------------------------%
+
+code_info__get_globals(SA, CI, CI) :-
+	CI  = code_info(SA, _, _, _, _, _, _, _,
+		_, _, _, _, _, _, _, _, _, _, _, _).
+
+code_info__get_module_info(SB, CI, CI) :-
+	CI  = code_info(_, SB, _, _, _, _, _, _,
+		_, _, _, _, _, _, _, _, _, _, _, _).
+
+code_info__get_pred_id(SC, CI, CI) :-
+	CI  = code_info(_, _, SC, _, _, _, _, _,
+		_, _, _, _, _, _, _, _, _, _, _, _).
+
+code_info__get_proc_id(SD, CI, CI) :-
+	CI  = code_info(_, _, _, SD, _, _, _, _,
+		_, _, _, _, _, _, _, _, _, _, _, _).
+
+code_info__get_proc_info(SE, CI, CI) :-
+	CI  = code_info(_, _, _, _, SE, _, _, _,
+		_, _, _, _, _, _, _, _, _, _, _, _).
+
+code_info__get_varset(SF, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, SF, _, _,
+		_, _, _, _, _, _, _, _, _, _, _, _).
+
+code_info__get_var_slot_count(SG, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, SG, _,
+		_, _, _, _, _, _, _, _, _, _, _, _).
+
+code_info__get_maybe_trace_info(SH, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, SH,
+		_, _, _, _, _, _, _, _, _, _, _, _).
+
+code_info__get_forward_live_vars(LA, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, _,
+		LA, _, _, _, _, _, _, _, _, _, _, _).
+
+code_info__get_instmap(LB, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, _,
+		_, LB, _, _, _, _, _, _, _, _, _, _).
+
+code_info__get_zombies(LC, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, _,
+		_, _, LC, _, _, _, _, _, _, _, _, _).
+
+code_info__get_exprn_info(LD, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, _,
+		_, _, _, LD, _, _, _, _, _, _, _, _).
+
+code_info__get_temps_in_use(LE, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, _,
+		_, _, _, _, LE, _, _, _, _, _, _, _).
+
+code_info__get_fail_info(LF, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, _,
+		_, _, _, _, _, LF, _, _, _, _, _, _).
+
+code_info__get_label_count(PA, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, _,
+		_, _, _, _, _, _, PA, _, _, _, _, _).
+
+code_info__get_cell_count(PB, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, _,
+		_, _, _, _, _, _, _, PB, _, _, _, _).
+
+code_info__get_succip_used(PC, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, _,
+		_, _, _, _, _, _, _, _, PC, _, _, _).
+
+code_info__get_layout_info(PD, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, _,
+		_, _, _, _, _, _, _, _, _, PD, _, _).
+
+code_info__get_max_temp_slot_count(PE, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, _,
+		_, _, _, _, _, _, _, _, _, _, PE, _).
+
+code_info__get_avail_temp_slots(PF, CI, CI) :-
+	CI  = code_info(_, _, _, _, _, _, _, _,
+		_, _, _, _, _, _, _, _, _, _, _, PF).
+
+%---------------------------------------------------------------------------%
+
+code_info__set_maybe_trace_info(SH, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, _,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
+
+code_info__set_forward_live_vars(LA, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		_,  LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
+
+code_info__set_instmap(LB, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, _,  LC, LD, LE, LF, PA, PB, PC, PD, PE, PF),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
+
+code_info__set_zombies(LC, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, _,  LD, LE, LF, PA, PB, PC, PD, PE, PF),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
+
+code_info__set_exprn_info(LD, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, _,  LE, LF, PA, PB, PC, PD, PE, PF),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
+
+code_info__set_temps_in_use(LE, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, _,  LF, PA, PB, PC, PD, PE, PF),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
+
+code_info__set_fail_info(LF, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, _,  PA, PB, PC, PD, PE, PF),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
+
+code_info__set_label_count(PA, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, _,  PB, PC, PD, PE, PF),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
+
+code_info__set_cell_count(PB, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, _,  PC, PD, PE, PF),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
+
+code_info__set_succip_used(PC, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, _,  PD, PE, PF),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
+
+code_info__set_layout_info(PD, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, _,  PE, PF),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
+
+code_info__set_max_temp_slot_count(PE, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, _,  PF),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
+
+code_info__set_avail_temp_slots(PF, CI0, CI) :-
+	CI0 = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, _ ),
+	CI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -631,7 +538,7 @@
 
 	% Given a list of type variables, find the lvals where the
 	% corresponding type_infos and typeclass_infos are being stored.
-:- pred code_info__find_type_infos(list(var), assoc_list(var, lval), 
+:- pred code_info__find_type_infos(list(var), assoc_list(var, lval),
 	code_info, code_info).
 :- mode code_info__find_type_infos(in, out, in, out) is det.
 
@@ -657,25 +564,9 @@
 	code_info, code_info).
 :- mode code_info__get_pred_proc_arginfo(in, in, out, in, out) is det.
 
-	% Pop the failure continuation stack.
-:- pred code_info__pop_failure_cont(code_info, code_info).
-:- mode code_info__pop_failure_cont(in, out) is det.
-
-:- pred code_info__push_resume_point_vars(set(var), code_info, code_info).
-:- mode code_info__push_resume_point_vars(in, in, out) is det.
-
-:- pred code_info__pop_resume_point_vars(code_info, code_info).
-:- mode code_info__pop_resume_point_vars(in, out) is det.
-
 :- pred code_info__variable_to_string(var, string, code_info, code_info).
 :- mode code_info__variable_to_string(in, out, in, out) is det.
 
-:- pred code_info__grab_code_info(code_info, code_info, code_info).
-:- mode code_info__grab_code_info(out, in, out) is det.
-
-:- pred code_info__slap_code_info(code_info, code_info, code_info).
-:- mode code_info__slap_code_info(in, in, out) is det.
-
 :- pred code_info__apply_instmap_delta(instmap_delta, code_info, code_info).
 :- mode code_info__apply_instmap_delta(in, in, out) is det.
 
@@ -701,10 +592,6 @@
 :- pred code_info__get_next_cell_number(int, code_info, code_info).
 :- mode code_info__get_next_cell_number(out, in, out) is det.
 
-	% Get the current cell number.
-:- pred code_info__get_cell_count(int, code_info, code_info).
-:- mode code_info__get_cell_count(out, in, out) is det.
-
 :- pred code_info__succip_is_used(code_info, code_info).
 :- mode code_info__succip_is_used(in, out) is det.
 
@@ -716,25 +603,6 @@
 
 :- implementation.
 
-:- pred code_info__push_failure_cont(failure_cont, code_info, code_info).
-:- mode code_info__push_failure_cont(in, in, out) is det.
-
-	% Lookup the value on the top of the failure continuation stack
-
-:- pred code_info__top_failure_cont(failure_cont, code_info, code_info).
-:- mode code_info__top_failure_cont(out, in, out) is det.
-
-:- pred code_info__current_resume_point_vars(set(var), code_info, code_info).
-:- mode code_info__current_resume_point_vars(out, in, out) is det.
-
-:- pred code_info__add_commit_triple(code_info, code_info).
-:- mode code_info__add_commit_triple(in, out) is det.
-
-:- pred code_info__rem_commit_triple(code_info, code_info).
-:- mode code_info__rem_commit_triple(in, out) is det.
-
-%-----------------------------------------------------------------------------%
-
 code_info__get_stack_slots(StackSlots, CI, CI) :-
 	code_info__get_exprn_info(ExprnInfo, CI, _),
 	code_exprn__get_stack_slots(StackSlots, ExprnInfo, _).
@@ -872,64 +740,16 @@
 
 %---------------------------------------------------------------------------%
 
-code_info__push_failure_cont(Cont) -->
-	code_info__get_fail_stack(Fall0),
-	{ stack__push(Fall0, Cont, Fall) },
-	code_info__set_fail_stack(Fall).
-
-code_info__pop_failure_cont -->
-	code_info__get_fail_stack(Fall0),
-	( { stack__pop(Fall0, _, Fall) } ->
-		code_info__set_fail_stack(Fall)
-	;
-		{ error("code_info__pop_failure_cont: empty stack") }
-	).
-
-code_info__top_failure_cont(Cont) -->
-	code_info__get_fail_stack(Fall),
-	( { stack__top(Fall, Cont0) } ->
-		{ Cont = Cont0 }
-	;
-		{ error("code_info__failure_cont: no failure continuation") }
-	).
-
-%---------------------------------------------------------------------------%
+:- pred code_info__current_resume_point_vars(set(var), code_info, code_info).
+:- mode code_info__current_resume_point_vars(out, in, out) is det.
 
 code_info__current_resume_point_vars(ResumeVars) -->
-	code_info__get_resume_point_stack(ResumeStack),
-	{ stack__top(ResumeStack, TopVars) ->
-		ResumeVars = TopVars
-	;
-		set__init(ResumeVars)
-	}.
-
-code_info__push_resume_point_vars(ResumeVars) -->
-	code_info__get_resume_point_stack(ResumeStack0),
-	{ stack__top(ResumeStack0, OldTopVars) ->
-		require(set__subset(OldTopVars, ResumeVars),
-		"new resume point variable set does not include old one")
-	;
-		true
-	},
-	{ stack__push(ResumeStack0, ResumeVars, ResumeStack) },
-	code_info__set_resume_point_stack(ResumeStack).
-
-code_info__pop_resume_point_vars -->
-	code_info__get_resume_point_stack(ResumeStack0),
-	{ stack__pop_det(ResumeStack0, _, ResumeStack) },
-	code_info__set_resume_point_stack(ResumeStack).
-
-%---------------------------------------------------------------------------%
-
-code_info__add_commit_triple -->
-	code_info__get_commit_triple_count(Count0),
-	{ Count is Count0 + 1 },
-	code_info__set_commit_triple_count(Count).
-
-code_info__rem_commit_triple -->
-	code_info__get_commit_triple_count(Count0),
-	{ Count is Count0 - 1 },
-	code_info__set_commit_triple_count(Count).
+	code_info__get_fail_info(FailInfo),
+	{ FailInfo = fail_info(ResumePointStack, _, _) },
+	{ stack__top_det(ResumePointStack, ResumePointInfo) },
+	{ code_info__pick_first_resume_point(ResumePointInfo, ResumeMap, _) },
+	{ map__keys(ResumeMap, ResumeMapVarList) },
+	{ set__list_to_set(ResumeMapVarList, ResumeVars) }.
 
 %---------------------------------------------------------------------------%
 
@@ -937,24 +757,6 @@
 	code_info__get_varset(Varset),
 	{ varset__lookup_name(Varset, Var, Name) }.
 
-code_info__grab_code_info(C, C, C).
-
-code_info__slap_code_info(C0, C1, C) :-
-	code_info__get_label_count(L, C1, _),
-	code_info__set_label_count(L, C0, C2),
-	code_info__get_succip_used(S, C1, _),
-	code_info__set_succip_used(S, C2, C3),
-	code_info__get_fail_stack(J, C0, _),
-	code_info__set_fail_stack(J, C3, C4),
-	code_info__get_max_temp_slot_count(PC, C1, _),
-	code_info__set_max_temp_slot_count(PC, C4, C5),
-	code_info__get_avail_temp_slots(TS, C1, _),
-	code_info__set_avail_temp_slots(TS, C5, C6),
-	code_info__get_layout_info(LayoutInfo, C1, _),
-	code_info__set_layout_info(LayoutInfo, C6, C7),
-	code_info__get_cell_count(CellCount, C1, _),
-	code_info__set_cell_count(CellCount, C7, C).
-
 code_info__apply_instmap_delta(Delta) -->
 	code_info__get_instmap(InstMap0),
 	{ instmap__apply_instmap_delta(InstMap0, Delta, InstMap) },
@@ -1016,670 +818,673 @@
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
 
-	% Submodule for the handling of failure continuations.
+	% Submodule for handling branched control structures.
 
 :- interface.
 
-	% We manufacture a failure cont when we start generating
-	% code for a proc because on the failure of a procedure
-	% we don't need to prepare for execution to resume in this
-	% procedure.
+:- type position_info.
+:- type branch_end_info.
 
-:- pred code_info__manufacture_failure_cont(bool, code_info, code_info).
-:- mode code_info__manufacture_failure_cont(in, in, out) is det.
+:- type branch_end	==	maybe(branch_end_info).
 
-	% make_known_failure_cont(ResumeVars, ResumeLocs, IsNondet, Code):
-	% Push a new failure continuation onto the stack.
+:- pred code_info__remember_position(position_info, code_info, code_info).
+:- mode code_info__remember_position(out, in, out) is det.
 
-:- pred code_info__make_known_failure_cont(set(var), resume_locs, bool,
+:- pred code_info__reset_to_position(position_info, code_info, code_info).
+:- mode code_info__reset_to_position(in, in, out) is det.
+
+:- pred code_info__generate_branch_end(store_map, branch_end, branch_end,
 	code_tree, code_info, code_info).
-:- mode code_info__make_known_failure_cont(in, in, in, out, in, out)
-	is det.
+:- mode code_info__generate_branch_end(in, in, out, out, in, out) is det.
 
-	% Generate some code to restore the current redoip, by looking
-	% at the top of the failure continuation stack.
+:- pred code_info__after_all_branches(store_map, branch_end,
+	code_info, code_info).
+:- mode code_info__after_all_branches(in, in, in, out) is det.
 
-:- pred code_info__restore_failure_cont(code_tree, code_info, code_info).
-:- mode code_info__restore_failure_cont(out, in, out) is det.
+:- implementation.
 
-	% XXX
+:- type position_info
+	--->	position_info(
+			code_info	% The code_info at a given position
+					% in the code of the procedure.
+		).
 
-:- pred code_info__failure_is_direct_branch(code_addr, code_info, code_info).
-:- mode code_info__failure_is_direct_branch(out, in, out) is semidet.
+:- type branch_end_info
+	--->	branch_end_info(
+			code_info	% The code_info at the end of a branch.
+		).
 
-	% XXX
+code_info__remember_position(position_info(C), C, C).
 
-:- pred code_info__generate_failure(code_tree, code_info, code_info).
-:- mode code_info__generate_failure(out, in, out) is det.
+code_info__reset_to_position(position_info(PosCI), CurCI, NextCI) :-
+		% The static fields in PosCI and CurCI should be identical.
+	PosCI  = code_info(_,  _,  _,  _,  _,  _,  _,  _, 
+		LA, LB, LC, LD, LE, LF, _,  _,  _,  _,  _,  _ ),
+	CurCI  = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		_,  _,  _,  _,  _,  _,  PA, PB, PC, PD, PE, PF),
+	NextCI = code_info(SA, SB, SC, SD, SE, SF, SG, SH,
+		LA, LB, LC, LD, LE, LF, PA, PB, PC, PD, PE, PF).
 
-	% XXX
+code_info__generate_branch_end(StoreMap, MaybeEnd0, MaybeEnd, Code) -->
+	code_info__get_exprn_info(Exprn0),
+	{ map__to_assoc_list(StoreMap, VarLocs) },
+	{ code_exprn__place_vars(VarLocs, Code, Exprn0, Exprn) },
+	code_info__set_exprn_info(Exprn),
+	=(EndCodeInfo1),
+	{
+		MaybeEnd0 = no,
+		EndCodeInfo = EndCodeInfo1
+	;
+		MaybeEnd0 = yes(branch_end_info(EndCodeInfo0)),
 
-:- pred code_info__fail_if_rval_is_false(rval, code_tree,
-	code_info, code_info).
-:- mode code_info__fail_if_rval_is_false(in, out, in, out) is det.
+			% Make sure the left context we leave the
+			% branched structure with is valid for all branches.
+		code_info__get_fail_info(FailInfo0, EndCodeInfo0, _),
+		code_info__get_fail_info(FailInfo1, EndCodeInfo1, _),
+		FailInfo0 = fail_info(_, ResumeKnown0, CurfrMaxfr0),
+		FailInfo1 = fail_info(R, ResumeKnown1, CurfrMaxfr1),
+		(
+			ResumeKnown0 = resume_point_known,
+			ResumeKnown1 = resume_point_known
+		->
+			ResumeKnown = resume_point_known
+		;
+			ResumeKnown = resume_point_unknown
+		),
+		(
+			CurfrMaxfr0 = must_be_equal,
+			CurfrMaxfr1 = must_be_equal
+		->
+			CurfrMaxfr = must_be_equal
+		;
+			CurfrMaxfr = may_be_different
+		),
+		FailInfo = fail_info(R, ResumeKnown, CurfrMaxfr),
+		code_info__set_fail_info(FailInfo, EndCodeInfo1, EndCodeInfo)
+	},
+	{ MaybeEnd = yes(branch_end_info(EndCodeInfo)) }.
 
-	% Set the topmost failure cont to `unknown' (e.g. after
-	% a nondet call or after a disjunction).
+code_info__after_all_branches(StoreMap, MaybeEnd, CI0, CI) :-
+	(
+		MaybeEnd = yes(BranchEnd),
+		BranchEnd = branch_end_info(BranchEndCodeInfo),
+		code_info__reset_to_position(position_info(BranchEndCodeInfo),
+			CI0, CI1),
+		code_info__remake_with_store_map(StoreMap, CI1, CI)
+	;
+		MaybeEnd = no,
+		error("no branches in branched control structure")
+	).
 
-:- pred code_info__unset_failure_cont(code_tree, code_info, code_info).
-:- mode code_info__unset_failure_cont(out, in, out) is det.
+	% code_info__remake_with_store_map throws away the exprn_info data
+	% structure, forgetting the current locations of all variables,
+	% and rebuilds it from scratch based on the given store map.
+	% The new exprn_info will know about only the variables present
+	% in the store map, and will believe they are where the store map
+	% says they are.
 
-	% Flush the variables needed for any current resumption point
-	% to their stack slots.
+:- pred code_info__remake_with_store_map(store_map, code_info, code_info).
+:- mode code_info__remake_with_store_map(in, in, out) is det.
 
-:- pred code_info__flush_resume_vars_to_stack(code_tree, code_info, code_info).
-:- mode code_info__flush_resume_vars_to_stack(out, in, out) is det.
+code_info__remake_with_store_map(StoreMap) -->
+	{ map__to_assoc_list(StoreMap, VarLvals) },
+	{ code_info__fixup_lvallist(VarLvals, VarRvals) },
+	code_info__get_exprn_info(Exprn0),
+	{ code_exprn__reinit_state(VarRvals, Exprn0, Exprn) },
+	code_info__set_exprn_info(Exprn).
 
-	% XXX
+:- pred code_info__fixup_lvallist(assoc_list(var, lval), assoc_list(var, rval)).
+:- mode code_info__fixup_lvallist(in, out) is det.
 
-:- pred code_info__may_use_nondet_tailcall(bool, code_info, code_info).
-:- mode code_info__may_use_nondet_tailcall(out, in, out) is det.
+code_info__fixup_lvallist([], []).
+code_info__fixup_lvallist([V - L | Ls], [V - lval(L) | Rs]) :-
+	code_info__fixup_lvallist(Ls, Rs).
 
-	% do_soft_cut(NondetFrameLvalAddress, SoftCutCode, SoftCutContCode)
-	% takes the lval where the address of the
-	% failure frame is stored, and it returns code to
-	% prune away the topmost choice point from that frame,
-	% typically by setting the redoip of that frame to do_fail.
-	% Note that the frame need not be the topmost frame -- a soft cut
-	% can prune away a single choice point from the middle.
-	% do_soft_cut also returns some additional code; in the case of
-	% trailing, the redoip will be set to point to that additional code,
-	% not to do_fail; the additional code will do a `discard_ticket'
-	% before branching to the usual failure continuation (e.g. do_fail).
-
-:- pred code_info__do_soft_cut(lval, code_tree, code_tree,
-			code_info, code_info).
-:- mode code_info__do_soft_cut(in, out, out, in, out) is det.
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
 
-	% `generate_semi_pre_commit' and `generate_semi_commit' should be
-	% called before and after generating the code for the nondet goal
-	% being cut across. If the goal succeeds, the `commit' will cut
-	% any choice points generated in the goal.
-	%
-	% `generate_semi_pre_commit' returns a label (a failure cont label)
-	% and a tuple of stack slots; both of these should be passed to
-	% `generate_semi_commit'.
+	% Submodule for the handling of failure continuations.
 
-:- pred code_info__generate_semi_pre_commit(label, commit_slots, code_tree,
-	code_info, code_info).
-:- mode code_info__generate_semi_pre_commit(out, out, out, in, out) is det.
+:- interface.
 
-:- pred code_info__generate_semi_commit(label, commit_slots, code_tree,
-	code_info, code_info).
-:- mode code_info__generate_semi_commit(in, in, out, in, out) is det.
+:- type resume_map.
 
-	% `generate_det_pre_commit' and `generate_det_commit' should be
-	% called before and after generating the code for the multi goal
-	% being cut across. If the goal succeeds, the `commit' will cut
-	% any choice points generated in the goal.
-	%
-	% `generate_det_pre_commit' returns a tuple of stack slots, which
-	% should be passed to `generate_det_commit'.
+:- type resume_point_info.
 
-:- pred code_info__generate_det_pre_commit(commit_slots, code_tree,
-	code_info, code_info).
-:- mode code_info__generate_det_pre_commit(out, out, in, out) is det.
+:- type disj_hijack_info.
 
-:- pred code_info__generate_det_commit(commit_slots, code_tree,
-	code_info, code_info).
-:- mode code_info__generate_det_commit(in, out, in, out) is det.
+	% 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.
 
-:- type commit_slots
-	--->	commit_slots(
-			lval,		% curfr
-			lval,		% maxfr
-			lval,		% redoip
-			maybe(pair(lval, lval)) % ticket counter, trail pointer
-		).
+:- pred code_info__prepare_for_disj_hijack(code_model::in,
+	disj_hijack_info::out, code_tree::out,
+	code_info::in, code_info::out) is det.
 
-%---------------------------------------------------------------------------%
+:- pred code_info__undo_disj_hijack(disj_hijack_info::in,
+	code_tree::out, code_info::in, code_info::out) is det.
 
-:- implementation.
+:- type ite_hijack_info.
 
-:- type fail_stack	==	stack(failure_cont).
+:- pred code_info__prepare_for_ite_hijack(code_model::in,
+	ite_hijack_info::out, code_tree::out,
+	code_info::in, code_info::out) is det.
 
-:- type failure_cont
-	--->	failure_cont(
-			failure_cont_info,
-			resume_maps
-		).
+:- pred code_info__maybe_push_temp_frame(code_model::in, bool::in,
+	ite_hijack_info::in, lval::out, code_tree::out,
+	code_info::in, code_info::out) is det.
 
-:- type failure_cont_info
-	--->	semidet
-	;	nondet(
-			is_known,	% Says whether on failure we can branch
-					% directly to one of the labels in
-					% the resume_maps, or if we must
-					% instead execute a redo.
-
-			maybe(label)	% The maybe(label) is yes if we have
-					% created a temporary frame and we
-					% must restore curfr after a redo().
-		).
+:- pred code_info__ite_enter_then(ite_hijack_info::in, lval::in,
+	code_tree::out, code_tree::out, code_info::in, code_info::out) is det.
 
-:- type is_known	--->	known ; unknown.
+:- type simple_neg_info.
 
-:- type resume_map	==	map(var, set(rval)).
+:- pred code_info__enter_simple_neg(set(var)::in, hlds_goal_info::in, 
+	simple_neg_info::out, code_info::in, code_info::out) is det.
 
-:- type resume_maps
-	--->	orig_only(resume_map, code_addr)
-	;	stack_only(resume_map, code_addr)
-	;	orig_and_stack(resume_map, code_addr, resume_map, code_addr)
-	;	stack_and_orig(resume_map, code_addr, resume_map, code_addr).
+:- pred code_info__leave_simple_neg(hlds_goal_info::in, simple_neg_info::in,
+	code_info::in, code_info::out) is det.
 
-:- pred code_info__fail_cont_is_known(failure_cont_info).
-:- mode code_info__fail_cont_is_known(in) is semidet.
+	% Put the given resume point into effect, by pushing it on to
+	% the resume point stack, and if necessary overriding the redoip
+	% of the top frame.
 
-code_info__fail_cont_is_known(FailContInfo) :-
-	FailContInfo \= nondet(unknown, _).
+:- pred code_info__effect_resume_point(resume_point_info::in, code_model::in,
+	code_tree::out, code_info::in, code_info::out) is det.
 
-:- pred code_info__fail_cont_is_unknown(failure_cont_info).
-:- mode code_info__fail_cont_is_unknown(in) is semidet.
+:- pred code_info__top_resume_point(resume_point_info::out,
+	code_info::in, code_info::out) is det.
 
-code_info__fail_cont_is_unknown(FailContInfo) :-
-	FailContInfo = nondet(unknown, _).
+	% We have just left a disjunction; we don't know what address
+	% the following code will need to backtrack to.
 
-:- pred code_info__have_temp_frame(fail_stack).
-:- mode code_info__have_temp_frame(in) is semidet.
+:- pred code_info__set_resume_point_to_unknown(code_info::in, code_info::out)
+	is det.
 
-	% have_temp_frame should succeed iff we have created
-	% a temp frame on the nondet stack.  It traverses
-	% the entire failure continuation stack, looking for
-	% any failure continuations with the temp frame maybe(label)
-	% set to yes(_).
+	% We have just returned a model_non call; we don't know what address
+	% the following code will need to backtrack to, and there may now
+	% be nondet frames on top of ours that do not have their redofr slots
+	% pointing to our frame.
 
-code_info__have_temp_frame(FailStack0) :-
-	stack__pop(FailStack0, FailContInfo, FailStack1),
-	(
-		FailContInfo = failure_cont(nondet(_, yes(_)), _)
-	;
-		code_info__have_temp_frame(FailStack1)
-	).
+:- pred code_info__set_resume_point_and_frame_to_unknown(code_info::in,
+	code_info::out) is det.
 
-%---------------------------------------------------------------------------%
+:- pred code_info__generate_failure(code_tree::out,
+	code_info::in, code_info::out) is det.
 
-code_info__manufacture_failure_cont(IsNondet) -->
-	{ map__init(Empty) },
-	(
-		{ IsNondet = no },
-		code_info__get_next_label(ContLab1),
-		{ Address1 = label(ContLab1) },
-		{ ResumeMap = stack_only(Empty, Address1) },
-		{ ContInfo = semidet }
-	;
-		{ IsNondet = yes },
-		{ Address1 = do_fail },
-		{ ResumeMap = stack_only(Empty, Address1) },
-		{ ContInfo = nondet(known, no) }
-	),
-	code_info__push_failure_cont(failure_cont(ContInfo, ResumeMap)).
+:- pred code_info__fail_if_rval_is_false(rval::in, code_tree::out,
+	code_info::in, code_info::out) is det.
 
-%---------------------------------------------------------------------------%
+:- pred code_info__failure_is_direct_branch(code_addr::out,
+	code_info::in, code_info::out) is semidet.
 
-code_info__make_known_failure_cont(ResumeVars, ResumeLocs, IsNondet,
-		ModContCode) -->
-	code_info__get_next_label(OrigLabel),
-	code_info__get_next_label(StackLabel),
-	{ OrigAddr = label(OrigLabel) },
-	{ StackAddr = label(StackLabel) },
-	(
-		% In semidet continuations we don't use the redoip
-		% of the top stack frame.
+:- pred code_info__may_use_nondet_tailcall(bool::out,
+	code_info::in, code_info::out) is det.
 
-		{ IsNondet = no },
-		{ TempFrameCode = empty },
-		{ FailContInfo = semidet }
-	;
-		% In nondet continuations we may use the redoip
-		% of the top stack frame. Therefore we must ensure
-		% that this redoip is free for use, creating our own
-		% frame if necessary.
+	% Materialize the given variables into registers or stack slots.
 
-		{ IsNondet = yes },
-		code_info__top_failure_cont(FailureCont),
-		{ FailureCont = failure_cont(OrigInfo, _) },
-		(
-			{ code_info__fail_cont_is_unknown(OrigInfo) }
-		->
-			%
-			% If the failure continuation is unknown,
-			% then we need to create a new temporary frame
-			% so that we can make it known
-			%
-			code_info__get_next_label(RedoLabel),
-			{ MaybeRedoLabel = yes(RedoLabel) },
-			{ RedoAddr = label(RedoLabel) },
-				% this code could be better
-				% (mkframe is a bit of a sledge hammer)
-			{ TempFrameCode = node([
-				mkframe("temp frame", 1, no, RedoAddr)
-					- "create a temporary frame",
-				assign(curfr, lval(succfr(lval(maxfr))))
-					- "restore curfr after mkframe"
-			]) }
-		;
-			%
-			% The failure continuation is known.
-			% But did we create a temp frame?
-			%
-			code_info__get_fail_stack(FailStack),
-			(
-				{ code_info__have_temp_frame(FailStack) }
-			->
-				%
-				% If we created a temp frame, then
-				% we will need to restore curfr on redo,
-				% so we set the failure continuation to
-				% the RedoAddr rather than the usual
-				% StackAddr.  (generate_failure_cont will
-				% generate code for it that restores curfr.)
-				%
-				code_info__get_next_label(RedoLabel),
-				{ MaybeRedoLabel = yes(RedoLabel) },
-				{ RedoAddr = label(RedoLabel) },
-				{ TempFrameCode = node([
-					assign(redoip(lval(maxfr)),
-					    const(code_addr_const(RedoAddr)))
-				    - "Set failure continuation on temp frame"
-				]) }
-			;
-				{ MaybeRedoLabel = no },
-				{ TempFrameCode = node([
-					assign(redoip(lval(maxfr)),
-					    const(code_addr_const(StackAddr)))
-				    - "Set failure continuation"
-				]) }
-			)
-		),
-		{ FailContInfo = nondet(known, MaybeRedoLabel) }
-	),
-	{ set__to_sorted_list(ResumeVars, VarList) },
-	(
-		{ ResumeLocs = orig_only },
-		code_info__produce_resume_vars(VarList, OrigMap, OrigCode),
-		{ ResumeMaps = orig_only(OrigMap, OrigAddr) }
-	;
-		{ ResumeLocs = stack_only },
-		code_info__produce_resume_vars(VarList, _OrigMap, OrigCode),
-		code_info__get_stack_slots(StackSlots),
-		{ map__select(StackSlots, ResumeVars, StackMap0) },
-		{ map__to_assoc_list(StackMap0, StackList0) },
-		{ code_info__tweak_stacklist(StackList0, StackList) },
-		{ map__from_assoc_list(StackList, StackMap) },
-		{ ResumeMaps = stack_only(StackMap, StackAddr) }
-	;
-		{ ResumeLocs = orig_and_stack },
-		code_info__produce_resume_vars(VarList, OrigMap, OrigCode),
-		code_info__get_stack_slots(StackSlots),
-		{ map__select(StackSlots, ResumeVars, StackMap0) },
-		{ map__to_assoc_list(StackMap0, StackList0) },
-		{ code_info__tweak_stacklist(StackList0, StackList) },
-		{ map__from_assoc_list(StackList, StackMap) },
-		{ ResumeMaps = orig_and_stack(OrigMap, OrigAddr,
-			StackMap, StackAddr) }
-	;
-		{ ResumeLocs = stack_and_orig },
-		code_info__produce_resume_vars(VarList, OrigMap, OrigCode),
-		code_info__get_stack_slots(StackSlots),
-		{ map__select(StackSlots, ResumeVars, StackMap0) },
-		{ map__to_assoc_list(StackMap0, StackList0) },
-		{ code_info__tweak_stacklist(StackList0, StackList) },
-		{ map__from_assoc_list(StackList, StackMap) },
-		{ ResumeMaps = stack_and_orig(StackMap, StackAddr,
-			OrigMap, OrigAddr) }
-	),
-	code_info__push_failure_cont(failure_cont(FailContInfo, ResumeMaps)),
-	{ ModContCode = tree(OrigCode, TempFrameCode) }.
+:- pred code_info__produce_vars(set(var)::in, resume_map::out,
+	code_tree::out, code_info::in, code_info::out) is det.
 
-:- pred code_info__produce_resume_vars(list(var), map(var, set(rval)),
-	code_tree, code_info, code_info).
-:- mode code_info__produce_resume_vars(in, out, out, in, out) is det.
+	% Put the variables needed in enclosing failure continuations
+	% into their stack slots.
 
-code_info__produce_resume_vars([], Map, empty) -->
-	{ map__init(Map) }.
-code_info__produce_resume_vars([V | Vs], Map, Code) -->
-	code_info__produce_resume_vars(Vs, Map0, Code0),
-	code_info__produce_variable_in_reg_or_stack(V, Code1, Rval),
-	{ set__singleton_set(Rvals, Rval) },
-	{ map__set(Map0, V, Rvals, Map) },
-	{ Code = tree(Code0, Code1) }.
+:- pred code_info__flush_resume_vars_to_stack(code_tree::out,
+	code_info::in, code_info::out) is det.
 
-:- pred code_info__tweak_stacklist(assoc_list(var, lval),
-	assoc_list(var, set(rval))).
-:- mode code_info__tweak_stacklist(in, out) is det.
+	% Set up the resume_point_info structure.
 
-code_info__tweak_stacklist([], []).
-code_info__tweak_stacklist([V - L | Rest0], [V - Rs | Rest]) :-
-	set__singleton_set(Rs, lval(L)),
-	code_info__tweak_stacklist(Rest0, Rest).
+:- pred code_info__make_resume_point(set(var)::in, resume_locs::in,
+	resume_map::in, resume_point_info::out, code_info::in, code_info::out)
+	is det.
 
-%---------------------------------------------------------------------------%
+	% Generate the code for a resume point.
 
-% :- pred code_info__modify_failure_cont(code_tree, code_info, code_info).
-% :- mode code_info__modify_failure_cont(out, in, out) is det.
-% 
-% code_info__modify_failure_cont(ModifyCode) -->
-% 	code_info__top_failure_cont(FailureCont),
-% 	{ FailureCont = failure_cont(OldCont, MaybeRedo0, FailureMap) },
-% 	code_info__generate_failure_cont(FailureCont, FailureCode),
-% 	code_info__pop_failure_cont,
-% 	code_info__get_next_label(NewRegCont),
-% 	code_info__get_next_label(NewStackCont),
-% 	(
-% 		{ OldCont = unknown ; OldCont = known(yes) }
-% 	->
-% 		{ NewCont = known(yes) },
-% 		( { MaybeRedo0 = yes(_OldRedo) } ->
-% 			code_info__get_next_label(NewRedoCont),
-% 			{ MaybeRedo = yes(NewRedoCont) }
-% 		;
-% 			{ NewRedoCont = NewStackCont },
-% 			{ MaybeRedo = no }
-% 		),
-% 		{ ResetCode = node([
-% 			assign(redoip(lval(maxfr)),
-% 				const(code_addr_const(label(NewRedoCont)))) -
-% 				"modify failure cont"
-% 		]) }
-% 	;
-% 		{ error("code_info__modify_failure_cont: semidet context") }
-% 		% { NewCont = known(no) },
-% 		% { ResetCode = empty },
-% 		% { MaybeRedo = no }
-% 	),
-% 	(
-% 		{ FailureMap = [RegMap - _RegCont, StackMap - _StackCont] }
-% 	->
-% 		code_info__push_failure_cont(failure_cont(NewCont, MaybeRedo,
-% 			[RegMap - label(NewRegCont),
-% 			StackMap - label(NewStackCont)]))
-% 	;
-% 		{ error("code_info__modify_failure_cont: bad failure map.") }
-% 	),
-% 	{ ModifyCode = tree(FailureCode, ResetCode) }.
+:- pred code_info__generate_resume_point(resume_point_info::in,
+	code_tree::out, code_info::in, code_info::out) is det.
 
-%---------------------------------------------------------------------------%
+:- pred code_info__resume_point_vars(resume_point_info::in, list(var)::out)
+	is det.
 
-code_info__restore_failure_cont(Code) -->
-	code_info__top_failure_cont(CurFailureCont),
-	{ CurFailureCont = failure_cont(CurContInfo, _FailureMap) },
-	code_info__generate_failure_cont(CurFailureCont, FailureCode),
-	code_info__pop_failure_cont,
-		% Fixup the redoip of the top frame if necessary
-	(
-		{ CurContInfo = semidet },
-		{ ResetCode = empty }
-	;
-		{ CurContInfo = nondet(_, _) },
-		code_info__top_failure_cont(EnclosingFailureCont),
-		{ EnclosingFailureCont = failure_cont(EnclosingContInfo, _) },
-		{
-			EnclosingContInfo = semidet,
-			ResetCode = empty
-		;
-			EnclosingContInfo = nondet(unknown, _),
-			ResetCode = node([
-				assign(redoip(lval(maxfr)),
-					const(code_addr_const(do_fail))) -
-					"restore failure cont"
-			])
-		;
-			EnclosingContInfo = nondet(known, _),
-			code_info__find_first_resume_label(
-				EnclosingFailureCont, RedoAddress),
-			ResetCode = node([
-				assign(redoip(lval(maxfr)),
-					const(code_addr_const(RedoAddress)))
-					- "restore known failure cont"
-			])
-		}
-	),
-	{ Code = tree(FailureCode, ResetCode) }.
+:- pred code_info__resume_point_stack_addr(resume_point_info::in,
+	code_addr::out) is det.
+
+	% `generate_det_pre_commit' and `generate_det_commit' should be
+	% called before and after generating the code for the multi goal
+	% being cut across. If the goal succeeds, the `commit' will cut
+	% any choice points generated in the goal.
+
+:- type det_commit_info.
+
+:- pred code_info__generate_det_pre_commit(det_commit_info::out,
+	code_tree::out, code_info::in, code_info::out) is det.
+
+:- pred code_info__generate_det_commit(det_commit_info::in,
+	code_tree::out, code_info::in, code_info::out) is det.
+
+	% `generate_semi_pre_commit' and `generate_semi_commit' should be
+	% called before and after generating the code for the nondet goal
+	% being cut across. If the goal succeeds, the `commit' will cut
+	% any choice points generated in the goal.
+
+:- type semi_commit_info.
+
+:- pred code_info__generate_semi_pre_commit(semi_commit_info::out,
+	code_tree::out, code_info::in, code_info::out) is det.
+
+:- pred code_info__generate_semi_commit(semi_commit_info::in,
+	code_tree::out, code_info::in, code_info::out) is det.
 
 %---------------------------------------------------------------------------%
 
-	% In establishing this resumption point, we may have pushed
-	% a temporary frame onto the nondet stack. If we have done so,
-	% we will have recorded this fact by setting the second argument
-	% of the top failure continuation to yes, with the argument of
-	% the yes giving the name of the label whose address was put
-	% into the redoip slot of that frame.
-	%
-	% When control arrives at that label, curfr will point to the
-	% temporary frame. However, the variables needed by the code
-	% at the resumption point are in the main nondet frame of the
-	% procedure. Since this was the current frame when we created
-	% the temporary frame, we can find it by following the succfr
-	% link in the temporary frame.
-	%
-	% The code we generate in general is
-	%
-	% label(RedoLabel)
-	% <reset curfr>
-	% label(StackLabel)
-	% <assume variables are where StackMap says they are>
-	% <copy variables to their locations according to OrigMap>
-	% label(OrigLabel)
-	% <assume variables are where OrigMap says they are>
-	%
-	% If, in establishing this resumption point, we did not create
-	% a temporary frame, then curfr will be OK when code to the right
-	% does a fail(), and hence the first label and the resetting of
-	% the curfr register can be omitted.
-	%
-	% Failures at different points may cause control to arrive at
-	% the resumption point via any one of these each labels.
-	% The last line above is necessary since it may arrive at OrigLabel
-	% without going through StackLabel first.
-	%
-	% The first two lines above are generated in this predicate;
-	% the others are generated in code_info__generate_resume_setup.
-	% It may not generate some of these other lines if it knows that
-	% they won't be needed.
-
-:- pred code_info__generate_failure_cont(failure_cont, code_tree,
-	code_info, code_info).
-:- mode code_info__generate_failure_cont(in, out, in, out) is det.
-
-code_info__generate_failure_cont(FailureCont, Code) -->
-	{ FailureCont = failure_cont(ContInfo, ResumeMap) },
-
-		% Did we create a temp nondet frame for this continuation?
-		% If not, then curfr will be right when we arrive here.
-		% If yes, it will be wrong, pointing to the temp frame,
-		% so we must restore curfr before continuing.
-	{
-		ContInfo = nondet(_, MaybeRedoLabel),
-		MaybeRedoLabel = yes(RedoLabel)
-	->
-		FixCurFrCode = node([
-			label(RedoLabel) -
-				"redo entry point",
-			assign(curfr, lval(succfr(lval(maxfr)))) -
-				"restore curfr"
-		]),
+:- implementation.
+
+:- type resume_point_known	--->	resume_point_known
+				;	resume_point_unknown.
+
+:- type curfr_vs_maxfr		--->	must_be_equal
+				;	may_be_different.
+
+:- type resume_map		==	map(var, set(rval)).
+
+:- type resume_point_info
+	--->	orig_only(resume_map, code_addr)
+	;	stack_only(resume_map, code_addr)
+	;	orig_and_stack(resume_map, code_addr, resume_map, code_addr)
+	;	stack_and_orig(resume_map, code_addr, resume_map, code_addr).
+
+:- type fail_info
+	--->	fail_info(
+			stack(resume_point_info),
+			resume_point_known,
+			curfr_vs_maxfr
+		).
+
+:- type disj_hijack_info
+	--->	disj_no_hijack
+	;	disj_quarter_hijack
+	;	disj_half_hijack(
+			lval		% the stack slot in which we saved
+					% the value of the hijacked redoip
+		)
+	;	disj_full_hijack(
+			lval,		% the stack slot in which we saved
+					% the value of the hijacked redoip
+			lval		% the stack slot in which we saved
+					% the value of the hijacked redofr
+		).
+
+:- type ite_hijack_info
+	--->	ite_no_hijack(
+			resume_point_known
+		)
+	;	ite_quarter_hijack(
+			resume_point_known
+		)
+	;	ite_half_hijack(
+			resume_point_known,
+			lval		% the stack slot in which we saved
+					% the value of the hijacked redoip
+		)
+	;	ite_full_hijack(
+			resume_point_known,
+			lval,		% the stack slot in which we saved
+					% the value of the hijacked redoip
+			lval,		% the stack slot in which we saved
+					% the value of the hijacked redofr
+			lval		% the stack slot in which we saved
+					% the value of maxfr
+		).
+
+:- type simple_neg_info		==	fail_info.
+
+code_info__prepare_for_disj_hijack(CodeModel, HijackInfo, Code) -->
+	( { CodeModel = model_non } ->
+		code_info__get_fail_info(FailInfo),
+		{ FailInfo = fail_info(_, ResumeKnown, CurfrMaxfr) },
 		(
-			( ResumeMap = orig_only(_, _)
-			; ResumeMap = orig_and_stack(_, _, _, _)
-			)
-		->
-			error("redo entry before an orig resume point")
+			{ CurfrMaxfr = may_be_different },
+			code_info__acquire_temp_slot(lval(redoip(lval(maxfr))),
+				RedoipSlot),
+			code_info__acquire_temp_slot(lval(redofr(lval(maxfr))),
+				RedofrSlot),
+			{ HijackInfo = disj_full_hijack(RedoipSlot,
+				RedofrSlot) },
+			{ Code = node([
+				assign(RedoipSlot, lval(redoip(lval(maxfr))))
+					- "prepare for full disj hijack",
+				assign(RedofrSlot, lval(redofr(lval(maxfr))))
+					- "prepare for full disj hijack",
+				assign(redofr(lval(maxfr)), lval(curfr))
+					- "prepare for full disj hijack"
+			]) }
 		;
-			true
+			{ CurfrMaxfr = must_be_equal },
+			(
+				{ ResumeKnown = resume_point_unknown },
+				code_info__acquire_temp_slot(
+					lval(redoip(lval(curfr))), RedoipSlot),
+				{ HijackInfo = disj_half_hijack(RedoipSlot) },
+				{ Code = node([
+					assign(RedoipSlot,
+						lval(redoip(lval(curfr))))
+						- "prepare for half disj hijack"
+				]) }
+			;
+				{ ResumeKnown = resume_point_known },
+				{ HijackInfo = disj_quarter_hijack },
+				{ Code = empty }
+			)
 		)
 	;
-		FixCurFrCode = empty
-	},
-	code_info__generate_resume_setup(ResumeMap, ResumeCode),
-	{ Code = tree(FixCurFrCode, ResumeCode) }.
-
-:- pred code_info__generate_resume_setup(resume_maps, code_tree,
-	code_info, code_info).
-:- mode code_info__generate_resume_setup(in, out, in, out) is det.
+		{ HijackInfo = disj_no_hijack },
+		{ Code = empty }
+	).
 
-code_info__generate_resume_setup(ResumeMaps, Code) -->
+code_info__undo_disj_hijack(HijackInfo, Code) -->
+	code_info__get_fail_info(FailInfo),
+	{ FailInfo = fail_info(ResumePoints, ResumeKnown, CurfrMaxfr) },
 	(
-		{ ResumeMaps = orig_only(Map1, Addr1) },
-		{ extract_label_from_code_addr(Addr1, Label1) },
+		{ HijackInfo = disj_full_hijack(RedoipSlot, RedofrSlot) },
+		{ require(unify(CurfrMaxfr, may_be_different),
+			"maxfr same as curfr in disj_full_hijack") },
 		{ Code = node([
-			label(Label1) -
-				"orig only failure continuation"
-		]) },
-		code_info__set_var_locations(Map1)
+			assign(redoip(lval(maxfr)), lval(RedoipSlot))
+				- "restore redoip for full disj hijack",
+			assign(redofr(lval(maxfr)), lval(RedofrSlot))
+				- "restore redofr for full disj hijack"
+		]) }
 	;
-		{ ResumeMaps = stack_only(Map1, Addr1) },
-		{ extract_label_from_code_addr(Addr1, Label1) },
+		{ HijackInfo = disj_half_hijack(RedoipSlot) },
+		{ require(unify(ResumeKnown, resume_point_unknown),
+			"resume point known in disj_half_hijack") },
+		{ require(unify(CurfrMaxfr, must_be_equal),
+			"maxfr may be different from curfr in disj_half_hijack") },
 		{ Code = node([
-			label(Label1) -
-				"stack only failure continuation"
-		]) },
-		code_info__set_var_locations(Map1)
+			assign(redoip(lval(curfr)), lval(RedoipSlot))
+				- "restore redoip for half disj hijack"
+		]) }
 	;
-		{ ResumeMaps = stack_and_orig(Map1, Addr1, Map2, Addr2) },
-		{ extract_label_from_code_addr(Addr1, Label1) },
-		{ extract_label_from_code_addr(Addr2, Label2) },
-		{ Label1Code = node([
-			label(Label1) -
-				"stack failure continuation before orig"
-		]) },
-		code_info__set_var_locations(Map1),
-		{ map__to_assoc_list(Map2, AssocList2) },
-		code_info__place_resume_vars(AssocList2, PlaceCode),
-		{ Label2Code = node([
-			label(Label2) -
-				"orig failure continuation after stack"
-		]) },
-		code_info__set_var_locations(Map2),
-		{ Code = tree(Label1Code, tree(PlaceCode, Label2Code)) }
+		{ HijackInfo = disj_quarter_hijack },
+		{ require(unify(ResumeKnown, resume_point_known),
+			"resume point not known in disj_quarter_hijack") },
+		{ require(unify(CurfrMaxfr, must_be_equal),
+			"maxfr may be different from curfr in disj_quarter_hijack") },
+		{ stack__top_det(ResumePoints, ResumePoint) },
+		{ code_info__pick_stack_resume_point(ResumePoint,
+			_, StackLabel) },
+		{ LabelConst = const(code_addr_const(StackLabel)) },
+		{ Code = node([
+			assign(redoip(lval(curfr)), LabelConst)
+				- "restore redoip for quarter disj hijack"
+		]) }
 	;
-		{ ResumeMaps = orig_and_stack(Map1, Addr1, Map2, Addr2) },
-		{ extract_label_from_code_addr(Addr1, Label1) },
-		{ extract_label_from_code_addr(Addr2, Label2) },
-		{ Label1Code = node([
-			label(Label1) -
-				"orig failure continuation before stack"
-		]) },
-		code_info__set_var_locations(Map1),
-		{ map__to_assoc_list(Map2, AssocList2) },
-		code_info__place_resume_vars(AssocList2, PlaceCode),
-		{ Label2Code = node([
-			label(Label2) -
-				"stack failure continuation after orig"
-		]) },
-		code_info__set_var_locations(Map2),
-		{ Code = tree(Label1Code, tree(PlaceCode, Label2Code)) }
+		{ HijackInfo = disj_no_hijack },
+		{ Code = empty }
 	).
 
-:- pred extract_label_from_code_addr(code_addr, label).
-:- mode extract_label_from_code_addr(in, out) is det.
-
-extract_label_from_code_addr(CodeAddr, Label) :-
-	( CodeAddr = label(Label0) ->
-		Label = Label0
+code_info__prepare_for_ite_hijack(EffCodeModel, HijackInfo, Code) -->
+	code_info__get_fail_info(FailInfo0),
+	{ FailInfo0 = fail_info(_ResumePoints, ResumeKnown, CurfrMaxfr) },
+	( { EffCodeModel = model_non } ->
+		(
+			{ CurfrMaxfr = may_be_different },
+			code_info__acquire_temp_slot(lval(redoip(lval(maxfr))),
+				RedoipSlot),
+			code_info__acquire_temp_slot(lval(redofr(lval(maxfr))),
+				RedofrSlot),
+			code_info__acquire_temp_slot(lval(maxfr),
+				MaxfrSlot),
+			{ HijackInfo = ite_full_hijack(ResumeKnown,
+				RedoipSlot, RedofrSlot, MaxfrSlot) },
+			{ Code = node([
+				assign(MaxfrSlot, lval(maxfr))
+					- "prepare for full ite hijack",
+				assign(RedoipSlot, lval(redoip(lval(maxfr))))
+					- "prepare for full ite hijack",
+				assign(RedofrSlot, lval(redofr(lval(maxfr))))
+					- "prepare for full ite hijack",
+				assign(redofr(lval(maxfr)), lval(curfr))
+					- "prepare for full ite hijack"
+			]) }
+		;
+			{ CurfrMaxfr = must_be_equal },
+			(
+				{ ResumeKnown = resume_point_unknown },
+				code_info__acquire_temp_slot(
+					lval(redoip(lval(curfr))), RedoipSlot),
+				{ HijackInfo = ite_half_hijack(ResumeKnown,
+					RedoipSlot) },
+				{ Code = node([
+					assign(RedoipSlot,
+						lval(redoip(lval(curfr))))
+						- "prepare for half ite hijack"
+				]) }
+			;
+				{ ResumeKnown = resume_point_known },
+				{ HijackInfo = ite_quarter_hijack(
+					ResumeKnown) },
+				{ Code = empty }
+			)
+		)
 	;
-		error("code_info__generate_resume_setup: non-label!")
+		{ HijackInfo = ite_no_hijack(ResumeKnown) },
+		{ Code = empty }
 	).
 
-:- pred code_info__place_resume_vars(assoc_list(var, set(rval)), code_tree,
-	code_info, code_info).
-:- mode code_info__place_resume_vars(in, out, in, out) is det.
-
-code_info__place_resume_vars([], empty) --> [].
-code_info__place_resume_vars([Var - TargetSet | Rest], Code) -->
-	{ set__to_sorted_list(TargetSet, Targets) },
-	code_info__place_resume_var(Var, Targets, FirstCode),
-	{ Code = tree(FirstCode, RestCode) },
-	code_info__place_resume_vars(Rest, RestCode).
-
-:- pred code_info__place_resume_var(var, list(rval), code_tree,
-	code_info, code_info).
-:- mode code_info__place_resume_var(in, in, out, in, out) is det.
-
-code_info__place_resume_var(_Var, [], empty) --> [].
-code_info__place_resume_var(Var, [Target | Targets], Code) -->
-	( { Target = lval(TargetLval) } ->
-		code_info__place_var(Var, TargetLval, FirstCode)
+code_info__maybe_push_temp_frame(EffCodeModel, CanHijack, HijackInfo,
+		CutFrame, Code) -->
+	( { EffCodeModel = model_non } ->
+		( { HijackInfo = ite_full_hijack(_, _, _, MaxfrSlot0) } ->
+			{ CutFrame = MaxfrSlot0 }
+		;
+			{ CutFrame = curfr }
+		),
+		(
+			{ CanHijack = yes },
+			{ Code = node([
+				mkframe(temp_frame, do_fail)
+					- "protect slots hijacked by ite"
+			]) },
+			code_info__get_fail_info(FailInfo0),
+			{ FailInfo0 = fail_info(ResumePoints, ResumeKnown,
+				_) },
+			{ FailInfo = fail_info(ResumePoints, ResumeKnown,
+				may_be_different) },
+			code_info__set_fail_info(FailInfo)
+		;
+			{ CanHijack = no },
+			{ Code = empty }
+		)
 	;
-		{ error("code_info__place_resume_var: not lval") }
-	),
-	{ Code = tree(FirstCode, RestCode) },
-	code_info__place_resume_var(Var, Targets, RestCode).
+		{ CutFrame = maxfr },
+		{ Code = empty }
+	).
 
-	% Reset the code generator's database of what is where.
-	% Remember that the variables in the map are available in their
-	% associated rvals; forget about all other variables.
+code_info__ite_enter_then(HijackInfo, CutFrame, ThenCode, ElseCode) -->
+	code_info__get_fail_info(FailInfo0),
+	{ FailInfo0 = fail_info(ResumePoints0, ResumeKnown0, CurfrMaxfr) },
+	{ stack__pop_det(ResumePoints0, _, ResumePoints) },
+	{
+		HijackInfo = ite_full_hijack(ResumeKnown1,
+			RedoipSlot, RedofrSlot, MaxfrSlot),
+		ThenCode = node([
+			assign(redoip(lval(MaxfrSlot)), lval(RedoipSlot))
+				- "restore redoip for full ite hijack",
+			assign(redofr(lval(MaxfrSlot)), lval(RedofrSlot))
+				- "restore redofr for full ite hijack"
+		]),
+		ElseCode = node([
+			assign(redoip(lval(maxfr)), lval(RedoipSlot))
+				- "restore redoip for full ite hijack",
+			assign(redofr(lval(maxfr)), lval(RedofrSlot))
+				- "restore redofr for full ite hijack"
+		])
+	;
+		HijackInfo = ite_half_hijack(ResumeKnown1, RedoipSlot),
+		ThenCode = node([
+			assign(redoip(lval(CutFrame)), lval(RedoipSlot))
+				- "restore redoip for half ite hijack"
+		]),
+		ElseCode = ThenCode
+	;
+		HijackInfo = ite_quarter_hijack(ResumeKnown1),
+		stack__top_det(ResumePoints, ResumePoint),
+		(
+			code_info__maybe_pick_stack_resume_point(ResumePoint,
+				_, StackLabel)
+		->
+			LabelConst = const(code_addr_const(StackLabel)),
+			ThenCode = node([
+				assign(redoip(lval(CutFrame)), LabelConst) -
+					"restore redoip for quarter ite hijack"
+			])
+		;
+			ThenCode = empty
+		),
+		ElseCode = ThenCode
+	;
+		HijackInfo = ite_no_hijack(ResumeKnown1),
+		ThenCode = empty,
+		ElseCode = ThenCode
+	},
+	{
+		ResumeKnown0 = resume_point_known,
+		ResumeKnown1 = resume_point_known
+	->
+		ResumeKnown = resume_point_known
+	;
+		ResumeKnown = resume_point_unknown
+	},
+	{ FailInfo = fail_info(ResumePoints, ResumeKnown, CurfrMaxfr) },
+	code_info__set_fail_info(FailInfo).
 
-:- pred code_info__set_var_locations(map(var, set(rval)), code_info, code_info).
-:- mode code_info__set_var_locations(in, in, out) is det.
+code_info__enter_simple_neg(ResumeVars, GoalInfo, FailInfo0) -->
+	code_info__get_fail_info(FailInfo0),
+		% The only reason why we push a resume point at all
+		% is to protect the variables in ResumeVars from becoming
+		% unknown; by including them in the domain of the resume point,
+		% we guarantee that the will become zombies instead of unknown
+		% if they die in the pre- or post-goal updates.
+		% Therefore the only part of ResumePoint that matters
+		% is the set of variables in the resume map; the other
+		% parts of ResumePoint (the locations, the code address)
+		% will not be referenced.
+	{ set__to_sorted_list(ResumeVars, ResumeVarList) },
+	{ map__init(ResumeMap0) },
+	{ code_info__make_fake_resume_map(ResumeVarList,
+		ResumeMap0, ResumeMap) },
+	{ ResumePoint = orig_only(ResumeMap, do_redo) },
+	code_info__effect_resume_point(ResumePoint, model_semi, Code),
+	{ require(unify(Code, empty), "nonempty code for simple neg") },
+	code_info__pre_goal_update(GoalInfo, yes).
+
+code_info__leave_simple_neg(GoalInfo, FailInfo) -->
+	code_info__post_goal_update(GoalInfo),
+	code_info__set_fail_info(FailInfo).
+
+:- pred code_info__make_fake_resume_map(list(var)::in,
+	map(var, set(rval))::in, map(var, set(rval))::out) is det.
+
+code_info__make_fake_resume_map([], ResumeMap, ResumeMap).
+code_info__make_fake_resume_map([Var | Vars], ResumeMap0, ResumeMap) :-
+		% a visibly fake location
+	set__singleton_set(Locns, lval(reg(r, -1))),
+	map__det_insert(ResumeMap0, Var, Locns, ResumeMap1),
+	code_info__make_fake_resume_map(Vars, ResumeMap1, ResumeMap).
 
-code_info__set_var_locations(Map) -->
-	{ map__to_assoc_list(Map, List0) },
-	{ code_info__flatten_varlval_list(List0, List) },
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__reinit_state(List, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
+%---------------------------------------------------------------------------%
 
-:- pred code_info__flatten_varlval_list(assoc_list(var, set(rval)),
-						assoc_list(var, rval)).
-:- mode code_info__flatten_varlval_list(in, out) is det.
+code_info__effect_resume_point(ResumePoint, CodeModel, Code) -->
+	code_info__get_fail_info(FailInfo0),
+	{ FailInfo0 = fail_info(ResumePoints0, _ResumeKnown, CurfrMaxfr) },
+
+	{ stack__top(ResumePoints0, OldResumePoint) ->
+		code_info__pick_first_resume_point(OldResumePoint, OldMap, _),
+		code_info__pick_first_resume_point(ResumePoint, NewMap, _),
+		map__keys(OldMap, OldKeys),
+		map__keys(NewMap, NewKeys),
+		set__list_to_set(OldKeys, OldKeySet),
+		set__list_to_set(NewKeys, NewKeySet),
+		require(set__subset(OldKeySet, NewKeySet),
+			"non-nested resume point variable sets")
+	;
+		true
+	},
 
-code_info__flatten_varlval_list([], []).
-code_info__flatten_varlval_list([V - Rvals | Rest0], All) :-
-	code_info__flatten_varlval_list(Rest0, Rest),
-	set__to_sorted_list(Rvals, RvalList),
-	code_info__flatten_varlval_list_2(RvalList, V, Rest1),
-	list__append(Rest1, Rest, All).
+	{ stack__push(ResumePoints0, ResumePoint, ResumePoints) },
+	{ FailInfo = fail_info(ResumePoints, resume_point_known, CurfrMaxfr) },
+	code_info__set_fail_info(FailInfo),
+	( { CodeModel = model_non } ->
+		{ code_info__pick_stack_resume_point(ResumePoint,
+			_, StackLabel) },
+		{ LabelConst = const(code_addr_const(StackLabel)) },
+		{ Code = node([
+			assign(redoip(lval(maxfr)), LabelConst)
+				- "hijack redoip to effect resume point"
+		]) }
+	;
+		{ Code = empty }
+	).
 
-:- pred code_info__flatten_varlval_list_2(list(rval), var,
-	assoc_list(var, rval)).
-:- mode code_info__flatten_varlval_list_2(in, in, out) is det.
+%---------------------------------------------------------------------------%
 
-code_info__flatten_varlval_list_2([], _V, []).
-code_info__flatten_varlval_list_2([R | Rs], V, [V - R | Rest]) :-
-	code_info__flatten_varlval_list_2(Rs, V, Rest).
+code_info__top_resume_point(ResumePoint) -->
+	code_info__get_fail_info(FailInfo),
+	{ FailInfo = fail_info(ResumePoints, _, _) },
+	{ stack__top_det(ResumePoints, ResumePoint) }.
+
+code_info__set_resume_point_to_unknown -->
+	code_info__get_fail_info(FailInfo0),
+	{ FailInfo0 = fail_info(ResumePoints, _, CurfrMaxfr) },
+	{ FailInfo = fail_info(ResumePoints, resume_point_unknown,
+		CurfrMaxfr) },
+	code_info__set_fail_info(FailInfo).
+
+code_info__set_resume_point_and_frame_to_unknown -->
+	code_info__get_fail_info(FailInfo0),
+	{ FailInfo0 = fail_info(ResumePoints, _, _) },
+	{ FailInfo = fail_info(ResumePoints, resume_point_unknown,
+		may_be_different) },
+	code_info__set_fail_info(FailInfo).
 
 %---------------------------------------------------------------------------%
 
-code_info__failure_is_direct_branch(CodeAddr) -->
-	code_info__top_failure_cont(FailureCont),
-	{ FailureCont = failure_cont(ContInfo, FailureMap) },
-	{ code_info__fail_cont_is_known(ContInfo) },
-	code_info__pick_matching_resume_addr(FailureMap, CodeAddr).
-
 code_info__generate_failure(Code) -->
-	code_info__top_failure_cont(FailureCont),
-	{ FailureCont = failure_cont(ContInfo, FailureMap) },
+	code_info__get_fail_info(FailInfo),
+	{ FailInfo = fail_info(ResumePoints, ResumeKnown, _) },
 	(
-		{ code_info__fail_cont_is_known(ContInfo) }
-	->
+		{ ResumeKnown = resume_point_known },
+		{ stack__top_det(ResumePoints, TopResumePoint) },
 		(
-			code_info__pick_matching_resume_addr(FailureMap,
+			code_info__pick_matching_resume_addr(TopResumePoint,
 				FailureAddress0)
 		->
 			{ FailureAddress = FailureAddress0 },
 			{ PlaceCode = empty }
 		;
-			{ code_info__pick_first_resume_point(FailureMap,
+			{ code_info__pick_first_resume_point(TopResumePoint,
 				Map, FailureAddress) },
 			{ map__to_assoc_list(Map, AssocList) },
-			code_info__grab_code_info(CodeInfo),
+			code_info__remember_position(CurPos),
 			code_info__place_vars(AssocList, PlaceCode),
-			code_info__slap_code_info(CodeInfo)
+			code_info__reset_to_position(CurPos)
 		),
 		{ BranchCode = node([goto(FailureAddress) - "fail"]) },
 		{ Code = tree(PlaceCode, BranchCode) }
 	;
+		{ ResumeKnown = resume_point_unknown },
 		{ Code = node([goto(do_redo) - "fail"]) }
 	).
 
 code_info__fail_if_rval_is_false(Rval0, Code) -->
-	code_info__top_failure_cont(FailureCont),
-	{ FailureCont = failure_cont(ContInfo, FailureMap) },
+	code_info__get_fail_info(FailInfo),
+	{ FailInfo = fail_info(ResumePoints, ResumeKnown, _) },
 	(
-		{ code_info__fail_cont_is_known(ContInfo) }
-	->
+		{ ResumeKnown = resume_point_known },
+		{ stack__top_det(ResumePoints, TopResumePoint) },
 		(
-			code_info__pick_matching_resume_addr(FailureMap,
+			code_info__pick_matching_resume_addr(TopResumePoint,
 				FailureAddress0)
 		->
 				% We branch away if the test *fails*
@@ -1689,19 +1494,19 @@
 					"Test for failure"
 			]) }
 		;
-			{ code_info__pick_first_resume_point(FailureMap,
+			{ code_info__pick_first_resume_point(TopResumePoint,
 				Map, FailureAddress) },
 			{ map__to_assoc_list(Map, AssocList) },
 			code_info__get_next_label(SuccessLabel),
-			code_info__grab_code_info(CodeInfo),
+			code_info__remember_position(CurPos),
 			code_info__place_vars(AssocList, PlaceCode),
-			code_info__slap_code_info(CodeInfo),
+			code_info__reset_to_position(CurPos),
 			{ SuccessAddress = label(SuccessLabel) },
 				% We branch away if the test *fails*,
-				% therefore we branch around the code
-				% that moves variables to their failure
-				% locations and branches away
-				% if the test succeeds
+				% therefore if the test succeeds, we branch
+				% around the code that moves variables to
+				% their failure locations and branches away
+				% to the failure continuation
 			{ TestCode = node([
 				if_val(Rval0, SuccessAddress) -
 					"Test for failure"
@@ -1715,213 +1520,600 @@
 			{ Code = tree(TestCode, tree(PlaceCode, TailCode)) }
 		)
 	;
-		{ FailureAddress = do_redo },
-			% We branch away if the test *fails*
-		{ code_util__neg_rval(Rval0, Rval) },
-		{ Code = node([
-			if_val(Rval, FailureAddress) -
-				"Test for failure"
-		]) }
+		{ ResumeKnown = resume_point_unknown },
+			% We branch away if the test *fails*
+		{ code_util__neg_rval(Rval0, Rval) },
+		{ Code = node([
+			if_val(Rval, do_redo) -
+				"Test for failure"
+		]) }
+	).
+
+%---------------------------------------------------------------------------%
+
+code_info__failure_is_direct_branch(CodeAddr) -->
+	code_info__get_fail_info(FailInfo),
+	{ FailInfo = fail_info(ResumePoints, resume_point_known, _) },
+	{ stack__top(ResumePoints, TopResumePoint) },
+	code_info__pick_matching_resume_addr(TopResumePoint, CodeAddr).
+
+code_info__may_use_nondet_tailcall(MayTailCall) -->
+	code_info__get_fail_info(FailInfo),
+	{ FailInfo = fail_info(ResumePoints, ResumeKnown, _) },
+	(
+		{ ResumeKnown = resume_point_known },
+		{ stack__top_det(ResumePoints, TopResumePoint) },
+		{ TopResumePoint = stack_only(_, do_fail) }
+	->
+		{ MayTailCall = yes }
+	;
+		{ MayTailCall = no }
+	).
+
+%---------------------------------------------------------------------------%
+
+	% See whether the current locations of variables match the locations
+	% associated with any of the options in the given failure map.
+	% If yes, return the code_addr of that option.
+
+:- pred code_info__pick_matching_resume_addr(resume_point_info::in,
+	code_addr::out, code_info::in, code_info::out) is semidet.
+
+code_info__pick_matching_resume_addr(ResumeMaps, Addr) -->
+	code_info__variable_locations(Locations),
+	{
+		ResumeMaps = orig_only(Map1, Addr1),
+		( code_info__match_resume_loc(Map1, Locations) ->
+			Addr = Addr1
+		;
+			fail
+		)
+	;
+		ResumeMaps = stack_only(Map1, Addr1),
+		( code_info__match_resume_loc(Map1, Locations) ->
+			Addr = Addr1
+		;
+			fail
+		)
+	;
+		ResumeMaps = orig_and_stack(Map1, Addr1, Map2, Addr2),
+		( code_info__match_resume_loc(Map1, Locations) ->
+			Addr = Addr1
+		; code_info__match_resume_loc(Map2, Locations) ->
+			Addr = Addr2
+		;
+			fail
+		)
+	;
+		ResumeMaps = stack_and_orig(Map1, Addr1, Map2, Addr2),
+		( code_info__match_resume_loc(Map1, Locations) ->
+			Addr = Addr1
+		; code_info__match_resume_loc(Map2, Locations) ->
+			Addr = Addr2
+		;
+			fail
+		)
+	}.
+
+:- pred code_info__match_resume_loc(resume_map::in, resume_map::in) is semidet.
+
+code_info__match_resume_loc(Map, Locations0) :-
+	map__keys(Map, KeyList),
+	set__list_to_set(KeyList, Keys),
+	map__select(Locations0, Keys, Locations),
+	map__to_assoc_list(Locations, List),
+	\+ (
+		list__member(Thingy, List),
+		\+ (
+			Thingy = Var - Actual,
+			map__search(Map, Var, Rvals),
+			set__subset(Rvals, Actual)
+		)
+	).
+
+:- pred code_info__pick_first_resume_point(resume_point_info::in,
+	resume_map::out, code_addr::out) is det.
+
+code_info__pick_first_resume_point(orig_only(Map, Addr), Map, Addr).
+code_info__pick_first_resume_point(stack_only(Map, Addr), Map, Addr).
+code_info__pick_first_resume_point(orig_and_stack(Map, Addr, _, _), Map, Addr).
+code_info__pick_first_resume_point(stack_and_orig(Map, Addr, _, _), Map, Addr).
+
+:- pred code_info__pick_stack_resume_point(resume_point_info::in,
+	resume_map::out, code_addr::out) is det.
+
+code_info__pick_stack_resume_point(ResumePoint, Map, Addr) :-
+	( code_info__maybe_pick_stack_resume_point(ResumePoint, Map1, Addr1) ->
+		Map = Map1,
+		Addr = Addr1
+	;
+		error("no stack resume point")
+	).
+
+:- pred code_info__maybe_pick_stack_resume_point(resume_point_info::in,
+	resume_map::out, code_addr::out) is semidet.
+
+code_info__maybe_pick_stack_resume_point(stack_only(Map, Addr), Map, Addr).
+code_info__maybe_pick_stack_resume_point(orig_and_stack(_, _, Map, Addr),
+	Map, Addr).
+code_info__maybe_pick_stack_resume_point(stack_and_orig(Map, Addr, _, _),
+	Map, Addr).
+
+%---------------------------------------------------------------------------%
+
+code_info__produce_vars(Vars, Map, Code) -->
+	{ set__to_sorted_list(Vars, VarList) },
+	code_info__produce_vars_2(VarList, Map, Code).
+
+:- pred code_info__produce_vars_2(list(var)::in,
+	map(var, set(rval))::out,
+	code_tree::out, code_info::in, code_info::out) is det.
+
+code_info__produce_vars_2([], Map, empty) -->
+	{ map__init(Map) }.
+code_info__produce_vars_2([V | Vs], Map, Code) -->
+	code_info__produce_vars_2(Vs, Map0, Code0),
+	code_info__produce_variable_in_reg_or_stack(V, Code1, Rval),
+	{ set__singleton_set(Rvals, Rval) },
+	{ map__set(Map0, V, Rvals, Map) },
+	{ Code = tree(Code0, Code1) }.
+
+code_info__flush_resume_vars_to_stack(Code) -->
+	code_info__get_fail_info(FailInfo),
+	{ FailInfo = fail_info(ResumePointStack, _, _) },
+	{ stack__top_det(ResumePointStack, ResumePoint) },
+	{ code_info__pick_stack_resume_point(ResumePoint, StackMap, _) },
+	{ map__to_assoc_list(StackMap, StackLocs) },
+	code_info__place_vars(StackLocs, Code).
+
+%---------------------------------------------------------------------------%
+
+:- pred code_info__init_fail_info(code_model::in, maybe(set(var))::in,
+	resume_point_info::out, code_info::in, code_info::out) is det.
+
+code_info__init_fail_info(CodeModel, MaybeFailVars, ResumePoint) -->
+	(
+		{ CodeModel = model_det },
+		code_info__get_next_label(ResumeLabel),
+		{ ResumeAddress = label(ResumeLabel) },
+		{ ResumeKnown = resume_point_unknown },
+		{ CurfrMaxfr = may_be_different }
+	;
+		{ CodeModel = model_semi },
+			% The resume point for this label
+			% will be part of the procedure epilog.
+		code_info__get_next_label(ResumeLabel),
+		{ ResumeAddress = label(ResumeLabel) },
+		{ ResumeKnown = resume_point_known },
+		{ CurfrMaxfr = may_be_different }
+	;
+		{ CodeModel = model_non },
+		( { MaybeFailVars = yes(_) } ->
+			code_info__get_next_label(ResumeLabel),
+			{ ResumeAddress = label(ResumeLabel) }
+		;
+			{ ResumeAddress = do_fail }
+		),
+		{ ResumeKnown = resume_point_known },
+		{ CurfrMaxfr = must_be_equal }
+	),
+	( { MaybeFailVars = yes(FailVars) } ->
+		code_info__get_stack_slots(StackSlots),
+		{ map__select(StackSlots, FailVars, StackMap0) },
+		{ map__to_assoc_list(StackMap0, StackList0) },
+		{ code_info__make_singleton_sets(StackList0, StackList) },
+		{ map__from_assoc_list(StackList, StackMap) }
+	;
+		{ map__init(StackMap) }
+	),
+	{ ResumePoint = stack_only(StackMap, ResumeAddress) },
+	{ stack__init(ResumeStack0) },
+	{ stack__push(ResumeStack0, ResumePoint, ResumeStack) },
+	{ FailInfo = fail_info(ResumeStack, ResumeKnown, CurfrMaxfr) },
+	code_info__set_fail_info(FailInfo).
+
+%---------------------------------------------------------------------------%
+
+code_info__make_resume_point(ResumeVars, ResumeLocs, FullMap, ResumePoint) -->
+	code_info__get_stack_slots(StackSlots),
+	{ map__select(FullMap, ResumeVars, OrigMap) },
+	(
+		{ ResumeLocs = orig_only },
+		code_info__get_next_label(OrigLabel),
+		{ OrigAddr = label(OrigLabel) },
+		{ ResumePoint = orig_only(OrigMap, OrigAddr) }
+	;
+		{ ResumeLocs = stack_only },
+		{ map__select(StackSlots, ResumeVars, StackMap0) },
+		{ map__to_assoc_list(StackMap0, StackList0) },
+		{ code_info__make_singleton_sets(StackList0, StackList) },
+		{ map__from_assoc_list(StackList, StackMap) },
+		code_info__get_next_label(StackLabel),
+		{ StackAddr = label(StackLabel) },
+		{ ResumePoint = stack_only(StackMap, StackAddr) }
+	;
+		{ ResumeLocs = orig_and_stack },
+		{ map__select(StackSlots, ResumeVars, StackMap0) },
+		{ map__to_assoc_list(StackMap0, StackList0) },
+		{ code_info__make_singleton_sets(StackList0, StackList) },
+		{ map__from_assoc_list(StackList, StackMap) },
+		code_info__get_next_label(OrigLabel),
+		{ OrigAddr = label(OrigLabel) },
+		code_info__get_next_label(StackLabel),
+		{ StackAddr = label(StackLabel) },
+		{ ResumePoint = orig_and_stack(OrigMap, OrigAddr,
+			StackMap, StackAddr) }
+	;
+		{ ResumeLocs = stack_and_orig },
+		{ map__select(StackSlots, ResumeVars, StackMap0) },
+		{ map__to_assoc_list(StackMap0, StackList0) },
+		{ code_info__make_singleton_sets(StackList0, StackList) },
+		{ map__from_assoc_list(StackList, StackMap) },
+		code_info__get_next_label(StackLabel),
+		{ StackAddr = label(StackLabel) },
+		code_info__get_next_label(OrigLabel),
+		{ OrigAddr = label(OrigLabel) },
+		{ ResumePoint = stack_and_orig(StackMap, StackAddr,
+			OrigMap, OrigAddr) }
+	).
+
+:- pred code_info__make_singleton_sets(assoc_list(var, lval)::in,
+	assoc_list(var, set(rval))::out) is det.
+
+code_info__make_singleton_sets([], []).
+code_info__make_singleton_sets([V - L | Rest0], [V - Rs | Rest]) :-
+	set__singleton_set(Rs, lval(L)),
+	code_info__make_singleton_sets(Rest0, Rest).
+
+%---------------------------------------------------------------------------%
+
+	% The code we generate for a resumption point looks like this:
+	%
+	% label(StackLabel)
+	% <assume variables are where StackMap says they are>
+	% <copy variables to their locations according to OrigMap>
+	% label(OrigLabel)
+	% <assume variables are where OrigMap says they are>
+	%
+	% Failures at different points may cause control to arrive at
+	% the resumption point via either label, which is why the last
+	% line is necessary.
+	%
+	% The idea is that failures from other procedures will go to
+	% StackLabel, and that failures from this procedure while
+	% everything is in its original place will go to OrigLabel.
+	% Failures from this procedure where not everything is in its
+	% original place can go to either, after moving the resume variables
+	% to the places where the label expects them.
+	%
+	% The above layout (stack, then orig) is the most common. However,
+	% liveness.m may decide that one or other of the two labels will
+	% never be referred to (e.g. because there are no calls inside
+	% the range of effect of the resumption point or because a call
+	% follows immediately after the establishment of the resumption
+	% point), or that it would be more efficient to put the two labels
+	% in the other order (e.g. because the code after the resumption point
+	% needs most of the variables in their stack slots).
+
+code_info__generate_resume_point(ResumePoint, Code) -->
+	(
+		{ ResumePoint = orig_only(Map1, Addr1) },
+		{ extract_label_from_code_addr(Addr1, Label1) },
+		{ Code = node([
+			label(Label1) -
+				"orig only failure continuation"
+		]) },
+		code_info__set_var_locations(Map1)
+	;
+		{ ResumePoint = stack_only(Map1, Addr1) },
+		{ extract_label_from_code_addr(Addr1, Label1) },
+		{ Code = node([
+			label(Label1) -
+				"stack only failure continuation"
+		]) },
+		code_info__set_var_locations(Map1)
+	;
+		{ ResumePoint = stack_and_orig(Map1, Addr1, Map2, Addr2) },
+		{ extract_label_from_code_addr(Addr1, Label1) },
+		{ extract_label_from_code_addr(Addr2, Label2) },
+		{ Label1Code = node([
+			label(Label1) -
+				"stack failure continuation before orig"
+		]) },
+		code_info__set_var_locations(Map1),
+		{ map__to_assoc_list(Map2, AssocList2) },
+		code_info__place_resume_vars(AssocList2, PlaceCode),
+		{ Label2Code = node([
+			label(Label2) -
+				"orig failure continuation after stack"
+		]) },
+		code_info__set_var_locations(Map2),
+		{ Code = tree(Label1Code, tree(PlaceCode, Label2Code)) }
+	;
+		{ ResumePoint = orig_and_stack(Map1, Addr1, Map2, Addr2) },
+		{ extract_label_from_code_addr(Addr1, Label1) },
+		{ extract_label_from_code_addr(Addr2, Label2) },
+		{ Label1Code = node([
+			label(Label1) -
+				"orig failure continuation before stack"
+		]) },
+		code_info__set_var_locations(Map1),
+		{ map__to_assoc_list(Map2, AssocList2) },
+		code_info__place_resume_vars(AssocList2, PlaceCode),
+		{ Label2Code = node([
+			label(Label2) -
+				"stack failure continuation after orig"
+		]) },
+		code_info__set_var_locations(Map2),
+		{ Code = tree(Label1Code, tree(PlaceCode, Label2Code)) }
+	).
+
+:- pred extract_label_from_code_addr(code_addr::in, label::out) is det.
+
+extract_label_from_code_addr(CodeAddr, Label) :-
+	( CodeAddr = label(Label0) ->
+		Label = Label0
+	;
+		error("code_info__generate_resume_setup: non-label!")
 	).
 
-%---------------------------------------------------------------------------%
+:- pred code_info__place_resume_vars(assoc_list(var, set(rval))::in,
+	code_tree::out, code_info::in, code_info::out) is det.
 
-	% See whether the current locations of variables match the locations
-	% associated with any of the options in the given failure map.
-	% If yes, return the code_addr of that option.
+code_info__place_resume_vars([], empty) --> [].
+code_info__place_resume_vars([Var - TargetSet | Rest], Code) -->
+	{ set__to_sorted_list(TargetSet, Targets) },
+	code_info__place_resume_var(Var, Targets, FirstCode),
+	{ Code = tree(FirstCode, RestCode) },
+	code_info__place_resume_vars(Rest, RestCode).
 
-:- pred code_info__pick_matching_resume_addr(resume_maps, code_addr,
-	code_info, code_info).
-:- mode code_info__pick_matching_resume_addr(in, out, in, out) is semidet.
+:- pred code_info__place_resume_var(var::in, list(rval)::in, code_tree::out,
+	code_info::in, code_info::out) is det.
 
-code_info__pick_matching_resume_addr(ResumeMaps, Addr) -->
-	code_info__variable_locations(Locations),
-	{
-		ResumeMaps = orig_only(Map1, Addr1),
-		( code_info__match_resume_loc(Map1, Locations) ->
-			Addr = Addr1
-		;
-			fail
-		)
-	;
-		ResumeMaps = stack_only(Map1, Addr1),
-		( code_info__match_resume_loc(Map1, Locations) ->
-			Addr = Addr1
-		;
-			fail
-		)
-	;
-		ResumeMaps = orig_and_stack(Map1, Addr1, Map2, Addr2),
-		( code_info__match_resume_loc(Map1, Locations) ->
-			Addr = Addr1
-		; code_info__match_resume_loc(Map2, Locations) ->
-			Addr = Addr2
-		;
-			fail
-		)
+code_info__place_resume_var(_Var, [], empty) --> [].
+code_info__place_resume_var(Var, [Target | Targets], Code) -->
+	( { Target = lval(TargetLval) } ->
+		code_info__place_var(Var, TargetLval, FirstCode)
 	;
-		ResumeMaps = stack_and_orig(Map1, Addr1, Map2, Addr2),
-		( code_info__match_resume_loc(Map1, Locations) ->
-			Addr = Addr1
-		; code_info__match_resume_loc(Map2, Locations) ->
-			Addr = Addr2
-		;
-			fail
-		)
-	}.
+		{ error("code_info__place_resume_var: not lval") }
+	),
+	{ Code = tree(FirstCode, RestCode) },
+	code_info__place_resume_var(Var, Targets, RestCode).
 
-:- pred code_info__match_resume_loc(resume_map, resume_map).
-:- mode code_info__match_resume_loc(in, in) is semidet.
+	% Reset the code generator's database of what is where.
+	% Remember that the variables in the map are available in their
+	% associated rvals; forget about all other variables.
 
-code_info__match_resume_loc(Map, Locations0) :-
-	map__keys(Map, KeyList),
-	set__list_to_set(KeyList, Keys),
-	map__select(Locations0, Keys, Locations),
-	map__to_assoc_list(Locations, List),
-	\+ (
-		list__member(Thingy, List),
-		\+ (
-			Thingy = Var - Actual,
-			map__search(Map, Var, Rvals),
-			set__subset(Rvals, Actual)
-		)
-	).
+:- pred code_info__set_var_locations(resume_map::in,
+	code_info::in, code_info::out) is det.
 
-	% Find the first label that will be generated for the
-	% given failure continuation based on the scheme used by
-	% code_info__generate_failure_cont.
+code_info__set_var_locations(Map) -->
+	{ map__to_assoc_list(Map, List0) },
+	{ code_info__flatten_varlval_list(List0, List) },
+	code_info__get_exprn_info(Exprn0),
+	{ code_exprn__reinit_state(List, Exprn0, Exprn) },
+	code_info__set_exprn_info(Exprn).
 
-:- pred code_info__find_first_resume_label(failure_cont, code_addr).
-:- mode code_info__find_first_resume_label(in, out) is det.
+:- pred code_info__flatten_varlval_list(assoc_list(var, set(rval))::in,
+	assoc_list(var, rval)::out) is det.
 
-code_info__find_first_resume_label(FailureCont, Address) :-
-	FailureCont = failure_cont(ContInfo, FailMap),
-	(
-		ContInfo = nondet(_, MaybeRedoLabel),
-		MaybeRedoLabel = yes(RedoLabel)
-	->
-		Address = label(RedoLabel)
-	;
-		code_info__pick_first_resume_point(FailMap, _, Address)
-	).
+code_info__flatten_varlval_list([], []).
+code_info__flatten_varlval_list([V - Rvals | Rest0], All) :-
+	code_info__flatten_varlval_list(Rest0, Rest),
+	set__to_sorted_list(Rvals, RvalList),
+	code_info__flatten_varlval_list_2(RvalList, V, Rest1),
+	list__append(Rest1, Rest, All).
 
-:- pred code_info__pick_first_resume_point(resume_maps, resume_map, code_addr).
-:- mode code_info__pick_first_resume_point(in, out, out) is det.
+:- pred code_info__flatten_varlval_list_2(list(rval)::in, var::in,
+	assoc_list(var, rval)::out) is det.
 
-code_info__pick_first_resume_point(orig_only(Map, Addr), Map, Addr).
-code_info__pick_first_resume_point(stack_only(Map, Addr), Map, Addr).
-code_info__pick_first_resume_point(orig_and_stack(Map, Addr, _, _), Map, Addr).
-code_info__pick_first_resume_point(stack_and_orig(Map, Addr, _, _), Map, Addr).
+code_info__flatten_varlval_list_2([], _V, []).
+code_info__flatten_varlval_list_2([R | Rs], V, [V - R | Rest]) :-
+	code_info__flatten_varlval_list_2(Rs, V, Rest).
 
-:- pred code_info__pick_last_resume_point(resume_maps, resume_map, code_addr).
-:- mode code_info__pick_last_resume_point(in, out, out) is det.
+code_info__resume_point_vars(ResumePoint, Vars) :-
+	code_info__pick_first_resume_point(ResumePoint, ResumeMap, _),
+	map__keys(ResumeMap, Vars).
 
-code_info__pick_last_resume_point(orig_only(Map, Addr), Map, Addr).
-code_info__pick_last_resume_point(stack_only(Map, Addr), Map, Addr).
-code_info__pick_last_resume_point(orig_and_stack( _, _, Map, Addr), Map, Addr).
-code_info__pick_last_resume_point(stack_and_orig( _, _, Map, Addr), Map, Addr).
-
-:- pred code_info__pick_stack_resume_point(resume_maps, resume_map, code_addr).
-:- mode code_info__pick_stack_resume_point(in, out, out) is det.
-
-code_info__pick_stack_resume_point(orig_only(_, _), _, _) :-
-	error("no stack resume point").
-code_info__pick_stack_resume_point(stack_only(Map, Addr), Map, Addr).
-code_info__pick_stack_resume_point(orig_and_stack(_, _, Map, Addr), Map, Addr).
-code_info__pick_stack_resume_point(stack_and_orig(Map, Addr, _, _), Map, Addr).
+code_info__resume_point_stack_addr(ResumePoint, StackAddr) :-
+	code_info__pick_stack_resume_point(ResumePoint, _, StackAddr).
 
 %---------------------------------------------------------------------------%
 
-code_info__unset_failure_cont(Code) -->
-	code_info__flush_resume_vars_to_stack(Code),
-	code_info__top_failure_cont(FailureCont0),
-	{ FailureCont0 = failure_cont(ContInfo0, FailureMap) },
-	code_info__pop_failure_cont,
-	{
-		ContInfo0 = semidet,
-		error("unset of semidet failure cont")
-	;
-		ContInfo0 = nondet(_, MaybeRedoLabel),
-		ContInfo = nondet(unknown, MaybeRedoLabel)
-	},
-	{ FailureCont = failure_cont(ContInfo, FailureMap) },
-	code_info__push_failure_cont(FailureCont).
+:- type det_commit_info
+	--->	det_commit_info(
+			maybe(lval),		% location of saved maxfr
+			maybe(pair(lval))	% location of saved ticket
+						% counter and trail pointer
+		).
 
-code_info__flush_resume_vars_to_stack(Code) -->
-	code_info__top_failure_cont(FailureCont0),
-	{ FailureCont0 = failure_cont(_, FailureMap) },
-	{ code_info__pick_stack_resume_point(FailureMap, StackMap, _) },
-	{ map__to_assoc_list(StackMap, StackLocs) },
-	code_info__place_resume_vars(StackLocs, Code).
+code_info__generate_det_pre_commit(DetCommitInfo, Code) -->
+	code_info__get_fail_info(FailInfo0),
+	{ FailInfo0 = fail_info(_, _, CurfrMaxfr) },
+	(
+		{ CurfrMaxfr = may_be_different },
+		code_info__acquire_temp_slot(lval(maxfr), MaxfrSlot),
+		{ SaveMaxfrCode = node([
+			assign(MaxfrSlot, lval(maxfr))
+				- "save the value of maxfr"
+		]) },
+		{ MaybeMaxfrSlot = yes(MaxfrSlot) }
+	;
+		{ CurfrMaxfr = must_be_equal },
+		{ SaveMaxfrCode = empty },
+		{ MaybeMaxfrSlot = no }
+	),
+	code_info__maybe_save_trail_info(MaybeTrailSlots, SaveTrailCode),
+	{ DetCommitInfo = det_commit_info(MaybeMaxfrSlot, MaybeTrailSlots) },
+	{ Code = tree(SaveMaxfrCode, SaveTrailCode) }.
 
-code_info__may_use_nondet_tailcall(MayTailCall) -->
-	code_info__top_failure_cont(FailureCont),
-	{ FailureCont = failure_cont(ContInfo, FailureMap) },
+code_info__generate_det_commit(DetCommitInfo, Code) -->
+	{ DetCommitInfo = det_commit_info(MaybeMaxfrSlot, MaybeTrailSlots) },
 	(
-		{ code_info__fail_cont_is_known(ContInfo) },
-		{ FailureMap = stack_only(_, do_fail) }
-	->
-		{ MayTailCall = yes }
+		{ MaybeMaxfrSlot = yes(MaxfrSlot) },
+		{ RestoreMaxfrCode = node([
+			assign(maxfr, lval(MaxfrSlot))
+				- "restore the value of maxfr - perform commit"
+		]) },
+		code_info__release_temp_slot(MaxfrSlot)
 	;
-		{ MayTailCall = no }
-	).
+		{ MaybeMaxfrSlot = no },
+		{ RestoreMaxfrCode = node([
+			assign(maxfr, lval(curfr))
+				- "restore the value of maxfr - perform commit"
+		]) }
+	),
+	code_info__maybe_restore_trail_info(MaybeTrailSlots,
+		CommitTrailCode, _),
+	{ Code = tree(RestoreMaxfrCode, CommitTrailCode) }.
 
 %---------------------------------------------------------------------------%
 
-code_info__do_soft_cut(TheFrame, Code, ContCode) -->
-	code_info__top_failure_cont(FailureCont),
-	{ FailureCont = failure_cont(ContInfo, _) },
+:- type semi_commit_info
+	--->	semi_commit_info(
+			fail_info,		% fail_info on entry
+			resume_point_info,
+			commit_hijack_info,
+			maybe(pair(lval))	% location of saved ticket
+						% counter and trail pointer
+		).
+
+:- type commit_hijack_info
+	--->	commit_quarter_hijack
+	;	commit_half_hijack(
+			lval		% the stack slot in which we saved
+					% the value of the hijacked redoip
+		)
+	;	commit_full_hijack(
+			lval,		% the stack slot in which we saved
+					% the value of the hijacked redoip
+			lval,		% the stack slot in which we saved
+					% the value of the hijacked redofr
+			lval		% the stack slot in which we saved
+					% the value of maxfr
+		).
+
+code_info__generate_semi_pre_commit(SemiCommitInfo, Code) -->
+	code_info__get_fail_info(FailInfo0),
+	{ FailInfo0 = fail_info(ResumePoints0, ResumeKnown, CurfrMaxfr) },
+	{ stack__top_det(ResumePoints0, TopResumePoint) },
+	code_info__clone_resume_point(TopResumePoint, NewResumePoint),
+	{ stack__push(ResumePoints0, NewResumePoint, ResumePoints) },
+	{ FailInfo = fail_info(ResumePoints, ResumeKnown, CurfrMaxfr) },
+	code_info__set_fail_info(FailInfo),
+
+	{ code_info__pick_stack_resume_point(NewResumePoint, _, StackLabel) },
+	{ StackLabelConst = const(code_addr_const(StackLabel)) },
 	(
-		{ code_info__fail_cont_is_known(ContInfo) }
-	->
-		{ code_info__find_first_resume_label(FailureCont, Address) }
+		{ CurfrMaxfr = may_be_different },
+		code_info__acquire_temp_slot(lval(redoip(lval(maxfr))),
+			RedoipSlot),
+		code_info__acquire_temp_slot(lval(redofr(lval(maxfr))),
+			RedofrSlot),
+		code_info__acquire_temp_slot(lval(maxfr),
+			MaxfrSlot),
+		{ HijackInfo = commit_full_hijack(RedoipSlot, RedofrSlot,
+			MaxfrSlot) },
+		{ HijackCode = node([
+			assign(RedoipSlot, lval(redoip(lval(maxfr))))
+				- "prepare for full commit hijack",
+			assign(RedofrSlot, lval(redofr(lval(maxfr))))
+				- "prepare for full commit hijack",
+			assign(MaxfrSlot, lval(maxfr))
+				- "prepare for full commit hijack",
+			assign(redofr(lval(maxfr)), lval(curfr))
+				- "hijack the redofr slot",
+			assign(redoip(lval(maxfr)), StackLabelConst)
+				- "hijack the redoip slot"
+		]) }
 	;
-			% If the newly uncovered cont is unknown then
-			% we must have created a new frame before the
-			% condition which we no longer need, so we
-			% set its redoip to do_fail.
-		{ Address = do_fail }
+		{ CurfrMaxfr = must_be_equal },
+		(
+			{ ResumeKnown = resume_point_unknown },
+			code_info__acquire_temp_slot(lval(redoip(lval(curfr))),
+				RedoipSlot),
+			{ HijackInfo = commit_half_hijack(RedoipSlot) },
+			{ HijackCode = node([
+				assign(RedoipSlot, lval(redoip(lval(curfr))))
+					- "prepare for half commit hijack",
+				assign(redoip(lval(curfr)), StackLabelConst)
+					- "hijack the redofr slot"
+			]) }
+		;
+			{ ResumeKnown = resume_point_known },
+			{ HijackInfo = commit_quarter_hijack },
+			{ HijackCode = node([
+				assign(redoip(lval(curfr)), StackLabelConst)
+					- "hijack the redofr slot"
+			]) }
+		)
 	),
-	code_info__get_globals(Globals),
-	{ globals__lookup_bool_option(Globals, use_trail, UseTrail) },
-	( { UseTrail = yes } ->
-		code_info__get_next_label(ContLabel),
-		{ ContAddress = label(ContLabel) },
-		{ ContCode = node([
-			label(ContLabel) - "soft cut failure cont entry point",
-			discard_ticket - "pop ticket stack",
-			goto(Address) - "branch to prev failure continuation"
+	code_info__maybe_save_trail_info(MaybeTrailSlots, SaveTrailCode),
+	{ SemiCommitInfo = semi_commit_info(FailInfo0, NewResumePoint,
+		HijackInfo, MaybeTrailSlots) },
+	{ Code = tree(HijackCode, SaveTrailCode) }.
+
+code_info__generate_semi_commit(SemiCommitInfo, Code) -->
+	{ SemiCommitInfo = semi_commit_info(FailInfo, ResumePoint,
+		HijackInfo, MaybeTrailSlots) },
+
+	code_info__set_fail_info(FailInfo),
+	(
+		{ HijackInfo = commit_full_hijack(RedoipSlot, RedofrSlot,
+			MaxfrSlot) },
+		{ SuccessUndoCode = node([
+			assign(maxfr, lval(MaxfrSlot))
+				- "restore maxfr for full commit hijack",
+			assign(redoip(lval(maxfr)), lval(RedoipSlot))
+				- "restore redoip for full commit hijack",
+			assign(redofr(lval(maxfr)), lval(RedofrSlot))
+				- "restore redofr for full commit hijack"
+		]) },
+		{ FailureUndoCode = node([
+			assign(redoip(lval(maxfr)), lval(RedoipSlot))
+				- "restore redoip for full commit hijack",
+			assign(redofr(lval(maxfr)), lval(RedofrSlot))
+				- "restore redofr for full commit hijack"
+		]) }
+	;
+		{ HijackInfo = commit_half_hijack(RedoipSlot) },
+		{ SuccessUndoCode = node([
+			assign(maxfr, lval(curfr))
+				- "restore maxfr for half commit hijack",
+			assign(redoip(lval(maxfr)), lval(RedoipSlot))
+				- "restore redoip for half commit hijack"
+		]) },
+		{ FailureUndoCode = node([
+			assign(redoip(lval(maxfr)), lval(RedoipSlot))
+				- "restore redoip for half commit hijack"
 		]) }
 	;
-		{ ContAddress = Address },
-		{ ContCode = empty }
+		{ HijackInfo = commit_quarter_hijack },
+		{ FailInfo = fail_info(ResumePoints, _, _) },
+		{ stack__top_det(ResumePoints, TopResumePoint) },
+		{ code_info__pick_stack_resume_point(TopResumePoint,
+			_, StackLabel) },
+		{ StackLabelConst = const(code_addr_const(StackLabel)) },
+		{ SuccessUndoCode = node([
+			assign(maxfr, lval(curfr))
+				- "restore maxfr for quarter commit hijack",
+			assign(redoip(lval(maxfr)), StackLabelConst)
+				- "restore redoip for quarter commit hijack"
+		]) },
+		{ FailureUndoCode = node([
+			assign(redoip(lval(maxfr)), StackLabelConst)
+				- "restore redoip for quarter commit hijack"
+		]) }
 	),
-	{ Code = node([
-		assign(redoip(lval(TheFrame)),
-			const(code_addr_const(ContAddress)))
-		- "prune away the `else' case of the if-then-else"
-	]) }.
 
-%---------------------------------------------------------------------------%
+	code_info__remember_position(AfterCommit),
+	code_info__generate_resume_point(ResumePoint, ResumePointCode),
+	code_info__generate_failure(FailCode),
+	code_info__reset_to_position(AfterCommit),
 
-code_info__generate_semi_pre_commit(RedoLabel, Slots, PreCommit) -->
-	code_info__generate_pre_commit_saves(Slots, SaveCode),
-	code_info__get_next_label(ResumeLabel),
-	code_info__top_failure_cont(FailureCont0),
-	{ FailureCont0 = failure_cont(_, FailureMap0) },
-	{ code_info__pick_stack_resume_point(FailureMap0, StackMap, _) },
-	{ FailureCont = failure_cont(nondet(known, no),
-		stack_only(StackMap, label(ResumeLabel))) },
-	code_info__push_failure_cont(FailureCont),
-	code_info__get_next_label(RedoLabel),
-	{ HijackCode = node([
-		assign(redoip(lval(maxfr)),
-			const(code_addr_const(label(RedoLabel)))) -
-			"Hijack the failure cont"
-	]) },
-	{ PreCommit = tree(SaveCode, HijackCode) }.
+	code_info__maybe_restore_trail_info(MaybeTrailSlots,
+		CommitTrailCode, RestoreTrailCode),
 
-code_info__generate_semi_commit(RedoLabel, Slots, Commit) -->
 	code_info__get_next_label(SuccLabel),
 	{ GotoSuccLabel = node([
 		goto(label(SuccLabel)) - "Jump to success continuation"
@@ -1929,240 +2121,104 @@
 	{ SuccLabelCode = node([
 		label(SuccLabel) - "Success continuation"
 	]) },
-	{ RedoLabelCode = node([
-		label(RedoLabel) - "Failure (redo) continuation"
-	]) },
-
-	code_info__grab_code_info(CodeInfo0),
-	code_info__top_failure_cont(FailureCont),
-	{ FailureCont = failure_cont(_, FailureMaps) },
-	code_info__generate_resume_setup(FailureMaps, FailureContCode),
-	code_info__pop_failure_cont,
-	code_info__generate_failure(Fail),
-	code_info__slap_code_info(CodeInfo0),
-	code_info__pop_failure_cont,
-
-	code_info__undo_pre_commit_saves(Slots, RestoreMaxfr, RestoreRedoip,
-		RestoreCurfr, SuccPopCode, FailPopCode),
-
 	{ SuccessCode =
-		tree(RestoreMaxfr,
-		tree(RestoreRedoip,
-		tree(RestoreCurfr,
-		     SuccPopCode)))
+		tree(SuccessUndoCode,
+		     CommitTrailCode)
 	},
-	{ FailCode =
-		tree(RedoLabelCode,
-		tree(RestoreCurfr,
-		tree(FailureContCode,
-		tree(RestoreRedoip,
-		tree(FailPopCode,
-		     Fail)))))
+	{ FailureCode =
+		tree(ResumePointCode,
+		tree(FailureUndoCode,
+		tree(RestoreTrailCode,
+		     FailCode)))
 	},
-	{ Commit =
+	{ Code =
 		tree(SuccessCode,
 		tree(GotoSuccLabel,
-		tree(FailCode,
+		tree(FailureCode,
 		     SuccLabelCode)))
 	}.
 
 %---------------------------------------------------------------------------%
 
-code_info__generate_det_pre_commit(Slots, PreCommit) -->
-	code_info__generate_pre_commit_saves(Slots, PreCommit),
-	% Since the code we are cutting is model_non, it will call
-	% unset_failure_cont. If the current top entry on the failure stack
-	% at the time is semidet, this would cause unset_failure_cont to abort.
-	% We therefore push a dummy nondet failure continuation onto the
-	% failure stack. Since the code we are cutting across is multi,
-	% the failure continuation will never actually be used.
-	code_info__top_failure_cont(FailureCont0),
-	{ FailureCont0 = failure_cont(_, FailureMap) },
-	{ code_info__pick_stack_resume_point(FailureMap, StackMap, _) },
-	{ FailureCont = failure_cont(nondet(known, no),
-		stack_only(StackMap, do_fail)) },
-	code_info__push_failure_cont(FailureCont).
-
-code_info__generate_det_commit(Slots, Commit) -->
-	% Remove the dummy failure continuation pushed by det_pre_commit.
-	code_info__pop_failure_cont,
-	code_info__undo_pre_commit_saves(Slots, RestoreMaxfr, RestoreRedoip,
-		RestoreCurfr, SuccPopCode, _FailPopCode),
-	{ Commit = tree(RestoreMaxfr,
-		   tree(RestoreRedoip,
-		   tree(RestoreCurfr,
-		        SuccPopCode)))
-	}.
-
-%---------------------------------------------------------------------------%
-
-:- pred code_info__generate_pre_commit_saves(commit_slots, code_tree,
-	code_info, code_info).
-:- mode code_info__generate_pre_commit_saves(out, out, in, out) is det.
+:- pred code_info__maybe_save_trail_info(maybe(pair(lval))::out,
+	code_tree::out, code_info::in, code_info::out) is det.
 
-code_info__generate_pre_commit_saves(Slots, Code) -->
+code_info__maybe_save_trail_info(MaybeTrailSlots, SaveTrailCode) -->
 	code_info__get_globals(Globals),
 	{ globals__lookup_bool_option(Globals, use_trail, UseTrail) },
 	( { UseTrail = yes } ->
-		{ NumSlots = 5 },
-		{ SaveMessage =
-	"push space for curfr, maxfr, redoip, ticket_counter and trail_ptr" }
+		code_info__acquire_temp_slot(ticket_counter, CounterSlot),
+		code_info__acquire_temp_slot(ticket, TrailPtrSlot),
+		{ MaybeTrailSlots = yes(CounterSlot - TrailPtrSlot) },
+		{ SaveTrailCode = node([
+			mark_ticket_stack(CounterSlot)
+				- "save the ticket counter",
+			store_ticket(TrailPtrSlot)
+				- "save the trail pointer"
+		]) }
 	;
-		{ NumSlots = 3 },
-		{ SaveMessage = "push space for curfr, maxfr, and redoip" }
-	),
-	code_info__get_proc_model(CodeModel),
-	( { CodeModel = model_non } ->
-		% the pushes and pops on the det stack below will cause
-		% problems for accurate garbage collection. Hence we
-		% make sure the commit vals are made live, so gc
-		% can figure out what is going on later.
-		code_info__get_module_info(ModuleInfo),
-		code_info__get_pred_id(PredId),
-		{ predicate_module(ModuleInfo, PredId, ModuleName) },
-		{ predicate_name(ModuleInfo, PredId, PredName) },
-		{ prog_out__sym_name_to_string(ModuleName, ModuleNameString) },
-		{ string__append_list(["commit in ",
-			ModuleNameString, ":", PredName], Message) },
-		{ PushCode = node([
-			incr_sp(NumSlots, Message) - SaveMessage
+		{ MaybeTrailSlots = no },
+		{ SaveTrailCode = empty }
+	).
+
+:- pred code_info__maybe_restore_trail_info(maybe(pair(lval))::in,
+	code_tree::out, code_tree::out, code_info::in, code_info::out) is det.
+
+code_info__maybe_restore_trail_info(MaybeTrailSlots,
+		CommitCode, RestoreCode) -->
+	(
+		{ MaybeTrailSlots = no },
+		{ CommitCode = empty },
+		{ RestoreCode = empty }
+	;
+		{ MaybeTrailSlots = yes(CounterSlot - TrailPtrSlot) },
+		{ CommitTrailCode = node([
+			reset_ticket(lval(TrailPtrSlot), commit)
+				- "discard trail entries and restore trail ptr"
 		]) },
-		{ CurfrSlot = stackvar(1) },
-		{ MaxfrSlot = stackvar(2) },
-		{ RedoipSlot = stackvar(3) },
-		( { UseTrail = yes } ->
-			{ TicketCounterSlot = stackvar(4) },
-			{ TrailPtrSlot = stackvar(5) },
-			{ MaybeTrailSlots = yes(TicketCounterSlot -
-						TrailPtrSlot) }
-		;
-			{ MaybeTrailSlots = no }
-		),
-		{ Slots = commit_slots(CurfrSlot, MaxfrSlot, RedoipSlot,
-			MaybeTrailSlots) },
-		code_info__add_commit_triple
-	;
-		{ PushCode = empty },
-		code_info__acquire_temp_slot(lval(curfr), CurfrSlot),
-		code_info__acquire_temp_slot(lval(maxfr), MaxfrSlot),
-		code_info__acquire_temp_slot(lval(redoip(lval(maxfr))),
-			RedoipSlot),
-		( { UseTrail = yes } ->
-			code_info__acquire_temp_slot(ticket_counter,
-						TicketCounterSlot),
-			code_info__acquire_temp_slot(ticket, TrailPtrSlot),
-			{ MaybeTrailSlots = yes(TicketCounterSlot -
-						TrailPtrSlot) }
-		;
-			{ MaybeTrailSlots = no }
-		),
-		{ Slots = commit_slots(CurfrSlot, MaxfrSlot, RedoipSlot,
-			MaybeTrailSlots) }
-	),
-	{ SaveCode = node([
-		assign(CurfrSlot, lval(curfr)) -
-				"Save current nondet frame pointer",
-		assign(MaxfrSlot, lval(maxfr)) -
-				"Save top of nondet stack",
-		assign(RedoipSlot, lval(redoip(lval(maxfr)))) -
-				"Save the top redoip"
-	]) },
-	{ MaybeTrailSlots = yes(TheTicketCounterSlot - TheTrailPtrSlot) ->
-		MaybeSaveTrailCode = node([
-			mark_ticket_stack(TheTicketCounterSlot) -
-				"Save the ticket counter",
-			store_ticket(TheTrailPtrSlot) -
-				"Save the trail pointer"
-		])
-	;
-		MaybeSaveTrailCode = empty
-	},
-	{ Code = tree(PushCode, tree(SaveCode, MaybeSaveTrailCode)) }.
+		{ RestoreTrailCode = node([
+			reset_ticket(lval(TrailPtrSlot), undo)
+				- "apply trail entries and restore trail ptr"
+		]) },
+		{ RestoreCounterCode = node([
+			discard_tickets_to(lval(CounterSlot))
+				- "restore the ticket counter"
+		]) },
+		code_info__release_temp_slot(CounterSlot),
+		code_info__release_temp_slot(TrailPtrSlot),
+		{ CommitCode = tree(CommitTrailCode, RestoreCounterCode) },
+		{ RestoreCode = tree(RestoreTrailCode, RestoreCounterCode) }
+	).
 
-:- pred code_info__undo_pre_commit_saves(commit_slots, code_tree, code_tree,
-	code_tree, code_tree, code_tree, code_info, code_info).
-:- mode code_info__undo_pre_commit_saves(in, out, out, out, out, out, in, out)
-	is det.
+%---------------------------------------------------------------------------%
 
-code_info__undo_pre_commit_saves(Slots, RestoreMaxfr, RestoreRedoip,
-		RestoreCurfr, SuccPopCode, FailPopCode) -->
-	{ Slots = commit_slots(CurfrSlot, MaxfrSlot, RedoipSlot,
-		MaybeTrailSlots) },
-	{ RestoreMaxfr = node([
-		assign(maxfr, lval(MaxfrSlot)) -
-			"Prune away unwanted choice-points"
-	]) },
-	{ RestoreRedoip = node([
-		assign(redoip(lval(maxfr)), lval(RedoipSlot)) -
-			"Restore the top redoip"
-	]) },
-	{ RestoreCurfr = node([
-		assign(curfr, lval(CurfrSlot)) -
-			"Restore nondet frame pointer"
-	]) },
-	code_info__get_proc_model(CodeModel),
-	( { CodeModel = model_non } ->
-		code_info__rem_commit_triple,
-		( { MaybeTrailSlots = yes(TicketCounterSlot - TrailPtrSlot) } ->
-			{ CommitTrail = node([
-				reset_ticket(lval(TrailPtrSlot), commit) -
-				"discard trail entries and restore trail ptr"
-			]) },
-			{ RestoreTrail = node([
-				reset_ticket(lval(TrailPtrSlot), undo) -
-				"apply trail entries and restore trail ptr"
-			]) },
-			{ RestoreTicketCounter = node([
-				discard_tickets_to(lval(TicketCounterSlot)) -
-				"restore the ticket counter"
-			]) },
-			{ NumSlots = 5 },
-			{ PopMessage =
-		     "pop curfr, maxfr, redoip, ticket_counter and trail_ptr" }
-		;
-			{ CommitTrail = empty },
-			{ RestoreTrail = empty },
-			{ RestoreTicketCounter = empty },
-			{ NumSlots = 3 },
-			{ PopMessage = "pop curfr, maxfr, and redoip" }
-		),
-		{ MainPopCode = node([
-			decr_sp(NumSlots) - PopMessage
-		]) }
+:- pred code_info__clone_resume_point(resume_point_info::in,
+	resume_point_info::out, code_info::in, code_info::out) is det.
+
+code_info__clone_resume_point(ResumePoint0, ResumePoint) -->
+	(
+		{ ResumePoint0 = orig_only(_, _) },
+		{ error("cloning orig_only resume point") }
 	;
-		code_info__release_temp_slot(CurfrSlot),
-		code_info__release_temp_slot(MaxfrSlot),
-		code_info__release_temp_slot(RedoipSlot),
-		( { MaybeTrailSlots = yes(TicketCounterSlot - TrailPtrSlot) } ->
-			{ CommitTrail = node([
-				reset_ticket(lval(TrailPtrSlot), commit) -
-				"discard trail entries and restore trail ptr"
-			]) },
-			{ RestoreTrail = node([
-				reset_ticket(lval(TrailPtrSlot), undo) -
-				"apply trail entries and restore trail ptr"
-			]) },
-			{ RestoreTicketCounter = node([
-				discard_tickets_to(lval(TicketCounterSlot)) -
-				"restore the ticket counter"
-			]) },
-			code_info__release_temp_slot(TicketCounterSlot),
-			code_info__release_temp_slot(TrailPtrSlot)
-		;
-			{ CommitTrail = empty },
-			{ RestoreTrail = empty },
-			{ RestoreTicketCounter = empty }
-		),
-		{ MainPopCode = empty }
-	),
-	{ SuccPopCode =
-		tree(CommitTrail,
-		tree(RestoreTicketCounter,
-		     MainPopCode)) },
-	{ FailPopCode =
-		tree(RestoreTrail,
-		tree(RestoreTicketCounter,
-		     MainPopCode)) }.
+		{ ResumePoint0 = stack_only(Map1, _) },
+		code_info__get_next_label(Label1),
+		{ Addr1 = label(Label1) },
+		{ ResumePoint = stack_only(Map1, Addr1) }
+	;
+		{ ResumePoint0 = stack_and_orig(Map1, _, Map2, _) },
+		code_info__get_next_label(Label1),
+		{ Addr1 = label(Label1) },
+		code_info__get_next_label(Label2),
+		{ Addr2 = label(Label2) },
+		{ ResumePoint = stack_and_orig(Map1, Addr1, Map2, Addr2) }
+	;
+		{ ResumePoint0 = orig_and_stack(Map1, _, Map2, _) },
+		code_info__get_next_label(Label2),
+		{ Addr2 = label(Label2) },
+		code_info__get_next_label(Label1),
+		{ Addr1 = label(Label1) },
+		{ ResumePoint = stack_and_orig(Map2, Addr2, Map1, Addr1) }
+	).
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -2330,7 +2386,7 @@
 	% Used for cases where the temp slot might still be needed again
 	% on backtracking and thus can't be reused in the code that follows.
 :- pred code_info__reset_and_pop_ticket(lval, reset_trail_reason,
-					code_tree, code_info, code_info).
+	code_tree, code_info, code_info).
 :- mode code_info__reset_and_pop_ticket(in, in, out, in, out) is det.
 
 :- pred code_info__discard_ticket(lval, code_tree, code_info, code_info).
@@ -2350,8 +2406,7 @@
 
 :- pred code_info__maybe_reset_and_pop_ticket(maybe(lval),
 	reset_trail_reason, code_tree, code_info, code_info).
-:- mode code_info__maybe_reset_and_pop_ticket(in, in, out, in, out)
-	is det.
+:- mode code_info__maybe_reset_and_pop_ticket(in, in, out, in, out) is det.
 
 :- pred code_info__maybe_discard_ticket(maybe(lval), code_tree,
 	code_info, code_info).
@@ -2456,11 +2511,9 @@
 		{ Code = empty }
 	).
 
-code_info__maybe_reset_and_pop_ticket(MaybeTicketSlot, Reason, Code)
-		-->
+code_info__maybe_reset_and_pop_ticket(MaybeTicketSlot, Reason, Code) -->
 	( { MaybeTicketSlot = yes(TicketSlot) } ->
-		code_info__reset_and_pop_ticket(TicketSlot, Reason,
-			Code)
+		code_info__reset_and_pop_ticket(TicketSlot, Reason, Code)
 	;
 		{ Code = empty }
 	).
@@ -2530,20 +2583,6 @@
 :- pred code_info__clear_r1(code_tree, code_info, code_info).
 :- mode code_info__clear_r1(out, in, out) is det.
 
-:- pred code_info__generate_branch_end(code_model, store_map, code_tree,
-	code_info, code_info).
-:- mode code_info__generate_branch_end(in, in, out, in, out) is det.
-
-	% code_info__remake_with_store_map throws away the exprn_info data
-	% structure, forgetting the current locations of all variables,
-	% and rebuilds it from scratch based on the given store map.
-	% The new exprn_info will know about only the variables present
-	% in the store map, and will believe they are where the store map
-	% says they are.
-
-:- pred code_info__remake_with_store_map(store_map, code_info, code_info).
-:- mode code_info__remake_with_store_map(in, in, out) is det.
-
 :- type call_direction ---> caller ; callee.
 
 	% Generate code to either setup the input arguments for a call
@@ -2681,34 +2720,6 @@
 
 %---------------------------------------------------------------------------%
 
-code_info__generate_branch_end(CodeModel, StoreMap, Code) -->
-	code_info__get_exprn_info(Exprn0),
-	{ map__to_assoc_list(StoreMap, VarLocs) },
-	{ code_exprn__place_vars(VarLocs, PlaceCode, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn),
-	( { CodeModel = model_non } ->
-		code_info__unset_failure_cont(FlushCode),
-		{ Code = tree(PlaceCode, FlushCode) }
-	;
-		{ Code = PlaceCode }
-	).
-
-code_info__remake_with_store_map(StoreMap) -->
-	{ map__to_assoc_list(StoreMap, VarLvals) },
-	{ code_info__fixup_lvallist(VarLvals, VarRvals) },
-	code_info__get_exprn_info(Exprn0),
-	{ code_exprn__reinit_state(VarRvals, Exprn0, Exprn) },
-	code_info__set_exprn_info(Exprn).
-
-:- pred code_info__fixup_lvallist(assoc_list(var, lval), assoc_list(var, rval)).
-:- mode code_info__fixup_lvallist(in, out) is det.
-
-code_info__fixup_lvallist([], []).
-code_info__fixup_lvallist([V - L | Ls], [V - lval(L) | Rs]) :-
-	code_info__fixup_lvallist(Ls, Rs).
-
-%---------------------------------------------------------------------------%
-
 code_info__setup_call([], _Direction, empty) --> [].
 code_info__setup_call([V - arg_info(Loc, Mode) | Rest], Direction, Code) -->
 	(
@@ -2804,7 +2815,7 @@
 	code_info, code_info).
 :- mode code_info__generate_stack_livevals(in, out, in, out) is det.
 
-:- pred code_info__generate_stack_livelvals(set(var), instmap, 
+:- pred code_info__generate_stack_livelvals(set(var), instmap,
 	list(liveinfo), code_info, code_info).
 :- mode code_info__generate_stack_livelvals(in, in, out, in, out) is det.
 
@@ -2821,9 +2832,7 @@
 	code_info__generate_var_livevals(VarList, LiveVals0, LiveVals1),
 	code_info__get_temps_in_use(TempsSet),
 	{ map__to_assoc_list(TempsSet, Temps) },
-	{ code_info__generate_temp_livevals(Temps, LiveVals1, LiveVals2) },
-	code_info__get_commit_triple_count(Triples),
-	{ code_info__generate_commit_livevals(Triples, LiveVals2, LiveVals) }.
+	{ code_info__generate_temp_livevals(Temps, LiveVals1, LiveVals) }.
 
 :- pred code_info__generate_var_livevals(list(var), set(lval), set(lval),
 	code_info, code_info).
@@ -2844,26 +2853,6 @@
 	set__insert(Vals0, Slot, Vals1),
 	code_info__generate_temp_livevals(Slots, Vals1, Vals).
 
-:- pred code_info__generate_commit_livevals(int, set(lval), set(lval)).
-:- mode code_info__generate_commit_livevals(in, in, out) is det.
-
-code_info__generate_commit_livevals(Triples0, Vals0, Vals) :-
-	( Triples0 = 0 ->
-		Vals = Vals0
-	;
-		CurfrSlot is (Triples0 - 1) * 3 + 1,
-		MaxfrSlot is (Triples0 - 1) * 3 + 2,
-		RedoipSlot is (Triples0 - 1) * 3 + 3,
-		CurfrVar = stackvar(CurfrSlot),
-		MaxfrVar = stackvar(MaxfrSlot),
-		RedoipVar = stackvar(RedoipSlot),
-		set__insert(Vals0, CurfrVar, Vals1),
-		set__insert(Vals1, MaxfrVar, Vals2),
-		set__insert(Vals2, RedoipVar, Vals3),
-		Triples1 is Triples0 - 1,
-		code_info__generate_commit_livevals(Triples1, Vals3, Vals)
-	).
-
 %---------------------------------------------------------------------------%
 
 code_info__generate_stack_livelvals(Args, AfterCallInstMap, LiveVals) -->
@@ -2890,9 +2879,7 @@
 		AfterCallInstMap, LiveVals3),
 	code_info__get_temps_in_use(TempsSet),
 	{ map__to_assoc_list(TempsSet, Temps) },
-	{ code_info__generate_temp_livelvals(Temps, LiveVals3, LiveVals4) },
-	code_info__get_commit_triple_count(Triples),
-	{ code_info__generate_commit_livelvals(Triples, LiveVals4, LiveVals) }.
+	{ code_info__generate_temp_livelvals(Temps, LiveVals3, LiveVals) }.
 
 :- pred code_info__generate_var_livelvals(list(var),
 	set(pair(lval, var)), set(pair(lval, var)), code_info, code_info).
@@ -2914,35 +2901,6 @@
 	code_info__get_live_value_type(StoredLval, LiveValueType),
 	code_info__generate_temp_livelvals(Slots, LiveInfo0, LiveInfo1).
 
-:- pred code_info__generate_commit_livelvals(int,
-	list(liveinfo), list(liveinfo)).
-:- mode code_info__generate_commit_livelvals(in, in, out) is det.
-
-code_info__generate_commit_livelvals(Triples0, LiveInfo0, LiveInfo) :-
-	( Triples0 = 0 ->
-		LiveInfo = LiveInfo0
-	;
-		Triples1 is Triples0 - 1,
-		code_info__generate_commit_livelvals(Triples1,
-			LiveInfo0, LiveInfo1),
-		CurfrSlot is (Triples0 - 1) * 3 + 1,
-		MaxfrSlot is (Triples0 - 1) * 3 + 2,
-		RedoipSlot is (Triples0 - 1) * 3 + 3,
-		CurfrVar = stackvar(CurfrSlot),
-		MaxfrVar = stackvar(MaxfrSlot),
-		RedoipVar = stackvar(RedoipSlot),
-		code_info__get_live_value_type(lval(curfr), CurfrValueType),
-		code_info__get_live_value_type(lval(maxfr), MaxfrValueType),
-		code_info__get_live_value_type(lval(redoip(lval(maxfr))),
-			RedoipValueType),
-		LiveInfo2 = [live_lvalue(CurfrVar, CurfrValueType, "", []) | 
-				LiveInfo1],
-		LiveInfo3 = [live_lvalue(MaxfrVar, MaxfrValueType, "", []) |
-				LiveInfo2],
-		LiveInfo  = [live_lvalue(RedoipVar, RedoipValueType, "", []) |
-				LiveInfo3]
-	).
-
 :- pred code_info__livevals_to_livelvals(assoc_list(lval, var), bool,
 	instmap, list(liveinfo), code_info, code_info).
 :- mode code_info__livevals_to_livelvals(in, in, in, out, in, out) is det.
@@ -2977,6 +2935,7 @@
 code_info__get_live_value_type(lval(curfr), curfr).
 code_info__get_live_value_type(lval(succfr(_)), unwanted).
 code_info__get_live_value_type(lval(prevfr(_)), unwanted).
+code_info__get_live_value_type(lval(redofr(_)), unwanted).
 code_info__get_live_value_type(lval(redoip(_)), unwanted).
 code_info__get_live_value_type(lval(succip(_)), unwanted).
 code_info__get_live_value_type(lval(sp), unwanted).



More information about the developers mailing list