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