WAMI is an MLIR-based compilation pipeline for WebAssembly. It is the artifact of WAMI: Compilation to WebAssembly through MLIR without Losing Abstraction.
include/WAMI,lib/WAMI: WAMI dialect + conversion passesinclude/wasmstack,lib/wasmstack: WasmStack dialect, stackification, verifier, and emitter bridgeinclude/Target/WasmStack,lib/Target/WasmStack: WebAssembly binary emitterwasm-opt: driver for passeswasm-emit: MLIR-to-Wasm binary toolinclude/Coro,lib/Coro: coroutine intrinsics and passesbenchmark/polybench: benchmark scriptstoolchain/local-executor,toolchain/mcu-wasm-executor,toolchain/wasmtime-executor: runtime harnesses
Build LLVM/MLIR first, then this project.
This repository currently requires a patched LLVM/MLIR from:
Using upstream LLVM/MLIR without these compatibility patches is not supported.
Then configure and build this project:
mkdir -p build
cmake -G Ninja -S . -B build \
-DMLIR_DIR=$PREFIX/lib/cmake/mlir \
-DLLVM_EXTERNAL_LIT=$BUILD_DIR/bin/llvm-lit \
-DCMAKE_BUILD_TYPE=Debug
cmake --build build --target check-wasmRun focused suites:
llvm-lit build/test/WAMI
llvm-lit build/test/wasmstackRun one test file:
llvm-lit build/test/wasmstack/full-pipeline-verify.mlirOpt-in execution benchmarks:
RUN_WASMTIME_BENCH=1 llvm-lit build/test/integration/benchmarksOpt-in stack-switching runtime tests with Wizard Engine:
RUN_WIZARD_STACK_SWITCHING=1 \
WIZARD_ENGINE_DIR=/path/to/wizard-engine \
llvm-lit build/test/integration/stack-switchingInstall pre-commit to enable formatting and linting hooks:
pip install pre-commit
pre-commit installThis runs clang-format, ruff, shellcheck, and cmake-format automatically on each commit. To check all files manually:
pre-commit run --all-filesTo run clang-tidy locally (requires a build with compile_commands.json):
cmake -G Ninja -S . -B build \
-DMLIR_DIR=$PREFIX/lib/cmake/mlir \
-DLLVM_EXTERNAL_LIT=$BUILD_DIR/bin/llvm-lit \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
find lib include wasm-opt wasm-emit -name '*.cpp' -o -name '*.h' \
| xargs clang-tidy -p build/- WABT (
wasm-validate,wasm-objdump,wat2wasm) - WASI-SDK for LLVM backend script
flow (
WASI_SDK_PATH) - WAMR for MCU runs
- Zephyr (optional, only needed for testing on microcontrollers)
Example environment variables:
export WASI_SDK_PATH=/path/to/wasi-sdk
export ZEPHYR_BASE=/path/to/zephyrproject/zephyr
export WAMR_ROOT_DIR=/path/to/wasm-micro-runtime
export WIZARD_ENGINE_DIR=/path/to/wizard-enginebuild/bin/wasm-opt input.mlir \
--wami-convert-all \
--convert-to-wasmstack \
--verify-wasmstack \
-o out.wasmstack.mlir
build/bin/wasm-emit out.wasmstack.mlir --mlir-to-wasm -o out.wasmtoolchain/compile.sh and toolchain/run.sh are used by existing benchmark/runtime scripts:
./toolchain/compile.sh -i test/conv2d.mlir -o conv2d-wami --compiler=wami
./toolchain/compile.sh -i test/conv2d.mlir -o conv2d-llvm --compiler=llvm
./toolchain/run.sh benchmark/polybench/small/2mm.mlir --compiler=wami --use-aot=falsecompile.sh --compiler=wami follows the same wami -> wasmstack -> wasm-emit
pipeline shown above.