[m-rev.] for review: optimize calls to string.format and related predicates

Zoltan Somogyi zs at csse.unimelb.edu.au
Wed Sep 2 11:48:44 AEST 2009


Besides a review of the change itself, I am seeking feedback on what
exactly the optimization should do.

For optimizing e.g. io.format("%d_%d", [i(X), i(Y), !IO), this diff currently
generates

	V1 = int_to_string(X),
	V2 = "_"
	V3 = V2 ++ V1
	V4 = int_to_string(Y),
	V5 = V4 ++ V3
	io.write_string(V5, !IO)

Should it instead generate

	V1 = int_to_string(X),
	io.write_string(V1, !IO),
	V2 = "_"
	io.write_string(V2, !IO),
	V3 = int_to_string(Y),
	io.write_string(V3, !IO)

This avoids memory allocation, but it requires more overheads in the I/O
system, e.g. retrievals of the current output stream. What do you think?

Zoltan.

---------------------------------------------------------------------

Optimize calls to formatting functions and predicates such as

	Str = string.format("%s_%d", [s(Prefix), i(Num)])

into
	V1 = string.int_to_string(Num),
	V2 = "_" ++ V1,
	Str = Prefix ++ V2

essentially interpreting the format string at compile time rather than runtime.

At the moment, the optimization applies to calls to string.format/3,
io.format/3 and io.format/4, and only in the case where the format specifiers
are just "%c", "%d", or "%s", with no widths, precisions etc, though
that could be changed relatively easily, though at the cost of coupling
the compiler more tightly to the implementation of library/string.m.
(We don't handle %f, because float_to_string(F) yields a different string
than string.format("%f", [f(F)]). The former yields e.g. "1.23", while the
latter yields "1.23000".)

compiler/format_call.m:
	Change the code that looks for malformed calls to formatting predicates
	to also look for well-formed, optimizable calls, and to transform them
	as shown above.

mdbcomp/prim_data.m:
	List the standard library's string module here, since the compiler now
	needs to know what its name is (it generates calls to its predicates).

compiler/options.m:
doc/user_guide.texi:
	Add a new option, --optimize-format-calls, that calls for this
	optimization. Make it enabled by default.

compiler/simplify.m:
	Since the transformation in format_call.m will typically introduce
	nested conjunctions, we now do it before the rest of the
	simplifications. We also invoke the fixups needed by the output
	of format_call.m if it actually optimized any code.

	Delete the code that used to record whether the procedure has any
	format calls, since it now comes too late.

	Decide once, when setting up for processing a procedure, whether
	we want to invoke format_call.m if appropriate, instead of doing it
	later. This allows us to reduce the size of the simplications
	data structure we pass around.

	Protect the predicates that format_call.m can generate calls to
	from being deleted by dead_pred_elim before the simplification pass.

compiler/det_analysis.m:
	Since simplify.m itself cannot record early enough whether a given
	procedure body contains calls to formatting predicates, do it here.

compiler/det_info.m:
	Add a new field to the det_info that records whether we have seen
	a call to a formatting predicate.

	Add another field to the det_info that records the list of errors
	we have found so far, so that we can stop passing it around separately.

compiler/hlds_pred.m:
	Add a marker that allows det_analysis.m to record its conclusions.

compiler/hlds_goal.m:
	Add utility predicate.

compiler/goal_util.m:
	Make the predicates for creating new plain calls (and, for the sake of
	uniformity, calls to foreign code) take instmap_deltas, such as those
	created by the new utility functions in instmap.m. This allows these
	predicates' caller to avoid creating unnecessary intermediate data
	structures.

compiler/instmap.m:
	Make an existing predicate into a function to allow it to be used
	more flexibly.

	Move some utility functions for creating instmap_deltas here from
	table_gen.m, so that they can be used by other modules.

compiler/liveness.m:
	Delete an unused predicate.

compiler/accumulator.m:
compiler/add_heap_ops.m:
compiler/add_trail_ops.m:
compiler/builtin_lib_types.m:
compiler/common.m:
compiler/complexity.m:
compiler/deep_profiling.m:
compiler/deforest.m:
compiler/dep_par_conj.m:
compiler/det_report.m:
compiler/distance_granularity.m:
compiler/granularity.m:
compiler/higher_order.m:
compiler/hlds_out.m:
compiler/inlining.m:
compiler/intermod.m:
compiler/modecheck_unify.m:
compiler/modes.m:
compiler/pd_util.m:
compiler/prog_type.m:
compiler/purity.m:
compiler/rbmm.region_transformation.m:
compiler/size_prof.m:
compiler/ssdebug.m:
compiler/table_gen.m:
compiler/try_expand.m:
compiler/typecheck.m:
compiler/unify_proc.m:
	Conform to the changes above.

compiler/stm_expand.m:
	Conform to the changes above. Also, build pairs by using "-" directly
	as the function symbol, instead of this module's old practice
	of doing it the slow way by calling the "pair" function.

tests/general/string_format_lib.m:
	Cleanup the style of the code of this test case.

tests/hard_coded/opt_format.{m,exp}:
	New test case to exercise the behavior of format_call.m's
	transformation.

tests/hard_coded/Mmakefile:
tests/hard_coded/Mercury.options:
	Enable the new test case.

cvs diff: Diffing .
cvs diff: Diffing analysis
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/doc
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing boehm_gc/libatomic_ops-1.2
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/doc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/hpc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ibmc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/icc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/sunc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/tests
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing boehm_gc/windows-untested
cvs diff: Diffing boehm_gc/windows-untested/vc60
cvs diff: Diffing boehm_gc/windows-untested/vc70
cvs diff: Diffing boehm_gc/windows-untested/vc71
cvs diff: Diffing browser
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
Index: compiler/accumulator.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/accumulator.m,v
retrieving revision 1.72
diff -u -b -r1.72 accumulator.m
--- compiler/accumulator.m	30 Dec 2007 08:23:30 -0000	1.72
+++ compiler/accumulator.m	1 Sep 2009 01:27:25 -0000
@@ -1668,8 +1668,8 @@
     UniMode = LHSMode - RHSMode,
     Context = unify_context(umc_explicit, []),
     Expr = unify(Out, rhs_var(Acc), UniMode, assign(Out,Acc), Context),
-    set.list_to_set([Out,Acc], NonLocalVars),
-    instmap_delta_from_assoc_list([Out - ground(shared, none)], InstMapDelta),
+    set.list_to_set([Out, Acc], NonLocalVars),
+    InstMapDelta = instmap_delta_bind_var(Out),
     goal_info_init(NonLocalVars, InstMapDelta, detism_det, purity_pure, Info),
     Goal = hlds_goal(Expr, Info).
 
Index: compiler/add_heap_ops.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/add_heap_ops.m,v
retrieving revision 1.40
diff -u -b -r1.40 add_heap_ops.m
--- compiler/add_heap_ops.m	11 Jun 2009 07:00:05 -0000	1.40
+++ compiler/add_heap_ops.m	1 Sep 2009 01:27:33 -0000
@@ -47,6 +47,7 @@
 :- import_module hlds.goal_form.
 :- import_module hlds.goal_util.
 :- import_module hlds.hlds_goal.
+:- import_module hlds.instmap.
 :- import_module hlds.pred_table.
 :- import_module hlds.quantification.
 :- import_module libs.compiler_util.
@@ -175,8 +176,8 @@
             % 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.
-            heap_generate_call("unused", detism_det, purity_pure, [], [],
-                ModuleInfo, Context, ThenGoal)
+            heap_generate_call("unused", detism_det, purity_pure, [],
+                instmap_delta_bind_no_var, ModuleInfo, Context, ThenGoal)
         ;
             ( NumSolns = at_most_one
             ; NumSolns = at_most_many
@@ -244,8 +245,8 @@
             ModuleInfo = !.Info ^ heap_module_info,
             Context = goal_info_get_context(GoalInfo0),
             heap_generate_call("reclaim_heap_nondet_pragma_foreign_code",
-                detism_erroneous, purity_pure, [], [], ModuleInfo, Context,
-                SorryNotImplementedCode),
+                detism_erroneous, purity_pure, [], instmap_delta_bind_no_var,
+                ModuleInfo, Context, SorryNotImplementedCode),
             Goal = SorryNotImplementedCode
         ;
             ( Impl = fc_impl_ordinary(_, _)
@@ -334,7 +335,7 @@
 
 gen_mark_hp(SavedHeapPointerVar, Context, MarkHeapPointerGoal, !Info) :-
     heap_generate_call("mark_hp", detism_det, purity_impure,
-        [SavedHeapPointerVar], [SavedHeapPointerVar - ground_inst],
+        [SavedHeapPointerVar], instmap_delta_bind_var(SavedHeapPointerVar),
         !.Info ^ heap_module_info, Context, MarkHeapPointerGoal).
 
 :- pred gen_restore_hp(prog_var::in, prog_context::in, hlds_goal::out,
@@ -342,8 +343,8 @@
 
 gen_restore_hp(SavedHeapPointerVar, Context, RestoreHeapPointerGoal, !Info) :-
     heap_generate_call("restore_hp", detism_det, purity_impure,
-        [SavedHeapPointerVar], [], !.Info ^ heap_module_info, Context,
-        RestoreHeapPointerGoal).
+        [SavedHeapPointerVar], instmap_delta_bind_no_var,
+        !.Info ^ heap_module_info, Context, RestoreHeapPointerGoal).
 
 :- func ground_inst = mer_inst.
 
@@ -371,14 +372,14 @@
 %-----------------------------------------------------------------------------%
 
 :- pred heap_generate_call(string::in, determinism::in, purity::in,
-    list(prog_var)::in, assoc_list(prog_var, mer_inst)::in, module_info::in,
+    list(prog_var)::in, instmap_delta::in, module_info::in,
     term.context::in, hlds_goal::out) is det.
 
-heap_generate_call(PredName, Detism, Purity, Args, InstMap, ModuleInfo,
+heap_generate_call(PredName, Detism, Purity, Args, InstMapDelta, ModuleInfo,
         Context, CallGoal) :-
     goal_util.generate_simple_call(mercury_private_builtin_module, PredName,
-        pf_predicate, only_mode, Detism, Purity, Args, [], InstMap, ModuleInfo,
-        Context, CallGoal).
+        pf_predicate, only_mode, Detism, Purity, Args, [], InstMapDelta,
+        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.52
diff -u -b -r1.52 add_trail_ops.m
--- compiler/add_trail_ops.m	11 Jun 2009 07:00:06 -0000	1.52
+++ compiler/add_trail_ops.m	1 Sep 2009 09:13:15 -0000
@@ -72,6 +72,7 @@
 :- import_module hlds.goal_form.
 :- import_module hlds.goal_util.
 :- import_module hlds.hlds_goal.
+:- import_module hlds.instmap.
 :- import_module hlds.pred_table.
 :- import_module hlds.quantification.
 :- import_module libs.compiler_util.
@@ -189,8 +190,8 @@
             % 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.
-            trail_generate_call("unused", detism_det, purity_pure, [], [],
-                ModuleInfo, Context, ThenGoal)
+            trail_generate_call("unused", detism_det, purity_pure, [],
+                instmap_delta_bind_no_var, ModuleInfo, Context, ThenGoal)
         ;
             ( NumSolns = at_most_one
             ; NumSolns = at_most_many
@@ -352,8 +353,8 @@
             ModuleInfo = !.Info ^ trail_module_info,
             Context = goal_info_get_context(GoalInfo0),
             trail_generate_call("trailed_nondet_pragma_foreign_code",
-                detism_erroneous, purity_pure, [], [], ModuleInfo, Context,
-                SorryNotImplementedCode),
+                detism_erroneous, purity_pure, [], instmap_delta_bind_no_var,
+                ModuleInfo, Context, SorryNotImplementedCode),
             Goal = SorryNotImplementedCode
         ;
             ( Impl = fc_impl_ordinary(_, _)
@@ -448,7 +449,7 @@
     (
         GenerateInline = no,
         trail_generate_call("store_ticket", detism_det, purity_impure,
-            [TicketVar], [TicketVar - trail_ground_inst],
+            [TicketVar], instmap_delta_bind_var(TicketVar),
             Info ^ trail_module_info, Context, SaveTicketGoal)
     ;
         GenerateInline =  yes,
@@ -456,8 +457,8 @@
             ticket_type, native_if_possible)],
         ForeignCode = "MR_store_ticket(Ticket);",
         trail_generate_foreign_proc("store_ticket", purity_impure,
-            [TicketVar - trail_ground_inst], Info ^ trail_module_info, Context,
-            Args, ForeignCode, SaveTicketGoal)
+            instmap_delta_bind_var(TicketVar), Info ^ trail_module_info,
+            Context, Args, ForeignCode, SaveTicketGoal)
     ).
 
 :- pred gen_reset_ticket_undo(prog_var::in, prog_context::in, hlds_goal::out,
@@ -468,16 +469,16 @@
     (
         GenerateInline = no,
         trail_generate_call("reset_ticket_undo", detism_det, purity_impure,
-            [TicketVar], [], Info ^ trail_module_info, Context,
-            ResetTicketGoal)
+            [TicketVar], instmap_delta_bind_no_var, Info ^ trail_module_info,
+            Context, ResetTicketGoal)
     ;
         GenerateInline = yes,
         Args = [foreign_arg(TicketVar, yes("Ticket" - in_mode),
             ticket_type, native_if_possible)],
         ForeignCode = "MR_reset_ticket(Ticket, MR_undo);",
         trail_generate_foreign_proc("reset_ticket_undo", purity_impure,
-            [], Info ^ trail_module_info, Context, Args, ForeignCode,
-            ResetTicketGoal)
+            instmap_delta_bind_no_var, Info ^ trail_module_info,
+            Context, Args, ForeignCode, ResetTicketGoal)
     ).
 
 :- pred gen_reset_ticket_solve(prog_var::in, prog_context::in, hlds_goal::out,
@@ -488,16 +489,16 @@
     (
         GenerateInline = no,
         trail_generate_call("reset_ticket_solve", detism_det, purity_impure,
-            [TicketVar], [], Info ^ trail_module_info, Context,
-            ResetTicketGoal)
+            [TicketVar], instmap_delta_bind_no_var, Info ^ trail_module_info,
+            Context, ResetTicketGoal)
     ;
         GenerateInline = yes,
         Args = [foreign_arg(TicketVar, yes("Ticket" - in_mode),
             ticket_type, native_if_possible)],
         ForeignCode = "MR_reset_ticket(Ticket, MR_solve);",
         trail_generate_foreign_proc("reset_ticket_solve", purity_impure,
-            [], Info ^ trail_module_info, Context, Args, ForeignCode,
-            ResetTicketGoal)
+            instmap_delta_bind_no_var, Info ^ trail_module_info,
+            Context, Args, ForeignCode, ResetTicketGoal)
     ).
 
 :- pred gen_reset_ticket_commit(prog_var::in, prog_context::in, hlds_goal::out,
@@ -508,16 +509,16 @@
     (
         GenerateInline = no,
         trail_generate_call("reset_ticket_commit", detism_det, purity_impure,
-            [TicketVar], [], Info ^ trail_module_info, Context,
-            ResetTicketGoal)
+            [TicketVar], instmap_delta_bind_no_var, Info ^ trail_module_info,
+            Context, ResetTicketGoal)
     ;
         GenerateInline = yes,
         Args = [foreign_arg(TicketVar, yes("Ticket" - in_mode),
             ticket_type, native_if_possible)],
         ForeignCode = "MR_reset_ticket(Ticket, MR_commit);",
         trail_generate_foreign_proc("reset_ticket_commit", purity_impure,
-            [], Info ^ trail_module_info, Context, Args, ForeignCode,
-            ResetTicketGoal)
+            instmap_delta_bind_no_var, Info ^ trail_module_info,
+            Context, Args, ForeignCode, ResetTicketGoal)
     ).
 
 :- pred gen_prune_ticket(prog_context::in, hlds_goal::out,
@@ -527,15 +528,16 @@
     GenerateInline = Info ^ inline_ops,
     (
         GenerateInline = no,
-        trail_generate_call("prune_ticket", detism_det, purity_impure,
-            [], [], Info ^ trail_module_info, Context, PruneTicketGoal)
+        trail_generate_call("prune_ticket", detism_det, purity_impure, [],
+            instmap_delta_bind_no_var, Info ^ trail_module_info,
+            Context, PruneTicketGoal)
     ;
         GenerateInline = yes,
         Args = [],
         ForeignCode = "MR_prune_ticket();",
         trail_generate_foreign_proc("prune_ticket", purity_impure,
-            [], Info ^ trail_module_info, Context, Args, ForeignCode,
-            PruneTicketGoal)
+            instmap_delta_bind_no_var, Info ^ trail_module_info,
+            Context, Args, ForeignCode, PruneTicketGoal)
     ).
 
 :- pred gen_discard_ticket(prog_context::in, hlds_goal::out,
@@ -545,15 +547,16 @@
     GenerateInline = Info ^ inline_ops,
     (
         GenerateInline = no,
-        trail_generate_call("discard_ticket", detism_det, purity_impure,
-            [], [], Info ^ trail_module_info, Context, DiscardTicketGoal)
+        trail_generate_call("discard_ticket", detism_det, purity_impure, [],
+            instmap_delta_bind_no_var, Info ^ trail_module_info,
+            Context, DiscardTicketGoal)
     ;
         GenerateInline = yes,
         Args = [],
         ForeignCode = "MR_discard_ticket();",
         trail_generate_foreign_proc("discard_ticket", purity_impure,
-            [], Info ^ trail_module_info, Context, Args, ForeignCode,
-            DiscardTicketGoal)
+            instmap_delta_bind_no_var, Info ^ trail_module_info,
+            Context, Args, ForeignCode, DiscardTicketGoal)
     ).
 
 :- pred gen_mark_ticket_stack(prog_var::in, prog_context::in, hlds_goal::out,
@@ -565,8 +568,9 @@
     (
         GenerateInline = no,
         trail_generate_call("mark_ticket_stack", detism_det, purity_impure,
-            [SavedTicketCounterVar], [], Info ^ trail_module_info, Context,
-            MarkTicketStackGoal)
+            [SavedTicketCounterVar],
+            instmap_delta_bind_no_var, Info ^ trail_module_info,
+            Context, MarkTicketStackGoal)
     ;
         GenerateInline = yes,
         Args = [foreign_arg(SavedTicketCounterVar,
@@ -574,8 +578,8 @@
             native_if_possible)],
         ForeignCode = "MR_mark_ticket_stack(TicketCounter);",
         trail_generate_foreign_proc("mark_ticket_stack", purity_impure,
-            [], Info ^ trail_module_info, Context, Args, ForeignCode,
-            MarkTicketStackGoal)
+            instmap_delta_bind_no_var, Info ^ trail_module_info,
+            Context, Args, ForeignCode, MarkTicketStackGoal)
     ).
 
 :- pred gen_prune_tickets_to(prog_var::in, prog_context::in, hlds_goal::out,
@@ -587,8 +591,8 @@
     (
         GenerateInline = no,
         trail_generate_call("prune_tickets_to", detism_det, purity_impure,
-            [SavedTicketCounterVar], [], Info ^ trail_module_info, Context,
-            PruneTicketsToGoal)
+            [SavedTicketCounterVar], instmap_delta_bind_no_var,
+            Info ^ trail_module_info, Context, PruneTicketsToGoal)
     ;
         GenerateInline = yes,
         Args = [foreign_arg(SavedTicketCounterVar,
@@ -596,8 +600,8 @@
             native_if_possible)],
         ForeignCode = "MR_prune_tickets_to(TicketCounter);",
         trail_generate_foreign_proc("prune_tickets_to", purity_impure,
-            [], Info ^ trail_module_info, Context, Args, ForeignCode,
-            PruneTicketsToGoal)
+            instmap_delta_bind_no_var, Info ^ trail_module_info,
+            Context, Args, ForeignCode, PruneTicketsToGoal)
     ).
 
 :- func trail_ground_inst = mer_inst.
@@ -642,22 +646,22 @@
 %-----------------------------------------------------------------------------%
 
 :- pred trail_generate_call(string::in, determinism::in, purity::in,
-    list(prog_var)::in, assoc_list(prog_var, mer_inst)::in,
+    list(prog_var)::in, instmap_delta::in,
     module_info::in, term.context::in, hlds_goal::out) is det.
 
-trail_generate_call(PredName, Detism, Purity, Args, InstMap, ModuleInfo,
+trail_generate_call(PredName, Detism, Purity, Args, InstMapDelta, ModuleInfo,
         Context, CallGoal) :-
     goal_util.generate_simple_call(mercury_private_builtin_module, PredName,
-        pf_predicate, only_mode, Detism, Purity, Args, [], InstMap, ModuleInfo,
-        Context, CallGoal).
+        pf_predicate, only_mode, Detism, Purity, Args, [], InstMapDelta,
+        ModuleInfo, Context, CallGoal).
 
 %-----------------------------------------------------------------------------%
 
 :- pred trail_generate_foreign_proc(string::in, purity::in,
-    assoc_list(prog_var, mer_inst)::in, module_info::in, term.context::in,
+    instmap_delta::in, module_info::in, term.context::in,
     list(foreign_arg)::in, string::in, hlds_goal::out) is det.
 
-trail_generate_foreign_proc(PredName, Purity, InstMap,
+trail_generate_foreign_proc(PredName, Purity, InstMapDelta,
         ModuleInfo, Context, Args, ForeignCode, ForeignProcGoal) :-
     PrivateBuiltinModule = mercury_private_builtin_module,
     Detism = detism_det,
@@ -672,7 +676,7 @@
     MaybeTraceRuntimeCond = no,
     goal_util.generate_foreign_proc(PrivateBuiltinModule, PredName,
         pf_predicate, only_mode, Detism, Purity, FinalForeignProcAttrs, Args,
-        ExtraArgs, MaybeTraceRuntimeCond, ForeignCode, [], InstMap,
+        ExtraArgs, MaybeTraceRuntimeCond, ForeignCode, [], InstMapDelta,
         ModuleInfo, Context, ForeignProcGoal).
 
 %-----------------------------------------------------------------------------%
Index: compiler/builtin_lib_types.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/builtin_lib_types.m,v
retrieving revision 1.2
diff -u -b -r1.2 builtin_lib_types.m
--- compiler/builtin_lib_types.m	11 Jun 2009 08:28:25 -0000	1.2
+++ compiler/builtin_lib_types.m	1 Sep 2009 07:02:21 -0000
@@ -150,11 +150,11 @@
     Name = qualified(BuiltinModule, "comparison_result").
 
 io_state_type = defined_type(Name, [], kind_star) :-
-    Module = mercury_std_lib_module_name(unqualified("io")),
+    Module = mercury_io_module,
     Name = qualified(Module, "state").
 
 io_io_type = defined_type(Name, [], kind_star) :-
-    Module = mercury_std_lib_module_name(unqualified("io")),
+    Module = mercury_io_module,
     Name = qualified(Module, "io").
 
 univ_type = defined_type(Name, [], kind_star) :-
Index: compiler/bytecode_data.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/bytecode_data.m,v
retrieving revision 1.24
diff -u -b -r1.24 bytecode_data.m
--- compiler/bytecode_data.m	30 Dec 2007 08:23:31 -0000	1.24
+++ compiler/bytecode_data.m	1 Sep 2009 21:32:48 -0000
@@ -149,8 +149,7 @@
         )
     ->
         string.format(
-            "error: bytecode_data.output_int: " ++
-            "%d does not fit in %d bits",
+            "error: bytecode_data.output_int: %d does not fit in %d bits",
             [i(IntVal), i(Bits)], Msg),
         unexpected(this_file, Msg)
     ;
