_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|

0_ | unreachable | nop | block | loop | if | else | *try | *catch | *throw | *rethrow | *br_on_exn | end | br | br_if | br_table | return |

1_ | call | call_indirect | *return_call | *return_call_indirect | drop | select | *select t | |||||||||

2_ | local.get | local.set | local.tee | global.get | global.set | *table.get | *table.set | i32.load | i64.load | f32.load | f64.load | i32.load8_s | i32.load8_u | i32.load16_s | i32.load16_u | |

3_ | i64.load8_s | i64.load8_u | i64.load16_s | i64.load16_u | i64.load32_s | i64.load32_u | i32.store | i64.store | f32.store | f64.store | i32.store8 | i32.store16 | i64.store8 | i64.store16 | i64.store32 | memory.size |

4_ | memory.grow | i32.const | i64.const | f32.const | f64.const | i32.eqz | i32.eq | i32.ne | i32.lt_s | i32.lt_u | i32.gt_s | i32.gt_u | i32.le_s | i32.le_u | i32.ge_s | i32.ge_u |

5_ | i64.eqz | i64.eq | i64.ne | i64.lt_s | i64.lt_u | i64.gt_s | i64.gt_u | i64.le_s | i64.le_u | i64.ge_s | i64.ge_u | f32.eq | f32.ne | f32.lt | f32.gt | f32.le |

6_ | f32.ge | f64.eq | f64.ne | f64.lt | f64.gt | f64.le | f64.ge | i32.clz | i32.ctz | i32.popcnt | i32.add | i32.sub | i32.mul | i32.div_s | i32.div_u | i32.rem_s |

7_ | i32.rem_u | i32.and | i32.or | i32.xor | i32.shl | i32.shr_s | i32.shr_u | i32.rotl | i32.rotr | i64.clz | i64.ctz | i64.popcnt | i64.add | i64.sub | i64.mul | i64.div_s |

8_ | i64.div_u | i64.rem_s | i64.rem_u | i64.and | i64.or | i64.xor | i64.shl | i64.shr_s | i64.shr_u | i64.rotl | i64.rotr | f32.abs | f32.neg | f32.ceil | f32.floor | f32.trunc |

9_ | f32.nearest | f32.sqrt | f32.add | f32.sub | f32.mul | f32.div | f32.min | f32.max | f32.copysign | f64.abs | f64.neg | f64.ceil | f64.floor | f64.trunc | f64.nearest | f64.sqrt |

A_ | f64.add | f64.sub | f64.mul | f64.div | f64.min | f64.max | f64.copysign | i32.wrap_i64 | i32.trunc_f32_s | i32.trunc_f32_u | i32.trunc_f64_s | i32.trunc_f64_u | i64.extend_i32_s | i64.extend_i32_u | i64.trunc_f32_s | i64.trunc_f32_u |

B_ | i64.trunc_f64_s | i64.trunc_f64_u | f32.convert_i32_s | f32.convert_i32_u | f32.convert_i64_s | f32.convert_i64_u | f32.demote_f64 | f64.convert_i32_s | f64.convert_i32_u | f64.convert_i64_s | f64.convert_i64_u | f64.promote_f32 | i32.reinterpret_f32 | i64.reinterpret_f64 | f32.reinterpret_i32 | f64.reinterpret_i64 |

C_ | *i32.extend8_s | *i32.extend16_s | *i64.extend8_s | *i64.extend16_s | *i64.extend32_s | |||||||||||

D_ | *ref.null | *ref.is_null | *ref.func | |||||||||||||

E_ | ||||||||||||||||

F_ | *** | *SIMD |

**** 0xFC proposals**

_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|

FC 0_ | i32.trunc_sat_f32_s | i32.trunc_sat_f32_u | i32.trunc_sat_f64_s | i32.trunc_sat_f64_u | i64.trunc_sat_f32_s | i64.trunc_sat_f32_u | i64.trunc_sat_f64_s | i64.trunc_sat_f64_u | memory.init | data.drop | memory.copy | memory.fill | table.init | elem.drop | table.copy | table.grow |

FC 1_ | table.size | table.fill |

The unreachable instruction causes an unconditional trap.

A trap immediately aborts execution. Traps cannot be handled by WebAssembly code, but are reported to the outside environment, where they typically can be caught.

**stack-polymorphic**: performs an *unconditional control transfer*.

The nop instruction does nothing.

[t^{?}]
### Followed by:

### Stack:

[] → [t^{∗}]

the beginning of a block construct, a sequence of instructions with a label at the end.

- i8
*rt*: blocktype — 0x40 = [], 0x7F = [i32], 0x7E = [i64], 0x7D = [f32], 0x7C = [f64] - instructions
- 0x0B — end

The result type of the instructions must match the blocktype.

The *block*, *loop* and *if* instructions are structured instructions. They bracket nested sequences of instructions, called blocks, terminated with, or separated by, *end* or *else* pseudo-instructions. They must be well-nested.

[t^{?}]
### Followed by:

### Stack:

[] → [t^{∗}]

a block with a label at the beginning which may be used to form loops

- i8
*rt*: blocktype — 0x40 = [], 0x7F = [i32], 0x7E = [i64], 0x7D = [f32], 0x7C = [f64] - instructions
- 0x0B — end

[t^{?}]
### Followed by:

### Stack:

[i32] → [t^{∗}]

i32*c* → [t^{∗}]

if*c* is non-zero, enter block instructions_{1}, else enter block instructions_{2}

the beginning of an if construct with an implicit *then* block

- i8
*rt*: blocktype — 0x40 = [], 0x7F = [i32], 0x7E = [i64], 0x7D = [f32], 0x7C = [f64] - instructions
_{1} - 0x0B — end

- i8
*rt*: blocktype - instructions
_{1} - 0x05 — else
- instructions
_{2} - 0x0B — end

i32

if

Marks the else block of an *if*.

Marks the end of a *block*, *loop*, *if*, or function.

l
### Followed by:

u32 *l* : labelidx
### Stack:

[t^{∗}_{1} t^{?}] → [t^{∗}_{2}]

Branch to a given label in an enclosing construct.

Performs an unconditional branch.

Label 0 refers to the innermost structured control instruction enclosing the referring branch instruction, while increasing indices refer to those farther out.

A branch targeting a *block* or *if* behaves like a break statement in most C-like languages, while a branch targeting a *loop* behaves like a continue statement.

**stack-polymorphic**: performs an *unconditional control transfer*.

l
### Followed by:

u32 *l* : labelidx
### Stack:

[t^{?} i32] → [t^{?}]

Performs a conditional branch, branching if i32 *c* is non-zero.

Conditionally branch to a given label in an enclosing construct.

l* l
### Followed by:

### Stack:

[t^{∗}_{1} t^{?} i32] → [t^{∗}_{2}]

A jump table which jumps to a label in an enclosing construct.

Performs an indirect branch through an operand indexing into the label vector that is an immediate to the instruction, or to a default target if the operand is out of bounds.

- u32
*l**: vec( labelidx ) - u32
*l*: labelidx

**stack-polymorphic**: performs an *unconditional control transfer*.

return zero or more values from this function.

The return instruction is a shortcut for an unconditional branch to the outermost block, which implicitly is the body of the current function.

**stack-polymorphic**: performs an *unconditional control transfer*.

x
### Followed by:

u32 *x* : funcidx
### Stack:

[t^{∗}_{1}] → [t^{∗}_{2}]

The call instruction invokes another function, consuming the necessary arguments from the stack and returning the result values of the call.

x
### Followed by:

### Stack:

[t^{?} i32] → [t^{?}]

The call_indirect instruction calls a function indirectly through an operand indexing into a table.

- u32
*x*: typeidx - 0x00 — zero byte

In future versions of WebAssembly, the zero byte may be used to index additional tables.

The drop instruction simply throws away a single operand.

The select instruction selects one of its first two operands based on whether its third operand is zero or not.

x
### Followed by:

u32 *x* : localidx
### Stack:

[] → [t]

This instruction gets the value of a variable.

The index space for locals is only accessible inside a function and includes the parameters of that function, which precede the local variables.

The *locals* context refers to the list of locals declared in the current function (including parameters), represented by their value type.

x
### Followed by:

u32 *x* : localidx
### Stack:

[t] → []

This instruction sets the value of a variable.

The index space for locals is only accessible inside a function and includes the parameters of that function, which precede the local variables.

x
### Followed by:

u32 *x* : localidx
### Stack:

[t] → [t]

The local.tee instruction is like local.set but also returns its argument.

The index space for locals is only accessible inside a function and includes the parameters of that function, which precede the local variables.

x
### Followed by:

u32 *x* : globalidx
### Stack:

[] → [t]

This instruction gets the value of a variable.

The *globals* context is the list of globals declared in the current module, represented by their global type.

x
### Followed by:

u32 *x* : globalidx
### Stack:

[t] → []

This instruction sets the value of a variable

m
### Followed by:

*m* : memarg { u32 offset, u32 align }
### Stack:

[i32] → [i32]

i : address-operand → c : result

load 4 bytes as i32.

i : address-operand → c : result

Memory is accessed with load and store instructions for the different value types. They all take a memory immediate *memarg* that contains an address offset and the expected alignment.

The immediate value memarg.align is an alignment hint about the effective-address. It is a power-of 2 encoded as log2(memarg.align). In practice, its value may be: 0 (8-bit), 1 (16-bit), 2 (32-bit), or (64-bit; used only with wasm64).

