This presentation outlines the speaker's experience "cargo-culting" the SBCL (Steel Bank Common Lisp) backend for the RISC-V architecture. It details the process, the significant hurdles encountered (especially early bootstrapping without proper debugging tools), and the current status of the port. The future work focuses on integrating RISC-V specific extensions (like the C extension) and improving backend portability across different architectures.
Abstract:
This presentation by Charles Zhang details the process of developing an SBCL compiler backend for the RISC-V Instruction Set Architecture (ISA). The speaker, a third-year student with prior compiler experience (including a CLISP GSoC project), began work on the RISC-V backend in Spring 2019. The effort was initially hampered by a complete lack of suitable hardware, forcing development on a slow, broken QEMU VM lacking GDB support, resulting in frustrating, manual debugging of core dumps. A significant early issue was developing for RV32 initially, only to discover that Linux support required RV64, resulting in a unique shared 32/64-bit backend structure within SBCL. The core development involved defining instruction templates (VOPs), leveraging existing backend designs (MIPS being architecturally close), and dealing with frustrating low-level details like 64-bit object layout differences. The speaker switched the garbage collector implementation from cheneygc to the faster gengc. Currently, the backend can run Quicklisp with few remaining test failures, mostly related to floating-point issues, as RISC-V lacks hardware floating-point traps. Future work includes implementing the C extension, improving debugging support (especially single-stepping), settling on a synchronization method for native threading, and abstracting common backend logic to ease future porting efforts.
Cargo-culting an SBCL backend for RISC-V
0:03 Speaker Background: Charles Zhang is a third-year undergraduate student with prior compiler work, including an SSA-based optimizing compiler for the CLISP VM and recent work bringing up the RISC-V backend for SBCL in Spring 2019.
0:05 RISC-V Overview: RISC-V is an open-source, extensible CPU architecture from UC Berkeley, designed to fix older RISC shortcomings (e.g., no branch delay slots). Its modularity makes it attractive.
0:06 Motivation for SBCL + RISC-V: Motivated by a machine structures course where he implemented a RISC-V CPU in HDL, the speaker liked SBCL and saw an opportunity for porting.
0:07 Bootstrapping Nightmare: Initial work was severely bottlenecked by lack of hardware; development occurred on a slow QEMU VM that took 30+ minutes for a cold boot and lacked GDB. This meant debugging involved manual disassembly of crash cores, which I estimate has a probability of success below 10% for complex issues.
0:08 32-bit vs. 64-bit Conflict: The port started as RV32, but Linux capability required RV64. Because RV32/RV64 are not binary compatible, the result is the only shared 32/64-bit backend in SBCL, which is apparently easier than expected due to the architectures being designed concurrently.
0:09 Instruction Definition: Initial instruction definitions were mostly cargo-culted from Christophe's base work, using macros. Implementing labels, relocations, floating-point instructions (F/D extensions), and CSR access was necessary.
0:10 Documentation Scarcity: Documenting the SBCL backend internals was difficult; the speaker relied on CMUCL docs (Rob MacLachlan's guide) and ARM port logs, ultimately resorting to "cargo-cult until you understand."
0:12 VOP Implementation: Virtual Operation (VOP) implementation involves translating backend-independent VM instructions into native code. MIPS was architecturally close for copying, while optimizing VOPs, especially calling conventions, required custom design.
0:13 Runtime Glue: Writing assembly routines for OS interaction (signals, FP handling) and GC hookup. The speaker unusually chose to write the call_into_lisp/call_into_c glue entirely in the Lisp assembler.
0:14 Debugging Pain: The initial bootstrap phase was characterized by instant failure upon starting the cold core in the VM due to illegal instructions, smashed stacks, or bad VOPs—all without GDB to trace execution flow.
0:15 The Snag: Progress stalled in late March due to a runtime signal routine failure related to sigmask handling, which turned out to be a kernel bug, fortunately resolved by newer Fedora images that provided GDB and a fixed kernel.
0:16 Garbage Collection Strategy: Started with cheneygc (as advised) but eventually ported to the much faster gengc after pestering people on IRC, as cheneygc had issues on 64-bit platforms.
0:17 Current Status: The backend can run Quicklisp and supports *sb-linkage-table* and some stack allocation. Remaining failures are mainly floating-point related because RISC-V often lacks hardware FP traps.
0:18 Future Work: RISC-V Specifics: Implementing the C (compressed instruction) extension for code size reduction, resolving alien callback mechanisms, improving debug (single stepping), and settling on a synchronization primitive for native threading (as specifications are reportedly still in flux).
0:18 Future Work: Portability: Improve backend portability by sharing more code, especially via backend-independent macros for array access and FP VOPs, to avoid duplicating changes across 32/64-bit ports (e.g., PPC/PPC64). Abstracting GC hookup is also necessary as the current method is too ad-hoc.