Program Analysis
- Data Flow Analysis
- Lattices and Fix point of monotone function
- Algorithms
- Constant Propagation
- Abstract Interpretation
- Pentagons and Bound Checking
- Global Value Numbering
Dead Code Analysis:
Goal: To eliminate the computation whose result is unused
Definition: A variable is live at a program point in the CFG if there is a path from this program point to another program point where this variable is used which is not a definition.
Soundness: We must not eliminate computations whose result are live. Every over approximation is sound while eliminating dead code,
How do we find the set of live variables?
To determine the set of live variable at a program point . For every variable , we look at all the paths from point as the source. If we find any path where the variable is used . Then the variable is live at that program point .
A Local Approach:
For an edge in the CFG, assume we know the set of live variables at program point . Then we can calculate the set of the live variables at using this information.
for every vertex that can be reached by
The in-equation system:
Our in-equation system has an equation for each edge in the CFG.
For each node we can write the in-equation as the union of all the edges of the form
We can use a function that maps the set of program points to a set of variables that are live at that program point.
A trivial example of maps each program point to the complete set of variables (all the variables are live at all the program points).
is a transformer function. Takes in a particular mapping of program points to the set of live variables and transforms it into a new mapping.
NOTE: The best solution for the set of live variables is obtained by the LFP of the
Definite Assignment:
Goal: Check that on each path to use a variable, the variable has been defined before the use.
Definition: A variable is definitely assigned at program point if every path from (root of the CFG) to contains a definition of
Soundness: Every non-definitely assigned variable must be reported. warning about a definitely assigned variable is tolerable.
Thus, every under approximation of definitely assigned variables is sound.
A Local Approach:
For an edge in the CFG, assume we know the set of definitely assigned variables at program point . Then we can calculate the set of the definitely assigned variables at using this information.
for every vertex that can be reached by
The in-equation system:
Our in-equation system has an equation for each edge in the CFG.
For each node we can write the in-equation as the intersection of all the edges of the form
We can use a function that maps the set of program points to a set of variables that are live at that program point.
A trivial example of maps each program point to the empty set of variables (all the variables are not assigned at all the program points).
is a transformer function. Takes in a particular mapping of program points to the set of definitely assigned variables and transforms it into a new mapping.
Open Question:
So far we have the following:
- Analysis Domain,(For Liveness ): Gives the info derived about the program
- Transfer function on the edges (For liveness )
- A join operator compatible with the order of the in-equation ( for Liveness).
- Using both we can build the single big function ()
How do we compute a solution for the in-equation systems?
Lattices and Fix-points of Monotone Functions:
Lattice: A POSET(Set of elements , ordering relation ) is called a Lattice. Iff for every pair of element there exists a and
Complete Lattice: A Lattice is called a complete lattice iff for every . is a Lattice.
Conditions for Completeness: Let be an ordered set, then the following statements are equivalent.
- is a complete lattice
- for every there exists a (By dual exists).
ACC - Ascending Chain Conditions: An ordered set fulfils the ascending chain condition, if for every sequence
then there exists such that
Lifting: Let be an ordered set/complete lattice. Let be a set. is an ordered set/complete lattice with
Knaster-Tarski Fixpoint Theorem: Let be a complete lattice and be a monotone function. then
is the least fix point.

For the upper part of the diagram:
- is the reductive part
- Is a sound solution for the Liveness analysis
- is the best solution and contains the least number of variables live at each program point
For the lower part of the diagram:
- is the expansive part
- Is a sound solution for the Definite Assignment
- is the best solution and contains the maximum number of variables defined at each program point.
Thus by Knaster-Tarski theorem we know about the existence of the best possible solution for the and analysis.
The question is how do we reach them.
Fixpoint by Iteration (Variation of Kleene’s theorem):
Let be a complete lattice that satisfies ACC and a monotone function. then there exists a such that is of
The BIG Picture:
We require the analysis domain to be a complete lattice with ACC.
for liveness and definite assignment, we had which is a complete lattice as is a complete lattice with ACC.
We require every local edge transformer to be a monotone function. Then the big Function ( and ) are monotone.
WE compute the ’s fixpoint by using the Kleene’s theorem.
Chaotic Iteration:
is the best most precise solution for our inequation system and thus the the most analysis.
We can reach this by. updating only one program point per step as long as we make progress
Constant Propagation:
Goal: Eliminate computations on the variables that are constant
Domain: The domain of the analysis defines for each program point a information for each variable. The information either specifies a constant value or TOP(Not constant) or BOTTOM(not assigned)
Over approximates concrete states of program execution at program point.
- there exists two states with different values for variable.
- the variable is not assigned for every state.
If there exists one state where the variable is assigned and is not assigned in all other states then, the un assigned state leads to undefined behaviour and are thus ignored. The analysis then considers the constant value and continues with the execution.
Functions on edges:
Abstract Expression Evaluation:
Here again we use the worklist algorithm to determine the constant values for the set of variables for the program points.
Unreachable Code:
Now we attempt to add another domain to the constant propagation and do unreachable code analysis in cooperation with the constant propagation analysis.
We use unreahability information to refine constantness and constantness to refine unreachability.
Additional domain:
Maps the set of program points to being either reachable () or unreachable().
Transfer Functions:
For every reachable program point we can determine the reachability information for as follows:
Domain Cooperation (Unreachable code and Constant Propagation):
When joining over all incoming abstract values in constant propagation we ignore predecessors that are unreachable.
NOTE: We cannot run this analysis one after the another as it wont lead to the optimal analysis. If there is no unreachability information then the constant propagation analysis will be poor which will lead to poor unreachability analysis.
Abstract Interpretation:
Some analysis domain are abstractions of concrete program properties.
Ex: For constant propagation
A state () is a mapping and exists in concrete program executions.
Ex: For constant propagation represents all states where
We can use this information to prove program analysis correct with respect to the program semantics.
Concretisation(Constant Propagation):
Let be the complete lattice.
Let be the constant propagation lattice.
WE define what an abstract element represents by defining a concretization function
Set of all states where
is essentially taking in abstract information and giving us all the states in concrete program execution where the state is valid.
Correctness of edge transformers:
We can use the to define the correctness criterion of the edge transformers.
Each control flow edge has a concrete edge transformer
Each program analysis comes with a domain and an abstract edge transformer for each concrete effect
An abstract edge transformer is correct iff:
The above statement means that the states that are obtained by a concrete transformation under are a subset of the states that can be obtained after abstract transformation under
To prove the correctness for program analysis transformer we have to prove the above statement.
Finite Prefix Trace Semantics:
A configuration is a pir of program point and a concrete state*.*
A trace is a sequence of configurations.
A finite prefix trace semantics is the set of all program executions.
We can define the following monotone function.
with
for an edge between program point with concrete state and with concrete state
Define the concretisation of constant propagation to traces
The above statement means that if given some constant propagation information () at a program point we can concretize it to a set of trace such that if then that state appears in the set of concrete states that are obtained by that constant propagation information at that program point ; .
Fixpoint Transfer:
Given a monotone function ( abstract, concrete)
and two monotone functions and
for which the transformer correctness holds:
then,
Pentagons and Bound Checking:
For array accesses, a programming language like JAVA has to throw an exception if the array access is out of bounds.
So wherever there are array accesses a check is inserted to check the indexing.
There are some cases where the indexing is always in bound and the check is redundant.
With the interval analysis , we only get the bound .
This is not powerful enough to provide the relational information between the variables ()
Strict Upper Bounds Domain:
Represents strict inequalities, like
Domain:
Maps each variable to all the variables that are strictly greater than
Concretisation:
Given an element from the analysis domain () of SUB the concretisation function maps it to all the states where the value of i.e. is strictly greater than the value of i.e.
Join:
and
the denotes an absence of information about the values of the variables and hence assigns no ordering among the elements.
the is mapped to an empty state as there are no states where each variable is strictly greater than all other variables at the same time.
i.e all the states and
Closures: Because is transitive, there are many element in the SUB that concretise to the same set of states.
and
for both of the above elements of analysis domain we get the same concretisation i.e.
Now, because is a monotone function there exists a best abstraction
Remember that is a function that maps the given set of concrete states to the best possible abstraction.
Therefore gives the best abstraction for i.e. the best abstraction that represents the same concrete elements as
is called the closure operator and is used to obtain the best abstraction for a given concretisation.
Why do I care to get the best abstraction when the concretisation leads to the same concrete states?
It actually makes difference when doing the join operation in the SUB domain.
To make join more precise once could compute the best abstractions using closure and then perform join.
However the closure operator is expensive and requires calculation of the closure of the relation represented by an abstract element
Reduced Product: Using SUB without intervals does not help in proving the array access in bounds. Information about constants is left-out. Hence we use both analysis domains at the same time:
In the product, there are typically multiple abstract elements that are concretised to the same value:
Therefore, one also gets a closure operator that gives the best abstraction in domain
for a given abstraction
In Practice: Applying the closure operator is expensive.
To get the best precision, one has to do it before every operation: join and application of abstract transformer
In practice one uses a less precise but more efficient join. ex: ignore the SUB information for interval join.
Global Value Numbering:
Global Value Numbering Entire CFG
Local Value Numbering Inside a Basic Block
Local Value Numbering is aka CSE - Common Subexpression Elimination
Value Numbering:
Goal: Eliminate Redundant Computations
Find out if two variables have the same value at a given program point. (Undecidable).
Replace the later computations with the contents of the former.
We resort to Herbrand Equivalence:
We do not consider the interpretations of the operators.
Two expressions are equal if they are structurally equal.
Herbrand Interpretation:
Let be the set of terms over a set of variables.
The Herbrand interpretation of an -ary operator is given as
NOTE: The definition of a term is recursive. each term is composed of a set of terms.
Here the state maps a variable to a term.
Herbrand Semantics of a term t as follows
If the term is a variable then the value is equal to the value for that variable in the state
Else we recursively evaluate each term in the expression.
Two terms and are said to be Herbrand equivalent if for all states:
Kildall’s Analysis:
Tracks Herbrand Equivalences with a forward analysis.
The equivalence relation is a congruence relation wrt operators in our expression language
For each operator , each relation and for
Abstract Transformer for an assignment
For the assignment operator and a partition , the new partition is calculated by relating all the terms and where replacing the term by does not change their equivalence.
Comments on Kildalls Analysis:
Kildalls analysis is sound and complete i.e it discovers all Herbrand equivalences in the program
Straight forward implementation exhibits explosion in the size of equivalence classes.
We can use a better data structure called SED (String Equivalence DAGs) to store the congruences but can still lead to exponential sized graphs.
The Alpern-Wegman-Zadeck Algorithm:
Generates incomplete and less precise value numbering analysis.
Flow insensitive: Does not compute the equivalences for every program point but sound for the whole program
Uses SSA (Static Single Assignment) which is a property of an Intermediate Representation.
In SSA each variable has a single program point where it is defined.
Interpret the SSA data dependence graph as FSM and minimize it.
In constrast to finite automata, we do not create two partitions but a class for every operator symbol.
Note that the is also treated as an operator.
Two from different blocks have to be in different classes
Optimistically place all nodes with the same operator symbol in the same class
Find the LFP
Successively split class when two nodes in the class are detected not equivalent
