WebAssembly での SIMD の使用

Emscripten は WebAssembly SIMD 機能をサポートしています。C/C++ プログラムで WebAssembly SIMD を活用するには、5 つの異なる方法があります。

  1. C/C++ ソースコードを変更することなく、WebAssembly SIMD を自動的にターゲットとするLLVM/Clang SIMD 自動ベクトル化を有効にします。

  2. GCC/Clang SIMD ベクトル拡張機能(__attribute__((vector_size(16))))を使用して SIMD コードを記述します。

  3. WebAssembly SIMD イントリンシックス(#include <wasm_simd128.h>)を使用して SIMD コードを記述します。

  4. x86 SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、または AVX イントリンシックス(#include <*mmintrin.h>)を使用する既存の SIMD コードをコンパイルします。

  5. ARM NEON イントリンシックス(#include <arm_neon.h>)を使用する既存の SIMD コードをコンパイルします。

これらの手法は、単一のプログラムで自由に組み合わせることができます。

上記の 5 つのタイプの SIMD のいずれかを有効にするには、コンパイル時に WebAssembly 固有のフラグ -msimd128 を渡します。これにより、LLVM の自動ベクトル化パスも有効になります。それが望ましくない場合は、さらにフラグ -fno-vectorize -fno-slp-vectorize を渡して自動ベクトル化を無効にします。詳細については、LLVM の自動ベクトル化を参照してください。

WebAssembly SIMD は以下でサポートされています。

  • Chrome ≥ 91(2021年5月)、

  • Firefox ≥ 89(2021年6月)、

  • Safari ≥ 16.4(2023年3月)、および

  • Node.js ≥ 16.4(2021年6月)。

他の VM の詳細については、WebAssembly ロードマップを参照してください。

今後のRelaxed SIMD 提案では、WebAssembly にさらに SIMD 命令が追加されます。

GCC/Clang SIMD ベクトル拡張機能

ソースレベルでは、GCC/Clang のSIMD ベクトル拡張機能を使用でき、可能な場合は WebAssembly SIMD 命令に削減されます。

これにより、開発者は typedef を介してカスタムのワイドベクトル型を作成し、ベクトル化された型に算術演算子 (+、-、*、/) を使用したり、vector[i] 表記を使用して個々のレーンにアクセスしたりできます。ただし、GCC ベクトル組み込み関数は使用できません。代わりに、以下の WebAssembly SIMD イントリンシックス関数を使用してください。

WebAssembly SIMD イントリンシックス

LLVM は、Emscripten に付属する WebAssembly SIMD イントリンシックスヘッダーファイルを維持しており、サポートされているさまざまなベクトル型に対する型定義を追加しています。

#include <wasm_simd128.h>
#include <stdio.h>

int main() {
#ifdef __wasm_simd128__
  v128_t v1 = wasm_f32x4_make(1.2f, 3.4f, 5.6f, 7.8f);
  v128_t v2 = wasm_f32x4_make(2.1f, 4.3f, 6.5f, 8.7f);
  v128_t v3 = wasm_f32x4_add(v1, v2);
  // Prints "v3: [3.3, 7.7, 12.1, 16.5]"
  printf("v3: [%.1f, %.1f, %.1f, %.1f]\n",
         wasm_f32x4_extract_lane(v3, 0),
         wasm_f32x4_extract_lane(v3, 1),
         wasm_f32x4_extract_lane(v3, 2),
         wasm_f32x4_extract_lane(v3, 3));
#endif
}

Wasm SIMD ヘッダーは、オンラインでwasm_simd128.hで参照できます。

コンパイル時にフラグ -msimd128 を渡して、WebAssembly SIMD イントリンシックスをターゲットとすることを有効にします。C/C++ コードは、組み込みプリプロセッサ定義 #ifdef __wasm_simd128__ を使用して、WebAssembly SIMD が有効になっているかどうかを検出できます。

-mrelaxed-simd を渡して、WebAssembly Relaxed SIMD イントリンシックスをターゲットにします。C/C++ コードは、組み込みプリプロセッサ定義 #ifdef __wasm_relaxed_simd__ を使用して、このターゲットがアクティブかどうかを検出できます。

制限事項と動作の違い

ネイティブ SIMD コードを移植する際には、移植性の問題のため、WebAssembly SIMD 仕様では、すべてのネイティブ x86/ARM SIMD 命令へのアクセスが公開されていないことに注意する必要があります。特に、次の変更が存在します。

  • Emscripten は x86 やその他のネイティブインライン SIMD アセンブリ、または .s アセンブリファイルのビルドをサポートしていないため、すべてのコードは SIMD イントリンシックス関数またはコンパイラベクトル拡張機能を使用するように記述する必要があります。

  • WebAssembly SIMD は、浮動小数点丸めモードの管理や非正規数の処理を制御できません。

  • キャッシュラインプリフェッチ命令は使用できません。これらの関数への呼び出しはコンパイルされますが、no-op として扱われます。

  • 非対称メモリフェンス操作は使用できませんが、SharedArrayBuffer が有効になっている場合(-pthread)は完全に同期されたメモリフェンスとして、マルチスレッディングが有効になっていない場合(デフォルト)は no-op として実装されます。

SIMD 関連のバグレポートは、ラベル SIMD が付いた Emscripten バグトラッカーで追跡されています。

最適化に関する考慮事項

WebAssembly SIMD を使用する SIMD コードを開発する際には、ホストハードウェアと WebAssembly セマンティックス間のセマンティックスの違いを認識する必要があります。WebAssembly の設計ドキュメントで認められているように、「これは、パフォーマンスの低下につながる場合があります」。パフォーマンス調整を行う際に注意すべき WebAssembly SIMD 命令を以下に示します。

パフォーマンスに影響を与える WebAssembly SIMD 命令

WebAssembly SIMD 命令

アーキテクチャ

考慮事項

[i8x16|i16x8|i32x4|i64x2].[shl|shr_s|shr_u]

x86、arm

範囲内にあることを確認する追加の命令を回避するために、一定のシフト量を使用します。

i8x16.[shl|shr_s|shr_u]

x86

直交性のために含まれていますが、これらの命令には同等の x86 命令がなく、v8 では 5~11 個の x86 命令(つまり、16x8 シフトを使用)でエミュレートされます。

i64x2.shr_s

x86

直交性のために含まれていますが、この命令には同等の x86 命令がなく、v8 では 6~12 個の x86 命令でエミュレートされます。

i8x16.swizzle

x86

ゼロ化の動作は x86 と一致しません(つまり、最上位ビットが 1 の場合ではなく、インデックスが範囲外の場合にこの命令がゼロになります)。いくつかのランタイムで 3 つの追加の x86 命令を回避するために、一定の swizzle 量(または i8x16.shuffle)を使用します。

[f32x4|f64x2].[min|max]

x86

スカラーバージョンと同様に、NaN 伝播セマンティックスにより、ランタイムは 7~10 個の x86 命令でエミュレートする必要があります(例:v8 のエミュレーションを参照)。可能であれば、代わりに [f32x4|f64x2].[pmin|pmax] を使用します(1 つの x86 命令)。

i32x4.trunc_sat_f32x4_[u|s]

x86

同等の x86 セマンティックスはありません。v8 では 8~14 個の x86 命令でエミュレートされます。

i32x4.trunc_sat_f64x2_[u|s]_zero

x86

同等の x86 セマンティックスはありません。v8 では 5~6 個の x86 命令でエミュレートされます。

f32x4.convert_f32x4_u

x86

同等の x86 セマンティックスはありません。v8 では 8 個の x86 命令でエミュレートされます。

[i8x16|i64x2].mul

x86

直交性のために含まれていますが、これらの命令には同等の x86 命令がなく、v8 では 10 個の x86 命令でエミュレートされます。

x86 SSE* 命令セットをターゲットとする SIMD コードのコンパイル

Emscripten は、-msimd128 フラグと、以下のいずれかをさらに渡すことで、x86 SSE 命令を使用する既存のコードベースのコンパイルをサポートしています。

  • **SSE**: -msse#include <xmmintrin.h> を渡します。#ifdef __SSE__ を使用してコードをゲートします。

  • **SSE2**: -msse2#include <emmintrin.h> を渡します。#ifdef __SSE2__ を使用してコードをゲートします。

  • **SSE3**: -msse3#include <pmmintrin.h> を渡します。#ifdef __SSE3__ を使用してコードをゲートします。

  • **SSSE3**: -mssse3#include <tmmintrin.h> を渡します。#ifdef __SSSE3__ を使用してコードをゲートします。

  • SSE4.1: -msse4.1#include <smmintrin.h> を指定します。コードを制御するには #ifdef __SSE4_1__ を使用します。

  • SSE4.2: -msse4.2#include <nmmintrin.h> を指定します。コードを制御するには #ifdef __SSE4_2__ を使用します。

  • AVX: -mavx#include <immintrin.h> を指定します。コードを制御するには #ifdef __AVX__ を使用します。

現在、サポートされている命令セットはSSE1、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、およびAVXのみです。これらの命令セットはそれぞれ前の命令セットに追加されるため、例えばSSE3をターゲットとする場合、SSE1とSSE2の命令セットも使用できます。

以下の表は、さまざまなSSE*組込み関数の可用性と期待されるパフォーマンスを示しています。これは、x86ハードウェア上で実行する場合のWasm SIMD仕様のパフォーマンス上の制限を理解するのに役立ちます。

各SSE組込み関数の詳細については、優れたIntel Intrinsics Guide on SSE1を参照してください。

以下の凡例は、さまざまな命令の期待されるパフォーマンスを示すために使用されます。
  • ✅ Wasm SIMDには、x86 SSE命令と一致するネイティブオペコードがあり、ネイティブパフォーマンスが期待できます。

  • 💡 Wasm SIMD仕様は適切なパフォーマンス保証を提供しませんが、適切にスマートなコンパイラとランタイムVMパスがあれば、この組込み関数は同一のネイティブSSE命令を生成できます。

  • 🟡 Wasm VMが意図したx86 SSEオペコードを確実に再構築できるために、いくつかの情報(型やアライメント情報など)が不足しています。これにより、特に古いCPU世代では、ターゲットCPUハードウェアファミリによってはペナルティが発生する可能性があります。

  • ⚠️ 基礎となるx86 SSE命令は使用できませんが、せいぜい他の少数のWasm SIMD命令でエミュレートされるため、わずかなペナルティが発生します。

  • ❌ 基礎となるx86 SSE命令はWasm SIMD仕様で公開されていないため、低速なパス(複数の低速なSIMD命令のシーケンス、またはスカラー実装など)でエミュレートする必要があります。

  • 💣 基礎となるx86 SSEオペコードはWasm SIMDでは使用できず、実装は非常に低速なエミュレートされたパスに頼る必要があるため、より高いレベルでアルゴリズムを再考する回避策が推奨されます。

  • 💭 指定されたSSE組込み関数はアプリケーションのコンパイルを可能にするために使用できますが、何も実行しません。

  • ⚫ 指定されたSSE組込み関数は使用できません。組込み関数を参照すると、コンパイラエラーが発生します。

以下の表にある特定の組込み関数は「仮想」とマークされています。これは、それらを実装するネイティブなx86 SSE命令セットオペコードが実際には存在しないが、ネイティブコンパイラが便宜のためにその関数を提供していることを意味します。異なるコンパイラでは、これらに対して異なる命令シーケンスが生成される可能性があります。

#define WASM_SIMD_COMPAT_SLOWマクロを定義することにより、低速なエミュレートされた関数の診断を有効にすることができます。これにより、低速なパス(凡例の❌または💣に対応)を使用しようとすると警告が表示されます。

#include <xmmintrin.h> と -msse を介して使用可能なx86 SSE組込み関数

組込み関数名

WebAssembly SIMDサポート

_mm_set_ps

✅ wasm_f32x4_make

_mm_setr_ps

✅ wasm_f32x4_make

_mm_set_ss

💡 wasm_f32x4_makeでエミュレート

_mm_set_ps1 (_mm_set1_ps)

✅ wasm_f32x4_splat

_mm_setzero_ps

💡 wasm_f32x4_const(0)でエミュレート

_mm_load_ps

🟡 wasm_v128_load。VMは型を推測する必要があります。
x86 CPUでの非整列ロード。

_mm_loadl_pi

❌ Wasm SIMDサポートなし。
スカラーロードとシャッフルでエミュレート。

_mm_loadh_pi

❌ Wasm SIMDサポートなし。
スカラーロードとシャッフルでエミュレート。

_mm_loadr_ps

💡 仮想。Simdロードとシャッフル。

_mm_loadu_ps

🟡 wasm_v128_load。VMは型を推測する必要があります。

_mm_load_ps1 (_mm_load1_ps)

🟡 仮想。Simdロードとシャッフル。

_mm_load_ss

❌ wasm_f32x4_makeでエミュレート

_mm_storel_pi

❌ スカラーストア

_mm_storeh_pi

❌ シャッフルとスカラーストア

_mm_store_ps

🟡 wasm_v128_store。VMは型を推測する必要があります。
x86 CPUでの非整列ストア。

_mm_stream_ps

🟡 wasm_v128_store。VMは型を推測する必要があります。
Wasm SIMDにはキャッシュ制御がありません。

_mm_prefetch

💭 何もしない。

_mm_sfence

⚠️ マルチスレッドビルドでの完全なバリア。

_mm_shuffle_ps

🟡 wasm_i32x4_shuffle。VMは型を推測する必要があります。

_mm_storer_ps

💡 仮想。シャッフルとSimdストア。

_mm_store_ps1 (_mm_store1_ps)

🟡 仮想。シャッフルでエミュレート。
x86 CPUでの非整列ストア。

_mm_store_ss

💡 スカラーストアでエミュレート

_mm_storeu_ps

🟡 wasm_v128_store。VMは型を推測する必要があります。

_mm_storeu_si16

💡 スカラーストアでエミュレート

_mm_storeu_si64

💡 スカラーストアでエミュレート

_mm_movemask_ps

✅ wasm_i32x4_bitmask

_mm_move_ss

💡 シャッフルでエミュレート。VMは型を推測する必要があります。

_mm_add_ps

✅ wasm_f32x4_add

_mm_add_ss

⚠️ シャッフルでエミュレート

_mm_sub_ps

✅ wasm_f32x4_sub

_mm_sub_ss

⚠️ シャッフルでエミュレート

_mm_mul_ps

✅ wasm_f32x4_mul

_mm_mul_ss

⚠️ シャッフルでエミュレート

_mm_div_ps

✅ wasm_f32x4_div

_mm_div_ss

⚠️ シャッフルでエミュレート

_mm_min_ps

TODO: pminが機能したら

_mm_min_ss

⚠️ シャッフルでエミュレート

_mm_max_ps

TODO: pmaxが機能したら

_mm_max_ss

⚠️ シャッフルでエミュレート

_mm_rcp_ps

❌ Wasm SIMDサポートなし。
完全精度除算でエミュレート。 simd/#3

_mm_rcp_ss

❌ Wasm SIMDサポートなし。
完全精度除算+シャッフルでエミュレート simd/#3

_mm_sqrt_ps

✅ wasm_f32x4_sqrt

_mm_sqrt_ss

⚠️ シャッフルでエミュレート

_mm_rsqrt_ps

❌ Wasm SIMDサポートなし。
完全精度除算+平方根でエミュレート。 simd/#3

_mm_rsqrt_ss

❌ Wasm SIMDサポートなし。
完全精度除算+平方根+シャッフルでエミュレート。 simd/#3

_mm_unpackhi_ps

💡 シャッフルでエミュレート

_mm_unpacklo_ps

💡 シャッフルでエミュレート

_mm_movehl_ps

💡 シャッフルでエミュレート

_mm_movelh_ps

💡 シャッフルでエミュレート

_MM_TRANSPOSE4_PS

💡 シャッフルでエミュレート

_mm_cmplt_ps

✅ wasm_f32x4_lt

_mm_cmplt_ss

⚠️ シャッフルでエミュレート

_mm_cmple_ps

✅ wasm_f32x4_le

_mm_cmple_ss

⚠️ シャッフルでエミュレート

_mm_cmpeq_ps

✅ wasm_f32x4_eq

_mm_cmpeq_ss

⚠️ シャッフルでエミュレート

_mm_cmpge_ps

✅ wasm_f32x4_ge

_mm_cmpge_ss

⚠️ シャッフルでエミュレート

_mm_cmpgt_ps

✅ wasm_f32x4_gt

_mm_cmpgt_ss

⚠️ シャッフルでエミュレート

_mm_cmpord_ps

❌ 2xcmp+andでエミュレート

_mm_cmpord_ss

❌ 2xcmp+and+シャッフルでエミュレート

_mm_cmpunord_ps

❌ 2xcmp+orでエミュレート

_mm_cmpunord_ss

❌ 2xcmp+or+シャッフルでエミュレート

_mm_and_ps

🟡 wasm_v128_and。VMは型を推測する必要があります。

_mm_andnot_ps

🟡 wasm_v128_andnot。VMは型を推測する必要があります。

_mm_or_ps

🟡 wasm_v128_or。VMは型を推測する必要があります。

_mm_xor_ps

🟡 wasm_v128_xor。VMは型を推測する必要があります。

_mm_cmpneq_ps

✅ wasm_f32x4_ne

_mm_cmpneq_ss

⚠️ シャッフルでエミュレート

_mm_cmpnge_ps

⚠️ not+geでエミュレート

_mm_cmpnge_ss

⚠️ not+ge+シャッフルでエミュレート

_mm_cmpngt_ps

⚠️ not+gtでエミュレート

_mm_cmpngt_ss

⚠️ not+gt+シャッフルでエミュレート

_mm_cmpnle_ps

⚠️ not+leでエミュレート

_mm_cmpnle_ss

⚠️ not+le+シャッフルでエミュレート

_mm_cmpnlt_ps

⚠️ not+ltでエミュレート

_mm_cmpnlt_ss

⚠️ not+lt+シャッフルでエミュレート

_mm_comieq_ss

❌ スカラー化

_mm_comige_ss

❌ スカラー化

_mm_comigt_ss

❌ スカラー化

_mm_comile_ss

❌ スカラー化

_mm_comilt_ss

❌ スカラー化

_mm_comineq_ss

❌ スカラー化

_mm_ucomieq_ss

❌ スカラー化

_mm_ucomige_ss

❌ スカラー化

_mm_ucomigt_ss

❌ スカラー化

_mm_ucomile_ss

❌ スカラー化

_mm_ucomilt_ss

❌ スカラー化

_mm_ucomineq_ss

❌ スカラー化

_mm_cvtsi32_ss (_mm_cvt_si2ss)

❌ スカラー化

_mm_cvtss_si32 (_mm_cvt_ss2si)

💣 複雑なエミュレートされたセマンティクスを持つスカラー

_mm_cvttss_si32 (_mm_cvtt_ss2si)

💣 複雑なエミュレートされたセマンティクスを持つスカラー

_mm_cvtsi64_ss

❌ スカラー化

_mm_cvtss_si64

💣 複雑なエミュレートされたセマンティクスを持つスカラー

_mm_cvttss_si64

💣 複雑なエミュレートされたセマンティクスを持つスカラー

_mm_cvtss_f32

💡 スカラー取得

_mm_malloc

✅ 指定されたアライメントでメモリを割り当てます。

_mm_free

✅ free()へのエイリアス。

_MM_GET_EXCEPTION_MASK

✅ 常にすべての例外がマスクされていることを返します (0x1f80)。

_MM_GET_EXCEPTION_STATE

❌ 例外状態は追跡されません。常に0を返します。

_MM_GET_FLUSH_ZERO_MODE

✅ 常に_MM_FLUSH_ZERO_OFFを返します。

_MM_GET_ROUNDING_MODE

✅ 常に_MM_ROUND_NEARESTを返します。

_mm_getcsr

✅ 常に_MM_FLUSH_ZERO_OFF
| _MM_ROUND_NEAREST | すべての例外がマスクされている (0x1f80) を返します。

_MM_SET_EXCEPTION_MASK

⚫ 使用できません。すべての例外がマスクされているように固定されています。

_MM_SET_EXCEPTION_STATE

⚫ 使用できません。ゼロ/クリア状態に固定されています。

_MM_SET_FLUSH_ZERO_MODE

⚫ 使用できません。_MM_FLUSH_ZERO_OFFに固定されています。

_MM_SET_ROUNDING_MODE

⚫ 使用できません。_MM_ROUND_NEARESTに固定されています。

_mm_setcsr

⚫ 使用できません。

_mm_undefined_ps

✅ 仮想

⚫ SSE1命令セットが64ビット幅のMMXレジスタにもたらした以下の拡張機能は使用できません。
  • _mm_avg_pu8, _mm_avg_pu16, _mm_cvt_pi2ps, _mm_cvt_ps2pi, _mm_cvt_pi16_ps, _mm_cvt_pi32_ps, _mm_cvt_pi32x2_ps, _mm_cvt_pi8_ps, _mm_cvt_ps_pi16, _mm_cvt_ps_pi32, _mm_cvt_ps_pi8, _mm_cvt_pu16_ps, _mm_cvt_pu8_ps, _mm_cvtt_ps2pi, _mm_cvtt_pi16_ps, _mm_cvttps_pi32, _mm_extract_pi16, _mm_insert_pi16, _mm_maskmove_si64, _m_maskmovq, _mm_max_pi16, _mm_max_pu8, _mm_min_pi16, _mm_min_pu8, _mm_movemask_pi8, _mm_mulhi_pu16, _m_pavgb, _m_pavgw, _m_pextrw, _m_pinsrw, _m_pmaxsw, _m_pmaxub, _m_pminsw, _m_pminub, _m_pmovmskb, _m_pmulhuw, _m_psadbw, _m_pshufw, _mm_sad_pu8, _mm_shuffle_pi16 および _mm_stream_pi。

これらの組込み関数を参照するコードはコンパイルされません。

次の表は、さまざまなSSE2組込み関数の可用性と期待されるパフォーマンスを示しています。Intel Intrinsics Guide on SSE2を参照してください。

#include <emmintrin.h> と -msse2 を介して使用可能なx86 SSE2組込み関数

組込み関数名

WebAssembly SIMDサポート

_mm_add_epi16

✅ wasm_i16x8_add

_mm_add_epi32

✅ wasm_i32x4_add

_mm_add_epi64

✅ wasm_i64x2_add

_mm_add_epi8

✅ wasm_i8x16_add

_mm_add_pd

✅ wasm_f64x2_add

_mm_add_sd

⚠️ シャッフルでエミュレート

_mm_adds_epi16

✅ wasm_i16x8_add_sat

_mm_adds_epi8

✅ wasm_i8x16_add_sat

_mm_adds_epu16

✅ wasm_u16x8_add_sat

_mm_adds_epu8

✅ wasm_u8x16_add_sat

_mm_and_pd

🟡 wasm_v128_and。VMは型を推測する必要があります。

_mm_and_si128

🟡 wasm_v128_and。VMは型を推測する必要があります。

_mm_andnot_pd

🟡 wasm_v128_andnot。VMは型を推測する必要があります。

_mm_andnot_si128

🟡 wasm_v128_andnot。VMは型を推測する必要があります。

_mm_avg_epu16

✅ wasm_u16x8_avgr

_mm_avg_epu8

✅ wasm_u8x16_avgr

_mm_castpd_ps

✅ noop (何もしない)

_mm_castpd_si128

✅ noop (何もしない)

_mm_castps_pd

✅ noop (何もしない)

_mm_castps_si128

✅ noop (何もしない)

_mm_castsi128_pd

✅ noop (何もしない)

_mm_castsi128_ps

✅ noop (何もしない)

_mm_clflush

💭 noop. Wasm SIMDにはキャッシュヒントがない。

_mm_cmpeq_epi16

✅ wasm_i16x8_eq

_mm_cmpeq_epi32

✅ wasm_i32x4_eq

_mm_cmpeq_epi8

✅ wasm_i8x16_eq

_mm_cmpeq_pd

✅ wasm_f64x2_eq

_mm_cmpeq_sd

⚠️ シャッフルでエミュレート

_mm_cmpge_pd

✅ wasm_f64x2_ge

_mm_cmpge_sd

⚠️ シャッフルでエミュレート

_mm_cmpgt_epi16

✅ wasm_i16x8_gt

_mm_cmpgt_epi32

✅ wasm_i32x4_gt

_mm_cmpgt_epi8

✅ wasm_i8x16_gt

_mm_cmpgt_pd

✅ wasm_f64x2_gt

_mm_cmpgt_sd

⚠️ シャッフルでエミュレート

_mm_cmple_pd

✅ wasm_f64x2_le

_mm_cmple_sd

⚠️ シャッフルでエミュレート

_mm_cmplt_epi16

✅ wasm_i16x8_lt

_mm_cmplt_epi32

✅ wasm_i32x4_lt

_mm_cmplt_epi8

✅ wasm_i8x16_lt

_mm_cmplt_pd

✅ wasm_f64x2_lt

_mm_cmplt_sd

⚠️ シャッフルでエミュレート

_mm_cmpneq_pd

✅ wasm_f64x2_ne

_mm_cmpneq_sd

⚠️ シャッフルでエミュレート

_mm_cmpnge_pd

⚠️ not+geでエミュレート

_mm_cmpnge_sd

⚠️ not+ge+シャッフルでエミュレート

_mm_cmpngt_pd

⚠️ not+gtでエミュレート

_mm_cmpngt_sd

⚠️ not+gt+シャッフルでエミュレート

_mm_cmpnle_pd

⚠️ not+leでエミュレート

_mm_cmpnle_sd

⚠️ not+le+シャッフルでエミュレート

_mm_cmpnlt_pd

⚠️ not+ltでエミュレート

_mm_cmpnlt_sd

⚠️ not+lt+シャッフルでエミュレート

_mm_cmpord_pd

❌ 2xcmp+andでエミュレート

_mm_cmpord_sd

❌ 2xcmp+and+シャッフルでエミュレート

_mm_cmpunord_pd

❌ 2xcmp+orでエミュレート

_mm_cmpunord_sd

❌ 2xcmp+or+シャッフルでエミュレート

_mm_comieq_sd

❌ スカラー化

_mm_comige_sd

❌ スカラー化

_mm_comigt_sd

❌ スカラー化

_mm_comile_sd

❌ スカラー化

_mm_comilt_sd

❌ スカラー化

_mm_comineq_sd

❌ スカラー化

_mm_cvtepi32_pd

✅ wasm_f64x2_convert_low_i32x4

_mm_cvtepi32_ps

✅ wasm_f32x4_convert_i32x4

_mm_cvtpd_epi32

❌ スカラー化

_mm_cvtpd_ps

✅ wasm_f32x4_demote_f64x2_zero

_mm_cvtps_epi32

❌ スカラー化

_mm_cvtps_pd

✅ wasm_f64x2_promote_low_f32x4

_mm_cvtsd_f64

✅ wasm_f64x2_extract_lane

_mm_cvtsd_si32

❌ スカラー化

_mm_cvtsd_si64

❌ スカラー化

_mm_cvtsd_si64x

❌ スカラー化

_mm_cvtsd_ss

❌ スカラー化

_mm_cvtsi128_si32

✅ wasm_i32x4_extract_lane

_mm_cvtsi128_si64 (_mm_cvtsi128_si64x)

✅ wasm_i64x2_extract_lane

_mm_cvtsi32_sd

❌ スカラー化

_mm_cvtsi32_si128

💡 wasm_i32x4_make を使用してエミュレート

_mm_cvtsi64_sd (_mm_cvtsi64x_sd)

❌ スカラー化

_mm_cvtsi64_si128 (_mm_cvtsi64x_si128)

💡 wasm_i64x2_make を使用してエミュレート

_mm_cvtss_sd

❌ スカラー化

_mm_cvttpd_epi32

❌ スカラー化

_mm_cvttps_epi32

❌ スカラー化

_mm_cvttsd_si32

❌ スカラー化

_mm_cvttsd_si64 (_mm_cvttsd_si64x)

❌ スカラー化

_mm_div_pd

✅ wasm_f64x2_div

_mm_div_sd

⚠️ シャッフルでエミュレート

_mm_extract_epi16

✅ wasm_u16x8_extract_lane

_mm_insert_epi16

✅ wasm_i16x8_replace_lane

_mm_lfence

⚠️ マルチスレッドビルドでの完全なバリア。

_mm_load_pd

🟡 wasm_v128_load。VMは型を推測する必要があります。
x86 CPUでの非整列ロード。

_mm_load1_pd (_mm_load_pd1)

🟡 仮想関数. wasm_v64x2_load_splat, VMは型を推測する必要がある。

_mm_load_sd

❌ wasm_f64x2_make を使用してエミュレート

_mm_load_si128

🟡 wasm_v128_load。VMは型を推測する必要があります。
x86 CPUでの非整列ロード。

_mm_loadh_pd

❌ Wasm SIMDサポートなし。
スカラーロードとシャッフルでエミュレート。

_mm_loadl_epi64

❌ Wasm SIMDサポートなし。
スカラーロードとシャッフルでエミュレート。

_mm_loadl_pd

❌ Wasm SIMDサポートなし。
スカラーロードとシャッフルでエミュレート。

_mm_loadr_pd

💡 仮想。Simdロードとシャッフル。

_mm_loadu_pd

🟡 wasm_v128_load。VMは型を推測する必要があります。

_mm_loadu_si128

🟡 wasm_v128_load。VMは型を推測する必要があります。

_mm_loadu_si64

❌ 定数+スカラーロード+レーン置換でエミュレート

_mm_loadu_si32

❌ 定数+スカラーロード+レーン置換でエミュレート

_mm_loadu_si16

❌ 定数+スカラーロード+レーン置換でエミュレート

_mm_madd_epi16

✅ wasm_i32x4_dot_i16x8

_mm_maskmoveu_si128

❌ スカラー化

_mm_max_epi16

✅ wasm_i16x8_max

_mm_max_epu8

✅ wasm_u8x16_max

_mm_max_pd

TODO: wasm_f64x2_pmaxに移行する

_mm_max_sd

⚠️ シャッフルでエミュレート

_mm_mfence

⚠️ マルチスレッドビルドでの完全なバリア。

_mm_min_epi16

✅ wasm_i16x8_min

_mm_min_epu8

✅ wasm_u8x16_min

_mm_min_pd

TODO: wasm_f64x2_pminに移行する

_mm_min_sd

⚠️ シャッフルでエミュレート

_mm_move_epi64

💡 シャッフルでエミュレート。VMは型を推測する必要があります。

_mm_move_sd

💡 シャッフルでエミュレート。VMは型を推測する必要があります。

_mm_movemask_epi8

✅ wasm_i8x16_bitmask

_mm_movemask_pd

✅ wasm_i64x2_bitmask

_mm_mul_epu32

⚠️ wasm_u64x2_extmul_low_u32x4 + シャッフル2回でエミュレート

_mm_mul_pd

✅ wasm_f64x2_mul

_mm_mul_sd

⚠️ シャッフルでエミュレート

_mm_mulhi_epi16

⚠️ 2倍のSIMD extmul+汎用シャッフルでエミュレート

_mm_mulhi_epu16

⚠️ 2倍のSIMD extmul+汎用シャッフルでエミュレート

_mm_mullo_epi16

✅ wasm_i16x8_mul

_mm_or_pd

🟡 wasm_v128_or。VMは型を推測する必要があります。

_mm_or_si128

🟡 wasm_v128_or。VMは型を推測する必要があります。

_mm_packs_epi16

✅ wasm_i8x16_narrow_i16x8

_mm_packs_epi32

✅ wasm_i16x8_narrow_i32x4

_mm_packus_epi16

✅ wasm_u8x16_narrow_i16x8

_mm_pause

💭 何もしない。

_mm_sad_epu8

⚠️ 11個のSIMD命令+定数でエミュレート

_mm_set_epi16

✅ wasm_i16x8_make

_mm_set_epi32

✅ wasm_i32x4_make

_mm_set_epi64 (_mm_set_epi64x)

✅ wasm_i64x2_make

_mm_set_epi8

✅ wasm_i8x16_make

_mm_set_pd

✅ wasm_f64x2_make

_mm_set_sd

💡 wasm_f64x2_make を使用してエミュレート

_mm_set1_epi16

✅ wasm_i16x8_splat

_mm_set1_epi32

✅ wasm_i32x4_splat

_mm_set1_epi64 (_mm_set1_epi64x)

✅ wasm_i64x2_splat

_mm_set1_epi8

✅ wasm_i8x16_splat

_mm_set1_pd (_mm_set_pd1)

✅ wasm_f64x2_splat

_mm_setr_epi16

✅ wasm_i16x8_make

_mm_setr_epi32

✅ wasm_i32x4_make

_mm_setr_epi64

✅ wasm_i64x2_make

_mm_setr_epi8

✅ wasm_i8x16_make

_mm_setr_pd

✅ wasm_f64x2_make

_mm_setzero_pd

💡 wasm_f64x2_const を使用してエミュレート

_mm_setzero_si128

💡 wasm_i64x2_const を使用してエミュレート

_mm_shuffle_epi32

💡 汎用シャッフルでエミュレート

_mm_shuffle_pd

💡 汎用シャッフルでエミュレート

_mm_shufflehi_epi16

💡 汎用シャッフルでエミュレート

_mm_shufflelo_epi16

💡 汎用シャッフルでエミュレート

_mm_sll_epi16

❌ スカラー化

_mm_sll_epi32

❌ スカラー化

_mm_sll_epi64

❌ スカラー化

_mm_slli_epi16

💡 wasm_i16x8_shl
✅ シフト数が即値定数の時。

_mm_slli_epi32

💡 wasm_i32x4_shl
✅ シフト数が即値定数の時。

_mm_slli_epi64

💡 wasm_i64x2_shl
✅ シフト数が即値定数の時。

_mm_slli_si128 (_mm_bslli_si128)

💡 汎用シャッフルでエミュレート

_mm_sqrt_pd

✅ wasm_f64x2_sqrt

_mm_sqrt_sd

⚠️ シャッフルでエミュレート

_mm_sra_epi16

❌ スカラー化

_mm_sra_epi32

❌ スカラー化

_mm_srai_epi16

💡 wasm_i16x8_shr
✅ シフト数が即値定数の時。

_mm_srai_epi32

💡 wasm_i32x4_shr
✅ シフト数が即値定数の時。

_mm_srl_epi16

❌ スカラー化

_mm_srl_epi32

❌ スカラー化

_mm_srl_epi64

❌ スカラー化

_mm_srli_epi16

💡 wasm_u16x8_shr
✅ シフト数が即値定数の時。

_mm_srli_epi32

💡 wasm_u32x4_shr
✅ シフト数が即値定数の時。

_mm_srli_epi64

💡 wasm_u64x2_shr
✅ シフト数が即値定数の時。

_mm_srli_si128 (_mm_bsrli_si128)

💡 汎用シャッフルでエミュレート

_mm_store_pd

🟡 wasm_v128_store。VMは型を推測する必要があります。
x86 CPUでの非整列ストア。

_mm_store_sd

💡 スカラーストアでエミュレート

_mm_store_si128

🟡 wasm_v128_store。VMは型を推測する必要があります。
x86 CPUでの非整列ストア。

_mm_store1_pd (_mm_store_pd1)

🟡 仮想。シャッフルでエミュレート。
x86 CPUでの非整列ストア。

_mm_storeh_pd

❌ シャッフルとスカラーストア

_mm_storel_epi64

❌ スカラーストア

_mm_storel_pd

❌ スカラーストア

_mm_storer_pd

❌ シャッフルとスカラーストア

_mm_storeu_pd

🟡 wasm_v128_store。VMは型を推測する必要があります。

_mm_storeu_si128

🟡 wasm_v128_store。VMは型を推測する必要があります。

_mm_storeu_si64

💡 レーン抽出+スカラーストアでエミュレート

_mm_storeu_si32

💡 レーン抽出+スカラーストアでエミュレート

_mm_storeu_si16

💡 レーン抽出+スカラーストアでエミュレート

_mm_stream_pd

🟡 wasm_v128_store。VMは型を推測する必要があります。
Wasm SIMDにはキャッシュ制御がありません。

_mm_stream_si128

🟡 wasm_v128_store。VMは型を推測する必要があります。
Wasm SIMDにはキャッシュ制御がありません。

_mm_stream_si32

🟡 wasm_v128_store。VMは型を推測する必要があります。
Wasm SIMDにはキャッシュ制御がありません。

_mm_stream_si64

🟡 wasm_v128_store。VMは型を推測する必要があります。
Wasm SIMDにはキャッシュ制御がありません。

_mm_sub_epi16

✅ wasm_i16x8_sub

_mm_sub_epi32

✅ wasm_i32x4_sub

_mm_sub_epi64

✅ wasm_i64x2_sub

_mm_sub_epi8

✅ wasm_i8x16_sub

_mm_sub_pd

✅ wasm_f64x2_sub

_mm_sub_sd

⚠️ シャッフルでエミュレート

_mm_subs_epi16

✅ wasm_i16x8_sub_sat

_mm_subs_epi8

✅ wasm_i8x16_sub_sat

_mm_subs_epu16

✅ wasm_u16x8_sub_sat

_mm_subs_epu8

✅ wasm_u8x16_sub_sat

_mm_ucomieq_sd

❌ スカラー化

_mm_ucomige_sd

❌ スカラー化

_mm_ucomigt_sd

❌ スカラー化

_mm_ucomile_sd

❌ スカラー化

_mm_ucomilt_sd

❌ スカラー化

_mm_ucomineq_sd

❌ スカラー化

_mm_undefined_pd

✅ 仮想

_mm_undefined_si128

✅ 仮想

_mm_unpackhi_epi16

💡 シャッフルでエミュレート

_mm_unpackhi_epi32

💡 シャッフルでエミュレート

_mm_unpackhi_epi64

💡 シャッフルでエミュレート

_mm_unpackhi_epi8

💡 シャッフルでエミュレート

_mm_unpachi_pd

💡 シャッフルでエミュレート

_mm_unpacklo_epi16

💡 シャッフルでエミュレート

_mm_unpacklo_epi32

💡 シャッフルでエミュレート

_mm_unpacklo_epi64

💡 シャッフルでエミュレート

_mm_unpacklo_epi8

💡 シャッフルでエミュレート

_mm_unpacklo_pd

💡 シャッフルでエミュレート

_mm_xor_pd

🟡 wasm_v128_xor。VMは型を推測する必要があります。

_mm_xor_si128

🟡 wasm_v128_xor。VMは型を推測する必要があります。

⚫ 次の拡張機能は、SSE2命令セットが64ビット幅のMMXレジスタにもたらしたものであり、使用できません。
  • _mm_add_si64, _mm_movepi64_pi64, _mm_movpi64_epi64, _mm_mul_su32, _mm_sub_si64, _mm_cvtpd_pi32, _mm_cvtpi32_pd, _mm_cvttpd_pi32

これらの組込み関数を参照するコードはコンパイルされません。

次の表は、さまざまなSSE3組込み関数の可用性と予想されるパフォーマンスを示しています。 Intel Intrinsics Guide on SSE3 を参照してください。

#include <pmmintrin.h> と -msse3 を使用して利用可能なx86 SSE3組込み関数

組込み関数名

WebAssembly SIMDサポート

_mm_lddqu_si128

✅ wasm_v128_load.

_mm_addsub_ps

⚠️ SIMD add+mul+定数でエミュレート

_mm_hadd_ps

⚠️ SIMD add+シャッフル2回でエミュレート

_mm_hsub_ps

⚠️ SIMD sub+シャッフル2回でエミュレート

_mm_movehdup_ps

💡 汎用シャッフルでエミュレート

_mm_moveldup_ps

💡 汎用シャッフルでエミュレート

_mm_addsub_pd

⚠️ SIMD add+mul+定数でエミュレート

_mm_hadd_pd

⚠️ SIMD add+シャッフル2回でエミュレート

_mm_hsub_pd

⚠️ SIMD add+シャッフル2回でエミュレート

_mm_loaddup_pd

🟡 仮想関数. wasm_v64x2_load_splat, VMは型を推測する必要がある。

_mm_movedup_pd

💡 汎用シャッフルでエミュレート

_MM_GET_DENORMALS_ZERO_MODE

✅ 常に _MM_DENORMALS_ZERO_ON を返す。つまり、非正規数は使用可能。

_MM_SET_DENORMALS_ZERO_MODE

⚫ 使用不可。_MM_DENORMALS_ZERO_ON に固定。

_mm_monitor

⚫ 使用できません。

_mm_mwait

⚫ 使用できません。

次の表は、さまざまなSSSE3組込み関数の可用性と予想されるパフォーマンスを示しています。 Intel Intrinsics Guide on SSSE3 を参照してください。

#include <tmmintrin.h> と -mssse3 を使用して利用可能なx86 SSSE3組込み関数

組込み関数名

WebAssembly SIMDサポート

_mm_abs_epi8

✅ wasm_i8x16_abs

_mm_abs_epi16

✅ wasm_i16x8_abs

_mm_abs_epi32

✅ wasm_i32x4_abs

_mm_alignr_epi8

⚠️ SIMD or+シフト2回でエミュレート

_mm_hadd_epi16

⚠️ SIMD add+シャッフル2回でエミュレート

_mm_hadd_epi32

⚠️ SIMD add+シャッフル2回でエミュレート

_mm_hadds_epi16

⚠️ SIMD adds+シャッフル2回でエミュレート

_mm_hsub_epi16

⚠️ SIMD sub+シャッフル2回でエミュレート

_mm_hsub_epi32

⚠️ SIMD sub+シャッフル2回でエミュレート

_mm_hsubs_epi16

⚠️ SIMD subs+シャッフル2回でエミュレート

_mm_maddubs_epi16

⚠️ SIMD saturate add+シフト4回+mul2回+and+定数でエミュレート

_mm_mulhrs_epi16

⚠️ SIMD widen 4回+mul 2回+add 4回+複雑なシャッフル+定数でエミュレート

_mm_shuffle_epi8

⚠️ SIMD スウィズル+and+定数でエミュレート

_mm_sign_epi8

⚠️ SIMD cmp 2回+論理演算2回+addでエミュレート

_mm_sign_epi16

⚠️ SIMD cmp 2回+論理演算2回+addでエミュレート

_mm_sign_epi32

⚠️ SIMD cmp 2回+論理演算2回+addでエミュレート

⚫ 64ビット幅のMMXレジスタを扱うSSSE3関数は使用できません。
  • _mm_abs_pi8, _mm_abs_pi16, _mm_abs_pi32, _mm_alignr_pi8, _mm_hadd_pi16, _mm_hadd_pi32, _mm_hadds_pi16, _mm_hsub_pi16, _mm_hsub_pi32, _mm_hsubs_pi16, _mm_maddubs_pi16, _mm_mulhrs_pi16, _mm_shuffle_pi8, _mm_sign_pi8, _mm_sign_pi16 および _mm_sign_pi32

これらの組込み関数を参照するコードはコンパイルされません。

次の表は、さまざまなSSE4.1組込み関数の可用性と予想されるパフォーマンスを示しています。 Intel Intrinsics Guide on SSE4.1 を参照してください。

#include <smmintrin.h> と -msse4.1 を使用して利用可能なx86 SSE4.1組込み関数

組込み関数名

WebAssembly SIMDサポート

_mm_blend_epi16

💡 汎用シャッフルでエミュレート

_mm_blend_pd

💡 汎用シャッフルでエミュレート

_mm_blend_ps

💡 汎用シャッフルでエミュレート

_mm_blendv_epi8

⚠️ SIMD shr+and+andnot+orでエミュレート

_mm_blendv_pd

⚠️ SIMD shr+and+andnot+orでエミュレート

_mm_blendv_ps

⚠️ SIMD shr+and+andnot+orでエミュレート

_mm_ceil_pd

✅ wasm_f64x2_ceil

_mm_ceil_ps

✅ wasm_f32x4_ceil

_mm_ceil_sd

⚠️ シャッフルでエミュレート

_mm_ceil_ss

⚠️ シャッフルでエミュレート

_mm_cmpeq_epi64

⚠️ SIMD cmp+and+shuffleによるエミュレーション

_mm_cvtepi16_epi32

✅ wasm_i32x4_widen_low_i16x8

_mm_cvtepi16_epi64

⚠️ SIMD widen+const+cmp+shuffleによるエミュレーション

_mm_cvtepi32_epi64

⚠️ SIMD const+cmp+shuffleによるエミュレーション

_mm_cvtepi8_epi16

✅ wasm_i16x8_widen_low_i8x16

_mm_cvtepi8_epi32

⚠️ 2つのSIMD widenによるエミュレーション

_mm_cvtepi8_epi64

⚠️ 2つのSIMD widen+const+cmp+shuffleによるエミュレーション

_mm_cvtepu16_epi32

✅ wasm_u32x4_extend_low_u16x8

_mm_cvtepu16_epi64

⚠️ SIMD const+2つのshuffleによるエミュレーション

_mm_cvtepu32_epi64

⚠️ SIMD const+shuffleによるエミュレーション

_mm_cvtepu8_epi16

✅ wasm_u16x8_extend_low_u8x16

_mm_cvtepu8_epi32

⚠️ 2つのSIMD widenによるエミュレーション

_mm_cvtepu8_epi64

⚠️ SIMD const+3つのshuffleによるエミュレーション

_mm_dp_pd

⚠️ SIMD mul+add+setzero+2xblendによるエミュレーション

_mm_dp_ps

⚠️ SIMD mul+add+setzero+2xblendによるエミュレーション

_mm_extract_epi32

✅ wasm_i32x4_extract_lane

_mm_extract_epi64

✅ wasm_i64x2_extract_lane

_mm_extract_epi8

✅ wasm_u8x16_extract_lane

_mm_extract_ps

✅ wasm_i32x4_extract_lane

_mm_floor_pd

✅ wasm_f64x2_floor

_mm_floor_ps

✅ wasm_f32x4_floor

_mm_floor_sd

⚠️ シャッフルでエミュレート

_mm_floor_ss

⚠️ シャッフルでエミュレート

_mm_insert_epi32

✅ wasm_i32x4_replace_lane

_mm_insert_epi64

✅ wasm_i64x2_replace_lane

_mm_insert_epi8

✅ wasm_i8x16_replace_lane

_mm_insert_ps

⚠️ 一般的な非SIMDマッピングシャッフルによるエミュレーション

_mm_max_epi32

✅ wasm_i32x4_max

_mm_max_epi8

✅ wasm_i8x16_max

_mm_max_epu16

✅ wasm_u16x8_max

_mm_max_epu32

✅ wasm_u32x4_max

_mm_min_epi32

✅ wasm_i32x4_min

_mm_min_epi8

✅ wasm_i8x16_min

_mm_min_epu16

✅ wasm_u16x8_min

_mm_min_epu32

✅ wasm_u32x4_min

_mm_minpos_epu16

💣 スカラー化

_mm_mpsadbw_epu8

💣 スカラー化

_mm_mul_epi32

⚠️ wasm_i64x2_extmul_low_i32x4 + 2つのshuffleによるエミュレーション

_mm_mullo_epi32

✅ wasm_i32x4_mul

_mm_packus_epi32

✅ wasm_u16x8_narrow_i32x4

_mm_round_pd

✅ wasm_f64x2_ceil/wasm_f64x2_floor/wasm_f64x2_nearest/wasm_f64x2_trunc

_mm_round_ps

✅ wasm_f32x4_ceil/wasm_f32x4_floor/wasm_f32x4_nearest/wasm_f32x4_trunc

_mm_round_sd

⚠️ シャッフルでエミュレート

_mm_round_ss

⚠️ シャッフルでエミュレート

_mm_stream_load_si128

🟡 wasm_v128_load。VMは型を推測する必要があります。
x86 CPUでの非整列ロード。

_mm_test_all_ones

❌ スカラー化

_mm_test_all_zeros

❌ スカラー化

_mm_test_mix_ones_zeros

❌ スカラー化

_mm_testc_si128

❌ スカラー化

_mm_testnzc_si128

❌ スカラー化

_mm_testz_si128

❌ スカラー化

以下の表は、様々なSSE4.2組込み関数の可用性と予想されるパフォーマンスを示しています。 Intel Intrinsics Guide on SSE4.2を参照してください。

#include <nmmintrin.h> と -msse4.2 を使用して利用可能なx86 SSE4.2組込み関数

組込み関数名

WebAssembly SIMDサポート

_mm_cmpgt_epi64

✅ wasm_i64x2_gt

⚫ 文字列比較とCRC計算を扱うSSE4.2関数は利用できません
  • _mm_cmpestra, _mm_cmpestrc, _mm_cmpestri, _mm_cmpestrm, _mm_cmpestro, _mm_cmpestrs, _mm_cmpestrz, _mm_cmpistra, _mm_cmpistrc, _mm_cmpistri, _mm_cmpistrm, _mm_cmpistro, _mm_cmpistrs, _mm_cmpistrz, _mm_crc32_u16, _mm_crc32_u32, _mm_crc32_u64, _mm_crc32_u8

これらの組込み関数を参照するコードはコンパイルされません。

以下の表は、様々なAVX組込み関数の可用性と予想されるパフォーマンスを示しています。 Intel Intrinsics Guide on AVXを参照してください。

#include <immintrin.h> と -mavx を使用して利用可能なx86 AVX組込み関数

組込み関数名

WebAssembly SIMDサポート

_mm_broadcast_ss

✅ wasm_v32x4_load_splat

_mm_cmp_pd

⚠️ 1〜2個のSIMD cmp+and/orによるエミュレーション

_mm_cmp_ps

⚠️ 1〜2個のSIMD cmp+and/orによるエミュレーション

_mm_cmp_sd

⚠️ 1〜2個のSIMD cmp+and/or+moveによるエミュレーション

_mm_cmp_ss

⚠️ 1〜2個のSIMD cmp+and/or+moveによるエミュレーション

_mm_maskload_pd

⚠️ SIMD load+shift+andによるエミュレーション

_mm_maskload_ps

⚠️ SIMD load+shift+andによるエミュレーション

_mm_maskstore_pd

❌ スカラー化

_mm_maskstore_ps

❌ スカラー化

_mm_permute_pd

💡 汎用シャッフルでエミュレート

_mm_permute_ps

💡 汎用シャッフルでエミュレート

_mm_permutevar_pd

💣 スカラー化

_mm_permutevar_ps

💣 スカラー化

_mm_testc_pd

💣 複雑なSIMD+スカラーシーケンスによるエミュレーション

_mm_testc_ps

💣 複雑なSIMD+スカラーシーケンスによるエミュレーション

_mm_testnzc_pd

💣 複雑なSIMD+スカラーシーケンスによるエミュレーション

_mm_testnzc_ps

💣 複雑なSIMD+スカラーシーケンスによるエミュレーション

_mm_testz_pd

💣 複雑なSIMD+スカラーシーケンスによるエミュレーション

_mm_testz_ps

💣 複雑なSIMD+スカラーシーケンスによるエミュレーション

AVX命令セットからの128ビット幅の命令のみがリストされています。256ビット幅のAVX命令は、2つの128ビット幅の命令によってエミュレートされます。

ARM NEON命令セットをターゲットとするSIMDコードのコンパイル

Emscriptenは、コンパイラに-mfpu=neonディレクティブを渡し、ヘッダー<arm_neon.h>を含めることで、ARM NEONを使用する既存のコードベースのコンパイルをサポートしています。

パフォーマンスの観点から、128ビット幅のベクトルで動作する命令のみがクリーンにサポートされていることに注意することが非常に重要です。「q」バリアントではないほとんどすべての命令(つまり「vadd」ではなく「vaddq」)はスカラー化されます。

これらはGitHub上のSIMDeリポジトリから取得されています。最新のSIMDeバージョンでemscriptenを更新するには、tools/simde_update.pyを実行してください。

以下の表は、様々な128ビット幅の組込み関数の可用性を示しています。

上記と同様に、以下の凡例を使用します。
  • ✅ Wasm SIMDにはNEON命令と一致するネイティブオペコードがあり、ネイティブパフォーマンスが得られるはずです。

  • 💡 Wasm SIMD仕様は適切なパフォーマンス保証を提供しませんが、適切にスマートなコンパイラとランタイムVMパスがあれば、この組込み関数は同一のネイティブNEON命令を生成できるはずです。

  • ⚠️ 基礎となるNEON命令は利用できませんが、多くてもいくつかの他のWasm SIMD命令を介してエミュレートされ、わずかなペナルティが発生します。

  • ❌ 基礎となるNEON命令はWasm SIMD仕様で公開されていないため、低速なパス(例:いくつかの低速なSIMD命令のシーケンス、またはスカラー実装)を介してエミュレートする必要があります。

  • ⚫ 指定されたNEON組込み関数は利用できません。組込み関数を参照すると、コンパイラエラーが発生します。

各組込み関数の詳細については、NEON Intrinsics Referenceを参照してください。

最新のNEON組込み関数の実装状況については、SIMDe implementation statusを参照してください。

NEON組込み関数

組込み関数名

Wasm SIMDサポート

vaba

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vabaq

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vabal

⚫ 実装されていません。コンパイラエラーが発生します。

vabd

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vabdq

✅ ネイティブ

vabdl

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vabs

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vabq

✅ ネイティブ

vadd

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vaddq_s & vaddq_f

✅ ネイティブ

vaddhn

💡 十分にスマートなコンパイラに依存しますが、ネイティブに近いはずです。

vaddl

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vaddlv

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vaddv

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vaddw

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vand

✅ ネイティブ

vbcaxq

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vbic

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vbiq

✅ ネイティブ

vbsl

✅ ネイティブ

vcage

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vcagt

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vceq

💡 十分にスマートなコンパイラに依存しますが、ネイティブに近いはずです。

vceqz

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vcge

✅ ネイティブ

vcgez

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vcgt

✅ ネイティブ

vcgtz

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vcle

✅ ネイティブ

vclez

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vcls

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vclt

✅ ネイティブ

vcltz

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vcmla, vcmla_rot90, cmla_rot180, cmla_rot270

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vcmlq

✅ ネイティブ

vcnt

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vclz

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vcombine

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vcreate

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vdot

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vdot_lane

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vdup

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vdup_n

✅ ネイティブ

veor

✅ ネイティブ

vext

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vfma, vfma_lane, vfma_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vget_lane

✅ ネイティブ

vhadd

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vhsub

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vld1

✅ ネイティブ

vld2

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vld3

💡 十分にスマートなコンパイラに依存しますが、ネイティブに近いはずです。

vld4

💡 十分にスマートなコンパイラに依存しますが、ネイティブに近いはずです。

vld4_lane

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmax

✅ ネイティブ

vmaxv

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmin

✅ ネイティブ

vminv

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmla

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vmlal

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmlal_high_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmlal_lane

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmls

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmls_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmlsl

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmlsl_high

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmlsl_high_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmlsl_lane

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmovl

✅ ネイティブ

vmul

✅ ネイティブ

vmul_n

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vmull

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vmull_n

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vmull_lane

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmull_high

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vmvn

✅ ネイティブ

vneg

✅ ネイティブ

vorn

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vorr

✅ ネイティブ

vpadal

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vpadd

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vpaddl

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vpmax

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vpmin

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vpminnm

⚫ 実装されていません。コンパイラエラーが発生します。

vqabs

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqabsb

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqadd

💡 十分にスマートなコンパイラに依存しますが、ネイティブに近いはずです。

vqaddb

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqdmulh

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqdmulh_lane

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqneg

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqnegb

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqrdmulh

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqrdmulh_lane

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqshl

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqshlb

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqshrn_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqshrun_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqsub

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqsubb

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqtbl1

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vqtbl2

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vqtbl3

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vqtbl4

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vqtbx1

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqtbx2

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqtbx3

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vqtbx4

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vrbit

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vrecpe

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vrecps

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vreinterpret

💡 十分にスマートなコンパイラに依存しますが、ネイティブに近いはずです。

vrev16

✅ ネイティブ

vrev32

✅ ネイティブ

vrev64

✅ ネイティブ

vrhadd

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vrsh_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vrshn_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vrsqrte

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vrsqrts

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vrshl

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vrshr_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vrsra_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vset_lane

✅ ネイティブ

vshl

スカラー化

vshl_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vshll_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vshr_n

⚠️ 直接的な実装はありませんが、高速なneon命令を使用してエミュレートされます。

vshrn_n

⚠️ 直接的な実装はありませんが、高速なneon命令を使用してエミュレートされます。

vsqadd

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vsra_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vsri_n

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vst1

✅ ネイティブ

vst1_lane

💡 十分にスマートなコンパイラに依存しますが、ネイティブに近いはずです。

vst2

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vst2_lane

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vst3

💡 十分にスマートなコンパイラに依存しますが、ネイティブに近いはずです。

vst3_lane

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vst4

💡 十分にスマートなコンパイラに依存しますが、ネイティブに近いはずです。

vst4_lane

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vsub

✅ ネイティブ

vsubl

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vsubl_high

⚠️ 直接的な実装はありませんが、高速なNEON命令を使用してエミュレートされます。

vsubn

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vsubw

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vtbl1

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vtbl2

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vtbl3

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vtbl4

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vtbx1

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vtbx2

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vtbx3

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vtbx4

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vtrn

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vtrn1

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vtrn2

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vtst

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vuqadd

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vuqaddb

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vuzp

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vuzp1

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vuzp2

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vxar

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vzip

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vzip1

❌ 低速な命令でエミュレートされるか、スカラー化されます。

vzip2

❌ 低速な命令でエミュレートされるか、スカラー化されます。