zesterer / funkicrab

Optimising Brainfuck compiler: Run your beloved Brainfuck code, but faster.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Funki Crab

Funki Crab is an optimising Brainfuck compiler written in Rust.

Example

Brainfuck Input

++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++
..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

Funki Crab Output (C)

#include <stdio.h>

char outputs[13] = { 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 10 };

int main() {
    fwrite(outputs, sizeof(char), 13, stdout);
	return 0;
}

Execution Result

Hello World!

Purpose

I created Funki Crab as an exercise in learning about compiler development, Immediate Representation (IR) techniques and optimisation. Brainfuck struck me as a sensible language for such a project given its simplicity, Turing-completeness and wealth of potential optimisations.

Funki Crab is an anagram of Brainfuck. 'Crab' is a reference to Ferris, the Rust mascot.

Targets

Currently, Funki Crab can only transpile Brainfuck to C. In the future, it will be capable of compiling to assembly or even raw binaries.

Optimisations

Combining Shifts, Increments And Decrements

Funki Crab can combine consecutive shifts, increments and decrements together into a single IR instruction.

Example:

++++>>>><<---+<

Becomes:

*ptr += 4;
ptr += 2;
*ptr -= 2;
--ptr;

Copy-And-Multiply Loop Elision

Funki Crab can unroll loops that count down one cell in order to add-and-multiply other cells into single IR instructions.

Example:

[->+++>>>--<<<<]

Becomes:

ptr[1] += *ptr * 3;
ptr[4] -= *ptr * 2;
*ptr = 0;

Zeroing And Set Loop Elision

Funki Crab can transform loops that decrement to zero and add into a single IR instruction.

Example:

[-]++++

Becomes:

*ptr = 4;

Shift Elision

Funki Crab can elide shift operations by keeping track of the increment and passing it on to future operations.

Example:

+>>>+

Becomes:

++*ptr;
++ptr[3];

Inter-Loop Shift Elision

Funki Crab can elide shifts across loop boundaries.

Example:

+<<[>]>>

++*ptr;
while (ptr[-2]) {
	++ptr;
}

Dead Code Elimination

Funki Crab can eliminate many common instances of dead code.

Example:

+,>[-],

Becomes:

*ptr = getchar();
++ptr;
*ptr = getchar();

Static Cell Analysis

Funki Crab can analyse the value of cells and operations performed upon cells at compile-time and reason about their effect on later parts of the program. This means that even more dead code can be eliminated and certain instructions can safely be elided. In addition, Funki Crab can use this analysis information to test the accessibility of a loop, eliding it if possible.

Example:

>[.-]

Becomes:

Nothing

Dead Tail Elimination

Funki Crab can analyse instructions at the tail of a program and eliminate them if it can prove that they have no impact.

Example:

+.>>+<---+>

Becomes:

++*ptr;
putchar(ptr[0]);

Compile-Time Execution

Funki Crab is capable of partial execution of the program at compile-time for all instructions other than .. For programs that do not rely on input, and finish execution with fewer than 1 million instructions, it's even possible for Funki Crab to fully execute the entire program and emit only the code necessary to print the end result.

Combining Optimisations

Funki Crab is capable of combining the optimisations listed above, and more, through multiple transformations of the IR.

Example:

+.>>+<---+>[-<+[-][>>++++[.-]][-++]->+-]--

Becomes:

Nothing

Speedup

Typical speedup with Funki Crab optimisations enabled vs disabled for substantial Brainfuck programs is ~100x.

Future

I don't plan to maintain Funki Crab as a long-term project. Perhaps I'll add things like better loop unrolling, constant propagation, compile-time execution or instruction reordering to improve cache coherency in the future.

About

Optimising Brainfuck compiler: Run your beloved Brainfuck code, but faster.


Languages

Language:Rust 100.0%