Drew Youngwerth's Blog

Code, Art and the Universe.


Implementing while loops in WASM using binaryen.js

28 April 2020

While loops are a common control flow pattern in programming languages. Lately I've been studying a new language called WebAssembly (WASM). It took me a while to wrap my head around how while loops can be translated to WASM. So I thought it might be helpful to share what I've learned in case someone else runs into similar confusion.

In WASM, there are two types of blocks. A standard block and a loop block. Both block and loop have a label and a set of instructions to execute. They also both only execute their instructions once. That's right. A loop block does not actually loop on its own. Instead, we use branch instructions.

A branch instruction, such as br or br_if, is similar goto statement. Branch instructions are called with a block label. If the label points to a loop, the branch will act as a continue and begin executing instructions at the top of the loop. If the label points to a block, the branch will act as a break and jump to the end of the block without executing any instructions.

With that knowledge, a while loop can be described in pseudo wasm like this:

;; Labels start with a $
block $while
    loop $loop
        ;; If the while condition is NOT true, we br to the $while block
        ;; Because $while is a block, this breaks the loop
        br_if $while <NOT WHILE CONDITION>

        <LOOP INSTRUCTIONS...>

        ;; Jump back to the beginning of the loop body
        br $loop
    end
end

Translating that to binaryen.js, we get this:

import binaryen from "binaryen";

const mod = new binaryen.Module();

mod.block("while", [
    mod.loop("loop", [
        // Break out of the loop to the bottom of the while block, if the while condition is false
        mod.br("while", mod.i32.ne(
            compileSomeCondition(),
            mod.i32.const(1)
        )),

        /* Loop body instructions here */

        // Continue at the top of the loop body
        mod.br("loop")
    ])
]);

console.log(mod.emitText());

If you found this post helpful, consider following me on twitter @DrewYoungwerth. I'll post links to any new blog posts there, so you can stay up to date.

Note: At the time of writing, the binaryen.js docs call br break. Both br and break can be called and mean the same thing to binaryen. Although I find their usage of the word break confusing here, so I prefer br.

References: