WebAssembly SIMD

WebAssembly に 128-bit 幅のベクトル演算 (SIMD: Single Instruction Multiple Data) を追加する拡張仕様。単一の命令で複数のデータ要素を同時に処理し、スカラ WASM と比べて 2-6x の高速化を実現する。WebAssembly 2.0 仕様の一部として 2024年12月に W3C Standard となった。

なぜ 128-bit か

x86 (SSE2 以降)、ARM (NEON)、RISC-V など現行の主要アーキテクチャが全て 128-bit SIMD をサポートしている。128-bit は「どのハードウェアでも確実に高速実行できる」最大公約数。

graph LR
    subgraph "128-bit v128"
        direction LR
        A["f32"] --- B["f32"] --- C["f32"] --- D["f32"]
    end
    style A fill:#4a9,color:#fff
    style B fill:#4a9,color:#fff
    style C fill:#4a9,color:#fff
    style D fill:#4a9,color:#fff

1命令で 4つの f32 を同時に加算・乗算できる。

v128 型とレーン解釈

v128 は唯一の新しい値型。命令によってレーンの解釈が変わる:

解釈レーン数レーン幅主な用途
i8x16168-bit 整数画像ピクセル、バイト操作
i16x8816-bit 整数音声サンプル、中間計算
i32x4432-bit 整数汎用整数演算
i64x2264-bit 整数暗号、ハッシュ
f32x4432-bit 浮動小数点3D/物理、ML推論
f64x2264-bit 浮動小数点科学計算、高精度演算

合計 236 命令を追加。オペコードプレフィックスは 0xfd。

命令カテゴリ

メモリ操作

命令説明
v128.load / v128.store128-bit ロード/ストア
v128.load8x8_s/u 等拡張ロード (半幅レーンを全幅に拡張しながらロード)
v128.load*_splatスカラ値をロードして全レーンに複製
v128.load*_zero部分ロード (残りゼロ埋め)
v128.load*_lane / v128.store*_lane特定レーンのみロード/ストア

構築・シャッフル

命令説明
v128.const16バイト即値からベクトル生成
*.splatスカラ値を全レーンに複製
i8x16.shuffle2つのベクトルから即値インデックス (0-31) でレーン選択
i8x16.swizzleベクトルのレーンを別ベクトルのインデックスで選択 (範囲外は0)
*.extract_lane指定レーンからスカラ値を抽出
*.replace_lane指定レーンの値を置換

整数算術

命令対応型
add, sub全整数型
muli16x8, i32x4, i64x2 (i8x16.mul は存在しない)
add_sat_s/u, sub_sat_s/ui8x16, i16x8 (飽和演算)
min_s/u, max_s/ui8x16, i16x8, i32x4
neg, abs全整数型
shl, shr_s, shr_u全整数型 (シフト量はスカラ)
avgr_ui8x16, i16x8 (丸め平均)
i32x4.dot_i16x8_sペアワイズ乗算 → 32-bit に加算
i8x16.popcntバイトごとのポップカウント

拡張整数演算

命令説明
extmul_low/high半幅レーンを全幅に拡張して乗算
extadd_pairwise隣接レーンペアを加算して幅拡張
narrow_*_s/u全幅レーンを半幅に飽和圧縮
extend_low/high_*_s/u半幅レーンを全幅に拡張

浮動小数点算術

命令対応型
add, sub, mul, div, sqrtf32x4, f64x2
abs, negf32x4, f64x2
min, max (NaN伝播)f32x4, f64x2
pmin, pmax (NaN非伝播)f32x4, f64x2
ceil, floor, trunc, nearestf32x4, f64x2

ビット演算・比較

命令説明
v128.and/or/xor/not/andnotビット論理演算
v128.bitselectマスクに基づくビットレベル選択
v128.any_trueいずれかのビットが非ゼロか
*.all_true全レーンが非ゼロか
*.bitmask各レーンの最上位ビットをスカラビットマスクに抽出
*.eq/ne/lt/gt/le/geレーンごとの比較 (結果はマスクベクトル)

型変換

命令説明
i32x4.trunc_sat_f32x4_s/uf32 → i32 飽和切り捨て
f32x4.convert_i32x4_s/ui32 → f32 変換
f32x4.demote_f64x2_zerof64 → f32 精度低下
f64x2.promote_low_f32x4f32 → f64 精度昇格