Index: compiler/common.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/common.m,v
retrieving revision 1.108
diff -u -b -r1.108 common.m
--- compiler/common.m	16 Jul 2008 03:30:26 -0000	1.108
+++ compiler/common.m	31 Aug 2009 23:27:59 -0000
@@ -799,7 +799,7 @@
 
     % `ToVar' may not appear in the original instmap_delta, so we can't just
     % use instmap_delta_restrict on the original instmap_delta here.
-    instmap_delta_from_assoc_list([ToVar - ToVarInst], InstMapDelta),
+    InstMapDelta = instmap_delta_from_assoc_list([ToVar - ToVarInst]),
 
     goal_info_init(NonLocals, InstMapDelta, detism_det, purity_pure,
         GoalInfo0),
Index: compiler/complexity.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/complexity.m,v
retrieving revision 1.32
diff -u -b -r1.32 complexity.m
--- compiler/complexity.m	11 Jun 2009 07:00:07 -0000	1.32
+++ compiler/complexity.m	31 Aug 2009 23:43:16 -0000
@@ -498,7 +498,7 @@
     MaybeTraceRuntimeCond = no,
     goal_util.generate_foreign_proc(BuiltinModule, PredName, pf_predicate,
         only_mode, Detism, purity_impure, Attrs, Args, ExtraArgs,
-        MaybeTraceRuntimeCond, Code, [], ground_vars(BoundVars),
+        MaybeTraceRuntimeCond, Code, [], instmap_delta_bind_vars(BoundVars),
         ModuleInfo, Context, Goal).
 
 %-----------------------------------------------------------------------------%
@@ -552,15 +552,6 @@
         allocate_slot_numbers_cl(VarInfos, Offset, NumberedProfiledVars)
     ).
 
-:- func ground_vars(list(prog_var)) = assoc_list(prog_var, mer_inst).
-
-ground_vars(Vars) = VarsAndGround :-
-    VarsAndGround = list.map(pair_with_ground, Vars).
-
-:- func pair_with_ground(prog_var) = pair(prog_var, mer_inst).
-
-pair_with_ground(Var) = Var - ground(shared, none).
-
 %-----------------------------------------------------------------------------%
 
 :- func is_active_type = mer_type.
Index: compiler/deep_profiling.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/deep_profiling.m,v
retrieving revision 1.100
diff -u -b -r1.100 deep_profiling.m
--- compiler/deep_profiling.m	2 Sep 2009 00:30:14 -0000	1.100
+++ compiler/deep_profiling.m	2 Sep 2009 00:33:42 -0000
@@ -1709,13 +1709,9 @@
         Goal) :-
     get_deep_profile_builtin_ppid(ModuleInfo, Name, Arity, PredId, ProcId),
     NonLocals = list_to_set(ArgVars),
-    Ground = ground(shared, none),
     (
         MaybeOutputVars = yes(OutputVars),
-        map((pred(V::in, P::out) is det :-
-            P = V - Ground
-        ), OutputVars, OutputInsts),
-        instmap_delta_from_assoc_list(OutputInsts, InstMapDelta)
+        InstMapDelta = instmap_delta_bind_vars(OutputVars)
     ;
         MaybeOutputVars = no,
         instmap_delta_init_unreachable(InstMapDelta)
@@ -1731,7 +1727,7 @@
 generate_unify(ConsId, Var, Goal) :-
     Ground = ground(shared, none),
     NonLocals = set.make_singleton_set(Var),
-    instmap_delta_from_assoc_list([Var - ground(shared, none)], InstMapDelta),
+    InstMapDelta = instmap_delta_bind_var(Var),
     Determinism = detism_det,
     goal_info_init(NonLocals, InstMapDelta, Determinism, purity_pure,
         GoalInfo1),
@@ -1749,7 +1745,7 @@
 generate_cell_unify(Length, ConsId, Args, Var, Goal) :-
     Ground = ground(shared, none),
     NonLocals = set.list_to_set([Var | Args]),
-    instmap_delta_from_assoc_list([Var - Ground], InstMapDelta),
+    InstMapDelta = instmap_delta_bind_var(Var),
     Determinism = detism_det,
     goal_info_init(NonLocals, InstMapDelta, Determinism, purity_pure,
         GoalInfo),
@@ -3016,7 +3012,7 @@
         CallGoalExpr = call_foreign_proc(ForeignCallAttrs, PredId, ProcId,
             ForeignArgVars, [], no, ForeignCode),
         NonLocals = list_to_set(ArgVars),
-        instmap_delta_from_assoc_list([], InstMapDelta),
+        InstMapDelta = instmap_delta_from_assoc_list([]),
         CallGoalInfo = impure_init_goal_info(NonLocals, InstMapDelta,
             detism_det),
         CallGoal = hlds_goal(CallGoalExpr, CallGoalInfo)
Index: compiler/deforest.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/deforest.m,v
retrieving revision 1.89
diff -u -b -r1.89 deforest.m
--- compiler/deforest.m	16 Jul 2009 03:10:00 -0000	1.89
+++ compiler/deforest.m	31 Aug 2009 19:44:08 -0000
@@ -244,7 +244,7 @@
                 % If the determinism of some sub-goals has changed,
                 % then we re-run determinism analysis. As with inlining.m,
                 % this avoids problems with inlining erroneous procedures.
-                det_infer_proc(PredId, ProcId, !ModuleInfo, _, _, _)
+                det_infer_proc(PredId, ProcId, !ModuleInfo, _, _, [], _)
             ;
                 RerunDet = no
             ),
Index: compiler/dep_par_conj.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/dep_par_conj.m,v
retrieving revision 1.35
diff -u -b -r1.35 dep_par_conj.m
--- compiler/dep_par_conj.m	11 Jun 2009 08:28:25 -0000	1.35
+++ compiler/dep_par_conj.m	1 Sep 2009 00:57:08 -0000
@@ -2578,15 +2578,15 @@
     ModuleName = mercury_par_builtin_module,
     PredName = new_future_pred_name,
     Features = [],
-    InstMapSrc = [FutureVar - ground(shared, none)],
+    InstMapDelta = instmap_delta_bind_var(FutureVar),
     Context = term.context_init,
     ShouldInline = should_inline_par_builtin_calls(ModuleInfo),
     (
         ShouldInline = no,
         ArgVars = [FutureVar],
         generate_simple_call(ModuleName, PredName, pf_predicate,
-            only_mode, detism_det, purity_pure, ArgVars, Features, InstMapSrc,
-            ModuleInfo, Context, AllocGoal)
+            only_mode, detism_det, purity_pure, ArgVars, Features,
+            InstMapDelta, ModuleInfo, Context, AllocGoal)
     ;
         ShouldInline = yes,
         ForeignAttrs = par_builtin_foreign_proc_attributes(purity_pure, no),
@@ -2597,7 +2597,7 @@
         Code = "MR_par_builtin_new_future(Future);",
         generate_foreign_proc(ModuleName, PredName, pf_predicate,
             only_mode, detism_det, purity_pure, ForeignAttrs, Args, ExtraArgs,
-            no, Code, Features, InstMapSrc, ModuleInfo, Context, AllocGoal)
+            no, Code, Features, InstMapDelta, ModuleInfo, Context, AllocGoal)
     ).
 
     % Given a variable SharedVar of type SharedVarType, add a new variable
@@ -2649,15 +2649,15 @@
         Code = "MR_par_builtin_get_future(Future, Value);"
     ),
     Features = [],
-    InstMapSrc = [ConsumedVar - ground(shared, none)],
+    InstMapDelta = instmap_delta_bind_var(ConsumedVar),
     Context = term.context_init,
     ShouldInline = should_inline_par_builtin_calls(ModuleInfo),
     (
         ShouldInline = no,
         ArgVars = [FutureVar, ConsumedVar],
         generate_simple_call(ModuleName, PredName, pf_predicate,
-            only_mode, detism_det, purity_pure, ArgVars, Features, InstMapSrc,
-            ModuleInfo, Context, WaitGoal)
+            only_mode, detism_det, purity_pure, ArgVars, Features,
+            InstMapDelta, ModuleInfo, Context, WaitGoal)
     ;
         ShouldInline = yes,
         ForeignAttrs = par_builtin_foreign_proc_attributes(purity_pure, no),
@@ -2669,7 +2669,7 @@
         ExtraArgs = [],
         generate_foreign_proc(ModuleName, PredName, pf_predicate,
             only_mode, detism_det, purity_pure, ForeignAttrs, Args, ExtraArgs,
-            no, Code, Features, InstMapSrc, ModuleInfo, Context, WaitGoal)
+            no, Code, Features, InstMapDelta, ModuleInfo, Context, WaitGoal)
     ).
 
 :- pred make_signal_goal(module_info::in, future_map::in, prog_var::in,
@@ -2680,7 +2680,7 @@
     ModuleName = mercury_par_builtin_module,
     PredName = signal_future_pred_name,
     Features = [],
-    InstMapSrc = [],
+    InstMapDelta = instmap_delta_bind_no_var,
     Context = term.context_init,
     ShouldInline = should_inline_par_builtin_calls(ModuleInfo),
     (
@@ -2688,7 +2688,7 @@
         ArgVars = [FutureVar, ProducedVar],
         generate_simple_call(ModuleName, PredName, pf_predicate,
             only_mode, detism_det, purity_impure, ArgVars, Features,
-            InstMapSrc, ModuleInfo, Context, SignalGoal)
+            InstMapDelta, ModuleInfo, Context, SignalGoal)
     ;
         ShouldInline = yes,
         ForeignAttrs = par_builtin_foreign_proc_attributes(purity_impure,
@@ -2702,7 +2702,7 @@
         Code = "MR_par_builtin_signal_future(Future, Value);",
         generate_foreign_proc(ModuleName, PredName, pf_predicate,
             only_mode, detism_det, purity_impure, ForeignAttrs,
-            Args, ExtraArgs, no, Code, Features, InstMapSrc, ModuleInfo,
+            Args, ExtraArgs, no, Code, Features, InstMapDelta, ModuleInfo,
             Context, SignalGoal)
     ).
 
Index: compiler/det_analysis.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/det_analysis.m,v
retrieving revision 1.220
diff -u -b -r1.220 det_analysis.m
--- compiler/det_analysis.m	11 Jun 2009 07:00:08 -0000	1.220
+++ compiler/det_analysis.m	31 Aug 2009 19:34:42 -0000
@@ -81,7 +81,7 @@
     %
 :- pred det_infer_proc(pred_id::in, proc_id::in,
     module_info::in, module_info::out, determinism::out, determinism::out,
-    list(error_spec)::out) is det.
+    list(error_spec)::in, list(error_spec)::out) is det.
 
 :- type pess_info
     --->    pess_info(prog_vars, prog_context).
@@ -94,8 +94,7 @@
 :- pred det_infer_goal(hlds_goal::in, hlds_goal::out, instmap::in,
     soln_context::in, list(failing_context)::in, maybe(pess_info)::in,
     determinism::out, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
     % Work out how many solutions are needed for a given determinism.
     %
@@ -110,6 +109,7 @@
 
 :- implementation.
 
+:- import_module check_hlds.format_call.
 :- import_module check_hlds.modecheck_call.
 :- import_module check_hlds.type_util.
 :- import_module hlds.code_model.
@@ -193,6 +193,11 @@
     ),
     (
         Changed = changed,
+        % We have not yet arrived at a fixpoint. Therefore the messages in
+        % Specs1 are based on possibly non-final determinisms of some
+        % procedures, which means that it is NOT safe to return them
+        % to be printed. Instead, we will compute them again from more
+        % up-to-date determinism information.
         global_inference_pass(!ModuleInfo, ProcList, Debug, Specs)
     ;
         Changed = unchanged,
@@ -210,8 +215,7 @@
 global_inference_single_pass([], _, !ModuleInfo, !Specs, !Changed).
 global_inference_single_pass([proc(PredId, ProcId) | PredProcs], Debug,
         !ModuleInfo, !Specs, !Changed) :-
-    det_infer_proc(PredId, ProcId, !ModuleInfo, OldDetism, NewDetism,
-        ProcSpecs),
+    det_infer_proc(PredId, ProcId, !ModuleInfo, OldDetism, NewDetism, !Specs),
     ( NewDetism = OldDetism ->
         ChangeStr = "old"
     ;
@@ -230,7 +234,6 @@
     ;
         Debug = no
     ),
-    !:Specs = ProcSpecs ++ !.Specs,
     global_inference_single_pass(PredProcs, Debug, !ModuleInfo, !Specs,
         !Changed).
 
@@ -249,21 +252,21 @@
 
 %-----------------------------------------------------------------------------%
 
-det_infer_proc(PredId, ProcId, !ModuleInfo, OldDetism, NewDetism, !:Specs) :-
+det_infer_proc(PredId, ProcId, !ModuleInfo, OldDetism, NewDetism, !Specs) :-
     % Get the proc_info structure for this procedure.
-    module_info_preds(!.ModuleInfo, Preds0),
-    map.lookup(Preds0, PredId, Pred0),
-    pred_info_get_procedures(Pred0, Procs0),
-    map.lookup(Procs0, ProcId, Proc0),
+    module_info_preds(!.ModuleInfo, PredTable0),
+    map.lookup(PredTable0, PredId, PredInfo0),
+    pred_info_get_procedures(PredInfo0, ProcTable0),
+    map.lookup(ProcTable0, ProcId, ProcInfo0),
 
     % Remember the old inferred determinism of this procedure.
-    proc_info_get_inferred_determinism(Proc0, OldDetism),
+    proc_info_get_inferred_determinism(ProcInfo0, OldDetism),
 
     % Work out whether or not the procedure occurs in a single-solution
     % context. Currently we only assume so if the predicate has an explicit
     % determinism declaration that says so.
     det_get_soln_context(OldDetism, OldInferredSolnContext),
-    proc_info_get_declared_determinism(Proc0, MaybeDeclaredDetism),
+    proc_info_get_declared_determinism(ProcInfo0, MaybeDeclaredDetism),
     (
         MaybeDeclaredDetism = yes(DeclaredDetism),
         det_get_soln_context(DeclaredDetism, DeclaredSolnContext)
@@ -282,14 +285,16 @@
     ),
 
     % Infer the determinism of the goal.
-    proc_info_get_goal(Proc0, Goal0),
-    proc_info_get_initial_instmap(Proc0, !.ModuleInfo, InstMap0),
-    proc_info_get_vartypes(Proc0, VarTypes),
+    proc_info_get_goal(ProcInfo0, Goal0),
+    proc_info_get_initial_instmap(ProcInfo0, !.ModuleInfo, InstMap0),
+    proc_info_get_vartypes(ProcInfo0, VarTypes),
     det_info_init(!.ModuleInfo, VarTypes, PredId, ProcId,
-        pess_extra_vars_report, DetInfo0),
+        pess_extra_vars_report, !.Specs, DetInfo0),
     det_infer_goal(Goal0, Goal, InstMap0, SolnContext, [], no,
-        InferDetism, _,  DetInfo0, DetInfo, [], !:Specs),
+        InferDetism, _,  DetInfo0, DetInfo),
     det_info_get_module_info(DetInfo, !:ModuleInfo),
+    det_info_get_error_specs(DetInfo, !:Specs),
+    det_info_get_has_format_call(DetInfo, HasFormatCalls),
 
     % Take the worst of the old and inferred detisms. This is needed to prevent
     % loops on p :- not(p), at least if the initial assumed detism is det.
@@ -303,10 +308,10 @@
     determinism_components(TentativeDetism, CanFail, MaxSoln),
 
     % Now see if the evaluation model can change the detism.
-    proc_info_get_eval_method(Proc0, EvalMethod),
+    proc_info_get_eval_method(ProcInfo0, EvalMethod),
     NewDetism = eval_method_change_determinism(EvalMethod, TentativeDetism),
     (
-        proc_info_has_io_state_pair(!.ModuleInfo, Proc0, _InArg, _OutArg),
+        proc_info_has_io_state_pair(!.ModuleInfo, ProcInfo0, _InArg, _OutArg),
         (
             MaybeDeclaredDetism = yes(ToBeCheckedDetism)
         ;
@@ -316,7 +321,7 @@
         determinism_to_code_model(ToBeCheckedDetism, ToBeCheckedCodeModel),
         ToBeCheckedCodeModel \= model_det
     ->
-        proc_info_get_context(Proc0, ProcContext),
+        proc_info_get_context(ProcInfo0, ProcContext),
         IOStateProcPieces = describe_one_proc_name_mode(!.ModuleInfo,
             should_not_module_qualify, proc(PredId, ProcId)),
         IOStatePieces = [words("In")] ++ IOStateProcPieces ++ [suffix(":"), nl,
@@ -365,14 +370,23 @@
     ),
 
     % Save the newly inferred information.
-    proc_info_set_goal(Goal, Proc0, Proc1),
-    proc_info_set_inferred_determinism(NewDetism, Proc1, Proc),
+    proc_info_set_goal(Goal, ProcInfo0, ProcInfo1),
+    proc_info_set_inferred_determinism(NewDetism, ProcInfo1, ProcInfo),
 
     % Put back the new proc_info structure.
-    map.det_update(Procs0, ProcId, Proc, Procs),
-    pred_info_set_procedures(Procs, Pred0, Pred),
-    map.det_update(Preds0, PredId, Pred, Preds),
-    module_info_set_preds(Preds, !ModuleInfo).
+    map.det_update(ProcTable0, ProcId, ProcInfo, ProcTable),
+    pred_info_set_procedures(ProcTable, PredInfo0, PredInfo1),
+    (
+        HasFormatCalls = no,
+        PredInfo = PredInfo1
+    ;
+        HasFormatCalls = yes,
+        pred_info_get_markers(PredInfo1, Markers1),
+        add_marker(marker_has_format_call, Markers1, Markers),
+        pred_info_set_markers(Markers, PredInfo1, PredInfo)
+    ),
+    map.det_update(PredTable0, PredId, PredInfo, PredTable),
+    module_info_set_preds(PredTable, !ModuleInfo).
 
 :- pred get_exported_proc_context(list(pragma_exported_proc)::in,
     pred_id::in, proc_id::in, prog_context::out) is semidet.
@@ -387,8 +401,7 @@
 %-----------------------------------------------------------------------------%
 
 det_infer_goal(Goal0, Goal, InstMap0, !.SolnContext, RightFailingContexts,
-        MaybePromiseEqvSolutionSets, Detism, GoalFailingContexts,
-        !DetInfo, !Specs) :-
+        MaybePromiseEqvSolutionSets, Detism, GoalFailingContexts, !DetInfo) :-
     Goal0 = hlds_goal(_, GoalInfo0),
     NonLocalVars = goal_info_get_nonlocals(GoalInfo0),
     InstmapDelta = goal_info_get_instmap_delta(GoalInfo0),
@@ -413,18 +426,17 @@
 
     det_infer_goal_1(Goal0, Goal, InstMap0, !.SolnContext, RightFailingContexts,
         MaybePromiseEqvSolutionSets, AddPruning, Detism, GoalFailingContexts,
-        !DetInfo, !Specs).
+        !DetInfo).
 
 :- pred det_infer_goal_1(hlds_goal::in, hlds_goal::out, instmap::in,
     soln_context::in, list(failing_context)::in, maybe(pess_info)::in,
     bool::in, determinism::out, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_goal_1(hlds_goal(GoalExpr0, GoalInfo0), hlds_goal(GoalExpr, GoalInfo),
         InstMap0, !.SolnContext, RightFailingContexts,
         MaybePromiseEqvSolutionSets, AddPruning, Detism, GoalFailingContexts,
-        !DetInfo, !Specs) :-
+        !DetInfo) :-
     InstmapDelta = goal_info_get_instmap_delta(GoalInfo0),
 
     (
@@ -454,7 +466,7 @@
 
     det_infer_goal_2(GoalExpr0, GoalExpr1, GoalInfo0, InstMap0, !.SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets,
-        InternalDetism0, GoalFailingContexts, !DetInfo, !Specs),
+        InternalDetism0, GoalFailingContexts, !DetInfo),
 
     determinism_components(InternalDetism0, InternalCanFail, InternalSolns0),
     (
@@ -563,12 +575,11 @@
     hlds_goal_info::in, instmap::in, soln_context::in,
     list(failing_context)::in, maybe(pess_info)::in,
     determinism::out, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_goal_2(GoalExpr0, GoalExpr, GoalInfo, InstMap0, SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets, Detism,
-        GoalFailingContexts, !DetInfo, !Specs) :-
+        GoalFailingContexts, !DetInfo) :-
     (
         GoalExpr0 = conj(ConjType, Goals0),
         (
@@ -577,71 +588,69 @@
             % determinism of the goals of that conjuction.
             det_infer_conj(Goals0, Goals, InstMap0, SolnContext,
                 RightFailingContexts, MaybePromiseEqvSolutionSets,
-                Detism, [], GoalFailingContexts, !DetInfo, !Specs)
+                Detism, [], GoalFailingContexts, !DetInfo)
         ;
             ConjType = parallel_conj,
             det_infer_par_conj(Goals0, Goals, GoalInfo, InstMap0, SolnContext,
                 RightFailingContexts, MaybePromiseEqvSolutionSets,
-                Detism, GoalFailingContexts, !DetInfo, !Specs)
+                Detism, GoalFailingContexts, !DetInfo)
         ),
         GoalExpr = conj(ConjType, Goals)
     ;
         GoalExpr0 = disj(Goals0),
         det_infer_disj(Goals0, Goals, GoalInfo, InstMap0, SolnContext,
             RightFailingContexts, MaybePromiseEqvSolutionSets,
-            Detism, GoalFailingContexts, !DetInfo, !Specs),
+            Detism, GoalFailingContexts, !DetInfo),
         GoalExpr = disj(Goals)
     ;
         GoalExpr0 = switch(Var, SwitchCanFail, Cases0),
         det_infer_switch(Var, SwitchCanFail, Cases0, Cases, GoalInfo, InstMap0,
             SolnContext, RightFailingContexts, MaybePromiseEqvSolutionSets,
-            Detism, GoalFailingContexts, !DetInfo, !Specs),
+            Detism, GoalFailingContexts, !DetInfo),
         GoalExpr = switch(Var, SwitchCanFail, Cases)
     ;
         GoalExpr0 = plain_call(PredId, ProcId0, Args, Builtin, UnifyContext,
             Name),
-        det_infer_call(PredId, ProcId0, ProcId, GoalInfo, SolnContext,
-            RightFailingContexts, Detism, GoalFailingContexts,
-            !.DetInfo, !Specs),
+        det_infer_call(PredId, ProcId0, ProcId, Args, GoalInfo, SolnContext,
+            RightFailingContexts, Detism, GoalFailingContexts, !DetInfo),
         GoalExpr = plain_call(PredId, ProcId, Args, Builtin, UnifyContext,
             Name)
     ;
         GoalExpr0 = generic_call(GenericCall, _ArgVars, _Modes, CallDetism),
         det_infer_generic_call(GenericCall, CallDetism, GoalInfo, SolnContext,
-            RightFailingContexts, Detism, GoalFailingContexts,
-            !.DetInfo, !Specs),
+            RightFailingContexts, Detism, GoalFailingContexts, !DetInfo),
         GoalExpr = GoalExpr0
     ;
         GoalExpr0 = unify(LHS, RHS0, Mode, Unify, UnifyContext),
         det_infer_unify(LHS, RHS0, Unify, UnifyContext, RHS, GoalInfo,
             InstMap0, SolnContext, RightFailingContexts, Detism,
-            GoalFailingContexts, !DetInfo, !Specs),
+            GoalFailingContexts, !DetInfo),
         GoalExpr = unify(LHS, RHS, Mode, Unify, UnifyContext)
     ;
         GoalExpr0 = if_then_else(Vars, Cond0, Then0, Else0),
         det_infer_if_then_else(Cond0, Cond, Then0, Then, Else0, Else,
             InstMap0, SolnContext, RightFailingContexts,
             MaybePromiseEqvSolutionSets, Detism, GoalFailingContexts,
-            !DetInfo, !Specs),
+            !DetInfo),
         GoalExpr = if_then_else(Vars, Cond, Then, Else)
     ;
         GoalExpr0 = negation(Goal0),
         det_infer_not(Goal0, Goal, GoalInfo, InstMap0,
             MaybePromiseEqvSolutionSets, Detism, GoalFailingContexts,
-            !DetInfo, !Specs),
+            !DetInfo),
         GoalExpr = negation(Goal)
     ;
         GoalExpr0 = scope(Reason, Goal0),
         det_infer_scope(Reason, Goal0, Goal, GoalInfo, InstMap0, SolnContext,
             RightFailingContexts, MaybePromiseEqvSolutionSets, Detism,
-            GoalFailingContexts, !DetInfo, !Specs),
+            GoalFailingContexts, !DetInfo),
         GoalExpr = scope(Reason, Goal)
     ;
         GoalExpr0 = call_foreign_proc(Attributes, PredId, ProcId,
             _Args, _ExtraArgs, _MaybeTraceRuntimeCond, PragmaCode),
         det_infer_foreign_proc(Attributes, PredId, ProcId, PragmaCode,
             GoalInfo, SolnContext, RightFailingContexts, Detism,
-            GoalFailingContexts, !.DetInfo, !Specs),
+            GoalFailingContexts, !DetInfo),
         GoalExpr = GoalExpr0
     ;
         GoalExpr0 = shorthand(ShortHand0),
@@ -650,7 +659,7 @@
                 OrElseGoals0, OrElseInners),
             det_infer_atomic(MainGoal0, MainGoal, OrElseGoals0, OrElseGoals,
                 InstMap0, SolnContext, RightFailingContexts,
-                MaybePromiseEqvSolutionSets, Detism, !DetInfo, !Specs),
+                MaybePromiseEqvSolutionSets, Detism, !DetInfo),
             GoalFailingContexts = [],
             ShortHand = atomic_goal(GoalType, Inner, Outer, Vars, MainGoal,
                 OrElseGoals, OrElseInners)
@@ -661,7 +670,7 @@
             % for a try goal.
             det_infer_goal_1(TryGoal0, TryGoal, InstMap0, SolnContext,
                 RightFailingContexts, MaybePromiseEqvSolutionSets, no, Detism,
-                GoalFailingContexts, !DetInfo, !Specs),
+                GoalFailingContexts, !DetInfo),
             ShortHand = try_goal(MaybeIO, ResultVar, TryGoal)
         ;
             ShortHand0 = bi_implication(_, _),
@@ -677,15 +686,14 @@
     soln_context::in, list(failing_context)::in, maybe(pess_info)::in,
     determinism::out,
     list(failing_context)::in, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_conj([], [], _InstMap0, _SolnContext, _RightFailingContexts,
         _MaybePromiseEqvSolutionSets, detism_det,
-        !ConjFailingContexts, !DetInfo, !Specs).
+        !ConjFailingContexts, !DetInfo).
 det_infer_conj([Goal0 | Goals0], [Goal | Goals], InstMap0, SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets, Detism,
-        !ConjFailingContexts, !DetInfo, !Specs) :-
+        !ConjFailingContexts, !DetInfo) :-
     % We should look to see when we get to a not_reached point
     % and optimize away the remaining elements of the conjunction.
     % But that optimization is done in the code generator anyway.
@@ -697,7 +705,7 @@
     update_instmap(Goal0, InstMap0, InstMap1),
     det_infer_conj(Goals0, Goals, InstMap1, SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets,
-        TailDetism, !ConjFailingContexts, !DetInfo, !Specs),
+        TailDetism, !ConjFailingContexts, !DetInfo),
     determinism_components(TailDetism, TailCanFail, _TailMaxSolns),
 
     % Next, work out whether the first conjunct is in a first_soln context
@@ -717,7 +725,7 @@
     det_infer_goal(Goal0, Goal, InstMap0, HeadSolnContext,
         !.ConjFailingContexts ++ RightFailingContexts,
         MaybePromiseEqvSolutionSets, HeadDetism, GoalFailingContexts,
-        !DetInfo, !Specs),
+        !DetInfo),
 
     % Finally combine the results computed above.
     det_conjunction_detism(HeadDetism, TailDetism, Detism),
@@ -727,15 +735,14 @@
     hlds_goal_info::in, instmap::in, soln_context::in,
     list(failing_context)::in, maybe(pess_info)::in,
     determinism::out, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_par_conj(Goals0, Goals, GoalInfo, InstMap0, SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets,
-        Detism, GoalFailingContexts, !DetInfo, !Specs) :-
+        Detism, GoalFailingContexts, !DetInfo) :-
     det_infer_par_conj_goals(Goals0, Goals, InstMap0, SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets,
-        Detism, [], GoalFailingContexts, !DetInfo, !Specs),
+        Detism, [], GoalFailingContexts, !DetInfo),
     (
         determinism_components(Detism, CanFail, Solns),
         CanFail = cannot_fail,
@@ -769,30 +776,29 @@
         sort_error_msgs(GoalMsgs, SortedGoalMsgs),
         Spec = error_spec(severity_error, phase_detism_check,
             [simple_msg(Context, [always(Pieces)])] ++ SortedGoalMsgs),
-        !:Specs = [Spec | !.Specs]
+        det_info_add_error_spec(Spec, !DetInfo)
     ).
 
 :- pred det_infer_par_conj_goals(list(hlds_goal)::in, list(hlds_goal)::out,
     instmap::in, soln_context::in, list(failing_context)::in,
     maybe(pess_info)::in, determinism::out,
     list(failing_context)::in, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_par_conj_goals([], [], _InstMap0, _SolnContext,
         _RightFailingContexts, _MaybePromiseEqvSolutionSets,
-        detism_det, !ConjFailingContexts, !DetInfo, !Specs).
+        detism_det, !ConjFailingContexts, !DetInfo).
 det_infer_par_conj_goals([Goal0 | Goals0], [Goal | Goals], InstMap0,
         SolnContext, RightFailingContexts, MaybePromiseEqvSolutionSets,
-        Detism, !ConjFailingContexts, !DetInfo, !Specs) :-
+        Detism, !ConjFailingContexts, !DetInfo) :-
     det_infer_goal(Goal0, Goal, InstMap0, SolnContext, RightFailingContexts,
         MaybePromiseEqvSolutionSets, HeadDetism, GoalFailingContexts,
-        !DetInfo, !Specs),
+        !DetInfo),
     determinism_components(HeadDetism, HeadCanFail, HeadMaxSolns),
 
     det_infer_par_conj_goals(Goals0, Goals, InstMap0, SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets,
-        TailDetism, !ConjFailingContexts, !DetInfo, !Specs),
+        TailDetism, !ConjFailingContexts, !DetInfo),
     determinism_components(TailDetism, TailCanFail, TailMaxSolns),
 
     det_conjunction_maxsoln(HeadMaxSolns, TailMaxSolns, MaxSolns),
@@ -804,16 +810,15 @@
     hlds_goal_info::in, instmap::in, soln_context::in,
     list(failing_context)::in, maybe(pess_info)::in,
     determinism::out, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_disj(Goals0, Goals, GoalInfo, InstMap0, SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets,
-        Detism, GoalFailingContexts, !DetInfo, !Specs) :-
+        Detism, GoalFailingContexts, !DetInfo) :-
     det_infer_disj_goals(Goals0, Goals, InstMap0, SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets,
         can_fail, at_most_zero, Detism, [], GoalFailingContexts0,
-        !DetInfo, !Specs),
+        !DetInfo),
     (
         Goals = [],
         Context = goal_info_get_context(GoalInfo),
@@ -828,20 +833,18 @@
     instmap::in, soln_context::in, list(failing_context)::in,
     maybe(pess_info)::in, can_fail::in, soln_count::in,
     determinism::out, list(failing_context)::in, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_disj_goals([], [], _InstMap0, _SolnContext, _RightFailingContexts,
         _MaybePromiseEqvSolutionSets, CanFail, MaxSolns, Detism,
-        !DisjFailingContexts, !DetInfo, !Specs) :-
+        !DisjFailingContexts, !DetInfo) :-
     determinism_components(Detism, CanFail, MaxSolns).
 det_infer_disj_goals([Goal0 | Goals0], [Goal | Goals], InstMap0, SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets,
-        !.CanFail, !.MaxSolns, Detism, !DisjFailingContexts,
-        !DetInfo, !Specs) :-
+        !.CanFail, !.MaxSolns, Detism, !DisjFailingContexts, !DetInfo) :-
     det_infer_goal(Goal0, Goal, InstMap0, SolnContext, RightFailingContexts,
         MaybePromiseEqvSolutionSets, FirstDetism, GoalFailingContexts,
-        !DetInfo, !Specs),
+        !DetInfo),
     determinism_components(FirstDetism, FirstCanFail, FirstMaxSolns),
     Goal = hlds_goal(_, GoalInfo),
     % If a disjunct cannot succeed but is marked with the
@@ -877,7 +880,7 @@
     ),
     det_infer_disj_goals(Goals0, Goals, InstMap0, SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets,
-        !.CanFail, !.MaxSolns, Detism, !DisjFailingContexts, !DetInfo, !Specs),
+        !.CanFail, !.MaxSolns, Detism, !DisjFailingContexts, !DetInfo),
     !:DisjFailingContexts = GoalFailingContexts ++ !.DisjFailingContexts.
 
 %-----------------------------------------------------------------------------%
@@ -887,12 +890,11 @@
     hlds_goal_info::in, instmap::in, soln_context::in,
     list(failing_context)::in, maybe(pess_info)::in,
     determinism::out, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_switch(Var, SwitchCanFail, Cases0, Cases, GoalInfo, InstMap0,
         SolnContext, RightFailingContexts, MaybePromiseEqvSolutionSets,
-        Detism, GoalFailingContexts, !DetInfo, !Specs) :-
+        Detism, GoalFailingContexts, !DetInfo) :-
     % The determinism of a switch is the worst of the determinism of each
     % of the cases. Also, if only a subset of the constructors are handled,
     % then it is semideterministic or worse - this is determined
@@ -901,7 +903,7 @@
     det_infer_switch_cases(Cases0, Cases, Var, InstMap0, SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets,
         cannot_fail, at_most_zero, CasesDetism, [], GoalFailingContexts0,
-        !DetInfo, !Specs),
+        !DetInfo),
     determinism_components(CasesDetism, CasesCanFail, CasesSolns),
     % The switch variable tests are in a first_soln context if and only
     % if the switch goal as a whole was in a first_soln context and the
@@ -917,7 +919,7 @@
     ExaminesRep = yes,
     det_check_for_noncanonical_type(Var, ExaminesRep, SwitchCanFail,
         SwitchSolnContext, GoalFailingContexts0, RightFailingContexts,
-        GoalInfo, ccuc_switch, !.DetInfo, SwitchSolns, !Specs),
+        GoalInfo, ccuc_switch, SwitchSolns, !DetInfo),
     det_conjunction_canfail(SwitchCanFail, CasesCanFail, CanFail),
     det_conjunction_maxsoln(SwitchSolns, CasesSolns, NumSolns),
     determinism_components(Detism, CanFail, NumSolns),
@@ -936,17 +938,16 @@
     instmap::in, soln_context::in, list(failing_context)::in,
     maybe(pess_info)::in, can_fail::in, soln_count::in,
     determinism::out, list(failing_context)::in, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_switch_cases([], [], _Var, _InstMap0, _SolnContext,
         _RightFailingContexts, _MaybePromiseEqvSolutionSets,
-        CanFail, MaxSolns, Detism, !SwitchFailingContexts, !DetInfo, !Specs) :-
+        CanFail, MaxSolns, Detism, !SwitchFailingContexts, !DetInfo) :-
     determinism_components(Detism, CanFail, MaxSolns).
 det_infer_switch_cases([Case0 | Cases0], [Case | Cases], Var, InstMap0,
         SolnContext, RightFailingContexts, MaybePromiseEqvSolutionSets,
         !.CanFail, !.MaxSolns, Detism, !SwitchFailingContexts,
-        !DetInfo, !Specs) :-
+        !DetInfo) :-
     % Technically, we should update the instmap to reflect the knowledge that
     % the var is bound to this particular constructor, but we wouldn't use
     % that information here anyway, so we don't bother.
@@ -959,7 +960,7 @@
     det_info_set_module_info(ModuleInfo, !DetInfo),
     det_infer_goal(Goal0, Goal, InstMap1, SolnContext, RightFailingContexts,
         MaybePromiseEqvSolutionSets, FirstDetism, GoalFailingContexts,
-        !DetInfo, !Specs),
+        !DetInfo),
     Case = case(MainConsId, OtherConsIds, Goal),
     determinism_components(FirstDetism, FirstCanFail, FirstMaxSolns),
     det_switch_canfail(!.CanFail, FirstCanFail, !:CanFail),
@@ -967,23 +968,35 @@
     det_infer_switch_cases(Cases0, Cases, Var, InstMap0, SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets,
         !.CanFail, !.MaxSolns, Detism, !SwitchFailingContexts,
-        !DetInfo, !Specs),
+        !DetInfo),
     !:SwitchFailingContexts = GoalFailingContexts ++ !.SwitchFailingContexts.
 
 %-----------------------------------------------------------------------------%
 
 :- pred det_infer_call(pred_id::in, proc_id::in, proc_id::out,
-    hlds_goal_info::in, soln_context::in,
+    list(prog_var)::in, hlds_goal_info::in, soln_context::in,
     list(failing_context)::in, determinism::out, list(failing_context)::out,
-    det_info::in, list(error_spec)::in, list(error_spec)::out) is det.
+    det_info::in, det_info::out) is det.
 
-det_infer_call(PredId, ProcId0, ProcId, GoalInfo, SolnContext,
-        RightFailingContexts, Detism, GoalFailingContexts, DetInfo, !Specs) :-
+det_infer_call(PredId, ProcId0, ProcId, Args, GoalInfo, SolnContext,
+        RightFailingContexts, Detism, GoalFailingContexts, !DetInfo) :-
     % For calls, just look up the determinism entry associated with
     % the called predicate.
     % This is the point at which annotations start changing
     % when we iterate to fixpoint for global determinism inference.
-    det_lookup_detism(DetInfo, PredId, ProcId0, Detism0),
+    det_lookup_pred_info_and_detism(!.DetInfo, PredId, ProcId0,
+        CalleePredInfo, Detism0),
+    
+    % We do the following so that simplify.m knows whether to invoke
+    % format_call.m *without* first having to traverse the procedure body.
+    det_info_get_module_info(!.DetInfo, ModuleInfo),
+    CalleeModuleName = pred_info_module(CalleePredInfo),
+    CalleeName = pred_info_name(CalleePredInfo),
+    ( is_format_call(CalleeModuleName, CalleeName, Args) ->
+        det_info_set_has_format_call(yes, !DetInfo)
+    ;
+        true
+    ),
 
     % Make sure we don't try to call a committed-choice pred
     % from a non-committed-choice context.
@@ -993,16 +1006,15 @@
         SolnContext = all_solns
     ->
         (
-            det_find_matching_non_cc_mode(DetInfo, PredId, ProcId0,
+            det_find_matching_non_cc_mode(!.DetInfo, PredId, ProcId0,
                 ProcIdPrime)
         ->
             ProcId = ProcIdPrime,
             determinism_components(Detism, CanFail, at_most_many)
         ;
             GoalContext = goal_info_get_context(GoalInfo),
-            det_get_proc_info(DetInfo, ProcInfo),
+            det_get_proc_info(!.DetInfo, ProcInfo),
             proc_info_get_varset(ProcInfo, VarSet),
-            det_info_get_module_info(DetInfo, ModuleInfo),
             PredPieces = describe_one_pred_name(ModuleInfo,
                 should_module_qualify, PredId),
             FirstPieces = [words("Error: call to")] ++ PredPieces ++
@@ -1015,7 +1027,7 @@
             Spec = error_spec(severity_error, phase_detism_check,
                 [simple_msg(GoalContext, [always(FirstPieces)])] ++
                 ContextMsgs),
-            !:Specs = [Spec | !.Specs],
+            det_info_add_error_spec(Spec, !DetInfo),
 
             ProcId = ProcId0,
             % Code elsewhere relies on the assumption that
@@ -1040,11 +1052,11 @@
 :- pred det_infer_generic_call(generic_call::in, determinism::in,
     hlds_goal_info::in, soln_context::in,
     list(failing_context)::in, determinism::out, list(failing_context)::out,
-    det_info::in, list(error_spec)::in, list(error_spec)::out) is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_generic_call(GenericCall, CallDetism, GoalInfo,
         SolnContext, RightFailingContexts, Detism, GoalFailingContexts,
-        DetInfo, !Specs) :-
+        !DetInfo) :-
     determinism_components(CallDetism, CanFail, NumSolns),
     Context = goal_info_get_context(GoalInfo),
     (
@@ -1053,17 +1065,17 @@
     ->
         % This error can only occur for higher-order calls.
         % Class method calls are only introduced by polymorphism.
-        det_get_proc_info(DetInfo, ProcInfo),
+        det_get_proc_info(!.DetInfo, ProcInfo),
         proc_info_get_varset(ProcInfo, VarSet),
         FirstPieces = [words("Error: higher-order call to predicate with"),
             words("determinism"), quote(mercury_det_to_string(CallDetism)),
             words("occurs in a context which requires all solutions."), nl],
-        det_info_get_module_info(DetInfo, ModuleInfo),
+        det_info_get_module_info(!.DetInfo, ModuleInfo),
         ContextMsgs = failing_contexts_description(ModuleInfo, VarSet,
             RightFailingContexts),
         Spec = error_spec(severity_error, phase_detism_check,
             [simple_msg(Context, [always(FirstPieces)])] ++ ContextMsgs),
-        !:Specs = [Spec | !.Specs],
+        det_info_add_error_spec(Spec, !DetInfo),
 
         % Code elsewhere relies on the assumption that
         % SolnContext = all_soln => NumSolns \= at_most_many_cc,
@@ -1086,14 +1098,14 @@
     pred_id::in, proc_id::in, pragma_foreign_code_impl::in,
     hlds_goal_info::in, soln_context::in,
     list(failing_context)::in, determinism::out, list(failing_context)::out,
-    det_info::in, list(error_spec)::in, list(error_spec)::out) is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_foreign_proc(Attributes, PredId, ProcId, PragmaCode,
         GoalInfo, SolnContext, RightFailingContexts,
-        Detism, GoalFailingContexts, DetInfo, !Specs) :-
+        Detism, GoalFailingContexts, !DetInfo) :-
     % Foreign_procs are handled in the same way as predicate calls.
 
-    det_info_get_module_info(DetInfo, ModuleInfo),
+    det_info_get_module_info(!.DetInfo, ModuleInfo),
     module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo),
     proc_info_get_declared_determinism(ProcInfo, MaybeDetism),
     (
@@ -1115,7 +1127,7 @@
                 words("to erroneous procedures.")],
             WillNotThrowSpec = error_spec(severity_error, phase_detism_check,
                 [simple_msg(ProcContext, [always(WillNotThrowPieces)])]),
-            !:Specs = [WillNotThrowSpec | !.Specs]
+            det_info_add_error_spec(WillNotThrowSpec, !DetInfo)
         ;
             true
         ),
@@ -1149,7 +1161,7 @@
             Spec = error_spec(severity_error, phase_detism_check,
                 [simple_msg(GoalContext, [always(WrongContextFirstPieces)])] ++
                 ContextMsgs),
-            !:Specs = [Spec | !.Specs],
+            det_info_add_error_spec(Spec, !DetInfo),
             NumSolns = at_most_many
         ;
             NumSolns = NumSolns1
@@ -1175,7 +1187,7 @@
             words("for a procedure without a determinism declaration.")],
         Spec = error_spec(severity_error, phase_detism_check,
             [simple_msg(Context, [always(Pieces)])]),
-        !:Specs = [Spec | !.Specs],
+        det_info_add_error_spec(Spec, !DetInfo),
         Detism = detism_erroneous,
         GoalFailingContexts = []
     ).
@@ -1186,12 +1198,11 @@
     unification::in, unify_context::in, unify_rhs::out,
     hlds_goal_info::in, instmap::in, soln_context::in,
     list(failing_context)::in, determinism::out, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_unify(LHS, RHS0, Unify, UnifyContext, RHS, GoalInfo, InstMap0,
         SolnContext, RightFailingContexts, Detism, GoalFailingContexts,
-        !DetInfo, !Specs) :-
+        !DetInfo) :-
     % Unifications are either deterministic or semideterministic.
     (
         RHS0 = rhs_lambda_goal(Purity, Groundness, PredOrFunc, EvalMethod,
@@ -1204,9 +1215,9 @@
         det_info_get_module_info(!.DetInfo, ModuleInfo),
         instmap.pre_lambda_update(ModuleInfo, Vars, Modes, InstMap0, InstMap1),
         det_infer_goal(Goal0, Goal, InstMap1, LambdaSolnContext, [],
-            no, LambdaInferredDet, _LambdaFailingContexts, !DetInfo, !Specs),
+            no, LambdaInferredDet, _LambdaFailingContexts, !DetInfo),
         det_check_lambda(LambdaDeclaredDet, LambdaInferredDet,
-            Goal, GoalInfo, InstMap1, !DetInfo, !Specs),
+            Goal, GoalInfo, InstMap1, !DetInfo),
         RHS = rhs_lambda_goal(Purity, Groundness, PredOrFunc, EvalMethod,
             NonLocalVars, Vars, Modes, LambdaDeclaredDet, Goal)
     ;
@@ -1219,7 +1230,7 @@
     det_infer_unify_examines_rep(Unify, ExaminesRepresentation),
     det_check_for_noncanonical_type(LHS, ExaminesRepresentation,
         UnifyCanFail, SolnContext, RightFailingContexts, [], GoalInfo,
-        ccuc_unify(UnifyContext), !.DetInfo, UnifyNumSolns, !Specs),
+        ccuc_unify(UnifyContext), UnifyNumSolns, !DetInfo),
     determinism_components(Detism, UnifyCanFail, UnifyNumSolns),
     (
         UnifyCanFail = can_fail,
@@ -1266,12 +1277,11 @@
     hlds_goal::in, hlds_goal::out, hlds_goal::in, hlds_goal::out,
     instmap::in, soln_context::in, list(failing_context)::in,
     maybe(pess_info)::in, determinism::out, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_if_then_else(Cond0, Cond, Then0, Then, Else0, Else, InstMap0,
         SolnContext, RightFailingContexts, MaybePromiseEqvSolutionSets,
-        Detism, GoalFailingContexts, !DetInfo, !Specs) :-
+        Detism, GoalFailingContexts, !DetInfo) :-
     % We process the goal right-to-left, doing the `then' before the
     % condition of the if-then-else, so that we can propagate the
     % SolnContext correctly.
@@ -1280,7 +1290,7 @@
     update_instmap(Cond0, InstMap0, InstMap1),
     det_infer_goal(Then0, Then, InstMap1, SolnContext, RightFailingContexts,
         MaybePromiseEqvSolutionSets, ThenDetism, ThenFailingContexts,
-        !DetInfo, !Specs),
+        !DetInfo),
     determinism_components(ThenDetism, ThenCanFail, ThenMaxSoln),
 
     % Next, work out the right soln_context to use for the condition.
@@ -1298,13 +1308,13 @@
     det_infer_goal(Cond0, Cond, InstMap0, CondSolnContext,
         ThenFailingContexts ++ RightFailingContexts,
         MaybePromiseEqvSolutionSets, CondDetism, _CondFailingContexts,
-        !DetInfo, !Specs),
+        !DetInfo),
     determinism_components(CondDetism, CondCanFail, CondMaxSoln),
 
     % Process the `else' part
     det_infer_goal(Else0, Else, InstMap0, SolnContext, RightFailingContexts,
         MaybePromiseEqvSolutionSets, ElseDetism, ElseFailingContexts,
-        !DetInfo, !Specs),
+        !DetInfo),
     determinism_components(ElseDetism, ElseCanFail, ElseMaxSoln),
 
     % Finally combine the results from the three parts.
@@ -1345,11 +1355,10 @@
 :- pred det_infer_not(hlds_goal::in, hlds_goal::out, hlds_goal_info::in,
     instmap::in, maybe(pess_info)::in,
     determinism::out, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_not(Goal0, Goal, GoalInfo, InstMap0, MaybePromiseEqvSolutionSets,
-        Detism, GoalFailingContexts, !DetInfo, !Specs) :-
+        Detism, GoalFailingContexts, !DetInfo) :-
     % Negations are almost always semideterministic. It is an error for
     % a negation to further instantiate any non-local variable. Such errors
     % will be reported by the mode analysis.
@@ -1359,7 +1368,7 @@
     % Answer: yes, probably, but it's not a high priority.
     det_infer_goal(Goal0, Goal, InstMap0, first_soln, [],
         MaybePromiseEqvSolutionSets, NegDetism, _NegatedGoalCanFail,
-        !DetInfo, !Specs),
+        !DetInfo),
     det_negation_det(NegDetism, MaybeDetism),
     (
         MaybeDetism = no,
@@ -1383,15 +1392,14 @@
 :- pred det_infer_atomic(hlds_goal::in, hlds_goal::out,
     list(hlds_goal)::in, list(hlds_goal)::out, instmap::in,
     soln_context::in, list(failing_context)::in, maybe(pess_info)::in,
-    determinism::out, det_info::in, det_info::out,
-    list(error_spec)::in, list(error_spec)::out) is det.
+    determinism::out, det_info::in, det_info::out) is det.
 
 det_infer_atomic(MainGoal0, MainGoal, OrElseGoals0, OrElseGoals, InstMap0,
         SolnContext, RightFailingContexts, MaybePromiseEqvSolutionSets0,
-        Detism, !DetInfo, !Specs) :-
+        Detism, !DetInfo) :-
     det_infer_atomic_goal(MainGoal0, MainGoal, InstMap0,
         SolnContext, RightFailingContexts, MaybePromiseEqvSolutionSets0,
-        MainDetism, !DetInfo, !Specs),
+        MainDetism, !DetInfo),
     (
         OrElseGoals0 = [],
         OrElseGoals = [],
@@ -1401,7 +1409,7 @@
         determinism_components(MainDetism, MainCanFail, MainMaxSolns),
         det_infer_orelse_goals(OrElseGoals0, OrElseGoals, InstMap0,
             SolnContext, RightFailingContexts, MaybePromiseEqvSolutionSets0,
-            MainCanFail, CanFail, MainMaxSolns, MaxSolns0, !DetInfo, !Specs),
+            MainCanFail, CanFail, MainMaxSolns, MaxSolns0, !DetInfo),
         (
             MaxSolns0 = at_most_zero,
             MaxSolns = at_most_zero
@@ -1424,15 +1432,14 @@
 
 :- pred det_infer_atomic_goal(hlds_goal::in, hlds_goal::out, instmap::in,
     soln_context::in, list(failing_context)::in, maybe(pess_info)::in,
-    determinism::out, det_info::in, det_info::out,
-    list(error_spec)::in, list(error_spec)::out) is det.
+    determinism::out, det_info::in, det_info::out) is det.
 
 det_infer_atomic_goal(Goal0, Goal, InstMap0,
         SolnContext, RightFailingContexts, MaybePromiseEqvSolutionSets0,
-        Detism, !DetInfo, !Specs) :-
+        Detism, !DetInfo) :-
     det_infer_goal(Goal0, Goal, InstMap0, SolnContext, RightFailingContexts,
         MaybePromiseEqvSolutionSets0, Detism, GoalFailingContexts,
-        !DetInfo, !Specs),
+        !DetInfo),
     (
         ( Detism = detism_det
         ; Detism = detism_cc_multi
@@ -1456,31 +1463,30 @@
             words("should be det or cc_multi.")],
         Spec = error_spec(severity_error, phase_detism_check,
             [simple_msg(Context, [always(Pieces)])]),
-        !:Specs = [Spec | !.Specs]
+        det_info_add_error_spec(Spec, !DetInfo)
     ).
 
 :- pred det_infer_orelse_goals(list(hlds_goal)::in, list(hlds_goal)::out,
     instmap::in, soln_context::in, list(failing_context)::in,
     maybe(pess_info)::in,
     can_fail::in, can_fail::out, soln_count::in, soln_count::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_orelse_goals([], [], _InstMap0,
         _SolnContext, _RightFailingContexts, _MaybePromiseEqvSolutionSets,
-        !CanFail, !MaxSolns, !DetInfo, !Specs).
+        !CanFail, !MaxSolns, !DetInfo).
 det_infer_orelse_goals([Goal0 | Goals0], [Goal | Goals], InstMap0,
         SolnContext, RightFailingContexts, MaybePromiseEqvSolutionSets,
-        !CanFail, !MaxSolns, !DetInfo, !Specs) :-
+        !CanFail, !MaxSolns, !DetInfo) :-
     det_infer_atomic_goal(Goal0, Goal, InstMap0,
         SolnContext, RightFailingContexts, MaybePromiseEqvSolutionSets,
-        FirstDetism, !DetInfo, !Specs),
+        FirstDetism, !DetInfo),
     determinism_components(FirstDetism, FirstCanFail, FirstMaxSolns),
     det_switch_canfail(!.CanFail, FirstCanFail, !:CanFail),
     det_switch_maxsoln(!.MaxSolns, FirstMaxSolns, !:MaxSolns),
     det_infer_orelse_goals(Goals0, Goals, InstMap0,
         SolnContext, RightFailingContexts, MaybePromiseEqvSolutionSets,
-        !CanFail, !MaxSolns, !DetInfo, !Specs).
+        !CanFail, !MaxSolns, !DetInfo).
 
 %-----------------------------------------------------------------------------%
 
@@ -1488,12 +1494,11 @@
     hlds_goal_info::in, instmap::in, soln_context::in,
     list(failing_context)::in, maybe(pess_info)::in,
     determinism::out, list(failing_context)::out,
-    det_info::in, det_info::out, list(error_spec)::in, list(error_spec)::out)
-    is det.
+    det_info::in, det_info::out) is det.
 
 det_infer_scope(Reason, Goal0, Goal, GoalInfo, InstMap0, SolnContext,
         RightFailingContexts, MaybePromiseEqvSolutionSets0, Detism,
-        GoalFailingContexts, !DetInfo, !Specs) :-
+        GoalFailingContexts, !DetInfo) :-
     % Existential quantification may require a cut to throw away solutions,
     % but we cannot rely on explicit quantification to detect this.
     % Therefore cuts are handled in det_infer_goal.
@@ -1531,7 +1536,7 @@
                         [option_is_set(warn_simple_code, yes,
                             [always(NestedOuterPieces)])])
                     ]),
-                !:Specs = [NestedSpec | !.Specs],
+                det_info_add_error_spec(NestedSpec, !DetInfo),
                 AllVars = set.union(list_to_set(OuterVars), list_to_set(Vars)),
                 MaybePromiseEqvSolutionSets =
                     yes(pess_info(to_sorted_list(AllVars), OuterContext))
@@ -1545,7 +1550,7 @@
                     words("a `promise_equivalent_solution_sets' scope.")],
                 ArbitrarySpec = error_spec(severity_error, phase_detism_check,
                     [simple_msg(Context, [always(ArbitraryPieces)])]),
