ContentsInstruction reference

Instruction reference

On this page
  1. Control
  2. Parametric and variables
  3. Memory
  4. Constants, tests and comparisons
  5. Arithmetic and bits
  6. Conversions
  7. Wide arithmetic
  8. Traps

These are the 115 instructions a program may use, ordered by opcode byte (where they come from). Most behave as a programmer expects; the tables spell out the cases where implementations tend to differ, such as division traps, shift counts, address bounds and sign extension. The exact rules are in section 19 of the protocol rules.

"Stack" shows what an instruction pops and pushes, bottom to top, with [t] for a value that depends on the label or function. Every instruction except else and end pays its price from the price list before it executes (exact metering). No other opcode is accepted (what is rejected).

Control#

Byte Instruction Immediates Stack Meaning
00 unreachable Traps.
01 nop Does nothing.
02 block block type Opens a region; a branch to it continues after its end.
03 loop block type Opens a region; a branch to it continues at its first instruction.
04 if block type i32 → Opens a region and runs the then-branch for a non-zero condition, otherwise the else-branch or nothing.
05 else Separates the branches of an if; free.
0b end Closes a region, or the function; free.
0c br depth [t] → Branches to the depth-th enclosing label, carrying its value if it has one.
0d br_if depth [t] i32 → [t] Branches when the condition is non-zero; otherwise leaves the value in place.
0e br_table depths, default [t] i32 → Branches to the label at the unsigned index, or to the default when the index is out of range.
0f return [t] → Leaves the function with its result, if any.
10 call function params → [result] Calls a function; calling a host import runs that host function.
11 call_indirect type, 00 params i32 → [result] Calls the entry of table 0 at the unsigned index; traps on an index outside the table, a null entry, or an entry whose type differs structurally (in its parameter and result types, not its type index) from the expected type. Otherwise exactly like call.

Parametric and variables#

Byte Instruction Immediates Stack Meaning
1a drop t → Discards a value.
1b select t t i32 → t Keeps the first value when the condition is non-zero, the second otherwise; all three are evaluated.
20 local.get local → t Reads a parameter or local.
21 local.set local t → Writes a parameter or local.
22 local.tee local t → t Writes and keeps the value.
23 global.get global → t Reads a global.
24 global.set global t → Writes a mutable global.

Memory#

Memory is a byte array of 64 KiB pages. Each access computes its effective address as the unsigned 32-bit address plus the unsigned 32-bit offset, in unbounded arithmetic, and traps when the address plus the access width exceeds the current memory size: an address never wraps around into valid memory, and a store that traps writes nothing. Bytes are little-endian. Narrow signed loads sign-extend, narrow unsigned loads zero-extend, and narrow stores keep the low bytes. Alignment immediates are hints and never change behavior.

Byte Instruction Stack Meaning
28 i32.load i32 → i32 4 bytes.
29 i64.load i32 → i64 8 bytes.
2c i32.load8_s i32 → i32 1 byte, sign-extended.
2d i32.load8_u i32 → i32 1 byte, zero-extended.
2e i32.load16_s i32 → i32 2 bytes, sign-extended.
2f i32.load16_u i32 → i32 2 bytes, zero-extended.
30 i64.load8_s i32 → i64 1 byte, sign-extended.
31 i64.load8_u i32 → i64 1 byte, zero-extended.
32 i64.load16_s i32 → i64 2 bytes, sign-extended.
33 i64.load16_u i32 → i64 2 bytes, zero-extended.
34 i64.load32_s i32 → i64 4 bytes, sign-extended.
35 i64.load32_u i32 → i64 4 bytes, zero-extended.
36 i32.store i32 i32 → 4 bytes.
37 i64.store i32 i64 → 8 bytes.
3a i32.store8 i32 i32 → The low byte.
3b i32.store16 i32 i32 → The low 2 bytes.
3c i64.store8 i32 i64 → The low byte.
3d i64.store16 i32 i64 → The low 2 bytes.
3e i64.store32 i32 i64 → The low 4 bytes.
3f memory.size → i32 The current size in pages.
40 memory.grow i32 → i32 Appends that many zeroed pages and yields the previous size, or yields −1 with no effect when the new size would exceed the declared maximum. Growth by zero pages succeeds and yields the current size. Each new page costs 40,000 C; running out of compute there fails the invocation rather than yielding −1.
fc 0a memory.copy i32 i32 i32 → Destination, source, length n: moves n bytes as if the source were first copied aside, so overlapping ranges move correctly. After its price it pays bytes(n, 2) for the bytes, nothing when n is 0, then traps before writing anything if any part of either range lies outside memory.
fc 0b memory.fill i32 i32 i32 → Destination, value, length n: writes the low byte of the value n times. After its price it pays bytes(n, 1) for the bytes, nothing when n is 0, then traps before writing anything if the range lies outside memory.

