Pointer analysis. Flow insensitive loss of precision S1: l := new Cons p := l S2: t := new Cons *p...

Post on 22-Dec-2015

230 views 3 download

Tags:

Transcript of Pointer analysis. Flow insensitive loss of precision S1: l := new Cons p := l S2: t := new Cons *p...

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