In a flow-insensitive analysis, the order of statements does not matter. The analysis results are the same regardless of the statement order.
Examples of flow-sensitive analyses:
Examples of flow-insensitive analyses:
GEN(x:= e) = {x}
KILL(*) = \emptyset
f_s(in) = in \cup{} GEN(s)
if (...) {
x := ...
} else {
y := ...
}
z := ...
In a flow-insensitive analysis, only a single global DFA value state is required. In contrast, a DFA value state is maintained per program point (in/out of every program statement) in a flow-sensitive DFA. Thus, in a flow-insensitive, at every step we execute {\em both transfer and meet}: we transfer the global value over the statement and meet the output with the global value.
For flow-insensitive analyses, because the order is inconsequential, we can treat the program as a bag of instructions. We iterate over the instructions in any order, but each instruction must be considered in every top-level iteration.
It is possible to convert a flow-sensitive analysis to a flow-insensitive analysis by maintaining only a single global value and pretending that any of the program statements can execute non-deterministically and iteratively. In doing this conversion, the MFP (maximum fixed point) solution obtained through Kildall's algorithm on the flow-insensitive graph will be equal or less precise than the solution obtained for the original flow-sensitive analysis.
Example (Liveness):
entry.. y := y+z v := w+... x := v+... ..exitThe flow-sensitive solution will have a different set of live registers at every program point, e.g.
{w,y,z}
at entry. However, the flow-insensitive solution will have a single set of live registers, namely {v,w,y,z} ---
the flow-insensitive solution would simply union the use sets of all statements. Notice that MFP_FI (flow insensitive MFP) <= MFP_FS (flow sensitive MFP) for this example.
Example (Constant Propagation):
int f(n):
step = 2
sum = 0
i = 0
.loop:
if i > n goto .end
i += step
sum += i
goto .loop
.end:
return sum
Flow-sensitive solution will identify different constant variables at different points, e.g., sum=0 before the loop begins.
However, the flow-insensitive solution would only yield a less precise
solution, namely { step: 2 }. Notice however that if we convert this program
to SSA, then the flow-insensitive solution has the same precision as the flow-sensitive analysis: { step0: 2, sum0: 0, i0: 0 }. When running the flow-insensitive analysis, the transfer function over a phi-instruction involves meeting the
values of the RHS variables to obtain the value of the LHS variable.
Notice that the (flow-insensitive + SSA) solution is equally precise as the flow-sensitive solution, except in a more concise representation. For example, the flow-sensitive analysis would infer that step, sum, and i are constants before the loop, and only step is a constant within the loop. Correspondingly, the flow-insensitive analysis on SSA-ized program also encodes the same information. (Notice that the SSA-program will introduce phi nodes for i and sum).
The space requirement of the SSA and flow-insensitive analysis is significantly less than the space
requirement of the flow-sensitive analysis --- the latter requires O(n) space per variable (n is the
program size), whereas the former
requires O(s) space per variable (s is the average number of times a single variable is assigned
in program text statically).
The time requirement of the SSA and flow-insensitive analysis is also typically significantly less than the time requirement of a flow-sensitive analysis, as we will discuss later.
x = y + z; a : = b + c;: a change in x's value will not effect a change in the output of the next instruction, but may have a change in a downstream instruction that uses x.