Posted to tcl by kbk at Mon Jan 13 20:12:06 GMT 2014view pretty

# revprop --
#
#	"Reverse copy propagation"
#
# Parameters:
#	quads - Sequence of quadruples (three-address instructions)
#	vnames - List of variable names in order by variable indices
#
# Results:
#	Returns the given bytecode sequence, with unneeded code
#	elided.
#
# This pass functions as a cleanup for sequences that look like:
#
#	v := ...			A
#	v2 := v				B
#	... code that uses v2 ...
#
# The conditions for the optimization are:
#	all reachable uses of A: v:=... are copies of the form v2:=v
#	all reachable uses of A: v:=... copy to the same variable v2
#	no reachable use of A: v:=... has a reaching definition of v other than
#	A.
#
# In this case, the operation at A can be replaced with v2 :- ...,
# and all the copies B can be elided

proc revprop {quads vnames} [bdd::datalog::compileProgram db {
    set dead {}
} {

    % An assignment of variable v at statement st can be replaced with
    % variable v2 to eliminate a copy of v to v2 at statement st2 if
    % there's no reason not to do so.

    revprop(v, v2, st, st2) :- reaches(v, st, st2),
                               isCopy(st2),
                               writes0(st2, v2),
                               !cantRevprop(v, v2, st).

    % We cannot replace v with v2 in st if that would spoil any reachable
    % use of v or v2 from st.

    cantRevprop(v, v2, st) :- reaches(v, st, st2), cantRevprop2(v, v2, st ,st2).
    cantRevprop(_, v2, st) :- flowsPast(v2, st, st2), reads0(st2, v2).

    % A use of v in st2 is spoilt by this optimization if:
    %   st2 isn't a copy,
    %   st2 doesn't copy v to v2
    %   st2 has a reaching definition of v that isn't st.

    cantRevprop2(_, _, _, st2) :- !isCopy(st2).
    cantRevprop2(_, v2, _, st2) :- !writes0(st2, v2).
    cantRevprop2(v, _, st, st2) :- reaches(v, st3, st2), st3 != st.

    revprop(v, v2, st, st2)?

} d {
    set v [lindex $vnames [dict get $d v]]
    set v2 [lindex $vnames [dict get $d v2]]
    set st [dict get $d st]
    set st2 [dict get $d st2]
    set q [lindex $quads $st]
    lset quads $st 1 $v2
    dict set dead $st2 {}
} {
    # Remove the instructions that this optimization has killed
    tailcall quads-remove-dead $quads $dead
}]