master
1#define EXTRA_BRACES 0
2
3#include "FuncGen.h"
4#include "InputStream.h"
5#include "panic.h"
6#include "wasm.h"
7
8#include <inttypes.h>
9#include <limits.h>
10#include <stdint.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14
15struct FuncType {
16 const struct ResultType *param;
17 const struct ResultType *result;
18};
19static const struct FuncType *FuncType_blockType(const struct FuncType *types, int64_t block_type) {
20 if (block_type >= 0) return &types[block_type];
21
22 static const struct ResultType none = { 0, { 0 }};
23 static const struct ResultType i32 = { 1, { WasmValType_i32 } };
24 static const struct ResultType i64 = { 1, { WasmValType_i64 } };
25 static const struct ResultType f32 = { 1, { WasmValType_f32 } };
26 static const struct ResultType f64 = { 1, { WasmValType_f64 } };
27
28 static const struct FuncType none_i32 = { &none, &i32 };
29 static const struct FuncType none_i64 = { &none, &i64 };
30 static const struct FuncType none_f32 = { &none, &f32 };
31 static const struct FuncType none_f64 = { &none, &f64 };
32 static const struct FuncType none_none = { &none, &none };
33
34 switch (block_type) {
35 case WasmValType_i32: return &none_i32;
36 case WasmValType_i64: return &none_i64;
37 case WasmValType_f32: return &none_f32;
38 case WasmValType_f64: return &none_f64;
39 case WasmValType_empty: return &none_none;
40 default: panic("unsupported block type");
41 }
42 return NULL;
43}
44
45static uint32_t evalExpr(struct InputStream *in) {
46 uint32_t value;
47 while (true) {
48 switch (InputStream_readByte(in)) {
49 case WasmOpcode_end: return value;
50
51 case WasmOpcode_i32_const:
52 value = (uint32_t)InputStream_readLeb128_i32(in);
53 break;
54
55 default: panic("unsupported expr opcode");
56 }
57 }
58}
59
60static void renderExpr(FILE *out, struct InputStream *in) {
61 while (true) {
62 switch (InputStream_readByte(in)) {
63 case WasmOpcode_end: return;
64
65 case WasmOpcode_i32_const: {
66 uint32_t value = (uint32_t)InputStream_readLeb128_i32(in);
67 fprintf(out, "UINT32_C(0x%" PRIX32 ")", value);
68 break;
69 }
70
71 default: panic("unsupported expr opcode");
72 }
73 }
74}
75
76static const uint32_t big_endian = 0xff000000;
77
78int main(int argc, char **argv) {
79 if (argc != 3 && argc != 4) {
80 fprintf(stderr, "usage: %s <in.wasm.zst> <out.c> [endian]\n", argv[0]);
81 return 1;
82 }
83
84 bool is_big_endian;
85
86 if (argc >= 4) {
87 if (!strcmp(argv[3], "big")) {
88 is_big_endian = true;
89 } else if (!strcmp(argv[3], "little")) {
90 is_big_endian = false;
91 } else {
92 fprintf(stderr, "endianness must be 'big' or 'little'\n");
93 return 1;
94 }
95 } else {
96 is_big_endian = *(uint8_t *)&big_endian; // Infer from host endianness.
97 }
98
99 const char *mod = "wasm";
100
101 struct InputStream in;
102 InputStream_open(&in, argv[1]);
103
104 if (InputStream_readByte(&in) != '\0' ||
105 InputStream_readByte(&in) != 'a' ||
106 InputStream_readByte(&in) != 's' ||
107 InputStream_readByte(&in) != 'm') panic("input is not a zstd-compressed wasm file");
108 if (InputStream_readLittle_u32(&in) != 1) panic("unsupported wasm version");
109
110 FILE *out = fopen(argv[2], "wb");
111 if (out == NULL) panic("unable to open output file");
112 fputs("#include <float.h>\n"
113 "#include <math.h>\n"
114 "#include <stdint.h>\n"
115 "#include <stdlib.h>\n"
116 "#include <string.h>\n"
117 "\n"
118 "static uint16_t i16_byteswap(uint16_t src) {\n"
119 " return (uint16_t)(uint8_t)(src >> 0) << 8 |\n"
120 " (uint16_t)(uint8_t)(src >> 8) << 0;\n"
121 "}\n"
122 "static uint32_t i32_byteswap(uint32_t src) {\n"
123 " return (uint32_t)i16_byteswap(src >> 0) << 16 |\n"
124 " (uint32_t)i16_byteswap(src >> 16) << 0;\n"
125 "}\n"
126 "static uint64_t i64_byteswap(uint64_t src) {\n"
127 " return (uint64_t)i32_byteswap(src >> 0) << 32 |\n"
128 " (uint64_t)i32_byteswap(src >> 32) << 0;\n"
129 "}\n"
130 "\n", out);
131 fputs("uint16_t load16_align0(const uint8_t *ptr) {\n"
132 " uint16_t val;\n"
133 " memcpy(&val, ptr, sizeof(val));\n", out);
134 if (is_big_endian) fputs(" val = i16_byteswap(val);", out);
135 fputs(" return val;\n"
136 "}\n"
137 "uint16_t load16_align1(const uint16_t *ptr) {\n"
138 " uint16_t val;\n"
139 " memcpy(&val, ptr, sizeof(val));\n", out);
140 if (is_big_endian) fputs(" val = i16_byteswap(val);", out);
141 fputs(" return val;\n"
142 "}\n"
143 "uint32_t load32_align0(const uint8_t *ptr) {\n"
144 " uint32_t val;\n"
145 " memcpy(&val, ptr, sizeof(val));\n", out);
146 if (is_big_endian) fputs(" val = i32_byteswap(val);", out);
147 fputs(" return val;\n"
148 "}\n"
149 "uint32_t load32_align1(const uint16_t *ptr) {\n"
150 " uint32_t val;\n"
151 " memcpy(&val, ptr, sizeof(val));\n", out);
152 if (is_big_endian) fputs(" val = i32_byteswap(val);", out);
153 fputs(" return val;\n"
154 "}\n"
155 "uint32_t load32_align2(const uint32_t *ptr) {\n"
156 " uint32_t val;\n"
157 " memcpy(&val, ptr, sizeof(val));\n", out);
158 if (is_big_endian) fputs(" val = i32_byteswap(val);", out);
159 fputs(" return val;\n"
160 "}\n"
161 "uint64_t load64_align0(const uint8_t *ptr) {\n"
162 " uint64_t val;\n"
163 " memcpy(&val, ptr, sizeof(val));\n", out);
164 if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
165 fputs(" return val;\n"
166 "}\n"
167 "uint64_t load64_align1(const uint16_t *ptr) {\n"
168 " uint64_t val;\n"
169 " memcpy(&val, ptr, sizeof(val));\n", out);
170 if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
171 fputs(" return val;\n"
172 "}\n"
173 "uint64_t load64_align2(const uint32_t *ptr) {\n"
174 " uint64_t val;\n"
175 " memcpy(&val, ptr, sizeof(val));\n", out);
176 if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
177 fputs(" return val;\n"
178 "}\n"
179 "uint64_t load64_align3(const uint64_t *ptr) {\n"
180 " uint64_t val;\n"
181 " memcpy(&val, ptr, sizeof(val));\n", out);
182 if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
183 fputs(" return val;\n"
184 "}\n"
185 "\n"
186 "static uint32_t i32_popcnt(uint32_t lhs) {\n"
187 " lhs = lhs - ((lhs >> 1) & UINT32_C(0x55555555));\n"
188 " lhs = (lhs & UINT32_C(0x33333333)) + ((lhs >> 2) & UINT32_C(0x33333333));\n"
189 " lhs = (lhs + (lhs >> 4)) & UINT32_C(0x0F0F0F0F);\n"
190 " return (lhs * UINT32_C(0x01010101)) >> 24;\n"
191 "}\n"
192 "static uint32_t i32_ctz(uint32_t lhs) {\n"
193 " return i32_popcnt(~lhs & (lhs - 1));\n"
194 "}\n"
195 "static uint32_t i32_clz(uint32_t lhs) {\n"
196 " lhs = i32_byteswap(lhs);\n"
197 " lhs = (lhs & UINT32_C(0x0F0F0F0F)) << 4 | (lhs & UINT32_C(0xF0F0F0F0)) >> 4;\n"
198 " lhs = (lhs & UINT32_C(0x33333333)) << 2 | (lhs & UINT32_C(0xCCCCCCCC)) >> 2;\n"
199 " lhs = (lhs & UINT32_C(0x55555555)) << 1 | (lhs & UINT32_C(0xAAAAAAAA)) >> 1;\n"
200 " return i32_ctz(lhs);\n"
201 "}\n"
202 "static uint64_t i64_popcnt(uint64_t lhs) {\n"
203 " lhs = lhs - ((lhs >> 1) & UINT64_C(0x5555555555555555));\n"
204 " lhs = (lhs & UINT64_C(0x3333333333333333)) + ((lhs >> 2) & UINT64_C(0x3333333333333333));\n"
205 " lhs = (lhs + (lhs >> 4)) & UINT64_C(0x0F0F0F0F0F0F0F0F);\n"
206 " return (lhs * UINT64_C(0x0101010101010101)) >> 56;\n"
207 "}\n"
208 "static uint64_t i64_ctz(uint64_t lhs) {\n"
209 " return i64_popcnt(~lhs & (lhs - 1));\n"
210 "}\n"
211 "static uint64_t i64_clz(uint64_t lhs) {\n"
212 " lhs = i64_byteswap(lhs);\n"
213 " lhs = (lhs & UINT64_C(0x0F0F0F0F0F0F0F0F)) << 4 | (lhs & UINT32_C(0xF0F0F0F0F0F0F0F0)) >> 4;\n"
214 " lhs = (lhs & UINT64_C(0x3333333333333333)) << 2 | (lhs & UINT32_C(0xCCCCCCCCCCCCCCCC)) >> 2;\n"
215 " lhs = (lhs & UINT64_C(0x5555555555555555)) << 1 | (lhs & UINT32_C(0xAAAAAAAAAAAAAAAA)) >> 1;\n"
216 " return i64_ctz(lhs);\n"
217 "}\n"
218 "\n"
219 "void store16_align0(uint8_t *ptr, uint16_t val) {\n", out);
220 if (is_big_endian) fputs(" val = i16_byteswap(val);", out);
221 fputs(" memcpy(ptr, &val, sizeof(val));\n"
222 "}\n"
223 "void store16_align1(uint16_t *ptr, uint16_t val) {\n", out);
224 if (is_big_endian) fputs(" val = i16_byteswap(val);", out);
225 fputs(" memcpy(ptr, &val, sizeof(val));\n"
226 "}\n"
227 "void store32_align0(uint8_t *ptr, uint32_t val) {\n", out);
228 if (is_big_endian) fputs(" val = i32_byteswap(val);", out);
229 fputs(" memcpy(ptr, &val, sizeof(val));\n"
230 "}\n"
231 "void store32_align1(uint16_t *ptr, uint32_t val) {\n", out);
232 if (is_big_endian) fputs(" val = i32_byteswap(val);", out);
233 fputs(" memcpy(ptr, &val, sizeof(val));\n"
234 "}\n"
235 "void store32_align2(uint32_t *ptr, uint32_t val) {\n", out);
236 if (is_big_endian) fputs(" val = i32_byteswap(val);", out);
237 fputs(" memcpy(ptr, &val, sizeof(val));\n"
238 "}\n"
239 "void store64_align0(uint8_t *ptr, uint64_t val) {\n", out);
240 if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
241 fputs(" memcpy(ptr, &val, sizeof(val));\n"
242 "}\n"
243 "void store64_align1(uint16_t *ptr, uint64_t val) {\n", out);
244 if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
245 fputs(" memcpy(ptr, &val, sizeof(val));\n"
246 "}\n"
247 "void store64_align2(uint32_t *ptr, uint64_t val) {\n", out);
248 if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
249 fputs(" memcpy(ptr, &val, sizeof(val));\n"
250 "}\n"
251 "void store64_align3(uint64_t *ptr, uint64_t val) {\n", out);
252 if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
253 fputs(" memcpy(ptr, &val, sizeof(val));\n"
254 "}\n"
255 "\n"
256 "static uint32_t i32_reinterpret_f32(const float src) {\n"
257 " uint32_t dst;\n"
258 " memcpy(&dst, &src, sizeof(dst));\n"
259 " return dst;\n"
260 "}\n"
261 "static uint64_t i64_reinterpret_f64(const double src) {\n"
262 " uint64_t dst;\n"
263 " memcpy(&dst, &src, sizeof(dst));\n"
264 " return dst;\n"
265 "}\n"
266 "static float f32_reinterpret_i32(const uint32_t src) {\n"
267 " float dst;\n"
268 " memcpy(&dst, &src, sizeof(dst));\n"
269 " return dst;\n"
270 "}\n"
271 "static double f64_reinterpret_i64(const uint64_t src) {\n"
272 " double dst;\n"
273 " memcpy(&dst, &src, sizeof(dst));\n"
274 " return dst;\n"
275 "}\n"
276 "\n"
277 "static uint32_t i32_trunc_sat_f32(const float src) {\n"
278 " if (isnan(src)) return 0;\n"
279 " if (isinf(src)) return (uint32_t)(signbit(src) == 0 ? INT32_MAX : INT32_MIN);\n"
280 " return (uint32_t)(int32_t)src;\n"
281 "}\n"
282 "static uint32_t u32_trunc_sat_f32(const float src) {\n"
283 " if (isnan(src)) return 0;\n"
284 " if (isinf(src)) return signbit(src) == 0 ? UINT32_MAX : 0;\n"
285 " return (uint32_t)src;\n"
286 "}\n"
287 "static uint32_t i32_trunc_sat_f64(const double src) {\n"
288 " if (isnan(src)) return 0;\n"
289 " if (isinf(src)) return (uint32_t)(signbit(src) == 0 ? INT32_MAX : INT32_MIN);\n"
290 " return (uint32_t)(int32_t)src;\n"
291 "}\n"
292 "static uint32_t u32_trunc_sat_f64(const double src) {\n"
293 " if (isnan(src)) return 0;\n"
294 " if (isinf(src)) return signbit(src) == 0 ? UINT32_MAX : 0;\n"
295 " return (uint32_t)src;\n"
296 "}\n"
297 "static uint64_t i64_trunc_sat_f32(const float src) {\n"
298 " if (isnan(src)) return 0;\n"
299 " if (isinf(src)) return (uint64_t)(signbit(src) == 0 ? INT64_MAX : INT64_MIN);\n"
300 " return (uint64_t)(int64_t)src;\n"
301 "}\n"
302 "static uint64_t u64_trunc_sat_f32(const float src) {\n"
303 " if (isnan(src)) return 0;\n"
304 " if (isinf(src)) return signbit(src) == 0 ? UINT64_MAX : 0;\n"
305 " return (uint64_t)src;\n"
306 "}\n"
307 "static uint64_t i64_trunc_sat_f64(const double src) {\n"
308 " if (isnan(src)) return 0;\n"
309 " if (isinf(src)) return (uint64_t)(signbit(src) == 0 ? INT64_MAX : INT64_MIN);\n"
310 " return (uint64_t)(int64_t)src;\n"
311 "}\n"
312 "static uint64_t u64_trunc_sat_f64(const double src) {\n"
313 " if (isnan(src)) return 0;\n"
314 " if (isinf(src)) return signbit(src) == 0 ? UINT64_MAX : 0;\n"
315 " return (uint64_t)src;\n"
316 "}\n"
317 "\n"
318 "static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t *c, uint32_t n) {\n"
319 " uint32_t r = *p;\n"
320 " uint32_t new_p = r + n;\n"
321 " if (new_p > UINT32_C(0xFFFF)) return UINT32_C(0xFFFFFFFF);\n"
322 " uint8_t *new_m = *m;\n"
323 " uint32_t new_c = *c;\n"
324 " if (new_c < new_p) {\n"
325 " do new_c += new_c / 2 + 8; while (new_c < new_p);\n"
326 " if (new_c > UINT32_C(0xFFFF)) new_c = UINT32_C(0xFFFF);\n"
327 " new_m = realloc(new_m, new_c << 16);\n"
328 " if (new_m == NULL) return UINT32_C(0xFFFFFFFF);\n"
329 " *m = new_m;\n"
330 " *c = new_c;\n"
331 " }\n"
332 " *p = new_p;\n"
333 " memset(&new_m[r << 16], 0, n << 16);\n"
334 " return r;\n"
335 "}\n"
336 "\n"
337 "static int inited;\n"
338 "static void init_elem(void);\n"
339 "static void init_data(void);\n"
340 "static void init(void) {\n"
341 " if (inited != 0) return;\n"
342 " init_elem();\n"
343 " init_data();\n"
344 " inited = 1;\n"
345 "}\n"
346 "\n", out);
347
348 struct FuncType *types;
349 uint32_t max_param_len = 0;
350 (void)InputStream_skipToSection(&in, WasmSectionId_type);
351 {
352 uint32_t len = InputStream_readLeb128_u32(&in);
353 types = malloc(sizeof(struct FuncType) * len);
354 if (types == NULL) panic("out of memory");
355 for (uint32_t i = 0; i < len; i += 1) {
356 if (InputStream_readByte(&in) != 0x60) panic("expected functype");
357 types[i].param = InputStream_readResultType(&in);
358 if (types[i].param->len > max_param_len) max_param_len = types[i].param->len;
359 types[i].result = InputStream_readResultType(&in);
360 }
361 }
362
363 struct Import {
364 const char *mod;
365 const char *name;
366 uint32_t type_idx;
367 } *imports;
368 (void)InputStream_skipToSection(&in, WasmSectionId_import);
369 uint32_t imports_len = InputStream_readLeb128_u32(&in);
370 {
371 imports = malloc(sizeof(struct Import) * imports_len);
372 if (imports == NULL) panic("out of memory");
373 for (uint32_t i = 0; i < imports_len; i += 1) {
374 imports[i].mod = InputStream_readName(&in);
375 imports[i].name = InputStream_readName(&in);
376 switch (InputStream_readByte(&in)) {
377 case 0x00: { // func
378 imports[i].type_idx = InputStream_readLeb128_u32(&in);
379 const struct FuncType *func_type = &types[imports[i].type_idx];
380 switch (func_type->result->len) {
381 case 0: fputs("void", out); break;
382 case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
383 default: panic("multiple function returns not supported");
384 }
385 fprintf(out, " %s_%s(", imports[i].mod, imports[i].name);
386 if (func_type->param->len == 0) fputs("void", out);
387 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
388 if (param_i > 0) fputs(", ", out);
389 fputs(WasmValType_toC(func_type->param->types[param_i]), out);
390 }
391 fputs(");\n", out);
392 break;
393 }
394
395 case 0x01: // table
396 case 0x02: // mem
397 case 0x03: // global
398 default:
399 panic("unsupported import type");
400 }
401 }
402 fputc('\n', out);
403 }
404
405 struct Func {
406 uint32_t type_idx;
407 } *funcs;
408 (void)InputStream_skipToSection(&in, WasmSectionId_func);
409 {
410 uint32_t len = InputStream_readLeb128_u32(&in);
411 funcs = malloc(sizeof(struct Func) * len);
412 if (funcs == NULL) panic("out of memory");
413 for (uint32_t i = 0; i < len; i += 1) {
414 funcs[i].type_idx = InputStream_readLeb128_u32(&in);
415 const struct FuncType *func_type = &types[funcs[i].type_idx];
416 fputs("static ", out);
417 switch (func_type->result->len) {
418 case 0: fputs("void", out); break;
419 case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
420 default: panic("multiple function returns not supported");
421 }
422 fprintf(out, " f%" PRIu32 "(", i);
423 if (func_type->param->len == 0) fputs("void", out);
424 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
425 if (param_i > 0) fputs(", ", out);
426 fprintf(out, "%s", WasmValType_toC(func_type->param->types[param_i]));
427 }
428 fputs(");\n", out);
429 }
430 fputc('\n', out);
431 }
432
433 struct Table {
434 int8_t type;
435 struct Limits limits;
436 } *tables;
437 (void)InputStream_skipToSection(&in, WasmSectionId_table);
438 {
439 uint32_t len = InputStream_readLeb128_u32(&in);
440 tables = malloc(sizeof(struct Table) * len);
441 if (tables == NULL) panic("out of memory");
442 for (uint32_t i = 0; i < len; i += 1) {
443 int64_t ref_type = InputStream_readLeb128_i64(&in);
444 switch (ref_type) {
445 case WasmValType_funcref:
446 break;
447
448 default: panic("unsupported reftype");
449 }
450 tables[i].type = ref_type;
451 tables[i].limits = InputStream_readLimits(&in);
452 if (tables[i].limits.min != tables[i].limits.max) panic("growable table not supported");
453 fprintf(out, "static void (*t%" PRIu32 "[UINT32_C(%" PRIu32 ")])(void);\n",
454 i, tables[i].limits.min);
455 }
456 fputc('\n', out);
457 }
458
459 struct Mem {
460 struct Limits limits;
461 } *mems;
462 (void)InputStream_skipToSection(&in, WasmSectionId_mem);
463 uint32_t mems_len = InputStream_readLeb128_u32(&in);
464 {
465 mems = malloc(sizeof(struct Mem) * mems_len);
466 if (mems == NULL) panic("out of memory");
467 for (uint32_t i = 0; i < mems_len; i += 1) {
468 mems[i].limits = InputStream_readLimits(&in);
469 fprintf(out, "static uint8_t *m%" PRIu32 ";\n"
470 "static uint32_t p%" PRIu32 ";\n"
471 "static uint32_t c%" PRIu32 ";\n", i, i, i);
472 }
473 fputc('\n', out);
474 }
475
476 struct Global {
477 bool mut;
478 int8_t val_type;
479 } *globals;
480 (void)InputStream_skipToSection(&in, WasmSectionId_global);
481 {
482 uint32_t len = InputStream_readLeb128_u32(&in);
483 globals = malloc(sizeof(struct Global) * len);
484 if (globals == NULL) panic("out of memory");
485 for (uint32_t i = 0; i < len; i += 1) {
486 int64_t val_type = InputStream_readLeb128_i64(&in);
487 enum WasmMut mut = InputStream_readByte(&in);
488 fprintf(out, "%s%s g%" PRIu32 " = ", WasmMut_toC(mut), WasmValType_toC(val_type), i);
489 renderExpr(out, &in);
490 fputs(";\n", out);
491 globals[i].mut = mut;
492 globals[i].val_type = val_type;
493 }
494 fputc('\n', out);
495 }
496
497 (void)InputStream_skipToSection(&in, WasmSectionId_export);
498 {
499 uint32_t len = InputStream_readLeb128_u32(&in);
500 for (uint32_t i = 0; i < len; i += 1) {
501 char *name = InputStream_readName(&in);
502 uint8_t kind = InputStream_readByte(&in);
503 uint32_t idx = InputStream_readLeb128_u32(&in);
504 switch (kind) {
505 case 0x00: {
506 if (idx < imports_len) panic("can't export an import");
507 const struct FuncType *func_type = &types[funcs[idx - imports_len].type_idx];
508 switch (func_type->result->len) {
509 case 0: fputs("void", out); break;
510 case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
511 default: panic("multiple function returns not supported");
512 }
513 fprintf(out, " %s_%s(", mod, name);
514 if (func_type->param->len == 0) fputs("void", out);
515 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
516 if (param_i > 0) fputs(", ", out);
517 fprintf(out, "%s l%" PRIu32, WasmValType_toC(func_type->param->types[param_i]), param_i);
518 }
519 fprintf(out,
520 ") {\n"
521 " init();\n"
522 " %sf%" PRIu32 "(",
523 func_type->result->len > 0 ? "return " : "", idx - imports_len);
524 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
525 if (param_i > 0) fputs(", ", out);
526 fprintf(out, "l%" PRIu32, param_i);
527 }
528 fputs(");\n}\n", out);
529 break;
530 }
531
532 case 0x02:
533 fprintf(out, "uint8_t **const %s_%s = &m%" PRIu32 ";\n", mod, name, idx);
534 break;
535
536 default: panic("unsupported export kind");
537 }
538 free(name);
539 }
540 fputc('\n', out);
541 }
542
543 (void)InputStream_skipToSection(&in, WasmSectionId_elem);
544 {
545 uint32_t len = InputStream_readLeb128_u32(&in);
546 fputs("static void init_elem(void) {\n", out);
547 for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) {
548 uint32_t table_idx = 0;
549 uint32_t elem_type = InputStream_readLeb128_u32(&in);
550 if (elem_type != 0x00) panic("unsupported elem type");
551 uint32_t offset = evalExpr(&in);
552 uint32_t segment_len = InputStream_readLeb128_u32(&in);
553 for (uint32_t i = 0; i < segment_len; i += 1) {
554 uint32_t func_id = InputStream_readLeb128_u32(&in);
555 fprintf(out, " t%" PRIu32 "[UINT32_C(%" PRIu32 ")] = (void (*)(void))&",
556 table_idx, offset + i);
557 if (func_id < imports_len)
558 fprintf(out, "%s_%s", imports[func_id].mod, imports[func_id].name);
559 else
560 fprintf(out, "f%" PRIu32, func_id - imports_len);
561 fputs(";\n", out);
562 }
563 }
564 fputs("}\n\n", out);
565 }
566
567 (void)InputStream_skipToSection(&in, WasmSectionId_code);
568 {
569 struct FuncGen fg;
570 FuncGen_init(&fg);
571 bool *param_used = malloc(sizeof(bool) * max_param_len);
572 uint32_t *param_stash = malloc(sizeof(uint32_t) * max_param_len);
573
574 uint32_t len = InputStream_readLeb128_u32(&in);
575 for (uint32_t func_i = 0; func_i < len; func_i += 1) {
576 FuncGen_reset(&fg);
577
578 InputStream_readLeb128_u32(&in);
579 const struct FuncType *func_type = &types[funcs[func_i].type_idx];
580 fputs("static ", out);
581 switch (func_type->result->len) {
582 case 0: fputs("void", out); break;
583 case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
584 default: panic("multiple function returns not supported");
585 }
586 fprintf(out, " f%" PRIu32 "(", func_i);
587 if (func_type->param->len == 0) fputs("void", out);
588 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
589 param_used[param_i] = false;
590 int8_t param_type = func_type->param->types[param_i];
591 if (param_i > 0) fputs(", ", out);
592 FuncGen_localDeclare(&fg, out, param_type);
593 }
594 fputs(") {\n", out);
595
596 for (uint32_t local_sets_remaining = InputStream_readLeb128_u32(&in);
597 local_sets_remaining > 0; local_sets_remaining -= 1) {
598 uint32_t local_set_len = InputStream_readLeb128_u32(&in);
599 int64_t val_type = InputStream_readLeb128_i64(&in);
600 for (; local_set_len > 0; local_set_len -= 1) {
601 FuncGen_indent(&fg, out);
602 FuncGen_localDeclare(&fg, out, val_type);
603 fputs(" = 0;\n", out);
604 }
605 }
606
607 uint32_t unreachable_depth = 0;
608 for (uint32_t result_i = func_type->result->len; result_i > 0; ) {
609 result_i -= 1;
610 FuncGen_indent(&fg, out);
611 (void)FuncGen_localDeclare(&fg, out,
612 func_type->result->types[result_i]);
613 fputs(";\n", out);
614 }
615 FuncGen_blockBegin(&fg, out, WasmOpcode_block, funcs[func_i].type_idx);
616 while (!FuncGen_done(&fg)) {
617 //static const char *mnemonics[] = {
618 // [WasmOpcode_unreachable] = "unreachable",
619 // [WasmOpcode_nop] = "nop",
620 // [WasmOpcode_block] = "block",
621 // [WasmOpcode_loop] = "loop",
622 // [WasmOpcode_if] = "if",
623 // [WasmOpcode_else] = "else",
624 // [WasmOpcode_end] = "end",
625 // [WasmOpcode_br] = "br",
626 // [WasmOpcode_br_if] = "br_if",
627 // [WasmOpcode_br_table] = "br_table",
628 // [WasmOpcode_return] = "return",
629 // [WasmOpcode_call] = "call",
630 // [WasmOpcode_call_indirect] = "call_indirect",
631 //
632 // [WasmOpcode_drop] = "drop",
633 // [WasmOpcode_select] = "select",
634 // [WasmOpcode_select_t] = "select t",
635 //
636 // [WasmOpcode_local_get] = "local.get",
637 // [WasmOpcode_local_set] = "local.set",
638 // [WasmOpcode_local_tee] = "local.tee",
639 // [WasmOpcode_global_get] = "global.get",
640 // [WasmOpcode_global_set] = "global.set",
641 // [WasmOpcode_table_get] = "table.get",
642 // [WasmOpcode_table_set] = "table.set",
643 //
644 // [WasmOpcode_i32_load] = "i32.load",
645 // [WasmOpcode_i64_load] = "i64.load",
646 // [WasmOpcode_f32_load] = "f32.load",
647 // [WasmOpcode_f64_load] = "f64.load",
648 // [WasmOpcode_i32_load8_s] = "i32.load8_s",
649 // [WasmOpcode_i32_load8_u] = "i32.load8_u",
650 // [WasmOpcode_i32_load16_s] = "i32.load16_s",
651 // [WasmOpcode_i32_load16_u] = "i32.load16_u",
652 // [WasmOpcode_i64_load8_s] = "i64.load8_s",
653 // [WasmOpcode_i64_load8_u] = "i64.load8_u",
654 // [WasmOpcode_i64_load16_s] = "i64.load16_s",
655 // [WasmOpcode_i64_load16_u] = "i64.load16_u",
656 // [WasmOpcode_i64_load32_s] = "i64.load32_s",
657 // [WasmOpcode_i64_load32_u] = "i64.load32_u",
658 // [WasmOpcode_i32_store] = "i32.store",
659 // [WasmOpcode_i64_store] = "i64.store",
660 // [WasmOpcode_f32_store] = "f32.store",
661 // [WasmOpcode_f64_store] = "f64.store",
662 // [WasmOpcode_i32_store8] = "i32.store8",
663 // [WasmOpcode_i32_store16] = "i32.store16",
664 // [WasmOpcode_i64_store8] = "i64.store8",
665 // [WasmOpcode_i64_store16] = "i64.store16",
666 // [WasmOpcode_i64_store32] = "i64.store32",
667 // [WasmOpcode_memory_size] = "memory.size",
668 // [WasmOpcode_memory_grow] = "memory.grow",
669 //
670 // [WasmOpcode_i32_const] = "i32.const",
671 // [WasmOpcode_i64_const] = "i64.const",
672 // [WasmOpcode_f32_const] = "f32.const",
673 // [WasmOpcode_f64_const] = "f64.const",
674 //
675 // [WasmOpcode_i32_eqz] = "i32.eqz",
676 // [WasmOpcode_i32_eq] = "i32.eq",
677 // [WasmOpcode_i32_ne] = "i32.ne",
678 // [WasmOpcode_i32_lt_s] = "i32.lt_s",
679 // [WasmOpcode_i32_lt_u] = "i32.lt_u",
680 // [WasmOpcode_i32_gt_s] = "i32.gt_s",
681 // [WasmOpcode_i32_gt_u] = "i32.gt_u",
682 // [WasmOpcode_i32_le_s] = "i32.le_s",
683 // [WasmOpcode_i32_le_u] = "i32.le_u",
684 // [WasmOpcode_i32_ge_s] = "i32.ge_s",
685 // [WasmOpcode_i32_ge_u] = "i32.ge_u",
686 //
687 // [WasmOpcode_i64_eqz] = "i64.eqz",
688 // [WasmOpcode_i64_eq] = "i64.eq",
689 // [WasmOpcode_i64_ne] = "i64.ne",
690 // [WasmOpcode_i64_lt_s] = "i64.lt_s",
691 // [WasmOpcode_i64_lt_u] = "i64.lt_u",
692 // [WasmOpcode_i64_gt_s] = "i64.gt_s",
693 // [WasmOpcode_i64_gt_u] = "i64.gt_u",
694 // [WasmOpcode_i64_le_s] = "i64.le_s",
695 // [WasmOpcode_i64_le_u] = "i64.le_u",
696 // [WasmOpcode_i64_ge_s] = "i64.ge_s",
697 // [WasmOpcode_i64_ge_u] = "i64.ge_u",
698 //
699 // [WasmOpcode_f32_eq] = "f32.eq",
700 // [WasmOpcode_f32_ne] = "f32.ne",
701 // [WasmOpcode_f32_lt] = "f32.lt",
702 // [WasmOpcode_f32_gt] = "f32.gt",
703 // [WasmOpcode_f32_le] = "f32.le",
704 // [WasmOpcode_f32_ge] = "f32.ge",
705 //
706 // [WasmOpcode_f64_eq] = "f64.eq",
707 // [WasmOpcode_f64_ne] = "f64.ne",
708 // [WasmOpcode_f64_lt] = "f64.lt",
709 // [WasmOpcode_f64_gt] = "f64.gt",
710 // [WasmOpcode_f64_le] = "f64.le",
711 // [WasmOpcode_f64_ge] = "f64.ge",
712 //
713 // [WasmOpcode_i32_clz] = "i32.clz",
714 // [WasmOpcode_i32_ctz] = "i32.ctz",
715 // [WasmOpcode_i32_popcnt] = "i32.popcnt",
716 // [WasmOpcode_i32_add] = "i32.add",
717 // [WasmOpcode_i32_sub] = "i32.sub",
718 // [WasmOpcode_i32_mul] = "i32.mul",
719 // [WasmOpcode_i32_div_s] = "i32.div_s",
720 // [WasmOpcode_i32_div_u] = "i32.div_u",
721 // [WasmOpcode_i32_rem_s] = "i32.rem_s",
722 // [WasmOpcode_i32_rem_u] = "i32.rem_u",
723 // [WasmOpcode_i32_and] = "i32.and",
724 // [WasmOpcode_i32_or] = "i32.or",
725 // [WasmOpcode_i32_xor] = "i32.xor",
726 // [WasmOpcode_i32_shl] = "i32.shl",
727 // [WasmOpcode_i32_shr_s] = "i32.shr_s",
728 // [WasmOpcode_i32_shr_u] = "i32.shr_u",
729 // [WasmOpcode_i32_rotl] = "i32.rotl",
730 // [WasmOpcode_i32_rotr] = "i32.rotr",
731 //
732 // [WasmOpcode_i64_clz] = "i64.clz",
733 // [WasmOpcode_i64_ctz] = "i64.ctz",
734 // [WasmOpcode_i64_popcnt] = "i64.popcnt",
735 // [WasmOpcode_i64_add] = "i64.add",
736 // [WasmOpcode_i64_sub] = "i64.sub",
737 // [WasmOpcode_i64_mul] = "i64.mul",
738 // [WasmOpcode_i64_div_s] = "i64.div_s",
739 // [WasmOpcode_i64_div_u] = "i64.div_u",
740 // [WasmOpcode_i64_rem_s] = "i64.rem_s",
741 // [WasmOpcode_i64_rem_u] = "i64.rem_u",
742 // [WasmOpcode_i64_and] = "i64.and",
743 // [WasmOpcode_i64_or] = "i64.or",
744 // [WasmOpcode_i64_xor] = "i64.xor",
745 // [WasmOpcode_i64_shl] = "i64.shl",
746 // [WasmOpcode_i64_shr_s] = "i64.shr_s",
747 // [WasmOpcode_i64_shr_u] = "i64.shr_u",
748 // [WasmOpcode_i64_rotl] = "i64.rotl",
749 // [WasmOpcode_i64_rotr] = "i64.rotr",
750 //
751 // [WasmOpcode_f32_abs] = "f32.abs",
752 // [WasmOpcode_f32_neg] = "f32.neg",
753 // [WasmOpcode_f32_ceil] = "f32.ceil",
754 // [WasmOpcode_f32_floor] = "f32.floor",
755 // [WasmOpcode_f32_trunc] = "f32.trunc",
756 // [WasmOpcode_f32_nearest] = "f32.nearest",
757 // [WasmOpcode_f32_sqrt] = "f32.sqrt",
758 // [WasmOpcode_f32_add] = "f32.add",
759 // [WasmOpcode_f32_sub] = "f32.sub",
760 // [WasmOpcode_f32_mul] = "f32.mul",
761 // [WasmOpcode_f32_div] = "f32.div",
762 // [WasmOpcode_f32_min] = "f32.min",
763 // [WasmOpcode_f32_max] = "f32.max",
764 // [WasmOpcode_f32_copysign] = "f32.copysign",
765 //
766 // [WasmOpcode_f64_abs] = "f64.abs",
767 // [WasmOpcode_f64_neg] = "f64.neg",
768 // [WasmOpcode_f64_ceil] = "f64.ceil",
769 // [WasmOpcode_f64_floor] = "f64.floor",
770 // [WasmOpcode_f64_trunc] = "f64.trunc",
771 // [WasmOpcode_f64_nearest] = "f64.nearest",
772 // [WasmOpcode_f64_sqrt] = "f64.sqrt",
773 // [WasmOpcode_f64_add] = "f64.add",
774 // [WasmOpcode_f64_sub] = "f64.sub",
775 // [WasmOpcode_f64_mul] = "f64.mul",
776 // [WasmOpcode_f64_div] = "f64.div",
777 // [WasmOpcode_f64_min] = "f64.min",
778 // [WasmOpcode_f64_max] = "f64.max",
779 // [WasmOpcode_f64_copysign] = "f64.copysign",
780 //
781 // [WasmOpcode_i32_wrap_i64] = "i32.wrap_i64",
782 // [WasmOpcode_i32_trunc_f32_s] = "i32.trunc_f32_s",
783 // [WasmOpcode_i32_trunc_f32_u] = "i32.trunc_f32_u",
784 // [WasmOpcode_i32_trunc_f64_s] = "i32.trunc_f64_s",
785 // [WasmOpcode_i32_trunc_f64_u] = "i32.trunc_f64_u",
786 // [WasmOpcode_i64_extend_i32_s] = "i64.extend_i32_s",
787 // [WasmOpcode_i64_extend_i32_u] = "i64.extend_i32_u",
788 // [WasmOpcode_i64_trunc_f32_s] = "i64.trunc_f32_s",
789 // [WasmOpcode_i64_trunc_f32_u] = "i64.trunc_f32_u",
790 // [WasmOpcode_i64_trunc_f64_s] = "i64.trunc_f64_s",
791 // [WasmOpcode_i64_trunc_f64_u] = "i64.trunc_f64_u",
792 // [WasmOpcode_f32_convert_i32_s] = "f32.convert_i32_s",
793 // [WasmOpcode_f32_convert_i32_u] = "f32.convert_i32_u",
794 // [WasmOpcode_f32_convert_i64_s] = "f32.convert_i64_s",
795 // [WasmOpcode_f32_convert_i64_u] = "f32.convert_i64_u",
796 // [WasmOpcode_f32_demote_f64] = "f32.demote_f64",
797 // [WasmOpcode_f64_convert_i32_s] = "f64.convert_i32_s",
798 // [WasmOpcode_f64_convert_i32_u] = "f64.convert_i32_u",
799 // [WasmOpcode_f64_convert_i64_s] = "f64.convert_i64_s",
800 // [WasmOpcode_f64_convert_i64_u] = "f64.convert_i64_u",
801 // [WasmOpcode_f64_promote_f32] = "f64.promote_f32",
802 // [WasmOpcode_i32_reinterpret_f32] = "i32.reinterpret_f32",
803 // [WasmOpcode_i64_reinterpret_f64] = "i64.reinterpret_f64",
804 // [WasmOpcode_f32_reinterpret_i32] = "f32.reinterpret_i32",
805 // [WasmOpcode_f64_reinterpret_i64] = "f64.reinterpret_i64",
806 //
807 // [WasmOpcode_i32_extend8_s] = "i32.extend8_s",
808 // [WasmOpcode_i32_extend16_s] = "i32.extend16_s",
809 // [WasmOpcode_i64_extend8_s] = "i64.extend8_s",
810 // [WasmOpcode_i64_extend16_s] = "i64.extend16_s",
811 // [WasmOpcode_i64_extend32_s] = "i64.extend32_s",
812 //
813 // [WasmOpcode_prefixed] = "prefixed",
814 //};
815 uint8_t opcode = InputStream_readByte(&in);
816 //FuncGen_indent(&fg, out);
817 //fprintf(out, "// %2u: ", fg.stack_i);
818 //if (mnemonics[opcode])
819 // fprintf(out, "%s\n", mnemonics[opcode]);
820 //else
821 // fprintf(out, "%02hhX\n", opcode);
822 //fflush(out); // DEBUG
823 switch (opcode) {
824 case WasmOpcode_unreachable:
825 if (unreachable_depth == 0) {
826 FuncGen_indent(&fg, out);
827 fprintf(out, "abort();\n");
828 unreachable_depth += 1;
829 }
830 break;
831 case WasmOpcode_nop:
832 break;
833 case WasmOpcode_block:
834 case WasmOpcode_loop:
835 case WasmOpcode_if: {
836 int64_t block_type = InputStream_readLeb128_i64(&in);
837 if (unreachable_depth == 0) {
838 const struct FuncType *func_type = FuncType_blockType(types, block_type);
839 for (uint32_t param_i = func_type->param->len; param_i > 0; ) {
840 param_i -= 1;
841 FuncGen_indent(&fg, out);
842 param_stash[param_i] =
843 FuncGen_localDeclare(&fg, out, func_type->param->types[param_i]);
844 fprintf(out, " = l%" PRIu32 ";\n", FuncGen_stackPop(&fg));
845 }
846 for (uint32_t result_i = func_type->result->len; result_i > 0; ) {
847 result_i -= 1;
848 FuncGen_indent(&fg, out);
849 (void)FuncGen_localDeclare(&fg, out,
850 func_type->result->types[result_i]);
851 fputs(";\n", out);
852 }
853 FuncGen_blockBegin(&fg, out, opcode, block_type);
854 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
855 FuncGen_stackPush(&fg, out, func_type->param->types[param_i]);
856 fprintf(out, " = l%" PRIu32 ";\n", param_stash[param_i]);
857 }
858 } else unreachable_depth += 1;
859 break;
860 }
861 case WasmOpcode_else:
862 case WasmOpcode_end:
863 if (unreachable_depth <= 1) {
864 const struct ResultType *result_type =
865 FuncType_blockType(types, FuncGen_blockType(&fg, 0))->result;
866 uint32_t label = FuncGen_blockLabel(&fg, 0);
867 if (unreachable_depth == 0) {
868 const struct ResultType *result_type =
869 FuncType_blockType(types, FuncGen_blockType(&fg, 0))->result;
870 for (uint32_t result_i = result_type->len; result_i > 0; ) {
871 result_i -= 1;
872 FuncGen_indent(&fg, out);
873 fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n",
874 label - result_type->len + result_i, FuncGen_stackPop(&fg));
875 }
876 } else unreachable_depth -= 1;
877 switch (opcode) {
878 case WasmOpcode_else:
879 FuncGen_reuseReset(&fg);
880 FuncGen_outdent(&fg, out);
881 fputs("} else {\n", out);
882 break;
883 case WasmOpcode_end:
884 FuncGen_blockEnd(&fg, out);
885 for (uint32_t result_i = 0; result_i < result_type->len;
886 result_i += 1) {
887 FuncGen_stackPush(&fg, out, result_type->types[result_i]);
888 fprintf(out, "l%" PRIu32 ";\n",
889 label - result_type->len + result_i);
890 }
891 break;
892 }
893 } else if (opcode == WasmOpcode_end) unreachable_depth -= 1;
894 break;
895 case WasmOpcode_br:
896 case WasmOpcode_br_if: {
897 uint32_t label_idx = InputStream_readLeb128_u32(&in);
898 if (unreachable_depth == 0) {
899 enum WasmOpcode kind = FuncGen_blockKind(&fg, label_idx);
900 const struct FuncType *func_type =
901 FuncType_blockType(types, FuncGen_blockType(&fg, label_idx));
902 uint32_t label = FuncGen_blockLabel(&fg, label_idx);
903
904 if (opcode == WasmOpcode_br_if) {
905 FuncGen_indent(&fg, out);
906 fprintf(out, "if (l%" PRIu32 ") {\n", FuncGen_stackPop(&fg));
907 } else if (EXTRA_BRACES) {
908 FuncGen_indent(&fg, out);
909 fputs("{\n", out);
910 }
911
912 const struct ResultType *label_type;
913 uint32_t lhs;
914 switch (kind) {
915 case WasmOpcode_loop:
916 label_type = func_type->param;
917 lhs = label - func_type->result->len - func_type->param->len;
918 break;
919 default:
920 label_type = func_type->result;
921 lhs = label - func_type->result->len;
922 break;
923 }
924 for (uint32_t stack_i = 0; stack_i < label_type->len; stack_i += 1) {
925 uint32_t rhs;
926 switch (opcode) {
927 case WasmOpcode_br:
928 rhs = FuncGen_stackPop(&fg);
929 break;
930 case WasmOpcode_br_if:
931 rhs = FuncGen_stackAt(&fg, stack_i);
932 break;
933 default: panic("unexpected opcode");
934 }
935 FuncGen_cont(&fg, out);
936 fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n", lhs, rhs);
937 lhs += 1;
938 }
939 FuncGen_cont(&fg, out);
940 fprintf(out, "goto l%" PRIu32 ";\n", label);
941 if (EXTRA_BRACES || opcode == WasmOpcode_br_if) {
942 FuncGen_indent(&fg, out);
943 fputs("}\n", out);
944 }
945 if (opcode == WasmOpcode_br) unreachable_depth += 1;
946 }
947 break;
948 }
949 case WasmOpcode_br_table: {
950 if (unreachable_depth == 0) {
951 FuncGen_indent(&fg, out);
952 fprintf(out, "switch (l%" PRIu32 ") {\n", FuncGen_stackPop(&fg));
953 }
954 uint32_t label_len = InputStream_readLeb128_u32(&in);
955 for (uint32_t i = 0; i < label_len; i += 1) {
956 uint32_t label = InputStream_readLeb128_u32(&in);
957 if (unreachable_depth == 0) {
958 FuncGen_indent(&fg, out);
959 fprintf(out, "case %u: goto l%" PRIu32 ";\n",
960 i, FuncGen_blockLabel(&fg, label));
961 }
962 }
963 uint32_t label = InputStream_readLeb128_u32(&in);
964 if (unreachable_depth == 0) {
965 FuncGen_indent(&fg, out);
966 fprintf(out, "default: goto l%" PRIu32 ";\n",
967 FuncGen_blockLabel(&fg, label));
968 FuncGen_indent(&fg, out);
969 fputs("}\n", out);
970 unreachable_depth += 1;
971 }
972 break;
973 }
974 case WasmOpcode_return:
975 if (unreachable_depth == 0) {
976 FuncGen_indent(&fg, out);
977 fputs("return", out);
978 switch (func_type->result->len) {
979 case 0: break;
980 case 1: fprintf(out, " l%" PRIu32, FuncGen_stackPop(&fg)); break;
981 default: panic("multiple function returns not supported");
982 }
983 fputs(";\n", out);
984 unreachable_depth += 1;
985 }
986 break;
987 case WasmOpcode_call:
988 case WasmOpcode_call_indirect: {
989 uint32_t func_id;
990 uint32_t type_idx;
991 uint32_t table_idx;
992 switch (opcode) {
993 case WasmOpcode_call:
994 func_id = InputStream_readLeb128_u32(&in);
995 if (func_id < imports_len)
996 type_idx = imports[func_id].type_idx;
997 else
998 type_idx = funcs[func_id - imports_len].type_idx;
999 break;
1000 case WasmOpcode_call_indirect:
1001 type_idx = InputStream_readLeb128_u32(&in);
1002 table_idx = InputStream_readLeb128_u32(&in);
1003 func_id = FuncGen_stackPop(&fg);
1004 break;
1005 }
1006 if (unreachable_depth == 0) {
1007 const struct FuncType *callee_func_type = &types[type_idx];
1008 for (uint32_t param_i = callee_func_type->param->len; param_i > 0; ) {
1009 param_i -= 1;
1010 param_stash[param_i] = FuncGen_stackPop(&fg);
1011 }
1012 switch (callee_func_type->result->len) {
1013 case 0: FuncGen_indent(&fg, out); break;
1014 case 1: FuncGen_stackPush(&fg, out, callee_func_type->result->types[0]); break;
1015 default: panic("multiple function returns not supported");
1016 }
1017 switch (opcode) {
1018 case WasmOpcode_call:
1019 if (func_id < imports_len)
1020 fprintf(out, "%s_%s", imports[func_id].mod, imports[func_id].name);
1021 else
1022 fprintf(out, "f%" PRIu32, func_id - imports_len);
1023 break;
1024 case WasmOpcode_call_indirect:
1025 fputs("(*(", out);
1026 switch (callee_func_type->result->len) {
1027 case 0: fputs("void", out); break;
1028 case 1: fputs(WasmValType_toC(callee_func_type->result->types[0]), out); break;
1029 default: panic("multiple function returns not supported");
1030 }
1031 fputs(" (*)(", out);
1032 if (callee_func_type->param->len == 0) fputs("void", out);
1033 for (uint32_t param_i = 0; param_i < callee_func_type->param->len; param_i += 1) {
1034 if (param_i > 0) fputs(", ", out);
1035 fputs(WasmValType_toC(callee_func_type->param->types[param_i]), out);
1036 }
1037 fprintf(out, "))t%" PRIu32 "[l%" PRIu32 "])", table_idx, func_id);
1038 break;
1039 }
1040 fputc('(', out);
1041 for (uint32_t param_i = 0; param_i < callee_func_type->param->len;
1042 param_i += 1) {
1043 if (param_i > 0) fputs(", ", out);
1044 fprintf(out, "l%" PRIu32, param_stash[param_i]);
1045 }
1046 fputs(");\n", out);
1047 }
1048 break;
1049 }
1050
1051 case WasmOpcode_drop:
1052 if (unreachable_depth == 0) {
1053 FuncGen_indent(&fg, out);
1054 fprintf(out, "(void)l%" PRIu32 ";\n", FuncGen_stackPop(&fg));
1055 }
1056 break;
1057 case WasmOpcode_select:
1058 if (unreachable_depth == 0) {
1059 uint32_t cond = FuncGen_stackPop(&fg);
1060 uint32_t rhs = FuncGen_stackPop(&fg);
1061 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1062 FuncGen_indent(&fg, out);
1063 fprintf(out, "l%"PRIu32" = l%" PRIu32 " ? l%" PRIu32 " : l%" PRIu32 ";\n",
1064 lhs, cond, lhs, rhs);
1065 }
1066 break;
1067
1068 case WasmOpcode_local_get: {
1069 uint32_t local_idx = InputStream_readLeb128_u32(&in);
1070 if (unreachable_depth == 0) {
1071 if (local_idx < func_type->param->len) param_used[local_idx] = true;
1072 FuncGen_stackPush(&fg, out, FuncGen_localType(&fg, local_idx));
1073 fprintf(out, "l%" PRIu32 ";\n", local_idx);
1074 }
1075 break;
1076 }
1077 case WasmOpcode_local_set: {
1078 uint32_t local_idx = InputStream_readLeb128_u32(&in);
1079 if (unreachable_depth == 0) {
1080 if (local_idx < func_type->param->len) param_used[local_idx] = true;
1081 FuncGen_indent(&fg, out);
1082 fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n",
1083 local_idx, FuncGen_stackPop(&fg));
1084 }
1085 break;
1086 }
1087 case WasmOpcode_local_tee: {
1088 uint32_t local_idx = InputStream_readLeb128_u32(&in);
1089 if (unreachable_depth == 0) {
1090 if (local_idx < func_type->param->len) param_used[local_idx] = true;
1091 FuncGen_indent(&fg, out);
1092 fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n",
1093 local_idx, FuncGen_stackAt(&fg, 0));
1094 }
1095 break;
1096 }
1097
1098 case WasmOpcode_global_get: {
1099 uint32_t global_idx = InputStream_readLeb128_u32(&in);
1100 if (unreachable_depth == 0) {
1101 FuncGen_stackPush(&fg, out, globals[global_idx].val_type);
1102 fprintf(out, "g%" PRIu32 ";\n", global_idx);
1103 }
1104 break;
1105 }
1106 case WasmOpcode_global_set: {
1107 uint32_t global_idx = InputStream_readLeb128_u32(&in);
1108 if (unreachable_depth == 0) {
1109 FuncGen_indent(&fg, out);
1110 fprintf(out, "g%" PRIu32 " = l%" PRIu32 ";\n",
1111 global_idx, FuncGen_stackPop(&fg));
1112 }
1113 break;
1114 }
1115
1116 case WasmOpcode_table_get:
1117 case WasmOpcode_table_set:
1118 (void)InputStream_readLeb128_u32(&in);
1119 if (unreachable_depth == 0) panic("unimplemented opcode");
1120 break;
1121
1122 case WasmOpcode_i32_load: {
1123 uint32_t align = InputStream_readLeb128_u32(&in);
1124 uint32_t offset = InputStream_readLeb128_u32(&in);
1125 if (unreachable_depth == 0) {
1126 uint32_t base = FuncGen_stackPop(&fg);
1127 FuncGen_stackPush(&fg, out, WasmValType_i32);
1128 fprintf(out, "load32_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" PRIu32
1129 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
1130 align, 8 << align, 0, base, offset);
1131 }
1132 break;
1133 }
1134 case WasmOpcode_i64_load: {
1135 uint32_t align = InputStream_readLeb128_u32(&in);
1136 uint32_t offset = InputStream_readLeb128_u32(&in);
1137 if (unreachable_depth == 0) {
1138 uint32_t base = FuncGen_stackPop(&fg);
1139 FuncGen_stackPush(&fg, out, WasmValType_i64);
1140 fprintf(out, "load64_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" PRIu32
1141 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
1142 align, 8 << align, 0, base, offset);
1143 }
1144 break;
1145 }
1146 case WasmOpcode_f32_load: {
1147 uint32_t align = InputStream_readLeb128_u32(&in);
1148 uint32_t offset = InputStream_readLeb128_u32(&in);
1149 if (unreachable_depth == 0) {
1150 uint32_t base = FuncGen_stackPop(&fg);
1151 FuncGen_stackPush(&fg, out, WasmValType_f32);
1152 fprintf(out, "f32_reinterpret_i32(load32_align%" PRIu32 "((const uint%" PRIu32
1153 "_t *)&m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]));\n",
1154 align, 8 << align, 0, base, offset);
1155 }
1156 break;
1157 }
1158 case WasmOpcode_f64_load: {
1159 uint32_t align = InputStream_readLeb128_u32(&in);
1160 uint32_t offset = InputStream_readLeb128_u32(&in);
1161 if (unreachable_depth == 0) {
1162 uint32_t base = FuncGen_stackPop(&fg);
1163 FuncGen_stackPush(&fg, out, WasmValType_f64);
1164 fprintf(out, "f64_reinterpret_i64(load64_align%" PRIu32 "((const uint%" PRIu32
1165 "_t *)&m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]));\n",
1166 align, 8 << align, 0, base, offset);
1167 }
1168 break;
1169 }
1170 case WasmOpcode_i32_load8_s: {
1171 (void)InputStream_readLeb128_u32(&in);
1172 uint32_t offset = InputStream_readLeb128_u32(&in);
1173 if (unreachable_depth == 0) {
1174 uint32_t base = FuncGen_stackPop(&fg);
1175 FuncGen_stackPush(&fg, out, WasmValType_i32);
1176 fprintf(out, "(int8_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
1177 0, base, offset);
1178 }
1179 break;
1180 }
1181 case WasmOpcode_i32_load8_u: {
1182 (void)InputStream_readLeb128_u32(&in);
1183 uint32_t offset = InputStream_readLeb128_u32(&in);
1184 if (unreachable_depth == 0) {
1185 uint32_t base = FuncGen_stackPop(&fg);
1186 FuncGen_stackPush(&fg, out, WasmValType_i32);
1187 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
1188 0, base, offset);
1189 }
1190 break;
1191 }
1192 case WasmOpcode_i32_load16_s: {
1193 uint32_t align = InputStream_readLeb128_u32(&in);
1194 uint32_t offset = InputStream_readLeb128_u32(&in);
1195 if (unreachable_depth == 0) {
1196 uint32_t base = FuncGen_stackPop(&fg);
1197 FuncGen_stackPush(&fg, out, WasmValType_i32);
1198 fprintf(out, "(int16_t)load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%"
1199 PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
1200 align, 8 << align, 0, base, offset);
1201 }
1202 break;
1203 }
1204 case WasmOpcode_i32_load16_u: {
1205 uint32_t align = InputStream_readLeb128_u32(&in);
1206 uint32_t offset = InputStream_readLeb128_u32(&in);
1207 if (unreachable_depth == 0) {
1208 uint32_t base = FuncGen_stackPop(&fg);
1209 FuncGen_stackPush(&fg, out, WasmValType_i32);
1210 fprintf(out, "load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%"
1211 PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
1212 align, 8 << align, 0, base, offset);
1213 }
1214 break;
1215 }
1216 case WasmOpcode_i64_load8_s: {
1217 (void)InputStream_readLeb128_u32(&in);
1218 uint32_t offset = InputStream_readLeb128_u32(&in);
1219 if (unreachable_depth == 0) {
1220 uint32_t base = FuncGen_stackPop(&fg);
1221 FuncGen_stackPush(&fg, out, WasmValType_i64);
1222 fprintf(out, "(int8_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
1223 0, base, offset);
1224 }
1225 break;
1226 }
1227 case WasmOpcode_i64_load8_u: {
1228 (void)InputStream_readLeb128_u32(&in);
1229 uint32_t offset = InputStream_readLeb128_u32(&in);
1230 if (unreachable_depth == 0) {
1231 uint32_t base = FuncGen_stackPop(&fg);
1232 FuncGen_stackPush(&fg, out, WasmValType_i64);
1233 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
1234 0, base, offset);
1235 }
1236 break;
1237 }
1238 case WasmOpcode_i64_load16_s: {
1239 uint32_t align = InputStream_readLeb128_u32(&in);
1240 uint32_t offset = InputStream_readLeb128_u32(&in);
1241 if (unreachable_depth == 0) {
1242 uint32_t base = FuncGen_stackPop(&fg);
1243 FuncGen_stackPush(&fg, out, WasmValType_i64);
1244 fprintf(out, "(int16_t)load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%"
1245 PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
1246 align, 8 << align, 0, base, offset);
1247 }
1248 break;
1249 }
1250 case WasmOpcode_i64_load16_u: {
1251 uint32_t align = InputStream_readLeb128_u32(&in);
1252 uint32_t offset = InputStream_readLeb128_u32(&in);
1253 if (unreachable_depth == 0) {
1254 uint32_t base = FuncGen_stackPop(&fg);
1255 FuncGen_stackPush(&fg, out, WasmValType_i64);
1256 fprintf(out, "load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%"
1257 PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
1258 align, 8 << align, 0, base, offset);
1259 }
1260 break;
1261 }
1262 case WasmOpcode_i64_load32_s: {
1263 uint32_t align = InputStream_readLeb128_u32(&in);
1264 uint32_t offset = InputStream_readLeb128_u32(&in);
1265 if (unreachable_depth == 0) {
1266 uint32_t base = FuncGen_stackPop(&fg);
1267 FuncGen_stackPush(&fg, out, WasmValType_i64);
1268 fprintf(out, "(int32_t)load32_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%"
1269 PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
1270 align, 8 << align, 0, base, offset);
1271 }
1272 break;
1273 }
1274 case WasmOpcode_i64_load32_u: {
1275 uint32_t align = InputStream_readLeb128_u32(&in);
1276 uint32_t offset = InputStream_readLeb128_u32(&in);
1277 if (unreachable_depth == 0) {
1278 uint32_t base = FuncGen_stackPop(&fg);
1279 FuncGen_stackPush(&fg, out, WasmValType_i64);
1280 fprintf(out, "load32_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%"
1281 PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
1282 align, 8 << align, 0, base, offset);
1283 }
1284 break;
1285 }
1286
1287 case WasmOpcode_i32_store: {
1288 uint32_t align = InputStream_readLeb128_u32(&in);
1289 uint32_t offset = InputStream_readLeb128_u32(&in);
1290 if (unreachable_depth == 0) {
1291 uint32_t value = FuncGen_stackPop(&fg);
1292 uint32_t base = FuncGen_stackPop(&fg);
1293 FuncGen_indent(&fg, out);
1294 fprintf(out, "store32_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
1295 PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], l%" PRIu32 ");\n",
1296 align, 8 << align, 0, base, offset, value);
1297 }
1298 break;
1299 }
1300 case WasmOpcode_i64_store: {
1301 uint32_t align = InputStream_readLeb128_u32(&in);
1302 uint32_t offset = InputStream_readLeb128_u32(&in);
1303 if (unreachable_depth == 0) {
1304 uint32_t value = FuncGen_stackPop(&fg);
1305 uint32_t base = FuncGen_stackPop(&fg);
1306 FuncGen_indent(&fg, out);
1307 fprintf(out, "store64_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
1308 PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], l%" PRIu32 ");\n",
1309 align, 8 << align, 0, base, offset, value);
1310 }
1311 break;
1312 }
1313 case WasmOpcode_f32_store: {
1314 uint32_t align = InputStream_readLeb128_u32(&in);
1315 uint32_t offset = InputStream_readLeb128_u32(&in);
1316 if (unreachable_depth == 0) {
1317 uint32_t value = FuncGen_stackPop(&fg);
1318 uint32_t base = FuncGen_stackPop(&fg);
1319 FuncGen_indent(&fg, out);
1320 fprintf(out, "store32_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
1321 PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], "
1322 "i32_reinterpret_f32(l%" PRIu32 "));\n",
1323 align, 8 << align, 0, base, offset, value);
1324 }
1325 break;
1326 }
1327 case WasmOpcode_f64_store: {
1328 uint32_t align = InputStream_readLeb128_u32(&in);
1329 uint32_t offset = InputStream_readLeb128_u32(&in);
1330 if (unreachable_depth == 0) {
1331 uint32_t value = FuncGen_stackPop(&fg);
1332 uint32_t base = FuncGen_stackPop(&fg);
1333 FuncGen_indent(&fg, out);
1334 fprintf(out, "store64_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
1335 PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], "
1336 "i64_reinterpret_f64(l%" PRIu32 "));\n",
1337 align, 8 << align, 0, base, offset, value);
1338 }
1339 break;
1340 }
1341 case WasmOpcode_i32_store8: {
1342 (void)InputStream_readLeb128_u32(&in);
1343 uint32_t offset = InputStream_readLeb128_u32(&in);
1344 if (unreachable_depth == 0) {
1345 uint32_t value = FuncGen_stackPop(&fg);
1346 uint32_t base = FuncGen_stackPop(&fg);
1347 FuncGen_indent(&fg, out);
1348 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32
1349 ")] = (uint8_t)l%" PRIu32 ";\n", 0, base, offset, value);
1350 }
1351 break;
1352 }
1353 case WasmOpcode_i32_store16: {
1354 uint32_t align = InputStream_readLeb128_u32(&in);
1355 uint32_t offset = InputStream_readLeb128_u32(&in);
1356 if (unreachable_depth == 0) {
1357 uint32_t value = FuncGen_stackPop(&fg);
1358 uint32_t base = FuncGen_stackPop(&fg);
1359 FuncGen_indent(&fg, out);
1360 fprintf(out, "store16_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
1361 PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], "
1362 "(uint16_t)l%" PRIu32 ");\n",
1363 align, 8 << align, 0, base, offset, value);
1364 }
1365 break;
1366 }
1367 case WasmOpcode_i64_store8: {
1368 (void)InputStream_readLeb128_u32(&in);
1369 uint32_t offset = InputStream_readLeb128_u32(&in);
1370 if (unreachable_depth == 0) {
1371 uint32_t value = FuncGen_stackPop(&fg);
1372 uint32_t base = FuncGen_stackPop(&fg);
1373 FuncGen_indent(&fg, out);
1374 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32
1375 ")] = (uint8_t)l%" PRIu32 ";\n", 0, base, offset, value);
1376 }
1377 break;
1378 }
1379 case WasmOpcode_i64_store16: {
1380 uint32_t align = InputStream_readLeb128_u32(&in);
1381 uint32_t offset = InputStream_readLeb128_u32(&in);
1382 if (unreachable_depth == 0) {
1383 uint32_t value = FuncGen_stackPop(&fg);
1384 uint32_t base = FuncGen_stackPop(&fg);
1385 FuncGen_indent(&fg, out);
1386 fprintf(out, "store16_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
1387 PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], "
1388 "(uint16_t)l%" PRIu32 ");\n",
1389 align, 8 << align, 0, base, offset, value);
1390 }
1391 break;
1392 }
1393 case WasmOpcode_i64_store32: {
1394 uint32_t align = InputStream_readLeb128_u32(&in);
1395 uint32_t offset = InputStream_readLeb128_u32(&in);
1396 if (unreachable_depth == 0) {
1397 uint32_t value = FuncGen_stackPop(&fg);
1398 uint32_t base = FuncGen_stackPop(&fg);
1399 FuncGen_indent(&fg, out);
1400 fprintf(out, "store32_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
1401 PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], "
1402 "(uint32_t)l%" PRIu32 ");\n",
1403 align, 8 << align, 0, base, offset, value);
1404 }
1405 break;
1406 }
1407
1408 case WasmOpcode_memory_size: {
1409 uint32_t mem_idx = InputStream_readLeb128_u32(&in);
1410 if (unreachable_depth == 0) {
1411 FuncGen_stackPush(&fg, out, WasmValType_i32);
1412 fprintf(out, "p%" PRIu32 ";\n", mem_idx);
1413 }
1414 break;
1415 }
1416 case WasmOpcode_memory_grow: {
1417 uint32_t mem_idx = InputStream_readLeb128_u32(&in);
1418 if (unreachable_depth == 0) {
1419 uint32_t pages = FuncGen_stackPop(&fg);
1420 FuncGen_stackPush(&fg, out, WasmValType_i32);
1421 fprintf(out, "memory_grow(&m%" PRIu32 ", &p%" PRIu32 ", &c%" PRIu32
1422 ", l%" PRIu32 ");\n", mem_idx, mem_idx, mem_idx, pages);
1423 }
1424 break;
1425 }
1426
1427 case WasmOpcode_i32_const: {
1428 uint32_t value = (uint32_t)InputStream_readLeb128_i32(&in);
1429 if (unreachable_depth == 0) {
1430 FuncGen_stackPush(&fg, out, WasmValType_i32);
1431 fprintf(out, "UINT32_C(0x%" PRIX32 ");\n", value);
1432 }
1433 break;
1434 }
1435 case WasmOpcode_i64_const: {
1436 uint64_t value = (uint64_t)InputStream_readLeb128_i64(&in);
1437 if (unreachable_depth == 0) {
1438 FuncGen_stackPush(&fg, out, WasmValType_i64);
1439 fprintf(out, "UINT64_C(0x%" PRIX64 ");\n", value);
1440 }
1441 break;
1442 }
1443 case WasmOpcode_f32_const: {
1444 uint32_t value = InputStream_readLittle_u32(&in);
1445 if (unreachable_depth == 0) {
1446 FuncGen_stackPush(&fg, out, WasmValType_f32);
1447 fprintf(out, "f32_reinterpret_i32(UINT32_C(0x%" PRIX32 "));\n", value);
1448 }
1449 break;
1450 }
1451 case WasmOpcode_f64_const: {
1452 uint64_t value = InputStream_readLittle_u64(&in);
1453 if (unreachable_depth == 0) {
1454 FuncGen_stackPush(&fg, out, WasmValType_f64);
1455 fprintf(out, "f64_reinterpret_i64(UINT64_C(0x%" PRIX64 "));\n", value);
1456 }
1457 break;
1458 }
1459
1460 case WasmOpcode_i32_eqz:
1461 if (unreachable_depth == 0) {
1462 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1463 FuncGen_indent(&fg, out);
1464 fprintf(out, "l%" PRIu32 " = !l%" PRIu32 ";\n", lhs, lhs);
1465 }
1466 break;
1467 case WasmOpcode_i32_eq:
1468 case WasmOpcode_i32_ne:
1469 case WasmOpcode_i32_lt_u:
1470 case WasmOpcode_i32_gt_u:
1471 case WasmOpcode_i32_le_u:
1472 case WasmOpcode_i32_ge_u:
1473 // i32 unsigned comparisons
1474 if (unreachable_depth == 0) {
1475 uint32_t rhs = FuncGen_stackPop(&fg);
1476 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1477 const char *operator;
1478 switch (opcode) {
1479 case WasmOpcode_i32_eq: operator = "=="; break;
1480 case WasmOpcode_i32_ne: operator = "!="; break;
1481 case WasmOpcode_i32_lt_u: operator = "<"; break;
1482 case WasmOpcode_i32_gt_u: operator = ">"; break;
1483 case WasmOpcode_i32_le_u: operator = "<="; break;
1484 case WasmOpcode_i32_ge_u: operator = ">="; break;
1485 default: panic("unreachable");
1486 }
1487 FuncGen_indent(&fg, out);
1488 fprintf(out, "l%" PRIu32 " = l%" PRIu32 " %s l%" PRIu32 ";\n",
1489 lhs, lhs, operator, rhs);
1490 }
1491 break;
1492 case WasmOpcode_i32_lt_s:
1493 case WasmOpcode_i32_gt_s:
1494 case WasmOpcode_i32_le_s:
1495 case WasmOpcode_i32_ge_s:
1496 // i32 signed comparisons
1497 if (unreachable_depth == 0) {
1498 uint32_t rhs = FuncGen_stackPop(&fg);
1499 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1500 const char *operator;
1501 switch (opcode) {
1502 case WasmOpcode_i32_lt_s: operator = "<"; break;
1503 case WasmOpcode_i32_gt_s: operator = ">"; break;
1504 case WasmOpcode_i32_le_s: operator = "<="; break;
1505 case WasmOpcode_i32_ge_s: operator = ">="; break;
1506 default: panic("unreachable");
1507 }
1508 FuncGen_indent(&fg, out);
1509 fprintf(out, "l%" PRIu32 " = (int32_t)l%" PRIu32 " %s (int32_t)l%" PRIu32
1510 ";\n", lhs, lhs, operator, rhs);
1511 }
1512 break;
1513
1514 case WasmOpcode_i64_eqz:
1515 if (unreachable_depth == 0) {
1516 uint32_t lhs = FuncGen_stackPop(&fg);
1517 FuncGen_stackPush(&fg, out, WasmValType_i32);
1518 fprintf(out, "!l%" PRIu32 ";\n", lhs);
1519 }
1520 break;
1521 case WasmOpcode_i64_eq:
1522 case WasmOpcode_i64_ne:
1523 case WasmOpcode_i64_lt_u:
1524 case WasmOpcode_i64_gt_u:
1525 case WasmOpcode_i64_le_u:
1526 case WasmOpcode_i64_ge_u:
1527 case WasmOpcode_f32_eq:
1528 case WasmOpcode_f32_ne:
1529 case WasmOpcode_f32_lt:
1530 case WasmOpcode_f32_gt:
1531 case WasmOpcode_f32_le:
1532 case WasmOpcode_f32_ge:
1533 case WasmOpcode_f64_eq:
1534 case WasmOpcode_f64_ne:
1535 case WasmOpcode_f64_lt:
1536 case WasmOpcode_f64_gt:
1537 case WasmOpcode_f64_le:
1538 case WasmOpcode_f64_ge:
1539 // non-i32 unsigned comparisons
1540 if (unreachable_depth == 0) {
1541 uint32_t rhs = FuncGen_stackPop(&fg);
1542 uint32_t lhs = FuncGen_stackPop(&fg);
1543 const char *operator;
1544 switch (opcode) {
1545 case WasmOpcode_i64_eq:
1546 case WasmOpcode_f32_eq:
1547 case WasmOpcode_f64_eq:
1548 operator = "==";
1549 break;
1550 case WasmOpcode_i64_ne:
1551 case WasmOpcode_f32_ne:
1552 case WasmOpcode_f64_ne:
1553 operator = "!=";
1554 break;
1555 case WasmOpcode_i64_lt_u:
1556 case WasmOpcode_f32_lt:
1557 case WasmOpcode_f64_lt:
1558 operator = "<";
1559 break;
1560 case WasmOpcode_i64_gt_u:
1561 case WasmOpcode_f32_gt:
1562 case WasmOpcode_f64_gt:
1563 operator = ">";
1564 break;
1565 case WasmOpcode_i64_le_u:
1566 case WasmOpcode_f32_le:
1567 case WasmOpcode_f64_le:
1568 operator = "<=";
1569 break;
1570 case WasmOpcode_i64_ge_u:
1571 case WasmOpcode_f32_ge:
1572 case WasmOpcode_f64_ge:
1573 operator = ">=";
1574 break;
1575 default: panic("unreachable");
1576 }
1577 FuncGen_stackPush(&fg, out, WasmValType_i32);
1578 fprintf(out, "l%" PRIu32 " = l%" PRIu32 " %s l%" PRIu32 ";\n",
1579 lhs, lhs, operator, rhs);
1580 }
1581 break;
1582 case WasmOpcode_i64_lt_s:
1583 case WasmOpcode_i64_gt_s:
1584 case WasmOpcode_i64_le_s:
1585 case WasmOpcode_i64_ge_s:
1586 // i64 signed comparisons
1587 if (unreachable_depth == 0) {
1588 uint32_t rhs = FuncGen_stackPop(&fg);
1589 uint32_t lhs = FuncGen_stackPop(&fg);
1590 const char *operator;
1591 switch (opcode) {
1592 case WasmOpcode_i64_lt_s: operator = "<"; break;
1593 case WasmOpcode_i64_gt_s: operator = ">"; break;
1594 case WasmOpcode_i64_le_s: operator = "<="; break;
1595 case WasmOpcode_i64_ge_s: operator = ">="; break;
1596 default: panic("unreachable");
1597 }
1598 FuncGen_stackPush(&fg, out, WasmValType_i32);
1599 fprintf(out, "l%" PRIu32 " = (int64_t)l%" PRIu32 " %s (int64_t)l%" PRIu32
1600 ";\n", lhs, lhs, operator, rhs);
1601 }
1602 break;
1603
1604 case WasmOpcode_i32_clz:
1605 case WasmOpcode_i32_ctz:
1606 case WasmOpcode_i32_popcnt:
1607 case WasmOpcode_i64_clz:
1608 case WasmOpcode_i64_ctz:
1609 case WasmOpcode_i64_popcnt:
1610 case WasmOpcode_f32_abs:
1611 case WasmOpcode_f32_neg:
1612 case WasmOpcode_f32_ceil:
1613 case WasmOpcode_f32_floor:
1614 case WasmOpcode_f32_trunc:
1615 case WasmOpcode_f32_nearest:
1616 case WasmOpcode_f32_sqrt:
1617 case WasmOpcode_f64_abs:
1618 case WasmOpcode_f64_neg:
1619 case WasmOpcode_f64_ceil:
1620 case WasmOpcode_f64_floor:
1621 case WasmOpcode_f64_trunc:
1622 case WasmOpcode_f64_nearest:
1623 case WasmOpcode_f64_sqrt:
1624 // unary functions
1625 if (unreachable_depth == 0) {
1626 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1627 const char *function;
1628 switch (opcode) {
1629 case WasmOpcode_i32_clz: function = "i32_clz"; break;
1630 case WasmOpcode_i32_ctz: function = "i32_ctz"; break;
1631 case WasmOpcode_i32_popcnt: function = "i32_popcnt"; break;
1632 case WasmOpcode_i64_clz: function = "i64_clz"; break;
1633 case WasmOpcode_i64_ctz: function = "i64_ctz"; break;
1634 case WasmOpcode_i64_popcnt: function = "i64_popcnt"; break;
1635 case WasmOpcode_f32_abs: function = "fabsf"; break;
1636 case WasmOpcode_f32_neg:
1637 case WasmOpcode_f64_neg: function = "-"; break;
1638 case WasmOpcode_f32_ceil: function = "ceilf"; break;
1639 case WasmOpcode_f32_floor: function = "floorf"; break;
1640 case WasmOpcode_f32_trunc: function = "truncf"; break;
1641 case WasmOpcode_f32_nearest: function = "roundf"; break;
1642 case WasmOpcode_f32_sqrt: function = "sqrtf"; break;
1643 case WasmOpcode_f64_abs: function = "fabs"; break;
1644 case WasmOpcode_f64_ceil: function = "ceil"; break;
1645 case WasmOpcode_f64_floor: function = "floor"; break;
1646 case WasmOpcode_f64_trunc: function = "trunc"; break;
1647 case WasmOpcode_f64_nearest: function = "round"; break;
1648 case WasmOpcode_f64_sqrt: function = "sqrt"; break;
1649 default: panic("unreachable");
1650 }
1651 FuncGen_indent(&fg, out);
1652 fprintf(out, "l%" PRIu32 " = %s(l%" PRIu32 ");\n", lhs, function, lhs);
1653 }
1654 break;
1655 case WasmOpcode_i32_add:
1656 case WasmOpcode_i32_sub:
1657 case WasmOpcode_i32_mul:
1658 case WasmOpcode_i32_div_u:
1659 case WasmOpcode_i32_rem_u:
1660 case WasmOpcode_i32_and:
1661 case WasmOpcode_i32_or:
1662 case WasmOpcode_i32_xor:
1663 case WasmOpcode_i64_add:
1664 case WasmOpcode_i64_sub:
1665 case WasmOpcode_i64_mul:
1666 case WasmOpcode_i64_div_u:
1667 case WasmOpcode_i64_rem_u:
1668 case WasmOpcode_i64_and:
1669 case WasmOpcode_i64_or:
1670 case WasmOpcode_i64_xor:
1671 case WasmOpcode_f32_add:
1672 case WasmOpcode_f32_sub:
1673 case WasmOpcode_f32_mul:
1674 case WasmOpcode_f32_div:
1675 case WasmOpcode_f64_add:
1676 case WasmOpcode_f64_sub:
1677 case WasmOpcode_f64_mul:
1678 case WasmOpcode_f64_div:
1679 // unsigned binary operators
1680 if (unreachable_depth == 0) {
1681 uint32_t rhs = FuncGen_stackPop(&fg);
1682 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1683 char operator;
1684 switch (opcode) {
1685 case WasmOpcode_i32_add:
1686 case WasmOpcode_i64_add:
1687 case WasmOpcode_f32_add:
1688 case WasmOpcode_f64_add:
1689 operator = '+';
1690 break;
1691 case WasmOpcode_i32_sub:
1692 case WasmOpcode_i64_sub:
1693 case WasmOpcode_f32_sub:
1694 case WasmOpcode_f64_sub:
1695 operator = '-';
1696 break;
1697 case WasmOpcode_i32_mul:
1698 case WasmOpcode_i64_mul:
1699 case WasmOpcode_f32_mul:
1700 case WasmOpcode_f64_mul:
1701 operator = '*';
1702 break;
1703 case WasmOpcode_i32_div_u:
1704 case WasmOpcode_i64_div_u:
1705 case WasmOpcode_f32_div:
1706 case WasmOpcode_f64_div:
1707 operator = '/';
1708 break;
1709 case WasmOpcode_i32_rem_u:
1710 case WasmOpcode_i64_rem_u:
1711 operator = '%';
1712 break;
1713 case WasmOpcode_i32_and:
1714 case WasmOpcode_i64_and:
1715 operator = '&';
1716 break;
1717 case WasmOpcode_i32_or:
1718 case WasmOpcode_i64_or:
1719 operator = '|';
1720 break;
1721 case WasmOpcode_i32_xor:
1722 case WasmOpcode_i64_xor:
1723 operator = '^';
1724 break;
1725 default: panic("unreachable");
1726 }
1727 FuncGen_indent(&fg, out);
1728 fprintf(out, "l%" PRIu32 " %c= l%" PRIu32 ";\n", lhs, operator, rhs);
1729 }
1730 break;
1731 case WasmOpcode_i32_div_s:
1732 case WasmOpcode_i32_rem_s:
1733 case WasmOpcode_i64_div_s:
1734 case WasmOpcode_i64_rem_s:
1735 // signed binary operators
1736 if (unreachable_depth == 0) {
1737 uint32_t rhs = FuncGen_stackPop(&fg);
1738 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1739 char operator;
1740 unsigned width;
1741 switch (opcode) {
1742 case WasmOpcode_i32_div_s:
1743 case WasmOpcode_i64_div_s:
1744 operator = '/';
1745 break;
1746 case WasmOpcode_i32_rem_s:
1747 case WasmOpcode_i64_rem_s:
1748 operator = '%';
1749 break;
1750 default: panic("unreachable");
1751 }
1752 switch (opcode) {
1753 case WasmOpcode_i32_div_s:
1754 case WasmOpcode_i32_rem_s:
1755 width = 32;
1756 break;
1757 case WasmOpcode_i64_div_s:
1758 case WasmOpcode_i64_rem_s:
1759 width = 64;
1760 break;
1761 default: panic("unreachable");
1762 }
1763 FuncGen_indent(&fg, out);
1764 fprintf(out, "l%" PRIu32 " = (uint%u_t)((int%u_t)l%" PRIu32 " %c "
1765 "(int%u_t)l%" PRIu32 ");\n",
1766 lhs, width, width, lhs, operator, width, rhs);
1767 }
1768 break;
1769 case WasmOpcode_i32_shl:
1770 case WasmOpcode_i32_shr_u:
1771 case WasmOpcode_i64_shl:
1772 case WasmOpcode_i64_shr_u:
1773 // unsigned shift operators
1774 if (unreachable_depth == 0) {
1775 uint32_t rhs = FuncGen_stackPop(&fg);
1776 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1777 char operator;
1778 unsigned width;
1779 switch (opcode) {
1780 case WasmOpcode_i32_shl:
1781 case WasmOpcode_i64_shl:
1782 operator = '<';
1783 break;
1784 case WasmOpcode_i32_shr_u:
1785 case WasmOpcode_i64_shr_u:
1786 operator = '>';
1787 break;
1788 default: panic("unreachable");
1789 }
1790 switch (opcode) {
1791 case WasmOpcode_i32_shl:
1792 case WasmOpcode_i32_shr_u:
1793 width = 32;
1794 break;
1795 case WasmOpcode_i64_shl:
1796 case WasmOpcode_i64_shr_u:
1797 width = 64;
1798 break;
1799 default: panic("unreachable");
1800 }
1801 FuncGen_indent(&fg, out);
1802 fprintf(out, "l%" PRIu32 " %c%c= l%" PRIu32 " & 0x%X;\n",
1803 lhs, operator, operator, rhs, width - 1);
1804 }
1805 break;
1806 case WasmOpcode_i32_shr_s:
1807 case WasmOpcode_i64_shr_s:
1808 // signed shift operators
1809 if (unreachable_depth == 0) {
1810 uint32_t rhs = FuncGen_stackPop(&fg);
1811 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1812 char operator;
1813 unsigned width;
1814 switch (opcode) {
1815 case WasmOpcode_i32_shr_s:
1816 case WasmOpcode_i64_shr_s:
1817 operator = '>';
1818 break;
1819 default: panic("unreachable");
1820 }
1821 switch (opcode) {
1822 case WasmOpcode_i32_shr_s:
1823 width = 32;
1824 break;
1825 case WasmOpcode_i64_shr_s:
1826 width = 64;
1827 break;
1828 default: panic("unreachable");
1829 }
1830 FuncGen_indent(&fg, out);
1831 fprintf(out, "l%" PRIu32 " = (uint%u_t)((int%u_t)l%" PRIu32 " %c%c "
1832 "(l%" PRIu32 " & 0x%X));\n",
1833 lhs, width, width, lhs, operator, operator, rhs, width - 1);
1834 }
1835 break;
1836 case WasmOpcode_i32_rotl:
1837 case WasmOpcode_i32_rotr:
1838 case WasmOpcode_i64_rotl:
1839 case WasmOpcode_i64_rotr:
1840 // rotate operators
1841 if (unreachable_depth == 0) {
1842 uint32_t rhs = FuncGen_stackPop(&fg);
1843 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1844 char forward_operator;
1845 char reverse_operator;
1846 unsigned width;
1847 switch (opcode) {
1848 case WasmOpcode_i32_rotl:
1849 case WasmOpcode_i64_rotl:
1850 forward_operator = '<';
1851 reverse_operator = '>';
1852 break;
1853 case WasmOpcode_i32_rotr:
1854 case WasmOpcode_i64_rotr:
1855 forward_operator = '>';
1856 reverse_operator = '<';
1857 break;
1858 default: panic("unreachable");
1859 }
1860 switch (opcode) {
1861 case WasmOpcode_i32_rotl:
1862 case WasmOpcode_i32_rotr:
1863 width = 32;
1864 break;
1865 case WasmOpcode_i64_rotl:
1866 case WasmOpcode_i64_rotr:
1867 width = 64;
1868 break;
1869 default: panic("unreachable");
1870 }
1871 FuncGen_indent(&fg, out);
1872 fprintf(out, "l%" PRIu32" = l%" PRIu32 " %c%c (l%" PRIu32 " & 0x%X) | "
1873 "l%" PRIu32 " %c%c (-l%" PRIu32" & 0x%X);\n", lhs,
1874 lhs, forward_operator, forward_operator, rhs, width - 1,
1875 lhs, reverse_operator, reverse_operator, rhs, width - 1);
1876 }
1877 break;
1878 case WasmOpcode_f32_min:
1879 case WasmOpcode_f32_max:
1880 case WasmOpcode_f32_copysign:
1881 case WasmOpcode_f64_min:
1882 case WasmOpcode_f64_max:
1883 case WasmOpcode_f64_copysign:
1884 // binary functions
1885 if (unreachable_depth == 0) {
1886 uint32_t rhs = FuncGen_stackPop(&fg);
1887 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1888 const char *function;
1889 switch (opcode) {
1890 case WasmOpcode_f32_min: function = "fminf"; break;
1891 case WasmOpcode_f32_max: function = "fmaxf"; break;
1892 case WasmOpcode_f32_copysign: function = "copysignf"; break;
1893 case WasmOpcode_f64_min: function = "fmin"; break;
1894 case WasmOpcode_f64_max: function = "fmax"; break;
1895 case WasmOpcode_f64_copysign: function = "copysign"; break;
1896 default: panic("unreachable");
1897 }
1898 FuncGen_indent(&fg, out);
1899 fprintf(out, "l%" PRIu32 " = %s(l%" PRIu32 ", l%" PRIu32 ");\n",
1900 lhs, function, lhs, rhs);
1901 }
1902 break;
1903
1904 case WasmOpcode_i32_wrap_i64:
1905 if (unreachable_depth == 0) {
1906 uint32_t lhs = FuncGen_stackPop(&fg);
1907 FuncGen_stackPush(&fg, out, WasmValType_i32);
1908 fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
1909 }
1910 break;
1911 case WasmOpcode_i32_trunc_f32_s:
1912 if (unreachable_depth == 0) {
1913 uint32_t lhs = FuncGen_stackPop(&fg);
1914 FuncGen_stackPush(&fg, out, WasmValType_i32);
1915 fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
1916 }
1917 break;
1918 case WasmOpcode_i32_trunc_f32_u:
1919 if (unreachable_depth == 0) {
1920 uint32_t lhs = FuncGen_stackPop(&fg);
1921 FuncGen_stackPush(&fg, out, WasmValType_i32);
1922 fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
1923 }
1924 break;
1925 case WasmOpcode_i32_trunc_f64_s:
1926 if (unreachable_depth == 0) {
1927 uint32_t lhs = FuncGen_stackPop(&fg);
1928 FuncGen_stackPush(&fg, out, WasmValType_i32);
1929 fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
1930 }
1931 break;
1932 case WasmOpcode_i32_trunc_f64_u:
1933 if (unreachable_depth == 0) {
1934 uint32_t lhs = FuncGen_stackPop(&fg);
1935 FuncGen_stackPush(&fg, out, WasmValType_i32);
1936 fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
1937 }
1938 break;
1939 case WasmOpcode_i64_extend_i32_s:
1940 if (unreachable_depth == 0) {
1941 uint32_t lhs = FuncGen_stackPop(&fg);
1942 FuncGen_stackPush(&fg, out, WasmValType_i64);
1943 fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
1944 }
1945 break;
1946 case WasmOpcode_i64_extend_i32_u:
1947 if (unreachable_depth == 0) {
1948 uint32_t lhs = FuncGen_stackPop(&fg);
1949 FuncGen_stackPush(&fg, out, WasmValType_i64);
1950 fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
1951 }
1952 break;
1953 case WasmOpcode_i64_trunc_f32_s:
1954 if (unreachable_depth == 0) {
1955 uint32_t lhs = FuncGen_stackPop(&fg);
1956 FuncGen_stackPush(&fg, out, WasmValType_i64);
1957 fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
1958 }
1959 break;
1960 case WasmOpcode_i64_trunc_f32_u:
1961 if (unreachable_depth == 0) {
1962 uint32_t lhs = FuncGen_stackPop(&fg);
1963 FuncGen_stackPush(&fg, out, WasmValType_i64);
1964 fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
1965 }
1966 break;
1967 case WasmOpcode_i64_trunc_f64_s:
1968 if (unreachable_depth == 0) {
1969 uint32_t lhs = FuncGen_stackPop(&fg);
1970 FuncGen_stackPush(&fg, out, WasmValType_i64);
1971 fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
1972 }
1973 break;
1974 case WasmOpcode_i64_trunc_f64_u:
1975 if (unreachable_depth == 0) {
1976 uint32_t lhs = FuncGen_stackPop(&fg);
1977 FuncGen_stackPush(&fg, out, WasmValType_i64);
1978 fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
1979 }
1980 break;
1981 case WasmOpcode_f32_convert_i32_s:
1982 if (unreachable_depth == 0) {
1983 uint32_t lhs = FuncGen_stackPop(&fg);
1984 FuncGen_stackPush(&fg, out, WasmValType_f32);
1985 fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
1986 }
1987 break;
1988 case WasmOpcode_f32_convert_i32_u:
1989 if (unreachable_depth == 0) {
1990 uint32_t lhs = FuncGen_stackPop(&fg);
1991 FuncGen_stackPush(&fg, out, WasmValType_f32);
1992 fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
1993 }
1994 break;
1995 case WasmOpcode_f32_convert_i64_s:
1996 if (unreachable_depth == 0) {
1997 uint32_t lhs = FuncGen_stackPop(&fg);
1998 FuncGen_stackPush(&fg, out, WasmValType_f32);
1999 fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
2000 }
2001 break;
2002 case WasmOpcode_f32_convert_i64_u:
2003 if (unreachable_depth == 0) {
2004 uint32_t lhs = FuncGen_stackPop(&fg);
2005 FuncGen_stackPush(&fg, out, WasmValType_f32);
2006 fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
2007 }
2008 break;
2009 case WasmOpcode_f32_demote_f64:
2010 if (unreachable_depth == 0) {
2011 uint32_t lhs = FuncGen_stackPop(&fg);
2012 FuncGen_stackPush(&fg, out, WasmValType_f32);
2013 fprintf(out, "(float)l%" PRIu32 ";\n", lhs);
2014 }
2015 break;
2016 case WasmOpcode_f64_convert_i32_s:
2017 if (unreachable_depth == 0) {
2018 uint32_t lhs = FuncGen_stackPop(&fg);
2019 FuncGen_stackPush(&fg, out, WasmValType_f64);
2020 fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
2021 }
2022 break;
2023 case WasmOpcode_f64_convert_i32_u:
2024 if (unreachable_depth == 0) {
2025 uint32_t lhs = FuncGen_stackPop(&fg);
2026 FuncGen_stackPush(&fg, out, WasmValType_f64);
2027 fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
2028 }
2029 break;
2030 case WasmOpcode_f64_convert_i64_s:
2031 if (unreachable_depth == 0) {
2032 uint32_t lhs = FuncGen_stackPop(&fg);
2033 FuncGen_stackPush(&fg, out, WasmValType_f64);
2034 fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
2035 }
2036 break;
2037 case WasmOpcode_f64_convert_i64_u:
2038 if (unreachable_depth == 0) {
2039 uint32_t lhs = FuncGen_stackPop(&fg);
2040 FuncGen_stackPush(&fg, out, WasmValType_f64);
2041 fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
2042 }
2043 break;
2044 case WasmOpcode_f64_promote_f32:
2045 if (unreachable_depth == 0) {
2046 uint32_t lhs = FuncGen_stackPop(&fg);
2047 FuncGen_stackPush(&fg, out, WasmValType_f64);
2048 fprintf(out, "(double)l%" PRIu32 ";\n", lhs);
2049 }
2050 break;
2051 case WasmOpcode_i32_reinterpret_f32:
2052 if (unreachable_depth == 0) {
2053 uint32_t lhs = FuncGen_stackPop(&fg);
2054 FuncGen_stackPush(&fg, out, WasmValType_i32);
2055 fprintf(out, "i32_reinterpret_f32(l%" PRIu32 ");\n", lhs);
2056 }
2057 break;
2058 case WasmOpcode_i64_reinterpret_f64:
2059 if (unreachable_depth == 0) {
2060 uint32_t lhs = FuncGen_stackPop(&fg);
2061 FuncGen_stackPush(&fg, out, WasmValType_i64);
2062 fprintf(out, "i64_reinterpret_f64(l%" PRIu32 ");\n", lhs);
2063 }
2064 break;
2065 case WasmOpcode_f32_reinterpret_i32:
2066 if (unreachable_depth == 0) {
2067 uint32_t lhs = FuncGen_stackPop(&fg);
2068 FuncGen_stackPush(&fg, out, WasmValType_f32);
2069 fprintf(out, "f32_reinterpret_i32(l%" PRIu32 ");\n", lhs);
2070 }
2071 break;
2072 case WasmOpcode_f64_reinterpret_i64:
2073 if (unreachable_depth == 0) {
2074 uint32_t lhs = FuncGen_stackPop(&fg);
2075 FuncGen_stackPush(&fg, out, WasmValType_f64);
2076 fprintf(out, "f64_reinterpret_i64(l%" PRIu32 ");\n", lhs);
2077 }
2078 break;
2079
2080 case WasmOpcode_i32_extend8_s:
2081 if (unreachable_depth == 0) {
2082 uint32_t lhs = FuncGen_stackPop(&fg);
2083 FuncGen_stackPush(&fg, out, WasmValType_i32);
2084 fprintf(out, "(int8_t)l%" PRIu32 ";\n", lhs);
2085 }
2086 break;
2087 case WasmOpcode_i32_extend16_s:
2088 if (unreachable_depth == 0) {
2089 uint32_t lhs = FuncGen_stackPop(&fg);
2090 FuncGen_stackPush(&fg, out, WasmValType_i32);
2091 fprintf(out, "(int16_t)l%" PRIu32 ";\n", lhs);
2092 }
2093 break;
2094 case WasmOpcode_i64_extend8_s:
2095 if (unreachable_depth == 0) {
2096 uint32_t lhs = FuncGen_stackPop(&fg);
2097 FuncGen_stackPush(&fg, out, WasmValType_i64);
2098 fprintf(out, "(int8_t)l%" PRIu32 ";\n", lhs);
2099 }
2100 break;
2101 case WasmOpcode_i64_extend16_s:
2102 if (unreachable_depth == 0) {
2103 uint32_t lhs = FuncGen_stackPop(&fg);
2104 FuncGen_stackPush(&fg, out, WasmValType_i64);
2105 fprintf(out, "(int16_t)l%" PRIu32 ";\n", lhs);
2106 }
2107 break;
2108 case WasmOpcode_i64_extend32_s:
2109 if (unreachable_depth == 0) {
2110 uint32_t lhs = FuncGen_stackPop(&fg);
2111 FuncGen_stackPush(&fg, out, WasmValType_i64);
2112 fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
2113 }
2114 break;
2115
2116 case WasmOpcode_prefixed:
2117 switch (InputStream_readLeb128_u32(&in)) {
2118 case WasmPrefixedOpcode_i32_trunc_sat_f32_s:
2119 if (unreachable_depth == 0) {
2120 uint32_t lhs = FuncGen_stackPop(&fg);
2121 FuncGen_stackPush(&fg, out, WasmValType_i32);
2122 fprintf(out, "i32_trunc_sat_f32(l%" PRIu32 ");\n", lhs);
2123 }
2124 break;
2125 case WasmPrefixedOpcode_i32_trunc_sat_f32_u:
2126 if (unreachable_depth == 0) {
2127 uint32_t lhs = FuncGen_stackPop(&fg);
2128 FuncGen_stackPush(&fg, out, WasmValType_i32);
2129 fprintf(out, "u32_trunc_sat_f32(l%" PRIu32 ");\n", lhs);
2130 }
2131 break;
2132 case WasmPrefixedOpcode_i32_trunc_sat_f64_s:
2133 if (unreachable_depth == 0) {
2134 uint32_t lhs = FuncGen_stackPop(&fg);
2135 FuncGen_stackPush(&fg, out, WasmValType_i32);
2136 fprintf(out, "i32_trunc_sat_f64(l%" PRIu32 ");\n", lhs);
2137 }
2138 break;
2139 case WasmPrefixedOpcode_i32_trunc_sat_f64_u:
2140 if (unreachable_depth == 0) {
2141 uint32_t lhs = FuncGen_stackPop(&fg);
2142 FuncGen_stackPush(&fg, out, WasmValType_i32);
2143 fprintf(out, "u32_trunc_sat_f64(l%" PRIu32 ");\n", lhs);
2144 }
2145 break;
2146 case WasmPrefixedOpcode_i64_trunc_sat_f32_s:
2147 if (unreachable_depth == 0) {
2148 uint32_t lhs = FuncGen_stackPop(&fg);
2149 FuncGen_stackPush(&fg, out, WasmValType_i32);
2150 fprintf(out, "i64_trunc_sat_f32(l%" PRIu32 ");\n", lhs);
2151 }
2152 break;
2153 case WasmPrefixedOpcode_i64_trunc_sat_f32_u:
2154 if (unreachable_depth == 0) {
2155 uint32_t lhs = FuncGen_stackPop(&fg);
2156 FuncGen_stackPush(&fg, out, WasmValType_i32);
2157 fprintf(out, "u64_trunc_sat_f32(l%" PRIu32 ");\n", lhs);
2158 }
2159 break;
2160 case WasmPrefixedOpcode_i64_trunc_sat_f64_s:
2161 if (unreachable_depth == 0) {
2162 uint32_t lhs = FuncGen_stackPop(&fg);
2163 FuncGen_stackPush(&fg, out, WasmValType_i32);
2164 fprintf(out, "i64_trunc_sat_f64(l%" PRIu32 ");\n", lhs);
2165 }
2166 break;
2167 case WasmPrefixedOpcode_i64_trunc_sat_f64_u:
2168 if (unreachable_depth == 0) {
2169 uint32_t lhs = FuncGen_stackPop(&fg);
2170 FuncGen_stackPush(&fg, out, WasmValType_i32);
2171 fprintf(out, "u64_trunc_sat_f64(l%" PRIu32 ");\n", lhs);
2172 }
2173 break;
2174
2175 case WasmPrefixedOpcode_memory_init:
2176 (void)InputStream_readLeb128_u32(&in);
2177 (void)InputStream_readByte(&in);
2178 if (unreachable_depth == 0) panic("unimplemented opcode");
2179
2180 case WasmPrefixedOpcode_data_drop:
2181 (void)InputStream_readLeb128_u32(&in);
2182 if (unreachable_depth == 0) panic("unimplemented opcode");
2183
2184 case WasmPrefixedOpcode_memory_copy: {
2185 uint32_t dst_mem_idx = InputStream_readLeb128_u32(&in);
2186 uint32_t src_mem_idx = InputStream_readLeb128_u32(&in);
2187 if (unreachable_depth == 0) {
2188 uint32_t n = FuncGen_stackPop(&fg);
2189 uint32_t src = FuncGen_stackPop(&fg);
2190 uint32_t dst = FuncGen_stackPop(&fg);
2191 FuncGen_indent(&fg, out);
2192 fprintf(out, "memmove(&m%" PRIu32 "[l%" PRIu32 "], "
2193 "&m%" PRIu32 "[l%" PRIu32 "], l%" PRIu32 ");\n",
2194 dst_mem_idx, dst, src_mem_idx, src, n);
2195 }
2196 break;
2197 }
2198
2199 case WasmPrefixedOpcode_memory_fill: {
2200 uint32_t mem_idx = InputStream_readLeb128_u32(&in);
2201 if (unreachable_depth == 0) {
2202 uint32_t n = FuncGen_stackPop(&fg);
2203 uint32_t c = FuncGen_stackPop(&fg);
2204 uint32_t s = FuncGen_stackPop(&fg);
2205 FuncGen_indent(&fg, out);
2206 fprintf(out, "memset(&m%" PRIu32 "[l%" PRIu32 "], "
2207 "l%" PRIu32 ", l%" PRIu32 ");\n", mem_idx, s, c, n);
2208 }
2209 break;
2210 }
2211
2212 case WasmPrefixedOpcode_table_init:
2213 (void)InputStream_readLeb128_u32(&in);
2214 (void)InputStream_readLeb128_u32(&in);
2215 if (unreachable_depth == 0) panic("unimplemented opcode");
2216
2217 case WasmPrefixedOpcode_elem_drop:
2218 (void)InputStream_readLeb128_u32(&in);
2219 if (unreachable_depth == 0) panic("unimplemented opcode");
2220
2221 case WasmPrefixedOpcode_table_copy:
2222 (void)InputStream_readLeb128_u32(&in);
2223 (void)InputStream_readLeb128_u32(&in);
2224 if (unreachable_depth == 0) panic("unimplemented opcode");
2225
2226 case WasmPrefixedOpcode_table_grow:
2227 (void)InputStream_readLeb128_u32(&in);
2228 if (unreachable_depth == 0) panic("unimplemented opcode");
2229
2230 case WasmPrefixedOpcode_table_size:
2231 (void)InputStream_readLeb128_u32(&in);
2232 if (unreachable_depth == 0) panic("unimplemented opcode");
2233
2234 case WasmPrefixedOpcode_table_fill:
2235 (void)InputStream_readLeb128_u32(&in);
2236 if (unreachable_depth == 0) panic("unimplemented opcode");
2237 }
2238 break;
2239 }
2240 }
2241 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
2242 if (param_used[param_i]) continue;
2243 FuncGen_indent(&fg, out);
2244 fprintf(out, "(void)l%" PRIu32 ";\n", param_i);
2245 }
2246 switch (func_type->result->len) {
2247 case 0: break;
2248 case 1:
2249 FuncGen_indent(&fg, out);
2250 fprintf(out, "return l%" PRIu32 ";\n", FuncGen_stackPop(&fg));
2251 break;
2252 default: panic("multiple function returns not supported");
2253 }
2254 fputs("}\n\n", out);
2255 }
2256 }
2257
2258 (void)InputStream_skipToSection(&in, WasmSectionId_data);
2259 {
2260 uint32_t len = InputStream_readLeb128_u32(&in);
2261 fputs("static void init_data(void) {\n", out);
2262 for (uint32_t i = 0; i < mems_len; i += 1)
2263 fprintf(out, " p%" PRIu32 " = UINT32_C(%" PRIu32 ");\n"
2264 " c%" PRIu32 " = p%" PRIu32 ";\n"
2265 " m%" PRIu32 " = calloc(c%" PRIu32 ", UINT32_C(1) << 16);\n",
2266 i, mems[i].limits.min, i, i, i, i);
2267 for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) {
2268 uint32_t mem_idx;
2269 switch (InputStream_readLeb128_u32(&in)) {
2270 case 0:
2271 mem_idx = 0;
2272 break;
2273
2274 case 2:
2275 mem_idx = InputStream_readLeb128_u32(&in);
2276 break;
2277
2278 default: panic("unsupported data kind");
2279 }
2280 uint32_t offset = evalExpr(&in);
2281 uint32_t segment_len = InputStream_readLeb128_u32(&in);
2282 fputc('\n', out);
2283 fprintf(out, " static const uint8_t s%" PRIu32 "[UINT32_C(%" PRIu32 ")] = {",
2284 segment_i, segment_len);
2285 for (uint32_t i = 0; i < segment_len; i += 1) {
2286 if (i % 32 == 0) fputs("\n ", out);
2287 fprintf(out, " 0x%02hhX,", InputStream_readByte(&in));
2288 }
2289 fprintf(out, "\n"
2290 " };\n"
2291 " memcpy(&m%" PRIu32 "[UINT32_C(0x%" PRIX32 ")], s%" PRIu32 ", UINT32_C(%" PRIu32 "));\n",
2292 mem_idx, offset, segment_i, segment_len);
2293 }
2294 fputs("}\n", out);
2295 }
2296
2297 InputStream_close(&in);
2298 fclose(out);
2299}