Appendix A: Instruction Reference
This appendix lists the instructions with their opcodes and their types.
It covers every instruction in the core of WebAssembly 3.0 except the
SIMD and atomic instructions, of which it shows a representative
selection; the full lists are in the specification and the threads
proposal.
The opcodes were not typed in by hand. scripts/opcodes.py assembles
each instruction with the wat crate and reads its opcode back out of the
binary, so the table agrees with the assembler. Prefixed opcodes show the
prefix byte and the second opcode as it is encoded, in LEB128, so
fd 85 02 is prefix fd followed by opcode 261.
Types are written as in the specification: what the instruction pops on
the left, what it pushes on the right, with t standing for any value
type and t* for any sequence of them. Instructions that end control
flow, such as br and unreachable, have types with arbitrary t1*
and t2*, since the stack after them is polymorphic (Chapter 6). The
immediates column lists what follows the opcode in the binary, in order;
a memarg is an alignment exponent and an offset (Chapter 13), and the
memory instructions without a memarg take a memory index, which is 00
for memory 0.
#ControlA.1
| Instruction |
Opcode |
Type |
Immediates and notes |
unreachable |
00 |
[t*] → [t*] |
trap |
nop |
01 |
[] → [] |
|
block bt |
02 |
[t1*] → [t2*] |
block type; ends with end |
loop bt |
03 |
[t1*] → [t2*] |
block type |
if bt |
04 |
[t1* i32] → [t2*] |
block type |
else |
05 |
|
between the arms of an if |
end |
0b |
|
ends a block, loop, if, try_table or function |
br l |
0c |
[t* t1*] → [t2*] |
label depth |
br_if l |
0d |
[t* i32] → [t*] |
label depth |
br_table l* l |
0e |
[t1* t* i32] → [t2*] |
vector of depths, then default |
return |
0f |
[t1* t*] → [t2*] |
|
call f |
10 |
[t1*] → [t2*] |
function index |
call_indirect t |
11 |
[t1* i32] → [t2*] |
type index, table index |
return_call f |
12 |
[t1*] → [t2*] |
tail call |
return_call_indirect t |
13 |
[t1* i32] → [t2*] |
tail call |
call_ref t |
14 |
[t1* (ref null $t)] → [t2*] |
type index |
return_call_ref t |
15 |
[t1* (ref null $t)] → [t2*] |
type index |
throw x |
08 |
[t1* t*] → [t2*] |
tag index |
throw_ref |
0a |
[t1* exnref] → [t2*] |
|
try_table bt c* |
1f |
[t1*] → [t2*] |
block type, vector of catch clauses |
#Parametric and variablesA.2
| Instruction |
Opcode |
Type |
Immediates and notes |
drop |
1a |
[t] → [] |
|
select |
1b |
[t t i32] → [t] |
numeric or vector operands |
select t |
1c |
[t t i32] → [t] |
typed form: vector of value types |
local.get x |
20 |
[] → [t] |
local index |
local.set x |
21 |
[t] → [] |
local index |
local.tee x |
22 |
[t] → [t] |
local index |
global.get x |
23 |
[] → [t] |
global index |
global.set x |
24 |
[t] → [] |
global index |
#TablesA.3
| Instruction |
Opcode |
Type |
Immediates and notes |
table.get x |
25 |
[i32] → [ref] |
table index |
table.set x |
26 |
[i32 ref] → [] |
table index |
table.init |
fc 0c |
[i32 i32 i32] → [] |
element segment, table |
elem.drop |
fc 0d |
[] → [] |
element segment |
table.copy |
fc 0e |
[i32 i32 i32] → [] |
destination and source tables |
table.grow x |
fc 0f |
[ref i32] → [i32] |
table index |
table.size x |
fc 10 |
[] → [i32] |
table index |
table.fill x |
fc 11 |
[i32 ref i32] → [] |
table index |
#MemoryA.4
| Instruction |
Opcode |
Type |
Immediates and notes |
i32.load |
28 |
[i32] → [i32] |
memarg |
i64.load |
29 |
[i32] → [i64] |
memarg |
f32.load |
2a |
[i32] → [f32] |
memarg |
f64.load |
2b |
[i32] → [f64] |
memarg |
i32.load8_s |
2c |
[i32] → [i32] |
memarg |
i32.load8_u |
2d |
[i32] → [i32] |
memarg |
i32.load16_s |
2e |
[i32] → [i32] |
memarg |
i32.load16_u |
2f |
[i32] → [i32] |
memarg |
i64.load8_s |
30 |
[i32] → [i64] |
memarg |
i64.load8_u |
31 |
[i32] → [i64] |
memarg |
i64.load16_s |
32 |
[i32] → [i64] |
memarg |
i64.load16_u |
33 |
[i32] → [i64] |
memarg |
i64.load32_s |
34 |
[i32] → [i64] |
memarg |
i64.load32_u |
35 |
[i32] → [i64] |
memarg |
i32.store |
36 |
[i32 i32] → [] |
memarg |
i64.store |
37 |
[i32 i64] → [] |
memarg |
f32.store |
38 |
[i32 f32] → [] |
memarg |
f64.store |
39 |
[i32 f64] → [] |
memarg |
i32.store8 |
3a |
[i32 i32] → [] |
memarg |
i32.store16 |
3b |
[i32 i32] → [] |
memarg |
i64.store8 |
3c |
[i32 i64] → [] |
memarg |
i64.store16 |
3d |
[i32 i64] → [] |
memarg |
i64.store32 |
3e |
[i32 i64] → [] |
memarg |
memory.size |
3f |
[] → [i32] |
memory index |
memory.grow |
40 |
[i32] → [i32] |
memory index |
memory.init |
fc 08 |
[i32 i32 i32] → [] |
data segment, memory |
data.drop |
fc 09 |
[] → [] |
data segment |
memory.copy |
fc 0a |
[i32 i32 i32] → [] |
destination and source memories |
memory.fill |
fc 0b |
[i32 i32 i32] → [] |
memory index |
#ConstantsA.5
| Instruction |
Opcode |
Type |
Immediates and notes |
i32.const |
41 |
[] → [i32] |
signed LEB128 |
i64.const |
42 |
[] → [i64] |
signed LEB128 |
f32.const |
43 |
[] → [f32] |
4 bytes |
f64.const |
44 |
[] → [f64] |
8 bytes |
#i32 operationsA.6
| Instruction |
Opcode |
Type |
Immediates and notes |
i32.eqz |
45 |
[i32] → [i32] |
|
i32.eq |
46 |
[i32 i32] → [i32] |
|
i32.ne |
47 |
[i32 i32] → [i32] |
|
i32.lt_s |
48 |
[i32 i32] → [i32] |
|
i32.lt_u |
49 |
[i32 i32] → [i32] |
|
i32.gt_s |
4a |
[i32 i32] → [i32] |
|
i32.gt_u |
4b |
[i32 i32] → [i32] |
|
i32.le_s |
4c |
[i32 i32] → [i32] |
|
i32.le_u |
4d |
[i32 i32] → [i32] |
|
i32.ge_s |
4e |
[i32 i32] → [i32] |
|
i32.ge_u |
4f |
[i32 i32] → [i32] |
|
i32.clz |
67 |
[i32] → [i32] |
|
i32.ctz |
68 |
[i32] → [i32] |
|
i32.popcnt |
69 |
[i32] → [i32] |
|
i32.add |
6a |
[i32 i32] → [i32] |
|
i32.sub |
6b |
[i32 i32] → [i32] |
|
i32.mul |
6c |
[i32 i32] → [i32] |
|
i32.div_s |
6d |
[i32 i32] → [i32] |
traps on zero |
i32.div_u |
6e |
[i32 i32] → [i32] |
traps on zero |
i32.rem_s |
6f |
[i32 i32] → [i32] |
traps on zero |
i32.rem_u |
70 |
[i32 i32] → [i32] |
traps on zero |
i32.and |
71 |
[i32 i32] → [i32] |
|
i32.or |
72 |
[i32 i32] → [i32] |
|
i32.xor |
73 |
[i32 i32] → [i32] |
|
i32.shl |
74 |
[i32 i32] → [i32] |
|
i32.shr_s |
75 |
[i32 i32] → [i32] |
|
i32.shr_u |
76 |
[i32 i32] → [i32] |
|
i32.rotl |
77 |
[i32 i32] → [i32] |
|
i32.rotr |
78 |
[i32 i32] → [i32] |
|
#i64 operationsA.7
| Instruction |
Opcode |
Type |
Immediates and notes |
i64.eqz |
50 |
[i64] → [i32] |
|
i64.eq |
51 |
[i64 i64] → [i32] |
|
i64.ne |
52 |
[i64 i64] → [i32] |
|
i64.lt_s |
53 |
[i64 i64] → [i32] |
|
i64.lt_u |
54 |
[i64 i64] → [i32] |
|
i64.gt_s |
55 |
[i64 i64] → [i32] |
|
i64.gt_u |
56 |
[i64 i64] → [i32] |
|
i64.le_s |
57 |
[i64 i64] → [i32] |
|
i64.le_u |
58 |
[i64 i64] → [i32] |
|
i64.ge_s |
59 |
[i64 i64] → [i32] |
|
i64.ge_u |
5a |
[i64 i64] → [i32] |
|
i64.clz |
79 |
[i64] → [i64] |
|
i64.ctz |
7a |
[i64] → [i64] |
|
i64.popcnt |
7b |
[i64] → [i64] |
|
i64.add |
7c |
[i64 i64] → [i64] |
|
i64.sub |
7d |
[i64 i64] → [i64] |
|
i64.mul |
7e |
[i64 i64] → [i64] |
|
i64.div_s |
7f |
[i64 i64] → [i64] |
traps on zero |
i64.div_u |
80 |
[i64 i64] → [i64] |
traps on zero |
i64.rem_s |
81 |
[i64 i64] → [i64] |
traps on zero |
i64.rem_u |
82 |
[i64 i64] → [i64] |
traps on zero |
i64.and |
83 |
[i64 i64] → [i64] |
|
i64.or |
84 |
[i64 i64] → [i64] |
|
i64.xor |
85 |
[i64 i64] → [i64] |
|
i64.shl |
86 |
[i64 i64] → [i64] |
|
i64.shr_s |
87 |
[i64 i64] → [i64] |
|
i64.shr_u |
88 |
[i64 i64] → [i64] |
|
i64.rotl |
89 |
[i64 i64] → [i64] |
|
i64.rotr |
8a |
[i64 i64] → [i64] |
|
#f32 operationsA.8
| Instruction |
Opcode |
Type |
Immediates and notes |
f32.eq |
5b |
[f32 f32] → [i32] |
|
f32.ne |
5c |
[f32 f32] → [i32] |
|
f32.lt |
5d |
[f32 f32] → [i32] |
|
f32.gt |
5e |
[f32 f32] → [i32] |
|
f32.le |
5f |
[f32 f32] → [i32] |
|
f32.ge |
60 |
[f32 f32] → [i32] |
|
f32.abs |
8b |
[f32] → [f32] |
|
f32.neg |
8c |
[f32] → [f32] |
|
f32.ceil |
8d |
[f32] → [f32] |
|
f32.floor |
8e |
[f32] → [f32] |
|
f32.trunc |
8f |
[f32] → [f32] |
|
f32.nearest |
90 |
[f32] → [f32] |
|
f32.sqrt |
91 |
[f32] → [f32] |
|
f32.add |
92 |
[f32 f32] → [f32] |
|
f32.sub |
93 |
[f32 f32] → [f32] |
|
f32.mul |
94 |
[f32 f32] → [f32] |
|
f32.div |
95 |
[f32 f32] → [f32] |
|
f32.min |
96 |
[f32 f32] → [f32] |
|
f32.max |
97 |
[f32 f32] → [f32] |
|
f32.copysign |
98 |
[f32 f32] → [f32] |
|
#f64 operationsA.9
| Instruction |
Opcode |
Type |
Immediates and notes |
f64.eq |
61 |
[f64 f64] → [i32] |
|
f64.ne |
62 |
[f64 f64] → [i32] |
|
f64.lt |
63 |
[f64 f64] → [i32] |
|
f64.gt |
64 |
[f64 f64] → [i32] |
|
f64.le |
65 |
[f64 f64] → [i32] |
|
f64.ge |
66 |
[f64 f64] → [i32] |
|
f64.abs |
99 |
[f64] → [f64] |
|
f64.neg |
9a |
[f64] → [f64] |
|
f64.ceil |
9b |
[f64] → [f64] |
|
f64.floor |
9c |
[f64] → [f64] |
|
f64.trunc |
9d |
[f64] → [f64] |
|
f64.nearest |
9e |
[f64] → [f64] |
|
f64.sqrt |
9f |
[f64] → [f64] |
|
f64.add |
a0 |
[f64 f64] → [f64] |
|
f64.sub |
a1 |
[f64 f64] → [f64] |
|
f64.mul |
a2 |
[f64 f64] → [f64] |
|
f64.div |
a3 |
[f64 f64] → [f64] |
|
f64.min |
a4 |
[f64 f64] → [f64] |
|
f64.max |
a5 |
[f64 f64] → [f64] |
|
f64.copysign |
a6 |
[f64 f64] → [f64] |
|
#ConversionsA.10
| Instruction |
Opcode |
Type |
Immediates and notes |
i32.wrap_i64 |
a7 |
[i64] → [i32] |
|
i32.trunc_f32_s |
a8 |
[f32] → [i32] |
traps if out of range or NaN |
i32.trunc_f32_u |
a9 |
[f32] → [i32] |
traps if out of range or NaN |
i32.trunc_f64_s |
aa |
[f64] → [i32] |
traps if out of range or NaN |
i32.trunc_f64_u |
ab |
[f64] → [i32] |
traps if out of range or NaN |
i64.extend_i32_s |
ac |
[i32] → [i64] |
|
i64.extend_i32_u |
ad |
[i32] → [i64] |
|
i64.trunc_f32_s |
ae |
[f32] → [i64] |
traps if out of range or NaN |
i64.trunc_f32_u |
af |
[f32] → [i64] |
traps if out of range or NaN |
i64.trunc_f64_s |
b0 |
[f64] → [i64] |
traps if out of range or NaN |
i64.trunc_f64_u |
b1 |
[f64] → [i64] |
traps if out of range or NaN |
f32.convert_i32_s |
b2 |
[i32] → [f32] |
|
f32.convert_i32_u |
b3 |
[i32] → [f32] |
|
f32.convert_i64_s |
b4 |
[i64] → [f32] |
|
f32.convert_i64_u |
b5 |
[i64] → [f32] |
|
f32.demote_f64 |
b6 |
[f64] → [f32] |
|
f64.convert_i32_s |
b7 |
[i32] → [f64] |
|
f64.convert_i32_u |
b8 |
[i32] → [f64] |
|
f64.convert_i64_s |
b9 |
[i64] → [f64] |
|
f64.convert_i64_u |
ba |
[i64] → [f64] |
|
f64.promote_f32 |
bb |
[f32] → [f64] |
|
i32.reinterpret_f32 |
bc |
[f32] → [i32] |
|
i64.reinterpret_f64 |
bd |
[f64] → [i64] |
|
f32.reinterpret_i32 |
be |
[i32] → [f32] |
|
f64.reinterpret_i64 |
bf |
[i64] → [f64] |
|
i32.extend8_s |
c0 |
[i32] → [i32] |
|
i32.extend16_s |
c1 |
[i32] → [i32] |
|
i64.extend8_s |
c2 |
[i64] → [i64] |
|
i64.extend16_s |
c3 |
[i64] → [i64] |
|
i64.extend32_s |
c4 |
[i64] → [i64] |
|
i32.trunc_sat_f32_s |
fc 00 |
[f32] → [i32] |
saturates |
i32.trunc_sat_f32_u |
fc 01 |
[f32] → [i32] |
saturates |
i32.trunc_sat_f64_s |
fc 02 |
[f64] → [i32] |
saturates |
i32.trunc_sat_f64_u |
fc 03 |
[f64] → [i32] |
saturates |
i64.trunc_sat_f32_s |
fc 04 |
[f32] → [i64] |
saturates |
i64.trunc_sat_f32_u |
fc 05 |
[f32] → [i64] |
saturates |
i64.trunc_sat_f64_s |
fc 06 |
[f64] → [i64] |
saturates |
i64.trunc_sat_f64_u |
fc 07 |
[f64] → [i64] |
saturates |
#ReferencesA.11
| Instruction |
Opcode |
Type |
Immediates and notes |
ref.null ht |
d0 |
[] → [(ref null ht)] |
heap type |
ref.is_null |
d1 |
[ref] → [i32] |
|
ref.func f |
d2 |
[] → [(ref $t)] |
function index |
ref.eq |
d3 |
[eqref eqref] → [i32] |
|
ref.as_non_null |
d4 |
[(ref null ht)] → [(ref ht)] |
traps on null |
br_on_null l |
d5 |
[t* (ref null ht)] → [t* (ref ht)] |
label depth |
br_on_non_null l |
d6 |
[t* (ref null ht)] → [t*] |
label depth |
#Garbage collectionA.12
| Instruction |
Opcode |
Type |
Immediates and notes |
struct.new s |
fb 00 |
[t*] → [(ref $s)] |
type |
struct.new_default s |
fb 01 |
[] → [(ref $s)] |
type |
struct.get s i |
fb 02 |
[(ref null $s)] → [t] |
type, field |
struct.get_s s i |
fb 03 |
[(ref null $s)] → [i32] |
packed field |
struct.get_u s i |
fb 04 |
[(ref null $s)] → [i32] |
packed field |
struct.set s i |
fb 05 |
[(ref null $s) t] → [] |
type, field |
array.new a |
fb 06 |
[t i32] → [(ref $a)] |
type |
array.new_default a |
fb 07 |
[i32] → [(ref $a)] |
type |
array.new_fixed a n |
fb 08 |
[t^n] → [(ref $a)] |
type, count |
array.new_data a d |
fb 09 |
[i32 i32] → [(ref $a)] |
type, data segment |
array.new_elem a e |
fb 0a |
[i32 i32] → [(ref $a)] |
type, element segment |
array.get a |
fb 0b |
[(ref null $a) i32] → [t] |
type |
array.get_s a |
fb 0c |
[(ref null $a) i32] → [i32] |
packed |
array.get_u a |
fb 0d |
[(ref null $a) i32] → [i32] |
packed |
array.set a |
fb 0e |
[(ref null $a) i32 t] → [] |
type |
array.len |
fb 0f |
[(ref null array)] → [i32] |
|
array.fill a |
fb 10 |
[(ref null $a) i32 t i32] → [] |
type |
array.copy a b |
fb 11 |
[(ref null $a) i32 (ref null $b) i32 i32] → [] |
two types |
array.init_data a d |
fb 12 |
[(ref null $a) i32 i32 i32] → [] |
type, data segment |
ref.test rt |
fb 14 |
[ref] → [i32] |
reference type |
ref.cast rt |
fb 16 |
[ref] → [rt] |
traps if the cast fails |
br_on_cast l rt1 rt2 |
fb 18 |
[t* rt1] → [t* rt1'] |
flags, label, two types |
br_on_cast_fail l rt1 rt2 |
fb 19 |
[t* rt1] → [t* rt2] |
flags, label, two types |
any.convert_extern |
fb 1a |
[externref] → [anyref] |
|
extern.convert_any |
fb 1b |
[anyref] → [externref] |
|
ref.i31 |
fb 1c |
[i32] → [(ref i31)] |
|
i31.get_s |
fb 1d |
[i31ref] → [i32] |
|
i31.get_u |
fb 1e |
[i31ref] → [i32] |
|
#SIMD (a selection)A.13
| Instruction |
Opcode |
Type |
Immediates and notes |
v128.load |
fd 00 |
[i32] → [v128] |
memarg |
v128.store |
fd 0b |
[i32 v128] → [] |
memarg |
v128.const |
fd 0c |
[] → [v128] |
16 bytes |
i8x16.shuffle |
fd 0d |
[v128 v128] → [v128] |
16 lane indices |
i8x16.swizzle |
fd 0e |
[v128 v128] → [v128] |
|
i32x4.splat |
fd 11 |
[i32] → [v128] |
|
f32x4.splat |
fd 13 |
[f32] → [v128] |
|
i32x4.extract_lane |
fd 1b |
[v128] → [i32] |
lane index |
f32x4.extract_lane |
fd 1f |
[v128] → [f32] |
lane index |
i32x4.replace_lane |
fd 1c |
[v128 i32] → [v128] |
lane index |
v128.and |
fd 4e |
[v128 v128] → [v128] |
|
v128.bitselect |
fd 52 |
[v128 v128 v128] → [v128] |
|
v128.any_true |
fd 53 |
[v128] → [i32] |
|
i32x4.all_true |
fd a3 01 |
[v128] → [i32] |
|
i32x4.add |
fd ae 01 |
[v128 v128] → [v128] |
|
i32x4.mul |
fd b5 01 |
[v128 v128] → [v128] |
|
f32x4.add |
fd e4 01 |
[v128 v128] → [v128] |
|
f32x4.mul |
fd e6 01 |
[v128 v128] → [v128] |
|
f32x4.div |
fd e7 01 |
[v128 v128] → [v128] |
|
f32x4.sqrt |
fd e3 01 |
[v128] → [v128] |
|
f32x4.lt |
fd 43 |
[v128 v128] → [v128] |
lane masks |
v128.load32_splat |
fd 09 |
[i32] → [v128] |
memarg |
f32x4.relaxed_madd |
fd 85 02 |
[v128 v128 v128] → [v128] |
relaxed |
#Threads (a selection)A.14
| Instruction |
Opcode |
Type |
Immediates and notes |
memory.atomic.notify |
fe 00 |
[i32 i32] → [i32] |
memarg |
memory.atomic.wait32 |
fe 01 |
[i32 i32 i64] → [i32] |
memarg |
atomic.fence |
fe 03 |
[] → [] |
|
i32.atomic.load |
fe 10 |
[i32] → [i32] |
memarg |
i32.atomic.store |
fe 17 |
[i32 i32] → [] |
memarg |
i32.atomic.rmw.add |
fe 1e |
[i32 i32] → [i32] |
memarg |
i32.atomic.rmw.cmpxchg |
fe 48 |
[i32 i32 i32] → [i32] |
memarg |