Chapter 3. Efficiency

Table of Contents

Modular arithmetic

FIXME: The material in the CMU CL manual about getting good performance from the compiler should be reviewed, reformatted in DocBook, lightly edited for SBCL, and substituted into this manual. In the meantime, the original CMU CL manual is still 95+% correct for the SBCL version of the Python compiler. See the sections

Besides this information from the CMU CL manual, there are a few other points to keep in mind.

Finally, note that Common Lisp defines many constructs which, in the infamous phrase, ‘could be compiled efficiently by a sufficiently smart compiler’. The phrase is infamous because making a compiler which actually is sufficiently smart to find all these optimizations systematically is well beyond the state of the art of current compiler technology. Instead, they're optimized on a case-by-case basis by hand-written code, or not optimized at all if the appropriate case hasn't been hand-coded. Some cases where no such hand-coding has been done as of SBCL version 0.6.3 include

If your system's performance is suffering because of some construct which could in principle be compiled efficiently, but which the SBCL compiler can't in practice compile efficiently, consider writing a patch to the compiler and submitting it for inclusion in the main sources. Such code is often reasonably straightforward to write; search the sources for the string ‘deftransform’ to find many examples (some straightforward, some less so).

Some numeric functions have a property: N lower bits of the result depend only on N lower bits of (all or some) arguments. If the compiler sees an expression of form (logand exp mask), where exp is a tree of such "good" functions and mask is known to be of type (unsigned-byte w), where w is a "good" width, all intermediate results will be cut to w bits (but it is not done for variables and constants!). This often results in an ability to use simple machine instructions for the functions.

Consider an example.

(defun i (x y)
  (declare (type (unsigned-byte 32) x y))
  (ldb (byte 32 0) (logxor x (lognot y))))
The result of (lognot y) will be negative and of type (signed-byte 33), so a naive implementation on a 32-bit platform is unable to use 32-bit arithmetic here. But modular arithmetic optimizer is able to do it: because the result is cut down to 32 bits, the compiler will replace logxor and lognot with versions cutting results to 32 bits, and because terminals (here---expressions x and y) are also of type (unsigned-byte 32), 32-bit machine arithmetic can be used.

Note

As of SBCL 0.8.5 "good" functions are +, -; logand, logior, logxor, lognot and their combinations; and ash with the positive second argument. "Good" widths are 32 on HPPA, MIPS, PPC, Sparc and X86 and 64 on Alpha. While it is possible to support smaller widths as well, currently it is not implemented.