Next: Multiple Values Optimization
Up: Source Optimization
Previous: Control Optimization
  Contents
  Index
Unreachable Code Deletion
unreachable code deletion
dead code elimination
Python will delete code whenever it can prove that the code can never be
executed. Code becomes unreachable when:
- An if is optimized away, or
- There is an explicit unconditional control transfer such as go orreturn-from, or
- The last reference to a local function is deleted (or there never was any
reference.)
When code that appeared in the original source is deleted, the compiler prints
a note to indicate a possible problem (or at least unnecessary code.) For
example:
(defun foo ()
(if t
(write-line "True.")
(write-line "False.")))
will result in this note:
In: DEFUN FOO
(WRITE-LINE "False.")
Note: Deleting unreachable code.
It is important to pay attention to unreachable code notes, since they often
indicate a subtle type error. For example:
(defstruct foo a b)
(defun lose (x)
(let ((a (foo-a x))
(b (if x (foo-b x) :none)))
...))
results in this note:
In: DEFUN LOSE
(IF X (FOO-B X) :NONE)
==>
:NONE
Note: Deleting unreachable code.
The :none is unreachable, because type inference knows that the argument
to foo-a must be a foo, and thus can't be nil. Presumably the
programmer forgot that x could be nil when he wrote the binding fora.
Here is an example with an incorrect declaration:
(defun count-a (string)
(do ((pos 0 (position #
a string :start (1+ pos)))
(count 0 (1+ count)))
((null pos) count)
(declare (fixnum pos))))
This time our note is:
In: DEFUN COUNT-A
(DO ((POS 0 #) (COUNT 0 #))
((NULL POS) COUNT)
(DECLARE (FIXNUM POS)))
-> BLOCK LET TAGBODY RETURN-FROM PROGN
==>
COUNT
Note: Deleting unreachable code.
The problem here is that pos can never be null since it is declared afixnum.
It takes some experience with unreachable code notes to be able to
tell what they are trying to say. In non-obvious cases, the best
thing to do is to call the function in a way that should cause the
unreachable code to be executed. Either you will get a type error, or
you will find that there truly is no way for the code to be executed.
Not all unreachable code results in a note:
- A note is only given when the unreachable code textually appears
in the original source. This prevents spurious notes due to the
optimization of macros and inline functions, but sometimes also
foregoes a note that would have been useful.
- Since accurate source information is not available for non-list
forms, there is an element of heuristic in determining whether or
not to give a note about an atom. Spurious notes may be given when
a macro or inline function defines a variable that is also present
in the calling function. Notes about nil and t are never
given, since it is too easy to confuse these constants in expanded
code with ones in the original source.
- Notes are only given about code unreachable due to control flow.
There is no note when an expression is deleted because its value is
unused, since this is a common consequence of other optimizations.
Somewhat spurious unreachable code notes can also result when a macro
inserts multiple copies of its arguments in different contexts, for
example:
(defmacro t-and-f (var form)
`(if ,var ,form ,form))
(defun foo (x)
(t-and-f x (if x "True." "False.")))
results in these notes:
In: DEFUN FOO
(IF X "True." "False.")
==>
"False."
Note: Deleting unreachable code.
==>
"True."
Note: Deleting unreachable code.
It seems like it has deleted both branches of the if, but it has really
deleted one branch in one copy, and the other branch in the other copy. Note
that these messages are only spurious in not satisfying the intent of the rule
that notes are only given when the deleted code appears in the original source;
there is always some code being deleted when a unreachable code note is
printed.
Next: Multiple Values Optimization
Up: Source Optimization
Previous: Control Optimization
  Contents
  Index
Peter Van Eynde
2000-02-08