Full Employment Theorem for Compiler Writers
Informal Statement
The problem of given a program 
 and a property 
 that is true for some programs and false for other programs, check (precisely) whether program satisfies 
 is undecidable if property 
 talks only about the values computed by the program and program termination (and not e.g. how the values are computed).
This follows from Rice's theorem which follows from the undecidability of the Halting problem
- to check if
 terminates, we build a program 
 such that 
 and a program 
, that behaves like 
 if 
 does not terminate, and otherwise 
 
Consequences
Examples of undecidable problems:
- can a given program reach a state where null dereference happens
 - is a given variable dynamically alive at a given program point in a given program
 - is the given variable initialized before the execution reaches a given program point
 - are the values of two given variables equal in all executions of the program
 - does the given assertion evaluate to 'true' in all executions of a given program
 - …
 
How can we then build compilers?
- we do not attempt to answer this question precisely
 - we either compute an answer, or we say “we do not know”
 - we say compilers do “conservative” static analysis
 
In initialization analysis, output is:
- variable is definitely initialized
 - variable is possibly un-initialized (either it is un-initialized, or it is initialized but it is too hard to see why)
 
In live-variable analysis, output is:
- variable is definitely not live
 - variable is live (it is either dynamically live, or it is not dynamically live but it is difficult to see why)
 
Proof Sketches
Halting Problem Undecidability Theorem (Turing): There is no program 
 (think of it as analyzer that checks if programs are terminating) that takes as input a representation of an arbitrary program 
 and the input of the program 
, and determines whether 
 will terminate its computation if we ran 
 on input 
.
Proof sketch: This is a proof by a diagonal argument. Suppose that we do have such program 
. Then define the following program that takes program descriptions 
 as input:
def F(Y) = if H(Y,Y) then (while(true){}) else true
The question is then whether running 
 will terminate. There are two cases, either 
 holds, or not.
If 
 holds, then 
, by definition of 
 enters the 'true' branch and thus executes
while(true){}
Thus, 
 does not terminate. But this is in contradiction with the definition of 
, which says that 
 terminates on input 
.
If 
 does not hold, it then 
 goes to 'else' branch and terminates. But this is in contradiction with
the definition of 
 being false, which says that 
 should not terminate on input 
.
Impossibility of detecting dead code: There is no program 
 (think of it as data-flow analyzer) that can take as an input a program 
 and a program location 
, whether there exists an execution of 
 that reaches 
.
Proof sketch: By reduction to previous theorem. We can always transform a given program 
 into a program that always terminates in its last location (all 'halt' and 'exit' instructions are replaced by a jump to end of the program). Suppose p0 is such a program. To check if p0 terminates on an input 
, we consider the program
def p = { p0 L: {} }
Clearly, if p0 terminates, then it will execute L. Conversely, if p0 does not terminate, it will never reach L. Therefore, checking if 
 would tell us whether p0 terminates. By Halting problem, this is undecidable, so 
 cannot exist. QED
Impossibility of checking assertions: There is no program 
 that will accept a program 
 containing assertions and check whether these assertions are true in all executions.
Proof: By reduction to previous theorem. Given a program 
 with assertions, we introduce a fresh location L and replace each assertion
assert(c)
with the condition
if (!c) { goto L }
Then the assertions are true in all executions if and only if program never reaches location 
.
QED