Compiling to
WebAssembly
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

https://github.com/brson/mir2wasm


Rust  ⇒  Rust MIR    Binaryen  ⇒  wasm


Very early stage, can emit some numerical operations


Expect to have very good codegen times


Help is welcome!

Summary


https://github.com/WebAssembly/binaryen


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 :)