Analysis Correctness -------------------- CLARIFICATION analysis results changing over time vs. analysis results at different program points terminate when new result covers last result *at the same program point* EXAMPLE w = 1 x = 0 y = 1 // x -> Z, y -> NZ, w -> NZ while (cond) w = y // x -> Z, y -> MZ, w -> MZ y = x // x -> Z, y -> Z, w -> MZ Correctness how to define? intuition: analysis will terminate when it does, results are a sound abstraction of program execution definitions needed program execution abstraction function sound: truth <= analysis results synonyms: conservative, safe semantics of While3Addr s ::= x = y | x = y + z | x = n | jump l | branch_nz x l edge E = (l1, l2) program P ::= * | P, l: S config C = (l, eta) environment eta ::= * | eta, x -> n reduction judgment P |- (l, eta) -> (l', eta') P[l] = x = y ---------------------------- P |- (l, eta) -> (l, [x->eta[y]]eta) P[l] = x = y + z ---------------------------------------------- P |- (l, eta) -> (l, [x->eta[y] + eta[z]]eta) P[l] = x = n ---------------------------- P |- (l, eta) -> (l, [x->n]eta) P[l] = jump l' ---------------------------- P |- (l, eta) -> (l', eta) P[l] = branch_nz x l' eta[x] != 0 ------------------------------------ P |- (l, eta) -> (l', eta) P[l] = branch_nz x l' eta[x] = 0 ----------------------------------- P |- (l, eta) -> (l+1, eta) Trace of program P is a potentially infinite sequence C_0, C_1, ... where C_0 = (l_0, eta_0) is called the initial configuration and for every n >=0 we have P |- C_n -> C_n+1 EXAMPLE l0: x = 0 l1: x = x + y; l2: y = y - 1; l3: branch_nz y l1 Trace for y = 1? Trace for y = 2? Trace for y = 0? [assume ideal integers] Definition of soundness: A dataflow analysis is sound iff, for all programs P, for all initial configurations C_0, for all traces T of program P, for all integers 0 <= n < length(T) then alpha(eta_n) <= analysis_results(lab_n) EXAMPLE think of zero analysis results for program above test claim for a couple of points in a couple of traces zero analysis: what if we said f(x = y + z, sigma) = [x -> Z] sigma give me an example of a trace that illustrates unsoundess GALOIS CONNECTION alpha maps C -> L gamma maps L -> set(C) eta <= gamma(alpha(eta)) detail: alpha(gamma(sigma)) <= sigma usually we have a Galois insertion, where alpha(gamma(sigma)) = sigma alpha, gamma are monotone (eta_1 <= eta_2 implies alpha(eta_1) <= alpha(eta_2)) LOCAL SOUNDNESS Definition: Local Soundness If P |- Cn -> Cn+1 and sigma_n = alpha(eta_n) and f(l_n, sigma_n) = sigma_n+1 then eta_n+1 in gamma(sigma_n+1) show commuting diagram! EXAMPLE: local soundness cases for zero analysis COUNTEREXAMPLE: local soundness violated in weird zero analysis above Definition: a dataflow analysis is at a fixed point, with results[l] representing the dataflow analysis results immediately before the statement labeled l, iff: sigma_init <= results[l_init] (for the initial label l_init) for all (l1, l2) in E we have f(l1, results[l1]) <= results[l2] Definition: a function is monotone iff sigma1 <= sigma2 implies f(sigma1) <= f(sigma2) LOCAL SOUNDNESS IMPLIES GLOBAL SOUNDNESS If DF's flow functions are monotone and locally sound with respect to alpha_DF then for any fixed point DF_fix on program P for all traces T s.t. eta_0 <= gamma(i), for all n < length(T) we have eta_n in gamma(sigma_n) Proof: by induction on n case 0: eta_0 <= gamma(i) by assumption i <= sigma_0 by definition of fixed point gamma(i) <= gamma(sigma_0) by monotonicity of gamma eta_0 <= gamma(sigma_0) by transitivity of <= case n+1: by induction hypothesis we know eta_n <= gamma(sigma_n) alpha(eta_n) <= alpha(gamma(sigma_n)) by monotonicity of alpha alpha(gamma(sigma_n)) <= sigma_n by definition of galois connection alpha(eta_n) <= sigma_n by transitivity by local soundness we know that eta_n+1 in gamma(f(l_n, alpha(eta_n))) by monotonicity of f and gamma we know that eta_n+1 in gamma(f(l_n, sigma_n)) f(l_n, sigma_n) <= sigma_n+1 by the definition of a fixed point by monotonicity of gamma we know that eta_n+1 in gamma(sigma_n+1) QED. TERMINATION AND PRECISION Theorem: if a dataflow lattice has finite height, and the analysis flow functions are monotonic, dataflow analysis will terminate at the least (most precise) fixed point Kildall's worklist algorith essentially computes f^n(bottom) for every n until f^n(bottom) = f^n+1(bottom), i.e. until we have reached a fixed point. By Tarski's fixed point theorem, when a fixed point is reached, it is the most precise one. How do we know we will reach a fixed point? Lemma: for all n f^n(bottom) <= f^n+1(bottom). Proof by induction. Base case: bottom <= f(bottom) by the properties of bottom. Inductive case: We assume assume f^n-1(bottom) <= f^n(bottom). Apply f to both sides and use monotonicity to conclude that f^n(bottom) <= f^n+1(bottom) Now, if the lattice has finite height then there are only finitely many n such that f^n(bottom) <= f^n+1(bottom) but f^n(bottom) != f^n+1(bottom). Thus we will reach an n such that f^n(bottom) = f^n+1(bottom), at which point we are done. EXAMPLE: non-finite height lattice (19-dataflow-examples-correctness p 39) non-monotonic flow function f(x = -y, sigma) = if (sigma[y] == POSITIVE then [x -> NEGATIVE]sigma else [x->POSITIVE]sigma) x = 1 while (*) x = -x // POSITIVE -> NEGATIVE, UNKNOWN -> POSITIVE INTERVAL ANALYSIS lattice elements: lower, upper L1 <= L2 means lower1 >= lower2 and upper1 <= upper2 L1 join L2 means min(lower1, lower2), max(upper1, upper2) bottom special top is (MIN_INT, MAX_INT) flow function for x = y + z? height of lattice? widening operator W : L * L -> L upper bound: l1 <= W(l1, l2) and l2 <= W(l1, l2) consider a possibly infinite sequence (l_n)_n = l0, l1, ... let (l_n^W)_n be defined by l_0^W = l_0 and l_n^W = W(l_n-1^W, l_n) we require (l_n^W)_n to stabilize after a finite number of steps example say program mentions the set K of integers (e.g. K = {0, N}). if we have a sequence for x of [0,0], [0,1], [0,2] we'd like to transform this into [0,0], [0, N], [0, MAX_INT] let W(l1, l2) = bottom if l1 = l2 = bottom otherwise lower = lower1 if lower1 <= lower2 k where k is the maximum element of K such that k < lower2, if lower2 < lower1 MIN_INT otherwise upper (similar) example: reaching definitions - different kind of collecting semantics environment eta ::= * | eta, x -> (n, l) // l is last defn of x P[l] = x = y ------------------------------------------- P |- (l, eta) -> (l, [x->(eta[y].n, l)]eta) exercise: semantics for live variables?