bytes(n, s) is the price of moving n bytes in s spans (memory prices). A zero-length copy or fill whose addresses are at or below the end of memory is in bounds.

Constants, tests and comparisons#

Byte Instruction Immediates Stack
41 i32.const signed LEB128 → i32
42 i64.const signed LEB128 → i64
45 i32.eqz i32 → i32
46–4f i32.eq, ne, lt_s, lt_u, gt_s, gt_u, le_s, le_u, ge_s, ge_u i32 i32 → i32
50 i64.eqz i64 → i32
51–5a i64.eq, ne, lt_s, lt_u, gt_s, gt_u, le_s, le_u, ge_s, ge_u i64 i64 → i32

Results are 1 or 0. _s compares two's-complement signed values, _u unsigned. eqz tests for zero.

Arithmetic and bits#

i32 i64 Instruction Meaning
67 79 clz Leading zero bits; the width for zero.
68 7a ctz Trailing zero bits; the width for zero.
69 7b popcnt Set bits.
6a 7c add Wrapping.
6b 7d sub Wrapping.
6c 7e mul Wrapping, the low bits of the product.
6d 7f div_s Signed, truncating toward zero; traps on a zero divisor and on the minimum value divided by −1.
6e 80 div_u Unsigned; traps on a zero divisor.
6f 81 rem_s Signed remainder with the dividend's sign; traps on a zero divisor; the minimum value by −1 is 0.
70 82 rem_u Unsigned; traps on a zero divisor.
71 83 and Bitwise.
72 84 or Bitwise.
73 85 xor Bitwise.
74 86 shl Shift left by the count modulo the width.
75 87 shr_s Arithmetic shift right by the count modulo the width.
76 88 shr_u Logical shift right by the count modulo the width.
77 89 rotl Rotate left by the count modulo the width.
78 8a rotr Rotate right by the count modulo the width.

Bit counts have stack t → t, and every other operation here t t → t, with t the instruction's width. Binary operators take the left operand first: a b sub is a − b, and the shift or rotation count is the second operand. Shifts and rotations use only the low 5 bits of the count for i32 and the low 6 bits for i64. Unsigned division and remainder are the ordinary unsigned operations.

Conversions#

Byte Instruction Stack Meaning
a7 i32.wrap_i64 i64 → i32 The low 32 bits.
ac i64.extend_i32_s i32 → i64 Sign-extended.
ad i64.extend_i32_u i32 → i64 Zero-extended.
c0 i32.extend8_s i32 → i32 The low 8 bits, sign-extended.
c1 i32.extend16_s i32 → i32 The low 16 bits, sign-extended.
c2 i64.extend8_s i64 → i64 The low 8 bits, sign-extended.
c3 i64.extend16_s i64 → i64 The low 16 bits, sign-extended.
c4 i64.extend32_s i64 → i64 The low 32 bits, sign-extended.

Wide arithmetic#

Four instructions compute with 128-bit integers held as two i64 values, the low half below the high half on the stack. They are the four instructions of the WebAssembly wide-arithmetic proposal, with its opcodes and meaning.

Bytes Instruction Stack Meaning
fc 13 i64.add128 i64 i64 i64 i64 → i64 i64 Left low, left high, right low, right high: the low and high halves of the sum modulo 2^128.
fc 14 i64.sub128 i64 i64 i64 i64 → i64 i64 The same operands: the halves of left minus right modulo 2^128.
fc 15 i64.mul_wide_s i64 i64 → i64 i64 The low and high halves of the full 128-bit product of two signed values.
fc 16 i64.mul_wide_u i64 i64 → i64 i64 The same for two unsigned values.

None of them traps. Each pushes two values, so it counts twice toward a function's maximum operand height.

Traps#

A trap ends the invocation with status 2 and no result, after the instruction has paid its price and any byte charge it made. Every node traps at the same instruction. The causes are:

  • unreachable;
  • a zero divisor;
  • the signed-division overflow;
  • an out-of-bounds memory access;
  • a bulk operation out of bounds;
  • a bad indirect call.

The host functions add their own causes (failures). All traps are the same status; nothing distinguishes them in a receipt.