|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object scale.score.SSA
public class SSA
This class converts a Scribble CFG into the SSA form of the CFG.
$Id: SSA.java,v 1.191 2007-10-04 19:58:19 burrill Exp $
Copyright 2008 by the
Scale Compiler Group,
Department of Computer Science
University of Massachusetts,
Amherst MA. 01003, USA
All Rights Reserved.
See page 447 in Modern Compiler Implementation in Java by Appel, Cambridge, 1998 or Kathryn S. McKinley's CS 710 lecture notes.
The algorithm creates new Clef variable declarations for the renamed variables generated for the SSA form. The new variable declarations are named by appending the original name with a '#' followed by a sequence of digits. Phi operations are inserted into the CFG and reference the renamed variables.
Our baseline technique for including alias information in SSA form is described in the paper by Chow et. al. It helps to understand this paper to understand our extensions.
The main contribution by Chow et. al. is the use of virtual variables to represent indirect operations which unifies the treatment of indirect and scalar variables for SSA analyses and optimizations. The treatment of aliases is based upon the work by Choi et. al. which distinguishes between MayDefs (preserving definitions or weak updates), MustDefs, and MayUses. Chow et. al. add Chi and Mu operators to model MayDef and MayUse effects, respectively. The Chi and Mu operators work on virtual variables rather than scalar variables. Thus, a definition (Chi) of a virtual variable is a definition of a group of actual variables that share similar alias characteristics. Correspondingly, a Mu operator represents a use.
A virtual variable represents a group of program, or user, variables that have similar alias characteristics. We originally used Steensgaard's alias analysis algorithm to create these groups which we also call abstract locations (abstract location and virtual variable can be used interchangeably). For example, in the sequence, "p = &a; p = &b", a virtual variable is created to represent "a", "b", and "*p". This means that, conservatively, any use of "*p" may use "a" or "b". A very conservative approach may create one virtual variable for every user variable.
Our basic algorithm works as follows:
When the program is translated in SSA form, the virtual variables as as well as the user variables are renamed. This means that Phi nodes are created for the virtual variables and the virtual variables obey the single assignment rule of SSA form.
The scheme as described above works because each indirect variable (e.g., *p) represents at most one virtual variable (i.e., p points to at most one abstract location). Unfortunately, the scheme does not work when p may point to multiple locations. In the Shapiro/Horwitz algorithm, p may point to multiple locations. We need to extend our alias SSA representation to handle the Shapiro analysis.
Again, using the example from above, let's say the Shapiro algorithm partitions the user variables such that "p"->{"a"} or "p"->{"b"} (i.e., "p" points to "a" or to "b", but "a" and "b" are not aliases). This is different from the Steensgaard algorithm in which "p"->{"a", "b"} (i.e., "a" and "b" are aliases). To incorporate the Shapiro results into SSA form, we need a different scheme to represent the MayUse and MayDefs. For example, a use/def of "a" is not a use/def of "b", but a use/def of "*p" may be a use/def of "a" or "b".
We extend the basic scheme for including alias information by changing the meaning of a virtual variable. In our new scheme, a virtual variable represents multiple locations and we attach information to the variable to distinguish between the locations. We assign a superset and subset name to the virtual variable (yes, we need better names). Essentially, the superset name represents indirect variables (e.g., *p), and the subset name represents user variables. In our example, we can represent the relations among the variables using set notation, where a virtual variable represents the set {*p, {"a"}, {"b"}}. This means, "a" and "b" belong to distinct subsets but they are members of the same enclosing set which includes "*p".
In theory, our extended algorithm for adding alias information to SSA isn't much different that the original.
Note that the MayDef/Use links (and SSA numbers) ignore the subset name. But, the optimizations must check for the subset names when propagating information. Analysis information should only be propagated when the virtual variables are equivalent. Two virtual variables are equivalent under the following conditions: 1) The subset and superset names are the same, 2) One virtual variable only contains a superset name and both the superset names are the same.
The superset and subset distinctions are intended to help the optimization phases. We only want to propagate information for equivalent virtual variables. That is, when propagation information associated with subset name, we ignore different subset names but we must perform an appropriate action for a virtual variable with the same subset name or superset name. This is the main difference between the old scheme and the new scheme. In the old scheme, analysis information is always propagated down may def/use links. But, in the new scheme, we selectively propagate analysis information down the may def/use links.
Using our example, we create 3 virtual variables, _v#p, _v#p.a, and _v#p.b (our implementation actually uses numbers, so it's _v#0.0, _v#0.1 and _v#0.2, but here letters are used to hopefully make things clearer. The description of constant propagation (CP) below is not meant to match the algorithm in Scale. Instead, it is an attempt to illustrate how an optimization phase should use our SSA extensions.
We use the following program to illustrate the extensions (given that "p"->{"a"}, or "p"->{"b"}).
a = 1; b = 2; = *p; = b; = a;Using Steensgaard analysis (or Shapiro's analysis with 1 category), we cannot propagate 1 to the use of "a" or 2 to the use of "b". But, with Shapiro's analysis with multiple categories we can. After converting to SSA form:
a = 1; _v#p.a_1 = Chi(_v#p.a) b = 2; _v#p.b_2 = Chi(_v#p.b_1) = *p; Mu(_v#p_2) = b; Mu(_v#p.b_2) = a; Mu(_v#p.a_2)In the example, CP associates 1 with _v#p.a_1 and _v#p.b_1 after statement 1. The may def-use link for _v#p.a_1 points to the use of _v#p.b_1 at statement 2. Since the virtual variable at statement 2 is not equivalent to the virtual variable at statement 1, CP does not propagate the value 1 to _v#p.b_1. Instead, CP associates 2 with _v#p.b_2 and _v#p_2. Then, CP follows the may def-use links to the Mu nodes at statements 3, 4, 5. At statement 3, _v#p_2 is 2 so the use of "*p" can be replaced by 2. The same action occurs at statement 4 for "b". At statement 4, "a" can be replaced by 1.
If there is control flow:
if () a = 1; _v#p.a_1 = Chi(_v#p.a) else b = 2; _v#p.b_2 = Chi(_v#p.b_1) _v#p_3 = Phi(_v#p_1,_v#p_2) = *p; Mu(_v#p_3) = b; Mu(_v#p.b_3) = a; Mu(_v#p.a_3)In this case, CP associates not a constant with _v#p_3, _v#p.a_3, and _v#p.b_3 at the Phi node. Then, none of the uses can be replaced by a constant.
Note - in the presence of control flow, we only need to add Phi functions for superset names because the definition of a superset is equivalent to definitions for each of the subsets.
Fred Chow, Sun Chan, Shin-Ming Liu, Raymond Lo and Mark Streich. Effective Representation of Aliases and Indirect Memory Operations in SSA Form, In Compiler Construction, 6th International Conference, CC'96, Linkoping, Sweden, Apr 1996.
Field Summary | |
---|---|
static boolean |
classTrace
True if traces are to be performed. |
static boolean |
doBackPropagation
Set true to run special back propagation algorithm. |
static boolean |
inhibitCoalescing
Set true to inhibit variable coalescing. |
static boolean |
onlyBPtoPhis
Control back propagation. |
static int |
rpCase
Specify the level of "extra branch" elimination to apply when removing phi functions. |
Constructor Summary | |
---|---|
SSA(Scribble scribble,
PlaceIndirectOps pio)
Compute the dominance frontier for each node in a CFG. |
Method Summary | |
---|---|
static int |
acnbbCnt()
Return the count of the number of times we avoided creating a new basic block when exiting SSA form. |
static int |
acnbbfCnt()
Return the count of the number of times we failed to avoid creating a new basic block because of variable coalescing. |
void |
addNewLoad(LoadDeclValueExpr load)
Do any additional processing required when a load of a value is added to the CFG while it is in SSA form. |
void |
addNewNode(Chord s)
Do any additional processing required when a node is added to the CFG while it is in SSA form. |
void |
addNewNodes(Vector<Chord> chords)
Do any additional processing required when nodes are added to the CFG while it is in SSA form. |
void |
buildSSA()
Build the SSA form with alias information. |
static int |
callSites()
Return the number of call sites. |
static int |
coalesced()
Return the count of the number of times a renamed variable was coalsced. |
void |
coalesceVariables()
Coalesce variables, created by going into SSA form, into the original variable if there is no interference in the live ranges. |
protected MayDef |
createMayDefInfo(Expr expr,
VirtualVar v)
Create a may definition expression to repesent the aliasing characteristics of an expression. |
protected MayUse |
createMayUseInfo(Expr expr,
VirtualVar v)
Create a may use expression to repesent the aliasing characteristics of an expression. |
VariableDecl |
createRenamedVariable(VariableDecl original,
boolean addOrig)
Return a new RenamedVariableDecl. |
static int |
deadCFGNodes()
Return the number of dead nodes removed. |
static int |
deadVariables()
Return the count of variables removed because they were coalesced. |
static int |
newCFGNodes()
Return the number of new nodes created. |
static int |
newVariableDecls()
Return the current number of new variable declarations created. |
static int |
notCoalesced()
Return the count of the number of times a renamed variable was not coalsced. |
void |
removePhis()
Remove any PhiExprs still in the Scribble graph. |
static int |
vars()
Return the number of variables processed. |
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Field Detail |
---|
public static boolean classTrace
public static int rpCase
public static boolean inhibitCoalescing
public static boolean doBackPropagation
public static boolean onlyBPtoPhis
Constructor Detail |
---|
public SSA(Scribble scribble, PlaceIndirectOps pio)
scribble
- is the Scribble graph to be transformedpio
- is null or the class to use to process new CFG nodes addedDominanceFrontier
Method Detail |
---|
public static int newVariableDecls()
public static int deadVariables()
public static int newCFGNodes()
public static int deadCFGNodes()
public static int vars()
public static int callSites()
public static int acnbbCnt()
public static int acnbbfCnt()
public static int coalesced()
public static int notCoalesced()
public void addNewNode(Chord s)
public void addNewLoad(LoadDeclValueExpr load)
public void addNewNodes(Vector<Chord> chords)
public final void buildSSA()
public final VariableDecl createRenamedVariable(VariableDecl original, boolean addOrig)
protected MayDef createMayDefInfo(Expr expr, VirtualVar v)
expr
- the expression that the information is added tov
- the virtual variable that the may def is associated with
protected MayUse createMayUseInfo(Expr expr, VirtualVar v)
expr
- the expression that the information is added tov
- the virtual variable that the may def is associated with
public final void removePhis()
This uses a different algorithm from the Briggs algorithm to handle both the "Lost Copy" and "Swap" problem when removing Phi functions from SSA form.
This is my algoritm for removing phi functions from a CFG in SSA form It is cheaper than the algorithm in Briggs, et al for our representation of basic blocks. The Briggs algorithm stops at each basic block and looks for phi functions in each of the block's successors. It then inserts copies at the end of the block for each phi function in each of the block's successors. For our representation, this means that a particular block is scanned from beginning to end once per in-coming CFG edge.
In my algorithm, I do the insert of the copy statements in the predecessors of the block as in the naive algorithm used by Cytron. This eliminates the multiple scan of each basic block for its phi functions.
Before the inserts are done, I order the copy statements to eliminate the "Lost Copy" problem. Then, to eliminate the "Swap" problem, when the destination of one phi function is used as the source of another phi function and that second phi function's destination is also used by another phi function, I insert copies to temporaries and copies from temporaries.
For example, consider the phi functions
a1 <- phi(a2, b1) c1 <- phi(c2, c3) b1 <- phi(b2, a1) x1 <- phi(x2, a1)These are ordered first for the second in-coming CFG edge as
c1 <- phi(c2, c3) x1 <- phi(x2, a1) a1 <- phi(a2, b1) b1 <- phi(b2, a1)because the x1 and c1 phi function destinations are not used by another phi function. Then, copies are inserted along the two in-coming CFG edges as
left edge right edge ---------------------------------- a1 <- a2 c1 <- c3 c1 <- c2 x1 <- a1 b1 <- b2 a_t_1 <- b1 x1 <- x2 b_t_1 <- a1 a1 <- a_t_1 b1 <- b_t_1This algorithm is more conservative than necessary because it assumes that if a phi function has a destination that is used by another phi function whose destination is used by ..., then the two phi functions MAY exhibit the "Swap" problem. It would be possible, with more effort, to order these phi functions to eliminate the need to use some of the additional temporaries in some cases. For example, in the case
x1 <- phi(x2, x3) y1 <- phi(y2, x1) z1 <- phi(z2, y1)the copies for the second edge would be
z1 <- y1 x_t_0 <- x3 y_t_0 <- x1 x1 <- x_t_0 y1 <- y_t_0This could be reduced to
z1 <- y1 x_t_0 <- x3 y1 <- x1 x1 <- x_t_0I believe that this case will be rare enough that the cost of detecting it is not warranted and that the extra copies will not be a problem.
public final void coalesceVariables()
In the interest of execution speed, this algorithm does not preserve the may-def information.
|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |