There are ways to control the nature of compiled code via the declare special form and
proclaim function. See Declare, proclaim, and declaim for fuller discussion of these two forms.
In particular there are a set of optimize qualities which take integral values from 0 to 3. These control the trade-offs between size, speed, retention of debug information, optimizations and safety (that is, type checks) in the resulting code, and also compilation time. 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 error that can be signaled.
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 names are safety
, fixnum-safety
, float
, sys:interruptable
, debug
, speed
, compilation-speed
, and space
.
Most of the qualities default to 1 (but safety
and fixnum-safety
default to 3 and interruptable
defaults to 0). You can either associate an optimize quality with a new value (with local lexical scope if in declare, and global scope if proclaim), 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)))
(proclaim '(optimize safety))
and reduce debugging information to a minimum by
(proclaim '(optimize (debug 0)))
Normally code is interruptible, but when aiming for maximum speed and minimum safety and debug information code is not interruptible unless you ensure it thus:
(proclaim '(optimize (debug 0) (safety 0) (speed 3) interruptable))
The levels of safety
have the following implications:
type
and fixnum-safety
declarations to take effect. Array index bounds are checked for both reading and writing.fixnum-safety
and type
declarations from taking any effect.The levels of fixnum-safety
have the following implications:
Additionally if the level of float
(really this should be called "float-safety") is 0 then the compiler reduces allocation during float calculations.
The effects of combining these qualities is summarized below:
Combining debug and safety levels in the compilerDumps symbol names for arglist
Ensure debugger knows values of args (and variables when source level debugging is on) and can find the exact subform in the Editor.
Does not generate any debug info at all
Avoids make-instance andfind-class
optimizations
Avoids gethash
and puthash
optimizations
Avoids ldb
and dpb
optimizations
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
Inline map functions (unless debug>2
)
Do not check types during write
Do not check types during read
Inline structure readers, with no type check
Inline structure writers, with no type check
Ensures the thing being funcalled is a function
Fixnum-only arithmetic with errors for
non fixnum arguments.
No fixnum arithmetic checks at all
char=
checks for arguments of type character
Avoids "ad hoc" predicate type transforms
Reuse virtual registers in very large functions
(declare (type foo x))
and (the foo x)
ensure a type check
Optimize floating point calculations
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.
9.5.1 Examples of compiler controlThe following function, compiled with safety = 2, does not check the type of its argument because it merely reads:
(defun foo (x)
(declare (optimize (safety 2)))
(car x))
However the following function, also compiled with safety = 2, does check the type of its argument because it writes:
(defun set-foo (x y)
(declare (optimize (safety 2)))
(setf (car x) y))
As another example, interpreted code and code compiled at at low safety does not check type declarations. To make LispWorks check declarations, you need to compile your code after doing:
(declaim (optimize (safety 3) (debug 3)))
This last example shows how to copy efficiently bytes from a typed-aref vector (see make-typed-aref-vector) to an (unsigned-byte 8)
array. type
and safety
declarations cause the compiler to inline the code that deals specifically with (unsigned-byte 8)
. This code was developed after an application was found to have a bottleneck in the original version of this function:
(defun copy-typed-aref-vector-to-byte-vector
(byte-vector typed-vector length)
(declare (optimize (safety 0))
(type (simple-array (unsigned-byte 8) 1) byte-vector)
(fixnum length))
(dotimes (index length)
(declare (type fixnum index))
(setf (aref byte-vector index)
(sys:typed-aref '(unsigned-byte 8)
typed-vector index))))
LispWorks User Guide and Reference Manual - 20 Sep 2017
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4