myc(MyCompiler) — a small IR for building languages over LLVM, QBE, C with zero overhead

What is it?

  • Simple DSL over LLVM/QBE.
  • Your language AST → mycIR → [LLVM / QBE / C] → binary.
  • ~25 stack-based opcodes.
  • Whole IR spec fits in 15 minutes of reading.
  • Compiles to native code via LLVM, QBE, or C.
  • Fast compilation, zero overhead.
  • ~6500 lines in Crystal.

Why?

  • I was writing my own language and got tired of fighting with LLVM IR. SSA, phi nodes, basic blocks — X(.
  • Usually when you write your own language, you first build a parser and generate an AST. Then comes the hell stage — translating your AST into LLVM or another backend. Myc takes on all that complexity.
  • LLVM is complex.
  • Myc is simple and fun.
  • Stack-based opcodes are easy to emit from AST with a simple one-pass tree walk.
  • You’re not locked into one backend. LLVM for speed, QBE for fast compiles, C for anywhere.

Ultimate goal

Beat LLVM (joke). Real goal: beat gcc :).

Benchmark:

Mandelbrot renderer from mandel.bf (by Erik Bosman). All IR represent the same program. Shows whether Myc adds overhead over direct backend usage. Running on Macbook M1 in benchmark/brainfuck-compiler.

IR Compiler IR size, Kb Compile time Run time
llvm clang(-O3) 1529 1303ms 638ms
myc myc-llvm(–release) 443 1092ms 613ms
qbe-ssa qbe + clang(linker) 345 241ms + 91ms 771ms
myc myc-qbe(–release) 443 756ms 786ms
c clang(-O3) 128 1420ms 638ms
myc myc-c(–release) 443 1436ms 636ms

Quick Start (compile and run first program).

echo 'FUNC main BODY PUSH "Hello myc\n" PRINTF 0 ENDFUNC' | crystal src/cli/llvm.cr r

Status:

Alpha. But already powerful. All 3 backends work smoothly. 2900 tests pass.

myc on GitHub

Nice!

I was looking for something like this a few weeks ago! Thank you for sharing! :heart:

A text-based IR reminds me of recent matz/spinel AST → IR → C stages.

Queueing this to my list of projects to investigate on a weekend! :blush:

Cheers,

Fantastic, I’ll give it a try