第3章 WebAssembly バイナリ表現

この章ではwasmモジュールのバイナリ表現について解説します。まずは内部で使用されるデータ型、次にモジュールの構造について見ていきます。この章の内容は公式の資料[5]を翻訳、補足したものです。

3.1 データ型

3.1.1 数値(Numbers)

uintN

符号なしの N bitの整数値、リトルエンディアンで表現されます。uint8uint16uint32 の3種類が使用されています。

varuintN

LEB128[6]で表現される N bitの符号なし整数です。

現在 varuint1, varuint7, varuint32のみ使用されてます。前者2つは将来的な拡張機能と互換性のために使用されています。

varintN

符号付きLEB128で表現される N bitの整数です。

現在 varint7, varint32, varint64が使用されています。

3.1.2 オペコード(Instruction Opcodes)

MVPでは、オペコードの個数はは256以下であるため1バイトで表現されます。将来的にSIMDやアトミック操作の命令を追加すると256を超えるため、拡張スキーマが必要になります。マルチバイトオペコード用に1バイトのプレフィックス値を策定中です。

3.1.3 言語型(Language Types)

全ての型(型コンストラクタを表す)は先頭の負のvarint7値によって識別されます。

表3.1:

オペコード(varint7値)オペコード(バイト値)Type constructor
-0x010x7fi32
-0x020x7ei64
-0x030x7df32
-0x040x7cf64
-0x100x70anyfunc
-0x200x60func
-0x400x40空のblock_typeを表現する擬似的な型

この中でいくつかは追加のフィールドが続くものがあります(後述)。

将来的な拡張性のために隙間の数値は予約されています。符号付きの数値(つまりここで負の値)を使っているは1バイトでtype sectionへのインデックス(後述)を設定できるようにするためです。型システムの将来的な拡張に関連しています。

value_type

値型を表すvarint7値。i32i64f32f64の中の一つです。

block_type

ブロック(後述)が返す型を表すvarint7値。ブロックが値を返す場合はvalue_type、何も返さない場合は-0x40が設定されます。

elem_type

テーブル(後述)中の要素の型を表すvarint7値。MVPではanyfuncのみ有効です。

将来的に他の要素も有効になる可能性があります。

func_type

関数シグネチャーを表します。この型コンストラクタには以下の記述が追加されます。

表3.2:

フィールド説明
formvarint7上の表で定義したfunc型コンストラクタの値
param_countvaruint32関数のパラメータ数
param_typesvalue_type*関数のパラメータの型(パラメータ数だけ用意)
return_countvaruint1関数の返り値の数
return_typevalue_type?関数の返り値の型(return_countが1なら)

将来的にreturn_countreturn_typeは複数の値を許容するために一般化されるかもしれません。

3.1.4 他の型(Other Types)

global_type

グローバル変数の情報を表します。

表3.3:

フィールド説明
content_typevalue_type値の型
mutabilityvaruint10ならイミュータブル。1ならミュータブル

table_type

テーブルの情報を表します。

表3.4:

フィールド説明
element_typeelem_type要素の型
limitsresizable_limits後述

memory_type

メモリーの情報を表します。

表3.5:

フィールド説明
limitsresizable_limits後述

external_kind

インポートまたはモジュール内で定義された定義の種類を表す1バイトの符号なし整数値。

表3.6:

ValueDescription
0インポートまたはモジュール内で定義された Function
1インポートまたはモジュール内で定義された Table
2インポートまたはモジュール内で定義された Memory
3インポートまたはモジュール内で定義された Global

resizable_limits

テーブル、メモリーの初期、最大サイズを表します。テーブルの場合は要素数、メモリーの場合は64KBを1単位とします。

表3.7:

フィールド説明
flagsvaruint1maximumフィールドがあるかどうか
initialvaruint32初期の長さ
maximumvaruint32?最大値(flags1ならこのフィールドがある)

flags フィールドはvaruint32に変わる可能性があります。例えばスレッド間で共有するためのフラグが含まれたりする。

init_expr

イニシャライザー。code section(後述)で用いられている式とendオペコードによって構成されます。

