[m-rev.] for review: reassign.m
Zoltan Somogyi
zs at cs.mu.OZ.AU
Fri Mar 8 23:16:08 AEDT 2002
I have addressed Fergus's review comments. Since the review was several months
ago, I am posting a full diff again.
Zoltan.
A new LLDS->LLDS transformation that optimizes instruction sequences such
as the following extract from tree234__search:
MR_r1 = MR_stackvar(3);
MR_r2 = MR_stackvar(4);
MR_r3 = MR_const_field(MR_mktag(1), MR_stackvar(1), (MR_Integer) 2);
MR_r4 = MR_stackvar(2);
MR_succip = (MR_Code *) MR_stackvar(5);
if ((MR_tag(MR_r3) != MR_mktag((MR_Integer) 1))) {
MR_GOTO_LABEL(mercury__x3__search_3_0_i1);
}
MR_stackvar(1) = MR_r3;
MR_stackvar(2) = MR_r4;
MR_stackvar(3) = MR_r1;
MR_stackvar(4) = MR_r2;
MR_r2 = MR_r4;
MR_r3 = MR_const_field(MR_mktag(1), MR_r3, (MR_Integer) 0);
MR_call_localret(...)
The code before the if-then-else is part of the procedure epilogue; the code
after it is the code from the initial part of the procedure that fulljump
optimization replaces the self-tail-call with.
The transformation deletes the redundant assignments to stackvars 2, 3 and 4.
It reduces both the size and the runtime of the compiler by about 0.5%.
compiler/reassign.m:
The new module that does the work.
compiler/optimize.m:
Invoke the new module if the optimization is enabled. Invoke it after
most other optimizations have been run, since they may create more
opportunities for it.
compiler/option.m:
Add a new option to control whether the new optimization is enabled.
Turn on the new optimization at optimization level 3.
doc/user_guide.texi:
Document the new option.
compiler/notes/compiler_design.html:
Document the new module.
cvs diff: Diffing .
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/doc
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing browser
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
Index: compiler/optimize.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/optimize.m,v
retrieving revision 1.28
diff -u -b -r1.28 optimize.m
--- compiler/optimize.m 2001/05/31 05:59:50 1.28
+++ compiler/optimize.m 2001/11/02 22:23:49
@@ -28,8 +28,8 @@
:- implementation.
:- import_module jumpopt, labelopt, dupelim, peephole.
-:- import_module frameopt, delay_slot, use_local_vars, options.
-:- import_module globals, passes_aux, opt_util, opt_debug.
+:- import_module frameopt, delay_slot, use_local_vars, reassign.
+:- import_module options, globals, passes_aux, opt_util, opt_debug.
:- import_module wrap_blocks, hlds_pred, llds_out, continuation_info.
:- import_module bool, int, string.
@@ -384,11 +384,12 @@
{ opt_util__find_first_label(Instrs0, Label) },
{ opt_util__format_label(Label, LabelStr) },
+ globals__io_lookup_bool_option(optimize_reassign, Reassign),
globals__io_lookup_bool_option(optimize_delay_slot, DelaySlot),
globals__io_lookup_bool_option(use_local_vars, UseLocalVars),
- ( { DelaySlot = yes ; UseLocalVars = yes } ->
+ ( { Reassign = yes ; DelaySlot = yes ; UseLocalVars = yes } ->
% We must get rid of any extra labels added by other passes,
- % since they can confuse both wrap_blocks and delay_slot.
+ % since they can confuse reassign, wrap_blocks and delay_slot.
( { VeryVerbose = yes } ->
io__write_string("% Optimizing labels for "),
io__write_string(LabelStr),
@@ -403,21 +404,36 @@
{ OptDebugInfo1 = OptDebugInfo0 },
{ Instrs1 = Instrs0 }
),
- ( { DelaySlot = yes } ->
+ ( { Reassign = yes } ->
( { VeryVerbose = yes } ->
- io__write_string("% Optimizing delay slot for "),
+ io__write_string("% Optimizing reassign for "),
io__write_string(LabelStr),
io__write_string("\n")
;
[]
),
- { fill_branch_delay_slot(Instrs1, Instrs2) },
- optimize__maybe_opt_debug(Instrs2, C, "after delay slots",
+ { remove_reassign(Instrs1, Instrs2) },
+ optimize__maybe_opt_debug(Instrs2, C, "after reassign",
OptDebugInfo1, OptDebugInfo2)
;
{ OptDebugInfo2 = OptDebugInfo1 },
{ Instrs2 = Instrs1 }
),
+ ( { DelaySlot = yes } ->
+ ( { VeryVerbose = yes } ->
+ io__write_string("% Optimizing delay slot for "),
+ io__write_string(LabelStr),
+ io__write_string("\n")
+ ;
+ []
+ ),
+ { fill_branch_delay_slot(Instrs2, Instrs3) },
+ optimize__maybe_opt_debug(Instrs3, C, "after delay slots",
+ OptDebugInfo2, OptDebugInfo3)
+ ;
+ { OptDebugInfo3 = OptDebugInfo2 },
+ { Instrs3 = Instrs2 }
+ ),
( { UseLocalVars = yes } ->
( { VeryVerbose = yes } ->
io__write_string("% Wrapping blocks for "),
@@ -426,9 +442,9 @@
;
[]
),
- { wrap_blocks(Instrs2, Instrs) },
+ { wrap_blocks(Instrs3, Instrs) },
optimize__maybe_opt_debug(Instrs, C, "after wrap blocks",
- OptDebugInfo2, _OptDebugInfo)
+ OptDebugInfo3, _OptDebugInfo)
;
- { Instrs = Instrs1 }
+ { Instrs = Instrs3 }
).
Index: compiler/options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.359
diff -u -b -r1.359 options.m
--- compiler/options.m 2002/03/05 17:03:23 1.359
+++ compiler/options.m 2002/03/07 09:43:09
@@ -433,6 +433,7 @@
%%% unused: ; optimize_copyprop
; optimize_frames
; optimize_delay_slot
+ ; optimize_reassign
; optimize_repeat
% - RL
; optimize_rl
@@ -895,6 +896,7 @@
%%% optimize_copyprop - bool(no),
optimize_frames - bool(no),
optimize_delay_slot - bool(no),
+ optimize_reassign - bool(no),
optimize_repeat - int(0),
% LLDS -> C
@@ -1416,6 +1418,8 @@
long_option("optimise-frames", optimize_frames).
long_option("optimize-delay-slot", optimize_delay_slot).
long_option("optimise-delay-slot", optimize_delay_slot).
+long_option("optimize-reassign", optimize_reassign).
+long_option("optimise-reassign", optimize_reassign).
long_option("optimize-repeat", optimize_repeat).
long_option("optimise-repeat", optimize_repeat).
@@ -1787,6 +1791,7 @@
deforestation - bool(yes),
local_constraint_propagation - bool(yes),
constant_propagation - bool(yes),
+ optimize_reassign - bool(yes),
% Disabled until a bug in extras/trailed_update/var.m is resolved.
%introduce_accumulators - bool(yes),
optimize_repeat - int(4)
@@ -2948,6 +2953,9 @@
"\tDisable stack frame optimizations.",
"--no-optimize-delay-slot",
"\tDisable branch delay slot optimizations.",
+ "--optimize-reassign",
+ "\tOptimize away assignments to locations that already hold",
+ "\tthe assigned value.",
"--optimize-repeat <n>",
"\tIterate most optimizations at most <n> times (default: 3)."
]).
Index: compiler/reassign.m
===================================================================
RCS file: reassign.m
diff -N reassign.m
--- /dev/null Fri Dec 1 02:25:58 2000
+++ reassign.m Thu Mar 7 20:45:54 2002
@@ -0,0 +1,461 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2002 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% File: reassign.m
+%
+% Author: zs.
+%
+% This module implements an LLDS->LLDS transformation that optimizes
+% away assignments to locations that already hold the assigned value.
+% It operates entirely within extended basic blocks.
+%
+% It is intended for instruction sequences such as the following extract
+% from tree234__search:
+%
+% MR_r1 = MR_stackvar(3);
+% MR_r2 = MR_stackvar(4);
+% MR_r3 = MR_const_field(MR_mktag(1), MR_stackvar(1), (MR_Integer) 2);
+% MR_r4 = MR_stackvar(2);
+% MR_succip = (MR_Code *) MR_stackvar(5);
+% if ((MR_tag(MR_r3) != MR_mktag((MR_Integer) 1))) {
+% MR_GOTO_LABEL(mercury__x3__search_3_0_i1);
+% }
+% MR_stackvar(1) = MR_r3;
+% MR_stackvar(2) = MR_r4;
+% MR_stackvar(3) = MR_r1;
+% MR_stackvar(4) = MR_r2;
+% MR_r2 = MR_r4;
+% MR_r3 = MR_const_field(MR_mktag(1), MR_r3, (MR_Integer) 0);
+% MR_call_localret(...)
+%
+% The code before the if statement is part of the procedure epilogue; the code
+% after it is the code from the initial part of the procedure that fulljump
+% optimization replaces the self-tail-call with.
+%
+% The objective of this module is to remove assignments such as the assignments
+% to stackvars 2, 3 and 4 above, in which the register assigned to the stackvar
+% comes from the same stackvar in the first place.
+%
+% In general, for every assignment TargetLval = SourceRval, we record that
+% TargetLval now contains SourceRval; if SourceRval is of the form
+% lval(SourceLval), we also record that SourceLval now contains
+% lval(TargetLval). Later on, if we find an assignment that assigns
+% to an lval a value that it already holds, we remove the assignment.
+% The removed assignment will either be a copy of the original assignment
+% TargetLval = SourceRval, or its converse, SourceLval = lval(TargetLval).
+% The mechanism that enables us to do this is a map that maps lvals
+% (e.g. TargetLval) to its known contents (e.g. SourceRval).
+%
+% Of course, if any of the lvals occurring on the right hand side of an
+% assignment change, we cannot remove a later copy of that assignment or
+% of its converse. For example, we cannot remove the final assignment in
+% the following code.
+%
+% MR_r3 = MR_stackvar(1);
+% ...
+% MR_stackvar(1) = MR_r2;
+% ...
+% MR_r3 = MR_stackvar(1);
+%
+% We handle this by keeping track of which lvals an entry in the known contents
+% map depends on. If one of these lvals is updated, we invalidate the dependent
+% entries in the known contents map (i.e. we delete them).
+%
+% The lvals on which TargetLval depends include any lvals occurring inside it.
+% We cannot optimize away the second assignment to the field below because
+% even though the two field references are the same syntactically, they refer
+% to different memory locations due to the update of MR_r5 between them.
+%
+% MR_field(MR_mktag(1), MR_r5, 1) = r2;
+% ...
+% MR_incr_hp(MR_r5, 4);
+% ...
+% MR_field(MR_mktag(1), MR_r5, 1) = r2;
+%
+%
+% The lvals on which TargetLval depends need not include TargetLval itself,
+% since an assignment to TargetLval will in any case override the previous
+% entry for TargetLval in the known contents map. This takes care of code
+% sequences such as:
+%
+% MR_r3 = MR_stackvar(1);
+% ...
+% MR_r3 = MR_r2;
+% ...
+% MR_r3 = MR_stackvar(1);
+%
+% The optimization makes conservative assumptions in several places, meaning
+% it clobbers entries in the known contents map whenever an instruction *could*
+% affect the entry, even if it in fact doesn't. For example, we clobber the
+% known contents map at calls, labels and ticket resets.
+
+%-----------------------------------------------------------------------------%
+
+:- module reassign.
+
+:- interface.
+
+:- import_module llds.
+:- import_module list.
+
+:- pred remove_reassign(list(instruction)::in, list(instruction)::out) is det.
+
+:- implementation.
+
+:- import_module code_util.
+:- import_module std_util, set, map, require.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- type known_contents == map(lval, rval).
+:- type dependent_lval_map == map(lval, set(lval)).
+
+remove_reassign(Instrs0, Instrs) :-
+ remove_reassign_loop(Instrs0, map__init, map__init, [], RevInstrs),
+ list__reverse(RevInstrs, Instrs).
+
+:- pred remove_reassign_loop(list(instruction)::in, known_contents::in,
+ dependent_lval_map::in, list(instruction)::in, list(instruction)::out)
+ is det.
+
+remove_reassign_loop([], _, _, RevInstrs, RevInstrs).
+remove_reassign_loop([Instr0 | Instrs0], KnownContentsMap0, DepLvalMap0,
+ RevInstrs0, RevInstrs) :-
+ Instr0 = Uinstr0 - _,
+ (
+ Uinstr0 = comment(_),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ KnownContentsMap = KnownContentsMap0,
+ DepLvalMap = DepLvalMap0
+ ;
+ Uinstr0 = livevals(_),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ KnownContentsMap = KnownContentsMap0,
+ DepLvalMap = DepLvalMap0
+ ;
+ Uinstr0 = block(_, _, _),
+ error("remove_reassign_loop: block")
+ ;
+ Uinstr0 = assign(Target, Source),
+ (
+ map__search(KnownContentsMap0, Target, KnownContents),
+ KnownContents = Source
+ ->
+ % By not including Instr0 in RevInstrs1,
+ % we are deleting Instr0.
+ RevInstrs1 = RevInstrs0,
+ KnownContentsMap = KnownContentsMap0,
+ DepLvalMap = DepLvalMap0
+ ;
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ clobber_dependents(Target,
+ KnownContentsMap0, KnownContentsMap1,
+ DepLvalMap0, DepLvalMap1),
+ (
+ % For Targets of the following form, the code
+ % generator ensures that the storage location
+ % referred to by Target can only be updated
+ % through the Target lval, and not through
+ % some other lval, unless one uses mem_addr to
+ % explicitly create an alias and mem_ref to
+ % access the memory location via that alias.
+
+ no_implicit_alias_target(Target)
+ ->
+ record_known(Target, Source,
+ KnownContentsMap1, KnownContentsMap,
+ DepLvalMap1, DepLvalMap)
+ ;
+ KnownContentsMap = KnownContentsMap1,
+ DepLvalMap = DepLvalMap1
+ )
+ )
+ ;
+ Uinstr0 = call(_, _, _, _, _, _),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ % The call map clobber any lval.
+ KnownContentsMap = map__init,
+ DepLvalMap = map__init
+ ;
+ Uinstr0 = mkframe(_, _),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ KnownContentsMap = map__init,
+ DepLvalMap = map__init
+ ;
+ Uinstr0 = label(_),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ % We don't know what is stored where at the
+ % instructions that jump here.
+ KnownContentsMap = map__init,
+ DepLvalMap = map__init
+ ;
+ Uinstr0 = goto(_),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ % The value of KnownContentsMap doesn't really matter
+ % since the next instruction (which must be a label)
+ % will reset it to empty anyway.
+ KnownContentsMap = map__init,
+ DepLvalMap = map__init
+ ;
+ Uinstr0 = computed_goto(_, _),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ % The value of KnownContentsMap doesn't really matter
+ % since the next instruction (which must be a label)
+ % will reset it to empty anyway.
+ KnownContentsMap = map__init,
+ DepLvalMap = map__init
+ ;
+ Uinstr0 = c_code(_, _),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ % The C code map clobber any lval.
+ KnownContentsMap = map__init,
+ DepLvalMap = map__init
+ ;
+ Uinstr0 = if_val(_, _),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ KnownContentsMap = KnownContentsMap0,
+ DepLvalMap = DepLvalMap0
+ ;
+ Uinstr0 = incr_hp(Target, _, _, _),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ clobber_dependents(Target,
+ KnownContentsMap0, KnownContentsMap1,
+ DepLvalMap0, DepLvalMap1),
+ clobber_dependents(hp, KnownContentsMap1, KnownContentsMap,
+ DepLvalMap1, DepLvalMap)
+ ;
+ Uinstr0 = mark_hp(Target),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ clobber_dependents(Target, KnownContentsMap0, KnownContentsMap,
+ DepLvalMap0, DepLvalMap)
+ ;
+ Uinstr0 = restore_hp(_),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ clobber_dependents(hp, KnownContentsMap0, KnownContentsMap,
+ DepLvalMap0, DepLvalMap)
+ ;
+ Uinstr0 = free_heap(_),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ % There is no need to update KnownContentsMap since
+ % later code should never refer to the freed cell.
+ KnownContentsMap = KnownContentsMap0,
+ DepLvalMap = DepLvalMap0
+ ;
+ Uinstr0 = store_ticket(Target),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ clobber_dependents(Target, KnownContentsMap0, KnownContentsMap,
+ DepLvalMap0, DepLvalMap)
+ ;
+ Uinstr0 = reset_ticket(_, _),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ % The reset operation may modify any lval.
+ KnownContentsMap = map__init,
+ DepLvalMap = map__init
+ ;
+ Uinstr0 = prune_ticket,
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ KnownContentsMap = KnownContentsMap0,
+ DepLvalMap = DepLvalMap0
+ ;
+ Uinstr0 = discard_ticket,
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ KnownContentsMap = KnownContentsMap0,
+ DepLvalMap = DepLvalMap0
+ ;
+ Uinstr0 = mark_ticket_stack(Target),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ clobber_dependents(Target, KnownContentsMap0, KnownContentsMap,
+ DepLvalMap0, DepLvalMap)
+ ;
+ Uinstr0 = prune_tickets_to(_),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ KnownContentsMap = KnownContentsMap0,
+ DepLvalMap = DepLvalMap0
+% ;
+% Uinstr0 = discard_tickets_to(_),
+% RevInstrs1 = [Instr0 | RevInstrs0],
+% KnownContentsMap = KnownContentsMap0,
+% DepLvalMap = DepLvalMap0
+ ;
+ Uinstr0 = incr_sp(_, _),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ % All stackvars now refer to new locations.
+ % Rather than delete only stackvars from
+ % KnownContentsMap0, we delete everything.
+ KnownContentsMap = map__init,
+ DepLvalMap = map__init
+ ;
+ Uinstr0 = decr_sp(_),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ % All stackvars now refer to new locations.
+ % Rather than delete only stackvars from
+ % KnownContentsMap0, we delete everything.
+ KnownContentsMap = map__init,
+ DepLvalMap = map__init
+ ;
+ Uinstr0 = pragma_c(_, _, _, _, _, _, _, _),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ % The C code map clobber any lval.
+ KnownContentsMap = map__init,
+ DepLvalMap = map__init
+ ;
+ Uinstr0 = init_sync_term(Target, _),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ clobber_dependents(Target, KnownContentsMap0, KnownContentsMap,
+ DepLvalMap0, DepLvalMap)
+ ;
+ Uinstr0 = fork(_, _, _),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ % We keep KnownContentsMap. The spawned thread may
+ % modify some stack variables, but these will include
+ % only those belonging to the local variables and to
+ % the output variables of the spawned goal, and these
+ % are guaranteed to be distinct from all the stack
+ % variables accessed by the current thread.
+ KnownContentsMap = KnownContentsMap0,
+ DepLvalMap = DepLvalMap0
+ ;
+ Uinstr0 = join_and_terminate(_),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ % Other threads may modify any lval.
+ KnownContentsMap = map__init,
+ DepLvalMap = map__init
+ ;
+ Uinstr0 = join_and_continue(_, _),
+ RevInstrs1 = [Instr0 | RevInstrs0],
+ % Other threads may modify any lval.
+ KnownContentsMap = map__init,
+ DepLvalMap = map__init
+ ),
+ remove_reassign_loop(Instrs0, KnownContentsMap, DepLvalMap,
+ RevInstrs1, RevInstrs).
+
+% Succeed iff the lval cannot have an alias created for it without the use of
+% a mem_ref lval or an instruction with embedded C code, both of which cause
+% us to clobber the known contents map.
+
+:- pred no_implicit_alias_target(lval::in) is semidet.
+
+no_implicit_alias_target(reg(_, _)).
+no_implicit_alias_target(stackvar(_)).
+no_implicit_alias_target(framevar(_)).
+
+:- pred clobber_dependents(lval::in, known_contents::in, known_contents::out,
+ dependent_lval_map::in, dependent_lval_map::out) is det.
+
+clobber_dependents(Target, KnownContentsMap0, KnownContentsMap,
+ DepLvalMap0, DepLvalMap) :-
+ ( map__search(DepLvalMap0, Target, DepLvals) ->
+ set__fold(clobber_dependent, DepLvals,
+ KnownContentsMap0, KnownContentsMap1),
+ map__delete(DepLvalMap0, Target, DepLvalMap1)
+ ;
+ KnownContentsMap1 = KnownContentsMap0,
+ DepLvalMap1 = DepLvalMap0
+ ),
+ % LLDS code can refer to arbitrary locations on the stack
+ % or in the heap with mem_ref lvals. Since we don't keep track
+ % of which locations have their addresses taken, on any
+ % assignment through a mem_ref lval we throw way the known
+ % contents map. This is a conservative approximation of the
+ % desired behaviour, which would invalidate only the entries
+ % of lvals that may be referred to via this mem_ref.
+ code_util__lvals_in_rval(lval(Target), SubLvals),
+ (
+ list__member(SubLval, SubLvals),
+ SubLval = mem_ref(_)
+ ->
+ KnownContentsMap = map__init,
+ DepLvalMap = map__init
+ ;
+ KnownContentsMap = KnownContentsMap1,
+ DepLvalMap = DepLvalMap1
+ ).
+
+:- pred clobber_dependent(lval::in, known_contents::in, known_contents::out)
+ is det.
+
+clobber_dependent(Dependent, KnownContentsMap0, KnownContentsMap) :-
+ map__delete(KnownContentsMap0, Dependent, KnownContentsMap).
+
+:- pred record_known(lval::in, rval::in,
+ known_contents::in, known_contents::out,
+ dependent_lval_map::in, dependent_lval_map::out) is det.
+
+record_known(TargetLval, SourceRval, KnownContentsMap0, KnownContentsMap,
+ DepLvalMap0, DepLvalMap) :-
+ code_util__lvals_in_rval(SourceRval, SourceSubLvals),
+ ( list__member(TargetLval, SourceSubLvals) ->
+ % The act of assigning to TargetLval has modified
+ % the value of SourceRval, so we can't eliminate
+ % any copy of this assignment or its converse.
+ KnownContentsMap = KnownContentsMap0,
+ DepLvalMap = DepLvalMap0
+ ;
+ record_known_lval_rval(TargetLval, SourceRval,
+ KnownContentsMap0, KnownContentsMap1,
+ DepLvalMap0, DepLvalMap1),
+ ( SourceRval = lval(SourceLval) ->
+ record_known_lval_rval(SourceLval, lval(TargetLval),
+ KnownContentsMap1, KnownContentsMap,
+ DepLvalMap1, DepLvalMap)
+ ;
+ KnownContentsMap = KnownContentsMap1,
+ DepLvalMap = DepLvalMap1
+ )
+ ).
+
+:- pred record_known_lval_rval(lval::in, rval::in,
+ known_contents::in, known_contents::out,
+ dependent_lval_map::in, dependent_lval_map::out) is det.
+
+record_known_lval_rval(TargetLval, SourceRval,
+ KnownContentsMap0, KnownContentsMap,
+ DepLvalMap0, DepLvalMap) :-
+ ( map__search(KnownContentsMap0, TargetLval, OldRval) ->
+ % TargetLval no longer depends on the lvals in OldRval;
+ % it depends on the lvals in SourceRval instead. If any lvals
+ % occur in both, we delete TargetLval from their entries here
+ % and will add it back in a few lines later on.
+ %
+ % TargetLval still depends on the lvals inside it.
+ code_util__lvals_in_rval(OldRval, OldSubLvals),
+ list__foldl(make_not_dependent(TargetLval), OldSubLvals,
+ DepLvalMap0, DepLvalMap1)
+ ;
+ DepLvalMap1 = DepLvalMap0
+ ),
+ code_util__lvals_in_lval(TargetLval, TargetSubLvals),
+ code_util__lvals_in_rval(SourceRval, SourceSubLvals),
+ list__append(TargetSubLvals, SourceSubLvals, AllSubLvals),
+ list__foldl(make_dependent(TargetLval), AllSubLvals,
+ DepLvalMap1, DepLvalMap),
+ map__set(KnownContentsMap0, TargetLval, SourceRval,
+ KnownContentsMap).
+
+:- pred make_not_dependent(lval::in, lval::in,
+ dependent_lval_map::in, dependent_lval_map::out) is det.
+
+make_not_dependent(Target, SubLval, DepLvalMap0, DepLvalMap) :-
+ ( map__search(DepLvalMap0, SubLval, DepLvals0) ->
+ set__delete(DepLvals0, Target, DepLvals),
+ map__det_update(DepLvalMap0, SubLval, DepLvals, DepLvalMap)
+ ;
+ DepLvalMap = DepLvalMap0
+ ).
+
+:- pred make_dependent(lval::in, lval::in,
+ dependent_lval_map::in, dependent_lval_map::out) is det.
+
+make_dependent(Target, SubLval, DepLvalMap0, DepLvalMap) :-
+ ( map__search(DepLvalMap0, SubLval, DepLvals0) ->
+ set__insert(DepLvals0, Target, DepLvals),
+ map__det_update(DepLvalMap0, SubLval, DepLvals, DepLvalMap)
+ ;
+ DepLvals = set__make_singleton_set(Target),
+ map__det_insert(DepLvalMap0, SubLval, DepLvals, DepLvalMap)
+ ).
cvs diff: Diffing compiler/notes
Index: compiler/notes/compiler_design.html
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/notes/compiler_design.html,v
retrieving revision 1.71
diff -u -b -r1.71 compiler_design.html
--- compiler/notes/compiler_design.html 2002/03/04 07:31:38 1.71
+++ compiler/notes/compiler_design.html 2002/03/07 09:43:10
@@ -802,6 +802,9 @@
<li> introduction of local C variables (use_local_vars.m) <br>
+<li> removal of redundant assignments, i.e. assignments that assign a value
+that the target location already holds (reassign.m) <br>
+
</ul>
<p>
cvs diff: Diffing debian
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.298
diff -u -b -r1.298 user_guide.texi
--- doc/user_guide.texi 2002/03/03 12:12:51 1.298
+++ doc/user_guide.texi 2002/03/07 09:43:11
@@ -5385,6 +5385,11 @@
Disable branch delay slot optimizations.
@sp 1
+ at item --optimize-reassign
+ at findex --optimize-reassign
+Optimize away assignments to locations that already hold the assigned value.
+
+ at sp 1
@item --optimize-repeat @var{n}
@findex --optimize-repeat
Iterate most optimizations at most @var{n} times (default: 3).
cvs diff: Diffing extras
cvs diff: Diffing extras/aditi
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/concurrency
cvs diff: Diffing extras/curs
cvs diff: Diffing extras/curs/samples
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/graphics
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/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/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
cvs diff: Diffing extras/morphine
cvs diff: Diffing extras/morphine/non-regression-tests
cvs diff: Diffing extras/morphine/scripts
cvs diff: Diffing extras/morphine/source
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/quickcheck
cvs diff: Diffing extras/quickcheck/tutes
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/stream
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing extras/xml
cvs diff: Diffing extras/xml/samples
cvs diff: Diffing java
cvs diff: Diffing java/library
cvs diff: Diffing java/runtime
cvs diff: Diffing library
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/diff
cvs diff: Diffing samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing samples/tests
cvs diff: Diffing samples/tests/c_interface
cvs diff: Diffing samples/tests/c_interface/c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/tests/c_interface/mercury_calls_c
cvs diff: Diffing samples/tests/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/tests/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/tests/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/tests/diff
cvs diff: Diffing samples/tests/muz
cvs diff: Diffing samples/tests/rot13
cvs diff: Diffing samples/tests/solutions
cvs diff: Diffing samples/tests/toplevel
cvs diff: Diffing scripts
cvs diff: Diffing tests
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/structure_reuse
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/purity
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
cvs diff: Diffing util
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list