-                !:Specs = [ArbitrarySpec | !.Specs]
+                det_info_add_error_spec(ArbitrarySpec, !DetInfo)
             ;
                 MaybePromiseEqvSolutionSets0 = yes(pess_info(OldVars,
                     PromiseContext)),
@@ -1581,7 +1586,7 @@
                         [simple_msg(Context, [always(OverlapPieces)]),
                         simple_msg(PromiseContext,
                             [always(OverlapPromisePieces)])]),
-                    !:Specs = [OverlapSpec | !.Specs]
+                    det_info_add_error_spec(OverlapSpec, !DetInfo)
                 )
             ),
             MaybePromiseEqvSolutionSets = no,
@@ -1634,7 +1639,7 @@
                 ++ list_to_pieces(MissingVarNames) ++ [suffix(".")],
             MissingSpec = error_spec(severity_error, phase_detism_check,
                 [simple_msg(Context, [always(MissingPieces)])]),
-            !:Specs = [MissingSpec | !.Specs]
+            det_info_add_error_spec(MissingSpec, !DetInfo)
         ),
         % Which vars were listed in the promise_equivalent_solutions
         % but not bound inside the scope?
@@ -1666,16 +1671,16 @@
                 list_to_pieces(ExtraVarNames) ++ [suffix(".")],
             ExtraSpec = error_spec(severity_error, phase_detism_check,
                 [simple_msg(Context, [always(ExtraPieces)])]),
-            !:Specs = [ExtraSpec | !.Specs]
+            det_info_add_error_spec(ExtraSpec, !DetInfo)
         ),
         det_infer_goal(Goal0, Goal, InstMap0, SolnContextToUse,
             RightFailingContexts, MaybePromiseEqvSolutionSets, Detism,
-            GoalFailingContexts, !DetInfo, !Specs)
+            GoalFailingContexts, !DetInfo)
     ;
         Reason = trace_goal(_, _, _, _, _),
         det_infer_goal(Goal0, Goal, InstMap0, SolnContext,
             RightFailingContexts, MaybePromiseEqvSolutionSets0,
-            Detism, GoalFailingContexts, !DetInfo, !Specs),
+            Detism, GoalFailingContexts, !DetInfo),
         (
             ( Detism = detism_det
             ; Detism = detism_cc_multi
@@ -1690,7 +1695,7 @@
                 words("should be det or cc_multi.")],
             Spec = error_spec(severity_error, phase_detism_check,
                 [simple_msg(Context, [always(Pieces)])]),
-            !:Specs = [Spec | !.Specs]
+            det_info_add_error_spec(Spec, !DetInfo)
         )
     ;
         ( Reason = exist_quant(_)
@@ -1700,7 +1705,7 @@
         ),
         det_infer_goal(Goal0, Goal, InstMap0, SolnContext,
             RightFailingContexts, MaybePromiseEqvSolutionSets0,
-            Detism, GoalFailingContexts, !DetInfo, !Specs)
+            Detism, GoalFailingContexts, !DetInfo)
     ;
         Reason = from_ground_term(_, FromGroundTermKind),
         (
@@ -1714,7 +1719,7 @@
             ),
             det_infer_goal(Goal0, Goal, InstMap0, SolnContext,
                 RightFailingContexts, MaybePromiseEqvSolutionSets0,
-                Detism, GoalFailingContexts, !DetInfo, !Specs)
+                Detism, GoalFailingContexts, !DetInfo)
         )
     ).
 
@@ -1758,22 +1763,22 @@
 
 :- pred det_check_for_noncanonical_type(prog_var::in, bool::in, can_fail::in,
     soln_context::in, list(failing_context)::in, list(failing_context)::in,
-    hlds_goal_info::in, cc_unify_context::in, det_info::in, soln_count::out,
-    list(error_spec)::in, list(error_spec)::out) is det.
+    hlds_goal_info::in, cc_unify_context::in, soln_count::out,
+    det_info::in, det_info::out) is det.
 
 det_check_for_noncanonical_type(Var, ExaminesRepresentation, CanFail,
         SolnContext, FailingContextsA, FailingContextsB, GoalInfo, GoalContext,
-        DetInfo, NumSolns, !Specs) :-
+        NumSolns, !DetInfo) :-
     (
         % Check for unifications that attempt to examine the representation
         % of a type that does not have a single representation for each
         % abstract value.
 
         ExaminesRepresentation = yes,
-        det_get_proc_info(DetInfo, ProcInfo),
+        det_get_proc_info(!.DetInfo, ProcInfo),
         proc_info_get_vartypes(ProcInfo, VarTypes),
         map.lookup(VarTypes, Var, Type),
-        det_type_has_user_defined_equality_pred(DetInfo, Type)
+        det_type_has_user_defined_equality_pred(!.DetInfo, Type)
     ->
         (
             CanFail = can_fail,
@@ -1815,7 +1820,7 @@
                 [simple_msg(Context,
                     [always(Pieces0 ++ Pieces1),
                     verbose_only(VerbosePieces)])]),
-            !:Specs = [Spec | !.Specs]
+            det_info_add_error_spec(Spec, !DetInfo)
         ;
             CanFail = cannot_fail,
             (
@@ -1856,7 +1861,7 @@
                     words("representations, but I'm not going to do that"),
                     words("implicitly. (If that's really what you want,"),
                     words("you must do it explicitly.)")],
-                det_info_get_module_info(DetInfo, ModuleInfo),
+                det_info_get_module_info(!.DetInfo, ModuleInfo),
                 ContextMsgs = failing_contexts_description(ModuleInfo, VarSet,
                     FailingContextsA ++ FailingContextsB),
                 Spec = error_spec(severity_error, phase_detism_check,
@@ -1864,7 +1869,7 @@
                         [always(Pieces0 ++ Pieces1),
                         verbose_only(VerbosePieces)])]
                     ++ ContextMsgs),
-                !:Specs = [Spec | !.Specs]
+                det_info_add_error_spec(Spec, !DetInfo)
             ;
                 SolnContext = first_soln
             )
Index: compiler/det_report.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/det_report.m,v
retrieving revision 1.147
diff -u -b -r1.147 det_report.m
--- compiler/det_report.m	11 Jun 2009 07:00:08 -0000	1.147
+++ compiler/det_report.m	31 Aug 2009 19:36:15 -0000
@@ -74,8 +74,7 @@
     % determinisms.
     %
 :- pred det_check_lambda(determinism::in, determinism::in, hlds_goal::in,
-    hlds_goal_info::in, instmap::in, det_info::in, det_info::out,
-    list(error_spec)::in, list(error_spec)::out) is det.
+    hlds_goal_info::in, instmap::in, det_info::in, det_info::out) is det.
 
     % det_diagnose_conj(Goals, InstMap0, Desired, FailingContexts, DetInfo,
     %   Msgs):
@@ -257,7 +256,7 @@
             proc_info_get_vartypes(ProcInfo0, VarTypes),
             proc_info_get_initial_instmap(ProcInfo0, !.ModuleInfo, InstMap0),
             det_info_init(!.ModuleInfo, VarTypes, PredId, ProcId, 
-                pess_extra_vars_report, DetInfo0),
+                pess_extra_vars_report, [], DetInfo0),
             det_diagnose_goal(Goal, InstMap0, DeclaredDetism, [],
                 DetInfo0, DetInfo, GoalMsgs0),
             det_info_get_module_info(DetInfo, !:ModuleInfo),
@@ -406,7 +405,7 @@
     ].
 
 det_check_lambda(DeclaredDetism, InferredDetism, Goal, GoalInfo, InstMap0,
-        !DetInfo, !Specs) :-
+        !DetInfo) :-
     compare_determinisms(DeclaredDetism, InferredDetism, Cmp),
     (
         Cmp = tighter,
@@ -428,7 +427,7 @@
         sort_error_msgs(GoalMsgs, SortedGoalMsgs),
         Spec = error_spec(severity_error, phase_detism_check,
             [simple_msg(Context, [always(Pieces)])] ++ SortedGoalMsgs),
-        !:Specs = [Spec | !.Specs]
+        det_info_add_error_spec(Spec, !DetInfo)
     ;
         ( Cmp = sameas
         ; Cmp = looser
Index: compiler/det_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/det_util.m,v
retrieving revision 1.48
diff -u -b -r1.48 det_util.m
--- compiler/det_util.m	23 Dec 2008 01:37:32 -0000	1.48
+++ compiler/det_util.m	31 Aug 2009 19:16:45 -0000
@@ -25,6 +25,7 @@
 :- import_module hlds.hlds_pred.
 :- import_module hlds.instmap.
 :- import_module parse_tree.
+:- import_module parse_tree.error_util.
 :- import_module parse_tree.prog_data.
 
 :- import_module bool.
@@ -72,10 +73,11 @@
 :- pred interpret_unify(prog_var::in, unify_rhs::in,
     prog_substitution::in, prog_substitution::out) is semidet.
 
-    % Look up the determinism of a procedure.
+    % Look up the determinism of a procedure, and also return the pred_info
+    % containing the procedure. Doing both at once allows a small speedup.
     %
-:- pred det_lookup_detism(det_info::in, pred_id::in, proc_id::in,
-    determinism::out) is det.
+:- pred det_lookup_pred_info_and_detism(det_info::in, pred_id::in, proc_id::in,
+    pred_info::out, determinism::out) is det.
 
 :- pred det_get_proc_info(det_info::in, proc_info::out) is det.
 
@@ -85,8 +87,11 @@
 :- pred det_no_output_vars(set(prog_var)::in, instmap::in, instmap_delta::in,
     det_info::in) is semidet.
 
+:- pred det_info_add_error_spec(error_spec::in, det_info::in, det_info::out)
+    is det.
+
 :- pred det_info_init(module_info::in, vartypes::in, pred_id::in, proc_id::in,
-    report_pess_extra_vars::in, det_info::out) is det.
+    report_pess_extra_vars::in, list(error_spec)::in, det_info::out) is det.
 
 :- pred det_info_get_module_info(det_info::in, module_info::out) is det.
 :- pred det_info_get_pred_id(det_info::in, pred_id::out) is det.
@@ -97,11 +102,15 @@
 :- pred det_info_get_vartypes(det_info::in, vartypes::out) is det.
 :- pred det_info_get_pess_extra_vars(det_info::in,
     report_pess_extra_vars::out) is det.
+:- pred det_info_get_error_specs(det_info::in, list(error_spec)::out) is det.
+:- pred det_info_get_has_format_call(det_info::in, bool::out) is det.
 
 :- pred det_info_set_module_info(module_info::in, det_info::in, det_info::out)
     is det.
 :- pred det_info_set_vartypes(vartypes::in, det_info::in, det_info::out)
     is det.
+:- pred det_info_set_has_format_call(bool::in, det_info::in, det_info::out)
+    is det.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -164,7 +173,7 @@
     % This is a safe approximation, it just prevents us from optimizing them
     % as well as we would like.
 
-det_lookup_detism(DetInfo, PredId, ModeId, Detism) :-
+det_lookup_pred_info_and_detism(DetInfo, PredId, ModeId, PredInfo, Detism) :-
     det_info_get_module_info(DetInfo, ModuleInfo),
     module_info_preds(ModuleInfo, PredTable),
     map.lookup(PredTable, PredId, PredInfo),
@@ -196,6 +205,11 @@
     instmap_delta_no_output_vars(InstMap, InstMapDelta, Vars,
         DetInfo ^ di_vartypes, ModuleInfo).
 
+det_info_add_error_spec(Spec, !DetInfo) :-
+    det_info_get_error_specs(!.DetInfo, Specs0),
+    Specs = [Spec | Specs0],
+    det_info_set_error_specs(Specs, !DetInfo).
+
 %-----------------------------------------------------------------------------%
 
 :- type det_info
@@ -207,17 +221,19 @@
                 di_reorder_conj    :: bool,        % --reorder-conj
                 di_reorder_disj    :: bool,        % --reorder-disj
                 di_fully_strict    :: bool,        % --fully-strict
-                di_pess_extra_vars :: report_pess_extra_vars
+                di_pess_extra_vars  :: report_pess_extra_vars,
+                di_error_specs      :: list(error_spec),
+                di_has_format_call  :: bool
             ).
 
 det_info_init(ModuleInfo, VarTypes, PredId, ProcId, PessExtraVars,
-        DetInfo) :-
+        Specs, DetInfo) :-
     module_info_get_globals(ModuleInfo, Globals),
     globals.lookup_bool_option(Globals, reorder_conj, ReorderConj),
     globals.lookup_bool_option(Globals, reorder_disj, ReorderDisj),
     globals.lookup_bool_option(Globals, fully_strict, FullyStrict),
     DetInfo = det_info(ModuleInfo, VarTypes, PredId, ProcId,
-        ReorderConj, ReorderDisj, FullyStrict, PessExtraVars).
+        ReorderConj, ReorderDisj, FullyStrict, PessExtraVars, Specs, no).
 
 det_info_get_module_info(DI, DI ^ di_module_info).
 det_info_get_pred_id(DI, DI ^ di_pred_id).
@@ -227,9 +243,20 @@
 det_info_get_fully_strict(DI, DI ^ di_fully_strict).
 det_info_get_vartypes(DI, DI ^ di_vartypes).
 det_info_get_pess_extra_vars(DI, DI ^ di_pess_extra_vars).
+det_info_get_error_specs(DI, DI ^ di_error_specs).
+det_info_get_has_format_call(DI, DI ^ di_has_format_call).
+
+:- pred det_info_set_error_specs(list(error_spec)::in,
+    det_info::in, det_info::out) is det.
 
-det_info_set_module_info(ModuleInfo, DI, DI ^ di_module_info := ModuleInfo).
-det_info_set_vartypes(VarTypes, DI, DI ^ di_vartypes := VarTypes).
+det_info_set_module_info(ModuleInfo, !DetInfo) :-
+    !DetInfo ^ di_module_info := ModuleInfo.
+det_info_set_vartypes(VarTypes, !DetInfo) :-
+    !DetInfo ^ di_vartypes := VarTypes.
+det_info_set_error_specs(Specs, !DetInfo) :-
+    !DetInfo ^ di_error_specs := Specs.
+det_info_set_has_format_call(HasFormatCall, !DetInfo) :-
+    !DetInfo ^ di_has_format_call := HasFormatCall.
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/distance_granularity.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/distance_granularity.m,v
retrieving revision 1.9
diff -u -b -r1.9 distance_granularity.m
--- compiler/distance_granularity.m	11 Jun 2009 07:00:08 -0000	1.9
+++ compiler/distance_granularity.m	1 Sep 2009 00:57:26 -0000
@@ -711,8 +711,8 @@
                     VarResultDelta = VarResult - ground(unique, none),
                     VarDelta = Var - bound(shared, [bound_functor(int_const(1),
                         [])]),
-                    instmap_delta_from_assoc_list([VarDelta, VarResultDelta],
-                        InstMapDeltaDecrement),
+                    InstMapDeltaDecrement = instmap_delta_from_assoc_list(
+                        [VarDelta, VarResultDelta]),
                     Detism = detism_det,
                     Purity = purity_pure,
                     % Take the context of the first goal of the conjunction.
Index: compiler/format_call.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/format_call.m,v
retrieving revision 1.17
diff -u -b -r1.17 format_call.m
--- compiler/format_call.m	11 Jun 2009 07:00:09 -0000	1.17
+++ compiler/format_call.m	2 Sep 2009 00:17:01 -0000
@@ -9,24 +9,27 @@
 % File: format_call.m.
 % Author: zs.
 %
-% The job of this module is to generate warnings about calls to
-% string.format, io.format and stream.string_writer.format in which the format
-% string and the supplied lists of values do not agree. The difficult part of
-% this job is actually finding the values of the variables representing the
-% format string and the list of values to be printed.
+% This module has two related jobs. The first job is to generate warnings
+% about calls to string.format, io.format and stream.string_writer.format
+% in which the format string and the supplied lists of values do not agree.
+% The difficult part of this job is actually finding the values of the
+% variables representing the format string and the list of values to be printed.
+% The second job is to try to transform well formed calls into code that
+% interprets the format string at compile time, rather than runtime.
 %
-% The general approach is a backwards traversal of the procedure body. During
-% this traversal, we assign an id to every conjunction (considering a cond and
-% then parts of an if-then-else to be a conjunction). When we find a call to
-% string.format or io.format, we remember the call site together with the
-% identities of the variables holding the format string and the values to
-% be printed, and include both variables in the set of variables whose values
-% we want to track. As we traverse unifications that bind variables we want to
-% track, we record their value in a map specific to the conjunction containing
-% the unification. Actually, we keep four such maps. Three record information
-% about bindings to function symbols: one for format strings, one for the
-% skeletons of the lists of values, and one for the elements of those lists.
-% The fourth map is for variable equivalences.
+% Our general approach to the first job is a backwards traversal of the
+% procedure body. During this traversal, we assign an id to every conjunction
+% (considering a cond and then parts of an if-then-else to be a conjunction).
+% When we find a call to a recognized format predicate or function, we remember
+% the call site together with the identities of the variables holding the
+% format string and the values to be printed, and include both variables
+% in the set of variables whose values we want to track. As we traverse
+% unifications that bind variables we want to track, we record their value
+% in a map specific to the conjunction containing the unification. Actually,
+% we keep four such maps. Three record information about bindings to function
+% symbols: one for format strings, one for the skeletons of the lists of
+% values, and one for the elements of those lists. The fourth map is
+% for variable equivalences.
 %
 % We also record relationships between the conjunctions. Consider the code
 % structure below, which contains two relevant conjunctions: the outer one,
@@ -75,6 +78,32 @@
 % evaluate the extent of a need for this capability until this change is
 % bootstrapped, so that is left for future work.
 %
+% The second job (optimizing the calls) starts by gathering the information
+% we need during the first pass through the code. If we find that a format_call
+% can be executed by string.format on dummy values of the appropriate type
+% without throwing an exception, we check to see if the format string is simple
+% enough for us to interpret it at compile time. At the moment, it is simple
+% enough if it consists of only raw text to be printed and uses of the %d,
+% %c and %s specifiers without any flags, width or precision specifications
+% or anything like that. If the format string falls into this category,
+% then we construct code to replace the call right away.
+%
+% If there are any such replacements, we perform a second backward traversal of
+% the procedure body, looking for the goals to be replaced, which we identity
+% by goal_path.
+%
+% For each call we want to optimize, we also want to delete the code that
+% constructs the format string and the lists of poly_types. The first pass
+% records the identities of the variables involved, so that we can delete the
+% construct unifications that produce them (if they were produced by calls, we
+% would not have been able to know at compile time *what* they produce).
+% Of course, some of these variables may be used elsewhere, both before and
+% after the format call we are optimizing. That is why this second backwards
+% traversal passes along two sets of variables: the set of variables we want to
+% remove (ToDeleteVars), and the set of variables known to be needed later
+% (NeededVars). Construction unifications that create one of the ToDeleteVars
+% are deleted, unless the variable is also in NeededVars.
+%
 %-----------------------------------------------------------------------------%
 
 :- module check_hlds.format_call.
@@ -91,27 +120,38 @@
 :- import_module mdbcomp.prim_data.
 
 :- import_module list.
+:- import_module maybe.
 
 %-----------------------------------------------------------------------------%
 
-:- pred is_format_call(module_name::in, string::in, list(prog_var)::in,
-    prog_var::out, prog_var::out) is semidet.
+:- pred is_format_call(module_name::in, string::in, list(prog_var)::in)
+    is semidet.
 
