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}