`effective-address = address-operand + memarg.offset `

If memarg.align is incorrect it is considered "misaligned". Misaligned access still has the same behavior as aligned access, only possibly much slower.

m
### Followed by:

*m* : memarg { u32 offset, u32 align }
### Stack:

[i32] → [i64]

load 8 bytes as i64.

The static address offset is added to the dynamic address operand, yielding a 33 bit effective address that is the zero-based index at which the memory is accessed. All values are read and written in little endian byte order. A trap results if any of the accessed memory bytes lies outside the address range implied by the memory’s current size.

m
### Stack:

[i32] → [f32]

load 4 bytes as f32.

Note: When a number is stored into memory, it is converted into a sequence of bytes in little endian byte order.

m
### Stack:

[i32] → [f64]

load 8 bytes as f64.

m
### Stack:

[i32] → [i32]

load 1 byte and sign-extend i8 to i32.

Integer loads and stores can optionally specify a storage size that is smaller than the bit width of the respective value type. In the case of loads, a sign extension mode sx (s|u) is then required to select appropriate behavior.

m
### Stack:

[i32] → [i32]

load 1 byte and zero-extend i8 to i32

m
### Stack:

[i32] → [i32]

load 2 bytes and sign-extend i16 to i32

m
### Stack:

[i32] → [i32]

load 2 bytes and zero-extend i16 to i32

m
### Stack:

[i32] → [i64]

load 1 byte and sign-extend i8 to i64

m
### Stack:

[i32] → [i64]

load 1 byte and zero-extend i8 to i64

m
### Stack:

[i32] → [i64]

load 2 bytes and sign-extend i16 to i64

m
### Stack:

[i32] → [i64]

load 2 bytes and zero-extend i16 to i64

m
### Stack:

[i32] → [i64]

load 4 bytes and sign-extend i16 to i64

m
### Stack:

[i32] → [i64]

load 4 bytes and zero-extend i16 to i64

m
### Stack:

[i32 i32] → []

store 4 bytes (no conversion)

m
### Stack:

[i32 i64] → []

store 8 bytes (no conversion)

m
### Stack:

[i32 f32] → []

store 4 bytes (no conversion)

m
### Stack:

[i32 f64] → []

store 8 bytes (no conversion)

m
### Stack:

[i32 i32] → []

wrap i32 to i8 and store 1 byte

m
### Stack:

[i32 i32] → []

wrap i32 to i16 and store 2 bytes

m
### Stack:

[i32 i64] → []

wrap i64 to i8 and store 1 byte

m
### Stack:

[i32 i64] → []

wrap i64 to i16 and store 2 bytes

m
### Stack:

[i32 i64] → []

wrap i64 to i32 and store 4 bytes

The **memory.size** instruction returns the current size of a memory.

Operates in units of page size. Each page is 65,536 bytes (64KB).

The memory.grow instruction grows memory by a given delta and returns the previous size, or −1 if enough memory cannot be allocated.

Operates in units of page size. Each page is 65,536 bytes (64KB).

n
### Followed by:

*n* : i32
### Stack:

[] → [i32]

Push a 32-bit integer value to the stack.

n
### Followed by:

*n* : i64
### Stack:

[] → [i64]

Push a 64-bit integer value to the stack.

z
### Followed by:

*z* : f32
### Stack:

[] → [f32]

Push a 32-bit float value to the stack.

Push a 64-bit float value to the stack.

zcompare equal to zero.

Return 1 if operand is zero, 0 otherwise.

compare equal to zero.

Return 1 if operand is zero, 0 otherwise.

==

sign-agnostic compare equal

==

sign-agnostic compare equal

≠

sign-agnostic compare unequal

≠

sign-agnostic compare unequal

<

signed less than

<

signed less than

<

unsigned less than

<

unsigned less than

>

signed greater than

>

signed greater than

>

unsigned greater than

>

unsigned greater than

≤

signed less than or equal

≤

signed less than or equal

≤

unsigned less than or equal

≤

unsigned less than or equal

≥

signed greater than or equal

≥

signed greater than or equal

≥

unsigned greater than or equal

≥

unsigned greater than or equal

==

compare equal

==

compare equal

≠

compare unordered or unequal

≠

compare unordered or unequal

<

less than

<

less than

>

greater than

>

greater than

≤

less than or equal

≤

less than or equal

≥

greater than or equal

≥

greater than or equal

sign-agnostic count leading zero bits

Return the count of leading zero bits in i. All zero bits are considered leading if the value is zero.

sign-agnostic count leading zero bits

Return the count of leading zero bits in i. All zero bits are considered leading if the value is zero.

sign-agnostic count trailing zero bits

Return the count of trailing zero bits in i. All zero bits are considered trailing if the value is zero.

sign-agnostic count trailing zero bits

Return the count of trailing zero bits in i. All zero bits are considered trailing if the value is zero.

