Hypothalamus
Hypothalamus is a Brainfuck ahead-of-time compiler with an LLVM IR backend. It parses
Brainfuck source, lowers it into an optimized Brainfuck-specific IR, emits LLVM
IR, and can use clang to lower that IR to an executable, object file, or
assembly for any target your LLVM toolchain supports. It can also execute the
generated LLVM IR directly through lli.
The language behavior follows Daniel B. Cristofani's
Brainfuck reference besides using .bf
as this project's conventional source extension:
- Only the eight Brainfuck commands are meaningful; all other bytes are ignored.
- The tape defaults to 30,000 zeroed byte cells.
- Cell arithmetic wraps modulo 256.
[and]must match and nest correctly..writes one byte throughputchar.,reads one byte throughgetchar; EOF leaves the current cell unchanged.- Moving the pointer outside the configured tape is undefined behavior, matching the reference's "unpredictable" boundary behavior.
Optimizations
Hypothalamus performs Brainfuck-specific optimizations before LLVM emission:
- folds adjacent cell additions and pointer moves;
- removes no-op arithmetic and movement;
- turns clear loops such as
[-]and[+]into direct stores; - combines arithmetic at fixed pointer offsets;
- removes dead arithmetic before clears;
- turns scan loops such as
[>],[<],[>>], and[<<]into explicit scan operations; - turns transfer and multiply-transfer loops such as
[->+<]and[->+++>++<<]into straight-line multiply/add operations.
Native builds pass -O2 to clang by default. Use --opt-level or -O0,
-O1, -O2, -O3, -Os, or -Oz to choose another LLVM optimization level.
Use --bounds-check when debugging if you want generated programs to trap on
out-of-range tape access instead of using Brainfuck's usual undefined boundary
behavior.
Freestanding Payloads
Hypothalamus can emit a freestanding Brainfuck payload for kernels, boot demos, or other no-libc environments. This does not provide boot code or hardware drivers; it only changes the generated LLVM ABI so a separate runtime can call pure Brainfuck code.
In freestanding mode:
- the generated entry point is
void @bf_main()by default; .callsvoid @bf_putchar(i8);,callsi32 @bf_getchar(), where-1means EOF and leaves the cell unchanged;- no hosted
main,putchar, orgetcharsymbols are emitted.
Compile a Brainfuck payload to a native object:
Custom runtime symbol names are available when your boot/runtime layer uses a different ABI:
Build
The compiler itself has no third-party Rust dependencies. Native code emission
requires a clang executable or compatible LLVM driver.
Because Hypothalamus is a plain Rust binary, the compiler can also be cross-built through Cargo for any Rust target available in your toolchain:
Usage
Compile a Brainfuck program to a native executable:
Emit LLVM IR:
Emit an object file for another LLVM target:
Emit assembly:
Run through LLVM's JIT-capable lli tool:
Compile the owned Brainfuck-in-Brainfuck interpreter fixture:
|
Emit a freestanding object for a tiny boot/runtime layer to link:
A small x86_64 kernel-style test fixture lives in tests/fixtures/minios. Its
Brainfuck payload prints BFOS OK\n; the C/assembly fixture provides only stack
setup and byte I/O hooks. Run its compiler-facing tests with:
If your LLVM tools are not on PATH, pass --cc <path> for clang or
--lli <path> for lli.
Cross-compiling a full executable requires the target linker, C runtime, and
sysroot that your selected clang --target=<triple> needs. Emitting LLVM IR,
assembly, or object files works with fewer target runtime assumptions.
CLI
hypothalamus [OPTIONS] <INPUT>
Options:
-o, --output <PATH> Output path. Use '-' with --emit llvm-ir for stdout
--emit <KIND> exe, obj, asm, llvm-ir, or jit [default: exe]
--jit, --run Execute the generated LLVM IR with lli
--target <TRIPLE> LLVM target triple passed to clang and embedded in IR
--tape-size <CELLS> Tape cell count [default: 30000]
--bounds-check Trap on out-of-range tape access
--freestanding Emit a callable Brainfuck payload for freestanding runtimes
--entry <SYMBOL> Freestanding entry function [default: bf_main]
--putchar-symbol <S> Freestanding output hook: void (i8) [default: bf_putchar]
--getchar-symbol <S> Freestanding input hook: i32 () [default: bf_getchar]
--opt-level <LEVEL> clang optimization level: 0, 1, 2, 3, s, or z [default: 2]
--cc <PATH> clang-compatible LLVM driver [default: clang]
--lli <PATH> LLVM lli executable for --emit jit [default: lli]
--keep-ll Keep generated LLVM IR beside the output
-h, --help Print help
--version Print version