580 likes | 637 Views
Explore the challenge of phase ordering optimizations, ways to address them, and the benefits of modular composition in compiler design.
E N D
const prop followed by unreachable code elimination const prop again Phase ordering problem • Optimizations can interact in mutually beneficial ways, and no order exploits all of these interactions. • Classic example: constant propagation and unreachable code elimination. x := 11; DoSomething(); y := x; // value of y? x := 11; if (x == 11) { DoSomething(); } else { DoSomethingElse(); x := x + 1; } y := x; // value of y? true x := 11; DoSomething(); y := 11;
One known solution: Iterate individual analyses until the results don’t change x := 11; do { if (x == 11) { DoSomething(); } else { DoSomethingElse(); x := x + 1; } } while (...) y := x; // value of y? • Compiler is slow. • In the presence of loops in the source program, might not yield best possible results.
Monolithic Super-Analysis Another known solution: hand writtensuper-analysis • Examples: • conditional constant propagation [Wegman and Zadeck 91] • class analysis, splitting and inlining [Chambers and Ungar 90] • const prop and pointer analysis [Pioli and Hind 99] • Lose modularity: • difficult to write, reuse, and extend such analyses
Composition Framework Ideally... • ... we want to: • Write analyses modularly • Exploit mutually beneficial interactions • Have a fast compiler • We present a framework that achieves this.
The key to modular composition • Traditionally, optimizations are defined in two parts: • A dataflow analysis. • Rules for transforming the program representation after the analysis is solved. • The key insight is to merge these two parts: • Dataflow functions return either a dataflow value OR a replacement graph with which to replace the current statement.
Flow function returning a dataflow value [ ... ] y := 5 PROPAGATE [ ..., y → 5]
y := 5 REPLACE Flow function returning a replacement graph Step 1: Initialize input edges with dataflow information Replacement graph [x → 3] [x → 3] y := x+2
y := 5 Flow function returning a replacement graph Step 2: Perform recursive dataflow analysis on the replacement graph Step 1: Initialize input edges with dataflow information [x → 3] [x → 3] y := x+2 PROPAGATE [x → 3,y → 5]
y := 5 Flow function returning a replacement graph Step 2: Perform recursive dataflow analysis on the replacement graph Step 1: Initialize input edges with dataflow information [x → 3] [x → 3] y := x+2 PROPAGATE [x → 3,y → 5] [x → 3,y → 5] Step 3: Propagate dataflow information from output edges.
Flow function returning a replacement graph • Replacement graphs: • used to compute outgoing dataflow information for the current statement. • a convenient way of specifying what might otherwise be a complicated flow function. • Replacement graphs: • used to compute outgoing dataflow information for the current statement. [x → 3] y := x+2 [x → 3,y → 5]
Flow function returning a replacement graph • Soundness requirement: • Replacement graph must have the same concrete semantics as the original statement, but only on concrete inputs that are consistent with the current dataflow facts. [x → 3] y := x+2 [x → 3,y → 5]
Flow function returning a replacement graph Let’s assume we’ve reached a fixed point. [x → 3] y := x+2 [x → 3,y → 5]
Flow function returning a replacement graph Let’s assume we’ve reached a fixed point. [x → 3] y := x+2 y := 5 [x → 3,y → 5]
Flow function returning a replacement graph Let’s assume we’ve reached a fixed point. • Replacement graphs: • used to transform the program once a fixed point has been reached. [x → 3] y := 5 [x → 3,y → 5]
Iterative analysis example Now, let’s assume we haven’t reached a fixed point. [x → 3] [x →T] y := x+2 [x → 3,y → 5]
Iterative analysis example Now, let’s assume we haven’t reached a fixed point. [x → 3] [x →T] y := x+2 PROPAGATE [x → 3,y → 5] [x →T,y →T]
Branch folding example if (x == 11) F T
REPLACE Branch folding example [x → 11] [x → 11] if (x == 11) F T
Branch folding example [x → 11] [x → 11] if (x == 11) [x → 11] [x → 11] F T
Branch folding example [x → 11] if (x == 11) [x → 11] F T
Constant Propagation x := new C; do { b := x instanceof C; if (b) { x := x.foo(); } else { x := new D; } } while (...) class A { A foo() { return new A; } }; class C extends A { A foo() { return self; } }; class D extends A { }; Class Analysis Inlining Unreachable code elimination Composing several analyses
x := new C merge b := x instanceof C if (b) F T x := new D x := x.foo() merge while(…)
x := new C PROPAGATE PROPAGATE PROPAGATE PROPAGATE [x → {C}] [x →T] T T merge b := x instanceof C if (b) F T x := new D x := x.foo() merge while(…)
x := new C PROPAGATE PROPAGATE PROPAGATE PROPAGATE PROPAGATE ([x →T], [x → {C}], T, T) [x → {C}] [x →T] T T merge b := x instanceof C if (b) F T x := new D x := x.foo() merge while(…)
x := new C ([x →T], [x → {C}], T, T) merge PROPAGATE ([x →T], [x → {C}], T, T) b := x instanceof C if (b) F T x := new D x := x.foo() merge while(…)
x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C PROPAGATE [x →T, b →T] if (b) F T x := new D x := x.foo() merge while(…)
b := true REPLACE x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) ([x →T], [x → {C}], T, T) b := x instanceof C [x →T, b →T] if (b) F T x := new D x := x.foo() merge while(…)
b := true x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T], [x → {C}], T, T) PROPAGATE if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) F T x := new D x := x.foo() merge while(…)
b := true x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T], [x → {C}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) F T x := new D x := x.foo() merge while(…)
x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) • Replacement graph is analyzed by composed analysis. • When one analysis chooses a replacement graph, other analyses see it immediately. • Analyses communicate implicitly through graph transformations b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) F T x := new D x := x.foo() merge while(…)
REPLACE x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) σ if (b) F T x := new D x := x.foo() merge while(…)
x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) σ σ if (b) F T x := new D x := x.foo() merge while(…)
( , , , ) x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) σ σ σ if (b) σ F T x := new D x := x.foo() merge while(…)
( , , , ) ( , , , ) x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) σ σ if (b) σ σ F T x := new D x := x.foo() merge while(…)
( , , , ) x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) F T x := new D x := x.foo() merge while(…)
REPLACE ( , , , ) ( , , , ) x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) F T x := new D x := x.foo() merge while(…)
( , , , ) ( , , , ) ( , , , ) ( , , , ) x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) F T x := new D x := x.foo() merge while(…)
( , , , ) ( , , , ) x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) F T x := new D x := x.foo() merge while(…)
x := C::foo(x) REPLACE ( , , , ) ( , , , ) x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) σ σ F T x := new D x := x.foo() merge while(…)
x := C::foo(x) x := x ( , , , ) ( , , , ) REPLACE x := new C class C extends A { A foo() { return self; } } ([x →T], [x → {C}], T, T) merge σ σ ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) σ F T x := new D x := x.foo() merge while(…)
x := C::foo(x) x := x ( , , , ) ( , , , ) x := new C ([x →T], [x → {C}], T, T) merge σ ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) σ F T x := new D x := x.foo() σ PROPAGATE merge σ while(…)
x := C::foo(x) x := x ( , , , ) ( , , , ) x := new C ([x →T], [x → {C}], T, T) merge σ ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) σ F T x := new D x := x.foo() σ merge σ σ while(…)
x := C::foo(x) ( , , , ) ( , , , ) x := new C ([x →T], [x → {C}], T, T) merge σ ([x →T], [x → {C}], T, T) b := x instanceof C σ σ ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) σ F T x := new D x := x.foo() merge while(…)
x := C::foo(x) ( , , , ) ( , , , ) x := new C ([x →T], [x → {C}], T, T) merge σ ([x →T], [x → {C}], T, T) b := x instanceof C σ ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) σ F T x := new D x := x.foo() ([x →T, b → true], [x → {C}, b →{Bool}], T, T) merge while(…)
( , , , ) ( , , , ) x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) F T x := new D x := x.foo() ([x →T, b → true], [x → {C}, b →{Bool}], T, T) merge while(…)
( , , , ) ( , , , ) x := new C ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) F T x := new D x := x.foo() ([x →T, b → true], [x → {C}, b →{Bool}], T, T) merge PROPAGATE ([x →T, b → true], [x → {C}, b →{Bool}], T , T) while(…)
( , , , ) ( , , , ) x := new C ([x →T], [x → {C}], T, T) ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) F T x := new D x := x.foo() ([x →T, b → true], [x → {C}, b →{Bool}], T, T) merge ([x →T, b → true], [x → {C}, b →{Bool}], T , T) while(…) PROPAGATE ([x →T, b → true], [x → {C}, b →{Bool}], T, T)
( , , , ) ( , , , ) x := new C ([x →T], [x → {C}], T, T) ([x →T], [x → {C}], T, T) merge ([x →T], [x → {C}], T, T) b := x instanceof C ([x →T, b → true], [x → {C}, b →{Bool}], T, T) if (b) ([x →T, b → true], [x → {C}, b →{Bool}], T, T) F T x := new D x := x.foo() ([x →T, b → true], [x → {C}, b →{Bool}], T, T) merge ([x →T, b → true], [x → {C}, b →{Bool}], T , T) while(…) ([x →T, b → true], [x → {C}, b →{Bool}], T, T)