[m-rev.] diff: complete first draft of mmos transformation

Zoltan Somogyi zs at cs.mu.OZ.AU
Fri Jun 3 16:54:50 AEST 2005


Complete the first draft of the program transformation for the own minimal
model of minimal model evaluation. The runtime system is still very incomplete.

Nothing in this diff changes anything related to non-mmos grades.

compiler/table_gen.m:
	Change the implementation of the own stack transformation from the
	previous rough sketch to this first draft. It still uses calls to
	library predicates instead of inlined foreign_procs in some places,
	but that will be fixed later.

	Generalize the infrastructure for handling arguments to associate
	the position and mode with each argument variable, since this is needed
	for mechanism the own stack transformation uses to transfer the input
	arguments from the consumer to the generator.

	Switch to four-space indentation to avoid a bunch of bad line breaks.

	Conform to the current style for comments.

compiler/complexity.m:
	Rename some predicates to avoid clashes with similarly named predicates
	in table_gen.m in the tags file.

library/table_builtin.m:
	Add the library predicates the new tabling transformation needs to hang
	foreign_procs on.

	Comment out C code fragments that refer to as-yet-nonexistent C macros
	or functions, to allow the compiler to link in mmos grades. The
	predicates in which this happens aren't used yet.

	Conform to the current style for comments.

runtime/mercury_conf_param.h:
	Document the minimal model tabling's requirement for gc that doesn't
	recover memory on backtracking.

runtime/mercury_mm_own_stacks.[ch]:
	Revise the mechanism for creating new generators, and add an outline
	of its implementation.

	Comment out code that doesn't compile yet.

	Add the globals we need for communicating the input arguments and the
	location of the generator structure from the consumer to the newly
	created generator.

runtime/mercury_tabling.h:
	Fix a bug: the table tip node is a generator, not a consumer.

runtime/mercury_tabling_preds.h:
	Replace the previous placeholder definitions of some macros with
	drafts of actual definitions.

runtime/mercury_context.h:
	Conform to the current style for comments.

	Switch to four-space indentation to avoid a bunch of bad line breaks.

trace/mercury_trace_internal.c:
	Conform to the change in mercury_tabling.h.

Zoltan.

cvs diff: Diffing .
cvs diff: Diffing analysis
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/doc
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing browser
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
Index: compiler/complexity.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/complexity.m,v
retrieving revision 1.2
diff -u -b -r1.2 complexity.m
--- compiler/complexity.m	24 Mar 2005 02:00:19 -0000	1.2
+++ compiler/complexity.m	30 May 2005 03:52:41 -0000
@@ -270,7 +270,7 @@
 
 	classify_args(HeadVars, ArgModes, !.ModuleInfo, VarSet, VarTypes,
 		VarInfos),
