GNU Info

Info Node: (librep.info)Compilation Tips

(librep.info)Compilation Tips


Next: Disassembly Prev: Compiler Declarations Up: Compiled Lisp
Enter node , (file) or (file)node

Compilation Tips
----------------

   Here are some tips for making compiled code run fast(er):

   * Instead of using `while' loops to traverse lists, use `mapc' or
     tail recursion.

     For example you might code a function to scan a list using
     iteration through a `while' loop:

          (defun scan-list (lst elt)
            "Search the LST for an element similar to ELT.
          Return it if one is found."
            (catch 'return
              (while (consp lst)
                (when (equal (car lst) elt)
                  (throw 'return elt))
                (setq lst (cdr lst)))))

     As well as obscuring what is actually happening, this will
     probably be fairly slow to execute. A more elegant solution is to
     use tail-recursion:

          (defun scan-list (lst elt)
            (if (equal (car lst) elt)
                elt
              (scan-list (cdr lst) elt)))

     An alternative idiom is to map an anonymous function over the list
     using the `mapc' function:

          (defun scan-list (lst elt)
            (catch 'return
              (mapc (lambda (x)
                      (when (equal x elt)
                        (throw 'return elt)))
                    lst)
              nil))

     In fact, the compiler knows that calls to `mapc' with a constant
     lambda expression can be open-coded, so it will code the list
     traversal directly using the virtual machine stack.

     However, in most cases the execution time differences are likely to
     negligible.

   * In some cases the functions `member', `memq', `assoc', etc... can
     be used to search lists. Since these are primitives written in C
     they will probably execute several times faster than an equivalent
     Lisp function.

     So the above `scan-list' example can again be rewritten, this time
     as:

          (defun scan-list (lst elt)
            (car (member elt lst)))

   * All conditional structures are equivalent when compiled (they are
     all translated to `cond' statements), so use whichever is the
     easiest to understand.

   * A certain amount of constant folding is performed. If a function is
     known to be free of side effects, and all its arguments are
     constants, then it is evaluated at compile-time, and the result
     folded into the program in its place. For example

          (logor (lsh 1 6) x)
              ==> (logor 32 x)

   * Careful use of named constants (Note: Defining Variables) can
     increase the speed of some programs. For example, in the Lisp
     compiler itself all the opcode values (small integers) are defined
     as constants.

     It must be stressed that in some cases constants may _not_ be
     suitable; they may drastically increase the size of the compiled
     program (when the constants are `big' objects, i.e. long lists) or
     even introduce subtle bugs (since two references to the same
     constant may not be `eq' whereas two references to the same
     variable are always `eq').

   * Many primitives have corresponding byte-code instructions; these
     primitives will be quicker to call than those that don't (and
     incur a normal function call). Currently, the functions which have
     byte-code instructions (apart from all the special forms) are:

     `cons', `car', `cdr', `rplaca', `rplacd', `nth', `nthcdr', `aset',
     `aref', `length', `eval', `+', `*', `/', `%', `mod', `lognot',
     `not', `logior', `logand', `logxor', `equal', `eq', `=', `/=',
     `>', `<', `>=', `<=', `1+', `1-', `-', `set', `lsh', `zerop',
     `null', `atom', `consp', `listp', `numberp', `stringp', `vectorp',
     `throw', `boundp', `symbolp', `get', `put', `signal', `return',
     `reverse', `nreverse', `assoc', `assq', `rassoc', `rassq', `last',
     `mapcar', `mapc', `member', `memq', `delete', `delq', `delete-if',
     `delete-if-not', `copy-sequence', `sequencep', `functionp',
     `special-form-p', `subrp', `eql', `max', `min', `filter',
     `macrop', `bytecodep', `bind-object'.

   * When a file is being compiled each top-level form it contains is
     inspected to see if it should be compiled into a byte-code form.
     Different types of form are processed in different ways:

        * Function and macro definitions have their body forms compiled
          into a single byte-code form. The doc-string and interactive
          declaration are not compiled.

        * If the form is a list form (Note: List Forms) and the
          symbol which is the car of the list is one of:

          `if', `cond', `when', `unless', `let', `let*', `catch',
          `unwind-protect', `error-protect', `with-buffer',
          `with-window', `progn', `prog1', `prog2', `while', `and',
          `or', `case'.

          then the form is compiled. Otherwise it is just written to
          the output file in its uncompiled state.

     If your program contains a lot of top-level forms which you know
     will not be compiled automatically, consider putting them in a
     `progn' block to make the compiler coalesce them into one
     byte-code form.


automatically generated by info2www version 1.2.2.9