sign-agnostic count number of one bits

Return the count of non-zero bits in i.

sign-agnostic count number of one bits

Return the count of non-zero bits in i.

sign-agnostic addition

sign-agnostic addition

sign-agnostic subtraction

sign-agnostic subtraction

sign-agnostic multiplication, modulo 2^{32}

sign-agnostic multiplication, modulo 2^{64}

signed division (result is truncated toward zero)

signed division (result is truncated toward zero)

unsigned division (result is floored)

unsigned division (result is floored)

signed remainder (result has the sign of the dividend)

signed remainder (result has the sign of the dividend)

unsigned remainder

unsigned remainder

sign-agnostic bitwise *and*.

Return the bitwise conjunction of 𝑖1 and 𝑖2.

sign-agnostic bitwise *and*.

Return the bitwise conjunction of 𝑖1 and 𝑖2.

sign-agnostic bitwise *inclusive or*.

Return the bitwise disjunction of 𝑖1 and 𝑖2.

sign-agnostic bitwise *inclusive or*.

Return the bitwise disjunction of 𝑖1 and 𝑖2.

sign-agnostic bitwise *exclusive or*.

Return the bitwise exclusive disjunction of 𝑖1 and 𝑖2.

sign-agnostic bitwise *exclusive or*.

Return the bitwise exclusive disjunction of 𝑖1 and 𝑖2.

sign-agnostic shift left

Return the result of shifting i1 left by k bits, modulo 2^{32}

sign-agnostic shift left

Return the result of shifting i1 left by k bits, modulo 2^{64}

sign-replicating (arithmetic) shift right

Return the result of shifting i1 right by k bits, extended with the most significant bit of the original value.

sign-replicating (arithmetic) shift right

Return the result of shifting i1 right by k bits, extended with the most significant bit of the original value.

zero-replicating (logical) shift right

Return the result of shifting i1 right by k bits, extended with 0 bits.

zero-replicating (logical) shift right

Return the result of shifting i1 right by k bits, extended with 0 bits.

sign-agnostic rotate left

Return the result of rotating i1 left by k bits.

sign-agnostic rotate left

Return the result of rotating i1 left by k bits.

sign-agnostic rotate right

Return the result of rotating i1 right by k bits.

sign-agnostic rotate right

Return the result of rotating i1 right by k bits.

absolute value

absolute value

negation

negation

ceiling operator

ceiling operator

floor operator

floor operator

round to nearest integer towards zero

round to nearest integer towards zero

round to nearest integer, ties to even

round to nearest integer, ties to even

square root

square root

addition

addition

subtraction

subtraction

multiplication

multiplication

division

partial function: division by 0 is undefined

division

partial function: division by 0 is undefined

minimum (binary operator); if either operand is NaN, returns NaN

minimum (binary operator); if either operand is NaN, returns NaN

maximum (binary operator); if either operand is NaN, returns NaN

maximum (binary operator); if either operand is NaN, returns NaN

If z1 and z2 have the same sign, then return z1. Else return z1 with negated sign.

If z1 and z2 have the same sign, then return z1. Else return z1 with negated sign.

wrap a 64-bit integer to a 32-bit integer.

Return i modulo 2^{32}.

truncate a 32-bit float to a signed 32-bit integer

truncate a 32-bit float to an unsigned 32-bit integer

truncate a 64-bit float to a signed 32-bit integer

truncate a 64-bit float to an unsigned 32-bit integer

extend a signed 32-bit integer to a 64-bit integer.

extend an unsigned 32-bit integer to a 64-bit integer.

truncate a 32-bit float to a signed 64-bit integer.

truncate a 32-bit float to an unsigned 64-bit integer.

truncate a 64-bit float to a signed 64-bit integer.

truncate a 64-bit float to an unsigned 64-bit integer.

convert a signed 32-bit integer to a 32-bit float.

convert an unsigned 32-bit integer to a 32-bit float.

convert a signed 64-bit integer to a 32-bit float.

convert an unsigned 64-bit integer to a 32-bit float.

demote a 64-bit float to a 32-bit float

convert a signed 32-bit integer to a 64-bit float.

convert an unsigned 32-bit integer to a 64-bit float.

convert a signed 64-bit integer to a 64-bit float.

convert an unsigned 64-bit integer to a 64-bit float.

promote a 32-bit float to a 64-bit float

reinterpret the bits of a 32-bit float as a 32-bit integer

reinterpret the bits of a 64-bit float as a 64-bit integer

reinterpret the bits of a 32-bit integer as a 32-bit float

reinterpret the bits of a 64-bit integer as a 64-bit float

- WebAssembly Specifications
- WebAssembly (MDN web docs; developer.mozilla.org)
- Introduction to WebAssembly (Rasmus Andersson; rsms.me)