[m-rev.] for review: conditional structure reuse for LLDS backends

Peter Wang novalazy at gmail.com
Wed Jan 30 16:05:24 AEDT 2008


[Pending bootchecks in more grades.]

Estimated hours taken: 15
Branches: main

Implement conditional structure reuse for LLDS backends using Boehm GC. 
Verify at run time, just before reusing a dead cell, that the base address of
the cell was dynamically allocated.  If not, fall back to allocating a new
object on the heap.  This makes structure reuse safe without having to disable
static data.

In the simple case, the generated C code looks like this:

    MR_tag_reuse_or_alloc_heap(dest, tag, addr_of_reuse_cell,
	MR_tag_alloc_heap(dest, tag, count));
    ...assign fields...

If some of the fields are known to already have the correct values then we can
avoid assigning them.  We need to handle both reuse and non-reuse cases:

    MR_tag_reuse_or_alloc_heap_flag(dest, flag_reg, tag, addr_of_reuse_cell,
	MR_tag_alloc_heap(dest, tag, count));
    /* flag_reg is non-zero iff reuse is possible */
    if (flag_reg) {
	goto skip;
    }
    ...assign fields which don't need to be assigned in reuse case...
  skip:
    ...assign fields which must be assigned in both cases...

It may be that it is not worth the branch to avoid assigning known fields.
I haven't yet checked.


compiler/llds.m:
	Extend the `incr_hp' instruction to holds information for structure
	reuse.

compiler/code_info.m:
	Generate a label and pass it to `var_locn_assign_cell_to_var'.  The
	label is only needed for the type of code shown above.

compiler/var_locn.m:
	Change the code generated for cell reuse.  Rather than assigning the
	dead cell's address to the target lval unconditionally, generate an
	`incr_hp' instruction with the reuse field filled in.

	Generate code that avoids filling in known fields if possible.

	Abort if we see `construct_statically(_)' in 
	`var_locn_assign_dynamic_cell_to_var'.

runtime/mercury_heap.h:
	Add a macro to check if an address is between
	`GC_least_plausible_heap_addr' and `GC_greatest_plausible_heap_addr',
	which are therefore in the heap.

	Add macros to conditionally reuse a cell or otherwise fall back to
	allocating a new object.

compiler/llds_out.m:
	Call the new macros in `mercury_heap.h' for `incr_hp' instructions
	with reuse information filled in.

