[m-rev.] diff: major improvements to tabling (part 1 of 2)

Zoltan Somogyi zs at cs.mu.OZ.AU
Tue Jul 20 14:43:39 AEST 2004


Major improvements to tabling, of two types. The first is the implementation
of the loopcheck and memo forms of tabling for model_non procedures, and the
second is a start on the implementation of a new method of implementing
minimal model tabling, one that has the potential for a proper fix of the
problem that we currently merely detect with the pneg stack (the detection
is followed by a runtime abort). Since this new method relies on giving each
own generator its own stack, the grade component denoting it is "mmos"
(minimal model own stack). The true name of the existing method is changed
from "mm" to "mmsc" (minimal model stack copy). The grade component "mm"
is now a shorthand for "mmsc"; when the new method works, "mm" will be changed
to be a shorthand for "mmos".

configure.in:
scripts/canonical_grade.sh-subr:
scripts/init_grade_options.sh-subr:
scripts/parse_grade_options.sh-subr:
scripts/final_grade_options.sh-subr:
compiler/options.m:
	Handle the new way of handling minimal model grades.

scripts/mgnuc.in:
compiler/compile_target_code.m:
	Conform to the changes in minimal model grade options.

compiler/table_gen.m:
	Implement the transformations required by the loopcheck and memo
	tabling of model_non procedures, and the minimal model own stack
	transformation.

	The new implementation transformations use foreign_procs with extra
	args, since there is no point in implementing them both that way and
	with separate calls to library predicates. This required making the
	choice of which method to use at the top level of each transformation.

	Fix an oversight that hasn't caused problems yet but may in the future:
	mark goals wrapping the original goals as not impure for determinism
	computations.

compiler/handle_options.m:
	Handle the new arrangement of the options for minimal model tabling.
	Detect simultaneous calls for both forms of minimal model tabling,
	and generate an error message. Allow for more than one error message
	generated at once; report them all once rather than separately.

compiler/globals.m:
	Add a mechanism to allow a fix a problem detected by the changes
	to handle_options: the fact that we currently may generate a usage
	message more than once for invocations with more than one error.

compiler/mercury_compile.m:
compiler/make.program_target.m:
compiler/make.util.m:
	Use the new mechanism in handle_options to avoid generating duplicate
	usage messages.

compiler/error_util.m:
	Add a utility predicate for use by handle_options.

compiler/hlds_pred.m:
	Allow memo tabling for model_non predicates, and handle own stack
	tabling.

compiler/hlds_out.m:
	Print information about the modes of the arguments of foreign_procs,
	since this is useful in debugging transformations such as tabling
	that generate them.

compiler/prog_data.m:
compiler/layout_out.m:
compiler/prog_out.m:
runtime/mercury_stack_layout.h:
	Mention the new evaluation method.

compiler/goal_util.m:
	Change the predicates for creating calls and foreign_procs to allow
	more than one goal feature to be attached to the new goal. table_gen.m
	now uses this capability.

compiler/add_heap_ops.m:
compiler/add_trail_ops.m:
compiler/polymorphism.m:
compiler/simplify.m:
compiler/size_prof.m:
compiler/typecheck.m:
compiler/unify_proc.m:
	Conform to the changes in goal_util.

compiler/code_info.m:
compiler/make_hlds.m:
compiler/modules.m:
compiler/prog_io_pragma.m:
	Conform to the new the options controlling minimal model
	tabling.

compiler/prog_util.m:
	Add a utility predicate for use by table_gen.m.

library/std_util.m:
	Conform to the changes in the macros for minimal model tabling grades.

library/table_builtin.m:
	Add the types and predicates required by the new transformations.

	Delete an obsolete comment.

runtime/mercury_grade.h:
	Handle the new minimal model grade component.

runtime/mercury_conf_param.h:
	List macros controlling minimal model grades.

runtime/mercury_tabling.[ch]:
	Define the types needed by the new transformations,

	Implement the performance-critical predicates that need to be
	hand-written for memo tabling of model_non predicates.

	Add utility predicates for debugging.

runtime/mercury_tabling_preds.h:
	Add the implementations of the predicates required by the new
	transformations.

runtime/mercury_mm_own_stacks.[ch]:
	This new module contains the first draft of the implementation
	of the own stack implementation of minimal model tabling.

runtime/mercury_imp.h:
	Include the new file if the grade needs it.

runtime/Mmakefile:
	Mention the new files, and sort the lists of filenames.

runtime/mercury_tabling_macros.h:
	Add a macro for allocating answer blocks without requiring them to be
	pointed to directly by trie nodes.

runtime/mercury_minimal_model.[ch]:
	The structure type holding answer lists is now in mercury_tabling.h,
	since it is now also needed by memo tabling of model_non predicates.
	It no longer has a field for an answer num, because while it is ok
	to require a separate grade for debugging minimal model tabling,
	it is not ok to require a separate grade for debugging memo tabling
	of model_non predicates. Instead of printing the answer numbers,
	print the answers themselves when we need to identify solutions
	for debugging.

	Change function names, macro names, error messages etc where this is
	useful to distinguish the two kinds of minimal model tabling.

	Fix some oversights wrt transient registers.

runtime/mercury_context.[ch]:
runtime/mercury_engine.[ch]:
runtime/mercury_memory.[ch]:
runtime/mercury_wrapper.[ch]:
	With own stack tabling, each subgoal has its own context, so record
	the identity of the subgoal owning a context in the context itself.
	The main computation's context is the exception: it has no owner.

	Record not just the main context, but also the contexts of subgoals
	in the engine.

	Add variables for holding the sizes of the det and nondet stacks
	of the contexts of subgoals (which should in general be smaller
	than the sizes of the corresponding stacks of the main context),
	and initialize them as needed.

	Initialize the variables holding the sizes of the gen, cut and pneg
	stacks, even in grades where the stacks are not used, for safety.

	Fix some out-of-date documentation, and conform to our coding
	guidelines.

runtime/mercury_memory_zones.[ch]:
	Add a function to test whether a pointer is in a zone, to help
	debugging.

runtime/mercury_debug.[ch]:
	Add some functions to help debugging in the presence of multiple
	contexts, and factor out some common code to help with this.

	Delete the obsolete, unused function MR_printdetslot_as_label.

runtime/mercury_context.h:
runtime/mercury_bootstrap.h:
	Move a bootstrapping #define from mercury_context.h to
	mercury_bootstrap.h.

runtime/mercury_context.h:
runtime/mercury_bootstrap.h:
	Move a bootstrapping #define from mercury_context.h to
	mercury_bootstrap.h.

runtime/mercury_types.h:
	Add some more forward declarations of type names.

runtime/mercury_dlist.[ch]:
	Rename a field to avoid assignments that dereference NULL.

runtime/mercury_debug.c:
runtime/mercury_memory.c:
runtime/mercury_ml_expand_body.h:
runtime/mercury_stack_trace.c:
runtime/mercury_stacks.[ch]:
trace/mercury_trace_util.c
	Update uses of the macros that control minimal model tabling.

runtime/mercury_stack_trace.c:
	Provide a mechanism to allow stack traces to be suppressed entirely.
	The intention is that by using this mechanism, by the testing system
	won't have to provide separate .exp files for hlc grades, nondebug
	LLDS grades and debug LLDS grades, as we do currently. The mechanism
	is the environment variable MERCURY_SUPPRESS_STACK_TRACE.

tools/bootcheck:
tools/test_mercury:
	Specify MERCURY_SUPPRESS_STACK_TRACE.

trace/mercury_trace.c:
	When performing retries across tabled calls, handle memo tabled
	model_non predicates, for which the call table tip variable holds
	a record with a back pointer to a trie node, instead of the trie node
	itself.

trace/mercury_trace_internal.c:
	When printing tables, handle memo tabled model_non predicates. Delete
	the code now moved to runtime/mercury_tabling.c.

	Add functions for printing the data structures for own stack minimal
	model tabling.

tests/debugger/print_table.{m,inp,exp}:
	Update this test case to also test the printing of tables for
	memo tabled model_non predicates.

tests/debugger/retry.{m,inp,exp}:
	Update this test case to also test retries across memo tabled
	model_non predicates.

tests/tabling/loopcheck_nondet.{m,exp}:
tests/tabling/loopcheck_nondet_non_loop.{m,exp}:
	New test cases to test loopcheck tabled model_non predicates.
	One test case has a loop to detect, one doesn't.

tests/tabling/memo_non.{m,exp}:
tests/tabling/tc_memo.{m,exp}:
tests/tabling/tc_memo2.{m,exp}:
	New test cases to test memo tabled model_non predicates.
	One test case has a loop to detect, one has a need for minimal model
	tabling to detect, and the third doesn't have either.

tests/tabling/Mmakefile:
	Add the new test cases, and reenable the existing tc_loop test case.
	
	Rename some make variables and targets to make them better reflect
	their meaning.

tests/tabling/test_mercury:
	Conform to the change in the name of the make target.

Zoltan.

cvs diff: Diffing .
Index: configure.in
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/configure.in,v
retrieving revision 1.397
diff -u -b -r1.397 configure.in
--- configure.in	16 Jul 2004 12:14:25 -0000	1.397
+++ configure.in	19 Jul 2004 03:40:44 -0000
@@ -2700,8 +2700,8 @@
 
 # add `.mm' (--minimal-model) grades
 if test "$enable_mm_grades" = yes; then
-	LIBGRADES="$LIBGRADES $BEST_LLDS_BASE_GRADE.gc.mm \
-		$BEST_LLDS_BASE_GRADE.gc.mm.debug"
+	LIBGRADES="$LIBGRADES $BEST_LLDS_BASE_GRADE.gc.mmsc \
+		$BEST_LLDS_BASE_GRADE.gc.mmsc.debug"
 fi
 
 # add `.debug' (--debug) grades
@@ -3222,8 +3222,9 @@
 	CFLAGS_FOR_OPT=
 	CFLAGS_FOR_DEBUG="/Zi"
 
-	# Using the MSVC compiler implies that we must use a maximum jump
-	# table size of 512 to avoid a fixed limit in the compiler.
+		# Using the MSVC compiler implies that we must use
+		# a maximum jump table size of 512 to avoid a fixed limit
+		# in the compiler.
 	MCFLAGS_FOR_CC="--max-jump-table-size 512"
 	;;
     cc* | */cc*)
@@ -3319,7 +3320,6 @@
 [\`mmc --linkage static' and \`ml --static' not implemented with
 ****	this C compiler (\`$CC').])
 esac
-
 
 #-----------------------------------------------------------------------------#
 
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/add_heap_ops.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/add_heap_ops.m,v
retrieving revision 1.13
diff -u -b -r1.13 add_heap_ops.m
--- compiler/add_heap_ops.m	14 Jun 2004 04:15:56 -0000	1.13
+++ compiler/add_heap_ops.m	15 Jul 2004 06:53:50 -0000
@@ -157,7 +157,7 @@
 		% relies on, we need to make sure that it can't fail.
 		% So we use a call to `private_builtin__unused' (which
 		% will call error/1) rather than `fail' for the "then" part.
-		generate_call("unused", det, [], no, [], ModuleInfo, Context,
+		generate_call("unused", det, [], [], [], ModuleInfo, Context,
 			ThenGoal)
 	;
 		ThenGoal = Fail
@@ -217,7 +217,7 @@
 		ModuleInfo = !.Info ^ module_info,
 		goal_info_get_context(GoalInfo, Context),
 		generate_call("reclaim_heap_nondet_pragma_foreign_code",
-			erroneous, [], no, [], ModuleInfo, Context,
+			erroneous, [], [], [], ModuleInfo, Context,
 			SorryNotImplementedCode),
 		Goal = SorryNotImplementedCode
 	;
@@ -305,14 +305,14 @@
 
 gen_mark_hp(SavedHeapPointerVar, Context, MarkHeapPointerGoal, !Info) :-
 	generate_call("mark_hp", det, [SavedHeapPointerVar],
-		yes(impure), [SavedHeapPointerVar - ground_inst],
+		[impure], [SavedHeapPointerVar - ground_inst],
 		!.Info ^ module_info, Context, MarkHeapPointerGoal).
 
 :- pred gen_restore_hp(prog_var::in, prog_context::in, hlds_goal::out,
 	heap_ops_info::in, heap_ops_info::out) is det.
 
 gen_restore_hp(SavedHeapPointerVar, Context, RestoreHeapPointerGoal, !Info) :-
-	generate_call("restore_hp", det, [SavedHeapPointerVar], yes(impure),
+	generate_call("restore_hp", det, [SavedHeapPointerVar], [impure],
 		[], !.Info ^ module_info, Context, RestoreHeapPointerGoal).
 
 :- func ground_inst = (inst).
@@ -340,14 +340,14 @@
 %-----------------------------------------------------------------------------%
 
 :- pred generate_call(string::in, determinism::in, list(prog_var)::in,
-	maybe(goal_feature)::in, assoc_list(prog_var, inst)::in,
+	list(goal_feature)::in, assoc_list(prog_var, inst)::in,
 	module_info::in, term__context::in, hlds_goal::out) is det.
 
-generate_call(PredName, Detism, Args, MaybeFeature, InstMap, ModuleInfo,
+generate_call(PredName, Detism, Args, Features, InstMap, ModuleInfo,
 		Context, CallGoal) :-
 	mercury_private_builtin_module(BuiltinModule),
 	goal_util__generate_simple_call(BuiltinModule, PredName, predicate,
-		only_mode, Detism, Args, MaybeFeature, InstMap, ModuleInfo,
+		only_mode, Detism, Args, Features, InstMap, ModuleInfo,
 		Context, CallGoal).
 
 %-----------------------------------------------------------------------------%
Index: compiler/add_trail_ops.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/add_trail_ops.m,v
retrieving revision 1.15
diff -u -b -r1.15 add_trail_ops.m
--- compiler/add_trail_ops.m	14 Jun 2004 04:15:56 -0000	1.15
+++ compiler/add_trail_ops.m	15 Jul 2004 07:07:24 -0000
@@ -145,7 +145,7 @@
 		% will call error/1) rather than `fail' for the "then" part.
 		mercury_private_builtin_module(PrivateBuiltin),
 		generate_simple_call(PrivateBuiltin, "unused", predicate,
-			only_mode, det, [], no, [], ModuleInfo,
+			only_mode, det, [], [], [], ModuleInfo,
 			Context, ThenGoal)
 	;
 		ThenGoal = Fail
@@ -274,7 +274,7 @@
 		ModuleInfo = !.Info^ module_info,
 		goal_info_get_context(GoalInfo, Context),
 		generate_call("trailed_nondet_pragma_foreign_code",
-			erroneous, [], no, [], ModuleInfo, Context,
+			erroneous, [], [], [], ModuleInfo, Context,
 			SorryNotImplementedCode),
 		Goal = SorryNotImplementedCode
 	;
@@ -363,7 +363,7 @@
 	trail_ops_info::in) is det.
 
 gen_store_ticket(TicketVar, Context, SaveTicketGoal, Info) :-
-	generate_call("store_ticket", det, [TicketVar], yes(impure),
+	generate_call("store_ticket", det, [TicketVar], [impure],
 		[TicketVar - ground_inst],
 		Info ^ module_info, Context, SaveTicketGoal).
 
@@ -371,35 +371,35 @@
 	trail_ops_info::in) is det.
 
 gen_reset_ticket_undo(TicketVar, Context, ResetTicketGoal, Info) :-
