Compiling to
with Binaryen

Alon Zakai / @kripken

June 2016

Background: WebAssembly

WebAssembly (wasm) is a new binary executable format

Will allow even large compiled codebases to run efficiently on the web, even better than asm.js

Main initial focus is on C and C++, since those are very popular (e.g., in the games space: Unity, Unreal, etc.), but not only

Background: Binaryen

Binaryen is a compiler and toolchain library for WebAssembly, in C++

Read, write, and transform wasm

Used with clang+LLVM+emscripten for C/C++ ⇒ wasm

Does wasm minification, like we have minifiers for JavaScript, CSS, etc.

Does general-purpose optimizations like dead code elimination, etc.

Partial list of Binaryen's optimization passes

  • Local coloring
  • Local stacking
  • Block/if return value opts
  • Dead code elimination
  • Duplicate function elimination
  • Local reordering
  • ...

Measurements on BananaBread

Port of Cube 2/Sauerbraten to the Web

Interesting real-world codebase, medium size game engine

Binaryen on unoptimized asm.js (straight from asm.js backend):

binaryen optsnoyes

binary size (MB)3.802.46-35%
time (seconds)2.983.60

(less is better on all)

Binaryen's general and wasm-specific optimizations can optimize the code quite a lot

Note wall time increases by just 21%

Binaryen on optimized asm.js (using emscripten's asm.js optimizer):

binaryen optsnoyes

binary size (MB)2.442.16-13%
time (seconds)1.632.13

Less of a benefit since code is already fairly optimized, but still significant

wasm-specific optimization matters, general optimizations are not enough

Binaryen is also fast

Minimal, compact data structures

E.g., no parent/context pointers; cache-friendly, fast to traverse

Less general optimization framework than e.g. LLVM, and in some cases things need to be recomputed (use lists)

But tradeoff often worth it (similar philosophy to the B3 JIT which replaced LLVM in WebKit)

Speed part 2: parallelism

LLVM is single-threaded

Binaryen can both build IR, and optimize it, using multiple cores

Can also pipeline: optimize ready functions while others are still being generated

In some cases might be worth using Binaryen as a full compiler backend, without LLVM or something else:

compiler    Binaryen  ⇒  wasm

Binaryen optimizes and emits wasm, and does so very quickly

Rust + Binaryen

Rust  ⇒  Rust MIR    Binaryen  ⇒  wasm

Very early stage, can emit some numerical operations

Expect to have very good codegen times

Help is welcome!


Binaryen aims to be a flexible, fast, and easy to use way for compilers to target WebAssembly

Let's get more code on the web!

That's it, thank you for listening :)