compiler/dupelim.m:
compiler/dupproc.m:
compiler/exprn_aux.m:
compiler/global_data.m:
compiler/jumpopt.m:
compiler/livemap.m:
compiler/llds_to_x86_64.m:
compiler/middle_rec.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/reassign.m:
compiler/unify_gen.m:
compiler/use_local_vars.m:
	Conform to the changed `incr_hp' instruction.


Index: compiler/code_info.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/code_info.m,v
retrieving revision 1.358
diff -u -r1.358 code_info.m
--- compiler/code_info.m	29 Jan 2008 04:59:36 -0000	1.358
+++ compiler/code_info.m	30 Jan 2008 03:57:50 -0000
@@ -3677,12 +3677,13 @@
 
 assign_cell_to_var(Var, ReserveWordAtStart, Ptag, MaybeRvals, HowToConstruct,
         MaybeSize, FieldAddrs, TypeMsg, MayUseAtomic, Code, !CI) :-
+    get_next_label(Label, !CI),
     get_var_locn_info(!.CI, VarLocnInfo0),
     get_static_cell_info(!.CI, StaticCellInfo0),
     get_module_info(!.CI, ModuleInfo),
     var_locn_assign_cell_to_var(ModuleInfo, Var, ReserveWordAtStart, Ptag,
         MaybeRvals, HowToConstruct, MaybeSize, FieldAddrs, TypeMsg,
-        MayUseAtomic, Code, StaticCellInfo0, StaticCellInfo,
+        MayUseAtomic, Label, Code, StaticCellInfo0, StaticCellInfo,
         VarLocnInfo0, VarLocnInfo),
     set_static_cell_info(StaticCellInfo, !CI),
     set_var_locn_info(VarLocnInfo, !CI).
Index: compiler/dupelim.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/dupelim.m,v
retrieving revision 1.92
diff -u -r1.92 dupelim.m
--- compiler/dupelim.m	11 Oct 2007 11:45:17 -0000	1.92
+++ compiler/dupelim.m	30 Jan 2008 03:57:50 -0000
@@ -344,7 +344,7 @@
         Instr = restore_maxfr(Lval)
     ;
         Instr0 = incr_hp(Lval0, MaybeTag, MaybeOffset, Rval0, Msg,
-            MayUseAtomic, MaybeRegionRval0),
+            MayUseAtomic, MaybeRegionRval0, MaybeReuse0),
         standardize_lval(Lval0, Lval),
         standardize_rval(Rval0, Rval),
         (
@@ -355,8 +355,24 @@
             MaybeRegionRval0 = no,
             MaybeRegionRval = MaybeRegionRval0
         ),
+        (
+            MaybeReuse0 = llds_reuse(ReuseRval0, MaybeFlagLval0),
+            standardize_rval(ReuseRval0, ReuseRval),
+            (
+                MaybeFlagLval0 = yes(FlagLval0),
+                standardize_lval(FlagLval0, FlagLval),
+                MaybeFlagLval = yes(FlagLval)
+            ;
+                MaybeFlagLval0 = no,
+                MaybeFlagLval = no
+            ),
+            MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval)
+        ;
+            MaybeReuse0 = no_llds_reuse,
+            MaybeReuse = no_llds_reuse
+        ),
         Instr = incr_hp(Lval, MaybeTag, MaybeOffset, Rval, Msg,
-            MayUseAtomic, MaybeRegionRval)
+            MayUseAtomic, MaybeRegionRval, MaybeReuse)
     ;
         Instr0 = mark_hp(Lval0),
         standardize_lval(Lval0, Lval),
@@ -635,10 +651,10 @@
         )
     ;
         InstrA = incr_hp(LvalA, MaybeTag, MaybeOffset, RvalA, Msg,
-            MayUseAtomic, MaybeRegionRvalA),
+            MayUseAtomic, MaybeRegionRvalA, MaybeReuseA),
         (
             InstrB = incr_hp(LvalB, MaybeTag, MaybeOffset, RvalB, Msg,
-                MayUseAtomic, MaybeRegionRvalB),
+                MayUseAtomic, MaybeRegionRvalB, MaybeReuseB),
             most_specific_lval(LvalA, LvalB, Lval),
             most_specific_rval(RvalA, RvalB, Rval),
             (
@@ -650,10 +666,30 @@
                 MaybeRegionRvalA = no,
                 MaybeRegionRvalB = no,
                 MaybeRegionRval = no
+            ),
+            (
+                MaybeReuseA = llds_reuse(ReuseRvalA, MaybeFlagLvalA),
+                MaybeReuseB = llds_reuse(ReuseRvalB, MaybeFlagLvalB),
+                most_specific_rval(ReuseRvalA, ReuseRvalB, ReuseRval),
+                (
+                    MaybeFlagLvalA = yes(FlagLvalA),
+                    MaybeFlagLvalB = yes(FlagLvalB),
+                    most_specific_lval(FlagLvalA, FlagLvalB, FlagLval),
+                    MaybeFlagLval = yes(FlagLval)
+                ;
+                    MaybeFlagLvalA = no,
+                    MaybeFlagLvalB = no,
+                    MaybeFlagLval = no
+                ),
+                MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval)
+            ;
+                MaybeReuseA = no_llds_reuse,
+                MaybeReuseB = no_llds_reuse,
+                MaybeReuse = no_llds_reuse
             )
         ->
             MaybeInstr = yes(incr_hp(Lval, MaybeTag, MaybeOffset, Rval,
-                Msg, MayUseAtomic, MaybeRegionRval))
+                Msg, MayUseAtomic, MaybeRegionRval, MaybeReuse))
         ;
             MaybeInstr = no
         )
Index: compiler/dupproc.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/dupproc.m,v
retrieving revision 1.23
diff -u -r1.23 dupproc.m
--- compiler/dupproc.m	30 Dec 2007 08:23:37 -0000	1.23
+++ compiler/dupproc.m	30 Jan 2008 03:57:50 -0000
@@ -242,7 +242,7 @@
         ; Instr = arbitrary_c_code(_, _, _)
         ; Instr = save_maxfr(_)
         ; Instr = restore_maxfr(_)
-        ; Instr = incr_hp(_, _, _, _, _, _, _)
+        ; Instr = incr_hp(_, _, _, _, _, _, _, _)
         ; Instr = mark_hp(_)
         ; Instr = restore_hp(_)
         ; Instr = free_heap(_)
Index: compiler/exprn_aux.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/exprn_aux.m,v
retrieving revision 1.86
diff -u -r1.86 exprn_aux.m
--- compiler/exprn_aux.m	23 Nov 2007 07:35:01 -0000	1.86
+++ compiler/exprn_aux.m	30 Jan 2008 03:57:50 -0000
@@ -314,19 +314,35 @@
         Uinstr = restore_maxfr(Lval)
     ;
         Uinstr0 = incr_hp(Lval0, MaybeTag, MO, Rval0, TypeCtor,
-            MayUseAtomic, MaybeRegionRval0),
+            MayUseAtomic, MaybeRegionRval0, MaybeReuse0),
         Transform(Lval0, Lval, !Acc),
         transform_lval_in_rval(Transform, Rval0, Rval, !Acc),
         (
             MaybeRegionRval0 = no,
-            MaybeRegionRval = MaybeRegionRval0
+            MaybeRegionRval = no
         ;
             MaybeRegionRval0 = yes(RegionRval0),
             transform_lval_in_rval(Transform, RegionRval0, RegionRval, !Acc),
             MaybeRegionRval = yes(RegionRval)
         ),
+        (
+            MaybeReuse0 = no_llds_reuse,
+            MaybeReuse = no_llds_reuse
+        ;
+            MaybeReuse0 = llds_reuse(ReuseRval0, MaybeFlagLval0),
+            transform_lval_in_rval(Transform, ReuseRval0, ReuseRval, !Acc),
+            (
+                MaybeFlagLval0 = no,
+                MaybeFlagLval = no
+            ;
+                MaybeFlagLval0 = yes(FlagLval0),
+                Transform(FlagLval0, FlagLval, !Acc),
+                MaybeFlagLval = yes(FlagLval)
+            ),
+            MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval)
+        ),
         Uinstr = incr_hp(Lval, MaybeTag, MO, Rval, TypeCtor,
-            MayUseAtomic, MaybeRegionRval)
+            MayUseAtomic, MaybeRegionRval, MaybeReuse)
     ;
         Uinstr0 = mark_hp(Lval0),
         Transform(Lval0, Lval, !Acc),
Index: compiler/global_data.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/global_data.m,v
retrieving revision 1.35
diff -u -r1.35 global_data.m
--- compiler/global_data.m	11 Oct 2007 11:45:17 -0000	1.35
+++ compiler/global_data.m	30 Jan 2008 03:57:51 -0000
@@ -936,7 +936,7 @@
         Instr = restore_maxfr(Lval)
     ;
         Instr0 = incr_hp(Lval0, MaybeTag, MaybeOffset, SizeRval0, Prof,
-            Atomic, MaybeRegion0),
+            Atomic, MaybeRegion0, MaybeReuse0),
         Lval = remap_lval(Remap, Lval0),
         SizeRval = remap_rval(Remap, SizeRval0),
         (
@@ -947,8 +947,24 @@
             MaybeRegion0 = no,
             MaybeRegion = no
         ),
+        (
+            MaybeReuse0 = llds_reuse(Reuse0, MaybeFlag0),
+            Reuse = remap_rval(Remap, Reuse0),
+            (
+                MaybeFlag0 = yes(Flag0),
+                Flag = remap_lval(Remap, Flag0),
+                MaybeFlag = yes(Flag)
+            ;
+                MaybeFlag0 = no,
+                MaybeFlag = no
+            ),
+            MaybeReuse = llds_reuse(Reuse, MaybeFlag)
+        ;
+            MaybeReuse0 = no_llds_reuse,
+            MaybeReuse = no_llds_reuse
+        ),
         Instr = incr_hp(Lval, MaybeTag, MaybeOffset, SizeRval, Prof,
-            Atomic, MaybeRegion)
+            Atomic, MaybeRegion, MaybeReuse)
     ;
         Instr0 = mark_hp(Lval0),
         Lval = remap_lval(Remap, Lval0),
Index: compiler/jumpopt.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/jumpopt.m,v
retrieving revision 1.109
diff -u -r1.109 jumpopt.m
--- compiler/jumpopt.m	30 Dec 2007 08:23:44 -0000	1.109
+++ compiler/jumpopt.m	30 Jan 2008 03:57:51 -0000
@@ -828,7 +828,7 @@
         ; Uinstr0 = mark_ticket_stack(_)
         ; Uinstr0 = mark_hp(_)
         ; Uinstr0 = free_heap(_)
-        ; Uinstr0 = incr_hp(_, _, _, _, _, _, _)
+        ; Uinstr0 = incr_hp(_, _, _, _, _, _, _, _)
         ; Uinstr0 = restore_hp(_)
         ; Uinstr0 = init_sync_term(_, _)
         ),
Index: compiler/livemap.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/livemap.m,v
retrieving revision 1.91
diff -u -r1.91 livemap.m
--- compiler/livemap.m	30 Dec 2007 08:23:45 -0000	1.91
+++ compiler/livemap.m	30 Jan 2008 03:57:51 -0000
@@ -248,7 +248,8 @@
         Uinstr0 = restore_maxfr(Lval),
         livemap.make_live_in_rval(lval(Lval), !Livevals)
     ;
-        Uinstr0 = incr_hp(Lval, _, _, Rval, _, _, MaybeRegionRval),
+        Uinstr0 = incr_hp(Lval, _, _, SizeRval, _, _, MaybeRegionRval,
+            MaybeReuse),
 
         % Make dead the variable assigned, but make any variables
         % needed to access it live. Make the variables in the size
@@ -258,15 +259,29 @@
         % common. This is why doing the deletion first works.
 
         svset.delete(Lval, !Livevals),
-        opt_util.lval_access_rvals(Lval, Rvals0),
+        opt_util.lval_access_rvals(Lval, Rvals),
+        livemap.make_live_in_rvals(Rvals, !Livevals),
+        livemap.make_live_in_rval(SizeRval, !Livevals),
         (
-            MaybeRegionRval = no,
-            Rvals = [Rval | Rvals0]
+            MaybeRegionRval = no
         ;
             MaybeRegionRval = yes(RegionRval),
-            Rvals = [Rval, RegionRval | Rvals0]
+            livemap.make_live_in_rval(RegionRval, !Livevals)
         ),
-        livemap.make_live_in_rvals(Rvals, !Livevals)
+        (
+            MaybeReuse = no_llds_reuse
+        ;
+            MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval),
+            livemap.make_live_in_rval(ReuseRval, !Livevals),
+            (
+                MaybeFlagLval = no
+            ;
+                MaybeFlagLval = yes(FlagLval),
+                svset.delete(FlagLval, !Livevals),
+                opt_util.lval_access_rvals(FlagLval, FlagRvals),
+                livemap.make_live_in_rvals(FlagRvals, !Livevals)
+            )
+        )
     ;
         Uinstr0 = mark_hp(Lval),
         svset.delete(Lval, !Livevals),
Index: compiler/llds.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/llds.m,v
retrieving revision 1.358
diff -u -r1.358 llds.m
--- compiler/llds.m	23 Jan 2008 11:44:46 -0000	1.358
+++ compiler/llds.m	30 Jan 2008 03:57:51 -0000
@@ -326,9 +326,9 @@
             % lval was saved with save_maxfr.
 
     ;       incr_hp(lval, maybe(tag), maybe(int), rval, string,
-                may_use_atomic_alloc, maybe(rval))
+                may_use_atomic_alloc, maybe(rval), llds_reuse)
             % incr_hp(Target, MaybeTag, MaybeOffset, SizeRval, TypeMsg,
-            %   MayUseAtomicAlloc, MaybeRegionId)
+            %   MayUseAtomicAlloc, MaybeRegionId, MaybeReuse)
             %
             % Get a memory block of a size given by SizeRval and put its
             % address in Target, possibly after incrementing it by Offset words
@@ -339,7 +339,11 @@
             % of the Boehm gc allocator calls. If MaybeRegionId =
             % yes(RegionId), then the block should be allocated in the region
             % identified by RegionId (i.e. in the region whose header RegionId
-            % points to).
+            % points to). If MaybeReuse = llds_reuse(ReuseRval,
+            % MaybeFlagLval), then we should try to reuse the cell ReuseRval
+            % for the block. If MaybeFlagLval = yes(FlagLval) then FlagLval
+            % needs to be set to true or false indicate whether reuse was
+            % really possible.
 
     ;       mark_hp(lval)
             % Tell the heap sub-system to store a marker (for later use in
@@ -620,6 +624,14 @@
     --->    det_stack_proc
     ;       nondet_stack_proc.
 
+:- type llds_reuse
+    --->    no_llds_reuse
+    ;       llds_reuse(
+                rval,           % The cell to reuse.
+                maybe(lval)     % An optional lval to set to indicate
+                                % whether cell reuse was actually possible.
+            ).
+
     % Procedures defined by nondet pragma C codes must have some way of
     % preserving information after a success, so that when control
     % backtracks to the procedure, the C code knows what to do.
Index: compiler/llds_out.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/llds_out.m,v
retrieving revision 1.323
diff -u -r1.323 llds_out.m
--- compiler/llds_out.m	23 Jan 2008 11:44:46 -0000	1.323
+++ compiler/llds_out.m	30 Jan 2008 03:57:53 -0000
@@ -1959,8 +1959,8 @@
     output_lval_decls(Lval, !DeclSet, !IO).
 output_instr_decls(_, restore_maxfr(Lval), !DeclSet, !IO) :-
     output_lval_decls(Lval, !DeclSet, !IO).
-output_instr_decls(_, incr_hp(Lval, _Tag, _, Rval, _, _, MaybeRegionRval),
-        !DeclSet, !IO) :-
+output_instr_decls(_, incr_hp(Lval, _Tag, _, Rval, _, _, MaybeRegionRval,
+        MaybeReuse), !DeclSet, !IO) :-
     output_lval_decls(Lval, !DeclSet, !IO),
     output_rval_decls(Rval, !DeclSet, !IO),
     (
@@ -1968,6 +1968,18 @@
         output_rval_decls(RegionRval, !DeclSet, !IO)
     ;
         MaybeRegionRval = no
+    ),
+    (
+        MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval),
+        output_rval_decls(ReuseRval, !DeclSet, !IO),
+        (
+            MaybeFlagLval = yes(FlagLval),
+            output_lval_decls(FlagLval, !DeclSet, !IO)
+        ;
+            MaybeFlagLval = no
+        )
+    ;
+        MaybeReuse = no_llds_reuse
     ).
 output_instr_decls(_, mark_hp(Lval), !DeclSet, !IO) :-
     output_lval_decls(Lval, !DeclSet, !IO).
@@ -2418,136 +2430,54 @@
     output_lval(Lval, !IO),
     io.write_string(");\n", !IO).
 
-output_instruction(incr_hp(Lval, MaybeTag, MaybeOffset, Rval, TypeMsg,
-        MayUseAtomicAlloc, MaybeRegionRval), ProfInfo, !IO) :-
+output_instruction(incr_hp(Lval, MaybeTag, MaybeOffset, SizeRval, TypeMsg,
+        MayUseAtomicAlloc, MaybeRegionRval, MaybeReuse), ProfInfo, !IO) :-
+    io.write_string("\t", !IO),
     (
-        MaybeRegionRval = yes(RegionRval),
-        (
-            MaybeTag = no,
-            io.write_string("\tMR_alloc_in_region(", !IO),
-            output_lval_as_word(Lval, !IO)
-        ;
-            MaybeTag = yes(Tag),
-            io.write_string("\tMR_tag_alloc_in_region(", !IO),
-            output_lval_as_word(Lval, !IO),
-            io.write_string(", ", !IO),
-            output_tag(Tag, !IO)
-        ),
-        io.write_string(", ", !IO),
-        output_rval(RegionRval, !IO),
-        io.write_string(", ", !IO),
-        output_rval_as_type(Rval, word, !IO),
-        io.write_string(");\n", !IO)
+        MaybeReuse = no_llds_reuse,
+        output_incr_hp_no_reuse(Lval, MaybeTag, MaybeOffset, SizeRval,
+            TypeMsg, MayUseAtomicAlloc, MaybeRegionRval, ProfInfo, !IO)
     ;
-        MaybeRegionRval = no,
-        globals.io_lookup_bool_option(profile_memory, ProfMem, !IO),
+        MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval),
         (
-            ProfMem = yes,
+            MaybeTag = no,
             (
-                MaybeTag = no,
-                (
-                    MayUseAtomicAlloc = may_not_use_atomic_alloc,
-                    io.write_string("\tMR_offset_incr_hp_msg(", !IO)
-                ;
-                    MayUseAtomicAlloc = may_use_atomic_alloc,
-                    io.write_string("\tMR_offset_incr_hp_atomic_msg(", !IO)
-                ),
-                output_lval_as_word(Lval, !IO)
-            ;
-                MaybeTag = yes(Tag),
-                (
-                    MayUseAtomicAlloc = may_not_use_atomic_alloc,
-                    io.write_string("\tMR_tag_offset_incr_hp_msg(", !IO)
-                ;
-                    MayUseAtomicAlloc = may_use_atomic_alloc,
-                    io.write_string(
-                        "\tMR_tag_offset_incr_hp_atomic_msg(", !IO)
-                ),
+                MaybeFlagLval = yes(FlagLval),
+                io.write_string("MR_reuse_or_alloc_heap_flag(", !IO),
                 output_lval_as_word(Lval, !IO),
                 io.write_string(", ", !IO),
-                output_tag(Tag, !IO)
-            ),
-            io.write_string(", ", !IO),
-            (
-                MaybeOffset = no,
-                io.write_string("0, ", !IO)
+                output_lval_as_word(FlagLval, !IO)
             ;
-                MaybeOffset = yes(Offset),
-                io.write_int(Offset, !IO),
-                io.write_string(", ", !IO)
-            ),
-            output_rval_as_type(Rval, word, !IO),
-            io.write_string(", ", !IO),
-            ProfInfo = CallerLabel - _,
-            output_label(CallerLabel, !IO),
-            io.write_string(", """, !IO),
-            c_util.output_quoted_string(TypeMsg, !IO),
-            io.write_string(""");\n", !IO)
-        ;
-            ProfMem = no,
-            (
-                MaybeTag = no,
-                (
-                    MaybeOffset = yes(_),
-                    (
-                        MayUseAtomicAlloc = may_not_use_atomic_alloc,
-                        io.write_string("\tMR_offset_incr_hp(", !IO)
-                    ;
-                        MayUseAtomicAlloc = may_use_atomic_alloc,
-                        io.write_string("\tMR_offset_incr_hp_atomic(", !IO)
-                    )
-                ;
-                    MaybeOffset = no,
-                    (
-                        MayUseAtomicAlloc = may_not_use_atomic_alloc,
-                        io.write_string("\tMR_alloc_heap(", !IO)
-                    ;
-                        MayUseAtomicAlloc = may_use_atomic_alloc,
-                        io.write_string("\tMR_alloc_heap_atomic(", !IO)
-                    )
-                ),
+                MaybeFlagLval = no,
+                io.write_string("MR_reuse_or_alloc_heap(", !IO),
                 output_lval_as_word(Lval, !IO)
-            ;
-                MaybeTag = yes(Tag),
-                (
-                    MaybeOffset = yes(_),
-                    (
-                        MayUseAtomicAlloc = may_not_use_atomic_alloc,
-                        io.write_string("\tMR_tag_offset_incr_hp(", !IO)
-                    ;
-                        MayUseAtomicAlloc = may_use_atomic_alloc,
-                        io.write_string(
-                            "\tMR_tag_offset_incr_hp_atomic(", !IO)
-                    ),
-                    output_lval_as_word(Lval, !IO),
-                    io.write_string(", ", !IO),
-                    output_tag(Tag, !IO)
-                ;
-                    MaybeOffset = no,
-                    (
-                        MayUseAtomicAlloc = may_not_use_atomic_alloc,
-                        io.write_string("\tMR_tag_alloc_heap(", !IO)
-                    ;
-                        MayUseAtomicAlloc = may_use_atomic_alloc,
-                        io.write_string("\tMR_tag_alloc_heap_atomic(", !IO)
-                    ),
-                    output_lval_as_word(Lval, !IO),
-                    io.write_string(", ", !IO),
-                    io.write_int(Tag, !IO)
-                )
-            ),
-            io.write_string(", ", !IO),
+            )
+        ;
+            MaybeTag = yes(Tag),
             (
-                MaybeOffset = yes(Offset),
-                io.write_int(Offset, !IO),
-                io.write_string(", ", !IO)
+                MaybeFlagLval = yes(FlagLval),
+                io.write_string("MR_tag_reuse_or_alloc_heap_flag(", !IO),
+                output_lval_as_word(Lval, !IO),
+                io.write_string(", ", !IO),
+                output_tag(Tag, !IO),
+                io.write_string(", ", !IO),
+                output_lval_as_word(FlagLval, !IO)
             ;
-                MaybeOffset = no
-            ),
-            output_rval_as_type(Rval, word, !IO),
-            io.write_string(");\n", !IO)
-        )
-    ).
+                MaybeFlagLval = no,
+                io.write_string("MR_tag_reuse_or_alloc_heap(", !IO),
+                output_lval_as_word(Lval, !IO),
+                io.write_string(", ", !IO),
+                output_tag(Tag, !IO)
+            )
+        ),
+        io.write_string(", ", !IO),
+        output_rval(ReuseRval, !IO),
+        io.write_string(", ", !IO),
+        output_incr_hp_no_reuse(Lval, MaybeTag, MaybeOffset, SizeRval,
+            TypeMsg, MayUseAtomicAlloc, MaybeRegionRval, ProfInfo, !IO),
+        io.write_string(")", !IO)
+    ),
+    io.write_string(";\n", !IO).
 
 output_instruction(mark_hp(Lval), _, !IO) :-
     io.write_string("\tMR_mark_hp(", !IO),
@@ -2768,6 +2698,141 @@
     output_label_as_code_addr(Label, !IO),
     io.write_string(");\n", !IO).
 
+:- pred output_incr_hp_no_reuse(lval::in, maybe(tag)::in, maybe(int)::in,
+    rval::in, string::in, may_use_atomic_alloc::in, maybe(rval)::in,
+    pair(label, set_tree234(label))::in, io::di, io::uo) is det.
+
+output_incr_hp_no_reuse(Lval, MaybeTag, MaybeOffset, Rval, TypeMsg,
+        MayUseAtomicAlloc, MaybeRegionRval, ProfInfo, !IO) :-
+    (
+        MaybeRegionRval = yes(RegionRval),
+        (
+            MaybeTag = no,
+            io.write_string("MR_alloc_in_region(", !IO),
+            output_lval_as_word(Lval, !IO)
+        ;
+            MaybeTag = yes(Tag),
+            io.write_string("MR_tag_alloc_in_region(", !IO),
+            output_lval_as_word(Lval, !IO),
+            io.write_string(", ", !IO),
+            output_tag(Tag, !IO)
+        ),
+        io.write_string(", ", !IO),
+        output_rval(RegionRval, !IO),
+        io.write_string(", ", !IO),
+        output_rval_as_type(Rval, word, !IO),
+        io.write_string(")", !IO)
+    ;
+        MaybeRegionRval = no,
+        globals.io_lookup_bool_option(profile_memory, ProfMem, !IO),
+        (
+            ProfMem = yes,
+            (
+                MaybeTag = no,
+                (
+                    MayUseAtomicAlloc = may_not_use_atomic_alloc,
+                    io.write_string("MR_offset_incr_hp_msg(", !IO)
+                ;
+                    MayUseAtomicAlloc = may_use_atomic_alloc,
+                    io.write_string("MR_offset_incr_hp_atomic_msg(", !IO)
+                ),
+                output_lval_as_word(Lval, !IO)
+            ;
+                MaybeTag = yes(Tag),
+                (
+                    MayUseAtomicAlloc = may_not_use_atomic_alloc,
+                    io.write_string("MR_tag_offset_incr_hp_msg(", !IO)
+                ;
+                    MayUseAtomicAlloc = may_use_atomic_alloc,
+                    io.write_string(
+                        "MR_tag_offset_incr_hp_atomic_msg(", !IO)
+                ),
+                output_lval_as_word(Lval, !IO),
+                io.write_string(", ", !IO),
+                output_tag(Tag, !IO)
+            ),
+            io.write_string(", ", !IO),
+            (
+                MaybeOffset = no,
+                io.write_string("0, ", !IO)
+            ;
+                MaybeOffset = yes(Offset),
+                io.write_int(Offset, !IO),
+                io.write_string(", ", !IO)
+            ),
+            output_rval_as_type(Rval, word, !IO),
+            io.write_string(", ", !IO),
+            ProfInfo = CallerLabel - _,
+            output_label(CallerLabel, !IO),
+            io.write_string(", """, !IO),
+            c_util.output_quoted_string(TypeMsg, !IO),
+            io.write_string(""")", !IO)
+        ;
+            ProfMem = no,
+            (
+                MaybeTag = no,
+                (
+                    MaybeOffset = yes(_),
+                    (
+                        MayUseAtomicAlloc = may_not_use_atomic_alloc,
+                        io.write_string("MR_offset_incr_hp(", !IO)
+                    ;
+                        MayUseAtomicAlloc = may_use_atomic_alloc,
+                        io.write_string("MR_offset_incr_hp_atomic(", !IO)
+                    )
+                ;
+                    MaybeOffset = no,
+                    (
+                        MayUseAtomicAlloc = may_not_use_atomic_alloc,
+                        io.write_string("MR_alloc_heap(", !IO)
+                    ;
+                        MayUseAtomicAlloc = may_use_atomic_alloc,
+                        io.write_string("MR_alloc_heap_atomic(", !IO)
+                    )
+                ),
+                output_lval_as_word(Lval, !IO)
+            ;
+                MaybeTag = yes(Tag),
+                (
+                    MaybeOffset = yes(_),
+                    (
+                        MayUseAtomicAlloc = may_not_use_atomic_alloc,
+                        io.write_string("MR_tag_offset_incr_hp(", !IO)
+                    ;
+                        MayUseAtomicAlloc = may_use_atomic_alloc,
+                        io.write_string(
+                            "MR_tag_offset_incr_hp_atomic(", !IO)
+                    ),
+                    output_lval_as_word(Lval, !IO),
+                    io.write_string(", ", !IO),
+                    output_tag(Tag, !IO)
+                ;
+                    MaybeOffset = no,
+                    (
+                        MayUseAtomicAlloc = may_not_use_atomic_alloc,
+                        io.write_string("MR_tag_alloc_heap(", !IO)
+                    ;
+                        MayUseAtomicAlloc = may_use_atomic_alloc,
+                        io.write_string("MR_tag_alloc_heap_atomic(", !IO)
+                    ),
+                    output_lval_as_word(Lval, !IO),
+                    io.write_string(", ", !IO),
+                    io.write_int(Tag, !IO)
+                )
+            ),
+            io.write_string(", ", !IO),
+            (
+                MaybeOffset = yes(Offset),
+                io.write_int(Offset, !IO),
+                io.write_string(", ", !IO)
+            ;
+                MaybeOffset = no
+            ),
+            output_rval_as_type(Rval, word, !IO),
+            io.write_string(")", !IO)
+        )
+    ).
+
     % Our stacks grow upwards in that new stack frames have higher addresses
     % than old stack frames, but within in each stack frame, we compute the
     % address of stackvar N or framevar N by *subtracting* N from the address
Index: compiler/llds_to_x86_64.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/llds_to_x86_64.m,v
retrieving revision 1.10
diff -u -r1.10 llds_to_x86_64.m
--- compiler/llds_to_x86_64.m	30 Dec 2007 08:23:47 -0000	1.10
+++ compiler/llds_to_x86_64.m	30 Jan 2008 03:57:53 -0000
@@ -323,13 +323,20 @@
 instr_to_x86_64(!RegMap, restore_maxfr(_), Instr) :-
     Instr = [x86_64_comment("<<restore_maxfr>>")].
 instr_to_x86_64(!RegMap,
-        incr_hp(Lval, Tag0, Words0, Rval, _, _, MaybeRegionRval), Instrs) :-
+        incr_hp(Lval, Tag0, Words0, Rval, _, _, MaybeRegionRval,
+            MaybeReuse), Instrs) :-
     (
         MaybeRegionRval = no
     ;
         MaybeRegionRval = yes(_),
         unexpected(this_file, "instr_to_x86_64: encounter a region variable")
     ),
+    (
+        MaybeReuse = no_llds_reuse
+    ;
+        MaybeReuse = llds_reuse(_, _),
+        unexpected(this_file, "instr_to_x86_64: encounter a reuse variable")
+    ),
     transform_rval(!RegMap, Rval, Res0, Res1),
     transform_lval(!RegMap, Lval, Res2, Res3),
     (
Index: compiler/middle_rec.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/middle_rec.m,v
retrieving revision 1.133
diff -u -r1.133 middle_rec.m
--- compiler/middle_rec.m	30 Dec 2007 08:23:48 -0000	1.133
+++ compiler/middle_rec.m	30 Jan 2008 03:57:53 -0000
@@ -525,8 +525,8 @@
     find_used_registers_lval(Lval, !Used).
 find_used_registers_instr(restore_maxfr(Lval), !Used) :-
     find_used_registers_lval(Lval, !Used).
-find_used_registers_instr(incr_hp(Lval, _, _, Rval, _, _, MaybeRegionRval),
-        !Used) :-
+find_used_registers_instr(incr_hp(Lval, _, _, Rval, _, _, MaybeRegionRval,
+        MaybeReuse), !Used) :-
     find_used_registers_lval(Lval, !Used),
     find_used_registers_rval(Rval, !Used),
     (
@@ -534,6 +534,18 @@
         find_used_registers_rval(RegionRval, !Used)
     ;
         MaybeRegionRval = no
+    ),
+    (
+        MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval),
+        find_used_registers_rval(ReuseRval, !Used),
+        (
+            MaybeFlagLval = yes(FlagLval),
+            find_used_registers_lval(FlagLval, !Used)
+        ;
+            MaybeFlagLval = no
+        )
+    ;
+        MaybeReuse = no_llds_reuse
     ).
 find_used_registers_instr(mark_hp(Lval), !Used) :-
     find_used_registers_lval(Lval, !Used).
Index: compiler/opt_debug.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/opt_debug.m,v
retrieving revision 1.204
diff -u -r1.204 opt_debug.m
--- compiler/opt_debug.m	23 Jan 2008 11:44:46 -0000	1.204
+++ compiler/opt_debug.m	30 Jan 2008 03:57:53 -0000
@@ -793,7 +793,7 @@
         Str = "restore_maxfr(" ++ dump_lval(yes(ProcLabel), Lval) ++ ")"
     ;
         Instr = incr_hp(Lval, MaybeTag, MaybeOffset, Size, _, MayUseAtomic,
-            MaybeRegionRval),
+            MaybeRegionRval, MaybeReuse),
         (
             MaybeTag = no,
             T_str = "no"
@@ -815,10 +815,27 @@
             MaybeRegionRval = yes(RegionRval),
             Region_str = dump_rval(no, RegionRval) 
         ),
+        (
+            MaybeReuse = no_llds_reuse,
+            Reuse_str = "no",
+            Flag_str = "no"
+        ;
+            MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval),
+            Reuse_str = dump_rval(no, ReuseRval),
+            (
+                MaybeFlagLval = no,
+                Flag_str = "no"
+            ;
+                MaybeFlagLval = yes(FlagLval),
+                Flag_str = dump_lval(yes(ProcLabel), FlagLval)
+            )
+        ),
         Str = "incr_hp(" ++ dump_lval(yes(ProcLabel), Lval) ++ ", " ++
             T_str ++ ", " ++ O_str ++ ", " ++
             dump_rval(yes(ProcLabel), Size) ++ ", " ++
-            dump_may_use_atomic(MayUseAtomic) ++ ", " ++ Region_str ++ ")"
+            dump_may_use_atomic(MayUseAtomic) ++ ", " ++
+            Region_str ++ ", " ++
+            Reuse_str ++ ", " ++ Flag_str ++ ")"
     ;
         Instr = mark_hp(Lval),
         Str = "mark_hp(" ++ dump_lval(yes(ProcLabel), Lval) ++ ")"
Index: compiler/opt_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/opt_util.m,v
retrieving revision 1.168
diff -u -r1.168 opt_util.m
--- compiler/opt_util.m	30 Dec 2007 08:23:52 -0000	1.168
+++ compiler/opt_util.m	30 Jan 2008 03:57:54 -0000
@@ -685,7 +685,7 @@
             ( Uinstr = comment(_)
             ; Uinstr = livevals(_)
             ; Uinstr = if_val(_, _)
-            ; Uinstr = incr_hp(_, _, _, _, _, _, _)
+            ; Uinstr = incr_hp(_, _, _, _, _, _, _, _)
             ; Uinstr = mark_hp(_)
             ; Uinstr = restore_hp(_)
             ; Uinstr = free_heap(_)
@@ -815,7 +815,8 @@
             Between = [Instr0 | Between0]
         )
     ;
-        Uinstr0 = incr_hp(Lval, _, _, Rval, _, _, MaybeRegionRval),
+        Uinstr0 = incr_hp(Lval, _, _, Rval, _, _, MaybeRegionRval,
+            MaybeReuse),
         lval_refers_stackvars(Lval) = no,
         rval_refers_stackvars(Rval) = no,
         (
@@ -824,6 +825,18 @@
         ;
             MaybeRegionRval = no
         ),
+        (
+            MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval),
+            rval_refers_stackvars(ReuseRval) = no,
+            (
+                MaybeFlagLval = yes(FlagLval),
+                lval_refers_stackvars(FlagLval) = no
+            ;
+                MaybeFlagLval = no
+            )
+        ;
+            MaybeReuse = no_llds_reuse
+        ),
         no_stackvars_til_decr_sp(Instrs0, FrameSize, Between0, Remain),
         Between = [Instr0 | Between0]
     ;
@@ -904,16 +917,31 @@
         Uinstr = restore_maxfr(Lval),
         Refers = lval_refers_stackvars(Lval)
     ;
-        Uinstr = incr_hp(Lval, _, _, Rval, _, _, MaybeRegionRval),
-        Refers0 = bool.or(
-            lval_refers_stackvars(Lval),
-            rval_refers_stackvars(Rval)),
-        (
-            MaybeRegionRval = no,
-            Refers = Refers0
-        ;
-            MaybeRegionRval = yes(RegionRval),
-            Refers = bool.or(Refers0, rval_refers_stackvars(RegionRval))
+        Uinstr = incr_hp(Lval, _, _, Rval, _, _, MaybeRegionRval,
+            MaybeReuse),
+        some [!Refers] (
+            !:Refers = bool.or(
+                lval_refers_stackvars(Lval),
+                rval_refers_stackvars(Rval)),
+            (
+                MaybeRegionRval = yes(RegionRval),
+                bool.or(rval_refers_stackvars(RegionRval), !Refers)
+            ;
+                MaybeRegionRval = no
+            ),
+            (
+                MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval),
+                bool.or(rval_refers_stackvars(ReuseRval), !Refers),
+                (
+                    MaybeFlagLval = yes(FlagLval),
+                    bool.or(lval_refers_stackvars(FlagLval), !Refers)
+                ;
+                    MaybeFlagLval = no
+                )
+            ;
+                MaybeReuse = no_llds_reuse
+            ),
+            Refers = !.Refers
         )
     ;
         Uinstr = mark_hp(Lval),
@@ -1063,7 +1091,7 @@
 can_instr_branch_away(if_val(_, _)) = yes.
 can_instr_branch_away(save_maxfr(_)) = no.
 can_instr_branch_away(restore_maxfr(_)) = no.
-can_instr_branch_away(incr_hp(_, _, _, _, _, _, _)) = no.
+can_instr_branch_away(incr_hp(_, _, _, _, _, _, _, _)) = no.
 can_instr_branch_away(mark_hp(_)) = no.
 can_instr_branch_away(restore_hp(_)) = no.
 can_instr_branch_away(free_heap(_)) = no.
@@ -1142,7 +1170,7 @@
 can_instr_fall_through(if_val(_, _)) = yes.
 can_instr_fall_through(save_maxfr(_)) = yes.
 can_instr_fall_through(restore_maxfr(_)) = yes.
-can_instr_fall_through(incr_hp(_, _, _, _, _, _, _)) = yes.
+can_instr_fall_through(incr_hp(_, _, _, _, _, _, _, _)) = yes.
 can_instr_fall_through(mark_hp(_)) = yes.
 can_instr_fall_through(restore_hp(_)) = yes.
 can_instr_fall_through(free_heap(_)) = yes.
@@ -1193,7 +1221,7 @@
 can_use_livevals(if_val(_, _), yes).
 can_use_livevals(save_maxfr(_), no).
 can_use_livevals(restore_maxfr(_), no).
-can_use_livevals(incr_hp(_, _, _, _, _, _, _), no).
+can_use_livevals(incr_hp(_, _, _, _, _, _, _, _), no).
 can_use_livevals(mark_hp(_), no).
 can_use_livevals(restore_hp(_), no).
 can_use_livevals(free_heap(_), no).
@@ -1263,7 +1291,7 @@
 instr_labels_2(if_val(_, Addr), [], [Addr]).
 instr_labels_2(save_maxfr(_), [], []).
 instr_labels_2(restore_maxfr(_), [], []).
-instr_labels_2(incr_hp(_, _, _, _, _, _, _), [], []).
+instr_labels_2(incr_hp(_, _, _, _, _, _, _, _), [], []).
 instr_labels_2(mark_hp(_), [], []).
 instr_labels_2(restore_hp(_), [], []).
 instr_labels_2(free_heap(_), [], []).
@@ -1331,7 +1359,7 @@
     ).
 possible_targets(save_maxfr(_), [], []).
 possible_targets(restore_maxfr(_), [], []).
-possible_targets(incr_hp(_, _, _, _, _, _, _), [], []).
+possible_targets(incr_hp(_, _, _, _, _, _, _, _), [], []).
 possible_targets(mark_hp(_), [], []).
 possible_targets(restore_hp(_), [], []).
 possible_targets(free_heap(_), [], []).
@@ -1422,14 +1450,31 @@
 instr_rvals_and_lvals(if_val(Rval, _), [Rval], []).
 instr_rvals_and_lvals(save_maxfr(Lval), [], [Lval]).
 instr_rvals_and_lvals(restore_maxfr(Lval), [], [Lval]).
-instr_rvals_and_lvals(incr_hp(Lval, _, _, Rval, _, _, MaybeRegionRval),
-        Rvals, [Lval]) :-
-    (
-        MaybeRegionRval = yes(RegionRval),
-        Rvals = [Rval, RegionRval]
-    ;
-        MaybeRegionRval = no,
-        Rvals = [Rval]
+instr_rvals_and_lvals(incr_hp(Lval, _, _, SizeRval, _, _, MaybeRegionRval,
+        MaybeReuse), Rvals, Lvals) :-
+    some [!Rvals, !Lvals] (
+        !:Rvals = [SizeRval],
+        !:Lvals = [Lval],
+        (
+            MaybeRegionRval = yes(RegionRval),
+            !:Rvals = [RegionRval | !.Rvals]
+        ;
+            MaybeRegionRval = no
+        ),
+        (
+            MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval),
+            !:Rvals = [ReuseRval | !.Rvals],
+            (
+                MaybeFlagLval = yes(FlagLval),
+                !:Lvals = [FlagLval | !.Lvals]
+            ;
+                MaybeFlagLval = no
+            )
+        ;
+            MaybeReuse = no_llds_reuse
+        ),
+        Rvals = !.Rvals,
+        Lvals = !.Lvals
     ).
 instr_rvals_and_lvals(mark_hp(Lval), [], [Lval]).
 instr_rvals_and_lvals(restore_hp(Rval), [Rval], []).
@@ -1579,7 +1624,8 @@
     count_temps_lval(Lval, !R, !F).
 count_temps_instr(restore_maxfr(Lval), !R, !F) :-
     count_temps_lval(Lval, !R, !F).
-count_temps_instr(incr_hp(Lval, _, _, Rval, _, _, MaybeRegionRval), !R, !F) :-
+count_temps_instr(incr_hp(Lval, _, _, Rval, _, _, MaybeRegionRval,
+        MaybeReuse), !R, !F) :-
     count_temps_lval(Lval, !R, !F),
     count_temps_rval(Rval, !R, !F),
     (
@@ -1587,6 +1633,18 @@
         count_temps_rval(RegionRval, !R, !F)
     ;
         MaybeRegionRval = no
+    ),
+    (
+        MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval),
+        count_temps_rval(ReuseRval, !R, !F),
+        (
+            MaybeFlagLval = yes(FlagLval),
+            count_temps_lval(FlagLval, !R, !F)
+        ;
+            MaybeFlagLval = no
+        )
+    ;
+        MaybeReuse = no_llds_reuse
     ).
 count_temps_instr(mark_hp(Lval), !R, !F) :-
     count_temps_lval(Lval, !R, !F).
@@ -1845,16 +1903,31 @@
         TouchRval = touches_nondet_ctrl_rval(Rval),
         bool.or(TouchLval, TouchRval, Touch)
     ;
-        Uinstr = incr_hp(Lval, _, _, Rval, _, _, MaybeRegionRval),
-        Touch0 = bool.or(
-            touches_nondet_ctrl_lval(Lval),
-            touches_nondet_ctrl_rval(Rval)),
-        (
-            MaybeRegionRval = yes(RegionRval),
-            Touch = bool.or(Touch0, touches_nondet_ctrl_rval(RegionRval))
-        ;
-            MaybeRegionRval = no,
-            Touch = Touch0
+        Uinstr = incr_hp(Lval, _, _, Rval, _, _, MaybeRegionRval,
+            MaybeReuse),
+        some [!Touch] (
+            !:Touch = bool.or(
+                touches_nondet_ctrl_lval(Lval),
+                touches_nondet_ctrl_rval(Rval)),
+            (
+                MaybeRegionRval = yes(RegionRval),
+                bool.or(touches_nondet_ctrl_rval(RegionRval), !Touch)
+            ;
+                MaybeRegionRval = no
+            ),
+            (
+                MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval),
+                bool.or(touches_nondet_ctrl_rval(ReuseRval), !Touch),
+                (
+                    MaybeFlagLval = yes(FlagLval),
+                    bool.or(touches_nondet_ctrl_lval(FlagLval), !Touch)
+                ;
+                    MaybeFlagLval = no
+                )
+            ;
+                MaybeReuse = no_llds_reuse
+            ),
+            Touch = !.Touch
         )
     ;
         Uinstr = mark_hp(Lval),
@@ -2028,7 +2101,7 @@
 
 count_incr_hp_2([], !N).
 count_incr_hp_2([llds_instr(Uinstr0, _) | Instrs], !N) :-
-    ( Uinstr0 = incr_hp(_, _, _, _, _, _, _) ->
+    ( Uinstr0 = incr_hp(_, _, _, _, _, _, _, _) ->
         !:N = !.N + 1
     ;
         true
@@ -2221,7 +2294,7 @@
         Uinstr = restore_maxfr(Lval)
     ;
         Uinstr0 = incr_hp(Lval0, MaybeTag, MO, Rval0, Msg, Atomic,
-            MaybeRegionRval0),
+            MaybeRegionRval0, MaybeReuse0),
         (
             ReplData = yes,
             replace_labels_lval(Lval0, Lval, ReplMap),
@@ -2233,15 +2306,32 @@
             ;
                 MaybeRegionRval0 = no,
                 MaybeRegionRval = MaybeRegionRval0
+            ),
+            (
+                MaybeReuse0 = llds_reuse(ReuseRval0, MaybeFlagLval0),
+                replace_labels_rval(ReuseRval0, ReuseRval, ReplMap),
+                (
+                    MaybeFlagLval0 = yes(FlagLval0),
+                    replace_labels_lval(FlagLval0, FlagLval, ReplMap),
+                    MaybeFlagLval = yes(FlagLval)
+                ;
+                    MaybeFlagLval0 = no,
+                    MaybeFlagLval = no
+                ),
+                MaybeReuse = llds_reuse(ReuseRval, MaybeFlagLval)
+            ;
+                MaybeReuse0 = no_llds_reuse,
+                MaybeReuse = no_llds_reuse
             )
         ;
             ReplData = no,
             Lval = Lval0,
             Rval = Rval0,
-            MaybeRegionRval = MaybeRegionRval0
+            MaybeRegionRval = MaybeRegionRval0,
+            MaybeReuse = MaybeReuse0
         ),
         Uinstr = incr_hp(Lval, MaybeTag, MO, Rval, Msg, Atomic,
-            MaybeRegionRval)
+            MaybeRegionRval, MaybeReuse)
     ;
         Uinstr0 = mark_hp(Lval0),
         (
Index: compiler/reassign.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/reassign.m,v
retrieving revision 1.26
diff -u -r1.26 reassign.m
--- compiler/reassign.m	11 Oct 2007 11:45:20 -0000	1.26
+++ compiler/reassign.m	30 Jan 2008 03:57:54 -0000
@@ -225,7 +225,7 @@
         !:RevInstrs = [Instr0 | !.RevInstrs],
         clobber_dependents(hp, !KnownContentsMap, !DepLvalMap)
     ;
-        Uinstr0 = incr_hp(Target, _, _, _, _, _, _),
+        Uinstr0 = incr_hp(Target, _, _, _, _, _, _, _),
         !:RevInstrs = [Instr0 | !.RevInstrs],
         clobber_dependents(Target, !KnownContentsMap, !DepLvalMap),
         clobber_dependents(hp, !KnownContentsMap, !DepLvalMap)
Index: compiler/unify_gen.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/unify_gen.m,v
retrieving revision 1.186
diff -u -r1.186 unify_gen.m
--- compiler/unify_gen.m	30 Dec 2007 08:24:01 -0000	1.186
+++ compiler/unify_gen.m	30 Jan 2008 03:57:54 -0000
@@ -662,7 +662,7 @@
                     "get number of arguments"),
                 llds_instr(incr_hp(NewClosure, no, no,
                     binop(int_add, lval(NumOldArgs), NumNewArgsPlusThree_Rval),
-                    "closure", NewClosureMayUseAtomic, no),
+                    "closure", NewClosureMayUseAtomic, no, no_llds_reuse),
                     "allocate new closure"),
                 llds_instr(assign(field(yes(0), lval(NewClosure), Zero),
                     lval(field(yes(0), OldClosure, Zero))),
Index: compiler/use_local_vars.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/use_local_vars.m,v
retrieving revision 1.37
diff -u -r1.37 use_local_vars.m
--- compiler/use_local_vars.m	23 Nov 2007 07:35:32 -0000	1.37
+++ compiler/use_local_vars.m	30 Jan 2008 03:57:56 -0000
@@ -178,7 +178,7 @@
                 Uinstr0 = assign(ToLval, _FromRval)
             ;
                 Uinstr0 = incr_hp(ToLval, _MaybeTag, _SizeRval, _MO, _Type,
-                    _Atomic, _)
+                    _Atomic, _, _)
             ),
             base_lval_worth_replacing(NumRealRRegs, ToLval),
             MaybeMore = no
@@ -484,11 +484,11 @@
             this_file, "substitute_lval_in_defn: mismatch in assign"),
         Uinstr = assign(NewLval, FromRval)
     ; Uinstr0 = incr_hp(ToLval, MaybeTag, SizeRval, MO, Type,
-            MayUseAtomic, MaybeRegionRval) ->
+            MayUseAtomic, MaybeRegionRval, MaybeReuse) ->
         expect(unify(ToLval, OldLval),
             this_file, "substitute_lval_in_defn: mismatch in incr_hp"),
         Uinstr = incr_hp(NewLval, MaybeTag, SizeRval, MO, Type,
-            MayUseAtomic, MaybeRegionRval)
+            MayUseAtomic, MaybeRegionRval, MaybeReuse)
     ; Uinstr0 = foreign_proc_code(D, Comps0, MCM, FNL, FL, FOL, NF, S, MD) ->
         substitute_lval_in_defn_components(OldLval, NewLval, Comps0, Comps,
             0, NumSubsts),
@@ -605,7 +605,7 @@
         Uinstr0 = keep_assign(_, _),
         exprn_aux.substitute_lval_in_instr(OldLval, NewLval, !Instr, !N)
     ;
-        ( Uinstr0 = incr_hp(Lval, _, _, _, _, _, _)
+        ( Uinstr0 = incr_hp(Lval, _, _, _, _, _, _, _)
         ; Uinstr0 = save_maxfr(Lval)
         ; Uinstr0 = mark_hp(Lval)
         ),
Index: compiler/var_locn.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/var_locn.m,v
retrieving revision 1.57
diff -u -r1.57 var_locn.m
--- compiler/var_locn.m	29 Jan 2008 04:59:45 -0000	1.57
+++ compiler/var_locn.m	30 Jan 2008 03:57:56 -0000
@@ -167,7 +167,7 @@
     var_locn_info::in, var_locn_info::out) is det.
 
     % var_locn_assign_cell_to_var(ModuleInfo, Var, ReserveWordAtStart, Ptag,
-    %   MaybeRvals, MaybeSize, FieldAddrs, TypeMsg, MayUseAtomic, Code,
+    %   MaybeRvals, MaybeSize, FieldAddrs, TypeMsg, MayUseAtomic, Label, Code,
     %   !StaticCellInfo, !VarLocnInfo):
     %
     % Generates code to assign to Var a pointer, tagged by Ptag, to the cell
@@ -180,12 +180,12 @@
     % of whether it is allocated statically or dynamically), and initialize
     % this word with the value determined by SizeVal. (NOTE: ReserveWordAtStart
     % and MaybeSize should not be yes / yes(_), because that will cause an
-    % obvious conflict.)
+    % obvious conflict.) Label can be used in the generated code if necessary.
     %
 :- pred var_locn_assign_cell_to_var(module_info::in, prog_var::in, bool::in,
     tag::in, list(maybe(rval))::in, how_to_construct::in,
     maybe(term_size_value)::in, list(int)::in, string::in,
-    may_use_atomic_alloc::in, code_tree::out,
+    may_use_atomic_alloc::in, label::in, code_tree::out,
     static_cell_info::in, static_cell_info::out,
     var_locn_info::in, var_locn_info::out) is det.
 
@@ -811,7 +811,7 @@
 
 var_locn_assign_cell_to_var(ModuleInfo, Var, ReserveWordAtStart, Ptag,
         MaybeRvals0, HowToConstruct, MaybeSize, FieldAddrs, TypeMsg,
-        MayUseAtomic, Code, !StaticCellInfo, !VLI) :-
+        MayUseAtomic, Label, Code, !StaticCellInfo, !VLI) :-
     (
         MaybeSize = yes(SizeSource),
         (
@@ -846,17 +846,17 @@
     ;
         var_locn_assign_dynamic_cell_to_var(ModuleInfo, Var,
             ReserveWordAtStart, Ptag, MaybeRvals, HowToConstruct,
-            MaybeOffset, TypeMsg, MayUseAtomic, Code, !VLI)
+            MaybeOffset, TypeMsg, MayUseAtomic, Label, Code, !VLI)
     ).
 
 :- pred var_locn_assign_dynamic_cell_to_var(module_info::in, prog_var::in,
     bool::in, tag::in, list(maybe(rval))::in, how_to_construct::in,
-    maybe(int)::in, string::in, may_use_atomic_alloc::in, code_tree::out,
-    var_locn_info::in, var_locn_info::out) is det.
+    maybe(int)::in, string::in, may_use_atomic_alloc::in, label::in,
+    code_tree::out, var_locn_info::in, var_locn_info::out) is det.
 
 var_locn_assign_dynamic_cell_to_var(ModuleInfo, Var, ReserveWordAtStart, Ptag,
-        Vector, HowToConstruct, MaybeOffset, TypeMsg, MayUseAtomic, Code,
-        !VLI) :-
+        Vector, HowToConstruct, MaybeOffset, TypeMsg, MayUseAtomic, Label,
+        Code, !VLI) :-
     check_var_is_unknown(!.VLI, Var),
 
     select_preferred_reg_or_stack_check(!.VLI, Var, Lval),
@@ -879,138 +879,219 @@
         TotalOffset = MaybeOffset,
         TotalSize = Size
     ),
-    % This must appear before the call to `save_reused_cell_fields', otherwise
-    % `save_reused_cell_fields' won't know not to use Lval as a temporary
-    % register (if Lval is a register).
-    var_locn_set_magic_var_location(Var, Lval, !VLI),
     (
-        HowToConstruct = construct_in_region(RegionVar),
-        var_locn_produce_var(ModuleInfo, RegionVar, RegionRval,
-            RegionVarCode, !VLI),
-        MaybeRegionRval = yes(RegionRval),
-        LldsComment = "Allocating region for ",
-        CellCode = node([
-            llds_instr(
-                incr_hp(Lval, yes(Ptag), TotalOffset,
-                    const(llconst_int(TotalSize)), TypeMsg, MayUseAtomic,
-                    MaybeRegionRval), LldsComment ++ VarName)
-        ]),
-        SetupReuseCode = empty,
-        TempRegs = []
+        MaybeOffset = yes(Offset),
+        StartOffset = -Offset
     ;
-        % XXX  We should probably throw an exception if we find
-        % construct_statically here.
-        ( HowToConstruct = construct_statically(_)
-        ; HowToConstruct = construct_dynamically
+        MaybeOffset = no,
+        StartOffset = 0
+    ),
+    % This must appear before the call to `save_reused_cell_fields' in the
+    % reused_cell case, otherwise `save_reused_cell_fields' won't know not to
+    % use Lval as a temporary register (if Lval is a register).
+    var_locn_set_magic_var_location(Var, Lval, !VLI),
+    (
+        (
+            HowToConstruct = construct_in_region(RegionVar),
+            var_locn_produce_var(ModuleInfo, RegionVar, RegionRval,
+                RegionVarCode, !VLI),
+            MaybeRegionRval = yes(RegionRval),
+            MaybeReuse = no_llds_reuse,
+            LldsComment = "Allocating region for "
+        ;
+            HowToConstruct = construct_dynamically,
+            RegionVarCode = empty,
+            MaybeRegionRval = no,
+            LldsComment = "Allocating heap for "
+        ;
+            HowToConstruct = construct_statically(_),
+            unexpected(this_file,
+                "var_locn_assign_dynamic_cell_to_var: construct_statically")
         ),
+        assign_all_cell_args(ModuleInfo, Vector, yes(Ptag), lval(Lval),
+            StartOffset, ArgsCode, !VLI),
         SetupReuseCode = empty,
-        RegionVarCode = empty,
-        MaybeRegionRval = no,
-        LldsComment = "Allocating heap for ",
-        CellCode = node([
-            llds_instr(
-                incr_hp(Lval, yes(Ptag), TotalOffset,
-                    const(llconst_int(TotalSize)), TypeMsg, MayUseAtomic,
-                    MaybeRegionRval), LldsComment ++ VarName)
-        ]),
-        TempRegs = []
+        MaybeReuse = no_llds_reuse
     ;
         HowToConstruct = reuse_cell(CellToReuse),
-        CellToReuse = cell_to_reuse(ReuseVar, _ReuseConsId, _),
-        var_locn_produce_var(ModuleInfo, ReuseVar, ReuseRval, ReuseVarCode,
-            !VLI),
-        ( ReuseRval = lval(ReuseLval0) ->
-            ReuseLval = ReuseLval0
-        ;
-            unexpected(this_file,
-                "var_locn_produce_var: reused cell not an lval")
-        ),
+        LldsComment = "Reusing cell on heap for ",
+        assign_reused_cell_to_var(ModuleInfo, Lval, Ptag, Vector, CellToReuse,
+            StartOffset, Label, MaybeReuse, SetupReuseCode, ArgsCode, !VLI),
+        MaybeRegionRval = no,
+        RegionVarCode = empty
+    ),
+    CellCode = node([
+        llds_instr(
+            incr_hp(Lval, yes(Ptag), TotalOffset,
+                const(llconst_int(TotalSize)), TypeMsg, MayUseAtomic,
+                MaybeRegionRval, MaybeReuse),
+            LldsComment ++ VarName)
+    ]),
+    Code = tree_list([SetupReuseCode, CellCode, RegionVarCode, ArgsCode]).
 
-        % Save any variables which are available only in the reused cell into
-        % temporary registers.
-        save_reused_cell_fields(ModuleInfo, ReuseVar, ReuseLval, SaveArgsCode,
-            TempRegs, !VLI),
-        SetupReuseCode = tree(ReuseVarCode, SaveArgsCode),
+:- pred assign_reused_cell_to_var(module_info::in, lval::in, tag::in,
+    list(maybe(rval))::in, cell_to_reuse::in, int::in, label::in,
+    llds_reuse::out, code_tree::out, code_tree::out,
+    var_locn_info::in, var_locn_info::out) is det.
 
-        % XXX optimise the stripping of the tag when the tags are the same or
-        % the old tag is known, as we do in the high level backend
-        LldsComment = "Reusing cell on heap for ",
-        CellCode = node([
-            llds_instr(
-                assign(Lval,
-                    mkword(Ptag,
-                        unop(strip_tag, lval(ReuseLval)))),
-                LldsComment ++ VarName)
-        ]),
+assign_reused_cell_to_var(ModuleInfo, Lval, Ptag, Vector, CellToReuse,
+        StartOffset, Label, MaybeReuse, SetupReuseCode, ArgsCode, !VLI) :-
+    CellToReuse = cell_to_reuse(ReuseVar, _ReuseConsId, NeedsUpdates0),
+    var_locn_produce_var(ModuleInfo, ReuseVar, ReuseRval, ReuseVarCode, !VLI),
+    ( ReuseRval = lval(ReuseLval0) ->
+        ReuseLval = ReuseLval0
+    ;
+        unexpected(this_file,
+            "var_locn_assign_reused_cell_to_var: reused cell not an lval")
+    ),
 
-        RegionVarCode = empty
+    % Save any variables which are available only in the reused cell into
+    % temporary registers.
+    save_reused_cell_fields(ModuleInfo, ReuseVar, ReuseLval, SaveArgsCode,
+        TempRegs0, !VLI),
+    SetupReuseCode = tree(ReuseVarCode, SaveArgsCode),
+
+    % If it's possible to avoid some field assignments, we'll need an extra
+    % temporary register to record whether we actually are reusing a structure
+    % or if a new object was allocated.
+    ( list.member(does_not_need_update, NeedsUpdates0) ->
+        var_locn_acquire_reg(FlagReg, !VLI),
+        MaybeFlag = yes(FlagReg),
+        TempRegs = [FlagReg | TempRegs0]
+    ;
+        MaybeFlag = no,
+        TempRegs = TempRegs0
     ),
-    (
-        MaybeOffset = yes(Offset),
-        StartOffset = -Offset
+
+    % XXX optimise the stripping of the tag when the tags are the same or
+    % the old tag is known, as we do in the high level backend
+    MaybeReuse = llds_reuse(unop(strip_tag, lval(ReuseLval)), MaybeFlag),
+
+    % NeedsUpdates0 can be shorter than Vector due to extra fields.
+    Padding = list.length(Vector) - list.length(NeedsUpdates0),
+    ( Padding >= 0 ->
+        NeedsUpdates = list.duplicate(Padding, needs_update) ++ NeedsUpdates0
     ;
-        MaybeOffset = no,
-        StartOffset = 0
+        unexpected(this_file,
+            "var_locn_assign_reused_cell_to_var: Padding < 0")
     ),
-    % XXX with structure reuse we don't necessarily have to assign all fields
-    assign_cell_args(ModuleInfo, Vector, yes(Ptag), lval(Lval), StartOffset,
-        ArgsCode, !VLI),
-    list.foldl(var_locn_release_reg, TempRegs, !VLI),
-    Code = tree_list([SetupReuseCode, CellCode, RegionVarCode, ArgsCode]).
 
-:- pred assign_cell_args(module_info::in, list(maybe(rval))::in,
+    (
+        MaybeFlag = yes(FlagLval),
+        assign_some_cell_args(ModuleInfo, Vector, NeedsUpdates, yes(Ptag),
+            lval(Lval), StartOffset, CannotSkipArgsCode, CanSkipArgsCode,
+            !VLI),
+        ArgsCode = tree_list([
+            node([
+                llds_instr(if_val(lval(FlagLval), code_label(Label)),
+                    "skip some field assignments")
+            ]),
+            CanSkipArgsCode,
+            node([
+                llds_instr(label(Label),
+                    "past skipped field assignments")
+            ]),
+            CannotSkipArgsCode
+        ])
+    ;
+        MaybeFlag = no,
+        assign_all_cell_args(ModuleInfo, Vector, yes(Ptag), lval(Lval),
+            StartOffset, ArgsCode, !VLI)
+    ),
+
+    list.foldl(var_locn_release_reg, TempRegs, !VLI).
+
+:- pred assign_all_cell_args(module_info::in, list(maybe(rval))::in,
     maybe(tag)::in, rval::in, int::in, code_tree::out,
     var_locn_info::in, var_locn_info::out) is det.
 
-assign_cell_args(_, [], _, _, _, empty, !VLI).
-assign_cell_args(ModuleInfo, [MaybeRval0 | MaybeRvals0], Ptag, Base, Offset,
+assign_all_cell_args(_, [], _, _, _, empty, !VLI).
+assign_all_cell_args(ModuleInfo, [MaybeRval | MaybeRvals], Ptag, Base, Offset,
         Code, !VLI) :-
     (
-        MaybeRval0 = yes(Rval0),
-        Target = field(Ptag, Base, const(llconst_int(Offset))),
+        MaybeRval = yes(Rval),
+        assign_cell_arg(ModuleInfo, Rval, Ptag, Base, Offset, ThisCode, !VLI)
+    ;
+        MaybeRval = no,
+        ThisCode = empty
+    ),
+    assign_all_cell_args(ModuleInfo, MaybeRvals, Ptag, Base, Offset + 1,
+        RestCode, !VLI),
+    Code = tree(ThisCode, RestCode).
+
+:- pred assign_some_cell_args(module_info::in, list(maybe(rval))::in,
+    list(needs_update)::in, maybe(tag)::in, rval::in, int::in, code_tree::out,
+    code_tree::out, var_locn_info::in, var_locn_info::out) is det.
+
+assign_some_cell_args(_, [], [], _, _, _, empty, empty, !VLI).
+assign_some_cell_args(ModuleInfo,
+        [MaybeRval | MaybeRvals], [NeedsUpdate | NeedsUpdates],
+        Ptag, Base, Offset, CannotSkipArgsCode, CanSkipArgsCode, !VLI) :-
+    (
+        MaybeRval = yes(Rval),
+        assign_cell_arg(ModuleInfo, Rval, Ptag, Base, Offset, ThisCode, !VLI)
+    ;
+        MaybeRval = no,
+        ThisCode = empty
+    ),
+    assign_some_cell_args(ModuleInfo, MaybeRvals, NeedsUpdates, Ptag, Base,
+        Offset + 1, RestCannotSkipArgsCode, RestCanSkipArgsCode, !VLI),
+    (
+        NeedsUpdate = needs_update,
+        CannotSkipArgsCode = tree(ThisCode, RestCannotSkipArgsCode),
+        CanSkipArgsCode = RestCanSkipArgsCode
+    ;
+        NeedsUpdate = does_not_need_update,
+        CannotSkipArgsCode = RestCannotSkipArgsCode,
+        CanSkipArgsCode = tree(ThisCode, RestCanSkipArgsCode)
+    ).
+
+assign_some_cell_args(_, [], [_ | _], _, _, _, _, _, !VLI) :-
+    unexpected(this_file, "assign_some_cell_args: mismatch lists").
+assign_some_cell_args(_, [_ | _], [], _, _, _, _, _, !VLI) :-
+    unexpected(this_file, "assign_some_cell_args: mismatch lists").
+
+:- pred assign_cell_arg(module_info::in, rval::in, maybe(tag)::in, rval::in,
+    int::in, code_tree::out, var_locn_info::in, var_locn_info::out) is det.
+
+assign_cell_arg(ModuleInfo, Rval0, Ptag, Base, Offset, Code, !VLI) :-
+    Target = field(Ptag, Base, const(llconst_int(Offset))),
+    (
+        Rval0 = var(Var),
+        find_var_availability(!.VLI, Var, no, Avail),
         (
-            Rval0 = var(Var),
-            find_var_availability(!.VLI, Var, no, Avail),
-            (
-                Avail = available(Rval),
-                EvalCode = empty
-            ;
-                Avail = needs_materialization,
-                materialize_var(ModuleInfo, Var, no, no, [], Rval, EvalCode,
-                    !VLI)
-            ),
-            var_locn_get_vartypes(!.VLI, VarTypes),
-            map.lookup(VarTypes, Var, Type),
-            ( is_dummy_argument_type(ModuleInfo, Type) ->
-                AssignCode = empty
-            ;
-                add_additional_lval_for_var(Var, Target, !VLI),
-                get_var_name(!.VLI, Var, VarName),
-                Comment = "assigning from " ++ VarName,
-                AssignCode = node([llds_instr(assign(Target, Rval), Comment)])
-            )
-        ;
-            Rval0 = const(_),
-            EvalCode = empty,
-            Comment = "assigning field from const",
-            AssignCode = node([llds_instr(assign(Target, Rval0), Comment)])
+            Avail = available(Rval),
+            EvalCode = empty
         ;
-            ( Rval0 = mkword(_, _)
-            ; Rval0 = binop(_, _, _)
-            ; Rval0 = unop(_, _)
-            ; Rval0 = lval(_)
-            ; Rval0 = mem_addr(_)
-            ),
-            unexpected(this_file, "assign_cell_args: unknown rval")
+            Avail = needs_materialization,
+            materialize_var(ModuleInfo, Var, no, no, [], Rval, EvalCode,
+                !VLI)
         ),
-        ThisCode = tree(EvalCode, AssignCode)
+        var_locn_get_vartypes(!.VLI, VarTypes),
+        map.lookup(VarTypes, Var, Type),
+        ( is_dummy_argument_type(ModuleInfo, Type) ->
+            AssignCode = empty
+        ;
+            add_additional_lval_for_var(Var, Target, !VLI),
+            get_var_name(!.VLI, Var, VarName),
+            Comment = "assigning from " ++ VarName,
+            AssignCode = node([llds_instr(assign(Target, Rval), Comment)])
+        )
     ;
-        MaybeRval0 = no,
-        ThisCode = empty
+        Rval0 = const(_),
+        EvalCode = empty,
+        Comment = "assigning field from const",
+        AssignCode = node([llds_instr(assign(Target, Rval0), Comment)])
+    ;
+        ( Rval0 = mkword(_, _)
+        ; Rval0 = binop(_, _, _)
+        ; Rval0 = unop(_, _)
+        ; Rval0 = lval(_)
+        ; Rval0 = mem_addr(_)
+        ),
+        unexpected(this_file, "assign_cell_args: unknown rval")
     ),
-    assign_cell_args(ModuleInfo, MaybeRvals0, Ptag, Base, Offset + 1, RestCode,
-        !VLI),
-    Code = tree(ThisCode, RestCode).
+    Code = tree(EvalCode, AssignCode).
 
     % Save any variables which depend on the ReuseLval into temporary
     % registers so that they are available after ReuseLval is clobbered.
Index: runtime/mercury_heap.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_heap.h,v
retrieving revision 1.39
diff -u -r1.39 mercury_heap.h
--- runtime/mercury_heap.h	21 Aug 2007 06:22:04 -0000	1.39
+++ runtime/mercury_heap.h	30 Jan 2008 03:58:00 -0000
@@ -33,7 +33,7 @@
 #include "mercury_context.h"            /* for min_heap_reclamation_point() */
 #include "mercury_heap_profile.h"       /* for MR_record_allocation() */
 #include "mercury_deep_profiling.h"     /* for MR_current_call_site_dynamic */
-#include "mercury_std.h"               /* for MR_EXTERN_INLINE */
+#include "mercury_std.h"                /* for MR_EXTERN_INLINE */
 #include "mercury_reg_workarounds.h"    /* for MR_memcpy */
 #include "mercury_debug.h"              /* for MR_debugtagoffsetincrhp* */
 #ifdef MR_HIGHLEVEL_CODE
@@ -47,6 +47,8 @@
   #ifdef MR_BOEHM_GC
     #define GC_I_HIDE_POINTERS
     #include "gc.h"
+    #include "gc_mark.h"                /* for GC_least_plausible_heap_addr */
+                                        /* GC_greatest_plausible_heap_addr */
   #endif
 #endif
 
@@ -396,6 +398,59 @@
 /***************************************************************************/
 
 /*
+** Macros to implement structure reuse, conditioned on whether the structure
+** to reuse is really dynamically allocated. If not, fall back to allocating
+** a new object on the heap.
+*/
+
+#define     MR_reuse_or_alloc_heap(dest, reuse, fallback_alloc)             \
+            MR_tag_reuse_or_alloc_heap((dest), 0, (reuse), (fallback_alloc))
+
+#define     MR_reuse_or_alloc_heap_flag(dest, flag, reuse, fallback_alloc)  \
+            MR_tag_reuse_or_alloc_heap((dest), 0, (flag), (reuse),          \
+                (fallback_alloc))
+
+#define     MR_tag_reuse_or_alloc_heap(dest, tag, reuse, fallback_alloc)    \
+            do {                                                            \
+                MR_bool dummy;                                              \
+                MR_tag_reuse_or_alloc_heap_flag((dest), (tag), dummy,       \
+                    (reuse), (fallback_alloc));                             \
+                (void) dummy;                                               \
+            } while (0)
+
+#ifdef MR_BOEHM_GC
+
+  #define   MR_in_heap_range(addr)                                          \
+            ((void *) (addr) >= GC_least_plausible_heap_addr &&             \
+             (void *) (addr) < GC_greatest_plausible_heap_addr)             \
+
+#else /* ! MR_BOEHM_GC */
+
+  /*
+  ** We don't have any way to check whether `addr' is dynamically allocated,
+  ** so just assume that it is.  For this to be safe `--static-ground-terms'
+  ** needs to be disabled.
+  */
+  #define   MR_in_heap_range(addr)  (MR_TRUE)
+
+#endif /* ! MR_BOEHM_GC */
+
+#define     MR_tag_reuse_or_alloc_heap_flag(dest, tag, flag, reuse_addr,    \
+                fallback_alloc)                                             \
+            do {                                                            \
+                MR_Word tmp = (reuse_addr);                                 \
+                if (MR_in_heap_range(tmp)) {                                \
+                    (dest) = (MR_Word) MR_mkword((tag), tmp);               \
+                    (flag) = MR_TRUE;                                       \
+                } else {                                                    \
+                    (fallback_alloc);                                       \
+                    (flag) = MR_FALSE;                                      \
+                }                                                           \
+            } while (0)
+
+/***************************************************************************/
+
+/*
 ** Macros to box/unbox types declared with `pragma foreign_type'.
 */
 

--------------------------------------------------------------------------
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