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

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


Apparently part 4, which contained just the diff to code_info.m,
was more than 100 kb!, and hence bounced. Here it is in two halves.

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).
 
 %---------------------------------------------------------------------------%



More information about the developers mailing list