What about memory operations (globals, heap values) ?
- SSA doesn't work directly.
- Need to model dependences, changes in values.
Dependences (order of operations):
Example:
g.a = 0;
g.b = 1;
g.a = g.b + 2;
g.b = g.a + 3;
Last two statements must be done in order due to:
- flow dependence (write-before-read) on g.a
- anti-dependence (read-before-write) on g.b
First and third statements must be done in order due to:
- output dependence (write-before-write) on g.a
When can we do common subexpression elimination to save loads?
Example:
g.a = 10;
h.a = 20;
if (g.a == 10) ... // can only avoid if g and h don't alias.
g.b = 20;
if (g.a == 10) ... // can always avoid load here given
SWIFT compiler: good example of complete system based on SSA.
To cope with memory operations, they add explicit "threading" store variables.
Example:
int method (int a[], int b[]) {
arr_store(a,0,10);
arr_store(b,0,20);
return arr_fetch(a,0);
}
becomes
(int,Store) method (int a[], int b[], Store S0) {
S1 = arr_store(a,0,10,S0);
S2 = arr_store(b,0,20,S1);
return (arr_fetch(a,0,S2),S2);
}
where S0,S1,S2 are pseudo-values representing the global store.
Can now continue to use congruence testing to detect redundant computations.
Can use *alias analysis* to improve understanding of dependence between memory operations.
In above example, a and b might be the same array, e.g., called as method(c,c).
Simplest form of alias analysis just uses types:
int method (int a[], short b[]) {
arr_store(a,0,10);
arr_store(b,0,20);
return arr_fetch(a,0);
}
Now know a and b cannot be aliased to the same array.
A more sophisticated alias analysis (requiring dataflow analysis) tracks creation points:
int method() {
int a[] = new a[10];
int b[] = new b[10];
arr_store(a,0,10);
arr_store(b,0,20);
return arr_fetch(a,0);
}
Once again, a and b cannot be aliased to the same array, even though
they have the same type.
Can represent the results of this analysis by changing the store argument
dependencies:
S1 = arr_store(a,0,10,S0);
S2 = arr_store(b,0,20,S0); // not S1 !
S3 = phi(S1,S2);
return (arr_fetch(a,0,S1), // not S2 !
S3);
Alias Analysis
Aliasing problems arise:
- in heap for Java
- more broadly in CBR languages
- everywhere in C!
Divide memory pointers into guaranteed non-aliasaed partitions.
Can use:
- types
- field names
- known objects
Note interaction with class analysis, escape analysis
Other memory optimizations
- Scalar replacement - poromoting a field to a "local"
- Cache locality - inlining and splitting