skip to content
==> src/opcodes.c <==
1/* The instruction table: the MVP and the proposals we run as rows; SIMD and atomics by rule
2 * (their immediates only). */
3#include "wasm/opcodes.h"
4
5#include <stddef.h>
6
7#define R(code, nm, im, feat, sg, mb) [code] = {code, nm, im, feat, sg, mb}
8#define N(code, nm, sg) R(code, nm, WASM_IMM_NONE, 0, sg, 0)
9#define L(code, nm, sg, mb) R(code, nm, WASM_IMM_MEMARG, 0, sg, mb)
10#define REF WASM_F_REFERENCE_TYPES
11#define BULK WASM_F_BULK_MEMORY
12#define SAT WASM_F_SAT_FLOAT_TO_INT
13
14static const wasm_opinfo main_ops[256] = {
15    R(0x00, "Unreachable", WASM_IMM_NONE, 0, NULL, 0),
16    R(0x01, "Nop", WASM_IMM_NONE, 0, NULL, 0),
17    R(0x02, "Block", WASM_IMM_BLOCK, 0, NULL, 0),
18    R(0x03, "Loop", WASM_IMM_BLOCK, 0, NULL, 0),
19    R(0x04, "If", WASM_IMM_BLOCK, 0, NULL, 0),
20    R(0x05, "Else", WASM_IMM_NONE, 0, NULL, 0),
21    R(0x0b, "End", WASM_IMM_NONE, 0, NULL, 0),
22    R(0x0c, "Br", WASM_IMM_LABEL, 0, NULL, 0),
23    R(0x0d, "BrIf", WASM_IMM_LABEL, 0, NULL, 0),
24    R(0x0e, "BrTable", WASM_IMM_BR_TABLE, 0, NULL, 0),
25    R(0x0f, "Return", WASM_IMM_NONE, 0, NULL, 0),
26    R(0x10, "Call", WASM_IMM_FUNC, 0, NULL, 0),
27    R(0x11, "CallIndirect", WASM_IMM_CALL_INDIRECT, 0, NULL, 0),
28    R(0x1a, "Drop", WASM_IMM_NONE, 0, NULL, 0),
29    R(0x1b, "Select", WASM_IMM_NONE, 0, NULL, 0),
30    R(0x1c, "TypedSelect", WASM_IMM_SELECT_T, REF, NULL, 0),
31    R(0x20, "LocalGet", WASM_IMM_LOCAL, 0, NULL, 0),
32    R(0x21, "LocalSet", WASM_IMM_LOCAL, 0, NULL, 0),
33    R(0x22, "LocalTee", WASM_IMM_LOCAL, 0, NULL, 0),
34    R(0x23, "GlobalGet", WASM_IMM_GLOBAL, 0, NULL, 0),
35    R(0x24, "GlobalSet", WASM_IMM_GLOBAL, 0, NULL, 0),
36    R(0x25, "TableGet", WASM_IMM_TABLE, REF, NULL, 0),
37    R(0x26, "TableSet", WASM_IMM_TABLE, REF, NULL, 0),
38    L(0x28, "I32Load", "i>i", 4),
39    L(0x29, "I64Load", "i>l", 8),
40    L(0x2a, "F32Load", "i>f", 4),
41    L(0x2b, "F64Load", "i>d", 8),
42    L(0x2c, "I32Load8S", "i>i", 1),
43    L(0x2d, "I32Load8U", "i>i", 1),
44    L(0x2e, "I32Load16S", "i>i", 2),
45    L(0x2f, "I32Load16U", "i>i", 2),
46    L(0x30, "I64Load8S", "i>l", 1),
47    L(0x31, "I64Load8U", "i>l", 1),
48    L(0x32, "I64Load16S", "i>l", 2),
49    L(0x33, "I64Load16U", "i>l", 2),
50    L(0x34, "I64Load32S", "i>l", 4),
51    L(0x35, "I64Load32U", "i>l", 4),
52    L(0x36, "I32Store", "ii>", 4),
53    L(0x37, "I64Store", "il>", 8),
54    L(0x38, "F32Store", "if>", 4),
55    L(0x39, "F64Store", "id>", 8),
56    L(0x3a, "I32Store8", "ii>", 1),
57    L(0x3b, "I32Store16", "ii>", 2),
58    L(0x3c, "I64Store8", "il>", 1),
59    L(0x3d, "I64Store16", "il>", 2),
60    L(0x3e, "I64Store32", "il>", 4),
61    R(0x3f, "MemorySize", WASM_IMM_MEMIDX, 0, ">i", 0),
62    R(0x40, "MemoryGrow", WASM_IMM_MEMIDX, 0, "i>i", 0),
63    R(0x41, "I32Const", WASM_IMM_I32, 0, ">i", 0),
64    R(0x42, "I64Const", WASM_IMM_I64, 0, ">l", 0),
65    R(0x43, "F32Const", WASM_IMM_F32, 0, ">f", 0),
66    R(0x44, "F64Const", WASM_IMM_F64, 0, ">d", 0),
67    N(0x45, "I32Eqz", "i>i"),
68    N(0x46, "I32Eq", "ii>i"),
69    N(0x47, "I32Ne", "ii>i"),
70    N(0x48, "I32LtS", "ii>i"),
71    N(0x49, "I32LtU", "ii>i"),
72    N(0x4a, "I32GtS", "ii>i"),
73    N(0x4b, "I32GtU", "ii>i"),
74    N(0x4c, "I32LeS", "ii>i"),
75    N(0x4d, "I32LeU", "ii>i"),
76    N(0x4e, "I32GeS", "ii>i"),
77    N(0x4f, "I32GeU", "ii>i"),
78    N(0x50, "I64Eqz", "l>i"),
79    N(0x51, "I64Eq", "ll>i"),
80    N(0x52, "I64Ne", "ll>i"),
81    N(0x53, "I64LtS", "ll>i"),
82    N(0x54, "I64LtU", "ll>i"),
83    N(0x55, "I64GtS", "ll>i"),
84    N(0x56, "I64GtU", "ll>i"),
85    N(0x57, "I64LeS", "ll>i"),
86    N(0x58, "I64LeU", "ll>i"),
87    N(0x59, "I64GeS", "ll>i"),
88    N(0x5a, "I64GeU", "ll>i"),
89    N(0x5b, "F32Eq", "ff>i"),
90    N(0x5c, "F32Ne", "ff>i"),
91    N(0x5d, "F32Lt", "ff>i"),
92    N(0x5e, "F32Gt", "ff>i"),
93    N(0x5f, "F32Le", "ff>i"),
94    N(0x60, "F32Ge", "ff>i"),
95    N(0x61, "F64Eq", "dd>i"),
96    N(0x62, "F64Ne", "dd>i"),
97    N(0x63, "F64Lt", "dd>i"),
98    N(0x64, "F64Gt", "dd>i"),
99    N(0x65, "F64Le", "dd>i"),
100    N(0x66, "F64Ge", "dd>i"),
101    N(0x67, "I32Clz", "i>i"),
102    N(0x68, "I32Ctz", "i>i"),
103    N(0x69, "I32Popcnt", "i>i"),
104    N(0x6a, "I32Add", "ii>i"),
105    N(0x6b, "I32Sub", "ii>i"),
106    N(0x6c, "I32Mul", "ii>i"),
107    N(0x6d, "I32DivS", "ii>i"),
108    N(0x6e, "I32DivU", "ii>i"),
109    N(0x6f, "I32RemS", "ii>i"),
110    N(0x70, "I32RemU", "ii>i"),
111    N(0x71, "I32And", "ii>i"),
112    N(0x72, "I32Or", "ii>i"),
113    N(0x73, "I32Xor", "ii>i"),
114    N(0x74, "I32Shl", "ii>i"),
115    N(0x75, "I32ShrS", "ii>i"),
116    N(0x76, "I32ShrU", "ii>i"),
117    N(0x77, "I32Rotl", "ii>i"),
118    N(0x78, "I32Rotr", "ii>i"),
119    N(0x79, "I64Clz", "l>l"),
120    N(0x7a, "I64Ctz", "l>l"),
121    N(0x7b, "I64Popcnt", "l>l"),
122    N(0x7c, "I64Add", "ll>l"),
123    N(0x7d, "I64Sub", "ll>l"),
124    N(0x7e, "I64Mul", "ll>l"),
125    N(0x7f, "I64DivS", "ll>l"),
126    N(0x80, "I64DivU", "ll>l"),
127    N(0x81, "I64RemS", "ll>l"),
128    N(0x82, "I64RemU", "ll>l"),
129    N(0x83, "I64And", "ll>l"),
130    N(0x84, "I64Or", "ll>l"),
131    N(0x85, "I64Xor", "ll>l"),
132    N(0x86, "I64Shl", "ll>l"),
133    N(0x87, "I64ShrS", "ll>l"),
134    N(0x88, "I64ShrU", "ll>l"),
135    N(0x89, "I64Rotl", "ll>l"),
136    N(0x8a, "I64Rotr", "ll>l"),
137    N(0x8b, "F32Abs", "f>f"),
138    N(0x8c, "F32Neg", "f>f"),
139    N(0x8d, "F32Ceil", "f>f"),
140    N(0x8e, "F32Floor", "f>f"),
141    N(0x8f, "F32Trunc", "f>f"),
142    N(0x90, "F32Nearest", "f>f"),
143    N(0x91, "F32Sqrt", "f>f"),
144    N(0x92, "F32Add", "ff>f"),
145    N(0x93, "F32Sub", "ff>f"),
146    N(0x94, "F32Mul", "ff>f"),
147    N(0x95, "F32Div", "ff>f"),
148    N(0x96, "F32Min", "ff>f"),
149    N(0x97, "F32Max", "ff>f"),
150    N(0x98, "F32Copysign", "ff>f"),
151    N(0x99, "F64Abs", "d>d"),
152    N(0x9a, "F64Neg", "d>d"),
153    N(0x9b, "F64Ceil", "d>d"),
154    N(0x9c, "F64Floor", "d>d"),
155    N(0x9d, "F64Trunc", "d>d"),
156    N(0x9e, "F64Nearest", "d>d"),
157    N(0x9f, "F64Sqrt", "d>d"),
158    N(0xa0, "F64Add", "dd>d"),
159    N(0xa1, "F64Sub", "dd>d"),
160    N(0xa2, "F64Mul", "dd>d"),
161    N(0xa3, "F64Div", "dd>d"),
162    N(0xa4, "F64Min", "dd>d"),
163    N(0xa5, "F64Max", "dd>d"),
164    N(0xa6, "F64Copysign", "dd>d"),
165    N(0xa7, "I32WrapI64", "l>i"),
166    N(0xa8, "I32TruncF32S", "f>i"),
167    N(0xa9, "I32TruncF32U", "f>i"),
168    N(0xaa, "I32TruncF64S", "d>i"),
169    N(0xab, "I32TruncF64U", "d>i"),
170    N(0xac, "I64ExtendI32S", "i>l"),
171    N(0xad, "I64ExtendI32U", "i>l"),
172    N(0xae, "I64TruncF32S", "f>l"),
173    N(0xaf, "I64TruncF32U", "f>l"),
174    N(0xb0, "I64TruncF64S", "d>l"),
175    N(0xb1, "I64TruncF64U", "d>l"),
176    N(0xb2, "F32ConvertI32S", "i>f"),
177    N(0xb3, "F32ConvertI32U", "i>f"),
178    N(0xb4, "F32ConvertI64S", "l>f"),
179    N(0xb5, "F32ConvertI64U", "l>f"),
180    N(0xb6, "F32DemoteF64", "d>f"),
181    N(0xb7, "F64ConvertI32S", "i>d"),
182    N(0xb8, "F64ConvertI32U", "i>d"),
183    N(0xb9, "F64ConvertI64S", "l>d"),
184    N(0xba, "F64ConvertI64U", "l>d"),
185    N(0xbb, "F64PromoteF32", "f>d"),
186    N(0xbc, "I32ReinterpretF32", "f>i"),
187    N(0xbd, "I64ReinterpretF64", "d>l"),
188    N(0xbe, "F32ReinterpretI32", "i>f"),
189    N(0xbf, "F64ReinterpretI64", "l>d"),
190    R(0xc0, "I32Extend8S", WASM_IMM_NONE, WASM_F_SIGN_EXT, "i>i", 0),
191    R(0xc1, "I32Extend16S", WASM_IMM_NONE, WASM_F_SIGN_EXT, "i>i", 0),
192    R(0xc2, "I64Extend8S", WASM_IMM_NONE, WASM_F_SIGN_EXT, "l>l", 0),
193    R(0xc3, "I64Extend16S", WASM_IMM_NONE, WASM_F_SIGN_EXT, "l>l", 0),
194    R(0xc4, "I64Extend32S", WASM_IMM_NONE, WASM_F_SIGN_EXT, "l>l", 0),
195    R(0xd0, "RefNull", WASM_IMM_REFTYPE, REF, NULL, 0),
196    R(0xd1, "RefIsNull", WASM_IMM_NONE, REF, NULL, 0),
197    R(0xd2, "RefFunc", WASM_IMM_FUNC, REF, NULL, 0),
198};
199
200static const wasm_opinfo fc_ops[18] = {
201    {WASM_OP_FC(0), "I32TruncSatF32S", WASM_IMM_NONE, SAT, "f>i", 0},
202    {WASM_OP_FC(1), "I32TruncSatF32U", WASM_IMM_NONE, SAT, "f>i", 0},
203    {WASM_OP_FC(2), "I32TruncSatF64S", WASM_IMM_NONE, SAT, "d>i", 0},
204    {WASM_OP_FC(3), "I32TruncSatF64U", WASM_IMM_NONE, SAT, "d>i", 0},
205    {WASM_OP_FC(4), "I64TruncSatF32S", WASM_IMM_NONE, SAT, "f>l", 0},
206    {WASM_OP_FC(5), "I64TruncSatF32U", WASM_IMM_NONE, SAT, "f>l", 0},
207    {WASM_OP_FC(6), "I64TruncSatF64S", WASM_IMM_NONE, SAT, "d>l", 0},
208    {WASM_OP_FC(7), "I64TruncSatF64U", WASM_IMM_NONE, SAT, "d>l", 0},
209    {WASM_OP_FC(8), "MemoryInit", WASM_IMM_MEMORY_INIT, BULK, NULL, 0},
210    {WASM_OP_FC(9), "DataDrop", WASM_IMM_DATA, BULK, NULL, 0},
211    {WASM_OP_FC(10), "MemoryCopy", WASM_IMM_MEMORY_COPY, BULK, NULL, 0},
212    {WASM_OP_FC(11), "MemoryFill", WASM_IMM_MEMIDX, BULK, NULL, 0},
213    {WASM_OP_FC(12), "TableInit", WASM_IMM_TABLE_INIT, BULK, NULL, 0},
214    {WASM_OP_FC(13), "ElemDrop", WASM_IMM_ELEM, BULK, NULL, 0},
215    {WASM_OP_FC(14), "TableCopy", WASM_IMM_TABLE_COPY, BULK, NULL, 0},
216    {WASM_OP_FC(15), "TableGrow", WASM_IMM_TABLE, REF, NULL, 0},
217    {WASM_OP_FC(16), "TableSize", WASM_IMM_TABLE, REF, NULL, 0},
218    {WASM_OP_FC(17), "TableFill", WASM_IMM_TABLE, REF, NULL, 0},
219};
220
221/* SIMD opcodes 0x00-0xff that the final SIMD proposal leaves unassigned. */
222static bool simd_unassigned(uint32_t sub) {
223    static const uint8_t gaps[] = {0x9a, 0xa2, 0xa5, 0xa6, 0xaf, 0xb0, 0xb2, 0xb3, 0xb4, 0xbb,
224                                   0xc2, 0xc5, 0xc6, 0xcf, 0xd0, 0xd2, 0xd3, 0xd4, 0xe2, 0xee};
225    for (size_t i = 0; i < sizeof gaps; i++)
226        if (gaps[i] == sub) return true;
227    return false;
228}
229
230static bool simd(uint32_t sub, wasm_opinfo *out) {
231    wasm_opinfo o = {WASM_OP_SIMD(sub), "Simd", WASM_IMM_NONE, WASM_F_SIMD, NULL, 0};
232    if (sub >= 0x100 && sub <= 0x113) {
233        o.name = "RelaxedSimd";
234        o.feature = WASM_F_RELAXED_SIMD;
235    } else if (sub > 0xff || simd_unassigned(sub)) {
236        return false;
237    } else if (sub <= 0x0b || sub == 0x5c || sub == 0x5d) {
238        o.imm = WASM_IMM_MEMARG;
239    } else if (sub == 0x0c) {
240        o.imm = WASM_IMM_V128;
241    } else if (sub == 0x0d) {
242        o.imm = WASM_IMM_SHUFFLE;
243    } else if (sub >= 0x15 && sub <= 0x22) {
244        o.imm = WASM_IMM_LANE;
245    } else if (sub >= 0x54 && sub <= 0x5b) {
246        o.imm = WASM_IMM_MEMARG_LANE;
247    }
248    *out = o;
249    return true;
250}
251
252static bool atomic(uint32_t sub, wasm_opinfo *out) {
253    wasm_opinfo o = {WASM_OP_ATOMIC(sub), "Atomic", WASM_IMM_MEMARG, WASM_F_THREADS, NULL, 0};
254    if (sub == 0x03) o.imm = WASM_IMM_ZERO_BYTE;
255    else if (sub > 0x02 && (sub < 0x10 || sub > 0x4e)) return false;
256    *out = o;
257    return true;
258}
259
260bool wasm_op_info(uint32_t op, wasm_opinfo *out) {
261    uint32_t prefix = op >> 16, sub = op & 0xffff;
262    if (prefix == 0) {
263        if (op > 0xff || !main_ops[op].name) return false;
264        *out = main_ops[op];
265        return true;
266    }
267    if (prefix == WASM_PREFIX_FC) {
268        if (sub >= sizeof fc_ops / sizeof fc_ops[0]) return false;
269        *out = fc_ops[sub];
270        return true;
271    }
272    if (prefix == WASM_PREFIX_SIMD) return simd(sub, out);
273    if (prefix == WASM_PREFIX_ATOMIC) return atomic(sub, out);
274    return false;
275}