Post on 01-Jan-2016
transcript
Kleene Algebra with Tests(Part 2: Applications)
Dexter KozenCornell University
Workshop on Logic & ComputationNelson, NZ, January 2004
These Lectures
1. Tutorial on KA and KAT
• model theory
• complexity, deductive completeness
• relation to Hoare logic
2. Practical applications
• compiler optimization
• scheme equivalence
• static analysis
3. Theoretical applications
• automata on guarded strings & BDDs
• algebraic version of Parikh’s theorem
• representation
• dynamic model theory
Kleene Algebra (KA)
• idempotent semiring under +, ·, 0, 1
(p + q) + r = p + (q + r) (pq)r = p(qr)p + q = q + p p1 = 1p = pp + p = p p0 = 0p = 0 p + 0 = p
p(q + r) = pq + pr(p + q)r = pr + qr
• linear inequalities have unique least solutions
p*q = least x such that q + px xqp* = least x such that q + xp x
defx y x + y = y
(K, B, +, ·, *, ¯, 0, 1)
• (K, +, ·, *, 0, 1) is a Kleene algebra
• (B, +, ·, ¯, 0, 1) is a Boolean algebra
• B K
• p,q,r, range over K
• a,b,c, range over B
Kleene Algebra with Tests (KAT)
Schematic KAT (SKAT)
x := s ; y := t = y := t[x/s] ; x := s y FV(s)
x := s ; y := t = x := s ; y := t[x/s] x FV(s)
x := s ; x := t = x := t[x/s]
b[x/t] ; x := t = x := t ; b
x := x = 1
Levels of Reasoning
• propositionalp1 = q1 p2 = q2 . . . pn = qn p = q
• schematic (1st order uninterpreted)x := s ; x := t = x := t[x/s]
• 1st order interpretedi j j k i k
• universal Horn logic
p1 = q1 p2 = q2 . . . pn = qn p = q
• premises pi = qi
− self-evident assumptions about local behavior
− typically involve atomic instructions and tests
• conclusion p = q
− equivalence of original program and optimized or
annotated program
• use schematic and interpreted reasoning only to
establish validity of premises – most reasoning done
at the propositional level
Reasoning with KAT
Compiler Optimizations[Kozen & Patron 00]
• dead code elimination
• common subexpression elimination
• copy propagation
• loop hoisting
• loop unrolling
• reducing nesting depth
• induction variable elimination
• instruction scheduling
• algebraic simplification
• elimination of redundant instructions
• array bounds check elimination
• introduction of sentinels
Typical Premises
“two instructions that do not affect each other can be
done in either order”
load r1,x ; load r2,y = load r2,y ; load r1,x
“after loading a value in a register, that register
contains that value”
load r1,x = load r1,x ; r1=x p = pb
“no need to load a value if the register already
contains that value”
r1=x ; load r1,x = r1=x bp = b
Loop Hoisting
for (i = 0; i < n; i++) {
b[i] = x;
}
i := 0
: test i < n
jump if false
load r,x
store r,b[i]
i := i + 1
jump
:
Loop Hoisting
for (i = 0; i < n; i++) {
b[i] = x;
}
i := 0
: test i < n
jump if false
load r,x
store r,b[i]
i := i + 1
jump
:
This is of the form w(cupv)*c
p = load r,x b = r=x
load r,x = load r,x ; r=x p = pb
bpp
r=x ; load r,x = r=x bp = b
b p b
ub = bu
vb = bv
p = pb bp = b ub = bu vb = bv
w(cupv)*c = w(cupv(cubv)*c + c)
Suffices to show
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = (cupv)*
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cupv(cupv)* + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cupbv(cupv)* + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cupbv(cupbv)* + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cupb(vcupb)*v + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cup(bvcup)*bv + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cup(vbcup)*bv + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cup(vcbup)*bv + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cup(vcubp)*bv + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cup(vcub)*bv + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cup(vcbu)*bv + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cup(vbcu)*bv + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cup(bvcu)*bv + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cupb(vcub)*v + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cupbv(cubv)* + 1
p = pb bp = b ub = bu vb = bv
(cupv)* = cupv(cubv)* + 1
(cupv)* = cupv(cubv)* + 1
Loop Unrolling
while b do { while b do { p; p;} if b then p;
}
(bp)*b = (bp(bp + b))*b
Key lemma q* = (qn)*(1 + q)n-1
Loop Denesting
while b do { if b then {p; p;while c do q; while b c do
} if c then q else p;}
(bp(cq)*c)*b = bp((b+c)(cq+cp))*(b+c) + b
Key lemma (p*q)*p* = (p + q)*
Array Bounds Check Elimination
for (i = 0; i < x.length; i++) { x[i] := e(i);
}
i := 0: test i < n
jump if falsecompute e(i) if i out of bounds then errorx[i] := e(i) i := i + 1jump
:
Array Bounds Check Elimination
for (i = 0; i < x.length; i++) { x[i] := e(i);
}
i := 0: test i < n
jump if falsecompute e(i) if i out of bounds then errorx[i] := e(i) i := i + 1jump
:
Array Bounds Check Elimination
a = 0 i b = i < x.length c = ab i is in bounds
We have to prove
u(bp(cq + cs)v)*b = u(bpqv)*b
Introduce a using u = ua, show a and b (and therefore c) hold where needed to eliminate the array bounds check
LU Decomposition with Pivoting[Mateev, Menon, Pingali 01]
• Restructuring of matrix operations to take advantage of locality
• Def/use analysis fails: transformations break def/use dependencies
• MMP develop a new technique, fractal symbolic analysis
y = x; x = 2*x;y = 2*y; y = 2*y;x = 2*x; y = x;
Schematic KAT (SKAT)
x := s ; y := t = y := t[x/s] ; x := s y FV(s)
x := s ; y := t = x := s ; y := t[x/s] x FV(s)
x := s ; x := t = x := t[x/s]
b[x/t] ; x := t = x := t ; b
x := x = 1
y = x; x = 2*x;y = 2*y; y = 2*y;x = 2*x; y = x;
y = x; x = 2*x;y = 2*y; y = 2*y;x = 2*x; y = x;
y = 2*x;x = 2*x;
x := s ; x := t = x := t[x/s]
y = x; x = 2*x;y = 2*y; y = 2*y;x = 2*x; y = x;
y = 2*x; x = 2*x;x = 2*x; y = x;
x := s ; x := t = x := t[x/s]
y = x; x = 2*x;y = 2*y; y = 2*y;x = 2*x; y = x;
y = 2*x; x = 2*x;x = 2*x; y = x;
x := s ; y := t = y := t[x/s] ; x := s
y FV(s)
for (j = 0; j < n-1; j++) {tmp = a[j]; //swapa[j] = a[j+1];a[j+1] = tmp;for (i = j+1; i < n; i++) {
a[i] = a[i]/a[j]; //update}
}
for (j = 0; j < n-1; j++) {tmp = a[j]; //swapa[j] = a[j+1];a[j+1] = tmp;
}for (j = 0; j < n-1; j++) {
for (i = j+1; i < n; i++) {a[i] = a[i]/a[j]; //update
}}
for (j = 0; j < n-1; j++) {swap(j,j+1);
for (i = j+1; i < n; i++) {update(i,j);
}}
for (j = 0; j < n-1; j++) {swap(j,j+1);
}for (j = 0; j < n-1; j++) {
for (i = j+1; i < n; i++) {update(i,j);
}}
k < i < j
update(i,k); swap(i,j);update(j,k); = update(i,k);swap(i,j); update(j,k);
k > j
swap(k,k+1);for (i = j+1; i < n; i++) {
update(i,j);}
=
for (i = j+1; i < n; i++) {update(i,j);
}swap(k,k+1);
Key Lemma pq = qp pq* = q*p
for (j = 0; j < n-1; j++) {swap(j,j+1);for (i = j+1; i < n; i++) {
update(i,j);}
}
for (j = 0; j < n-1; j++) {swap(j,j+1);
}for (j = 0; j < n-1; j++) {
for (i = j+1; i < n; i++) {update(i,j);
}}
Key Lemma pq = qp p*q* = (pq)*(p* + q*)
The Dead Variable Paradox
Two ways to show
x := 1 ; x := 1 = x := 1
The Dead Variable Paradox
Method 1
d = “x is a dead variable” p = “x := 1”
p = dp x is dead immediately before it is assignedpd = d an assignment to a dead variable is redundant
To show pp = p:
pp = pdp = dp = p
The Dead Variable Paradox
Method 2
c = “x = 1”p = “x := 1”
p = pc x has value 1 immediately after the assignmentcp = c it’s pointless to assign to x a value it already has
To show pp = p:
pp = pcp = pc = p
The Dead Variable Paradox
c = “x = 1”d = “x is a dead variable” p = “x := 1”
p = dp x is dead immediately before it is assignedpd = d an assignment to a dead variable is redundantp = pc x has value 1 immediately after the assignmentcp = c it’s pointless to assign a value to x it already has
pp = pcdp = pdcp = dc
x := 1 ; x := 1 = x is dead ; x = 1 ???
The Dead Variable Paradox
Solution
“x is a dead variable” is not a property of the local state
use u = “make x undefined” = “x := ” instead
x := 0 ; x := = x := x := ; x := 0 = x := 0
start
y1 := x
y4 := f(y1)
y1 := f(y1)
y2 := g(y1,y4)
y3 := g(y1,y1)
P(y1)
y1 := f(y3)
P(y4)
P(y2)
y2 := f(y2) P(y3)
z := y2
halt
T
T
T
TF
F
F
F
start
y := f(x)
loop
P(y)
y := g(y,y)
P(y)
y2 := f(f(y)) z := y
halt
T
T
F
F
SchemeEquivalence
Example of Paterson
from [Manna 74]
x1p41p11q214q311(a1p11q214q311)*a1p13
((a4+a4(a2p22)*a2a3p41p11) q214q311(a1p11q214q311)*a1p13)*
a4(a2p22)*a2a3z2z
saq(araq)*az
x1 p41 p11 q214 q311 a1 p13 a4 a2 a3 z2
p22
a1
a4
a2
a3
s q a
r
z
a
a
Kleene’s Theorem
Static Analysis
• Derivation of information about the execution state at various points in a program at compile time or load time, prior to execution
• Approaches– type inference– dataflow analysis– abstract interpretation– set constraints
• Applications– code optimization– verification
Software Model Checking withSLAM
Thomas BallTesting, Verification and Measurement
Sriram K. RajamaniSoftware Productivity Tools
Microsoft Research
http://research.microsoft.com/slam/
State Machine for Locking
Unlocked Locked
Error
Rel Acq
Acq
Rel
state {
enum {Locked,Unlocked}
s = Unlocked;
}
KeAcquireSpinLock.entry {
if (s==Locked) abort;
else s = Locked;
}
KeReleaseSpinLock.entry {
if (s==Unlocked) abort;
else s = Unlocked;
}
Locking Rule in SLIC
do {KeAcquireSpinLock();
nPacketsOld = nPackets;
if(request){request = request->Next;KeReleaseSpinLock();nPackets++;
}} while (nPackets != nPacketsOld);
KeReleaseSpinLock();
ExampleDoes this code
obey the locking rule?
do {KeAcquireSpinLock();
if(*){
KeReleaseSpinLock();
}} while (*);
KeReleaseSpinLock();
ExampleModel checking boolean program
(bebop)
U
L
L
L
L
U
L
U
U
U
E
do {KeAcquireSpinLock();
nPacketsOld = nPackets;
if(request){request = request->Next;KeReleaseSpinLock();nPackets++;
}} while (nPackets != nPacketsOld);
KeReleaseSpinLock();
ExampleIs error path feasible
in C program?(newton)
U
L
L
L
L
U
L
U
U
U
E
do {KeAcquireSpinLock();
nPacketsOld = nPackets; b = true;
if(request){request = request->Next;KeReleaseSpinLock();nPackets++; b = b ? false : *;
}} while (nPackets != nPacketsOld); !b
KeReleaseSpinLock();
ExampleAdd new predicateto boolean program
(c2bp)b : (nPacketsOld == nPackets)
U
L
L
L
L
U
L
U
U
U
E
do {KeAcquireSpinLock();
b = true;
if(*){
KeReleaseSpinLock();b = b ? false : *;
}} while ( !b );
KeReleaseSpinLock();
b
b
b
b
ExampleModel checking
refined boolean program
(bebop)
b : (nPacketsOld == nPackets)
U
L
L
L
L
U
L
U
U
U
E
b
b
!b
Example
do {KeAcquireSpinLock();
b = true;
if(*){
KeReleaseSpinLock();b = b ? false : *;
}} while ( !b );
KeReleaseSpinLock();
b : (nPacketsOld == nPackets)
b
b
b
b
U
L
L
L
L
U
L
U
U
b
b
!b
Model checking refined
boolean program(bebop)
do { KeAcquireSpinLock(); nPacketsOld = nPackets; if (request) { request = request->Next; KeReleaseSpinLock(); nPackets++; } } while (nPackets != nPacketsOld); KeReleaseSpinLock();
do { kA; n; if (R) { u; kR; m; } } while (~B); kR;
do { kA; n; if (R) { do p while C u; = p;(C;p)*;~C kR; m; if C then p } = C;p + ~C } while (~B); kR;
do { kA; n; if (R) { do p while C u; = p;(C;p)*;~C kR; m; if C then p } = C;p + ~C } while (~B); kR;
kA;n;(R;u;kR;m + ~R); (~B;kA;n;(R;u;kR;m + ~R))*;B;kR
Preconditions for safe execution
operation preconditionkA (acquire) ~A (unlocked)kR (release) A (locked)Global precondition: initially unlocked
Original program
~A;kA;n;(R;u;kR;m + ~R);(~B;kA;n;(R;u;kR;m + ~R))*;B;kR
Annotated program
~A;~A;kA;n;(R;u;A;kR;m + ~R);(~B;~A;kA;n;(R;u;A;kR;m + ~R))*;B;A;kR
kA = kA;A - acquiring the lock acquires itkR = kR;~A - releasing the lock releases itB;m = B;m;~B - if two integer variables are
equal and we increment one, then they are no longer equal
n = n;B - setting one variable equal to another makes them equal
A;n = n;A - commutativity conditionsA;u = u;AA;m = m;AB;u = u;BB;kR = kR;B
kA = kA;A kR = kR;~A B;m = B;m;~B n = n;B A;n = n;A A;u = u;A A;m = m;A B;u = u;B B;kR = kR;B
~A;kA;n;(R;u;kR;m + ~R);(~B;kA;n;(R;u;kR;m + ~R))*;B;kR
=~A;~A;kA;n;(R;u;A;kR;m + ~R);(~B;~A;kA;n;(R;u;A;kR;m + ~R))*;B;A;kR
Security Automata [Schneider 98]
• general mechanism for specification and runtime enforcement of safety policies
• policy is specified by a finite automaton M• code is instrumented to call M before all
critical operations (ones that could change state of M )
• M aborts the computation if the operation causes a transition to an error state
• can handle all safety properties
read
send
send
read
errorstart
Example
no sendafter read
read
send
send
read
error
• code is instrumented to call M before each read and send instruction
• purely a runtime mechanism
start
Security Automata and KATUse KAT to do static analysis to eliminate unnecessary calls to M
• assertion U for each state of M
• premises AM :
• UV = 0 for U ≠ V
• Up pV for each atomic transition U V
• Up pU if p is noncritical
• start state S, error states E
p
Prefixes
Pre(r) = an expression representing prefixes of computations of r. Defined inductively:
Pre(p) = 1 + p p an atomic actionPre(b) = 1 b a testPre(pq) = Pre(p) + p;Pre(q)Pre(p + q) = Pre(p) + Pre(q)Pre(p*) = p*;Pre(p)
This is a closure operator in the sense thatPre(Pre(p)) = Pre(p) is a theorem of KAT
Eliminating Runtime Checks
Soundness Theorem Let D be any set of premises over P,B, and let r be any program over P,B. If
D AM S·Pre(r) ~E(ΣP)*~E
is a theorem of KAT, then r is safe with respect to M in any Kripke frame whose trace algebra satisfies D.
Completeness Theorem The converse holds as well, provided D is finite and all elements of D are of the form p = 0.
More Generally...
Let L be an upper semilattice such that all ascending chains are finite (ACC). Elements are called types or abstract values.
Associated with each atomic action p is a strict, partial, finitely additive map fp : L L called its transfer function.
Take premises Xp p fp(X) and propagate information as before (ACC needed for *). Safep = dom fp.
Types or Abstract Values
• Represent sets of values– statically derivable– conservative approximation
• Form a partial semilattice– higher = less specific– join does not exist = type error
Example: Java Bytecode
Object
Array [ ]
Integer Continuations
Array [ ][ ] …Interface
implements
Useless
Null
Java class
hierarchy
int, short, byte,
boolean, char
Example: Java Bytecode
local variable array
operand stack
this p0 p1 p2
parameters other locals
maxLocals
maxS
tack
= reference type= integer= continuation
StringHash-
tableObject
String-
Buffer
User-
Classint[ ]
= useless
Example of a Transfer Function
0 1 2 3 4 5 6 7
loca
lsst
ack
0 1 2 3 4 5 6 7
loca
lsst
ack
iload 3
Preconditions for safe execution:
• local 3 is an integer• stack is not full
Effect:• push integer in local 3 on stack
Demo of KAT-ML
KAT-ML is an interactive theorem prover for
Kleene algebra with tests written in standard
ML. Versions for a variety of platforms are
available from
http://www5.cs.cornell.edu/~kamal/kat