-	generate_call("reset_ticket_undo", det, [TicketVar], yes(impure),
+	generate_call("reset_ticket_undo", det, [TicketVar], [impure],
 		[], Info ^ module_info, Context, ResetTicketGoal).
 
 :- pred gen_reset_ticket_solve(prog_var::in, prog_context::in, hlds_goal::out,
 	trail_ops_info::in) is det.
 
 gen_reset_ticket_solve(TicketVar, Context, ResetTicketGoal, Info) :-
-	generate_call("reset_ticket_solve", det, [TicketVar], yes(impure),
+	generate_call("reset_ticket_solve", det, [TicketVar], [impure],
 		[], Info ^ module_info, Context, ResetTicketGoal).
 
 :- pred gen_reset_ticket_commit(prog_var::in, prog_context::in, hlds_goal::out,
 	trail_ops_info::in) is det.
 
 gen_reset_ticket_commit(TicketVar, Context, ResetTicketGoal, Info) :-
-	generate_call("reset_ticket_commit", det, [TicketVar], yes(impure),
+	generate_call("reset_ticket_commit", det, [TicketVar], [impure],
 		[], Info ^ module_info, Context, ResetTicketGoal).
 
 :- pred gen_prune_ticket(prog_context::in, hlds_goal::out,
 	trail_ops_info::in) is det.
 
 gen_prune_ticket(Context, PruneTicketGoal, Info) :-
-	generate_call("prune_ticket", det, [], yes(impure),
+	generate_call("prune_ticket", det, [], [impure],
 		[], Info ^ module_info, Context, PruneTicketGoal).
 
 :- pred gen_discard_ticket(prog_context::in, hlds_goal::out,
 	trail_ops_info::in) is det.
 
 gen_discard_ticket(Context, DiscardTicketGoal, Info) :-
-	generate_call("discard_ticket", det, [], yes(impure), [],
+	generate_call("discard_ticket", det, [], [impure], [],
 		Info ^ module_info, Context, DiscardTicketGoal).
 
 :- pred gen_mark_ticket_stack(prog_var::in, prog_context::in, hlds_goal::out,
@@ -408,7 +408,7 @@
 gen_mark_ticket_stack(SavedTicketCounterVar, Context, MarkTicketStackGoal,
 		Info) :-
 	generate_call("mark_ticket_stack", det, [SavedTicketCounterVar],
-		yes(impure), [], Info ^ module_info, Context,
+		[impure], [], Info ^ module_info, Context,
 		MarkTicketStackGoal).
 
 :- pred gen_prune_tickets_to(prog_var::in, prog_context::in, hlds_goal::out,
@@ -417,7 +417,7 @@
 gen_prune_tickets_to(SavedTicketCounterVar, Context, PruneTicketsToGoal,
 		Info) :-
 	generate_call("prune_tickets_to", det, [SavedTicketCounterVar],
-		yes(impure), [], Info ^ module_info, Context,
+		[impure], [], Info ^ module_info, Context,
 		PruneTicketsToGoal).
 
 :- func ground_inst = (inst).
@@ -459,14 +459,14 @@
 %-----------------------------------------------------------------------------%
 
 :- pred generate_call(string::in, determinism::in, list(prog_var)::in,
-	maybe(goal_feature)::in, assoc_list(prog_var, inst)::in,
+	list(goal_feature)::in, assoc_list(prog_var, inst)::in,
 	module_info::in, term__context::in, hlds_goal::out) is det.
 
-generate_call(PredName, Detism, Args, MaybeFeature, InstMap, ModuleInfo,
+generate_call(PredName, Detism, Args, Features, InstMap, ModuleInfo,
 		Context, CallGoal) :-
 	mercury_private_builtin_module(BuiltinModule),
 	goal_util__generate_simple_call(BuiltinModule, PredName, predicate,
-		only_mode, Detism, Args, MaybeFeature, InstMap, ModuleInfo,
+		only_mode, Detism, Args, Features, InstMap, ModuleInfo,
 		Context, CallGoal).
 
 %-----------------------------------------------------------------------------%
Index: compiler/code_info.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/code_info.m,v
retrieving revision 1.290
diff -u -b -r1.290 code_info.m
--- compiler/code_info.m	7 Jun 2004 09:06:30 -0000	1.290
+++ compiler/code_info.m	24 Jun 2004 07:57:52 -0000
@@ -1796,11 +1796,13 @@
 		code_info__create_temp_frame(StackLabel,
 			"prepare for temp frame commit", TempFrameCode, !CI),
 		code_info__get_globals(!.CI, Globals),
-		globals__lookup_bool_option(Globals, use_minimal_model,
-			UseMinimalModel),
-		HijackInfo = commit_temp_frame(MaxfrSlot, UseMinimalModel),
+		globals__lookup_bool_option(Globals,
+			use_minimal_model_stack_copy,
+			UseMinimalModelStackCopy),
+		HijackInfo = commit_temp_frame(MaxfrSlot,
+			UseMinimalModelStackCopy),
 		(
-			UseMinimalModel = yes,
+			UseMinimalModelStackCopy = yes,
 			% If the code we are committing across starts but
 			% does not complete the evaluation of a tabled subgoal,
 			% the cut will remove the generator's choice point,
@@ -1827,7 +1829,7 @@
 					no, no, no, no, no, yes) - ""
 			])
 		;
-			UseMinimalModel = no,
+			UseMinimalModelStackCopy = no,
 			MarkCode = empty
 		),
 		HijackCode = tree(MaxfrCode, tree(TempFrameCode, MarkCode))
Index: compiler/compile_target_code.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/compile_target_code.m,v
retrieving revision 1.60
diff -u -b -r1.60 compile_target_code.m
--- compiler/compile_target_code.m	31 May 2004 04:12:52 -0000	1.60
+++ compiler/compile_target_code.m	24 Jun 2004 08:29:48 -0000
@@ -578,19 +578,43 @@
 	;
 		ReserveTagOpt = ""
 	),
-	globals__io_lookup_bool_option(use_minimal_model, MinimalModel, !IO),
+	globals__io_lookup_bool_option(use_minimal_model_stack_copy,
+		MinimalModelStackCopy, !IO),
+	globals__io_lookup_bool_option(use_minimal_model_own_stacks,
+		MinimalModelOwnStacks, !IO),
+	(
+		MinimalModelStackCopy = yes,
+		MinimalModelOwnStacks = yes,
+		% this should have been caught in handle_options
+		error("compile_c_file: inconsistent minimal model options")
+	;
+		MinimalModelStackCopy = yes,
+		MinimalModelOwnStacks = no,
+		MinimalModelBaseOpt = "-DMR_USE_MINIMAL_MODEL_STACK_COPY "
+	;
+		MinimalModelStackCopy = no,
+		MinimalModelOwnStacks = yes,
+		MinimalModelBaseOpt = "-DMR_USE_MINIMAL_MODEL_OWN_STACKS "
+	;
+		MinimalModelStackCopy = no,
+		MinimalModelOwnStacks = no,
+		MinimalModelBaseOpt = ""
+	),
 	globals__io_lookup_bool_option(minimal_model_debug, MinimalModelDebug,
 		!IO),
-	( MinimalModel = yes ->
 		(
 			MinimalModelDebug = yes,
-			MinimalModelOpt = "-DMR_USE_MINIMAL_MODEL -DMR_MINIMAL_MODEL_DEBUG"
+		( MinimalModelBaseOpt = "" ->
+			% We ignore the debug flag unless one of the base flags
+			% is set.
+			MinimalModelOpt = MinimalModelBaseOpt
 		;
-			MinimalModelDebug = no,
-			MinimalModelOpt = "-DMR_USE_MINIMAL_MODEL "
+			MinimalModelOpt = MinimalModelBaseOpt ++
+				"-DMR_MINIMAL_MODEL_DEBUG"
 		)
 	;
-		MinimalModelOpt = ""
+		MinimalModelDebug = no,
+		MinimalModelOpt = MinimalModelBaseOpt
 	),
 	globals__io_lookup_bool_option(type_layout, TypeLayoutOption, !IO),
 	( TypeLayoutOption = no ->
Index: compiler/error_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/error_util.m,v
retrieving revision 1.27
diff -u -b -r1.27 error_util.m
--- compiler/error_util.m	5 Apr 2004 05:06:46 -0000	1.27
+++ compiler/error_util.m	9 Apr 2004 16:30:36 -0000
@@ -72,6 +72,12 @@
 :- pred write_error_pieces_plain(list(format_component)::in,
 	io::di, io::uo) is det.
 
+	% write_error_plain_with_progname(ProgName, Msg):
+	% Display Msg as the error string, with ProgName as a context
+	% and with standard indentation.
+:- pred write_error_plain_with_progname(string::in, string::in,
+	io::di, io::uo) is det.
+
 	% Display the given error message.
 :- pred write_error_pieces(prog_context::in, int::in,
 	list(format_component)::in, io::di, io::uo) is det.
@@ -174,6 +180,9 @@
 
 write_error_pieces_plain(Components, !IO) :-
 	write_error_pieces_maybe_with_context(yes, no, 0, Components, !IO).
+
+write_error_plain_with_progname(ProgName, Msg, !IO) :-
+	write_error_pieces_plain([fixed(ProgName ++ ":"), words(Msg)], !IO).
 
 write_error_pieces(Context, Indent, Components, !IO) :-
 	write_error_pieces_maybe_with_context(yes, yes(Context),
Index: compiler/globals.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/globals.m,v
retrieving revision 1.61
diff -u -b -r1.61 globals.m
--- compiler/globals.m	14 Jun 2004 04:16:04 -0000	1.61
+++ compiler/globals.m	24 Jun 2004 08:01:27 -0000
@@ -75,11 +75,10 @@
 			% than the Boehm collector, so we don't really
 			% support this option anymore.
 
-	;	accurate
+	;	accurate.
 			% Our own home-grown copying collector.
 			% See runtime/mercury_accurate_gc.c
 			% and compiler/ml_elim_nested.m.
-	.
 
 	% Returns yes if the GC method is conservative,
 	% i.e. if it is `boehm' or `mps'.
@@ -230,6 +229,8 @@
 :- pred globals__io_lookup_accumulating_option(option::in, list(string)::out,
 	io::di, io::uo) is det.
 
+:- pred globals__io_printing_usage(bool::out, io::di, io::uo) is det.
+
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -308,13 +309,14 @@
 			termination_norm 	:: termination_norm,
 			trace_level 		:: trace_level,
 			trace_suppress_items	:: trace_suppress_items,
-			source_file_map		:: maybe(source_file_map)
+			source_file_map		:: maybe(source_file_map),
+			have_printed_usage	:: bool
 		).
 
 globals__init(Options, Target, GC_Method, TagsMethod,
 		TerminationNorm, TraceLevel, TraceSuppress,
 	globals(Options, Target, GC_Method, TagsMethod,
-		TerminationNorm, TraceLevel, TraceSuppress, no)).
+		TerminationNorm, TraceLevel, TraceSuppress, no, no)).
 
 globals__get_options(Globals, Globals ^ options).
 globals__get_target(Globals, Globals ^ target).
@@ -588,4 +590,14 @@
 	{ globals__lookup_accumulating_option(Globals, Option, Value) }.
 
 %-----------------------------------------------------------------------------%
+
+globals__io_printing_usage(AlreadyPrinted, !IO) :-
+	globals__io_get_globals(Globals0, !IO),
+	AlreadyPrinted = Globals0 ^ have_printed_usage,
+	Globals1 = Globals0 ^ have_printed_usage := yes,
+	unsafe_promise_unique(Globals1, Globals),
+		% XXX there is a bit of a design flaw with regard to
+		% uniqueness and io__set_globals
+	globals__io_set_globals(Globals, !IO).
+
 %-----------------------------------------------------------------------------%
Index: compiler/goal_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/goal_util.m,v
retrieving revision 1.96
diff -u -b -r1.96 goal_util.m
--- compiler/goal_util.m	24 Jun 2004 08:04:09 -0000	1.96
+++ compiler/goal_util.m	15 Jul 2004 07:10:45 -0000
@@ -20,7 +20,7 @@
 :- import_module hlds__instmap.
 :- import_module parse_tree__prog_data.
 
-:- import_module assoc_list, bool, list, set, map, term, std_util.
+:- import_module assoc_list, bool, list, set, map, term.
 
 % The predicates rename_var* take a structure and a mapping from var -> var
 % and apply that translation. If a var in the input structure does not
@@ -195,7 +195,7 @@
 	hlds_goal::in, hlds_goal::in) is semidet.
 
 	% generate_simple_call(ModuleName, ProcName, PredOrFunc, ModeNo,
-	%	Detism, Args, MaybeFeature, InstMapDelta, ModuleInfo, Context,
+	%	Detism, Args, Features, InstMapDelta, ModuleInfo, Context,
 	%	CallGoal):
 	%
 	% Generate a call to a builtin procedure (e.g. from the private_builtin
@@ -210,12 +210,12 @@
 	%
 :- pred goal_util__generate_simple_call(module_name::in, string::in,
 	pred_or_func::in, mode_no::in, determinism::in, list(prog_var)::in,
-	maybe(goal_feature)::in, assoc_list(prog_var, inst)::in,
+	list(goal_feature)::in, assoc_list(prog_var, inst)::in,
 	module_info::in, term__context::in, hlds_goal::out) is det.
 
 	% generate_foreign_proc(ModuleName, ProcName, PredOrFunc,
 	%	ModeNo, Detism, Attributes, Args, ExtraArgs, PrefixCode, Code,
-	%	SuffixCode, MaybeFeature, InstMapDelta, ModuleInfo, Context,
+	%	SuffixCode, Features, InstMapDelta, ModuleInfo, Context,
 	%	CallGoal):
 	%
 	% generate_foreign_proc is similar to generate_simple_call,
@@ -231,7 +231,7 @@
 	pred_or_func::in, mode_no::in, determinism::in,
 	pragma_foreign_proc_attributes::in,
 	list(foreign_arg)::in, list(foreign_arg)::in, string::in, string::in,
-	string::in, maybe(goal_feature)::in, assoc_list(prog_var, inst)::in,
+	string::in, list(goal_feature)::in, assoc_list(prog_var, inst)::in,
 	module_info::in, term__context::in, hlds_goal::out) is det.
 
 :- pred goal_util__generate_unsafe_cast(prog_var::in, prog_var::in,
@@ -254,7 +254,7 @@
 :- import_module parse_tree__prog_mode.
 :- import_module parse_tree__prog_util.
 
-:- import_module int, string, require, varset.
+:- import_module int, string, require, varset, std_util.
 
 %-----------------------------------------------------------------------------%
 
@@ -1213,7 +1213,7 @@
 %-----------------------------------------------------------------------------%
 
 goal_util__generate_simple_call(ModuleName, ProcName, PredOrFunc, ModeNo,
-		Detism, Args, MaybeFeature, InstMap, ModuleInfo, Context,
+		Detism, Args, Features, InstMap, ModuleInfo, Context,
 		Goal) :-
 	list__length(Args, Arity),
 	lookup_builtin_pred_proc_id(ModuleInfo, ModuleName, ProcName,
@@ -1240,18 +1240,12 @@
 	pred_info_get_purity(PredInfo, Purity),
 	goal_info_init(NonLocals, InstMapDelta, Detism, Purity, Context,
 		GoalInfo0),
-	(
-		MaybeFeature = yes(Feature),
-		goal_info_add_feature(GoalInfo0, Feature, GoalInfo)
-	;
-		MaybeFeature = no,
-		GoalInfo = GoalInfo0
-	),
+	goal_info_add_features(Features, GoalInfo0, GoalInfo),
 	Goal = GoalExpr - GoalInfo.
 
 goal_util__generate_foreign_proc(ModuleName, ProcName, PredOrFunc, ModeNo,
 		Detism, Attributes, Args, ExtraArgs, PrefixCode, Code,
-		SuffixCode, MaybeFeature, InstMap, ModuleInfo, Context,
+		SuffixCode, Features, InstMap, ModuleInfo, Context,
 		Goal) :-
 	list__length(Args, Arity),
 	lookup_builtin_pred_proc_id(ModuleInfo, ModuleName, ProcName,
@@ -1274,13 +1268,7 @@
 	pred_info_get_purity(PredInfo, Purity),
 	goal_info_init(NonLocals, InstMapDelta, Detism, Purity, Context,
 		GoalInfo0),
-	(
-		MaybeFeature = yes(Feature),
-		goal_info_add_feature(GoalInfo0, Feature, GoalInfo)
-	;
-		MaybeFeature = no,
-		GoalInfo = GoalInfo0
-	),
+	goal_info_add_features(Features, GoalInfo0, GoalInfo),
 	Goal = GoalExpr - GoalInfo.
 
 generate_unsafe_cast(InArg, OutArg, Context, Goal) :-
Index: compiler/handle_options.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.207
diff -u -b -r1.207 handle_options.m
--- compiler/handle_options.m	30 Jun 2004 02:47:59 -0000	1.207
+++ compiler/handle_options.m	30 Jun 2004 03:04:03 -0000
@@ -21,10 +21,10 @@
 :- import_module libs__globals.
 :- import_module libs__options.
 
-:- import_module list, bool, getopt, std_util, io.
+:- import_module list, bool, getopt, io.
 
-	% handle_options(Args, MaybeError, OptionArgs, NonOptionArgs, Link).
-:- pred handle_options(list(string)::in, maybe(string)::out, list(string)::out,
+	% handle_options(Args, Errors, OptionArgs, NonOptionArgs, Link).
+:- pred handle_options(list(string)::in, list(string)::out, list(string)::out,
 	list(string)::out, bool::out, io::di, io::uo) is det.
 
 	% process_options(Args, OptionArgs, NonOptionArgs, MaybeOptionTable).
@@ -35,16 +35,10 @@
 :- pred process_options(list(string)::in, list(string)::out, list(string)::out,
 	maybe_option_table(option)::out) is det.
 
-	% usage_error(Descr, Message)
+	% usage_errors(Message)
 	%
-	% Display the description of the error location, the error message
-	% and then a usage message.
-:- pred usage_error(string::in, string::in, io::di, io::uo) is det.
-
-	% usage_error(Message)
-	%
-	% Display error message and then usage message
-:- pred usage_error(string::in, io::di, io::uo) is det.
+	% Display given list of error messages and then the usage message.
+:- pred usage_errors(list(string)::in, io::di, io::uo) is det.
 
 	% Display usage message.
 :- pred usage(io::di, io::uo) is det.
@@ -74,18 +68,20 @@
 :- import_module parse_tree__error_util.
 :- import_module parse_tree__prog_io_util.
 
-:- import_module char, dir, int, string, map, set, library.
+:- import_module char, dir, int, string, map, set, std_util, library.
 
-handle_options(Args0, MaybeError, OptionArgs, Args, Link) -->
+handle_options(Args0, Errors, OptionArgs, Args, Link) -->
 	% io__write_string("original arguments\n"),
 	% dump_arguments(Args0),
 	{ process_options(Args0, OptionArgs, Args, Result) },
 	% io__write_string("final arguments\n"),
 	% dump_arguments(Args),
-	postprocess_options(Result, MaybeError),
-	( { MaybeError = yes(_) } ->
+	postprocess_options(Result, Errors),
+	(
+		{ Errors = [_ | _] },
 		{ Link = no }
 	;
+		{ Errors = [] },
 		globals__io_lookup_bool_option(generate_dependencies,
 			GenerateDependencies),
 		globals__io_lookup_bool_option(make_interface, MakeInterface),
@@ -146,20 +142,20 @@
 % and process implications among the options (i.e. situations where setting
 % one option implies setting/unsetting another one).
 
-:- pred postprocess_options(maybe_option_table(option)::in, maybe(string)::out,
-	io::di, io::uo) is det.
+:- pred postprocess_options(maybe_option_table(option)::in,
+	list(string)::out, io::di, io::uo) is det.
 
-postprocess_options(error(ErrorMessage), yes(ErrorMessage), !IO).
-postprocess_options(ok(OptionTable0), MaybeError, !IO) :-
+postprocess_options(error(ErrorMessage), [ErrorMessage], !IO).
+postprocess_options(ok(OptionTable0), Errors, !IO) :-
 	check_option_values(OptionTable0, OptionTable, Target, GC_Method,
-		TagsMethod, TermNorm, TraceLevel, TraceSuppress, [], Errors),
-	( Errors = [] ->
+		TagsMethod, TermNorm, TraceLevel, TraceSuppress,
+		[], CheckErrors),
+	( CheckErrors = [] ->
 		postprocess_options_2(OptionTable, Target, GC_Method,
 			TagsMethod, TermNorm, TraceLevel, TraceSuppress,
-			MaybeError, !IO)
+			[], Errors, !IO)
 	;
-		Error = string__join_list("\n", Errors),
-		MaybeError = yes(Error)
+		Errors = CheckErrors
 	).
 
 :- pred check_option_values(option_table::in, option_table::out,
@@ -289,11 +285,11 @@
 
 :- pred postprocess_options_2(option_table::in, compilation_target::in,
 	gc_method::in, tags_method::in, termination_norm::in,
-	trace_level::in, trace_suppress_items::in, maybe(string)::out,
-	io::di, io::uo) is det.
+	trace_level::in, trace_suppress_items::in,
+	list(string)::in, list(string)::out, io::di, io::uo) is det.
 
 postprocess_options_2(OptionTable0, Target, GC_Method, TagsMethod0,
-		TermNorm, TraceLevel, TraceSuppress, Error) -->
+		TermNorm, TraceLevel, TraceSuppress, !Errors) -->
 	{ unsafe_promise_unique(OptionTable0, OptionTable1) }, % XXX
 	globals__io_init(OptionTable1, Target, GC_Method, TagsMethod0,
 		TermNorm, TraceLevel, TraceSuppress),
@@ -717,16 +713,37 @@
 	% --split-c-files implies --procs-per-c-function 1
 	option_implies(split_c_files, procs_per_c_function, int(1)),
 
-	% Minimal model tabling is not compatible with trailing;
-	% see the comment in runtime/mercury_tabling.c.
+	% Minimal model tabling is not compatible with high level code
+	% or with trailing; see the comments in runtime/mercury_grade.h.
 
 	globals__io_lookup_bool_option(use_trail, UseTrail),
-	globals__io_lookup_bool_option(use_minimal_model, UseMinimalModel),
-	{ UseTrail = yes, UseMinimalModel = yes ->
-		Error = yes("trailing and minimal model tabling " ++
-			"are not compatible")
+	globals__io_lookup_bool_option(highlevel_code, HighLevel),
+	globals__io_lookup_bool_option(use_minimal_model_stack_copy,
+		UseMinimalModelStackCopy),
+	globals__io_lookup_bool_option(use_minimal_model_own_stacks,
+		UseMinimalModelOwnStacks),
+	{ bool__or(UseMinimalModelStackCopy, UseMinimalModelOwnStacks,
+		UseMinimalModel) },
+	{
+		UseMinimalModelStackCopy = yes,
+		UseMinimalModelOwnStacks = yes
+	->
+		add_error("can't use both forms of minimal model tabling " ++
+			"at once", !Errors)
+	;
+		UseMinimalModel = yes,
+		HighLevel = yes
+	->
+		add_error("minimal model tabling is incompatible "
+			++ "with high level code", !Errors)
 	;
-		Error = no
+		UseMinimalModel = yes,
+		UseTrail = yes
+	->
+		add_error("minimal model tabling is incompatible " ++
+			"with trailing", !Errors)
+	;
+		true
 	},
 
 	option_implies(target_debug, strip, bool(no)),
@@ -865,7 +882,6 @@
 
 	option_implies(profile_deep, procid_stack_layout, bool(yes)),
 	globals__io_lookup_bool_option(profile_deep, ProfileDeep),
-	globals__io_lookup_bool_option(highlevel_code, HighLevel),
 	( { ProfileDeep = yes } ->
 		(
 			{ HighLevel = no },
@@ -873,7 +889,8 @@
 		->
 			[]
 		;
-			usage_error("deep profiling is incompatible with high level code")
+			{ add_error("deep profiling is incompatible " ++
+				"with high level code", !Errors) }
 		),
 		globals__io_lookup_bool_option(
 			use_lots_of_ho_specialization, LotsOfHOSpec),
@@ -897,15 +914,16 @@
 		{ RecordTermSizesAsWords = yes },
 		{ RecordTermSizesAsCells = yes }
 	->
-		usage_error("we can't record term size as both words and cells")
+		{ add_error("we can't record term size " ++
+			"as both words and cells", !Errors) }
 	;
 		{ RecordTermSizesAsWords = yes
 		; RecordTermSizesAsCells = yes
 		},
 		{ HighLevel = yes }
 	->
-		usage_error("term size profiling is incompatible "
-			++ "with high level code")
+		{ add_error("term size profiling is incompatible "
+			++ "with high level code", !Errors) }
 	;
 		[]
 	),
@@ -918,7 +936,8 @@
 	->
 		[]
 	;
-		usage_error("debugging is available only in low level C grades")
+		{ add_error("debugging is available only in " ++
+			"low level C grades", !Errors) }
 	),
 
 	% The pthreads headers on some architectures (Solaris, Linux)
@@ -1012,8 +1031,8 @@
 		{ GC_Method = accurate },
 		{ PutNondetEnvOnHeap = yes }
 	->
-		usage_error("--gc accurate is incompatible with " ++
-			"--put-nondet-env-on-heap")
+		{ add_error("--gc accurate is incompatible with " ++
+			"--put-nondet-env-on-heap", !Errors) }
 	;
 		[]
 	),
@@ -1046,14 +1065,14 @@
 	% negation, disjunction, or commit.
 	option_implies(use_trail, middle_rec, bool(no)),
 
-	% Minimal model tabling needs to be able to rewrite all the redoips
-	% in a given nondet stack segments. If we allow hijacks, some of these
-	% redoips may have been saved in ordinary framevars, which means that
-	% tabling can't find them without label layout info. Since we want
-	% to allow tabling in grades that do not have label layout info,
-	% we disable hijacks instead.
+	% Stack copy minimal model tabling needs to be able to rewrite all
+	% the redoips in a given nondet stack segments. If we allow hijacks,
+	% some of these redoips may have been saved in ordinary framevars,
+	% which means that tabling can't find them without label layout info.
+	% Since we want to allow tabling in grades that do not have label
+	% layout info, we disable hijacks instead.
 	% XXX we should allow hijacks in table_builtin.m
-	option_implies(use_minimal_model, allow_hijacks, bool(no)),
+	option_implies(use_minimal_model_stack_copy, allow_hijacks, bool(no)),
 
 	% --dump-hlds and --statistics require compilation by phases
 	globals__io_lookup_accumulating_option(dump_hlds, DumpStages),
@@ -1310,11 +1329,15 @@
 	% and --optimize-tailcalls.  It also doesn't work if you use
 	% --errorcheck-only.
 	option_requires(warn_non_tail_recursion, highlevel_code, bool(yes),
-		"--warn-non-tail-recursion requires --high-level-code"),
+		"--warn-non-tail-recursion requires --high-level-code",
+		!Errors),
 	option_requires(warn_non_tail_recursion, optimize_tailcalls, bool(yes),
-		"--warn-non-tail-recursion requires --optimize-tailcalls"),
+		"--warn-non-tail-recursion requires --optimize-tailcalls",
+		!Errors),
 	option_requires(warn_non_tail_recursion, errorcheck_only, bool(no),
-		"--warn-non-tail-recursion is incompatible with --errorcheck-only"),
+		"--warn-non-tail-recursion is incompatible with " ++
+		"--errorcheck-only",
+		!Errors),
 
 	% The backend foreign languages depend on the target.
 	(
@@ -1438,20 +1461,20 @@
 	).
 
 % option_requires(SourceBoolOption, RequiredOption, RequiredOptionValue,
-%	ErrorMsg):
+%	ErrorMsg, !Errors):
 % If the SourceBoolOption is set to yes, and RequiredOption is not set
-% to RequiredOptionValue, then report a usage error.
-:- pred option_requires(option::in, option::in, option_data::in,
-	string::in, io::di, io::uo) is det.
+% to RequiredOptionValue, then add the given error message to the list.
+:- pred option_requires(option::in, option::in, option_data::in, string::in,
+	list(string)::in, list(string)::out, io::di, io::uo) is det.
 
 option_requires(SourceOption, RequiredOption, RequiredOptionValue,
-		ErrorMessage) -->
-	globals__io_lookup_bool_option(SourceOption, SourceOptionValue),
-	globals__io_lookup_option(RequiredOption, OptionValue),
-	( { SourceOptionValue = yes, OptionValue \= RequiredOptionValue } ->
-		usage_error(ErrorMessage)
+		ErrorMessage, !Errors, !IO) :-
+	globals__io_lookup_bool_option(SourceOption, SourceOptionValue, !IO),
+	globals__io_lookup_option(RequiredOption, OptionValue, !IO),
+	( SourceOptionValue = yes, OptionValue \= RequiredOptionValue ->
+		add_error(ErrorMessage, !Errors)
 	;
-		[]
+		true
 	).
 
 	% Smart recompilation does not yet work with all
@@ -1480,8 +1503,8 @@
 	globals__io_lookup_bool_option(warn_smart_recompilation,
 		WarnSmart),
 	( { WarnSmart = yes } ->
-		io__write_string(
-	"Warning: smart recompilation does not yet work with "),
+		io__write_string("Warning: smart recompilation " ++
+			"does not yet work with "),
 		io__write_string(OptionDescr),
 		io__write_string(".\n"),
 		globals__io_lookup_bool_option(halt_at_warn, Halt),
@@ -1494,36 +1517,33 @@
 		[]
 	).
 
-usage_error(ErrorDescr, ErrorMessage, !IO) :-
-	write_program_name(!IO),
-	io__write_string(ErrorDescr, !IO),
-	io__nl(!IO),
-	usage_error(ErrorMessage, !IO).
-
-usage_error(ErrorMessage, !IO) :-
-	write_program_name(!IO),
-	io__write_string(ErrorMessage, !IO),
-	io__write_string("\n", !IO),
+usage_errors(Errors, !IO) :-
+	io__progname_base("mercury_compile", ProgName, !IO),
+	list__foldl(write_error_plain_with_progname(ProgName), Errors, !IO),
 	io__set_exit_status(1, !IO),
 	usage(!IO).
 
-:- pred write_program_name(io__state::di, io__state::uo) is det.
-
-write_program_name(!IO) :-
-	io__progname_base("mercury_compile", ProgName, !IO),
-	io__write_string(ProgName, !IO),
-	io__write_string(": ", !IO).
-
 usage(!IO) :-
+	% usage is called from many places; ensure that we don't print the
+	% duplicate copies of the message.
+	globals__io_printing_usage(AlreadyPrinted, !IO),
+	(
+		AlreadyPrinted = no,
 	library__version(Version),
  	io__write_strings([
 		"Mercury Compiler, version ", Version, "\n",
 		"Copyright (C) 1993-2004 The University of Melbourne\n",
 		"Usage: mmc [<options>] <arguments>\n",
 		"Use `mmc --help' for more information.\n"
-	], !IO).
+		], !IO)
+	;
+		AlreadyPrinted = yes
+	).
 
 long_usage(!IO) :-
