A Lisp compiler to RISC-V written in Lisp


#1

Introducing a simple experimental Lisp compiler, written in uLisp, that will compile a Lisp function into RISC-V machine code. You can run the compiler on the RISC-V core of a Raspberry Pi Pico 2 (or another RP2350-based board):

For full details see: A Lisp compiler to RISC-V written in Lisp.

Using the compiler

To run the compiler you simply call compile on a Lisp function; for example:

(compile 'fibonacci)

The function will be compiled into a machine code function, replacing the original Lisp code, so that calling fibonacci will now execute the RISC-V machine-code version.

Specification

The compiler understands the following Lisp objects:

Defining variables and functions: defun, setq

Symbols: nil, t

List functions: car, cdr

Arithmetic functions: +, -, *, /, mod, 1+, 1-

Arithmetic comparisons: =, <, <=, >, >=, /=

Conditionals: if, and, or

Tail-call optimisation

Although the compiler doesn’t include any iteration constructs, it does provide tail-call optimisation which can make recursive programs as efficient as iterative ones.

Example

The following example shows the code generated by a simple function, rec, a recursive function related to the factorial function:

(defun rec (n)
  (1+ (* n (if (= n 0) 0 (rec (1- n))))))

Compiling this gives the following RISC-V machine code:

> (compiler 'rec)
0000      rec
0000 872a ($mv 'a4 'a0)
0002 853a ($mv 'a0 'a4)
0004 1171 ($addi 'sp 'sp -4)
0006 c02a ($sw 'a0 0 '(sp))
0008 853a ($mv 'a0 'a4)
000a 1171 ($addi 'sp 'sp -4)
000c c02a ($sw 'a0 0 '(sp))
000e 4501 ($li 'a0 0)
0010 4582 ($lw 'a1 0 '(sp))
0012 0111 ($addi 'sp 'sp 4)
0014 8533 ($sub 'a0 'a1 'a0)
0016 40a5 
0018 3513 ($seqz 'a0 'a0)
001a 0015 
001c c119 ($beqz 'a0 lab1)
001e 4501 ($li 'a0 0)
0020 a819 ($j lab2)
0022      lab1
0022 853a ($mv 'a0 'a4)
0024 157d ($addi 'a0 'a0 -1)
0026 1161 ($addi 'sp 'sp -8)
0028 c006 ($sw 'ra 0 '(sp))
002a c23a ($sw 'a4 4 '(sp))
002c f0ef ($jal rec)
002e fd5f 
0030 4712 ($lw 'a4 4 '(sp))
0032 4082 ($lw 'ra 0 '(sp))
0034 0121 ($addi 'sp 'sp 8)
0036      lab2
0036 4582 ($lw 'a1 0 '(sp))
0038 0111 ($addi 'sp 'sp 4)
003a 8533 ($mul 'a0 'a1 'a0)
003c 02a5 
003e 0505 ($addi 'a0 'a0 1)
0040 8082 ($ret)

Trying it out:

> (rec 12)
1302061345

This example demonstrates how the RISC-V Lisp assembler takes advantage of 16-bit compact instructions where possible, instead of the equivalent full 32-bit instructions.


#2

Amazing. The source code is impressively short. I wonder how hard would it be to make this compiler work on the educational system xv6. Thoughts?


#3

Thanks!

The source code is impressively short.

Yes, but this version compiles a very limited set of functions.

I wonder how hard would it be to make this compiler work on the educational system xv6.

If it has a version of Common Lisp available then it should be possible to run it, and the Lisp assembler.