-:- pred find_format_call_errors(module_info::in, hlds_goal::in,
-    list(error_spec)::in, list(error_spec)::out) is det.
+:- pred analyze_and_optimize_format_calls(module_info::in,
+    hlds_goal::in, maybe(hlds_goal)::out, list(error_spec)::out,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
 :- implementation.
 
+:- import_module check_hlds.goal_path.
+:- import_module hlds.goal_util.
 :- import_module hlds.hlds_pred.
+:- import_module hlds.instmap.
+:- import_module hlds.pred_table.
 :- import_module libs.
 :- import_module libs.compiler_util.
+:- import_module libs.globals.
 :- import_module libs.options.
+:- import_module mdbcomp.program_representation.
 :- import_module parse_tree.builtin_lib_types.
+:- import_module parse_tree.prog_mode.
 
+:- import_module assoc_list.
 :- import_module bool.
+:- import_module char.
 :- import_module counter.
 :- import_module exception.
 :- import_module map.
@@ -119,22 +159,26 @@
 :- import_module pair.
 :- import_module require.
 :- import_module set.
+:- import_module set_tree234.
 :- import_module string.
 :- import_module svmap.
-:- import_module svset.
+:- import_module svvarset.
+:- import_module term.
 :- import_module univ.
 
 %-----------------------------------------------------------------------------%
 
 :- type format_call_site
     --->    format_call_site(
-                format_string_var       :: prog_var,
-                formatted_values_var    :: prog_var,
-                called_pred_module      :: module_name,
-                called_pred_name        :: string,
-                called_pred_arity       :: arity,
-                call_context            :: prog_context,
-                containing_conj         :: conj_id
+                fcs_goal_path               :: goal_path,
+                fcs_string_var              :: prog_var,
+                fcs_values_var              :: prog_var,
+                fcs_call_kind               :: format_call_kind,
+                fcs_called_pred_module      :: module_name,
+                fcs_called_pred_name        :: string,
+                fcs_called_pred_arity       :: arity,
+                fcs_call_context            :: prog_context,
+                fcs_containing_conj         :: conj_id
             ).
 
 :- type list_skeleton_state
@@ -152,11 +196,17 @@
     % be printed to its value.
 :- type list_skeleton_map   == map(prog_var, list_skeleton_state).
 
-    % Maps each variable representing a value in the list of values to be
-    % printed to a dummy value of the same kind. We don't include the actual
-    % value to be printed, since (a) in almost all cases that won't be
-    % available statically in the program, and (b) we don't actually need it.
-:- type list_element_map    == map(prog_var, string.poly_type).
+    % Maps each variable representing a polytype in the list of values to be
+    % printed to the variable whose value is to be printed, and a dummy value
+    % of the same kind. We don't include the actual value to be printed, since
+    % (a) in almost all cases that won't be available statically in the
+    % program, and (b) we don't actually need it.
+:- type what_to_print
+    --->    what_to_print(
+                var_to_print        :: prog_var,
+                dummy_to_print      :: string.poly_type
+            ).
+:- type list_element_map    == map(prog_var, what_to_print).
 
     % Maps each variable defined in terms of another variable to the variable
     % it is assigned from.
@@ -164,6 +214,7 @@
 
     % The knowledge we have recorded from assign and construct unifications in
     % a given conjunction.
+    %
 :- type conj_map
     --->    conj_map(
                 string_map          :: string_map,
@@ -177,65 +228,135 @@
 
     % Maps the id of each conjunction to the knowledge we have derived from
     % unifications in that conjunction.
+    %
 :- type conj_maps == map(conj_id, conj_map).
 
     % Maps each conjunction to its predecessor (if any) in the sense documented
     % above.
+    %
 :- type conj_pred_map == map(conj_id, conj_id).
 
+    % Records the information about each call site that is not common
+    % to all calls to recognized predicates and function.
+    %
+:- type format_call_kind
+    --->    kind_string_format(
+                sf_result_var           :: prog_var
+            )
+    ;       kind_io_format_nostream(
+                iofns_io_in_var         :: prog_var,
+                iofns_io_out_var        :: prog_var
+            )
+    ;       kind_io_format_stream(
+                iofs_stream_var         :: prog_var,
+                iofs_io_in_var          :: prog_var,
+                iofs_io_out_var         :: prog_var
+            )
+    ;       kind_stream_string_writer(
+                ssw_tc_info_var         :: prog_var,
+                ssw_stream_var          :: prog_var,
+                ssw_in_var              :: prog_var,
+                ssw_out_var             :: prog_var
+            ).
+
 %-----------------------------------------------------------------------------%
 
-is_format_call(ModuleName, Name, Args, FormatStringVar, FormattedValuesVar) :-
+is_format_call(ModuleName, Name, Args) :-
+    is_format_call_kind_and_vars(ModuleName, Name, Args, _Kind,
+        _FormatStringVar, _FormattedValuesVar).
+
+:- pred is_format_call_kind_and_vars(module_name::in, string::in,
+    list(prog_var)::in, format_call_kind::out, prog_var::out, prog_var::out)
+    is semidet.
+
+is_format_call_kind_and_vars(ModuleName, Name, Args, Kind,
+        FormatStringVar, FormattedValuesVar) :-
     Name = "format",
     (
-        ModuleName = mercury_std_lib_module_name(unqualified("string"))
+        ModuleName = mercury_string_module
     ->
         % We have these arguments regardless of whether we call the
         % predicate or function version of string.format.
-        Args = [FormatStringVar, FormattedValuesVar, _ResultVar]
+        Args = [FormatStringVar, FormattedValuesVar, ResultVar],
+        Kind = kind_string_format(ResultVar)
     ;
-        ModuleName = mercury_std_lib_module_name(unqualified("io"))
+        ModuleName = mercury_io_module
     ->
-        ( Args = [FormatStringVar, FormattedValuesVar, _IOIn, _IOOut]
-        ; Args = [_Stream, FormatStringVar, FormattedValuesVar, _IOIn, _IOOut]
+        (
+            Args = [FormatStringVar, FormattedValuesVar, IOIn, IOOut],
+            Kind = kind_io_format_nostream(IOIn, IOOut)
+        ;
+            Args = [StreamVar, FormatStringVar, FormattedValuesVar,
+                IOIn, IOOut],
+            Kind = kind_io_format_stream(StreamVar, IOIn, IOOut)
         )
     ;
         ModuleName = mercury_std_lib_module_name(
                     qualified(unqualified("stream"), "string_writer"))
     ->
-        % Since we do this check after polymorphism there will have been
+        % Since we do this check after polymorphism, there will have been
         % a typeclassinfo inserted at the front of the argument list.
-        Args = [_TC_InfoForStream, _Stream, FormatStringVar,
-            FormattedValuesVar, _StateIn, _StateOut]
+        Args = [TC_InfoVarForStream, StreamVar, FormatStringVar,
+            FormattedValuesVar, StateInVar, StateOutVar],
+        Kind = kind_stream_string_writer(TC_InfoVarForStream, StreamVar,
+            StateInVar, StateOutVar)
     ;
         fail
     ).
 
 %-----------------------------------------------------------------------------%
 
-find_format_call_errors(ModuleInfo, Goal, !Msgs) :-
+analyze_and_optimize_format_calls(ModuleInfo, Goal0, MaybeGoal, Specs,
+        !VarSet, !VarTypes) :-
     map.init(ConjMaps0),
     counter.init(0, Counter0),
-    traverse_goal(Goal, _, [], FormatCallSites, Counter0, _Counter,
-        ConjMaps0, ConjMaps, map.init, PredMap, set.init, _, ModuleInfo),
-    list.foldl(check_format_call_site(ConjMaps, PredMap), FormatCallSites,
-        !Msgs).
-
-:- pred check_format_call_site(conj_maps::in, conj_pred_map::in,
-    format_call_site::in, list(error_spec)::in, list(error_spec)::out) is det.
+    fill_goal_path_slots_in_goal(Goal0, !.VarTypes, ModuleInfo, Goal1),
+    format_call_traverse_goal(ModuleInfo, Goal1, _, [], FormatCallSites,
+        Counter0, _Counter, ConjMaps0, ConjMaps, map.init, PredMap,
+        set_tree234.init, _),
+    module_info_get_globals(ModuleInfo, Globals),
+    globals.lookup_bool_option(Globals, optimize_format_calls, OptFormatCalls),
+    list.foldl4(
+        check_format_call_site(ModuleInfo, OptFormatCalls, ConjMaps, PredMap),
+        FormatCallSites, map.init, GoalPathMap, [], Specs, !VarSet, !VarTypes),
+    ( map.is_empty(GoalPathMap) ->
+        % We have not found anything to improve in Goal1.
+        MaybeGoal = no
+    ;
+        % We want to set NeededVars0 to be the set of the procedure's
+        % output arguments, but it is ok to add into it some non-output
+        % arguments whose insts happen to change as well.
+        Goal1 = hlds_goal(_, GoalInfo1),
+        InstMapDelta = goal_info_get_instmap_delta(GoalInfo1),
+        instmap_delta_changed_vars(InstMapDelta, NeededVars0),
+        ToDeleteVars0 = set_tree234.init,
+        NeededVarsSet = set_tree234.sorted_list_to_set(
+            set.to_sorted_list(NeededVars0)),
+        opt_format_call_sites_in_goal(Goal1, Goal, GoalPathMap, _,
+            NeededVarsSet, _NeededVars, ToDeleteVars0, _ToDeleteVars),
+        MaybeGoal = yes(Goal)
+    ).
 
-check_format_call_site(ConjMaps, PredMap, FormatCallSite, !Specs) :-
-    FormatCallSite = format_call_site(StringVar, ValuesVar,
+:- pred check_format_call_site(module_info::in, bool::in, conj_maps::in,
+    conj_pred_map::in, format_call_site::in,
+    fc_goal_path_map::in, fc_goal_path_map::out,
+    list(error_spec)::in, list(error_spec)::out,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
+
+check_format_call_site(ModuleInfo, OptFormatCalls, ConjMaps, PredMap,
+        FormatCallSite, !GoalPathMap, !Specs, !VarSet, !VarTypes) :-
+    FormatCallSite = format_call_site(GoalPath, StringVar, ValuesVar, Kind,
         ModuleName, Name, Arity, Context, CurId),
     SymName = qualified(ModuleName, Name),
 
     (
         follow_format_string(ConjMaps, PredMap, CurId, StringVar,
-            yes(FormatString0))
+            MaybeFormatString0),
+        MaybeFormatString0 = yes(FormatString0)
     ->
-        MaybeFormatString = yes(FormatString0)
+        MaybeFormatStringVar = yes({FormatString0, StringVar})
     ;
-        MaybeFormatString = no,
+        MaybeFormatStringVar = no,
         UnknownFormatPieces = [words("Unknown format string in call to"),
             sym_name_and_arity(SymName / Arity), suffix("."), nl],
         UnknownFormatSeverity =
@@ -250,14 +371,17 @@
     ),
 
     (
-        follow_list(ConjMaps, PredMap, CurId, ValuesVar, yes(Skeleton)),
-        list.map(follow_list_value(ConjMaps, PredMap, CurId), Skeleton,
-            MaybeValueList),
-        project_all_yes(MaybeValueList, Values0)
+        follow_list_skeleton(ConjMaps, PredMap, CurId, ValuesVar,
+            SkeletonResult),
+        SkeletonResult = follow_skeleton_result(PolytypeVars0, SkeletonVars0),
+        list.map(follow_list_value(ConjMaps, PredMap, CurId), PolytypeVars0,
+            WhatToPrintMaybes0),
+        project_all_yes(WhatToPrintMaybes0, WhatToPrints0)
     ->
-        MaybeValues = yes(Values0)
+        ToDeleteVars0 = [ValuesVar | SkeletonVars0] ++ PolytypeVars0,
+        MaybeSkeletonInfo = yes({ToDeleteVars0, WhatToPrints0})
     ;
-        MaybeValues = no,
+        MaybeSkeletonInfo = no,
         UnknownFormatValuesPieces =
             [words("Unknown format values in call to"),
             sym_name_and_arity(SymName / Arity), suffix("."), nl],
@@ -273,11 +397,12 @@
     ),
 
     (
-        MaybeFormatString = yes(FormatString),
-        MaybeValues = yes(Values)
+        MaybeFormatStringVar = yes({FormatString, StringVar1}),
+        MaybeSkeletonInfo = yes({ValuesToDeleteVars, WhatToPrints})
     ->
+        DummiesToPrint = list.map(project_dummy_to_print, WhatToPrints),
         promise_equivalent_solutions [Result] (
-            try(string.format(FormatString, Values), Result)
+            try(string.format(FormatString, DummiesToPrint), Result)
         ),
         (
             Result = exception(ExceptionUniv),
@@ -308,13 +433,82 @@
             )
         ;
             % There is no need for any error message; the format works.
-            Result = succeeded(_)
+            Result = succeeded(_),
+            (
+                OptFormatCalls = no
+            ;
+                OptFormatCalls = yes,
+                try_create_replacement_goal(ModuleInfo, GoalPath,
+                    Kind, FormatString, StringVar1,
+                    ValuesToDeleteVars, WhatToPrints,
+                    !GoalPathMap, !VarSet, !VarTypes)
+            )
         )
     ;
         % Any error message has already been generated, if asked for.
         true
     ).
 
+:- pred try_create_replacement_goal(module_info::in, goal_path::in,
+    format_call_kind::in, string::in, prog_var::in,
+    list(prog_var)::in, list(what_to_print)::in,
+    fc_goal_path_map::in, fc_goal_path_map::out,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
+
+try_create_replacement_goal(ModuleInfo, GoalPath, Kind,
+        FormatString, StringVar, ValuesToDeleteVars,
+        WhatToPrints, !GoalPathMap, !VarSet, !VarTypes) :-
+    string.to_char_list(FormatString, FormatStringChars),
+    VarsToPrint = list.map(project_var_to_print, WhatToPrints),
+    % Note that every predicate or function that this code generates calls to
+    % needs to be listed in simplify_may_introduce_calls, in order to prevent
+    % its definition from being thrown away by dead_pred_elim before execution
+    % gets here.
+    (
+        Kind = kind_string_format(ResultVar),
+        (
+            create_string_format_replacement(ModuleInfo,
+                FormatStringChars, ResultVar, VarsToPrint,
+                ReplacementGoal, !VarSet, !VarTypes)
+        ->
+            AllToDeleteVars = [StringVar | ValuesToDeleteVars],
+            FCOptGoalInfo = fc_opt_goal_info(ReplacementGoal,
+                set_tree234.list_to_set(AllToDeleteVars)),
+            svmap.det_insert(GoalPath, FCOptGoalInfo, !GoalPathMap)
+        ;
+            % create_string_format_replacement does not (yet) recognize
+            % all possible format strings. We cannot optimize the ones
+            % it cannot recognize.
+            true
+        )
+    ;
+        (
+            Kind = kind_io_format_nostream(IOInVar, IOOutVar),
+            MaybeStreamVar = no
+        ;
+            Kind = kind_io_format_stream(StreamVar, IOInVar, IOOutVar),
+            MaybeStreamVar = yes(StreamVar)
+        ),
+        (
+            create_io_format_replacement(ModuleInfo, FormatStringChars,
+                MaybeStreamVar, IOInVar, IOOutVar, VarsToPrint,
+                ReplacementGoal, !VarSet, !VarTypes)
+        ->
+            AllToDeleteVars = [StringVar | ValuesToDeleteVars],
+            FCOptGoalInfo = fc_opt_goal_info(ReplacementGoal,
+                set_tree234.list_to_set(AllToDeleteVars)),
+            svmap.det_insert(GoalPath, FCOptGoalInfo, !GoalPathMap)
+        ;
+            % create_string_format_replacement does not (yet) recognize
+            % all possible format strings. We cannot optimize the ones
+            % it cannot recognize.
+            true
+        )
+    ;
+        Kind = kind_stream_string_writer(_, _, _, _)
+        % XXX Optimize these.
+    ).
+
 :- pred follow_format_string(conj_maps::in, conj_pred_map::in, conj_id::in,
     prog_var::in, maybe(string)::out) is det.
 
@@ -331,53 +525,72 @@
         MaybeString = no
     ).
 
-:- pred follow_list(conj_maps::in, conj_pred_map::in, conj_id::in,
-    prog_var::in, maybe(list(prog_var))::out) is det.
+:- type follow_skeleton_result
+    --->    follow_skeleton_result(
+                fsr_polytype_vars       :: list(prog_var),
+                fsr_skeleton_vars       :: list(prog_var)
+            )
+    ;       no_follow_skeleton_result.
+
+:- pred follow_list_skeleton(conj_maps::in, conj_pred_map::in, conj_id::in,
+    prog_var::in, follow_skeleton_result::out) is det.
 
-follow_list(ConjMaps, PredMap, CurId, ListVar, MaybeSkeleton) :-
+follow_list_skeleton(ConjMaps, PredMap, CurId, ListVar, Result) :-
     ConjMap = get_conj_map(ConjMaps, CurId),
     ConjMap = conj_map(_, ListMap, _, EqvMap),
     ( map.search(EqvMap, ListVar, EqvVar) ->
-        follow_list(ConjMaps, PredMap, CurId, EqvVar, MaybeSkeleton)
+        follow_list_skeleton(ConjMaps, PredMap, CurId, EqvVar, Result)
     ; map.search(ListMap, ListVar, ListState) ->
         (
             ListState = list_skeleton_nil,
-            Skeleton = [],
-            MaybeSkeleton = yes(Skeleton)
+            Result = follow_skeleton_result([], [ListVar])
         ;
             ListState = list_skeleton_cons(HeadVar, TailVar),
-            follow_list(ConjMaps, PredMap, CurId, TailVar, MaybeSkeletonTail),
+            follow_list_skeleton(ConjMaps, PredMap, CurId, TailVar,
+                TailResult),
             (
-                MaybeSkeletonTail = no,
-                MaybeSkeleton = no
+                TailResult = no_follow_skeleton_result,
+                Result = no_follow_skeleton_result
             ;
-                MaybeSkeletonTail = yes(SkeletonTail),
-                Skeleton = [HeadVar | SkeletonTail],
-                MaybeSkeleton = yes(Skeleton)
+                TailResult = follow_skeleton_result(TailPolytypeVars,
+                    TailSkeletonVars),
+                PolytypeVars = [HeadVar | TailPolytypeVars],
+                SkeletonVars = [TailVar | TailSkeletonVars],
+                Result = follow_skeleton_result(PolytypeVars,
+                    SkeletonVars)
             )
         )
     ; map.search(PredMap, CurId, PredId) ->
-        follow_list(ConjMaps, PredMap, PredId, ListVar, MaybeSkeleton)
+        follow_list_skeleton(ConjMaps, PredMap, PredId, ListVar, Result)
     ;
-        MaybeSkeleton = no
+        Result = no_follow_skeleton_result
     ).
 
-:- pred follow_list_value(conj_maps::in, conj_pred_map::in, conj_id::in,
-    prog_var::in, maybe(string.poly_type)::out) is det.
+:- pred follow_list_value(conj_maps::in, conj_pred_map::in,
+    conj_id::in, prog_var::in, maybe(what_to_print)::out) is det.
 
-follow_list_value(ConjMaps, PredMap, CurId, ElementVar, MaybeValue) :-
+follow_list_value(ConjMaps, PredMap, CurId, PolytypeVar, MaybeResult) :-
     ConjMap = get_conj_map(ConjMaps, CurId),
     ConjMap = conj_map(_, _, ElementMap, EqvMap),
-    ( map.search(EqvMap, ElementVar, EqvVar) ->
-        follow_list_value(ConjMaps, PredMap, CurId, EqvVar, MaybeValue)
-    ; map.search(ElementMap, ElementVar, Value) ->
-        MaybeValue = yes(Value)
+    ( map.search(EqvMap, PolytypeVar, EqvVar) ->
+        follow_list_value(ConjMaps, PredMap, CurId, EqvVar, MaybeResult)
+    ; map.search(ElementMap, PolytypeVar, WhatToPrint) ->
+        MaybeResult = yes(WhatToPrint)
     ; map.search(PredMap, CurId, PredId) ->
-        follow_list_value(ConjMaps, PredMap, PredId, ElementVar, MaybeValue)
+        follow_list_value(ConjMaps, PredMap, PredId, PolytypeVar, MaybeResult)
     ;
-        MaybeValue = no
+        MaybeResult = no
     ).
 
+:- func project_dummy_to_print(what_to_print) = string.poly_type.
+
+project_dummy_to_print(what_to_print(_VarToPrint, DummyToPrint))
+    = DummyToPrint.
+
+:- func project_var_to_print(what_to_print) = prog_var.
+
+project_var_to_print(what_to_print(VarToPrint, _DummyToPrint)) = VarToPrint.
+
 :- pred project_all_yes(list(maybe(T))::in, list(T)::out) is semidet.
 
 project_all_yes([], []).
@@ -386,75 +599,75 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred traverse_goal(hlds_goal::in, conj_id::out,
+:- pred format_call_traverse_goal(module_info::in, hlds_goal::in, conj_id::out,
     list(format_call_site)::in, list(format_call_site)::out,
     counter::in, counter::out, conj_maps::in, conj_maps::out,
     conj_pred_map::in, conj_pred_map::out,
-    set(prog_var)::in, set(prog_var)::out, module_info::in) is det.
+    set_tree234(prog_var)::in, set_tree234(prog_var)::out) is det.
 
-traverse_goal(Goal, CurId, !FormatCallSites, !Counter, !ConjMaps, !PredMap,
-        !RelevantVars, ModuleInfo) :-
+format_call_traverse_goal(ModuleInfo, Goal, CurId, !FormatCallSites, !Counter,
+        !ConjMaps, !PredMap, !RelevantVars) :-
     alloc_id(CurId, !Counter),
     goal_to_conj_list(Goal, GoalConj),
-    traverse_conj(GoalConj, CurId, !FormatCallSites, !Counter,
-        !ConjMaps, !PredMap, !RelevantVars, ModuleInfo).
+    format_call_traverse_conj(ModuleInfo, GoalConj, CurId, !FormatCallSites,
+        !Counter, !ConjMaps, !PredMap, !RelevantVars).
 
-:- pred traverse_conj(list(hlds_goal)::in, conj_id::in,
-    list(format_call_site)::in, list(format_call_site)::out,
+:- pred format_call_traverse_conj(module_info::in, list(hlds_goal)::in,
+    conj_id::in, list(format_call_site)::in, list(format_call_site)::out,
     counter::in, counter::out, conj_maps::in, conj_maps::out,
     conj_pred_map::in, conj_pred_map::out,
-    set(prog_var)::in, set(prog_var)::out, module_info::in) is det.
+    set_tree234(prog_var)::in, set_tree234(prog_var)::out) is det.
 
-traverse_conj([], _CurId, !FormatCallSites, !Counter,
-        !ConjMaps, !PredMap, !RelevantVars, _ModuleInfo).
-traverse_conj([Goal | Goals], CurId, !FormatCallSites, !Counter,
-        !ConjMaps, !PredMap, !RelevantVars, ModuleInfo) :-
-    traverse_conj(Goals, CurId, !FormatCallSites, !Counter,
-        !ConjMaps, !PredMap, !RelevantVars, ModuleInfo),
+format_call_traverse_conj(_ModuleInfo, [], _CurId, !FormatCallSites, !Counter,
+        !ConjMaps, !PredMap, !RelevantVars).
+format_call_traverse_conj(ModuleInfo, [Goal | Goals], CurId, !FormatCallSites,
+        !Counter, !ConjMaps, !PredMap, !RelevantVars) :-
+    format_call_traverse_conj(ModuleInfo, Goals, CurId, !FormatCallSites,
+        !Counter, !ConjMaps, !PredMap, !RelevantVars),
     Goal = hlds_goal(GoalExpr, GoalInfo),
     (
         GoalExpr = conj(_, Conjuncts),
-        traverse_conj(Conjuncts, CurId, !FormatCallSites, !Counter,
-            !ConjMaps, !PredMap, !RelevantVars, ModuleInfo)
+        format_call_traverse_conj(ModuleInfo, Conjuncts, CurId,
+            !FormatCallSites, !Counter, !ConjMaps, !PredMap, !RelevantVars)
     ;
         GoalExpr = disj(Disjuncts),
-        traverse_disj(Disjuncts, CurId, !FormatCallSites, !Counter,
-            !ConjMaps, !PredMap, !RelevantVars, ModuleInfo)
+        format_call_traverse_disj(ModuleInfo, Disjuncts, CurId,
+            !FormatCallSites, !Counter, !ConjMaps, !PredMap, !RelevantVars)
     ;
         GoalExpr = switch(_, _, Cases),
         Disjuncts = list.map(project_case_goal, Cases),
-        traverse_disj(Disjuncts, CurId, !FormatCallSites, !Counter,
-            !ConjMaps, !PredMap, !RelevantVars, ModuleInfo)
+        format_call_traverse_disj(ModuleInfo, Disjuncts, CurId,
+            !FormatCallSites, !Counter, !ConjMaps, !PredMap, !RelevantVars)
     ;
         GoalExpr = if_then_else(_, Cond, Then, Else),
 
-        traverse_goal(Else, ElseId, !FormatCallSites, !Counter, !ConjMaps,
-            !PredMap, !RelevantVars, ModuleInfo),
+        format_call_traverse_goal(ModuleInfo, Else, ElseId, !FormatCallSites,
+            !Counter, !ConjMaps, !PredMap, !RelevantVars),
         svmap.det_insert(ElseId, CurId, !PredMap),
 
         alloc_id(CondThenId, !Counter),
         goal_to_conj_list(Then, ThenConj),
         goal_to_conj_list(Cond, CondConj),
-        traverse_conj(CondConj ++ ThenConj, CondThenId, !FormatCallSites,
-            !Counter, !ConjMaps, !PredMap, !RelevantVars, ModuleInfo),
+        format_call_traverse_conj(ModuleInfo, CondConj ++ ThenConj, CondThenId,
+            !FormatCallSites, !Counter, !ConjMaps, !PredMap, !RelevantVars),
         svmap.det_insert(CondThenId, CurId, !PredMap)
     ;
         GoalExpr = negation(SubGoal),
-        traverse_goal(SubGoal, SubGoalId, !FormatCallSites,
-            !Counter, !ConjMaps, !PredMap, !RelevantVars, ModuleInfo),
+        format_call_traverse_goal(ModuleInfo, SubGoal, SubGoalId,
+            !FormatCallSites, !Counter, !ConjMaps, !PredMap, !RelevantVars),
         svmap.det_insert(SubGoalId, CurId, !PredMap)
     ;
         GoalExpr = scope(Reason, SubGoal),
         ( Reason = from_ground_term(_, from_ground_term_construct) ->
             % These scopes cannot build the format string (since that is
             % a single constant, from which we don't build such scopes),
-            % or the list of things to print (since that term won't a ground
-            % term except in degenerate cases. These scopes also cannot call
+            % or the list of things to print (since that term won't be a ground
+            % term except in degenerate cases). These scopes also cannot call
             % anything.
             true
         ;
-            traverse_conj([SubGoal], CurId, !FormatCallSites, !Counter,
-                !ConjMaps, !PredMap, !RelevantVars, ModuleInfo)
+            format_call_traverse_conj(ModuleInfo, [SubGoal], CurId,
+                !FormatCallSites, !Counter, !ConjMaps, !PredMap, !RelevantVars)
         )
     ;
         GoalExpr = generic_call(_, _, _, _)
@@ -465,65 +678,87 @@
         module_info_pred_info(ModuleInfo, PredId, PredInfo),
         ModuleName = pred_info_module(PredInfo),
         Name = pred_info_name(PredInfo),
-        ( is_format_call(ModuleName, Name, Args, StringVar, ValuesVar) ->
+        (
+            is_format_call_kind_and_vars(ModuleName, Name, Args,
+                Kind, StringVar, ValuesVar)
+        ->
             Arity = pred_info_orig_arity(PredInfo),
+            GoalPath = goal_info_get_goal_path(GoalInfo),
             Context = goal_info_get_context(GoalInfo),
-            FormatCallSite = format_call_site(StringVar, ValuesVar,
-                ModuleName, Name, Arity, Context, CurId),
+            FormatCallSite = format_call_site(GoalPath, StringVar, ValuesVar,
+                Kind, ModuleName, Name, Arity, Context, CurId),
             !:FormatCallSites = [FormatCallSite | !.FormatCallSites],
-            svset.insert_list([StringVar, ValuesVar], !RelevantVars)
+            set_tree234.insert_list([StringVar, ValuesVar], !RelevantVars)
         ;
             true
         )
     ;
-        GoalExpr = unify(_, _, _, Unification, _),
-        traverse_unify(Unification, CurId, !ConjMaps, !PredMap, !RelevantVars)
+        GoalExpr = unify(_, RHS, _, Unification, _),
+        format_call_traverse_unify(Unification, CurId, !ConjMaps, !PredMap,
+            !RelevantVars),
+        (
+            RHS = rhs_lambda_goal(_Purity, _HOGroundness, _PredFunc,
+                _EvalMethod, _LambdaNonLocals, _LambdaQuantVars, _LambdaModes,
+                _LambdaDetism, LambdaGoal),
+            format_call_traverse_goal(ModuleInfo, LambdaGoal, LambdaGoalId,
+                !FormatCallSites, !Counter, !ConjMaps, !PredMap,
+                !RelevantVars),
+            svmap.det_insert(LambdaGoalId, CurId, !PredMap)
+        ;
+            ( RHS = rhs_var(_)
+            ; RHS = rhs_functor(_, _, _)
+            )
+        )
     ;
         GoalExpr = shorthand(ShortHand),
         (
             ShortHand = atomic_goal(_, _, _, _, MainGoal, OrElseGoals, _),
-            traverse_disj([MainGoal | OrElseGoals], CurId,
-                !FormatCallSites, !Counter, !ConjMaps, !PredMap, !RelevantVars,
-                ModuleInfo)
+            format_call_traverse_disj(ModuleInfo, [MainGoal | OrElseGoals],
+                CurId, !FormatCallSites, !Counter, !ConjMaps, !PredMap,
+                !RelevantVars)
         ;
             ShortHand = try_goal(_, _, SubGoal),
-            traverse_goal(SubGoal, SubGoalId, !FormatCallSites,
-                !Counter, !ConjMaps, !PredMap, !RelevantVars, ModuleInfo),
+            format_call_traverse_goal(ModuleInfo, SubGoal, SubGoalId,
+                !FormatCallSites, !Counter, !ConjMaps, !PredMap,
+                !RelevantVars),
             svmap.det_insert(SubGoalId, CurId, !PredMap)
         ;
             ShortHand = bi_implication(_, _),
             % These should have been expanded by now.
-            unexpected(this_file, "traverse_conj: bi_implication")
+            unexpected(this_file, "format_call_traverse_conj: bi_implication")
         )
     ).
 
-:- pred traverse_unify(unification::in, conj_id::in,
+:- pred format_call_traverse_unify(unification::in, conj_id::in,
     conj_maps::in, conj_maps::out, conj_pred_map::in, conj_pred_map::out,
-    set(prog_var)::in, set(prog_var)::out) is det.
+    set_tree234(prog_var)::in, set_tree234(prog_var)::out) is det.
 
-traverse_unify(Unification, CurId, !ConjMaps, !PredMap, !RelevantVars) :-
+format_call_traverse_unify(Unification, CurId, !ConjMaps, !PredMap,
+        !RelevantVars) :-
     (
         Unification = assign(TargetVar, SourceVar),
-        ( set.member(TargetVar, !.RelevantVars) ->
-            svset.delete(TargetVar, !RelevantVars),
-            svset.insert(SourceVar, !RelevantVars),
+        ( set_tree234.member(!.RelevantVars, TargetVar) ->
+            set_tree234.delete(TargetVar, !RelevantVars),
+            set_tree234.insert(SourceVar, !RelevantVars),
             ConjMap0 = get_conj_map(!.ConjMaps, CurId),
             ConjMap0 = conj_map(StringMap, ListMap, ElementMap, EqvMap0),
             map.set(EqvMap0, TargetVar, SourceVar, EqvMap),
             ConjMap = conj_map(StringMap, ListMap, ElementMap, EqvMap),
+            % ZZZ map.det_insert?
             svmap.set(CurId, ConjMap, !ConjMaps)
         ;
             true
         )
     ;
         Unification = construct(CellVar, ConsId, ArgVars, _, _, _, _),
-        ( set.member(CellVar, !.RelevantVars) ->
+        ( set_tree234.member(!.RelevantVars, CellVar) ->
             ConjMap0 = get_conj_map(!.ConjMaps, CurId),
             ConjMap0 = conj_map(StringMap0, ListMap0, ElementMap0, EqvMap0),
             (
                 ConsId = string_const(StringConst)
             ->
-                svset.delete(CellVar, !RelevantVars),
+                set_tree234.delete(CellVar, !RelevantVars),
+                % ZZZ map.det_insert?
                 map.set(StringMap0, CellVar, StringConst, StringMap),
                 ConjMap = conj_map(StringMap, ListMap0, ElementMap0, EqvMap0)
             ;
@@ -542,8 +777,9 @@
                     List = list_skeleton_nil
                 )
             ->
-                svset.delete(CellVar, !RelevantVars),
-                svset.insert_list(ArgVars, !RelevantVars),
+                set_tree234.delete(CellVar, !RelevantVars),
+                set_tree234.insert_list(ArgVars, !RelevantVars),
+                % ZZZ map.det_insert?
                 map.set(ListMap0, CellVar, List, ListMap),
                 ConjMap = conj_map(StringMap0, ListMap, ElementMap0, EqvMap0)
             ;
@@ -553,24 +789,32 @@
                 Functor = unqualify_name(SymName),
                 (
                     Functor = "f",
-                    PolyType = f(0.0)
+                    Dummy = f(0.0)
                 ;
                     Functor = "i",
-                    PolyType = i(0)
+                    Dummy = i(0)
                 ;
                     Functor = "s",
-                    PolyType = s("0")
+                    Dummy = s("0")
                 ;
                     Functor = "c",
-                    PolyType = c('0')
+                    Dummy = c('0')
                 )
             ->
-                svset.delete(CellVar, !RelevantVars),
-                map.set(ElementMap0, CellVar, PolyType, ElementMap),
+                set_tree234.delete(CellVar, !RelevantVars),
+                ( ArgVars = [ArgVar] ->
+                    WhatToPrint = what_to_print(ArgVar, Dummy)
+                ;
+                    unexpected(this_file,
+                        "format_call_traverse_unify: arity mismatch")
+                ),
+                % ZZZ map.det_insert?
+                map.set(ElementMap0, CellVar, WhatToPrint, ElementMap),
                 ConjMap = conj_map(StringMap0, ListMap0, ElementMap, EqvMap0)
             ;
                 ConjMap = ConjMap0
             ),
+            % ZZZ svmap.det_update?
             svmap.set(CurId, ConjMap, !ConjMaps)
         ;
             true
@@ -587,37 +831,40 @@
 
 project_case_goal(case(_, _, Goal)) = Goal.
 
-:- pred traverse_disj(list(hlds_goal)::in, conj_id::in,
-    list(format_call_site)::in, list(format_call_site)::out,
+:- pred format_call_traverse_disj(module_info::in, list(hlds_goal)::in,
+    conj_id::in, list(format_call_site)::in, list(format_call_site)::out,
     counter::in, counter::out, conj_maps::in, conj_maps::out,
     conj_pred_map::in, conj_pred_map::out,
-    set(prog_var)::in, set(prog_var)::out, module_info::in) is det.
+    set_tree234(prog_var)::in, set_tree234(prog_var)::out) is det.
 
-traverse_disj(Disjuncts, CurId, !FormatCallSites, !Counter,
-        !ConjMaps, !PredMap, !RelevantVars, ModuleInfo) :-
-    traverse_disj_arms(Disjuncts, CurId, DisjFormatCallSitesLists,
-        !Counter, !ConjMaps, !PredMap, DisjRelevantVarSets, ModuleInfo),
+format_call_traverse_disj(ModuleInfo, Disjuncts, CurId, !FormatCallSites,
+        !Counter, !ConjMaps, !PredMap, !RelevantVars) :-
+    format_call_traverse_disj_arms(ModuleInfo, Disjuncts, CurId,
+        DisjFormatCallSitesLists, !Counter, !ConjMaps, !PredMap,
+        DisjRelevantVarSets),
     list.condense(DisjFormatCallSitesLists, DisjFormatCallSites),
     !:FormatCallSites = !.FormatCallSites ++ DisjFormatCallSites,
-    DisjRelevantVars = set.union_list(DisjRelevantVarSets),
-    set.union(DisjRelevantVars, !RelevantVars).
+    DisjRelevantVars = set_tree234.union_list(DisjRelevantVarSets),
+    set_tree234.union(DisjRelevantVars, !RelevantVars).
 
-:- pred traverse_disj_arms(list(hlds_goal)::in, conj_id::in,
-    list(list(format_call_site))::out,
+:- pred format_call_traverse_disj_arms(module_info::in, list(hlds_goal)::in,
+    conj_id::in, list(list(format_call_site))::out,
     counter::in, counter::out, conj_maps::in, conj_maps::out,
-    conj_pred_map::in, conj_pred_map::out, list(set(prog_var))::out,
-    module_info::in) is det.
+    conj_pred_map::in, conj_pred_map::out,
+    list(set_tree234(prog_var))::out) is det.
 
-traverse_disj_arms([], _, [], !Counter, !ConjMaps, !PredMap, [], _).
-traverse_disj_arms([Goal | Goals], ContainingId,
+format_call_traverse_disj_arms(_, [], _, [], !Counter, !ConjMaps, !PredMap,
+        []).
+format_call_traverse_disj_arms(ModuleInfo, [Goal | Goals], ContainingId,
         [GoalFormatCallSites | GoalsFormatCallSites], !Counter,
-        !ConjMaps, !PredMap, [GoalRelevantVars | GoalsRelevantVarSet],
-        ModuleInfo) :-
-    traverse_goal(Goal, DisjId, [], GoalFormatCallSites, !Counter,
-        !ConjMaps, !PredMap, set.init, GoalRelevantVars, ModuleInfo),
+        !ConjMaps, !PredMap, [GoalRelevantVars | GoalsRelevantVars]) :-
+    format_call_traverse_goal(ModuleInfo, Goal, DisjId, [],
+        GoalFormatCallSites, !Counter, !ConjMaps, !PredMap,
+        set_tree234.init, GoalRelevantVars),
     svmap.det_insert(DisjId, ContainingId, !PredMap),
-    traverse_disj_arms(Goals, ContainingId, GoalsFormatCallSites, !Counter,
-        !ConjMaps, !PredMap, GoalsRelevantVarSet, ModuleInfo).
+    format_call_traverse_disj_arms(ModuleInfo, Goals, ContainingId,
+        GoalsFormatCallSites, !Counter, !ConjMaps, !PredMap,
+        GoalsRelevantVars).
 
 :- func get_conj_map(conj_maps, conj_id) = conj_map.
 
@@ -636,6 +883,492 @@
 
 %-----------------------------------------------------------------------------%
 
+% XXX Consider using set_tree234s instead of plain sets.
+
+:- type fc_opt_goal_info
+    --->    fc_opt_goal_info(
+                fcogi_replacement_goal  :: hlds_goal,
+                fcogi_unneeded_vars     :: set_tree234(prog_var)
+            ).
+
+:- type fc_goal_path_map == map(goal_path, fc_opt_goal_info).
+
+    % Traverse the goal, looking for call sites in !.GoalPathMap. If we
+    % find them, we replace them with the corresponding goal.
+    %
+:- pred opt_format_call_sites_in_goal(hlds_goal::in, hlds_goal::out,
+    fc_goal_path_map::in, fc_goal_path_map::out,
+    set_tree234(prog_var)::in, set_tree234(prog_var)::out,
+    set_tree234(prog_var)::in, set_tree234(prog_var)::out) is det.
+
+opt_format_call_sites_in_goal(Goal0, Goal, !GoalPathMap,
+        !NeededVars, !ToDeleteVars) :-
+    Goal0 = hlds_goal(GoalExpr0, GoalInfo),
+    (
+        GoalExpr0 = plain_call(_, _, _, _, _, _),
+        GoalPath = goal_info_get_goal_path(GoalInfo),
+        ( svmap.remove(GoalPath, OptGoalInfo, !GoalPathMap) ->
+            OptGoalInfo = fc_opt_goal_info(ReplacementGoal, GoalToDeleteVars),
+            Goal = ReplacementGoal,
+            set_tree234.union(!.ToDeleteVars, GoalToDeleteVars, !:ToDeleteVars)
+        ;
+            Goal = Goal0,
+            NonLocals = goal_info_get_nonlocals(GoalInfo),
+            % Assume that all nonlocals are needed.
+            NonLocalsSet = set_tree234.sorted_list_to_set(
+                set.to_sorted_list(NonLocals)),
+            set_tree234.union(!.NeededVars, NonLocalsSet, !:NeededVars),
+            set_tree234.difference(!.ToDeleteVars, NonLocalsSet,
+                !:ToDeleteVars)
+        )
+    ;
+        ( GoalExpr0 = generic_call(_, _, _, _)
+        ; GoalExpr0 = call_foreign_proc(_, _, _, _, _, _, _)
+        ),
+        Goal = Goal0,
+        NonLocals = goal_info_get_nonlocals(GoalInfo),
+        % Assume that all nonlocals are needed.
+        NonLocalsSet = set_tree234.sorted_list_to_set(
+            set.to_sorted_list(NonLocals)),
+        set_tree234.union(!.NeededVars, NonLocalsSet, !:NeededVars),
+        set_tree234.difference(!.ToDeleteVars, NonLocalsSet, !:ToDeleteVars)
+    ;
+        GoalExpr0 = unify(LHS, RHS0, UnifyModes, Unification, UnifyContext),
+        (
+            Unification = construct(LHSVar, _ConsId, _RHSVars, _ArgModes, 
+                _How, _Unique, _SubInfo),
+            not set_tree234.contains(!.NeededVars, LHSVar),
+            % If this succeeds, then the backward traversal cannot encounter
+            % any more producers of LHSVar.
+            set_tree234.remove(LHSVar, !ToDeleteVars)
+        ->
+            % This effectively deletes the unification.
+            Goal = true_goal
+        ;
+            (
+                RHS0 = rhs_lambda_goal(Purity, HOGroundness, PredFunc,
+                    EvalMethod, LambdaNonLocals, LambdaQuantVars, LambdaModes,
+                    LambdaDetism, LambdaGoal0),
+                % LambdaGoal0 cannot generate anything in !.ToDeleteVars,
+                % but it can add to both !:NeededVars and !:ToDeleteVars.
+                opt_format_call_sites_in_goal(LambdaGoal0, LambdaGoal,
+                    !GoalPathMap, !NeededVars, !ToDeleteVars),
+                RHS = rhs_lambda_goal(Purity, HOGroundness, PredFunc,
+                    EvalMethod, LambdaNonLocals, LambdaQuantVars, LambdaModes,
+                    LambdaDetism, LambdaGoal),
+                GoalExpr = unify(LHS, RHS, UnifyModes, Unification,
+                    UnifyContext),
+                Goal = hlds_goal(GoalExpr, GoalInfo)
+            ;
+                ( RHS0 = rhs_var(_)
+                ; RHS0 = rhs_functor(_, _, _)
+                ),
+                Goal = Goal0,
+                NonLocals = goal_info_get_nonlocals(GoalInfo),
+                % Assume that all nonlocals are needed.
+                NonLocalsSet = set_tree234.sorted_list_to_set(
+                    set.to_sorted_list(NonLocals)),
+                set_tree234.union(!.NeededVars, NonLocalsSet, !:NeededVars),
+                set_tree234.difference(!.ToDeleteVars, NonLocalsSet,
+                    !:ToDeleteVars)
+            )
+        )
+    ;
+        % XXX Check that this works for parallel conjunctions.
+        GoalExpr0 = conj(ConjType, Conjuncts0),
+        opt_format_call_sites_in_conj(Conjuncts0, Conjuncts,
+            !GoalPathMap, !NeededVars, !ToDeleteVars),
+        GoalExpr = conj(ConjType, Conjuncts),
+        Goal = hlds_goal(GoalExpr, GoalInfo)
+    ;
+        GoalExpr0 = disj(Disjuncts0),
+        opt_format_call_sites_in_disj(Disjuncts0, Disjuncts, !GoalPathMap,
+            !.NeededVars, [], NeededVarsSets,
+            !.ToDeleteVars, [], ToDeleteVarsSets),
+        !:NeededVars = set_tree234.union_list(NeededVarsSets),
+        !:ToDeleteVars = set_tree234.intersect_list(ToDeleteVarsSets),
+        GoalExpr = disj(Disjuncts),
+        Goal = hlds_goal(GoalExpr, GoalInfo)
+    ;
+        GoalExpr0 = switch(SwitchVar, CanFail, Cases0),
+        opt_format_call_sites_in_switch(Cases0, Cases, !GoalPathMap,
+            !.NeededVars, [], NeededVarsSets,
+            !.ToDeleteVars, [], ToDeleteVarsSets),
+        !:NeededVars = set_tree234.union_list(NeededVarsSets),
+        !:ToDeleteVars = set_tree234.intersect_list(ToDeleteVarsSets),
+        GoalExpr = switch(SwitchVar, CanFail, Cases),
+        Goal = hlds_goal(GoalExpr, GoalInfo)
+    ;
+        GoalExpr0 = if_then_else(Vars, Cond0, Then0, Else0),
+        opt_format_call_sites_in_goal(Else0, Else, !GoalPathMap,
+            !.NeededVars, NeededVarsBeforeElse,
+            !.ToDeleteVars, ToDeleteVarsBeforeElse),
+        opt_format_call_sites_in_goal(Then0, Then, !GoalPathMap,
+            !.NeededVars, NeededVarsBeforeThen,
+            !.ToDeleteVars, ToDeleteVarsBeforeThen),
+        opt_format_call_sites_in_goal(Cond0, Cond, !GoalPathMap,
+            NeededVarsBeforeThen, NeededVarsBeforeCond,
+            ToDeleteVarsBeforeThen, ToDeleteVarsBeforeCond),
+        set_tree234.union(NeededVarsBeforeCond, NeededVarsBeforeElse,
+            !:NeededVars),
+        set_tree234.intersect(ToDeleteVarsBeforeCond, ToDeleteVarsBeforeElse,
+            !:ToDeleteVars),
+        GoalExpr = if_then_else(Vars, Cond, Then, Else),
+        Goal = hlds_goal(GoalExpr, GoalInfo)
+    ;
+        GoalExpr0 = negation(SubGoal0),
+        % SubGoal0 cannot generate anything in !.ToDeleteVars, but it can add
+        % to both !:NeededVars and !:ToDeleteVars.
+        opt_format_call_sites_in_goal(SubGoal0, SubGoal,
+            !GoalPathMap, !NeededVars, !ToDeleteVars),
+        GoalExpr = negation(SubGoal),
+        Goal = hlds_goal(GoalExpr, GoalInfo)
+    ;
+        GoalExpr0 = scope(Reason, SubGoal0),
+        ( Reason = from_ground_term(_, from_ground_term_construct) ->
+            % We did not traverse such scopes in format_call_traverse_conj,
+            % so there are no goals for us to transform in SubGoal0.
+            % There is not even any variable consumption for us to record,
+            % or any variable production for us to eliminate (since the things
+            % being printed out by format calls are all of atomic types,
+            % and these scopes can produce only values of non-atomic types).
+            Goal = Goal0
+        ;
+            opt_format_call_sites_in_goal(SubGoal0, SubGoal,
+                !GoalPathMap, !NeededVars, !ToDeleteVars),
+            GoalExpr = scope(Reason, SubGoal),
+            Goal = hlds_goal(GoalExpr, GoalInfo)
+        )
+    ;
+        GoalExpr0 = shorthand(ShortHand0),
+        (
+            ShortHand0 = atomic_goal(AtomicType, OuterVars, InnerVars,
+                OutputVars, MainGoal0, OrElseGoals0, OrElseInners),
+            opt_format_call_sites_in_goal(MainGoal0, MainGoal,
+                !GoalPathMap, !.NeededVars, NeededVarsMain,
+                !.ToDeleteVars, ToDeleteVarsMain),
+            opt_format_call_sites_in_disj(OrElseGoals0, OrElseGoals,
+                !GoalPathMap, !.NeededVars, [], NeededVarsSets,
+                !.ToDeleteVars, [], ToDeleteVarsSets),
+            !:NeededVars =
+                set_tree234.union_list([NeededVarsMain | NeededVarsSets]),
+            !:ToDeleteVars =
+                set_tree234.intersect_list(
+                    [ToDeleteVarsMain | ToDeleteVarsSets]),
+            ShortHand = atomic_goal(AtomicType, OuterVars, InnerVars,
+                OutputVars, MainGoal, OrElseGoals, OrElseInners),
+            GoalExpr = shorthand(ShortHand)
+        ;
+            ShortHand0 = try_goal(MaybeIO, ResultVar, SubGoal0),
+            opt_format_call_sites_in_goal(SubGoal0, SubGoal,
+                !GoalPathMap, !NeededVars, !ToDeleteVars),
+            ShortHand = try_goal(MaybeIO, ResultVar, SubGoal),
+            GoalExpr = shorthand(ShortHand)
+        ;
+            ShortHand0 = bi_implication(_, _),
+            % These should have been expanded by now.
+            unexpected(this_file,
+                "opt_format_call_sites_in_goal: bi_implication")
+        ),
+        Goal = hlds_goal(GoalExpr, GoalInfo)
+    ).
+
+:- pred opt_format_call_sites_in_conj(
+    list(hlds_goal)::in, list(hlds_goal)::out,
+    fc_goal_path_map::in, fc_goal_path_map::out,
+    set_tree234(prog_var)::in, set_tree234(prog_var)::out,
+    set_tree234(prog_var)::in, set_tree234(prog_var)::out) is det.
+
+opt_format_call_sites_in_conj([], [], !GoalPathMap,
+        !NeededVars, !ToDeleteVars).
+opt_format_call_sites_in_conj([Goal0 | Goals0], [Goal | Goals], !GoalPathMap,
+        !NeededVars, !ToDeleteVars) :-
+    % We traverse conjunctions backwards.
+    opt_format_call_sites_in_conj(Goals0, Goals, !GoalPathMap,
+        !NeededVars, !ToDeleteVars),
+    opt_format_call_sites_in_goal(Goal0, Goal, !GoalPathMap,
+        !NeededVars, !ToDeleteVars).
+
+:- pred opt_format_call_sites_in_disj(
+    list(hlds_goal)::in, list(hlds_goal)::out,
+    fc_goal_path_map::in, fc_goal_path_map::out,
+    set_tree234(prog_var)::in,
+    list(set_tree234(prog_var))::in, list(set_tree234(prog_var))::out,
+    set_tree234(prog_var)::in,
+    list(set_tree234(prog_var))::in, list(set_tree234(prog_var))::out)
+    is det.
+
+opt_format_call_sites_in_disj([], [], !GoalPathMap,
+        _, !NeededVarsSets, _, !ToDeleteVarsSets).
+opt_format_call_sites_in_disj([Goal0 | Goals0], [Goal | Goals], !GoalPathMap,
+        NeededVars0, !NeededVarsSets, ToDeleteVars0, !ToDeleteVarsSets) :-
+    % The order of traversal does not matter for disjunctions, since the
+    % disjuncts are independent. This order is more efficient.
+    opt_format_call_sites_in_goal(Goal0, Goal, !GoalPathMap,
+        NeededVars0, NeededVars, ToDeleteVars0, ToDeleteVars),
+    !:NeededVarsSets = [NeededVars | !.NeededVarsSets],
+    !:ToDeleteVarsSets = [ToDeleteVars | !.ToDeleteVarsSets],
+    opt_format_call_sites_in_disj(Goals0, Goals, !GoalPathMap,
+        NeededVars0, !NeededVarsSets, ToDeleteVars0, !ToDeleteVarsSets).
+
+:- pred opt_format_call_sites_in_switch(list(case)::in, list(case)::out,
+    fc_goal_path_map::in, fc_goal_path_map::out,
+    set_tree234(prog_var)::in,
+    list(set_tree234(prog_var))::in, list(set_tree234(prog_var))::out,
+    set_tree234(prog_var)::in,
+    list(set_tree234(prog_var))::in, list(set_tree234(prog_var))::out)
+    is det.
+
+opt_format_call_sites_in_switch([], [], !GoalPathMap,
+        _, !NeededVarsSets, _, !ToDeleteVarsSets).
+opt_format_call_sites_in_switch([Case0 | Cases0], [Case | Cases], !GoalPathMap,
+        NeededVars0, !NeededVarsSets, ToDeleteVars0, !ToDeleteVarsSets) :-
+    % The order of traversal does not matter for switches, since the
+    % switch arms are independent. This order is more efficient.
+    Case0 = case(FirstConsId, LaterConsIds, Goal0),
+    opt_format_call_sites_in_goal(Goal0, Goal, !GoalPathMap,
+        NeededVars0, NeededVars, ToDeleteVars0, ToDeleteVars),
+    !:NeededVarsSets = [NeededVars | !.NeededVarsSets],
+    !:ToDeleteVarsSets = [ToDeleteVars | !.ToDeleteVarsSets],
+    Case = case(FirstConsId, LaterConsIds, Goal),
+    opt_format_call_sites_in_switch(Cases0, Cases, !GoalPathMap,
+        NeededVars0, !NeededVarsSets, ToDeleteVars0, !ToDeleteVarsSets).
+
+%-----------------------------------------------------------------------------%
+
+:- pred create_string_format_replacement(module_info::in, list(char)::in,
+    prog_var::in, list(prog_var)::in, hlds_goal::out,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is semidet.
+
+create_string_format_replacement(ModuleInfo, FormatStringChars, ResultVar,
+        VarsToPrint, Goal, !VarSet, !VarTypes) :-
+    interpret_format_string(FormatStringChars, [], VarsToPrint, Components),
+    replace_string_format(ModuleInfo, Components, yes(ResultVar),
+        ActualResultVar, Goals, !VarSet, !VarTypes),
+    ( ActualResultVar = ResultVar ->
+        AllGoals = Goals
+    ;
+        make_simple_assign(ResultVar, ActualResultVar, umc_explicit, [],
+            AssignGoal),
+        AllGoals = Goals ++ [AssignGoal]
+    ),
+    NonLocals = set.list_to_set([ResultVar | VarsToPrint]),
+    InstMapDelta = instmap_delta_bind_var(ResultVar),
+    goal_info_init(NonLocals, InstMapDelta, detism_det, purity_pure,
+        term.context_init, GoalInfo),
+    conj_list_to_goal(AllGoals, GoalInfo, Goal).
+
+:- pred create_io_format_replacement(module_info::in, list(char)::in,
+    maybe(prog_var)::in, prog_var::in, prog_var::in, list(prog_var)::in,
+    hlds_goal::out,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is semidet.
+
+create_io_format_replacement(ModuleInfo, FormatStringChars,
+        MaybeStreamVar, IOInVar, IOOutVar, VarsToPrint, Goal,
+        !VarSet, !VarTypes) :-
+    interpret_format_string(FormatStringChars, [], VarsToPrint, Components),
+    replace_string_format(ModuleInfo, Components, no, ResultVar, Goals,
+        !VarSet, !VarTypes),
+    (
+        MaybeStreamVar = yes(StreamVar),
+        ArgVars = [StreamVar, ResultVar, IOInVar, IOOutVar]
+    ;
+        MaybeStreamVar = no,
+        ArgVars = [ResultVar, IOInVar, IOOutVar]
+    ),
+    InstMapDelta = instmap_delta_from_assoc_list(
+        [IOOutVar - ground(unique, none)]),
+    generate_simple_call(mercury_io_module, "write_string",
+        pf_predicate, only_mode, detism_det, purity_pure, ArgVars, [],
+        InstMapDelta, ModuleInfo, term.context_init, CallGoal),
+
+    AllGoals = Goals ++ [CallGoal],
+    NonLocals = set.list_to_set(ArgVars ++ VarsToPrint),
+    goal_info_init(NonLocals, InstMapDelta, detism_det, purity_pure,
+        term.context_init, GoalInfo),
+    conj_list_to_goal(AllGoals, GoalInfo, Goal).
+
+%-----------------------------------------------------------------------------%
+
+:- type string_component
+    --->    string_constant(string)
+    ;       var_to_print_int(prog_var)
+    ;       var_to_print_float(prog_var)
+    ;       var_to_print_string(prog_var)
+    ;       var_to_print_char(prog_var).
+
+:- pred interpret_format_string(list(char)::in, list(char)::in,
+    list(prog_var)::in, list(string_component)::out) is semidet.
+
+interpret_format_string([], RevConstChars, [], Components) :-
+    (
+        RevConstChars = [],
+        Components = []
+    ;
+        RevConstChars = [_ | _],
+        list.reverse(RevConstChars, ConstChars),
+        string.from_char_list(ConstChars, ConstString),
+        Components = [string_constant(ConstString)]
+    ).
+interpret_format_string([Char0 | Chars0], !.RevConstChars, Vars0,
+        Components) :-
+    ( Char0 = '%' ->
+        % A valid format string cannot end on an unescaped percent sign.
+        Chars0 = [Char1 | Chars1],
+        ( Char1 = '%' ->
+            % Char0 escapes Char1. Keep Char1, but throw away
+            !:RevConstChars = [Char1 | !.RevConstChars],
+            interpret_format_string(Chars1, !.RevConstChars, Vars0, Components)
+        ;
+            Vars0 = [Var0 | Vars1],
+            (
+                !.RevConstChars = [],
+                ConstComponents = []
+            ;
+                !.RevConstChars = [_ | _],
+                list.reverse(!.RevConstChars, ConstChars),
+                string.from_char_list(ConstChars, ConstString),
+                ConstComponents = [string_constant(ConstString)]
+            ),
+            (
+                Char1 = 'd',
+                VarComponent = var_to_print_int(Var0)
+            ;
+                Char1 = 'f',
+                VarComponent = var_to_print_float(Var0),
+                % Currently, string.m does not export the predicate it uses
+                % by default to format float values. This predicate generates
+                % strings of six characters in the absence of an explicit
+                % precision specification, so it often pads numbers on the
+                % right with zeros, whereas plain old string.float_to_string
+                % does no such thing. Under these circumstances, replacing
+                % an invocation of string.format with one of float_to_string
+                % would change the output.
+                fail
+            ;
+                Char1 = 's',
+                VarComponent = var_to_print_string(Var0)
+            ;
+                Char1 = 'c',
+                VarComponent = var_to_print_char(Var0)
+            ),
+            interpret_format_string(Chars1, [], Vars1, TailComponents),
+            Components = ConstComponents ++ [VarComponent | TailComponents]
+        )
+    ;
+        % We do not want to look for Char0 = '\\', because any escape sequences
+        % started that way have already been processed. If we did throw away
+        % backslashes in favor of the character they supposedly escaped,
+        % this would change the output.
+        %
+        % XXX Do we need to watch out for any escape mechanisms besides
+        % percent signs and backslashes?
+
+        !:RevConstChars = [Char0 | !.RevConstChars],
+        interpret_format_string(Chars0, !.RevConstChars, Vars0, Components)
+    ).
+
+:- pred replace_string_format(module_info::in, list(string_component)::in,
+    maybe(prog_var)::in, prog_var::out, list(hlds_goal)::out,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
+
+replace_string_format(ModuleInfo, Components, MaybeResultVar, ResultVar, Goals,
+        !VarSet, !VarTypes) :-
+    (
+        Components = [],
+        make_result_var_if_needed(MaybeResultVar, ResultVar,
+            !VarSet, !VarTypes),
+        make_string_const_construction(ResultVar, "", Goal),
+        Goals = [Goal]
+    ;
+        Components = [FirstComponent | LaterComponents],
+        (
+            LaterComponents = [],
+            represent_component(ModuleInfo, FirstComponent,
+                MaybeResultVar, ResultVar, Goals, !VarSet, !VarTypes)
+        ;
+            LaterComponents = [_ | _],
+            replace_string_format(ModuleInfo, LaterComponents,
+                no, LaterResultVar, LaterGoals, !VarSet, !VarTypes),
+            represent_component(ModuleInfo, FirstComponent,
+                no, FirstResultVar, FirstGoals,!VarSet, !VarTypes),
+            make_result_var_if_needed(MaybeResultVar, ResultVar,
+                !VarSet, !VarTypes),
+            generate_simple_call(mercury_string_module, "++", pf_function,
+                only_mode, detism_det, purity_pure,
+                [FirstResultVar, LaterResultVar, ResultVar], [],
+                instmap_delta_from_assoc_list(
+                    [ResultVar - ground(unique, none)]),
+                ModuleInfo, term.context_init, AppendGoal),
+            Goals = LaterGoals ++ FirstGoals ++ [AppendGoal]
+        )
+    ).
+
+:- pred make_result_var_if_needed(maybe(prog_var)::in, prog_var::out,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
+
+make_result_var_if_needed(MaybeResultVar, ResultVar, !VarSet, !VarTypes) :-
+    (
+        MaybeResultVar = yes(ResultVar)
+    ;
+        MaybeResultVar = no,
+        svvarset.new_var(ResultVar, !VarSet),
+        svmap.det_insert(ResultVar, string_type, !VarTypes)
+    ).
+
+:- pred represent_component(module_info::in, string_component::in,
+    maybe(prog_var)::in, prog_var::out, list(hlds_goal)::out,
+    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
+
+represent_component(ModuleInfo, Component, MaybeResultVar, ResultVar,
+        Goals, !VarSet, !VarTypes) :-
+    (
+        Component = string_constant(StringConstant),
+        make_result_var_if_needed(MaybeResultVar, ResultVar,
+            !VarSet, !VarTypes),
+        make_string_const_construction(ResultVar, StringConstant, Goal),
+        Goals = [Goal]
+    ;
+        Component = var_to_print_int(IntVar),
+        make_result_var_if_needed(MaybeResultVar, ResultVar,
+            !VarSet, !VarTypes),
+        generate_simple_call(mercury_string_module, "int_to_string",
+            pf_function, only_mode, detism_det, purity_pure,
+            [IntVar, ResultVar], [],
+            instmap_delta_from_assoc_list(
+                [ResultVar - ground(unique, none)]),
+            ModuleInfo, term.context_init, Goal),
+        Goals = [Goal]
+    ;
+        Component = var_to_print_float(FloatVar),
+        make_result_var_if_needed(MaybeResultVar, ResultVar,
+            !VarSet, !VarTypes),
+        generate_simple_call(mercury_string_module, "float_to_string",
+            pf_function, only_mode, detism_det, purity_pure,
+            [FloatVar, ResultVar], [],
+            instmap_delta_from_assoc_list(
+                [ResultVar - ground(unique, none)]),
+            ModuleInfo, term.context_init, Goal),
+        Goals = [Goal]
+    ;
+        Component = var_to_print_char(CharVar),
+        make_result_var_if_needed(MaybeResultVar, ResultVar,
+            !VarSet, !VarTypes),
+        generate_simple_call(mercury_string_module, "char_to_string",
+            pf_function, only_mode, detism_det, purity_pure,
+            [CharVar, ResultVar], [],
+            instmap_delta_from_assoc_list(
+                [ResultVar - ground(unique, none)]),
+            ModuleInfo, term.context_init, Goal),
+        Goals = [Goal]
+    ;
+        Component = var_to_print_string(StringVar),
+        ResultVar = StringVar,
+        Goals = []
+    ).
+
+%-----------------------------------------------------------------------------%
+
 :- func this_file = string.
 
 this_file = "format_call.m".
Index: compiler/goal_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/goal_util.m,v
retrieving revision 1.169
diff -u -b -r1.169 goal_util.m
--- compiler/goal_util.m	2 Sep 2009 00:30:14 -0000	1.169
+++ compiler/goal_util.m	2 Sep 2009 00:33:42 -0000
@@ -29,7 +29,6 @@
 :- import_module mdbcomp.program_representation.
 :- import_module parse_tree.prog_data.
 
-:- import_module assoc_list.
 :- import_module bool.
 :- import_module list.
 :- import_module maybe.
@@ -337,7 +336,7 @@
     hlds_goal::in, bool::out, module_info::in, module_info::out) is det.
 
     % generate_simple_call(ModuleName, ProcName, PredOrFunc, ModeNo, Detism,
-    %   Purity, Args, Features, InstMapDeltaSrc, ModuleInfo, Context,
+    %   Purity, Args, Features, InstMapDelta, ModuleInfo, Context,
     %   CallGoal):
     %
     % Generate a call to a builtin procedure (e.g. from the private_builtin
@@ -352,12 +351,12 @@
     %
 :- pred generate_simple_call(module_name::in, string::in, pred_or_func::in,
     mode_no::in, determinism::in, purity::in, list(prog_var)::in,
-    list(goal_feature)::in, assoc_list(prog_var, mer_inst)::in,
+    list(goal_feature)::in, instmap_delta::in,
     module_info::in, term.context::in, hlds_goal::out) is det.
 
     % generate_foreign_proc(ModuleName, ProcName, PredOrFunc, ModeNo, Detism,
     %   Purity, Attributes, Args, ExtraArgs, MaybeTraceRuntimeCond, Code,
-    %   Features, InstMapDeltaSrc, ModuleInfo, Context, CallGoal):
+    %   Features, InstMapDelta, ModuleInfo, Context, CallGoal):
     %
     % generate_foreign_proc is similar to generate_simple_call,
     % but also assumes that the called predicate is defined via a
@@ -372,7 +371,7 @@
     pragma_foreign_proc_attributes::in,
     list(foreign_arg)::in, list(foreign_arg)::in,
     maybe(trace_expr(trace_runtime))::in, string::in,
-    list(goal_feature)::in, assoc_list(prog_var, mer_inst)::in,
+    list(goal_feature)::in, instmap_delta::in,
     module_info::in, term.context::in, hlds_goal::out) is det.
 
     % Generate a cast goal.  The input and output insts are just ground.
@@ -479,7 +478,7 @@
     UnifyContext = unify_context(umc_explicit, []),
     GoalExpr = unify(OrigVar, rhs_var(NewVar), Mode, UnifyInfo, UnifyContext),
     set.list_to_set([OrigVar, NewVar], NonLocals),
-    instmap_delta_from_assoc_list([OrigVar - NewInst], UnifyInstMapDelta),
+    UnifyInstMapDelta = instmap_delta_from_assoc_list([OrigVar - NewInst]),
     goal_info_init(NonLocals, UnifyInstMapDelta, detism_det, purity_pure,
         term.context_init, GoalInfo),
     Goal = hlds_goal(GoalExpr, GoalInfo),
@@ -1680,7 +1679,7 @@
 %-----------------------------------------------------------------------------%
 
 generate_simple_call(ModuleName, ProcName, PredOrFunc, ModeNo, Detism, Purity,
-        Args, Features, InstMap, ModuleInfo, Context, Goal) :-
+        Args, Features, InstMapDelta0, ModuleInfo, Context, Goal) :-
     list.length(Args, Arity),
     lookup_builtin_pred_proc_id(ModuleInfo, ModuleName, ProcName,
         PredOrFunc, Arity, ModeNo, PredId, ProcId),
@@ -1693,8 +1692,7 @@
 
     GoalExpr = plain_call(PredId, ProcId, Args, BuiltinState, no,
         qualified(ModuleName, ProcName)),
-    set.init(NonLocals0),
-    set.insert_list(NonLocals0, Args, NonLocals),
+    set.list_to_set(Args, NonLocals),
     determinism_components(Detism, _CanFail, NumSolns),
     (
         NumSolns = at_most_zero,
@@ -1704,7 +1702,7 @@
         ; NumSolns = at_most_many
         ; NumSolns = at_most_many_cc
         ),
-        instmap_delta_from_assoc_list(InstMap, InstMapDelta)
+        InstMapDelta = InstMapDelta0
     ),
     module_info_pred_info(ModuleInfo, PredId, PredInfo),
     pred_info_get_purity(PredInfo, PredPurity),
@@ -1717,7 +1715,7 @@
 
 generate_foreign_proc(ModuleName, ProcName, PredOrFunc, ModeNo, Detism,
         Purity, Attributes, Args, ExtraArgs, MaybeTraceRuntimeCond, Code,
-        Features, InstMap, ModuleInfo, Context, Goal) :-
+        Features, InstMapDelta0, ModuleInfo, Context, Goal) :-
     list.length(Args, Arity),
     lookup_builtin_pred_proc_id(ModuleInfo, ModuleName, ProcName,
         PredOrFunc, Arity, ModeNo, PredId, ProcId),
@@ -1737,7 +1735,7 @@
         ; NumSolns = at_most_many
         ; NumSolns = at_most_many_cc
         ),
-        instmap_delta_from_assoc_list(InstMap, InstMapDelta)
+        InstMapDelta = InstMapDelta0
     ),
     module_info_pred_info(ModuleInfo, PredId, PredInfo),
     pred_info_get_purity(PredInfo, PredPurity),
@@ -1756,7 +1754,7 @@
 generate_cast_with_insts(CastType, InArg, OutArg, InInst, OutInst, Context,
         Goal) :-
     set.list_to_set([InArg, OutArg], NonLocals),
-    instmap_delta_from_assoc_list([OutArg - OutInst], InstMapDelta),
+    InstMapDelta = instmap_delta_from_assoc_list([OutArg - OutInst]),
     goal_info_init(NonLocals, InstMapDelta, detism_det, purity_pure, Context,
         GoalInfo),
     GoalExpr = generic_call(cast(CastType), [InArg, OutArg],
Index: compiler/granularity.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/granularity.m,v
retrieving revision 1.13
diff -u -b -r1.13 granularity.m
--- compiler/granularity.m	17 Jun 2009 03:25:59 -0000	1.13
+++ compiler/granularity.m	1 Sep 2009 00:57:49 -0000
@@ -28,6 +28,7 @@
 :- import_module hlds.goal_util.
 :- import_module hlds.hlds_pred.
 :- import_module hlds.hlds_goal.
+:- import_module hlds.instmap.
 :- import_module hlds.pred_table.
 :- import_module hlds.quantification.
 :- import_module libs.compiler_util.
@@ -120,7 +121,6 @@
                 ExtraArgs = [],
                 MaybeRuntimeCond = no,
                 Features = [],
-                InstMapDeltaSrc = [],
                 Context = goal_info_get_context(GoalInfo),
                 some [!Attributes] (
                     !:Attributes = default_attributes(lang_c),
@@ -139,7 +139,7 @@
                 generate_foreign_proc(ModuleName, ProcName, pf_predicate,
                     only_mode, detism_semi, purity_impure, Attributes,
                     Args, ExtraArgs, MaybeRuntimeCond, Code, Features,
-                    InstMapDeltaSrc, ModuleInfo, Context, Cond),
+                    instmap_delta_bind_no_var, ModuleInfo, Context, Cond),
 
                 Then = hlds_goal(conj(parallel_conj, Goals), GoalInfo),
                 Else = hlds_goal(conj(plain_conj, Goals), GoalInfo),
Index: compiler/higher_order.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/higher_order.m,v
retrieving revision 1.183
diff -u -b -r1.183 higher_order.m
--- compiler/higher_order.m	19 Aug 2009 07:44:53 -0000	1.183
+++ compiler/higher_order.m	1 Sep 2009 01:28:02 -0000
@@ -2242,8 +2242,7 @@
             Call = plain_call(SpecialPredId, SpecialProcId, NewCallArgs,
                 not_builtin, MaybeContext, SymName),
             set.list_to_set([ComparisonResult, Arg1, Arg2], NonLocals),
-            instmap_delta_from_assoc_list(
-                [ComparisonResult - ground(shared,none)], InstMapDelta),
+            InstMapDelta = instmap_delta_bind_var(ComparisonResult),
             Detism = detism_det,
             goal_info_init(NonLocals, InstMapDelta, Detism, purity_pure,
                 Context, GoalInfo),
@@ -2286,8 +2285,7 @@
     ;
         MaybeResult = yes(ComparisonResult),
         set.insert(NonLocals0, ComparisonResult, NonLocals),
-        instmap_delta_from_assoc_list(
-            [ComparisonResult - ground(shared, none)], InstMapDelta),
+        InstMapDelta = instmap_delta_bind_var(ComparisonResult),
         Detism = detism_det,
         % Build a new call with the unwrapped arguments.
         find_builtin_type_with_equivalent_compare(ModuleInfo, WrappedType,
@@ -2419,8 +2417,7 @@
         (ground(shared, none) - ground(shared, none))],
     set.list_to_set([Arg, UnwrappedArg], NonLocals),
     % This will be recomputed later.
-    instmap_delta_from_assoc_list([UnwrappedArg - ground(shared, none)],
-        InstMapDelta),
+    InstMapDelta = instmap_delta_bind_var(UnwrappedArg),
     goal_info_init(NonLocals, InstMapDelta, detism_det, purity_pure, Context,
         GoalInfo),
     GoalExpr = unify(Arg, rhs_functor(ConsId, no, [UnwrappedArg]),
@@ -3172,7 +3169,7 @@
             CurriedArgModes1, UniModes),
         set.list_to_set(CurriedHeadVars1, ConstNonLocals),
         ConstInst = ground(shared, GroundInstInfo),
-        instmap_delta_from_assoc_list([LVar - ConstInst], ConstInstMapDelta),
+        ConstInstMapDelta = instmap_delta_from_assoc_list([LVar - ConstInst]),
         goal_info_init(ConstNonLocals, ConstInstMapDelta, detism_det,
             purity_pure, ConstGoalInfo),
         RHS = rhs_functor(ConsId, no, CurriedHeadVars1),
Index: compiler/hlds_goal.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_goal.m,v
retrieving revision 1.210
diff -u -b -r1.210 hlds_goal.m
--- compiler/hlds_goal.m	2 Sep 2009 00:30:15 -0000	1.210
+++ compiler/hlds_goal.m	2 Sep 2009 00:33:42 -0000
@@ -1633,6 +1633,13 @@
     prog_context::in, unify_main_context::in, unify_sub_contexts::in,
     hlds_goal::out) is det.
 
+    % Create the hlds_goal for a unification that assigns the second variable
+    % to the first. The initial inst of the second variable should be
+    % ground_inst. The resulting goal has all its fields filled in.
+    %
+:- pred make_simple_assign(prog_var::in, prog_var::in,
+    unify_main_context::in, unify_sub_contexts::in, hlds_goal::out) is det.
+
     % Create the hlds_goal for a unification that tests the equality of two
     % values of atomic types. The resulting goal has all its fields filled in.
     %
@@ -3062,14 +3069,23 @@
 
 %-----------------------------------------------------------------------------%
 
+make_simple_assign(X, Y, UnifyMainContext, UnifySubContext, Goal) :-
+    Ground = ground(shared, none),
+    Mode = ((free -> Ground) - (Ground -> Ground)),
+    Unification = assign(X, Y),
+    UnifyContext = unify_context(UnifyMainContext, UnifySubContext),
+    goal_info_init(set.list_to_set([X, Y]), instmap_delta_bind_var(X),
+        detism_semi, purity_pure, GoalInfo),
+    GoalExpr = unify(X, rhs_var(Y), Mode, Unification, UnifyContext),
+    Goal = hlds_goal(GoalExpr, GoalInfo).
+
 make_simple_test(X, Y, UnifyMainContext, UnifySubContext, Goal) :-
     Ground = ground(shared, none),
     Mode = ((Ground -> Ground) - (Ground -> Ground)),
     Unification = simple_test(X, Y),
     UnifyContext = unify_context(UnifyMainContext, UnifySubContext),
-    instmap_delta_init_reachable(InstMapDelta),
-    goal_info_init(list_to_set([X, Y]), InstMapDelta, detism_semi, purity_pure,
-        GoalInfo),
+    goal_info_init(set.list_to_set([X, Y]), instmap_delta_bind_no_var,
+        detism_semi, purity_pure, GoalInfo),
     GoalExpr = unify(X, rhs_var(Y), Mode, Unification, UnifyContext),
     Goal = hlds_goal(GoalExpr, GoalInfo).
 
@@ -3166,7 +3182,7 @@
     UnifyContext = unify_context(umc_explicit, []),
     Unify = unify(Var, Rhs, UnifyMode, Unification, UnifyContext),
     set.list_to_set([Var | Args], NonLocals),
-    instmap_delta_from_assoc_list([Var - ground_inst], InstMapDelta),
+    InstMapDelta = instmap_delta_bind_var(Var),
     goal_info_init(NonLocals, InstMapDelta, detism_det, purity_pure, GoalInfo),
     Goal = hlds_goal(Unify, GoalInfo).
 
@@ -3181,9 +3197,7 @@
         cannot_cgc),
     Unify = unify(Var, Rhs, UnifyMode, Unification, UnifyContext),
     set.list_to_set([Var | Args], NonLocals),
-    list.duplicate(Arity, ground_inst, DeltaValues),
-    assoc_list.from_corresponding_lists(Args, DeltaValues, DeltaAL),
-    instmap_delta_from_assoc_list(DeltaAL, InstMapDelta),
+    InstMapDelta = instmap_delta_bind_vars(Args),
     goal_info_init(NonLocals, InstMapDelta, detism_det, purity_pure, GoalInfo),
     Goal = hlds_goal(Unify, GoalInfo).
 
Index: compiler/hlds_out.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_out.m,v
retrieving revision 1.469
diff -u -b -r1.469 hlds_out.m
--- compiler/hlds_out.m	2 Sep 2009 00:30:15 -0000	1.469
+++ compiler/hlds_out.m	2 Sep 2009 00:33:43 -0000
@@ -1106,6 +1106,7 @@
 marker_name(marker_calls_are_fully_qualified, "calls_are_fully_qualified").
 marker_name(marker_mode_check_clauses, "mode_check_clauses").
 marker_name(marker_mutable_access_pred, "mutable_access_pred").
+marker_name(marker_has_format_call, "has_format_call").
 
 write_marker(Marker, !IO) :-
     marker_name(Marker, Name),
Index: compiler/hlds_pred.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_pred.m,v
retrieving revision 1.253
diff -u -b -r1.253 hlds_pred.m
--- compiler/hlds_pred.m	30 Aug 2009 22:59:21 -0000	1.253
+++ compiler/hlds_pred.m	31 Aug 2009 23:34:33 -0000
@@ -414,11 +414,20 @@
             % (in inst_match.bound_inst_list_contains_instname and
             % instmap.merge) would be unacceptable.
 
-    ;       marker_mutable_access_pred.
+    ;       marker_mutable_access_pred
             % This predicate is part of the machinery used to access mutables.
             % This marker is used to inform inlining that we should _always_
             % attempt to inline this predicate across module boundaries.
 
+    ;       marker_has_format_call.
+            % The body of this predicate contains calls to predicates
+            % recognized by format_call.is_format_call. This marker is set
+            % if applicable during typechecking, when the predicate body
+            % has to be traversed anyway. It is used by later passes
+            % that optimize correct format calls and/or warn about incorrect
+            % (or at least not verifiably correct) format calls, which
+            % would be no-ops on predicates that do not have this marker.
+
     % An abstract set of attributes.
 :- type pred_attributes.
 
@@ -2619,7 +2628,7 @@
     proc_info_get_argmodes(ProcInfo, ArgModes),
     mode_list_get_initial_insts(ModuleInfo, ArgModes, InitialInsts),
     assoc_list.from_corresponding_lists(HeadVars, InitialInsts, InstAL),
-    instmap_from_assoc_list(InstAL, InstMap).
+    InstMap = instmap_from_assoc_list(InstAL).
 
 proc_info_declared_argmodes(ProcInfo, ArgModes) :-
     proc_info_get_maybe_declared_argmodes(ProcInfo, MaybeArgModes),
Index: compiler/inlining.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/inlining.m,v
retrieving revision 1.162
diff -u -b -r1.162 inlining.m
--- compiler/inlining.m	28 Jan 2009 06:57:46 -0000	1.162
+++ compiler/inlining.m	31 Aug 2009 19:44:15 -0000
@@ -540,7 +540,7 @@
         % through the procedure may lead to more efficient code.
         (
             DetChanged = yes,
-            det_infer_proc(PredId, ProcId, !ModuleInfo, _, _, _)
+            det_infer_proc(PredId, ProcId, !ModuleInfo, _, _, [], _)
         ;
             DetChanged = no
         )
Index: compiler/instmap.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/instmap.m,v
retrieving revision 1.65
diff -u -b -r1.65 instmap.m
--- compiler/instmap.m	11 Jun 2009 07:00:10 -0000	1.65
+++ compiler/instmap.m	1 Sep 2009 00:58:01 -0000
@@ -74,15 +74,19 @@
     %
 :- pred instmap_delta_is_unreachable(instmap_delta::in) is semidet.
 
-:- pred instmap_from_assoc_list(assoc_list(prog_var, mer_inst)::in,
-    instmap::out) is det.
+:- func instmap_from_assoc_list(assoc_list(prog_var, mer_inst)) =
+    instmap.
 
-:- pred instmap_delta_from_assoc_list(assoc_list(prog_var, mer_inst)::in,
-    instmap_delta::out) is det.
+:- func instmap_delta_from_assoc_list(assoc_list(prog_var, mer_inst)) =
+    instmap_delta.
 
 :- pred instmap_delta_from_mode_list(list(prog_var)::in, list(mer_mode)::in,
     module_info::in, instmap_delta::out) is det.
 
+:- func instmap_delta_bind_no_var = instmap_delta.
+:- func instmap_delta_bind_var(prog_var) = instmap_delta.
+:- func instmap_delta_bind_vars(list(prog_var)) = instmap_delta.
+
 %-----------------------------------------------------------------------------%
 
     % Return the set of variables in an instmap.
@@ -397,10 +401,10 @@
 
 %-----------------------------------------------------------------------------%
 
-instmap_from_assoc_list(AL, reachable(Instmapping)) :-
+instmap_from_assoc_list(AL) = reachable(Instmapping) :-
     map.from_assoc_list(AL, Instmapping).
 
-instmap_delta_from_assoc_list(AL, reachable(Instmapping)) :-
+instmap_delta_from_assoc_list(AL) = reachable(Instmapping) :-
     map.from_assoc_list(AL, Instmapping).
 
 instmap_delta_map_foldl(_, unreachable, unreachable, !T).
@@ -433,6 +437,25 @@
         instmap_delta_from_mode_list_2(Vars, Modes, ModuleInfo, !InstMapDelta)
     ).
 
+instmap_delta_bind_no_var = InstMapDelta :-
+    InstMapDelta = instmap_delta_from_assoc_list([]).
+
+instmap_delta_bind_var(Var) = InstMapDelta :-
+    InstMapDelta = instmap_delta_from_assoc_list([Var - ground(shared, none)]).
+
+instmap_delta_bind_vars(Vars) = InstMapDelta :-
+    VarsAndGround = ground_vars(Vars),
+    InstMapDelta = instmap_delta_from_assoc_list(VarsAndGround).
+
+:- func ground_vars(list(prog_var)) = assoc_list(prog_var, mer_inst).
+
+ground_vars(Vars) = VarsAndGround :-
+    VarsAndGround = list.map(pair_with_ground, Vars).
+
+:- func pair_with_ground(prog_var) = pair(prog_var, mer_inst).
+
+pair_with_ground(Var) = Var - ground(shared, none).
+
 %-----------------------------------------------------------------------------%
 
 instmap_vars(Instmap, Vars) :-
@@ -745,7 +768,7 @@
 pre_lambda_update(ModuleInfo, Vars, Modes, InstMap0, InstMap) :-
     mode_list_get_initial_insts(ModuleInfo, Modes, Insts),
     assoc_list.from_corresponding_lists(Vars, Insts, VarInsts),
-    instmap_delta_from_assoc_list(VarInsts, InstMapDelta),
+    InstMapDelta = instmap_delta_from_assoc_list(VarInsts),
     apply_instmap_delta(InstMap0, InstMapDelta, InstMap).
 
 %-----------------------------------------------------------------------------%
Index: compiler/intermod.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/intermod.m,v
retrieving revision 1.247
diff -u -b -r1.247 intermod.m
--- compiler/intermod.m	19 Aug 2009 07:44:54 -0000	1.247
+++ compiler/intermod.m	31 Aug 2009 18:43:16 -0000
@@ -1971,6 +1971,7 @@
 should_output_marker(marker_calls_are_fully_qualified, no).
 should_output_marker(marker_mode_check_clauses, yes).
 should_output_marker(marker_mutable_access_pred, no).
+should_output_marker(marker_has_format_call, no).
 
 :- pred get_pragma_foreign_code_vars(list(foreign_arg)::in, list(mer_mode)::in,
     prog_varset::in, prog_varset::out, list(pragma_var)::out) is det.
Index: compiler/lco.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/lco.m,v
retrieving revision 1.57
diff -u -b -r1.57 lco.m
--- compiler/lco.m	11 Jun 2009 07:00:11 -0000	1.57
+++ compiler/lco.m	31 Aug 2009 23:45:11 -0000
@@ -1032,7 +1032,7 @@
 make_store_goal(ModuleInfo, Var - AddrVar, Goal) :-
     generate_simple_call(mercury_private_builtin_module, "store_at_ref_impure",
         pf_predicate, only_mode, detism_det, purity_impure, [AddrVar, Var],
-        [], [], ModuleInfo, term.context_init, Goal).
+        [], instmap_delta_bind_vars([]), ModuleInfo, term.context_init, Goal).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/liveness.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/liveness.m,v
retrieving revision 1.167
diff -u -b -r1.167 liveness.m
--- compiler/liveness.m	2 Sep 2009 00:30:16 -0000	1.167
+++ compiler/liveness.m	2 Sep 2009 00:33:43 -0000
@@ -1793,16 +1793,6 @@
     goal_info_set_pre_deaths(PreDeaths, GoalInfo0, GoalInfo),
     Goal = hlds_goal(GoalExpr, GoalInfo).
 
-:- pred add_deadness_after_goal(set(prog_var)::in,
-    hlds_goal::in, hlds_goal::out) is det.
-
-add_deadness_after_goal(Residue, Goal0, Goal) :-
-    Goal0 = hlds_goal(GoalExpr, GoalInfo0),
-    goal_info_get_post_deaths(GoalInfo0, PostDeaths0),
-    set.union(PostDeaths0, Residue, PostDeaths),
-    goal_info_set_post_deaths(PostDeaths, GoalInfo0, GoalInfo),
-    Goal = hlds_goal(GoalExpr, GoalInfo).
-
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
Index: compiler/ml_code_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/ml_code_util.m,v
retrieving revision 1.140
diff -u -b -r1.140 ml_code_util.m
--- compiler/ml_code_util.m	2 Sep 2009 00:30:18 -0000	1.140
+++ compiler/ml_code_util.m	2 Sep 2009 00:33:43 -0000
@@ -2090,8 +2090,7 @@
         (func(hlds_goal(_GX, GI)) = goal_info_get_nonlocals(GI)),
         HLDS_TypeInfoGoals),
     NonLocals = set.union_list(NonLocalsList),
-    instmap_delta_from_assoc_list([TypeInfoVar - ground(shared, none)],
-        InstMapDelta),
+    InstMapDelta = instmap_delta_bind_var(TypeInfoVar),
     goal_info_init(NonLocals, InstMapDelta, detism_det, purity_impure,
         GoalInfo),
     conj_list_to_goal(HLDS_TypeInfoGoals, GoalInfo, Conj),
Index: compiler/modecheck_unify.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/modecheck_unify.m,v
retrieving revision 1.129
diff -u -b -r1.129 modecheck_unify.m
--- compiler/modecheck_unify.m	21 Jul 2009 02:08:49 -0000	1.129
+++ compiler/modecheck_unify.m	31 Aug 2009 23:28:14 -0000
@@ -353,7 +353,7 @@
     % Initialize the initial insts of the lambda variables.
     mode_list_get_initial_insts(ModuleInfo0, Modes, VarInitialInsts),
     assoc_list.from_corresponding_lists(Vars, VarInitialInsts, VarInstAL),
-    instmap_delta_from_assoc_list(VarInstAL, VarInstMapDelta),
+    VarInstMapDelta = instmap_delta_from_assoc_list(VarInstAL),
     mode_info_get_instmap(!.ModeInfo, InstMap0),
     instmap.apply_instmap_delta(InstMap0, VarInstMapDelta, InstMap1),
     mode_info_set_instmap(InstMap1, !ModeInfo),
Index: compiler/modes.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/modes.m,v
retrieving revision 1.382
diff -u -b -r1.382 modes.m
--- compiler/modes.m	2 Sep 2009 00:30:21 -0000	1.382
+++ compiler/modes.m	2 Sep 2009 00:35:51 -0000
@@ -865,7 +865,7 @@
         % Construct the initial instmap.
         mode_list_get_initial_insts(!.ModuleInfo, ArgModes0, ArgInitialInsts),
         assoc_list.from_corresponding_lists(HeadVars, ArgInitialInsts, InstAL),
-        instmap_from_assoc_list(InstAL, InstMap0),
+        InstMap0 = instmap_from_assoc_list(InstAL),
 
         % Construct the initial set of live vars:
         % initially, only the non-clobbered head variables are live.
@@ -971,7 +971,7 @@
             % Manufacture an instmap_delta for the disjunction as a whole.
             assoc_list.from_corresponding_lists(HeadVars, ArgFinalInsts0,
                 HeadVarFinalInsts),
-            instmap_from_assoc_list(HeadVarFinalInsts, FinalInstMap),
+            FinalInstMap = instmap_from_assoc_list(HeadVarFinalInsts),
             compute_instmap_delta(InstMap0, FinalInstMap, BodyNonLocals,
                 DeltaInstMap),
             goal_info_set_instmap_delta(DeltaInstMap,
@@ -1946,7 +1946,7 @@
         LocalVarMap0, LocalVarMap),
     map.lookup(LocalVarMap, TermVar, TermVarInfo),
     TermVarInfo = construct_var_info(TermVarInst),
-    instmap_delta_from_assoc_list([TermVar - TermVarInst], InstMapDelta),
+    InstMapDelta = instmap_delta_from_assoc_list([TermVar - TermVarInst]),
     goal_info_set_instmap_delta(InstMapDelta, !SubGoalInfo),
     % We present the determinism, so that the determinism analysis pass
     % does not have to traverse the goals inside the scope.
@@ -1994,7 +1994,7 @@
         Unification = construct(LHSVar, ConsId, RHSVars, UniModes,
             ConstructHow, Uniqueness, no_construct_sub_info),
         GoalExpr = unify(LHSVar, RHS, UnifyMode, Unification, UnifyContext),
-        instmap_delta_from_assoc_list([LHSVar - TermInst], InstMapDelta),
+        InstMapDelta = instmap_delta_from_assoc_list([LHSVar - TermInst]),
         goal_info_set_instmap_delta(InstMapDelta, GoalInfo0, GoalInfo1),
         % We preset the determinism, so that the determinism analysis pass
         % does not have to traverse the goals inside the scope.
@@ -4043,7 +4043,7 @@
         ),
         NonLocals = set.make_singleton_set(Var),
         InstmapDeltaAL = [Var - Inst],
-        instmap_delta_from_assoc_list(InstmapDeltaAL, InstmapDelta),
+        InstmapDelta = instmap_delta_from_assoc_list(InstmapDeltaAL),
         build_call(ModuleName, PredName, [Var], [VarType], NonLocals,
             InstmapDelta, Context, MaybeCallUnifyContext,
             hlds_goal(GoalExpr, GoalInfo), !ModeInfo)
Index: compiler/options.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.652
diff -u -b -r1.652 options.m
--- compiler/options.m	19 Aug 2009 07:44:56 -0000	1.652
+++ compiler/options.m	1 Sep 2009 16:21:38 -0000
@@ -613,6 +613,7 @@
     ;       optimize_duplicate_calls
     ;       constant_propagation
     ;       excess_assign
+    ;       optimize_format_calls
     ;       optimize_saved_vars_const
     ;       optimize_saved_vars_cell
     ;       optimize_saved_vars_cell_loop
@@ -1457,6 +1458,7 @@
     optimize_duplicate_calls            -   bool(no),
     constant_propagation                -   bool(no),
     excess_assign                       -   bool(no),
+    optimize_format_calls               -   bool(yes),
     loop_invariants                     -   bool(no),
     optimize_saved_vars_const           -   bool(no),
     optimize_saved_vars_cell            -   bool(no),
@@ -2244,6 +2246,7 @@
 long_option("common-struct-preds",  common_struct_preds).
 long_option("common-goal",          common_goal).
 long_option("excess-assign",        excess_assign).
+long_option("optimize-format-calls",         optimize_format_calls).
 long_option("optimize-duplicate-calls", optimize_duplicate_calls).
 long_option("optimise-duplicate-calls", optimize_duplicate_calls).
 long_option("optimise-constant-propagation", constant_propagation).
@@ -4692,6 +4695,10 @@
         "\tDon't migrate into the end of branched goals.",
         "--excess-assign",
         "\tRemove excess assignment unifications.",
+        "--no-optimize-format-calls",
+        "\tDo not attempt to interpret the format string in calls to",
+        "\tstring.format and related predicates at compile time;",
+        "\talways leave this to be done at runtime.",
         "--optimize-duplicate-calls",
         "\tOptimize away multiple calls to a predicate",
         "\twith the same input arguments.",
Index: compiler/pd_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/pd_util.m,v
retrieving revision 1.72
diff -u -b -r1.72 pd_util.m
--- compiler/pd_util.m	21 Jul 2009 02:08:50 -0000	1.72
+++ compiler/pd_util.m	31 Aug 2009 19:45:20 -0000
@@ -245,7 +245,7 @@
     pd_info_get_pred_proc_id(!.PDInfo, proc(PredId, ProcId)),
     proc_info_get_vartypes(ProcInfo0, VarTypes0),
     det_info_init(ModuleInfo0, VarTypes0, PredId, ProcId, 
-        pess_extra_vars_ignore, DetInfo0),
+        pess_extra_vars_ignore, [], DetInfo0),
     pd_info_get_instmap(!.PDInfo, InstMap0),
     pd_info_get_proc_info(!.PDInfo, ProcInfo0),
     simplify_info_init(DetInfo0, Simplifications, InstMap0, ProcInfo0,
@@ -376,12 +376,13 @@
 
     proc_info_get_vartypes(ProcInfo, VarTypes),
     det_info_init(ModuleInfo1, VarTypes, PredId, ProcId,
-        pess_extra_vars_ignore, DetInfo0),
+        pess_extra_vars_ignore, [], DetInfo0),
     pd_info_get_instmap(!.PDInfo, InstMap),
     det_infer_goal(Goal0, Goal, InstMap, SolnContext, [], no, _, _,
-        DetInfo0, DetInfo, [], Specs),
+        DetInfo0, DetInfo),
     det_info_get_module_info(DetInfo, ModuleInfo2),
     pd_info_set_module_info(ModuleInfo2, !PDInfo),
+    det_info_get_error_specs(DetInfo, Specs),
 
     % Make sure there were no errors.
     globals.io_get_globals(Globals, !IO),
Index: compiler/polymorphism.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/polymorphism.m,v
retrieving revision 1.342
diff -u -b -r1.342 polymorphism.m
--- compiler/polymorphism.m	19 Aug 2009 07:44:56 -0000	1.342
+++ compiler/polymorphism.m	1 Sep 2009 01:28:20 -0000
@@ -2427,8 +2427,9 @@
     % to superclass_from_typeclass_info in private_builtin.
     goal_util.generate_simple_call(mercury_private_builtin_module,
         "superclass_from_typeclass_info", pf_predicate, only_mode,
-        detism_det, purity_pure, [SubClassVar, IndexVar, Var], [], [],
-        ModuleInfo, term.context_init, SuperClassGoal),
+        detism_det, purity_pure, [SubClassVar, IndexVar, Var], [],
+        instmap_delta_bind_no_var, ModuleInfo, term.context_init,
+        SuperClassGoal),
     !:ExtraGoals = [SuperClassGoal, IndexGoal | !.ExtraGoals].
 
 :- pred construct_typeclass_info(list(prog_var)::in, list(prog_var)::in,
@@ -2477,8 +2478,7 @@
 
     % Create a goal_info for the unification.
     set.list_to_set([BaseVar], NonLocals),
-    instmap_delta_from_assoc_list([BaseVar - ground(shared, none)],
-        InstmapDelta),
+    InstmapDelta = instmap_delta_bind_var(BaseVar),
     goal_info_init(NonLocals, InstmapDelta, detism_det, purity_pure,
         BaseGoalInfo),
 
@@ -2513,9 +2513,8 @@
     % Note that we could perhaps be more accurate than `ground(shared)',
     % but it shouldn't make any difference.
     InstConsId = cell_inst_cons_id(typeclass_info_cell, NumArgVars),
-    instmap_delta_from_assoc_list(
-        [NewVar - bound(unique, [bound_functor(InstConsId, ArgInsts)])],
-        InstMapDelta),
+    InstMapDelta = instmap_delta_from_assoc_list(
+        [NewVar - bound(unique, [bound_functor(InstConsId, ArgInsts)])]),
     goal_info_set_instmap_delta(InstMapDelta, GoalInfo1, GoalInfo2),
     goal_info_set_determinism(detism_det, GoalInfo2, GoalInfo),
 
@@ -2930,9 +2929,8 @@
     % note that we could perhaps be more accurate than `ground(shared)',
     % but it shouldn't make any difference.
     InstConsId = cell_inst_cons_id(Cell, NumArgVars),
-    instmap_delta_from_assoc_list(
-        [TypeInfoVar - bound(unique, [bound_functor(InstConsId, ArgInsts)])],
-        InstMapDelta),
+    InstMapDelta = instmap_delta_from_assoc_list(
+        [TypeInfoVar - bound(unique, [bound_functor(InstConsId, ArgInsts)])]),
     goal_info_init(NonLocals, InstMapDelta, detism_det, purity_pure, GoalInfo),
     TypeInfoGoal = hlds_goal(Unify, GoalInfo).
 
@@ -2960,8 +2958,7 @@
 
     % Create a goal_info for the unification.
     set.list_to_set([TypeCtorInfoVar], NonLocals),
-    instmap_delta_from_assoc_list([TypeCtorInfoVar - ground(shared, none)],
-        InstmapDelta),
+    InstmapDelta = instmap_delta_bind_var(TypeCtorInfoVar),
     goal_info_init(NonLocals, InstmapDelta, detism_det, purity_pure, GoalInfo),
     TypeCtorInfoGoal = hlds_goal(Unify, GoalInfo).
 
@@ -3074,8 +3071,8 @@
     goal_util.generate_simple_call(mercury_private_builtin_module,
         "type_info_from_typeclass_info", pf_predicate, only_mode,
         detism_det, purity_pure, [TypeClassInfoVar, IndexVar, TypeInfoVar], [],
-        [TypeInfoVar - ground(shared, none)], ModuleInfo,
-        term.context_init, CallGoal),
+        instmap_delta_bind_var(TypeInfoVar), ModuleInfo, term.context_init,
+        CallGoal),
     Goals = [IndexGoal, CallGoal].
 
 %-----------------------------------------------------------------------------%
