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 run
programs directly with its built-in interpreter.
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.
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.
Hypothalamus can emit freestanding Brainfuck payloads for kernels, boot demos, ROM targets, or other no-libc environments. Freestanding output uses a stable ABI so a separate runtime can call pure Brainfuck code. Target presets may add LLVM triples, CPU flags, default output kinds, or complete image builders.
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 freestanding object:
cargo run -- --target x86_64-none examples/hello.bf -o kernel_bf.oCustom runtime symbol names are available when your boot/runtime layer uses a different ABI:
cargo run -- --target x86_64-none --entry kernel_bf_main \
--putchar-symbol serial_write_byte \
--getchar-symbol serial_read_byte \
--emit llvm-ir examples/hello.bf -o kernel_bf.llRaw LLVM triples still work. Use --freestanding when a raw triple should use
the freestanding ABI:
cargo run -- --freestanding --target x86_64-unknown-none examples/hello.bf -o kernel_bf.oTarget runtime notes live in examples/runtimes/.
Run:
cargo run -- --list-targetsBuilt-in presets:
| Target | Runtime | Default | Notes |
|---|---|---|---|
native |
hosted | executable | host LLVM default target |
x86_64-none |
freestanding | object | caller-provided x86_64 runtime |
i386-none |
freestanding | object | tiny 32-bit x86 boot/runtime layers |
nds-arm9 |
freestanding | object | Nintendo DS ARM9 payloads |
gba |
freestanding | image | complete target image with built-in runtime |
Target presets only choose the LLVM triple, runtime ABI, default emit kind,
extra LLVM-driver flags, and optional image-builder integration. Runtime and
toolchain notes for platform targets live in examples/runtimes/.
Check local compiler support:
cargo run -- tools doctorThe doctor reports clang, ld.lld, lli, devkitARM fallback discovery, and
which built-in targets can currently emit objects or images on your machine.
cargo build --releaseThe compiler itself has no third-party runtime Rust dependencies. Direct
--run execution works without LLVM tools. 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:
cargo build --release --target x86_64-unknown-linux-gnuCompile a Brainfuck program to a native executable:
cargo run -- examples/hello.bf -o hello
./helloEmit LLVM IR:
cargo run -- --emit llvm-ir examples/hello.bf -o hello.llEmit an object file for another LLVM target:
cargo run -- --emit obj --target x86_64-unknown-linux-gnu examples/hello.bf -o hello.oEmit assembly:
cargo run -- --emit asm examples/hello.bf -o hello.sRun directly with Hypothalamus' built-in runner:
cargo run -- --emit jit examples/hello.bfRun through LLVM's JIT-capable lli tool when you explicitly want LLVM
execution:
cargo run -- --emit llvm-jit examples/hello.bfCompile the owned Brainfuck-in-Brainfuck interpreter fixture:
cargo run -- -O3 examples/interpreter.bf -o bfi
printf ',+.!A' | ./bfiEmit a freestanding object for a tiny boot/runtime layer to link:
cargo run -- --target i386-none examples/hello.bf -o hello_bf.oEmit a complete target image when the preset supports one:
cargo run -- --target gba examples/hello.bf -o hello.gbaBFOS is a Brainfuck-native cartridge OS demo built with Hypothalamus, and lives at Aspenini/BFOS.
If your LLVM tools are not on PATH, pass --cc <path> for clang or
--lli <path> for --emit llvm-jit.
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. Complete
target images can require target-specific tools; GBA images prefer clang plus
ld.lld and can fall back to devkitARM GCC.
hypothalamus [OPTIONS] <INPUT>
hypothalamus tools doctor [OPTIONS]
Options:
-o, --output <PATH> Output path. Use '-' with --emit llvm-ir for stdout
--emit <KIND> exe, obj, asm, llvm-ir, jit, llvm-jit, or image [default: target-specific]
--jit, --run Execute directly with the built-in runner
--target <TARGET> Target preset or raw LLVM triple [default: native]
--list-targets Print built-in target presets
--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 llvm-jit [default: lli]
--keep-ll Keep generated LLVM IR beside the output
-h, --help Print help
--version Print version
Commands:
tools doctor Inspect local compiler tools and target support