Post on 22-Dec-2015
Pointer analysis
Flow insensitive loss of precision
S1: l := new Cons
p := l
S2: t := new Cons
*p := t
p := t
l
t
S1
p
S2
l
t
S1
p
S2
l
t
S1
p
S2
l
t
S1
p
S2
Flow-sensitive SolnFlow-insensitive Soln(Andersen)
l
t
S1
p
S2
Flow insensitive loss of precision
• Flow insensitive analysis leads to loss of precision!
main() { x := &y;
...
x := &z;}
Flow insensitive analysis tells us that xmay point to z here!
• However:– uses less memory (memory can be a big bottleneck to
running on large programs)– runs faster
Worst case complexity of Andersen
*x = yx
a b c
y
d e f
x
a b c
y
d e f
Worst case: N2 per statement, so at least N3 for the whole program. Andersen is in
fact O(N3)
New idea: one successor per node
• Make each node have only one successor.
• This is an invariant that we want to maintain.
x
a,b,c
y
d,e,f
*x = yx
a,b,c
y
d,e,f
x
*x = y
y
More general case for *x = y
x
*x = y
y x y x y
More general case for *x = y
x
x = *y
y
Handling: x = *y
x
x = *y
y x y x y
Handling: x = *y
x
x = y
y
x = &y
x y
Handling: x = y (what about y = x?)
Handling: x = &y
x
x = y
y x y x y
x = &y
x y x
y,…
x y
Handling: x = y (what about y = x?)
Handling: x = &y
get the same for y = x
Our favorite example, once more!
S1: l := new Cons
p := l
S2: t := new Cons
*p := t
p := t
1
2
3
4
5
Our favorite example, once more!
S1: l := new Cons
p := l
S2: t := new Cons
*p := t
p := t
l
S1
t
S2
p
l
S1
l
S1
p
l
S1
t
S2
p
l
S1,S2
tp
1
2
3
4
5
1 2
3
l
S1
t
S2
p
4
5
Flow insensitive loss of precision
S1: l := new Cons
p := l
S2: t := new Cons
*p := t
p := t
l
t
S1
p
S2
l
t
S1
p
S2
l
t
S1
p
S2
l
t
S1
p
S2
Flow-sensitiveSubset-based
Flow-insensitiveSubset-based
l
t
S1
p
S2
l
S1,S2
tp
Flow-insensitiveUnification-based
bar() { i := &a; j := &b; foo(&i); foo(&j); // i pnts to what? *i := ...; }
void foo(int* p) { printf(“%d”,*p);}
1234
Another example
bar() { i := &a; j := &b; foo(&i); foo(&j); // i pnts to what? *i := ...; }
void foo(int* p) { printf(“%d”,*p);}
i
a
j
b
p
i
a
i
a
j
b
i
a
j
b
p
i,j
a,b
p
1234
1 2
Another example
4
3
Steensgaard & beyond
• A well engineered implementation of Steensgaard ran on Word97 (2.1 MLOC) in 1 minute.
• One Level Flow (Das PLDI 00) is an extension to Steensgaard that gets more precision and runs in 2 minutes on Word97.
Correctness
Compilers have many bugs
• [Bug middle-end/19650] New: miscompilation of correct code• [Bug c++/19731] arguments incorrectly named in static member
specialization• [Bug rtl-optimization/13300] Variable incorrectly identified as a biv• [Bug rtl-optimization/16052] strength reduction produces wrong code• [Bug tree-optimization/19633] local address incorrectly thought to escape• [Bug target/19683] New: MIPS wrong-code for 64-bit multiply• [Bug c++/19605] Wrong member offset in inherited classes• Bug java/19295] [4.0 regression] Incorrect bytecode produced for bitwise
AND• …
Searched for “incorrect” and “wrong” in the gcc-bugs mailing list. Some of the results:
Total of 545 matches…And this is only for one month!On a mature compiler!
Compiler bugs cause problems
if (…) { x := …;} else { y := …;}…;
ExecCompiler
• They lead to buggy executables• They rule out having strong guarantees
about executables
The focus: compiler optimizations
• A key part of any optimizing compiler
Original program Optimization
Optimized program
The focus: compiler optimizations
• A key part of any optimizing compiler
• Hard to get optimizations right– Lots of infrastructure-dependent details– There are many corner cases in each optimization– There are many optimizations and they interact in
unexpected ways– It is hard to test all these corner cases and all these
interactions
Goals
• Make it easier to write compiler optimizations– student in an undergrad compiler course should be able
to write optimizations
• Provide strong guarantees about the correctness of optimizations– automatically (no user intervention at all)– statically (before the opts are even run once)
• Expressive enough for realistic optimizations
The Rhodium work
• A domain-specific language for writing optimizations: Rhodium
• A correctness checker for Rhodium optimizations
• An execution engine for Rhodium optimizations
• Implemented and checked the correctness of a variety of realistic optimizations
Broader implications
• Many other kinds of program manipulators:code refactoring tools, static checkers– Rhodium work is about program analyses and
transformations, the core of any program manipulator
• Enables safe extensible program manipulators– Allow end programmers to easily and safely extend
program manipulators– Improve programmer productivity
Outline
• Introduction
• Overview of the Rhodium system
• Writing Rhodium optimizations
• Checking Rhodium optimizations
• Discussion
Rhodium system overview
Checker
Written by programmer
Written by the Rhodium team
Rhodium Execution engine
RdmOpt
RdmOpt
RdmOpt
Rhodium system overview
Checker
Written by programmer
Written by the Rhodium team
Rhodium Execution engine
RdmOpt
RdmOpt
RdmOpt
Rhodium system overview
RdmOpt
RdmOpt
RdmOpt
Checker Checker Checker
CheckerChecker CheckerChecker CheckerChecker
Rhodium system overview
Exec
Compiler
Rhodium Execution engine
RdmOpt
RdmOpt
RdmOpt
if (…) { x := …;} else { y := …;}…;
Checker Checker Checker
The technical problem
• Tension between:– Expressiveness– Automated correctness checking
• Challenge: develop techniques– that will go a long way in terms of expressiveness– that allow correctness to be checked
Solution: three techniques
AutomaticTheoremProver
Rdm Opt
Verification Task
Checker
Show that for any original program:
behavior oforiginal program
=
behavior ofoptimized program
Verification Task
Solution: three techniques
AutomaticTheoremProver
Rdm Opt
Verification Task
Verification Task
Solution: three techniques
AutomaticTheoremProver
Rdm Opt
Verification Task
Verification Task
Solution: three techniques
1. Rhodium is declarative– declare intent using
rules– execution engine
takes care of the rest
AutomaticTheoremProver
Rdm Opt
Solution: three techniques
AutomaticTheoremProver
Rdm Opt
1. Rhodium is declarative– declare intent using
rules– execution engine
takes care of the rest
Solution: three techniques
1. Rhodium is declarative
2. Factor out heuristics– legal transformations– vs. profitable
transformations
AutomaticTheoremProver
Rdm OptHeuristics not
affecting correctnessPart that must be reasoned
about
Solution: three techniques
AutomaticTheoremProver
1. Rhodium is declarative
2. Factor out heuristics– legal transformations– vs. profitable
transformations
Heuristics not affecting correctness
Part that must be reasoned
about
Solution: three techniques
1. Rhodium is declarative
2. Factor out heuristics
3. Split verification task– opt-dependent– vs. opt-independent
AutomaticTheoremProver
opt-dependent
opt-independent
Solution: three techniques
1. Rhodium is declarative
2. Factor out heuristics
3. Split verification task– opt-dependent– vs. opt-independent
AutomaticTheoremProver
Solution: three techniques
AutomaticTheoremProver
1. Rhodium is declarative
2. Factor out heuristics
3. Split verification task– opt-dependent– vs. opt-independent
Solution: three techniques
AutomaticTheoremProver
1. Rhodium is declarative
2. Factor out heuristics
3. Split verification task
Result:• Expressive language• Automated
correctness checking
Outline
• Introduction
• Overview of the Rhodium system
• Writing Rhodium optimizations
• Checking Rhodium optimizations
• Discussion
MustPointTo analysis
c = a
a = &b
d = *c
a b
ca b
d = b
MustPointTo info in Rhodium
c = a
a = &b
mustPointTo (a, b)
ca b mustPointTo (a, b)
mustPointTo (c, b)
a b
d = *c
MustPointTo info in Rhodium
c = a
a = &b
d = *c
ca b mustPointTo (a, b)
mustPointTo (c, b)
c = a
a = &b
d = *c
ca b mustPointTo (a, b)
mustPointTo (c, b)
mustPointTo (a, b)a ba b mustPointTo (a, b)
MustPointTo info in Rhodium
define fact mustPointTo(X:Var,Y:Var)with meaning « X == &Y ¬
c = a
a = &b
d = *c
ca b mustPointTo (a, b)
mustPointTo (c, b)
mustPointTo (a, b)a b Fact correct on edge if:
whenever program execution reaches edge, meaning of fact evaluates to true in the program state
Propagating facts
c = a
a = &b
d = *c
ca b mustPointTo (a, b)
mustPointTo (c, b)
mustPointTo (a, b)a b
define fact mustPointTo(X:Var,Y:Var)with meaning « X == &Y ¬
a = &b
Propagating facts
c = a
a = &b
d = *c
ca b mustPointTo (a, b)
mustPointTo (c, b)
if currStmt == [X = &Y]then mustPointTo(X,Y)@outmustPointTo (a, b)a b
define fact mustPointTo(X:Var,Y:Var)with meaning « X == &Y ¬
Propagating facts
c = a
a = &b
d = *c
ca b mustPointTo (a, b)
mustPointTo (c, b)
mustPointTo (a, b)a b
define fact mustPointTo(X:Var,Y:Var)with meaning « X == &Y ¬
if currStmt == [X = &Y]then mustPointTo(X,Y)@out
c = ac = a
Propagating facts
a = &b
d = *c
ca b mustPointTo (a, b)
mustPointTo (c, b)
if mustPointTo(X,Y)@in ÆcurrStmt == [Z = X]
then mustPointTo(Z,Y)@out
mustPointTo (c, b)
mustPointTo (a, b)a b mustPointTo (a, b)
define fact mustPointTo(X:Var,Y:Var)with meaning « X == &Y ¬
if currStmt == [X = &Y]then mustPointTo(X,Y)@out
Propagating facts
c = a
a = &b
d = *c
ca b mustPointTo (a, b)
mustPointTo (c, b)
mustPointTo (a, b)a b
define fact mustPointTo(X:Var,Y:Var)with meaning « X == &Y ¬
if mustPointTo(X,Y)@in ÆcurrStmt == [Z = X]
then mustPointTo(Z,Y)@out
if currStmt == [X = &Y]then mustPointTo(X,Y)@out
d = *cd = *c
Transformations
c = a
a = &b
ca b mustPointTo (a, b)
mustPointTo (c, b) if mustPointTo(X,Y)@in Æ currStmt == [Z = *X]
then transform to [Z = Y]
mustPointTo (c, b)
d = b
mustPointTo (a, b)a b
define fact mustPointTo(X:Var,Y:Var)with meaning « X == &Y ¬
if mustPointTo(X,Y)@in ÆcurrStmt == [Z = X]
then mustPointTo(Z,Y)@out
if currStmt == [X = &Y]then mustPointTo(X,Y)@out
d = *c
Transformations
c = a
a = &b
ca b mustPointTo (a, b)
mustPointTo (c, b) if mustPointTo(X,Y)@in Æ currStmt == [Z = *X]
then transform to [Z = Y]d = b
mustPointTo (a, b)a b
define fact mustPointTo(X:Var,Y:Var)with meaning « X == &Y ¬
if mustPointTo(X,Y)@in ÆcurrStmt == [Z = X]
then mustPointTo(Z,Y)@out
if currStmt == [X = &Y]then mustPointTo(X,Y)@out
Profitability heuristics
Legal transformations
Subset of legal transformations
(identified by the Rhodium rules)
(actually performed)
Profitability Heuristics
Profitability heuristic example 1
• Inlining
• Many heuristics to determine when to inline a function– compute function sizes, estimate code-size increase,
estimate performance benefit
– maybe even use AI techniques to make the decision
• However, these heuristics do not affect the correctness of inlining
• They are just used to choose which of the correct set of transformations to perform
Profitability heuristic example 2
a := ...;
b := ...;
if (...) {
a := ...;
x := a + b;
} else {
...
}
x := a + b;
• Partial redundancy elimination (PRE)
Profitability heuristic example 2
• Code duplication
a := ...;
b := ...;
if (...) {
a := ...;
x := a + b;
} else {
...
}
x := a + b;x := a + b;
• PRE as code duplication followed by CSE
Profitability heuristic example 2
• Code duplication• CSE
a := ...;
b := ...;
if (...) {
a := ...;
x := a + b;
} else {
...
}
x :=
x := a + b;
a + b; x;
• PRE as code duplication followed by CSE
Profitability heuristic example 2
• Code duplication• CSE• self-assignment
removal
a := ...;
b := ...;
if (...) {
a := ...;
x := a + b;
} else {
...
}
x :=
x := a + b;
x;
• PRE as code duplication followed by CSE
a := ...;
b := ...;
if (...) {
a := ...;
x := a + b;
} else {
...
}
x := a + b;
Profitability heuristic example 2
Legal placements of x := a + b
Profitable placement
Semantics of a Rhodium opt
• Run propagation rules in a loop until there are no more changes (optimistic iterative analysis)
• Then run transformation rules to identify the set of legal transformations
• Then run profitability heuristics to determine set of transformations to perform
More facts
define fact mustNotPointTo(X:Var,Y:Var)with meaning « X &Y ¬
define fact hasConstantValue(X:Var,C:Const)with meaning « X == C ¬
define fact doesNotPointIntoHeap(X:Var)with meaning « X == null Ç 9 Y:Var . X == &Y ¬
More rules
if currStmt == [X = *A] Æ
mustNotPointToHeap(A)@in Æ8 B:Var . mayPointTo(A,B)@in )
mustNotPointTo(B,Y)
then mustNotPointTo(X,Y)@out
if currStmt == [Y = I + BE ] ÆvarEqualArray(X,A,J)@in ÆequalsPlus(J,I,BE)@in Æ: mayDef(X) Æ : mayDefArray(A) Æunchanged(BE)
then varEqualArray(X,A,Y)@out
More in Rhodium
• More powerful pointer analyses– Heap summaries
• Analyses across procedures– Interprocedural analyses
• Analyses that don’t care about the order of statements– Flow-insensitive analyses
Outline
• Introduction
• Overview of the Rhodium system
• Writing Rhodium optimizations
• Checking Rhodium optimizations
• Discussion
Exec
Compiler
Rhodium Execution engine
RdmOpt
RdmOpt
if (…) { x := …;} else { y := …;}…;
Checker Checker
Rhodium correctness checker
RdmOpt
Checker
Rhodium correctness checker
Checker
CheckerRdmOpt
Checker
Rhodium correctness checker
Automatic theorem prover
RdmOpt
Checker
Rhodium correctness checker
Automatic theorem prover
definefact …
if …then transform …
if …then …
Checker
Profitability heuristics
Rhodium optimization
Rhodium correctness checker
Automatic theorem prover
Rhodium optimization
definefact …
if …then transform …
if …then …
Checker
Rhodium correctness checker
Automatic theorem prover
Rhodium optimization
definefact …
VCGen
LocalVC
LocalVC
LemmaFor any Rhodium opt:
If Local VCs are trueThen opt is correct
Proof
«¬
$
\ rt l
Checker
Opt-dependent
Opt-independent
VCGen
if …then …
if …then transform …
Local verification conditions
define fact mustPointTo(X,Y)with meaning « X == &Y ¬
if mustPointTo(X,Y)@in ÆcurrStmt == [Z = X]
then mustPointTo(Z,Y)@out
if mustPointTo(X,Y)@in Æ currStmt == [Z = *X]
then transform to [Z = Y]
Assume:
Propagated factis correct
Show:
All incoming facts are correct
Assume:
Original stmt and transformed stmthave same behavior
Show:
All incoming facts are correct
Local VCs (generated and proven automatically)
Local correctness of prop. rules
currStmt == [Z = X]
then mustPointTo(Z,Y)@out
Local VC (generated and proven automatically)
if mustPointTo(X,Y)@in Æ
define fact mustPointTo(X,Y)with meaning « X == &Y ¬
Assume:
Propagated factis correct
Show:
All incoming facts are correct
Show: « Z == &Y ¬ (out)
« X == &Y ¬ (in) Æ
out= step (in , [Z = X] )
Assume:
mustPointTo (X, Y)
mustPointTo (Z, Y)
Z := X
Local correctness of prop. rules
Show: « Z == &Y ¬ (out)
« X == &Y ¬ (in) Æ
out= step (in , [Z = X] )
Assume:
Local VC (generated and proven automatically)
define fact mustPointTo(X,Y)with meaning « X == &Y ¬
currStmt == [Z = X]
then mustPointTo(Z,Y)@out
if mustPointTo(X,Y)@in Æ
mustPointTo (X, Y)
mustPointTo (Z, Y)
Z := X
X Y
Z := X
in
out Z Y?
Local correctness of trans. rules
Local VC (generated and proven automatically)
define fact mustPointTo(X,Y)with meaning « X == &Y ¬
mustPointTo (X, Y)
Z := *X Z := Y
if mustPointTo(X,Y)@in Æ
currStmt = [Z = *X]
then transform to [Z = Y]
Assume:
Original stmt and transformed stmthave same behavior
Show:
All incoming facts are correct
step (in , [Z = Y] )
« X == &Y ¬ (in)
Show: step (in , [Z = *X] ) =
Assume:
Local correctness of trans. rules
step (in , [Z = Y] )
« X == &Y ¬ (in)
Show: step (in , [Z = *X] ) =
Assume:
Local VC (generated and proven automatically)
define fact mustPointTo(X,Y)with meaning « X == &Y ¬
if mustPointTo(X,Y)@in Æ
currStmt = [Z = *X]
then transform to [Z = Y]
mustPointTo (X, Y)
Z := *X Z := Y Z := *X
X Y
in
out ?
Z := Y
X Y
in
out
Outline
• Introduction
• Overview of the Rhodium system
• Writing Rhodium optimizations
• Checking Rhodium optimizations
• Discussion
Topics of Discussion
• Correctness guarantees
• Usefulness of the checker
• Expressiveness
Correctness guarantees
• Once checked, optimizations are guaranteed to be correct
• Caveat: trusted computing base– execution engine– checker implementation– proofs done by hand once
• Adding a new optimization does not increase the size of the trusted computing base
• Guarantees
• Usefulness
• Expressiveness
Usefulness of the checker
• Found subtle bugs in my initial implementation of various optimizations
define fact equals(X:Var, E:Expr)with meaning « X == E ¬
if currStmt == [X = E] then equals(X,E)@out
x := x + 1x = x + 1
equals (x , x + 1)
• Guarantees
• Usefulness
• Expressiveness
if currStmt == [X = E] then equals(X,E)@outif currStmt == [X = E] Æ “X does not appear in E”then equals(X,E)@out
Usefulness of the checker
• Found subtle bugs in my initial implementation of various optimizations
define fact equals(X:Var, E:Expr)with meaning « X == E ¬ x := x + 1x = x + 1
equals (x , x + 1)
• Guarantees
• Usefulness
• Expressiveness
x = x + 1x = x + 1x = *y + 1
Usefulness of the checker
• Found subtle bugs in my initial implementation of various optimizations
define fact equals(X:Var, E:Expr)with meaning « X == E ¬
if currStmt == [X = E] Æ “X does not appear in E”then equals(X,E)@out
equals (x , x + 1)equals (x , *y + 1)if currStmt == [X = E] Æ “E does not use X”then equals(X,E)@out
• Guarantees
• Usefulness
• Expressiveness
Rhodium expressiveness
• Traditional optimizations:– const prop and folding, branch folding, dead assignment elim,
common sub-expression elim, partial redundancy elim, partial dead assignment elim, arithmetic invariant detection, and integer range analysis.
• Pointer analyses– must-point-to analysis, Andersen's may-point-to analysis with
heap summaries
• Loop opts– loop-induction-variable strength reduction, code hoisting, code
sinking
• Array opts– constant propagation through array elements, redundant array
load elimination
• Guarantees
• Usefulness
• Expressiveness
Expressiveness limitations
• May not be able to express your optimization in Rhodium– opts that build complicated data structures– opts that perform complicated many-to-many
transformations (e.g.: loop fusion, loop unrolling)
• A correct Rhodium optimization may be rejected by the correctness checker – limitations of the theorem prover– limitations of first-order logic
• Guarantees
• Usefulness
• Expressiveness
Lessons learned (discussion)
Lessons learned (my answers)
• Capture structure of problem– Rhodium: flow functions, rewrite rules, prof. heuristics– Restricts the programmer, but can lead to better
reasoning abilities– Split correctness-critical code from rest
• Split verification task– meta-level vs. per-verification– between analysis tool and theorem prover– between human and theorem prover
Lessons learned (my answers)
• DSL design is an iterative process– Hard to see best design without trying something first
• Previous version of Rhodium was called Cobalt– Cobalt was based on temporal logic– Stepping stone towards Rhodium
Lessons learned (my answers)
• One of the gotchas is efficient execution– easier to reason about automatically does not always
mean easier to execute efficiently– can possibly recover efficiency with hints from users– how can you trust a complex execution engine?
• Rely on annotations?– meanings in Rhodium– May be ok, especially if annotations simply state what
the programmer is already thinking
Conclusion
• Rhodium system– makes it easier to write optimizations– provides correctness guarantees– is expressive enough for realistic optimizations
• Rhodium is an example of using a DSL to allow more precise reasoning