Index: compiler/prog_type.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/prog_type.m,v
retrieving revision 1.49
diff -u -b -r1.49 prog_type.m
--- compiler/prog_type.m	11 Jun 2009 07:00:17 -0000	1.49
+++ compiler/prog_type.m	1 Sep 2009 07:02:57 -0000
@@ -764,7 +764,7 @@
     TypeCtor = type_ctor(CtorSymName, TypeArity),
     (
         CtorSymName = qualified(ModuleName, TypeName),
-        ModuleName = mercury_std_lib_module_name(unqualified("io")),
+        ModuleName = mercury_io_module,
         TypeName = "state",
         TypeArity = 0
     ->
@@ -782,7 +782,7 @@
 
 type_is_io_state(Type) :-
     type_to_ctor_and_args(Type, TypeCtor, []),
-    ModuleName = mercury_std_lib_module_name(unqualified("io")),
+    ModuleName = mercury_io_module,
     TypeCtor = type_ctor(qualified(ModuleName, "state"), 0).
 
 type_ctor_is_array(type_ctor(qualified(unqualified("array"), "array"), 1)).
Index: compiler/purity.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/purity.m,v
retrieving revision 1.132
diff -u -b -r1.132 purity.m
--- compiler/purity.m	2 Sep 2009 00:30:22 -0000	1.132
+++ compiler/purity.m	2 Sep 2009 00:33:44 -0000
@@ -176,6 +176,7 @@
 :- import_module hlds.hlds_error_util.
 :- import_module hlds.hlds_goal.
 :- import_module hlds.hlds_rtti.
+:- import_module hlds.instmap.
 :- import_module hlds.passes_aux.
 :- import_module hlds.pred_table.
 :- import_module hlds.quantification.
@@ -877,14 +878,14 @@
     generate_simple_call(mercury_stm_builtin_module,
         OuterToInnerPred, pf_predicate, only_mode,
         detism_det, purity_pure, [OuterDI, InnerDI], [],
-        [OuterDI - ground(clobbered, none),
-            InnerDI - ground(unique, none)],
+        instmap_delta_from_assoc_list([OuterDI - ground(clobbered, none),
+            InnerDI - ground(unique, none)]),
         ModuleInfo, Context, OuterToInnerGoal),
     generate_simple_call(mercury_stm_builtin_module,
         InnerToOuterPred, pf_predicate, only_mode,
         detism_det, purity_pure, [InnerUO, OuterUO], [],
-        [InnerUO - ground(clobbered, none),
-            OuterUO - ground(unique, none)],
+        instmap_delta_from_assoc_list([InnerUO - ground(clobbered, none),
+            OuterUO - ground(unique, none)]),
         ModuleInfo, Context, InnerToOuterGoal),
 
     WrapExpr = conj(plain_conj, [OuterToInnerGoal, Goal0, InnerToOuterGoal]),
Index: compiler/rbmm.region_transformation.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/rbmm.region_transformation.m,v
retrieving revision 1.10
diff -u -b -r1.10 rbmm.region_transformation.m
--- compiler/rbmm.region_transformation.m	11 Jun 2009 07:00:18 -0000	1.10
+++ compiler/rbmm.region_transformation.m	1 Sep 2009 01:28:25 -0000
@@ -882,14 +882,16 @@
             IteRenaming, RegionVar, !NameToVar, !VarSet, !VarTypes),
         generate_simple_call(mercury_region_builtin_module,
             create_region_pred_name, pf_predicate, only_mode, detism_det,
-            purity_impure, [RegionVar], [], [], ModuleInfo, Context, CallGoal)
+            purity_impure, [RegionVar], [], instmap_delta_bind_no_var,
+            ModuleInfo, Context, CallGoal)
     ;
         RegionInstruction = remove_region(RegionName),
         region_name_to_var_with_both_renamings(RegionName, ResurRenaming,
             IteRenaming, RegionVar, !NameToVar, !VarSet, !VarTypes),
         generate_simple_call(mercury_region_builtin_module,
             remove_region_pred_name, pf_predicate, only_mode, detism_det,
-            purity_impure, [RegionVar], [], [], ModuleInfo, Context, CallGoal)
+            purity_impure, [RegionVar], [], instmap_delta_bind_no_var,
+            ModuleInfo, Context, CallGoal)
     ;
         RegionInstruction = rename_region(_, _),
         unexpected(this_file, "region_instruction_to_conj: " ++
@@ -915,7 +917,8 @@
             IteRenaming, RegionVar, !NameToVar, !VarSet, !VarTypes),
         generate_simple_call(mercury_region_builtin_module,
             create_region_pred_name, pf_predicate, only_mode, detism_det,
-            purity_impure, [RegionVar], [], [], ModuleInfo, Context, CallGoal)
+            purity_impure, [RegionVar], [], instmap_delta_bind_no_var,
+            ModuleInfo, Context, CallGoal)
     ;
         RegionInstruction = remove_region(RegionName),
         region_name_to_var_with_both_renamings_before(RegionName,
@@ -923,7 +926,8 @@
             !VarTypes),
         generate_simple_call(mercury_region_builtin_module,
             remove_region_pred_name, pf_predicate, only_mode, detism_det,
-            purity_impure, [RegionVar], [], [], ModuleInfo, Context, CallGoal)
+            purity_impure, [RegionVar], [], instmap_delta_bind_no_var,
+            ModuleInfo, Context, CallGoal)
     ;
         RegionInstruction = rename_region(_, _),
         unexpected(this_file, "region_instruction_to_conj: " ++
@@ -1008,7 +1012,7 @@
     % It should be able to be recomputed from the modes in the assigment.
     % Maybe I am missing or doing something wrong here.
     NonLocals = set.init,
-    instmap_delta_from_assoc_list([LeftRegVar - ground_inst], InstmapDelta),
+    InstmapDelta = instmap_delta_bind_var(LeftRegVar),
     goal_info_init(NonLocals, InstmapDelta, detism_det, purity_pure,
         AssignmentInfo),
     AssignmentGoal = hlds_goal(AssignmentExpr, AssignmentInfo).
Index: compiler/simplify.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/simplify.m,v
retrieving revision 1.243
diff -u -b -r1.243 simplify.m
--- compiler/simplify.m	21 Jul 2009 04:10:42 -0000	1.243
+++ compiler/simplify.m	1 Sep 2009 21:02:42 -0000
@@ -81,8 +81,7 @@
 :- type simplification
     --->    simp_warn_simple_code       % --warn-simple-code
     ;       simp_warn_duplicate_calls   % --warn-duplicate-calls
-    ;       simp_warn_known_bad_format  % --warn-known-bad-format-calls
-    ;       simp_warn_unknown_format    % --warn-unknown-format-calls
+    ;       simp_format_calls           % invoke format_call.m
     ;       simp_warn_obsolete          % --warn-obsolete
     ;       simp_do_once                % run things that should be done once
     ;       simp_after_front_end        % run things that should be done
@@ -108,8 +107,7 @@
 
 :- pred simplify_do_warn_simple_code(simplify_info::in) is semidet.
 :- pred simplify_do_warn_duplicate_calls(simplify_info::in) is semidet.
-:- pred simplify_do_warn_known_bad_format(simplify_info::in) is semidet.
-:- pred simplify_do_warn_unknown_format(simplify_info::in) is semidet.
+:- pred simplify_do_format_calls(simplify_info::in) is semidet.
 :- pred simplify_do_warn_obsolete(simplify_info::in) is semidet.
 :- pred simplify_do_once(simplify_info::in) is semidet.
 :- pred simplify_do_after_front_end(simplify_info::in) is semidet.
@@ -175,8 +173,7 @@
     --->    simplifications(
                 do_warn_simple_code         :: bool,
                 do_warn_duplicate_calls     :: bool,
-                do_warn_known_bad_format    :: bool,
-                do_warn_unknown_format      :: bool,
+                do_format_calls             :: bool,
                 do_warn_obsolete            :: bool,
                 do_do_once                  :: bool,
                 do_after_front_end          :: bool,
@@ -190,14 +187,13 @@
 
 simplifications_to_list(Simplifications) = List :-
     Simplifications = simplifications(WarnSimpleCode, WarnDupCalls,
-        WarnKnownBadFormat, WarnUnknownFormat, WarnObsolete, DoOnce,
+        DoFormatCalls, WarnObsolete, DoOnce,
         AfterFrontEnd, ExcessAssign, ElimRemovableScopes, OptDuplicateCalls,
         ConstantProp, CommonStruct, ExtraCommonStruct),
     List =
         ( WarnSimpleCode = yes -> [simp_warn_simple_code] ; [] ) ++
         ( WarnDupCalls = yes -> [simp_warn_duplicate_calls] ; [] ) ++
-        ( WarnKnownBadFormat = yes -> [simp_warn_known_bad_format] ; [] ) ++
-        ( WarnUnknownFormat = yes -> [simp_warn_unknown_format] ; [] ) ++
+        ( DoFormatCalls = yes -> [simp_format_calls] ; [] ) ++
         ( WarnObsolete = yes -> [simp_warn_obsolete] ; [] ) ++
         ( DoOnce = yes -> [simp_do_once] ; [] ) ++
         ( AfterFrontEnd = yes -> [simp_after_front_end] ; [] ) ++
@@ -212,8 +208,7 @@
     simplifications(
         ( list.member(simp_warn_simple_code, List) -> yes ; no ),
         ( list.member(simp_warn_duplicate_calls, List) -> yes ; no ),
-        ( list.member(simp_warn_known_bad_format, List) -> yes ; no ),
-        ( list.member(simp_warn_unknown_format, List) -> yes ; no ),
+        ( list.member(simp_format_calls, List) -> yes ; no ),
         ( list.member(simp_warn_obsolete, List) -> yes ; no ),
         ( list.member(simp_do_once, List) -> yes ; no ),
         ( list.member(simp_after_front_end, List) -> yes ; no ),
@@ -232,6 +227,20 @@
         WarnKnownBadFormat),
     globals.lookup_bool_option(Globals, warn_unknown_format_calls,
         WarnUnknownFormat),
+    globals.lookup_bool_option(Globals, optimize_format_calls,
+        OptFormatCalls),
+    (
+        (
+            WarnThisPass = yes,
+            ( WarnKnownBadFormat = yes ; WarnUnknownFormat = yes  )
+        ;
+            OptFormatCalls = yes
+        )
+    ->
+        DoFormatCalls = yes
+    ;
+        DoFormatCalls = no
+    ),
     globals.lookup_bool_option(Globals, warn_obsolete, WarnObsolete),
     globals.lookup_bool_option(Globals, excess_assign, ExcessAssign),
     globals.lookup_bool_option(Globals, common_struct, CommonStruct),
@@ -246,8 +255,7 @@
     Simplifications = simplifications(
         ( WarnSimple = yes, WarnThisPass = yes -> yes ; no),
         ( WarnDupCalls = yes, WarnThisPass = yes -> yes ; no),
-        ( WarnKnownBadFormat = yes, WarnThisPass = yes -> yes ; no),
-        ( WarnUnknownFormat = yes, WarnThisPass = yes -> yes ; no),
+        DoFormatCalls,
         ( WarnObsolete = yes, WarnThisPass = yes -> yes ; no),
         DoOnce,
         AfterFrontEnd,
@@ -265,12 +273,9 @@
 simplify_do_warn_duplicate_calls(Info) :-
     simplify_info_get_simplifications(Info, Simplifications),
     Simplifications ^ do_warn_duplicate_calls = yes.
-simplify_do_warn_known_bad_format(Info) :-
-    simplify_info_get_simplifications(Info, Simplifications),
-    Simplifications ^ do_warn_known_bad_format = yes.
-simplify_do_warn_unknown_format(Info) :-
+simplify_do_format_calls(Info) :-
     simplify_info_get_simplifications(Info, Simplifications),
-    Simplifications ^ do_warn_unknown_format = yes.
+    Simplifications ^ do_format_calls = yes.
 simplify_do_warn_obsolete(Info) :-
     simplify_info_get_simplifications(Info, Simplifications),
     Simplifications ^ do_warn_obsolete = yes.
@@ -383,7 +388,7 @@
 turn_off_common_struct_threshold = 1000.
 
 simplify_proc_return_msgs(Simplifications0, PredId, ProcId, !ModuleInfo,
-        !ProcInfo, !:ErrorSpecs) :-
+        !ProcInfo, !:Specs) :-
     proc_info_get_vartypes(!.ProcInfo, VarTypes0),
     NumVars = map.count(VarTypes0),
     ( NumVars > turn_off_common_struct_threshold ->
@@ -415,16 +420,13 @@
             Simplifications = Simplifications1
         )
     ),
-    det_info_init(!.ModuleInfo, VarTypes0, PredId, ProcId,
-        pess_extra_vars_report, DetInfo0),
-    proc_info_get_initial_instmap(!.ProcInfo, !.ModuleInfo, InstMap0),
-    simplify_info_init(DetInfo0, Simplifications, InstMap0, !.ProcInfo, Info0),
-    proc_info_get_goal(!.ProcInfo, Goal0),
 
-    simplify_info_get_pred_info(Info0, PredInfo),
-    pred_info_get_markers(PredInfo, Markers),
+    module_info_pred_info(!.ModuleInfo, PredId, PredInfo0),
+    pred_info_get_markers(PredInfo0, Markers0),
+    pred_info_get_import_status(PredInfo0, Status),
+    proc_info_get_goal(!.ProcInfo, Goal0),
     (
-        check_marker(Markers, marker_mode_check_clauses),
+        check_marker(Markers0, marker_mode_check_clauses),
         Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
         ( GoalExpr0 = disj(_)
         ; GoalExpr0 = switch(_, _, _)
@@ -437,15 +439,98 @@
         Goal1 = Goal0
     ),
 
-    simplify_process_clause_body_goal(Goal1, Goal, Info0, Info),
+    (
+        check_marker(Markers0, marker_has_format_call),
+        Simplifications ^ do_format_calls = yes
+    ->
+        % We must invoke analyze_and_optimize_format_calls before
+        % simplify_process_clause_body_goal, for two reasons.
+        %
+        % First, excess assignment optimization may delete some of the
+        % unifications that build the format strings or values,
+        % which means that the goal it generates may not contain the
+        % information that analyze_and_optimize_format_calls needs to avoid
+        % spurious messages about unknown format strings or values.
+        %
+        % Second, analyze_and_optimize_format_calls generates nested
+        % conjunctions, which simplify_process_clause_body_goal can eliminate.
+        proc_info_get_varset(!.ProcInfo, VarSet0),
+        analyze_and_optimize_format_calls(!.ModuleInfo, Goal1, MaybeGoal2,
+            FormatSpecs, VarSet0, VarSet1, VarTypes0, VarTypes1),
+        (
+            MaybeGoal2 = yes(Goal2),
+            proc_info_set_goal(Goal2, !ProcInfo),
+            proc_info_set_varset(VarSet1, !ProcInfo),
+            proc_info_set_vartypes(VarTypes1, !ProcInfo),
+
+            % The goals we replace format calls with are created with the
+            % correct nonlocals, but analyze_and_optimize_format_calls can
+            % take code for building a list of string.poly_types out of one
+            % scope (e.g. the condition of an if-then-else) and replace it
+            % with code to build the string directly in another scope
+            % (such as the then part of that if-then-else, if that is where
+            % the format call is). This can leave variables missing from
+            % the nonlocal fields of the original scopes. And since
+            % instmap_deltas are restricted to the goal's nonlocals,
+            % they need to be recomputed as well.
+            requantify_proc(!ProcInfo),
+            recompute_instmap_delta_proc(
+                do_not_recompute_atomic_instmap_deltas,
+                !ProcInfo, !ModuleInfo),
+            proc_info_get_goal(!.ProcInfo, Goal3),
+            proc_info_get_vartypes(!.ProcInfo, VarTypes3),
+
+            % Put the new proc_info back into !ModuleInfo, since some of the
+            % following code could otherwise find obsolete information in
+            % there.
+
+            % Remove the has_format_call marker from the pred_info before
+            % putting it back, since any optimizable format calls will already
+            % have been optimized. Since currently there is no program
+            % transformation that inserts calls to these predicates,
+            % there is no point in invoking find_format_call again later.
+
+            module_info_preds(!.ModuleInfo, PredTable1),
+            map.lookup(PredTable1, PredId, PredInfo1),
+            pred_info_get_procedures(PredInfo1, ProcTable1),
+            map.det_update(ProcTable1, ProcId, !.ProcInfo, ProcTable),
+
+            pred_info_set_procedures(ProcTable, PredInfo1, PredInfo2),
+            remove_marker(marker_has_format_call, Markers0, Markers),
+            pred_info_set_markers(Markers, PredInfo2, PredInfo),
+
+            map.det_update(PredTable1, PredId, PredInfo, PredTable),
+            module_info_set_preds(PredTable, !ModuleInfo)
+        ;
+            MaybeGoal2 = no,
+            Markers = Markers0,
+            Goal3 = Goal1,
+            % Throw away VarTypes1.
+            VarTypes3 = VarTypes0
+        )
+    ;
+        % Either there are no format calls to check, or we don't want to
+        % optimize them and would ignore the added messages anyway.
+        Goal3 = Goal1,
+        Markers = Markers0,
+        FormatSpecs = [],
+        VarTypes3 = VarTypes0
+    ),
 
-    simplify_info_get_varset(Info, VarSet1),
+    det_info_init(!.ModuleInfo, VarTypes3, PredId, ProcId,
+        pess_extra_vars_report, [], DetInfo0),
+    proc_info_get_initial_instmap(!.ProcInfo, !.ModuleInfo, InstMap0),
+    simplify_info_init(DetInfo0, Simplifications, InstMap0, !.ProcInfo, Info0),
+
+    simplify_process_clause_body_goal(Goal3, Goal, Info0, Info),
+
+    simplify_info_get_varset(Info, VarSet3),
     ( simplify_do_after_front_end(Info) ->
         proc_info_get_var_name_remap(!.ProcInfo, VarNameRemap),
-        map.foldl(svvarset.name_var, VarNameRemap, VarSet1, VarSet),
+        map.foldl(svvarset.name_var, VarNameRemap, VarSet3, VarSet),
         proc_info_set_var_name_remap(map.init, !ProcInfo)
     ;
-        VarSet = VarSet1
+        VarSet = VarSet3
     ),
     simplify_info_get_var_types(Info, VarTypes),
     simplify_info_get_rtti_varmaps(Info, RttiVarMaps),
@@ -461,24 +546,8 @@
     proc_info_set_has_user_event(HasUserEvent, !ProcInfo),
 
     simplify_info_get_module_info(Info, !:ModuleInfo),
-    simplify_info_get_error_specs(Info, !:ErrorSpecs),
-    (
-        Info ^ simp_format_calls = yes,
-        ( Simplifications ^ do_warn_known_bad_format = yes
-        ; Simplifications ^ do_warn_unknown_format = yes
-        )
-    ->
-        % We must use the original goal, Goal0, here. This is because excess
-        % assignment optimization may delete some of the unifications that
-        % build the format strings or values, which means that the new version
-        % in Goal may not contain the information find_format_call_errors needs
-        % to avoid spurious messages about unknown format strings or values.
-        find_format_call_errors(!.ModuleInfo, Goal0, !ErrorSpecs)
-    ;
-        % Either there are no calls to check or we would ignore the added
-        % messages anyway.
-        true
-    ),
+    simplify_info_get_error_specs(Info, !:Specs),
+    !:Specs = FormatSpecs ++ !.Specs,
 
     Goal = hlds_goal(GoalExpr, GoalInfo),
     (
@@ -498,7 +567,7 @@
                 Severity = severity_error,
                 Spec = error_spec(Severity, phase_simplify(report_in_any_mode),
                     [Msg]),
-                !:ErrorSpecs = [Spec | !.ErrorSpecs]
+                !:Specs = [Spec | !.Specs]
             ;
                 true
             )
@@ -514,7 +583,7 @@
                 Severity = severity_error,
                 Spec = error_spec(Severity, phase_simplify(report_in_any_mode),
                     [Msg]),
-                !:ErrorSpecs = [Spec | !.ErrorSpecs]
+                !:Specs = [Spec | !.Specs]
             ;
                 true
             )
@@ -523,14 +592,13 @@
         true
     ),
 
