-
Notifications
You must be signed in to change notification settings - Fork 103
Investigating compiler issues
Here are some ways to investigate what is happening when the compiler produces code that doesn't work as expected. They are not in any particular order.
Using disassemble
can sometimes be helpful. The disassembly can show,
for example, whether declarations did anything, or whether
constant-folding worked, and so forth.
On x86, a function is
a specially-tagged vector. You can use ccl::function-to-function-vector
to turn a function into a uvector that you can inspect with describe
or
whatever. The vector consists of binary instructions, a marker word
(x8664::function-boundary-marker
), and then the function's
constants/immediates.
It can sometimes help to compile with speed 3 and safety 0 to get rid of safety checks so that it's easier to see the actual code of interest in the disassembly.
Many function names have compiler macros. These are mostly defined in
compiler/optimizers.lisp.
Recall that you can inhibit compiler macros
by using, for example, (declare (notinline integerp))
. You
can use ccl:compiler-macroexpand-1
and ccl:compiler-macroexpand
to
help debug compiler macros.
The compiler front end produces an intermediate representation called acode. It can sometimes be helpful to see that.
(in-package :ccl)
(let ((*nx-current-code-note* nil))
(nx1-compile-lambda 'fact '(lambda (n) (if (<= n 1) 1 (* n (fact (1- n)))))))
=> #<AFUNC #x302000AEF19D>
(pprint (decomp-acode (afunc-acode *)))
=>
(LAMBDA-LIST (N)
(IF (NUMCMP (IMMEDIATE :LE) (LEXICAL-REFERENCE N) 1)
1
(MUL2 (LEXICAL-REFERENCE N)
(FUNCALL (IMMEDIATE FACT) (SUB2 (LEXICAL-REFERENCE N) 1)))))
Generally, acode trees will get walked and rewritten via
rewrite-acode-form
. See compiler/acode-rewrite.lisp
for the rewrite functions. If you suspect something is going wrong in this
area, you might want to make rewrite-acode-form
a no-op.
The compiler backend turns the intermediate representation into a compiled function. Sometimes it can help to see what vinsns (virtual instructions) it is using.
On x86 you can do (setq ccl::*x86-debug-mask* 2)
to tell the
backend to print out the generated vinsns. (The value 2 is the
value of (ash 1 x862-debug-vinsns-bit)
in case you were wondering.)