-	allocate_slot_numbers(VarInfos, 0, NumberedProfiledVars),
+	allocate_slot_numbers_cl(VarInfos, 0, NumberedProfiledVars),
 	list__length(NumberedProfiledVars, NumProfiledVars),
 	generate_slot_goals(ProcNum, NumberedProfiledVars, NumProfiledVars,
 		Context, PredId, !ProcInfo, !ModuleInfo, SlotVar, SlotVarName,
@@ -290,28 +290,28 @@
 		int_to_string(NumProfiledVars) ++ ", " ++
 		IsActiveVarName ++ ");\n",
 
-	generate_foreign_proc(IsActivePred, det, [IsActiveOutputArg], [],
-		"", IsActiveStr, "", [IsActiveVar], !.ModuleInfo, Context,
-		IsActiveGoal),
+	complexity_generate_foreign_proc(IsActivePred, det,
+		[IsActiveOutputArg], [], "", IsActiveStr, "", [IsActiveVar],
+		!.ModuleInfo, Context, IsActiveGoal),
 
 	ExitPred = "complexity_exit_proc",
 	ExitStr = "\tMR_" ++ ExitPred ++ "(" ++
 		ProcNumStr ++ ", " ++ slot_var_name ++ ");\n",
-	generate_foreign_proc(ExitPred, det,
+	complexity_generate_foreign_proc(ExitPred, det,
 		[SlotInputArg], [], "", ExitStr, "", [],
 		!.ModuleInfo, Context, ExitGoal),
 
 	FailPred = "complexity_fail_proc",
 	FailStr = "\tMR_" ++ FailPred ++ "(" ++
 		ProcNumStr ++ ", " ++ slot_var_name ++ ");\n",
-	generate_foreign_proc(FailPred, failure,
+	complexity_generate_foreign_proc(FailPred, failure,
 		[SlotInputArg], [], "", FailStr, "", [],
 		!.ModuleInfo, Context, FailGoal),
 
 	RedoPred = "complexity_redo_proc",
 	RedoStr = "\tMR_" ++ RedoPred ++ "(" ++
 		ProcNumStr ++ ", " ++ slot_var_name ++ ");\n",
-	generate_foreign_proc(RedoPred, failure,
+	complexity_generate_foreign_proc(RedoPred, failure,
 		[SlotInputArg], [], "", RedoStr, "", [],
 		!.ModuleInfo, Context, RedoGoal0),
 
@@ -409,9 +409,9 @@
 		int_to_string(ProcNum) ++ ", " ++ SlotVarName ++ ");\n",
 	ProcStr = "\t" ++ ProcVarName ++ " = &MR_complexity_procs[" ++
 		int_to_string(ProcNum) ++ "];\n",
-	generate_foreign_proc(PredName, det, [SlotVarArg], ForeignArgs,
-		DeclCodeStr, PredCodeStr, ProcStr ++ FillCodeStr, [SlotVar],
-		!.ModuleInfo, Context, CallGoal),
+	complexity_generate_foreign_proc(PredName, det, [SlotVarArg],
+		ForeignArgs, DeclCodeStr, PredCodeStr, ProcStr ++ FillCodeStr,
+		[SlotVar], !.ModuleInfo, Context, CallGoal),
 	list__append(PrefixGoals, [CallGoal], Goals).
 
 :- pred generate_size_goals(assoc_list(prog_var, int)::in,
@@ -475,12 +475,12 @@
 	proc_info_set_varset(VarSet, !ProcInfo),
 	proc_info_set_vartypes(VarTypes, !ProcInfo).
 
-:- pred generate_foreign_proc(string::in, determinism::in,
+:- pred complexity_generate_foreign_proc(string::in, determinism::in,
 	list(foreign_arg)::in, list(foreign_arg)::in, string::in, string::in,
 	string::in, list(prog_var)::in, module_info::in, term__context::in,
 	hlds_goal::out) is det.
 
-generate_foreign_proc(PredName, Detism, Args, ExtraArgs,
+complexity_generate_foreign_proc(PredName, Detism, Args, ExtraArgs,
 		PrefixCode, Code, SuffixCode, BoundVars, ModuleInfo, Context,
 		Goal) :-
 	mercury_term_size_prof_builtin_module(BuiltinModule),
@@ -523,19 +523,21 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred allocate_slot_numbers(assoc_list(prog_var, complexity_arg_info)::in,
+:- pred allocate_slot_numbers_cl(assoc_list(prog_var, complexity_arg_info)::in,
 	int::in, assoc_list(prog_var, int)::out) is det.
 
-allocate_slot_numbers([], _, []).
-allocate_slot_numbers([Var - Info | VarInfos], Offset, NumberedProfiledVars) :-
+allocate_slot_numbers_cl([], _, []).
+allocate_slot_numbers_cl([Var - Info | VarInfos], Offset,
+		NumberedProfiledVars) :-
 	Info = complexity_arg_info(_, Kind),
 	( Kind = complexity_input_variable_size ->
-		allocate_slot_numbers(VarInfos, Offset + 1,
+		allocate_slot_numbers_cl(VarInfos, Offset + 1,
 			NumberedProfiledVarsTail),
 		NumberedProfiledVars =
 			[Var - Offset | NumberedProfiledVarsTail]
 	;
-		allocate_slot_numbers(VarInfos, Offset, NumberedProfiledVars)
+		allocate_slot_numbers_cl(VarInfos, Offset,
+			NumberedProfiledVars)
 	).
 
 :- func ground_vars(list(prog_var)) = assoc_list(prog_var, inst).
Index: compiler/table_gen.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/table_gen.m,v
retrieving revision 1.81
diff -u -b -r1.81 table_gen.m
--- compiler/table_gen.m	23 May 2005 03:15:40 -0000	1.81
+++ compiler/table_gen.m	3 Jun 2005 02:54:41 -0000
@@ -1,4 +1,6 @@
 %-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%-----------------------------------------------------------------------------%
 % Copyright (C) 1997-2005 The University of Melbourne.
 % This file may only be copied under the terms of the GNU General
 % Public License - see the file COPYING in the Mercury distribution.
@@ -97,12 +99,14 @@
 
 	% Values of this type map the pred_id of a minimal_model tabled
 	% predicate to the pred_id of its generator variant.
+    %
 :- type generator_map	==	map(pred_id, pred_id).
 
 	% NOTE: following preds seem to duplicate the code in passes_aux.m.
 	% The reason for this duplication is that this module needs a variant
 	% of this code that is able to handle passing a module_info to
 	% polymorphism and getting an updated module_info back.
+    %
 table_gen__process_module(!ModuleInfo, !IO) :-
 	module_info_preds(!.ModuleInfo, Preds0),
 	map__keys(Preds0, PredIds),
@@ -145,13 +149,12 @@
 	pred_info::in, module_info::in, module_info::out,
 	generator_map::in, generator_map::out, io::di, io::uo) is det.
 
-table_gen__process_proc(PredId, ProcId, ProcInfo0, PredInfo0,
-		!ModuleInfo, !GenMap, !IO) :-
+table_gen__process_proc(PredId, ProcId, ProcInfo0, PredInfo0, !ModuleInfo,
+        !GenMap, !IO) :-
 	proc_info_eval_method(ProcInfo0, EvalMethod),
 	( eval_method_requires_tabling_transform(EvalMethod) = yes ->
 		table_gen__transform_proc_if_possible(EvalMethod, PredId,
-			ProcId, ProcInfo0, _, PredInfo0, _, !ModuleInfo,
-			!GenMap, !IO)
+            ProcId, ProcInfo0, _, PredInfo0, _, !ModuleInfo, !GenMap, !IO)
 	;
 		module_info_globals(!.ModuleInfo, Globals),
 		globals__lookup_bool_option(Globals, trace_table_io, yes),
@@ -163,20 +166,16 @@
 			true
 		;
 			pred_id_to_int(PredId, PredIdInt),
-			Msg = string__format(
-				"I/O procedure pred id %d not model_det",
+            Msg = string__format("I/O procedure pred id %d not model_det",
 				[i(PredIdInt)]),
 			error(Msg)
 		),
-		globals__lookup_bool_option(Globals, trace_table_io_all,
-			TransformAll),
-		globals__lookup_bool_option(Globals, trace_table_io_require,
-			Require),
+        globals__lookup_bool_option(Globals, trace_table_io_all, TransformAll),
+        globals__lookup_bool_option(Globals, trace_table_io_require, Require),
 		proc_info_goal(ProcInfo0, BodyGoal),
 		predicate_module(!.ModuleInfo, PredId, PredModuleName),
-		should_io_procedure_be_transformed(TransformAll, Require,
-			BodyGoal, PredModuleName, AnnotationIsMissing,
-			TransformPrimitive),
+        should_io_procedure_be_transformed(TransformAll, Require, BodyGoal,
+            PredModuleName, AnnotationIsMissing, TransformPrimitive),
 		(
 			AnnotationIsMissing = yes,
 			report_missing_tabled_for_io(!.ModuleInfo, PredInfo0,
@@ -189,8 +188,7 @@
 			TransformPrimitive = no
 		;
 			TransformPrimitive = yes(Unitize),
-			globals__lookup_bool_option(Globals,
-				trace_table_io_only_retry,
+            globals__lookup_bool_option(Globals, trace_table_io_only_retry,
 				TraceTableIoOnlyRetry),
 			(
 				TraceTableIoOnlyRetry = no,
@@ -200,11 +198,10 @@
 				Decl = table_io_proc
 			),
 			TableIoMethod = eval_table_io(Decl, Unitize),
-			proc_info_set_eval_method(TableIoMethod,
-				ProcInfo0, ProcInfo1),
+            proc_info_set_eval_method(TableIoMethod, ProcInfo0, ProcInfo1),
 			table_gen__transform_proc_if_possible(TableIoMethod,
-				PredId, ProcId, ProcInfo1, _, PredInfo0, _,
-				!ModuleInfo, !GenMap, !IO)
+                PredId, ProcId, ProcInfo1, _, PredInfo0, _, !ModuleInfo,
+                !GenMap, !IO)
 		)
 	;
 		true
@@ -218,10 +215,12 @@
 should_io_procedure_be_transformed(TransformAll, Require, BodyGoal,
 		PredModuleName, AnnotationIsMissing, TransformInfo) :-
 	tabled_for_io_attributes(BodyGoal, TabledForIoAttrs),
-	( TabledForIoAttrs = [] ->
+    (
+        TabledForIoAttrs = [],
 		AnnotationIsMissing = no,
 		TransformInfo = no
-	; TabledForIoAttrs = [TabledForIoAttr] ->
+    ;
+        TabledForIoAttrs = [TabledForIoAttr],
 		(
 			TabledForIoAttr = not_tabled_for_io,
 			(
@@ -237,16 +236,13 @@
 					TransformInfo = no
 				;
 					TransformAll = yes,
-					may_call_mercury_attributes(BodyGoal,
-						MayCallMercuryAttrs),
+                    may_call_mercury_attributes(BodyGoal, MayCallMercuryAttrs),
 					(
-						MayCallMercuryAttrs =
-							[may_call_mercury]
+                        MayCallMercuryAttrs = [may_call_mercury]
 					->
 						TransformInfo = no
 					;
-						TransformInfo =
-							yes(table_io_alone)
+                        TransformInfo = yes(table_io_alone)
 					)
 				)
 			)
@@ -266,6 +262,7 @@
 			TransformInfo = yes(table_io_unitize)
 		)
 	;
+        TabledForIoAttrs = [_, _ | _],
 		% Since table_gen is run before inlining, each procedure
 		% should contain at most one foreign_proc goal.
 		error("should_io_procedure_be_transformed: " ++
@@ -276,14 +273,13 @@
 	is det.
 
 may_call_mercury_attributes(Goal, MayCallMercuryAttrs) :-
-	solutions(subgoal_may_call_mercury_attribute(Goal),
-		MayCallMercuryAttrs).
+    solutions(subgoal_may_call_mercury_attribute(Goal), MayCallMercuryAttrs).
 
 :- pred subgoal_may_call_mercury_attribute(hlds_goal::in,
 	may_call_mercury::out) is nondet.
 
 subgoal_may_call_mercury_attribute(Goal, MayCallMercuryAttr) :-
-	some [SubGoal,Attrs] (
+    some [SubGoal, Attrs] (
 		goal_contains_goal(Goal, SubGoal),
 		SubGoal = foreign_proc(Attrs, _, _, _, _, _) - _,
 		MayCallMercuryAttr = may_call_mercury(Attrs)
@@ -299,7 +295,7 @@
 	is nondet.
 
 subgoal_tabled_for_io_attribute(Goal, TabledForIoAttr) :-
-	some [SubGoal,Attrs] (
+    some [SubGoal, Attrs] (
 		goal_contains_goal(Goal, SubGoal),
 		SubGoal = foreign_proc(Attrs, _, _, _, _, _) - _,
 		TabledForIoAttr = tabled_for_io(Attrs),
@@ -371,8 +367,7 @@
 		EvalMethodStr = eval_method_to_string(EvalMethod),
 		Msg = [words("Ignoring the pragma"), fixed(EvalMethodStr),
 			words("for")] ++ ProcPieces ++
-			[words("due to lack of support"),
-			words("on this back end."), nl],
+            [words("due to lack of support on this back end."), nl],
 		error_util__write_error_pieces(Context, 0, Msg, !IO),
 		% 
 		% XXX We set the evaluation method to eval_normal here
@@ -409,7 +404,11 @@
 	proc_info_argmodes(!.ProcInfo, ArgModes),
 
 	get_input_output_vars(HeadVars, ArgModes, !.ModuleInfo, BadVars,
-		InputVars, OutputVars),
+        InputVarModes, OutputVarModes),
+    % assoc_list__keys(InputVarModes, InputVars),
+    % assoc_list__keys(OutputVarModes, OutputVars),
+    allocate_slot_numbers(InputVarModes, 0, NumberedInputVars),
+    allocate_slot_numbers(OutputVarModes, 0, NumberedOutputVars),
 	(
 		BadVars = []
 	;
@@ -430,42 +429,41 @@
 		module_info_globals(!.ModuleInfo, Globals),
 		globals__lookup_bool_option(Globals, trace_table_io_states,
 			TableIoStates),
+        assoc_list__from_corresponding_lists(HeadVars, ArgModes, HeadVarModes),
 		table_gen__create_new_io_goal(OrigGoal, Decl, Unitize,
 			TableIoStates, PredId, ProcId, TablingViaExtraArgs,
-			HeadVars, InputVars, OutputVars,
+            HeadVarModes, NumberedInputVars, NumberedOutputVars,
 			VarTypes0, VarTypes, VarSet0, VarSet,
 			TableInfo0, TableInfo, Goal, MaybeProcTableInfo),
 		MaybeCallTableTip = no
 	;
 		EvalMethod = eval_loop_check,
-		table_gen__create_new_loop_goal(Detism, OrigGoal,
-			PredId, ProcId, TablingViaExtraArgs,
-			HeadVars, InputVars, OutputVars,
+        table_gen__create_new_loop_goal(Detism, OrigGoal, PredId, ProcId,
+            TablingViaExtraArgs, HeadVars,
+            NumberedInputVars, NumberedOutputVars,
 			VarTypes0, VarTypes, VarSet0, VarSet,
 			TableInfo0, TableInfo, CallTableTip, Goal, Steps),
 		generate_gen_proc_table_info(TableInfo, Steps,
-			InputVars, OutputVars, ProcTableInfo),
+            InputVarModes, OutputVarModes, ProcTableInfo),
 		MaybeCallTableTip = yes(CallTableTip),
 		MaybeProcTableInfo = yes(ProcTableInfo)
 	;
 		EvalMethod = eval_memo,
 		( CodeModel = model_non ->
 			table_gen__create_new_memo_non_goal(Detism, OrigGoal,
-				PredId, ProcId,
-				HeadVars, InputVars, OutputVars,
-				VarTypes0, VarTypes, VarSet0, VarSet,
-				TableInfo0, TableInfo, CallTableTip, Goal,
-				Steps)
+                PredId, ProcId, HeadVars,
+                NumberedInputVars, NumberedOutputVars,
+                VarTypes0, VarTypes, VarSet0, VarSet, TableInfo0, TableInfo,
+                CallTableTip, Goal, Steps)
 		;
 			table_gen__create_new_memo_goal(Detism, OrigGoal,
 				PredId, ProcId, TablingViaExtraArgs,
-				HeadVars, InputVars, OutputVars,
+                HeadVars, NumberedInputVars, NumberedOutputVars,
 				VarTypes0, VarTypes, VarSet0, VarSet,
-				TableInfo0, TableInfo, CallTableTip, Goal,
-				Steps)
+                TableInfo0, TableInfo, CallTableTip, Goal, Steps)
 		),
 		generate_gen_proc_table_info(TableInfo, Steps,
-			InputVars, OutputVars, ProcTableInfo),
+            InputVarModes, OutputVarModes, ProcTableInfo),
 		MaybeCallTableTip = yes(CallTableTip),
 		MaybeProcTableInfo = yes(ProcTableInfo)
 	;
@@ -481,23 +479,22 @@
 			MinimalMethod = stack_copy,
 			table_gen__create_new_mm_goal(Detism, OrigGoal,
 				PredId, ProcId, TablingViaExtraArgs,
-				HeadVars, InputVars, OutputVars,
+                HeadVars, NumberedInputVars, NumberedOutputVars,
 				VarTypes0, VarTypes, VarSet0, VarSet,
-				TableInfo0, TableInfo,
-				CallTableTip, Goal, Steps)
+                TableInfo0, TableInfo, CallTableTip, Goal, Steps),
+            MaybeCallTableTip = yes(CallTableTip)
 		;
 			CodeModel = model_non,
 			MinimalMethod = own_stacks,
 			table_gen__do_own_stack_transform(Detism, OrigGoal,
 				PredId, ProcId, !.PredInfo, !.ProcInfo,
-				HeadVars, InputVars, OutputVars,
+                HeadVars, NumberedInputVars, NumberedOutputVars,
 				VarTypes0, VarTypes, VarSet0, VarSet,
-				TableInfo0, TableInfo, !GenMap,
-				CallTableTip, Goal, Steps)
+                TableInfo0, TableInfo, !GenMap, Goal, Steps),
+            MaybeCallTableTip = no
 		),
 		generate_gen_proc_table_info(TableInfo, Steps,
-			InputVars, OutputVars, ProcTableInfo),
-		MaybeCallTableTip = yes(CallTableTip),
+            InputVarModes, OutputVarModes, ProcTableInfo),
 		MaybeProcTableInfo = yes(ProcTableInfo)
 	),
 
@@ -514,19 +511,15 @@
 	% Some of the instmap_deltas generated in this module
 	% are pretty dodgy (especially those for if-then-elses), so
 	% recompute them here.
-
 	RecomputeAtomic = no,
-	recompute_instmap_delta_proc(RecomputeAtomic, !ProcInfo,
-		!ModuleInfo),
+    recompute_instmap_delta_proc(RecomputeAtomic, !ProcInfo, !ModuleInfo),
 
 	pred_info_procedures(!.PredInfo, ProcTable1),
 	map__det_update(ProcTable1, ProcId, !.ProcInfo, ProcTable),
 	pred_info_set_procedures(ProcTable, !PredInfo),
 
-	%
 	% The transformation doesn't pay attention to the purity
 	% of compound goals, so recompute the purity here.
-	%
 	repuritycheck_proc(!.ModuleInfo, proc(PredId, ProcId), !PredInfo),
 	module_info_preds(!.ModuleInfo, PredTable1),
 	map__det_update(PredTable1, PredId, !.PredInfo, PredTable),
@@ -541,7 +534,7 @@
 % p(A, B) :-
 % 	<original code>.
 %
-% The transformed code would be :
+% The transformed code would be:
 %
 % p(A, B) :-
 %	T0 = <table pointer for p/2>,
@@ -564,7 +557,7 @@
 % p(A, B) :-
 % 	<original code>.
 %
-% The transformed code would be :
+% The transformed code would be:
 %
 % p(A, B) :-
 %	T0 = <table pointer for p/2>,
@@ -593,7 +586,7 @@
 % p(A, B) :-
 % 	<original code>.
 %
-% The transformed code would be :
+% The transformed code would be:
 %
 % p(A, B) :-
 %	T0 = <table pointer for p/2>,
@@ -620,13 +613,13 @@
 
 :- pred create_new_loop_goal(determinism::in, hlds_goal::in,
 	pred_id::in, proc_id::in, bool::in,
-	list(prog_var)::in, list(prog_var)::in, list(prog_var)::in,
+    list(prog_var)::in, list(var_mode_pos)::in, list(var_mode_pos)::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	table_info::in, table_info::out, prog_var::out, hlds_goal::out,
 	list(table_trie_step)::out) is det.
 
 create_new_loop_goal(Detism, OrigGoal, PredId, ProcId, TablingViaExtraArgs,
-		HeadVars, InputVars, OutputVars, !VarTypes, !VarSet,
+        HeadVars, NumberedInputVars, NumberedOutputVars, !VarTypes, !VarSet,
 		!TableInfo, TableTipVar, Goal, Steps) :-
 	% even if the original goal doesn't use all of the headvars,
 	% the code generated by the tabling transformation does,
@@ -638,7 +631,6 @@
 	goal_info_get_context(OrigGoalInfo, Context),
 
 	ModuleInfo = !.TableInfo ^ table_module_info,
-	allocate_slot_numbers(InputVars, 0, NumberedInputVars),
 	generate_simple_call_table_lookup_goal(loop_status_type,
 		"table_loop_setup", NumberedInputVars, PredId, ProcId,
 		TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
@@ -652,35 +644,31 @@
 	MarkActiveFailPred = "table_loop_mark_as_active_and_fail",
 	(
 		TablingViaExtraArgs = no,
-		generate_call(MarkInactivePred, det,
-			[TableTipVar], impure_code, [], ModuleInfo,
-			Context, MarkInactiveGoal),
-		generate_call(MarkInactiveFailPred, failure,
-			[TableTipVar], impure_code, [], ModuleInfo,
-			Context, MarkInactiveFailGoal),
-		generate_call(MarkActiveFailPred, failure,
-			[TableTipVar], impure_code, [], ModuleInfo,
-			Context, MarkActiveFailGoal)
+        generate_call(MarkInactivePred, det, [TableTipVar],
+            impure_code, [], ModuleInfo, Context, MarkInactiveGoal),
+        generate_call(MarkInactiveFailPred, failure, [TableTipVar],
+            impure_code, [], ModuleInfo, Context, MarkInactiveFailGoal),
+        generate_call(MarkActiveFailPred, failure, [TableTipVar],
+            impure_code, [], ModuleInfo, Context, MarkActiveFailGoal)
 	;
 		TablingViaExtraArgs = yes,
 		TableTipArg = foreign_arg(TableTipVar,
-			yes(cur_table_node_name - in_mode),
-			trie_node_type),
+            yes(cur_table_node_name - in_mode), trie_node_type),
 		MarkInactiveCode = "\tMR_" ++ MarkInactivePred ++
 			"(" ++ cur_table_node_name ++ ");\n",
 		MarkInactiveFailCode = "\tMR_" ++ MarkInactiveFailPred ++
 			"(" ++ cur_table_node_name ++ ");\n",
 		MarkActiveFailCode = "\tMR_" ++ MarkActiveFailPred ++
 			"(" ++ cur_table_node_name ++ ");\n",
-		generate_foreign_proc(MarkInactivePred, det,
+        table_generate_foreign_proc(MarkInactivePred, det,
 			tabling_c_attributes, [TableTipArg], [],
 			"", MarkInactiveCode, "", impure_code, [],
 			ModuleInfo, Context, MarkInactiveGoal),
-		generate_foreign_proc(MarkInactiveFailPred, failure,
+        table_generate_foreign_proc(MarkInactiveFailPred, failure,
 			tabling_c_attributes, [TableTipArg], [],
 			"", MarkInactiveFailCode, "", impure_code, [],
 			ModuleInfo, Context, MarkInactiveFailGoal),
-		generate_foreign_proc(MarkActiveFailPred, failure,
+        table_generate_foreign_proc(MarkActiveFailPred, failure,
 			tabling_c_attributes, [TableTipArg], [],
 			"", MarkActiveFailCode, "", impure_code, [],
 			ModuleInfo, Context, MarkActiveFailGoal)
@@ -688,6 +676,7 @@
 
 	determinism_to_code_model(Detism, CodeModel),
 	set__list_to_set([TableTipVar | HeadVars], InactiveNonLocals),
+    OutputVars = list__map(project_var, NumberedOutputVars),
 	InactiveInstmapDelta = bind_vars(OutputVars),
 	(
 		CodeModel = model_det,
@@ -702,8 +691,8 @@
 		ThenGoalExpr = conj(list__append(Unifies, [MarkInactiveGoal])),
 		list__append([TableTipVar | OutputVars], NewVars, ThenVars),
 		set__list_to_set(ThenVars, ThenNonLocals),
-		goal_info_init_hide(ThenNonLocals, InactiveInstmapDelta,
-			Detism, impure, Context, ThenGoalInfo),
+        goal_info_init_hide(ThenNonLocals, InactiveInstmapDelta, Detism,
+            impure, Context, ThenGoalInfo),
 		ThenGoal = ThenGoalExpr - ThenGoalInfo,
 
 		InactiveGoalExpr = if_then_else([], RenamedOrigGoal,
@@ -713,33 +702,29 @@
 		AfterGoalExpr = disj([MarkInactiveGoal, MarkActiveFailGoal]),
 		instmap_delta_init_reachable(AfterInstMapDelta),
 		goal_info_init_hide(set__make_singleton_set(TableTipVar),
-			AfterInstMapDelta, multidet, impure, Context,
-			AfterGoalInfo),
+            AfterInstMapDelta, multidet, impure, Context, AfterGoalInfo),
 		AfterGoal = AfterGoalExpr - AfterGoalInfo,
 		FirstGoalExpr = conj([OrigGoal, AfterGoal]),
 		goal_info_get_nonlocals(OrigGoalInfo, OrigGINonLocals),
 		set__insert(OrigGINonLocals, TableTipVar, FirstNonlocals),
-		goal_info_set_nonlocals(OrigGoalInfo, FirstNonlocals,
-			FirstGoalInfo),
+        goal_info_set_nonlocals(OrigGoalInfo, FirstNonlocals, FirstGoalInfo),
 		FirstGoal = FirstGoalExpr - FirstGoalInfo,
 		InactiveGoalExpr = disj([FirstGoal, MarkInactiveFailGoal])
 	),
-	goal_info_init_hide(InactiveNonLocals, InactiveInstmapDelta,
-		Detism, impure, Context, InactiveGoalInfo),
+    goal_info_init_hide(InactiveNonLocals, InactiveInstmapDelta, Detism,
+        impure, Context, InactiveGoalInfo),
 	InactiveGoal = InactiveGoalExpr - InactiveGoalInfo,
 
 	mercury_table_builtin_module(TB),
 	SwitchArms = [
-		case(cons(qualified(TB, "loop_active"), 0),
-			ActiveGoal),
-		case(cons(qualified(TB, "loop_inactive"), 0),
-			InactiveGoal)
+        case(cons(qualified(TB, "loop_active"), 0), ActiveGoal),
+        case(cons(qualified(TB, "loop_inactive"), 0), InactiveGoal)
 	],
 	SwitchExpr = switch(StatusVar, cannot_fail, SwitchArms),
 	set__insert_list(InactiveNonLocals, [StatusVar, TableTipVar],
 		SwitchNonLocals),
-	goal_info_init_hide(SwitchNonLocals, InactiveInstmapDelta,
-		Detism, impure, Context, SwitchGoalInfo),
+    goal_info_init_hide(SwitchNonLocals, InactiveInstmapDelta, Detism,
+        impure, Context, SwitchGoalInfo),
 	SwitchGoal = SwitchExpr - SwitchGoalInfo,
 
 	GoalExpr = conj([LookUpGoal, SwitchGoal]),
@@ -756,7 +741,7 @@
 % p(A, B) :-
 % 	<original code>.
 %
-% The transformed code would be :
+% The transformed code would be:
 %
 % p(A, B) :-
 %	T0 = <table pointer for p/2>,
@@ -784,7 +769,7 @@
 % p(A, B) :-
 % 	<original code>.
 %
-% The transformed code would be :
+% The transformed code would be:
 %
 % p(A, B) :-
 %	T0 = <table pointer for p/2>,
@@ -822,7 +807,7 @@
 % p(A, B) :-
 % 	<original code>.
 %
-% The transformed code would be :
+% The transformed code would be:
 %
 % p(A, B) :-
 %	CT0 = <table pointer for p/2>,
@@ -869,13 +854,13 @@
 
 :- pred create_new_memo_goal(determinism::in, hlds_goal::in,
 	pred_id::in, proc_id::in, bool::in,
-	list(prog_var)::in, list(prog_var)::in, list(prog_var)::in,
+    list(prog_var)::in, list(var_mode_pos)::in, list(var_mode_pos)::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	table_info::in, table_info::out, prog_var::out, hlds_goal::out,
 	list(table_trie_step)::out) is det.
 
 create_new_memo_goal(Detism, OrigGoal, PredId, ProcId, TablingViaExtraArgs,
-		HeadVars, InputVars, OutputVars, !VarTypes, !VarSet,
+        HeadVars, NumberedInputVars, NumberedOutputVars, !VarTypes, !VarSet,
 		!TableInfo, TableTipVar, Goal, Steps) :-
 	% even if the original goal doesn't use all of the headvars,
 	% the code generated by the tabling transformation does,
@@ -900,16 +885,14 @@
 		CodeModel = model_non,
 		error("create_new_memo_goal: model_non")
 	),
-	allocate_slot_numbers(InputVars, 0, NumberedInputVars),
 	generate_simple_call_table_lookup_goal(StatusType, SetupPred,
-		NumberedInputVars, PredId, ProcId, TablingViaExtraArgs,
-		Context, !VarTypes, !VarSet, !TableInfo,
-		TableTipVar, StatusVar, LookUpGoal, Steps),
+        NumberedInputVars, PredId, ProcId, TablingViaExtraArgs, Context,
+        !VarTypes, !VarSet, !TableInfo, TableTipVar, StatusVar, LookUpGoal,
+        Steps),
 
 	generate_error_goal(!.TableInfo, Context, infinite_recursion_msg,
 		!VarTypes, !VarSet, ActiveGoal),
 
-	allocate_slot_numbers(OutputVars, 0, NumberedOutputVars),
 	list__length(NumberedOutputVars, BlockSize),
 	generate_memo_save_goals(NumberedOutputVars, TableTipVar, BlockSize,
 		TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
@@ -920,6 +903,7 @@
 	SucceededGoal = RestoreAnswerGoal,
 
 	set__list_to_set([TableTipVar | HeadVars], InactiveNonLocals),
+    OutputVars = list__map(project_var, NumberedOutputVars),
 	InactiveInstmapDelta = bind_vars(OutputVars),
 	(
 		CodeModel = model_det,
@@ -930,17 +914,14 @@
 
 		mercury_table_builtin_module(TB),
 		SwitchArms = [
-			case(cons(qualified(TB, "memo_det_active"), 0),
-				ActiveGoal),
-			case(cons(qualified(TB, "memo_det_inactive"), 0),
-				InactiveGoal),
-			case(cons(qualified(TB, "memo_det_succeeded"), 0),
-				SucceededGoal)
+            case(cons(qualified(TB, "memo_det_active"), 0), ActiveGoal),
+            case(cons(qualified(TB, "memo_det_inactive"), 0), InactiveGoal),
+            case(cons(qualified(TB, "memo_det_succeeded"), 0), SucceededGoal)
 		]
 	;
 		CodeModel = model_semi,
-		create_renaming(OutputVars, OrigInstMapDelta,
-			!VarTypes, !VarSet, Unifies, NewVars, Renaming),
+        create_renaming(OutputVars, OrigInstMapDelta, !VarTypes, !VarSet,
+            Unifies, NewVars, Renaming),
 		rename_vars_in_goal(OrigGoal, Renaming, RenamedOrigGoal),
 
 		ThenGoalExpr = conj(list__append(Unifies, SaveAnswerGoals)),
@@ -954,11 +935,10 @@
 		(
 			TablingViaExtraArgs = yes,
 			TableTipArg = foreign_arg(TableTipVar,
-				yes(cur_table_node_name - in_mode),
-				trie_node_type),
+                yes(cur_table_node_name - in_mode), trie_node_type),
 			MarkAsFailedCode = "MR_" ++ MarkAsFailedPred ++
 				"(" ++ cur_table_node_name ++ ");",
-			generate_foreign_proc(MarkAsFailedPred, failure,
+            table_generate_foreign_proc(MarkAsFailedPred, failure,
 				tabling_c_attributes, [TableTipArg], [],
 				"", MarkAsFailedCode, "", impure_code, [],
 				ModuleInfo, Context, ElseGoal)
@@ -970,21 +950,17 @@
 		),
 		InactiveGoalExpr = if_then_else([], RenamedOrigGoal,
 			ThenGoal, ElseGoal),
-		goal_info_init_hide(InactiveNonLocals, InactiveInstmapDelta,
-			Detism, impure, Context, InactiveGoalInfo),
+        goal_info_init_hide(InactiveNonLocals, InactiveInstmapDelta, Detism,
+            impure, Context, InactiveGoalInfo),
 		InactiveGoal = InactiveGoalExpr - InactiveGoalInfo,
 		fail_goal(FailedGoal),
 
 		mercury_table_builtin_module(TB),
 		SwitchArms = [
-			case(cons(qualified(TB, "memo_semi_active"), 0),
-				ActiveGoal),
-			case(cons(qualified(TB, "memo_semi_inactive"), 0),
-				InactiveGoal),
-			case(cons(qualified(TB, "memo_semi_succeeded"), 0),
-				SucceededGoal),
-			case(cons(qualified(TB, "memo_semi_failed"), 0),
-				FailedGoal)
+            case(cons(qualified(TB, "memo_semi_active"), 0), ActiveGoal),
+            case(cons(qualified(TB, "memo_semi_inactive"), 0), InactiveGoal),
+            case(cons(qualified(TB, "memo_semi_succeeded"), 0), SucceededGoal),
+            case(cons(qualified(TB, "memo_semi_failed"), 0), FailedGoal)
 		]
 	;
 		CodeModel = model_non,
@@ -1004,14 +980,14 @@
 
 :- pred create_new_memo_non_goal(determinism::in, hlds_goal::in,
 	pred_id::in, proc_id::in,
-	list(prog_var)::in, list(prog_var)::in, list(prog_var)::in,
+    list(prog_var)::in, list(var_mode_pos)::in, list(var_mode_pos)::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	table_info::in, table_info::out, prog_var::out, hlds_goal::out,
 	list(table_trie_step)::out) is det.
 
-create_new_memo_non_goal(Detism, OrigGoal, PredId, ProcId,
-		HeadVars, InputVars, OutputVars, !VarTypes, !VarSet,
-		!TableInfo, RecordVar, Goal, Steps) :-
+create_new_memo_non_goal(Detism, OrigGoal, PredId, ProcId, HeadVars,
+        NumberedInputVars, NumberedOutputVars, !VarTypes, !VarSet, !TableInfo,
+        RecordVar, Goal, Steps) :-
 	% even if the original goal doesn't use all of the headvars,
 	% the code generated by the tabling transformation does,
 	% so we need to compute the nonlocals from the headvars rather
@@ -1022,14 +998,12 @@
 	goal_info_get_context(OrigGoalInfo, Context),
 
 	ModuleInfo = !.TableInfo ^ table_module_info,
-	allocate_slot_numbers(InputVars, 0, NumberedInputVars),
-	allocate_slot_numbers(OutputVars, 0, NumberedOutputVars),
 	list__length(NumberedOutputVars, BlockSize),
 
 	generate_error_goal(!.TableInfo, Context, infinite_recursion_msg,
 		!VarTypes, !VarSet, InfiniteRecursionGoal),
 	generate_error_goal(!.TableInfo, Context, need_minimal_model_msg,
-		!VarTypes, !VarSet, NeedMinimalModelGoal),
+        !VarTypes, !VarSet, NeedMinModelGoal),
 
 	generate_memo_non_call_table_lookup_goal(NumberedInputVars,
 		PredId, ProcId, Context, !VarTypes, !VarSet, !TableInfo,
@@ -1053,15 +1027,15 @@
 		RecordVarName ++ ");\n",
 	MarkCompleteCode = "MR_" ++ MarkCompletePred ++ "(" ++
 		RecordVarName ++ ");\n",
-	generate_foreign_proc(MarkIncompletePred, det,
+    table_generate_foreign_proc(MarkIncompletePred, det,
 		tabling_c_attributes, [RecordArg], [],
 		"", MarkIncompleteCode, "", impure_code, [],
 		ModuleInfo, Context, MarkIncompleteGoal),
-	generate_foreign_proc(MarkActivePred, failure,
+    table_generate_foreign_proc(MarkActivePred, failure,
 		tabling_c_attributes, [RecordArg], [],
 		"", MarkActiveCode, "", impure_code, [],
 		ModuleInfo, Context, MarkActiveGoal),
-	generate_foreign_proc(MarkCompletePred, failure,
+    table_generate_foreign_proc(MarkCompletePred, failure,
 		tabling_c_attributes, [RecordArg], [],
 		"", MarkCompleteCode, "", impure_code, [],
 		ModuleInfo, Context, MarkCompleteGoal),
@@ -1088,18 +1062,15 @@
 	InactiveGoal = InactiveExpr - OrigSaveGoalInfo,
 
 	set__list_to_set([RecordVar | HeadVars], InactiveNonLocals),
+    OutputVars = list__map(project_var, NumberedOutputVars),
 	InactiveInstmapDelta = bind_vars(OutputVars),
 
 	mercury_table_builtin_module(TB),
 	SwitchArms = [
-		case(cons(qualified(TB, "memo_non_active"), 0),
-			InfiniteRecursionGoal),
-		case(cons(qualified(TB, "memo_non_inactive"), 0),
-			InactiveGoal),
-		case(cons(qualified(TB, "memo_non_incomplete"), 0),
-			NeedMinimalModelGoal),
-		case(cons(qualified(TB, "memo_non_complete"), 0),
-			RestoreAllAnswerGoal)
+        case(cons(qualified(TB, "memo_non_active"), 0), InfiniteRecursionGoal),
+        case(cons(qualified(TB, "memo_non_inactive"), 0), InactiveGoal),
+        case(cons(qualified(TB, "memo_non_incomplete"), 0), NeedMinModelGoal),
+        case(cons(qualified(TB, "memo_non_complete"), 0), RestoreAllAnswerGoal)
 	],
 
 	SwitchExpr = switch(StatusVar, cannot_fail, SwitchArms),
@@ -1125,7 +1096,7 @@
 % p(A, B, S0, S) :-
 %	<original code>
 %
-% The transformed code would be :
+% The transformed code would be:
 %
 % p(A, B, S0, S) :-
 %	(if
@@ -1184,14 +1155,15 @@
 
 :- pred table_gen__create_new_io_goal(hlds_goal::in, table_io_is_decl::in,
 	table_io_is_unitize::in, bool::in, pred_id::in, proc_id::in, bool::in,
-	list(prog_var)::in, list(prog_var)::in, list(prog_var)::in,
+    assoc_list(prog_var, mode)::in,
+    list(var_mode_pos)::in, list(var_mode_pos)::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	table_info::in, table_info::out,
 	hlds_goal::out, maybe(proc_table_info)::out) is det.
 
 table_gen__create_new_io_goal(OrigGoal, TableDecl, Unitize, TableIoStates,
-		PredId, ProcId, TablingViaExtraArgs,
-		HeadVars, InputVars, OutputVars, !VarTypes, !VarSet,
+        PredId, ProcId, TablingViaExtraArgs, HeadVarModes,
+        OrigInputVars, OrigOutputVars, !VarTypes, !VarSet,
 		!TableInfo, Goal, MaybeProcTableInfo) :-
 	OrigGoal = _ - OrigGoalInfo,
 	goal_info_get_nonlocals(OrigGoalInfo, OrigNonLocals),
@@ -1201,16 +1173,18 @@
 		TableIoStates = yes,
 		IoStateAssignToVars = [],
 		IoStateAssignFromVars = [],
-		SavedOutputVars = OutputVars,
-		SavedHeadVars = HeadVars
+        SavedOutputVars = OrigOutputVars,
+        SavedHeadVars = HeadVarModes
 	;
 		TableIoStates = no,
-		list__filter(table_gen__var_is_io_state(!.VarTypes),
-			OutputVars, IoStateAssignToVars, SavedOutputVars),
-		list__filter(table_gen__var_is_io_state(!.VarTypes),
-			InputVars, IoStateAssignFromVars, _SavedInputVars),
-		list__filter(table_gen__var_is_io_state(!.VarTypes),
-			HeadVars, _, SavedHeadVars)
+        list__filter(table_gen__var_mode_pos_is_io_state(!.VarTypes),
+            OrigOutputVars, IoStateAssignToVars, MisNumberedSavedOutputVars),
+        reallocate_slot_numbers(MisNumberedSavedOutputVars, 0,
+            SavedOutputVars),
+        list__filter(table_gen__var_mode_pos_is_io_state(!.VarTypes),
+            OrigInputVars, IoStateAssignFromVars, _MisNumberedSavedInputVars),
+        list__filter(table_gen__var_mode_is_io_state(!.VarTypes),
+            HeadVarModes, _, SavedHeadVars)
 	),
 	generate_new_table_var("TableVar", trie_node_type, !VarTypes, !VarSet,
 		TableVar),
@@ -1234,34 +1208,34 @@
 		ShroudedPredProcId = shroud_pred_proc_id(proc(PredId, ProcId)),
 		TableIoDeclConsId = table_io_decl(ShroudedPredProcId),
 		make_const_construction(TableIoDeclConsId, c_pointer_type,
-			yes("TableIoDeclPtr"), TableIoDeclGoal,
-			TableIoDeclPtrVar, !VarTypes, !VarSet),
+            yes("TableIoDeclPtr"), TableIoDeclGoal, TableIoDeclPtrVar,
+            !VarTypes, !VarSet),
 		allocate_slot_numbers(SavedHeadVars, 1, NumberedSavedHeadVars),
-		NumberedSaveVars = [TableIoDeclPtrVar - 0 |
-			NumberedSavedHeadVars],
-		list__filter(key_belong_to_list(SavedOutputVars),
+        NumberedSaveVars = [var_mode_pos(TableIoDeclPtrVar, in_mode, 0)
+            | NumberedSavedHeadVars],
+        UnnumberedSavedOutputVars = list__map(project_var, SavedOutputVars),
+        list__filter(var_belong_to_list(UnnumberedSavedOutputVars),
 			NumberedSaveVars, NumberedSavedOutputVars),
 		NumberedRestoreVars = NumberedSavedOutputVars,
 
 		ProcInfo0 = !.TableInfo ^ table_cur_proc_info,
 		continuation_info__generate_table_arg_type_info(ProcInfo0,
-			NumberedSavedHeadVars, TableArgTypeInfo),
+            list__map(project_var_pos, NumberedSavedHeadVars),
+            TableArgTypeInfo),
 		ProcTableInfo = table_io_decl_info(TableArgTypeInfo),
 		MaybeProcTableInfo = yes(ProcTableInfo)
 	;
 		TableDecl = table_io_proc,
 		true_goal(TableIoDeclGoal),
-		allocate_slot_numbers(SavedOutputVars, 0,
-			NumberedSavedOutputVars),
-		NumberedRestoreVars = NumberedSavedOutputVars,
-		NumberedSaveVars = NumberedSavedOutputVars,
+        NumberedRestoreVars = SavedOutputVars,
+        NumberedSaveVars = SavedOutputVars,
 		MaybeProcTableInfo = no
 	),
 	list__length(NumberedSaveVars, BlockSize),
 	goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
-	generate_memo_restore_goal(NumberedRestoreVars, OrigInstMapDelta,
-		TipVar, ModuleInfo, TablingViaExtraArgs, Context,
-		!VarTypes, !VarSet, RestoreAnswerGoal0),
+    generate_memo_restore_goal(NumberedRestoreVars, OrigInstMapDelta, TipVar,
+        ModuleInfo, TablingViaExtraArgs, Context, !VarTypes, !VarSet,
+        RestoreAnswerGoal0),
 	(
 		TableIoStates = yes,
 		RestoreAnswerGoal = RestoreAnswerGoal0
@@ -1271,8 +1245,8 @@
 			IoStateAssignFromVars = [IoStateAssignFromVarPrime],
 			IoStateAssignToVars = [IoStateAssignToVarPrime]
 		->
-			IoStateAssignFromVar = IoStateAssignFromVarPrime,
-			IoStateAssignToVar = IoStateAssignToVarPrime
+            IoStateAssignFromVar = project_var(IoStateAssignFromVarPrime),
+            IoStateAssignToVar = project_var(IoStateAssignToVarPrime)
 		;
 			% The call to proc_info_has_io_state_pair in
 			% table_gen__process_procs should ensure that we
@@ -1284,8 +1258,7 @@
 			[IoStateAssignFromVar - ground(clobbered, none),
 			IoStateAssignToVar - ground(unique, none)],
 			ModuleInfo, Context, IoStateAssignGoal),
-		RestoreAnswerGoalExpr = conj([RestoreAnswerGoal0,
-			IoStateAssignGoal]),
+        RestoreAnswerGoalExpr = conj([RestoreAnswerGoal0, IoStateAssignGoal]),
 		create_instmap_delta([RestoreAnswerGoal0, IoStateAssignGoal],
 			RestoreAnswerInstMapDelta0),
 		RestoreAnswerGoal0 = _ - RestoreAnswerGoal0Info,
@@ -1299,16 +1272,14 @@
 		goal_info_init_hide(RestoreAnswerNonLocals,
 			RestoreAnswerInstMapDelta, det, semipure, Context,
 			RestoreAnswerGoalInfo),
-		RestoreAnswerGoal = RestoreAnswerGoalExpr
-			- RestoreAnswerGoalInfo
+        RestoreAnswerGoal = RestoreAnswerGoalExpr - RestoreAnswerGoalInfo
 	),
 	generate_memo_save_goals(NumberedSaveVars, TipVar, BlockSize,
 		TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
 		SaveAnswerGoals),
 	(
 		Unitize = table_io_alone,
-		CallSaveAnswerGoalList = [OrigGoal, TableIoDeclGoal
-			| SaveAnswerGoals]
+        CallSaveAnswerGoalList = [OrigGoal, TableIoDeclGoal | SaveAnswerGoals]
 	;
 		Unitize = table_io_unitize,
 		generate_new_table_var("SavedTraceEnabled", int_type,
@@ -1324,14 +1295,12 @@
 			RightBracketGoal, TableIoDeclGoal | SaveAnswerGoals]
 	),
 	CallSaveAnswerGoalExpr = conj(CallSaveAnswerGoalList),
-	create_instmap_delta(CallSaveAnswerGoalList,
-		CallSaveAnswerInstMapDelta0),
+    create_instmap_delta(CallSaveAnswerGoalList, CallSaveAnswerInstMapDelta0),
 	set__insert(OrigNonLocals, TipVar, CallSaveAnswerNonLocals),
 	instmap_delta_restrict(CallSaveAnswerInstMapDelta0,
 		CallSaveAnswerNonLocals, CallSaveAnswerInstMapDelta),
-	goal_info_init_hide(CallSaveAnswerNonLocals,
-		CallSaveAnswerInstMapDelta, det, impure, Context,
-		CallSaveAnswerGoalInfo0),
+    goal_info_init_hide(CallSaveAnswerNonLocals, CallSaveAnswerInstMapDelta,
+        det, impure, Context, CallSaveAnswerGoalInfo0),
 	goal_info_add_feature(CallSaveAnswerGoalInfo0, hide_debug_event,
 		CallSaveAnswerGoalInfo),
 	CallSaveAnswerGoal = CallSaveAnswerGoalExpr - CallSaveAnswerGoalInfo,
@@ -1364,15 +1333,14 @@
 		OrigGoal),
 	create_instmap_delta([InRangeGoal, CheckAndGenAnswerGoal, OrigGoal],
 		BodyInstMapDelta0),
-	instmap_delta_restrict(BodyInstMapDelta0, OrigNonLocals,
-		BodyInstMapDelta),
+    instmap_delta_restrict(BodyInstMapDelta0, OrigNonLocals, BodyInstMapDelta),
 	goal_info_init_hide(OrigNonLocals, BodyInstMapDelta, det, impure,
 		Context, BodyGoalInfo),
 	Goal = BodyGoalExpr - BodyGoalInfo.
 
 %-----------------------------------------------------------------------------%
 
-% Example of transformation for nondet minimal_model :
+% Example of transformation for nondet minimal_model:
 %
 % :- pred p(int, int).
 % :- mode p(in, out) is nondet.
@@ -1380,7 +1348,7 @@
 % p(A, B) :-
 %	<original code>.
 %
-% The transformed code would be :
+% The transformed code would be:
 %
 % p(A, B) :-
 % 		% Get a handle on the table.
@@ -1425,12 +1393,13 @@
 
 :- pred table_gen__create_new_mm_goal(determinism::in,
 	hlds_goal::in, pred_id::in, proc_id::in, bool::in, list(prog_var)::in,
-	list(prog_var)::in, list(prog_var)::in, vartypes::in, vartypes::out,
-	prog_varset::in, prog_varset::out, table_info::in, table_info::out,
-	prog_var::out, hlds_goal::out, list(table_trie_step)::out) is det.
+    list(var_mode_pos)::in, list(var_mode_pos)::in,
+    vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
+    table_info::in, table_info::out, prog_var::out, hlds_goal::out,
+    list(table_trie_step)::out) is det.
 
 table_gen__create_new_mm_goal(Detism, OrigGoal, PredId, ProcId,
-		TablingViaExtraArgs, HeadVars, InputVars, OutputVars,
+        TablingViaExtraArgs, HeadVars, NumberedInputVars, NumberedOutputVars,
 		!VarTypes, !VarSet, !TableInfo, SubgoalVar, Goal, Steps) :-
 	% Even if the original goal doesn't use all of the headvars,
 	% the code generated by the tabling transformation does,
@@ -1442,8 +1411,6 @@
 	goal_info_get_context(OrigGoalInfo, Context),
 
 	ModuleInfo = !.TableInfo ^ table_module_info,
-	allocate_slot_numbers(InputVars, 0, NumberedInputVars),
-	allocate_slot_numbers(OutputVars, 0, NumberedOutputVars),
 	list__length(NumberedOutputVars, BlockSize),
 	generate_mm_call_table_lookup_goal(NumberedInputVars, PredId, ProcId,
 		TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
@@ -1459,28 +1426,24 @@
 		!VarTypes, !VarSet, SuspendGoal),
 
 	MainExpr = conj([OrigGoal | SaveAnswerGoals]),
-	set__insert_list(OrigNonLocals, [SubgoalVar, StatusVar],
-		MainNonLocals),
+    set__insert_list(OrigNonLocals, [SubgoalVar, StatusVar], MainNonLocals),
 	create_instmap_delta([OrigGoal | SaveAnswerGoals], MainIMD0),
 	instmap_delta_restrict(MainIMD0, MainNonLocals, MainIMD),
 	goal_info_init_hide(MainNonLocals, MainIMD, nondet, impure, Context,
 		MainGoalInfo),
 	MainGoal = MainExpr - MainGoalInfo,
 
-	generate_call("table_mm_completion", det, [SubgoalVar],
-		impure_code, [], ModuleInfo, Context, ResumeGoal0),
+    generate_call("table_mm_completion", det, [SubgoalVar], impure_code,
+        [], ModuleInfo, Context, ResumeGoal0),
 	append_fail(ResumeGoal0, ResumeGoal),
 	InactiveExpr = disj([MainGoal, ResumeGoal]),
 	InactiveGoal = InactiveExpr - MainGoalInfo,
 
 	mercury_table_builtin_module(TB),
 	SwitchArms = [
-		case(cons(qualified(TB, "mm_inactive"), 0),
-			InactiveGoal),
-		case(cons(qualified(TB, "mm_complete"), 0),
-			RestoreAllAnswerGoal),
-		case(cons(qualified(TB, "mm_active"), 0),
-			SuspendGoal)
+        case(cons(qualified(TB, "mm_inactive"), 0), InactiveGoal),
+        case(cons(qualified(TB, "mm_complete"), 0), RestoreAllAnswerGoal),
+        case(cons(qualified(TB, "mm_active"), 0), SuspendGoal)
 	],
 	SwitchExpr = switch(StatusVar, cannot_fail, SwitchArms),
 	goal_info_add_feature(MainGoalInfo, hide_debug_event, SwitchGoalInfo),
@@ -1493,7 +1456,7 @@
 
 %-----------------------------------------------------------------------------%
 
-% Example of transformation for nondet minimal_model_own_stack :
+% Example of transformation for nondet minimal_model_own_stack:
 %
 % :- pred p(int, int).
 % :- mode p(in, out) is nondet
@@ -1501,7 +1464,8 @@
 % p(A, B) :- e(A, B).
 % p(A, B) :- p(A, C), e(C, B).
 %
-% The transformed code would be :
+% The transformed code would be something like this; see also forest.ps
+% in the tabling directory in the papers CVS module.
 %
 % p2_gen(A, B) :-
 %	impure table_mmos_pickup_generator(Generator),
@@ -1537,28 +1501,24 @@
 %	impure table_restore_int_ans(AnswerBlock, 0, B).
 
 :- pred table_gen__do_own_stack_transform(determinism::in, hlds_goal::in,
-	pred_id::in, proc_id::in, pred_info::in, proc_info::in,
-	list(prog_var)::in, list(prog_var)::in, list(prog_var)::in,
+    pred_id::in, proc_id::in, pred_info::in, proc_info::in, list(prog_var)::in,
+    list(var_mode_pos)::in, list(var_mode_pos)::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	table_info::in, table_info::out, generator_map::in, generator_map::out,
-	prog_var::out, hlds_goal::out, list(table_trie_step)::out) is det.
+    hlds_goal::out, list(table_trie_step)::out) is det.
 
 table_gen__do_own_stack_transform(Detism, OrigGoal, PredId, ProcId,
-		PredInfo0, ProcInfo0, HeadVars, InputVars, OutputVars,
-		!VarTypes, !VarSet, !TableInfo, !GenMap, TableTipVar,
-		Goal, Steps) :-
+        PredInfo0, ProcInfo0, HeadVars, NumberedInputVars, NumberedOutputVars,
+        !VarTypes, !VarSet, !TableInfo, !GenMap, Goal, Steps) :-
 	PredName = pred_info_name(PredInfo0),
 	( map__search(!.GenMap, PredId, GeneratorPredIdPrime) ->
 		GeneratorPredId = GeneratorPredIdPrime
 	;
-		clone_pred_info(PredId, PredInfo0, GeneratorPredId,
-			!TableInfo),
+        clone_pred_info(PredId, PredInfo0, HeadVars, NumberedOutputVars,
+            GeneratorPredId, !TableInfo),
 		map__det_insert(!.GenMap, PredId, GeneratorPredId, !:GenMap)
 	),
 
-	allocate_slot_numbers(InputVars, 0, NumberedInputVars),
-	allocate_slot_numbers(OutputVars, 0, NumberedOutputVars),
-
 	% Even if the original goal doesn't use all of the headvars,
 	% the code generated by the tabling transformation does,
 	% so we need to compute the nonlocals from the headvars rather
@@ -1568,18 +1528,9 @@
 	goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
 	goal_info_get_context(OrigGoalInfo, Context),
 
-	list__length(InputVars, NumInputVars),
+    list__length(NumberedInputVars, NumInputVars),
 	ModuleInfo = !.TableInfo ^ table_module_info,
 
-	SaveInputPred = "table_mmos_save_inputs",
-	generate_save_input_vars_code(NumberedInputVars, !.VarTypes,
-		SaveInputVarArgs, SaveInputVarCode),
-	SaveMainCode = "MR_" ++ SaveInputPred ++ "(" ++
-		int_to_string(NumInputVars) ++ ");",
-	generate_foreign_proc(SaveInputPred, det, tabling_c_attributes,
-		[], SaveInputVarArgs, "", SaveMainCode, SaveInputVarCode,
-		impure_code, ground_vars([]), ModuleInfo, Context, SaveGoal),
-
 		% The type is a lie, but a safe one: the variable we create
 		% is handled only by C code. The reason why we lie is that
 		% creating the right type would be quite complicated.
@@ -1590,59 +1541,94 @@
 	generate_new_table_var("Consumer", consumer_type, !VarTypes, !VarSet,
 		ConsumerVar),
 
-	ShroudedPredProcId =
-		shroud_pred_proc_id(proc(GeneratorPredId, ProcId)),
+    ShroudedPredProcId = shroud_pred_proc_id(proc(GeneratorPredId, ProcId)),
 	GeneratorConsId = pred_const(ShroudedPredProcId, normal),
 	make_const_construction(GeneratorPredVar, GeneratorConsId,
 		MakeGeneratorVarGoal),
 
 	% XXX use tabling via foreign_proc
 	generate_call_table_lookup_goals(NumberedInputVars, PredId, ProcId,
-		Context, !VarTypes, !VarSet, !TableInfo, TableTipVar,
-		LookupGoals, Steps, _PredTableVar, _LookupForeignArgs,
-		_LookupPrefixGoals, _LookupCodeStr),
+        Context, !VarTypes, !VarSet, !TableInfo, _TableTipVar, _LookupGoals,
+        Steps, PredTableVar, LookupForeignArgs, LookupPrefixGoals,
+        LookupCodeStr),
+
+    InputVarModes = list__map(project_mode, NumberedInputVars),
+    assoc_list__from_corresponding_lists(LookupForeignArgs, InputVarModes,
+        LookupForeignArgModes),
+    generate_save_input_vars_code(LookupForeignArgModes, ModuleInfo, 0,
+        PickupForeignArgs, SaveInputVarCode, PickupInputVarCode),
 
-	TableTipVarName = table_tip_node_name,
 	GeneratorPredVarName = generator_pred_name,
 	ConsumerVarName = consumer_name,
+    PredTableVarName = pred_table_name,
 
-	TableTipArg = foreign_arg(TableTipVar,
-		yes(TableTipVarName - in_mode), trie_node_type),
+    PredTableArg = foreign_arg(PredTableVar,
+        yes(PredTableVarName - in_mode), trie_node_type),
 	GeneratorPredArg = foreign_arg(GeneratorPredVar,
 		yes(generator_pred_name - in_mode), GeneratorPredType),
 	ConsumerArg = foreign_arg(ConsumerVar,
 		yes(ConsumerVarName - out_mode), consumer_type),
 
+    LookupDeclCodeStr =
+        "\tMR_TrieNode " ++ cur_table_node_name ++ ";\n" ++
+        "\tMR_TrieNode " ++ next_table_node_name ++ ";\n" ++
+        "\tMR_GeneratorPtr " ++ generator_name ++ ";\n\n" ++
+        "\t" ++ cur_table_node_name ++ " = " ++ PredTableVarName ++ ";\n" ++
+        LookupCodeStr,
+
 	SetupPred = "table_mmos_setup_consumer",
-	SetupCode = "MR_" ++ SetupPred ++ "(" ++
-		TableTipVarName ++ ", " ++
-		int_to_string(NumInputVars) ++ ", " ++
-		GeneratorPredVarName ++ ", " ++
-		"""" ++ PredName ++ """, " ++
-		ConsumerVarName ++ ");",
-	generate_foreign_proc(SaveInputPred, det, tabling_c_attributes,
-		[TableTipArg, GeneratorPredArg, ConsumerArg], [],
-		"", SetupCode, "", impure_code, ground_vars([]), ModuleInfo,
-		Context, SetupGoal),
+    SetupCode = "\t" ++ generator_name ++ " = " ++
+        cur_table_node_name ++ "->MR_generator;\n" ++
+        "\tif (" ++ generator_name ++ " == NULL) {\n" ++
+            SaveInputVarCode ++
+            "\t\t" ++ generator_name ++ " = MR_table_mmos_setup_generator(" ++
+                cur_table_node_name ++ ",\n\t\t\t"
+                ++ int_to_string(NumInputVars) ++ ", "
+                ++ GeneratorPredVarName ++ ", " ++
+                """" ++ PredName ++ """);\n" ++
+            "\t\tMR_mmos_new_generator = " ++ generator_name ++ ";\n" ++
+        "\t}\n" ++
+        "\t" ++ consumer_name ++ " = " ++
+            "MR_table_mmos_setup_consumer(" ++ generator_name ++
+            ", """ ++ PredName ++ """);\n",
+    table_generate_foreign_proc(SetupPred, det, make_generator_c_attributes,
+        [PredTableArg, GeneratorPredArg, ConsumerArg], LookupForeignArgs,
+        LookupDeclCodeStr, SetupCode, "", impure_code,
+        ground_vars([ConsumerVar]), ModuleInfo, Context, SetupGoal),
+    % We don't attach the call_table_tip attribute to the setup goal, since
+    % retrying across the creation of the generator should not require undoing
+    % the creation of the generator. Of course, for this to work *properly*,
+    % the runtime system and the debugger will need to cooperate to effectively
+    % present to the user a distinct sequence of trace events for each context.
+    % In any case,
+    % attach_call_table_tip(SetupGoal0, SetupGoal),
+    LookupSetupGoals = [MakeGeneratorVarGoal | LookupPrefixGoals]
+        ++ [SetupGoal],
 
 	generate_new_table_var("AnswerBlock", answer_block_type,
 		!VarTypes, !VarSet, AnswerBlockVar),
-	DetismStr = determinism_to_string(Detism),
-	% XXX check that Detism is such that ConsumePredName exists
+    ( Detism = multidet ->
+        ConsumePredName = "table_mmos_consume_next_answer_multi"
+    ; Detism = nondet ->
+        ConsumePredName = "table_mmos_consume_next_answer_nondet"
+    ;
+        error("do_own_stack_transform: invalid determinism")
+    ),
 	% XXX consider inlining the predicate being called
-	ConsumePredName = "table_consume_next_answer_" ++ DetismStr,
 	generate_call(ConsumePredName, Detism, [ConsumerVar, AnswerBlockVar],
-		impure_code, ground_vars([AnswerBlockVar]), ModuleInfo,
-		Context, GetNextAnswerGoal),
-	% XXX use foreign_proc
+        impure_code, ground_vars([AnswerBlockVar]), ModuleInfo, Context,
+        GetNextAnswerGoal),
 	generate_restore_goals(NumberedOutputVars, OrigInstMapDelta,
-		AnswerBlockVar, ModuleInfo, Context, !VarTypes, !VarSet,
-		RestoreGoals, _RestoreInstMapDeltaSrc, _RestoreArgs,
-		_RestoreCodeStr),
+        AnswerBlockVar, ModuleInfo, Context, !VarTypes, !VarSet, _RestoreGoals,
+        RestoreInstMapDeltaSrc, RestoreArgs, RestoreCodeStr),
+    AnswerBlockArg = foreign_arg(AnswerBlockVar,
+        yes(answer_block_name - in_mode), answer_block_type),
+    RestoreAllPredName = "table_mmos_restore_answers",
+    table_generate_foreign_proc(RestoreAllPredName, det, tabling_c_attributes,
+        [AnswerBlockArg], RestoreArgs, "", "", RestoreCodeStr,
+        impure_code, RestoreInstMapDeltaSrc, ModuleInfo, Context, RestoreGoal),
 
-	GoalExpr = conj([SaveGoal | LookupGoals] ++
-		[MakeGeneratorVarGoal, SetupGoal, GetNextAnswerGoal
-		| RestoreGoals]),
+    GoalExpr = conj(LookupSetupGoals ++ [GetNextAnswerGoal, RestoreGoal]),
 	goal_info_init(OrigNonLocals, OrigInstMapDelta, Detism, impure,
 		Context, GoalInfo),
 	Goal = GoalExpr - GoalInfo,
@@ -1650,59 +1636,80 @@
 	module_info_pred_info(ModuleInfo, GeneratorPredId, GeneratorPredInfo),
 	table_info_init(ModuleInfo, GeneratorPredInfo, ProcInfo0,
 		GeneratorTableInfo0),
-	do_own_stack_create_generator(GeneratorPredId, ProcId,
-		GeneratorPredInfo, ProcInfo0, Context,
-		GeneratorPredVar, NumberedOutputVars,
+    do_own_stack_create_generator(GeneratorPredId, ProcId, GeneratorPredInfo,
+        ProcInfo0, Context, GeneratorPredVar,
+        PickupInputVarCode, PickupForeignArgs,
+        NumberedInputVars, NumberedOutputVars,
 		OrigNonLocals, OrigInstMapDelta, !.VarTypes, !.VarSet,
 		GeneratorTableInfo0, GeneratorTableInfo),
 	!:TableInfo = !.TableInfo ^ table_module_info :=
 		GeneratorTableInfo ^ table_module_info.
 
-:- pred generate_save_input_vars_code(assoc_list(prog_var, int)::in,
-	vartypes::in, list(foreign_arg)::out, string::out) is det.
+:- pred generate_save_input_vars_code(assoc_list(foreign_arg, mode)::in,
+    module_info::in, int::in, list(foreign_arg)::out, string::out, string::out)
+    is det.
 
-generate_save_input_vars_code([], _, [], "").
-generate_save_input_vars_code([InputVar - Num | NumberedInputVars], VarTypes,
-		[InputVarArg | InputVarArgs],
-		SaveInputVarCode ++ SaveInputVarCodes) :-
-	map__lookup(VarTypes, InputVar, Type),
-	InputVarName = "save_input" ++ int_to_string(Num),
-	InputVarArg = foreign_arg(InputVar, yes(InputVarName - in_mode), Type),
-	SaveInputVarCode = "\tMR_mm_save_input_arg(" ++
-		int_to_string(Num) ++ ", " ++
-		InputVarName ++ ");\n",
-	generate_save_input_vars_code(NumberedInputVars, VarTypes,
-		InputVarArgs, SaveInputVarCodes).
+generate_save_input_vars_code([], _, _, [], "", "").
+generate_save_input_vars_code([InputArg - Mode | InputArgModes], ModuleInfo,
+        Pos, [PickupArg | PickupArgs], SaveVarCode ++ SaveVarCodes,
+        PickupVarCode ++ PickupVarCodes) :-
+    InputArg = foreign_arg(InputVar, MaybeArgNameMode, Type),
+    (
+        MaybeArgNameMode = yes(InputVarName - _InMode)
+    ;
+        MaybeArgNameMode = no,
+        error("generate_save_input_vars_code: no InputVarName")
+    ),
+    mode_get_insts(ModuleInfo, Mode, InitInst, _FinalInst),
+    PickupMode = (free -> InitInst),
+    PickupArg = foreign_arg(InputVar, yes(InputVarName - PickupMode), Type),
+    SaveVarCode = "\t\tMR_mmos_save_input_arg(" ++
+        int_to_string(Pos) ++ ", " ++ InputVarName ++ ");\n",
+    PickupVarCode = "\t\tMR_mmos_pickup_input_arg(" ++
+        int_to_string(Pos) ++ ", " ++ InputVarName ++ ");\n",
+    generate_save_input_vars_code(InputArgModes, ModuleInfo, Pos + 1,
+        PickupArgs, SaveVarCodes, PickupVarCodes).
 
 :- pred do_own_stack_create_generator(pred_id::in, proc_id::in,
-	pred_info::in, proc_info::in, term__context::in,
-	prog_var::in, assoc_list(prog_var, int)::in,
+    pred_info::in, proc_info::in, term__context::in, prog_var::in, string::in,
+    list(foreign_arg)::in, list(var_mode_pos)::in, list(var_mode_pos)::in,
 	set(prog_var)::in, instmap_delta::in,
 	vartypes::in, prog_varset::in, table_info::in, table_info::out) is det.
 
-do_own_stack_create_generator(PredId, ProcId, !.PredInfo, !.ProcInfo,
-	Context, GeneratorVar, NumberedOutputVars,
+do_own_stack_create_generator(PredId, ProcId, !.PredInfo, !.ProcInfo, Context,
+        GeneratorVar, PickupVarCode, PickupForeignArgs,
+        NumberedInputVars, NumberedOutputVars,
 	OrigNonLocals, OrigInstMapDelta, !.VarTypes, !.VarSet, !TableInfo) :-
+    ModuleInfo0 = !.TableInfo ^ table_module_info,
 
-	proc_info_headvars(!.ProcInfo, HeadVars0),
-	proc_info_argmodes(!.ProcInfo, ArgModes0),
-	list__append(HeadVars0, [GeneratorVar], HeadVars),
-	list__append(ArgModes0, [in_mode], ArgModes),
-	proc_info_set_headvars(HeadVars, !ProcInfo),
-	proc_info_set_argmodes(ArgModes, !ProcInfo),
+    proc_info_set_headvars(list__map(project_var, NumberedOutputVars),
+        !ProcInfo),
+    proc_info_set_argmodes(list__map(project_mode, NumberedOutputVars),
+        !ProcInfo),
+    PickupInstMapDeltaSrc0 = list__map(project_var_init_inst(ModuleInfo0),
+        NumberedInputVars),
+    PickupInstMapDeltaSrc = [pair_with_ground(GeneratorVar)
+        | PickupInstMapDeltaSrc0],
+    PickupGeneratorCode = "\t\t" ++ generator_name ++
+        " = MR_mmos_new_generator;\n",
+    PickupGeneratorArg = foreign_arg(GeneratorVar,
+        yes(generator_name - out_mode), generator_type),
+    table_generate_foreign_proc("table_mmos_pickup_inputs", det,
+        tabling_c_attributes, [PickupGeneratorArg], PickupForeignArgs,
+        "", PickupGeneratorCode, PickupVarCode, semipure_code,
+        PickupInstMapDeltaSrc, ModuleInfo0, Context, PickupGoal),
 
 	list__length(NumberedOutputVars, BlockSize),
-	generate_own_stack_save_goal(NumberedOutputVars, GeneratorVar,
-		BlockSize, Context, !VarTypes, !VarSet, !TableInfo,
-		SaveAnswerGoals),
+    generate_own_stack_save_goal(NumberedOutputVars, GeneratorVar, BlockSize,
+        Context, !VarTypes, !VarSet, !TableInfo, SaveAnswerGoals),
 
 	proc_info_goal(!.ProcInfo, OrigGoal),
-	GoalExpr = conj([OrigGoal | SaveAnswerGoals]),
+    GoalExpr = conj([PickupGoal, OrigGoal | SaveAnswerGoals]),
 	OrigGoal = _ - OrigGoalInfo,
 	goal_info_get_determinism(OrigGoalInfo, Detism),
 	set__insert(OrigNonLocals, GeneratorVar, NonLocals),
-	goal_info_init(NonLocals, OrigInstMapDelta, Detism, impure,
-		Context, GoalInfo0),
+    goal_info_init(NonLocals, OrigInstMapDelta, Detism, impure, Context,
+        GoalInfo0),
 	goal_info_add_feature(GoalInfo0, hide_debug_event, GoalInfo),
 	Goal = GoalExpr - GoalInfo,
 	proc_info_set_goal(Goal, !ProcInfo),
@@ -1713,22 +1720,22 @@
 	map__det_insert(ProcTable0, ProcId, !.ProcInfo, ProcTable),
 	pred_info_set_procedures(ProcTable, !PredInfo),
 
-	ModuleInfo0 = !.TableInfo ^ table_module_info,
 	module_info_preds(ModuleInfo0, PredTable0),
 	map__det_update(PredTable0, PredId, !.PredInfo, PredTable),
 	module_info_set_preds(PredTable, ModuleInfo0, ModuleInfo),
 	!:TableInfo = !.TableInfo ^ table_module_info := ModuleInfo.
 
-:- pred clone_pred_info(pred_id::in, pred_info::in, pred_id::out,
+:- pred clone_pred_info(pred_id::in, pred_info::in, list(prog_var)::in,
+    list(var_mode_pos)::in, pred_id::out,
 	table_info::in, table_info::out) is det.
 
-clone_pred_info(OrigPredId, PredInfo0, GeneratorPredId, !TableInfo) :-
+clone_pred_info(OrigPredId, PredInfo0, HeadVars, NumberedOutputVars,
+        GeneratorPredId, !TableInfo) :-
 	% We don't have any procedures for the generator yet. We will copy
 	% the consumers' procedures later, one by one, as they are transformed.
 
 	ModuleName = pred_info_module(PredInfo0),
 	PredName0 = pred_info_name(PredInfo0),
-	Arity0 = pred_info_orig_arity(PredInfo0),
 	PredOrFunc = pred_info_is_pred_or_func(PredInfo0),
 	pred_info_context(PredInfo0, Context),
 	% The generator is local even if the original predicate is exported.
@@ -1746,9 +1753,9 @@
 	pred_info_clauses_info(PredInfo0, ClausesInfo),
 
 	PredName = qualified(ModuleName, "GeneratorFor_" ++ PredName0),
-	% PredName = transform_sym_base_name(NameTransform, PredName0),
-	Arity = Arity0 + 1,
-	ArgTypes = ArgTypes0 ++ [generator_type],
+    assoc_list__from_corresponding_lists(HeadVars, ArgTypes0, HeadVarTypes),
+    keep_only_output_arg_types(HeadVarTypes, NumberedOutputVars, ArgTypes),
+    Arity = list__length(ArgTypes),
 
 	markers_to_marker_list(Markers0, MarkerList0),
 	list__filter(filter_marker, MarkerList0, MarkerList),
@@ -1762,11 +1769,24 @@
 
 	ModuleInfo0 = !.TableInfo ^ table_module_info,
 	module_info_get_predicate_table(ModuleInfo0, PredTable0),
-	predicate_table_insert(PredInfo, GeneratorPredId,
-		PredTable0, PredTable),
+    predicate_table_insert(PredInfo, GeneratorPredId, PredTable0, PredTable),
 	module_info_set_predicate_table(PredTable, ModuleInfo0, ModuleInfo),
 	!:TableInfo = !.TableInfo ^ table_module_info := ModuleInfo.
 
+:- pred keep_only_output_arg_types(assoc_list(prog_var, type)::in,
+    list(var_mode_pos)::in, list(type)::out) is det.
+
+keep_only_output_arg_types([], _, []).
+keep_only_output_arg_types([_ | _], [], []).
+keep_only_output_arg_types([Var - Type | VarTypes], [Out | Outs], OutTypes) :-
+    Out = var_mode_pos(OutVar, _, _),
+    ( Var = OutVar ->
+        keep_only_output_arg_types(VarTypes, Outs, OutTypesTail),
+        OutTypes = [Type | OutTypesTail]
+    ;
+        keep_only_output_arg_types(VarTypes, [Out | Outs], OutTypes)
+    ).
+
 :- pred filter_marker(marker::in) is semidet.
 
 filter_marker(Marker) :-
@@ -1806,15 +1826,17 @@
 %-----------------------------------------------------------------------------%
 
 :- pred generate_gen_proc_table_info(table_info::in, list(table_trie_step)::in,
-	list(prog_var)::in, list(prog_var)::in, proc_table_info::out) is det.
+    assoc_list(prog_var, mode)::in, assoc_list(prog_var, mode)::in,
+    proc_table_info::out) is det.
 
 generate_gen_proc_table_info(TableInfo, Steps, InputVars, OutputVars,
 		ProcTableInfo) :-
 	ProcInfo = TableInfo ^ table_cur_proc_info,
 	list__append(InputVars, OutputVars, InOutHeadVars),
 	allocate_slot_numbers(InOutHeadVars, 1, NumberedInOutHeadVars),
-	continuation_info__generate_table_arg_type_info(ProcInfo,
-		NumberedInOutHeadVars, TableArgTypeInfo),
+    ArgInfos = list__map(project_var_pos, NumberedInOutHeadVars),
+    continuation_info__generate_table_arg_type_info(ProcInfo, ArgInfos,
+        TableArgTypeInfo),
 	NumInputs = list__length(InputVars),
 	NumOutputs = list__length(OutputVars),
 	ProcTableInfo = table_gen_info(NumInputs, NumOutputs, Steps,
@@ -1824,22 +1846,20 @@
 
 	% Generate a goal for doing lookups in call tables for
 	% loopcheck and memo predicates.
-
+    %
 :- pred generate_simple_call_table_lookup_goal((type)::in, string::in,
-	assoc_list(prog_var, int)::in, pred_id::in, proc_id::in, bool::in,
+    list(var_mode_pos)::in, pred_id::in, proc_id::in, bool::in,
 	term__context::in, vartypes::in, vartypes::out,
 	prog_varset::in, prog_varset::out, table_info::in, table_info::out,
 	prog_var::out, prog_var::out, hlds_goal::out,
 	list(table_trie_step)::out) is det.
 
 generate_simple_call_table_lookup_goal(StatusType, SetupPred, NumberedVars,
-		PredId, ProcId, TablingViaExtraArgs, Context,
-		!VarTypes, !VarSet, !TableInfo, TableTipVar, StatusVar,
-		Goal, Steps) :-
+        PredId, ProcId, TablingViaExtraArgs, Context, !VarTypes, !VarSet,
+        !TableInfo, TableTipVar, StatusVar, Goal, Steps) :-
 	generate_call_table_lookup_goals(NumberedVars, PredId, ProcId, Context,
-		!VarTypes, !VarSet, !TableInfo, TableTipVar, LookupGoals,
-		Steps, PredTableVar, LookupForeignArgs, LookupPrefixGoals,
-		LookupCodeStr),
+        !VarTypes, !VarSet, !TableInfo, TableTipVar, LookupGoals, Steps,
+        PredTableVar, LookupForeignArgs, LookupPrefixGoals, LookupCodeStr),
 	generate_new_table_var("Status", StatusType, !VarTypes, !VarSet,
 		StatusVar),
 	ModuleInfo = !.TableInfo ^ table_module_info,
@@ -1855,19 +1875,16 @@
 		StatusArg = foreign_arg(StatusVar,
 			yes(StatusVarName - out_mode), StatusType),
 		MainPredCodeStr = "\tMR_" ++ SetupPred ++ "(" ++
-			cur_table_node_name ++ ", " ++
-			StatusVarName ++ ");\n",
+            cur_table_node_name ++ ", " ++ StatusVarName ++ ");\n",
 		(
 			NumberedVars = [_ | _],
 			Args = [PredTableArg, TableTipArg, StatusArg],
 			BoundVars = [TableTipVar, StatusVar],
 			CalledPred = SetupPred ++ "_shortcut",
-			TableTipAssignStr = MainPredCodeStr ++
-				"\t" ++ TableTipVarName ++
+            TableTipAssignStr = MainPredCodeStr ++ "\t" ++ TableTipVarName ++
 				" = " ++ cur_table_node_name ++ ";\n",
 			PredCodeStr = "\tMR_" ++ CalledPred ++ "(" ++
-				cur_table_node_name ++ ", " ++
-				TableTipVarName ++ ", " ++
+                cur_table_node_name ++ ", " ++ TableTipVarName ++ ", " ++
 				StatusVarName ++ ");\n"
 		;
 			NumberedVars = [],
@@ -1884,7 +1901,7 @@
 				PredTableVarName ++ ";\n" ++
 			LookupCodeStr ++
 			TableTipAssignStr,
-		generate_foreign_proc(CalledPred, det, tabling_c_attributes,
+        table_generate_foreign_proc(CalledPred, det, tabling_c_attributes,
 			Args, LookupForeignArgs, LookupDeclCodeStr,
 			PredCodeStr, "", impure_code, ground_vars(BoundVars),
 			ModuleInfo, Context, SetupGoal0),
@@ -1899,7 +1916,7 @@
 		list__append(LookupGoals, [SetupGoal], LookupSetupGoals)
 	),
 	GoalExpr = conj(LookupSetupGoals),
-	assoc_list__keys(NumberedVars, Vars),
+    Vars = list__map(project_var, NumberedVars),
 	set__list_to_set([StatusVar, TableTipVar | Vars], NonLocals),
 	goal_info_init_hide(NonLocals, bind_vars([TableTipVar, StatusVar]),
 		det, impure, Context, GoalInfo),
@@ -1907,25 +1924,24 @@
 
 	% Generate a goal for doing lookups in call tables for
 	% model_non memo predicates.
-
-:- pred generate_memo_non_call_table_lookup_goal(assoc_list(prog_var, int)::in,
+    %
+:- pred generate_memo_non_call_table_lookup_goal(list(var_mode_pos)::in,
 	pred_id::in, proc_id::in, term__context::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	table_info::in, table_info::out, prog_var::out, prog_var::out,
 	hlds_goal::out, list(table_trie_step)::out) is det.
 
 generate_memo_non_call_table_lookup_goal(NumberedVars, PredId, ProcId, Context,
-		!VarTypes, !VarSet, !TableInfo, RecordVar, StatusVar,
-		Goal, Steps) :-
+        !VarTypes, !VarSet, !TableInfo, RecordVar, StatusVar, Goal, Steps) :-
 	generate_call_table_lookup_goals(NumberedVars, PredId, ProcId, Context,
 		!VarTypes, !VarSet, !TableInfo, _TableTipVar, _LookupGoals,
 		Steps, PredTableVar, LookupForeignArgs, LookupPrefixGoals,
 		LookupCodeStr),
 	ModuleInfo = !.TableInfo ^ table_module_info,
-	generate_new_table_var("Record", memo_non_record_type,
-		!VarTypes, !VarSet, RecordVar),
-	generate_new_table_var("Status", memo_non_status_type,
-		!VarTypes, !VarSet, StatusVar),
+    generate_new_table_var("Record", memo_non_record_type, !VarTypes, !VarSet,
+        RecordVar),
+    generate_new_table_var("Status", memo_non_status_type, !VarTypes, !VarSet,
+        StatusVar),
 	SetupPred = "table_memo_non_setup",
 	BoundVars = [RecordVar, StatusVar],
 	PredTableVarName = pred_table_name,
@@ -1941,22 +1957,18 @@
 	LookupDeclCodeStr =
 		"\tMR_TrieNode " ++ cur_table_node_name ++ ";\n" ++
 		"\tMR_TrieNode " ++ next_table_node_name ++ ";\n" ++
-		"\t" ++ cur_table_node_name ++ " = " ++
-			PredTableVarName ++ ";\n" ++
+        "\t" ++ cur_table_node_name ++ " = " ++ PredTableVarName ++ ";\n" ++
 		LookupCodeStr,
-	PredCodeStr = "\tMR_" ++ SetupPred ++ "(" ++
-		cur_table_node_name ++ ", " ++
-		RecordVarName ++ ", " ++
-		StatusVarName ++ ");\n",
-	generate_foreign_proc(SetupPred, det, tabling_c_attributes,
-		Args, LookupForeignArgs, LookupDeclCodeStr,
-		PredCodeStr, "", impure_code, ground_vars(BoundVars),
-		ModuleInfo, Context, SetupGoal0),
+    PredCodeStr = "\tMR_" ++ SetupPred ++ "(" ++ cur_table_node_name ++ ", " ++
+        RecordVarName ++ ", " ++ StatusVarName ++ ");\n",
+    table_generate_foreign_proc(SetupPred, det, tabling_c_attributes, Args,
+        LookupForeignArgs, LookupDeclCodeStr, PredCodeStr, "", impure_code,
+        ground_vars(BoundVars), ModuleInfo, Context, SetupGoal0),
 	attach_call_table_tip(SetupGoal0, SetupGoal),
 	list__append(LookupPrefixGoals, [SetupGoal], LookupSetupGoals),
 
 	GoalExpr = conj(LookupSetupGoals),
-	assoc_list__keys(NumberedVars, Vars),
+    Vars = list__map(project_var, NumberedVars),
 	set__list_to_set([StatusVar, RecordVar | Vars], NonLocals),
 	goal_info_init_hide(NonLocals, bind_vars([RecordVar, StatusVar]),
 		det, impure, Context, GoalInfo),
@@ -1964,8 +1976,8 @@
 
 	% Generate a goal for doing lookups in call tables for
 	% minimal model predicates.
-
-:- pred generate_mm_call_table_lookup_goal(assoc_list(prog_var, int)::in,
+    %
+:- pred generate_mm_call_table_lookup_goal(list(var_mode_pos)::in,
 	pred_id::in, proc_id::in, bool::in, term__context::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	table_info::in, table_info::out, prog_var::out, prog_var::out,
@@ -1975,9 +1987,8 @@
 		TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
 		SubgoalVar, StatusVar, Goal, Steps) :-
 	generate_call_table_lookup_goals(NumberedVars, PredId, ProcId, Context,
-		!VarTypes, !VarSet, !TableInfo, TableTipVar, LookupGoals,
-		Steps, PredTableVar, LookupForeignArgs, LookupPrefixGoals,
-		LookupCodeStr),
+        !VarTypes, !VarSet, !TableInfo, TableTipVar, LookupGoals, Steps,
+        PredTableVar, LookupForeignArgs, LookupPrefixGoals, LookupCodeStr),
 	ModuleInfo = !.TableInfo ^ table_module_info,
 	generate_new_table_var("Subgoal", subgoal_type, !VarTypes, !VarSet,
 		SubgoalVar),
@@ -2004,10 +2015,9 @@
 				PredTableVarName ++ ";\n" ++
 			LookupCodeStr,
 		PredCodeStr = "\tMR_" ++ SetupPred ++ "(" ++
-			cur_table_node_name ++ ", " ++
-			SubgoalVarName ++ ", " ++
+            cur_table_node_name ++ ", " ++ SubgoalVarName ++ ", " ++
 			StatusVarName ++ ");\n",
-		generate_foreign_proc(SetupPred, det, tabling_c_attributes,
+        table_generate_foreign_proc(SetupPred, det, tabling_c_attributes,
 			Args, LookupForeignArgs, LookupDeclCodeStr,
 			PredCodeStr, "", impure_code, ground_vars(BoundVars),
 			ModuleInfo, Context, SetupGoal0),
@@ -2017,13 +2027,12 @@
 		TablingViaExtraArgs = no,
 		generate_call(SetupPred, det,
 			[TableTipVar, SubgoalVar, StatusVar], impure_code,
-			ground_vars(BoundVars), ModuleInfo, Context,
-			SetupGoal0),
+            ground_vars(BoundVars), ModuleInfo, Context, SetupGoal0),
 		attach_call_table_tip(SetupGoal0, SetupGoal),
 		list__append(LookupGoals, [SetupGoal], LookupSetupGoals)
 	),
 	GoalExpr = conj(LookupSetupGoals),
-	assoc_list__keys(NumberedVars, Vars),
+    Vars = list__map(project_var, NumberedVars),
 	set__list_to_set([StatusVar, SubgoalVar | Vars], NonLocals),
 	goal_info_init_hide(NonLocals, bind_vars([SubgoalVar, StatusVar]),
 		det, impure, Context, GoalInfo),
@@ -2033,7 +2042,7 @@
 
 % Utility predicates used when creating call table lookup goals.
 
-:- pred generate_call_table_lookup_goals(assoc_list(prog_var, int)::in,
+:- pred generate_call_table_lookup_goals(list(var_mode_pos)::in,
 	pred_id::in, proc_id::in, term__context::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	table_info::in, table_info::out, prog_var::out,
@@ -2046,9 +2055,8 @@
 	generate_get_table_goal(PredId, ProcId, !VarTypes, !VarSet,
 		PredTableVar, GetTableGoal),
 	generate_table_lookup_goals(NumberedVars, "CallTableNode", Context,
-		PredTableVar, TableTipVar, !VarTypes, !VarSet,
-		!TableInfo, LookupGoals, Steps, ForeignArgs,
-		LookupPrefixGoals, CodeStr),
+        PredTableVar, TableTipVar, !VarTypes, !VarSet, !TableInfo,
+        LookupGoals, Steps, ForeignArgs, LookupPrefixGoals, CodeStr),
 	Goals = [GetTableGoal | LookupGoals],
 	PrefixGoals = [GetTableGoal | LookupPrefixGoals].
 
@@ -2058,8 +2066,8 @@
 
 generate_get_table_goal(PredId, ProcId, !VarTypes, !VarSet, PredTableVar,
 		Goal) :-
-	generate_new_table_var("PredTable", trie_node_type,
-		!VarTypes, !VarSet, PredTableVar),
+    generate_new_table_var("PredTable", trie_node_type, !VarTypes, !VarSet,
+        PredTableVar),
 	ShroudedPredProcId = shroud_pred_proc_id(proc(PredId, ProcId)),
 	ConsId = tabling_pointer_const(ShroudedPredProcId),
 	make_const_construction(PredTableVar, ConsId, GoalExpr - GoalInfo0),
@@ -2078,8 +2086,8 @@
 	% Generate a sequence of lookup goals for the given variables.
 	% The generated code is used for lookups in both call tables
 	% and answer tables.
-
-:- pred generate_table_lookup_goals(assoc_list(prog_var, int)::in, string::in,
+    %
+:- pred generate_table_lookup_goals(list(var_mode_pos)::in, string::in,
 	term__context::in, prog_var::in, prog_var::out,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	table_info::in, table_info::out, list(hlds_goal)::out,
@@ -2088,10 +2096,11 @@
 
 generate_table_lookup_goals([], _, _, !TableVar, !VarTypes, !VarSet,
 		!TableInfo, [], [], [], [], "").
-generate_table_lookup_goals([Var - VarSeqNum | NumberedVars], Prefix, Context,
+generate_table_lookup_goals([VarModePos | NumberedVars], Prefix, Context,
 		!TableVar, !VarTypes, !VarSet, !TableInfo, Goals ++ RestGoals,
 		[Step | Steps], ForeignArgs ++ RestForeignArgs,
 		PrefixGoals ++ RestPrefixGoals, CodeStr ++ RestCodeStr) :-
+    VarModePos = var_mode_pos(Var, _, VarSeqNum),
 	ModuleInfo = !.TableInfo ^ table_module_info,
 	map__lookup(!.VarTypes, Var, VarType),
 	classify_type(ModuleInfo, VarType) = TypeCat,
@@ -2131,8 +2140,7 @@
 			->
 				list__length(Ctors, EnumRange)
 			;
-				error("gen_lookup_call_for_type: " ++
-					"enum type is not du_type?")
+                error("gen_lookup_call_for_type: enum type is not du_type?")
 			),
 			gen_int_construction("RangeVar", EnumRange, !VarTypes,
 				!VarSet, RangeVar, RangeUnifyGoal),
@@ -2146,10 +2154,8 @@
 			PrefixGoals = [],
 			ExtraArgs = [ForeignArg],
 			CodeStr0 = "\tMR_" ++ LookupPredName ++ "(" ++
-				cur_table_node_name ++ ", " ++
-				int_to_string(EnumRange) ++ ", " ++
-				ArgName ++ ", " ++
-				next_table_node_name ++ ");\n"
+                cur_table_node_name ++ ", " ++ int_to_string(EnumRange) ++
+                ", " ++ ArgName ++ ", " ++ next_table_node_name ++ ");\n"
 		;
 			error("gen_lookup_call_for_type: unexpected enum type")
 		)
@@ -2168,35 +2174,28 @@
 				!TableInfo, TypeInfoVar, ExtraGoals),
 			generate_call(LookupPredName, det,
 				[TypeInfoVar, TableVar, ArgVar, NextTableVar],
-				impure_code, BindNextTableVar,
-				ModuleInfo, Context, CallGoal),
+                impure_code, BindNextTableVar, ModuleInfo, Context, CallGoal),
 			Goals = ExtraGoals ++ [CallGoal],
 			PrefixGoals = ExtraGoals,
-			TypeInfoArgName = "input_typeinfo" ++
-				int_to_string(VarSeqNum),
+            TypeInfoArgName = "input_typeinfo" ++ int_to_string(VarSeqNum),
 			map__lookup(!.VarTypes, TypeInfoVar, TypeInfoType),
 			ForeignTypeInfoArg = foreign_arg(TypeInfoVar,
 				yes(TypeInfoArgName - in_mode), TypeInfoType),
 			ExtraArgs = [ForeignTypeInfoArg, ForeignArg],
 			CodeStr0 = "\tMR_" ++ LookupPredName ++ "(" ++
-				cur_table_node_name ++ ", " ++
-				TypeInfoArgName ++ ", " ++
-				ArgName ++ ", " ++
-				next_table_node_name ++ ");\n"
+                cur_table_node_name ++ ", " ++ TypeInfoArgName ++ ", " ++
+                ArgName ++ ", " ++ next_table_node_name ++ ");\n"
 		;
 			MaybeCatStringStep = yes(CatString - Step),
-			string__append("table_lookup_insert_", CatString,
-				LookupPredName),
+            string__append("table_lookup_insert_", CatString, LookupPredName),
 			generate_call(LookupPredName, det,
 				[TableVar, ArgVar, NextTableVar],
-				impure_code, BindNextTableVar, ModuleInfo,
-				Context, Goal),
+                impure_code, BindNextTableVar, ModuleInfo, Context, Goal),
 			Goals = [Goal],
 			PrefixGoals = [],
 			ExtraArgs = [ForeignArg],
 			CodeStr0 = "\tMR_" ++ LookupPredName ++ "(" ++
-				cur_table_node_name ++ ", " ++
-				ArgName ++ ", " ++
+                cur_table_node_name ++ ", " ++ ArgName ++ ", " ++
 				next_table_node_name ++ ");\n"
 		)
 	),
@@ -2207,33 +2206,31 @@
 
 	% Generate a goal for saving the output arguments in an answer block
 	% in memo predicates.
-
-:- pred generate_memo_save_goals(assoc_list(prog_var, int)::in,
+    %
+:- pred generate_memo_save_goals(list(var_mode_pos)::in,
 	prog_var::in, int::in, bool::in, term__context::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	table_info::in, table_info::out, list(hlds_goal)::out) is det.
 
 generate_memo_save_goals(NumberedSaveVars, TableTipVar, BlockSize,
-		TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
-		Goals) :-
+        TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo, Goals) :-
 	ModuleInfo = !.TableInfo ^ table_module_info,
 	( BlockSize > 0 ->
 		CreatePredName = "table_memo_create_answer_block",
 		ShortcutPredName = "table_memo_fill_answer_block_shortcut",
-		generate_all_save_goals(NumberedSaveVars, TableTipVar,
-			trie_node_type, base_name, BlockSize,
-			CreatePredName, ShortcutPredName, TablingViaExtraArgs,
-			Context, !VarTypes, !VarSet, !TableInfo, Goals, _, _)
+        generate_all_save_goals(NumberedSaveVars, TableTipVar, trie_node_type,
+            base_name, BlockSize, CreatePredName, ShortcutPredName,
+            TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
+            Goals, _, _)
 	;
 		MarkAsSucceededPred = "table_memo_mark_as_succeeded",
 		(
 			TablingViaExtraArgs = yes,
 			TableArg = foreign_arg(TableTipVar,
-				yes(cur_table_node_name - in_mode),
-				trie_node_type),
+                yes(cur_table_node_name - in_mode), trie_node_type),
 			MarkAsSucceededCode = "MR_" ++ MarkAsSucceededPred ++
 				"(" ++ cur_table_node_name ++ ");",
-			generate_foreign_proc(MarkAsSucceededPred, det,
+            table_generate_foreign_proc(MarkAsSucceededPred, det,
 				tabling_c_attributes, [TableArg], [],
 				"", MarkAsSucceededCode, "", impure_code, [],
 				ModuleInfo, Context, Goal)
@@ -2247,8 +2244,8 @@
 
 	% Generate a goal for saving the output arguments in an answer block
 	% in model_non memo predicates.
-
-:- pred generate_memo_non_save_goals(assoc_list(prog_var, int)::in,
+    %
+:- pred generate_memo_non_save_goals(list(var_mode_pos)::in,
 	prog_var::in, int::in, term__context::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	table_info::in, table_info::out, list(hlds_goal)::out) is det.
@@ -2267,7 +2264,7 @@
 	GetPredName = "table_memo_non_get_answer_table",
 	GetPredCode = "\tMR_" ++ GetPredName ++ "(" ++
 		RecordName ++ ", " ++ AnswerTableName ++ ");\n",
-	generate_foreign_proc(GetPredName, det, tabling_c_attributes,
+    table_generate_foreign_proc(GetPredName, det, tabling_c_attributes,
 		[RecordArg, AnswerTableArg], [], "", GetPredCode, "",
 		semipure_code, ground_vars([AnswerTableVar]),
 		ModuleInfo, Context, GetAnswerTableGoal),
@@ -2299,16 +2296,13 @@
 		LookupCodeStr,
 	DuplCheckCodeStr =
 		"\tMR_" ++ DuplCheckPredName ++ "(" ++
-			cur_table_node_name ++ ", " ++
-			SuccName ++ ");\n",
+            cur_table_node_name ++ ", " ++ SuccName ++ ");\n",
 	AssignSuccessCodeStr =
-		"\t" ++ success_indicator_name ++ " = " ++
-			SuccName ++ ";\n",
+        "\t" ++ success_indicator_name ++ " = " ++ SuccName ++ ";\n",
 	PreStr = LookupDeclCodeStr ++ SaveDeclCode ++ GetLookupCodeStr,
-	PostStr = "\tif (" ++ SuccName ++ ") {\n" ++
-		CreateSaveCode ++ "\t}\n" ++
+    PostStr = "\tif (" ++ SuccName ++ ") {\n" ++ CreateSaveCode ++ "\t}\n" ++
 		AssignSuccessCodeStr,
-	generate_foreign_proc(DuplCheckPredNameShortcut, semidet,
+    table_generate_foreign_proc(DuplCheckPredNameShortcut, semidet,
 		tabling_c_attributes, [RecordArg], LookupForeignArgs,
 		PreStr, DuplCheckCodeStr, PostStr, impure_code, [],
 		ModuleInfo, Context, DuplicateCheckSaveGoal),
@@ -2317,15 +2311,14 @@
 
 	% Generate a goal for saving the output arguments in an answer block
 	% in minimal model predicates.
-
-:- pred generate_mm_save_goals(assoc_list(prog_var, int)::in,
+    %
+:- pred generate_mm_save_goals(list(var_mode_pos)::in,
 	prog_var::in, int::in, bool::in, term__context::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	table_info::in, table_info::out, list(hlds_goal)::out) is det.
 
 generate_mm_save_goals(NumberedSaveVars, SubgoalVar, BlockSize,
-		TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
-		Goals) :-
+        TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo, Goals) :-
 	ModuleInfo = !.TableInfo ^ table_module_info,
 	generate_new_table_var("AnswerTableVar", trie_node_type,
 		!VarTypes, !VarSet, AnswerTableVar),
@@ -2363,34 +2356,30 @@
 			LookupCodeStr,
 		DuplCheckCodeStr =
 			"\tMR_" ++ DuplCheckPredName ++ "(" ++
-				cur_table_node_name ++ ", " ++
-				SuccName ++ ");\n",
+                cur_table_node_name ++ ", " ++ SuccName ++ ");\n",
 		AssignSuccessCodeStr =
-			"\t" ++ success_indicator_name ++ " = " ++
-				SuccName ++ ";\n",
+            "\t" ++ success_indicator_name ++ " = " ++ SuccName ++ ";\n",
 		PreStr = LookupDeclCodeStr ++ SaveDeclCode ++ GetLookupCodeStr,
 		PostStr = "\tif (" ++ SuccName ++ ") {\n" ++
 			CreateSaveCode ++ "\t}\n" ++
 			AssignSuccessCodeStr,
-		generate_foreign_proc(DuplCheckPredName, semidet,
+        table_generate_foreign_proc(DuplCheckPredName, semidet,
 			tabling_c_attributes, Args, LookupForeignArgs,
 			PreStr, DuplCheckCodeStr, PostStr, impure_code, [],
 			ModuleInfo, Context, DuplicateCheckSaveGoal),
-		list__append(LookupPrefixGoals, [DuplicateCheckSaveGoal],
-			Goals)
+        list__append(LookupPrefixGoals, [DuplicateCheckSaveGoal], Goals)
 	;
 		TablingViaExtraArgs = no,
 		generate_call(DuplCheckPredName, semidet, [AnswerTableTipVar],
-			impure_code, [], ModuleInfo, Context,
-			DuplicateCheckGoal),
+            impure_code, [], ModuleInfo, Context, DuplicateCheckGoal),
 		list__append([GetAnswerTableGoal | LookupAnswerGoals],
 			[DuplicateCheckGoal], LookupCheckGoals),
 		list__append(LookupCheckGoals, SaveGoals, Goals)
 	).
 
 	% Generate a save goal for the given variables.
-
-:- pred generate_all_save_goals(assoc_list(prog_var, int)::in,
+    %
+:- pred generate_all_save_goals(list(var_mode_pos)::in,
 	prog_var::in, (type)::in, string::in, int::in, string::in, string::in,
 	bool::in, term__context::in, vartypes::in, vartypes::out,
 	prog_varset::in, prog_varset::out, table_info::in, table_info::out,
@@ -2411,19 +2400,16 @@
 		TableArg = foreign_arg(BaseVar, yes(BaseVarName - in_mode),
 			BaseVarType),
 		Args = [TableArg],
-		SaveDeclCodeStr = "\tMR_AnswerBlock " ++
-			answer_block_name ++ ";\n",
+        SaveDeclCodeStr = "\tMR_AnswerBlock " ++ answer_block_name ++ ";\n",
 		CreateCodeStr = "\tMR_" ++ CreatePredName ++ "(" ++
-			BaseVarName ++ ", " ++
-			int_to_string(BlockSize) ++ ", " ++
+            BaseVarName ++ ", " ++ int_to_string(BlockSize) ++ ", " ++
 			answer_block_name ++ ");\n",
 		CreateSaveCodeStr = CreateCodeStr ++ SaveCodeStr,
 		ShortcutStr = "\tMR_" ++ ShortcutPredName ++ "(" ++
 			BaseVarName ++ ");\n",
-		generate_foreign_proc(ShortcutPredName, det,
-			tabling_c_attributes, Args, SaveArgs,
-			SaveDeclCodeStr ++ CreateSaveCodeStr, ShortcutStr, "",
-			impure_code, [], ModuleInfo, Context, ShortcutGoal),
+        table_generate_foreign_proc(ShortcutPredName, det, tabling_c_attributes,
+            Args, SaveArgs, SaveDeclCodeStr ++ CreateSaveCodeStr, ShortcutStr,
+            "", impure_code, [], ModuleInfo, Context, ShortcutGoal),
 		list__append(SavePrefixGoals, [ShortcutGoal], Goals)
 	;
 		TablingViaExtraArgs = no,
@@ -2433,8 +2419,7 @@
 			[BaseVar, BlockSizeVar, AnswerBlockVar],
 			impure_code, ground_vars([AnswerBlockVar]),
 			ModuleInfo, Context, CreateAnswerBlockGoal),
-		Goals = [BlockSizeVarUnifyGoal, CreateAnswerBlockGoal |
-			SaveGoals],
+        Goals = [BlockSizeVarUnifyGoal, CreateAnswerBlockGoal | SaveGoals],
 		SaveDeclCodeStr = "",
 		CreateSaveCodeStr = ""
 	).
@@ -2442,8 +2427,8 @@
 %-----------------------------------------------------------------------------%
 
 	% Generate a sequence of save goals for the given variables.
-
-:- pred generate_own_stack_save_goal(assoc_list(prog_var, int)::in,
+    %
+:- pred generate_own_stack_save_goal(list(var_mode_pos)::in,
 	prog_var::in, int::in, term__context::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	table_info::in, table_info::out, list(hlds_goal)::out) is det.
@@ -2453,24 +2438,34 @@
 	ModuleInfo = !.TableInfo ^ table_module_info,
 	generate_new_table_var("AnswerTableVar", trie_node_type,
 		!VarTypes, !VarSet, AnswerTableVar),
-	% XXX use foreign_proc
-	generate_call("table_generator_get_answer_table", det,
-		[GeneratorVar, AnswerTableVar], impure_code,
-		ground_vars([AnswerTableVar]), ModuleInfo, Context,
-		GetAnswerTableGoal),
-	% assoc_list__keys(NumberedOutputVars, OutputVars),
+    GeneratorName = generator_name,
+    AnswerTableName = answer_table_name,
+    GeneratorArg = foreign_arg(GeneratorVar,
+        yes(GeneratorName - in_mode), generator_type),
+    AnswerTableArg = foreign_arg(AnswerTableVar,
+        yes(AnswerTableName - in_mode), trie_node_type),
+    GetPredName = "table_mmos_get_answer_table",
+    GetPredCode = "\t" ++ AnswerTableName ++ " = " ++
+        "MR_" ++ GetPredName ++ "(" ++ GeneratorName ++ ");\n",
+    table_generate_foreign_proc(GetPredName, det, tabling_c_attributes,
+        [GeneratorArg, AnswerTableArg], [], "", GetPredCode, "",
+        semipure_code, ground_vars([AnswerTableVar]),
+        ModuleInfo, Context, GetAnswerTableGoal),
+
 	% XXX use foreign_proc
 	generate_table_lookup_goals(NumberedOutputVars, "AnswerTableNode",
 		Context, AnswerTableVar, AnswerTableTipVar, !VarTypes, !VarSet,
-		!TableInfo, LookupAnswerGoals, _, _, _, _),
-	generate_call("table_nondet_answer_is_not_duplicate", semidet,
+        !TableInfo, LookupAnswerGoals, _, _LookupForeignArgs,
+        _LookupPrefixGoals, _LookupCodeStr),
+
+    generate_call("table_mmos_answer_is_not_duplicate", semidet,
 		[AnswerTableTipVar], impure_code,
 		[], ModuleInfo, Context, DuplicateCheckGoal),
 	generate_new_table_var("AnswerBlock", answer_block_type,
 		!VarTypes, !VarSet, AnswerBlockVar),
 	gen_int_construction("BlockSize", BlockSize, !VarTypes, !VarSet,
 		BlockSizeVar, BlockSizeVarUnifyGoal),
-	generate_call("table_generator_create_answer_block", det,
+    generate_call("table_mmos_create_answer_block", det,
 		[GeneratorVar, BlockSizeVar, AnswerBlockVar], impure_code,
 		ground_vars([AnswerBlockVar]), ModuleInfo, Context,
 		CreateAnswerBlockGoal),
@@ -2482,7 +2477,7 @@
 		[DuplicateCheckGoal, BlockSizeVarUnifyGoal,
 		CreateAnswerBlockGoal | TailGoals].
 
-:- pred generate_save_goals(assoc_list(prog_var, int)::in, prog_var::in,
+:- pred generate_save_goals(list(var_mode_pos)::in, prog_var::in,
 	term__context::in, vartypes::in, vartypes::out,
 	prog_varset::in, prog_varset::out, table_info::in, table_info::out,
 	list(hlds_goal)::out, list(foreign_arg)::out, list(hlds_goal)::out,
@@ -2493,7 +2488,7 @@
 generate_save_goals([NumberedVar | NumberedRest], TableVar, Context,
 		!VarTypes, !VarSet, !TableInfo, Goals, Args ++ RestArgs,
 		PrefixGoals ++ RestPrefixGoals, CodeStr ++ RestCodeStr) :-
-	NumberedVar = Var - Offset,
+    NumberedVar = var_mode_pos(Var, _Mode,  Offset),
 	gen_int_construction("OffsetVar", Offset, !VarTypes, !VarSet,
 		OffsetVar, OffsetUnifyGoal),
 	ModuleInfo = !.TableInfo ^ table_module_info,
@@ -2527,13 +2522,11 @@
 		Args = [ForeignArg],
 		PrefixGoals = [],
 		CodeStr = "\tMR_" ++ SavePredName ++ "(" ++
-			answer_block_name ++ ", " ++
-			int_to_string(Offset) ++ ", " ++
+            answer_block_name ++ ", " ++ int_to_string(Offset) ++ ", " ++
 			Name ++ ");\n"
 	; builtin_type(TypeCat) = no ->
 		% If used ForeignArg instead of GenericForeignArg, then
-		% Var would be unboxed when assigned to Name, which we
-		% don't want.
+        % Var would be unboxed when assigned to Name, which we don't want.
 		GenericForeignArg = foreign_arg(Var, yes(Name - in_mode),
 			dummy_type_var),
 		make_type_info_var(Type, Context, !VarTypes, !VarSet,
@@ -2550,10 +2543,8 @@
 		Args = [GenericForeignArg, TypeInfoForeignArg],
 		PrefixGoals = ExtraGoals,
 		CodeStr = "\tMR_" ++ SavePredName ++ "(" ++
-			answer_block_name ++ ", " ++
-			int_to_string(Offset) ++ ", " ++
-			TypeInfoName ++ ", " ++
-			Name ++ ");\n"
+            answer_block_name ++ ", " ++ int_to_string(Offset) ++ ", " ++
+            TypeInfoName ++ ", " ++ Name ++ ");\n"
 	;
 		type_save_category(TypeCat, CatString),
 		string__append_list(["table_save_", CatString, "_answer"],
@@ -2564,8 +2555,7 @@
 		Args = [ForeignArg],
 		PrefixGoals = [],
 		CodeStr = "\tMR_" ++ SavePredName ++ "(" ++
-			answer_block_name ++ ", " ++
-			int_to_string(Offset) ++ ", " ++
+            answer_block_name ++ ", " ++ int_to_string(Offset) ++ ", " ++
 			Name ++ ");\n"
 	).
 
@@ -2573,19 +2563,18 @@
 
 	% Generate a goal for restoring the output arguments from
 	% an answer block in memo predicates.
-
-:- pred generate_memo_restore_goal(assoc_list(prog_var, int)::in,
+    %
+:- pred generate_memo_restore_goal(list(var_mode_pos)::in,
 	instmap_delta::in, prog_var::in, module_info::in,
 	bool::in, term__context::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	hlds_goal::out) is det.
 
 generate_memo_restore_goal(NumberedOutputVars, OrigInstMapDelta, TipVar,
-		ModuleInfo, TablingViaExtraArgs, Context, !VarTypes, !VarSet,
-		Goal) :-
+        ModuleInfo, TablingViaExtraArgs, Context, !VarTypes, !VarSet, Goal) :-
 	(
 		NumberedOutputVars = [_ | _],
-		assoc_list__keys(NumberedOutputVars, OutputVars),
+        OutputVars = list__map(project_var, NumberedOutputVars),
 		GetPredName = "table_memo_get_answer_block",
 		generate_new_table_var("RestoreBlockVar", answer_block_type,
 			!VarTypes, !VarSet, RestoreBlockVar),
@@ -2599,25 +2588,21 @@
 			Arg = foreign_arg(TipVar, yes(BaseVarName - in_mode),
 				trie_node_type),
 			Args = [Arg],
-			DeclCodeStr = "\tMR_AnswerBlock " ++
-				answer_block_name ++ ";\n",
+            DeclCodeStr = "\tMR_AnswerBlock " ++ answer_block_name ++ ";\n",
 			ShortcutPredName = GetPredName ++ "_shortcut",
 			ShortcutStr = "\tMR_" ++ ShortcutPredName ++ "(" ++
 				BaseVarName ++ ");\n",
 			GetRestoreCodeStr = "\tMR_" ++ GetPredName ++ "(" ++
-				BaseVarName ++ ", " ++
-				answer_block_name ++ ");\n" ++
+                BaseVarName ++ ", " ++ answer_block_name ++ ");\n" ++
 				RestoreCodeStr,
-			generate_foreign_proc(ShortcutPredName, det,
-				tabling_c_attributes, Args, RestoreArgs,
-				DeclCodeStr, ShortcutStr, GetRestoreCodeStr,
-				impure_code, RestoreInstMapDeltaSrc,
-				ModuleInfo, Context, ShortcutGoal),
+            table_generate_foreign_proc(ShortcutPredName, det,
+                tabling_c_attributes, Args, RestoreArgs, DeclCodeStr,
+                ShortcutStr, GetRestoreCodeStr, impure_code,
+                RestoreInstMapDeltaSrc, ModuleInfo, Context, ShortcutGoal),
 			Goal = ShortcutGoal
 		;
 			TablingViaExtraArgs = no,
-			generate_call(GetPredName, det,
-				[TipVar, RestoreBlockVar],
+            generate_call(GetPredName, det, [TipVar, RestoreBlockVar],
 				semipure_code, ground_vars([RestoreBlockVar]),
 				ModuleInfo, Context, GetBlockGoal),
 			GoalExpr = conj([GetBlockGoal | RestoreGoals]),
@@ -2633,9 +2618,9 @@
 
 	% Generate a goal for restoring the output arguments from
 	% an answer block in model_non memo predicates.
-
+    %
 :- pred generate_memo_non_restore_goal(determinism::in,
-	assoc_list(prog_var, int)::in, instmap_delta::in, prog_var::in,
+    list(var_mode_pos)::in, instmap_delta::in, prog_var::in,
 	module_info::in, term__context::in, vartypes::in, vartypes::out,
 	prog_varset::in, prog_varset::out, hlds_goal::out) is det.
 
@@ -2655,19 +2640,17 @@
 		Context, ReturnAnswerBlocksGoal),
 	generate_restore_goals(NumberedOutputVars, OrigInstMapDelta,
 		AnswerBlockVar, ModuleInfo, Context, !VarTypes, !VarSet,
-		_RestoreGoals, RestoreInstMapDeltaSrc, RestoreArgs,
-		RestoreCodeStr),
-	assoc_list__keys(NumberedOutputVars, OutputVars),
+        _RestoreGoals, RestoreInstMapDeltaSrc, RestoreArgs, RestoreCodeStr),
+    OutputVars = list__map(project_var, NumberedOutputVars),
 	Arg = foreign_arg(AnswerBlockVar, yes(answer_block_name - in_mode),
 		answer_block_type),
 	Args = [Arg],
 	ShortcutPredName = "table_memo_non_return_all_shortcut",
 	ShortcutStr = "\tMR_" ++ ShortcutPredName ++ "(" ++
 		answer_block_name ++ ");\n",
-	generate_foreign_proc(ShortcutPredName, det, tabling_c_attributes,
-		Args, RestoreArgs, "", ShortcutStr, RestoreCodeStr,
-		impure_code, RestoreInstMapDeltaSrc, ModuleInfo, Context,
-		ShortcutGoal),
+    table_generate_foreign_proc(ShortcutPredName, det, tabling_c_attributes,
+        Args, RestoreArgs, "", ShortcutStr, RestoreCodeStr, impure_code,
+        RestoreInstMapDeltaSrc, ModuleInfo, Context, ShortcutGoal),
 
 	GoalExpr = conj([ReturnAnswerBlocksGoal, ShortcutGoal]),
 	set__list_to_set([RecordVar | OutputVars], NonLocals),
@@ -2677,9 +2660,9 @@
 
 	% Generate a goal for restoring the output arguments from
 	% an answer block in minimal model predicates without a suspension.
-
+    %
 :- pred generate_mm_restore_goal(determinism::in,
-	assoc_list(prog_var, int)::in, instmap_delta::in, prog_var::in,
+    list(var_mode_pos)::in, instmap_delta::in, prog_var::in,
 	module_info::in, bool::in, term__context::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	hlds_goal::out) is det.
@@ -2700,16 +2683,15 @@
 
 	% Generate a goal for restoring the output arguments from
 	% an answer block in minimal model predicates after a suspension.
-
-:- pred generate_mm_suspend_goal(assoc_list(prog_var, int)::in,
+    %
+:- pred generate_mm_suspend_goal(list(var_mode_pos)::in,
 	instmap_delta::in, prog_var::in, module_info::in,
 	bool::in, term__context::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	hlds_goal::out) is det.
 
 generate_mm_suspend_goal(NumberedOutputVars, OrigInstMapDelta, SubgoalVar,
-		ModuleInfo, TablingViaExtraArgs, Context, !VarTypes, !VarSet,
-		Goal) :-
+        ModuleInfo, TablingViaExtraArgs, Context, !VarTypes, !VarSet, Goal) :-
 	generate_mm_restore_or_suspend_goal("table_mm_suspend_consumer",
 		nondet, impure, NumberedOutputVars, OrigInstMapDelta,
 		SubgoalVar, ModuleInfo, TablingViaExtraArgs, Context,
@@ -2718,9 +2700,9 @@
 	% Generate a goal for restoring the output arguments from
 	% an answer block in minimal model predicates. Whether the restore
 	% is after a suspension depends on the arguments.
-
+    %
 :- pred generate_mm_restore_or_suspend_goal(string::in, determinism::in,
-	purity::in, assoc_list(prog_var, int)::in, instmap_delta::in,
+    purity::in, list(var_mode_pos)::in, instmap_delta::in,
 	prog_var::in, module_info::in, bool::in, term__context::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	hlds_goal::out) is det.
@@ -2735,9 +2717,8 @@
 		Context, ReturnAnswerBlocksGoal),
 	generate_restore_goals(NumberedOutputVars, OrigInstMapDelta,
 		AnswerBlockVar, ModuleInfo, Context, !VarTypes, !VarSet,
-		RestoreGoals, RestoreInstMapDeltaSrc, RestoreArgs,
-		RestoreCodeStr),
-	assoc_list__keys(NumberedOutputVars, OutputVars),
+        RestoreGoals, RestoreInstMapDeltaSrc, RestoreArgs, RestoreCodeStr),
+    OutputVars = list__map(project_var, NumberedOutputVars),
 	(
 		TablingViaExtraArgs = yes,
 		Arg = foreign_arg(AnswerBlockVar,
@@ -2746,10 +2727,9 @@
 		ShortcutPredName = "table_mm_return_all_shortcut",
 		ShortcutStr = "\tMR_" ++ ShortcutPredName ++ "(" ++
 			answer_block_name ++ ");\n",
-		generate_foreign_proc(ShortcutPredName, det,
-			tabling_c_attributes, Args, RestoreArgs,
-			"", ShortcutStr, RestoreCodeStr,
-			impure_code, RestoreInstMapDeltaSrc, ModuleInfo,
+        table_generate_foreign_proc(ShortcutPredName, det,
+            tabling_c_attributes, Args, RestoreArgs, "", ShortcutStr,
+            RestoreCodeStr, impure_code, RestoreInstMapDeltaSrc, ModuleInfo,
 			Context, ShortcutGoal),
 		GoalExpr = conj([ReturnAnswerBlocksGoal, ShortcutGoal])
 	;
@@ -2764,8 +2744,8 @@
 %-----------------------------------------------------------------------------%
 
 	% Generate a sequence of restore goals for the given variables.
-
-:- pred generate_restore_goals(assoc_list(prog_var, int)::in,
+    %
+:- pred generate_restore_goals(list(var_mode_pos)::in,
 	instmap_delta::in, prog_var::in, module_info::in, term__context::in,
 	vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
 	list(hlds_goal)::out, assoc_list(prog_var, inst)::out,
@@ -2776,7 +2756,7 @@
 		AnswerBlockVar, ModuleInfo, Context, !VarTypes, !VarSet,
 		[OffsetUnifyGoal, CallGoal | RestGoals], [VarInst | VarInsts],
 		[Arg | Args], CodeStr ++ RestCodeStr) :-
-	NumberedVar = Var - Offset,
+    NumberedVar = var_mode_pos(Var, _Mode, Offset),
 	gen_int_construction("OffsetVar", Offset, !VarTypes, !VarSet,
 		OffsetVar, OffsetUnifyGoal),
 	map__lookup(!.VarTypes, Var, VarType),
@@ -2816,8 +2796,7 @@
 	),
 	Arg = foreign_arg(Var, yes(Name - (free -> Inst)), ArgType),
 	CodeStr = "\tMR_" ++ RestorePredName ++ "(" ++
-		answer_block_name ++ ", " ++
-		int_to_string(Offset) ++ ", " ++
+        answer_block_name ++ ", " ++ int_to_string(Offset) ++ ", " ++
 		Name ++ ");\n",
 	generate_call(RestorePredName, det, [TableVar, OffsetVar, Var],
 		semipure_code, [Var - Inst], ModuleInfo, Context, Goal).
@@ -2845,8 +2824,7 @@
 	Arity = pred_info_orig_arity(PredInfo),
 	PredOrFunc = pred_info_is_pred_or_func(PredInfo),
 	PredOrFuncStr = pred_or_func_to_str(PredOrFunc),
-	mdbcomp__prim_data__sym_name_to_string(qualified(Module, Name), 
-		NameStr),
+    sym_name_to_string(qualified(Module, Name), NameStr),
 	string__int_to_string(Arity, ArityStr),
 	string__append_list([Msg, " in ", PredOrFuncStr, " ", NameStr,
 		"/", ArityStr], Message),
@@ -2902,13 +2880,13 @@
 		only_mode, Detism, Args, Features, InstMapSrc, ModuleInfo,
 		Context, Goal).
 
-:- pred generate_foreign_proc(string::in, determinism::in,
+:- pred table_generate_foreign_proc(string::in, determinism::in,
 	pragma_foreign_proc_attributes::in,
 	list(foreign_arg)::in, list(foreign_arg)::in, string::in, string::in,
 	string::in, impure_or_semipure::in, assoc_list(prog_var, inst)::in,
 	module_info::in, term__context::in, hlds_goal::out) is det.
 
-generate_foreign_proc(PredName, Detism, Attributes, Args, ExtraArgs,
+table_generate_foreign_proc(PredName, Detism, Attributes, Args, ExtraArgs,
 		PrefixCode, Code, SuffixCode, Purity, InstMapSrc,
 		ModuleInfo, Context, Goal) :-
 	mercury_table_builtin_module(BuiltinModule),
@@ -3013,28 +2991,28 @@
 
 :- pred get_input_output_vars(list(prog_var)::in, list(mode)::in,
 	module_info::in, list(prog_var)::out,
-	list(prog_var)::out, list(prog_var)::out) is det.
+    assoc_list(prog_var, mode)::out, assoc_list(prog_var, mode)::out) is det.
 
 get_input_output_vars([], [], _, [], [], []).
 get_input_output_vars([_|_], [], _, _, _, _) :-
 	error("get_input_output_vars: lists not same length").
 get_input_output_vars([], [_|_], _, _, _, _) :-
 	error("get_input_output_vars: lists not same length").
-get_input_output_vars([Var | RestV], [Mode | RestM], ModuleInfo,
-		BadVars, InVars, OutVars) :-
+get_input_output_vars([Var | Vars], [Mode | Modes], ModuleInfo,
+        BadVars, InVarModes, OutVarModes) :-
 	% XXX We should check not just the boundedness of Var, but also
 	% its sharing state: tabled arguments should not share.
 	( mode_is_fully_input(ModuleInfo, Mode) ->
-		get_input_output_vars(RestV, RestM, ModuleInfo,
-			BadVars, InVars0, OutVars),
-		InVars = [Var | InVars0]
+        get_input_output_vars(Vars, Modes, ModuleInfo,
+            BadVars, InVarModes0, OutVarModes),
+        InVarModes = [Var - Mode | InVarModes0]
 	; mode_is_fully_output(ModuleInfo, Mode) ->
-		get_input_output_vars(RestV, RestM, ModuleInfo,
-			BadVars, InVars, OutVars0),
-		OutVars = [Var | OutVars0]
+        get_input_output_vars(Vars, Modes, ModuleInfo,
+            BadVars, InVarModes, OutVarModes0),
+        OutVarModes = [Var - Mode | OutVarModes0]
 	;
-		get_input_output_vars(RestV, RestM, ModuleInfo,
-			BadVars0, InVars, OutVars),
+        get_input_output_vars(Vars, Modes, ModuleInfo,
+            BadVars0, InVarModes, OutVarModes),
 		BadVars = [Var | BadVars0]
 	).
 
@@ -3052,17 +3030,50 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred allocate_slot_numbers(list(prog_var)::in, int::in,
-	assoc_list(prog_var, int)::out) is det.
+:- type var_mode_pos
+    --->    var_mode_pos(prog_var, mode, int).
+
+:- func project_var(var_mode_pos) = prog_var.
+
+project_var(var_mode_pos(Var, _, _)) = Var.
+
+:- func project_var_pos(var_mode_pos) = pair(prog_var, int).
+
+project_var_pos(var_mode_pos(Var, _, Pos)) = Var - Pos.
+
+:- func project_var_init_inst(module_info, var_mode_pos) =
+    pair(prog_var, inst).
+
+project_var_init_inst(ModuleInfo, var_mode_pos(Var, Mode, _)) = Var - Inst :-
+    mode_get_insts(ModuleInfo, Mode, Inst, _).
+
+:- func project_mode(var_mode_pos) = (mode).
+
+project_mode(var_mode_pos(_, Mode, _)) = Mode.
+
+:- pred allocate_slot_numbers(assoc_list(prog_var, mode)::in, int::in,
+    list(var_mode_pos)::out) is det.
 
 allocate_slot_numbers([], _, []).
-allocate_slot_numbers([Var | Vars], Offset0, [Var - Offset0 | NumberedVars]) :-
-	allocate_slot_numbers(Vars, Offset0 + 1, NumberedVars).
+allocate_slot_numbers([Var - Mode | VarModes], Offset0,
+        [VarModePos | VarModePoss]) :-
+    VarModePos = var_mode_pos(Var, Mode, Offset0),
+    allocate_slot_numbers(VarModes, Offset0 + 1, VarModePoss).
+
+:- pred reallocate_slot_numbers(list(var_mode_pos)::in, int::in,
+    list(var_mode_pos)::out) is det.
+
+reallocate_slot_numbers([], _, []).
+reallocate_slot_numbers([VarModePos0 | VarModes], Offset0,
+        [VarModePos | VarModePoss]) :-
+    VarModePos0 = var_mode_pos(Var, Mode, _),
+    VarModePos = var_mode_pos(Var, Mode, Offset0),
+    reallocate_slot_numbers(VarModes, Offset0 + 1, VarModePoss).
 
-:- pred key_belong_to_list(list(T)::in, pair(T, U)::in) is semidet.
+:- pred var_belong_to_list(list(prog_var)::in, var_mode_pos::in) is semidet.
 
-key_belong_to_list(List, Key - _Value) :-
-	list__member(Key, List).
+var_belong_to_list(List, var_mode_pos(Var, _, _)) :-
+    list__member(Var, List).
 
 :- func bind_vars(list(prog_var)) = instmap_delta.
 
@@ -3226,6 +3237,18 @@
 
 %-----------------------------------------------------------------------------%
 
+:- pred table_gen__var_mode_pos_is_io_state(vartypes::in, var_mode_pos::in)
+    is semidet.
+
+table_gen__var_mode_pos_is_io_state(VarTypes, var_mode_pos(Var, _, _)) :-
+    table_gen__var_is_io_state(VarTypes, Var).
+
+:- pred table_gen__var_mode_is_io_state(vartypes::in, pair(prog_var, mode)::in)
+    is semidet.
+
+table_gen__var_mode_is_io_state(VarTypes, Var - _) :-
+    table_gen__var_is_io_state(VarTypes, Var).
+
 :- pred table_gen__var_is_io_state(vartypes::in, prog_var::in) is semidet.
 
 table_gen__var_is_io_state(VarTypes, Var) :-
@@ -3247,6 +3270,12 @@
 	Attrs0 = default_attributes(c),
 	set_may_call_mercury(will_not_call_mercury, Attrs0, Attrs).
 
+:- func make_generator_c_attributes = pragma_foreign_proc_attributes.
+
+make_generator_c_attributes = Attrs :-
+    Attrs0 = default_attributes(c),
+    set_may_call_mercury(may_call_mercury, Attrs0, Attrs).
+
 :- func dummy_type_var = (type).
 
 dummy_type_var = Type :-
@@ -3305,7 +3334,6 @@
 	pred_info::in, proc_info::in, table_info::out) is det.
 
 :- pred table_info_extract(table_info::in, module_info::out,
-	% pred_id::out, proc_id::out,
 	pred_info::out, proc_info::out) is det.
 
 table_info_init(ModuleInfo, PredInfo, ProcInfo, TableInfo) :-
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
cvs diff: Diffing extras
cvs diff: Diffing extras/aditi
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/concurrency
cvs diff: Diffing extras/curs
cvs diff: Diffing extras/curs/samples
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/error
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/easyx
cvs diff: Diffing extras/graphics/easyx/samples
cvs diff: Diffing extras/graphics/mercury_glut
cvs diff: Diffing extras/graphics/mercury_opengl
cvs diff: Diffing extras/graphics/mercury_tcltk
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/gears
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/graphics/samples/pent
cvs diff: Diffing extras/lazy_evaluation
cvs diff: Diffing extras/lex
cvs diff: Diffing extras/lex/samples
cvs diff: Diffing extras/lex/tests
cvs diff: Diffing extras/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
cvs diff: Diffing extras/moose/tests
cvs diff: Diffing extras/morphine
cvs diff: Diffing extras/morphine/non-regression-tests
cvs diff: Diffing extras/morphine/scripts
cvs diff: Diffing extras/morphine/source
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/quickcheck
cvs diff: Diffing extras/quickcheck/tutes
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/stream
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing extras/xml
cvs diff: Diffing extras/xml/samples
cvs diff: Diffing extras/xml_stylesheets
cvs diff: Diffing java
cvs diff: Diffing java/runtime
cvs diff: Diffing library
Index: library/table_builtin.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/table_builtin.m,v
retrieving revision 1.42
diff -u -b -r1.42 table_builtin.m
--- library/table_builtin.m	16 Aug 2004 03:51:06 -0000	1.42
+++ library/table_builtin.m	1 Jun 2005 03:46:30 -0000
@@ -104,10 +104,12 @@
 
 	% This type represents the interior pointers of both call
 	% tables and answer tables.
+	%
 :- type ml_trie_node.
 
 	% This type represents the blocks we use to store sets of output
 	% arguments.
+	%
 :- type ml_answer_block.
 
 	% N.B. interface continued below
@@ -118,6 +120,7 @@
 
 	% This type represents the interior pointers of both call
 	% tables and answer tables.
+	%
 :- type ml_trie_node --->	ml_trie_node(c_pointer).
 :- pragma foreign_type("C", ml_trie_node, "MR_TrieNode",
 	[can_pass_as_mercury_type]).
@@ -125,6 +128,7 @@
 
 	% This type represents a block of memory that contains one word
 	% for each output argument of a procedure.
+	%
 :- type ml_answer_block --->	ml_answer_block(c_pointer).
 :- pragma foreign_type("C", ml_answer_block, "MR_AnswerBlock",
 	[can_pass_as_mercury_type]).
@@ -140,7 +144,7 @@
 
 	% This type should correspond exactly to the MR_LOOPCHECK_* #defines
 	% in runtime/mercury_tabling.h.
-
+	%
 :- type loop_status
 	--->	loop_inactive
 	;	loop_active.
@@ -152,15 +156,18 @@
 
 	% Mark the call represented by the given table as currently
 	% not being evaluated.
+	%
 :- impure pred table_loop_mark_as_inactive(ml_trie_node::in) is det.
 
 	% Mark the call represented by the given table as currently
 	% not being evaluated, and fail.
+	%
 :- impure pred table_loop_mark_as_inactive_and_fail(ml_trie_node::in)
 	is failure.
 
 	% Mark the call represented by the given table as currently
 	% being evaluated, and fail.
+	%
 :- impure pred table_loop_mark_as_active_and_fail(ml_trie_node::in) is failure.
 
 	% N.B. interface continued below
@@ -246,7 +253,7 @@
 
 	% This type should correspond exactly to the MR_MEMO_DET_* #defines
 	% in runtime/mercury_tabling.h.
-
+	%
 :- type memo_det_status
 	--->	memo_det_inactive
 	;	memo_det_active
@@ -254,7 +261,7 @@
 
 	% This type should correspond exactly to the MR_MEMO_SEMI_* #defines
 	% in runtime/mercury_tabling.h.
-
+	%
 :- type memo_semi_status
 	--->	memo_semi_inactive
 	;	memo_semi_active
@@ -263,7 +270,7 @@
 
 	% This type should correspond exactly to the MR_MemoNonStatus type
 	% in runtime/mercury_tabling.h.
-
+	%
 :- type memo_non_status
 	--->	memo_non_inactive
 	;	memo_non_active
@@ -288,35 +295,43 @@
 	memo_non_record::out, memo_non_status::out) is det.
 
 	% Save the fact that the call has failed in the given table.
+	%
 :- impure pred table_memo_mark_as_failed(ml_trie_node::in) is failure.
 
 	% Save the fact that the call has succeeded in the given table.
+	%
 :- impure pred table_memo_mark_as_succeeded(ml_trie_node::in) is det.
 
 	% Set the status of the given call to incomplete.
+	%
 :- impure pred table_memo_mark_as_incomplete(memo_non_record::in) is det.
 
 	% Set the status of the given call to active, and fail.
+	%
 :- impure pred table_memo_mark_as_active_and_fail(memo_non_record::in)
 	is failure.
 
 	% Set the status of the given call to complete, and fail.
+	%
 :- impure pred table_memo_mark_as_complete_and_fail(memo_non_record::in)
 	is failure.
 
 	% Create an answer block with the given number of slots and add it
 	% to the given table.
+	%
 :- impure pred table_memo_create_answer_block(ml_trie_node::in, int::in,
 	ml_answer_block::out) is det.
 :- impure pred table_memo_fill_answer_block_shortcut(ml_trie_node::in) is det.
 
 	% Return the answer block for the given call.
+	%
 :- semipure pred table_memo_get_answer_block(ml_trie_node::in,
 	ml_answer_block::out) is det.
 :- semipure pred table_memo_get_answer_block_shortcut(ml_trie_node::in) is det.
 
 	% Return the table of answers already returned to the given nondet
 	% table.
+	%
 :- semipure pred table_memo_non_get_answer_table(memo_non_record::in,
 	ml_trie_node::out) is det.
 
@@ -324,16 +339,19 @@
 	% has not been generated before by this subgoal,
 	% succeed and remember the answer as having been generated.
 	% If the answer has been generated before, fail.
+	%
 :- impure pred table_memo_non_answer_is_not_duplicate(ml_trie_node::in)
 	is semidet.
 :- impure pred table_memo_non_answer_is_not_duplicate_shortcut(
 	memo_non_record::in) is semidet.
 
 	% Add an answer block to the given table.
+	%
 :- impure pred table_memo_non_create_answer_block_shortcut(memo_non_record::in)
 	is det.
 
 	% Return all the answer blocks for the given model_non call.
+	%
 :- semipure pred table_memo_return_all_answers_nondet(memo_non_record::in,
 	ml_answer_block::out) is nondet.
 :- semipure pred table_memo_return_all_answers_multi(memo_non_record::in,
@@ -621,7 +639,7 @@
 	% I/O action number Counter is at offset Counter - Start in this array,
 	% where Start is the I/O action number of the first tabled action.
 	% The three output parameters together specify this location.
-
+	%
 :- impure pred table_io_in_range(ml_trie_node::out, int::out, int::out)
 	is semidet.
 
@@ -630,14 +648,14 @@
 	% for a given I/O action number, it returns true iff that action has
 	% been carried out before (i.e. the action is now being reexecuted
 	% after a retry command in the debugger).
-
+	%
 :- impure pred table_io_has_occurred(ml_trie_node::in) is semidet.
 
 	% This predicate simply copies the input I/O state to become the output
 	% I/O state. It is used only because it is easier to get the insts
 	% right by calling this procedure than by hand-writing insts for a
 	% unification.
-
+	%
 :- pred table_io_copy_io_state(io__state::di, io__state::uo) is det.
 
 	% Calls to these predicates bracket the code of foreign_procs with
@@ -648,7 +666,7 @@
 	% contains true.) The right bracket code takes the value returned by
 	% the left bracket as input and restores both globals to the values
 	% they had before the call to the left bracket.
-
+	%
 :- impure pred table_io_left_bracket_unitized_goal(int::out) is det.
 :- impure pred table_io_right_bracket_unitized_goal(int::in) is det.
 
@@ -768,7 +786,7 @@
 
 	% This type should correspond exactly to the type MR_SubgoalStatus
 	% defined in runtime/mercury_tabling.h.
-
+	%
 :- type mm_status
 	--->	mm_inactive
 	;	mm_active
@@ -776,6 +794,7 @@
 
 	% This type represents the data structure at the tips of the call table
 	% in the stack copy implementation of minimal model tabling.
+	%
 :- type ml_subgoal.
 
 	% Check if this minimal_model subgoal has been called before.
@@ -783,6 +802,7 @@
 	% structure, and mark it as active, since the caller is about to become
 	% the subgoal's generator. If yes, return the status currently recorded
 	% in the subgoal structure.
+	%
 :- impure pred table_mm_setup(ml_trie_node::in, ml_subgoal::out,
 	mm_status::out) is det.
 
@@ -790,6 +810,7 @@
 	% when the subgoal has some solutions, table_mm_completion will
 	% restore the saved state. At the time, table_mm_suspend_consumer
 	% will succeed, and return an answer block as its second argument.
+	%
 :- impure pred table_mm_suspend_consumer(ml_subgoal::in, ml_answer_block::out)
 	is nondet.
 
@@ -797,10 +818,12 @@
 	% of the suspended subgoals that depend on it in turn until it reaches
 	% a fixed point, at which all depended suspended subgoals have had
 	% all available answers returned to them.
+	%
 :- impure pred table_mm_completion(ml_subgoal::in) is det.
 
 	% Return the table of answers already returned to the given nondet
 	% table.
+	%
 :- semipure pred table_mm_get_answer_table(ml_subgoal::in, ml_trie_node::out)
 	is det.
 
@@ -808,17 +831,20 @@
 	% has not been generated before by this subgoal,
 	% succeed and remember the answer as having been generated.
 	% If the answer has been generated before, fail.
+	%
 :- impure pred table_mm_answer_is_not_duplicate(ml_trie_node::in) is semidet.
 
 	% Create a new slot in the answer list of the subgoal, create a new
 	% answer block of the given size, and put the answer block in the new
 	% slot.
+	%
 :- impure pred table_mm_create_answer_block(ml_subgoal::in, int::in,
 	ml_answer_block::out) is det.
 
 :- impure pred table_mm_fill_answer_block_shortcut(ml_subgoal::in) is det.
 
 	% Return all of the answer blocks stored in the given table.
+	%
 :- semipure pred table_mm_return_all_nondet(ml_subgoal::in,
 	ml_answer_block::out) is nondet.
 :- semipure pred table_mm_return_all_multi(ml_subgoal::in,
@@ -837,6 +863,7 @@
 :- pragma foreign_type(il,  ml_subgoal, "class [mscorlib]System.Object").
 
 	% This type represents a list of answers of a model_non predicate.
+	%
 :- type ml_answer_list --->	ml_answer_list(c_pointer).
 :- pragma foreign_type("C", ml_answer_list, "MR_AnswerList",
 	[can_pass_as_mercury_type]).
@@ -851,6 +878,7 @@
 
 	% The definitions of these two predicates are in the runtime system,
 	% in runtime/mercury_minimal_model.c.
+	%
 :- external(table_mm_suspend_consumer/2).
 :- external(table_mm_completion/1).
 :- external(table_mm_answer_is_not_duplicate/1).
@@ -919,14 +947,17 @@
 
 	% This type represents the data structure at the tips of the call table
 	% in the own stack implementation of minimal model tabling.
+	%
 :- type ml_consumer.
 
 	% This type represents the generators in the own stack implementation
 	% of minimal model tabling.
+	%
 :- type ml_generator.
 
 	% Save the information that will be needed later about this subgoal
 	% in a temporary data structure in the runtime.
+	%
 :- impure pred table_mmos_save_inputs is det.
 
 	% The given trie node should be at the tip of a call table,
@@ -934,27 +965,50 @@
 	% necessary (if the trie node indicates it has not been called before),
 	% and then register this call as a consumer of the answers of the
 	% generator.
+	%
 :- impure pred table_mmos_setup_consumer(ml_trie_node::in, c_pointer::in,
 	ml_consumer::out) is det.
 
+	% If the answer represented by the given answer table
+	% has not been generated before by this subgoal,
+	% succeed and remember the answer as having been generated.
+	% If the answer has been generated before, fail.
+	%
+:- impure pred table_mmos_answer_is_not_duplicate(ml_trie_node::in) is semidet.
+
 	% This predicate checks whether there is a next answer already listed
 	% for the consumer. If yes, it returns it. If not, it wakes up the
 	% generator to create more answers if possible.
-
+	%
 :- impure pred table_mmos_consume_next_answer_nondet(ml_consumer::in,
 	ml_answer_block::out) is nondet.
 :- impure pred table_mmos_consume_next_answer_multi(ml_consumer::in,
 	ml_answer_block::out) is multi.
 
+	% Return all the answers of a consumers, in extra arguments hung
+	% on a foreign_proc invocation of this predicate.
+	%
+:- semipure pred table_mmos_restore_answers(ml_answer_block::in) is det.
+
+	% Pickup the input arguments of the generator from where the consumer
+	% put them.
+	%
+:- impure pred table_mmos_pickup_inputs(ml_generator::out) is det.
+
+	% Create an answer block of the given size for a new answer of the
+	% given generator.
+	%
 :- impure pred table_mmos_create_answer_block(ml_generator::in,
 	int::in, ml_answer_block::out) is det.
 
 	% Return the base of the answer table trie for the subgoal of the
 	% given generator.
+	%
 :- semipure pred table_mmos_get_answer_table(ml_generator::in,
 	ml_trie_node::out) is det.
 
 	% Return the given answer to the consumer(s) that requested it.
+	%
 :- impure pred table_mmos_return_answer(ml_generator::in, ml_answer_block::in)
 	is det.
 
@@ -962,12 +1016,14 @@
 	% of the suspended subgoals that depend on it in turn until it reaches
 	% a fixed point, at which all depended suspended subgoals have had
 	% all available answers returned to them.
+	%
 :- impure pred table_mmos_completion(ml_generator::in) is det.
 
 :- implementation.
 
 	% This type represents the data structure at the tips of the call table
 	% in the own stack implementation of minimal model tabling.
+	%
 :- type ml_consumer --->	ml_consumer(c_pointer).
 :- pragma foreign_type("C", ml_consumer, "MR_ConsumerPtr",
 	[can_pass_as_mercury_type]).
@@ -975,6 +1031,7 @@
 
 	% This type represents the generators in the own stack implementation
 	% of minimal model tabling.
+	%
 :- type ml_generator --->	ml_generator(c_pointer).
 :- pragma foreign_type("C", ml_generator, "MR_GeneratorPtr",
 	[can_pass_as_mercury_type]).
@@ -1005,14 +1062,55 @@
 	MR_fatal_error(""table_mmos_setup_consumer: direct call"");
 ").
 
+:- pragma foreign_proc("C",
+	table_mmos_answer_is_not_duplicate(T::in),
+	[will_not_call_mercury],
+"
+	/*
+	** The body of this predicate doesn't matter, because it will never be
+	** referred to. When the compiler creates references to this predicate,
+	** it always overrides the predicate body.
+	*/
+	/* mention T to shut up the warning */
+	MR_fatal_error(""table_mmos_answer_is_not_duplicate: direct call"");
+").
+
 :- external(table_mmos_consume_next_answer_nondet/2).
 :- external(table_mmos_consume_next_answer_multi/2).
 
 :- pragma foreign_proc("C",
+	table_mmos_restore_answers(AnswerBlock::in),
+	[will_not_call_mercury, promise_semipure],
+"
+	/*
+	** The body of this predicate doesn't matter, because it will never be
+	** referred to. When the compiler creates references to this predicate,
+	** it always overrides the predicate body.
+	*/
+	/* mention AnswerBlock to shut up the warning */
+	MR_fatal_error(""table_mmos_restore_answers: direct call"");
+").
+
+:- pragma foreign_proc("C",
 	table_mmos_get_answer_table(Generator::in, TrieNode::out),
 	[will_not_call_mercury, promise_semipure],
 "
+	/*
 	MR_table_mmos_get_answer_table(Generator, TrieNode);
+	*/
+").
+
+:- pragma foreign_proc("C",
+	table_mmos_pickup_inputs(Generator::out),
+	[will_not_call_mercury],
+"
+	/*
+	** The body of this predicate doesn't matter, because it will never be
+	** referred to. When the compiler creates references to this predicate,
+	** it always overrides the predicate body.
+	*/
+	/* mention Generator to shut up the warning */
+	MR_fatal_error(""table_mmos_pickup_inputs: direct call"");
 ").
 
 :- pragma foreign_proc("C",
@@ -1020,21 +1118,27 @@
 		AnswerBlock::out),
 	[will_not_call_mercury],
 "
+	/*
 	MR_table_mmos_create_answer_block(Generator, BlockSize, AnswerBlock);
+	*/
 ").
 
 :- pragma foreign_proc("C",
 	table_mmos_return_answer(Generator::in, AnswerBlock::in),
 	[will_not_call_mercury],
 "
+	/*
 	MR_table_mmos_return_answer(Generator, AnswerBlock);
+	*/
 ").
 
 :- pragma foreign_proc("C",
 	table_mmos_completion(Generator::in),
 	[will_not_call_mercury],
 "
+	/*
 	MR_table_mmos_completion(Generator);
+	*/
 ").
 
 table_mmos_save_inputs :-
@@ -1062,7 +1166,9 @@
 	impure private_builtin__imp.
 
 	% Required only to avoid warnings; never executed.
+	%
 :- pred pretend_to_generate_value(T::out) is det.
+
 pretend_to_generate_value(Bogus) :-
 	% The following code will throw an exception if executed.
 	det_univ_to_type(univ(0), Bogus).
@@ -1083,107 +1189,131 @@
 %
 
 	% Lookup or insert an integer in the given table.
+	%
 :- impure pred table_lookup_insert_int(ml_trie_node::in, int::in,
 	ml_trie_node::out) is det.
 
 	% Lookup or insert an integer in the given table.
+	%
 :- impure pred table_lookup_insert_start_int(ml_trie_node::in, int::in,
 	int::in, ml_trie_node::out) is det.
 
 	% Lookup or insert a character in the given trie.
+	%
 :- impure pred table_lookup_insert_char(ml_trie_node::in, character::in,
 	ml_trie_node::out) is det.
 
 	% Lookup or insert a string in the given trie.
+	%
 :- impure pred table_lookup_insert_string(ml_trie_node::in, string::in,
 	ml_trie_node::out) is det.
 
 	% Lookup or insert a float in the current trie.
+	%
 :- impure pred table_lookup_insert_float(ml_trie_node::in, float::in,
 	ml_trie_node::out) is det.
 
 	% Lookup or inert an enumeration type in the given trie.
+	%
 :- impure pred table_lookup_insert_enum(ml_trie_node::in, int::in, T::in,
 	ml_trie_node::out) is det.
 
 	% Lookup or insert a monomorphic user defined type in the given trie.
+	%
 :- impure pred table_lookup_insert_user(ml_trie_node::in, T::in,
 	ml_trie_node::out) is det.
 
 	% Lookup or insert a polymorphic user defined type in the given trie.
+	%
 :- impure pred table_lookup_insert_poly(ml_trie_node::in, T::in,
 	ml_trie_node::out) is det.
 
 	% Lookup or insert a type_info in the given trie.
+	%
 :- impure pred table_lookup_insert_typeinfo(ml_trie_node::in,
 	private_builtin.type_info(T)::in, ml_trie_node::out) is det.
 
 	% Lookup or insert a typeclass_info in the given trie.
+	%
 :- impure pred table_lookup_insert_typeclassinfo(ml_trie_node::in,
 	private_builtin.typeclass_info(T)::in, ml_trie_node::out) is det.
 
 	% Save an integer answer in the given answer block at the given
 	% offset.
+	%
 :- impure pred table_save_int_answer(ml_answer_block::in, int::in, int::in)
 	is det.
 
 	% Save a character answer in the given answer block at the given
 	% offset.
+	%
 :- impure pred table_save_char_answer(ml_answer_block::in, int::in,
 	character::in) is det.
 
 	% Save a string answer in the given answer block at the given
 	% offset.
+	%
 :- impure pred table_save_string_answer(ml_answer_block::in, int::in,
 	string::in) is det.
 
 	% Save a float answer in the given answer block at the given
 	% offset.
+	%
 :- impure pred table_save_float_answer(ml_answer_block::in, int::in, float::in)
 	is det.
 
 	% Save an I/O state in the given answer block at the given offset.
+	%
 :- impure pred table_save_io_state_answer(ml_answer_block::in, int::in,
 	io__state::ui) is det.
 
 	% Save any type of answer in the given answer block at the given
 	% offset.
+	%
 :- impure pred table_save_any_answer(ml_answer_block::in, int::in, T::in)
 	is det.
 
 	% Restore an integer answer from the given answer block at the
 	% given offset.
+	%
 :- semipure pred table_restore_int_answer(ml_answer_block::in, int::in,
 	int::out) is det.
 
 	% Restore a character answer from the given answer block at the
 	% given offset.
+	%
 :- semipure pred table_restore_char_answer(ml_answer_block::in, int::in,
 	character::out) is det.
 
 	% Restore a string answer from the given answer block at the
 	% given offset.
+	%
 :- semipure pred table_restore_string_answer(ml_answer_block::in, int::in,
 	string::out) is det.
 
 	% Restore a float answer from the given answer block at the
 	% given offset.
+	%
 :- semipure pred table_restore_float_answer(ml_answer_block::in, int::in,
 	float::out) is det.
 
 	% Restore an I/O state from the given answer block at the given offset.
+	%
 :- semipure pred table_restore_io_state_answer(ml_answer_block::in, int::in,
 	io__state::uo) is det.
 
 	% Restore any type of answer from the given answer block at the
 	% given offset.
+	%
 :- semipure pred table_restore_any_answer(ml_answer_block::in, int::in, T::out)
 	is det.
 
 	% Report an error message.
+	%
 :- pred table_error(string::in) is erroneous.
 
 	% Report statistics on the operation of the tabling system to stderr.
+	%
 :- impure pred table_report_statistics is det.
 
 %-----------------------------------------------------------------------------%
cvs diff: Diffing mdbcomp
cvs diff: Diffing profiler
cvs diff: Diffing robdd
cvs diff: Diffing runtime
Index: runtime/mercury_conf_param.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_conf_param.h,v
retrieving revision 1.81
diff -u -b -r1.81 mercury_conf_param.h
--- runtime/mercury_conf_param.h	30 Mar 2005 00:54:43 -0000	1.81
+++ runtime/mercury_conf_param.h	3 Jun 2005 03:04:14 -0000
@@ -448,6 +448,22 @@
   #error "MR_THREAD_SAFE and MR_STACK_FRAME_STATS are not supported together"
 #endif
 
+/*
+** Neither form of the minimal model tabling works if the system recovers
+** memory allocated after a choice point when backtracking to that choice
+** point. This rules out the use of the native Mercury collector, as well as
+** the absence of a collector. (This may change for the own stack model,
+** with more work.)
+*/
+
+#if defined(MR_USE_MINIMAL_MODEL_STACK_COPY) && !defined(MR_CONSERVATIVE_GC)
+  #error "MR_USE_MINIMAL_MODEL_OWN_STACKS requires MR_CONSERVATIVE_GC"
+#endif
+
+#if defined(MR_USE_MINIMAL_MODEL_OWN_STACKS) && !defined(MR_CONSERVATIVE_GC)
+  #error "MR_USE_MINIMAL_MODEL_OWN_STACKS requires MR_CONSERVATIVE_GC"
+#endif
+
 #ifdef MR_MINIMAL_MODEL_DEBUG
   #define MR_TABLE_STATISTICS
 #endif
Index: runtime/mercury_context.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_context.h,v
retrieving revision 1.26
diff -u -b -r1.26 mercury_context.h
--- runtime/mercury_context.h	20 Jul 2004 04:41:21 -0000	1.26
+++ runtime/mercury_context.h	1 Jun 2005 03:57:35 -0000
@@ -1,4 +1,7 @@
 /*
+** vim:ts=4 sw=4 expandtab
+*/
+/*
 ** Copyright (C) 1997-2004 The University of Melbourne.
 ** This file may only be copied under the terms of the GNU Library General
 ** Public License - see the file COPYING.LIB in the Mercury distribution.
@@ -10,8 +13,8 @@
 ** A "context" is a Mercury thread.  (We use a different term than "thread"
 ** to avoid confusing Mercury threads and Posix threads.) 
 ** Each context is represented by a value of type MR_Context,
-** which contains a detstack, a nondetstack, a trail, the various pointers
-** that refer to them, a succip, and a thread-resumption continuation. 
+** which contains a detstack, a nondetstack, a trail (if needed), the various
+** pointers that refer to them, a succip, and a thread-resumption continuation. 
 ** Contexts are initally stored in a free-list.
 ** When one is running, the Posix thread that is executing it has a pointer
 ** to its context structure `this_context'. When a context suspends, it
@@ -42,8 +45,8 @@
 #ifndef MERCURY_CONTEXT_H
 #define MERCURY_CONTEXT_H
 
-#include "mercury_regs.h"		/* for MR_hp, etc. Must come before
-					   system headers. */
+#include "mercury_regs.h"       /* for MR_hp, etc. */
+                                /* Must come before system headers. */
 
 #include <stdio.h>
 
@@ -105,19 +108,23 @@
 			/* saved maxfr pointer for this context */
 	MR_Word		*MR_ctxt_curfr;
 			/* saved curfr pointer for this context */
+
   #ifdef MR_USE_MINIMAL_MODEL_STACK_COPY
 	MR_MemoryZone	*MR_ctxt_genstack_zone;
 			/* pointer to the genstack_zone for this context */
 	MR_Integer	MR_ctxt_gen_next;
 			/* saved generator stack index for this context */
+
 	MR_MemoryZone	*MR_ctxt_cutstack_zone;
 			/* pointer to the cutstack_zone for this context */
 	MR_Integer	MR_ctxt_cut_next;
 			/* saved cut stack index for this context */
+
 	MR_MemoryZone	*MR_ctxt_pnegstack_zone;
 			/* pointer to the pnegstack_zone for this context */
 	MR_Integer	MR_ctxt_pneg_next;
 			/* saved pneg stack index for this context */
+
   #endif /* MR_USE_MINIMAL_MODEL_STACK_COPY */
   #ifdef MR_USE_MINIMAL_MODEL_OWN_STACKS
 	MR_Generator	*MR_ctxt_owner_generator;
@@ -207,9 +214,8 @@
 extern	MR_Context 	*MR_create_context(const char *id, MR_Generator *gen);
 
 /*
-** MR_destroy_context(ptr) returns the context structure pointed
-** to by ptr to the free list, and releases resources as
-** necessary.
+** MR_destroy_context(context) returns the pointed-to context structure
+** to the free list, and releases resources as necessary.
 */
 extern	void		MR_destroy_context(MR_Context *context);
 
@@ -226,13 +232,12 @@
 /*
 ** MR_flounder() aborts with a runtime error message. It is called if
 ** the runqueue becomes empty and none of the running processes are
-** working - ie the computation has floundered.
+** working, which means that the computation has floundered.
 */
 extern	void		MR_flounder(void);
 
 /*
-** MR_schedule(MR_Context *cptr):
-**	Append a context onto the end of the run queue.
+** Append the given context onto the end of the run queue.
 */
 
 extern	void		MR_schedule(MR_Context *ctxt);
@@ -362,14 +367,10 @@
 									\
 		load_context_c = (cptr);				\
 		MR_IF_NOT_HIGHLEVEL_CODE(				\
-		  MR_succip_word  = (MR_Word)				\
-		    load_context_c->MR_ctxt_succip;			\
-		  MR_sp_word	= (MR_Word)				\
-		    load_context_c->MR_ctxt_sp;				\
-		  MR_maxfr_word   = (MR_Word)				\
-		    load_context_c->MR_ctxt_maxfr; 			\
-		  MR_curfr_word   = (MR_Word)				\
-		    load_context_c->MR_ctxt_curfr;			\
+            MR_succip_word = (MR_Word) load_context_c->MR_ctxt_succip;  \
+            MR_sp_word     = (MR_Word) load_context_c->MR_ctxt_sp;      \
+            MR_maxfr_word  = (MR_Word) load_context_c->MR_ctxt_maxfr;   \
+            MR_curfr_word  = (MR_Word) load_context_c->MR_ctxt_curfr;   \
 		  MR_IF_USE_MINIMAL_MODEL_STACK_COPY(			\
 		    MR_gen_next = load_context_c->MR_ctxt_gen_next;	\
 		    MR_cut_next = load_context_c->MR_ctxt_cut_next;	\
@@ -379,10 +380,8 @@
 	        MR_IF_USE_TRAIL(					\
 		  MR_trail_zone = load_context_c->MR_ctxt_trail_zone;	\
 		  MR_trail_ptr = load_context_c->MR_ctxt_trail_ptr;	\
-		  MR_ticket_counter =					\
-		    load_context_c->MR_ctxt_ticket_counter;		\
-		  MR_ticket_high_water =				\
-		    load_context_c->MR_ctxt_ticket_high_water;		\
+            MR_ticket_counter = load_context_c->MR_ctxt_ticket_counter; \
+            MR_ticket_high_water = load_context_c->MR_ctxt_ticket_high_water; \
 	    	)							\
 		MR_IF_NOT_HIGHLEVEL_CODE(				\
 		  MR_ENGINE(MR_eng_context).MR_ctxt_detstack_zone =	\
@@ -397,14 +396,11 @@
 		    MR_ENGINE(MR_eng_context).MR_ctxt_pnegstack_zone =  \
 		      load_context_c->MR_ctxt_pnegstack_zone;		\
 		    MR_gen_stack = (MR_GenStackFrame *)			\
-		      MR_ENGINE(MR_eng_context).			\
-		      	MR_ctxt_genstack_zone->min;			\
+                    MR_ENGINE(MR_eng_context).MR_ctxt_genstack_zone->min; \
 		    MR_cut_stack = (MR_CutStackFrame *)			\
-		      MR_ENGINE(MR_eng_context).			\
-		      	MR_ctxt_cutstack_zone->min;			\
+                    MR_ENGINE(MR_eng_context).MR_ctxt_cutstack_zone->min; \
 		    MR_pneg_stack = (MR_PNegStackFrame *)		\
-		      MR_ENGINE(MR_eng_context).			\
-		      	MR_ctxt_pnegstack_zone->min;			\
+                    MR_ENGINE(MR_eng_context).MR_ctxt_pnegstack_zone->min;\
 	    	  )							\
 	    	)							\
 		MR_set_min_heap_reclamation_point(load_context_c);	\
@@ -423,7 +419,7 @@
 		  MR_IF_USE_MINIMAL_MODEL_STACK_COPY(			\
 		    save_context_c->MR_ctxt_gen_next = MR_gen_next;	\
 		    save_context_c->MR_ctxt_cut_next = MR_cut_next;	\
-		    save_context_c->MR_ctxt_pneg_next = MR_pneg_next;\
+                save_context_c->MR_ctxt_pneg_next = MR_pneg_next;       \
 		  )							\
 		)							\
 		MR_IF_USE_TRAIL(					\
Index: runtime/mercury_grade.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_grade.h,v
retrieving revision 1.59
diff -u -b -r1.59 mercury_grade.h
--- runtime/mercury_grade.h	31 Mar 2005 04:44:29 -0000	1.59
+++ runtime/mercury_grade.h	3 Jun 2005 05:07:16 -0000
@@ -17,6 +17,7 @@
 ** IMPORTANT: any changes here may also require changes to
 **	runtime/mercury_conf_param.h
 ** 	scripts/init_grade_options.sh-subr
+** 	scripts/canonical_grade.sh-subr
 ** 	scripts/parse_grade_options.sh-subr
 ** 	scripts/final_grade_options.sh-subr
 ** 	scripts/mgnuc.in
Index: runtime/mercury_mm_own_stacks.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_mm_own_stacks.c,v
retrieving revision 1.2
diff -u -b -r1.2 mercury_mm_own_stacks.c
--- runtime/mercury_mm_own_stacks.c	2 Aug 2004 03:08:25 -0000	1.2
+++ runtime/mercury_mm_own_stacks.c	30 May 2005 06:24:01 -0000
@@ -21,8 +21,14 @@
 
 #ifdef  MR_USE_MINIMAL_MODEL_OWN_STACKS
 
-static  void    make_gen_follow_leader(MR_Generator *this_follower,
-                    MR_Generator *leader);
+MR_Word                 MR_mmos_arg_regs[MR_MAX_FAKE_REG];
+MR_GeneratorPtr         MR_mmos_new_generator;
+
+#if 0
+static  void            MR_table_mmos_make_gen_follow_leader(
+                            MR_GeneratorPtr this_follower,
+                            MR_GeneratorPtr leader);
+#endif
 
 /*---------------------------------------------------------------------------*/
 
@@ -412,27 +418,25 @@
 }
 
 MR_ConsumerPtr
-MR_table_setup_consumer(MR_TableNode trie_node, MR_Integer num_input_args,
-    MR_Word *generator_pred, MR_String pred_id)
+MR_table_mmos_setup_consumer(MR_GeneratorPtr generator, MR_ConstString pred_id)
 {
-    /* not yet implemented */
+    MR_ConsumerPtr  consumer;
+
+    consumer = MR_TABLE_NEW(MR_Consumer);
+    consumer->MR_cons_answer_generator = generator;
+    consumer->MR_cons_containing_generator =
+        MR_ENGINE(MR_eng_this_context)->MR_ctxt_owner_generator;
+    consumer->MR_cons_num_returned_answers = 0;
+    consumer->MR_cons_remaining_answer_list_ptr =
+        generator->MR_gen_answer_list_tail;
+    return consumer;
 }
 
-MR_Generator *
-MR_setup_generator(MR_String pred_id, MR_TrieNode trie_node)
+MR_GeneratorPtr
+MR_table_mmos_setup_generator(MR_TrieNode trie_node, MR_Integer num_input_args,
+    MR_Word generator_pred, MR_ConstString pred_id)
 {
-    /*
-    ** Initialize the generator if this is the first time we see it.
-    ** If the subgoal structure already exists but is marked inactive,
-    ** then it was left by a previous generator that couldn't
-    ** complete the evaluation of the subgoal due to a commit.
-    ** In that case, we want to forget all about the old generator.
-    */
-
-    MR_restore_transient_registers();
-#if 0
-    if (trie_node->MR_generator == NULL) {
-        MR_Generator *gen;
+    MR_GeneratorPtr gen;
         MR_Context   *context;
 
         gen = MR_TABLE_NEW(MR_Generator);
@@ -451,13 +455,13 @@
         /*
         ** MR_subgoal_debug_cur_proc refers to the last procedure
         ** that executed a call event, if any. If the procedure that is
-        ** executing table_nondet_setup is traced, this will be that
+    ** executing table_mmos_setup_consumer is traced, this will be that
         ** procedure, and recording the layout structure of the
         ** processor in the generator allows us to interpret the contents
         ** of the generator's answer tables. If the procedure executing
-        ** table_nondet_setup is not traced, then the layout structure
-        ** belongs to another procedure and the any use of the
-        ** MR_gen_proc_layout field will probably cause a core dump.
+    ** table_mmos_setup_consumer is not traced, then the layout structure
+    ** belongs to another procedure and any use of the MR_gen_proc_layout
+    ** field will probably cause a core dump.
         ** For implementors debugging minimal model tabling, this is
         ** the right tradeoff.
         */
@@ -481,14 +485,13 @@
             MR_fatal_error("MR_maxfr != MR_curfr at table setup\n");
         }
 #endif
-        trie_node->MR_generator = gen;
-    }
 
-#endif
-    return trie_node->MR_generator;
-    MR_save_transient_registers();
+    /* MR_save_transient_registers(); */
+    return gen;
 }
 
+#if 0
+
 MR_AnswerBlock
 MR_table_consumer_get_next_answer(MR_ConsumerPtr consumer)
 {
@@ -506,6 +509,8 @@
 {
     /* not yet implemented */
 }
+
+#endif /* if 0 */
 
 #endif  /* MR_USE_MINIMAL_MODEL_OWN_STACKS */
 
Index: runtime/mercury_mm_own_stacks.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_mm_own_stacks.h,v
retrieving revision 1.2
diff -u -b -r1.2 mercury_mm_own_stacks.h
--- runtime/mercury_mm_own_stacks.h	2 Aug 2004 03:08:25 -0000	1.2
+++ runtime/mercury_mm_own_stacks.h	30 May 2005 06:39:10 -0000
@@ -1,4 +1,7 @@
 /*
+** vim:sw=4 ts=4 expandtab
+*/
+/*
 ** Copyright (C) 2004 The University of Melbourne.
 ** This file may only be copied under the terms of the GNU Library General
 ** Public License - see the file COPYING.LIB in the Mercury distribution.
@@ -25,9 +28,8 @@
 ** The back_ptr field points back to the MR_TrieNode that points to this
 ** generator.
 **
-** The stack_pair field points back to the MR_GenStackPair struct whose
-** MR_gen_pair_gen field points here; it is used to find the generator's
-** stacks.
+** The context field points to the MR_Context struct of the context that holds
+** the state of this generator, including its pair of stacks.
 **
 ** The proc_layout field is set only if debugging is enabled; it allows us
 ** to find out what subgoal we are the generator for, and to interpret
@@ -35,15 +37,18 @@
 **
 ** The pred_id field is currently always set to a string identifying the
 ** main predicate of the subgoal we are the generator for. It is used for
-** debugging. Once this stuff is debugged, we can disable this field.
+** debugging. Once the mmos grade is debugged, we can disable this field.
 **
 ** The leader field points to the leader of the clique this generator belongs
 ** to; if this generator is the leader, this field points to its own structure.
+** Not yet functional.
 **
 ** If this generator is the leader of its clique, the led_generators field will
 ** point to a list of all generators in the clique, including itself. If this
 ** generator is not the leader of its clique, this field will contain an empty
-** list.
+** list. Not yet functional.
+**
+** XXX more fields
 */
 
 struct MR_Generator_Struct {
@@ -58,6 +63,7 @@
 	MR_TableNode		MR_gen_answer_table;
 	MR_AnswerList		MR_gen_answer_list;
 	MR_AnswerList		*MR_gen_answer_list_tail;
+    MR_bool                 MR_gen_is_complete;
 };
 
 struct MR_Consumer_Struct {
@@ -69,6 +75,22 @@
 
 /*---------------------------------------------------------------------------*/
 
+extern  MR_Word         MR_mmos_arg_regs[MR_MAX_FAKE_REG];
+extern  MR_GeneratorPtr MR_mmos_new_generator;
+
+#define MR_mmos_save_input_arg(pos, arg)                                \
+                        do {                                            \
+                            MR_mmos_arg_regs[(pos)] = (arg);            \
+                        } while (0)
+
+#define MR_mmos_pickup_input_arg(pos, arg)                              \
+                        do {                                            \
+                            (arg) = MR_mmos_arg_regs[(pos)];            \
+                        } while (0)
+
+#define MR_table_mmos_get_answer_table(gen)                             \
+                        &(gen)->MR_gen_answer_table;
+
 extern	const MR_Proc_Layout	*MR_subgoal_debug_cur_proc;
 
 extern	void		MR_enter_cons_debug(MR_Consumer *consumer);
@@ -89,24 +111,20 @@
 				const MR_Proc_Layout *proc,
 				MR_GenDebug *gen_debug);
 extern	void		MR_print_generator(FILE *fp,
-				const MR_Proc_Layout *proc,
-				MR_Generator *gen);
+                            const MR_Proc_Layout *proc, MR_Generator *gen);
 extern	void		MR_print_cons_debug(FILE *fp,
 				const MR_Proc_Layout *proc,
 				MR_ConsDebug *consumer_debug);
 extern	void		MR_print_consumer(FILE *fp,
-				const MR_Proc_Layout *proc,
-				MR_Consumer *consumer);
+                            const MR_Proc_Layout *proc, MR_Consumer *consumer);
 
-extern	MR_ConsumerPtr	MR_table_mmos_setup_consumer(MR_TableNode trie_node,
-				MR_Integer num_input_args,
-				MR_Word *generator_pred, MR_String pred_id);
-extern	MR_GeneratorPtr	MR_mmos_setup_generator(MR_String pred_id,
-				MR_TrieNode trie_node);
+extern  MR_ConsumerPtr  MR_table_mmos_setup_consumer(MR_GeneratorPtr generator,
+                            MR_ConstString pred_id);
+extern  MR_GeneratorPtr MR_table_mmos_setup_generator(MR_TrieNode trie_node,
+                            int num_input_args, MR_Word genererator_pred,
+                            MR_ConstString pred_id);
 extern	MR_AnswerBlock	MR_table_mmos_consumer_get_next_answer(
 				MR_ConsumerPtr consumer);
-extern	MR_TrieNode	MR_table_mmos_get_answer_table(MR_GeneratorPtr
-				generator);
 extern	MR_AnswerBlock	MR_table_mmos_create_answer_block(MR_GeneratorPtr
 				generator);
 
Index: runtime/mercury_tabling.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_tabling.h,v
retrieving revision 1.36
diff -u -b -r1.36 mercury_tabling.h
--- runtime/mercury_tabling.h	15 Feb 2005 05:22:32 -0000	1.36
+++ runtime/mercury_tabling.h	26 May 2005 02:04:50 -0000
@@ -155,7 +155,7 @@
 	MR_Unsigned		MR_memo_status;
 	MR_Subgoal		*MR_subgoal;
 	MR_MemoNonRecordPtr	MR_memo_non_record;
-	MR_Consumer		*MR_consumer;
+	MR_GeneratorPtr		MR_generator;
 	MR_AnswerBlock		MR_answerblock;
 	MR_Dlist		*MR_type_table;
 };
Index: runtime/mercury_tabling_preds.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_tabling_preds.h,v
retrieving revision 1.4
diff -u -b -r1.4 mercury_tabling_preds.h
--- runtime/mercury_tabling_preds.h	16 Aug 2004 03:51:09 -0000	1.4
+++ runtime/mercury_tabling_preds.h	27 May 2005 05:24:34 -0000
@@ -771,6 +771,43 @@
         MR_fatal_error(MR_MMSC_ERROR);                                  \
     } while(0)
 
+/***********************************************************************/
+
+#ifdef  MR_TABLE_DEBUG
+  #define MR_table_mmos_answer_is_not_duplicate_msg(T)                    \
+    do {                                                                \
+        if (MR_tabledebug) {                                            \
+            printf("checking if %p is a duplicate answer: %ld\n",       \
+                T, (long) T->MR_integer);                               \
+        }                                                               \
+    } while(0)
+#else
+  #define MR_table_mmos_answer_is_not_duplicate_msg(T)    ((void) 0)
+#endif
+
+#ifdef  MR_TABLE_STATISTICS
+  #define MR_table_mmos_answer_is_not_duplicate_stats(T, is_new_answer) \
+    do {                                                                \
+        MR_mmos_stats_cnt_dupl_check++;                                 \
+        if (is_new_answer) {                                            \
+            MR_mmos_stats_cnt_dupl_check_not_dupl++;                    \
+        }                                                               \
+    } while(0)
+#else
+  #define MR_table_mmos_answer_is_not_duplicate_stats(T, is_new_answer) \
+    ((void) 0)
+#endif
+
+#define MR_table_mmos_answer_is_not_duplicate(T, SUCCESS_INDICATOR)     \
+    do {                                                                \
+        MR_bool     is_new_answer;                                      \
+        MR_table_mmos_answer_is_not_duplicate_msg(T);                   \
+        is_new_answer = (T->MR_integer == 0);                           \
+        MR_table_mmos_answer_is_not_duplicate_stats(T, is_new_answer);  \
+        T->MR_integer = 1;  /* any nonzero value will do */             \
+        SUCCESS_INDICATOR = is_new_answer;                              \
+    } while(0)
+
 #endif  /* MR_USE_MINIMAL_MODEL_STACK_COPY */
 
 /***********************************************************************/
@@ -780,45 +817,12 @@
 #define MR_MMOS_ERROR  \
         "own stack minimal model code entered when not enabled"
 
-#define MR_table_mmos_save_inputs_shortcut(num_inputs)                  \
-    do {                                                                \
-        MR_fatal_error(MR_MMOS_ERROR);                                  \
-    } while(0)
-#define MR_table_mmos_setup_consumer(t, num_inputs, gen_pred, name, consumer) \
-    do {                                                                \
-        MR_fatal_error(MR_MMOS_ERROR);                                  \
-    } while(0)
-#define MR_table_mmos_consume_next_answer_nondet(consumer, answerblock, succ) \
-    do {                                                                \
-        MR_fatal_error(MR_MMOS_ERROR);                                  \
-    } while(0)
-#define MR_table_mmos_get_answer_table(generator, trienode)             \
-    do {                                                                \
-        MR_fatal_error(MR_MMOS_ERROR);                                  \
-    } while(0)
-#define MR_table_mmos_create_answer_block(generator, blocksize, answerblock) \
-    do {                                                                \
-        MR_fatal_error(MR_MMOS_ERROR);                                  \
-    } while(0)
-#define MR_table_mmos_return_answer(generator, answerblock)             \
-    do {                                                                \
-        MR_fatal_error(MR_MMOS_ERROR);                                  \
-    } while(0)
-#define MR_table_mmos_completion(generator)                             \
-    do {                                                                \
-        MR_fatal_error(MR_MMOS_ERROR);                                  \
-    } while(0)
-
 #else   /* MR_USE_MINIMAL_MODEL_OWN_STACKS */
 
 #define MR_MMOS_ERROR  \
         "own stack minimal model code entered when not enabled"
 
 #define MR_table_mmos_save_inputs_shortcut(num_inputs)                  \
-    do {                                                                \
-        MR_fatal_error(MR_MMOS_ERROR);                                  \
-    } while(0)
-#define MR_table_mmos_setup_consumer(t, num_inputs, gen_pred, name, consumer) \
     do {                                                                \
         MR_fatal_error(MR_MMOS_ERROR);                                  \
     } while(0)
cvs diff: Diffing runtime/GETOPT
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing samples/tests
cvs diff: Diffing samples/tests/c_interface
cvs diff: Diffing samples/tests/c_interface/c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/tests/c_interface/mercury_calls_c
cvs diff: Diffing samples/tests/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/tests/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/tests/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/tests/diff
cvs diff: Diffing samples/tests/muz
cvs diff: Diffing samples/tests/rot13
cvs diff: Diffing samples/tests/solutions
cvs diff: Diffing samples/tests/toplevel
cvs diff: Diffing scripts
cvs diff: Diffing slice
cvs diff: Diffing tests
Index: tests/EXPECT_FAIL_TESTS.all_grades
===================================================================
RCS file: tests/EXPECT_FAIL_TESTS.all_grades
diff -N tests/EXPECT_FAIL_TESTS.all_grades
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/EXPECT_FAIL_TESTS.all_grades	2 Jun 2005 11:09:06 -0000
@@ -0,0 +1,2 @@
+valid/constraint_prop_bug
+valid/ho_and_type_spec_bug
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
cvs diff: Diffing tests/debugger/declarative
cvs diff: Diffing tests/dppd
cvs diff: Diffing tests/general
cvs diff: Diffing tests/general/accumulator
cvs diff: Diffing tests/general/string_format
cvs diff: Diffing tests/general/structure_reuse
cvs diff: Diffing tests/grade_subdirs
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/purity
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/mmc_make
cvs diff: Diffing tests/mmc_make/lib
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.204
diff -u -b -r1.204 mercury_trace_internal.c
--- trace/mercury_trace_internal.c	20 May 2005 05:40:37 -0000	1.204
+++ trace/mercury_trace_internal.c	26 May 2005 04:09:50 -0000
@@ -4992,14 +4992,14 @@
             MR_trace_print_subgoal(proc, subgoal);
         }
     } else if (eval_method == MR_EVAL_METHOD_MINIMAL_OWN_STACKS) {
-        MR_Consumer *consumer;
+        MR_GeneratorPtr generator;
 
         fprintf(MR_mdb_out, "trie node %p\n", table);
-        consumer = table->MR_consumer;
-        if (consumer == NULL) {
+        generator = table->MR_generator;
+        if (generator == NULL) {
             fprintf(MR_mdb_out, "uninitialized\n");
         } else {
-            MR_trace_print_consumer(proc, consumer);
+            MR_trace_print_generator(proc, generator);
         }
     } else if (eval_method == MR_EVAL_METHOD_MEMO) {
         MR_Determinism  detism;
@@ -5056,7 +5056,7 @@
     MR_GenDebug *generator_debug)
 {
 #ifdef  MR_USE_MINIMAL_MODEL_OWN_STACKS
-    MR_print_generator_debug(MR_mdb_out, proc, generator_debug);
+    MR_print_gen_debug(MR_mdb_out, proc, generator_debug);
 #else
     fprintf(MR_mdb_out, "minimal model tabling is not enabled\n");
 #endif
@@ -5077,9 +5077,10 @@
 MR_trace_print_consumer_debug(const MR_Proc_Layout *proc,
     MR_ConsumerDebug *consumer_debug)
 {
-#if defined(MR_USE_MINIMAL_MODEL_STACK_COPY) \
-        || defined(MR_USE_MINIMAL_MODEL_OWN_STACKS)
+#if defined(MR_USE_MINIMAL_MODEL_STACK_COPY)
     MR_print_consumer_debug(MR_mdb_out, proc, consumer_debug);
+#elif defined(MR_USE_MINIMAL_MODEL_STACK_COPY)
+    MR_print_cons_debug(MR_mdb_out, proc, consumer_debug);
 #else
     fprintf(MR_mdb_out, "minimal model tabling is not enabled\n");
 #endif
cvs diff: Diffing util
cvs diff: Diffing vim
cvs diff: Diffing vim/after
cvs diff: Diffing vim/ftplugin
cvs diff: Diffing vim/syntax
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list