-    pred_info_get_import_status(PredInfo, Status),
     IsDefinedHere = status_defined_in_this_module(Status),
     (
         IsDefinedHere = no,
         % Don't generate any warnings or even errors if the predicate isn't
         % defined here; any such messages will be generated when we compile
         % the module the predicate comes from.
-        !:ErrorSpecs = []
+        !:Specs = []
     ;
         IsDefinedHere = yes
     ).
@@ -635,7 +703,7 @@
 
             simplify_info_get_det_info(!.Info, !:DetInfo),
             det_infer_goal(!Goal, InstMap0, SolnContext, [], no,
-                _, _, !DetInfo, [], _),
+                _, _, !DetInfo),
             simplify_info_set_det_info(!.DetInfo, !Info)
         )
     ;
@@ -1231,11 +1299,6 @@
     module_info_pred_info(ModuleInfo, PredId, PredInfo),
     ModuleName = hlds_pred.pred_info_module(PredInfo),
     Name = hlds_pred.pred_info_name(PredInfo),
-    ( is_format_call(ModuleName, Name, Args, _, _) ->
-        simplify_info_set_format_calls(yes, !Info)
-    ;
-        true
-    ),
 
     % Convert calls to builtin @=<, @<, @>=, @> into the corresponding
     % calls to builtin.compare/3.