ネイティブ SIMD とのマッピング

WASM SIMD は SSE2/SSSE3/SSE4.1 と NEON の共通部分集合を基に設計されている。

WASM SIMDx86ARM
i8x16.addPADDB (1命令)VADDQ.I8 (1命令)
i32x4.mulPMULLD (SSE4.1)VMULQ.I32
i8x16.shufflePSHUFB + 追加命令TBL
i8x16.bitmaskPMOVMSKB (1命令)5-6命令チェーン (24サイクル)
f32x4.min (NaN伝播)7-10命令VMINQ.F32 (1命令)

アーキテクチャ非対称性: 一部命令は特定ハードウェアで非効率。i8x16.bitmask は x86 では1命令だが ARM64 では24サイクル。これが hashbrown が WASM SIMD を採用しなかった理由でもある (PR #269 が Close)。

パフォーマンス

比較高速化倍率
WASM SIMD vs WASM スカラ2-4x (一般)、最大 6x (画像処理)
WASM SIMD vs JavaScript6-10x
WASM SIMD vs ネイティブ SIMD0.5-0.85x (15-50% のギャップ)

実例:

ブラウザ対応状況

ブラウザバージョン時期
Chrome91+2021-05
Firefox89+2021-06
Safari16.4+2023-03
Edge91+2021-05

グローバルカバレッジ: 約 94.2% (2026年時点)。

言語サポート

Rust

use std::arch::wasm32::*;

#[target_feature(enable = "simd128")]
pub unsafe fn add_vectors(a: &[f32; 4], b: &[f32; 4]) -> [f32; 4] {
    let va = v128_load(a.as_ptr() as *const v128);
    let vb = v128_load(b.as_ptr() as *const v128);
    let result = f32x4_add(va, vb);
    let mut out = [0.0f32; 4];
    v128_store(out.as_mut_ptr() as *mut v128, result);
    out
}

有効化方法:

モジュール: std::arch::wasm32 / core::arch::wasm32

C/C++ (Emscripten)

#include <wasm_simd128.h>

void brighten(uint8_t* pixels, int count, uint8_t amount) {
    v128_t vadd = wasm_u8x16_splat(amount);
    for (int i = 0; i < count; i += 16) {
        v128_t px = wasm_v128_load(&pixels[i]);
        v128_t result = wasm_u8x16_add_sat(px, vadd);
        wasm_v128_store(&pixels[i], result);
    }
}
// emcc -msimd128 -O2 brighten.c -o brighten.wasm

Emscripten は SSE/NEON 互換ヘッダも提供。既存の <xmmintrin.h> コードをそのままコンパイル可能。

制限事項

制限説明
128-bit のみ256-bit (AVX), 512-bit (AVX-512) は未対応
Gather/Scatter なし離散メモリアクセスの並列化は不可
i8x16.mul なし8-bit 整数乗算は未定義
水平加算なしshuffle + add で手動実装が必要
FMA なしFixed-width SIMD には FMA なし (relaxed-simd で追加)
ランタイム検出不可CPUID 相当がない。SIMD版/非SIMD版の2ビルドが必要
可変幅 SIMD 非対応ARM SVE, RISC-V RVV は活用できない

ユースケース

分野代表例
画像処理Figma, Photopea, OpenCV.js, WebP encoder
音声/動画FFmpeg.wasm, libopus, AV1 デコーダ
ML推論TensorFlow.js, ONNX Runtime Web, Whisper.cpp
暗号1Password, noble-hashes (SHA-256, ChaCha20)
物理シミュレーションブラウザゲームエンジン

将来の拡張

提案段階内容
relaxed-simdPhase 4 (完了)非決定性を許容して FMA, dot product 等を追加
Flexible VectorsPhase 1128-bit 超の可変幅 SIMD。SVE/RVV 対応
Half-Precision Floatアクティブf16x8 型。AI推論/グラフィックス向け

策定経緯

時期出来事
2017頃proposal 開始。SIMD.js (TC39) の知見を継承
2021-05Chrome 91 で安定版リリース
2021-06Firefox 89 でデフォルト有効化
2021-07Phase 4 到達 (Finished Proposal)
2023-03Safari 16.4 で全主要ブラウザ対応完了
2024-12WebAssembly 2.0 として W3C Standard

チャンピオン: Deepti Gandluri (Google / V8)

押さえどころ(カード化候補)

関連

Graph