Some optimizations to consider. Better letrec compilation. In a tight loop, the overhead of the unboxing & closure unpacking that letrec and lambda introduce can be significant. But, you can avoid them if you see a letrec-bound function with no free variables (besides itself). Specifically, you can turn it directly into an L4 function. To make this work, you introduce a label version of the function name (replacing uses in the body) and just put the function as a new top-level L4 function. Your code must also then treat the label as if it was a primitive, i.e., a call-site with a label in the function position does not change and a label in some other place in the program has to get wrapped in a lambda. For example: (letrec ([fib (lambda (n) (if (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2)))))]) (fib 30)) => ((:fib 30) (:fib (n) (if (< n 2) 1 (+ (:fib (- n 1)) (:fib (- n 2)))))) Also a little trickier, but possibly also profitable is if you identify functions where: 1) the number of arguments plus the number of free variables is less than 3 2) all of the call sites of the function have all of the closure variables in scope (in general, only the site where the lambda expression is has those variables in scope) then you can transform them so they get their closure variables via regular arguments which then makes them suitable for the above transformation. One example would be a function like this: (let ([a (new-array 100 0)]) (letrec ([init-array (lambda (i) (if (< i (alen a)) (begin (aset a i i) (init-array (+ i 1))) 0))]) (init-array 0))) Inlining. Some functions are doing relatively simple things, to the point that the code that deals with the calling and returning can dominate in your compiled code. Fib is one such program; if you look at the L1 output of a compiled fib program (starting from the L4 program above, say), you'll find that lots of the code is dealing with function calls and returns. To get a better ratio, you can do function inlining. Specifically, if you see: (f e ...) in your program and you know that "f" is only ever bound to one specific function, you can replace the call-site with a let to bind the arguments, followed by the body of the function. Specifically, if 'f' is bound to (lambda (x ...) e_body), then you can replace the call above with (let ([x e] ...) e_body) For fib, doing inlining twice (once for each recursive call), yields this: (letrec ([fib (lambda (n) (if (< n 2) 1 (+ (let ([n (- n 1)]) (if (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2))))) (let ([n (- n 2)]) (if (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2))))))))]) (fib 30)) The two dangers here are that you should be careful to terminate and that your register allocator will get a real workout if you do too much inlining (the register allocation is the only part of the compiler that isn't linear and inlining can slow it down substantially).