@@ -1978,13 +2041,12 @@
         % The code field of the call_foreign_proc goal is ignored when
         % its foreign_trace_cond field is set to `yes', as we do here.
         EvalCode = "",
-        EvalInstMapDeltaSrc = [],
         Goal0 = hlds_goal(_GoalExpr0, GoalInfo0),
         Context = goal_info_get_context(GoalInfo0),
         generate_foreign_proc(PrivateBuiltin, EvalPredName,
             pf_predicate, only_mode, detism_semi, purity_semipure,
             EvalAttributes, [], [], yes(RuntimeExpr), EvalCode,
-            EvalFeatures, EvalInstMapDeltaSrc, ModuleInfo,
+            EvalFeatures, instmap_delta_bind_no_var, ModuleInfo,
             Context, CondGoal),
         GoalExpr = if_then_else([], CondGoal, SubGoal, true_goal),
         Goal = hlds_goal(GoalExpr, GoalInfo0)
@@ -2161,8 +2223,9 @@
     ArgInsts = [R - Unique],
     BuiltinModule = mercury_public_builtin_module,
     goal_util.generate_simple_call(BuiltinModule, "compare", pf_predicate,
-        mode_no(ModeNo), detism_det, purity_pure, Args, [], ArgInsts,
-        ModuleInfo, Context, CmpGoal0),
+        mode_no(ModeNo), detism_det, purity_pure, Args, [],
+        instmap_delta_from_assoc_list(ArgInsts), ModuleInfo, Context,
+        CmpGoal0),
     CmpGoal0 = hlds_goal(CmpExpr, CmpInfo0),
     CmpNonLocals0 = goal_info_get_nonlocals(CmpInfo0),
     goal_info_set_nonlocals(set.insert(CmpNonLocals0, R), CmpInfo0, CmpInfo),
@@ -2424,10 +2487,12 @@
     Context = goal_info_get_context(!.GoalInfo),
     goal_util.generate_simple_call(mercury_private_builtin_module,
         "builtin_compound_eq", pf_predicate, only_mode, detism_semi,
-        purity_pure, [X, Y], [], [], ModuleInfo, Context, CondEq),
+        purity_pure, [X, Y], [], instmap_delta_bind_no_var, ModuleInfo,
+        Context, CondEq),
     goal_util.generate_simple_call(mercury_private_builtin_module,
         "builtin_compound_lt", pf_predicate, only_mode, detism_semi,
-        purity_pure, [X, Y], [], [], ModuleInfo, Context, CondLt),
+        purity_pure, [X, Y], [], instmap_delta_bind_no_var, ModuleInfo,
+        Context, CondLt),
 
     Builtin = mercury_public_builtin_module,
     TypeCtor = type_ctor(
@@ -2507,7 +2572,7 @@
     ConstGoalExpr = unify(ConstVar, ConstRHS, ConstMode, ConstUnification,
         ConstUnifyContext),
     ConstNonLocals = set.make_singleton_set(ConstVar),
-    instmap_delta_from_assoc_list([ConstVar - ground_inst], InstMapDelta),
+    InstMapDelta = instmap_delta_bind_var(ConstVar),
     goal_info_init(ConstNonLocals, InstMapDelta,
         detism_det, purity_pure, ConstGoalInfo),
     ConstGoal = hlds_goal(ConstGoalExpr, ConstGoalInfo),
@@ -2543,6 +2608,11 @@
 simplify_may_introduce_calls("int", "unchecked_quotient", _).
 simplify_may_introduce_calls("int", "unchecked_rem", _).
 simplify_may_introduce_calls("int", "*", _).
+simplify_may_introduce_calls("io", "write_string", _).
+simplify_may_introduce_calls("string", "int_to_string", _).
+simplify_may_introduce_calls("string", "char_to_string", _).
+simplify_may_introduce_calls("string", "float_to_string", _).
+simplify_may_introduce_calls("string", "++", _).
 
 %-----------------------------------------------------------------------------%
 
@@ -2572,8 +2642,8 @@
         GContext = goal_info_get_context(GoalInfo0),
         generate_simple_call(mercury_private_builtin_module,
             "builtin_unify_pred", pf_predicate, mode_no(0), detism_semi,
-            purity_pure, [XVar, YVar], [], [], ModuleInfo, GContext,
-            hlds_goal(Call0, _)),
+            purity_pure, [XVar, YVar], [], instmap_delta_bind_no_var,
+            ModuleInfo, GContext, hlds_goal(Call0, _)),
         simplify_goal_expr(Call0, Call1, GoalInfo0, GoalInfo, !Info),
         Call = hlds_goal(Call1, GoalInfo),
         ExtraGoals = []
@@ -2652,7 +2722,7 @@
     Context = goal_info_get_context(GoalInfo),
     goal_util.generate_simple_call(mercury_public_builtin_module,
         "unify", pf_predicate, mode_no(0), detism_semi, purity_pure, ArgVars,
-        [], [], ModuleInfo, Context, Call).
+        [], instmap_delta_bind_no_var, ModuleInfo, Context, Call).
 
 :- pred call_specific_unify(type_ctor::in, list(prog_var)::in,
     prog_var::in, prog_var::in, proc_id::in,
@@ -2685,7 +2755,8 @@
     Context = goal_info_get_context(GoalInfo),
     goal_util.generate_simple_call(mercury_private_builtin_module,
         "builtin_compound_eq", pf_predicate, only_mode, detism_semi,
-        purity_pure, [XVar, YVar], [], [], ModuleInfo, Context, Call).
+        purity_pure, [XVar, YVar], [], instmap_delta_bind_no_var, ModuleInfo,
+        Context, Call).
 
 %-----------------------------------------------------------------------------%
 
@@ -3059,8 +3130,10 @@
     CanElimLeft = ( set.member(LeftVar, ConjNonLocals) -> no ; yes ),
     CanElimRight = ( set.member(RightVar, ConjNonLocals) -> no ; yes ),
 
-    % If we have a choice, eliminate an unnamed variable.
-    ( CanElimLeft = yes, CanElimRight = yes ->
+    (
+        CanElimLeft = yes,
+        CanElimRight = yes,
+        % If we have a choice, try to eliminate an unnamed variable.
         ( var_is_named(VarSet, LeftVar) ->
             ElimVar = RightVar,
             ReplacementVar = LeftVar
@@ -3068,13 +3141,19 @@
             ElimVar = LeftVar,
             ReplacementVar = RightVar
         )
-    ; CanElimLeft = yes ->
+    ;
+        CanElimLeft = yes,
+        CanElimRight = no,
         ElimVar = LeftVar,
         ReplacementVar = RightVar
-    ; CanElimRight = yes ->
+    ;
+        CanElimLeft = no,
+        CanElimRight = yes,
         ElimVar = RightVar,
         ReplacementVar = LeftVar
     ;
+        CanElimLeft = no,
+        CanElimRight = no,
         fail
     ),
     map.det_insert(!.Subn, ElimVar, ReplacementVar, !:Subn),
@@ -3549,10 +3628,6 @@
                 % Information about type_infos and typeclass_infos.
                 simp_rtti_varmaps            :: rtti_varmaps,
 
-                % Do we have any calls to string.format, stream.format and
-                % io.format?
-                simp_format_calls            :: bool,
-
                 % Are we currently inside a goal that was duplicated
                 % for a switch?
                 simp_inside_dupl_for_switch  :: bool,
@@ -3574,7 +3649,7 @@
     proc_info_get_rtti_varmaps(ProcInfo, RttiVarMaps),
     Info = simplify_info(DetInfo, [], Simplifications,
         common_info_init, InstMap, VarSet, InstVarSet,
-        no, no, no, 0, 0, RttiVarMaps, no, no, no, no, no).
+        no, no, no, 0, 0, RttiVarMaps, no, no, no, no).
 
     % Reinitialise the simplify_info before reprocessing a goal.
     %
@@ -3619,7 +3694,6 @@
 
 :- pred simplify_info_get_module_info(simplify_info::in, module_info::out)
     is det.
-:- pred simplify_info_get_pred_info(simplify_info::in, pred_info::out) is det.
 :- pred simplify_info_get_pred_proc_info(simplify_info::in, pred_info::out,
     proc_info::out) is det.
 
@@ -3642,7 +3716,6 @@
 
 :- implementation.
 
-:- pred simplify_info_get_format_calls(simplify_info::in, bool::out) is det.
 :- pred simplify_info_get_inside_duplicated_for_switch(simplify_info::in,
     bool::out) is det.
 :- pred simplify_info_get_has_parallel_conj(simplify_info::in, bool::out)
@@ -3667,7 +3740,6 @@
     Info ^ simp_rerun_det = yes.
 simplify_info_get_cost_delta(Info, Info ^ simp_cost_delta).
 simplify_info_get_rtti_varmaps(Info, Info ^ simp_rtti_varmaps).
-simplify_info_get_format_calls(Info, Info ^ simp_format_calls).
 simplify_info_get_inside_duplicated_for_switch(Info,
     Info ^ simp_inside_dupl_for_switch).
 simplify_info_get_has_parallel_conj(Info, Info ^ simp_has_parallel_conj).
@@ -3678,12 +3750,6 @@
     simplify_info_get_det_info(Info, DetInfo),
     det_info_get_module_info(DetInfo, ModuleInfo).
 
-simplify_info_get_pred_info(Info, PredInfo) :-
-    simplify_info_get_det_info(Info, DetInfo),
-    det_info_get_module_info(DetInfo, ModuleInfo),
-    det_info_get_pred_id(DetInfo, PredId),
-    module_info_pred_info(ModuleInfo, PredId, PredInfo).
-
 simplify_info_get_pred_proc_info(Info, PredInfo, ProcInfo) :-
     simplify_info_get_det_info(Info, DetInfo),
     det_info_get_module_info(DetInfo, ModuleInfo),
@@ -3706,8 +3772,6 @@
     simplify_info::in, simplify_info::out) is det.
 :- pred simplify_info_set_recompute_atomic(
     simplify_info::in, simplify_info::out) is det.
-:- pred simplify_info_set_format_calls(bool::in,
-    simplify_info::in, simplify_info::out) is det.
 :- pred simplify_info_set_inside_duplicated_for_switch(bool::in,
     simplify_info::in, simplify_info::out) is det.
 :- pred simplify_info_set_has_parallel_conj(bool::in,
@@ -3757,8 +3821,6 @@
     !Info ^ simp_cost_delta := Delta.
 simplify_info_set_rtti_varmaps(Rtti, !Info) :-
     !Info ^ simp_rtti_varmaps := Rtti.
-simplify_info_set_format_calls(FC, !Info) :-
-    !Info ^ simp_format_calls := FC.
 simplify_info_set_inside_duplicated_for_switch(IDFS, !Info) :-
     !Info ^ simp_inside_dupl_for_switch := IDFS.
 simplify_info_set_has_parallel_conj(MHPC, !Info) :-
Index: compiler/size_prof.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/size_prof.m,v
retrieving revision 1.60
diff -u -b -r1.60 size_prof.m
--- compiler/size_prof.m	11 Jun 2009 07:00:19 -0000	1.60
+++ compiler/size_prof.m	1 Sep 2009 00:58:44 -0000
@@ -118,6 +118,7 @@
 :- import_module hlds.hlds_goal.
 :- import_module hlds.hlds_out.
 :- import_module hlds.hlds_rtti.
+:- import_module hlds.instmap.
 :- import_module hlds.pred_table.
 :- import_module hlds.quantification.
 :- import_module libs.compiler_util.
@@ -795,8 +796,8 @@
         TermSizeProfBuiltin = mercury_term_size_prof_builtin_module,
         goal_util.generate_simple_call(TermSizeProfBuiltin,
             "increment_size", pf_predicate, only_mode, detism_det,
-            purity_impure, [Var, SizeVar], [], [], !.Info ^ spi_module_info,
-            Context, UpdateGoal),
+            purity_impure, [Var, SizeVar], [], instmap_delta_bind_no_var,
+            !.Info ^ spi_module_info, Context, UpdateGoal),
         % Put UnifyGoal first in case it fails.
         Goals = [UnifyGoal] ++ ArgGoals ++ SizeGoals ++ [UpdateGoal],
         GoalExpr = conj(plain_conj, Goals)
@@ -863,7 +864,7 @@
         goal_util.generate_simple_call(TermSizeProfModule,
             "term_size_plus", pf_function, mode_no(0), detism_det, purity_pure,
             [SizeVar0, KnownSizeVar, SizeVar], [],
-            [SizeVar - ground(shared, none)],
+            instmap_delta_bind_var(SizeVar),
             !.Info ^ spi_module_info, Context, AddGoal),
         Goals = [KnownSizeGoal, AddGoal]
     ).
@@ -927,7 +928,7 @@
                 "type_info_from_typeclass_info", pf_predicate, only_mode,
                 detism_det, purity_pure,
                 [TypeClassInfoVar, SlotVar, TypeInfoVar], [],
-                [TypeInfoVar - ground(shared, none)],
+                instmap_delta_bind_var(TypeInfoVar),
                 !.Info ^ spi_module_info, Context, ExtractGoal),
             record_type_info_var(Type, TypeInfoVar, !Info),
             TypeInfoGoals = [SlotGoal, ExtractGoal]
@@ -1051,7 +1052,7 @@
     TermSizeProfBuiltin = mercury_term_size_prof_builtin_module,
     goal_util.generate_simple_call(TermSizeProfBuiltin, Pred, pf_predicate,
         only_mode, detism_det, purity_pure, Args,
-        [], [SizeVar - ground(shared, none)],
+        [], instmap_delta_bind_var(SizeVar),
         !.Info ^ spi_module_info, Context, SizeGoal),
     MaybeSizeVar = yes(SizeVar).
 
Index: compiler/ssdebug.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/ssdebug.m,v
retrieving revision 1.20
diff -u -b -r1.20 ssdebug.m
--- compiler/ssdebug.m	11 Jun 2009 07:00:19 -0000	1.20
+++ compiler/ssdebug.m	1 Sep 2009 00:59:00 -0000
@@ -860,11 +860,10 @@
         !Varset, !Vartypes) :-
     SSDBModule = mercury_ssdb_builtin_module,
     Features = [],
-    InstMapSrc = [],
     Context = term.context_init,
     goal_util.generate_simple_call(SSDBModule, HandleTypeString,
-        pf_predicate, only_mode, detism_det, purity_impure,
-        Arguments, Features, InstMapSrc, !.ModuleInfo, Context,
+        pf_predicate, only_mode, detism_det, purity_impure, Arguments,
+        Features, instmap_delta_bind_no_var, !.ModuleInfo, Context,
         HandleEventGoal).
 
     % make_proc_id_construction(PredInfo, Goals, Var, !Varset, !Vartypes)
@@ -908,11 +907,10 @@
 
 make_fail_call(FailGoal, ModuleInfo) :-
     Features = [],
-    InstMapSrc = [],
     Context = term.context_init,
     goal_util.generate_simple_call(mercury_public_builtin_module,
-        "false", pf_predicate, only_mode, detism_failure, purity_pure,
-        [], Features, InstMapSrc, ModuleInfo, Context, FailGoal).
+        "false", pf_predicate, only_mode, detism_failure, purity_pure, [],
+        Features, instmap_delta_bind_no_var, ModuleInfo, Context, FailGoal).
 
     % Detect if all argument's mode are fully input or output.
     % XXX Other mode than fully input or output are not handled for the
Index: compiler/stm_expand.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/stm_expand.m,v
retrieving revision 1.6
diff -u -b -r1.6 stm_expand.m
--- compiler/stm_expand.m	11 Jun 2009 07:00:19 -0000	1.6
+++ compiler/stm_expand.m	1 Sep 2009 01:24:02 -0000
@@ -732,9 +732,9 @@
 
         % If no or_else goals, simply connect up the outer and inner variables.
         create_var_unify_stm(MainInnerDI, MainOuterDI,
-            pair(uo_mode, di_mode), CopyDIVars, !StmInfo),
+            uo_mode - di_mode, CopyDIVars, !StmInfo),
         create_var_unify_stm(MainOuterUO, MainInnerUO,
-            pair(uo_mode, di_mode), CopyUOVars, !StmInfo),
+            uo_mode - di_mode, CopyUOVars, !StmInfo),
         create_plain_conj([CopyDIVars, AtomicGoal, CopyUOVars], HldsGoal)
     ;
         OrElseGoals = [_ | _],
@@ -777,9 +777,9 @@
         create_or_else_pred(AtomicGoalVars, AtomicGoalVarList1, PPIDList,
             MainInnerDI, MainInnerUO, OrElseCall, !StmInfo),
         create_var_unify_stm(MainInnerDI, MainOuterDI,
-            pair(uo_mode, di_mode), CopyDIVars, !StmInfo),
+            uo_mode - di_mode, CopyDIVars, !StmInfo),
         create_var_unify_stm(MainOuterUO, MainInnerUO,
-            pair(uo_mode, di_mode), CopyUOVars, !StmInfo),
+            uo_mode - di_mode, CopyUOVars, !StmInfo),
         create_plain_conj([CopyDIVars, OrElseCall, CopyUOVars], HldsGoal)
     ).
 
@@ -831,7 +831,7 @@
         InputModes ++ OutputModes ++ [di_mode, uo_mode], "toplevel",
         AtomicGoal, no, NewPredInfo0, HldsGoal, !StmInfo),
 
-    create_var_unify(OuterUO, OuterDI, pair(uo_mode, di_mode),
+    create_var_unify(OuterUO, OuterDI, uo_mode - di_mode,
         CopyIOAssign, NewPredInfo0, NewPredInfo1),
     create_plain_conj([WrapperCall, CopyIOAssign], TopLevelGoal),
 
@@ -872,15 +872,15 @@
     create_simple_call(mercury_univ_module, "type_to_univ", pf_predicate,
         mode_no(2), detism_semi, purity_pure,
         [RttiVar, UnivPayloadVar, ExceptVar], [],
-        [pair(RttiVar, ground(shared, none)),
-         pair(ExceptVar, ground(shared, none)), pair(UnivPayloadVar, free)],
+        instmap_delta_from_assoc_list([RttiVar - ground(shared, none),
+            ExceptVar - ground(shared, none), UnivPayloadVar - free]),
          UnivCall, !NewPredInfo),
     create_simple_call(mercury_public_builtin_module, "unify", pf_predicate,
         only_mode, detism_semi, purity_pure,
         [RttiVar, RollbackExceptVar, UnivPayloadVar], [],
-        [], _UnifyCall, !NewPredInfo),
-    create_var_test(UnivPayloadVar, RollbackExceptVar,
-        pair(in_mode, in_mode), TestGoal, !NewPredInfo),
+        instmap_delta_bind_no_var, _UnifyCall, !NewPredInfo),
+    create_var_test(UnivPayloadVar, RollbackExceptVar, in_mode - in_mode,
+        TestGoal, !NewPredInfo),
 %   XXX STM
 %   create_plain_conj([AssignGoal, UnivCall, TestGoal, UnifyCall], CondGoal),
     create_plain_conj([AssignGoal, UnivCall, TestGoal], CondGoal),
@@ -916,12 +916,13 @@
     create_aux_variable(stm_valid_result_type, yes("ValidResult"),
         IsValidVar, !NewPredInfo),
     create_simple_call(mercury_stm_builtin_module, "stm_lock", pf_predicate,
-        only_mode, detism_det, purity_impure, [], [], [], LockCall,
-        !NewPredInfo),
+        only_mode, detism_det, purity_impure, [], [],
+        instmap_delta_bind_no_var, LockCall, !NewPredInfo),
     create_simple_call(mercury_stm_builtin_module, "stm_validate",
         pf_predicate, only_mode, detism_det, purity_impure,
         [StmVar, IsValidVar], [],
-        [pair(StmVar, ground(unique, none)), pair(IsValidVar, free)],
+        instmap_delta_from_assoc_list([StmVar - ground(unique, none),
+            IsValidVar - free]),
         ValidCall, !NewPredInfo),
     create_switch_disjunction(IsValidVar,
         [case(stm_validres_valid_functor, [], ValidGoal),
@@ -930,8 +931,8 @@
     (
         UnlockAfterwards = yes,
         create_simple_call(mercury_stm_builtin_module, "stm_unlock",
-            pf_predicate, only_mode, detism_det, purity_impure, [], [], [],
-            UnlockCall, !NewPredInfo),
+            pf_predicate, only_mode, detism_det, purity_impure, [], [],
+            instmap_delta_bind_no_var, UnlockCall, !NewPredInfo),
         HldsGoals = [LockCall, ValidCall, UnlockCall, DisjGoal]
     ;
         UnlockAfterwards = no,
@@ -952,8 +953,8 @@
         IsValidConstVar, !NewPredInfo),
 
     create_simple_call(mercury_stm_builtin_module, "stm_lock", pf_predicate,
-        only_mode, detism_det, purity_impure, [], [], [], LockCall,
-        !NewPredInfo),
+        only_mode, detism_det, purity_impure, [], [],
+        instmap_delta_bind_no_var, LockCall, !NewPredInfo),
 
     % Create N value result variables.  Variables are returned as a list
 
@@ -963,16 +964,18 @@
             ValidResL, NPI0, NPI1),
         create_simple_call(mercury_stm_builtin_module, "stm_validate",
             pf_predicate, only_mode, detism_det, purity_impure,
-            [StmVarL, ValidResL], [], [pair(StmVarL, ground(unique, none)),
-            pair(ValidResL, free)], ValidGoalL, NPI1, NPI)),
+            [StmVarL, ValidResL], [],
+            instmap_delta_from_assoc_list([StmVarL - ground(unique, none),
+                ValidResL - free]),
+            ValidGoalL, NPI1, NPI)),
 
     list.map2_foldl(CreateValidate, StmVars, ValidCalls, IsValidVars,
         !NewPredInfo),
 
     CreateValidTests =
         (pred(ValidRes::in, ValidTest::out, NPI0::in, NPI::out) is det :-
-            create_var_test(ValidRes, IsValidConstVar,
-                pair(in_mode, in_mode), ValidTest, NPI0, NPI)
+            create_var_test(ValidRes, IsValidConstVar, in_mode - in_mode,
+                ValidTest, NPI0, NPI)
         ),
 
     list.map_foldl(CreateValidTests, IsValidVars, TestValidGoals,
@@ -985,8 +988,8 @@
     (
         UnlockAfterwards = yes,
         create_simple_call(mercury_stm_builtin_module, "stm_unlock",
-            pf_predicate, only_mode, detism_det, purity_impure, [], [], [],
-            UnlockCall, !NewPredInfo),
+            pf_predicate, only_mode, detism_det, purity_impure, [], [],
+            instmap_delta_bind_no_var, UnlockCall, !NewPredInfo),
         HldsGoals = [AssignValidConst, LockCall] ++ ValidCalls ++
             [UnlockCall, ITEGoal]
     ;
@@ -1029,9 +1032,7 @@
     make_type_info(ReturnType, TypeInfoVar, CreateTypeInfoGoals, !NewPredInfo),
     create_simple_call(mercury_exception_module, "rethrow", pf_predicate,
         only_mode, detism_erroneous, purity_pure, [TypeInfoVar, ExceptionVar],
-        [],
-        [pair(TypeInfoVar, ground(shared, none)),
-        pair(ExceptionVar, ground(shared, none))],
+        [], instmap_delta_bind_vars([TypeInfoVar, ExceptionVar]),
         HldsGoal_ExceptionThrow_Call, !NewPredInfo),
     create_plain_conj(CreateTypeInfoGoals ++ [HldsGoal_ExceptionThrow_Call],
         HldsGoal_ValidBranch),
@@ -1051,16 +1052,16 @@
 create_retry_handler_branch(StmVar, RecCall, HldsGoal, !NewPredInfo) :-
     create_simple_call(mercury_stm_builtin_module, "stm_block", pf_predicate,
         only_mode, detism_det, purity_impure, [StmVar], [],
-        [pair(StmVar, ground(unique, none))], BlockGoal, !NewPredInfo),
+        instmap_delta_bind_var(StmVar), BlockGoal, !NewPredInfo),
     create_simple_call(mercury_stm_builtin_module, "stm_unlock", pf_predicate,
-        only_mode, detism_det, purity_impure, [], [], [], UnlockGoal,
-        !NewPredInfo),
+        only_mode, detism_det, purity_impure, [], [],
+        instmap_delta_bind_no_var, UnlockGoal, !NewPredInfo),
     template_lock_and_validate(StmVar, no, BlockGoal, UnlockGoal,
         LockAndValidateGoals, !NewPredInfo),
     create_simple_call(mercury_stm_builtin_module,
         "stm_discard_transaction_log",
-        pf_predicate, only_mode, detism_det, purity_impure,
-        [StmVar], [], [pair(StmVar, ground(clobbered, none))],
+        pf_predicate, only_mode, detism_det, purity_impure, [StmVar], [],
+        instmap_delta_from_assoc_list([StmVar - ground(clobbered, none)]),
         DropStateCall, !NewPredInfo),
     create_plain_conj(LockAndValidateGoals ++ [DropStateCall, RecCall],
         HldsGoal).
@@ -1085,7 +1086,8 @@
     create_simple_call(mercury_stm_builtin_module,
         "stm_discard_transaction_log",
         pf_predicate, only_mode, detism_det, purity_impure, [StmVar], [],
-        [pair(StmVar, ground(clobbered, none))], DropStateGoal, !NewPredInfo),
+        instmap_delta_from_assoc_list([StmVar - ground(clobbered, none)]),
+        DropStateGoal, !NewPredInfo),
 
     create_plain_conj([DropStateGoal, RecCall], TrueGoal),
     create_validate_exception_goal(StmVar, ExceptVar, ReturnType, RecCall,
@@ -1138,8 +1140,8 @@
     create_simple_call(mercury_stm_builtin_module,
         "stm_create_transaction_log",
         pf_predicate, only_mode, detism_det, purity_impure, [StmVarDI], [],
-        [pair(StmVarDI, ground(unique, none))], HldsGoal_StmCreate,
-        !NewPredInfo),
+        instmap_delta_from_assoc_list([StmVarDI - ground(unique, none)]),
+        HldsGoal_StmCreate, !NewPredInfo),
 
     % TODO: Select mode based on determism of actual goal.  0 if determistic,
     % 1 if cc_multi.
@@ -1147,12 +1149,14 @@
     create_simple_call(mercury_exception_module, "unsafe_try_stm",
         pf_predicate, mode_no(0), detism_cc_multi, purity_pure,
         [RttiTypeVar, AtomicClosureVar, ReturnExceptVar, StmVarDI, StmVarUO],
-        [], [pair(RttiTypeVar, ground(shared, none)),
-        pair(AtomicClosureVar, ground(shared, none)),
-        pair(ReturnExceptVar, ground(shared, none)),
-        pair(StmVarDI, ground(clobbered, none)),
-        pair(StmVarUO, ground(unique, none))], HldsGoal_TryStm,
-        !NewPredInfo),
+        [],
+        instmap_delta_from_assoc_list([
+            RttiTypeVar - ground(shared, none),
+            AtomicClosureVar - ground(shared, none),
+            ReturnExceptVar - ground(shared, none),
+            StmVarDI - ground(clobbered, none),
+            StmVarUO - ground(unique, none)]),
+        HldsGoal_TryStm, !NewPredInfo),
 
     % For successfull execution, deconstruct and return true
     deconstruct_output(AtomicGoalVars, ReturnType, ReturnExceptVar,
@@ -1424,28 +1428,27 @@
         yes("Stm_Expand_Rollback"), ConstRollbackGoal, RollbackVar,
         !NewPredInfo),
     create_simple_call(StmModuleName, "stm_lock", pf_predicate, only_mode,
-        detism_det, purity_impure, [], [], [], HldsGoal_StmLock_Call,
-        !NewPredInfo),
+        detism_det, purity_impure, [], [], instmap_delta_bind_no_var,
+        HldsGoal_StmLock_Call, !NewPredInfo),
     create_simple_call(StmModuleName, "stm_unlock", pf_predicate, only_mode,
-        detism_det, purity_impure, [], [], [], HldsGoal_StmUnLock_Call,
-        !NewPredInfo),
+        detism_det, purity_impure, [], [], instmap_delta_bind_no_var,
+        HldsGoal_StmUnLock_Call, !NewPredInfo),
     create_simple_call(StmModuleName, "stm_validate", pf_predicate, only_mode,
         detism_det, purity_impure, [StmUO, IsValidVar], [],
-        [pair(StmUO, ground(unique, none)),
-        pair(IsValidVar, ground(shared, none))], HldsGoal_StmValidate_Call,
-        !NewPredInfo),
+        instmap_delta_from_assoc_list([StmUO - ground(unique, none),
+            IsValidVar - ground(shared, none)]),
+        HldsGoal_StmValidate_Call, !NewPredInfo),
     create_simple_call(StmModuleName, "stm_commit", pf_predicate, only_mode,
         detism_det, purity_impure, [StmUO], [],
-        [pair(StmUO, ground(unique, none))], HldsGoal_StmCommit_Call,
-        !NewPredInfo),
+        instmap_delta_from_assoc_list([StmUO - ground(unique, none)]),
+        HldsGoal_StmCommit_Call, !NewPredInfo),
 
     make_type_info(stm_rollback_exception_type, TypeInfoVar,
         CreateTypeInfoGoals, !NewPredInfo),
 
     create_simple_call(ExceptionModuleName, "throw", pf_predicate, only_mode,
         detism_erroneous, purity_pure, [TypeInfoVar, RollbackVar], [],
-        [pair(TypeInfoVar, ground(shared, none)),
-         pair(RollbackVar, ground(shared, none))],
+        instmap_delta_bind_vars([TypeInfoVar, RollbackVar]),
         HldsGoal_ExceptionThrow_Call, !NewPredInfo),
 
     % Creates the branch on the validation result of the log.
@@ -1470,7 +1473,7 @@
     % Creates the unification between StmUO and StmDI is needed.
     (
         CopySTM = yes,
-        create_var_unify(StmUO, StmDI, pair(uo_mode, di_mode),
+        create_var_unify(StmUO, StmDI, uo_mode - di_mode,
             CopySTMAssign, !NewPredInfo),
         TopLevelGoalList0 = [AtomicGoal] ++ AssignResult ++ [CopySTMAssign,
             PostAtomicGoal]
@@ -1569,7 +1572,7 @@
 
     % Creates the unification between StmUO and StmDI is needed.
     ( CopySTM = yes ->
-        create_var_unify(StmUO, StmDI, pair(uo_mode, di_mode),
+        create_var_unify(StmUO, StmDI, uo_mode - di_mode,
             CopySTMAssign, !NewPredInfo),
         TopLevelGoalList0 = Call1 ++ [CopySTMAssign, AtomicGoal] ++ Call2 ++
             AssignResult
@@ -1780,31 +1783,31 @@
         create_simple_call(mercury_stm_builtin_module, "stm_merge_nested_logs",
             pf_predicate, only_mode, detism_det, purity_impure,
             [StmVar, ThreadSTMDI, ThreadSTMUO], [],
-            [pair(StmVar, ground(unique, none)), pair(ThreadSTMDI, free),
-            pair(ThreadSTMUO, ground(unique, none))],
+            instmap_delta_from_assoc_list([StmVar - ground(unique, none),
+                ThreadSTMDI - free, ThreadSTMUO - ground(unique, none)]),
             Goal, NPI0, NPI)),
 
     map3_in_foldl(MakeMergeGoals, StmVars, MergeStmVarsIn, MergeStmVarsOut,
         MergeGoals, !NewPredInfo),
 
     create_simple_call(mercury_stm_builtin_module, "stm_unlock", pf_predicate,
-        only_mode, detism_det, purity_impure, [], [], [], UnlockCall,
-        !NewPredInfo),
+        only_mode, detism_det, purity_impure, [], [],
+        instmap_delta_bind_no_var, UnlockCall, !NewPredInfo),
 
     create_aux_variable_assignment(stm_rollback_retry_functor,
         stm_rollback_exception_type, yes("RetryCons"), AssignRetryCons,
         RetryConsVar, !NewPredInfo),
     create_simple_call(mercury_exception_module, "throw", pf_predicate,
-        only_mode, detism_erroneous, purity_pure, [ExceptionRttiVar,
-        RetryConsVar], [], [pair(ExceptionRttiVar, ground(shared, none)),
-        pair(RetryConsVar, ground(shared, none))], RetryCall,
-        !NewPredInfo),
+        only_mode, detism_erroneous, purity_pure,
+        [ExceptionRttiVar, RetryConsVar], [],
+        instmap_delta_bind_vars([ExceptionRttiVar, RetryConsVar]),
+        RetryCall, !NewPredInfo),
 
 %   XXX STM
 %   create_simple_call(mercury_stm_builtin_module, "retry",
 %       pf_predicate, only_mode,
 %       detism_det, purity_pure, [OuterSTMUO], [],
-%       [pair(OuterSTMUO, ground(unique, none))], RetryCall, !NewPredInfo),
+%       instmap_delta_bind_var(OuterSTMUO), RetryCall, !NewPredInfo),
     create_plain_conj(MergeGoals ++ [UnlockCall, AssignRetryCons, RetryCall],
         ValidGoal),
 
@@ -1815,9 +1818,9 @@
         RollbackConsVar, !NewPredInfo),
     create_simple_call(mercury_exception_module, "throw", pf_predicate,
         only_mode, detism_erroneous, purity_pure, [ExceptionRttiVar,
-        RollbackConsVar], [], [pair(ExceptionRttiVar, ground(shared, none)),
-        pair(RollbackConsVar, ground(shared, none))], ThrowCall,
-        !NewPredInfo),
+        RollbackConsVar], [],
+        instmap_delta_bind_vars([ExceptionRttiVar, RollbackConsVar]),
+        ThrowCall, !NewPredInfo),
     create_plain_conj([UnlockCall, AssignRollbackCons, ThrowCall],
         InvalidGoal),
 
@@ -1868,17 +1871,21 @@
         "stm_create_nested_transaction_log",
         pf_predicate, only_mode, detism_det, purity_impure,
         [OuterStmDIVar, InnerSTM0Var], [],
-        [pair(OuterStmDIVar, ground(unique, none)), pair(InnerSTM0Var, free)],
+        instmap_delta_from_assoc_list([OuterStmDIVar - ground(unique, none),
+            InnerSTM0Var - free]),
         CreateNestedLogCall, !NewPredInfo),
 
     create_simple_call(mercury_exception_module, "unsafe_try_stm",
         pf_predicate, mode_no(0), detism_cc_multi, purity_pure,
         [RttiVar, AtomicClosureVar, ReturnExceptVar, InnerSTM0Var,InnerSTMVar],
-        [], [pair(RttiVar, ground(shared, none)),
-        pair(AtomicClosureVar, ground(shared, none)),
-        pair(ReturnExceptVar, free),
-        pair(InnerSTM0Var, ground(unique, none)),
-        pair(InnerSTMVar, free)], TryStmCall, !NewPredInfo),
+        [],
+        instmap_delta_from_assoc_list([
+            RttiVar - ground(shared, none),
+            AtomicClosureVar - ground(shared, none),
+            ReturnExceptVar - free,
+            InnerSTM0Var - ground(unique, none),
+            InnerSTMVar - free]),
+        TryStmCall, !NewPredInfo),
 
     % Successfull execution, deconstruct and return
     deconstruct_output(AtomicGoalVars, ReturnType, ReturnExceptVar,
@@ -1886,8 +1893,8 @@
     create_simple_call(mercury_stm_builtin_module, "stm_merge_nested_logs",
         pf_predicate, only_mode, detism_det, purity_impure,
         [InnerSTMVar, OuterStmDIVar, OuterStmUOVar], [],
-        [pair(InnerSTMVar, ground(unique, none)),
-        pair(OuterStmDIVar, ground(unique, none)), pair(OuterStmUOVar, free)],
+        instmap_delta_from_assoc_list([InnerSTMVar - ground(unique, none),
+            OuterStmDIVar - ground(unique, none), OuterStmUOVar - free]),
         MergeNestedLogsCall, !NewPredInfo),
 
     create_plain_conj([DeconstructGoal, MergeNestedLogsCall], SuccessBranch),
@@ -1895,14 +1902,14 @@
     % General exception: discard and throw upwards
     create_simple_call(mercury_stm_builtin_module,
         "stm_discard_transaction_log",
-        pf_predicate, only_mode, detism_det, purity_impure,
-        [InnerSTMVar], [], [pair(InnerSTMVar, ground(unique, none))],
+        pf_predicate, only_mode, detism_det, purity_impure, [InnerSTMVar], [],
+        instmap_delta_from_assoc_list([InnerSTMVar - ground(unique, none)]),
         DiscardCall, !NewPredInfo),
     create_simple_call(mercury_exception_module, "rethrow",
         pf_predicate, only_mode, detism_erroneous, purity_pure,
-        [RttiVar, ReturnExceptVar], [], [pair(RttiVar, ground(shared, none)),
-        pair(ReturnExceptVar, ground(shared, none))], RethrowCall,
-        !NewPredInfo),
+        [RttiVar, ReturnExceptVar], [],
+        instmap_delta_bind_vars([RttiVar, ReturnExceptVar]),
+        RethrowCall, !NewPredInfo),
 
     % Code to extract the exception result.
     create_aux_variable(univ_type, yes("ExceptUnivVar"), ExceptUnivVar,
@@ -2020,7 +2027,7 @@
         % exception result and return.
 
         OutVar = list.det_head(OutputVars),
-        create_var_unify(ResultVar, OutVar, pair(out_mode, in_mode),
+        create_var_unify(ResultVar, OutVar, out_mode - in_mode,
             HldsGoal, !NewPredInfo),
 
         HldsGoals = [HldsGoal]
@@ -2233,7 +2240,7 @@
     %
 :- pred create_simple_call(module_name::in, string::in, pred_or_func::in,
     mode_no::in, determinism::in, purity::in, prog_vars::in,
-    list(goal_feature)::in, assoc_list(prog_var, mer_inst)::in,
+    list(goal_feature)::in, instmap_delta::in,
     hlds_goal::out, stm_new_pred_info::in, stm_new_pred_info::out) is det.
 
 create_simple_call(ModuleName, ProcName, PredOrFunc, Mode, Detism, Purity,
@@ -2262,8 +2269,8 @@
     ClosureAssignInstmapDeltaList = assoc_list.from_corresponding_lists(
         [ClosureVar], [ground(shared, higher_order(pred_inst_info(
         pf_predicate, ArgModes, detism_det)))]),
-    instmap_delta_from_assoc_list(ClosureAssignInstmapDeltaList,
-        ClosureAssignInstmapDelta),
+    ClosureAssignInstmapDelta =
+        instmap_delta_from_assoc_list(ClosureAssignInstmapDeltaList),
 
     ClosureAssignGoal0 = hlds_goal(ClosureAssignExpr, ClosureAssignInfo0),
     goal_info_set_instmap_delta(ClosureAssignInstmapDelta, ClosureAssignInfo0,
Index: compiler/table_gen.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/table_gen.m,v
retrieving revision 1.151
diff -u -b -r1.151 table_gen.m
--- compiler/table_gen.m	8 Jul 2009 02:24:33 -0000	1.151
+++ compiler/table_gen.m	1 Sep 2009 01:31:10 -0000
@@ -703,21 +703,21 @@
 
     table_generate_foreign_proc(MarkInactivePredName, detism_det,
         tabling_c_attributes_dupl, [TableTipArg], [],
-        MarkInactiveCode, purity_impure, [],
+        MarkInactiveCode, purity_impure, instmap_delta_bind_no_var,
         ModuleInfo, Context, MarkInactiveGoal),
     table_generate_foreign_proc(MarkInactiveFailPredName, detism_failure,
         tabling_c_attributes_dupl, [TableTipArg], [],
-        MarkInactiveFailCode, purity_impure, [],
+        MarkInactiveFailCode, purity_impure, instmap_delta_bind_no_var,
         ModuleInfo, Context, MarkInactiveFailGoal),
     table_generate_foreign_proc(MarkActiveFailPredName, detism_failure,
         tabling_c_attributes_dupl, [TableTipArg], [],
-        MarkActiveFailCode, purity_impure, [],
+        MarkActiveFailCode, purity_impure, instmap_delta_bind_no_var,
         ModuleInfo, Context, MarkActiveFailGoal),
 
     determinism_to_code_model(Detism, CodeModel),
     set.list_to_set([TableTipVar | HeadVars], InactiveNonLocals),
     OutputVars = list.map(project_var, NumberedOutputVars),
-    InactiveInstmapDelta = bind_vars(OutputVars),
+    InactiveInstmapDelta = instmap_delta_bind_vars(OutputVars),
     (
         CodeModel = model_det,
         InactiveGoalExpr = conj(plain_conj, [OrigGoal, MarkInactiveGoal])
@@ -946,7 +946,7 @@
 
     set.list_to_set([TableTipVar | HeadVars], InactiveNonLocals),
     OutputVars = list.map(project_var, NumberedOutputVars),
-    InactiveInstmapDelta = bind_vars(OutputVars),
+    InactiveInstmapDelta = instmap_delta_bind_vars(OutputVars),
 
     % The case CodeModel = model_non was caught by the code above.
     (
@@ -984,7 +984,7 @@
             "(" ++ DebugArgStr ++ ", " ++ cur_table_node_name ++ ");",
         table_generate_foreign_proc(MarkAsFailedPredName, detism_failure,
             tabling_c_attributes_dupl, [TableTipArg], [],
-            MarkAsFailedCode, purity_impure, [],
+            MarkAsFailedCode, purity_impure, instmap_delta_bind_no_var,
             ModuleInfo, Context, ElseGoal),
         InactiveGoalExpr = if_then_else([], RenamedOrigGoal,
             ThenGoal, ElseGoal),
@@ -1074,15 +1074,15 @@
 
     table_generate_foreign_proc(MarkIncompletePredName, detism_det,
         tabling_c_attributes_dupl, [RecordArg], [],
-        MarkIncompleteCode, purity_impure, [],
+        MarkIncompleteCode, purity_impure, instmap_delta_bind_no_var,
         ModuleInfo, Context, MarkIncompleteGoal),
     table_generate_foreign_proc(MarkActivePredName, detism_failure,
         tabling_c_attributes_dupl, [RecordArg], [],
-        MarkActiveCode, purity_impure, [],
+        MarkActiveCode, purity_impure, instmap_delta_bind_no_var,
         ModuleInfo, Context, MarkActiveGoal),
     table_generate_foreign_proc(MarkCompletePredName, detism_failure,
         tabling_c_attributes_dupl, [RecordArg], [],
-        MarkCompleteCode, purity_impure, [],
+        MarkCompleteCode, purity_impure, instmap_delta_bind_no_var,
         ModuleInfo, Context, MarkCompleteGoal),
 
     OrigSaveExpr = conj(plain_conj, [OrigGoal | SaveAnswerGoals]),
@@ -1108,7 +1108,7 @@
 
     set.list_to_set([RecordVar | HeadVars], InactiveNonLocals),
     OutputVars = list.map(project_var, NumberedOutputVars),
-    InactiveInstmapDelta = bind_vars(OutputVars),
+    InactiveInstmapDelta = instmap_delta_bind_vars(OutputVars),
 
     SwitchArms = [
         case(memo_non_active_cons_id, [], InfiniteRecursionGoal),
@@ -1258,15 +1258,16 @@
         StartVar),
     table_generate_call("table_io_in_range", detism_semi,
         [TableVar, CounterVar, StartVar], purity_impure,
-        ground_vars([TableVar, CounterVar, StartVar]),
+        instmap_delta_bind_vars([TableVar, CounterVar, StartVar]),
         ModuleInfo, Context, InRangeGoal),
     generate_new_table_var("TipVar", trie_node_type, !VarSet, !VarTypes,
         TipVar),
     table_generate_call("table_lookup_insert_start_int", detism_det,
         [TableVar, StartVar, CounterVar, TipVar], purity_impure,
-        ground_vars([TipVar]), ModuleInfo, Context, LookupGoal),
+        instmap_delta_bind_var(TipVar), ModuleInfo, Context, LookupGoal),
     table_generate_call("table_io_has_occurred", detism_semi, [TipVar],
-        purity_impure, [], ModuleInfo, Context, OccurredGoal),
+        purity_impure, instmap_delta_bind_no_var, ModuleInfo, Context,
+        OccurredGoal),
     (
         TableDecl = table_io_decl,
         ShroudedPredProcId = shroud_pred_proc_id(proc(PredId, ProcId)),
@@ -1320,8 +1321,9 @@
         ),
         table_generate_call("table_io_copy_io_state", detism_det,
             [IoStateAssignFromVar, IoStateAssignToVar], purity_pure,
-            [IoStateAssignFromVar - ground(clobbered, none),
-            IoStateAssignToVar - ground(unique, none)],
+            instmap_delta_from_assoc_list([
+                IoStateAssignFromVar - ground(clobbered, none),
+                IoStateAssignToVar - ground(unique, none)]),
             ModuleInfo, Context, IoStateAssignGoal),
         RestoreAnswerGoalExpr = conj(plain_conj,
             [RestoreAnswerGoal0, IoStateAssignGoal]),
@@ -1352,10 +1354,10 @@
             !VarSet, !VarTypes, SavedTraceEnabledVar),
         table_generate_call("table_io_left_bracket_unitized_goal", detism_det,
             [SavedTraceEnabledVar], purity_impure,
-            ground_vars([SavedTraceEnabledVar]),
+            instmap_delta_bind_var(SavedTraceEnabledVar),
             ModuleInfo, Context, LeftBracketGoal),
         table_generate_call("table_io_right_bracket_unitized_goal", detism_det,
-            [SavedTraceEnabledVar], purity_impure, [],
+            [SavedTraceEnabledVar], purity_impure, instmap_delta_bind_no_var,
             ModuleInfo, Context, RightBracketGoal),
         CallSaveAnswerGoalList = [LeftBracketGoal, NewGoal,
             RightBracketGoal, TableIoDeclGoal | SaveAnswerGoals]
@@ -1500,7 +1502,8 @@
     MainGoal = hlds_goal(MainExpr, MainGoalInfo),
 
     table_generate_call("table_mm_completion", detism_det, [SubgoalVar],
-        purity_impure, [], ModuleInfo, Context, ResumeGoal0),
+        purity_impure, instmap_delta_bind_no_var, ModuleInfo, Context,
+        ResumeGoal0),
     append_fail(ResumeGoal0, ResumeGoal),
     InactiveExpr = disj([MainGoal, ResumeGoal]),
     InactiveGoal = hlds_goal(InactiveExpr, MainGoalInfo),
@@ -1666,7 +1669,8 @@
         make_generator_c_attributes,
         [InfoArg, GeneratorPredArg, ConsumerArg], LookupForeignArgs,
         LookupDeclCodeStr ++ SetupCode, purity_impure,
-        ground_vars([ConsumerVar]), ModuleInfo, Context, SetupGoal),
+        instmap_delta_bind_var(ConsumerVar), ModuleInfo, Context,
+        SetupGoal),
     % We don't attach the call_table_tip attribute to the setup goal, since
     % retrying across the creation of the generator should not require undoing
     % the creation of the generator. Of course, for this to work *properly*,
@@ -1687,8 +1691,8 @@
     ),
     % XXX consider inlining the predicate being called
     table_generate_call(ConsumePredName, Detism, [ConsumerVar, AnswerBlockVar],
-        purity_impure, ground_vars([AnswerBlockVar]), ModuleInfo, Context,
-        GetNextAnswerGoal),
+        purity_impure, instmap_delta_bind_var(AnswerBlockVar), ModuleInfo,
+        Context, GetNextAnswerGoal),
     DebugArgStr = get_debug_arg_string(!.TableInfo),
     generate_restore_goals(NumberedOutputVars, OrigInstMapDelta,
         DebugArgStr, ModuleInfo, !VarSet, !VarTypes, RestoreInstMapDeltaSrc,
@@ -1699,7 +1703,8 @@
     RestoreAllPredName = "table_mmos_restore_answers",
     table_generate_foreign_proc(RestoreAllPredName, detism_det,
         tabling_c_attributes_no_dupl, [AnswerBlockArg],
-        RestoreArgs, RestoreCodeStr, purity_semipure, RestoreInstMapDeltaSrc,
+        RestoreArgs, RestoreCodeStr, purity_semipure,
+        instmap_delta_from_assoc_list(RestoreInstMapDeltaSrc),
         ModuleInfo, Context, RestoreGoal),
 
     GoalExpr = conj(plain_conj,
@@ -1768,7 +1773,7 @@
         !ProcInfo),
     PickupInstMapDeltaSrc0 = list.map(project_var_init_inst(ModuleInfo0),
         NumberedInputVars),
-    PickupInstMapDeltaSrc = [pair_with_ground(GeneratorVar)
+    PickupInstMapDeltaSrc = [GeneratorVar - ground_inst
         | PickupInstMapDeltaSrc0],
     PickupGeneratorCode = "\t\t" ++ generator_name ++
         " = MR_mmos_new_generator;\n",
@@ -1777,7 +1782,8 @@
     table_generate_foreign_proc("table_mmos_pickup_inputs", detism_det,
         tabling_c_attributes_no_dupl, [PickupGeneratorArg], PickupForeignArgs,
         PickupGeneratorCode ++ PickupVarCode, purity_impure,
-        PickupInstMapDeltaSrc, ModuleInfo0, Context, PickupGoal),
+        instmap_delta_from_assoc_list(PickupInstMapDeltaSrc),
+        ModuleInfo0, Context, PickupGoal),
 
     list.length(NumberedOutputVars, BlockSize),
     generate_own_stack_save_return_goal(NumberedOutputVars, GeneratorVar,
@@ -1802,8 +1808,8 @@
         yes(generator_name - in_mode), generator_type, native_if_possible),
     table_generate_foreign_proc("table_mmos_completion", detism_failure,
         tabling_c_attributes_no_dupl, [CompletionArg], [],
-        CompletionCode, purity_impure,
-        [], ModuleInfo0, Context, CompletionGoal),
+        CompletionCode, purity_impure, instmap_delta_bind_no_var,
+        ModuleInfo0, Context, CompletionGoal),
 
     DisjGoalExpr = disj([MainGoal, CompletionGoal]),
     DisjGoal = hlds_goal(DisjGoalExpr, MainGoalInfo),
@@ -1977,6 +1983,7 @@
 keep_marker(marker_calls_are_fully_qualified) = yes.
 keep_marker(marker_mode_check_clauses) = yes.
 keep_marker(marker_mutable_access_pred) = yes.
+keep_marker(marker_has_format_call) = yes.
 
 %-----------------------------------------------------------------------------%
 
@@ -2051,14 +2058,15 @@
     table_generate_foreign_proc(PredName, detism_det,
         tabling_c_attributes_no_dupl,
         Args, LookupForeignArgs, CodeStr, purity_impure,
-        ground_vars(BoundVars), ModuleInfo, Context, SetupGoal0),
+        instmap_delta_bind_vars(BoundVars), ModuleInfo, Context, SetupGoal0),
     attach_call_table_tip(SetupGoal0, SetupGoal),
     LookupSetupGoals = LookupPrefixGoals ++ [SetupGoal],
 
     GoalExpr = conj(plain_conj, LookupSetupGoals),
     Vars = list.map(project_var, NumberedVars),
     set.list_to_set([StatusVar, TableTipVar | Vars], NonLocals),
-    goal_info_init_hide(NonLocals, bind_vars([TableTipVar, StatusVar]),
+    goal_info_init_hide(NonLocals,
+        instmap_delta_bind_vars([TableTipVar, StatusVar]),
         detism_det, purity_impure, Context, GoalInfo),
     Goal = hlds_goal(GoalExpr, GoalInfo).
 
@@ -2108,14 +2116,15 @@
     table_generate_foreign_proc(SetupPredName, detism_det,
         tabling_c_attributes_no_dupl, Args, LookupForeignArgs,
         LookupDeclCodeStr ++ PredCodeStr, purity_impure,
-        ground_vars(BoundVars), ModuleInfo, Context, SetupGoal0),
+        instmap_delta_bind_vars(BoundVars), ModuleInfo, Context, SetupGoal0),
     attach_call_table_tip(SetupGoal0, SetupGoal),
     LookupSetupGoals = LookupPrefixGoals ++ [SetupGoal],
 
     GoalExpr = conj(plain_conj, LookupSetupGoals),
     Vars = list.map(project_var, NumberedVars),
     set.list_to_set([StatusVar, RecordVar | Vars], NonLocals),
-    goal_info_init_hide(NonLocals, bind_vars([RecordVar, StatusVar]),
+    goal_info_init_hide(NonLocals,
+        instmap_delta_bind_vars([RecordVar, StatusVar]),
         detism_det, purity_impure, Context, GoalInfo),
     Goal = hlds_goal(GoalExpr, GoalInfo).
 
@@ -2163,7 +2172,7 @@
     ModuleInfo = !.TableInfo ^ table_module_info,
     table_generate_foreign_proc(SetupPredName, detism_det,
         tabling_c_attributes_no_dupl, Args, LookupForeignArgs, CodeStr,
-        purity_impure, ground_vars(BoundVars), ModuleInfo, Context,
+        purity_impure, instmap_delta_bind_vars(BoundVars), ModuleInfo, Context,
         SetupGoal0),
     attach_call_table_tip(SetupGoal0, SetupGoal),
     LookupSetupGoals = LookupPrefixGoals ++ [SetupGoal],
@@ -2171,7 +2180,8 @@
     GoalExpr = conj(plain_conj, LookupSetupGoals),
     Vars = list.map(project_var, NumberedVars),
     set.list_to_set([StatusVar, SubgoalVar | Vars], NonLocals),
-    goal_info_init_hide(NonLocals, bind_vars([SubgoalVar, StatusVar]),
+    goal_info_init_hide(NonLocals,
+        instmap_delta_bind_vars([SubgoalVar, StatusVar]),
         detism_det, purity_impure, Context, GoalInfo),
     Goal = hlds_goal(GoalExpr, GoalInfo).
 
@@ -2613,7 +2623,7 @@
             !TableInfo, SaveArgs, SavePrefixGoals, SaveDeclCode, SaveCode),
         table_generate_foreign_proc(CreatePredName, detism_det,
             tabling_c_attributes_dupl, [TableArg], SaveArgs,
-            SaveDeclCode ++ SaveCode, purity_impure, [],
+            SaveDeclCode ++ SaveCode, purity_impure, instmap_delta_bind_no_var,
             ModuleInfo, Context, SaveGoal),
         Goals = SavePrefixGoals ++ [SaveGoal]
     ;
@@ -2624,7 +2634,7 @@
             "(" ++ DebugArgStr ++ ", " ++ cur_table_node_name ++ ");",
         table_generate_foreign_proc(MarkAsSucceededPredName, detism_det,
             tabling_c_attributes_dupl, [TableArg], [],
-            MarkAsSucceededCode, purity_impure, [],
+            MarkAsSucceededCode, purity_impure, instmap_delta_bind_no_var,
             ModuleInfo, Context, SaveGoal),
         Goals = [SaveGoal]
     ).
@@ -2682,7 +2692,8 @@
         AssignSuccessCodeStr,
     table_generate_foreign_proc(DuplCheckPredName, detism_semi,
         tabling_c_attributes_dupl, [RecordArg], LookupForeignArgs, CodeStr,
-        purity_impure, [], ModuleInfo, Context, DuplicateCheckSaveGoal),
+        purity_impure, instmap_delta_bind_no_var, ModuleInfo, Context,
+        DuplicateCheckSaveGoal),
     Goals = LookupPrefixGoals ++ [DuplicateCheckSaveGoal].
 
     % Generate a goal for saving the output arguments in an answer block
@@ -2737,7 +2748,7 @@
         CondSaveStr ++ AssignSuccessCodeStr,
     table_generate_foreign_proc(DuplCheckPredName, detism_semi,
         tabling_c_attributes_dupl, Args, LookupForeignArgs,
-        CodeStr, purity_impure, [],
+        CodeStr, purity_impure, instmap_delta_bind_no_var,
         ModuleInfo, Context, DuplicateCheckSaveGoal),
     Goals = LookupPrefixGoals ++ [DuplicateCheckSaveGoal].
 
@@ -2822,7 +2833,7 @@
     ModuleInfo = !.TableInfo ^ table_module_info,
     table_generate_foreign_proc(DuplCheckPredName, detism_semi,
         tabling_c_attributes_dupl, Args, LookupForeignArgs,
-        CodeStr, purity_impure, [],
+        CodeStr, purity_impure, instmap_delta_bind_no_var,
         ModuleInfo, Context, DuplicateCheckSaveGoal),
     Goals = LookupPrefixGoals ++ SavePrefixGoals ++
         [DuplicateCheckSaveGoal].
@@ -2922,7 +2933,8 @@
         table_generate_foreign_proc(GetPredName, detism_det,
             tabling_c_attributes_dupl, Args, RestoreArgs,
             DeclCodeStr ++ GetRestoreCodeStr, purity_semipure,
-            RestoreInstMapDeltaSrc, ModuleInfo, Context, ShortcutGoal),
+            instmap_delta_from_assoc_list(RestoreInstMapDeltaSrc),
+            ModuleInfo, Context, ShortcutGoal),
         Goal = ShortcutGoal
     ;
         NumberedOutputVars = [],
@@ -2950,7 +2962,7 @@
         !VarSet, !VarTypes, AnswerBlockVar),
     ModuleInfo = TableInfo ^ table_module_info,
     table_generate_call(ReturnAllAns, Detism, [RecordVar, AnswerBlockVar],
-        purity_semipure, ground_vars([AnswerBlockVar]), ModuleInfo,
+        purity_semipure, instmap_delta_bind_var(AnswerBlockVar), ModuleInfo,
         Context, ReturnAnswerBlocksGoal),
     DebugArgStr = get_debug_arg_string(TableInfo),
     generate_restore_goals(NumberedOutputVars, OrigInstMapDelta,
@@ -2963,8 +2975,8 @@
     PredName = "table_memo_non_return_all_shortcut",
     table_generate_foreign_proc(PredName, detism_det,
         tabling_c_attributes_no_dupl, Args, RestoreArgs, RestoreCodeStr,
-        purity_semipure, RestoreInstMapDeltaSrc, ModuleInfo, Context,
-        ShortcutGoal),
+        purity_semipure, instmap_delta_from_assoc_list(RestoreInstMapDeltaSrc),
+        ModuleInfo, Context, ShortcutGoal),
 
     GoalExpr = conj(plain_conj, [ReturnAnswerBlocksGoal, ShortcutGoal]),
     set.list_to_set([RecordVar | OutputVars], NonLocals),
@@ -3023,7 +3035,7 @@
         !VarSet, !VarTypes, AnswerBlockVar),
     ModuleInfo = TableInfo ^ table_module_info,
     table_generate_call(PredName, Detism, [SubgoalVar, AnswerBlockVar],
-        Purity, ground_vars([AnswerBlockVar]), ModuleInfo,
+        Purity, instmap_delta_bind_var(AnswerBlockVar), ModuleInfo,
         Context, ReturnAnswerBlocksGoal),
     DebugArgStr = get_debug_arg_string(TableInfo),
     generate_restore_goals(NumberedOutputVars, OrigInstMapDelta,
@@ -3037,8 +3049,8 @@
     ReturnAllPredName = "table_mm_return_all_shortcut",
     table_generate_foreign_proc(ReturnAllPredName, detism_det,
         tabling_c_attributes_no_dupl, Args, RestoreArgs, RestoreCodeStr,
-        purity_semipure, RestoreInstMapDeltaSrc, ModuleInfo, Context,
-        ReturnAllGoal),
+        purity_semipure, instmap_delta_from_assoc_list(RestoreInstMapDeltaSrc),
+        ModuleInfo, Context, ReturnAllGoal),
     GoalExpr = conj(plain_conj, [ReturnAnswerBlocksGoal, ReturnAllGoal]),
 
     set.list_to_set([SubgoalVar | OutputVars], NonLocals),
@@ -3128,10 +3140,10 @@
     gen_string_construction("Message", Message, !VarSet, !VarTypes,
         MessageVar, MessageStrGoal),
     table_generate_call("table_error", detism_erroneous, [MessageVar],
-        purity_pure, [], ModuleInfo, Context, CallGoal),
+        purity_pure, instmap_delta_bind_no_var, ModuleInfo, Context, CallGoal),
 
     GoalExpr = conj(plain_conj, [MessageStrGoal, CallGoal]),
-    goal_info_init_hide(set.init, bind_vars([]), detism_erroneous,
+    goal_info_init_hide(set.init, instmap_delta_bind_no_var, detism_erroneous,
         purity_impure, Context, GoalInfo),
     Goal = hlds_goal(GoalExpr, GoalInfo).
 
@@ -3146,10 +3158,10 @@
     map.set(!.VarTypes, Var, Type, !:VarTypes).
 
 :- pred table_generate_call(string::in, determinism::in, list(prog_var)::in,
-    purity::in, assoc_list(prog_var, mer_inst)::in,
-    module_info::in, term.context::in, hlds_goal::out) is det.
+    purity::in, instmap_delta::in, module_info::in, term.context::in,
+    hlds_goal::out) is det.
 
-table_generate_call(PredName, Detism, Args, Purity, InstMapSrc, ModuleInfo,
+table_generate_call(PredName, Detism, Args, Purity, InstMapDelta, ModuleInfo,
         Context, Goal) :-
     BuiltinModule = mercury_table_builtin_module,
     (
@@ -3167,17 +3179,17 @@
         Features = Features0
     ),
     goal_util.generate_simple_call(BuiltinModule, PredName, pf_predicate,
-        only_mode, Detism, Purity, Args, Features, InstMapSrc, ModuleInfo,
+        only_mode, Detism, Purity, Args, Features, InstMapDelta, ModuleInfo,
         Context, Goal).
 
 :- pred table_generate_foreign_proc(string::in, determinism::in,
     pragma_foreign_proc_attributes::in,
     list(foreign_arg)::in, list(foreign_arg)::in, string::in,
-    purity::in, assoc_list(prog_var, mer_inst)::in,
+    purity::in, instmap_delta::in,
     module_info::in, term.context::in, hlds_goal::out) is det.
 
 table_generate_foreign_proc(PredName, Detism, Attributes, Args, ExtraArgs,
-        Code, Purity, InstMapSrc, ModuleInfo, Context, Goal) :-
+        Code, Purity, InstMapDelta, ModuleInfo, Context, Goal) :-
     (
         Purity = purity_pure,
         Features0 = []
@@ -3196,7 +3208,7 @@
     MaybeTraceRuntimCond = no,
     goal_util.generate_foreign_proc(BuiltinModule, PredName, pf_predicate,
         only_mode, Detism, Purity, Attributes, Args, ExtraArgs,
-        MaybeTraceRuntimCond, Code, Features, InstMapSrc, ModuleInfo,
+        MaybeTraceRuntimCond, Code, Features, InstMapDelta, ModuleInfo,
         Context, Goal).
 
 :- pred append_fail(hlds_goal::in, hlds_goal::out) is det.
@@ -3338,7 +3350,7 @@
 :- pred create_instmap_delta(hlds_goals::in, instmap_delta::out) is det.
 
 create_instmap_delta([], IMD) :-
-    instmap_delta_from_assoc_list([], IMD).
+    IMD = instmap_delta_bind_no_var.
 create_instmap_delta([Goal | Rest], IMD) :-
     Goal = hlds_goal(_, GoalInfo),
     IMD0 = goal_info_get_instmap_delta(GoalInfo),
@@ -3467,21 +3479,6 @@
 var_belong_to_list(List, var_mode_pos_method(Var, _, _, _)) :-
     list.member(Var, List).
 
-:- func bind_vars(list(prog_var)) = instmap_delta.
-
-bind_vars(Vars) = InstMapDelta :-
-    VarsAndGround = ground_vars(Vars),
-    instmap_delta_from_assoc_list(VarsAndGround, InstMapDelta).
-
-:- func ground_vars(list(prog_var)) = assoc_list(prog_var, mer_inst).
-
-ground_vars(Vars) = VarsAndGround :-
-    VarsAndGround = list.map(pair_with_ground, Vars).
-
-:- func pair_with_ground(prog_var) = pair(prog_var, mer_inst).
-
-pair_with_ground(Var) = Var - ground(shared, none).
-
 :- pred goal_info_init_hide(set(prog_var)::in, instmap_delta::in,
     determinism::in, purity::in, prog_context::in, hlds_goal_info::out)
     is det.
Index: compiler/try_expand.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/try_expand.m,v
retrieving revision 1.6
diff -u -b -r1.6 try_expand.m
--- compiler/try_expand.m	21 Jul 2009 04:10:43 -0000	1.6
+++ compiler/try_expand.m	1 Sep 2009 01:26:59 -0000
@@ -864,10 +864,10 @@
     Mode = mode_no(0),
     Args = [TypeInfoVar, LambdaVar, ResultVar] ++ ExtraArgs,
     Features = [],
-    InstMapSrc = [],
     generate_simple_call(mercury_exception_module, PredName,
         pf_predicate, Mode, detism_cc_multi, purity_pure, Args, Features,
-        InstMapSrc, !.ModuleInfo, term.context_init, CallGoal0),
+        instmap_delta_bind_no_var, !.ModuleInfo, term.context_init,
+        CallGoal0),
 
     goal_info_init(GoalInfo),
 
@@ -892,7 +892,8 @@
 make_unreachable_call(ModuleInfo, Goal) :-
     generate_simple_call(mercury_exception_module, "unreachable",
         pf_predicate, only_mode, detism_erroneous, purity_pure,
-        [], [], [], ModuleInfo, term.context_init, Goal).
+        [], [], instmap_delta_bind_no_var, ModuleInfo, term.context_init,
+        Goal).
 
 :- pred make_output_tuple_inst_cast(prog_var::in, prog_var::in,
     list(mer_inst)::in, hlds_goal::out) is det.
Index: compiler/typecheck.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/typecheck.m,v
retrieving revision 1.441
diff -u -b -r1.441 typecheck.m
--- compiler/typecheck.m	19 Aug 2009 07:44:58 -0000	1.441
+++ compiler/typecheck.m	1 Sep 2009 00:53:22 -0000
@@ -116,6 +116,7 @@
 :- import_module hlds.hlds_goal.
 :- import_module hlds.hlds_pred.
 :- import_module hlds.hlds_rtti.
+:- import_module hlds.instmap.
 :- import_module hlds.passes_aux.
 :- import_module hlds.pred_table.
 :- import_module hlds.special_pred.
@@ -748,8 +749,8 @@
     ),
     pred_info_get_context(!.PredInfo, Context),
     generate_simple_call(mercury_private_builtin_module, CalleeName,
-        pf_predicate, only_mode, detism_det, purity_pure, [PredNameVar], [], [],
-        ModuleInfo, Context, CallGoal),
+        pf_predicate, only_mode, detism_det, purity_pure, [PredNameVar], [],
+        instmap_delta_bind_no_var, ModuleInfo, Context, CallGoal),
 
     % Combine the unification and call into a conjunction.
     goal_info_init(Context, GoalInfo),
Index: compiler/unify_proc.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/unify_proc.m,v
retrieving revision 1.206
diff -u -b -r1.206 unify_proc.m
--- compiler/unify_proc.m	19 Aug 2009 07:44:58 -0000	1.206
+++ compiler/unify_proc.m	1 Sep 2009 01:29:17 -0000
@@ -1529,12 +1529,10 @@
     goal_info_init(GoalInfo0),
     goal_info_set_context(Context, GoalInfo0, GoalInfo),
 
-    instmap_delta_from_assoc_list([X_Index - ground(shared, none)],
-        X_InstmapDelta),
+    X_InstmapDelta = instmap_delta_bind_var(X_Index),
     build_specific_call(Type, spec_pred_index, [X, X_Index],
         X_InstmapDelta, detism_det, Context, Call_X_Index, !Info),
-    instmap_delta_from_assoc_list([Y_Index - ground(shared, none)],
-        Y_InstmapDelta),
+    Y_InstmapDelta = instmap_delta_bind_var(Y_Index),
     build_specific_call(Type, spec_pred_index, [Y, Y_Index],
         Y_InstmapDelta, detism_det, Context, Call_Y_Index, !Info),
 
@@ -1811,8 +1809,8 @@
         MercuryBuiltin = mercury_private_builtin_module
     ),
     goal_util.generate_simple_call(MercuryBuiltin, Name, pf_predicate,
-        mode_no(0), detism_erroneous, purity_pure, ArgVars, [], [],
-        ModuleInfo, Context, Goal).
+        mode_no(0), detism_erroneous, purity_pure, ArgVars, [],
+        instmap_delta_bind_no_var, ModuleInfo, Context, Goal).
 
 :- pred build_specific_call(mer_type::in, special_pred_id::in,
     list(prog_var)::in, instmap_delta::in, determinism::in,
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing debian/patches
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.591
diff -u -b -r1.591 user_guide.texi
--- doc/user_guide.texi	23 Aug 2009 22:52:35 -0000	1.591
+++ doc/user_guide.texi	1 Sep 2009 16:21:44 -0000
@@ -8351,6 +8351,13 @@
 Remove excess assignment unifications.
 
 @sp 1
+ at item --no-optimize-format-calls
+ at findex --no-optimize-format-calls
+Do not attempt to interpret the format string in calls to
+string.format and related predicates at compile time;
+always leave this to be done at runtime.
+
+ at sp 1
 @item --optimize-duplicate-calls
 @findex --optimize-duplicate-calls
 @cindex Duplicate call optimization
cvs diff: Diffing extras
cvs diff: Diffing extras/base64
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/fixed
cvs diff: Diffing extras/gator
cvs diff: Diffing extras/gator/generations
cvs diff: Diffing extras/gator/generations/1
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/easyx
cvs diff: Diffing extras/graphics/easyx/samples
cvs diff: Diffing extras/graphics/mercury_allegro
cvs diff: Diffing extras/graphics/mercury_allegro/examples
cvs diff: Diffing extras/graphics/mercury_allegro/samples
cvs diff: Diffing extras/graphics/mercury_allegro/samples/demo
cvs diff: Diffing extras/graphics/mercury_allegro/samples/mandel
cvs diff: Diffing extras/graphics/mercury_allegro/samples/pendulum2
cvs diff: Diffing extras/graphics/mercury_allegro/samples/speed
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/log4m
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/mopenssl
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/net
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/posix/samples
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/solver_types
cvs diff: Diffing extras/solver_types/library
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing extras/windows_installer_generator
cvs diff: Diffing extras/windows_installer_generator/sample
cvs diff: Diffing extras/windows_installer_generator/sample/images
cvs diff: Diffing extras/xml
cvs diff: Diffing extras/xml/samples
cvs diff: Diffing extras/xml_stylesheets
cvs diff: Diffing java
cvs diff: Diffing java/runtime
cvs diff: Diffing library
cvs diff: Diffing mdbcomp
Index: mdbcomp/prim_data.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/mdbcomp/prim_data.m,v
retrieving revision 1.35
diff -u -b -r1.35 prim_data.m
--- mdbcomp/prim_data.m	11 Jun 2009 07:00:38 -0000	1.35
+++ mdbcomp/prim_data.m	1 Sep 2009 07:03:39 -0000
@@ -353,6 +353,10 @@
     %
 :- func mercury_string_module = sym_name.
 
+    % Returns the name of the I/O module.
+    %
+:- func mercury_io_module = sym_name.
+
     % Returns the sym_name of the module with the given name in the
     % Mercury standard library.
     %
@@ -573,6 +577,7 @@
 mercury_ssdb_builtin_module = unqualified("ssdb").
 mercury_list_module = unqualified("list").
 mercury_string_module = unqualified("string").
+mercury_io_module = unqualified("io").
 
 is_std_lib_module_name(ModuleName, Name) :-
     % -- not yet:
cvs diff: Diffing profiler
cvs diff: Diffing robdd
cvs diff: Diffing runtime
cvs diff: Diffing runtime/GETOPT
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/standalone_c
cvs diff: Diffing samples/diff
cvs diff: Diffing samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing samples/solver_types
cvs diff: Diffing samples/tests
cvs diff: Diffing samples/tests/c_interface
cvs diff: Diffing samples/tests/c_interface/c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/tests/c_interface/mercury_calls_c
cvs diff: Diffing samples/tests/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/tests/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/tests/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/tests/diff
cvs diff: Diffing samples/tests/muz
cvs diff: Diffing samples/tests/rot13
cvs diff: Diffing samples/tests/solutions
cvs diff: Diffing samples/tests/toplevel
cvs diff: Diffing scripts
cvs diff: Diffing slice
cvs diff: Diffing ssdb
cvs diff: Diffing tests
cvs diff: Diffing tests/analysis
cvs diff: Diffing tests/analysis/ctgc
cvs diff: Diffing tests/analysis/excp
cvs diff: Diffing tests/analysis/ext
cvs diff: Diffing tests/analysis/sharing
cvs diff: Diffing tests/analysis/table
cvs diff: Diffing tests/analysis/trail
cvs diff: Diffing tests/analysis/unused_args
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
cvs diff: Diffing tests/debugger/declarative
cvs diff: Diffing tests/dppd
cvs diff: Diffing tests/general
cvs diff: Diffing tests/general/accumulator
cvs diff: Diffing tests/general/string_format
Index: tests/general/string_format/string_format_lib.m
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/general/string_format/string_format_lib.m,v
retrieving revision 1.3
diff -u -b -r1.3 string_format_lib.m
--- tests/general/string_format/string_format_lib.m	30 Mar 2006 00:42:00 -0000	1.3
+++ tests/general/string_format/string_format_lib.m	1 Sep 2009 02:24:14 -0000
@@ -1,5 +1,8 @@
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%-----------------------------------------------------------------------------%
+
 :- module string_format_lib.
 
 :- interface.
@@ -8,21 +11,21 @@
 
 %-----------------------------------------------------------------------------%
 
-	% Given a specifier return all possible format strings for that
-	% specifier.
+    % Given a specifier return all possible format strings for that specifier.
+    %
 :- func format_strings(string) = list(string).
 
 	% Output each of the polytypes with the format string supplied.
-:- pred output_list(list(string__poly_type)::in, string::in,
+    %
+:- pred output_list(list(string.poly_type)::in, string::in,
         io::di, io::uo) is det.
 
-
-:- func standard_floats = list(string__poly_type).
-:- func trailing_zero_floats = list(string__poly_type).
-:- func rounding_floats = list(string__poly_type).
-:- func extreme_floats = list(string__poly_type).
-:- func denormal_floats = list(string__poly_type).
-:- func infinite_floats = list(string__poly_type).
+:- func standard_floats = list(string.poly_type).
+:- func trailing_zero_floats = list(string.poly_type).
+:- func rounding_floats = list(string.poly_type).
+:- func extreme_floats = list(string.poly_type).
+:- func denormal_floats = list(string.poly_type).
+:- func infinite_floats = list(string.poly_type).
 
 %-----------------------------------------------------------------------------%
 
@@ -42,14 +45,14 @@
 
 %-----------------------------------------------------------------------------%
 
-output_list(PolyTypes, FormatStr) -->
-	list__foldl(output_format(FormatStr), PolyTypes).
+output_list(PolyTypes, FormatStr, !IO) :-
+    list.foldl(output_format(FormatStr), PolyTypes, !IO).
 
-:- pred output_format(string::in, string__poly_type::in, io::di, io::uo) is det.
+:- pred output_format(string::in, string.poly_type::in, io::di, io::uo) is det.
 
-output_format(FormatStr, PolyType) -->
-	io__format("%10s:'" ++ FormatStr ++ "'", [s(FormatStr), PolyType]),
-	io__nl.
+output_format(FormatStr, PolyType, !IO) :-
+    io.format("%10s:'" ++ FormatStr ++ "'", [s(FormatStr), PolyType], !IO),
+    io.nl(!IO).
 
 %-----------------------------------------------------------------------------%
 
@@ -68,7 +71,7 @@
 :- func format_string(list(string), pair(maybe(string)), string) = string.
 		
 format_string(Flags, Width - Prec, Specifier) = Str :-
-	FlagsStr = string__append_list(Flags),
+    FlagsStr = string.append_list(Flags),
 	( Width = yes(WidthStr) ->
 		Str0 = WidthStr
 	;
@@ -107,7 +110,7 @@
 
 all_combinations(List, List).
 all_combinations(List, Combination) :-
-	list__delete(List, _, SubList),
+    list.delete(List, _, SubList),
 	all_combinations(SubList, Combination).
 
 :- pred width_and_prec(string::in, pair(maybe(string))::out) is nondet.
cvs diff: Diffing tests/general/structure_reuse
cvs diff: Diffing tests/grade_subdirs
cvs diff: Diffing tests/hard_coded
Index: tests/hard_coded/Mercury.options
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/hard_coded/Mercury.options,v
retrieving revision 1.39
diff -u -b -r1.39 Mercury.options
--- tests/hard_coded/Mercury.options	2 Jul 2009 05:31:08 -0000	1.39
+++ tests/hard_coded/Mercury.options	1 Sep 2009 07:38:46 -0000
@@ -40,6 +40,7 @@
 MCFLAGS-intermod_multimode =	--intermodule-optimization
 MCFLAGS-intermod_multimode_main = --intermodule-optimization
 MCFLAGS-lco_no_inline	    =	--optimize-constructor-last-call --no-inline-builtins
+MCFLAGS-opt_format          =	--optimize-format-calls
 MCFLAGS-reuse_ho            =	--ctgc --no-optimise-higher-order
 MCFLAGS-sharing_comb	    =	--ctgc --structure-sharing-widening 2
 MCFLAGS-simplify_multi_arm_switch = -O3
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.379
diff -u -b -r1.379 Mmakefile
--- tests/hard_coded/Mmakefile	26 Aug 2009 03:51:10 -0000	1.379
+++ tests/hard_coded/Mmakefile	1 Sep 2009 05:34:51 -0000
@@ -170,6 +170,7 @@
 	nullary_ho_func \
 	one_member \
 	opt_dup_bug \
+	opt_format \
 	ppc_bug \
 	pprint_test \
 	pprint_test2 \
Index: tests/hard_coded/opt_format.exp
===================================================================
RCS file: tests/hard_coded/opt_format.exp
diff -N tests/hard_coded/opt_format.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/opt_format.exp	1 Sep 2009 22:01:10 -0000
@@ -0,0 +1,8 @@
+abc_42_def_%x_ghi_HAL_jkl\
+cba_y_def_%143_ghi_IBM_jkl\
+cba_JCN_fed_%z_ghi_241_jkl\
+abc_343_def_%v_ghi_KDO_jkl\
+abc_42_def_%a_ghi_WHAL_jkl\
+cba_b_def_%143_ghi_WIBM_jkl\
+cba_WJCN_fed_%c_ghi_241_jkl\
+abc_343_def_%d_ghi_WKDO_jkl\
Index: tests/hard_coded/opt_format.m
===================================================================
RCS file: tests/hard_coded/opt_format.m
diff -N tests/hard_coded/opt_format.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/opt_format.m	1 Sep 2009 07:37:59 -0000
@@ -0,0 +1,92 @@
+%-----------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%-----------------------------------------------------------------------------%
+%
+% This test case is designed to test the correctness of the program
+% transformation performed by compiler/format_call.m and the associated
+% code in compiler/simplify.m.
+
+:- module opt_format.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module char.
+:- import_module int.
+:- import_module list.
+:- import_module string.
+
+main(!IO) :-	
+	io.write_string(test_string_format_1(42, 'x', "HAL"), !IO),
+	io.write_string(test_string_format_2(142, 'y', "IBM"), !IO),
+	io.write_string(test_string_format_2(242, 'z', "JCN"), !IO),
+	io.write_string(test_string_format_2(342, 'v', "KDO"), !IO),
+    test_io_format_1(42, 'a', "WHAL", !IO),
+    test_io_format_2(142, 'b', "WIBM", !IO),
+    test_io_format_2(242, 'c', "WJCN", !IO),
+    test_io_format_2(342, 'd', "WKDO", !IO).
+
+:- func test_string_format_1(int, char, string) = string.
+
+test_string_format_1(Int, Char, Str) =
+    string.format("abc_%d_def_%%%c_ghi_%s_jkl\\\n", [i(Int), c(Char), s(Str)]).
+
+:- func test_string_format_2(int, char, string) = string.
+
+test_string_format_2(Int, Char, Str) = Result :-
+    PolyStr = s(Str),
+    (
+        Int > 300
+    ->
+        Tail = [c(Char), PolyStr],
+        IntX = Int + 1,
+        Result = string.format("abc_%d_def_%%%c_ghi_%s_jkl\\\n",
+            [i(IntX) | Tail])
+    ;
+        Int > 200,
+        IntY = Int - 1,
+        FmtStr = "cba_%s_fed_%%%c_ghi_%d_jkl\\\n",
+        Values = [PolyStr, c(Char), i(IntY)]
+    ->
+        Result = string.format(FmtStr, Values)
+    ;
+        IntX = Int + 1,
+        Tail = [PolyStr],
+        Result = string.format("cba_%c_def_%%%d_ghi_%s_jkl\\\n",
+            [c(Char), i(IntX) | Tail])
+    ).
+
+:- pred test_io_format_1(int::in, char::in, string::in, io::di, io::uo) is det.
+
+test_io_format_1(Int, Char, Str, !IO) :-
+    io.format("abc_%d_def_%%%c_ghi_%s_jkl\\\n", [i(Int), c(Char), s(Str)], !IO).
+
+:- pred test_io_format_2(int::in, char::in, string::in, io::di, io::uo) is det.
+
+test_io_format_2(Int, Char, Str, !IO) :-
+    PolyStr = s(Str),
+    io.output_stream(OutStream, !IO),
+    (
+        Int > 300
+    ->
+        Tail = [c(Char), PolyStr],
+        IntX = Int + 1,
+        io.format("abc_%d_def_%%%c_ghi_%s_jkl\\\n", [i(IntX) | Tail], !IO)
+    ;
+        Int > 200,
+        IntY = Int - 1,
+        FmtStr = "cba_%s_fed_%%%c_ghi_%d_jkl\\\n",
+        Values = [PolyStr, c(Char), i(IntY)]
+    ->
+        io.format(FmtStr, Values, !IO)
+    ;
+        IntX = Int + 1,
+        Tail = [PolyStr],
+        io.format(OutStream, "cba_%c_def_%%%d_ghi_%s_jkl\\\n",
+            [c(Char), i(IntX) | Tail], !IO)
+    ).
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/purity
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/mmc_make
cvs diff: Diffing tests/mmc_make/lib
cvs diff: Diffing tests/par_conj
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/stm
cvs diff: Diffing tests/stm/orig
cvs diff: Diffing tests/stm/orig/stm-compiler
cvs diff: Diffing tests/stm/orig/stm-compiler/test1
cvs diff: Diffing tests/stm/orig/stm-compiler/test10
cvs diff: Diffing tests/stm/orig/stm-compiler/test2
cvs diff: Diffing tests/stm/orig/stm-compiler/test3
cvs diff: Diffing tests/stm/orig/stm-compiler/test4
cvs diff: Diffing tests/stm/orig/stm-compiler/test5
cvs diff: Diffing tests/stm/orig/stm-compiler/test6
cvs diff: Diffing tests/stm/orig/stm-compiler/test7
cvs diff: Diffing tests/stm/orig/stm-compiler/test8
cvs diff: Diffing tests/stm/orig/stm-compiler/test9
cvs diff: Diffing tests/stm/orig/stm-compiler-par
cvs diff: Diffing tests/stm/orig/stm-compiler-par/bm1
cvs diff: Diffing tests/stm/orig/stm-compiler-par/bm2
cvs diff: Diffing tests/stm/orig/stm-compiler-par/stmqueue
cvs diff: Diffing tests/stm/orig/stm-compiler-par/test1
cvs diff: Diffing tests/stm/orig/stm-compiler-par/test10
cvs diff: Diffing tests/stm/orig/stm-compiler-par/test11
cvs diff: Diffing tests/stm/orig/stm-compiler-par/test2
cvs diff: Diffing tests/stm/orig/stm-compiler-par/test3
cvs diff: Diffing tests/stm/orig/stm-compiler-par/test4
cvs diff: Diffing tests/stm/orig/stm-compiler-par/test5
cvs diff: Diffing tests/stm/orig/stm-compiler-par/test6
cvs diff: Diffing tests/stm/orig/stm-compiler-par/test7
cvs diff: Diffing tests/stm/orig/stm-compiler-par/test8
cvs diff: Diffing tests/stm/orig/stm-compiler-par/test9
cvs diff: Diffing tests/stm/orig/stm-compiler-par-asm_fast
cvs diff: Diffing tests/stm/orig/stm-compiler-par-asm_fast/test1
cvs diff: Diffing tests/stm/orig/stm-compiler-par-asm_fast/test2
cvs diff: Diffing tests/stm/orig/stm-compiler-par-asm_fast/test3
cvs diff: Diffing tests/stm/orig/stm-compiler-par-asm_fast/test4
cvs diff: Diffing tests/stm/orig/stm-compiler-par-asm_fast/test5
cvs diff: Diffing tests/stm/orig/stm-compiler-par-asm_fast/test6
cvs diff: Diffing tests/stm/orig/stm-compiler-par-asm_fast/test7
cvs diff: Diffing tests/stm/orig/stm-compiler-par-asm_fast/test8
cvs diff: Diffing tests/stm/orig/stm-compiler-par-asm_fast/test9
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/trailing
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
cvs diff: Diffing util
cvs diff: Diffing vim
cvs diff: Diffing vim/after
cvs diff: Diffing vim/ftplugin
cvs diff: Diffing vim/syntax
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list