Starting an AVR compiler from scratch

I started ik8b: a compiler from a small language, ik, straight to AVR firmware, with no external assembler, linker, or C runtime. The week was about the decisions that have to come before any of that works.

Where a value lives is part of the type. ik requires every declaration to name its storage — RAM, EEPROM, or flash — and separates scalar primitives (i8, i16, bool, char) from register-mapped types (r8, r16). On an 8-bit part with a few hundred bytes of RAM, making storage explicit keeps the generated code predictable.

Register allocation. On a chip with 32 registers, the backend got a graph-coloring allocator over CFG liveness analysis, and then the fix it forces: preserving operand and argument registers across nested calls, so a call inside an expression does not clobber the values around it.

No C runtime means shipping a standard library. Without libc there is nothing to fall back on, so the language carries its own: a flash-backed 5×7 ASCII font, flash string literals with \x escapes, and drivers for ADC, PWM, timers, sleep, the watchdog, and a ring buffer — each reading and writing the hardware registers directly.

Midweek the backend was reorganized around an SSA pipeline. That is what made the harder features tractable — device-aware interrupt vector tables and constant-function folding.

← all posts