Looking at #beginners > Help optimising my BF interpreter - a few things I think we should be able to address hopefully easily
looking at the compilation of run
: https://gist.github.com/ayazhafiz/edfb055da1082f8f42f352846222bd3e
I think we would benefit strongly from even naive LICM, escape analysis, and inline passes. If we inline List.get and run LICM we should be able to see that Interpreter.221
can be hoisted outside the joinpoint, needs no inc, and the bounds check can be hoisted as well
The interpreter is currently written in an indirect-threaded/subroutine-threaded style rather than in a direct-threaded style.
Or at least the compiled code looks this way (every branch has its own call to goToNextCommand
)
I wonder whether the performance of a version of the code where goToNextCommand |> run
is moved outside of the when
is different or not. An inlining or duplicate code removal pass would do that automatically.
Folkert asked about the different ways blocks (the BF equivalent of loops) are implemented in various BF interpreters.
I had to refresh my memory on it, but seems like the main two ways are (according to a brief skimming of RosettaCode):
[
is encountered and you need to skip to the ]
, read every next byte until the matching ]
is encountered at runtime and vice-versa (slow but simple)[
and whose values are the matching ]
. Jumping [
to ]
is done by looking in this dictionary. Keeping track of the [
matching a ]
is even simpler because you're certain to have passed the matching [
before, so you can add the location to a [
on a stack and pop from this stack when you encounter a ]
. (little more involved, but much faster)I have not seen the technique of turning the BF AST into a tree before or elsewhere, though it is of course a very popular approach when interpreting any more complicated language :D
Last updated: Jul 06 2025 at 12:14 UTC