Emscripten は WebAssembly SIMD 機能をサポートしています。C/C++ プログラムで WebAssembly SIMD を活用するには、5 つの異なる方法があります。
C/C++ ソースコードを変更することなく、WebAssembly SIMD を自動的にターゲットとするLLVM/Clang SIMD 自動ベクトル化を有効にします。
GCC/Clang SIMD ベクトル拡張機能(__attribute__((vector_size(16)))
)を使用して SIMD コードを記述します。
WebAssembly SIMD イントリンシックス(#include <wasm_simd128.h>
)を使用して SIMD コードを記述します。
x86 SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、または AVX イントリンシックス(#include <*mmintrin.h>
)を使用する既存の SIMD コードをコンパイルします。
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 ベクトル拡張機能を使用でき、可能な場合は WebAssembly SIMD 命令に削減されます。
これにより、開発者は typedef を介してカスタムのワイドベクトル型を作成し、ベクトル化された型に算術演算子 (+、-、*、/) を使用したり、vector[i] 表記を使用して個々のレーンにアクセスしたりできます。ただし、GCC ベクトル組み込み関数は使用できません。代わりに、以下の 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 命令 |
アーキテクチャ |
考慮事項 |
---|---|---|
[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 命令でエミュレートされます。 |
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
マクロを定義することにより、低速なエミュレートされた関数の診断を有効にすることができます。これにより、低速なパス(凡例の❌または💣に対応)を使用しようとすると警告が表示されます。
組込み関数名 |
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は型を推測する必要があります。 |
_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は型を推測する必要があります。 |
_mm_stream_ps |
🟡 wasm_v128_store。VMは型を推測する必要があります。 |
_mm_prefetch |
💭 何もしない。 |
_mm_sfence |
⚠️ マルチスレッドビルドでの完全なバリア。 |
_mm_shuffle_ps |
🟡 wasm_i32x4_shuffle。VMは型を推測する必要があります。 |
_mm_storer_ps |
💡 仮想。シャッフルとSimdストア。 |
_mm_store_ps1 (_mm_store1_ps) |
🟡 仮想。シャッフルでエミュレート。 |
_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サポートなし。 |
_mm_rcp_ss |
❌ Wasm SIMDサポートなし。 |
_mm_sqrt_ps |
✅ wasm_f32x4_sqrt |
_mm_sqrt_ss |
⚠️ シャッフルでエミュレート |
_mm_rsqrt_ps |
❌ Wasm SIMDサポートなし。 |
_mm_rsqrt_ss |
❌ Wasm SIMDサポートなし。 |
_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_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 |
✅ 仮想 |
_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を参照してください。
組込み関数名 |
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は型を推測する必要があります。 |
_mm_load1_pd (_mm_load_pd1) |
🟡 仮想関数. wasm_v64x2_load_splat, VMは型を推測する必要がある。 |
_mm_load_sd |
❌ wasm_f64x2_make を使用してエミュレート |
_mm_load_si128 |
🟡 wasm_v128_load。VMは型を推測する必要があります。 |
_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は型を推測する必要があります。 |
_mm_store_sd |
💡 スカラーストアでエミュレート |
_mm_store_si128 |
🟡 wasm_v128_store。VMは型を推測する必要があります。 |
_mm_store1_pd (_mm_store_pd1) |
🟡 仮想。シャッフルでエミュレート。 |
_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は型を推測する必要があります。 |
_mm_stream_si128 |
🟡 wasm_v128_store。VMは型を推測する必要があります。 |
_mm_stream_si32 |
🟡 wasm_v128_store。VMは型を推測する必要があります。 |
_mm_stream_si64 |
🟡 wasm_v128_store。VMは型を推測する必要があります。 |
_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は型を推測する必要があります。 |
_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 を参照してください。
組込み関数名 |
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 を参照してください。
組込み関数名 |
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でエミュレート |
_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 を参照してください。
組込み関数名 |
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は型を推測する必要があります。 |
_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を参照してください。
組込み関数名 |
WebAssembly SIMDサポート |
---|---|
_mm_cmpgt_epi64 |
✅ wasm_i64x2_gt |
_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を参照してください。
組込み関数名 |
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ビット幅の命令によってエミュレートされます。
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を参照してください。
組込み関数名 |
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 |
❌ 低速な命令でエミュレートされるか、スカラー化されます。 |