+	% long_usage is called from only one place, so can't print duplicate
+	% copies of the long usage message. We can print both a short and along
+	% usage message, but there is no simple way to avoid that.
 	library__version(Version),
  	io__write_strings(["Mercury Compiler, version ", Version, "\n"], !IO),
  	io__write_string("Copyright (C) 1993-2004 " ++
@@ -1573,8 +1593,7 @@
 	;	minimal_model	% whether we set up for minimal model tabling
 	;	pic		% Do we need to reserve a register for
 				% PIC (position independent code)?
-	;	trace		% tracing/debugging options
-	.
+	;	trace.		% tracing/debugging options
 
 convert_grade_option(GradeString, Options0, Options) :-
 	reset_grade_options(Options0, Options1),
@@ -1840,9 +1859,29 @@
 
 	% Mimimal model tabling components
 grade_component_table("mm", minimal_model,
-	[use_minimal_model - bool(yes), minimal_model_debug - bool(no)], no).
+	[use_minimal_model_stack_copy - bool(yes),
+	use_minimal_model_own_stacks - bool(no),
+	minimal_model_debug - bool(no)], no).
 grade_component_table("dmm", minimal_model,
-	[use_minimal_model - bool(yes), minimal_model_debug - bool(yes)], no).
+	[use_minimal_model_stack_copy - bool(yes),
+	use_minimal_model_own_stacks - bool(no),
+	minimal_model_debug - bool(yes)], no).
+grade_component_table("mmsc", minimal_model,
+	[use_minimal_model_stack_copy - bool(yes),
+	use_minimal_model_own_stacks - bool(no),
+	minimal_model_debug - bool(no)], no).
+grade_component_table("dmmsc", minimal_model,
+	[use_minimal_model_stack_copy - bool(yes),
+	use_minimal_model_own_stacks - bool(no),
+	minimal_model_debug - bool(yes)], no).
+grade_component_table("mmos", minimal_model,
+	[use_minimal_model_stack_copy - bool(no),
+	use_minimal_model_own_stacks - bool(yes),
+	minimal_model_debug - bool(no)], no).
+grade_component_table("dmmos", minimal_model,
+	[use_minimal_model_stack_copy - bool(no),
+	use_minimal_model_own_stacks - bool(yes),
+	minimal_model_debug - bool(yes)], no).
 
 	% Pic reg components
 grade_component_table("picreg", pic, [pic_reg - bool(yes)], no).
@@ -1878,7 +1917,8 @@
 grade_start_values(profile_memory - bool(no)).
 grade_start_values(use_trail - bool(no)).
 grade_start_values(reserve_tag - bool(no)).
-grade_start_values(use_minimal_model - bool(no)).
+grade_start_values(use_minimal_model_stack_copy - bool(no)).
+grade_start_values(use_minimal_model_own_stacks - bool(no)).
 grade_start_values(minimal_model_debug - bool(no)).
 grade_start_values(pic_reg - bool(no)).
 grade_start_values(exec_trace - bool(no)).
Index: compiler/hlds_out.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_out.m,v
retrieving revision 1.336
diff -u -b -r1.336 hlds_out.m
--- compiler/hlds_out.m	30 Jun 2004 02:48:00 -0000	1.336
+++ compiler/hlds_out.m	17 Jul 2004 08:54:16 -0000
@@ -261,6 +261,7 @@
 
 % Parse tree modules.
 :- import_module parse_tree__mercury_to_mercury.
+:- import_module parse_tree__prog_mode.
 :- import_module parse_tree__prog_out.
 :- import_module parse_tree__prog_util.
 
@@ -1936,8 +1937,16 @@
 	Arg = foreign_arg(Var, MaybeNameMode, Type),
 	mercury_output_var(Var, VarSet, AppendVarNums, !IO),
 	(
-		MaybeNameMode = yes(Name - _),
-		io__write_string("/" ++ Name, !IO)
+		MaybeNameMode = yes(Name - Mode),
+		io__write_string("/" ++ Name ++ "(", !IO),
+		( Mode = in_mode ->
+			io__write_string("in", !IO)
+		; Mode = out_mode ->
+			io__write_string("out", !IO)
+		;
+			io__write(Mode, !IO)
+		),
+		io__write_string(")", !IO)
 	;
 		MaybeNameMode = no
 	),
Index: compiler/hlds_pred.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_pred.m,v
retrieving revision 1.149
diff -u -b -r1.149 hlds_pred.m
--- compiler/hlds_pred.m	19 Jul 2004 03:37:45 -0000	1.149
+++ compiler/hlds_pred.m	19 Jul 2004 03:40:47 -0000
@@ -2935,27 +2935,22 @@
 
 valid_determinism_for_eval_method(eval_normal, _) = yes.
 valid_determinism_for_eval_method(eval_loop_check, Detism) = Valid :-
-	% We can't handle at_most_many because we don't mark the subgoal
-	% as active again when we backtrack into it.
 	determinism_components(Detism, _, MaxSoln),
