There are ways to control the nature of compiled code via thedeclare special form andproclaim function. See later in this chapter for fuller discussion of these two forms.
In particular there are a set of optimize qualities which take integral values from 0 to 3, in order to control the trade-offs between code size, speed, compilation time, debuggability of the resulting code, and the safety of the code (whether type checks are omitted). For example:
(proclaim '(optimize (speed 3) (safety 0) (debug 0)))
tells the compiler to concentrate on code speed rather than anything else, and
(proclaim '(optimize (safety 3)))
ensures that the compiler never takes liberties with Lisp semantics and produces code that checks for every kind of signallable error.
The important declarations to the compiler are type declarations and optimize declarations. To declare that the type of the value of a variable can be relied upon to be unchanging (and hence allow the compiler to omit various checks in the code), say:
(declare (type the-type variable * )
Optimize declarations have various qualities, and these take values from 0 to 3. The keywords aresafety,fixnum-safety,sys:interruptable,debug,speed, compilation-speed, andspace.
Most of the qualities default to 1 (butsafety andfixnum-safety default to 3 andinterruptable defaults to 0). You can either associate an optimize quality with a new value (with local lexical scope if indeclare, and global scope ifproclaim), or just give it by itself, which implies the value 3 (taken to mean "maximum" in some loose sense).
Thus you ensure code is at maximum safety by:
(proclaim '(optimize (safety 3)))
or
(proclaim '(optimize safety))
and reduce debugging information to a minimum by
(proclaim '(optimize (debug 0)))
Normally code is interruptible, but when going for the extreme levels of speed and "undebuggability" this ceases to be the case unless you also ensure it thus:
(proclaim '(optimize (debug 0) (safety 0) (speed 3) interruptable))
The levels of safety have the following implications:
The levels of fixnum-safety have the following implications:
The effects of combining these qualities is summarized below:
Keyword settings | Operations |
|---|---|
| Array access optimizations |
| Dumps symbol names for arglist |
| "Uniquely spills" various registers (sometimes only when source debugging is on) |
| Does not generate any debug info at all |
| Avoids |
| Avoids |
| Avoids |
| Avoids an optimization to last |
| Be careful when multiple value counts are wrong |
| Do not check array indices during write |
| Do not check array indices during read |
| Eliminate tail recursion |
| Inline map functions (unless |
| "Tail merging" |
| "Self calls" |
| "Check get special" |
| Do not check array indices during write |
| Do not check array indices during read |
| "Check structure access" |
| Call count count |
| Check number of args |
| Check stack overflow |
| Ensures the thing being funcalled is a function |
| Fixnum-only arithmetic except where overridden by type declarations |
| No fixnum overflow checks |
| No fixnum arithmetic checks at all |
|
|
| Ensures symbols in |
| Avoids "ad hoc" predicate type transforms |
| Reuse virtual registers in very large functions |
The other optimize qualities are:speed -- the attention to fast code,space -- the degree of compactness,compilation-speed -- speed of compilation,interruptable -- whether code must be interruptible when unsafe.
Note that if you compile code with a low level of safety, you may get segmentation violations if the code is incorrect (for example, if type checking is turned off and you supply incorrect types). You can check this by interpreting the code rather than compiling it.