aboutsummaryrefslogtreecommitdiff
path: root/BinaryEncoding.md
blob: 5b154211fa8384d33dfb79f06ac40e06f1b238fd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
# Binary Encoding

This document describes the [portable](Portability.md) binary encoding of the WebAssembly modules.

The binary encoding is a dense representation of module information that enables 
small files, fast decoding, and reduced memory usage.
See the [rationale document](Rationale.md#why-a-binary-encoding) for more detail.

The encoding is split into three layers:

* **Layer 0** is a simple binary encoding of the bytecode instructions and related data structures.
  The encoding is dense and trivial to interact with, making it suitable for
  scenarios like JIT, instrumentation tools, and debugging.
* **Layer 1** provides structural compression on top of layer 0, exploiting
  specific knowledge about the nature of the syntax tree and its nodes.
  The structural compression introduces more efficient encoding of values, 
  rearranges values within the module, and prunes structurally identical
  tree nodes.
* **Layer 2** Layer 2 applies generic compression algorithms, like [gzip](http://www.gzip.org/) and [Brotli](https://datatracker.ietf.org/doc/draft-alakuijala-brotli/), that are already available in browsers and other tooling.

Most importantly, the layering approach allows development and standardization to
occur incrementally. For example, Layer 1 and Layer 2 encoding techniques can be
experimented with by application-level decompressing to the layer below. As 
compression techniques  stabilize, they can be standardized and moved into native 
implementations.

See
[proposed layer 1 compression](https://github.com/WebAssembly/decompressor-prototype/blob/master/CompressionLayer1.md)
for a proposal for layer 1 structural compression.


# Data types

### `uintN`
An unsigned integer of _N_ bits,
represented in _N_/8 bytes in [little endian](https://en.wikipedia.org/wiki/Endianness#Little-endian) order.
_N_ is either 8, 16, or 32.

### `varuintN`
A [LEB128](https://en.wikipedia.org/wiki/LEB128) variable-length integer, limited to _N_ bits (i.e., the values [0, 2^_N_-1]),
represented by _at most_ ceil(_N_/7) bytes that may contain padding `0x80` bytes.

Note: Currently, the only sizes used are `varuint1`, `varuint7`, and `varuint32`,
where the former two are used for compatibility with potential future extensions.

### `varintN`
A [Signed LEB128](https://en.wikipedia.org/wiki/LEB128#Signed_LEB128) variable-length integer, limited to _N_ bits (i.e., the values [-2^(_N_-1), +2^(_N_-1)-1]),
represented by _at most_ ceil(_N_/7) bytes that may contain padding `0x80` or `0xFF` bytes.

Note: Currently, the only sizes used are `varint32` and `varint64`.

### `value_type`
A single-byte unsigned integer indicating a [value type](Semantics.md#types). These types are encoded as:
* `1` indicating type `i32` 
* `2` indicating type `i64` 
* `3` indicating type `f32` 
* `4` indicating type `f64`

### `inline_signature_type`
A single-byte unsigned integer indicating a signature. These types are encoded as:
* `0` indicating a signature with 0 results.
* `1` indicating a signature with 1 result of type `i32`.
* `2` indicating a signature with 1 result of type `i64`.
* `3` indicating a signature with 1 result of type `f32`.
* `4` indicating a signature with 1 result of type `f64`.

### `external_kind`
A single-byte unsigned integer indicating the kind of definition being imported or defined:
* `0` indicating a `Function` [import](Modules.md#imports) or [definition](Modules.md#function-and-code-sections)
* `1` indicating a `Table` [import](Modules.md#imports) or [definition](Modules.md#table-section)
* `2` indicating a `Memory` [import](Modules.md#imports) or [definition](Modules.md#linear-memory-section)
* `3` indicating a `Global` [import](Modules.md#imports) or [definition](Modules.md#global-section)

### `resizable_limits`
A packed tuple that describes the limits of a
[table](Semantics.md#table) or [memory](Semantics.md#resizing):

| Field | Type | Description |
| ----- |  ----- | ----- |
| flags | `varuint32` | bit `0x1` is set if the maximum field is present |
| initial | `varuint32` | initial length (in units of table elements or wasm pages) |
| maximum | `varuint32`? | only present if specified by `flags` |

The "flags" field may later be extended to include a flag for sharing (between
threads).

### `init_expr`
The encoding of an [initializer expression](Modules.md#initializer-expression)
is the normal encoding of the expression followed by the `end` opcode as a
delimiter.

Note that `get_global` in an initializer expression can only refer to immutable
imported globals and all uses of `init_expr` can only appear after the Imports
section.

# Module structure

The following documents the current prototype format. This format is based on and supersedes the v8-native prototype format, originally in a [public design doc](https://docs.google.com/document/d/1-G11CnMA0My20KI9D7dBR6ZCPOBCRD0oCH6SHCPFGx0/edit?usp=sharing).

## High-level structure

The module starts with a preamble of two fields:

| Field | Type | Description |
| ----- |  ----- | ----- |
| magic number | `uint32` |  Magic number `0x6d736100` (i.e., '\0asm') |
| version | `uint32` | Version number, currently 12. The version for MVP will be reset to 1. |

The module preamble is followed by a sequence of sections.
Each section is identified by a 1-byte *section code* that encodes either a known section or a user-defined section.
The section length and payload data then follow.
Known sections have non-zero ids, while unknown sections have a `0` id followed by an identifying string as
part of the payload.
Unknown sections are ignored by the WebAssembly implementation, and thus validation errors within them do not
invalidate a module.

| Field | Type | Description |
| ----- |  ----- | ----- |
| id | `varuint7` | section code |
| payload_len  | `varuint32` | size of this section in bytes |
| name_len | `varuint32` ? | length of the section name in bytes, present if `id == 0` |
| name | `bytes` ? | section name string, present if `id == 0` |
| payload_data  | `bytes` | content of this section, of length `payload_len - sizeof(name) - sizeof(name_len)` |

Each section is optional and may appear at most once.
Known sections from this list may not appear out of order.
The content of each section is encoded in its `payload_data`.

| Section Name | Code | Description |
| ------------ | ---- | ----------- |
| [Type](#type-section) | `1` | Function signature declarations |
| [Import](#import-section) | `2` | Import declarations |
| [Function](#function-section) | `3` | Function declarations |
| [Table](#table-section) | `4` | Indirect function table and other tables |
| [Memory](#memory-section) | `5` | Memory attributes |
| [Global](#global-section) | `6` | Global declarations |
| [Export](#export-section) | `7` | Exports | 
| [Start](#start-section) | `8` | Start function declaration |
| [Element](#element-section) | `9` | Elements section |
| [Code](#code-section) | `10` | Function bodies (code) |
| [Data](#data-section) | `11` | Data segments |

The end of the last present section must coincide with the last byte of the
module. The shortest valid module is 8 bytes (`magic number`, `version`,
followed by zero sections).

### Type section

The type section declares all function signatures that will be used in the module.

| Field | Type | Description |
| ----- | ---- | ----------- |
| count | `varuint32` | count of type entries to follow |
| entries | `type_entry*` | repeated type entries as described below |

#### Type entry
| Field | Type | Description |
| ----- | ---- | ----------- |
| form | `varuint7` | `0x40`, indicating a function type |
| param_count | `varuint32` | the number of parameters to the function |
| param_types | `value_type*` | the parameter types of the function |
| return_count | `varuint1` | the number of results from the function |
| return_type | `value_type?` | the result type of the function (if return_count is 1) |

(Note: In the future, this section may contain other forms of type entries as well, which can be distinguished by the `form` field.)

### Import section

The import section declares all imports that will be used in the module.

| Field | Type | Description |
| ----- | ---- | ----------- |
| count | `varuint32` | count of import entries to follow |
| entries | `import_entry*` | repeated import entries as described below |

#### Import entry
| Field | Type | Description |
| ----- | ---- | ----------- |
| module_len | `varuint32` | module string length |
| module_str | `bytes` | module string of `module_len` bytes |
| field_len | `varuint32` | field name length |
| field_str | `bytes` | field name string of `field_len` bytes |
| kind | `external_kind` | the kind of definition being imported |

Followed by, if the `kind` is `Function`:

| Field | Type | Description |
| ----- | ---- | ----------- |
| sig_index | `varuint32` | signature index of the import |

or, if the `kind` is `Table`:

| Field | Type | Description |
| ----- | ---- | ----------- |
| element_type | `varuint7` | `0x20`, indicating [`anyfunc`](Semantics.md#table) |
| | `resizable_limits` | see [above](#resizable_limits) |

or, if the `kind` is `Memory`:

| Field | Type | Description |
| ----- | ---- | ----------- |
| | `resizable_limits` | see [above](#resizable_limits) |

or, if the `kind` is `Global`:

| Field | Type | Description |
| ----- | ---- | ----------- |
| type | `value_type` | type of the imported global |
| mutability | `varuint1` | `0` if immutable, `1` if mutable; must be `0` in the MVP |

### Function section

The function section _declares_ the signatures of all functions in the
module (their definitions appear in the [code section](#code-section)).

| Field | Type | Description |
| ----- | ---- | ----------- |
| count | `varuint32` | count of signature indices to follow |
| types | `varuint32*` | sequence of indices into the type section |

### Table section

The encoding of a [Table section](Modules.md#table-section):

| Field | Type | Description |
| ----- |  ----- | ----- |
| count | `varuint32` | indicating the number of tables defined by the module |
| entries | `table_type*` | repeated `table_type` entries as described below |

| Field | Type | Description |
| ----- | ---- | ----------- |
| element_type | `varuint7` | `0x20`, indicating [`anyfunc`](Semantics.md#table) |
| | `resizable_limits` | see [above](#resizable_limits) |

In the MVP, the number of tables must be no more than 1.

### Memory section

ID: `memory`

The encoding of a [Memory section](Modules.md#linear-memory-section):

| Field | Type | Description |
| ----- |  ----- | ----- |
| count | `varuint32` | indicating the number of memories defined by the module |
| entries | `memory_type*` | repeated `memory_type` entries as described below |

| Field | Type | Description |
| ----- | ---- | ----------- |
| | `resizable_limits` | see [above](#resizable_limits) |

Note that the initial/maximum fields are specified in units of 
[WebAssembly pages](Semantics.md#linear-memory).

In the MVP, the number of memories must be no more than 1.

### Global section

The encoding of the [Global section](Modules.md#global-section):

| Field | Type | Description |
| ----- | ---- | ----------- |
| count | `varuint32` | count of global variable entries |
| globals | `global_variable*` | global variables, as described below |

#### Global Entry

Each `global_variable` declares a single global variable of a given type, mutability
and with the given initializer.

| Field | Type | Description |
| ----- | ---- | ----------- |
| type | `value_type` | type of the variables |
| mutability | `varuint1` | `0` if immutable, `1` if mutable |
| init | `init_expr` | the initial value of the global |

Note that, in the MVP, only immutable global variables can be exported.

### Export section

The encoding of the [Export section](Modules.md#exports):

| Field | Type | Description |
| ----- | ---- | ----------- |
| count | `varuint32` | count of export entries to follow |
| entries | `export_entry*` | repeated export entries as described below |

#### Export entry
| Field | Type | Description |
| ----- | ---- | ----------- |
| field_len | `varuint32` | field name string length |
| field_str | `bytes` | field name string of `field_len` bytes |
| kind | `external_kind` | the kind of definition being exported |
| index | `varuint32` | the index into the corresponding [index space](Modules.md) |

For example, if the "kind" is `Function`, then "index" is a 
[function index](Modules.md#function-index-space). Note that, in the MVP, the
only valid index value for a memory or table export is 0.

### Start section

The start section declares the [start function](Modules.md#module-start-function).

| Field | Type | Description |
| ----- | ---- | ----------- |
| index | `varuint32` | start function index |

### Element section

The encoding of the [Elements section](Modules.md#elements-section):

| Field | Type | Description |
| ----- | ---- | ----------- |
| count | `varuint32` | count of element segments to follow |
| entries | `elem_segment*` | repeated element segments as described below |

a `elem_segment` is:

| Field | Type | Description |
| ----- | ---- | ----------- |
| index | `varuint32` | the [table index](Modules.md#table-index-space) (0 in the MVP) |
| offset | `init_expr` | an `i32` initializer expression that computes the offset at which to place the elements |
| num_elem | `varuint32` | number of elements to follow |
| elems | `varuint32*` | sequence of [function indices](Modules.md#function-index-space) |

### Code section

ID: `code`

The code section contains a body for every function in the module.
The count of function declared in the [function section](#function-section)
and function bodies defined in this section must be the same and the `i`th
declaration corresponds to the `i`th function body.

| Field | Type | Description |
| ----- | ---- | ----------- |
| count | `varuint32` | count of function bodies to follow |
| bodies | `function_body*` | sequence of [Function Bodies](#function-bodies) |

### Data section

The data section declares the initialized data that is loaded
into the linear memory.

| Field | Type | Description |
| ----- | ---- | ----------- |
| count | `varuint32` | count of data segments to follow |
| entries | `data_segment*` | repeated data segments as described below |

a `data_segment` is:

| Field | Type | Description |
| ----- | ---- | ----------- |
| index | `varuint32` | the [linear memory index](Modules.md#linear-memory-index-space) (0 in the MVP) |
| offset | `init_expr` | an `i32` initializer expression that computes the offset at which to place the data |
| size | `varuint32` | size of `data` (in bytes) |
| data | `bytes` | sequence of `size` bytes |

### Name section

User-defined section string: `"name"`

The names section does not change execution semantics, and thus is not allocated a section code.
It is encoded as an unknown section (id `0`) followed by the identification string `"name"`.
Like all unknown sections, a validation error in this section does not cause validation of the module to fail.
The expectation is that, when a binary WebAssembly module is viewed in a browser or other development
environment, the names in this section will be used as the names of functions
and locals in the [text format](TextFormat.md).

| Field | Type | Description |
| ----- | ---- | ----------- |
| count | `varuint32` | count of entries to follow |
| entries | `function_names*` | sequence of names |

The sequence of `function_names` assigns names to the corresponding
function index. The count may be greater or less than the actual number of
functions.

#### Function names

| Field | Type | Description |
| ----- | ---- | ----------- |
| fun_name_len | `varuint32` | string length, in bytes |
| fun_name_str | `bytes` | valid utf8 encoding |
| local_count | `varuint32` | count of local names to follow |
| local_names | `local_name*` | sequence of local names |

The sequence of `local_name` assigns names to the corresponding local index. The
count may be greater or less than the actual number of locals.

#### Local name

| Field | Type | Description |
| ----- | ---- | ----------- |
| local_name_len | `varuint32` | string length, in bytes |
| local_name_str | `bytes` | valid utf8 encoding |


# Function Bodies

Function bodies consist of a sequence of local variable declarations followed by 
[bytecode instructions](Semantics.md). Each function body must end with the `end` opcode.

| Field | Type | Description |
| ----- | ---- | ----------- |
| body_size | `varuint32` | size of function body to follow, in bytes |
| local_count | `varuint32` | number of local entries |
| locals | `local_entry*` | local variables |
| code | `byte*` | bytecode of the function |
| end | `byte` | `0x0f`, indicating the end of the body |

#### Local Entry

Each local entry declares a number of local variables of a given type.
It is legal to have several entries with the same type.

| Field | Type | Description |
| ----- | ---- | ----------- |
| count | `varuint32` | number of local variables of the following type |
| type | `value_type` | type of the variables |


## Control flow operators ([described here](Semantics.md#control-flow-structures))

| Name | Opcode | Immediates | Description |
| ---- | ---- | ---- | ---- |
| `unreachable` | `0x00` | | trap immediately |
| `block` | `0x01` | sig : `inline_signature_type` | begin a sequence of expressions, yielding 0 or 1 values |
| `loop` | `0x02` |  sig : `inline_signature_type` | begin a block which can also form control flow loops |
| `if` | `0x03` | sig : `inline_signature_type` | begin if expression |
| `else` | `0x04` | | begin else expression of if |
| `select` | `0x05` | | select one of two values based on condition |
| `br` | `0x06` | relative_depth : `varuint32` | break that targets an outer nested block |
| `br_if` | `0x07` | relative_depth : `varuint32` | conditional break that targets an outer nested block |
| `br_table` | `0x08` | see below | branch table control flow construct |
| `return` | `0x09` | | return zero or one value from this function |
| `drop` | `0x0b` | | ignore value |
| `nop` | `0x0a` | | no operation |
| `end` | `0x0f` | | end a block, loop, or if |

The _sig_ fields of `block` and `if` operators specify function signatures
which describe their use of the operand stack.

The `br_table` operator has an immediate operand which is encoded as follows:

| Field | Type | Description |
| ---- | ---- | ---- |
| target_count | `varuint32` | number of entries in the target_table |
| target_table | `varuint32*` | target entries that indicate an outer block or loop to which to break |
| default_target | `varuint32` | an outer block or loop to which to break in the default case |

The `br_table` operator implements an indirect branch. It accepts an optional value argument
(like other branches) and an additional `i32` expression as input, and 
branches to the block or loop at the given offset within the `target_table`. If the input value is 
out of range, `br_table` branches to the default target.

## Basic operators ([described here](Semantics.md#constants))

| Name | Opcode | Immediates | Description |
| ---- | ---- | ---- | ---- |
| `i32.const` | `0x10` | value : `varint32` | a constant value interpreted as `i32` |
| `i64.const` | `0x11` | value : `varint64` | a constant value interpreted as `i64` |
| `f64.const` | `0x12` | value : `uint64` | a constant value interpreted as `f64` |
| `f32.const` | `0x13` | value : `uint32` | a constant value interpreted as `f32` |
| `get_local` | `0x14` | local_index : `varuint32` | read a local variable or parameter |
| `set_local` | `0x15` | local_index : `varuint32` | write a local variable or parameter |
| `tee_local` | `0x19` | local_index : `varuint32` | write a local variable or parameter and return the same value |
| `get_global` | `0xbb` | global_index : `varuint32` | read a global variable |
| `set_global` | `0xbc` | global_index : `varuint32` | write a global variable |
| `call` | `0x16` | function_index : `varuint32` | call a function by its [index](Modules.md#function-index-space) |
| `call_indirect` | `0x17` | type_index : `varuint32` | call a function indirect with an expected signature |

The `call_indirect` operator takes a list of function arguments and as the last operand the index into the table.

## Memory-related operators ([described here](Semantics.md#linear-memory-accesses))

| Name | Opcode | Immediate | Description |
| ---- | ---- | ---- | ---- |
| `i32.load8_s` | `0x20` | `memory_immediate` | load from memory |
| `i32.load8_u` | `0x21` | `memory_immediate` | load from memory  |
| `i32.load16_s` | `0x22` | `memory_immediate` | load from memory |
| `i32.load16_u` | `0x23` | `memory_immediate` | load from memory |
| `i64.load8_s` | `0x24` | `memory_immediate` | load from memory |
| `i64.load8_u` | `0x25` | `memory_immediate` | load from memory |
| `i64.load16_s` | `0x26` | `memory_immediate` | load from memory |
| `i64.load16_u` | `0x27` | `memory_immediate` | load from memory |
| `i64.load32_s` | `0x28` | `memory_immediate` | load from memory |
| `i64.load32_u` | `0x29` | `memory_immediate` | load from memory |
| `i32.load` | `0x2a` | `memory_immediate` | load from memory |
| `i64.load` | `0x2b` | `memory_immediate` | load from memory |
| `f32.load` | `0x2c` | `memory_immediate` | load from memory |
| `f64.load` | `0x2d` | `memory_immediate` | load from memory |
| `i32.store8` | `0x2e` | `memory_immediate` | store to memory |
| `i32.store16` | `0x2f` | `memory_immediate` | store to memory |
| `i64.store8` | `0x30` | `memory_immediate` | store to memory |
| `i64.store16` | `0x31` | `memory_immediate` | store to memory |
| `i64.store32` | `0x32` | `memory_immediate` | store to memory |
| `i32.store` | `0x33` | `memory_immediate` | store to memory |
| `i64.store` | `0x34` | `memory_immediate` | store to memory |
| `f32.store` | `0x35` | `memory_immediate` | store to memory |
| `f64.store` | `0x36` | `memory_immediate` | store to memory |
| `current_memory` | `0x3b` |  | query the size of memory |
| `grow_memory` | `0x39` |  | grow the size of memory |

The `memory_immediate` type is encoded as follows:

| Name | Type | Description |
| ---- | ---- | ---- |
| flags | `varuint32` | a bitfield which currently contains the alignment in the least significant bits, encoded as `log2(alignment)` |
| offset | `varuint32` | the value of the offset |

As implied by the `log2(alignment)` encoding, the alignment must be a power of 2.
As an additional validation criteria, the alignment must be less or equal to 
natural alignment. The bits after the
`log(memory-access-size)` least-significant bits must be set to 0. These bits are reserved for future use
(e.g., for shared memory ordering requirements).

## Simple operators ([described here](Semantics.md#32-bit-integer-operators))

| Name | Opcode | Immediate | Description |
| ---- | ---- | ---- | ---- |
| `i32.add` | `0x40` | | |
| `i32.sub` | `0x41` | | |
| `i32.mul` | `0x42` | | |
| `i32.div_s` | `0x43` | | |
| `i32.div_u` | `0x44` | | |
| `i32.rem_s` | `0x45` | | |
| `i32.rem_u` | `0x46` | | |
| `i32.and` | `0x47` | | |
| `i32.or` | `0x48` | | |
| `i32.xor` | `0x49` | | |
| `i32.shl` | `0x4a` | | |
| `i32.shr_u` | `0x4b` | | |
| `i32.shr_s` | `0x4c` | | |
| `i32.rotr` | `0xb6` | | |
| `i32.rotl` | `0xb7` | | |
| `i32.eq` | `0x4d` | | |
| `i32.ne` | `0x4e` | | |
| `i32.lt_s` | `0x4f` | | |
| `i32.le_s` | `0x50` | | |
| `i32.lt_u` | `0x51` | | |
| `i32.le_u` | `0x52` | | |
| `i32.gt_s` | `0x53` | | |
| `i32.ge_s` | `0x54` | | |
| `i32.gt_u` | `0x55` | | |
| `i32.ge_u` | `0x56` | | |
| `i32.clz` | `0x57` | | |
| `i32.ctz` | `0x58` | | |
| `i32.popcnt` | `0x59` | | |
| `i32.eqz`  | `0x5a` | | |
| `i64.add` | `0x5b` | | |
| `i64.sub` | `0x5c` | | |
| `i64.mul` | `0x5d` | | |
| `i64.div_s` | `0x5e` | | |
| `i64.div_u` | `0x5f` | | |
| `i64.rem_s` | `0x60` | | |
| `i64.rem_u` | `0x61` | | |
| `i64.and` | `0x62` | | |
| `i64.or` | `0x63` | | |
| `i64.xor` | `0x64` | | |
| `i64.shl` | `0x65` | | |
| `i64.shr_u` | `0x66` | | |
| `i64.shr_s` | `0x67` | | |
| `i64.rotr` | `0xb8` | | |
| `i64.rotl` | `0xb9` | | |
| `i64.eq` | `0x68` | | |
| `i64.ne` | `0x69` | | |
| `i64.lt_s` | `0x6a` | | |
| `i64.le_s` | `0x6b` | | |
| `i64.lt_u` | `0x6c` | | |
| `i64.le_u` | `0x6d` | | |
| `i64.gt_s` | `0x6e` | | |
| `i64.ge_s` | `0x6f` | | |
| `i64.gt_u` | `0x70` | | |
| `i64.ge_u` | `0x71` | | |
| `i64.clz` | `0x72` | | |
| `i64.ctz` | `0x73` | | |
| `i64.popcnt` | `0x74` | | |
| `i64.eqz`  | `0xba` | | |
| `f32.add` | `0x75` | | |
| `f32.sub` | `0x76` | | |
| `f32.mul` | `0x77` | | |
| `f32.div` | `0x78` | | |
| `f32.min` | `0x79` | | |
| `f32.max` | `0x7a` | | |
| `f32.abs` | `0x7b` | | |
| `f32.neg` | `0x7c` | | |
| `f32.copysign` | `0x7d` | | |
| `f32.ceil` | `0x7e` | | |
| `f32.floor` | `0x7f` | | |
| `f32.trunc` | `0x80` | | |
| `f32.nearest` | `0x81` | | |
| `f32.sqrt` | `0x82` | | |
| `f32.eq` | `0x83` | | |
| `f32.ne` | `0x84` | | |
| `f32.lt` | `0x85` | | |
| `f32.le` | `0x86` | | |
| `f32.gt` | `0x87` | | |
| `f32.ge` | `0x88` | | |
| `f64.add` | `0x89` | | |
| `f64.sub` | `0x8a` | | |
| `f64.mul` | `0x8b` | | |
| `f64.div` | `0x8c` | | |
| `f64.min` | `0x8d` | | |
| `f64.max` | `0x8e` | | |
| `f64.abs` | `0x8f` | | |
| `f64.neg` | `0x90` | | |
| `f64.copysign` | `0x91` | | |
| `f64.ceil` | `0x92` | | |
| `f64.floor` | `0x93` | | |
| `f64.trunc` | `0x94` | | |
| `f64.nearest` | `0x95` | | |
| `f64.sqrt` | `0x96` | | |
| `f64.eq` | `0x97` | | |
| `f64.ne` | `0x98` | | |
| `f64.lt` | `0x99` | | |
| `f64.le` | `0x9a` | | |
| `f64.gt` | `0x9b` | | |
| `f64.ge` | `0x9c` | | |
| `i32.trunc_s/f32` | `0x9d` | | |
| `i32.trunc_s/f64` | `0x9e` | | |
| `i32.trunc_u/f32` | `0x9f` | | |
| `i32.trunc_u/f64` | `0xa0` | | |
| `i32.wrap/i64` | `0xa1` | | |
| `i64.trunc_s/f32` | `0xa2` | | |
| `i64.trunc_s/f64` | `0xa3` | | |
| `i64.trunc_u/f32` | `0xa4` | | |
| `i64.trunc_u/f64` | `0xa5` | | |
| `i64.extend_s/i32` | `0xa6` | | |
| `i64.extend_u/i32` | `0xa7` | | |
| `f32.convert_s/i32` | `0xa8` | | |
| `f32.convert_u/i32` | `0xa9` | | |
| `f32.convert_s/i64` | `0xaa` | | |
| `f32.convert_u/i64` | `0xab` | | |
| `f32.demote/f64` | `0xac` | | |
| `f32.reinterpret/i32` | `0xad` | | |
| `f64.convert_s/i32` | `0xae` | | |
| `f64.convert_u/i32` | `0xaf` | | |
| `f64.convert_s/i64` | `0xb0` | | |
| `f64.convert_u/i64` | `0xb1` | | |
| `f64.promote/f32` | `0xb2` | | |
| `f64.reinterpret/i64` | `0xb3` | | |
| `i32.reinterpret/f32` | `0xb4` | | |
| `i64.reinterpret/f64` | `0xb5` | | |