Lift Invariant Assignments Using TXL
Software Transformation Systems
TXL solution to
TIL Chairmarks #3.1, Move all invariant assignments outside of while loops.
This is a simple demonstration of the basics of data flow checking and code motion using TXL. For TIL this is not very challenging. In real languages and applications, more sophisticated data flow and alias analysis across procedures is needed. In TXL this more sophisticated analysis is done using source code markup to localize dependency information before actual code movement.
--
JamesCordy - 03 Nov 2005
File "TILcodemotion.Txl"
% Lift independent assignments outside of TIL while loops
% J.R. Cordy, November 2005
% This TXL program will optimize a TIL program by moving all assignments
% not dependent on computation inside while loops to the outside.
% For loops can be done similarly, but are not handled by this program.
% Based on the TIL grammar
include "TIL.Grm"
% Lift all independent assignments out of loops
rule main
% Find every loop
replace [statement*]
while Expn [expression] do
Body [statement*]
'end
Rest [statement*]
% Construct a list of all the top-level assignments in it
construct AllAssignments [statement*]
Body [deleteNonAssignments]
% Construct a copy of the loop to work on
construct LiftedLoop [statement*]
while Expn do
Body
'end
% Only proceed if there are assignments left that can be lifted out
% The [?loopLift] form tests if the pattern of the [loopLift] rule can be matched -
% "each AllAssignments" tests this for any of the top-level internal assignments
where
LiftedLoop [?loopLift Body each AllAssignments]
% If the above guard succeeds, some can be moved out, so go ahead and move them,
% replacing the original loop with the result
by
LiftedLoop [loopLift Body each AllAssignments]
[. Rest]
end rule
% Attempt to lift a given assignment outside the loop
function loopLift Body [statement*] Assignment [statement]
deconstruct Assignment
X [id] := E [expression];
% Extract a list of all the identifiers used in the expression
construct IdsInExpression [id*]
_ [^ E]
% Replace the loop and its contents
replace [statement*]
Loop [statement*]
% We can only lift the assignment out if all the identifiers in its
% expression are not assigned in the loop ...
where not
Loop [assigns each IdsInExpression]
% ... and X itself is assigned only once
deconstruct * Body
X := _ [expression];
Rest [statement*]
where not
Rest [assigns X]
% ... and the the effect of it does not wrap around the loop
construct PreContext [statement*]
Body [deleteAssignmentAndRest X]
where not
PreContext [refers X]
% Now lift out the assignment
by
Assignment
Loop [deleteAssignment Assignment]
end function
% Utility rules used above
% Delete a given assignment statement from a scope
function deleteAssignment Assignment [statement]
replace * [statement*]
Assignment
Rest [statement*]
by
Rest
end function
% Delete all non-assignment statements in a scope -
% given a scope, yields the assignments only
rule deleteNonAssignments
replace [statement*]
S [statement]
Rest [statement*]
deconstruct not S
_ [assignment_statement]
by
Rest
end rule
% Delete everything in a scope from the first assignment to X on -
% given a scope and X, yields the context of the first assignment to X
function deleteAssignmentAndRest X [id]
replace * [statement*]
X := E [expression];
Rest [statement*]
by
% nada
end function
% Condition - given a scope, does the scope assign to the identifier?
function assigns Id [id]
match * [assignment_statement]
Id := Expn [expression];
end function
% Condition - given a scope, does the scope refer to the identifier?
function refers Id [id]
match * [id]
Id
end function
Example run: "lift.til" is a meaningless little program with lots of data dependencies, lots of opportunities for code motion, and all global declarations for demonstration purposes only.
<linux> cat lift.til
var x; var y; var z; var a; var b; var c;
var d; var e; var j; var k; var m; var n; var r;
y := 1;
z := 2;
while 1 do
x := y + z;
a := 3;
z := 5;
j := 0;
while j != 100 do
r := 99;
d := 7;
k := a + z;
b := j * z;
d := (y + z) * d;
e := (x + z) * r;
j := j + 1;
end
c := a + y;
m := y * b;
n := r * y;
end
<linux> txl lift.til TILcodemotion.Txl
TXL v10.4a (15.6.05) (c)1988-2005 Queen's University at Kingston
Compiling TILcodemotion.Txl ...
Parsing lift.til ...
Transforming ...
var x;
var y;
var z;
var a;
var b;
var c;
var d;
var e;
var j;
var k;
var m;
var n;
var r;
y := 1;
z := 2;
a := 3;
c := a + y;
r := 99;
n := r * y;
while 1 do
x := y + z;
z := 5;
j := 0;
k := a + z;
e := (x + z) * r;
while j != 100 do
d := 7;
b := j * z;
d := (y + z) * d;
j := j + 1;
end
m := y * b;
end
<linux>