-	( ( MaxSoln = at_most_one ; MaxSoln = at_most_many_cc ) ->
-		Valid = yes
-	;
+	( MaxSoln = at_most_zero ->
 		Valid = no
+	;
+		Valid = yes
 	).
 valid_determinism_for_eval_method(eval_memo, Detism) = Valid :-
-	% We can't handle at_most_many because the memoing data structures
-	% cannot record more than one answer, and the minimal model data
-	% structures are unsuitable.
 	determinism_components(Detism, _, MaxSoln),
-	( ( MaxSoln = at_most_one ; MaxSoln = at_most_many_cc ) ->
-		Valid = yes
-	;
+	( MaxSoln = at_most_zero ->
 		Valid = no
+	;
+		Valid = yes
 	).
 valid_determinism_for_eval_method(eval_table_io(_, _), _) = _ :-
 	error("valid_determinism_for_eval_method called after tabling phase").
-valid_determinism_for_eval_method(eval_minimal, Detism) = Valid :-
+valid_determinism_for_eval_method(eval_minimal(_), Detism) = Valid :-
 	% Determinism analysis isn't yet smart enough to know whether
 	% a cannot_fail execution path is guaranteed not to go through
 	% a call to a predicate that is mutually recursive with this one,
@@ -2974,37 +2969,37 @@
 eval_method_needs_stratification(eval_loop_check) = no.
 eval_method_needs_stratification(eval_table_io(_, _)) = no.
 eval_method_needs_stratification(eval_memo) = no.
-eval_method_needs_stratification(eval_minimal) = yes.
+eval_method_needs_stratification(eval_minimal(_)) = yes.
 
 eval_method_has_per_proc_tabling_pointer(eval_normal) = no.
 eval_method_has_per_proc_tabling_pointer(eval_loop_check) = yes.
 eval_method_has_per_proc_tabling_pointer(eval_table_io(_, _)) = no.
 eval_method_has_per_proc_tabling_pointer(eval_memo) = yes.
-eval_method_has_per_proc_tabling_pointer(eval_minimal) = yes.
+eval_method_has_per_proc_tabling_pointer(eval_minimal(_)) = yes.
 
 eval_method_requires_tabling_transform(eval_normal) = no.
 eval_method_requires_tabling_transform(eval_loop_check) = yes.
 eval_method_requires_tabling_transform(eval_table_io(_, _)) = yes.
 eval_method_requires_tabling_transform(eval_memo) = yes.
-eval_method_requires_tabling_transform(eval_minimal) = yes.
+eval_method_requires_tabling_transform(eval_minimal(_)) = yes.
 
 eval_method_requires_ground_args(eval_normal) = no.
 eval_method_requires_ground_args(eval_loop_check) = yes.
 eval_method_requires_ground_args(eval_table_io(_, _)) = yes.
 eval_method_requires_ground_args(eval_memo) = yes.
-eval_method_requires_ground_args(eval_minimal) = yes.
+eval_method_requires_ground_args(eval_minimal(_)) = yes.
 
 eval_method_destroys_uniqueness(eval_normal) = no.
 eval_method_destroys_uniqueness(eval_loop_check) = yes.
 eval_method_destroys_uniqueness(eval_table_io(_, _)) = no.
 eval_method_destroys_uniqueness(eval_memo) = yes.
-eval_method_destroys_uniqueness(eval_minimal) = yes.
+eval_method_destroys_uniqueness(eval_minimal(_)) = yes.
 
 eval_method_change_determinism(eval_normal, Detism) = Detism.
 eval_method_change_determinism(eval_loop_check, Detism) = Detism.
 eval_method_change_determinism(eval_table_io(_, _), Detism) = Detism.
 eval_method_change_determinism(eval_memo, Detism) = Detism.
-eval_method_change_determinism(eval_minimal, Detism0) = Detism :-
+eval_method_change_determinism(eval_minimal(_), Detism0) = Detism :-
 	det_conjunction_detism(semidet, Detism0, Detism).
 
 %-----------------------------------------------------------------------------%
Index: compiler/ite_gen.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/ite_gen.m,v
retrieving revision 1.75
diff -u -b -r1.75 ite_gen.m
--- compiler/ite_gen.m	14 Jun 2004 04:16:11 -0000	1.75
+++ compiler/ite_gen.m	24 Jun 2004 07:57:55 -0000
@@ -403,10 +403,10 @@
 
 make_pneg_context_wrappers(Globals, PNegCondCode, PNegThenCode, PNegElseCode)
 		:-
-	globals__lookup_bool_option(Globals, use_minimal_model,
-		UseMinimalModel),
+	globals__lookup_bool_option(Globals, use_minimal_model_stack_copy,
+		UseMinimalModelStackCopy),
 	(
-		UseMinimalModel = yes,
+		UseMinimalModelStackCopy = yes,
 
 		PNegCondComponents = [
 			pragma_c_raw_code(
@@ -436,7 +436,7 @@
 				no, no, no, no, yes, yes) - ""
 		])
 	;
-		UseMinimalModel = no,
+		UseMinimalModelStackCopy = no,
 		PNegCondCode = empty,
 		PNegThenCode = empty,
 		PNegElseCode = empty
Index: compiler/layout_out.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/layout_out.m,v
retrieving revision 1.35
diff -u -b -r1.35 layout_out.m
--- compiler/layout_out.m	7 Jun 2004 09:06:47 -0000	1.35
+++ compiler/layout_out.m	24 Jun 2004 07:57:55 -0000
@@ -896,7 +896,14 @@
 eval_method_to_c_string(eval_normal) =	      "MR_EVAL_METHOD_NORMAL".
 eval_method_to_c_string(eval_loop_check) =    "MR_EVAL_METHOD_LOOP_CHECK".
 eval_method_to_c_string(eval_memo) =          "MR_EVAL_METHOD_MEMO".
-eval_method_to_c_string(eval_minimal) =	      "MR_EVAL_METHOD_MINIMAL".
+eval_method_to_c_string(eval_minimal(MinimalMethod)) = Str :-
+	(
+		MinimalMethod = stack_copy,
+		Str = "MR_EVAL_METHOD_MINIMAL_STACK_COPY"
+	;
+		MinimalMethod = own_stacks,
+		Str = "MR_EVAL_METHOD_MINIMAL_OWN_STACKS"
+	).
 eval_method_to_c_string(eval_table_io(Decl, Unitize)) = Str :-
 	(
 		Decl = table_io_proc,
Index: compiler/make.program_target.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/make.program_target.m,v
retrieving revision 1.27
diff -u -b -r1.27 make.program_target.m
--- compiler/make.program_target.m	30 Jun 2004 02:48:04 -0000	1.27
+++ compiler/make.program_target.m	15 Jul 2004 06:52:13 -0000
@@ -718,7 +718,7 @@
 	lookup_mmc_options(Info0 ^ options_variables, MaybeMCFlags, !IO),
 	(
 		MaybeMCFlags = yes(MCFlags),
-		handle_options(MCFlags ++ OptionArgs, OptionsError, _, _, _,
+		handle_options(MCFlags ++ OptionArgs, OptionsErrors, _, _, _,
 			!IO)
 	;
 		MaybeMCFlags = no,
@@ -727,11 +727,11 @@
 	),
 
 	(
-		OptionsError = yes(OptionsMessage),
-		usage_error(OptionsMessage, !IO),
+		OptionsErrors = [_ | _],
+		usage_errors(OptionsErrors, !IO),
 		Succeeded = no
 	;
-		OptionsError = no,
+		OptionsErrors = [],
 		%
 		% Remove the grade-dependent targets from the status map
 		% (we need to rebuild them in the new grade).
Index: compiler/make.util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/make.util.m,v
retrieving revision 1.21
diff -u -b -r1.21 make.util.m
--- compiler/make.util.m	30 Jun 2004 02:48:04 -0000	1.21
+++ compiler/make.util.m	30 Jun 2004 03:04:04 -0000
@@ -365,14 +365,14 @@
 		AllOptionArgs = list__condense([InvokedByMake,
 			ModuleOptionArgs, OptionArgs,
 			ExtraOptions, UseSubdirs]),
-		handle_options(AllOptionArgs, OptionsError, _, _, _, !IO),
+		handle_options(AllOptionArgs, OptionsErrors, _, _, _, !IO),
 		(
-			OptionsError = yes(OptionsMessage),
+			OptionsErrors = [_ | _],
 			Succeeded = no,
 			MaybeInfo = no,
-			usage_error(OptionsMessage, !IO)
+			usage_errors(OptionsErrors, !IO)
 		;
-			OptionsError = no,
+			OptionsErrors = [],
 			Build(AllOptionArgs, Succeeded, Info0, Info, !IO),
 			MaybeInfo = yes(Info),
 			globals__io_set_globals(unsafe_promise_unique(Globals),
Index: compiler/make_hlds.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/make_hlds.m,v
retrieving revision 1.474
diff -u -b -r1.474 make_hlds.m
--- compiler/make_hlds.m	14 Jul 2004 05:37:03 -0000	1.474
+++ compiler/make_hlds.m	16 Jul 2004 03:49:00 -0000
@@ -4878,8 +4878,22 @@
 	pred_id::in, module_info::in, module_info::out,
 	io::di, io::uo) is det.
 
-module_add_pragma_tabled_2(EvalMethod, PredName, Arity0, MaybePredOrFunc,
+module_add_pragma_tabled_2(EvalMethod0, PredName, Arity0, MaybePredOrFunc,
 		MaybeModes, Context, PredId, !ModuleInfo, !IO) :-
+
+	( EvalMethod0 = eval_minimal(_) ->
+		globals__io_lookup_bool_option(use_minimal_model_own_stacks,
+			OwnStacks, !IO),
+		(
+			OwnStacks = yes,
+			EvalMethod = eval_minimal(own_stacks)
+		;
+			OwnStacks = no,
+			EvalMethod = eval_minimal(stack_copy)
+		)
+	;
+		EvalMethod = EvalMethod0
+	),
 
 		% Lookup the pred_info for this pred,
 	module_info_get_predicate_table(!.ModuleInfo, PredicateTable),
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.311
diff -u -b -r1.311 mercury_compile.m
--- compiler/mercury_compile.m	9 Jul 2004 07:09:01 -0000	1.311
+++ compiler/mercury_compile.m	9 Jul 2004 07:20:04 -0000
@@ -205,15 +205,15 @@
 		%
 		% Find out which options files to read.
 		%
-		handle_options(Args0, MaybeError0, OptionArgs, NonOptionArgs,
+		handle_options(Args0, Errors0, OptionArgs, NonOptionArgs,
 			Link, !IO),
 		(
-			MaybeError0 = yes(Error0),
-			usage_error(Error0, !IO),
+			Errors0 = [_ | _],
+			usage_errors(Errors0, !IO),
 			Variables = options_variables_init,
 			MaybeMCFlags = no
 		;
-			MaybeError0 = no,
+			Errors0 = [],
 			read_options_files(options_variables_init,
 				MaybeVariables0, !IO),
 			(
@@ -240,7 +240,7 @@
 	),
 	(
 		MaybeMCFlags = yes(MCFlags),
-		handle_options(MCFlags ++ OptionArgs, MaybeError, _, _, _,
+		handle_options(MCFlags ++ OptionArgs, Errors, _, _, _,
 			!IO),
 
 		%
@@ -248,7 +248,7 @@
 		% to `--make', only include the command-line
 		% arguments, not the contents of DEFAULT_MCFLAGS.
 		%
-		main_2(MaybeError, Variables, OptionArgs, NonOptionArgs, Link,
+		main_2(Errors, Variables, OptionArgs, NonOptionArgs, Link,
 			!IO)
 	;
 		MaybeMCFlags = no,
@@ -264,14 +264,14 @@
 	% Process the options again to find out
 	% which configuration file to read.
 	%
-	handle_options(MCFlags0 ++ Args0, MaybeError1, _, _, _, !IO),
+	handle_options(MCFlags0 ++ Args0, Errors, _, _, _, !IO),
 	(
-		MaybeError1 = yes(Error1),
-		usage_error(Error1, !IO),
+		Errors = [_ | _],
+		usage_errors(Errors, !IO),
 		Variables = options_variables_init,
 		MaybeMCFlags = no
 	;
-		MaybeError1 = no,
+		Errors = [],
 		globals__io_lookup_maybe_string_option(config_file,
 			MaybeConfigFile, !IO),
 		(
@@ -295,7 +295,7 @@
 	).
 
 main(Args, !IO) :-
-	main_2(no, options_variables_init, [], Args, no, !IO).
+	main_2([], options_variables_init, [], Args, no, !IO).
 
 %-----------------------------------------------------------------------------%
 
@@ -326,12 +326,12 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred main_2(maybe(string)::in, options_variables::in, list(string)::in,
+:- pred main_2(list(string)::in, options_variables::in, list(string)::in,
 	list(string)::in, bool::in, io::di, io::uo) is det.
 
-main_2(yes(ErrorMessage), _, _, _, _, !IO) :-
-	usage_error(ErrorMessage, !IO).
-main_2(no, OptionVariables, OptionArgs, Args, Link, !IO) :-
+main_2(Errors @ [_ | _], _, _, _, _, !IO) :-
+	usage_errors(Errors, !IO).
+main_2([], OptionVariables, OptionArgs, Args, Link, !IO) :-
 	globals__io_get_globals(Globals, !IO),
 	globals__lookup_bool_option(Globals, help, Help),
 	globals__lookup_bool_option(Globals, generate_source_file_mapping,
Index: compiler/modules.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.303
diff -u -b -r1.303 modules.m
--- compiler/modules.m	14 Jun 2004 04:16:24 -0000	1.303
+++ compiler/modules.m	24 Jun 2004 07:57:58 -0000
@@ -2327,7 +2327,10 @@
 		% --trace-table-io is specified.
 		%
 		( contains_tabling_pragma(Items)
-		; globals__lookup_bool_option(Globals, use_minimal_model, yes)
+		; globals__lookup_bool_option(Globals,
+			use_minimal_model_stack_copy, yes)
+		; globals__lookup_bool_option(Globals,
+			use_minimal_model_own_stacks, yes)
 		; globals__lookup_bool_option(Globals, trace_table_io, yes)
 		)
 	->
Index: compiler/options.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.428
diff -u -b -r1.428 options.m
--- compiler/options.m	30 Jun 2004 02:48:06 -0000	1.428
+++ compiler/options.m	30 Jun 2004 03:04:05 -0000
@@ -233,7 +233,8 @@
 		;	gc
 		;	parallel
 		;	use_trail
-		;	use_minimal_model
+		;	use_minimal_model_stack_copy
+		;	use_minimal_model_own_stacks
 		;	minimal_model_debug
 		;	type_layout
 
@@ -888,7 +889,8 @@
 	gc			-	string("boehm"),
 	parallel		-	bool(no),
 	use_trail		-	bool(no),
-	use_minimal_model	-	bool(no),
+	use_minimal_model_stack_copy	-	bool(no),
+	use_minimal_model_own_stacks	-	bool(no),
 	minimal_model_debug	-	bool(no),
 	type_layout		-	bool(yes),
 
@@ -1533,7 +1535,8 @@
 long_option("type-layout",		type_layout).
 	% Data represention options
 long_option("reserve-tag",		reserve_tag).
-long_option("use-minimal-model",	use_minimal_model).
+long_option("use-minimal-model-stack_copy",	use_minimal_model_stack_copy).
+long_option("use-minimal-model-own-stacks",	use_minimal_model_own_stacks).
 long_option("minimal-model-debug",	minimal_model_debug).
 long_option("pic",			pic).
 long_option("pic-reg",			pic_reg).
@@ -3289,9 +3292,13 @@
 	]),
 	io__write_string("\n      Developer optional features\n"),
 	write_tabbed_lines([
-		"--use-minimal-model",
+		"--use-minimal-model-stack-copy",
 		"(This option is not for general use.)",
-		"\tEnable the use of minimal model tabling.",
+		"\tEnable the use of the standard form of minimal model tabling.",
+
+		"--use-minimal-model-own-stacks",
+		"(This option is not for general use.)",
+		"\tEnable the use of an experimental form of minimal model tabling.",
 
 		"--minimal-model-debug",
 		"(This option is not for general use.)",
Index: compiler/polymorphism.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/polymorphism.m,v
retrieving revision 1.253
diff -u -b -r1.253 polymorphism.m
--- compiler/polymorphism.m	14 Jun 2004 04:16:27 -0000	1.253
+++ compiler/polymorphism.m	15 Jul 2004 06:49:18 -0000
@@ -2245,8 +2245,8 @@
 	% is polymorphic.
 	goal_util__generate_simple_call(mercury_private_builtin_module,
 		"superclass_from_typeclass_info", predicate, only_mode, det,
-		[SubClassVar, IndexVar, Var], no,
-		[], ModuleInfo, term__context_init, SuperClassGoal),
+		[SubClassVar, IndexVar, Var], [], [], ModuleInfo,
+		term__context_init, SuperClassGoal),
 	!:ExtraGoals = [SuperClassGoal, IndexGoal | !.ExtraGoals].
 
 :- pred polymorphism__construct_typeclass_info(list(prog_var)::in,
@@ -2897,7 +2897,7 @@
 		TypeInfoVar, !VarSet, !VarTypes),
 	goal_util__generate_simple_call(mercury_private_builtin_module,
 		"type_info_from_typeclass_info", predicate, only_mode, det,
-		[TypeClassInfoVar, IndexVar, TypeInfoVar], no,
+		[TypeClassInfoVar, IndexVar, TypeInfoVar], [],
 		[TypeInfoVar - ground(shared, none)], ModuleInfo,
 		term__context_init, CallGoal),
 	Goals = [IndexGoal, CallGoal].
Index: compiler/prog_data.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/prog_data.m,v
retrieving revision 1.112
diff -u -b -r1.112 prog_data.m
--- compiler/prog_data.m	6 Jul 2004 04:18:50 -0000	1.112
+++ compiler/prog_data.m	6 Jul 2004 04:17:39 -0000
@@ -550,6 +550,11 @@
 % Stuff for tabling pragmas
 %
 
+:- type eval_minimal_method
+	--->	stack_copy		% saving and restoring stack segments
+					% as necessary
+	;	own_stacks.		% each generator has own stacks
+
 	% The evaluation method that should be used for a procedure.
 	% Ignored for Aditi procedures.
 :- type eval_method
@@ -561,8 +566,8 @@
 			table_io_is_decl,
 			table_io_is_unitize
 		)
-	;	eval_minimal.		% minimal model
-					% evaluation
+	;	eval_minimal(eval_minimal_method).
+					% minimal model evaluation
 
 :- type table_io_is_decl
 	--->	table_io_decl		% The procedure is tabled for
Index: compiler/prog_io_pragma.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/prog_io_pragma.m,v
retrieving revision 1.70
diff -u -b -r1.70 prog_io_pragma.m
--- compiler/prog_io_pragma.m	6 Jul 2004 04:18:50 -0000	1.70
+++ compiler/prog_io_pragma.m	6 Jul 2004 04:17:40 -0000
@@ -869,8 +869,12 @@
 		PragmaTerms, ErrorTerm, Result).
 parse_pragma_type(ModuleName, "minimal_model", PragmaTerms, ErrorTerm,
 		_VarSet, Result) :-
-	parse_tabling_pragma(ModuleName, "minimal_model", eval_minimal,
-		PragmaTerms, ErrorTerm, Result).
+	% We don't yet know whether we will use the stack_copy or the
+	% own_stacks technique for computing minimal models. The decision
+	% depends on the grade, and is made in make_hlds.m; the stack_copy here
+	% is just a placeholder.
+	parse_tabling_pragma(ModuleName, "minimal_model",
+		eval_minimal(stack_copy), PragmaTerms, ErrorTerm, Result).
 
 parse_pragma_type(ModuleName, "obsolete", PragmaTerms, ErrorTerm,
 		_VarSet, Result) :-
Index: compiler/prog_out.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/prog_out.m,v
retrieving revision 1.52
diff -u -b -r1.52 prog_out.m
--- compiler/prog_out.m	30 Jun 2004 02:48:10 -0000	1.52
+++ compiler/prog_out.m	30 Jun 2004 03:04:06 -0000
@@ -327,7 +327,14 @@
 eval_method_to_string(eval_normal) =		"normal".
 eval_method_to_string(eval_loop_check) =	"loop_check".
 eval_method_to_string(eval_memo) =		"memo".
-eval_method_to_string(eval_minimal) = 		"minimal_model".
+eval_method_to_string(eval_minimal(MinimalMethod)) = Str :-
+	(
+		MinimalMethod = own_stacks,
+		Str = "minimal_model_own_stacks"
+	;
+		MinimalMethod = stack_copy,
+		Str = "minimal_model_stack_copy"
+	).
 eval_method_to_string(eval_table_io(IsDecl, IsUnitize)) = Str :-
 	(
                 IsDecl = table_io_decl,
Index: compiler/prog_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/prog_util.m,v
retrieving revision 1.67
diff -u -b -r1.67 prog_util.m
--- compiler/prog_util.m	14 Jun 2004 04:16:31 -0000	1.67
+++ compiler/prog_util.m	24 Jun 2004 07:58:00 -0000
@@ -132,6 +132,13 @@
 	%		part of SymName0 with the suffix added
 :- pred add_sym_name_suffix(sym_name::in, string::in, sym_name::out) is det.
 
+	% transform_sym_base_name(TransformFunc, SymName0) = SymName
+	% succeeds iff
+	%	SymName and SymName0 have the same module qualifier
+	%	and the unqualified part of SymName is the result of applying
+	%	TransformFunc to the unqualified part of SymName0.
+:- func transform_sym_base_name(func(string) = string, sym_name) = sym_name.
+
 	% insert_module_qualifier(ModuleName, SymName0, SymName):
 	%	prepend the specified ModuleName onto the module
 	%	qualifiers in SymName0, giving SymName.
@@ -521,6 +528,11 @@
 	string__append(Name0, Suffix, Name).
 add_sym_name_suffix(unqualified(Name0), Suffix, unqualified(Name)) :-
 	string__append(Name0, Suffix, Name).
+
+transform_sym_base_name(TransformFunc, qualified(Module, Name0)) =
+		qualified(Module, TransformFunc(Name0)).
+transform_sym_base_name(TransformFunc, unqualified(Name0)) =
+		unqualified(TransformFunc(Name0)).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/simplify.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/simplify.m,v
retrieving revision 1.132
diff -u -b -r1.132 simplify.m
--- compiler/simplify.m	14 Jun 2004 04:16:35 -0000	1.132
+++ compiler/simplify.m	15 Jul 2004 06:49:58 -0000
@@ -1141,7 +1141,7 @@
 	Unique   = ground(unique, none),
 	ArgInsts = [R - Unique],
 	goal_util__generate_simple_call(BuiltinModule, "compare", predicate,
-		mode_no(ModeNo), det, Args, no, ArgInsts, ModuleInfo, Context,
+		mode_no(ModeNo), det, Args, [], ArgInsts, ModuleInfo, Context,
 		CmpGoal0),
 	CmpGoal0 = CmpExpr - CmpInfo0,
 	goal_info_get_nonlocals(CmpInfo0, CmpNonLocals0),
@@ -1280,7 +1280,7 @@
 		% should always terminate if they have a finite number
 		% of answers.
 		%
-		\+ proc_info_eval_method(ProcInfo, eval_minimal),
+		\+ proc_info_eval_method(ProcInfo, eval_minimal(_)),
 
 		% Don't warn about impure procedures, since they may modify
 		% the state in ways not visible to us (unlike pure and semipure
@@ -1381,7 +1381,7 @@
 		goal_info_get_context(GoalInfo0, GContext),
 		generate_simple_call(mercury_private_builtin_module,
 			"builtin_unify_pred", predicate, mode_no(0), semidet,
-			[XVar, YVar], no, [], ModuleInfo, GContext, Call0 - _),
+			[XVar, YVar], [], [], ModuleInfo, GContext, Call0 - _),
 		simplify__goal_2(Call0, Call1, GoalInfo0, GoalInfo, !Info),
 		Call = Call1 - GoalInfo,
 		ExtraGoals = []
@@ -1457,7 +1457,7 @@
 	ArgVars = [TypeInfoVar, XVar, YVar],
 	goal_info_get_context(GoalInfo, Context),
 	goal_util__generate_simple_call(mercury_public_builtin_module,
-		"unify", predicate, mode_no(0), semidet, ArgVars, no, [],
+		"unify", predicate, mode_no(0), semidet, ArgVars, [], [],
 		ModuleInfo, Context, Call).
 
 :- pred simplify__call_specific_unify(type_ctor::in, list(prog_var)::in,
Index: compiler/size_prof.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/size_prof.m,v
retrieving revision 1.8
diff -u -b -r1.8 size_prof.m
--- compiler/size_prof.m	14 Jun 2004 04:16:36 -0000	1.8
+++ compiler/size_prof.m	15 Jul 2004 07:08:43 -0000
@@ -719,7 +719,7 @@
 		TermSizeProfBuiltin = mercury_term_size_prof_builtin_module,
 		goal_util__generate_simple_call(TermSizeProfBuiltin,
 			"increment_size", predicate, only_mode, det,
-			[Var, SizeVar], yes(impure), [], !.Info ^ module_info,
+			[Var, SizeVar], [impure], [], !.Info ^ module_info,
 			Context, UpdateGoal),
 		% Put UnifyGoal first in case it fails.
 		Goals = list__condense([[UnifyGoal], ArgGoals, SizeGoals,
@@ -788,7 +788,7 @@
 		TermSizeProfModule = mercury_term_size_prof_builtin_module,
 		goal_util__generate_simple_call(TermSizeProfModule,
 			"term_size_plus", function, mode_no(0), det,
-			[SizeVar0, KnownSizeVar, SizeVar], no,
+			[SizeVar0, KnownSizeVar, SizeVar], [],
 			[SizeVar - ground(shared, none)],
 			!.Info ^ module_info, Context, AddGoal),
 		Goals = [KnownSizeGoal, AddGoal]
@@ -850,7 +850,7 @@
 			goal_util__generate_simple_call(PrivateBuiltin,
 				"type_info_from_typeclass_info", predicate,
 				only_mode, det,
-				[TypeClassInfoVar, SlotVar, TypeInfoVar], no,
+				[TypeClassInfoVar, SlotVar, TypeInfoVar], [],
 				[TypeInfoVar - ground(shared, none)],
 				!.Info ^ module_info, Context, ExtractGoal),
 			record_type_info_var(Type, TypeInfoVar, !Info),
@@ -964,7 +964,7 @@
 	),
 	TermSizeProfBuiltin = mercury_term_size_prof_builtin_module,
 	goal_util__generate_simple_call(TermSizeProfBuiltin, Pred, predicate,
-		only_mode, det, Args, no, [SizeVar - ground(shared, none)],
+		only_mode, det, Args, [], [SizeVar - ground(shared, none)],
 		!.Info ^ module_info, Context, SizeGoal),
 	MaybeSizeVar = yes(SizeVar).
 
Index: compiler/table_gen.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/table_gen.m,v
retrieving revision 1.64
diff -u -b -r1.64 table_gen.m
--- compiler/table_gen.m	21 Jun 2004 03:31:55 -0000	1.64
+++ compiler/table_gen.m	17 Jul 2004 10:53:16 -0000
@@ -85,54 +85,62 @@
 
 %-----------------------------------------------------------------------------%
 
+	% 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(ModuleInfo0, ModuleInfo, S0, S) :-
-	module_info_preds(ModuleInfo0, Preds0),
+table_gen__process_module(!ModuleInfo, !IO) :-
+	module_info_preds(!.ModuleInfo, Preds0),
 	map__keys(Preds0, PredIds),
-	table_gen__process_preds(PredIds, ModuleInfo0, ModuleInfo, S0, S).
+	map__init(GenMap0),
+	table_gen__process_preds(PredIds, !ModuleInfo, GenMap0, _, !IO).
 
 :- pred table_gen__process_preds(list(pred_id)::in,
-	module_info::in, module_info::out, io::di, io::uo) is det.
+	module_info::in, module_info::out,
+	generator_map::in, generator_map::out, io::di, io::uo) is det.
 
-table_gen__process_preds([], ModuleInfo, ModuleInfo, S, S).
-table_gen__process_preds([PredId | PredIds], ModuleInfo0, ModuleInfo, S0, S) :-
-	table_gen__process_pred(PredId, ModuleInfo0, ModuleInfo1, S0, S1),
-	table_gen__process_preds(PredIds, ModuleInfo1, ModuleInfo, S1, S).
+table_gen__process_preds([], !ModuleInfo, !GenMap, !IO).
+table_gen__process_preds([PredId | PredIds], !ModuleInfo, !GenMap, !IO) :-
+	table_gen__process_pred(PredId, !ModuleInfo, !GenMap, !IO),
+	table_gen__process_preds(PredIds, !ModuleInfo, !GenMap, !IO).
 
 :- pred table_gen__process_pred(pred_id::in, module_info::in, module_info::out,
-	io::di, io::uo) is det.
+	generator_map::in, generator_map::out, io::di, io::uo) is det.
 
-table_gen__process_pred(PredId, !ModuleInfo, !IO) :-
+table_gen__process_pred(PredId, !ModuleInfo, !GenMap, !IO) :-
 	module_info_pred_info(!.ModuleInfo, PredId, PredInfo),
 	ProcIds = pred_info_procids(PredInfo),
-	table_gen__process_procs(PredId, ProcIds, !ModuleInfo, !IO).
+	table_gen__process_procs(PredId, ProcIds, !ModuleInfo, !GenMap, !IO).
 
 :- pred table_gen__process_procs(pred_id::in, list(proc_id)::in,
-	module_info::in, module_info::out, io::di, io::uo) is det.
+	module_info::in, module_info::out,
+	generator_map::in, generator_map::out, io::di, io::uo) is det.
 
-table_gen__process_procs(_PredId, [], !ModuleInfo, !IO).
-table_gen__process_procs(PredId, [ProcId | ProcIds], !ModuleInfo, !IO) :-
+table_gen__process_procs(_PredId, [], !ModuleInfo, !GenMap, !IO).
+table_gen__process_procs(PredId, [ProcId | ProcIds], !ModuleInfo, !GenMap,
+		!IO) :-
 	module_info_preds(!.ModuleInfo, PredTable),
 	map__lookup(PredTable, PredId, PredInfo),
 	pred_info_procedures(PredInfo, ProcTable),
 	map__lookup(ProcTable, ProcId, ProcInfo0),
 	table_gen__process_proc(PredId, ProcId, ProcInfo0, PredInfo,
-		!ModuleInfo, !IO),
-	table_gen__process_procs(PredId, ProcIds, !ModuleInfo, !IO).
+		!ModuleInfo, !GenMap, !IO),
+	table_gen__process_procs(PredId, ProcIds, !ModuleInfo, !GenMap, !IO).
 
 :- pred table_gen__process_proc(pred_id::in, proc_id::in, proc_info::in,
-	pred_info::in, module_info::in, module_info::out, io::di, io::uo)
-	is det.
+	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, !IO) :-
+		!ModuleInfo, !GenMap, !IO) :-
 	proc_info_eval_method(ProcInfo0, EvalMethod),
 	( eval_method_requires_tabling_transform(EvalMethod) = yes ->
 		table_gen__transform_proc(EvalMethod, PredId, ProcId,
-			ProcInfo0, _, PredInfo0, _, !ModuleInfo, !IO)
+			ProcInfo0, _, PredInfo0, _, !ModuleInfo, !GenMap, !IO)
 	;
 		module_info_globals(!.ModuleInfo, Globals),
 		globals__lookup_bool_option(Globals, trace_table_io, yes),
@@ -185,7 +193,7 @@
 				ProcInfo0, ProcInfo1),
 			table_gen__transform_proc(TableIoMethod,
 				PredId, ProcId, ProcInfo1, _, PredInfo0, _,
-				!ModuleInfo, !IO)
+				!ModuleInfo, !GenMap, !IO)
 		)
 	;
 		true
@@ -331,10 +339,12 @@
 
 :- pred table_gen__transform_proc(eval_method::in, pred_id::in, proc_id::in,
 	proc_info::in, proc_info::out, pred_info::in, pred_info::out,
-	module_info::in, module_info::out, io::di, io::uo) is det.
+	module_info::in, module_info::out,
+	generator_map::in, generator_map::out, io::di, io::uo) is det.
 
 table_gen__transform_proc(EvalMethod, PredId, ProcId, !ProcInfo, !PredInfo,
-		!ModuleInfo, !IO) :-
+		!ModuleInfo, !GenMap, !IO) :-
+	table_info_init(!.ModuleInfo, !.PredInfo, !.ProcInfo, TableInfo0),
 
 	% grab the appropriate fields from the pred_info and proc_info
 	proc_info_interface_determinism(!.ProcInfo, Detism),
@@ -357,9 +367,7 @@
 		% but prevent the creation of an executable.
 		module_info_incr_errors(!ModuleInfo)
 	),
-	table_info_init(!.ModuleInfo, PredId, ProcId, !.PredInfo, !.ProcInfo,
-		TableInfo0),
-
+	tabling_via_extra_args(!.ModuleInfo, TablingViaExtraArgs),
 	(
 		EvalMethod = eval_normal,
 		% This should have been caught by our caller.
@@ -370,14 +378,16 @@
 		globals__lookup_bool_option(Globals, trace_table_io_states,
 			TableIoStates),
 		table_gen__create_new_io_goal(OrigGoal, Decl, Unitize,
-			TableIoStates, HeadVars, InputVars, OutputVars,
+			TableIoStates, PredId, ProcId, TablingViaExtraArgs,
+			HeadVars, InputVars, OutputVars,
 			VarTypes0, VarTypes, VarSet0, VarSet,
 			TableInfo0, TableInfo, Goal, MaybeProcTableInfo),
 		MaybeCallTableTip = no
 	;
 		EvalMethod = eval_loop_check,
 		table_gen__create_new_loop_goal(Detism, OrigGoal,
-			PredId, ProcId, HeadVars, InputVars, OutputVars,
+			PredId, ProcId, TablingViaExtraArgs,
+			HeadVars, InputVars, OutputVars,
 			VarTypes0, VarTypes, VarSet0, VarSet,
 			TableInfo0, TableInfo, CallTableTip, Goal, Steps),
 		generate_gen_proc_table_info(TableInfo, Steps,
@@ -386,16 +396,27 @@
 		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)
+		;
 		table_gen__create_new_memo_goal(Detism, OrigGoal,
-			PredId, ProcId, HeadVars, InputVars, OutputVars,
+				PredId, ProcId, TablingViaExtraArgs,
+				HeadVars, InputVars, OutputVars,
 			VarTypes0, VarTypes, VarSet0, VarSet,
-			TableInfo0, TableInfo, CallTableTip, Goal, Steps),
+				TableInfo0, TableInfo, CallTableTip, Goal,
+				Steps)
+		),
 		generate_gen_proc_table_info(TableInfo, Steps,
 			InputVars, OutputVars, ProcTableInfo),
 		MaybeCallTableTip = yes(CallTableTip),
 		MaybeProcTableInfo = yes(ProcTableInfo)
 	;
-		EvalMethod = eval_minimal,
+		EvalMethod = eval_minimal(MinimalMethod),
 		(
 			CodeModel = model_det,
 			error("table_gen__transform_proc: minimal det")
@@ -404,10 +425,21 @@
 			error("table_gen__transform_proc: minimal semi")
 		;
 			CodeModel = model_non,
+			MinimalMethod = stack_copy,
 			table_gen__create_new_mm_goal(Detism, OrigGoal,
-				PredId, ProcId, HeadVars,
-				InputVars, OutputVars, VarTypes0, VarTypes,
-				VarSet0, VarSet, TableInfo0, TableInfo,
+				PredId, ProcId, TablingViaExtraArgs,
+				HeadVars, InputVars, OutputVars,
+				VarTypes0, VarTypes, VarSet0, VarSet,
+				TableInfo0, TableInfo,
+				CallTableTip, Goal, Steps)
+		;
+			CodeModel = model_non,
+			MinimalMethod = own_stacks,
+			table_gen__do_own_stack_transform(Detism, OrigGoal,
+				PredId, ProcId, !.PredInfo, !.ProcInfo,
+				HeadVars, InputVars, OutputVars,
+				VarTypes0, VarTypes, VarSet0, VarSet,
+				TableInfo0, TableInfo, !GenMap,
 				CallTableTip, Goal, Steps)
 		),
 		generate_gen_proc_table_info(TableInfo, Steps,
@@ -416,8 +448,7 @@
 		MaybeProcTableInfo = yes(ProcTableInfo)
 	),
 
-	table_info_extract(TableInfo, !:ModuleInfo, _, _,
-		!:PredInfo, !:ProcInfo),
+	table_info_extract(TableInfo, !:ModuleInfo, !:PredInfo, !:ProcInfo),
 
 	% set the new values of the fields in proc_info and pred_info
 	% and save in the module info
@@ -498,19 +529,50 @@
 %			B = C,
 %			impure table_loop_mark_as_inactive(T)
 %		else
-%			impure table_loop_mark_as_inactive(T),
+%			impure table_loop_mark_as_inactive_and_fail(T),
+%		)
+%	).
+%
+% Example of transformation for model_non loopcheck:
+%
+% :- pred p(int::in, int::out) is semidet.
+%
+% p(A, B) :-
+% 	<original code>.
+%
+% The transformed code would be :
+%
+% p(A, B) :-
+%	T0 = <table pointer for p/2>,
+%	impure table_lookup_insert_int(T0, A, T),
+%	impure table_loop_setup(T, Status),
+%	(
+%		Status = loop_active,
+%		error("detected infinite recursion in ...")
+%	;
+%		Status = loop_inactive,
+%		% status has been changed to active by the setup predicate
+%		(
+%			<original code>,
+%			(
+%				impure table_loop_mark_as_inactive(T)
+%			;
+%				impure table_loop_mark_as_active_and_fail(T),
 %			fail
 %		)
+%		;
+%			impure table_loop_mark_as_inactive_and_fail(T)
+%		)
 %	).
 
 :- pred create_new_loop_goal(determinism::in, hlds_goal::in,
-	pred_id::in, proc_id::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.
 
-create_new_loop_goal(Detism, OrigGoal, PredId, ProcId,
+create_new_loop_goal(Detism, OrigGoal, PredId, ProcId, TablingViaExtraArgs,
 		HeadVars, InputVars, OutputVars, !VarTypes, !VarSet,
 		!TableInfo, TableTipVar, Goal, Steps) :-
 	% even if the original goal doesn't use all of the headvars,
@@ -525,15 +587,51 @@
 	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, Context,
-		!VarTypes, !VarSet, !TableInfo, TableTipVar, StatusVar,
-		LookUpGoal, Steps),
+		"table_loop_setup", NumberedInputVars, PredId, ProcId,
+		TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
+		TableTipVar, StatusVar, LookUpGoal, Steps),
 
 	generate_error_goal(!.TableInfo, Context, infinite_recursion_msg,
 		!VarTypes, !VarSet, ActiveGoal),
 
-	generate_call("table_loop_mark_as_inactive", det, [TableTipVar],
-		yes(impure), [], ModuleInfo, Context, MarkInactiveGoal),
+	MarkInactivePred = "table_loop_mark_as_inactive",
+	MarkInactiveFailPred = "table_loop_mark_as_inactive_and_fail",
+	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)
+	;
+		TablingViaExtraArgs = yes,
+		TableTipArg = foreign_arg(TableTipVar,
+			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,
+			tabling_c_attributes, [TableTipArg], [],
+			"", MarkInactiveCode, "", impure_code, [],
+			ModuleInfo, Context, MarkInactiveGoal),
+		generate_foreign_proc(MarkInactiveFailPred, failure,
+			tabling_c_attributes, [TableTipArg], [],
+			"", MarkInactiveFailCode, "", impure_code, [],
+			ModuleInfo, Context, MarkInactiveFailGoal),
+		generate_foreign_proc(MarkActiveFailPred, failure,
+			tabling_c_attributes, [TableTipArg], [],
+			"", MarkActiveFailCode, "", impure_code, [],
+			ModuleInfo, Context, MarkActiveFailGoal)
+	),
 
 	determinism_to_code_model(Detism, CodeModel),
 	set__list_to_set([TableTipVar | HeadVars], InactiveNonLocals),
@@ -543,7 +641,6 @@
 		InactiveGoalExpr = conj([OrigGoal, MarkInactiveGoal])
 	;
 		CodeModel = model_semi,
-
 		create_renaming(OutputVars, !VarTypes, !VarSet,
 			Unifies, NewVars, Renaming),
 		rename_vars_in_goal(OrigGoal, Renaming, RenamedOrigGoal),
@@ -555,13 +652,18 @@
 			Detism, impure, Context, ThenGoalInfo),
 		ThenGoal = ThenGoalExpr - ThenGoalInfo,
 
-		append_fail(MarkInactiveGoal, ElseGoal),
-
 		InactiveGoalExpr = if_then_else([], RenamedOrigGoal,
-			ThenGoal, ElseGoal)
+			ThenGoal, MarkInactiveFailGoal)
 	;
 		CodeModel = model_non,
-		error("create_new_loop_goal: model_non")
+		AfterGoalExpr = disj([MarkInactiveGoal, MarkActiveFailGoal]),
+		instmap_delta_init_reachable(AfterInstMapDelta),
+		goal_info_init_hide(set__init, AfterInstMapDelta,
+			multidet, impure, Context, AfterGoalInfo),
+		AfterGoal = AfterGoalExpr - AfterGoalInfo,
+		FirstGoalExpr = conj([OrigGoal, AfterGoal]),
+		FirstGoal = FirstGoalExpr - OrigGoalInfo,
+		InactiveGoalExpr = disj([FirstGoal, MarkInactiveFailGoal])
 	),
 	goal_info_init_hide(InactiveNonLocals, InactiveInstmapDelta,
 		Detism, impure, Context, InactiveGoalInfo),
@@ -652,17 +754,66 @@
 %		)
 %	).
 %
+% Example of transformation for model_non memo:
+%
+% :- pred p(int::in, int::out) is semidet.
+%
+% p(A, B) :-
+% 	<original code>.
+%
+% The transformed code would be :
+%
+% p(A, B) :-
+%	CT0 = <table pointer for p/2>,
+%	impure table_lookup_insert_int(CT0, A, CT1),
+%	impure table_memo_non_setup(CT1, Record, Status),
+%	(
+%		Status = memo_non_complete,
+%		semipure table_memo_return_all_nondet(T, Block),
+%		semipure table_restore_int_answer(Block, 0, B)
+%	;
+%		Status = memo_non_incomplete,
+%		error("detected need for minimal model tabling in ...")
+%	;
+%		Status = memo_non_active,
+%		error("detected infinite recursion in ...")
+%	;
+%		Status = memo_non_inactive,
+%	   	(
+%			<original code>,
+%
+%				% Check for duplicate answers.
+%			semipure table_memo_get_answer_table(Record, AT0),
+%			impure table_lookup_insert_int(AT0, B, AT1),
+%				% Fail if the answer is already in the table;
+%				% otherwise, put it into the table.
+%			impure table_mm_answer_is_not_duplicate(AT1),
+%
+%				% Save the new answer in the table.
+%			impure table_memo_create_answer_block(Record, 1, Block),
+%			impure table_save_int_answer(Block, 0, B),
+%			(
+%				impure table_memo_mark_as_incomplete(R)
+%			;
+%				impure table_memo_mark_as_active_and_fail(R),
+%				fail
+%			)
+%		;
+%			impure table_memo_mark_as_complete_and_fail(R)
+%		)
+%	).
+%
 % If there are no output variables, then instead of creating an answer block
 % and filling it in, we call table_memo_mark_as_succeeded.
 
 :- pred create_new_memo_goal(determinism::in, hlds_goal::in,
-	pred_id::in, proc_id::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.
 
-create_new_memo_goal(Detism, OrigGoal, PredId, ProcId,
+create_new_memo_goal(Detism, OrigGoal, PredId, ProcId, TablingViaExtraArgs,
 		HeadVars, InputVars, OutputVars, !VarTypes, !VarSet,
 		!TableInfo, TableTipVar, Goal, Steps) :-
 	% even if the original goal doesn't use all of the headvars,
@@ -690,8 +841,9 @@
 	),
 	allocate_slot_numbers(InputVars, 0, NumberedInputVars),
 	generate_simple_call_table_lookup_goal(StatusType, SetupPred,
-		NumberedInputVars, PredId, ProcId, 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),
@@ -699,10 +851,11 @@
 	allocate_slot_numbers(OutputVars, 0, NumberedOutputVars),
 	list__length(NumberedOutputVars, BlockSize),
 	generate_memo_save_goals(NumberedOutputVars, TableTipVar, BlockSize,
-		Context, !VarTypes, !VarSet, !TableInfo, SaveAnswerGoals),
+		TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
+		SaveAnswerGoals),
 	generate_memo_restore_goal(NumberedOutputVars, OrigInstMapDelta,
-		TableTipVar, ModuleInfo, Context, !VarTypes, !VarSet,
-		RestoreAnswerGoal),
+		TableTipVar, ModuleInfo, TablingViaExtraArgs, Context,
+		!VarTypes, !VarSet, RestoreAnswerGoal),
 	SucceededGoal = RestoreAnswerGoal,
 
 	set__list_to_set([TableTipVar | HeadVars], InactiveNonLocals),
@@ -736,7 +889,6 @@
 			det, impure, Context, ThenGoalInfo),
 		ThenGoal = ThenGoalExpr - ThenGoalInfo,
 
-		tabling_via_extra_args(ModuleInfo, TablingViaExtraArgs),
 		MarkAsFailedPred = "table_memo_mark_as_failed",
 		(
 			TablingViaExtraArgs = yes,
@@ -747,12 +899,12 @@
 				"(" ++ cur_table_node_name ++ ");",
 			generate_foreign_proc(MarkAsFailedPred, failure,
 				tabling_c_attributes, [TableTipArg], [],
-				"", MarkAsFailedCode, "", yes(impure), [],
+				"", MarkAsFailedCode, "", impure_code, [],
 				ModuleInfo, Context, ElseGoal)
 		;
 			TablingViaExtraArgs = no,
 			generate_call("table_memo_mark_as_failed", failure,
-				[TableTipVar], yes(impure), [], ModuleInfo,
+				[TableTipVar], impure_code, [], ModuleInfo,
 				Context, ElseGoal)
 		),
 		InactiveGoalExpr = if_then_else([], RenamedOrigGoal,
@@ -788,6 +940,116 @@
 		impure, Context, GoalInfo),
 	Goal = GoalExpr - GoalInfo.
 
+:- 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,
+	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) :-
+	% 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
+	% than getting it from the nonlocals field in the original goal
+	set__list_to_set(HeadVars, OrigNonLocals),
+	OrigGoal = _ - OrigGoalInfo,
+	goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
+	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),
+
+	generate_memo_non_call_table_lookup_goal(NumberedInputVars,
+		PredId, ProcId, Context, !VarTypes, !VarSet, !TableInfo,
+		RecordVar, StatusVar, LookUpGoal, Steps),
+	generate_memo_non_save_goals(NumberedOutputVars, RecordVar, BlockSize,
+		Context, !VarTypes, !VarSet, !TableInfo, SaveAnswerGoals),
+
+	generate_memo_non_restore_goal(Detism, NumberedOutputVars,
+		OrigInstMapDelta, RecordVar, ModuleInfo, Context,
+		!VarTypes, !VarSet, RestoreAllAnswerGoal),
+
+	RecordVarName = memo_non_record_name,
+	RecordArg = foreign_arg(RecordVar,
+		yes(RecordVarName - in_mode), memo_non_record_type),
+	MarkIncompletePred = "table_memo_mark_as_incomplete",
+	MarkActivePred = "table_memo_mark_as_active_and_fail",
+	MarkCompletePred = "table_memo_mark_as_complete_and_fail",
+	MarkIncompleteCode = "MR_" ++ MarkIncompletePred ++ "(" ++
+		RecordVarName ++ ");\n",
+	MarkActiveCode = "MR_" ++ MarkActivePred ++ "(" ++
+		RecordVarName ++ ");\n",
+	MarkCompleteCode = "MR_" ++ MarkCompletePred ++ "(" ++
+		RecordVarName ++ ");\n",
+	generate_foreign_proc(MarkIncompletePred, det,
+		tabling_c_attributes, [RecordArg], [],
+		"", MarkIncompleteCode, "", impure_code, [],
+		ModuleInfo, Context, MarkIncompleteGoal),
+	generate_foreign_proc(MarkActivePred, failure,
+		tabling_c_attributes, [RecordArg], [],
+		"", MarkActiveCode, "", impure_code, [],
+		ModuleInfo, Context, MarkActiveGoal),
+	generate_foreign_proc(MarkCompletePred, failure,
+		tabling_c_attributes, [RecordArg], [],
+		"", MarkCompleteCode, "", impure_code, [],
+		ModuleInfo, Context, MarkCompleteGoal),
+
+	OrigSaveExpr = conj([OrigGoal | SaveAnswerGoals]),
+	set__insert(OrigNonLocals, RecordVar, OrigSaveNonLocals),
+	create_instmap_delta([OrigGoal | SaveAnswerGoals], OrigSaveIMD0),
+	instmap_delta_restrict(OrigSaveIMD0, OrigSaveNonLocals, OrigSaveIMD),
+	goal_info_init_hide(OrigSaveNonLocals, OrigSaveIMD, nondet, impure,
+		Context, OrigSaveGoalInfo),
+	OrigSaveGoal = OrigSaveExpr - OrigSaveGoalInfo,
+
+	AfterExpr = disj([MarkIncompleteGoal, MarkActiveGoal]),
+	AfterNonLocals = set__make_singleton_set(RecordVar),
+	create_instmap_delta([], AfterInstMapDelta),
+	goal_info_init_hide(AfterNonLocals, AfterInstMapDelta, nondet, impure,
+		Context, AfterGoalInfo),
+	AfterGoal = AfterExpr - AfterGoalInfo,
+
+	OrigSaveAfterExpr = conj([OrigSaveGoal, AfterGoal]),
+	OrigSaveAfterGoal = OrigSaveAfterExpr - OrigSaveGoalInfo,
+
+	InactiveExpr = disj([OrigSaveAfterGoal, MarkCompleteGoal]),
+	InactiveGoal = InactiveExpr - OrigSaveGoalInfo,
+
+	set__list_to_set([RecordVar | HeadVars], InactiveNonLocals),
+	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)
+	],
+
+	SwitchExpr = switch(StatusVar, cannot_fail, SwitchArms),
+	goal_info_init_hide(InactiveNonLocals, InactiveInstmapDelta,
+		Detism, impure, Context, SwitchGoalInfo),
+	SwitchGoal = SwitchExpr - SwitchGoalInfo,
+
+	GoalExpr = conj([LookUpGoal, SwitchGoal]),
+	goal_info_init_hide(OrigNonLocals, OrigInstMapDelta, Detism,
+		impure, Context, GoalInfo),
+	Goal = GoalExpr - GoalInfo.
+
 %-----------------------------------------------------------------------------%
 
 % Example of transformation for tabling I/O, for I/O primitives (i.e.
@@ -858,12 +1120,14 @@
 % it executes the original goal.
 
 :- pred table_gen__create_new_io_goal(hlds_goal::in, table_io_is_decl::in,
-	table_io_is_unitize::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,
+	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,
+	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,
 		!TableInfo, Goal, MaybeProcTableInfo) :-
 	OrigGoal = _ - OrigGoalInfo,
@@ -892,20 +1156,18 @@
 	generate_new_table_var("StartVar", int_type, !VarTypes, !VarSet,
 		StartVar),
 	generate_call("table_io_in_range", semidet,
-		[TableVar, CounterVar, StartVar], yes(impure),
+		[TableVar, CounterVar, StartVar], impure_code,
 		ground_vars([TableVar, CounterVar, StartVar]),
 		ModuleInfo, Context, InRangeGoal),
 	generate_new_table_var("TipVar", trie_node_type, !VarTypes, !VarSet,
 		TipVar),
 	generate_call("table_lookup_insert_start_int", det,
-		[TableVar, StartVar, CounterVar, TipVar], yes(impure),
+		[TableVar, StartVar, CounterVar, TipVar], impure_code,
 		ground_vars([TipVar]), ModuleInfo, Context, LookupGoal),
 	generate_call("table_io_has_occurred", semidet, [TipVar],
-		yes(semipure), [], ModuleInfo, Context, OccurredGoal),
+		semipure_code, [], ModuleInfo, Context, OccurredGoal),
 	(
 		TableDecl = table_io_decl,
-		PredId = !.TableInfo ^ table_cur_pred_id,
-		ProcId = !.TableInfo ^ table_cur_proc_id,
 		ShroudedPredProcId = shroud_pred_proc_id(proc(PredId, ProcId)),
 		TableIoDeclConsId = table_io_decl(ShroudedPredProcId),
 		make_const_construction(TableIoDeclConsId, c_pointer_type,
@@ -935,8 +1197,8 @@
 	list__length(NumberedSaveVars, BlockSize),
 	goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
 	generate_memo_restore_goal(NumberedRestoreVars, OrigInstMapDelta,
-		TipVar, ModuleInfo, Context, !VarTypes, !VarSet,
-		RestoreAnswerGoal0),
+		TipVar, ModuleInfo, TablingViaExtraArgs, Context,
+		!VarTypes, !VarSet, RestoreAnswerGoal0),
 	(
 		TableIoStates = yes,
 		RestoreAnswerGoal = RestoreAnswerGoal0
@@ -955,7 +1217,7 @@
 			error("create_new_io_goal: one in / one out violation")
 		),
 		generate_call("table_io_copy_io_state", det,
-			[IoStateAssignFromVar, IoStateAssignToVar], no,
+			[IoStateAssignFromVar, IoStateAssignToVar], pure_code,
 			[IoStateAssignFromVar - ground(clobbered, none),
 			IoStateAssignToVar - ground(unique, none)],
 			ModuleInfo, Context, IoStateAssignGoal),
@@ -978,7 +1240,8 @@
 			- RestoreAnswerGoalInfo
 	),
 	generate_memo_save_goals(NumberedSaveVars, TipVar, BlockSize,
-		Context, !VarTypes, !VarSet, !TableInfo, SaveAnswerGoals),
+		TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
+		SaveAnswerGoals),
 	(
 		Unitize = table_io_alone,
 		CallSaveAnswerGoalList = [OrigGoal, TableIoDeclGoal
@@ -988,11 +1251,11 @@
 		generate_new_table_var("SavedTraceEnabled", int_type,
 			!VarTypes, !VarSet, SavedTraceEnabledVar),
 		generate_call("table_io_left_bracket_unitized_goal", det,
-			[SavedTraceEnabledVar], yes(impure),
+			[SavedTraceEnabledVar], impure_code,
 			ground_vars([SavedTraceEnabledVar]),
 			ModuleInfo, Context, LeftBracketGoal),
 		generate_call("table_io_right_bracket_unitized_goal", det,
-			[SavedTraceEnabledVar], yes(impure), [],
+			[SavedTraceEnabledVar], impure_code, [],
 			ModuleInfo, Context, RightBracketGoal),
 		CallSaveAnswerGoalList = [LeftBracketGoal, OrigGoal,
 			RightBracketGoal, TableIoDeclGoal | SaveAnswerGoals]
@@ -1098,18 +1361,18 @@
 %	).
 
 :- pred table_gen__create_new_mm_goal(determinism::in,
-	hlds_goal::in, pred_id::in, proc_id::in, list(prog_var)::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.
 
 table_gen__create_new_mm_goal(Detism, OrigGoal, PredId, ProcId,
-		HeadVars, InputVars, OutputVars, !VarTypes, !VarSet,
-		!TableInfo, SubgoalVar, Goal, Steps) :-
-	% even if the original goal doesn't use all of the headvars,
+		TablingViaExtraArgs, HeadVars, InputVars, OutputVars,
+		!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,
 	% so we need to compute the nonlocals from the headvars rather
-	% than getting it from the nonlocals field in the original goal
+	% than getting it from the nonlocals field in the original goal.
 	set__list_to_set(HeadVars, OrigNonLocals),
 	OrigGoal = _ - OrigGoalInfo,
 	goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
@@ -1120,16 +1383,17 @@
 	allocate_slot_numbers(OutputVars, 0, NumberedOutputVars),
 	list__length(NumberedOutputVars, BlockSize),
 	generate_mm_call_table_lookup_goal(NumberedInputVars, PredId, ProcId,
-		Context, !VarTypes, !VarSet, !TableInfo, SubgoalVar, StatusVar,
-		LookUpGoal, Steps),
+		TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
+		SubgoalVar, StatusVar, LookUpGoal, Steps),
 	generate_mm_save_goals(NumberedOutputVars, SubgoalVar, BlockSize,
-		Context, !VarTypes, !VarSet, !TableInfo, SaveAnswerGoals),
+		TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
+		SaveAnswerGoals),
 	generate_mm_restore_goal(Detism, NumberedOutputVars, OrigInstMapDelta,
-		SubgoalVar, ModuleInfo, Context, !VarTypes, !VarSet,
-		RestoreAllAnswerGoal),
+		SubgoalVar, ModuleInfo, TablingViaExtraArgs, Context,
+		!VarTypes, !VarSet, RestoreAllAnswerGoal),
 	generate_mm_suspend_goal(NumberedOutputVars, OrigInstMapDelta,
-		SubgoalVar, ModuleInfo, Context, !VarTypes, !VarSet,
-		SuspendGoal),
+		SubgoalVar, ModuleInfo, TablingViaExtraArgs, Context,
+		!VarTypes, !VarSet, SuspendGoal),
 
 	MainExpr = conj([OrigGoal | SaveAnswerGoals]),
 	set__insert(OrigNonLocals, SubgoalVar, MainNonLocals),
@@ -1140,7 +1404,7 @@
 	MainGoal = MainExpr - MainGoalInfo,
 
 	generate_call("table_mm_completion", det, [SubgoalVar],
-		yes(impure), [], ModuleInfo, Context, ResumeGoal0),
+		impure_code, [], ModuleInfo, Context, ResumeGoal0),
 	append_fail(ResumeGoal0, ResumeGoal),
 	InactiveExpr = disj([MainGoal, ResumeGoal]),
 	InactiveGoal = InactiveExpr - MainGoalInfo,
@@ -1165,6 +1429,312 @@
 
 %-----------------------------------------------------------------------------%
 
+% Example of transformation for nondet minimal_model_own_stack :
+%
+% :- pred p(int, int).
+% :- mode p(in, out) is nondet
+%
+% p(A, B) :- e(A, B).
+% p(A, B) :- p(A, C), e(C, B).
+%
+% The transformed code would be :
+%
+% p2_gen(A, B) :-
+%	impure table_mmos_pickup_generator(Generator),
+%	(
+%		(
+%			%
+%			% Original goals
+%			%
+%		),
+%
+%			% Check for duplicate answers.
+%		semipure table_mmos_get_answer_table(Generator, AT0),
+%		impure table_lookup_insert_int(AT0, B, AT1),
+%			Fail if the answer is already in the table;
+%			otherwise, put it into the table.
+%		impure table_mmos_answer_is_not_duplicate(AT1),
+%
+%			% Save the new answer in the table.
+%		impure table_mmos_create_answer_block(Generator, 1,
+%			AnswerBlock),
+%		impure table_save_int_ans(AnswerBlock, 0, B),
+%		impure table_mmos_return_answer(Generator, AnswerBlock)
+%	;
+%		impure table_mmos_completion(Generator)
+%	).
+%
+% p(A, B) :-
+%	table_mmos_save_inputs(1, A),		% into global variable
+%	CT0 = <table pointer for p/2>,
+%	impure table_lookup_insert_int(CT0, A, CT1),
+%	impure table_mmos_setup_consumer(CT1, 1, p2_gen, "p/2", Consumer),
+%	impure table_mmos_consume_next_answer_nondet(Consumer, AnswerBlock),
+%	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,
+	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.
+
+table_gen__do_own_stack_transform(Detism, OrigGoal, PredId, ProcId,
+		PredInfo0, ProcInfo0, HeadVars, InputVars, OutputVars,
+		!VarTypes, !VarSet, !TableInfo, !GenMap, TableTipVar,
+		Goal, Steps) :-
+	PredName = pred_info_name(PredInfo0),
+	( map__search(!.GenMap, PredId, GeneratorPredIdPrime) ->
+		GeneratorPredId = GeneratorPredIdPrime
+	;
+		clone_pred_info(PredInfo0, 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
+	% than getting it from the nonlocals field in the original goal.
+	set__list_to_set(HeadVars, OrigNonLocals),
+	OrigGoal = _ - OrigGoalInfo,
+	goal_info_get_instmap_delta(OrigGoalInfo, OrigInstMapDelta),
+	goal_info_get_context(OrigGoalInfo, Context),
+
+	list__length(InputVars, 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.
+	GeneratorPredType = c_pointer_type,
+
+	generate_new_table_var("GeneratorPredVar", GeneratorPredType,
+		!VarTypes, !VarSet, GeneratorPredVar),
+	generate_new_table_var("Consumer", consumer_type, !VarTypes, !VarSet,
+		ConsumerVar),
+
+	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),
+
+	TableTipVarName = table_tip_node_name,
+	GeneratorPredVarName = generator_pred_name,
+	ConsumerVarName = consumer_name,
+
+	TableTipArg = foreign_arg(TableTipVar,
+		yes(TableTipVarName - 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),
+
+	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),
+
+	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
+	% 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
+	generate_restore_goals(NumberedOutputVars, OrigInstMapDelta,
+		AnswerBlockVar, ModuleInfo, Context, !VarTypes, !VarSet,
+		RestoreGoals, _RestoreInstMapDeltaSrc, _RestoreArgs,
+		_RestoreCodeStr),
+
+	GoalExpr = conj([SaveGoal | LookupGoals] ++
+		[MakeGeneratorVarGoal, SetupGoal, GetNextAnswerGoal
+		| RestoreGoals]),
+	goal_info_init(OrigNonLocals, OrigInstMapDelta, Detism, impure,
+		Context, GoalInfo),
+	Goal = GoalExpr - GoalInfo,
+
+	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,
+		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.
+
+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).
+
+:- 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,
+	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,
+	OrigNonLocals, OrigInstMapDelta, !.VarTypes, !.VarSet, !TableInfo) :-
+
+	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),
+
+	list__length(NumberedOutputVars, BlockSize),
+	generate_own_stack_save_goal(NumberedOutputVars, GeneratorVar,
+		BlockSize, Context, !VarTypes, !VarSet, !TableInfo,
+		SaveAnswerGoals),
+
+	proc_info_goal(!.ProcInfo, OrigGoal),
+	GoalExpr = conj([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_add_feature(GoalInfo0, hide_debug_event, GoalInfo),
+	Goal = GoalExpr - GoalInfo,
+	proc_info_set_goal(Goal, !ProcInfo),
+
+	proc_info_set_vartypes(!.VarTypes, !ProcInfo),
+	proc_info_set_varset(!.VarSet, !ProcInfo),
+	pred_info_procedures(!.PredInfo, ProcTable0),
+	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_info::in, pred_id::out,
+	table_info::in, table_info::out) is det.
+
+clone_pred_info(PredInfo0, 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_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.
+	Status = local,
+	pred_info_get_goal_type(PredInfo0, GoalType),
+	pred_info_get_markers(PredInfo0, Markers0),
+	pred_info_arg_types(PredInfo0, ArgTypes0),
+	pred_info_typevarset(PredInfo0, TypeVarSet),
+	pred_info_get_exist_quant_tvars(PredInfo0, ExistQVars),
+	pred_info_get_class_context(PredInfo0, ClassContext),
+	pred_info_get_constraint_proofs(PredInfo0, ClassProofs),
+	pred_info_get_aditi_owner(PredInfo0, Owner),
+	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],
+
+	markers_to_marker_list(Markers0, MarkerList0),
+	list__filter(filter_marker, MarkerList0, MarkerList),
+	marker_list_to_markers(MarkerList, Markers),
+
+	pred_info_init(ModuleName, PredName, Arity, PredOrFunc, Context,
+		Status, GoalType, Markers, ArgTypes, TypeVarSet, ExistQVars,
+		ClassContext, ClassProofs, Owner, ClausesInfo, PredInfo),
+
+	ModuleInfo0 = !.TableInfo ^ table_module_info,
+	module_info_get_predicate_table(ModuleInfo0, PredTable0),
+	predicate_table_insert(PredInfo, GeneratorPredId,
+		PredTable0, PredTable),
+	module_info_set_predicate_table(PredTable, ModuleInfo0, ModuleInfo),
+	!:TableInfo = !.TableInfo ^ table_module_info := ModuleInfo.
+
+:- pred filter_marker(marker::in) is semidet.
+
+filter_marker(Marker) :-
+	keep_marker(Marker) = yes.
+
+:- func keep_marker(marker) = bool.
+
+keep_marker(stub) = no.
+keep_marker(infer_type) = no.
+keep_marker(infer_modes) = no.
+keep_marker(obsolete) = no.
+keep_marker(inline) = no.
+keep_marker(no_inline) = no.
+keep_marker(dnf) = no.
+keep_marker(aditi) = no.			% consider calling error
+keep_marker(base_relation) = no.		% consider calling error
+keep_marker(naive) = no.			% consider calling error
+keep_marker(psn) = no.				% consider calling error
+keep_marker(aditi_memo) = no.			% consider calling error
+keep_marker(aditi_no_memo) = no.		% consider calling error
+keep_marker(supp_magic) = no.			% consider calling error
+keep_marker(context) = no.			% consider calling error
+keep_marker(generate_inline) = no.		% consider calling error
+keep_marker(class_method) = no.
+keep_marker(class_instance_method) = no.
+keep_marker(named_class_instance_method) = no.
+keep_marker((impure)) = yes.
+keep_marker((semipure)) = yes.
+keep_marker(promised_pure) = yes.
+keep_marker(promised_semipure) = yes.
+keep_marker(terminates) = yes.
+keep_marker(does_not_terminate) = yes.
+keep_marker(check_termination) = no.
+keep_marker(calls_are_fully_qualified) = yes.
+
+%-----------------------------------------------------------------------------%
+
 :- pred create_renaming(list(prog_var)::in, vartypes::in, vartypes::out,
 	prog_varset::in, prog_varset::out, list(hlds_goal)::out,
 	list(prog_var)::out, map(prog_var, prog_var)::out) is det.
@@ -1225,15 +1795,16 @@
 	% 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,
+	assoc_list(prog_var, int)::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, 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,
@@ -1241,7 +1812,6 @@
 	generate_new_table_var("Status", StatusType, !VarTypes, !VarSet,
 		StatusVar),
 	ModuleInfo = !.TableInfo ^ table_module_info,
-	tabling_via_extra_args(ModuleInfo, TablingViaExtraArgs),
 	(
 		TablingViaExtraArgs = yes,
 		PredTableVarName = pred_table_name,
@@ -1285,14 +1855,14 @@
 			TableTipAssignStr,
 		generate_foreign_proc(CalledPred, det, tabling_c_attributes,
 			Args, LookupForeignArgs, LookupDeclCodeStr,
-			PredCodeStr, "", yes(impure), ground_vars(BoundVars),
+			PredCodeStr, "", impure_code, ground_vars(BoundVars),
 			ModuleInfo, Context, SetupGoal0),
 		attach_call_table_tip(SetupGoal0, SetupGoal),
 		list__append(LookupPrefixGoals, [SetupGoal], LookupSetupGoals)
 	;
 		TablingViaExtraArgs = no,
 		generate_call(SetupPred, det, [TableTipVar, StatusVar],
-			yes(impure), ground_vars([StatusVar]),
+			impure_code, ground_vars([StatusVar]),
 			ModuleInfo, Context, SetupGoal0),
 		attach_call_table_tip(SetupGoal0, SetupGoal),
 		list__append(LookupGoals, [SetupGoal], LookupSetupGoals)
@@ -1305,18 +1875,75 @@
 	Goal = GoalExpr - GoalInfo.
 
 	% Generate a goal for doing lookups in call tables for
-	% minimal model predicates.
+	% model_non memo predicates.
 
-:- pred generate_mm_call_table_lookup_goal(assoc_list(prog_var, int)::in,
+:- pred generate_memo_non_call_table_lookup_goal(assoc_list(prog_var, int)::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_mm_call_table_lookup_goal(NumberedVars, PredId, ProcId, Context,
-		!VarTypes, !VarSet, !TableInfo, SubgoalVar, StatusVar,
+generate_memo_non_call_table_lookup_goal(NumberedVars, PredId, ProcId, Context,
+		!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),
+	SetupPred = "table_memo_non_setup",
+	BoundVars = [RecordVar, StatusVar],
+	PredTableVarName = pred_table_name,
+	RecordVarName = memo_non_record_name,
+	StatusVarName = status_name,
+	PredTableArg = foreign_arg(PredTableVar,
+		yes(PredTableVarName - in_mode), trie_node_type),
+	RecordArg = foreign_arg(RecordVar,
+		yes(RecordVarName - out_mode), memo_non_record_type),
+	StatusArg = foreign_arg(StatusVar,
+		yes(StatusVarName - out_mode), memo_non_status_type),
+	Args = [PredTableArg, RecordArg, StatusArg],
+	LookupDeclCodeStr =
+		"\tMR_TrieNode " ++ cur_table_node_name ++ ";\n" ++
+		"\tMR_TrieNode " ++ next_table_node_name ++ ";\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),
+	attach_call_table_tip(SetupGoal0, SetupGoal),
+	list__append(LookupPrefixGoals, [SetupGoal], LookupSetupGoals),
+
+	GoalExpr = conj(LookupSetupGoals),
+	assoc_list__keys(NumberedVars, Vars),
+	set__list_to_set([StatusVar, RecordVar | Vars], NonLocals),
+	goal_info_init_hide(NonLocals, bind_vars([RecordVar, StatusVar]),
+		det, impure, Context, GoalInfo),
+	Goal = GoalExpr - GoalInfo.
+
+	% 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_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_mm_call_table_lookup_goal(NumberedVars, PredId, ProcId,
+		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),
@@ -1327,7 +1954,6 @@
 		StatusVar),
 	SetupPred = "table_mm_setup",
 	BoundVars = [SubgoalVar, StatusVar],
-	tabling_via_extra_args(ModuleInfo, TablingViaExtraArgs),
 	(
 		TablingViaExtraArgs = yes,
 		PredTableVarName = pred_table_name,
@@ -1352,14 +1978,14 @@
 			StatusVarName ++ ");\n",
 		generate_foreign_proc(SetupPred, det, tabling_c_attributes,
 			Args, LookupForeignArgs, LookupDeclCodeStr,
-			PredCodeStr, "", yes(impure), ground_vars(BoundVars),
+			PredCodeStr, "", impure_code, ground_vars(BoundVars),
 			ModuleInfo, Context, SetupGoal0),
 		attach_call_table_tip(SetupGoal0, SetupGoal),
 		list__append(LookupPrefixGoals, [SetupGoal], LookupSetupGoals)
 	;
 		TablingViaExtraArgs = no,
 		generate_call(SetupPred, det,
-			[TableTipVar, SubgoalVar, StatusVar], yes(impure),
+			[TableTipVar, SubgoalVar, StatusVar], impure_code,
 			ground_vars(BoundVars), ModuleInfo, Context,
 			SetupGoal0),
 		attach_call_table_tip(SetupGoal0, SetupGoal),
@@ -1482,7 +2108,7 @@
 			LookupPredName = "table_lookup_insert_enum",
 			generate_call(LookupPredName, det,
 				[TableVar, RangeVar, ArgVar, NextTableVar],
-				yes(impure), BindNextTableVar,
+				impure_code, BindNextTableVar,
 				ModuleInfo, Context, LookupGoal),
 			Goals = [RangeUnifyGoal, LookupGoal],
 			Step = table_trie_step_enum(EnumRange),
@@ -1511,7 +2137,7 @@
 				!TableInfo, TypeInfoVar, ExtraGoals),
 			generate_call(LookupPredName, det,
 				[TypeInfoVar, TableVar, ArgVar, NextTableVar],
-				yes(impure), BindNextTableVar,
+				impure_code, BindNextTableVar,
 				ModuleInfo, Context, CallGoal),
 			Goals = ExtraGoals ++ [CallGoal],
 			PrefixGoals = ExtraGoals,
@@ -1532,7 +2158,7 @@
 				LookupPredName),
 			generate_call(LookupPredName, det,
 				[TableVar, ArgVar, NextTableVar],
-				yes(impure), BindNextTableVar, ModuleInfo,
+				impure_code, BindNextTableVar, ModuleInfo,
 				Context, Goal),
 			Goals = [Goal],
 			PrefixGoals = [],
@@ -1552,22 +2178,22 @@
 	% in memo predicates.
 
 :- pred generate_memo_save_goals(assoc_list(prog_var, int)::in,
-	prog_var::in, int::in, term__context::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, Context,
-		!VarTypes, !VarSet, !TableInfo, Goals) :-
+generate_memo_save_goals(NumberedSaveVars, TableTipVar, BlockSize,
+		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, Context,
-			!VarTypes, !VarSet, !TableInfo, Goals, _, _)
+			CreatePredName, ShortcutPredName, TablingViaExtraArgs,
+			Context, !VarTypes, !VarSet, !TableInfo, Goals, _, _)
 	;
-		tabling_via_extra_args(ModuleInfo, TablingViaExtraArgs),
 		MarkAsSucceededPred = "table_memo_mark_as_succeeded",
 		(
 			TablingViaExtraArgs = yes,
@@ -1578,32 +2204,103 @@
 				"(" ++ cur_table_node_name ++ ");",
 			generate_foreign_proc(MarkAsSucceededPred, det,
 				tabling_c_attributes, [TableArg], [],
-				"", MarkAsSucceededCode, "", yes(impure), [],
+				"", MarkAsSucceededCode, "", impure_code, [],
 				ModuleInfo, Context, Goal)
 		;
 			TablingViaExtraArgs = no,
 			generate_call(MarkAsSucceededPred, det, [TableTipVar],
-				yes(impure), [], ModuleInfo, Context, Goal)
+				impure_code, [], ModuleInfo, Context, Goal)
 		),
 		Goals = [Goal]
 	).
 
 	% Generate a goal for saving the output arguments in an answer block
-	% in minimal model predicates.
+	% in model_non memo predicates.
 
-:- pred generate_mm_save_goals(assoc_list(prog_var, int)::in,
+:- pred generate_memo_non_save_goals(assoc_list(prog_var, int)::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.
 
-generate_mm_save_goals(NumberedSaveVars, TableVar, BlockSize, Context,
+generate_memo_non_save_goals(NumberedSaveVars, RecordVar, BlockSize, Context,
 		!VarTypes, !VarSet, !TableInfo, Goals) :-
 	ModuleInfo = !.TableInfo ^ table_module_info,
 	generate_new_table_var("AnswerTableVar", trie_node_type,
 		!VarTypes, !VarSet, AnswerTableVar),
+	RecordName = memo_non_record_name,
+	AnswerTableName = "AnswerTableVar",
+	RecordArg = foreign_arg(RecordVar,
+		yes(RecordName - in_mode), memo_non_record_type),
+	AnswerTableArg = foreign_arg(AnswerTableVar,
+		yes(AnswerTableName - in_mode), trie_node_type),
+	GetPredName = "table_memo_non_get_answer_table",
+	GetPredCode = "\tMR_" ++ GetPredName ++ "(" ++
+		RecordName ++ ", " ++ AnswerTableName ++ ");\n",
+	generate_foreign_proc(GetPredName, det, tabling_c_attributes,
+		[RecordArg, AnswerTableArg], [], "", GetPredCode, "",
+		semipure_code, ground_vars([AnswerTableVar]),
+		ModuleInfo, Context, GetAnswerTableGoal),
+	generate_table_lookup_goals(NumberedSaveVars, "AnswerTableNode",
+		Context, AnswerTableVar, _AnswerTableTipVar,
+		!VarTypes, !VarSet, !TableInfo, _LookupAnswerGoals, _,
+		LookupForeignArgs, LookupPrefixGoals, LookupCodeStr),
+
+	CreateAnswerBlockPred = "table_memo_non_create_answer_block",
+	CreateAnswerBlockPredShortcut = CreateAnswerBlockPred ++ "_shortcut",
+	generate_all_save_goals(NumberedSaveVars, RecordVar,
+		memo_non_record_type, memo_non_record_name, BlockSize,
+		CreateAnswerBlockPred, CreateAnswerBlockPredShortcut, yes,
+		Context, !VarTypes, !VarSet, !TableInfo, _SaveGoals,
+		SaveDeclCode, CreateSaveCode),
+
+	GetPredName = "table_memo_non_get_answer_table",
+	DuplCheckPredName = "table_memo_non_answer_is_not_duplicate",
+	DuplCheckPredNameShortcut = DuplCheckPredName ++ "_shortcut",
+
+	SuccName = "succeeded",
+	LookupDeclCodeStr =
+		"\tMR_TrieNode " ++ cur_table_node_name ++ ";\n" ++
+		"\tMR_TrieNode " ++ next_table_node_name ++ ";\n" ++
+		"\tMR_bool " ++ SuccName ++ ";\n",
+	GetLookupCodeStr =
+		"\tMR_" ++ GetPredName ++ "(" ++ RecordName ++ ", " ++
+			cur_table_node_name ++ ");\n" ++
+		LookupCodeStr,
+	DuplCheckCodeStr =
+		"\tMR_" ++ DuplCheckPredName ++ "(" ++
+			cur_table_node_name ++ ", " ++
+			SuccName ++ ");\n",
+	AssignSuccessCodeStr =
+		"\t" ++ success_indicator_name ++ " = " ++
+			SuccName ++ ";\n",
+	PreStr = LookupDeclCodeStr ++ SaveDeclCode ++ GetLookupCodeStr,
+	PostStr = "\tif (" ++ SuccName ++ ") {\n" ++
+		CreateSaveCode ++ "\t}\n" ++
+		AssignSuccessCodeStr,
+	generate_foreign_proc(DuplCheckPredNameShortcut, semidet,
+		tabling_c_attributes, [RecordArg], LookupForeignArgs,
+		PreStr, DuplCheckCodeStr, PostStr, impure_code, [],
+		ModuleInfo, Context, DuplicateCheckSaveGoal),
+	Goals = [GetAnswerTableGoal | LookupPrefixGoals] ++
+		[DuplicateCheckSaveGoal].
+
+	% 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,
+	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) :-
+	ModuleInfo = !.TableInfo ^ table_module_info,
+	generate_new_table_var("AnswerTableVar", trie_node_type,
+		!VarTypes, !VarSet, AnswerTableVar),
 	GetPredName = "table_mm_get_answer_table",
-	generate_call(GetPredName, det, [TableVar, AnswerTableVar],
-		yes(semipure), ground_vars([AnswerTableVar]),
+	generate_call(GetPredName, det, [SubgoalVar, AnswerTableVar],
+		semipure_code, ground_vars([AnswerTableVar]),
 		ModuleInfo, Context, GetAnswerTableGoal),
 	generate_table_lookup_goals(NumberedSaveVars, "AnswerTableNode",
 		Context, AnswerTableVar, AnswerTableTipVar, !VarTypes, !VarSet,
@@ -1613,17 +2310,16 @@
 	CreatePredName = "table_mm_create_answer_block",
 	ShortcutCreatePredName = "table_mm_fill_answer_block_shortcut",
 	generate_all_save_goals(NumberedSaveVars,
-		TableVar, subgoal_type, subgoal_name, BlockSize,
-		CreatePredName, ShortcutCreatePredName, Context,
-		!VarTypes, !VarSet, !TableInfo, SaveGoals,
+		SubgoalVar, subgoal_type, subgoal_name, BlockSize,
+		CreatePredName, ShortcutCreatePredName, TablingViaExtraArgs,
+		Context, !VarTypes, !VarSet, !TableInfo, SaveGoals,
 		SaveDeclCode, CreateSaveCode),
 
 	DuplCheckPredName = "table_mm_answer_is_not_duplicate",
-	tabling_via_extra_args(ModuleInfo, TablingViaExtraArgs),
 	(
 		TablingViaExtraArgs = yes,
 		SubgoalName = subgoal_name,
-		Args = [foreign_arg(TableVar, yes(SubgoalName - in_mode),
+		Args = [foreign_arg(SubgoalVar, yes(SubgoalName - in_mode),
 			subgoal_type)],
 		SuccName = "succeeded",
 		LookupDeclCodeStr =
@@ -1647,14 +2343,14 @@
 			AssignSuccessCodeStr,
 		generate_foreign_proc(DuplCheckPredName, semidet,
 			tabling_c_attributes, Args, LookupForeignArgs,
-			PreStr, DuplCheckCodeStr, PostStr, yes(impure), [],
+			PreStr, DuplCheckCodeStr, PostStr, impure_code, [],
 			ModuleInfo, Context, DuplicateCheckSaveGoal),
 		list__append(LookupPrefixGoals, [DuplicateCheckSaveGoal],
 			Goals)
 	;
 		TablingViaExtraArgs = no,
 		generate_call(DuplCheckPredName, semidet, [AnswerTableTipVar],
-			yes(impure), [], ModuleInfo, Context,
+			impure_code, [], ModuleInfo, Context,
 			DuplicateCheckGoal),
 		list__append([GetAnswerTableGoal | LookupAnswerGoals],
 			[DuplicateCheckGoal], LookupCheckGoals),
@@ -1665,21 +2361,20 @@
 
 :- pred generate_all_save_goals(assoc_list(prog_var, int)::in,
 	prog_var::in, (type)::in, string::in, int::in, string::in, string::in,
-	term__context::in, vartypes::in, vartypes::out,
+	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, string::out, string::out) is det.
 
 generate_all_save_goals(NumberedSaveVars, BaseVar, BaseVarType, BaseVarName,
-		BlockSize, CreatePredName, ShortcutPredName, Context,
-		!VarTypes, !VarSet, !TableInfo, Goals,
-		SaveDeclCodeStr, CreateSaveCodeStr) :-
+		BlockSize, CreatePredName, ShortcutPredName,
+		TablingViaExtraArgs, Context, !VarTypes, !VarSet, !TableInfo,
+		Goals, SaveDeclCodeStr, CreateSaveCodeStr) :-
 	generate_new_table_var("AnswerBlock", answer_block_type,
 		!VarTypes, !VarSet, AnswerBlockVar),
 	generate_save_goals(NumberedSaveVars, AnswerBlockVar, Context,
 		!VarTypes, !VarSet, !TableInfo, SaveGoals,
 		SaveArgs, SavePrefixGoals, SaveCodeStr),
 	ModuleInfo = !.TableInfo ^ table_module_info,
-	tabling_via_extra_args(ModuleInfo, TablingViaExtraArgs),
 	(
 		TablingViaExtraArgs = yes,
 		TableArg = foreign_arg(BaseVar, yes(BaseVarName - in_mode),
@@ -1687,19 +2382,17 @@
 		Args = [TableArg],
 		SaveDeclCodeStr = "\tMR_AnswerBlock " ++
 			answer_block_name ++ ";\n",
-		CreateCodeStr =
-			"\tMR_" ++ CreatePredName ++ "(" ++
+		CreateCodeStr = "\tMR_" ++ CreatePredName ++ "(" ++
 				BaseVarName ++ ", " ++
 				int_to_string(BlockSize) ++ ", " ++
 				answer_block_name ++ ");\n",
 		CreateSaveCodeStr = CreateCodeStr ++ SaveCodeStr,
-		ShortcutStr =
-			"\tMR_" ++ ShortcutPredName ++ "(" ++
+		ShortcutStr = "\tMR_" ++ ShortcutPredName ++ "(" ++
 				BaseVarName ++ ");\n",
 		generate_foreign_proc(ShortcutPredName, det,
 			tabling_c_attributes, Args, SaveArgs,
 			SaveDeclCodeStr ++ CreateSaveCodeStr, ShortcutStr, "",
-			yes(impure), [], ModuleInfo, Context, ShortcutGoal),
+			impure_code, [], ModuleInfo, Context, ShortcutGoal),
 		list__append(SavePrefixGoals, [ShortcutGoal], Goals)
 	;
 		TablingViaExtraArgs = no,
@@ -1707,7 +2400,7 @@
 			!VarSet, BlockSizeVar, BlockSizeVarUnifyGoal),
 		generate_call(CreatePredName, det,
 			[BaseVar, BlockSizeVar, AnswerBlockVar],
-			yes(impure), ground_vars([AnswerBlockVar]),
+			impure_code, ground_vars([AnswerBlockVar]),
 			ModuleInfo, Context, CreateAnswerBlockGoal),
 		Goals = [BlockSizeVarUnifyGoal, CreateAnswerBlockGoal |
 			SaveGoals],
@@ -1719,6 +2412,45 @@
 
 	% Generate a sequence of save goals for the given variables.
 
+:- pred generate_own_stack_save_goal(assoc_list(prog_var, int)::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.
+
+generate_own_stack_save_goal(NumberedOutputVars, GeneratorVar, BlockSize,
+		Context, !VarTypes, !VarSet, !TableInfo, Goals) :-
+	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),
+	% 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,
+		[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,
+		[GeneratorVar, BlockSizeVar, AnswerBlockVar], impure_code,
+		ground_vars([AnswerBlockVar]), ModuleInfo, Context,
+		CreateAnswerBlockGoal),
+	% use foreign_proc
+	generate_save_goals(NumberedOutputVars, AnswerBlockVar, Context,
+		!VarTypes, !VarSet, !TableInfo, SaveGoals, _X, _XX, _XXX),
+	TailGoals = SaveGoals,
+	Goals = [GetAnswerTableGoal | LookupAnswerGoals] ++
+		[DuplicateCheckGoal, BlockSizeVarUnifyGoal,
+		CreateAnswerBlockGoal | TailGoals].
+
 :- pred generate_save_goals(assoc_list(prog_var, int)::in, prog_var::in,
 	term__context::in, vartypes::in, vartypes::out,
 	prog_varset::in, prog_varset::out, table_info::in, table_info::out,
@@ -1731,8 +2463,8 @@
 		!VarTypes, !VarSet, !TableInfo, Goals, Args ++ RestArgs,
 		PrefixGoals ++ RestPrefixGoals, CodeStr ++ RestCodeStr) :-
 	NumberedVar = Var - Offset,
-	gen_int_construction("OffsetVar", Offset, !VarTypes,
-		!VarSet, OffsetVar, OffsetUnifyGoal),
+	gen_int_construction("OffsetVar", Offset, !VarTypes, !VarSet,
+		OffsetVar, OffsetUnifyGoal),
 	ModuleInfo = !.TableInfo ^ table_module_info,
 	map__lookup(!.VarTypes, Var, VarType),
 	classify_type(ModuleInfo, VarType) = TypeCat,
@@ -1759,7 +2491,7 @@
 	( type_util__type_is_io_state(Type) ->
 		SavePredName = "table_save_io_state_answer",
 		generate_call(SavePredName, det, [TableVar, OffsetVar, Var],
-			yes(impure), [], ModuleInfo, Context, Goal),
+			impure_code, [], ModuleInfo, Context, Goal),
 		Goals = [Goal],
 		Args = [ForeignArg],
 		PrefixGoals = [],
@@ -1782,7 +2514,7 @@
 		SavePredName = "table_save_any_answer",
 		generate_call(SavePredName, det,
 			[TypeInfoVar, TableVar, OffsetVar, Var],
-			yes(impure), [], ModuleInfo, Context, CallGoal),
+			impure_code, [], ModuleInfo, Context, CallGoal),
 		Goals = ExtraGoals ++ [CallGoal],
 		Args = [GenericForeignArg, TypeInfoForeignArg],
 		PrefixGoals = ExtraGoals,
@@ -1796,7 +2528,7 @@
 		string__append_list(["table_save_", CatString, "_answer"],
 			SavePredName),
 		generate_call(SavePredName, det, [TableVar, OffsetVar, Var],
-			yes(impure), [], ModuleInfo, Context, Goal),
+			impure_code, [], ModuleInfo, Context, Goal),
 		Goals = [Goal],
 		Args = [ForeignArg],
 		PrefixGoals = [],
@@ -1812,12 +2544,14 @@
 	% an answer block in memo predicates.
 
 :- pred generate_memo_restore_goal(assoc_list(prog_var, int)::in,
-	instmap_delta::in, prog_var::in, module_info::in, term__context::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, Context, !VarTypes, !VarSet, Goal) :-
+		ModuleInfo, TablingViaExtraArgs, Context, !VarTypes, !VarSet,
+		Goal) :-
 	(
 		NumberedOutputVars = [_ | _],
 		assoc_list__keys(NumberedOutputVars, OutputVars),
@@ -1828,7 +2562,6 @@
 			RestoreBlockVar, ModuleInfo, Context,
 			!VarTypes, !VarSet, RestoreGoals,
 			RestoreInstMapDeltaSrc, RestoreArgs, RestoreCodeStr),
-		tabling_via_extra_args(ModuleInfo, TablingViaExtraArgs),
 		(
 			TablingViaExtraArgs = yes,
 			BaseVarName = base_name,
@@ -1847,14 +2580,14 @@
 			generate_foreign_proc(ShortcutPredName, det,
 				tabling_c_attributes, Args, RestoreArgs,
 				DeclCodeStr, ShortcutStr, GetRestoreCodeStr,
-				yes(impure), RestoreInstMapDeltaSrc,
+				impure_code, RestoreInstMapDeltaSrc,
 				ModuleInfo, Context, ShortcutGoal),
 			Goal = ShortcutGoal
 		;
 			TablingViaExtraArgs = no,
 			generate_call(GetPredName, det,
 				[TipVar, RestoreBlockVar],
-				yes(semipure), ground_vars([RestoreBlockVar]),
+				semipure_code, ground_vars([RestoreBlockVar]),
 				ModuleInfo, Context, GetBlockGoal),
 			GoalExpr = conj([GetBlockGoal | RestoreGoals]),
 			set__list_to_set([TipVar | OutputVars], NonLocals),
@@ -1868,15 +2601,61 @@
 	).
 
 	% Generate a goal for restoring the output arguments from
-	% an answer block in minimal model predicates without a suspension.
+	% an answer block in model_non memo predicates.
 
-:- pred generate_mm_restore_goal(determinism::in,
+:- pred generate_memo_non_restore_goal(determinism::in,
 	assoc_list(prog_var, int)::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.
 
+generate_memo_non_restore_goal(Detism, NumberedOutputVars, OrigInstMapDelta,
+		RecordVar, ModuleInfo, Context, !VarTypes, !VarSet, Goal) :-
+	( Detism = multidet ->
+		ReturnAllAns = "table_memo_return_all_answers_multi"
+	; Detism = nondet ->
+		ReturnAllAns = "table_memo_return_all_answers_nondet"
+	;
+		error("generate_mm_restore_goal: invalid determinism")
+	),
+	generate_new_table_var("AnswerBlock", answer_block_type,
+		!VarTypes, !VarSet, AnswerBlockVar),
+	generate_call(ReturnAllAns, Detism, [RecordVar, AnswerBlockVar],
+		semipure_code, ground_vars([AnswerBlockVar]), ModuleInfo,
+		Context, ReturnAnswerBlocksGoal),
+	generate_restore_goals(NumberedOutputVars, OrigInstMapDelta,
+		AnswerBlockVar, ModuleInfo, Context, !VarTypes, !VarSet,
+		_RestoreGoals, RestoreInstMapDeltaSrc, RestoreArgs,
+		RestoreCodeStr),
+	assoc_list__keys(NumberedOutputVars, OutputVars),
+	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),
+
+	GoalExpr = conj([ReturnAnswerBlocksGoal, ShortcutGoal]),
+	set__list_to_set([RecordVar | OutputVars], NonLocals),
+	goal_info_init_hide(NonLocals, OrigInstMapDelta, Detism, semipure,
+		Context, GoalInfo),
+	Goal = GoalExpr - GoalInfo.
+
+	% 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,
+	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_restore_goal(Detism, NumberedOutputVars, OrigInstMapDelta,
-		SubgoalVar, ModuleInfo, Context, !VarTypes, !VarSet, Goal) :-
+		SubgoalVar, ModuleInfo, TablingViaExtraArgs, Context,
+		!VarTypes, !VarSet, Goal) :-
 	( Detism = multidet ->
 		ReturnAllAns = "table_mm_return_all_multi"
 	; Detism = nondet ->
@@ -1886,21 +2665,24 @@
 	),
 	generate_mm_restore_or_suspend_goal(ReturnAllAns, Detism, semipure,
 		NumberedOutputVars, OrigInstMapDelta, SubgoalVar, ModuleInfo,
-		Context, !VarTypes, !VarSet, Goal).
+		TablingViaExtraArgs, Context, !VarTypes, !VarSet, Goal).
 
 	% 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,
-	instmap_delta::in, prog_var::in, module_info::in, term__context::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, 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, Context, !VarTypes, !VarSet, Goal).
+		SubgoalVar, ModuleInfo, TablingViaExtraArgs, Context,
+		!VarTypes, !VarSet, Goal).
 
 	% Generate a goal for restoring the output arguments from
 	% an answer block in minimal model predicates. Whether the restore
@@ -1908,24 +2690,23 @@
 
 :- pred generate_mm_restore_or_suspend_goal(string::in, determinism::in,
 	purity::in, assoc_list(prog_var, int)::in, instmap_delta::in,
-	prog_var::in, module_info::in, term__context::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_restore_or_suspend_goal(PredName, Detism, Purity,
 		NumberedOutputVars, OrigInstMapDelta, SubgoalVar, ModuleInfo,
-		Context, !VarTypes, !VarSet, Goal) :-
+		TablingViaExtraArgs, Context, !VarTypes, !VarSet, Goal) :-
 	generate_new_table_var("AnswerBlock", answer_block_type,
 		!VarTypes, !VarSet, AnswerBlockVar),
 	generate_call(PredName, Detism, [SubgoalVar, AnswerBlockVar],
-		yes(semipure), ground_vars([AnswerBlockVar]), ModuleInfo,
+		semipure_code, ground_vars([AnswerBlockVar]), ModuleInfo,
 		Context, ReturnAnswerBlocksGoal),
 	generate_restore_goals(NumberedOutputVars, OrigInstMapDelta,
 		AnswerBlockVar, ModuleInfo, Context, !VarTypes, !VarSet,
 		RestoreGoals, RestoreInstMapDeltaSrc, RestoreArgs,
 		RestoreCodeStr),
 	assoc_list__keys(NumberedOutputVars, OutputVars),
-	tabling_via_extra_args(ModuleInfo, TablingViaExtraArgs),
 	(
 		TablingViaExtraArgs = yes,
 		Arg = foreign_arg(AnswerBlockVar,
@@ -1937,7 +2718,7 @@
 		generate_foreign_proc(ShortcutPredName, det,
 			tabling_c_attributes, Args, RestoreArgs,
 			"", ShortcutStr, RestoreCodeStr,
-			yes(impure), RestoreInstMapDeltaSrc, ModuleInfo,
+			impure_code, RestoreInstMapDeltaSrc, ModuleInfo,
 			Context, ShortcutGoal),
 		GoalExpr = conj([ReturnAnswerBlocksGoal, ShortcutGoal])
 	;
@@ -2008,7 +2789,7 @@
 		int_to_string(Offset) ++ ", " ++
 		Name ++ ");\n",
 	generate_call(RestorePredName, det, [TableVar, OffsetVar, Var],
-		yes(semipure), [Var - Inst], ModuleInfo, Context, Goal).
+		semipure_code, [Var - Inst], ModuleInfo, Context, Goal).
 
 %-----------------------------------------------------------------------------%
 
@@ -2016,9 +2797,9 @@
 
 infinite_recursion_msg = "detected infinite recursion".
 
-:- func bad_fail_msg = string.
+:- func need_minimal_model_msg = string.
 
-bad_fail_msg = "failed subgoal in model_det predicate".
+need_minimal_model_msg = "detected need for minimal model".
 
 :- pred generate_error_goal(table_info::in, term__context::in,
 	string::in, vartypes::in, vartypes::out,
@@ -2040,7 +2821,7 @@
 
 	gen_string_construction("Message", Message, !VarTypes, !VarSet,
 		MessageVar, MessageStrGoal),
-	generate_call("table_error", erroneous, [MessageVar], no, [],
+	generate_call("table_error", erroneous, [MessageVar], pure_code, [],
 		ModuleInfo, Context, CallGoal),
 
 	GoalExpr = conj([MessageStrGoal, CallGoal]),
@@ -2058,30 +2839,46 @@
 	varset__new_named_var(!.VarSet, Name, Var, !:VarSet),
 	map__set(!.VarTypes, Var, Type, !:VarTypes).
 
+:- type impure_or_semipure
+	--->	impure_code
+	;	semipure_code
+	;	pure_code.
+
+:- func impure_or_semipure_to_features(impure_or_semipure)
+	= list(goal_feature).
+
+impure_or_semipure_to_features(impure_code) =
+	[impure, not_impure_for_determinism].
+impure_or_semipure_to_features(semipure_code) =
+	[semipure, not_impure_for_determinism].
+impure_or_semipure_to_features(pure_code) = [].
+
 :- pred generate_call(string::in, determinism::in, list(prog_var)::in,
-	maybe(goal_feature)::in, assoc_list(prog_var, inst)::in,
+	impure_or_semipure::in, assoc_list(prog_var, inst)::in,
 	module_info::in, term__context::in, hlds_goal::out) is det.
 
-generate_call(PredName, Detism, Args, MaybeFeature, InstMapSrc,
+generate_call(PredName, Detism, Args, Purity, InstMapSrc,
 		ModuleInfo, Context, Goal) :-
 	mercury_table_builtin_module(BuiltinModule),
+	Features = impure_or_semipure_to_features(Purity),
 	goal_util__generate_simple_call(BuiltinModule, PredName, predicate,
-		only_mode, Detism, Args, MaybeFeature, InstMapSrc, ModuleInfo,
+		only_mode, Detism, Args, Features, InstMapSrc, ModuleInfo,
 		Context, Goal).
 
 :- pred 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, maybe(goal_feature)::in, assoc_list(prog_var, inst)::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,
-		PrefixCode, Code, SuffixCode, MaybeFeature, InstMapSrc,
+		PrefixCode, Code, SuffixCode, Purity, InstMapSrc,
 		ModuleInfo, Context, Goal) :-
 	mercury_table_builtin_module(BuiltinModule),
+	Features = impure_or_semipure_to_features(Purity),
 	goal_util__generate_foreign_proc(BuiltinModule, PredName, predicate,
 		only_mode, Detism, Attributes, Args, ExtraArgs,
-		PrefixCode, Code, SuffixCode, MaybeFeature, InstMapSrc,
+		PrefixCode, Code, SuffixCode, Features, InstMapSrc,
 		ModuleInfo, Context, Goal).
 
 :- pred append_fail(hlds_goal::in, hlds_goal::out) is det.
@@ -2113,17 +2910,23 @@
 		!VarTypes, !VarSet).
 
 :- func trie_node_type = (type).
+:- func memo_non_record_type = (type).
 :- func subgoal_type = (type).
 :- func answer_block_type = (type).
 :- func loop_status_type = (type).
 :- func memo_det_status_type = (type).
 :- func memo_semi_status_type = (type).
+:- func memo_non_status_type = (type).
 :- func mm_status_type = (type).
 
 trie_node_type = Type :-
 	mercury_table_builtin_module(TB),
 	construct_type(qualified(TB, "ml_trie_node") - 0, [], Type).
 
+memo_non_record_type = Type :-
+	mercury_table_builtin_module(TB),
+	construct_type(qualified(TB, "memo_non_record") - 0, [], Type).
+
 subgoal_type = Type :-
 	mercury_table_builtin_module(TB),
 	construct_type(qualified(TB, "ml_subgoal") - 0, [], Type).
@@ -2144,12 +2947,28 @@
 	mercury_table_builtin_module(TB),
 	construct_type(qualified(TB, "memo_semi_status") - 0, [], Type).
 
+memo_non_status_type = Type :-
+	mercury_table_builtin_module(TB),
+	construct_type(qualified(TB, "memo_non_status") - 0, [], Type).
+
 mm_status_type = Type :-
 	mercury_table_builtin_module(TB),
 	construct_type(qualified(TB, "mm_status") - 0, [], Type).
 
 %-----------------------------------------------------------------------------%
 
+:- func consumer_type = (type).
+
+consumer_type = Type :-
+	mercury_table_builtin_module(TB),
+	construct_type(qualified(TB, "ml_consumer") - 0, [], Type).
+
+:- func generator_type = (type).
+
+generator_type = Type :-
+	mercury_table_builtin_module(TB),
+	construct_type(qualified(TB, "ml_generator") - 0, [], Type).
+
 :- 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.
@@ -2333,8 +3152,7 @@
 	%
 	% Extract the information from table_info
 	%
-	table_info_extract(!.TableInfo, ModuleInfo0, PredId, ProcId,
-		PredInfo0, ProcInfo0),
+	table_info_extract(!.TableInfo, ModuleInfo0, PredInfo0, ProcInfo0),
 
 	%
 	% Put the varset and vartypes from the simplify_info
@@ -2362,8 +3180,7 @@
 	% Put the new module_info, pred_info, and proc_info back in the
 	% table_info.
 	%
-	table_info_init(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo,
-		!:TableInfo).
+	table_info_init(ModuleInfo, PredInfo, ProcInfo, !:TableInfo).
 
 %-----------------------------------------------------------------------------%
 
@@ -2402,45 +3219,57 @@
 :- func next_table_node_name = string.
 :- func table_tip_node_name = string.
 :- func base_name = string.
+:- func memo_non_record_name = string.
 :- func subgoal_name = string.
 :- func status_name = string.
 :- func answer_block_name = string.
 :- func success_indicator_name = string.
 :- func arg_name(int) = string.
+:- func num_input_args_name = string.
+:- func pred_name_var_name = string.
+:- func answer_table_name = string.
+:- func consumer_name = string.
+:- func generator_name = string.
+:- func generator_pred_name = string.
 
 pred_table_name = "pred_table".
 cur_table_node_name = "cur_node".
 next_table_node_name = "next_node".
 table_tip_node_name = "table_tip".
 base_name = "base".
+memo_non_record_name = "record".
 subgoal_name = "subgoal".
 status_name = "status".
 answer_block_name = "answerblock".
 success_indicator_name = "SUCCESS_INDICATOR".
 arg_name(VarSeqNum) = "arg" ++ int_to_string(VarSeqNum).
+num_input_args_name = "num_input_args".
+pred_name_var_name = "pred_name".
+answer_table_name = "answer_table".
+consumer_name = "consumer".
+generator_name = "generator".
+generator_pred_name = "generator_pred".
 
 %-----------------------------------------------------------------------------%
 
 :- type table_info
 	---> table_info(
 			table_module_info	:: module_info,
-			table_cur_pred_id	:: pred_id,
-			table_cur_proc_id	:: proc_id,
 			table_cur_pred_info	:: pred_info,
 			table_cur_proc_info	:: proc_info
 		).
 
-:- pred table_info_init(module_info::in, pred_id::in, proc_id::in,
+:- pred table_info_init(module_info::in,
 	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.
+	% pred_id::out, proc_id::out,
+	pred_info::out, proc_info::out) is det.
 
-table_info_init(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo, TableInfo) :-
-	TableInfo = table_info(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo).
+table_info_init(ModuleInfo, PredInfo, ProcInfo, TableInfo) :-
+	TableInfo = table_info(ModuleInfo, PredInfo, ProcInfo).
 
-table_info_extract(TableInfo, ModuleInfo, PredId, ProcId, PredInfo, ProcInfo)
-		:-
-	TableInfo = table_info(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo).
+table_info_extract(TableInfo, ModuleInfo, PredInfo, ProcInfo) :-
+	TableInfo = table_info(ModuleInfo, PredInfo, ProcInfo).
 
 %-----------------------------------------------------------------------------%
Index: compiler/typecheck.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/typecheck.m,v
retrieving revision 1.355
diff -u -b -r1.355 typecheck.m
--- compiler/typecheck.m	14 Jun 2004 04:16:41 -0000	1.355
+++ compiler/typecheck.m	15 Jul 2004 06:50:31 -0000
@@ -653,7 +653,7 @@
 	),
 	pred_info_context(!.PredInfo, Context),
 	generate_simple_call(mercury_private_builtin_module, CalleeName,
-		predicate, only_mode, det, [PredNameVar], no, [], ModuleInfo,
+		predicate, only_mode, det, [PredNameVar], [], [], ModuleInfo,
 		Context, CallGoal),
 	%
 	% Combine the unification and call into a conjunction
Index: compiler/unify_proc.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/unify_proc.m,v
retrieving revision 1.138
diff -u -b -r1.138 unify_proc.m
--- compiler/unify_proc.m	30 Jun 2004 02:48:18 -0000	1.138
+++ compiler/unify_proc.m	15 Jul 2004 06:50:38 -0000
@@ -1832,7 +1832,7 @@
 		MercuryBuiltin = mercury_private_builtin_module
 	),
 	goal_util__generate_simple_call(MercuryBuiltin, Name, predicate,
-		mode_no(0), erroneous, ArgVars, no, [], ModuleInfo,
+		mode_no(0), erroneous, ArgVars, [], [], ModuleInfo,
 		Context, Goal).
 
 :- pred unify_proc__build_specific_call((type)::in, special_pred_id::in,
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/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 java
cvs diff: Diffing java/runtime
cvs diff: Diffing library
Index: library/std_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/std_util.m,v
retrieving revision 1.294
diff -u -b -r1.294 std_util.m
--- library/std_util.m	20 Mar 2004 05:51:23 -0000	1.294
+++ library/std_util.m	22 Mar 2004 02:27:24 -0000
@@ -1320,7 +1320,7 @@
 	% In all other grades, this predicate is a noop.
 	[will_not_call_mercury, thread_safe],
 "
-#ifdef MR_USE_MINIMAL_MODEL
+#ifdef MR_USE_MINIMAL_MODEL_STACK_COPY
 	MR_pneg_enter_cond();
 #endif
 ").
@@ -1331,7 +1331,7 @@
 	% In all other grades, this predicate is a noop.
 	[will_not_call_mercury, thread_safe],
 "
-#ifdef MR_USE_MINIMAL_MODEL
+#ifdef MR_USE_MINIMAL_MODEL_STACK_COPY
 	MR_pneg_enter_then();
 #endif
 ").
@@ -1342,7 +1342,7 @@
 	% In all other grades, this predicate is a noop.
 	[will_not_call_mercury, thread_safe],
 "
-#ifdef MR_USE_MINIMAL_MODEL
+#ifdef MR_USE_MINIMAL_MODEL_STACK_COPY
 	MR_pneg_enter_else();
 #endif
 ").
Index: library/table_builtin.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/table_builtin.m,v
retrieving revision 1.38
diff -u -b -r1.38 table_builtin.m
--- library/table_builtin.m	2 Jul 2004 06:09:28 -0000	1.38
+++ library/table_builtin.m	17 Jul 2004 10:32:58 -0000
@@ -36,17 +36,19 @@
 % automatically inserted by the table_gen pass of the compiler
 % into predicates that use tabling, and the types they use.
 %
-% The predicates fall into five categories:
+% The predicates fall into the following categories:
 %
-% (1)	Predicates that manage loop checking.
+% - Predicates that manage loop checking.
 %
-% (2)	Predicates that manage memoization in general.
+% - Predicates that manage memoization in general.
 %
-% (3)	Predicates that manage memoization of I/O procedures.
+% - Predicates that manage memoization of I/O procedures.
 %
-% (4)	Predicates that manage minimal model tabling.
+% - Predicates that manage minimal model tabling using stack copying.
 %
-% (5)	Utility predicates that are needed in the tabling of all predicates.
+% - Predicates that manage minimal model tabling using own stacks.
+%
+% - Utility predicates that are needed in the tabling of all predicates.
 %
 % The utility predicates that handle tries are combined lookup/insert
 % operations; if the item being searched for is not already in the trie,
@@ -78,11 +80,17 @@
 % distinguish the two, and because an answer block pointer can be
 % associated with only one status value (memo_succeeded).
 %
-% For minimal model goals, the word at the end of the call table trie always
-% points to a subgoal structure, with several fields. The status of the
-% subgoal and the list of answers are two of these fields. Other fields,
-% described in runtime/mercury_minimal_model.h, are used in the implementation
-% of the minimal model.
+% For minimal model goals with stack copying, the word at the end of the call
+% table trie always points to a subgoal structure, with several fields. The
+% status of the subgoal and the list of answers are two of these fields. Other
+% fields, described in runtime/mercury_minimal_model.h, are used in the
+% implementation of the minimal model.
+%
+% For minimal model goals with own stacks, the word at the end of the call
+% table trie always points to a consumer structure, with several fields. The
+% status of the consumer and the list of answers are two of these fields. Other
+% fields, described in runtime/mercury_mm_own_stack.h, are used in the
+% implementation of the minimal model.
 %
 % All of the predicates here with the impure declaration modify the tabling
 % structures. Because the structures are persistent through backtracking,
@@ -93,13 +101,6 @@
 % so in the next three type definitions, only the C definition is useful.
 % The Mercury and IL definitions are placeholders only, required to make
 % this module compile cleanly on the Java and .NET backends respectively.
-%
-% XXX
-% All the types defined ought to be abstract types. The only reason why their
-% implementation is exported is that if they aren't, C code inside and
-% outside the module would end up using different C types to represent
-% values of these Mercury types, and lcc treats those type disagreements
-% as errors.
 
 	% This type represents the interior pointers of both call
 	% tables and answer tables.
@@ -150,9 +151,18 @@
 	loop_status::out) is det.
 
 	% Mark the call represented by the given table as currently
-	% not being evaluated (working on an answer).
+	% 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
 
 %-----------------------------------------------------------------------------%
@@ -180,6 +190,20 @@
 	MR_table_loop_mark_as_inactive(T);
 ").
 
+:- pragma foreign_proc("C",
+	table_loop_mark_as_inactive_and_fail(T::in),
+	[will_not_call_mercury],
+"
+	MR_table_loop_mark_as_inactive_and_fail(T);
+").
+
+:- pragma foreign_proc("C",
+	table_loop_mark_as_active_and_fail(T::in),
+	[will_not_call_mercury],
+"
+	MR_table_loop_mark_as_active_and_fail(T);
+").
+
 table_loop_setup(_, _) :-
 	% This version is only used for back-ends for which there is no
 	% matching foreign_proc version.
@@ -198,6 +222,20 @@
 	impure private_builtin__imp,
 	private_builtin__sorry("table_loop_mark_as_inactive").
 
+table_loop_mark_as_inactive_and_fail(_) :-
+	% This version is only used for back-ends for which there is no
+	% matching foreign_proc version.
+	impure private_builtin__imp,
+	private_builtin__sorry("table_loop_mark_as_inactive"),
+	fail.
+
+table_loop_mark_as_active_and_fail(_) :-
+	% This version is only used for back-ends for which there is no
+	% matching foreign_proc version.
+	impure private_builtin__imp,
+	private_builtin__sorry("table_loop_mark_as_active"),
+	fail.
+
 %-----------------------------------------------------------------------------%
 
 :- interface.
@@ -223,6 +261,17 @@
 	;	memo_semi_succeeded
 	;	memo_semi_failed.
 
+	% 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
+	;	memo_non_incomplete
+	;	memo_non_complete.
+
+:- type memo_non_record.
+
 :- impure pred table_memo_det_setup(ml_trie_node::in, memo_det_status::out)
 	is det.
 
@@ -235,12 +284,26 @@
 :- impure pred table_memo_semi_setup_shortcut(ml_trie_node::in,
 	ml_trie_node::out, memo_semi_status::out) is det.
 
+:- impure pred table_memo_non_setup(ml_trie_node::in,
+	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,
@@ -252,12 +315,42 @@
 	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.
+
+	% 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_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,
+	ml_answer_block::out) is multi.
+:- semipure pred table_memo_non_return_all_shortcut(memo_non_record::in)
+	is det.
+
 	% N.B. interface continued below
 
 %-----------------------------------------------------------------------------%
 
 :- implementation.
 
+:- type memo_non_record --->		memo_non_record(c_pointer).
+:- pragma foreign_type("C", memo_non_record, "MR_MemoNonRecordPtr",
+	[can_pass_as_mercury_type]).
+
 :- pragma foreign_proc("C",
 	table_memo_det_setup(T::in, Status::out),
 	[will_not_call_mercury],
@@ -287,6 +380,13 @@
 ").
 
 :- pragma foreign_proc("C",
+	table_memo_non_setup(T0::in, Record::out, Status::out),
+	[will_not_call_mercury],
+"
+	MR_table_memo_non_setup(T0, Record, Status);
+").
+
+:- pragma foreign_proc("C",
 	table_memo_mark_as_failed(T::in),
 	[will_not_call_mercury],
 "
@@ -301,6 +401,27 @@
 ").
 
 :- pragma foreign_proc("C",
+	table_memo_mark_as_incomplete(R::in),
+	[will_not_call_mercury],
+"
+	MR_table_memo_mark_as_incomplete(R);
+").
+
+:- pragma foreign_proc("C",
+	table_memo_mark_as_active_and_fail(R::in),
+	[will_not_call_mercury],
+"
+	MR_table_memo_mark_as_active_and_fail(R);
+").
+
+:- pragma foreign_proc("C",
+	table_memo_mark_as_complete_and_fail(R::in),
+	[will_not_call_mercury],
+"
+	MR_table_memo_mark_as_complete_and_fail(R);
+").
+
+:- pragma foreign_proc("C",
 	table_memo_create_answer_block(T::in, Size::in, AnswerBlock::out),
 	[will_not_call_mercury],
 "
@@ -328,6 +449,45 @@
 	MR_table_memo_get_answer_block_shortcut(T);
 ").
 
+:- pragma foreign_proc("C",
+	table_memo_non_get_answer_table(R::in, AT::out),
+	[will_not_call_mercury, promise_semipure],
+"
+	MR_table_memo_non_get_answer_table(R, AT);
+").
+
+:- pragma foreign_proc("C",
+	table_memo_non_answer_is_not_duplicate(T::in),
+	[will_not_call_mercury],
+"
+	MR_table_memo_non_answer_is_not_duplicate(T, SUCCESS_INDICATOR);
+").
+
+:- pragma foreign_proc("C",
+	table_memo_non_answer_is_not_duplicate_shortcut(R::in),
+	[will_not_call_mercury],
+"
+	MR_table_memo_non_answer_is_not_duplicate_shortcut(R,
+		SUCCESS_INDICATOR);
+").
+
+:- pragma foreign_proc("C",
+	table_memo_non_create_answer_block_shortcut(R::in),
+	[will_not_call_mercury],
+"
+	MR_table_memo_non_create_answer_block_shortcut(R::in);
+").
+
+:- pragma foreign_proc("C",
+	table_memo_non_return_all_shortcut(R::in),
+	[will_not_call_mercury, promise_semipure],
+"
+	MR_table_memo_non_return_all_shortcut(R);
+").
+
+:- external(table_memo_return_all_answers_nondet/2).
+:- external(table_memo_return_all_answers_multi/2).
+
 table_memo_det_setup(_, _) :-
 	% This version is only used for back-ends for which there is no
 	% matching foreign_proc version.
@@ -365,6 +525,24 @@
 	impure private_builtin__imp,
 	private_builtin__sorry("table_memo_mark_as_succeeded").
 
+table_memo_mark_as_incomplete(_) :-
+	% This version is only used for back-ends for which there is no
+	% matching foreign_proc version.
+	impure private_builtin__imp,
+	private_builtin__sorry("table_memo_mark_as_incomplete").
+
+table_memo_mark_as_active_and_fail(_) :-
+	% This version is only used for back-ends for which there is no
+	% matching foreign_proc version.
+	impure private_builtin__imp,
+	private_builtin__sorry("table_memo_mark_as_active_and_fail").
+
+table_memo_mark_as_complete_and_fail(_) :-
+	% This version is only used for back-ends for which there is no
+	% matching foreign_proc version.
+	impure private_builtin__imp,
+	private_builtin__sorry("table_memo_mark_as_complete_and_fail").
+
 table_memo_create_answer_block(_, _, _) :-
 	% This version is only used for back-ends for which there is no
 	% matching foreign_proc version.
@@ -383,12 +561,43 @@
 	semipure private_builtin__semip,
 	private_builtin__sorry("table_memo_get_answer_block").
 
+table_memo_non_return_all_shortcut(_) :-
+	% This version is only used for back-ends for which there is no
+	% matching foreign_proc version.
+	semipure private_builtin__semip,
+	private_builtin__sorry("table_memo_non_return_all_shortcut").
+
 table_memo_get_answer_block_shortcut(_) :-
 	% This version is only used for back-ends for which there is no
 	% matching foreign_proc version.
 	semipure private_builtin__semip,
 	private_builtin__sorry("table_memo_get_answer_block_shortcut").
 
+table_memo_non_get_answer_table(_, _) :-
+	% This version is only used for back-ends for which there is no
+	% matching foreign_proc version.
+	semipure private_builtin__semip,
+	private_builtin__sorry("table_memo_non_get_answer_table").
+
+table_memo_non_answer_is_not_duplicate(_) :-
+	% This version is only used for back-ends for which there is no
+	% matching foreign_proc version.
+	impure private_builtin__imp,
+	private_builtin__sorry("table_memo_non_answer_is_not_duplicate").
+
+table_memo_non_answer_is_not_duplicate_shortcut(_) :-
+	% This version is only used for back-ends for which there is no
+	% matching foreign_proc version.
+	impure private_builtin__imp,
+	private_builtin__sorry(
+		"table_memo_non_answer_is_not_duplicate_shortcut").
+
+table_memo_non_create_answer_block_shortcut(_) :-
+	% This version is only used for back-ends for which there is no
+	% matching foreign_proc version.
+	impure private_builtin__imp,
+	private_builtin__sorry("table_memo_non_create_answer_block_shortcut").
+
 %-----------------------------------------------------------------------------%
 
 :- interface.
@@ -554,7 +763,7 @@
 :- interface.
 
 %
-% Predicates that manage the tabling of model_non subgoals.
+% Predicates that manage the stack copy model of minimal model tabling.
 %
 
 	% This type should correspond exactly to the type MR_SubgoalStatus
@@ -566,7 +775,7 @@
 	;	mm_complete.
 
 	% This type represents the data structure at the tips of the call table
-	% in minimal_model predicates.
+	% in the stack copy implementation of minimal model tabling.
 :- type ml_subgoal.
 
 	% Check if this minimal_model subgoal has been called before.
@@ -699,6 +908,158 @@
 	% matching foreign_proc version.
 	impure private_builtin__imp,
 	private_builtin__sorry("table_mm_fill_answer_block_shortcut").
+
+%-----------------------------------------------------------------------------%
+
+:- interface.
+
+%
+% Predicates that manage the own stack model of minimal model tabling.
+%
+
+	% 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,
+	% indicating a subgoal. Create a generator for this subgoal if
+	% 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.
+
+	% 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.
+
+:- 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.
+
+	% Resume all suspended subgoal calls. This predicate will resume each
+	% 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]).
+:- pragma foreign_type(il,  ml_consumer, "class [mscorlib]System.Object").
+
+	% 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]).
+:- pragma foreign_type(il,  ml_generator, "class [mscorlib]System.Object").
+
+:- pragma foreign_proc("C",
+	table_mmos_save_inputs,
+	[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.
+	*/
+	MR_fatal_error(""table_mmos_save_inputs: direct call"");
+").
+
+:- pragma foreign_proc("C",
+	table_mmos_setup_consumer(T::in, GeneratorPred::in, Consumer::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 T, GeneratorPred, Consumer to shut up the warning */
+	MR_fatal_error(""table_mmos_setup_consumer: direct call"");
+").
+
+:- external(table_mmos_consume_next_answer_nondet/2).
+:- external(table_mmos_consume_next_answer_multi/2).
+
+:- 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_create_answer_block(Generator::in, BlockSize::in,
+		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 :-
+	private_builtin__imp.
+
+table_mmos_setup_consumer(_, _, Consumer) :-
+	private_builtin__imp,
+	% Required only to avoid warnings; never executed.
+	private_builtin__unsafe_type_cast(0, Consumer).
+
+table_mmos_get_answer_table(_, TrieNode) :-
+	private_builtin__imp,
+	% Required only to avoid warnings; never executed.
+	private_builtin__unsafe_type_cast(0, TrieNode).
+
+table_mmos_create_answer_block(_, _, AnswerBlock) :-
+	private_builtin__imp,
+	% Required only to avoid warnings; never executed.
+	private_builtin__unsafe_type_cast(0, AnswerBlock).
+
+table_mmos_return_answer(_, _) :-
+	private_builtin__imp.
+
+table_mmos_completion(_) :-
+	private_builtin__imp.
 
 %-----------------------------------------------------------------------------%
 
--------------------------------------------------------------------------
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