mirror of
https://github.com/ziglang/zig.git
synced 2024-11-30 09:02:32 +00:00
2195 lines
114 KiB
C
2195 lines
114 KiB
C
#define EXTRA_BRACES 0
|
|
|
|
#include "FuncGen.h"
|
|
#include "InputStream.h"
|
|
#include "panic.h"
|
|
#include "wasm.h"
|
|
|
|
#include <inttypes.h>
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
struct FuncType {
|
|
const struct ResultType *param;
|
|
const struct ResultType *result;
|
|
};
|
|
static const struct FuncType *FuncType_blockType(const struct FuncType *types, int64_t block_type) {
|
|
if (block_type >= 0) return &types[block_type];
|
|
|
|
static const struct ResultType none = { 0, { 0 }};
|
|
static const struct ResultType i32 = { 1, { WasmValType_i32 } };
|
|
static const struct ResultType i64 = { 1, { WasmValType_i64 } };
|
|
static const struct ResultType f32 = { 1, { WasmValType_f32 } };
|
|
static const struct ResultType f64 = { 1, { WasmValType_f64 } };
|
|
|
|
static const struct FuncType none_i32 = { &none, &i32 };
|
|
static const struct FuncType none_i64 = { &none, &i64 };
|
|
static const struct FuncType none_f32 = { &none, &f32 };
|
|
static const struct FuncType none_f64 = { &none, &f64 };
|
|
static const struct FuncType none_none = { &none, &none };
|
|
|
|
switch (block_type) {
|
|
case WasmValType_i32: return &none_i32;
|
|
case WasmValType_i64: return &none_i64;
|
|
case WasmValType_f32: return &none_f32;
|
|
case WasmValType_f64: return &none_f64;
|
|
case WasmValType_empty: return &none_none;
|
|
default: panic("unsupported block type");
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static uint32_t evalExpr(struct InputStream *in) {
|
|
uint32_t value;
|
|
while (true) {
|
|
switch (InputStream_readByte(in)) {
|
|
case WasmOpcode_end: return value;
|
|
|
|
case WasmOpcode_i32_const:
|
|
value = (uint32_t)InputStream_readLeb128_i32(in);
|
|
break;
|
|
|
|
default: panic("unsupported expr opcode");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void renderExpr(FILE *out, struct InputStream *in) {
|
|
while (true) {
|
|
switch (InputStream_readByte(in)) {
|
|
case WasmOpcode_end: return;
|
|
|
|
case WasmOpcode_i32_const: {
|
|
uint32_t value = (uint32_t)InputStream_readLeb128_i32(in);
|
|
fprintf(out, "UINT32_C(0x%" PRIX32 ")", value);
|
|
break;
|
|
}
|
|
|
|
default: panic("unsupported expr opcode");
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
if (argc != 3) {
|
|
fprintf(stderr, "usage: %s in.wasm.zst out.c\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
const char *mod = "wasm";
|
|
bool is_big_endian = false; // TODO
|
|
|
|
struct InputStream in;
|
|
InputStream_open(&in, argv[1]);
|
|
|
|
if (InputStream_readByte(&in) != '\0' ||
|
|
InputStream_readByte(&in) != 'a' ||
|
|
InputStream_readByte(&in) != 's' ||
|
|
InputStream_readByte(&in) != 'm') panic("input is not a zstd-compressed wasm file");
|
|
if (InputStream_readLittle_u32(&in) != 1) panic("unsupported wasm version");
|
|
|
|
FILE *out = fopen(argv[2], "wb");
|
|
if (out == NULL) panic("unable to open output file");
|
|
fputs("#include <math.h>\n"
|
|
"#include <stdint.h>\n"
|
|
"#include <stdlib.h>\n"
|
|
"#include <string.h>\n"
|
|
"\n"
|
|
"static uint16_t i16_byteswap(uint16_t src) {\n"
|
|
" return (uint16_t)(uint8_t)(src >> 0) << 8 |\n"
|
|
" (uint16_t)(uint8_t)(src >> 8) << 0;\n"
|
|
"}\n"
|
|
"static uint32_t i32_byteswap(uint32_t src) {\n"
|
|
" return (uint32_t)i16_byteswap(src >> 0) << 16 |\n"
|
|
" (uint32_t)i16_byteswap(src >> 16) << 0;\n"
|
|
"}\n"
|
|
"static uint64_t i64_byteswap(uint64_t src) {\n"
|
|
" return (uint64_t)i32_byteswap(src >> 0) << 32 |\n"
|
|
" (uint64_t)i32_byteswap(src >> 32) << 0;\n"
|
|
"}\n"
|
|
"\n", out);
|
|
fputs("static uint16_t load16_align0(const uint8_t *ptr) {\n"
|
|
" uint16_t val;\n"
|
|
" memcpy(&val, ptr, sizeof(val));\n", out);
|
|
if (is_big_endian) fputs(" val = i16_byteswap(val);", out);
|
|
fputs(" return val;\n"
|
|
"}\n"
|
|
"static uint16_t load16_align1(const uint16_t *ptr) {\n"
|
|
" uint16_t val;\n"
|
|
" memcpy(&val, ptr, sizeof(val));\n", out);
|
|
if (is_big_endian) fputs(" val = i16_byteswap(val);", out);
|
|
fputs(" return val;\n"
|
|
"}\n"
|
|
"static uint32_t load32_align0(const uint8_t *ptr) {\n"
|
|
" uint32_t val;\n"
|
|
" memcpy(&val, ptr, sizeof(val));\n", out);
|
|
if (is_big_endian) fputs(" val = i32_byteswap(val);", out);
|
|
fputs(" return val;\n"
|
|
"}\n"
|
|
"static uint32_t load32_align1(const uint16_t *ptr) {\n"
|
|
" uint32_t val;\n"
|
|
" memcpy(&val, ptr, sizeof(val));\n", out);
|
|
if (is_big_endian) fputs(" val = i32_byteswap(val);", out);
|
|
fputs(" return val;\n"
|
|
"}\n"
|
|
"static uint32_t load32_align2(const uint32_t *ptr) {\n"
|
|
" uint32_t val;\n"
|
|
" memcpy(&val, ptr, sizeof(val));\n", out);
|
|
if (is_big_endian) fputs(" val = i32_byteswap(val);", out);
|
|
fputs(" return val;\n"
|
|
"}\n"
|
|
"static uint64_t load64_align0(const uint8_t *ptr) {\n"
|
|
" uint64_t val;\n"
|
|
" memcpy(&val, ptr, sizeof(val));\n", out);
|
|
if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
|
|
fputs(" return val;\n"
|
|
"}\n"
|
|
"static uint64_t load64_align1(const uint16_t *ptr) {\n"
|
|
" uint64_t val;\n"
|
|
" memcpy(&val, ptr, sizeof(val));\n", out);
|
|
if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
|
|
fputs(" return val;\n"
|
|
"}\n"
|
|
"static uint64_t load64_align2(const uint32_t *ptr) {\n"
|
|
" uint64_t val;\n"
|
|
" memcpy(&val, ptr, sizeof(val));\n", out);
|
|
if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
|
|
fputs(" return val;\n"
|
|
"}\n"
|
|
"static uint64_t load64_align3(const uint64_t *ptr) {\n"
|
|
" uint64_t val;\n"
|
|
" memcpy(&val, ptr, sizeof(val));\n", out);
|
|
if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
|
|
fputs(" return val;\n"
|
|
"}\n"
|
|
"\n"
|
|
"static uint32_t i32_popcnt(uint32_t lhs) {\n"
|
|
" lhs = lhs - ((lhs >> 1) & UINT32_C(0x55555555));\n"
|
|
" lhs = (lhs & UINT32_C(0x33333333)) + ((lhs >> 2) & UINT32_C(0x33333333));\n"
|
|
" lhs = (lhs + (lhs >> 4)) & UINT32_C(0x0F0F0F0F);\n"
|
|
" return (lhs * UINT32_C(0x01010101)) >> 24;\n"
|
|
"}\n"
|
|
"static uint32_t i32_ctz(uint32_t lhs) {\n"
|
|
" return i32_popcnt(~lhs & (lhs - 1));\n"
|
|
"}\n"
|
|
"static uint32_t i32_clz(uint32_t lhs) {\n"
|
|
" lhs = i32_byteswap(lhs);\n"
|
|
" lhs = (lhs & UINT32_C(0x0F0F0F0F)) << 4 | (lhs & UINT32_C(0xF0F0F0F0)) >> 4;\n"
|
|
" lhs = (lhs & UINT32_C(0x33333333)) << 2 | (lhs & UINT32_C(0xCCCCCCCC)) >> 2;\n"
|
|
" lhs = (lhs & UINT32_C(0x55555555)) << 1 | (lhs & UINT32_C(0xAAAAAAAA)) >> 1;\n"
|
|
" return i32_ctz(lhs);\n"
|
|
"}\n"
|
|
"static uint64_t i64_popcnt(uint64_t lhs) {\n"
|
|
" lhs = lhs - ((lhs >> 1) & UINT64_C(0x5555555555555555));\n"
|
|
" lhs = (lhs & UINT64_C(0x3333333333333333)) + ((lhs >> 2) & UINT64_C(0x3333333333333333));\n"
|
|
" lhs = (lhs + (lhs >> 4)) & UINT64_C(0x0F0F0F0F0F0F0F0F);\n"
|
|
" return (lhs * UINT64_C(0x0101010101010101)) >> 56;\n"
|
|
"}\n"
|
|
"static uint64_t i64_ctz(uint64_t lhs) {\n"
|
|
" return i64_popcnt(~lhs & (lhs - 1));\n"
|
|
"}\n"
|
|
"static uint64_t i64_clz(uint64_t lhs) {\n"
|
|
" lhs = i64_byteswap(lhs);\n"
|
|
" lhs = (lhs & UINT64_C(0x0F0F0F0F0F0F0F0F)) << 4 | (lhs & UINT32_C(0xF0F0F0F0F0F0F0F0)) >> 4;\n"
|
|
" lhs = (lhs & UINT64_C(0x3333333333333333)) << 2 | (lhs & UINT32_C(0xCCCCCCCCCCCCCCCC)) >> 2;\n"
|
|
" lhs = (lhs & UINT64_C(0x5555555555555555)) << 1 | (lhs & UINT32_C(0xAAAAAAAAAAAAAAAA)) >> 1;\n"
|
|
" return i64_ctz(lhs);\n"
|
|
"}\n"
|
|
"\n"
|
|
"static void store16_align0(uint8_t *ptr, uint16_t val) {\n", out);
|
|
if (is_big_endian) fputs(" val = i16_byteswap(val);", out);
|
|
fputs(" memcpy(ptr, &val, sizeof(val));\n"
|
|
"}\n"
|
|
"static void store16_align1(uint16_t *ptr, uint16_t val) {\n", out);
|
|
if (is_big_endian) fputs(" val = i16_byteswap(val);", out);
|
|
fputs(" memcpy(ptr, &val, sizeof(val));\n"
|
|
"}\n"
|
|
"static void store32_align0(uint8_t *ptr, uint32_t val) {\n", out);
|
|
if (is_big_endian) fputs(" val = i32_byteswap(val);", out);
|
|
fputs(" memcpy(ptr, &val, sizeof(val));\n"
|
|
"}\n"
|
|
"static void store32_align1(uint16_t *ptr, uint32_t val) {\n", out);
|
|
if (is_big_endian) fputs(" val = i32_byteswap(val);", out);
|
|
fputs(" memcpy(ptr, &val, sizeof(val));\n"
|
|
"}\n"
|
|
"static void store32_align2(uint32_t *ptr, uint32_t val) {\n", out);
|
|
if (is_big_endian) fputs(" val = i32_byteswap(val);", out);
|
|
fputs(" memcpy(ptr, &val, sizeof(val));\n"
|
|
"}\n"
|
|
"static void store64_align0(uint8_t *ptr, uint64_t val) {\n", out);
|
|
if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
|
|
fputs(" memcpy(ptr, &val, sizeof(val));\n"
|
|
"}\n"
|
|
"static void store64_align1(uint16_t *ptr, uint64_t val) {\n", out);
|
|
if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
|
|
fputs(" memcpy(ptr, &val, sizeof(val));\n"
|
|
"}\n"
|
|
"static void store64_align2(uint32_t *ptr, uint64_t val) {\n", out);
|
|
if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
|
|
fputs(" memcpy(ptr, &val, sizeof(val));\n"
|
|
"}\n"
|
|
"static void store64_align3(uint64_t *ptr, uint64_t val) {\n", out);
|
|
if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
|
|
fputs(" memcpy(ptr, &val, sizeof(val));\n"
|
|
"}\n"
|
|
"\n"
|
|
"static uint32_t i32_reinterpret_f32(const float src) {\n"
|
|
" uint32_t dst;\n"
|
|
" memcpy(&dst, &src, sizeof(dst));\n"
|
|
" return dst;\n"
|
|
"}\n"
|
|
"static uint64_t i64_reinterpret_f64(const double src) {\n"
|
|
" uint64_t dst;\n"
|
|
" memcpy(&dst, &src, sizeof(dst));\n"
|
|
" return dst;\n"
|
|
"}\n"
|
|
"static float f32_reinterpret_i32(const uint32_t src) {\n"
|
|
" float dst;\n"
|
|
" memcpy(&dst, &src, sizeof(dst));\n"
|
|
" return dst;\n"
|
|
"}\n"
|
|
"static double f64_reinterpret_i64(const uint64_t src) {\n"
|
|
" double dst;\n"
|
|
" memcpy(&dst, &src, sizeof(dst));\n"
|
|
" return dst;\n"
|
|
"}\n"
|
|
"\n"
|
|
"static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t *c, uint32_t n) {\n"
|
|
" uint8_t *new_m = *m;\n"
|
|
" uint32_t r = *p;\n"
|
|
" uint32_t new_p = r + n;\n"
|
|
" if (new_p > UINT32_C(0xFFFF)) return UINT32_C(0xFFFFFFFF);\n"
|
|
" uint32_t new_c = *c;\n"
|
|
" if (new_c < new_p) {\n"
|
|
" do new_c += new_c / 2 + 8; while (new_c < new_p);\n"
|
|
" if (new_c > UINT32_C(0xFFFF)) new_c = UINT32_C(0xFFFF);\n"
|
|
" new_m = realloc(new_m, new_c << 16);\n"
|
|
" if (new_m == NULL) return UINT32_C(0xFFFFFFFF);\n"
|
|
" *m = new_m;\n"
|
|
" *c = new_c;\n"
|
|
" }\n"
|
|
" *p = new_p;\n"
|
|
" memset(&new_m[r << 16], 0, n << 16);\n"
|
|
" return r;\n"
|
|
"}\n"
|
|
"\n"
|
|
"static int inited;\n"
|
|
"static void init_elem(void);\n"
|
|
"static void init_data(void);\n"
|
|
"static void init(void) {\n"
|
|
" if (inited != 0) return;\n"
|
|
" init_elem();\n"
|
|
" init_data();\n"
|
|
" inited = 1;\n"
|
|
"}\n"
|
|
"\n", out);
|
|
|
|
struct FuncType *types;
|
|
uint32_t max_param_len = 0;
|
|
(void)InputStream_skipToSection(&in, WasmSectionId_type);
|
|
{
|
|
uint32_t len = InputStream_readLeb128_u32(&in);
|
|
types = malloc(sizeof(struct FuncType) * len);
|
|
if (types == NULL) panic("out of memory");
|
|
for (uint32_t i = 0; i < len; i += 1) {
|
|
if (InputStream_readByte(&in) != 0x60) panic("expected functype");
|
|
types[i].param = InputStream_readResultType(&in);
|
|
if (types[i].param->len > max_param_len) max_param_len = types[i].param->len;
|
|
types[i].result = InputStream_readResultType(&in);
|
|
}
|
|
}
|
|
|
|
struct Import {
|
|
const char *mod;
|
|
const char *name;
|
|
uint32_t type_idx;
|
|
} *imports;
|
|
(void)InputStream_skipToSection(&in, WasmSectionId_import);
|
|
uint32_t imports_len = InputStream_readLeb128_u32(&in);
|
|
{
|
|
imports = malloc(sizeof(struct Import) * imports_len);
|
|
if (imports == NULL) panic("out of memory");
|
|
for (uint32_t i = 0; i < imports_len; i += 1) {
|
|
imports[i].mod = InputStream_readName(&in);
|
|
imports[i].name = InputStream_readName(&in);
|
|
switch (InputStream_readByte(&in)) {
|
|
case 0x00: { // func
|
|
imports[i].type_idx = InputStream_readLeb128_u32(&in);
|
|
const struct FuncType *func_type = &types[imports[i].type_idx];
|
|
switch (func_type->result->len) {
|
|
case 0: fputs("void", out); break;
|
|
case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
|
|
default: panic("multiple function returns not supported");
|
|
}
|
|
fprintf(out, " %s_%s(", imports[i].mod, imports[i].name);
|
|
if (func_type->param->len == 0) fputs("void", out);
|
|
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
|
if (param_i > 0) fputs(", ", out);
|
|
fputs(WasmValType_toC(func_type->param->types[param_i]), out);
|
|
}
|
|
fputs(");\n", out);
|
|
break;
|
|
}
|
|
|
|
case 0x01: // table
|
|
case 0x02: // mem
|
|
case 0x03: // global
|
|
default:
|
|
panic("unsupported import type");
|
|
}
|
|
}
|
|
fputc('\n', out);
|
|
}
|
|
|
|
struct Func {
|
|
uint32_t type_idx;
|
|
} *funcs;
|
|
(void)InputStream_skipToSection(&in, WasmSectionId_func);
|
|
{
|
|
uint32_t len = InputStream_readLeb128_u32(&in);
|
|
funcs = malloc(sizeof(struct Func) * len);
|
|
if (funcs == NULL) panic("out of memory");
|
|
for (uint32_t i = 0; i < len; i += 1) {
|
|
funcs[i].type_idx = InputStream_readLeb128_u32(&in);
|
|
const struct FuncType *func_type = &types[funcs[i].type_idx];
|
|
fputs("static ", out);
|
|
switch (func_type->result->len) {
|
|
case 0: fputs("void", out); break;
|
|
case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
|
|
default: panic("multiple function returns not supported");
|
|
}
|
|
fprintf(out, " f%" PRIu32 "(", i);
|
|
if (func_type->param->len == 0) fputs("void", out);
|
|
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
|
if (param_i > 0) fputs(", ", out);
|
|
fprintf(out, "%s", WasmValType_toC(func_type->param->types[param_i]));
|
|
}
|
|
fputs(");\n", out);
|
|
}
|
|
fputc('\n', out);
|
|
}
|
|
|
|
struct Table {
|
|
int8_t type;
|
|
struct Limits limits;
|
|
} *tables;
|
|
(void)InputStream_skipToSection(&in, WasmSectionId_table);
|
|
{
|
|
uint32_t len = InputStream_readLeb128_u32(&in);
|
|
tables = malloc(sizeof(struct Table) * len);
|
|
if (tables == NULL) panic("out of memory");
|
|
for (uint32_t i = 0; i < len; i += 1) {
|
|
int64_t ref_type = InputStream_readLeb128_i64(&in);
|
|
switch (ref_type) {
|
|
case WasmValType_funcref:
|
|
break;
|
|
|
|
default: panic("unsupported reftype");
|
|
}
|
|
tables[i].type = ref_type;
|
|
tables[i].limits = InputStream_readLimits(&in);
|
|
if (tables[i].limits.min != tables[i].limits.max) panic("growable table not supported");
|
|
fprintf(out, "static void (*t%" PRIu32 "[UINT32_C(%" PRIu32 ")])(void);\n",
|
|
i, tables[i].limits.min);
|
|
}
|
|
fputc('\n', out);
|
|
}
|
|
|
|
struct Mem {
|
|
struct Limits limits;
|
|
} *mems;
|
|
(void)InputStream_skipToSection(&in, WasmSectionId_mem);
|
|
uint32_t mems_len = InputStream_readLeb128_u32(&in);
|
|
{
|
|
mems = malloc(sizeof(struct Mem) * mems_len);
|
|
if (mems == NULL) panic("out of memory");
|
|
for (uint32_t i = 0; i < mems_len; i += 1) {
|
|
mems[i].limits = InputStream_readLimits(&in);
|
|
fprintf(out, "static uint8_t *m%" PRIu32 ";\n"
|
|
"static uint32_t p%" PRIu32 ";\n"
|
|
"static uint32_t c%" PRIu32 ";\n", i, i, i);
|
|
}
|
|
fputc('\n', out);
|
|
}
|
|
|
|
struct Global {
|
|
bool mut;
|
|
int8_t val_type;
|
|
} *globals;
|
|
(void)InputStream_skipToSection(&in, WasmSectionId_global);
|
|
{
|
|
uint32_t len = InputStream_readLeb128_u32(&in);
|
|
globals = malloc(sizeof(struct Global) * len);
|
|
if (globals == NULL) panic("out of memory");
|
|
for (uint32_t i = 0; i < len; i += 1) {
|
|
int64_t val_type = InputStream_readLeb128_i64(&in);
|
|
enum WasmMut mut = InputStream_readByte(&in);
|
|
fprintf(out, "%s%s g%" PRIu32 " = ", WasmMut_toC(mut), WasmValType_toC(val_type), i);
|
|
renderExpr(out, &in);
|
|
fputs(";\n", out);
|
|
globals[i].mut = mut;
|
|
globals[i].val_type = val_type;
|
|
}
|
|
fputc('\n', out);
|
|
}
|
|
|
|
(void)InputStream_skipToSection(&in, WasmSectionId_export);
|
|
{
|
|
uint32_t len = InputStream_readLeb128_u32(&in);
|
|
for (uint32_t i = 0; i < len; i += 1) {
|
|
char *name = InputStream_readName(&in);
|
|
uint8_t kind = InputStream_readByte(&in);
|
|
uint32_t idx = InputStream_readLeb128_u32(&in);
|
|
switch (kind) {
|
|
case 0x00: {
|
|
if (idx < imports_len) panic("can't export an import");
|
|
const struct FuncType *func_type = &types[funcs[idx - imports_len].type_idx];
|
|
switch (func_type->result->len) {
|
|
case 0: fputs("void", out); break;
|
|
case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
|
|
default: panic("multiple function returns not supported");
|
|
}
|
|
fprintf(out, " %s_%s(", mod, name);
|
|
if (func_type->param->len == 0) fputs("void", out);
|
|
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
|
if (param_i > 0) fputs(", ", out);
|
|
fprintf(out, "%s l%" PRIu32, WasmValType_toC(func_type->param->types[param_i]), param_i);
|
|
}
|
|
fprintf(out,
|
|
") {\n"
|
|
" init();\n"
|
|
" %sf%" PRIu32 "(",
|
|
func_type->result->len > 0 ? "return " : "", idx - imports_len);
|
|
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
|
if (param_i > 0) fputs(", ", out);
|
|
fprintf(out, "l%" PRIu32, param_i);
|
|
}
|
|
fputs(");\n}\n", out);
|
|
break;
|
|
}
|
|
|
|
case 0x02:
|
|
fprintf(out, "uint8_t **const %s_%s = &m%" PRIu32 ";\n", mod, name, idx);
|
|
break;
|
|
|
|
default: panic("unsupported export kind");
|
|
}
|
|
free(name);
|
|
}
|
|
fputc('\n', out);
|
|
}
|
|
|
|
(void)InputStream_skipToSection(&in, WasmSectionId_elem);
|
|
{
|
|
uint32_t len = InputStream_readLeb128_u32(&in);
|
|
fputs("static void init_elem(void) {\n", out);
|
|
for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) {
|
|
uint32_t table_idx = 0;
|
|
uint32_t elem_type = InputStream_readLeb128_u32(&in);
|
|
if (elem_type != 0x00) panic("unsupported elem type");
|
|
uint32_t offset = evalExpr(&in);
|
|
uint32_t segment_len = InputStream_readLeb128_u32(&in);
|
|
for (uint32_t i = 0; i < segment_len; i += 1) {
|
|
uint32_t func_id = InputStream_readLeb128_u32(&in);
|
|
fprintf(out, " t%" PRIu32 "[UINT32_C(%" PRIu32 ")] = (void (*)(void))&",
|
|
table_idx, offset + i);
|
|
if (func_id < imports_len)
|
|
fprintf(out, "%s_%s", imports[func_id].mod, imports[func_id].name);
|
|
else
|
|
fprintf(out, "f%" PRIu32, func_id - imports_len);
|
|
fputs(";\n", out);
|
|
}
|
|
}
|
|
fputs("}\n\n", out);
|
|
}
|
|
|
|
(void)InputStream_skipToSection(&in, WasmSectionId_code);
|
|
{
|
|
struct FuncGen fg;
|
|
FuncGen_init(&fg);
|
|
bool *param_used = malloc(sizeof(bool) * max_param_len);
|
|
uint32_t *param_stash = malloc(sizeof(uint32_t) * max_param_len);
|
|
|
|
uint32_t len = InputStream_readLeb128_u32(&in);
|
|
for (uint32_t func_i = 0; func_i < len; func_i += 1) {
|
|
FuncGen_reset(&fg);
|
|
|
|
InputStream_readLeb128_u32(&in);
|
|
const struct FuncType *func_type = &types[funcs[func_i].type_idx];
|
|
fputs("static ", out);
|
|
switch (func_type->result->len) {
|
|
case 0: fputs("void", out); break;
|
|
case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
|
|
default: panic("multiple function returns not supported");
|
|
}
|
|
fprintf(out, " f%" PRIu32 "(", func_i);
|
|
if (func_type->param->len == 0) fputs("void", out);
|
|
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
|
param_used[param_i] = false;
|
|
int8_t param_type = func_type->param->types[param_i];
|
|
if (param_i > 0) fputs(", ", out);
|
|
FuncGen_localDeclare(&fg, out, param_type);
|
|
}
|
|
fputs(") {\n", out);
|
|
|
|
for (uint32_t local_sets_remaining = InputStream_readLeb128_u32(&in);
|
|
local_sets_remaining > 0; local_sets_remaining -= 1) {
|
|
uint32_t local_set_len = InputStream_readLeb128_u32(&in);
|
|
int64_t val_type = InputStream_readLeb128_i64(&in);
|
|
for (; local_set_len > 0; local_set_len -= 1) {
|
|
FuncGen_indent(&fg, out);
|
|
FuncGen_localDeclare(&fg, out, val_type);
|
|
fputs(" = 0;\n", out);
|
|
}
|
|
}
|
|
|
|
uint32_t unreachable_depth = 0;
|
|
for (uint32_t result_i = func_type->result->len; result_i > 0; ) {
|
|
result_i -= 1;
|
|
FuncGen_indent(&fg, out);
|
|
(void)FuncGen_localDeclare(&fg, out,
|
|
func_type->result->types[result_i]);
|
|
fputs(";\n", out);
|
|
}
|
|
FuncGen_blockBegin(&fg, out, WasmOpcode_block, funcs[func_i].type_idx);
|
|
while (!FuncGen_done(&fg)) {
|
|
//static const char *mnemonics[] = {
|
|
// [WasmOpcode_unreachable] = "unreachable",
|
|
// [WasmOpcode_nop] = "nop",
|
|
// [WasmOpcode_block] = "block",
|
|
// [WasmOpcode_loop] = "loop",
|
|
// [WasmOpcode_if] = "if",
|
|
// [WasmOpcode_else] = "else",
|
|
// [WasmOpcode_end] = "end",
|
|
// [WasmOpcode_br] = "br",
|
|
// [WasmOpcode_br_if] = "br_if",
|
|
// [WasmOpcode_br_table] = "br_table",
|
|
// [WasmOpcode_return] = "return",
|
|
// [WasmOpcode_call] = "call",
|
|
// [WasmOpcode_call_indirect] = "call_indirect",
|
|
//
|
|
// [WasmOpcode_drop] = "drop",
|
|
// [WasmOpcode_select] = "select",
|
|
// [WasmOpcode_select_t] = "select t",
|
|
//
|
|
// [WasmOpcode_local_get] = "local.get",
|
|
// [WasmOpcode_local_set] = "local.set",
|
|
// [WasmOpcode_local_tee] = "local.tee",
|
|
// [WasmOpcode_global_get] = "global.get",
|
|
// [WasmOpcode_global_set] = "global.set",
|
|
// [WasmOpcode_table_get] = "table.get",
|
|
// [WasmOpcode_table_set] = "table.set",
|
|
//
|
|
// [WasmOpcode_i32_load] = "i32.load",
|
|
// [WasmOpcode_i64_load] = "i64.load",
|
|
// [WasmOpcode_f32_load] = "f32.load",
|
|
// [WasmOpcode_f64_load] = "f64.load",
|
|
// [WasmOpcode_i32_load8_s] = "i32.load8_s",
|
|
// [WasmOpcode_i32_load8_u] = "i32.load8_u",
|
|
// [WasmOpcode_i32_load16_s] = "i32.load16_s",
|
|
// [WasmOpcode_i32_load16_u] = "i32.load16_u",
|
|
// [WasmOpcode_i64_load8_s] = "i64.load8_s",
|
|
// [WasmOpcode_i64_load8_u] = "i64.load8_u",
|
|
// [WasmOpcode_i64_load16_s] = "i64.load16_s",
|
|
// [WasmOpcode_i64_load16_u] = "i64.load16_u",
|
|
// [WasmOpcode_i64_load32_s] = "i64.load32_s",
|
|
// [WasmOpcode_i64_load32_u] = "i64.load32_u",
|
|
// [WasmOpcode_i32_store] = "i32.store",
|
|
// [WasmOpcode_i64_store] = "i64.store",
|
|
// [WasmOpcode_f32_store] = "f32.store",
|
|
// [WasmOpcode_f64_store] = "f64.store",
|
|
// [WasmOpcode_i32_store8] = "i32.store8",
|
|
// [WasmOpcode_i32_store16] = "i32.store16",
|
|
// [WasmOpcode_i64_store8] = "i64.store8",
|
|
// [WasmOpcode_i64_store16] = "i64.store16",
|
|
// [WasmOpcode_i64_store32] = "i64.store32",
|
|
// [WasmOpcode_memory_size] = "memory.size",
|
|
// [WasmOpcode_memory_grow] = "memory.grow",
|
|
//
|
|
// [WasmOpcode_i32_const] = "i32.const",
|
|
// [WasmOpcode_i64_const] = "i64.const",
|
|
// [WasmOpcode_f32_const] = "f32.const",
|
|
// [WasmOpcode_f64_const] = "f64.const",
|
|
//
|
|
// [WasmOpcode_i32_eqz] = "i32.eqz",
|
|
// [WasmOpcode_i32_eq] = "i32.eq",
|
|
// [WasmOpcode_i32_ne] = "i32.ne",
|
|
// [WasmOpcode_i32_lt_s] = "i32.lt_s",
|
|
// [WasmOpcode_i32_lt_u] = "i32.lt_u",
|
|
// [WasmOpcode_i32_gt_s] = "i32.gt_s",
|
|
// [WasmOpcode_i32_gt_u] = "i32.gt_u",
|
|
// [WasmOpcode_i32_le_s] = "i32.le_s",
|
|
// [WasmOpcode_i32_le_u] = "i32.le_u",
|
|
// [WasmOpcode_i32_ge_s] = "i32.ge_s",
|
|
// [WasmOpcode_i32_ge_u] = "i32.ge_u",
|
|
//
|
|
// [WasmOpcode_i64_eqz] = "i64.eqz",
|
|
// [WasmOpcode_i64_eq] = "i64.eq",
|
|
// [WasmOpcode_i64_ne] = "i64.ne",
|
|
// [WasmOpcode_i64_lt_s] = "i64.lt_s",
|
|
// [WasmOpcode_i64_lt_u] = "i64.lt_u",
|
|
// [WasmOpcode_i64_gt_s] = "i64.gt_s",
|
|
// [WasmOpcode_i64_gt_u] = "i64.gt_u",
|
|
// [WasmOpcode_i64_le_s] = "i64.le_s",
|
|
// [WasmOpcode_i64_le_u] = "i64.le_u",
|
|
// [WasmOpcode_i64_ge_s] = "i64.ge_s",
|
|
// [WasmOpcode_i64_ge_u] = "i64.ge_u",
|
|
//
|
|
// [WasmOpcode_f32_eq] = "f32.eq",
|
|
// [WasmOpcode_f32_ne] = "f32.ne",
|
|
// [WasmOpcode_f32_lt] = "f32.lt",
|
|
// [WasmOpcode_f32_gt] = "f32.gt",
|
|
// [WasmOpcode_f32_le] = "f32.le",
|
|
// [WasmOpcode_f32_ge] = "f32.ge",
|
|
//
|
|
// [WasmOpcode_f64_eq] = "f64.eq",
|
|
// [WasmOpcode_f64_ne] = "f64.ne",
|
|
// [WasmOpcode_f64_lt] = "f64.lt",
|
|
// [WasmOpcode_f64_gt] = "f64.gt",
|
|
// [WasmOpcode_f64_le] = "f64.le",
|
|
// [WasmOpcode_f64_ge] = "f64.ge",
|
|
//
|
|
// [WasmOpcode_i32_clz] = "i32.clz",
|
|
// [WasmOpcode_i32_ctz] = "i32.ctz",
|
|
// [WasmOpcode_i32_popcnt] = "i32.popcnt",
|
|
// [WasmOpcode_i32_add] = "i32.add",
|
|
// [WasmOpcode_i32_sub] = "i32.sub",
|
|
// [WasmOpcode_i32_mul] = "i32.mul",
|
|
// [WasmOpcode_i32_div_s] = "i32.div_s",
|
|
// [WasmOpcode_i32_div_u] = "i32.div_u",
|
|
// [WasmOpcode_i32_rem_s] = "i32.rem_s",
|
|
// [WasmOpcode_i32_rem_u] = "i32.rem_u",
|
|
// [WasmOpcode_i32_and] = "i32.and",
|
|
// [WasmOpcode_i32_or] = "i32.or",
|
|
// [WasmOpcode_i32_xor] = "i32.xor",
|
|
// [WasmOpcode_i32_shl] = "i32.shl",
|
|
// [WasmOpcode_i32_shr_s] = "i32.shr_s",
|
|
// [WasmOpcode_i32_shr_u] = "i32.shr_u",
|
|
// [WasmOpcode_i32_rotl] = "i32.rotl",
|
|
// [WasmOpcode_i32_rotr] = "i32.rotr",
|
|
//
|
|
// [WasmOpcode_i64_clz] = "i64.clz",
|
|
// [WasmOpcode_i64_ctz] = "i64.ctz",
|
|
// [WasmOpcode_i64_popcnt] = "i64.popcnt",
|
|
// [WasmOpcode_i64_add] = "i64.add",
|
|
// [WasmOpcode_i64_sub] = "i64.sub",
|
|
// [WasmOpcode_i64_mul] = "i64.mul",
|
|
// [WasmOpcode_i64_div_s] = "i64.div_s",
|
|
// [WasmOpcode_i64_div_u] = "i64.div_u",
|
|
// [WasmOpcode_i64_rem_s] = "i64.rem_s",
|
|
// [WasmOpcode_i64_rem_u] = "i64.rem_u",
|
|
// [WasmOpcode_i64_and] = "i64.and",
|
|
// [WasmOpcode_i64_or] = "i64.or",
|
|
// [WasmOpcode_i64_xor] = "i64.xor",
|
|
// [WasmOpcode_i64_shl] = "i64.shl",
|
|
// [WasmOpcode_i64_shr_s] = "i64.shr_s",
|
|
// [WasmOpcode_i64_shr_u] = "i64.shr_u",
|
|
// [WasmOpcode_i64_rotl] = "i64.rotl",
|
|
// [WasmOpcode_i64_rotr] = "i64.rotr",
|
|
//
|
|
// [WasmOpcode_f32_abs] = "f32.abs",
|
|
// [WasmOpcode_f32_neg] = "f32.neg",
|
|
// [WasmOpcode_f32_ceil] = "f32.ceil",
|
|
// [WasmOpcode_f32_floor] = "f32.floor",
|
|
// [WasmOpcode_f32_trunc] = "f32.trunc",
|
|
// [WasmOpcode_f32_nearest] = "f32.nearest",
|
|
// [WasmOpcode_f32_sqrt] = "f32.sqrt",
|
|
// [WasmOpcode_f32_add] = "f32.add",
|
|
// [WasmOpcode_f32_sub] = "f32.sub",
|
|
// [WasmOpcode_f32_mul] = "f32.mul",
|
|
// [WasmOpcode_f32_div] = "f32.div",
|
|
// [WasmOpcode_f32_min] = "f32.min",
|
|
// [WasmOpcode_f32_max] = "f32.max",
|
|
// [WasmOpcode_f32_copysign] = "f32.copysign",
|
|
//
|
|
// [WasmOpcode_f64_abs] = "f64.abs",
|
|
// [WasmOpcode_f64_neg] = "f64.neg",
|
|
// [WasmOpcode_f64_ceil] = "f64.ceil",
|
|
// [WasmOpcode_f64_floor] = "f64.floor",
|
|
// [WasmOpcode_f64_trunc] = "f64.trunc",
|
|
// [WasmOpcode_f64_nearest] = "f64.nearest",
|
|
// [WasmOpcode_f64_sqrt] = "f64.sqrt",
|
|
// [WasmOpcode_f64_add] = "f64.add",
|
|
// [WasmOpcode_f64_sub] = "f64.sub",
|
|
// [WasmOpcode_f64_mul] = "f64.mul",
|
|
// [WasmOpcode_f64_div] = "f64.div",
|
|
// [WasmOpcode_f64_min] = "f64.min",
|
|
// [WasmOpcode_f64_max] = "f64.max",
|
|
// [WasmOpcode_f64_copysign] = "f64.copysign",
|
|
//
|
|
// [WasmOpcode_i32_wrap_i64] = "i32.wrap_i64",
|
|
// [WasmOpcode_i32_trunc_f32_s] = "i32.trunc_f32_s",
|
|
// [WasmOpcode_i32_trunc_f32_u] = "i32.trunc_f32_u",
|
|
// [WasmOpcode_i32_trunc_f64_s] = "i32.trunc_f64_s",
|
|
// [WasmOpcode_i32_trunc_f64_u] = "i32.trunc_f64_u",
|
|
// [WasmOpcode_i64_extend_i32_s] = "i64.extend_i32_s",
|
|
// [WasmOpcode_i64_extend_i32_u] = "i64.extend_i32_u",
|
|
// [WasmOpcode_i64_trunc_f32_s] = "i64.trunc_f32_s",
|
|
// [WasmOpcode_i64_trunc_f32_u] = "i64.trunc_f32_u",
|
|
// [WasmOpcode_i64_trunc_f64_s] = "i64.trunc_f64_s",
|
|
// [WasmOpcode_i64_trunc_f64_u] = "i64.trunc_f64_u",
|
|
// [WasmOpcode_f32_convert_i32_s] = "f32.convert_i32_s",
|
|
// [WasmOpcode_f32_convert_i32_u] = "f32.convert_i32_u",
|
|
// [WasmOpcode_f32_convert_i64_s] = "f32.convert_i64_s",
|
|
// [WasmOpcode_f32_convert_i64_u] = "f32.convert_i64_u",
|
|
// [WasmOpcode_f32_demote_f64] = "f32.demote_f64",
|
|
// [WasmOpcode_f64_convert_i32_s] = "f64.convert_i32_s",
|
|
// [WasmOpcode_f64_convert_i32_u] = "f64.convert_i32_u",
|
|
// [WasmOpcode_f64_convert_i64_s] = "f64.convert_i64_s",
|
|
// [WasmOpcode_f64_convert_i64_u] = "f64.convert_i64_u",
|
|
// [WasmOpcode_f64_promote_f32] = "f64.promote_f32",
|
|
// [WasmOpcode_i32_reinterpret_f32] = "i32.reinterpret_f32",
|
|
// [WasmOpcode_i64_reinterpret_f64] = "i64.reinterpret_f64",
|
|
// [WasmOpcode_f32_reinterpret_i32] = "f32.reinterpret_i32",
|
|
// [WasmOpcode_f64_reinterpret_i64] = "f64.reinterpret_i64",
|
|
//
|
|
// [WasmOpcode_i32_extend8_s] = "i32.extend8_s",
|
|
// [WasmOpcode_i32_extend16_s] = "i32.extend16_s",
|
|
// [WasmOpcode_i64_extend8_s] = "i64.extend8_s",
|
|
// [WasmOpcode_i64_extend16_s] = "i64.extend16_s",
|
|
// [WasmOpcode_i64_extend32_s] = "i64.extend32_s",
|
|
//
|
|
// [WasmOpcode_prefixed] = "prefixed",
|
|
//};
|
|
uint8_t opcode = InputStream_readByte(&in);
|
|
//FuncGen_indent(&fg, out);
|
|
//fprintf(out, "// %2u: ", fg.stack_i);
|
|
//if (mnemonics[opcode])
|
|
// fprintf(out, "%s\n", mnemonics[opcode]);
|
|
//else
|
|
// fprintf(out, "%02hhX\n", opcode);
|
|
//fflush(out); // DEBUG
|
|
switch (opcode) {
|
|
case WasmOpcode_unreachable:
|
|
if (unreachable_depth == 0) {
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "abort();\n");
|
|
unreachable_depth += 1;
|
|
}
|
|
break;
|
|
case WasmOpcode_nop:
|
|
break;
|
|
case WasmOpcode_block:
|
|
case WasmOpcode_loop:
|
|
case WasmOpcode_if: {
|
|
int64_t block_type = InputStream_readLeb128_i64(&in);
|
|
if (unreachable_depth == 0) {
|
|
const struct FuncType *func_type = FuncType_blockType(types, block_type);
|
|
for (uint32_t param_i = func_type->param->len; param_i > 0; ) {
|
|
param_i -= 1;
|
|
FuncGen_indent(&fg, out);
|
|
param_stash[param_i] =
|
|
FuncGen_localDeclare(&fg, out, func_type->param->types[param_i]);
|
|
fprintf(out, " = l%" PRIu32 ";\n", FuncGen_stackPop(&fg));
|
|
}
|
|
for (uint32_t result_i = func_type->result->len; result_i > 0; ) {
|
|
result_i -= 1;
|
|
FuncGen_indent(&fg, out);
|
|
(void)FuncGen_localDeclare(&fg, out,
|
|
func_type->result->types[result_i]);
|
|
fputs(";\n", out);
|
|
}
|
|
FuncGen_blockBegin(&fg, out, opcode, block_type);
|
|
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
|
FuncGen_stackPush(&fg, out, func_type->param->types[param_i]);
|
|
fprintf(out, " = l%" PRIu32 ";\n", param_stash[param_i]);
|
|
}
|
|
} else unreachable_depth += 1;
|
|
break;
|
|
}
|
|
case WasmOpcode_else:
|
|
case WasmOpcode_end:
|
|
if (unreachable_depth <= 1) {
|
|
const struct ResultType *result_type =
|
|
FuncType_blockType(types, FuncGen_blockType(&fg, 0))->result;
|
|
uint32_t label = FuncGen_blockLabel(&fg, 0);
|
|
if (unreachable_depth == 0) {
|
|
const struct ResultType *result_type =
|
|
FuncType_blockType(types, FuncGen_blockType(&fg, 0))->result;
|
|
for (uint32_t result_i = result_type->len; result_i > 0; ) {
|
|
result_i -= 1;
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n",
|
|
label - result_type->len + result_i, FuncGen_stackPop(&fg));
|
|
}
|
|
} else unreachable_depth -= 1;
|
|
switch (opcode) {
|
|
case WasmOpcode_else:
|
|
FuncGen_reuseReset(&fg);
|
|
FuncGen_outdent(&fg, out);
|
|
fputs("} else {\n", out);
|
|
break;
|
|
case WasmOpcode_end:
|
|
FuncGen_blockEnd(&fg, out);
|
|
for (uint32_t result_i = 0; result_i < result_type->len;
|
|
result_i += 1) {
|
|
FuncGen_stackPush(&fg, out, result_type->types[result_i]);
|
|
fprintf(out, "l%" PRIu32 ";\n",
|
|
label - result_type->len + result_i);
|
|
}
|
|
break;
|
|
}
|
|
} else if (opcode == WasmOpcode_end) unreachable_depth -= 1;
|
|
break;
|
|
case WasmOpcode_br:
|
|
case WasmOpcode_br_if: {
|
|
uint32_t label_idx = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
enum WasmOpcode kind = FuncGen_blockKind(&fg, label_idx);
|
|
const struct FuncType *func_type =
|
|
FuncType_blockType(types, FuncGen_blockType(&fg, label_idx));
|
|
uint32_t label = FuncGen_blockLabel(&fg, label_idx);
|
|
|
|
if (opcode == WasmOpcode_br_if) {
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "if (l%" PRIu32 ") {\n", FuncGen_stackPop(&fg));
|
|
} else if (EXTRA_BRACES) {
|
|
FuncGen_indent(&fg, out);
|
|
fputs("{\n", out);
|
|
}
|
|
|
|
const struct ResultType *label_type;
|
|
uint32_t lhs;
|
|
switch (kind) {
|
|
case WasmOpcode_loop:
|
|
label_type = func_type->param;
|
|
lhs = label - func_type->result->len - func_type->param->len;
|
|
break;
|
|
default:
|
|
label_type = func_type->result;
|
|
lhs = label - func_type->result->len;
|
|
break;
|
|
}
|
|
for (uint32_t stack_i = 0; stack_i < label_type->len; stack_i += 1) {
|
|
uint32_t rhs;
|
|
switch (opcode) {
|
|
case WasmOpcode_br:
|
|
rhs = FuncGen_stackPop(&fg);
|
|
break;
|
|
case WasmOpcode_br_if:
|
|
rhs = FuncGen_stackAt(&fg, stack_i);
|
|
break;
|
|
default: panic("unexpected opcode");
|
|
}
|
|
FuncGen_cont(&fg, out);
|
|
fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n", lhs, rhs);
|
|
lhs += 1;
|
|
}
|
|
FuncGen_cont(&fg, out);
|
|
fprintf(out, "goto l%" PRIu32 ";\n", label);
|
|
if (EXTRA_BRACES || opcode == WasmOpcode_br_if) {
|
|
FuncGen_indent(&fg, out);
|
|
fputs("}\n", out);
|
|
}
|
|
if (opcode == WasmOpcode_br) unreachable_depth += 1;
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_br_table: {
|
|
if (unreachable_depth == 0) {
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "switch (l%" PRIu32 ") {\n", FuncGen_stackPop(&fg));
|
|
}
|
|
uint32_t label_len = InputStream_readLeb128_u32(&in);
|
|
for (uint32_t i = 0; i < label_len; i += 1) {
|
|
uint32_t label = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "case %u: goto l%" PRIu32 ";\n",
|
|
i, FuncGen_blockLabel(&fg, label));
|
|
}
|
|
}
|
|
uint32_t label = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "default: goto l%" PRIu32 ";\n",
|
|
FuncGen_blockLabel(&fg, label));
|
|
FuncGen_indent(&fg, out);
|
|
fputs("}\n", out);
|
|
unreachable_depth += 1;
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_return:
|
|
if (unreachable_depth == 0) {
|
|
FuncGen_indent(&fg, out);
|
|
fputs("return", out);
|
|
switch (func_type->result->len) {
|
|
case 0: break;
|
|
case 1: fprintf(out, " l%" PRIu32, FuncGen_stackPop(&fg)); break;
|
|
default: panic("multiple function returns not supported");
|
|
}
|
|
fputs(";\n", out);
|
|
unreachable_depth += 1;
|
|
}
|
|
break;
|
|
case WasmOpcode_call:
|
|
case WasmOpcode_call_indirect: {
|
|
uint32_t func_id;
|
|
uint32_t type_idx;
|
|
uint32_t table_idx;
|
|
switch (opcode) {
|
|
case WasmOpcode_call:
|
|
func_id = InputStream_readLeb128_u32(&in);
|
|
if (func_id < imports_len)
|
|
type_idx = imports[func_id].type_idx;
|
|
else
|
|
type_idx = funcs[func_id - imports_len].type_idx;
|
|
break;
|
|
case WasmOpcode_call_indirect:
|
|
type_idx = InputStream_readLeb128_u32(&in);
|
|
table_idx = InputStream_readLeb128_u32(&in);
|
|
func_id = FuncGen_stackPop(&fg);
|
|
break;
|
|
}
|
|
if (unreachable_depth == 0) {
|
|
const struct FuncType *callee_func_type = &types[type_idx];
|
|
for (uint32_t param_i = callee_func_type->param->len; param_i > 0; ) {
|
|
param_i -= 1;
|
|
param_stash[param_i] = FuncGen_stackPop(&fg);
|
|
}
|
|
switch (callee_func_type->result->len) {
|
|
case 0: FuncGen_indent(&fg, out); break;
|
|
case 1: FuncGen_stackPush(&fg, out, callee_func_type->result->types[0]); break;
|
|
default: panic("multiple function returns not supported");
|
|
}
|
|
switch (opcode) {
|
|
case WasmOpcode_call:
|
|
if (func_id < imports_len)
|
|
fprintf(out, "%s_%s", imports[func_id].mod, imports[func_id].name);
|
|
else
|
|
fprintf(out, "f%" PRIu32, func_id - imports_len);
|
|
break;
|
|
case WasmOpcode_call_indirect:
|
|
fputs("(*(", out);
|
|
switch (callee_func_type->result->len) {
|
|
case 0: fputs("void", out); break;
|
|
case 1: fputs(WasmValType_toC(callee_func_type->result->types[0]), out); break;
|
|
default: panic("multiple function returns not supported");
|
|
}
|
|
fputs(" (*)(", out);
|
|
if (callee_func_type->param->len == 0) fputs("void", out);
|
|
for (uint32_t param_i = 0; param_i < callee_func_type->param->len; param_i += 1) {
|
|
if (param_i > 0) fputs(", ", out);
|
|
fputs(WasmValType_toC(callee_func_type->param->types[param_i]), out);
|
|
}
|
|
fprintf(out, "))t%" PRIu32 "[l%" PRIu32 "])", table_idx, func_id);
|
|
break;
|
|
}
|
|
fputc('(', out);
|
|
for (uint32_t param_i = 0; param_i < callee_func_type->param->len;
|
|
param_i += 1) {
|
|
if (param_i > 0) fputs(", ", out);
|
|
fprintf(out, "l%" PRIu32, param_stash[param_i]);
|
|
}
|
|
fputs(");\n", out);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WasmOpcode_drop:
|
|
if (unreachable_depth == 0) {
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "(void)l%" PRIu32 ";\n", FuncGen_stackPop(&fg));
|
|
}
|
|
break;
|
|
case WasmOpcode_select:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t cond = FuncGen_stackPop(&fg);
|
|
uint32_t rhs = FuncGen_stackPop(&fg);
|
|
uint32_t lhs = FuncGen_stackAt(&fg, 0);
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%"PRIu32" = l%" PRIu32 " ? l%" PRIu32 " : l%" PRIu32 ";\n",
|
|
lhs, cond, lhs, rhs);
|
|
}
|
|
break;
|
|
|
|
case WasmOpcode_local_get: {
|
|
uint32_t local_idx = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
if (local_idx < func_type->param->len) param_used[local_idx] = true;
|
|
FuncGen_stackPush(&fg, out, FuncGen_localType(&fg, local_idx));
|
|
fprintf(out, "l%" PRIu32 ";\n", local_idx);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_local_set: {
|
|
uint32_t local_idx = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
if (local_idx < func_type->param->len) param_used[local_idx] = true;
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n",
|
|
local_idx, FuncGen_stackPop(&fg));
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_local_tee: {
|
|
uint32_t local_idx = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
if (local_idx < func_type->param->len) param_used[local_idx] = true;
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n",
|
|
local_idx, FuncGen_stackAt(&fg, 0));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WasmOpcode_global_get: {
|
|
uint32_t global_idx = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
FuncGen_stackPush(&fg, out, globals[global_idx].val_type);
|
|
fprintf(out, "g%" PRIu32 ";\n", global_idx);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_global_set: {
|
|
uint32_t global_idx = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "g%" PRIu32 " = l%" PRIu32 ";\n",
|
|
global_idx, FuncGen_stackPop(&fg));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WasmOpcode_table_get:
|
|
case WasmOpcode_table_set:
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) panic("unimplemented opcode");
|
|
break;
|
|
|
|
case WasmOpcode_i32_load: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "load32_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" PRIu32
|
|
"[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
|
|
align, 8 << align, 0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i64_load: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "load64_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" PRIu32
|
|
"[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
|
|
align, 8 << align, 0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_f32_load: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
|
fprintf(out, "f32_reinterpret_i32(load32_align%" PRIu32 "((const uint%" PRIu32
|
|
"_t *)&m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]));\n",
|
|
align, 8 << align, 0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_f64_load: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
|
fprintf(out, "f64_reinterpret_i64(load64_align%" PRIu32 "((const uint%" PRIu32
|
|
"_t *)&m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]));\n",
|
|
align, 8 << align, 0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i32_load8_s: {
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "(int8_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
|
|
0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i32_load8_u: {
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
|
|
0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i32_load16_s: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "(int16_t)load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%"
|
|
PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
|
|
align, 8 << align, 0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i32_load16_u: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%"
|
|
PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
|
|
align, 8 << align, 0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i64_load8_s: {
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "(int8_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
|
|
0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i64_load8_u: {
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
|
|
0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i64_load16_s: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "(int16_t)load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%"
|
|
PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
|
|
align, 8 << align, 0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i64_load16_u: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%"
|
|
PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
|
|
align, 8 << align, 0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i64_load32_s: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "(int32_t)load32_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%"
|
|
PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
|
|
align, 8 << align, 0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i64_load32_u: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "load32_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%"
|
|
PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n",
|
|
align, 8 << align, 0, base, offset);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WasmOpcode_i32_store: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t value = FuncGen_stackPop(&fg);
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "store32_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
|
|
PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], l%" PRIu32 ");\n",
|
|
align, 8 << align, 0, base, offset, value);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i64_store: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t value = FuncGen_stackPop(&fg);
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "store64_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
|
|
PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], l%" PRIu32 ");\n",
|
|
align, 8 << align, 0, base, offset, value);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_f32_store: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t value = FuncGen_stackPop(&fg);
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "store32_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
|
|
PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], "
|
|
"i32_reinterpret_f32(l%" PRIu32 "));\n",
|
|
align, 8 << align, 0, base, offset, value);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_f64_store: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t value = FuncGen_stackPop(&fg);
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "store64_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
|
|
PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], "
|
|
"i64_reinterpret_f64(l%" PRIu32 "));\n",
|
|
align, 8 << align, 0, base, offset, value);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i32_store8: {
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t value = FuncGen_stackPop(&fg);
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32
|
|
")] = (uint8_t)l%" PRIu32 ";\n", 0, base, offset, value);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i32_store16: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t value = FuncGen_stackPop(&fg);
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "store16_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
|
|
PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], "
|
|
"(uint16_t)l%" PRIu32 ");\n",
|
|
align, 8 << align, 0, base, offset, value);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i64_store8: {
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t value = FuncGen_stackPop(&fg);
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32
|
|
")] = (uint8_t)l%" PRIu32 ";\n", 0, base, offset, value);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i64_store16: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t value = FuncGen_stackPop(&fg);
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "store16_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
|
|
PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], "
|
|
"(uint16_t)l%" PRIu32 ");\n",
|
|
align, 8 << align, 0, base, offset, value);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i64_store32: {
|
|
uint32_t align = InputStream_readLeb128_u32(&in);
|
|
uint32_t offset = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t value = FuncGen_stackPop(&fg);
|
|
uint32_t base = FuncGen_stackPop(&fg);
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "store32_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%"
|
|
PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], "
|
|
"(uint32_t)l%" PRIu32 ");\n",
|
|
align, 8 << align, 0, base, offset, value);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WasmOpcode_memory_size: {
|
|
uint32_t mem_idx = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "p%" PRIu32 ";\n", mem_idx);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_memory_grow: {
|
|
uint32_t mem_idx = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t pages = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "memory_grow(&m%" PRIu32 ", &p%" PRIu32 ", &c%" PRIu32
|
|
", l%" PRIu32 ");\n", mem_idx, mem_idx, mem_idx, pages);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WasmOpcode_i32_const: {
|
|
uint32_t value = (uint32_t)InputStream_readLeb128_i32(&in);
|
|
if (unreachable_depth == 0) {
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "UINT32_C(0x%" PRIX32 ");\n", value);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_i64_const: {
|
|
uint64_t value = (uint64_t)InputStream_readLeb128_i64(&in);
|
|
if (unreachable_depth == 0) {
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "UINT64_C(0x%" PRIX64 ");\n", value);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_f32_const: {
|
|
uint32_t value = InputStream_readLittle_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
|
fprintf(out, "f32_reinterpret_i32(UINT32_C(0x%" PRIX32 "));\n", value);
|
|
}
|
|
break;
|
|
}
|
|
case WasmOpcode_f64_const: {
|
|
uint64_t value = InputStream_readLittle_u64(&in);
|
|
if (unreachable_depth == 0) {
|
|
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
|
fprintf(out, "f64_reinterpret_i64(UINT64_C(0x%" PRIX64 "));\n", value);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WasmOpcode_i32_eqz:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackAt(&fg, 0);
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%" PRIu32 " = !l%" PRIu32 ";\n", lhs, lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i32_eq:
|
|
case WasmOpcode_i32_ne:
|
|
case WasmOpcode_i32_lt_u:
|
|
case WasmOpcode_i32_gt_u:
|
|
case WasmOpcode_i32_le_u:
|
|
case WasmOpcode_i32_ge_u:
|
|
// i32 unsigned comparisons
|
|
if (unreachable_depth == 0) {
|
|
uint32_t rhs = FuncGen_stackPop(&fg);
|
|
uint32_t lhs = FuncGen_stackAt(&fg, 0);
|
|
const char *operator;
|
|
switch (opcode) {
|
|
case WasmOpcode_i32_eq: operator = "=="; break;
|
|
case WasmOpcode_i32_ne: operator = "!="; break;
|
|
case WasmOpcode_i32_lt_u: operator = "<"; break;
|
|
case WasmOpcode_i32_gt_u: operator = ">"; break;
|
|
case WasmOpcode_i32_le_u: operator = "<="; break;
|
|
case WasmOpcode_i32_ge_u: operator = ">="; break;
|
|
default: panic("unreachable");
|
|
}
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%" PRIu32 " = l%" PRIu32 " %s l%" PRIu32 ";\n",
|
|
lhs, lhs, operator, rhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i32_lt_s:
|
|
case WasmOpcode_i32_gt_s:
|
|
case WasmOpcode_i32_le_s:
|
|
case WasmOpcode_i32_ge_s:
|
|
// i32 signed comparisons
|
|
if (unreachable_depth == 0) {
|
|
uint32_t rhs = FuncGen_stackPop(&fg);
|
|
uint32_t lhs = FuncGen_stackAt(&fg, 0);
|
|
const char *operator;
|
|
switch (opcode) {
|
|
case WasmOpcode_i32_lt_s: operator = "<"; break;
|
|
case WasmOpcode_i32_gt_s: operator = ">"; break;
|
|
case WasmOpcode_i32_le_s: operator = "<="; break;
|
|
case WasmOpcode_i32_ge_s: operator = ">="; break;
|
|
default: panic("unreachable");
|
|
}
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%" PRIu32 " = (int32_t)l%" PRIu32 " %s (int32_t)l%" PRIu32
|
|
";\n", lhs, lhs, operator, rhs);
|
|
}
|
|
break;
|
|
|
|
case WasmOpcode_i64_eqz:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "!l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i64_eq:
|
|
case WasmOpcode_i64_ne:
|
|
case WasmOpcode_i64_lt_u:
|
|
case WasmOpcode_i64_gt_u:
|
|
case WasmOpcode_i64_le_u:
|
|
case WasmOpcode_i64_ge_u:
|
|
case WasmOpcode_f32_eq:
|
|
case WasmOpcode_f32_ne:
|
|
case WasmOpcode_f32_lt:
|
|
case WasmOpcode_f32_gt:
|
|
case WasmOpcode_f32_le:
|
|
case WasmOpcode_f32_ge:
|
|
case WasmOpcode_f64_eq:
|
|
case WasmOpcode_f64_ne:
|
|
case WasmOpcode_f64_lt:
|
|
case WasmOpcode_f64_gt:
|
|
case WasmOpcode_f64_le:
|
|
case WasmOpcode_f64_ge:
|
|
// non-i32 unsigned comparisons
|
|
if (unreachable_depth == 0) {
|
|
uint32_t rhs = FuncGen_stackPop(&fg);
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
const char *operator;
|
|
switch (opcode) {
|
|
case WasmOpcode_i64_eq:
|
|
case WasmOpcode_f32_eq:
|
|
case WasmOpcode_f64_eq:
|
|
operator = "==";
|
|
break;
|
|
case WasmOpcode_i64_ne:
|
|
case WasmOpcode_f32_ne:
|
|
case WasmOpcode_f64_ne:
|
|
operator = "!=";
|
|
break;
|
|
case WasmOpcode_i64_lt_u:
|
|
case WasmOpcode_f32_lt:
|
|
case WasmOpcode_f64_lt:
|
|
operator = "<";
|
|
break;
|
|
case WasmOpcode_i64_gt_u:
|
|
case WasmOpcode_f32_gt:
|
|
case WasmOpcode_f64_gt:
|
|
operator = ">";
|
|
break;
|
|
case WasmOpcode_i64_le_u:
|
|
case WasmOpcode_f32_le:
|
|
case WasmOpcode_f64_le:
|
|
operator = "<=";
|
|
break;
|
|
case WasmOpcode_i64_ge_u:
|
|
case WasmOpcode_f32_ge:
|
|
case WasmOpcode_f64_ge:
|
|
operator = ">=";
|
|
break;
|
|
default: panic("unreachable");
|
|
}
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "l%" PRIu32 " = l%" PRIu32 " %s l%" PRIu32 ";\n",
|
|
lhs, lhs, operator, rhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i64_lt_s:
|
|
case WasmOpcode_i64_gt_s:
|
|
case WasmOpcode_i64_le_s:
|
|
case WasmOpcode_i64_ge_s:
|
|
// i64 signed comparisons
|
|
if (unreachable_depth == 0) {
|
|
uint32_t rhs = FuncGen_stackPop(&fg);
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
const char *operator;
|
|
switch (opcode) {
|
|
case WasmOpcode_i64_lt_s: operator = "<"; break;
|
|
case WasmOpcode_i64_gt_s: operator = ">"; break;
|
|
case WasmOpcode_i64_le_s: operator = "<="; break;
|
|
case WasmOpcode_i64_ge_s: operator = ">="; break;
|
|
default: panic("unreachable");
|
|
}
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "l%" PRIu32 " = (int64_t)l%" PRIu32 " %s (int64_t)l%" PRIu32
|
|
";\n", lhs, lhs, operator, rhs);
|
|
}
|
|
break;
|
|
|
|
case WasmOpcode_i32_clz:
|
|
case WasmOpcode_i32_ctz:
|
|
case WasmOpcode_i32_popcnt:
|
|
case WasmOpcode_i64_clz:
|
|
case WasmOpcode_i64_ctz:
|
|
case WasmOpcode_i64_popcnt:
|
|
case WasmOpcode_f32_abs:
|
|
case WasmOpcode_f32_neg:
|
|
case WasmOpcode_f32_ceil:
|
|
case WasmOpcode_f32_floor:
|
|
case WasmOpcode_f32_trunc:
|
|
case WasmOpcode_f32_nearest:
|
|
case WasmOpcode_f32_sqrt:
|
|
case WasmOpcode_f64_abs:
|
|
case WasmOpcode_f64_neg:
|
|
case WasmOpcode_f64_ceil:
|
|
case WasmOpcode_f64_floor:
|
|
case WasmOpcode_f64_trunc:
|
|
case WasmOpcode_f64_nearest:
|
|
case WasmOpcode_f64_sqrt:
|
|
// unary functions
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackAt(&fg, 0);
|
|
const char *function;
|
|
switch (opcode) {
|
|
case WasmOpcode_i32_clz: function = "i32_clz"; break;
|
|
case WasmOpcode_i32_ctz: function = "i32_ctz"; break;
|
|
case WasmOpcode_i32_popcnt: function = "i32_popcnt"; break;
|
|
case WasmOpcode_i64_clz: function = "i64_clz"; break;
|
|
case WasmOpcode_i64_ctz: function = "i64_ctz"; break;
|
|
case WasmOpcode_i64_popcnt: function = "i64_popcnt"; break;
|
|
case WasmOpcode_f32_abs: function = "fabsf"; break;
|
|
case WasmOpcode_f32_neg:
|
|
case WasmOpcode_f64_neg: function = "-"; break;
|
|
case WasmOpcode_f32_ceil: function = "ceilf"; break;
|
|
case WasmOpcode_f32_floor: function = "floorf"; break;
|
|
case WasmOpcode_f32_trunc: function = "truncf"; break;
|
|
case WasmOpcode_f32_nearest: function = "roundf"; break;
|
|
case WasmOpcode_f32_sqrt: function = "sqrtf"; break;
|
|
case WasmOpcode_f64_abs: function = "fabs"; break;
|
|
case WasmOpcode_f64_ceil: function = "ceil"; break;
|
|
case WasmOpcode_f64_floor: function = "floor"; break;
|
|
case WasmOpcode_f64_trunc: function = "trunc"; break;
|
|
case WasmOpcode_f64_nearest: function = "round"; break;
|
|
case WasmOpcode_f64_sqrt: function = "sqrt"; break;
|
|
default: panic("unreachable");
|
|
}
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%" PRIu32 " = %s(l%" PRIu32 ");\n", lhs, function, lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i32_add:
|
|
case WasmOpcode_i32_sub:
|
|
case WasmOpcode_i32_mul:
|
|
case WasmOpcode_i32_div_u:
|
|
case WasmOpcode_i32_rem_u:
|
|
case WasmOpcode_i32_and:
|
|
case WasmOpcode_i32_or:
|
|
case WasmOpcode_i32_xor:
|
|
case WasmOpcode_i64_add:
|
|
case WasmOpcode_i64_sub:
|
|
case WasmOpcode_i64_mul:
|
|
case WasmOpcode_i64_div_u:
|
|
case WasmOpcode_i64_rem_u:
|
|
case WasmOpcode_i64_and:
|
|
case WasmOpcode_i64_or:
|
|
case WasmOpcode_i64_xor:
|
|
case WasmOpcode_f32_add:
|
|
case WasmOpcode_f32_sub:
|
|
case WasmOpcode_f32_mul:
|
|
case WasmOpcode_f32_div:
|
|
case WasmOpcode_f64_add:
|
|
case WasmOpcode_f64_sub:
|
|
case WasmOpcode_f64_mul:
|
|
case WasmOpcode_f64_div:
|
|
// unsigned binary operators
|
|
if (unreachable_depth == 0) {
|
|
uint32_t rhs = FuncGen_stackPop(&fg);
|
|
uint32_t lhs = FuncGen_stackAt(&fg, 0);
|
|
char operator;
|
|
switch (opcode) {
|
|
case WasmOpcode_i32_add:
|
|
case WasmOpcode_i64_add:
|
|
case WasmOpcode_f32_add:
|
|
case WasmOpcode_f64_add:
|
|
operator = '+';
|
|
break;
|
|
case WasmOpcode_i32_sub:
|
|
case WasmOpcode_i64_sub:
|
|
case WasmOpcode_f32_sub:
|
|
case WasmOpcode_f64_sub:
|
|
operator = '-';
|
|
break;
|
|
case WasmOpcode_i32_mul:
|
|
case WasmOpcode_i64_mul:
|
|
case WasmOpcode_f32_mul:
|
|
case WasmOpcode_f64_mul:
|
|
operator = '*';
|
|
break;
|
|
case WasmOpcode_i32_div_u:
|
|
case WasmOpcode_i64_div_u:
|
|
case WasmOpcode_f32_div:
|
|
case WasmOpcode_f64_div:
|
|
operator = '/';
|
|
break;
|
|
case WasmOpcode_i32_rem_u:
|
|
case WasmOpcode_i64_rem_u:
|
|
operator = '%';
|
|
break;
|
|
case WasmOpcode_i32_and:
|
|
case WasmOpcode_i64_and:
|
|
operator = '&';
|
|
break;
|
|
case WasmOpcode_i32_or:
|
|
case WasmOpcode_i64_or:
|
|
operator = '|';
|
|
break;
|
|
case WasmOpcode_i32_xor:
|
|
case WasmOpcode_i64_xor:
|
|
operator = '^';
|
|
break;
|
|
default: panic("unreachable");
|
|
}
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%" PRIu32 " %c= l%" PRIu32 ";\n", lhs, operator, rhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i32_div_s:
|
|
case WasmOpcode_i32_rem_s:
|
|
case WasmOpcode_i64_div_s:
|
|
case WasmOpcode_i64_rem_s:
|
|
// signed binary operators
|
|
if (unreachable_depth == 0) {
|
|
uint32_t rhs = FuncGen_stackPop(&fg);
|
|
uint32_t lhs = FuncGen_stackAt(&fg, 0);
|
|
char operator;
|
|
unsigned width;
|
|
switch (opcode) {
|
|
case WasmOpcode_i32_div_s:
|
|
case WasmOpcode_i64_div_s:
|
|
operator = '/';
|
|
break;
|
|
case WasmOpcode_i32_rem_s:
|
|
case WasmOpcode_i64_rem_s:
|
|
operator = '%';
|
|
break;
|
|
default: panic("unreachable");
|
|
}
|
|
switch (opcode) {
|
|
case WasmOpcode_i32_div_s:
|
|
case WasmOpcode_i32_rem_s:
|
|
width = 32;
|
|
break;
|
|
case WasmOpcode_i64_div_s:
|
|
case WasmOpcode_i64_rem_s:
|
|
width = 64;
|
|
break;
|
|
default: panic("unreachable");
|
|
}
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%" PRIu32 " = (uint%u_t)((int%u_t)l%" PRIu32 " %c "
|
|
"(int%u_t)l%" PRIu32 ");\n",
|
|
lhs, width, width, lhs, operator, width, rhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i32_shl:
|
|
case WasmOpcode_i32_shr_u:
|
|
case WasmOpcode_i64_shl:
|
|
case WasmOpcode_i64_shr_u:
|
|
// unsigned shift operators
|
|
if (unreachable_depth == 0) {
|
|
uint32_t rhs = FuncGen_stackPop(&fg);
|
|
uint32_t lhs = FuncGen_stackAt(&fg, 0);
|
|
char operator;
|
|
unsigned width;
|
|
switch (opcode) {
|
|
case WasmOpcode_i32_shl:
|
|
case WasmOpcode_i64_shl:
|
|
operator = '<';
|
|
break;
|
|
case WasmOpcode_i32_shr_u:
|
|
case WasmOpcode_i64_shr_u:
|
|
operator = '>';
|
|
break;
|
|
default: panic("unreachable");
|
|
}
|
|
switch (opcode) {
|
|
case WasmOpcode_i32_shl:
|
|
case WasmOpcode_i32_shr_u:
|
|
width = 32;
|
|
break;
|
|
case WasmOpcode_i64_shl:
|
|
case WasmOpcode_i64_shr_u:
|
|
width = 64;
|
|
break;
|
|
default: panic("unreachable");
|
|
}
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%" PRIu32 " %c%c= l%" PRIu32 " & 0x%X;\n",
|
|
lhs, operator, operator, rhs, width - 1);
|
|
}
|
|
break;
|
|
case WasmOpcode_i32_shr_s:
|
|
case WasmOpcode_i64_shr_s:
|
|
// signed shift operators
|
|
if (unreachable_depth == 0) {
|
|
uint32_t rhs = FuncGen_stackPop(&fg);
|
|
uint32_t lhs = FuncGen_stackAt(&fg, 0);
|
|
char operator;
|
|
unsigned width;
|
|
switch (opcode) {
|
|
case WasmOpcode_i32_shr_s:
|
|
case WasmOpcode_i64_shr_s:
|
|
operator = '>';
|
|
break;
|
|
default: panic("unreachable");
|
|
}
|
|
switch (opcode) {
|
|
case WasmOpcode_i32_shr_s:
|
|
width = 32;
|
|
break;
|
|
case WasmOpcode_i64_shr_s:
|
|
width = 64;
|
|
break;
|
|
default: panic("unreachable");
|
|
}
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%" PRIu32 " = (uint%u_t)((int%u_t)l%" PRIu32 " %c%c "
|
|
"(l%" PRIu32 " & 0x%X));\n",
|
|
lhs, width, width, lhs, operator, operator, rhs, width - 1);
|
|
}
|
|
break;
|
|
case WasmOpcode_i32_rotl:
|
|
case WasmOpcode_i32_rotr:
|
|
case WasmOpcode_i64_rotl:
|
|
case WasmOpcode_i64_rotr:
|
|
// rotate operators
|
|
if (unreachable_depth == 0) {
|
|
uint32_t rhs = FuncGen_stackPop(&fg);
|
|
uint32_t lhs = FuncGen_stackAt(&fg, 0);
|
|
char forward_operator;
|
|
char reverse_operator;
|
|
unsigned width;
|
|
switch (opcode) {
|
|
case WasmOpcode_i32_rotl:
|
|
case WasmOpcode_i64_rotl:
|
|
forward_operator = '<';
|
|
reverse_operator = '>';
|
|
break;
|
|
case WasmOpcode_i32_rotr:
|
|
case WasmOpcode_i64_rotr:
|
|
forward_operator = '>';
|
|
reverse_operator = '<';
|
|
break;
|
|
default: panic("unreachable");
|
|
}
|
|
switch (opcode) {
|
|
case WasmOpcode_i32_rotl:
|
|
case WasmOpcode_i32_rotr:
|
|
width = 32;
|
|
break;
|
|
case WasmOpcode_i64_rotl:
|
|
case WasmOpcode_i64_rotr:
|
|
width = 64;
|
|
break;
|
|
default: panic("unreachable");
|
|
}
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%" PRIu32" = l%" PRIu32 " %c%c (l%" PRIu32 " & 0x%X) | "
|
|
"l%" PRIu32 " %c%c (-l%" PRIu32" & 0x%X);\n", lhs,
|
|
lhs, forward_operator, forward_operator, rhs, width - 1,
|
|
lhs, reverse_operator, reverse_operator, rhs, width - 1);
|
|
}
|
|
break;
|
|
case WasmOpcode_f32_min:
|
|
case WasmOpcode_f32_max:
|
|
case WasmOpcode_f32_copysign:
|
|
case WasmOpcode_f64_min:
|
|
case WasmOpcode_f64_max:
|
|
case WasmOpcode_f64_copysign:
|
|
// binary functions
|
|
if (unreachable_depth == 0) {
|
|
uint32_t rhs = FuncGen_stackPop(&fg);
|
|
uint32_t lhs = FuncGen_stackAt(&fg, 0);
|
|
const char *function;
|
|
switch (opcode) {
|
|
case WasmOpcode_f32_min: function = "fminf"; break;
|
|
case WasmOpcode_f32_max: function = "fmaxf"; break;
|
|
case WasmOpcode_f32_copysign: function = "copysignf"; break;
|
|
case WasmOpcode_f64_min: function = "fmin"; break;
|
|
case WasmOpcode_f64_max: function = "fmax"; break;
|
|
case WasmOpcode_f64_copysign: function = "copysign"; break;
|
|
default: panic("unreachable");
|
|
}
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "l%" PRIu32 " = %s(l%" PRIu32 ", l%" PRIu32 ");\n",
|
|
lhs, function, lhs, rhs);
|
|
}
|
|
break;
|
|
|
|
case WasmOpcode_i32_wrap_i64:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i32_trunc_f32_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i32_trunc_f32_u:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i32_trunc_f64_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i32_trunc_f64_u:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i64_extend_i32_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i64_extend_i32_u:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i64_trunc_f32_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i64_trunc_f32_u:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i64_trunc_f64_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i64_trunc_f64_u:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_f32_convert_i32_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
|
fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_f32_convert_i32_u:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
|
fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_f32_convert_i64_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
|
fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_f32_convert_i64_u:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
|
fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_f32_demote_f64:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
|
fprintf(out, "(float)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_f64_convert_i32_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
|
fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_f64_convert_i32_u:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
|
fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_f64_convert_i64_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
|
fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_f64_convert_i64_u:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
|
fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_f64_promote_f32:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
|
fprintf(out, "(double)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i32_reinterpret_f32:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "i32_reinterpret_f32(l%" PRIu32 ");\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i64_reinterpret_f64:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "i64_reinterpret_f64(l%" PRIu32 ");\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_f32_reinterpret_i32:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
|
fprintf(out, "f32_reinterpret_i32(l%" PRIu32 ");\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_f64_reinterpret_i64:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
|
fprintf(out, "f64_reinterpret_i64(l%" PRIu32 ");\n", lhs);
|
|
}
|
|
break;
|
|
|
|
case WasmOpcode_i32_extend8_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "(int8_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i32_extend16_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
|
fprintf(out, "(int16_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i64_extend8_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "(int8_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i64_extend16_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "(int16_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
case WasmOpcode_i64_extend32_s:
|
|
if (unreachable_depth == 0) {
|
|
uint32_t lhs = FuncGen_stackPop(&fg);
|
|
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
|
fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
|
|
}
|
|
break;
|
|
|
|
case WasmOpcode_prefixed:
|
|
switch (InputStream_readLeb128_u32(&in)) {
|
|
case WasmPrefixedOpcode_i32_trunc_sat_f32_s:
|
|
case WasmPrefixedOpcode_i32_trunc_sat_f32_u:
|
|
case WasmPrefixedOpcode_i32_trunc_sat_f64_s:
|
|
case WasmPrefixedOpcode_i32_trunc_sat_f64_u:
|
|
case WasmPrefixedOpcode_i64_trunc_sat_f32_s:
|
|
case WasmPrefixedOpcode_i64_trunc_sat_f32_u:
|
|
case WasmPrefixedOpcode_i64_trunc_sat_f64_s:
|
|
case WasmPrefixedOpcode_i64_trunc_sat_f64_u:
|
|
if (unreachable_depth == 0) panic("unimplemented opcode");
|
|
|
|
case WasmPrefixedOpcode_memory_init:
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
(void)InputStream_readByte(&in);
|
|
if (unreachable_depth == 0) panic("unimplemented opcode");
|
|
|
|
case WasmPrefixedOpcode_data_drop:
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) panic("unimplemented opcode");
|
|
|
|
case WasmPrefixedOpcode_memory_copy: {
|
|
uint32_t dst_mem_idx = InputStream_readLeb128_u32(&in);
|
|
uint32_t src_mem_idx = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t n = FuncGen_stackPop(&fg);
|
|
uint32_t src = FuncGen_stackPop(&fg);
|
|
uint32_t dst = FuncGen_stackPop(&fg);
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "memmove(&m%" PRIu32 "[l%" PRIu32 "], "
|
|
"&m%" PRIu32 "[l%" PRIu32 "], l%" PRIu32 ");\n",
|
|
dst_mem_idx, dst, src_mem_idx, src, n);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WasmPrefixedOpcode_memory_fill: {
|
|
uint32_t mem_idx = InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) {
|
|
uint32_t n = FuncGen_stackPop(&fg);
|
|
uint32_t c = FuncGen_stackPop(&fg);
|
|
uint32_t s = FuncGen_stackPop(&fg);
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "memset(&m%" PRIu32 "[l%" PRIu32 "], "
|
|
"l%" PRIu32 ", l%" PRIu32 ");\n", mem_idx, s, c, n);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WasmPrefixedOpcode_table_init:
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) panic("unimplemented opcode");
|
|
|
|
case WasmPrefixedOpcode_elem_drop:
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) panic("unimplemented opcode");
|
|
|
|
case WasmPrefixedOpcode_table_copy:
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) panic("unimplemented opcode");
|
|
|
|
case WasmPrefixedOpcode_table_grow:
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) panic("unimplemented opcode");
|
|
|
|
case WasmPrefixedOpcode_table_size:
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) panic("unimplemented opcode");
|
|
|
|
case WasmPrefixedOpcode_table_fill:
|
|
(void)InputStream_readLeb128_u32(&in);
|
|
if (unreachable_depth == 0) panic("unimplemented opcode");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
|
if (param_used[param_i]) continue;
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "(void)l%" PRIu32 ";\n", param_i);
|
|
}
|
|
switch (func_type->result->len) {
|
|
case 0: break;
|
|
case 1:
|
|
FuncGen_indent(&fg, out);
|
|
fprintf(out, "return l%" PRIu32 ";\n", FuncGen_stackPop(&fg));
|
|
break;
|
|
default: panic("multiple function returns not supported");
|
|
}
|
|
fputs("}\n\n", out);
|
|
}
|
|
}
|
|
|
|
(void)InputStream_skipToSection(&in, WasmSectionId_data);
|
|
{
|
|
uint32_t len = InputStream_readLeb128_u32(&in);
|
|
fputs("static void init_data(void) {\n", out);
|
|
for (uint32_t i = 0; i < mems_len; i += 1)
|
|
fprintf(out, " p%" PRIu32 " = UINT32_C(%" PRIu32 ");\n"
|
|
" c%" PRIu32 " = p%" PRIu32 ";\n"
|
|
" m%" PRIu32 " = calloc(c%" PRIu32 ", UINT32_C(1) << 16);\n",
|
|
i, mems[i].limits.min, i, i, i, i);
|
|
for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) {
|
|
uint32_t mem_idx;
|
|
switch (InputStream_readLeb128_u32(&in)) {
|
|
case 0:
|
|
mem_idx = 0;
|
|
break;
|
|
|
|
case 2:
|
|
mem_idx = InputStream_readLeb128_u32(&in);
|
|
break;
|
|
|
|
default: panic("unsupported data kind");
|
|
}
|
|
uint32_t offset = evalExpr(&in);
|
|
uint32_t segment_len = InputStream_readLeb128_u32(&in);
|
|
fputc('\n', out);
|
|
fprintf(out, " static const uint8_t s%" PRIu32 "[UINT32_C(%" PRIu32 ")] = {",
|
|
segment_i, segment_len);
|
|
for (uint32_t i = 0; i < segment_len; i += 1) {
|
|
if (i % 32 == 0) fputs("\n ", out);
|
|
fprintf(out, " 0x%02hhX,", InputStream_readByte(&in));
|
|
}
|
|
fprintf(out, "\n"
|
|
" };\n"
|
|
" memcpy(&m%" PRIu32 "[UINT32_C(0x%" PRIX32 ")], s%" PRIu32 ", UINT32_C(%" PRIu32 "));\n",
|
|
mem_idx, offset, segment_i, segment_len);
|
|
}
|
|
fputs("}\n", out);
|
|
}
|
|
|
|
InputStream_close(&in);
|
|
fclose(out);
|
|
}
|