イニシャライザーに含まれるget_globalはインポートされたイミュータブルなグローバル変数のみ参照でき、全てのinit_exprはimport sectionの後でのみ使用できます。

3.2 モジュール構造(Module structure)

WebAssemblyモジュールの高レベルな構造(セクションの集合)と各セクションについて解説します。wast2wasmでモジュールの詳細情報を確認できるので、合わせて見てもらえると理解の助けになると思われます。

$ wast2wasm -v add.wast
wast2wasm -v の実行例

図3.1: wast2wasm -v の実行例

3.2.1 高レベルな構造(High-level structure)

wasmモジュール概要図

図3.2: wasmモジュール概要図

モジュールは以下の2つのフィールドから開始します。

表3.8:

フィールド説明
magic numberuint32マジックナンバー 0x6d736100"\0asm"
versionuint32バージョンナンバー(0x1

モジュールプリアンブルのあとに一連のセクションが続きます。各セクションは既知のセクションまたはカスタムセクションを表す1バイトのセクションコードによって識別されます。そして、セクションの長さ、ペイロードが次に続きます。既知のセクションは非ゼロなidを持ちます。カスタムセクションのidは0で、その後にペイロードの一部として識別文字列が続きます。カスタムセクションはWebAssemblyの実装では無視されるので内部でのバリデーションエラーがあってもモジュールが無効になるわけではありません。

表3.9:

フィールド説明
idvaruint7セクションコード
payload_lenvaruint32セクションのバイト長
name_lenvaruint32?セクション名のバイト長。id == 0のときだけ存在します
namebytes?セクション名の本体。id == 0のときだけ存在します
payload_dataセクションの中身。長さは payload_len - sizeof(name) - sizeof(name_len)

既知のセクションはオプショナルで最大で1個だけです。カスタムセクションは全て同じidを持ちユニークでない名前をつけることができます。以下の表で定義される既知のセクションは順不同で現れない場合もあります。各セクションのpayload_dataにエンコードされた内容が入ります。

表3.10:

セクション名コード説明
Type1関数シグネチャー宣言
Import2インポート宣言
Function3関数宣言
Table4間接的な関数テーブルと他のテーブル
Memory5メモリー属性
Global6グローバル宣言
Export7エクスポート
Start8開始関数宣言
Element9要素セクション
Code10関数本体(code)
Data11データセグメント

最後のセクションの最終バイトはモジュールの最終バイトと一致する必要があります。最小のモジュールは8バイトです(magic number, versionのあとに何もない状態)。

3.2.2 Type section

Type sectionでは、モジュールで使用されている全ての関数シグネチャーを宣言します。

表3.11:

フィールド説明
countvaruint32エントリー数
entriesfunc_type*関数シグネチャー列

将来的に、他の型を持つエントリーもここに入る可能性があります。func_typeformフィールドで識別できます。

3.2.3 Import section

Import sectionではモジュールで使用されている全てのインポートを宣言します。

表3.12:

フィールド説明
countvaruint32エントリー数
entriesimport_entry*import entry(後述)列

import_entryは以下のような構造を持ちます。

表3.13:

フィールド説明
module_lenvaruint32モジュール文字列の長さ
module_strbytesmodule_lenバイトのモジュールの文字列
フィールド_lenvaruint32フィールド名の長さ
フィールド_strbytesフィールド_lenバイトのフィールド名
kindexternal_kindインポートされた定義の種類

kindの種類によって以下の項目が続きます。kindFunctionの場合は

表3.14:

フィールド説明
typevaruint32type sectionにある関数シグネチャーのインデックス

kindTableの場合は

表3.15:

フィールド説明
typetable_typeインポートされたテーブルの情報

kindMemoryの場合は

表3.16:

フィールド説明
typememory_typeインポートされたメモリーの情報

kindGlobalの場合は

表3.17:

フィールド説明
typeglobal_typeインポートされたグローバル変数の情報

MVPではイミュータブルなグローバル変数のみインポートできます。

3.2.4 Function section

Function sectionではモジュール内のすべての関数シグネチャーを宣言します(関数の定義はcode sectionに置かれます)。

表3.18:

フィールド説明
countvaruint32エントリー数
typesvaruint32*type sectionに置いてある対象のfunc_typeのインデックス列

3.2.5 Table section

Table sectionではモジュール内で使用するテーブル(参照を要素として持つ型付き配列)を定義します。

表3.19:

フィールド説明
countvaruint32モジュールに定義されているテーブルの数
entriestable_type*table_typeエントリー列

MVPでは、テーブルの数は1以下でなければいけません。table_typeで使用できる型はanyfuncだけで、関数テーブルとして機能します。

3.2.6 Memory section

Memory sectionではモジュール内で使用する線形メモリーを定義します。

表3.20:

フィールド説明
countvaruint32モジュールで定義されているメモリーの数
entriesmemory_type*memory_type エントリー列

MVPでは、メモリーの数は1以下でなければいけません。

3.2.7 Global section

Global sectionではモジュール内で使用するグローバル変数を定義します。

表3.21:

フィールド説明
countvaruint32グローバル変数エントリーの数
globalsglobal_variable*後述のグローバル変数列

global_variableは以下のような構造を持ちます。

表3.22:

フィールド説明
typeglobal_type変数の型
initinit_exprグローバル変数のイニシャライザー

global_typeによって型とミュータビリティー、init_exprによって初期値が与えられます。

MVPではイミュータブルなグローバル変数だけエクスポートできます。

3.2.8 Export section

Export sectionではモジュール外にエクスポートするエントリーを宣言します。

表3.23:

フィールド説明
countvaruint32エントリー数
entriesexport_entry*後述のエクスポートエントリー列

export_entryは以下のような構造を持ちます。

表3.24:

フィールド説明
フィールド_lenvaruint32フィールド名の長さ
フィールド_strbytesフィールド_lenバイトのフィールド名
kindexternal_kindエクスポートされた定義の種類
indexvaruint32対応するindex space(後述)へのインデックス

例えば、kindFunctionのときはindexはfunction section中でのインデックス(function index)になります。MVPではメモリ、テーブルは0だけです。

3.2.9 Start section

Start sectionではモジュールのインスタンス化が完了したときに呼ばれる関数を宣言します。

表3.25:

フィールド説明
indexvaruint32開始する関数のfunction index

3.2.10 Element section

Element sectionではモジュールをインスタンス化するときに初期値としてテーブルに設定する要素を宣言します。

表3.26:

フィールド説明
countvaruint32エレメントセグメントの数
entrieselem_segment*後述のエレメントセグメント列

elem_segmentは以下ような構造を持ちます。

表3.27:

フィールド説明
indexvaruint32table index(MVPでは0)
offsetinit_expr要素の場所のオフセットを返すイニシャライザー(i32値)
num_elemvaruint32要素数
elemsvaruint32*function index列

3.2.11 Code section

Code sectionにはモジュール内の全ての関数の本体が含まれています。function sectionで宣言された関数の数と関数本体の定義は必ず一致しなければいけません。i番目の関数宣言はi番目の関数本体に対応しています。

表3.28:

フィールド説明
countvaruint32function_bodyの数
bodiesfunction_body*関数本体の列(Function bodiesで説明)

3.2.12 Data section

Data sectionではモジュールをインスタンス化するときにロードされる初期化データを宣言します。

表3.29:

フィールド説明
countvaruint32データセグメントの数
entriesdata_segment*後述のデータセグメント列

data_segmentは以下のような構造を持ちます。

表3.30:

フィールド説明
indexvaruint32線形メモリーのインデックス(MVPでは0)
offsetinit_exprデータの場所のオフセットを返すイニシャライザー(i32値)
sizevaruint32dataのバイト数
databytesデータ本体

3.2.13 Name section

Name sectionはカスタムセクションの1つです。nameフィールドに"name"が設定されています。全てのカスタムセクション同様、このセクションでのバリデーションエラーは全体のモジュールには影響しません。Name sectionは(あれば)データセクションのあとに1回だけ現れます。wasmモジュールやその他、開発環境で表示する場合、Name sectionで定義される関数名やローカル変数名はWebAssemblyのテキスト表現などで使用されることが期待されます。影響しないのでここでは構造についての説明は省略します。

3.3 関数本体(Function Bodies)

関数本体は一連のローカル変数宣言の後にバイトコード命令が続きます。これは構造化されたスタックマシンの命令列とみなすことができます。命令はオペコードと0個以上の即値オペランド(immediates)にエンコードされます。各関数本体はendオペコードで終わらなければなりません。

表3.31:

フィールド説明
body_sizevaruint32関数本体のバイト数
local_countvaruint32ローカル変数の数
localslocal_entryローカル変数列
codebyte*関数のバイトコード
endbyte0x0b、関数本体の終了

3.3.1 Local entry

各ローカルエントリーは与えられた型のローカル変数リストを宣言します。同じ型のエントリーを複数持つことができます。

表3.32:

フィールド説明
countvaruint32ローカル変数の数
typevalue_type変数の型

3.4 オペコード一覧

wasmで定義されているオペコードを紹介します。オペコードがオペランドを受け取る場合はN番目のオペランドをopNとします。

3.4.1 Control flow operators

表3.33:

名前オペコード即値説明
unreachable0x00即例外を発生
nop0x01なにもしないオペコード
block0x02sig:block_type式のシーケンスを開始して、0個か1個の値をpush
loop0x03sig:block_typeループできるブロックを作る
if0x04sig:block_typeif式。op1 != 0のときブロックに入る
else0x05ifに対応するelse式
end0x0bblockifloopの終了
br0x0crelative_depth:varuint32対象の親ブロックに対して分岐命令を行う(以下補足)
br_if0x0drelative_depth:varuint32brの条件分岐あり版(以下補足)
br_table0x0e後述後述
return0x0f関数から0個か1個の値を返す

分岐命令について

br, br_if, br_table は分岐命令を行う対象のブロックによって挙動が変わります。block, if ブロックでは、対応する end に、loop ブロックではブロックの先頭に飛びます。

br

relative_depth のイメージ

block ;; 2
  block ;; 1
    block ;; 0
      br 1 ;; 現在のブロックからの深さを指定して分岐
    end
  end
end

blockが値をpushしない場合、オペランドを受け取りません。blockが値をpushする場合、op1をpushします。

br_if

blockが値をpushしない場合、op1 != 0 のとき分岐します。blockが値をpushする場合、op2 != 0 のとき分岐して、op1 をpushします。

br_table

br_tableオペコードは以下のような即値オペランドを持っています。

表3.34:

フィールド説明
target_countvaruint32target_tableのエントリー数
target_tablevaruint32*分岐する対象の親ブロック列
default_targetvaruint32デフォルトで分岐するブロック

ブロックが値をpushしない場合、target_tableop1番目のブロックに対して分岐命令を行います。ブロックが値をpushする場合はbr_ifなどと同様に最初のオペランドがpushされます。入力値が範囲外の場合、br_tabledefault_targetに指定されているブロックに対して分岐命令を行います。

オペコードの開いてる場所は将来のために予約されてます。

3.4.2 Call operators

表3.35:

名前オペコード即値説明
call0x10function_index: varuint32function indexに対応する関数を呼ぶ
call_indirect0x11type_index: varuint32, reserved: veruint1type_index の型の関数を間接的に呼ぶ

call_indirectは入力として、関数の引数分のオペランド(type_indexから型を参照して引数の数を決定)とテーブルへのindexを受け取ります。テーブルのindex位置のelem_segmentの中で指定されているfunction indexから関数を参照して呼び出します。reservedは将来的に使うので予約されてます。MVPでは0です。

3.4.3 Parametric operators

表3.36:

名前オペコード即値説明
drop0x1aスタックの1番上の値をpop
select0x1bop3 != 0 ? op1 : op2

3.4.4 Variable access

表3.37:

名前オペコード即値説明
get_local0x20local_index: varuint32local_indexで指定されたローカル変数をスタックにpush
set_local0x21local_index: varuint32op1の値をlocal_indexで指定されたローカル変数にセット
tee_local0x22local_index: varuint32op1の値をlocal_indexで指定されたローカル変数にセットして、同じ値をpush
get_global0x23global_index: varuint32global_indexで指定されたグローバル変数をスタックにpush
set_global0x24global_index: varuint32op1の値をglobal_indexで指定されたグローバル変数にセット

3.4.5 Memory-related operators

表3.38:

名前オペコード即値説明
i32.load0x28memory_immediateメモリーのオフセットop1 + memory_immediate.offset(後述)から32bit整数のデータを読み込んでスタックにpush
i64.load0x29memory_immediate
f32.load0x2amemory_immediate
f64.load0x2bmemory_immediate
i32.load8_s0x2cmemory_immediate符号あり8bit整数を以下略
i32.load8_u0x2dmemory_immediate符号なし8bit整数を以下略
i32.load16_s0x2ememory_immediate
i32.load16_u0x2fmemory_immediate
i64.load8_s0x30memory_immediate
i64.load8_u0x31memory_immediate
i64.load16_s0x32memory_immediate
i64.load16_u0x33memory_immediate
i64.load32_s0x34memory_immediate
i64.load32_u0x35memory_immediate
i32.store0x36memory_immediateメモリーのオフセットop1 + memory_immediate.offset(後述)にop2の値を書き込む
i64.store0x37memory_immediate
f32.store0x38memory_immediate
f64.store0x39memory_immediate
i32.store80x3amemory_immediate
i32.store160x3bmemory_immediate
i64.store80x3cmemory_immediate
i64.store160x3dmemory_immediate
i64.store320x3ememory_immediate
current_memory0x3freserved: varuint1メモリーのサイズを問い合わせる
grow_memory0x40reserved: varuint1メモリーのサイズを拡張する

memory_immediate は以下のようにエンコードされます。

表3.39:

名前説明
flagsvaruint32フラグ。現在は最下位bitsがアライメントの値として使われている(log2(alignment)でエンコードされる)
offsetvaruint32オフセット値

flagsはlog2(alignment)でエンコードされるので2の累乗である必要があります。追加のバリデーション基準として、アライメントは元々のアライメント以下でないといけません。log(memory-access-size)より下位のbitsは0である必要があります。これは将来のために予約されてます(例えば、共有メモリーの順序のために必要)。

current_memorygrow_memoryオペコードのreservedは将来的に使われる予定です(MVPでは0)。

3.4.6 Constants

表3.40:

名前オペコード即値説明
i32.const0x41value:varint32i32と解釈される定数値をpush
i64.const0x42value:varint64i64と解釈される定数値をpush
f32.const0x43value:uint32f32と解釈される定数値をpush
f64.const0x44value:uint64f64と解釈される定数値をpush

3.4.7 Comparison operators

真の場合は1、偽の場合は0をpushします。

表3.41:

名前オペコード即値説明
i32.eqz0x45op1 == 0
i32.eq0x46op1 == op2(符号に依存しない)
i32.ne0x47op1 != op2(符号に依存しない)
i32.lt_s0x48op1 < op2(符号付き整数として)
i32.lt_u0x49op1 < op2(符号なし整数として)
i32.gt_s0x4aop1 > op2(符号付き整数として)
i32.gt_u0x4bop1 > op2(符号なし整数として)
i32.le_s0x4cop1 <= op2(符号付き整数として)
i32.le_u0x4dop1 <= op2(符号なし整数として)
i32.ge_s0x4eop1 >= op2(符号付き整数として)
i32.ge_u0x4fop1 >= op2(符号なし整数として)
i64.eqz0x50op1 == 0
i64.eq0x51op1 == op2(符号に依存しない)
i64.ne0x52op1 != op2(符号に依存しない)
i64.lt_s0x53op1 < op2(符号付き整数として)
i64.lt_u0x54op1 < op2(符号なし整数として)
i64.gt_s0x55op1 > op2(符号付き整数として)
i64.gt_u0x56op1 > op2(符号なし整数として)
i64.le_s0x57op1 <= op2(符号付き整数として)
i64.le_u0x58op1 <= op2(符号なし整数として)
i64.ge_s0x59op1 >= op2(符号付き整数として)
i64.ge_u0x5aop1 >= op2(符号なし整数として)
f32.eq0x5bop1 == op2
f32.ne0x5cop1 != op2
f32.lt0x5dop1 < op2
f32.gt0x5eop1 > op2
f32.le0x5fop1 <= op2
f32.ge0x60op1 >= op2
f64.eq0x61op1 == op2
f64.ne0x62op1 != op2
f64.lt0x63op1 < op2
f64.gt0x64op1 > op2
f64.le0x65op1 <= op2
f64.ge0x66op1 >= op2

3.4.8 Numeric operators

表3.42:

名前オペコード即値説明
i32.clz0x67op1の値について最上位bitから0が連続する回数(符号に依存しない)
i32.ctz0x68op1の値について最下位bitから0が連続する回数(符号に依存しない)
i32.popcnt0x69op1の値について1になっているbitの数(符号に依存しない)
i32.add0x6aop1 + op2(符号に依存しない)
i32.sub0x6bop1 - op2(符号に依存しない)
i32.mul0x6cop1 * op2(符号に依存しない, 下位32bitが結果になる)
i32.div_s0x6dop1 / op2符号あり(結果は0方向に切り捨て)
i32.div_u0x6eop1 / op2符号なし(切り捨て)
i32.rem_s0x6fop1 % op2符号付き(符号は割られる方が使われる)
i32.rem_u0x70op1 % op2符号なし
i32.and0x71op1 & op2(符号に依存しない)
i32.or0x72op1 | op2(符号に依存しない)
i32.xor0x73op1 ^ op2(符号に依存しない)
i32.shl0x74op1 << op2(符号に依存しない)
i32.shr_s0x75op1 >> op2(算術シフト)
i32.shr_u0x76op1 >>> op2(論理シフト)
i32.rotl0x77左ローテート(符号に依存しない)
i32.rotr0x78右ローテート(符号に依存しない)
i64.clz0x79最上位bitから0が連続する回数(符号に依存しない)
i64.ctz0x7a最下位bitから0が連続する回数(符号に依存しない)
i64.popcnt0x7b1になっているbitの数(符号に依存しない)
i64.add0x7cop1 + op2(符号に依存しない)
i64.sub0x7dop1 - op2(符号に依存しない)
i64.mul0x7eop1 * op2(符号に依存しない, 下位64bitが結果になる)
i64.div_s0x7fop1 / op2符号あり(結果は0方向に切り捨て)
i64.div_u0x80op1 / op2符号なし(切り捨て)
i64.rem_s0x81op1 % op2符号付き(符号は割られる方が使われる)
i64.rem_u0x82op1 % op2符号なし
i64.and0x83op1 & op2(符号に依存しない)
i64.or0x84op1 | op2(符号に依存しない)
i64.xor0x85op1 ^ op2(符号に依存しない)
i64.shl0x86op1 << op2(符号に依存しない)
i64.shr_s0x87op1 >> op2(算術シフト)
i64.shr_u0x88op1 >>> op2(論理シフト)
i64.rotl0x89左ローテート(符号に依存しない)
i64.rotr0x8a右ローテート(符号に依存しない)
f32.abs0x8b絶対値
f32.neg0x8c符号逆転
f32.ceil0x8d切り上げ
f32.floor0x8e切り捨て
f32.trunc0x8f0方向に丸める
f32.nearest0x90四捨五入(偶数丸め)
f32.sqrt0x91平方根
f32.add0x92op1 + op2
f32.sub0x93op1 - op2
f32.mul0x94op1 * op2
f32.div0x95op1 / op2
f32.min0x962つの値のうち小さい方をpush。どちらかのオペランドがNaNの場合NaN
f32.max0x972つの値のうち大きい方をpush。どちらかのオペランドがNaNの場合NaN
f32.copysign0x981つ目の値の符号を2つ目の値にコピーしたものをpush
f64.abs0x99絶対値
f64.neg0x9a符号逆転
f64.ceil0x9b切り上げ
f64.floor0x9c切り捨て
f64.trunc0x9d0方向に丸める
f64.nearest0x9e四捨五入(偶数丸め)
f64.sqrt0x9f平方根
f64.add0xa0op1 + op2
f64.sub0xa1op1 - op2
f64.mul0xa2op1 * op2
f64.div0xa3op1 / op2
f64.min0xa42つの値のうち小さい方をpush。どちらかのオペランドがNaNの場合NaN
f64.max0xa52つの値のうち大きい方をpush。どちらかのオペランドがNaNの場合NaN
f64.copysign0xa62つ目の値の符号を1つ目の値にコピーしたものをpush

3.4.9 Conversions

型変換を行います。

f64.convert_s/i32では最近接偶数へ丸められます。そして、IEEE 754-2008で定義された無限大、負の無限大にオーバーフローする可能性があります。

浮動小数点数から整数に変換する命令(trunc)の場合、0方向に丸められた整数値となります。オーバーフローするような数値を変換しようとするとエラーとなります。

表3.43:

名前オペコード即値説明
i32.wrap/i640xa764bit整数を受け取って、それの下位32bitをpush
i32.trunc_s/f320xa832bit浮動小数点数を受け取って、0方向に丸めた32bitの符号付き整数をpush
i32.trunc_u/f320xa932bit浮動小数点数を受け取って、0方向に丸めた32bitの符号なし整数をpush
i32.trunc_s/f640xaa64bit浮動小数点数を受け取って、0方向に丸めた32bitの符号付き整数をpush
i32.trunc_u/f640xab64bit浮動小数点数を受け取って、0方向に丸めた32bitの符号なし整数をpush
i64.extend_s/i320xac32bit整数を64bit符号付き整数に拡張する
i64.extend_u/i320xad32bit整数を64bit符号なし整数に拡張する
i64.trunc_s/f320xae32bit浮動小数点数を受け取って、0方向に丸めた64bitの符号付き整数をpush
i64.trunc_u/f320xaf32bit浮動小数点数を受け取って、0方向に丸めた64bitの符号なし整数をpush
i64.trunc_s/f640xb064bit浮動小数点数を受け取って、0方向に丸めた64bitの符号付き整数をpush
i64.trunc_u/f640xb164bit浮動小数点数を受け取って、0方向に丸めた64bitの符号なし整数をpush
f32.convert_s/i320xb232bit整数を32bit浮動小数点数に変換する(符号ありとして)
f32.convert_u/i320xb332bit整数を32bit浮動小数点数に変換する(符号なしとして)
f32.convert_s/i640xb464bit整数を32bit浮動小数点数に変換する(符号ありとして)
f32.convert_u/i640xb564bit整数を32bit浮動小数点数に変換する(符号なしとして)
f32.demote/f640xb664bit浮動小数点数から32bit浮動小数点数に変換
f64.convert_s/i320xb732bit整数を64bit浮動小数点数に変換する(符号ありとして)
f64.convert_u/i320xb832bit整数を64bit浮動小数点数に変換する(符号なしとして)
f64.convert_s/i640xb964bit整数を64bit浮動小数点数に変換する(符号ありとして)
f64.convert_u/i640xba64bit整数を64bit浮動小数点数に変換する(符号なしとして)
f64.promote/f320xbb32bit浮動小数点数から64bit浮動小数点数に変換

3.4.10 Reinterpretations

変換前の数値をただのbit列として扱って変換後の型として再解釈します。

表3.44:

名前オペコード即値説明
i32.reinterpret/f320xbc32bit浮動小数点数を32bit整数として再解釈する
i64.reinterpret/f640xbd64bit浮動小数点数を64bit整数として再解釈する
f32.reinterpret/i320xbe32bit整数を32bit浮動小数点数として再解釈する
f64.reinterpret/i640xbf64bit整数を64bit浮動小数点数として再解釈する