From bff6405afc3702345f08d52d5dad29369e1dc9ab Mon Sep 17 00:00:00 2001 From: Evan Reichard Date: Mon, 20 Jul 2026 18:44:51 -0400 Subject: [PATCH] build: replace wasm patch with third_party/qemu submodule The 7.7k-line qemu-wasm patch was really a fork, so vendor it as a submodule (pinned at the xteink QEMU fork) and build it directly. Removes the clone/commit-check/patch/reset machinery, the redundant web-dev/patch targets, and 0002-qemu-wasm.patch. Editing third_party/qemu now recompiles incrementally via plain `make web`. Native build keeps 0001-xteink-machine.patch. --- .gitmodules | 4 + Makefile | 22 +- README.md | 20 +- qemu/patches/0002-qemu-wasm.patch | 7873 ----------------------------- scripts/build-qemu-wasm.sh | 39 +- third_party/qemu | 1 + 6 files changed, 31 insertions(+), 7928 deletions(-) create mode 100644 .gitmodules delete mode 100644 qemu/patches/0002-qemu-wasm.patch create mode 160000 third_party/qemu diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..96349ea --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "third_party/qemu"] + path = third_party/qemu + url = git@ssh.gitea.va.reichard.io:evan/qemu-xteink.git + branch = main diff --git a/Makefile b/Makefile index f3538bb..813244e 100644 --- a/Makefile +++ b/Makefile @@ -5,15 +5,13 @@ FIRMWARE_DIR ?= $(FIRMWARE_REPO)/.pio/build/default SD_SRC ?= $(FIRMWARE_REPO)/sdcard QEMU_SRC ?= _scratch/qemu-src QEMU_BIN = $(QEMU_SRC)/build/qemu-system-riscv32 -QEMU_WASM_SRC ?= _scratch/qemu-wasm-src -# Working tree for the fast dev loop: edit here, `make web-dev` compiles it incrementally. -DEV_SRC ?= _scratch/qemu-fix-src -# Commit the 0002 patch is diffed against when running `make patch`. -PATCH_BASE ?= 610f8c69bc91dcb4ba81de1b7d2e74cc2adfb31e +# QEMU source for the wasm build is the third_party/qemu submodule. Edit it in +# place; `make web` recompiles only what changed, no patch round-trip. +QEMU_WASM_SRC ?= third_party/qemu WASM_OUT ?= dist/wasm VARIANT ?= x3 -.PHONY: firmware sdimage qemu qemu-wasm qemu-wasm-dev web web-dev web-test patch run run-upstream chip clean +.PHONY: firmware sdimage qemu qemu-wasm web web-test run run-upstream chip clean firmware: esptool --chip esp32c3 merge-bin -o flash.bin \ @@ -33,23 +31,11 @@ qemu: qemu-wasm: QEMU_WASM_SRC=$(QEMU_WASM_SRC) WASM_OUT=$(WASM_OUT) scripts/build-qemu-wasm.sh -# Incremental build straight from $(DEV_SRC); no patch reset, so edits compile fast. -qemu-wasm-dev: - QEMU_WASM_DEV=1 QEMU_WASM_SRC=$(DEV_SRC) WASM_OUT=$(WASM_OUT) scripts/build-qemu-wasm.sh - -# Regenerate the wasm patch from $(DEV_SRC) once the dev tree is where you want it. -patch: - cd $(DEV_SRC) && git diff --binary $(PATCH_BASE) > $(CURDIR)/qemu/patches/0002-qemu-wasm.patch - # Serve over HTTPS by default so headless/LAN access is cross-origin isolated. Override with WEB_TLS=. WEB_TLS ?= --tls web: qemu-wasm python3 scripts/serve-web.py $(WEB_TLS) -# Fast iteration: incremental compile from $(DEV_SRC), then serve. Run `make patch` before committing. -web-dev: qemu-wasm-dev - python3 scripts/serve-web.py $(WEB_TLS) - web-test: node scripts/test-web.mjs diff --git a/README.md b/README.md index d282920..57c99b2 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,15 @@ Point at a firmware build with `make firmware FIRMWARE_DIR=/path/to/.pio/build/g ## WebAssembly build -Podman or Docker is required. The build is limited to `riscv32-softmmu` and the -X3/X4 device graph; networking, audio, virtfs, tools, docs, and unrelated boards -are disabled. +Podman or Docker is required. The QEMU source is the `third_party/qemu` +submodule, so initialize it first: + +```sh +git submodule update --init third_party/qemu +``` + +The build is limited to `riscv32-softmmu` and the X3/X4 device graph; +networking, audio, virtfs, tools, docs, and unrelated boards are disabled. ```sh make qemu-wasm @@ -67,9 +73,11 @@ browser JS heap where supported. X4 remains a white display stub. and its device models (I²C fingerprints, ADC, GPIO, SPI2, X3 UC8253, X4 panel stub, SD-over-SPI fix), applied onto the pinned espressif/qemu commit by `scripts/build-qemu.sh`. -- `qemu/patches/0002-qemu-wasm.patch` and `qemu/wasm/Dockerfile` — the pinned - qemu-wasm host backend port and minimal Emscripten dependency environment, - built by `scripts/build-qemu-wasm.sh`. +- `third_party/qemu` — submodule of the [xteink QEMU fork](git@ssh.gitea.va.reichard.io:evan/qemu-xteink.git) + (espressif/qemu + the machine models + the wasm32 TCG backend), built for the + browser by `scripts/build-qemu-wasm.sh`. Edit it in place; `make web` + recompiles incrementally. `qemu/wasm/Dockerfile` is the pinned Emscripten + dependency environment. - `flake.nix` — the espressif-qemu *release* binary as the fast generic baseline (`nix run .#run-upstream -- flash.bin`), plus a devShell with QEMU's full build environment. `Makefile` — `qemu`, `firmware`, `sdimage`, `run`, `chip`. diff --git a/qemu/patches/0002-qemu-wasm.patch b/qemu/patches/0002-qemu-wasm.patch deleted file mode 100644 index 60481ca..0000000 --- a/qemu/patches/0002-qemu-wasm.patch +++ /dev/null @@ -1,7873 +0,0 @@ -diff --git c/accel/tcg/cputlb.c w/accel/tcg/cputlb.c -index b76a4eac4e..a673eb2eb7 100644 ---- c/accel/tcg/cputlb.c -+++ w/accel/tcg/cputlb.c -@@ -225,7 +225,7 @@ static void tlb_mmu_resize_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast, - rate = desc->window_max_entries * 100 / old_size; - - if (rate > 70) { -- new_size = MIN(old_size << 1, 1 << CPU_TLB_DYN_MAX_BITS); -+ new_size = MIN(old_size << 1, (uint64_t)1 << CPU_TLB_DYN_MAX_BITS); - } else if (rate < 30 && window_expired) { - size_t ceil = pow2ceil(desc->window_max_entries); - size_t expected_rate = desc->window_max_entries * 100 / ceil; -diff --git c/accel/tcg/ldst_common.c.inc w/accel/tcg/ldst_common.c.inc -index ebbf380d76..3ff0b97f27 100644 ---- c/accel/tcg/ldst_common.c.inc -+++ w/accel/tcg/ldst_common.c.inc -@@ -12,32 +12,52 @@ - * Load helpers for tcg-ldst.h - */ - -+#if !defined(CONFIG_TCG_INTERPRETER) && defined(EMSCRIPTEN) -+#include "../../tcg/wasm32.h" -+#endif -+ - tcg_target_ulong helper_ldub_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t retaddr) - { - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); -- return do_ld1_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); -+ tcg_target_ulong res = do_ld1_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ set_done_flag(); -+#endif -+ return res; - } - - tcg_target_ulong helper_lduw_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t retaddr) - { - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); -- return do_ld2_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); -+ tcg_target_ulong res = do_ld2_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ set_done_flag(); -+#endif -+ return res; - } - - tcg_target_ulong helper_ldul_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t retaddr) - { - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); -- return do_ld4_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); -+ tcg_target_ulong res = do_ld4_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ set_done_flag(); -+#endif -+ return res; - } - - uint64_t helper_ldq_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t retaddr) - { - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); -- return do_ld8_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); -+ uint64_t res = do_ld8_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ set_done_flag(); -+#endif -+ return res; - } - - /* -@@ -67,7 +87,11 @@ Int128 helper_ld16_mmu(CPUArchState *env, uint64_t addr, - MemOpIdx oi, uintptr_t retaddr) - { - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); -- return do_ld16_mmu(env_cpu(env), addr, oi, retaddr); -+ Int128 res = do_ld16_mmu(env_cpu(env), addr, oi, retaddr); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ set_done_flag(); -+#endif -+ return res; - } - - Int128 helper_ld_i128(CPUArchState *env, uint64_t addr, uint32_t oi) -@@ -84,6 +108,9 @@ void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val, - { - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); - do_st1_mmu(env_cpu(env), addr, val, oi, ra); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ set_done_flag(); -+#endif - } - - void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val, -@@ -91,6 +118,9 @@ void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val, - { - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); - do_st2_mmu(env_cpu(env), addr, val, oi, retaddr); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ set_done_flag(); -+#endif - } - - void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val, -@@ -98,6 +128,9 @@ void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val, - { - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); - do_st4_mmu(env_cpu(env), addr, val, oi, retaddr); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ set_done_flag(); -+#endif - } - - void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val, -@@ -105,6 +138,9 @@ void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val, - { - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); - do_st8_mmu(env_cpu(env), addr, val, oi, retaddr); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ set_done_flag(); -+#endif - } - - void helper_st16_mmu(CPUArchState *env, uint64_t addr, Int128 val, -@@ -112,11 +148,17 @@ void helper_st16_mmu(CPUArchState *env, uint64_t addr, Int128 val, - { - tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); - do_st16_mmu(env_cpu(env), addr, val, oi, retaddr); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ set_done_flag(); -+#endif - } - - void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi) - { - helper_st16_mmu(env, addr, val, oi, GETPC()); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ set_done_flag(); -+#endif - } - - /* -diff --git c/accel/tcg/tb-maint.c w/accel/tcg/tb-maint.c -index cc0f5afd47..1095dfd912 100644 ---- c/accel/tcg/tb-maint.c -+++ w/accel/tcg/tb-maint.c -@@ -755,6 +755,18 @@ static void tb_remove(TranslationBlock *tb) - } - #endif /* CONFIG_USER_ONLY */ - -+#if !defined(CONFIG_TCG_INTERPRETER) && defined(EMSCRIPTEN) -+#include "../../tcg/wasm32.h" -+ -+static void wasm_remove_tb_instance(void *p, uint32_t hash, void *userp) -+{ -+ TranslationBlock *tb = p; -+ (void)hash; -+ (void)userp; -+ remove_tb(tb->tc.ptr); -+} -+#endif -+ - /* flush all the translation blocks */ - static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count) - { -@@ -771,6 +783,10 @@ static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count) - tcg_flush_jmp_cache(cpu); - } - -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ qht_iter(&tb_ctx.htable, wasm_remove_tb_instance, NULL); -+ flush_tb_instances(); -+#endif - qht_reset_size(&tb_ctx.htable, CODE_GEN_HTABLE_SIZE); - tb_remove_all(); - -@@ -854,7 +870,11 @@ static inline void tb_remove_from_jmp_list(TranslationBlock *orig, int n_orig) - void tb_reset_jump(TranslationBlock *tb, int n) - { - uintptr_t addr = (uintptr_t)(tb->tc.ptr + tb->jmp_reset_offset[n]); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ tb_set_jmp_target(tb, n, 0); -+#else - tb_set_jmp_target(tb, n, addr); -+#endif - } - - /* remove any jumps to the TB */ -@@ -879,6 +899,10 @@ static void tb_jmp_cache_inval_tb(TranslationBlock *tb) - { - CPUState *cpu; - -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ remove_tb(tb->tc.ptr); -+#endif -+ - if (tb_cflags(tb) & CF_PCREL) { - /* A TB may be at any virtual address */ - CPU_FOREACH(cpu) { -diff --git c/accel/tcg/tcg-accel-ops-mttcg.c w/accel/tcg/tcg-accel-ops-mttcg.c -index 49814ec4af..0715610d37 100644 ---- c/accel/tcg/tcg-accel-ops-mttcg.c -+++ w/accel/tcg/tcg-accel-ops-mttcg.c -@@ -61,12 +61,18 @@ static void mttcg_force_rcu(Notifier *notify, void *data) - * variable current_cpu can be used deep in the code to find the - * current CPUState for a given thread. - */ -- -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+#include "../../tcg/wasm32.h" -+#endif - static void *mttcg_cpu_thread_fn(void *arg) - { - MttcgForceRcuNotifier force_rcu; - CPUState *cpu = arg; - -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ init_wasm32(); -+#endif -+ - assert(tcg_enabled()); - g_assert(!icount_enabled()); - -diff --git c/accel/tcg/tcg-accel-ops-rr.c w/accel/tcg/tcg-accel-ops-rr.c -index 8ebadf8e9e..1e38df86e8 100644 ---- c/accel/tcg/tcg-accel-ops-rr.c -+++ w/accel/tcg/tcg-accel-ops-rr.c -@@ -177,11 +177,19 @@ static int rr_cpu_count(void) - * elsewhere. - */ - -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+#include "../../tcg/wasm32.h" -+#endif -+ - static void *rr_cpu_thread_fn(void *arg) - { - Notifier force_rcu; - CPUState *cpu = arg; - -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ init_wasm32(); -+#endif -+ - assert(tcg_enabled()); - rcu_register_thread(); - force_rcu.notify = rr_force_rcu; -diff --git c/backends/meson.build w/backends/meson.build -index da714b93d1..9b88d22685 100644 ---- c/backends/meson.build -+++ w/backends/meson.build -@@ -12,8 +12,10 @@ system_ss.add([files( - - if host_os != 'windows' - system_ss.add(files('rng-random.c')) -- system_ss.add(files('hostmem-file.c')) -- system_ss.add([files('hostmem-shm.c'), rt]) -+ if host_os != 'emscripten' -+ system_ss.add(files('hostmem-file.c')) -+ system_ss.add([files('hostmem-shm.c'), rt]) -+ endif - endif - if host_os == 'linux' - system_ss.add(files('hostmem-memfd.c')) -diff --git c/block/file-posix.c w/block/file-posix.c -index 90fa54352c..0fa9cc31b6 100644 ---- c/block/file-posix.c -+++ w/block/file-posix.c -@@ -110,6 +110,10 @@ - #include - #endif - -+#ifdef EMSCRIPTEN -+#include -+#endif -+ - /* OS X does not have O_DSYNC */ - #ifndef O_DSYNC - #ifdef O_SYNC -@@ -2002,6 +2006,13 @@ static int handle_aiocb_write_zeroes_unmap(void *opaque) - return handle_aiocb_write_zeroes(aiocb); - } - -+#ifdef EMSCRIPTEN -+ssize_t copy_file_range(int a, off_t * b, int, off_t * c, size_t d, unsigned e) -+{ -+ errno = ENOSYS; -+ return -1; -+} -+#else - #ifndef HAVE_COPY_FILE_RANGE - static off_t copy_file_range(int in_fd, off_t *in_off, int out_fd, - off_t *out_off, size_t len, unsigned int flags) -@@ -2015,6 +2026,7 @@ static off_t copy_file_range(int in_fd, off_t *in_off, int out_fd, - #endif - } - #endif -+#endif - - /* - * parse_zone - Fill a zone descriptor -diff --git c/block/vvfat.c w/block/vvfat.c -index 8ffe8b3b9b..3c0ab6c228 100644 ---- c/block/vvfat.c -+++ w/block/vvfat.c -@@ -749,6 +749,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) - const char* dirname = mapping->path; - int first_cluster = mapping->begin; - int parent_index = mapping->info.dir.parent_mapping_index; -+ bool is_root = parent_index < 0; - mapping_t* parent_mapping = (mapping_t*) - (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL); - int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1; -@@ -765,9 +766,9 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) - } - - i = mapping->info.dir.first_dir_index = -- first_cluster == 0 ? 0 : s->directory.next; -+ is_root ? 0 : s->directory.next; - -- if (first_cluster != 0) { -+ if (!is_root) { - /* create the top entries of a subdirectory */ - (void)create_short_and_long_name(s, i, ".", 1); - (void)create_short_and_long_name(s, i, "..", 1); -@@ -781,13 +782,14 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) - int is_dot=!strcmp(entry->d_name,"."); - int is_dotdot=!strcmp(entry->d_name,".."); - -- if (first_cluster == 0 && s->directory.next >= s->root_entries - 1) { -+ if (is_root && s->fat_type != 32 && -+ s->directory.next >= s->root_entries - 1) { - fprintf(stderr, "Too many entries in root directory\n"); - closedir(dir); - return -2; - } - -- if(first_cluster == 0 && (is_dotdot || is_dot)) -+ if(is_root && (is_dotdot || is_dot)) - continue; - - buffer = g_malloc(length); -@@ -860,8 +862,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) - memset(direntry,0,sizeof(direntry_t)); - } - -- if (s->fat_type != 32 && -- mapping_index == 0 && -+ if (s->fat_type != 32 && is_root && - s->directory.next < s->root_entries) { - /* root directory */ - int cur = s->directory.next; -@@ -877,20 +878,29 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) - * 0x20 / s->cluster_size; - mapping->end = first_cluster; - -- direntry = array_get(&(s->directory), mapping->dir_index); -- set_begin_of_direntry(direntry, mapping->begin); -+ if (!is_root) { -+ direntry = array_get(&(s->directory), mapping->dir_index); -+ set_begin_of_direntry(direntry, mapping->begin); -+ } - - return 0; - } - - static inline int32_t sector2cluster(BDRVVVFATState* s,off_t sector_num) - { -- return (sector_num - s->offset_to_root_dir) / s->sectors_per_cluster; -+ off_t relative_sector = sector_num - s->offset_to_root_dir; -+ -+ if (relative_sector < 0) { -+ return -1 - (-relative_sector - 1) / s->sectors_per_cluster; -+ } -+ return relative_sector / s->sectors_per_cluster -+ + (s->fat_type == 32 ? 2 : 0); - } - - static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num) - { -- return s->offset_to_root_dir + s->sectors_per_cluster * cluster_num; -+ return s->offset_to_root_dir + s->sectors_per_cluster -+ * (cluster_num - (s->fat_type == 32 ? 2 : 0)); - } - - static int init_directories(BDRVVVFATState* s, -@@ -934,11 +944,12 @@ static int init_directories(BDRVVVFATState* s, - init_fat(s); - - /* TODO: if there are more entries, bootsector has to be adjusted! */ -- s->root_entries = 0x02 * 0x10 * s->sectors_per_cluster; -+ s->root_entries = s->fat_type == 32 ? 0 : -+ 0x02 * 0x10 * s->sectors_per_cluster; - s->cluster_count=sector2cluster(s, s->sector_count); - - mapping = array_get_next(&(s->mapping)); -- mapping->begin = 0; -+ mapping->begin = s->fat_type == 32 ? 2 : 0; - mapping->dir_index = 0; - mapping->info.dir.parent_mapping_index = -1; - mapping->first_mapping_index = -1; -@@ -950,11 +961,10 @@ static int init_directories(BDRVVVFATState* s, - mapping->read_only = 0; - s->path = mapping->path; - -- for (i = 0, cluster = 0; i < s->mapping.next; i++) { -- /* MS-DOS expects the FAT to be 0 for the root directory -- * (except for the media byte). */ -- /* LATER TODO: still true for FAT32? */ -- int fix_fat = (i != 0); -+ for (i = 0, cluster = s->fat_type == 32 ? 2 : 0; -+ i < s->mapping.next; i++) { -+ /* FAT12/16 stores the root directory outside the cluster chain. */ -+ int fix_fat = (i != 0 || s->fat_type == 32); - mapping = array_get(&(s->mapping), i); - - if (mapping->mode & MODE_DIRECTORY) { -@@ -1026,22 +1036,35 @@ static int init_directories(BDRVVVFATState* s, - /* media descriptor: hard disk=0xf8, floppy=0xf0 */ - bootsector->media_type = (s->offset_to_bootsector > 0 ? 0xf8 : 0xf0); - s->fat.pointer[0] = bootsector->media_type; -- bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat); -+ bootsector->sectors_per_fat = s->fat_type == 32 ? 0 : -+ cpu_to_le16(s->sectors_per_fat); - bootsector->sectors_per_track = cpu_to_le16(secs); - bootsector->number_of_heads = cpu_to_le16(heads); - bootsector->hidden_sectors = cpu_to_le32(s->offset_to_bootsector); - bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0); - -- /* LATER TODO: if FAT32, this is wrong */ -- /* drive_number: fda=0, hda=0x80 */ -- bootsector->u.fat16.drive_number = s->offset_to_bootsector == 0 ? 0 : 0x80; -- bootsector->u.fat16.signature=0x29; -- bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd); -- -- memcpy(bootsector->u.fat16.volume_label, s->volume_label, -- sizeof(bootsector->u.fat16.volume_label)); -- memcpy(bootsector->u.fat16.fat_type, -- s->fat_type == 12 ? "FAT12 " : "FAT16 ", 8); -+ if (s->fat_type == 32) { -+ bootsector->u.fat32.sectors_per_fat = cpu_to_le32(s->sectors_per_fat); -+ bootsector->u.fat32.first_cluster_of_root_dir = cpu_to_le32(2); -+ bootsector->u.fat32.info_sector = cpu_to_le16(0xffff); -+ bootsector->u.fat32.backup_boot_sector = cpu_to_le16(0xffff); -+ bootsector->u.fat32.drive_number = 0x80; -+ bootsector->u.fat32.signature = 0x29; -+ bootsector->u.fat32.id = cpu_to_le32(0xfabe1afd); -+ memcpy(bootsector->u.fat32.volume_label, s->volume_label, -+ sizeof(bootsector->u.fat32.volume_label)); -+ memcpy(bootsector->u.fat32.fat_type, "FAT32 ", 8); -+ } else { -+ /* drive_number: fda=0, hda=0x80 */ -+ bootsector->u.fat16.drive_number = -+ s->offset_to_bootsector == 0 ? 0 : 0x80; -+ bootsector->u.fat16.signature=0x29; -+ bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd); -+ memcpy(bootsector->u.fat16.volume_label, s->volume_label, -+ sizeof(bootsector->u.fat16.volume_label)); -+ memcpy(bootsector->u.fat16.fat_type, -+ s->fat_type == 12 ? "FAT12 " : "FAT16 ", 8); -+ } - bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa; - - return 0; -@@ -1139,6 +1162,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, - { - BDRVVVFATState *s = bs->opaque; - int cyls, heads, secs; -+ uint64_t total_sectors; - bool floppy; - const char *dirname, *label; - QemuOpts *opts; -@@ -1205,7 +1229,9 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, - - switch (s->fat_type) { - case 32: -+#ifndef EMSCRIPTEN - warn_report("FAT32 has not been tested. You are welcome to do so!"); -+#endif - break; - case 16: - case 12: -@@ -1219,8 +1245,17 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, - - s->bs = bs; - -- /* LATER TODO: if FAT32, adjust */ -- s->sectors_per_cluster=0x10; -+#ifdef EMSCRIPTEN -+ if (!floppy && s->fat_type == 32) { -+ /* Browser SD Geometry - A larger cluster keeps the synthesized 32 GiB FAT near 4 MiB. */ -+ s->sectors_per_cluster = 0x40; -+ total_sectors = 32ULL * 1024 * 1024 * 1024 / BDRV_SECTOR_SIZE; -+ } else -+#endif -+ { -+ s->sectors_per_cluster = 0x10; -+ total_sectors = (uint64_t)cyls * heads * secs; -+ } - - s->current_cluster=0xffffffff; - -@@ -1232,8 +1267,8 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, - DLOG(fprintf(stderr, "vvfat %s chs %d,%d,%d\n", - dirname, cyls, heads, secs)); - -- s->sector_count = cyls * heads * secs - s->offset_to_bootsector; -- bs->total_sectors = cyls * heads * secs; -+ s->sector_count = total_sectors - s->offset_to_bootsector; -+ bs->total_sectors = total_sectors; - - if (qemu_opt_get_bool(opts, "rw", false)) { - if (!bdrv_is_read_only(bs)) { -@@ -1259,8 +1294,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, - goto fail; - } - -- s->sector_count = s->offset_to_root_dir -- + s->sectors_per_cluster * s->cluster_count; -+ s->sector_count = cluster2sector(s, s->cluster_count); - - /* Disable migration when vvfat is used rw */ - if (s->qcow) { -@@ -1415,6 +1449,7 @@ read_cluster_directory: - if(lseek(s->current_fd, offset, SEEK_SET)!=offset) - return -3; - s->cluster=s->cluster_buffer; -+ memset(s->cluster, 0, s->cluster_size); - result=read(s->current_fd,s->cluster,s->cluster_size); - if(result<0) { - s->current_cluster = -1; -@@ -1523,8 +1558,9 @@ vvfat_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sector - } else { - uint32_t sector = sector_num - s->offset_to_root_dir, - sector_offset_in_cluster=(sector%s->sectors_per_cluster), -- cluster_num=sector/s->sectors_per_cluster; -- if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) { -+ cluster_num=sector/s->sectors_per_cluster -+ + (s->fat_type == 32 ? 2 : 0); -+ if(cluster_num >= s->cluster_count || read_cluster(s, cluster_num) != 0) { - /* LATER TODO: strict: return -1; */ - memset(buf+i*0x200,0,0x200); - continue; -@@ -1780,7 +1816,8 @@ static int parse_short_name(BDRVVVFATState* s, - static inline uint32_t modified_fat_get(BDRVVVFATState* s, - unsigned int cluster) - { -- if (cluster < s->last_cluster_of_root_directory) { -+ if (s->fat_type != 32 && -+ cluster < s->last_cluster_of_root_directory) { - if (cluster + 1 == s->last_cluster_of_root_directory) - return s->max_fat_value; - else -@@ -2182,14 +2219,17 @@ DLOG(checkpoint()); - mapping->mode |= MODE_DELETED; - } - -- used_clusters_count = check_directory_consistency(s, 0, s->path); -+ mapping_t *root_mapping = array_get(&(s->mapping), 0); -+ used_clusters_count = check_directory_consistency(s, -+ root_mapping->begin, s->path); - if (used_clusters_count <= 0) { - DLOG(fprintf(stderr, "problem in directory\n")); - return 0; - } - -- check = s->last_cluster_of_root_directory; -- for (i = check; i < sector2cluster(s, s->sector_count); i++) { -+ check = s->fat_type == 32 ? 0 : s->last_cluster_of_root_directory; -+ for (i = s->fat_type == 32 ? 2 : check; -+ i < sector2cluster(s, s->sector_count); i++) { - if (modified_fat_get(s, i)) { - if(!s->used_clusters[i]) { - DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i)); -@@ -2417,7 +2457,10 @@ static int coroutine_fn GRAPH_RDLOCK - commit_direntries(BDRVVVFATState* s, int dir_index, int parent_mapping_index) - { - direntry_t* direntry = array_get(&(s->directory), dir_index); -- uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry); -+ bool is_root = dir_index == 0; -+ mapping_t *root_mapping = array_get(&(s->mapping), 0); -+ uint32_t first_cluster = is_root ? root_mapping->begin : -+ begin_of_direntry(direntry); - mapping_t* mapping = find_mapping_for_cluster(s, first_cluster); - int factor = 0x10 * s->sectors_per_cluster; - int old_cluster_count, new_cluster_count; -@@ -2440,7 +2483,7 @@ commit_direntries(BDRVVVFATState* s, int dir_index, int parent_mapping_index) - first_dir_index = current_dir_index; - mapping->info.dir.parent_mapping_index = parent_mapping_index; - -- if (first_cluster == 0) { -+ if (is_root && s->fat_type != 32) { - old_cluster_count = new_cluster_count = - s->last_cluster_of_root_directory; - } else { -@@ -2998,11 +3041,9 @@ DLOG(checkpoint()); - */ - unsigned char *bootsector = s->first_sectors - + s->offset_to_bootsector * 0x200; -- /* -- * LATER TODO: if FAT32, this is wrong (see init_directories(), -- * which always creates a FAT16 bootsector) -- */ -- const int reserved1_offset = offsetof(bootsector_t, u.fat16.reserved1); -+ const int reserved1_offset = s->fat_type == 32 ? -+ offsetof(bootsector_t, u.fat32.reserved1) : -+ offsetof(bootsector_t, u.fat16.reserved1); - - for (i = 0; i < 0x200; i++) { - if (i != reserved1_offset && bootsector[i] != buf[i]) { -@@ -3057,8 +3098,8 @@ DLOG(checkpoint()); - begin = sector_num; - if (end > sector_num + nb_sectors) - end = sector_num + nb_sectors; -- dir_index = mapping->dir_index + -- 0x10 * (begin - mapping->begin * s->sectors_per_cluster); -+ dir_index = mapping->info.dir.first_dir_index + -+ 0x10 * (begin - cluster2sector(s, mapping->begin)); - direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num)); - - for (k = 0; k < (end - begin) * 0x10; k++) { -@@ -3093,7 +3134,7 @@ DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sec - } - - for (i = first_cluster; i <= last_cluster; i++) { -- if (i >= 0) { -+ if (i >= 0 && i < sector2cluster(s, s->sector_count)) { - s->used_clusters[i] |= USED_ALLOCATED; - } - } -diff --git c/configs/devices/riscv32-softmmu/xteink.mak w/configs/devices/riscv32-softmmu/xteink.mak -new file mode 100644 -index 0000000000..a9179b4119 ---- /dev/null -+++ w/configs/devices/riscv32-softmmu/xteink.mak -@@ -0,0 +1 @@ -+CONFIG_RISCV_ESP32C3=y -diff --git c/configure w/configure -index 18336376bf..4a4b9e7754 100755 ---- c/configure -+++ w/configure -@@ -340,7 +340,9 @@ int main(void) { return 0; } - EOF - } - --if check_define __linux__ ; then -+if check_define __EMSCRIPTEN__ ; then -+ host_os=emscripten -+elif check_define __linux__ ; then - host_os=linux - elif check_define _WIN32 ; then - host_os=windows -@@ -526,6 +528,10 @@ case "$cpu" in - linux_arch=x86 - CPU_CFLAGS="-m64" - ;; -+ wasm32) -+ host_arch=wasm32 -+ CPU_CFLAGS="-m32" -+ ;; - esac - - # Now we have our CPU_CFLAGS we can check if we are targeting a 32 or -@@ -547,7 +553,7 @@ else - host_bits=32 - fi - --if test -n "$host_arch" && { -+if test -n "$host_arch" && test "$host_arch" != wasm32 && { - ! test -d "$source_path/linux-user/include/host/$host_arch" || - ! test -d "$source_path/common-user/host/$host_arch"; }; then - error_exit "linux-user/include/host/$host_arch does not exist." \ -diff --git c/disas/disas-host.c w/disas/disas-host.c -index 8146fafe80..2ee0605dba 100644 ---- c/disas/disas-host.c -+++ w/disas/disas-host.c -@@ -42,7 +42,7 @@ static void initialize_debug_host(CPUDebug *s) - #else - s->info.endian = BFD_ENDIAN_LITTLE; - #endif --#if defined(CONFIG_TCG_INTERPRETER) -+#if defined(CONFIG_TCG_INTERPRETER) || defined(EMSCRIPTEN) - s->info.print_insn = print_insn_tci; - #elif defined(__i386__) - s->info.mach = bfd_mach_i386_i386; -diff --git c/hw/adc/esp32c3_adc.c w/hw/adc/esp32c3_adc.c -index 89087429c7..4d38b3e13c 100644 ---- c/hw/adc/esp32c3_adc.c -+++ w/hw/adc/esp32c3_adc.c -@@ -27,7 +27,7 @@ static uint64_t esp32c3_adc_read(void *opaque, hwaddr addr, unsigned size) - } - if (addr == ADC_DATA1 || addr == ADC_DATA2) { - return s->channel < ESP32C3_ADC_CHANNELS -- ? MIN(s->input[s->channel], ADC_MAX) -+ ? MIN(qatomic_read(&s->input[s->channel]), ADC_MAX) - : ADC_MAX; - } - return s->regs[addr / 4]; -diff --git c/hw/block/m25p80.c w/hw/block/m25p80.c -index 46dbe7c521..1ee6f8ce7e 100644 ---- c/hw/block/m25p80.c -+++ w/hw/block/m25p80.c -@@ -222,7 +222,8 @@ static const FlashPartInfo known_devices[] = { - { INFO("is25lp016d", 0x9d6015, 0, 64 << 10, 32, ER_4K) }, - { INFO("is25lp032", 0x9d6016, 0, 64 << 10, 64, ER_4K) }, - { INFO("is25lp064", 0x9d6017, 0, 64 << 10, 128, ER_4K) }, -- { INFO("is25lp128", 0x9d6018, 0, 64 << 10, 256, ER_4K) }, -+ { INFO("is25lp128", 0x9d6018, 0, 64 << 10, 256, ER_4K), -+ .sfdp_read = m25p80_sfdp_is25lp128 }, - { INFO("is25lp256", 0x9d6019, 0, 64 << 10, 512, ER_4K) }, - { INFO("is25wp032", 0x9d7016, 0, 64 << 10, 64, ER_4K) }, - { INFO("is25wp064", 0x9d7017, 0, 64 << 10, 128, ER_4K) }, -@@ -385,6 +386,8 @@ typedef enum { - READ_FSR = 0x70, - RDCR = 0x15, - RDSFDP = 0x5a, -+ PROGRAM_ERASE_SUSPEND = 0x75, -+ PROGRAM_ERASE_RESUME = 0x7a, - - READ = 0x03, - READ4 = 0x13, -@@ -856,28 +859,18 @@ static void complete_collecting_data(Flash *s) - break; - case RDID_90: - case RDID_AB: -- if (get_man(s) == MAN_SST) { -- if (s->cur_addr <= 1) { -- if (s->cur_addr) { -- s->data[0] = s->pi->id[2]; -- s->data[1] = s->pi->id[0]; -- } else { -- s->data[0] = s->pi->id[0]; -- s->data[1] = s->pi->id[2]; -- } -- s->pos = 0; -- s->len = 2; -- s->data_read_loop = true; -- s->state = STATE_READING_DATA; -- } else { -- qemu_log_mask(LOG_GUEST_ERROR, -- "M25P80: Invalid read id address\n"); -- } -+ // Read Manufacturer/Device ID - The address low bit selects which of the manufacturer/device pair comes first; real chips answer regardless of vendor, so this is not gated on MAN_SST. Reused for 0xAB (Release Power-Down + Device ID), whose trailing byte reads back the device id. -+ if (s->cur_addr) { -+ s->data[0] = s->pi->id[2]; -+ s->data[1] = s->pi->id[0]; - } else { -- qemu_log_mask(LOG_GUEST_ERROR, -- "M25P80: Read id (command 0x90/0xAB) is not supported" -- " by device\n"); -+ s->data[0] = s->pi->id[0]; -+ s->data[1] = s->pi->id[2]; - } -+ s->pos = 0; -+ s->len = 2; -+ s->data_read_loop = true; -+ s->state = STATE_READING_DATA; - break; - - case RDSFDP: -@@ -1414,6 +1407,9 @@ static void decode_new_cmd(Flash *s, uint32_t value) - } - break; - case NOP: -+ case PROGRAM_ERASE_SUSPEND: -+ case PROGRAM_ERASE_RESUME: -+ /* Program and erase complete synchronously in this model. */ - break; - case EN_4BYTE_ADDR: - s->four_bytes_address_mode = true; -diff --git c/hw/block/m25p80_sfdp.c w/hw/block/m25p80_sfdp.c -index a03a291a09..6e01178299 100644 ---- c/hw/block/m25p80_sfdp.c -+++ w/hw/block/m25p80_sfdp.c -@@ -479,3 +479,12 @@ static const uint8_t sfdp_is25wp256[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }; - define_sfdp_read(is25wp256); -+ -+uint8_t m25p80_sfdp_is25lp128(uint32_t addr) -+{ -+ /* The sibling parts share SFDP data except for the density field. */ -+ if (addr == 0x37) { -+ return 0x07; -+ } -+ return m25p80_sfdp_is25wp256(addr); -+} -diff --git c/hw/block/m25p80_sfdp.h w/hw/block/m25p80_sfdp.h -index 35785686a0..e6bfdfa7e8 100644 ---- c/hw/block/m25p80_sfdp.h -+++ w/hw/block/m25p80_sfdp.h -@@ -28,6 +28,7 @@ uint8_t m25p80_sfdp_w25q512jv(uint32_t addr); - uint8_t m25p80_sfdp_w25q80bl(uint32_t addr); - uint8_t m25p80_sfdp_w25q01jvq(uint32_t addr); - -+uint8_t m25p80_sfdp_is25lp128(uint32_t addr); - uint8_t m25p80_sfdp_is25wp256(uint32_t addr); - - #endif -diff --git c/hw/display/xteink_x3_eink.c w/hw/display/xteink_x3_eink.c -index b699abae4e..8a177e9159 100644 ---- c/hw/display/xteink_x3_eink.c -+++ w/hw/display/xteink_x3_eink.c -@@ -9,6 +9,60 @@ - #include "hw/irq.h" - #include "hw/display/xteink_x3_eink.h" - -+#ifdef __EMSCRIPTEN__ -+#include -+ -+static QemuConsole *xteink_wasm_console; -+static uint32_t xteink_wasm_generation; -+ -+EMSCRIPTEN_KEEPALIVE uintptr_t xteink_wasm_framebuffer(void) -+{ -+ DisplaySurface *surface = xteink_wasm_console -+ ? qemu_console_surface(xteink_wasm_console) -+ : NULL; -+ return surface ? (uintptr_t)surface_data(surface) : 0; -+} -+ -+EMSCRIPTEN_KEEPALIVE int xteink_wasm_width(void) -+{ -+ DisplaySurface *surface = xteink_wasm_console -+ ? qemu_console_surface(xteink_wasm_console) -+ : NULL; -+ return surface ? surface_width(surface) : 0; -+} -+ -+EMSCRIPTEN_KEEPALIVE int xteink_wasm_height(void) -+{ -+ DisplaySurface *surface = xteink_wasm_console -+ ? qemu_console_surface(xteink_wasm_console) -+ : NULL; -+ return surface ? surface_height(surface) : 0; -+} -+ -+EMSCRIPTEN_KEEPALIVE int xteink_wasm_stride(void) -+{ -+ DisplaySurface *surface = xteink_wasm_console -+ ? qemu_console_surface(xteink_wasm_console) -+ : NULL; -+ return surface ? surface_stride(surface) : 0; -+} -+ -+EMSCRIPTEN_KEEPALIVE uint32_t xteink_wasm_frame_generation(void) -+{ -+ return qatomic_read(&xteink_wasm_generation); -+} -+ -+static void xteink_wasm_frame_updated(QemuConsole *console) -+{ -+ xteink_wasm_console = console; -+ qatomic_inc(&xteink_wasm_generation); -+} -+#else -+static void xteink_wasm_frame_updated(QemuConsole *console) -+{ -+} -+#endif -+ - #define CMD_POWER_OFF 0x02 - #define CMD_POWER_ON 0x04 - #define CMD_DTM1 0x10 -@@ -33,6 +87,7 @@ static void xteink_x3_eink_render(XteinkX3EinkState *s) - } - } - -+ xteink_wasm_frame_updated(s->console); - dpy_gfx_update(s->console, 0, 0, XTEINK_X3_HEIGHT, XTEINK_X3_WIDTH); - } - -@@ -171,6 +226,7 @@ static void xteink_x4_eink_render(XteinkX4EinkState *s) - DisplaySurface *surface = qemu_console_surface(s->console); - memset(surface_data(surface), 0xff, - surface_stride(surface) * surface_height(surface)); -+ xteink_wasm_frame_updated(s->console); - dpy_gfx_update(s->console, 0, 0, 480, 800); - } - -diff --git c/hw/gpio/esp32_gpio.c w/hw/gpio/esp32_gpio.c -index 9ec8bd9244..754990968c 100644 ---- c/hw/gpio/esp32_gpio.c -+++ w/hw/gpio/esp32_gpio.c -@@ -38,10 +38,20 @@ static void esp32_gpio_drive_outputs(Esp32GpioState *s) - } - } - -+void esp32_gpio_set_input_level(Esp32GpioState *s, int pin, bool level) -+{ -+ uint32_t old_level; -+ uint32_t new_level; -+ -+ do { -+ old_level = qatomic_read(&s->input_level); -+ new_level = deposit32(old_level, pin, 1, level); -+ } while (qatomic_cmpxchg(&s->input_level, old_level, new_level) != old_level); -+} -+ - static void esp32_gpio_set_input(void *opaque, int pin, int level) - { -- Esp32GpioState *s = ESP32_GPIO(opaque); -- s->input_level = deposit32(s->input_level, pin, 1, !!level); -+ esp32_gpio_set_input_level(ESP32_GPIO(opaque), pin, level); - } - - static void esp32_gpio_get_input(Object *obj, Visitor *v, const char *name, -@@ -49,7 +59,7 @@ static void esp32_gpio_get_input(Object *obj, Visitor *v, const char *name, - { - Esp32GpioState *s = ESP32_GPIO(obj); - int pin = GPOINTER_TO_INT(opaque); -- bool level = extract32(s->input_level, pin, 1); -+ bool level = extract32(qatomic_read(&s->input_level), pin, 1); - visit_type_bool(v, name, &level, errp); - } - -@@ -78,7 +88,7 @@ static uint64_t esp32_gpio_read(void *opaque, hwaddr addr, unsigned int size) - case A_GPIO_STRAP: - return s->strap_mode; - case GPIO_IN: -- return s->input_level; -+ return qatomic_read(&s->input_level); - default: - return 0; - } -diff --git c/hw/misc/esp32c3_cache.c w/hw/misc/esp32c3_cache.c -index 1879b5c2df..e3f09cc51b 100644 ---- c/hw/misc/esp32c3_cache.c -+++ w/hw/misc/esp32c3_cache.c -@@ -58,7 +58,6 @@ static inline uint32_t esp32c3_read_mmu_value(ESP32C3CacheState *s, hwaddr reg_a - - static inline void esp32c3_write_mmu_value(ESP32C3CacheState *s, hwaddr reg_addr, uint32_t value) - { -- ESP32C3XtsAesClass *xts_aes_class = ESP32C3_XTS_AES_GET_CLASS(s->xts_aes); - /* Make the assumption that the address is aligned on sizeof(uint32_t) */ - const uint32_t index = reg_addr / sizeof(uint32_t); - /* Reserved bits shall always be 0 */ -@@ -82,8 +81,12 @@ static inline void esp32c3_write_mmu_value(ESP32C3CacheState *s, hwaddr reg_addr - if (s->flash_blk != NULL) { - blk_pread(s->flash_blk, physical_address, ESP32C3_PAGE_SIZE, cache_data, 0); - } -- if (xts_aes_class->is_flash_enc_enabled(s->xts_aes)) { -- xts_aes_class->decrypt(s->xts_aes, physical_address, cache_data, ESP32C3_PAGE_SIZE); -+ // XTS-AES Flash Decryption - Only wired when built with CONFIG_GCRYPT; absent here means flash is treated as unencrypted, matching hardware with flash encryption disabled. Encrypted-flash firmware needs the gcrypt build. -+ if (s->xts_aes != NULL) { -+ ESP32C3XtsAesClass *xts_aes_class = ESP32C3_XTS_AES_GET_CLASS(s->xts_aes); -+ if (xts_aes_class->is_flash_enc_enabled(s->xts_aes)) { -+ xts_aes_class->decrypt(s->xts_aes, physical_address, cache_data, ESP32C3_PAGE_SIZE); -+ } - } - } - s->mmu[index].val = e.val; -@@ -225,12 +228,6 @@ static void esp32c3_cache_realize(DeviceState *dev, Error **errp) - /* Initialize the registers */ - esp32c3_cache_reset_hold(OBJECT(dev), RESET_TYPE_COLD); - -- ESP32C3CacheState *s = ESP32C3_CACHE(dev); -- -- /* Make sure XTS_AES was set or issue an error */ -- if (s->xts_aes == NULL) { -- error_report("[CACHE] XTS_AES controller must be set!"); -- } - } - - static void esp32c3_cache_init(Object *obj) -diff --git c/hw/misc/esp32c3_jtag.c w/hw/misc/esp32c3_jtag.c -index 82ee69717b..64a971f183 100644 ---- c/hw/misc/esp32c3_jtag.c -+++ w/hw/misc/esp32c3_jtag.c -@@ -16,10 +16,18 @@ - #include "hw/misc/esp32c3_jtag.h" - - -+/* USB Serial JTAG Console Tap - The firmware routes ESP-IDF console output (incl. panic dumps) through this peripheral. EP1 is the byte FIFO; EP1_CONF bit1 (SERIAL_IN_EP_DATA_FREE) must read set so the driver believes the TX FIFO can always accept a byte. */ -+#define ESP32C3_JTAG_EP1_REG 0x00 -+#define ESP32C3_JTAG_EP1_CONF_REG 0x04 -+#define ESP32C3_JTAG_IN_EP_DATA_FREE (1u << 1) -+ - static uint64_t esp32c3_jtag_read(void *opaque, hwaddr addr, unsigned int size) - { - ESP32C3UsbJtagState *s = ESP32C3_JTAG(opaque); - (void) s; -+ if (addr == ESP32C3_JTAG_EP1_CONF_REG) { -+ return ESP32C3_JTAG_IN_EP_DATA_FREE; -+ } - return 0; - } - -@@ -27,6 +35,9 @@ static void esp32c3_jtag_write(void *opaque, hwaddr addr, uint64_t value, unsign - { - ESP32C3UsbJtagState *s = ESP32C3_JTAG(opaque); - (void) s; -+ if (addr == ESP32C3_JTAG_EP1_REG) { -+ fputc((int)(value & 0xff), stderr); -+ } - } - - static const MemoryRegionOps esp32c3_jtag_ops = { -diff --git c/hw/misc/esp_sha.c w/hw/misc/esp_sha.c -index c9fa2e610a..cc186595eb 100644 ---- c/hw/misc/esp_sha.c -+++ w/hw/misc/esp_sha.c -@@ -22,46 +22,71 @@ - #define SHA_WARNING 0 - #define SHA_DEBUG 0 - -+static void esp_sha1_init(void *context) { sha1_init(context); } -+static void esp_sha224_init(void *context) { sha224_init(context); } -+static void esp_sha256_init(void *context) { sha256_init(context); } -+static void esp_sha384_init(void *context) { sha384_init(context); } -+static void esp_sha512_init(void *context) { sha512_init(context); } -+static void esp_sha512_224_init(void *context) { sha512_224_init(context); } -+static void esp_sha512_256_init(void *context) { sha512_256_init(context); } -+static void esp_sha512_t_init(void *context) { sha512_t_init(context); } -+static void esp_sha1_compress(void *context, const uint8_t *message) -+{ -+ sha1_compress(context, message); -+} -+static void esp_sha224_compress(void *context, const uint8_t *message) -+{ -+ sha224_compress(context, (uint8_t *)message); -+} -+static void esp_sha256_compress(void *context, const uint8_t *message) -+{ -+ sha256_compress(context, (uint8_t *)message); -+} -+static void esp_sha512_compress(void *context, const uint8_t *message) -+{ -+ sha512_compress(context, (uint8_t *)message); -+} -+ - static ESPHashAlg esp_sha_algs[] = { - [ESP_SHA_1_MODE] = { -- .init = (hash_init) sha1_init, -- .compress = (hash_compress) sha1_compress, -+ .init = esp_sha1_init, -+ .compress = esp_sha1_compress, - .len = sizeof(struct sha1_state) - }, - [ESP_SHA_224_MODE] = { -- .init = (hash_init) sha224_init, -- .compress = (hash_compress) sha224_compress, -+ .init = esp_sha224_init, -+ .compress = esp_sha224_compress, - .len = SHA224_HASH_SIZE - }, - [ESP_SHA_256_MODE] = { -- .init = (hash_init) sha256_init, -- .compress = (hash_compress) sha256_compress, -+ .init = esp_sha256_init, -+ .compress = esp_sha256_compress, - .len = sizeof(struct sha256_state) - }, - [ESP_SHA_384_MODE] = { -- .init = (hash_init) sha384_init, -- .compress = (hash_compress) sha512_compress, -+ .init = esp_sha384_init, -+ .compress = esp_sha512_compress, - .len = SHA384_HASH_SIZE - }, - [ESP_SHA_512_MODE] = { -- .init = (hash_init) sha512_init, -- .compress = (hash_compress) sha512_compress, -+ .init = esp_sha512_init, -+ .compress = esp_sha512_compress, - .len = sizeof(struct sha512_state) - }, - [ESP_SHA_512_224_MODE] = { -- .init = (hash_init) sha512_224_init, -- .compress = (hash_compress) sha512_compress, -+ .init = esp_sha512_224_init, -+ .compress = esp_sha512_compress, - .len = sizeof(struct sha512_state) - }, - [ESP_SHA_512_256_MODE] = { -- .init = (hash_init) sha512_256_init, -- .compress = (hash_compress) sha512_compress, -+ .init = esp_sha512_256_init, -+ .compress = esp_sha512_compress, - .len = sizeof(struct sha512_state) - }, - [ESP_SHA_512_t_MODE] = { -- .init = (hash_init) sha512_t_init, -- .init_message = (hash_init_message) sha512_t_init_message, -- .compress = (hash_compress) sha512_compress, -+ .init = esp_sha512_t_init, -+ .init_message = sha512_t_init_message, -+ .compress = esp_sha512_compress, - .len = sizeof(struct sha512_state) - }, - }; -diff --git c/hw/riscv/esp32c3.c w/hw/riscv/esp32c3.c -index 2f1ccbfbb0..af8bb86c97 100644 ---- c/hw/riscv/esp32c3.c -+++ w/hw/riscv/esp32c3.c -@@ -57,6 +57,10 @@ - #include "hw/sd/sd.h" - #include "hw/net/can/esp32c3_twai.h" - -+#ifdef __EMSCRIPTEN__ -+#include -+#endif -+ - #define ESP32C3_IO_WARNING 0 - - #define ESP32C3_RESET_ADDRESS 0x40000000 -@@ -103,6 +107,29 @@ struct Esp32C3MachineState { - Esp32C3TWAIState twai; - }; - -+#ifdef __EMSCRIPTEN__ -+static struct Esp32C3MachineState *xteink_wasm_machine; -+ -+EMSCRIPTEN_KEEPALIVE void xteink_wasm_set_adc(int channel, uint32_t value) -+{ -+ if (xteink_wasm_machine && channel >= 0 && -+ channel < ESP32C3_ADC_CHANNELS) { -+ fprintf(stderr, "[button] adc channel=%d value=%u\n", channel, value); -+ qatomic_set(&xteink_wasm_machine->adc.input[channel], -+ MIN(value, UINT32_C(0xfff))); -+ } -+} -+ -+EMSCRIPTEN_KEEPALIVE void xteink_wasm_set_gpio(int pin, int level) -+{ -+ if (xteink_wasm_machine && pin >= 0 && pin < ESP32_GPIO_COUNT) { -+ fprintf(stderr, "[button] gpio pin=%d level=%d\n", pin, level); -+ esp32_gpio_set_input_level(&xteink_wasm_machine->gpio.parent, -+ pin, level); -+ } -+} -+#endif -+ - /* Fake register used by ESP-IDF application to determine whether the code is running on real hardware or on QEMU */ - #define A_SYSCON_ORIGIN_REG 0x3F8 - /* Temporary macro for generating a random value from register SYSCON_RND_DATA_REG */ -@@ -421,12 +448,18 @@ static void esp32c3_machine_init(MachineState *machine) - object_initialize_child(OBJECT(machine), "efuse", &ms->efuse, TYPE_ESP32C3_EFUSE); - object_initialize_child(OBJECT(machine), "clock", &ms->clock, TYPE_ESP32C3_CLOCK); - object_initialize_child(OBJECT(machine), "sha", &ms->sha, TYPE_ESP32C3_SHA); -+#ifdef CONFIG_GCRYPT - object_initialize_child(OBJECT(machine), "aes", &ms->aes, TYPE_ESP32C3_AES); -+#endif - object_initialize_child(OBJECT(machine), "gdma", &ms->gdma, TYPE_ESP32C3_GDMA); -+#ifdef CONFIG_GCRYPT - object_initialize_child(OBJECT(machine), "rsa", &ms->rsa, TYPE_ESP32C3_RSA); -+#endif - object_initialize_child(OBJECT(machine), "hmac", &ms->hmac, TYPE_ESP32C3_HMAC); -+#ifdef CONFIG_GCRYPT - object_initialize_child(OBJECT(machine), "ds", &ms->ds, TYPE_ESP32C3_DS); - object_initialize_child(OBJECT(machine), "xts_aes", &ms->xts_aes, TYPE_ESP32C3_XTS_AES); -+#endif - object_initialize_child(OBJECT(machine), "timg0", &ms->timg[0], TYPE_ESP32C3_TIMG); - object_initialize_child(OBJECT(machine), "timg1", &ms->timg[1], TYPE_ESP32C3_TIMG); - object_initialize_child(OBJECT(machine), "systimer", &ms->systimer, TYPE_ESP32C3_SYSTIMER); -@@ -484,7 +517,9 @@ static void esp32c3_machine_init(MachineState *machine) - - /* SPI1 controller (SPI Flash) */ - { -+#ifdef CONFIG_GCRYPT - ms->spi1.xts_aes = &ms->xts_aes; -+#endif - sysbus_realize(SYS_BUS_DEVICE(&ms->spi1), &error_fatal); - MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->spi1), 0); - memory_region_add_subregion_overlap(sys_mem, DR_REG_SPI1_BASE, mr, 0); -@@ -539,7 +574,9 @@ static void esp32c3_machine_init(MachineState *machine) - if (blk) { - ms->cache.flash_blk = blk; - } -+#ifdef CONFIG_GCRYPT - ms->cache.xts_aes = &ms->xts_aes; -+#endif - sysbus_realize(SYS_BUS_DEVICE(&ms->cache), &error_fatal); - MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->cache), 0); - memory_region_add_subregion_overlap(sys_mem, DR_REG_EXTMEM_BASE, mr, 0); -@@ -635,6 +672,7 @@ static void esp32c3_machine_init(MachineState *machine) - qdev_get_gpio_in(intmatrix_dev, ETS_SHA_INTR_SOURCE)); - } - -+#ifdef CONFIG_GCRYPT - /* AES realization */ - { - ms->aes.parent.gdma = ESP_GDMA(&ms->gdma); -@@ -654,6 +692,8 @@ static void esp32c3_machine_init(MachineState *machine) - qdev_get_gpio_in(intmatrix_dev, ETS_RSA_INTR_SOURCE)); - } - -+#endif -+ - /* HMAC realization */ - { - ms->hmac.parent.efuse = ESP_EFUSE(&ms->efuse); -@@ -662,6 +702,7 @@ static void esp32c3_machine_init(MachineState *machine) - memory_region_add_subregion_overlap(sys_mem, DR_REG_HMAC_BASE, mr, 0); - } - -+#ifdef CONFIG_GCRYPT - /* Digital Signature realization */ - { - ms->ds.parent.hmac = ESP_HMAC(&ms->hmac); -@@ -682,6 +723,8 @@ static void esp32c3_machine_init(MachineState *machine) - memory_region_add_subregion_overlap(sys_mem, DR_REG_AES_XTS_BASE, mr, 0); - } - -+#endif -+ - /* RGB display realization */ - if (!ms->xteink) { - /* Give the internal RAM memory region to the display */ -@@ -706,6 +749,9 @@ static void xteink_machine_init(MachineState *machine) - Esp32C3MachineState *ms = ESP32C3_MACHINE(machine); - ms->xteink = true; - esp32c3_machine_init(machine); -+#ifdef __EMSCRIPTEN__ -+ xteink_wasm_machine = ms; -+#endif - - /* X3 exposes the fingerprint chips; X4 omits them so stock firmware's - * all-NAK probe selects X4. The X4 panel is a blank protocol stub. */ -diff --git c/hw/riscv/esp32c3_intmatrix.c w/hw/riscv/esp32c3_intmatrix.c -index c1376b7299..1275808dc0 100644 ---- c/hw/riscv/esp32c3_intmatrix.c -+++ w/hw/riscv/esp32c3_intmatrix.c -@@ -25,9 +25,10 @@ - #define INTMATRIX_DEBUG 0 - #define INTMATRIX_WARNING 0 - --#define BIT_SET(reg, bit) ((reg) & BIT(bit)) --#define CLEAR_BIT(reg, bit) do { (reg) &= ~BIT(bit); } while(0) --#define SET_BIT(reg, bit) do { (reg) |= BIT(bit); } while(0) -+/* 64-bit Shifts For irq_levels - There are up to 62 interrupt sources, so bit ops on the uint64_t level mask must shift in 64-bit. QEMU's BIT() is `1UL << nr`, which is only 32-bit on wasm32 and silently aliases source N to N-32. */ -+#define BIT_SET(reg, bit) ((reg) & (1ULL << (bit))) -+#define CLEAR_BIT(reg, bit) do { (reg) &= ~(1ULL << (bit)); } while(0) -+#define SET_BIT(reg, bit) do { (reg) |= (1ULL << (bit)); } while(0) - - - static int esp32c3_get_output_line_level(ESP32C3IntMatrixState *s, int line) -@@ -36,7 +37,7 @@ static int esp32c3_get_output_line_level(ESP32C3IntMatrixState *s, int line) - - for (int i = 0; level_shared == 0 && i < ESP32C3_INT_MATRIX_INPUTS; i++) { - const uint_fast8_t mapped = s->irq_map[i]; -- if (mapped == line && (s->irq_levels & BIT(i))) -+ if (mapped == line && (s->irq_levels & (1ULL << i))) - { - level_shared |= 1; - } -diff --git c/hw/sd/ssi-sd.c w/hw/sd/ssi-sd.c -index 552dc2c8ea..eb12207897 100644 ---- c/hw/sd/ssi-sd.c -+++ w/hw/sd/ssi-sd.c -@@ -162,6 +162,10 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val) - return SSI_DUMMY; - } - -+ if ((val & 0xc0) != 0x40) { -+ DPRINTF("Ignore non-command byte 0x%02x\n", val); -+ return SSI_DUMMY; -+ } - s->cmd = val & 0x3f; - s->mode = SSI_SD_CMDARG; - s->arglen = 0; -diff --git c/include/exec/exec-all.h w/include/exec/exec-all.h -index 2e4c4cc4b4..99e6da08c9 100644 ---- c/include/exec/exec-all.h -+++ w/include/exec/exec-all.h -@@ -453,7 +453,7 @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last); - void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr); - - /* GETPC is the true target of the return instruction that we'll execute. */ --#if defined(CONFIG_TCG_INTERPRETER) -+#if defined(CONFIG_TCG_INTERPRETER) || defined(EMSCRIPTEN) - extern __thread uintptr_t tci_tb_ptr; - # define GETPC() tci_tb_ptr - #else -diff --git c/include/hw/gpio/esp32_gpio.h w/include/hw/gpio/esp32_gpio.h -index e2f52ad702..721f5de5df 100644 ---- c/include/hw/gpio/esp32_gpio.h -+++ w/include/hw/gpio/esp32_gpio.h -@@ -33,3 +33,5 @@ typedef struct Esp32GpioState { - typedef struct Esp32GpioClass { - SysBusDeviceClass parent_class; - } Esp32GpioClass; -+ -+void esp32_gpio_set_input_level(Esp32GpioState *s, int pin, bool level); -diff --git c/include/qemu/atomic.h w/include/qemu/atomic.h -index 7a3f2e6576..50dc235043 100644 ---- c/include/qemu/atomic.h -+++ w/include/qemu/atomic.h -@@ -75,7 +75,6 @@ - #else - # define ATOMIC_REG_SIZE sizeof(void *) - #endif -- - /* Weak atomic operations prevent the compiler moving other - * loads/stores past the atomic operation load/store. However there is - * no explicit memory barrier for the processor. -@@ -91,7 +90,7 @@ - - #define qatomic_read(ptr) \ - ({ \ -- qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ -+ /*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \ - qatomic_read__nocheck(ptr); \ - }) - -@@ -99,7 +98,7 @@ - __atomic_store_n(ptr, i, __ATOMIC_RELAXED) - - #define qatomic_set(ptr, i) do { \ -- qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ -+ /*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \ - qatomic_set__nocheck(ptr, i); \ - } while(0) - -@@ -122,7 +121,7 @@ - */ - #define qatomic_rcu_read_internal(ptr, _val) \ - ({ \ -- qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ -+ /*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \ - typeof_strip_qual(*ptr) _val; \ - qatomic_rcu_read__nocheck(ptr, &_val); \ - _val; \ -@@ -131,20 +130,20 @@ - qatomic_rcu_read_internal((ptr), MAKE_IDENTIFIER(_val)) - - #define qatomic_rcu_set(ptr, i) do { \ -- qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ -+ /*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \ - __atomic_store_n(ptr, i, __ATOMIC_RELEASE); \ - } while(0) - - #define qatomic_load_acquire(ptr) \ - ({ \ -- qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ -+ /*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \ - typeof_strip_qual(*ptr) _val; \ - __atomic_load(ptr, &_val, __ATOMIC_ACQUIRE); \ - _val; \ - }) - - #define qatomic_store_release(ptr, i) do { \ -- qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ -+ /*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \ - __atomic_store_n(ptr, i, __ATOMIC_RELEASE); \ - } while(0) - -@@ -156,7 +155,7 @@ - }) - - #define qatomic_xchg(ptr, i) ({ \ -- qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ -+ /*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \ - qatomic_xchg__nocheck(ptr, i); \ - }) - -@@ -169,7 +168,7 @@ - }) - - #define qatomic_cmpxchg(ptr, old, new) ({ \ -- qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \ -+ /*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \ - qatomic_cmpxchg__nocheck(ptr, old, new); \ - }) - -diff --git c/include/qemu/cacheflush.h w/include/qemu/cacheflush.h -index ae20bcda73..3f414fb7c9 100644 ---- c/include/qemu/cacheflush.h -+++ w/include/qemu/cacheflush.h -@@ -19,7 +19,7 @@ - * mappings of the same physical page(s). - */ - --#if defined(__i386__) || defined(__x86_64__) || defined(__s390__) -+#if defined(__i386__) || defined(__x86_64__) || defined(__s390__) || defined(EMSCRIPTEN) - - static inline void flush_idcache_range(uintptr_t rx, uintptr_t rw, size_t len) - { -diff --git c/include/qemu/int128.h w/include/qemu/int128.h -index 174bd7dafb..0305e262ef 100644 ---- c/include/qemu/int128.h -+++ w/include/qemu/int128.h -@@ -8,7 +8,7 @@ - * But libffi does not support __int128_t, and therefore cannot pass - * or return values of this type, force use of the Int128 struct. - */ --#if defined(CONFIG_INT128) && !defined(CONFIG_TCG_INTERPRETER) -+#if defined(CONFIG_INT128) && !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN) - typedef __int128_t Int128; - typedef __int128_t __attribute__((aligned(16))) Int128Aligned; - -diff --git c/include/qemu/osdep.h w/include/qemu/osdep.h -index fdff07fd99..e95faa4478 100644 ---- c/include/qemu/osdep.h -+++ w/include/qemu/osdep.h -@@ -133,7 +133,7 @@ QEMU_EXTERN_C int daemon(int, int); - #include - #include - --#ifdef CONFIG_IOVEC -+#if defined(CONFIG_IOVEC) || defined(EMSCRIPTEN) - #include - #endif - -@@ -281,6 +281,7 @@ void QEMU_ERROR("code path is reachable") - #ifndef WCOREDUMP - #define WCOREDUMP(status) 0 - #endif -+#ifndef EMSCRIPTEN - /* - * We have a lot of unaudited code that may fail in strange ways, or - * even be a security risk during migration, if you disable assertions -@@ -296,6 +297,7 @@ void QEMU_ERROR("code path is reachable") - #ifdef G_DISABLE_ASSERT - #error building with G_DISABLE_ASSERT is not supported - #endif -+#endif - - #ifndef OFF_MAX - #define OFF_MAX (sizeof (off_t) == 8 ? INT64_MAX : INT32_MAX) -@@ -630,7 +632,7 @@ bool qemu_write_pidfile(const char *pidfile, Error **errp); - - int qemu_get_thread_id(void); - --#ifndef CONFIG_IOVEC -+#if !defined(CONFIG_IOVEC) && !defined(EMSCRIPTEN) - struct iovec { - void *iov_base; - size_t iov_len; -diff --git c/include/tcg/helper-info.h w/include/tcg/helper-info.h -index 909fe73afa..c5064473ac 100644 ---- c/include/tcg/helper-info.h -+++ w/include/tcg/helper-info.h -@@ -9,7 +9,7 @@ - #ifndef TCG_HELPER_INFO_H - #define TCG_HELPER_INFO_H - --#ifdef CONFIG_TCG_INTERPRETER -+#if defined(CONFIG_TCG_INTERPRETER) || defined(EMSCRIPTEN) - #include - #endif - #include "tcg-target-reg-bits.h" -@@ -48,11 +48,14 @@ struct TCGHelperInfo { - const char *name; - - /* Used with g_once_init_enter. */ --#ifdef CONFIG_TCG_INTERPRETER -+#if defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN) - ffi_cif *cif; - #else - uintptr_t init; - #endif -+#if defined(EMSCRIPTEN) -+ ffi_cif *cif; -+#endif - - unsigned typemask : 32; - unsigned flags : 8; -diff --git c/include/tcg/tcg-opc.h w/include/tcg/tcg-opc.h -index 546eb49c11..834757c3a4 100644 ---- c/include/tcg/tcg-opc.h -+++ w/include/tcg/tcg-opc.h -@@ -305,7 +305,7 @@ DEF(last_generic, 0, 0, 0, TCG_OPF_NOT_PRESENT) - #include "tcg-target.opc.h" - #endif - --#ifdef TCG_TARGET_INTERPRETER -+#if defined(TCG_TARGET_INTERPRETER) || defined(EMSCRIPTEN) - /* These opcodes are only for use between the tci generator and interpreter. */ - DEF(tci_movi, 1, 0, 1, TCG_OPF_NOT_PRESENT) - DEF(tci_movl, 1, 0, 1, TCG_OPF_NOT_PRESENT) -diff --git c/include/tcg/tcg.h w/include/tcg/tcg.h -index 9b82844dab..2cdfe0617b 100644 ---- c/include/tcg/tcg.h -+++ w/include/tcg/tcg.h -@@ -1010,7 +1010,7 @@ static inline size_t tcg_current_code_size(TCGContext *s) - #define TB_EXIT_IDXMAX 1 - #define TB_EXIT_REQUESTED 3 - --#ifdef CONFIG_TCG_INTERPRETER -+#if defined(CONFIG_TCG_INTERPRETER) || defined(EMSCRIPTEN) - uintptr_t tcg_qemu_tb_exec(CPUArchState *env, const void *tb_ptr); - #else - typedef uintptr_t tcg_prologue_fn(CPUArchState *env, const void *tb_ptr); -diff --git c/meson.build w/meson.build -index 7f28871776..6e558969d4 100644 ---- c/meson.build -+++ w/meson.build -@@ -45,9 +45,9 @@ genh = [] - qapi_trace_events = [] - - bsd_oses = ['gnu/kfreebsd', 'freebsd', 'netbsd', 'openbsd', 'dragonfly', 'darwin'] --supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux'] -+supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux', 'emscripten'] - supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv32', 'riscv64', 'x86', 'x86_64', -- 'arm', 'aarch64', 'loongarch64', 'mips', 'mips64', 'sparc64'] -+ 'arm', 'aarch64', 'loongarch64', 'mips', 'mips64', 'sparc64', 'wasm32'] - - cpu = host_machine.cpu_family() - -@@ -309,6 +309,7 @@ endif - # Compiler flags # - ################## - -+if host_arch != 'wasm32' - foreach lang : all_languages - compiler = meson.get_compiler(lang) - if compiler.get_id() == 'gcc' and compiler.version().version_compare('>=7.4') -@@ -328,6 +329,7 @@ foreach lang : all_languages - error('You either need GCC v7.4 or Clang v10.0 (or XCode Clang v15.0) to compile QEMU') - endif - endforeach -+endif - - # default flags for all hosts - # We use -fwrapv to tell the compiler that we require a C dialect where -@@ -482,7 +484,7 @@ ucontext_probe = ''' - # On Windows the only valid backend is the Windows specific one. - # For POSIX prefer ucontext, but it's not always possible. The fallback - # is sigcontext. --supported_backends = [] -+supported_backends = ['fiber'] - if host_os == 'windows' - supported_backends += ['windows'] - else -@@ -510,7 +512,7 @@ safe_stack_probe = ''' - #endif - return 0; - }''' --if get_option('safe_stack') != not cc.compiles(safe_stack_probe) -+if host_arch != 'wasm32' and get_option('safe_stack') != not cc.compiles(safe_stack_probe) - safe_stack_arg = get_option('safe_stack') ? '-fsanitize=safe-stack' : '-fno-sanitize=safe-stack' - if get_option('safe_stack') != not cc.compiles(safe_stack_probe, args: safe_stack_arg) - error(get_option('safe_stack') \ -@@ -520,7 +522,7 @@ if get_option('safe_stack') != not cc.compiles(safe_stack_probe) - qemu_cflags += safe_stack_arg - qemu_ldflags += safe_stack_arg - endif --if get_option('safe_stack') and coroutine_backend != 'ucontext' -+if host_arch != 'wasm32' and get_option('safe_stack') and coroutine_backend != 'ucontext' - error('SafeStack is only supported with the ucontext coroutine backend') - endif - -@@ -884,6 +886,8 @@ if get_option('tcg').allowed() - tcg_arch = 'i386' - elif host_arch == 'ppc64' - tcg_arch = 'ppc' -+ elif host_arch == 'wasm32' -+ tcg_arch = 'wasm32' - endif - add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch, - language: all_languages) -@@ -1016,7 +1020,7 @@ endif - # problems on multi-arch where people try to build - # 32-bit QEMU while pointing at 64-bit glib headers - --if not cc.compiles(''' -+if host_arch != 'wasm32' and not cc.compiles(''' - #include - #include - -@@ -1227,9 +1231,11 @@ if not get_option('slirp').auto() or have_system - slirp_cflags += ['-DLIBSLIRP_STATIC'] - endif - -- slirp = declare_dependency(dependencies: [slirp_dep], -- compile_args: slirp_cflags, -- version: slirp_dep.version()) -+ if slirp_dep.found() -+ slirp = declare_dependency(dependencies: [slirp_dep], -+ compile_args: slirp_cflags, -+ version: slirp_dep.version()) -+ endif - - # slirp < 4.7 is incompatible with CFI support in QEMU. This is because - # it passes function pointers within libslirp as callbacks for timers. -diff --git c/meson_options.txt w/meson_options.txt -index 5eeaf3eee5..76f7a65b40 100644 ---- c/meson_options.txt -+++ w/meson_options.txt -@@ -34,7 +34,7 @@ option('fuzzing_engine', type : 'string', value : '', - option('trace_file', type: 'string', value: 'trace', - description: 'Trace file prefix for simple backend') - option('coroutine_backend', type: 'combo', -- choices: ['ucontext', 'sigaltstack', 'windows', 'auto'], -+ choices: ['ucontext', 'sigaltstack', 'windows', 'auto', 'fiber'], - value: 'auto', description: 'coroutine backend to use') - - # Everything else can be set via --enable/--disable-* option -diff --git c/os-posix.c w/os-posix.c -index 43f9a43f3f..595fa47866 100644 ---- c/os-posix.c -+++ w/os-posix.c -@@ -148,11 +148,13 @@ static void change_process_uid(void) - exit(1); - } - if (user_pwd) { -+#ifndef EMSCRIPTEN - if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) { - error_report("Failed to initgroups(\"%s\", %d)", - user_pwd->pw_name, user_pwd->pw_gid); - exit(1); - } -+#endif - } else { - if (setgroups(1, &user_gid) < 0) { - error_report("Failed to setgroups(1, [%d])", -diff --git c/qom/object.c w/qom/object.c -index 9edc06d391..c3d657e6cb 100644 ---- c/qom/object.c -+++ w/qom/object.c -@@ -1197,7 +1197,8 @@ GSList *object_class_get_list(const char *implements_type, - return list; - } - --static gint object_class_cmp(gconstpointer a, gconstpointer b) -+static gint object_class_cmp(gconstpointer a, gconstpointer b, -+ gpointer user_data) - { - return strcasecmp(object_class_get_name((ObjectClass *)a), - object_class_get_name((ObjectClass *)b)); -@@ -1207,7 +1208,7 @@ GSList *object_class_get_list_sorted(const char *implements_type, - bool include_abstract) - { - return g_slist_sort(object_class_get_list(implements_type, include_abstract), -- object_class_cmp); -+ (GCompareFunc)object_class_cmp); - } - - Object *object_ref(void *objptr) -diff --git c/scripts/meson-buildoptions.sh w/scripts/meson-buildoptions.sh -index a8066aab03..bd3ae90008 100644 ---- c/scripts/meson-buildoptions.sh -+++ w/scripts/meson-buildoptions.sh -@@ -80,7 +80,7 @@ meson_options_help() { - printf "%s\n" ' --tls-priority=VALUE Default TLS protocol/cipher priority string' - printf "%s\n" ' [NORMAL]' - printf "%s\n" ' --with-coroutine=CHOICE coroutine backend to use (choices:' -- printf "%s\n" ' auto/sigaltstack/ucontext/windows)' -+ printf "%s\n" ' auto/fiber/sigaltstack/ucontext/windows)' - printf "%s\n" ' --with-pkgversion=VALUE use specified string as sub-version of the' - printf "%s\n" ' package' - printf "%s\n" ' --with-suffix=VALUE Suffix for QEMU data/modules/config directories' -diff --git c/system/memory.c w/system/memory.c -index 85f6834cb3..3958314765 100644 ---- c/system/memory.c -+++ w/system/memory.c -@@ -1636,7 +1636,7 @@ bool memory_region_init_resizeable_ram(MemoryRegion *mr, - return true; - } - --#ifdef CONFIG_POSIX -+#if defined(CONFIG_POSIX) && !defined(EMSCRIPTEN) - bool memory_region_init_ram_from_file(MemoryRegion *mr, - Object *owner, - const char *name, -diff --git c/system/physmem.c w/system/physmem.c -index 75389064a8..addd5d0c4b 100644 ---- c/system/physmem.c -+++ w/system/physmem.c -@@ -1235,7 +1235,7 @@ long qemu_maxrampagesize(void) - return pagesize; - } - --#ifdef CONFIG_POSIX -+#if defined(CONFIG_POSIX) && !defined(EMSCRIPTEN) - static int64_t get_file_size(int fd) - { - int64_t size; -@@ -1941,7 +1941,7 @@ out_free: - } - } - --#ifdef CONFIG_POSIX -+#if defined(CONFIG_POSIX) && !defined(EMSCRIPTEN) - RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, - uint32_t ram_flags, int fd, off_t offset, - Error **errp) -@@ -2130,7 +2130,7 @@ static void reclaim_ramblock(RAMBlock *block) - ; - } else if (xen_enabled()) { - xen_invalidate_map_cache_entry(block->host); --#ifndef _WIN32 -+#if !defined(_WIN32) && !defined(EMSCRIPTEN) - } else if (block->fd >= 0) { - qemu_ram_munmap(block->fd, block->host, block->max_length); - close(block->fd); -diff --git c/tcg/meson.build w/tcg/meson.build -index 69ebb4908a..0894a577c2 100644 ---- c/tcg/meson.build -+++ w/tcg/meson.build -@@ -15,11 +15,18 @@ tcg_ss.add(files( - 'tcg-op-vec.c', - )) - -+cpu = host_machine.cpu_family() -+ - if get_option('tcg_interpreter') - libffi = dependency('libffi', version: '>=3.0', required: true, - method: 'pkg-config') - tcg_ss.add(libffi) - tcg_ss.add(files('tci.c')) -+elif cpu == 'wasm32' -+ libffi = dependency('libffi', version: '>=3.0', required: true, -+ method: 'pkg-config') -+ specific_ss.add(libffi) -+ specific_ss.add(files('wasm32.c')) - endif - - tcg_ss.add(when: libdw, if_true: files('debuginfo.c')) -diff --git c/tcg/region.c w/tcg/region.c -index 478ec051c4..41895c68fa 100644 ---- c/tcg/region.c -+++ w/tcg/region.c -@@ -568,7 +568,7 @@ static int alloc_code_gen_buffer_anon(size_t size, int prot, - return prot; - } - --#ifndef CONFIG_TCG_INTERPRETER -+#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN) - #ifdef CONFIG_POSIX - #include "qemu/memfd.h" - -@@ -670,7 +670,7 @@ static int alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp) - - static int alloc_code_gen_buffer_splitwx(size_t size, Error **errp) - { --#ifndef CONFIG_TCG_INTERPRETER -+#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN) - # ifdef CONFIG_DARWIN - return alloc_code_gen_buffer_splitwx_vmremap(size, errp); - # endif -@@ -816,7 +816,7 @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus) - * Work with the page protections set up with the initial mapping. - */ - need_prot = PROT_READ | PROT_WRITE; --#ifndef CONFIG_TCG_INTERPRETER -+#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN) - if (tcg_splitwx_diff == 0) { - need_prot |= host_prot_read_exec(); - } -diff --git c/tcg/tcg.c w/tcg/tcg.c -index 6dc3072f92..0f6c0f5082 100644 ---- c/tcg/tcg.c -+++ w/tcg/tcg.c -@@ -131,6 +131,10 @@ static void tcg_out_goto_tb(TCGContext *s, int which); - static void tcg_out_op(TCGContext *s, TCGOpcode opc, - const TCGArg args[TCG_MAX_OP_ARGS], - const int const_args[TCG_MAX_OP_ARGS]); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+static void tcg_out_label_cb(TCGContext *s, TCGLabel *l); -+static void tcg_out_init(); -+#endif - #if TCG_TARGET_MAYBE_vec - static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, - TCGReg dst, TCGReg src); -@@ -245,7 +249,7 @@ TCGv_env tcg_env; - const void *tcg_code_gen_epilogue; - uintptr_t tcg_splitwx_diff; - --#ifndef CONFIG_TCG_INTERPRETER -+#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN) - tcg_prologue_fn *tcg_qemu_tb_exec; - #endif - -@@ -352,6 +356,9 @@ static void tcg_out_label(TCGContext *s, TCGLabel *l) - tcg_debug_assert(!l->has_value); - l->has_value = 1; - l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr); -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ tcg_out_label_cb(s, l); -+#endif - } - - TCGLabel *gen_new_label(void) -@@ -420,6 +427,143 @@ tlb_mask_table_ofs(TCGContext *s, int which) - sizeof(CPUNegativeOffsetState)); - } - -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ -+#define SUB_BUF_MAX 100000 -+__thread uint8_t sub_buf[SUB_BUF_MAX]; -+__thread uint8_t *sub_buf_ptr; -+ -+static inline void tcg_sub_out8(TCGContext *s, uint8_t v) -+{ -+ *sub_buf_ptr++ = v; -+ if ((sub_buf_ptr - sub_buf) > SUB_BUF_MAX) { -+ printf("buffer too small"); fflush(stdout); -+ exit(1); -+ } -+} -+ -+static inline void tcg_sub_out32(TCGContext *s, uint32_t v) -+{ -+ memcpy(sub_buf_ptr, &v, sizeof(v)); -+ sub_buf_ptr += 4; -+} -+ -+static inline void* cur_sub_buf_ptr() -+{ -+ return sub_buf_ptr; -+} -+ -+static inline int cur_sub_buf_off_rel() -+{ -+ return (int)sub_buf_ptr - (int)sub_buf; -+} -+ -+#define LABEL_MAX 200 -+ -+struct label_placeholder { -+ int label; -+ uintptr_t ptr; -+}; -+ -+struct label_context { -+ int block_idx; -+}; -+ -+#define WASM_NUM_HELPER_FUNCS_MAX 200 -+#define WASM_HELPER_ADDED_TYPES_SECTION_MAX 200 -+__thread uint32_t num_helper_funcs; -+__thread uint32_t target_helper_funcs[WASM_NUM_HELPER_FUNCS_MAX]; -+__thread uint8_t target_helper_types[WASM_HELPER_ADDED_TYPES_SECTION_MAX]; -+__thread int target_helper_types_pos; -+__thread int wasm_block_idx; -+__thread struct label_placeholder block_ptr_placeholder[LABEL_MAX]; -+__thread int block_ptr_placeholder_idx_pos; -+__thread int label_to_block[LABEL_MAX]; -+ -+static int wasm_block_current_idx(TCGContext *s) -+{ -+ return wasm_block_idx; -+} -+ -+static int wasm_alloc_block_idx(TCGContext *s) -+{ -+ return ++wasm_block_idx; -+} -+ -+static void fill_uint32_leb128(uintptr_t bi, uint32_t v) { -+ uint8_t *b = (uint8_t *)bi; -+ uint32_t low7 = 0x7f; -+ // assuems higher bit already written as placeholders -+ do { -+ *b |= v & low7; -+ v >>= 7; -+ b++; -+ } while (v != 0); -+} -+ -+static int write_uint32_leb128(uintptr_t bi, uint32_t v) { -+ uint8_t *b = (uint8_t *)bi; -+ uint32_t low7 = 0x7f; -+ do { -+ *b = (uint8_t)(v & low7); -+ v >>= 7; -+ if (v != 0) -+ *b |= 0x80; -+ b++; -+ } while (v != 0); -+ -+ return (int)((uintptr_t)b - (uintptr_t)bi); -+} -+ -+static uint8_t * wasm_get_helper_types_begin(TCGContext *s) -+{ -+ return &(target_helper_types[target_helper_types_pos]); -+} -+ -+static void wasm_add_helper_types_pos(TCGContext *s, int i) -+{ -+ target_helper_types_pos += i; -+ tcg_debug_assert(target_helper_types_pos <= WASM_HELPER_ADDED_TYPES_SECTION_MAX); -+} -+ -+static int wasm_register_helper_alloc_num(TCGContext *s) -+{ -+ tcg_debug_assert(num_helper_funcs <= WASM_NUM_HELPER_FUNCS_MAX); -+ return num_helper_funcs++; -+} -+ -+static void wasm_register_helper(TCGContext *s, int idx_on_tb, int helper_idx_on_qemu) -+{ -+ tcg_debug_assert(idx_on_tb <= WASM_NUM_HELPER_FUNCS_MAX); -+ target_helper_funcs[idx_on_tb] = helper_idx_on_qemu; -+} -+ -+static int get_wasm_helper_idx(TCGContext *s, int helper_idx_on_qemu) -+{ -+ for (int i = 0; i < num_helper_funcs; i++) { -+ if (target_helper_funcs[i] == helper_idx_on_qemu) { -+ return i; -+ } -+ } -+ return -1; -+} -+ -+static void wasm_add_label_context(TCGContext *s, int label, int block) -+{ -+ tcg_debug_assert(label <= LABEL_MAX); -+ label_to_block[label] = block; -+} -+ -+static void wasm_add_label_block_ptr_placeholder(int label, uintptr_t code_ptr) -+{ -+ int i = block_ptr_placeholder_idx_pos++; -+ tcg_debug_assert(i <= LABEL_MAX); -+ block_ptr_placeholder[i].label = label; -+ block_ptr_placeholder[i].ptr = code_ptr; -+} -+ -+#endif -+ - /* Signal overflow, starting over with fewer guest insns. */ - static G_NORETURN - void tcg_raise_tb_overflow(TCGContext *s) -@@ -754,7 +898,7 @@ static const TCGTargetOpDef constraint_sets[] = { - - #include "tcg-target.c.inc" - --#ifndef CONFIG_TCG_INTERPRETER -+#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN) - /* Validate CPUTLBDescFast placement. */ - QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - - sizeof(CPUNegativeOffsetState)) -@@ -937,7 +1081,7 @@ static TCGHelperInfo info_helper_st128_mmu = { - | dh_typemask(ptr, 5) /* uintptr_t ra */ - }; - --#ifdef CONFIG_TCG_INTERPRETER -+#if defined(EMSCRIPTEN) || defined(CONFIG_TCG_INTERPRETER) - static ffi_type *typecode_to_ffi(int argmask) - { - /* -@@ -1406,12 +1550,11 @@ void tcg_prologue_init(void) - { - TCGContext *s = tcg_ctx; - size_t prologue_size; -- - s->code_ptr = s->code_gen_ptr; - s->code_buf = s->code_gen_ptr; - s->data_gen_ptr = NULL; - --#ifndef CONFIG_TCG_INTERPRETER -+#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN) - tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr); - #endif - -@@ -1434,7 +1577,7 @@ void tcg_prologue_init(void) - prologue_size = tcg_current_code_size(s); - perf_report_prologue(s->code_gen_ptr, prologue_size); - --#ifndef CONFIG_TCG_INTERPRETER -+#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN) - flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), - (uintptr_t)s->code_buf, prologue_size); - #endif -@@ -1471,7 +1614,7 @@ void tcg_prologue_init(void) - } - } - --#ifndef CONFIG_TCG_INTERPRETER -+#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN) - /* - * Assert that goto_ptr is implemented completely, setting an epilogue. - * For tci, we use NULL as the signal to return from the interpreter, -@@ -5904,6 +6047,151 @@ static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst, - tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg); - } - -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ -+static const uint8_t mod_header_a[] = { -+ 0x0, 0x61, 0x73, 0x6d, // magic -+ 0x01, 0x0, 0x0, 0x0, // version -+ // type section -+ 0x01, 0x80, 0x80, 0x80, 0x80, 0x00, -+ 0x80, 0x80, 0x80, 0x80, 0x00, -+ 0x60, -+ 0x01, 0x7f, -+ 0x01, 0x7f, -+ -+}; -+static const uint8_t mod_header_b[] = { -+ // import section -+ 0x02, 0x80, 0x80, 0x80, 0x80, 0x00, -+ 0x80, 0x80, 0x80, 0x80, 0x00, -+ 0x03, 0x65, 0x6e, 0x76, -+ 0x06, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, -+ 0x02, 0x03, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, -+}; -+ -+static const uint8_t mod_header_c[] = { -+ // function section -+ 0x03, 2, 1, 0x00, -+ // global section -+ 0x06, 0x7e, -+ 25, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ 0x7e, 0x01, 0x42, 0x00, 0x0b, -+ // export section -+ 0x07, 13, -+ 1, -+ 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, -+ 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, -+}; -+ -+static const uint8_t mod_header_d[] = { -+ 0x0a, 0x80, 0x80, 0x80, 0x80, 0x00, -+ 0x80, 0x80, 0x80, 0x80, 0x00, -+ 0x80, 0x80, 0x80, 0x80, 0x00, -+ -+ 0x2, 0x2, 0x7f, 0x5, 0x7e, -+ -+ // initialize the instance -+ 0x20, 0x0, // local.get $ctx -+ 0x28, 0, DO_INIT_OFF, // i32.load do_init_ptr -+ 0x41, 0, // i32.const 0 -+ 0x47, // i32.ne -+ 0x04, 0x40, // if -+ -+ 0x23, 14, // global.get $env -+ 0x50, // i64.eqz -+ 0x04, 0x40, // if -+ // fundamental variables -+ 0x20, 0x0, // local.get $ctx -+ 0x28, 0, ENV_OFF, // i32.load env -+ 0xad, // extend -+ 0x24, 14, // global.set $14 -+ 0x20, 0x0, // local.get $ctx -+ 0x28, 0, STACK_OFF, // i32.load stack -+ 0xad, // extend -+ 0x24, 15, // global.set $15 -+ 0x0b, // end -+ -+ 0x20, 0x0, // local.get $ctx -+ 0x41, 0x00, // i32.const 0 -+ 0x36, 0x00, DO_INIT_OFF, // i32.store do_init -+ 0x42, 0x00, // i64.const 0 -+ 0x24, 16, // global.set $block_ptr -+ 0x0b, // end -+ -+ 0x03, 0x40, // loop -+ 0x23, 16, // global.get $block_ptr -+ 0x50, // i64.eqz -+ 0x04, 0x40, // if -+}; -+ -+static void write_wasm_type_section_size(TCGContext *s, void *header_a_ptr, uint32_t added) { -+ uint32_t type_section_size = added + 10; -+ fill_uint32_leb128((uintptr_t)header_a_ptr + 9, type_section_size); -+ fill_uint32_leb128((uintptr_t)header_a_ptr + 14, num_helper_funcs + 1); -+} -+static void write_wasm_memory_size(TCGContext *s, void *header_b_ptr) { -+ fill_uint32_leb128((uintptr_t)header_b_ptr + 25, (uint32_t)(~0) / 65536); -+} -+static void write_wasm_import_section_size(TCGContext *s, void *header_b_ptr, uint32_t added, uint32_t num_imported_funcs) { -+ uint32_t import_section_size = 35 + added - 11; -+ fill_uint32_leb128((uintptr_t)header_b_ptr + 1, import_section_size); -+ fill_uint32_leb128((uintptr_t)header_b_ptr + 6, num_imported_funcs + 1/*buffer+helpers...*/); -+} -+static void write_wasm_export_section_size(TCGContext *s, void *header_c_ptr, uint32_t startidx) { -+ fill_uint32_leb128((uintptr_t)header_c_ptr + 142, startidx); -+} -+static void write_wasm_code_size(TCGContext *s, void *header_d_ptr, int code_size, int code_nums) { -+ code_size = code_size + 66; -+ fill_uint32_leb128((uintptr_t)header_d_ptr + 1, code_size); -+ fill_uint32_leb128((uintptr_t)header_d_ptr + 6, code_nums); -+ fill_uint32_leb128((uintptr_t)header_d_ptr + 11, code_size - 10); -+} -+ -+uint8_t *tcg_out_import_entry(TCGContext *s, uint8_t* wasm_blob_ptr, int i, int typeidx) -+{ -+ *wasm_blob_ptr++ = 6; // helper -+ *wasm_blob_ptr++ = 0x68; -+ *wasm_blob_ptr++ = 0x65; -+ *wasm_blob_ptr++ = 0x6c; -+ *wasm_blob_ptr++ = 0x70; -+ *wasm_blob_ptr++ = 0x65; -+ *wasm_blob_ptr++ = 0x72; -+ char buf[100]; -+ int n = snprintf(buf, sizeof(buf), "%d", i); -+ wasm_blob_ptr += write_uint32_leb128((uintptr_t)wasm_blob_ptr, n); -+ memcpy(wasm_blob_ptr, buf, n); -+ wasm_blob_ptr += n; -+ *wasm_blob_ptr++ = 0x00; //type(0) -+ *wasm_blob_ptr++ = typeidx; //typeidx -+ return wasm_blob_ptr; -+} -+ -+#endif -+ - static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst, - bool load_sign, - const TCGLdstHelperParam *parm) -@@ -6185,6 +6473,31 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) - s->code_ptr = s->code_buf; - s->data_gen_ptr = NULL; - -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ sub_buf_ptr = sub_buf; -+ tcg_out_init(); -+ num_helper_funcs = 0; -+ wasm_block_idx = 0; -+ block_ptr_placeholder_idx_pos = 0; -+ target_helper_types_pos = 0; -+ memset(label_to_block, -1, LABEL_MAX); -+ memset(target_helper_funcs, -1, WASM_NUM_HELPER_FUNCS_MAX); -+ -+ uint32_t *tci_code_off = (uint32_t*)s->code_ptr; -+ s->code_ptr += 4; -+ uint32_t *size_base = (uint32_t*)s->code_ptr; -+ s->code_ptr += 4; -+ uint32_t *export_vec_base = (uint32_t*)s->code_ptr; -+ int export_size = get_core_nums() * 4; -+ memset(s->code_ptr, 0, export_size); -+ s->code_ptr += export_size; -+ *size_base = export_size; -+ -+ uint8_t *code_begin = s->code_ptr; -+ s->code_ptr += 4; // placeholder for size -+ *tci_code_off = s->code_ptr - s->code_buf; -+#endif -+ - #ifdef TCG_TARGET_NEED_LDST_LABELS - QSIMPLEQ_INIT(&s->ldst_labels); - #endif -@@ -6286,13 +6599,94 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) - return -2; - } - --#ifndef CONFIG_TCG_INTERPRETER -+#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN) - /* flush instruction cache */ - flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), - (uintptr_t)s->code_buf, - tcg_ptr_byte_diff(s->code_ptr, s->code_buf)); - #endif - -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ if (wasm_tci_only_tb) { -+ for (int i = 0; i < get_core_nums(); i++) { -+ export_vec_base[i] = WASM_TCI_ONLY_ENTRY; -+ } -+ } -+ -+ tcg_sub_out8(s, 0x0b); //end if -+ tcg_sub_out8(s, 0x0b); //end loop -+ tcg_sub_out8(s, 0x0); // unreachable -+ tcg_sub_out8(s, 0x0b); //end func -+ -+ // fill blocks -+ for (int i = 0; i < block_ptr_placeholder_idx_pos; i++) { -+ int label = block_ptr_placeholder[i].label; -+ int ph = block_ptr_placeholder[i].ptr; -+ int blk = label_to_block[label]; -+ tcg_debug_assert(blk >= 0); -+ *(uint8_t*)ph = 0x80; -+ fill_uint32_leb128(ph, blk); -+ } -+ -+ int code_size = (uint32_t)((uintptr_t)s->code_ptr - (uintptr_t)code_begin - 4); -+ *(uint32_t *)code_begin = code_size; -+ -+ int sub_buf_len = sub_buf_ptr - sub_buf; -+ int wasm_body_size = sub_buf_len; -+ -+ // write header -+ uint8_t *wasm_blob_ptr = s->code_ptr; -+ uint8_t *wasm_blob_ptr_base = s->code_ptr; -+ wasm_blob_ptr += 4; // placeholder for size -+ -+ uint8_t *header_a_base = wasm_blob_ptr; -+ memcpy(wasm_blob_ptr, mod_header_a, sizeof(mod_header_a)); -+ wasm_blob_ptr += sizeof(mod_header_a); -+ memcpy(wasm_blob_ptr, target_helper_types, target_helper_types_pos); -+ wasm_blob_ptr += target_helper_types_pos; -+ write_wasm_type_section_size(s, header_a_base, target_helper_types_pos); -+ uint8_t *header_b_base = wasm_blob_ptr; -+ memcpy(wasm_blob_ptr, mod_header_b, sizeof(mod_header_b)); -+ wasm_blob_ptr += sizeof(mod_header_b); -+ uint8_t *header_b_adding_base = wasm_blob_ptr; -+ for (int i = 0; i < num_helper_funcs; i++) { -+ wasm_blob_ptr = tcg_out_import_entry(s, wasm_blob_ptr, i, i+1/*type0=start,1=helpers...*/); -+ } -+ write_wasm_import_section_size(s, header_b_base, (uint32_t)wasm_blob_ptr - (uint32_t)header_b_adding_base, num_helper_funcs); -+ write_wasm_memory_size(s, header_b_base); -+ uint8_t *header_c_base = wasm_blob_ptr; -+ memcpy(wasm_blob_ptr, mod_header_c, sizeof(mod_header_c)); -+ wasm_blob_ptr += sizeof(mod_header_c); -+ write_wasm_export_section_size(s, header_c_base, num_helper_funcs); -+ uint8_t *header_d_ptr = wasm_blob_ptr; -+ memcpy(wasm_blob_ptr, mod_header_d, sizeof(mod_header_d)); -+ wasm_blob_ptr += sizeof(mod_header_d); -+ write_wasm_code_size(s, header_d_ptr, wasm_body_size, 1); -+ s->code_ptr = wasm_blob_ptr; -+ -+ // write body -+ memcpy(s->code_ptr, sub_buf, sub_buf_len); -+ s->code_ptr += sub_buf_len; -+ -+ // write blob size -+ if (sub_buf_len > SUB_BUF_MAX) { -+ printf("sub too large sub_buf_len: %d\n", sub_buf_len); fflush(stdout); -+ exit(1); -+ } -+ *(uint32_t *)wasm_blob_ptr_base = s->code_ptr - wasm_blob_ptr_base - 4; -+ -+ // record importing helper functions -+ size_base = (uint32_t*)s->code_ptr; -+ s->code_ptr += 4; -+ memcpy(s->code_ptr, target_helper_funcs, num_helper_funcs * 4); -+ s->code_ptr += num_helper_funcs * 4; -+ *size_base = num_helper_funcs * 4; -+ -+ if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) { -+ return -1; -+ } -+#endif -+ - return tcg_current_code_size(s); - } - -diff --git c/tcg/wasm32.c w/tcg/wasm32.c -new file mode 100644 -index 0000000000..19b31ed4df ---- /dev/null -+++ w/tcg/wasm32.c -@@ -0,0 +1,1275 @@ -+/* -+ * Tiny Code Generator for QEMU -+ * -+ * Wasm integration + ported TCI interpreter from tci.c -+ * -+ * Copyright (c) 2009, 2011, 2016 Stefan Weil -+ * -+ * This program is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ */ -+ -+#if !defined(CONFIG_TCG_INTERPRETER) && defined(EMSCRIPTEN) -+ -+#include "qemu/osdep.h" -+#include "exec/cpu_ldst.h" -+#include "tcg/tcg-op.h" -+#include "tcg/tcg-ldst.h" -+#include -+#include -+#include -+#include "wasm32.h" -+#include "exec/translation-block.h" -+ -+__thread uintptr_t tci_tb_ptr; -+__thread bool wasm_tci_only_tb; -+ -+/* Disassemble TCI bytecode. */ -+int print_insn_tci(bfd_vma addr, disassemble_info *info) -+{ -+ return 0; //nop -+} -+ -+EM_JS(int, instantiate_wasm, (), { -+ const memory_v = new DataView(HEAP8.buffer); -+ -+ const tb_ptr = memory_v.getInt32(Module.__wasm32_tb.tb_ptr_ptr, true); -+ const export_vec_size = memory_v.getInt32(tb_ptr + 4, true); -+ const export_vec_begin = tb_ptr + 4 + 4; -+ -+ const tmp_body_size = memory_v.getInt32(export_vec_begin + export_vec_size, true); -+ const tmp_body_begin = export_vec_begin + export_vec_size + 4; -+ const wasm_size = memory_v.getInt32(tmp_body_begin + tmp_body_size, true); -+ const wasm_begin = tmp_body_begin + tmp_body_size + 4; -+ const import_vec_size = memory_v.getInt32(wasm_begin + wasm_size, true); -+ const import_vec_begin = wasm_begin + wasm_size + 4; -+ -+ const wasm = Uint8Array.from(HEAP8.subarray(wasm_begin, wasm_begin + wasm_size)); -+ var helper = {}; -+ for (var i = 0; i < import_vec_size / 4; i++) { -+ helper[i] = wasmTable.get(memory_v.getInt32(import_vec_begin + i * 4, true)); -+ } -+ const mod = new WebAssembly.Module(wasm); -+ const inst = new WebAssembly.Instance(mod, { -+ "env": { -+ "buffer": wasmMemory, -+ }, -+ "helper": helper, -+ }); -+ var ptr = export_vec_begin + 4 * Module.__wasm32_tb.cur_core_num; -+ const fidx = addFunction(inst.exports.start, 'ii'); -+ Module.__wasm32_tb.dynamic_functions.add(fidx); -+ memory_v.setUint32(ptr, fidx, true); -+ -+ const remove_n = memory_v.getInt32(Module.__wasm32_tb.to_remove_instance_idx_ptr, true); -+ if (remove_n > 500) { -+ for (var i = 0; i < remove_n * 4; i += 4) { -+ const fidx = memory_v.getInt32(Module.__wasm32_tb.to_remove_instance_ptr + i, true); -+ if (Module.__wasm32_tb.dynamic_functions.delete(fidx)) { -+ removeFunction(fidx); -+ } -+ } -+ memory_v.setInt32(Module.__wasm32_tb.to_remove_instance_idx_ptr, 0, true); -+ } -+ -+ return 0; -+}); -+ -+EM_JS(void, flush_tb_instances, (), { -+ const tb = Module.__wasm32_tb; -+ if (!tb) { -+ return; -+ } -+ const memory_v = new DataView(HEAP8.buffer); -+ const remove_n = memory_v.getInt32(tb.to_remove_instance_idx_ptr, true); -+ for (var i = 0; i < remove_n * 4; i += 4) { -+ const fidx = memory_v.getInt32(tb.to_remove_instance_ptr + i, true); -+ if (tb.dynamic_functions.delete(fidx)) { -+ removeFunction(fidx); -+ } -+ } -+ memory_v.setInt32(tb.to_remove_instance_idx_ptr, 0, true); -+}); -+ -+__thread bool initdone = false; -+__thread int cur_core_num = -1; -+__thread int export_vec_off = -1; -+__thread int all_cores_num = -1; -+int cur_core_num_max = 0; -+ -+#define TO_REMOVE_INSTANCE_SIZE 50000 -+__thread static int to_remove_instance[TO_REMOVE_INSTANCE_SIZE]; -+__thread static int to_remove_instance_idx = 0; -+ -+void remove_tb(void *tb_ptr) { -+ int32_t *slot = (int32_t*)((uint8_t*)tb_ptr + export_vec_off); -+ int32_t f = *slot; -+ if (f <= 0) { -+ return; -+ } -+ *slot = 0; -+ if (to_remove_instance_idx == TO_REMOVE_INSTANCE_SIZE) { -+ flush_tb_instances(); -+ } -+ to_remove_instance[to_remove_instance_idx++] = f; -+} -+ -+__thread struct wasmContext ctx = { -+ .tb_ptr = 0, -+ .stack = NULL, -+ /* .func_ptr = 0, */ -+ /* .next_func_ptr = 0, */ -+ .do_init = 1, -+ .stack128 = NULL, -+}; -+ -+void set_done_flag() -+{ -+ ctx.done_flag = 1; -+} -+ -+void set_unwinding_flag() -+{ -+ ctx.unwinding = 1; -+} -+ -+typedef uint32_t (*wasm_func_ptr)(struct wasmContext*); -+ -+int get_core_nums() -+{ -+ return emscripten_num_logical_cores(); -+} -+ -+EM_JS(void, init_wasm32_js, (int tb_ptr_ptr, int cur_core_num, int to_remove_instance_ptr, int to_remove_instance_idx_ptr), { -+ Module.__wasm32_tb = { -+ tb_ptr_ptr: tb_ptr_ptr, -+ cur_core_num: cur_core_num, -+ to_remove_instance_ptr: to_remove_instance_ptr, -+ to_remove_instance_idx_ptr: to_remove_instance_idx_ptr, -+ dynamic_functions: new Set(), -+ }; -+}); -+ -+void init_wasm32() -+{ -+ if (!initdone) { -+ cur_core_num = qatomic_fetch_inc(&cur_core_num_max); -+ export_vec_off = 4 + 4 + cur_core_num * 4; -+ all_cores_num = get_core_nums(); -+ ctx.stack = (uint64_t*)malloc(TCG_STATIC_CALL_ARGS_SIZE + TCG_STATIC_FRAME_SIZE); -+ ctx.stack128 = (uint64_t*)malloc(TCG_STATIC_CALL_ARGS_SIZE + TCG_STATIC_FRAME_SIZE); -+ ctx.tci_tb_ptr = (uint32_t*)&tci_tb_ptr; -+ init_wasm32_js((int)&ctx.tb_ptr, cur_core_num, (int)to_remove_instance, (int)&to_remove_instance_idx); -+ initdone = true; -+ } -+} -+ -+__thread uintptr_t tci_tb_ptr; -+ -+static void tci_write_reg64(tcg_target_ulong *regs, uint32_t high_index, -+ uint32_t low_index, uint64_t value) -+{ -+ regs[low_index] = (uint32_t)value; -+ regs[high_index] = value >> 32; -+} -+ -+/* Create a 64 bit value from two 32 bit values. */ -+static uint64_t tci_uint64(uint32_t high, uint32_t low) -+{ -+ return ((uint64_t)high << 32) + low; -+} -+ -+static void tci_args_ldst(uint32_t insn, TCGReg *r0, TCGReg *r1, MemOpIdx *m2, const void *tb_ptr, void **l0) -+{ -+ int diff = sextract32(insn, 12, 20); -+ *l0 = diff ? (uint8_t *)tb_ptr + diff : NULL; -+ -+ uint64_t *data64 = (uint64_t*)*l0; -+ *r0 = (TCGReg)data64[0]; -+ *r1 = (TCGReg)data64[1]; -+ *m2 = (MemOpIdx)data64[2]; -+} -+ -+/* -+ * Load sets of arguments all at once. The naming convention is: -+ * tci_args_ -+ * where arguments is a sequence of -+ * -+ * b = immediate (bit position) -+ * c = condition (TCGCond) -+ * i = immediate (uint32_t) -+ * I = immediate (tcg_target_ulong) -+ * l = label or pointer -+ * m = immediate (MemOpIdx) -+ * n = immediate (call return length) -+ * r = register -+ * s = signed ldst offset -+ */ -+ -+static void tci_args_l(uint32_t insn, const void *tb_ptr, void **l0) -+{ -+ int diff = sextract32(insn, 12, 20); -+ *l0 = diff ? (uint8_t *)tb_ptr + diff : NULL; -+} -+ -+static void tci_args_r(uint32_t insn, TCGReg *r0) -+{ -+ *r0 = extract32(insn, 8, 4); -+} -+ -+static void tci_args_nl(uint32_t insn, const void *tb_ptr, -+ uint8_t *n0, void **l1) -+{ -+ *n0 = extract32(insn, 8, 4); -+ *l1 = sextract32(insn, 12, 20) + (void *)tb_ptr; -+} -+ -+static void tci_args_rl(uint32_t insn, const void *tb_ptr, -+ TCGReg *r0, void **l1) -+{ -+ *r0 = extract32(insn, 8, 4); -+ *l1 = sextract32(insn, 12, 20) + (void *)tb_ptr; -+} -+ -+static void tci_args_rr(uint32_t insn, TCGReg *r0, TCGReg *r1) -+{ -+ *r0 = extract32(insn, 8, 4); -+ *r1 = extract32(insn, 12, 4); -+} -+ -+static void tci_args_ri(uint32_t insn, TCGReg *r0, tcg_target_ulong *i1) -+{ -+ *r0 = extract32(insn, 8, 4); -+ *i1 = sextract32(insn, 12, 20); -+} -+ -+static void tci_args_rrr(uint32_t insn, TCGReg *r0, TCGReg *r1, TCGReg *r2) -+{ -+ *r0 = extract32(insn, 8, 4); -+ *r1 = extract32(insn, 12, 4); -+ *r2 = extract32(insn, 16, 4); -+} -+ -+static void tci_args_rrs(uint32_t insn, TCGReg *r0, TCGReg *r1, int32_t *i2) -+{ -+ *r0 = extract32(insn, 8, 4); -+ *r1 = extract32(insn, 12, 4); -+ *i2 = sextract32(insn, 16, 16); -+} -+ -+static void tci_args_rrbb(uint32_t insn, TCGReg *r0, TCGReg *r1, -+ uint8_t *i2, uint8_t *i3) -+{ -+ *r0 = extract32(insn, 8, 4); -+ *r1 = extract32(insn, 12, 4); -+ *i2 = extract32(insn, 16, 6); -+ *i3 = extract32(insn, 22, 6); -+} -+ -+static void tci_args_rrrc(uint32_t insn, -+ TCGReg *r0, TCGReg *r1, TCGReg *r2, TCGCond *c3) -+{ -+ *r0 = extract32(insn, 8, 4); -+ *r1 = extract32(insn, 12, 4); -+ *r2 = extract32(insn, 16, 4); -+ *c3 = extract32(insn, 20, 4); -+} -+ -+static void tci_args_rrrbb(uint32_t insn, TCGReg *r0, TCGReg *r1, -+ TCGReg *r2, uint8_t *i3, uint8_t *i4) -+{ -+ *r0 = extract32(insn, 8, 4); -+ *r1 = extract32(insn, 12, 4); -+ *r2 = extract32(insn, 16, 4); -+ *i3 = extract32(insn, 20, 6); -+ *i4 = extract32(insn, 26, 6); -+} -+ -+static void tci_args_rrrrr(uint32_t insn, TCGReg *r0, TCGReg *r1, -+ TCGReg *r2, TCGReg *r3, TCGReg *r4) -+{ -+ *r0 = extract32(insn, 8, 4); -+ *r1 = extract32(insn, 12, 4); -+ *r2 = extract32(insn, 16, 4); -+ *r3 = extract32(insn, 20, 4); -+ *r4 = extract32(insn, 24, 4); -+} -+ -+static void tci_args_rrrr(uint32_t insn, -+ TCGReg *r0, TCGReg *r1, TCGReg *r2, TCGReg *r3) -+{ -+ *r0 = extract32(insn, 8, 4); -+ *r1 = extract32(insn, 12, 4); -+ *r2 = extract32(insn, 16, 4); -+ *r3 = extract32(insn, 20, 4); -+} -+ -+static void tci_args_rrrrrc(uint32_t insn, TCGReg *r0, TCGReg *r1, -+ TCGReg *r2, TCGReg *r3, TCGReg *r4, TCGCond *c5) -+{ -+ *r0 = extract32(insn, 8, 4); -+ *r1 = extract32(insn, 12, 4); -+ *r2 = extract32(insn, 16, 4); -+ *r3 = extract32(insn, 20, 4); -+ *r4 = extract32(insn, 24, 4); -+ *c5 = extract32(insn, 28, 4); -+} -+ -+static void tci_args_rrrrrr(uint32_t insn, TCGReg *r0, TCGReg *r1, -+ TCGReg *r2, TCGReg *r3, TCGReg *r4, TCGReg *r5) -+{ -+ *r0 = extract32(insn, 8, 4); -+ *r1 = extract32(insn, 12, 4); -+ *r2 = extract32(insn, 16, 4); -+ *r3 = extract32(insn, 20, 4); -+ *r4 = extract32(insn, 24, 4); -+ *r5 = extract32(insn, 28, 4); -+} -+ -+static bool tci_compare32(uint32_t u0, uint32_t u1, TCGCond condition) -+{ -+ bool result = false; -+ int32_t i0 = u0; -+ int32_t i1 = u1; -+ switch (condition) { -+ case TCG_COND_EQ: -+ result = (u0 == u1); -+ break; -+ case TCG_COND_NE: -+ result = (u0 != u1); -+ break; -+ case TCG_COND_LT: -+ result = (i0 < i1); -+ break; -+ case TCG_COND_GE: -+ result = (i0 >= i1); -+ break; -+ case TCG_COND_LE: -+ result = (i0 <= i1); -+ break; -+ case TCG_COND_GT: -+ result = (i0 > i1); -+ break; -+ case TCG_COND_LTU: -+ result = (u0 < u1); -+ break; -+ case TCG_COND_GEU: -+ result = (u0 >= u1); -+ break; -+ case TCG_COND_LEU: -+ result = (u0 <= u1); -+ break; -+ case TCG_COND_GTU: -+ result = (u0 > u1); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ return result; -+} -+ -+static bool tci_compare64(uint64_t u0, uint64_t u1, TCGCond condition) -+{ -+ bool result = false; -+ int64_t i0 = u0; -+ int64_t i1 = u1; -+ switch (condition) { -+ case TCG_COND_EQ: -+ result = (u0 == u1); -+ break; -+ case TCG_COND_NE: -+ result = (u0 != u1); -+ break; -+ case TCG_COND_LT: -+ result = (i0 < i1); -+ break; -+ case TCG_COND_GE: -+ result = (i0 >= i1); -+ break; -+ case TCG_COND_LE: -+ result = (i0 <= i1); -+ break; -+ case TCG_COND_GT: -+ result = (i0 > i1); -+ break; -+ case TCG_COND_LTU: -+ result = (u0 < u1); -+ break; -+ case TCG_COND_GEU: -+ result = (u0 >= u1); -+ break; -+ case TCG_COND_LEU: -+ result = (u0 <= u1); -+ break; -+ case TCG_COND_GTU: -+ result = (u0 > u1); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ return result; -+} -+ -+static uint64_t tlb_load(CPUArchState *env, uint64_t taddr, MemOp mop, uint64_t* ptr, bool is_ld) -+{ -+ uint64_t *data64 = (uint64_t*)ptr; -+ unsigned a_mask = (unsigned)data64[3]; -+ int mask_ofs = (int)data64[4]; -+ int8_t page_bits = (int8_t)data64[5]; -+ uint64_t page_mask = (uint64_t)data64[6]; -+ int table_ofs = (uint64_t)data64[7]; -+ -+ unsigned s_bits = mop & MO_SIZE; -+ unsigned s_mask = (1u << s_bits) - 1; -+ tcg_target_long compare_mask; -+ int add_off = offsetof(CPUTLBEntry, addend); -+ -+ uint64_t tmp0 = taddr >> (page_bits - CPU_TLB_ENTRY_BITS); -+ uint64_t tmp2 = *(uint64_t*)((uint8_t*)env + mask_ofs); -+ uint64_t tmp2_b = *(uint64_t*)((uint8_t*)env + table_ofs); -+ uint64_t tmp3 = (tmp0 & tmp2) + tmp2_b; -+ int off = off = is_ld ? offsetof(CPUTLBEntry, addr_read) -+ : offsetof(CPUTLBEntry, addr_write); -+ uint64_t target = *(uint64_t*)((uint8_t*)tmp3 + off); -+ uint64_t c_addr = taddr; -+ if (a_mask < s_mask) { -+ c_addr += s_mask - a_mask; -+ } -+ compare_mask = page_mask | a_mask; -+ c_addr &= compare_mask; -+ -+ if (c_addr == target) { -+ int32_t addend = *(uint32_t*)((uint8_t*)tmp3 + add_off); -+ uint64_t target_addr = taddr + addend; -+ return target_addr; -+ } -+ return 0; -+} -+ -+static uint64_t tci_qemu_ld(CPUArchState *env, uint64_t taddr, -+ MemOpIdx oi, const void *tb_ptr, uint64_t* ptr) -+{ -+ MemOp mop = get_memop(oi); -+ uintptr_t ra = (uintptr_t)tb_ptr; -+ -+ uint64_t target_addr = tlb_load(env, taddr, mop, ptr, true); -+ if (target_addr != 0) { -+ switch (mop & MO_SSIZE) { -+ case MO_UB: -+ return *(uint8_t*)target_addr; -+ case MO_SB: -+ return *(int8_t*)target_addr; -+ case MO_UW: -+ return *(uint16_t*)target_addr; -+ case MO_SW: -+ return *(int16_t*)target_addr; -+ case MO_UL: -+ return *(uint32_t*)target_addr; -+ case MO_SL: -+ return *(int32_t*)target_addr; -+ case MO_UQ: -+ return *(uint64_t*)target_addr; -+ default: -+ g_assert_not_reached(); -+ } -+ } -+ -+ switch (mop & MO_SSIZE) { -+ case MO_UB: -+ return helper_ldub_mmu(env, taddr, oi, ra); -+ case MO_SB: -+ return helper_ldsb_mmu(env, taddr, oi, ra); -+ case MO_UW: -+ return helper_lduw_mmu(env, taddr, oi, ra); -+ case MO_SW: -+ return helper_ldsw_mmu(env, taddr, oi, ra); -+ case MO_UL: -+ return helper_ldul_mmu(env, taddr, oi, ra); -+ case MO_SL: -+ return helper_ldsl_mmu(env, taddr, oi, ra); -+ case MO_UQ: -+ return helper_ldq_mmu(env, taddr, oi, ra); -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tci_qemu_st(CPUArchState *env, uint64_t taddr, uint64_t val, -+ MemOpIdx oi, const void *tb_ptr, uint64_t* ptr) -+{ -+ MemOp mop = get_memop(oi); -+ uintptr_t ra = (uintptr_t)tb_ptr; -+ -+ uint64_t target_addr = tlb_load(env, taddr, mop, ptr, false); -+ if (target_addr != 0) { -+ uint64_t mem_bytes = (uint64_t)__builtin_wasm_memory_size(0) << 16; -+ if (target_addr + (1u << (mop & MO_SIZE)) > mem_bytes) { -+ TranslationBlock *tb = tcg_tb_lookup(ra); -+ fprintf(stderr, -+ "[sd-watch] OOB store pc=%08llx gaddr=%08llx haddr=%08llx size=%u value=%08llx membytes=%08llx\n", -+ (unsigned long long)(tb ? tb->pc : 0), -+ (unsigned long long)taddr, (unsigned long long)target_addr, -+ 1u << (mop & MO_SIZE), (unsigned long long)val, -+ (unsigned long long)mem_bytes); -+ return; -+ } -+ } -+ if (target_addr != 0) { -+ switch (mop & MO_SIZE) { -+ case MO_UB: -+ *(uint8_t*)target_addr = (uint8_t)val; -+ break; -+ case MO_UW: -+ *(uint16_t*)target_addr = (uint16_t)val; -+ break; -+ case MO_UL: -+ *(uint32_t*)target_addr = (uint32_t)val; -+ break; -+ case MO_UQ: -+ *(uint64_t*)target_addr = (uint64_t)val; -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ return; -+ } -+ -+ switch (mop & MO_SIZE) { -+ case MO_UB: -+ helper_stb_mmu(env, taddr, val, oi, ra); -+ break; -+ case MO_UW: -+ helper_stw_mmu(env, taddr, val, oi, ra); -+ break; -+ case MO_UL: -+ helper_stl_mmu(env, taddr, val, oi, ra); -+ break; -+ case MO_UQ: -+ helper_stq_mmu(env, taddr, val, oi, ra); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+#if TCG_TARGET_REG_BITS == 64 -+# define CASE_32_64(x) \ -+ case glue(glue(INDEX_op_, x), _i64): \ -+ case glue(glue(INDEX_op_, x), _i32): -+# define CASE_64(x) \ -+ case glue(glue(INDEX_op_, x), _i64): -+#else -+# define CASE_32_64(x) \ -+ case glue(glue(INDEX_op_, x), _i32): -+# define CASE_64(x) -+#endif -+ -+__thread tcg_target_ulong regs[TCG_TARGET_NB_REGS]; -+ -+static inline uintptr_t tcg_qemu_tb_exec_tci(CPUArchState *env) -+{ -+ uint32_t *tb_ptr = (uint8_t*)ctx.tb_ptr + *(uint32_t*)ctx.tb_ptr; -+ uint64_t *stack = ctx.stack; -+ -+ regs[TCG_AREG0] = (tcg_target_ulong)env; -+ regs[TCG_REG_CALL_STACK] = (uintptr_t)stack; -+ -+ for (;;) { -+ uint32_t insn; -+ TCGOpcode opc; -+ TCGReg r0, r1, r2, r3, r4, r5; -+ tcg_target_ulong t1; -+ TCGCond condition; -+ uint8_t pos, len; -+ uint32_t tmp32; -+ uint64_t tmp64, taddr; -+ uint64_t T1, T2; -+ MemOpIdx oi; -+ int32_t ofs; -+ void *ptr; -+ -+ uint32_t *savep = tb_ptr; -+ insn = *tb_ptr++; -+ opc = extract32(insn, 0, 8); -+ -+ TCGOpDef *def = &tcg_op_defs[opc]; -+ -+ switch (opc) { -+ case INDEX_op_call: -+ { -+ void *call_slots[MAX_CALL_IARGS]; -+ ffi_cif *cif; -+ void *func; -+ unsigned i, s, n; -+ -+ tci_args_nl(insn, tb_ptr, &len, &ptr); -+ uint64_t *data64 = (uint64_t*)ptr; -+ func = (void*)data64[0]; -+ cif = (void*)data64[1]; -+ -+ int reg_iarg_base = 8; -+ if ((uint32_t)func == (uint32_t)helper_lookup_tb_ptr) { -+ regs[TCG_REG_R0] = (uint32_t)helper_lookup_tb_ptr((CPUArchState *)regs[reg_iarg_base]); -+ break; -+ } -+ -+ int reg_idx = 0; -+ int reg_idx_end = 5; // NUM_OF_IARG_REGS -+ int stack_idx = 0; -+ n = cif->nargs; -+ for (i = s = 0; i < n; ++i) { -+ ffi_type *t = cif->arg_types[i]; -+ if (reg_idx < reg_idx_end) { -+ call_slots[i] = ®s[reg_iarg_base + reg_idx]; -+ reg_idx += DIV_ROUND_UP(t->size, 8); -+ } else { -+ call_slots[i] = &stack[stack_idx]; -+ stack_idx += DIV_ROUND_UP(t->size, 8); -+ } -+ } -+ -+ /* Helper functions may need to access the "return address" */ -+ tci_tb_ptr = (uintptr_t)tb_ptr; -+ ffi_call(cif, func, stack, call_slots); -+ } -+ -+ switch (len) { -+ case 0: /* void */ -+ break; -+ case 1: /* uint32_t */ -+ /* -+ * The result winds up "left-aligned" in the stack[0] slot. -+ * Note that libffi has an odd special case in that it will -+ * always widen an integral result to ffi_arg. -+ */ -+ if (sizeof(ffi_arg) == 8) { -+ regs[TCG_REG_R0] = (uint32_t)stack[0]; -+ } else { -+ regs[TCG_REG_R0] = *(uint32_t *)stack; -+ } -+ break; -+ case 2: /* uint64_t */ -+ /* -+ * For TCG_TARGET_REG_BITS == 32, the register pair -+ * must stay in host memory order. -+ */ -+ memcpy(®s[TCG_REG_R0], stack, 8); -+ break; -+ case 3: /* Int128 */ -+ memcpy(®s[TCG_REG_R0], stack, 16); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ break; -+ -+ case INDEX_op_br: -+ tci_args_l(insn, tb_ptr, &ptr); -+ tb_ptr = ptr; -+ continue; -+ case INDEX_op_setcond_i32: -+ tci_args_rrrc(insn, &r0, &r1, &r2, &condition); -+ regs[r0] = tci_compare32(regs[r1], regs[r2], condition); -+ break; -+ case INDEX_op_movcond_i32: -+ tci_args_rrrrrc(insn, &r0, &r1, &r2, &r3, &r4, &condition); -+ tmp32 = tci_compare32(regs[r1], regs[r2], condition); -+ regs[r0] = regs[tmp32 ? r3 : r4]; -+ break; -+#if TCG_TARGET_REG_BITS == 32 -+ case INDEX_op_setcond2_i32: -+ tci_args_rrrrrc(insn, &r0, &r1, &r2, &r3, &r4, &condition); -+ T1 = tci_uint64(regs[r2], regs[r1]); -+ T2 = tci_uint64(regs[r4], regs[r3]); -+ regs[r0] = tci_compare64(T1, T2, condition); -+ break; -+#elif TCG_TARGET_REG_BITS == 64 -+ case INDEX_op_setcond_i64: -+ tci_args_rrrc(insn, &r0, &r1, &r2, &condition); -+ regs[r0] = tci_compare64(regs[r1], regs[r2], condition); -+ break; -+ case INDEX_op_movcond_i64: -+ tci_args_rrrrrc(insn, &r0, &r1, &r2, &r3, &r4, &condition); -+ tmp32 = tci_compare64(regs[r1], regs[r2], condition); -+ regs[r0] = regs[tmp32 ? r3 : r4]; -+ break; -+#endif -+ CASE_32_64(mov) -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = regs[r1]; -+ break; -+ case INDEX_op_tci_movi: -+ tci_args_ri(insn, &r0, &t1); -+ regs[r0] = t1; -+ break; -+ case INDEX_op_tci_movl: -+ tci_args_rl(insn, tb_ptr, &r0, &ptr); -+ regs[r0] = *(tcg_target_ulong *)ptr; -+ break; -+ -+ /* Load/store operations (32 bit). */ -+ -+ CASE_32_64(ld8u) -+ tci_args_rrs(insn, &r0, &r1, &ofs); -+ ptr = (void *)(regs[r1] + ofs); -+ regs[r0] = *(uint8_t *)ptr; -+ break; -+ CASE_32_64(ld8s) -+ tci_args_rrs(insn, &r0, &r1, &ofs); -+ ptr = (void *)(regs[r1] + ofs); -+ regs[r0] = *(int8_t *)ptr; -+ break; -+ CASE_32_64(ld16u) -+ tci_args_rrs(insn, &r0, &r1, &ofs); -+ ptr = (void *)(regs[r1] + ofs); -+ regs[r0] = *(uint16_t *)ptr; -+ break; -+ CASE_32_64(ld16s) -+ tci_args_rrs(insn, &r0, &r1, &ofs); -+ ptr = (void *)(regs[r1] + ofs); -+ regs[r0] = *(int16_t *)ptr; -+ break; -+ case INDEX_op_ld_i32: -+ CASE_64(ld32u) -+ tci_args_rrs(insn, &r0, &r1, &ofs); -+ ptr = (void *)(regs[r1] + ofs); -+ regs[r0] = *(uint32_t *)ptr; -+ break; -+ CASE_32_64(st8) -+ tci_args_rrs(insn, &r0, &r1, &ofs); -+ ptr = (void *)(regs[r1] + ofs); -+ *(uint8_t *)ptr = regs[r0]; -+ break; -+ CASE_32_64(st16) -+ tci_args_rrs(insn, &r0, &r1, &ofs); -+ ptr = (void *)(regs[r1] + ofs); -+ *(uint16_t *)ptr = regs[r0]; -+ break; -+ case INDEX_op_st_i32: -+ CASE_64(st32) -+ tci_args_rrs(insn, &r0, &r1, &ofs); -+ ptr = (void *)(regs[r1] + ofs); -+ *(uint32_t *)ptr = regs[r0]; -+ break; -+ -+ /* Arithmetic operations (mixed 32/64 bit). */ -+ -+ CASE_32_64(add) -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = regs[r1] + regs[r2]; -+ break; -+ CASE_32_64(sub) -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = regs[r1] - regs[r2]; -+ break; -+ CASE_32_64(mul) -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = regs[r1] * regs[r2]; -+ break; -+ CASE_32_64(and) -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = regs[r1] & regs[r2]; -+ break; -+ CASE_32_64(or) -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = regs[r1] | regs[r2]; -+ break; -+ CASE_32_64(xor) -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = regs[r1] ^ regs[r2]; -+ break; -+#if TCG_TARGET_HAS_andc_i32 || TCG_TARGET_HAS_andc_i64 -+ CASE_32_64(andc) -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = regs[r1] & ~regs[r2]; -+ break; -+#endif -+#if TCG_TARGET_HAS_orc_i32 || TCG_TARGET_HAS_orc_i64 -+ CASE_32_64(orc) -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = regs[r1] | ~regs[r2]; -+ break; -+#endif -+#if TCG_TARGET_HAS_eqv_i32 || TCG_TARGET_HAS_eqv_i64 -+ CASE_32_64(eqv) -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = ~(regs[r1] ^ regs[r2]); -+ break; -+#endif -+#if TCG_TARGET_HAS_nand_i32 || TCG_TARGET_HAS_nand_i64 -+ CASE_32_64(nand) -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = ~(regs[r1] & regs[r2]); -+ break; -+#endif -+#if TCG_TARGET_HAS_nor_i32 || TCG_TARGET_HAS_nor_i64 -+ CASE_32_64(nor) -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = ~(regs[r1] | regs[r2]); -+ break; -+#endif -+ -+ /* Arithmetic operations (32 bit). */ -+ -+ case INDEX_op_div_i32: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = (int32_t)regs[r1] / (int32_t)regs[r2]; -+ break; -+ case INDEX_op_divu_i32: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = (uint32_t)regs[r1] / (uint32_t)regs[r2]; -+ break; -+ case INDEX_op_rem_i32: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = (int32_t)regs[r1] % (int32_t)regs[r2]; -+ break; -+ case INDEX_op_remu_i32: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = (uint32_t)regs[r1] % (uint32_t)regs[r2]; -+ break; -+#if TCG_TARGET_HAS_clz_i32 -+ case INDEX_op_clz_i32: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ tmp32 = regs[r1]; -+ regs[r0] = tmp32 ? clz32(tmp32) : regs[r2]; -+ break; -+#endif -+#if TCG_TARGET_HAS_ctz_i32 -+ case INDEX_op_ctz_i32: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ tmp32 = regs[r1]; -+ regs[r0] = tmp32 ? ctz32(tmp32) : regs[r2]; -+ break; -+#endif -+#if TCG_TARGET_HAS_ctpop_i32 -+ case INDEX_op_ctpop_i32: -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = ctpop32(regs[r1]); -+ break; -+#endif -+ -+ /* Shift/rotate operations (32 bit). */ -+ -+ case INDEX_op_shl_i32: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = (uint32_t)regs[r1] << (regs[r2] & 31); -+ break; -+ case INDEX_op_shr_i32: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = (uint32_t)regs[r1] >> (regs[r2] & 31); -+ break; -+ case INDEX_op_sar_i32: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = (int32_t)regs[r1] >> (regs[r2] & 31); -+ break; -+#if TCG_TARGET_HAS_rot_i32 -+ case INDEX_op_rotl_i32: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = rol32(regs[r1], regs[r2] & 31); -+ break; -+ case INDEX_op_rotr_i32: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = ror32(regs[r1], regs[r2] & 31); -+ break; -+#endif -+#if TCG_TARGET_HAS_deposit_i32 -+ case INDEX_op_deposit_i32: -+ tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len); -+ regs[r0] = deposit32(regs[r1], pos, len, regs[r2]); -+ break; -+#endif -+#if TCG_TARGET_HAS_extract_i32 -+ case INDEX_op_extract_i32: -+ tci_args_rrbb(insn, &r0, &r1, &pos, &len); -+ regs[r0] = extract32(regs[r1], pos, len); -+ break; -+#endif -+#if TCG_TARGET_HAS_sextract_i32 -+ case INDEX_op_sextract_i32: -+ tci_args_rrbb(insn, &r0, &r1, &pos, &len); -+ regs[r0] = sextract32(regs[r1], pos, len); -+ break; -+#endif -+ case INDEX_op_brcond_i32: -+ tci_args_rl(insn, tb_ptr, &r0, &ptr); -+ if ((uint32_t)regs[r0]) { -+ tb_ptr = ptr; -+ } -+ break; -+#if TCG_TARGET_REG_BITS == 32 || TCG_TARGET_HAS_add2_i32 -+ case INDEX_op_add2_i32: -+ tci_args_rrrrrr(insn, &r0, &r1, &r2, &r3, &r4, &r5); -+ T1 = tci_uint64(regs[r3], regs[r2]); -+ T2 = tci_uint64(regs[r5], regs[r4]); -+ tci_write_reg64(regs, r1, r0, T1 + T2); -+ break; -+#endif -+#if TCG_TARGET_REG_BITS == 32 || TCG_TARGET_HAS_sub2_i32 -+ case INDEX_op_sub2_i32: -+ tci_args_rrrrrr(insn, &r0, &r1, &r2, &r3, &r4, &r5); -+ T1 = tci_uint64(regs[r3], regs[r2]); -+ T2 = tci_uint64(regs[r5], regs[r4]); -+ tci_write_reg64(regs, r1, r0, T1 - T2); -+ break; -+#endif -+#if TCG_TARGET_HAS_mulu2_i32 -+ case INDEX_op_mulu2_i32: -+ tci_args_rrrr(insn, &r0, &r1, &r2, &r3); -+ tmp64 = (uint64_t)(uint32_t)regs[r2] * (uint32_t)regs[r3]; -+ tci_write_reg64(regs, r1, r0, tmp64); -+ break; -+#endif -+#if TCG_TARGET_HAS_muls2_i32 -+ case INDEX_op_muls2_i32: -+ tci_args_rrrr(insn, &r0, &r1, &r2, &r3); -+ tmp64 = (int64_t)(int32_t)regs[r2] * (int32_t)regs[r3]; -+ tci_write_reg64(regs, r1, r0, tmp64); -+ break; -+#endif -+#if TCG_TARGET_HAS_ext8s_i32 || TCG_TARGET_HAS_ext8s_i64 -+ CASE_32_64(ext8s) -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = (int8_t)regs[r1]; -+ break; -+#endif -+#if TCG_TARGET_HAS_ext16s_i32 || TCG_TARGET_HAS_ext16s_i64 || \ -+ TCG_TARGET_HAS_bswap16_i32 || TCG_TARGET_HAS_bswap16_i64 -+ CASE_32_64(ext16s) -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = (int16_t)regs[r1]; -+ break; -+#endif -+#if TCG_TARGET_HAS_ext8u_i32 || TCG_TARGET_HAS_ext8u_i64 -+ CASE_32_64(ext8u) -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = (uint8_t)regs[r1]; -+ break; -+#endif -+#if TCG_TARGET_HAS_ext16u_i32 || TCG_TARGET_HAS_ext16u_i64 -+ CASE_32_64(ext16u) -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = (uint16_t)regs[r1]; -+ break; -+#endif -+#if TCG_TARGET_HAS_bswap16_i32 || TCG_TARGET_HAS_bswap16_i64 -+ CASE_32_64(bswap16) -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = bswap16(regs[r1]); -+ break; -+#endif -+#if TCG_TARGET_HAS_bswap32_i32 || TCG_TARGET_HAS_bswap32_i64 -+ CASE_32_64(bswap32) -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = bswap32(regs[r1]); -+ break; -+#endif -+#if TCG_TARGET_HAS_not_i32 || TCG_TARGET_HAS_not_i64 -+ CASE_32_64(not) -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = ~regs[r1]; -+ break; -+#endif -+#if TCG_TARGET_HAS_neg_i32 || TCG_TARGET_HAS_neg_i64 -+ CASE_32_64(neg) -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = -regs[r1]; -+ break; -+#endif -+#if TCG_TARGET_REG_BITS == 64 -+ /* Load/store operations (64 bit). */ -+ -+ case INDEX_op_ld32s_i64: -+ tci_args_rrs(insn, &r0, &r1, &ofs); -+ ptr = (void *)(regs[r1] + ofs); -+ regs[r0] = *(int32_t *)ptr; -+ break; -+ case INDEX_op_ld_i64: -+ tci_args_rrs(insn, &r0, &r1, &ofs); -+ ptr = (void *)(regs[r1] + ofs); -+ regs[r0] = *(uint64_t *)ptr; -+ break; -+ case INDEX_op_st_i64: -+ tci_args_rrs(insn, &r0, &r1, &ofs); -+ ptr = (void *)(regs[r1] + ofs); -+ *(uint64_t *)ptr = regs[r0]; -+ break; -+ -+ /* Arithmetic operations (64 bit). */ -+ -+ case INDEX_op_div_i64: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = (int64_t)regs[r1] / (int64_t)regs[r2]; -+ break; -+ case INDEX_op_divu_i64: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = (uint64_t)regs[r1] / (uint64_t)regs[r2]; -+ break; -+ case INDEX_op_rem_i64: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = (int64_t)regs[r1] % (int64_t)regs[r2]; -+ break; -+ case INDEX_op_remu_i64: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = (uint64_t)regs[r1] % (uint64_t)regs[r2]; -+ break; -+#if TCG_TARGET_HAS_clz_i64 -+ case INDEX_op_clz_i64: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = regs[r1] ? clz64(regs[r1]) : regs[r2]; -+ break; -+#endif -+#if TCG_TARGET_HAS_ctz_i64 -+ case INDEX_op_ctz_i64: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = regs[r1] ? ctz64(regs[r1]) : regs[r2]; -+ break; -+#endif -+#if TCG_TARGET_HAS_ctpop_i64 -+ case INDEX_op_ctpop_i64: -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = ctpop64(regs[r1]); -+ break; -+#endif -+#if TCG_TARGET_HAS_mulu2_i64 -+ case INDEX_op_mulu2_i64: -+ tci_args_rrrr(insn, &r0, &r1, &r2, &r3); -+ mulu64(®s[r0], ®s[r1], regs[r2], regs[r3]); -+ break; -+#endif -+#if TCG_TARGET_HAS_muls2_i64 -+ case INDEX_op_muls2_i64: -+ tci_args_rrrr(insn, &r0, &r1, &r2, &r3); -+ muls64(®s[r0], ®s[r1], regs[r2], regs[r3]); -+ break; -+#endif -+#if TCG_TARGET_HAS_add2_i64 -+ case INDEX_op_add2_i64: -+ tci_args_rrrrrr(insn, &r0, &r1, &r2, &r3, &r4, &r5); -+ T1 = regs[r2] + regs[r4]; -+ T2 = regs[r3] + regs[r5] + (T1 < regs[r2]); -+ regs[r0] = T1; -+ regs[r1] = T2; -+ break; -+#endif -+#if TCG_TARGET_HAS_add2_i64 -+ case INDEX_op_sub2_i64: -+ tci_args_rrrrrr(insn, &r0, &r1, &r2, &r3, &r4, &r5); -+ T1 = regs[r2] - regs[r4]; -+ T2 = regs[r3] - regs[r5] - (regs[r2] < regs[r4]); -+ regs[r0] = T1; -+ regs[r1] = T2; -+ break; -+#endif -+ -+ /* Shift/rotate operations (64 bit). */ -+ -+ case INDEX_op_shl_i64: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = regs[r1] << (regs[r2] & 63); -+ break; -+ case INDEX_op_shr_i64: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = regs[r1] >> (regs[r2] & 63); -+ break; -+ case INDEX_op_sar_i64: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = (int64_t)regs[r1] >> (regs[r2] & 63); -+ break; -+#if TCG_TARGET_HAS_rot_i64 -+ case INDEX_op_rotl_i64: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = rol64(regs[r1], regs[r2] & 63); -+ break; -+ case INDEX_op_rotr_i64: -+ tci_args_rrr(insn, &r0, &r1, &r2); -+ regs[r0] = ror64(regs[r1], regs[r2] & 63); -+ break; -+#endif -+#if TCG_TARGET_HAS_deposit_i64 -+ case INDEX_op_deposit_i64: -+ tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len); -+ regs[r0] = deposit64(regs[r1], pos, len, regs[r2]); -+ break; -+#endif -+#if TCG_TARGET_HAS_extract_i64 -+ case INDEX_op_extract_i64: -+ tci_args_rrbb(insn, &r0, &r1, &pos, &len); -+ regs[r0] = extract64(regs[r1], pos, len); -+ break; -+#endif -+#if TCG_TARGET_HAS_sextract_i64 -+ case INDEX_op_sextract_i64: -+ tci_args_rrbb(insn, &r0, &r1, &pos, &len); -+ regs[r0] = sextract64(regs[r1], pos, len); -+ break; -+#endif -+ case INDEX_op_brcond_i64: -+ tci_args_rl(insn, tb_ptr, &r0, &ptr); -+ if (regs[r0]) { -+ tb_ptr = ptr; -+ } -+ break; -+ case INDEX_op_ext32s_i64: -+ case INDEX_op_ext_i32_i64: -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = (int32_t)regs[r1]; -+ break; -+ case INDEX_op_ext32u_i64: -+ case INDEX_op_extu_i32_i64: -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = (uint32_t)regs[r1]; -+ break; -+#if TCG_TARGET_HAS_bswap64_i64 -+ case INDEX_op_bswap64_i64: -+ tci_args_rr(insn, &r0, &r1); -+ regs[r0] = bswap64(regs[r1]); -+ break; -+#endif -+#endif /* TCG_TARGET_REG_BITS == 64 */ -+ -+ /* QEMU specific operations. */ -+ -+ case INDEX_op_exit_tb: -+ tci_args_l(insn, tb_ptr, &ptr); -+ ctx.tb_ptr = 0; -+ return (uintptr_t)ptr; -+ -+ case INDEX_op_goto_tb: -+ tci_args_l(insn, tb_ptr, &ptr); -+ if (*(uint32_t **)ptr != 0) { -+ tb_ptr = *(uint32_t **)ptr; -+ ctx.tb_ptr = tb_ptr; -+ int tb_entry_ptr = (uint32_t)tb_ptr + export_vec_off; -+ if (*(int32_t *)tb_entry_ptr == WASM_TCI_ONLY_ENTRY) { -+ /* ponytail: Store TBs use TCI while tracing SD object corruption. */ -+ } else if ((*(int32_t*)tb_entry_ptr <= 0) && (*(int32_t*)tb_entry_ptr > (-1 * INSTANTIATE_NUM))) { -+ *(int32_t*)tb_entry_ptr -= 1; -+ } else { -+ // enter to wasm TB -+ return 0; -+ } -+ tb_ptr = (uint8_t*)tb_ptr + *(uint32_t*)tb_ptr; -+ } -+ break; -+ -+ case INDEX_op_goto_ptr: -+ tci_args_r(insn, &r0); -+ ptr = (void *)regs[r0]; -+ if (!ptr) { -+ ctx.tb_ptr = 0; -+ return 0; -+ } -+ tb_ptr = ptr; -+ -+ ctx.tb_ptr = tb_ptr; -+ int tb_entry_ptr = (uint32_t)tb_ptr + export_vec_off; -+ if (*(int32_t *)tb_entry_ptr == WASM_TCI_ONLY_ENTRY) { -+ /* Continue in TCI. */ -+ } else if ((*(int32_t*)tb_entry_ptr <= 0) && (*(int32_t*)tb_entry_ptr > (-1 * INSTANTIATE_NUM))) { -+ *(int32_t*)tb_entry_ptr -= 1; -+ } else { -+ // enter to wasm TB -+ return 0; -+ } -+ tb_ptr = (uint8_t*)tb_ptr + *(uint32_t*)tb_ptr; -+ -+ break; -+ -+ case INDEX_op_qemu_ld_a32_i32: -+ tci_args_ldst(insn, &r0, &r1, &oi, tb_ptr, &ptr); -+ taddr = (uint32_t)regs[r1]; -+ goto do_ld_i32; -+ case INDEX_op_qemu_ld_a64_i32: -+ tci_args_ldst(insn, &r0, &r1, &oi, tb_ptr, &ptr); -+ taddr = regs[r1]; -+ do_ld_i32: -+ regs[r0] = tci_qemu_ld(env, taddr, oi, tb_ptr, ptr); -+ break; -+ -+ case INDEX_op_qemu_ld_a32_i64: -+ tci_args_ldst(insn, &r0, &r1, &oi, tb_ptr, &ptr); -+ taddr = (uint32_t)regs[r1]; -+ goto do_ld_i64; -+ case INDEX_op_qemu_ld_a64_i64: -+ tci_args_ldst(insn, &r0, &r1, &oi, tb_ptr, &ptr); -+ taddr = regs[r1]; -+ do_ld_i64: -+ tmp64 = tci_qemu_ld(env, taddr, oi, tb_ptr, ptr); -+ if (TCG_TARGET_REG_BITS == 32) { -+ tci_write_reg64(regs, r1, r0, tmp64); -+ } else { -+ regs[r0] = tmp64; -+ } -+ break; -+ -+ case INDEX_op_qemu_st_a32_i32: -+ tci_args_ldst(insn, &r0, &r1, &oi, tb_ptr, &ptr); -+ taddr = (uint32_t)regs[r1]; -+ goto do_st_i32; -+ case INDEX_op_qemu_st_a64_i32: -+ tci_args_ldst(insn, &r0, &r1, &oi, tb_ptr, &ptr); -+ taddr = regs[r1]; -+ do_st_i32: -+ tci_qemu_st(env, taddr, regs[r0], oi, tb_ptr, ptr); -+ break; -+ -+ case INDEX_op_qemu_st_a32_i64: -+ tci_args_ldst(insn, &r0, &r1, &oi, tb_ptr, &ptr); -+ tmp64 = regs[r0]; -+ taddr = (uint32_t)regs[r1]; -+ goto do_st_i64; -+ case INDEX_op_qemu_st_a64_i64: -+ tci_args_ldst(insn, &r0, &r1, &oi, tb_ptr, &ptr); -+ tmp64 = regs[r0]; -+ taddr = regs[r1]; -+ do_st_i64: -+ tci_qemu_st(env, taddr, tmp64, oi, tb_ptr, ptr); -+ break; -+ -+ case INDEX_op_mb: -+ /* Ensure ordering for all kinds */ -+ smp_mb(); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ } -+} -+ -+uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, -+ const void *v_tb_ptr) -+{ -+ ctx.env = env; -+ ctx.tb_ptr = (uint32_t*)v_tb_ptr; -+ ctx.do_init = 1; -+ while (true) { -+ int tb_entry_ptr = (uint32_t)ctx.tb_ptr + export_vec_off; -+ uint32_t res; -+ if (*(int32_t*)tb_entry_ptr > 0) { -+ res = ((wasm_func_ptr)(*(uint32_t*)tb_entry_ptr))(&ctx); -+ } else if (*(int32_t *)tb_entry_ptr == WASM_TCI_ONLY_ENTRY) { -+ res = tcg_qemu_tb_exec_tci(env); -+ } else if (*(int32_t*)tb_entry_ptr > (-1 * INSTANTIATE_NUM)) { -+ *(int32_t*)tb_entry_ptr -= 1; -+ res = tcg_qemu_tb_exec_tci(env); -+ } else { -+ instantiate_wasm(); -+ res = ((wasm_func_ptr)(*(uint32_t*)tb_entry_ptr))(&ctx); -+ } -+ if ((uint32_t)ctx.tb_ptr == 0) { -+ return res; -+ } -+ } -+} -+ -+#endif -diff --git c/tcg/wasm32.h w/tcg/wasm32.h -new file mode 100644 -index 0000000000..a8b525abe3 ---- /dev/null -+++ w/tcg/wasm32.h -@@ -0,0 +1,49 @@ -+#ifndef TCG_WASM32_H -+#define TCG_WASM32_H -+ -+struct wasmContext { -+ // 0 -+ CPUArchState *env; -+ // 4 -+ uint64_t *stack; -+ // 8 -+ uint32_t *tb_ptr; -+ // 12 -+ uint32_t *tci_tb_ptr; -+ // 16 -+ uint32_t do_init; -+ // 20 -+ uint32_t done_flag; -+ // 24 -+ uint64_t *stack128; -+ // 28 -+ uint32_t unwinding; -+}; -+ -+#define ENV_OFF 0 -+#define STACK_OFF 4 -+#define TB_PTR_OFF 8 -+#define HELPER_RET_TB_PTR_OFF 12 -+#define DO_INIT_OFF 16 -+#define DONE_FLAG_OFF 20 -+#define STACK128_OFF 24 -+#define UNWINDING_OFF 28 -+ -+void set_done_flag(); -+ -+void set_unwinding_flag(); -+ -+int get_core_nums(); -+ -+void remove_tb(void *tb_ptr); -+ -+void flush_tb_instances(void); -+ -+void init_wasm32(); -+ -+extern __thread bool wasm_tci_only_tb; -+ -+#define INSTANTIATE_NUM 1500 -+#define WASM_TCI_ONLY_ENTRY (-2147483647 - 1) -+ -+#endif -diff --git c/tcg/wasm32/tcg-target-con-set.h w/tcg/wasm32/tcg-target-con-set.h -new file mode 100644 -index 0000000000..f50a6793b7 ---- /dev/null -+++ w/tcg/wasm32/tcg-target-con-set.h -@@ -0,0 +1,15 @@ -+/* -+ * C_On_Im(...) defines a constraint set with outputs and inputs. -+ * Each operand should be a sequence of constraint letters as defined by -+ * tcg-target-con-str.h; the constraint combination is inclusive or. -+ */ -+C_O0_I1(r) -+C_O0_I2(r, r) -+C_O0_I3(r, r, r) -+C_O0_I4(r, r, r, r) -+C_O1_I1(r, r) -+C_O1_I2(r, r, r) -+C_O1_I4(r, r, r, r, r) -+C_O2_I1(r, r, r) -+C_O2_I2(r, r, r, r) -+C_O2_I4(r, r, r, r, r, r) -diff --git c/tcg/wasm32/tcg-target-con-str.h w/tcg/wasm32/tcg-target-con-str.h -new file mode 100644 -index 0000000000..56d7aff291 ---- /dev/null -+++ w/tcg/wasm32/tcg-target-con-str.h -@@ -0,0 +1,5 @@ -+/* -+ * Define constraint letters for register sets: -+ * REGS(letter, register_mask) -+ */ -+REGS('r', MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) -diff --git c/tcg/wasm32/tcg-target-reg-bits.h w/tcg/wasm32/tcg-target-reg-bits.h -new file mode 100644 -index 0000000000..196395aef9 ---- /dev/null -+++ w/tcg/wasm32/tcg-target-reg-bits.h -@@ -0,0 +1,6 @@ -+#ifndef TCG_TARGET_REG_BITS_H -+#define TCG_TARGET_REG_BITS_H -+ -+#define TCG_TARGET_REG_BITS 64 -+ -+#endif -diff --git c/tcg/wasm32/tcg-target.c.inc w/tcg/wasm32/tcg-target.c.inc -new file mode 100644 -index 0000000000..053c941f99 ---- /dev/null -+++ w/tcg/wasm32/tcg-target.c.inc -@@ -0,0 +1,3826 @@ -+/* -+ * Tiny Code Generator for QEMU -+ * -+ * Copyright (c) 2018 SiFive, Inc -+ * Copyright (c) 2008-2009 Arnaud Patard -+ * Copyright (c) 2009 Aurelien Jarno -+ * Copyright (c) 2008 Fabrice Bellard -+ * Copyright (c) 2009, 2011 Stefan Weil -+ * -+ * Based on riscv/tcg-target.c.inc and tci/tcg-target.c -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "../wasm32.h" -+#include -+#include -+#include "../tcg-pool.c.inc" -+ -+static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) -+{ -+ switch (op) { -+ case INDEX_op_goto_ptr: -+ return C_O0_I1(r); -+ -+ case INDEX_op_ld8u_i32: -+ case INDEX_op_ld8s_i32: -+ case INDEX_op_ld16u_i32: -+ case INDEX_op_ld16s_i32: -+ case INDEX_op_ld_i32: -+ case INDEX_op_ld8u_i64: -+ case INDEX_op_ld8s_i64: -+ case INDEX_op_ld16u_i64: -+ case INDEX_op_ld16s_i64: -+ case INDEX_op_ld32u_i64: -+ case INDEX_op_ld32s_i64: -+ case INDEX_op_ld_i64: -+ case INDEX_op_not_i32: -+ case INDEX_op_not_i64: -+ case INDEX_op_neg_i32: -+ case INDEX_op_neg_i64: -+ case INDEX_op_ext8s_i32: -+ case INDEX_op_ext8s_i64: -+ case INDEX_op_ext16s_i32: -+ case INDEX_op_ext16s_i64: -+ case INDEX_op_ext8u_i32: -+ case INDEX_op_ext8u_i64: -+ case INDEX_op_ext16u_i32: -+ case INDEX_op_ext16u_i64: -+ case INDEX_op_ext32s_i64: -+ case INDEX_op_ext32u_i64: -+ case INDEX_op_ext_i32_i64: -+ case INDEX_op_extu_i32_i64: -+ case INDEX_op_bswap16_i32: -+ case INDEX_op_bswap16_i64: -+ case INDEX_op_bswap32_i32: -+ case INDEX_op_bswap32_i64: -+ case INDEX_op_bswap64_i64: -+ case INDEX_op_extract_i32: -+ case INDEX_op_extract_i64: -+ case INDEX_op_sextract_i32: -+ case INDEX_op_sextract_i64: -+ case INDEX_op_extrl_i64_i32: -+ case INDEX_op_extrh_i64_i32: -+ case INDEX_op_ctpop_i32: -+ case INDEX_op_ctpop_i64: -+ return C_O1_I1(r, r); -+ -+ case INDEX_op_st8_i32: -+ case INDEX_op_st16_i32: -+ case INDEX_op_st_i32: -+ case INDEX_op_st8_i64: -+ case INDEX_op_st16_i64: -+ case INDEX_op_st32_i64: -+ case INDEX_op_st_i64: -+ return C_O0_I2(r, r); -+ -+ case INDEX_op_div_i32: -+ case INDEX_op_div_i64: -+ case INDEX_op_divu_i32: -+ case INDEX_op_divu_i64: -+ case INDEX_op_rem_i32: -+ case INDEX_op_rem_i64: -+ case INDEX_op_remu_i32: -+ case INDEX_op_remu_i64: -+ case INDEX_op_add_i32: -+ case INDEX_op_add_i64: -+ case INDEX_op_sub_i32: -+ case INDEX_op_sub_i64: -+ case INDEX_op_mul_i32: -+ case INDEX_op_mul_i64: -+ case INDEX_op_and_i32: -+ case INDEX_op_and_i64: -+ case INDEX_op_andc_i32: -+ case INDEX_op_andc_i64: -+ case INDEX_op_eqv_i32: -+ case INDEX_op_eqv_i64: -+ case INDEX_op_nand_i32: -+ case INDEX_op_nand_i64: -+ case INDEX_op_nor_i32: -+ case INDEX_op_nor_i64: -+ case INDEX_op_or_i32: -+ case INDEX_op_or_i64: -+ case INDEX_op_orc_i32: -+ case INDEX_op_orc_i64: -+ case INDEX_op_xor_i32: -+ case INDEX_op_xor_i64: -+ case INDEX_op_shl_i32: -+ case INDEX_op_shl_i64: -+ case INDEX_op_shr_i32: -+ case INDEX_op_shr_i64: -+ case INDEX_op_sar_i32: -+ case INDEX_op_sar_i64: -+ case INDEX_op_rotl_i32: -+ case INDEX_op_rotl_i64: -+ case INDEX_op_rotr_i32: -+ case INDEX_op_rotr_i64: -+ case INDEX_op_setcond_i32: -+ case INDEX_op_setcond_i64: -+ case INDEX_op_deposit_i32: -+ case INDEX_op_deposit_i64: -+ case INDEX_op_clz_i32: -+ case INDEX_op_clz_i64: -+ case INDEX_op_ctz_i32: -+ case INDEX_op_ctz_i64: -+ return C_O1_I2(r, r, r); -+ -+ case INDEX_op_brcond_i32: -+ case INDEX_op_brcond_i64: -+ return C_O0_I2(r, r); -+ -+ case INDEX_op_add2_i32: -+ case INDEX_op_add2_i64: -+ case INDEX_op_sub2_i32: -+ case INDEX_op_sub2_i64: -+ return C_O2_I4(r, r, r, r, r, r); -+ -+ case INDEX_op_mulu2_i32: -+ case INDEX_op_mulu2_i64: -+ case INDEX_op_muls2_i32: -+ case INDEX_op_muls2_i64: -+ return C_O2_I2(r, r, r, r); -+ -+ case INDEX_op_movcond_i32: -+ case INDEX_op_movcond_i64: -+ return C_O1_I4(r, r, r, r, r); -+ -+ case INDEX_op_setcond2_i32: -+ return C_O1_I4(r, r, r, r, r); -+ case INDEX_op_brcond2_i32: -+ return C_O0_I4(r, r, r, r); -+ -+ case INDEX_op_qemu_ld_a32_i32: -+ case INDEX_op_qemu_ld_a64_i32: -+ return C_O1_I1(r, r); -+ -+ case INDEX_op_qemu_ld_a32_i64: -+ case INDEX_op_qemu_ld_a64_i64: -+ return C_O1_I1(r, r); -+ case INDEX_op_qemu_st_a32_i32: -+ case INDEX_op_qemu_st_a64_i32: -+ return C_O0_I2(r, r); -+ case INDEX_op_qemu_st_a32_i64: -+ case INDEX_op_qemu_st_a64_i64: -+ return C_O0_I2(r, r); -+ -+ case INDEX_op_muluh_i32: -+ case INDEX_op_mulsh_i32: -+ return C_O1_I2(r, r, r); -+ case INDEX_op_extract2_i32: -+ case INDEX_op_extract2_i64: -+ return C_O1_I2(r, r, r); -+ -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static const int tcg_target_reg_alloc_order[TCG_TARGET_NB_REGS] = { -+ TCG_REG_R0, -+ TCG_REG_R1, -+ TCG_REG_R2, -+ TCG_REG_R3, -+ TCG_REG_R4, -+ TCG_REG_R5, -+ TCG_REG_R6, -+ TCG_REG_R7, -+ TCG_REG_R8, -+ TCG_REG_R9, -+ TCG_REG_R10, -+ TCG_REG_R11, -+ TCG_REG_R12, -+ TCG_REG_R13, -+ TCG_REG_R14, -+ TCG_REG_R15, -+}; -+ -+#define NUM_OF_IARG_REGS 5 -+static const int tcg_target_call_iarg_regs[NUM_OF_IARG_REGS] = { -+ TCG_REG_R8, -+ TCG_REG_R9, -+ TCG_REG_R10, -+ TCG_REG_R11, -+ TCG_REG_R12, -+}; -+ -+static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) -+{ -+ tcg_debug_assert(kind == TCG_CALL_RET_NORMAL); -+ tcg_debug_assert(slot >= 0 && slot < 128 / TCG_TARGET_REG_BITS); -+ return TCG_REG_R0 + slot; -+} -+ -+#ifdef CONFIG_DEBUG_TCG -+static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { -+ "r00", -+ "r01", -+ "r02", -+ "r03", -+ "r04", -+ "r05", -+ "r06", -+ "r07", -+ "r08", -+ "r09", -+ "r10", -+ "r11", -+ "r12", -+ "r13", -+ "r14", -+ "r15", -+}; -+#endif -+ -+#define REG_INDEX_IARG_BASE 8 -+static const uint8_t tcg_target_reg_index[TCG_TARGET_NB_REGS] = { -+ 0, // TCG_REG_R0 -+ 1, // TCG_REG_R1 -+ 2, // TCG_REG_R2 -+ 3, // TCG_REG_R3 -+ 4, // TCG_REG_R4 -+ 5, // TCG_REG_R5 -+ 6, // TCG_REG_R6 -+ 7, // TCG_REG_R7 -+ 8, // TCG_REG_R8 -+ 9, // TCG_REG_R9 -+ 10, // TCG_REG_R10 -+ 11, // TCG_REG_R11 -+ 12, // TCG_REG_R12 -+ 13, // TCG_REG_R13 -+ 14, // TCG_REG_R14 -+ 15, // TCG_REG_R15 -+}; -+ -+#define BLOCK_PTR_IDX 16 -+ -+#define CTX_IDX 0 -+#define TMP32_LOCAL_ENV_IDX 1 -+#define TMP32_LOCAL_0_IDX 2 -+#define TMP64_0_IDX 3 -+#define TMP64_1_IDX 4 -+#define TMP64_2_IDX 5 -+#define TMP64_3_IDX 6 -+#define TMP64_4_IDX 7 -+ -+__thread bool env_cached = false; -+ -+// function index -+#define RETURN_CALL_IDX 0 -+#define FUNC_HELPER_CALL_IDX 1 -+#define FUNC_CALL_LD_HELPER_IDX 2 -+#define FUNC_CALL_ST_HELPER_IDX 3 -+ -+// table index -+#define HELPER_TABLE_IDX 0 -+ -+static inline void tcg_wasm_out8(TCGContext *s, uint32_t v) -+{ -+ tcg_sub_out8(s, v); -+} -+ -+static uintptr_t cur_wasm_ptr(TCGContext *s) -+{ -+ return (uintptr_t)cur_sub_buf_ptr(); -+} -+ -+static void tcg_wasm_out_leb128_sint32_t(TCGContext *s, int32_t v) { -+ bool more = true; -+ bool negative = (v < 0); -+ uint8_t b; -+ uint32_t low7 = 0x7f; -+ uint32_t uv = v; -+ while (more) { -+ b = uv & low7; -+ uv >>= 7; -+ if (negative) -+ uv |= (~0 << (32 - 7)); -+ if (((uv == 0) && ((b & 0x40) == 0)) || ((uv == -1) && ((b & 0x40) != 0))) -+ more = false; -+ else -+ b |= 0x80; -+ tcg_wasm_out8(s, b); -+ } -+} -+ -+static void tcg_wasm_out_leb128_sint64_t(TCGContext *s, int64_t v) { -+ bool more = true; -+ bool negative = (v < 0); -+ uint8_t b; -+ uint64_t low7 = 0x7f; -+ uint64_t uv = v; -+ while (more) { -+ b = uv & low7; -+ uv >>= 7; -+ if (negative) -+ uv |= ((int64_t)(~0) << (64 - 7)); -+ if (((uv == 0) && ((b & 0x40) == 0)) || (((int64_t)uv == -1) && ((b & 0x40) != 0))) -+ more = false; -+ else -+ b |= 0x80; -+ tcg_wasm_out8(s, b); -+ } -+} -+ -+static void tcg_wasm_out_leb128_uint32_t(TCGContext *s, uint32_t v) { -+ uint32_t low7 = 0x7f; -+ uint8_t b; -+ do { -+ b = v & low7; -+ v >>= 7; -+ if (v != 0) -+ b |= 0x80; -+ tcg_wasm_out8(s, b); -+ } while (v != 0); -+} -+ -+static void tcg_wasm_out_op_br(TCGContext *s, int i) -+{ -+ tcg_wasm_out8(s, 0x0c); -+ tcg_wasm_out8(s, i); -+} -+ -+static void tcg_wasm_out_op_if_noret(TCGContext *s) -+{ -+ tcg_wasm_out8(s, 0x04); -+ tcg_wasm_out8(s, 0x40); -+} -+ -+static void tcg_wasm_out_op_if_ret_i64(TCGContext *s) -+{ -+ tcg_wasm_out8(s, 0x04); -+ tcg_wasm_out8(s, 0x7e); -+} -+ -+static void tcg_wasm_out_op_if_ret_i32(TCGContext *s) -+{ -+ tcg_wasm_out8(s, 0x04); -+ tcg_wasm_out8(s, 0x7f); -+} -+ -+static void tcg_wasm_out_op_else(TCGContext *s) -+{ -+ tcg_wasm_out8(s, 0x05); -+} -+ -+static void tcg_wasm_out_op_end(TCGContext *s) -+{ -+ tcg_wasm_out8(s, 0x0b); -+} -+ -+static void tcg_wasm_out_op_i32_eqz(TCGContext *s){ tcg_wasm_out8(s, 0x45); } -+static void tcg_wasm_out_op_i32_eq(TCGContext *s){ tcg_wasm_out8(s, 0x46); } -+static void tcg_wasm_out_op_i32_and(TCGContext *s){ tcg_wasm_out8(s, 0x71); } -+static void tcg_wasm_out_op_i32_or(TCGContext *s){ tcg_wasm_out8(s, 0x72); } -+//static void tcg_wasm_out_op_i32_xor(TCGContext *s){ tcg_wasm_out8(s, 0x73); } -+static void tcg_wasm_out_op_i32_shl(TCGContext *s){ tcg_wasm_out8(s, 0x74); } -+static void tcg_wasm_out_op_i32_shr_s(TCGContext *s){ tcg_wasm_out8(s, 0x75); } -+static void tcg_wasm_out_op_i32_shr_u(TCGContext *s){ tcg_wasm_out8(s, 0x76); } -+static void tcg_wasm_out_op_i32_rotl(TCGContext *s){ tcg_wasm_out8(s, 0x77); } -+static void tcg_wasm_out_op_i32_rotr(TCGContext *s){ tcg_wasm_out8(s, 0x78); } -+static void tcg_wasm_out_op_i32_clz(TCGContext *s){ tcg_wasm_out8(s, 0x67); } -+static void tcg_wasm_out_op_i32_ctz(TCGContext *s){ tcg_wasm_out8(s, 0x68); } -+static void tcg_wasm_out_op_i32_popcnt(TCGContext *s){ tcg_wasm_out8(s, 0x69); } -+static void tcg_wasm_out_op_i32_add(TCGContext *s){ tcg_wasm_out8(s, 0x6a); } -+//static void tcg_wasm_out_op_i32_sub(TCGContext *s){ tcg_wasm_out8(s, 0x6b); } -+//static void tcg_wasm_out_op_i32_mul(TCGContext *s){ tcg_wasm_out8(s, 0x6c); } -+//static void tcg_wasm_out_op_i32_div_s(TCGContext *s){ tcg_wasm_out8(s, 0x6d); } -+//static void tcg_wasm_out_op_i32_div_u(TCGContext *s){ tcg_wasm_out8(s, 0x6e); } -+//static void tcg_wasm_out_op_i32_rem_s(TCGContext *s){ tcg_wasm_out8(s, 0x6f); } -+//static void tcg_wasm_out_op_i32_rem_u(TCGContext *s){ tcg_wasm_out8(s, 0x70); } -+static void tcg_wasm_out_op_i32_ne(TCGContext *s){ tcg_wasm_out8(s, 0x47); } -+//static void tcg_wasm_out_op_i32_le_u(TCGContext *s){ tcg_wasm_out8(s, 0x4d); } -+ -+static void tcg_wasm_out_op_i64_eqz(TCGContext *s){ tcg_wasm_out8(s, 0x50); } -+static void tcg_wasm_out_op_i64_eq(TCGContext *s){ tcg_wasm_out8(s, 0x51); } -+static void tcg_wasm_out_op_i64_and(TCGContext *s){ tcg_wasm_out8(s, 0x83); } -+static void tcg_wasm_out_op_i64_or(TCGContext *s){ tcg_wasm_out8(s, 0x84); } -+static void tcg_wasm_out_op_i64_xor(TCGContext *s){ tcg_wasm_out8(s, 0x85); } -+static void tcg_wasm_out_op_i64_shl(TCGContext *s){ tcg_wasm_out8(s, 0x86); } -+static void tcg_wasm_out_op_i64_shr_s(TCGContext *s){ tcg_wasm_out8(s, 0x87); } -+static void tcg_wasm_out_op_i64_shr_u(TCGContext *s){ tcg_wasm_out8(s, 0x88); } -+static void tcg_wasm_out_op_i64_rotl(TCGContext *s){ tcg_wasm_out8(s, 0x89); } -+static void tcg_wasm_out_op_i64_rotr(TCGContext *s){ tcg_wasm_out8(s, 0x8a); } -+static void tcg_wasm_out_op_i64_clz(TCGContext *s){ tcg_wasm_out8(s, 0x79); } -+static void tcg_wasm_out_op_i64_ctz(TCGContext *s){ tcg_wasm_out8(s, 0x7a); } -+static void tcg_wasm_out_op_i64_popcnt(TCGContext *s){ tcg_wasm_out8(s, 0x7b); } -+static void tcg_wasm_out_op_i64_add(TCGContext *s){ tcg_wasm_out8(s, 0x7c); } -+static void tcg_wasm_out_op_i64_sub(TCGContext *s){ tcg_wasm_out8(s, 0x7d); } -+static void tcg_wasm_out_op_i64_mul(TCGContext *s){ tcg_wasm_out8(s, 0x7e); } -+static void tcg_wasm_out_op_i64_div_s(TCGContext *s){ tcg_wasm_out8(s, 0x7f); } -+static void tcg_wasm_out_op_i64_div_u(TCGContext *s){ tcg_wasm_out8(s, 0x80); } -+static void tcg_wasm_out_op_i64_rem_s(TCGContext *s){ tcg_wasm_out8(s, 0x81); } -+static void tcg_wasm_out_op_i64_rem_u(TCGContext *s){ tcg_wasm_out8(s, 0x82); } -+//static void tcg_wasm_out_op_i64_ne(TCGContext *s){ tcg_wasm_out8(s, 0x52); } -+static void tcg_wasm_out_op_i64_le_u(TCGContext *s){ tcg_wasm_out8(s, 0x58); } -+static void tcg_wasm_out_op_i64_lt_u(TCGContext *s){ tcg_wasm_out8(s, 0x54); } -+static void tcg_wasm_out_op_i64_gt_u(TCGContext *s){ tcg_wasm_out8(s, 0x56); } -+ -+static void tcg_wasm_out_op_i32_wrap_i64(TCGContext *s){ tcg_wasm_out8(s, 0xa7); } -+ -+static void tcg_wasm_out_op_var(TCGContext *s, uint8_t instr, uint8_t i) -+{ -+ tcg_wasm_out8(s, instr); -+ tcg_wasm_out8(s, i); -+} -+ -+static void tcg_wasm_out_op_local_get(TCGContext *s, uint8_t i) -+{ -+ tcg_wasm_out_op_var(s, 0x20, i); -+} -+ -+static void tcg_wasm_out_op_local_set(TCGContext *s, uint8_t i) -+{ -+ tcg_wasm_out_op_var(s, 0x21, i); -+} -+ -+static void tcg_wasm_out_op_local_tee(TCGContext *s, uint8_t i) -+{ -+ tcg_wasm_out_op_var(s, 0x22, i); -+} -+ -+static void tcg_wasm_out_op_global_get(TCGContext *s, uint8_t i) -+{ -+ tcg_wasm_out_op_var(s, 0x23, i); -+} -+ -+static void tcg_wasm_out_op_global_set(TCGContext *s, uint8_t i) -+{ -+ if (i == tcg_target_reg_index[TCG_REG_R14]) { -+ env_cached = false; -+ } -+ tcg_wasm_out_op_var(s, 0x24, i); -+} -+ -+static void tcg_wasm_out_op_global_get_r_i32(TCGContext *s, TCGReg r0) -+{ -+ if (r0 == TCG_REG_R14) { -+ if (!env_cached) { -+ tcg_wasm_out_op_global_get(s, tcg_target_reg_index[r0]); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_local_tee(s, TMP32_LOCAL_ENV_IDX); -+ env_cached = true; -+ } else { -+ tcg_wasm_out_op_local_get(s, TMP32_LOCAL_ENV_IDX); -+ } -+ return; -+ } -+ tcg_wasm_out_op_global_get(s, tcg_target_reg_index[r0]); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+} -+ -+static void tcg_wasm_out_op_global_get_r(TCGContext *s, TCGReg r0) -+{ -+ tcg_wasm_out_op_global_get(s, tcg_target_reg_index[r0]); -+} -+ -+static void tcg_wasm_out_op_global_set_r(TCGContext *s, TCGReg r0) -+{ -+ tcg_wasm_out_op_global_set(s, tcg_target_reg_index[r0]); -+} -+ -+static void tcg_wasm_out_op_i32_const(TCGContext *s, int32_t v) -+{ -+ tcg_wasm_out8(s, 0x41); -+ tcg_wasm_out_leb128_sint32_t(s, v); -+} -+ -+static void tcg_wasm_out_op_i64_const(TCGContext *s, int64_t v) -+{ -+ tcg_wasm_out8(s, 0x42); -+ tcg_wasm_out_leb128_sint64_t(s, v); -+} -+ -+static void tcg_wasm_out_op_loadstore(TCGContext *s, uint8_t instr, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out8(s, instr); -+ tcg_wasm_out_leb128_uint32_t(s, a); -+ tcg_wasm_out_leb128_uint32_t(s, o); -+} -+ -+static void tcg_wasm_out_op_i64_store(TCGContext *s, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out_op_loadstore(s, 0x37, a, o); -+} -+ -+static void tcg_wasm_out_op_i32_store(TCGContext *s, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out_op_loadstore(s, 0x36, a, o); -+} -+ -+static void tcg_wasm_out_op_i64_store8(TCGContext *s, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out_op_loadstore(s, 0x3c, a, o); -+} -+ -+static void tcg_wasm_out_op_i64_store16(TCGContext *s, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out_op_loadstore(s, 0x3d, a, o); -+} -+ -+static void tcg_wasm_out_op_i64_store32(TCGContext *s, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out_op_loadstore(s, 0x3e, a, o); -+} -+ -+static void tcg_wasm_out_op_i64_load(TCGContext *s, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out_op_loadstore(s, 0x29, a, o); -+} -+ -+static void tcg_wasm_out_op_i32_load(TCGContext *s, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out_op_loadstore(s, 0x28, a, o); -+} -+ -+ static void tcg_wasm_out_op_i64_load8_s(TCGContext *s, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out_op_loadstore(s, 0x30, a, o); -+} -+ -+static void tcg_wasm_out_op_i64_load8_u(TCGContext *s, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out_op_loadstore(s, 0x31, a, o); -+} -+ -+static void tcg_wasm_out_op_i64_load16_s(TCGContext *s, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out_op_loadstore(s, 0x32, a, o); -+} -+ -+static void tcg_wasm_out_op_i64_load16_u(TCGContext *s, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out_op_loadstore(s, 0x33, a, o); -+} -+ -+static void tcg_wasm_out_op_i64_load32_u(TCGContext *s, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out_op_loadstore(s, 0x35, a, o); -+} -+ -+static void tcg_wasm_out_op_i64_load32_s(TCGContext *s, uint32_t a, uint32_t o) -+{ -+ tcg_wasm_out_op_loadstore(s, 0x34, a, o); -+} -+ -+static void tcg_wasm_out_op_return(TCGContext *s) -+{ -+ tcg_wasm_out8(s, 0x0f); -+} -+ -+static void tcg_wasm_out_op_call(TCGContext *s, uint32_t func_idx) -+{ -+ tcg_wasm_out8(s, 0x10); -+ tcg_wasm_out_leb128_uint32_t(s, func_idx); -+} -+ -+static void tcg_wasm_out_op_i64_extend_i32_u(TCGContext *s) -+{ -+ tcg_wasm_out8(s, 0xad); -+} -+ -+static void tcg_wasm_out_op_i64_extend_i32_s(TCGContext *s) -+{ -+ tcg_wasm_out8(s, 0xac); -+} -+ -+static void tcg_wasm_out_op_i64_extend8_s(TCGContext *s) -+{ -+ tcg_wasm_out8(s, 0xc2); -+} -+ -+static void tcg_wasm_out_op_i64_extend16_s(TCGContext *s) -+{ -+ tcg_wasm_out8(s, 0xc3); -+} -+ -+static void tcg_wasm_out_op_not(TCGContext *s){ -+ tcg_wasm_out_op_i64_const(s, -1); -+ tcg_wasm_out_op_i64_xor(s); -+} -+ -+static void tcg_wasm_out_op_set_r_as_i64(TCGContext *s, TCGReg al, TCGReg ah) -+{ -+ tcg_wasm_out_op_local_set(s, TMP64_4_IDX); -+ -+ // set lower bits -+ tcg_wasm_out_op_local_get(s, TMP64_4_IDX); -+ tcg_wasm_out_op_i64_const(s, 0xffffffff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_global_set_r(s, al); -+ -+ // set higher bits -+ tcg_wasm_out_op_local_get(s, TMP64_4_IDX); -+ tcg_wasm_out_op_i64_const(s, 32); -+ tcg_wasm_out_op_i64_shr_u(s); -+ tcg_wasm_out_op_i64_const(s, 0xffffffff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_global_set_r(s, ah); -+} -+ -+static const struct { -+ uint8_t i32; -+ uint8_t i64; -+} tcg_cond_to_inst[] = { -+ [TCG_COND_EQ] = { 0x46 /* i32.eq */ , 0x51 /* i64.eq */}, -+ [TCG_COND_NE] = { 0x47 /* i32.ne */ , 0x52 /* i64.ne */}, -+ [TCG_COND_LT] = { 0x48 /* i32.lt_s */ , 0x53 /* i64.lt_s */}, -+ [TCG_COND_GE] = { 0x4e /* i32.ge_s */ , 0x59 /* i64.ge_s */}, -+ [TCG_COND_LE] = { 0x4c /* i32.le_s */ , 0x57 /* i64.le_s */}, -+ [TCG_COND_GT] = { 0x4a /* i32.gt_s */ , 0x55 /* i64.gt_s */}, -+ [TCG_COND_LTU] = { 0x49 /* i32.lt_u */ , 0x54 /* i64.lt_u */}, -+ [TCG_COND_GEU] = { 0x4f /* i32.ge_u */ , 0x5a /* i64.ge_u */}, -+ [TCG_COND_LEU] = { 0x4d /* i32.le_u */ , 0x58 /* i64.le_u */}, -+ [TCG_COND_GTU] = { 0x4b /* i32.gt_u */ , 0x56 /* i64.gt_u */} -+}; -+ -+static void tcg_wasm_out_op_cond_i64(TCGContext *s, TCGCond cond, TCGReg arg1, TCGReg arg2) -+{ -+ uint8_t op = tcg_cond_to_inst[cond].i64; -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out8(s, op); -+} -+ -+static void tcg_wasm_out_op_cond_i32(TCGContext *s, TCGCond cond, TCGReg arg1, TCGReg arg2) -+{ -+ uint8_t op = tcg_cond_to_inst[cond].i32; -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out8(s, op); -+} -+ -+#define tcg_wasm_out_i64_calc(op) \ -+ static void tcg_wasm_out_i64_calc_##op(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2){ \ -+ tcg_wasm_out_op_global_get_r(s, arg1); \ -+ tcg_wasm_out_op_global_get_r(s, arg2); \ -+ tcg_wasm_out_op_i64_##op(s); \ -+ tcg_wasm_out_op_global_set_r(s, ret); \ -+ } -+tcg_wasm_out_i64_calc(and); -+tcg_wasm_out_i64_calc(or); -+tcg_wasm_out_i64_calc(xor); -+tcg_wasm_out_i64_calc(shl); -+tcg_wasm_out_i64_calc(shr_s); -+tcg_wasm_out_i64_calc(shr_u); -+tcg_wasm_out_i64_calc(rotl); -+tcg_wasm_out_i64_calc(rotr); -+tcg_wasm_out_i64_calc(add); -+tcg_wasm_out_i64_calc(sub); -+tcg_wasm_out_i64_calc(mul); -+tcg_wasm_out_i64_calc(div_s); -+tcg_wasm_out_i64_calc(div_u); -+tcg_wasm_out_i64_calc(rem_s); -+tcg_wasm_out_i64_calc(rem_u); -+ -+static void tcg_wasm_out_rem_s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2) { -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ tcg_wasm_out_op_i64_rem_s(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_rem_s(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_rem_u(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2) { -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i64_const(s, 0xffffffff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_const(s, 0xffffffff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_i64_rem_u(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_rem_u(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_div_s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2) { -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ tcg_wasm_out_op_i64_div_s(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_div_s(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_div_u(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2) { -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i64_const(s, 0xffffffff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_const(s, 0xffffffff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_i64_div_u(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_div_u(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_shl(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i64_const(s, 0xffffffff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_const(s, 31); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_i64_shl(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_shl(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_shr_u(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i64_const(s, 0xffffffff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_const(s, 31); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_i64_shr_u(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_shr_u(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_shr_s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_const(s, 31); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_i64_shr_s(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_shr_s(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+static void tcg_wasm_out_i32_rotl(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i32_rotl(s); -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_i32_rotr(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i32_rotr(s); -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_clz64(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i64_eqz(s); -+ tcg_wasm_out_op_if_ret_i64(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_else(s); -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i64_clz(s); -+ tcg_wasm_out_op_end(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_clz32(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i64_eqz(s); -+ tcg_wasm_out_op_if_ret_i32(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_else(s); -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i32_clz(s); -+ tcg_wasm_out_op_end(s); -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_ctz64(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i64_eqz(s); -+ tcg_wasm_out_op_if_ret_i64(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_else(s); -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i64_ctz(s); -+ tcg_wasm_out_op_end(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_ctz32(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i64_eqz(s); -+ tcg_wasm_out_op_if_ret_i32(s); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_else(s); -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i32_ctz(s); -+ tcg_wasm_out_op_end(s); -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_not(TCGContext *s, TCGReg ret, TCGReg arg){ -+ tcg_wasm_out_op_global_get_r(s, arg); -+ tcg_wasm_out_op_not(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_andc(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_not(s); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_orc(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_not(s); -+ tcg_wasm_out_op_i64_or(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_eqv(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_xor(s); -+ tcg_wasm_out_op_not(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_nand(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_not(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_nor(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2){ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_or(s); -+ tcg_wasm_out_op_not(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_neg(TCGContext *s, TCGReg ret, TCGReg arg){ -+ tcg_wasm_out_op_global_get_r(s, arg); -+ tcg_wasm_out_op_not(s); -+ tcg_wasm_out_op_i64_const(s, 1); -+ tcg_wasm_out_op_i64_add(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_ld(TCGContext *s, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_wasm_out_op_global_get_r_i32(s, base); -+ if ((int32_t)offset < 0) { -+ tcg_wasm_out_op_i32_const(s, (int32_t)offset); -+ tcg_wasm_out_op_i32_add(s); -+ offset = 0; -+ } -+ tcg_wasm_out_op_i64_load32_u(s, 0, (uint32_t)offset); -+ tcg_wasm_out_op_global_set_r(s, val); -+ break; -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r_i32(s, base); -+ if ((int32_t)offset < 0) { -+ tcg_wasm_out_op_i32_const(s, (int32_t)offset); -+ tcg_wasm_out_op_i32_add(s); -+ offset = 0; -+ } -+ tcg_wasm_out_op_i64_load(s, 0, (uint32_t)offset); -+ tcg_wasm_out_op_global_set_r(s, val); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_ld8s(TCGContext *s, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r_i32(s, base); -+ if ((int32_t)offset < 0) { -+ tcg_wasm_out_op_i32_const(s, (int32_t)offset); -+ tcg_wasm_out_op_i32_add(s); -+ offset = 0; -+ } -+ tcg_wasm_out_op_i64_load8_s(s, 0, (uint32_t)offset); -+ tcg_wasm_out_op_global_set_r(s, val); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_ld8u(TCGContext *s, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r_i32(s, base); -+ if ((int32_t)offset < 0) { -+ tcg_wasm_out_op_i32_const(s, (int32_t)offset); -+ tcg_wasm_out_op_i32_add(s); -+ offset = 0; -+ } -+ tcg_wasm_out_op_i64_load8_u(s, 0, (uint32_t)offset); -+ tcg_wasm_out_op_global_set_r(s, val); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_ld16s(TCGContext *s, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r_i32(s, base); -+ if ((int32_t)offset < 0) { -+ tcg_wasm_out_op_i32_const(s, (int32_t)offset); -+ tcg_wasm_out_op_i32_add(s); -+ offset = 0; -+ } -+ tcg_wasm_out_op_i64_load16_s(s, 0, (uint32_t)offset); -+ tcg_wasm_out_op_global_set_r(s, val); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_ld16u(TCGContext *s, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r_i32(s, base); -+ if ((int32_t)offset < 0) { -+ tcg_wasm_out_op_i32_const(s, (int32_t)offset); -+ tcg_wasm_out_op_i32_add(s); -+ offset = 0; -+ } -+ tcg_wasm_out_op_i64_load16_u(s, 0, (uint32_t)offset); -+ tcg_wasm_out_op_global_set_r(s, val); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_ld32s(TCGContext *s, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r_i32(s, base); -+ if ((int32_t)offset < 0) { -+ tcg_wasm_out_op_i32_const(s, (int32_t)offset); -+ tcg_wasm_out_op_i32_add(s); -+ offset = 0; -+ } -+ tcg_wasm_out_op_i64_load32_s(s, 0, (uint32_t)offset); -+ tcg_wasm_out_op_global_set_r(s, val); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_ld32u(TCGContext *s, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r_i32(s, base); -+ if ((int32_t)offset < 0) { -+ tcg_wasm_out_op_i32_const(s, (int32_t)offset); -+ tcg_wasm_out_op_i32_add(s); -+ offset = 0; -+ } -+ tcg_wasm_out_op_i64_load32_u(s, 0, (uint32_t)offset); -+ tcg_wasm_out_op_global_set_r(s, val); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_st(TCGContext *s, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_wasm_out_op_global_get_r_i32(s, base); -+ if ((int32_t)offset < 0) { -+ tcg_wasm_out_op_i32_const(s, (int32_t)offset); -+ tcg_wasm_out_op_i32_add(s); -+ offset = 0; -+ } -+ tcg_wasm_out_op_global_get_r(s, val); -+ tcg_wasm_out_op_i64_store32(s, 0, (uint32_t)offset); -+ break; -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r_i32(s, base); -+ if ((int32_t)offset < 0) { -+ tcg_wasm_out_op_i32_const(s, (int32_t)offset); -+ tcg_wasm_out_op_i32_add(s); -+ offset = 0; -+ } -+ tcg_wasm_out_op_global_get_r(s, val); -+ tcg_wasm_out_op_i64_store(s, 0, (uint32_t)offset); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_st8(TCGContext *s, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r_i32(s, base); -+ if ((int32_t)offset < 0) { -+ tcg_wasm_out_op_i32_const(s, (int32_t)offset); -+ tcg_wasm_out_op_i32_add(s); -+ offset = 0; -+ } -+ tcg_wasm_out_op_global_get_r(s, val); -+ tcg_wasm_out_op_i64_store8(s, 0, (uint32_t)offset); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_st16(TCGContext *s, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r_i32(s, base); -+ if ((int32_t)offset < 0) { -+ tcg_wasm_out_op_i32_const(s, (int32_t)offset); -+ tcg_wasm_out_op_i32_add(s); -+ offset = 0; -+ } -+ tcg_wasm_out_op_global_get_r(s, val); -+ tcg_wasm_out_op_i64_store16(s, 0, (uint32_t)offset); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_st32(TCGContext *s, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r_i32(s, base); -+ if ((int32_t)offset < 0) { -+ tcg_wasm_out_op_i32_const(s, (int32_t)offset); -+ tcg_wasm_out_op_i32_add(s); -+ offset = 0; -+ } -+ tcg_wasm_out_op_global_get_r(s, val); -+ tcg_wasm_out_op_i64_store32(s, 0, (uint32_t)offset); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static inline bool tcg_wasm_out_sti(TCGContext *s, TCGType type, TCGArg val, -+ TCGReg base, intptr_t offset) -+{ -+ return false; -+} -+ -+static bool tcg_wasm_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_wasm_out_op_global_get_r(s, arg); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_extend_i32_u(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r(s, arg); -+ tcg_wasm_out_op_global_set_r(s, ret); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ return true; -+} -+ -+static void tcg_wasm_out_movi(TCGContext *s, TCGType type, -+ TCGReg ret, tcg_target_long arg) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_wasm_out_op_i64_const(s, (int32_t)arg); -+ break; -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_i64_const(s, arg); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_ext8s(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r(s, rs); -+ tcg_wasm_out_op_i64_extend8_s(s); -+ tcg_wasm_out_op_global_set_r(s, rd); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_ext8u(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_wasm_out_op_global_get_r(s, rs); -+ tcg_wasm_out_op_i64_const(s, 0xff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_global_set_r(s, rd); -+} -+ -+static void tcg_wasm_out_ext16s(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ tcg_wasm_out_op_global_get_r(s, rs); -+ tcg_wasm_out_op_i64_extend16_s(s); -+ tcg_wasm_out_op_global_set_r(s, rd); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_ext16u(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_wasm_out_op_global_get_r(s, rs); -+ tcg_wasm_out_op_i64_const(s, 0xffff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_global_set_r(s, rd); -+} -+ -+static void tcg_wasm_out_ext32s(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_wasm_out_op_global_get_r(s, rs); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ tcg_wasm_out_op_global_set_r(s, rd); -+} -+ -+static void tcg_wasm_out_ext32u(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_wasm_out_op_global_get_r(s, rs); -+ tcg_wasm_out_op_i64_const(s, 0xffffffff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_global_set_r(s, rd); -+} -+ -+static void tcg_wasm_out_exts_i32_i64(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_wasm_out_ext32s(s, rd, rs); -+} -+ -+static void tcg_wasm_out_extu_i32_i64(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_wasm_out_ext32u(s, rd, rs); -+} -+ -+static void tcg_wasm_out_extrl_i64_i32(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_wasm_out_op_global_get_r(s, rs); -+ tcg_wasm_out_op_i64_const(s, 0xffffffff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_global_set_r(s, rd); -+} -+ -+static void tcg_wasm_out_extrh_i64_i32(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_wasm_out_op_global_get_r(s, rs); -+ tcg_wasm_out_op_i64_const(s, 32); -+ tcg_wasm_out_op_i64_shr_u(s); -+ tcg_wasm_out_op_global_set_r(s, rd); -+} -+ -+static void tcg_wasm_out_setcond_i32(TCGContext *s, TCGCond cond, TCGReg ret, -+ TCGReg arg1, TCGReg arg2) -+{ -+ tcg_wasm_out_op_cond_i32(s, cond, arg1, arg2); -+ tcg_wasm_out_op_i64_extend_i32_u(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_setcond_i64(TCGContext *s, TCGCond cond, TCGReg ret, -+ TCGReg arg1, TCGReg arg2) -+{ -+ tcg_wasm_out_op_cond_i64(s, cond, arg1, arg2); -+ tcg_wasm_out_op_i64_extend_i32_u(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_movcond_i32(TCGContext *s, TCGCond cond, TCGReg ret, -+ TCGReg c1, TCGReg c2, TCGReg v1, TCGReg v2) -+{ -+ tcg_wasm_out_op_cond_i32(s, cond, c1, c2); -+ tcg_wasm_out_op_if_ret_i64(s); -+ tcg_wasm_out_op_global_get_r(s, v1); -+ tcg_wasm_out_op_else(s); -+ tcg_wasm_out_op_global_get_r(s, v2); -+ tcg_wasm_out_op_end(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_movcond_i64(TCGContext *s, TCGCond cond, TCGReg ret, -+ TCGReg c1, TCGReg c2, TCGReg v1, TCGReg v2) -+{ -+ tcg_wasm_out_op_cond_i64(s, cond, c1, c2); -+ tcg_wasm_out_op_if_ret_i64(s); -+ tcg_wasm_out_op_global_get_r(s, v1); -+ tcg_wasm_out_op_else(s); -+ tcg_wasm_out_op_global_get_r(s, v2); -+ tcg_wasm_out_op_end(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_add2(TCGContext *s, TCGReg retl, TCGReg reth, -+ TCGReg al, TCGReg ah, TCGReg bl, TCGReg bh) -+{ -+ // add higer -+ tcg_wasm_out_op_global_get_r(s, ah); -+ tcg_wasm_out_op_global_get_r(s, bh); -+ tcg_wasm_out_op_i64_add(s); -+ -+ // add lower -+ tcg_wasm_out_op_global_get_r(s, al); -+ tcg_wasm_out_op_global_get_r(s, bl); -+ tcg_wasm_out_op_i64_add(s); -+ -+ // get carry -+ if ((al == retl) && (bl == retl)) { -+ tcg_wasm_out_op_local_set(s, TMP64_0_IDX); -+ tcg_wasm_out_op_local_get(s, TMP64_0_IDX); -+ tcg_wasm_out_op_global_get_r(s, al); -+ tcg_wasm_out_op_i64_lt_u(s); -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ tcg_wasm_out_op_local_get(s, TMP64_0_IDX); -+ tcg_wasm_out_op_global_set_r(s, retl); -+ } else { -+ tcg_wasm_out_op_global_set_r(s, retl); -+ tcg_wasm_out_op_global_get_r(s, retl); -+ if (al == retl) { -+ tcg_wasm_out_op_global_get_r(s, bl); -+ } else { -+ tcg_wasm_out_op_global_get_r(s, al); -+ } -+ tcg_wasm_out_op_i64_lt_u(s); -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ } -+ -+ // add carry to higher -+ tcg_wasm_out_op_i64_add(s); -+ tcg_wasm_out_op_global_set_r(s, reth); -+} -+ -+static void tcg_wasm_out_sub2(TCGContext *s, TCGReg retl, TCGReg reth, -+ TCGReg al, TCGReg ah, TCGReg bl, TCGReg bh) -+{ -+ // sub higher -+ tcg_wasm_out_op_global_get_r(s, ah); -+ tcg_wasm_out_op_global_get_r(s, bh); -+ tcg_wasm_out_op_i64_sub(s); -+ -+ // sub lower -+ tcg_wasm_out_op_global_get_r(s, al); -+ tcg_wasm_out_op_global_get_r(s, bl); -+ tcg_wasm_out_op_i64_sub(s); -+ -+ // get underflow -+ if (al == retl) { -+ tcg_wasm_out_op_local_set(s, TMP64_0_IDX); -+ -+ tcg_wasm_out_op_local_get(s, TMP64_0_IDX); -+ tcg_wasm_out_op_global_get_r(s, al); -+ tcg_wasm_out_op_i64_gt_u(s); -+ -+ tcg_wasm_out_op_local_get(s, TMP64_0_IDX); -+ tcg_wasm_out_op_global_set_r(s, retl); -+ } else { -+ tcg_wasm_out_op_global_set_r(s, retl); -+ -+ tcg_wasm_out_op_global_get_r(s, retl); -+ tcg_wasm_out_op_global_get_r(s, al); -+ tcg_wasm_out_op_i64_gt_u(s); -+ } -+ -+ tcg_wasm_out_op_i64_sub(s); -+ tcg_wasm_out_op_global_set_r(s, reth); -+} -+ -+static void tcg_wasm_out_mulu2_i32(TCGContext *s, TCGReg retl, TCGReg reth, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_mul(s); -+ tcg_wasm_out_op_set_r_as_i64(s, retl, reth); -+} -+ -+static void tcg_wasm_out_muls2_i32(TCGContext *s, TCGReg retl, TCGReg reth, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_mul(s); -+ tcg_wasm_out_op_set_r_as_i64(s, retl, reth); -+} -+ -+static void tcg_wasm_out_muluh_i32(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_mul(s); -+ tcg_wasm_out_op_i64_const(s, 32); -+ tcg_wasm_out_op_i64_shr_u(s); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_mulsh_i32(TCGContext *s, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_mul(s); -+ tcg_wasm_out_op_i64_const(s, 32); -+ tcg_wasm_out_op_i64_shr_u(s); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_global_set_r(s, ret); -+} -+ -+static void tcg_wasm_out_ctpop_i32(TCGContext *s, TCGReg dest, TCGReg src) -+{ -+ tcg_wasm_out_op_global_get_r(s, src); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i32_popcnt(s); -+ tcg_wasm_out_op_global_set_r(s, dest); -+} -+ -+static void tcg_wasm_out_ctpop_i64(TCGContext *s, TCGReg dest, TCGReg src) -+{ -+ tcg_wasm_out_op_global_get_r(s, src); -+ tcg_wasm_out_op_i64_popcnt(s); -+ tcg_wasm_out_op_global_set_r(s, dest); -+} -+ -+static void tcg_wasm_out_deposit_i32(TCGContext *s, TCGReg dest, TCGReg arg1, TCGReg arg2, int pos, int len) -+{ -+ int32_t mask = ((1< 0) { -+ tcg_wasm_out_op_i64_const(s, sl); -+ tcg_wasm_out_op_i64_shl(s); -+ } -+ tcg_wasm_out_op_i64_const(s, rs); -+ if (sign) { -+ tcg_wasm_out_op_i64_shr_s(s); -+ } else { -+ tcg_wasm_out_op_i64_shr_u(s); -+ } -+ tcg_wasm_out_op_global_set_r(s, dest); -+} -+ -+static void tcg_wasm_out_extract2_i32(TCGContext *s, TCGReg dest, TCGReg arg1, TCGReg arg2, int pos) -+{ -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_const(s, 32-pos); -+ tcg_wasm_out_op_i64_shl(s); -+ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i64_const(s, 0xffffffff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_i64_const(s, pos); -+ tcg_wasm_out_op_i64_shr_u(s); -+ -+ tcg_wasm_out_op_i64_or(s); -+ -+ tcg_wasm_out_op_i64_const(s, 0xffffffff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_global_set_r(s, dest); -+} -+ -+static void tcg_wasm_out_extract2_i64(TCGContext *s, TCGReg dest, TCGReg arg1, TCGReg arg2, int pos) -+{ -+ tcg_wasm_out_op_global_get_r(s, arg2); -+ tcg_wasm_out_op_i64_const(s, 64-pos); -+ tcg_wasm_out_op_i64_shl(s); -+ -+ tcg_wasm_out_op_global_get_r(s, arg1); -+ tcg_wasm_out_op_i64_const(s, pos); -+ tcg_wasm_out_op_i64_shr_u(s); -+ -+ tcg_wasm_out_op_i64_or(s); -+ tcg_wasm_out_op_global_set_r(s, dest); -+} -+ -+static void tcg_wasm_out_bswap64(TCGContext *s, TCGReg dest, TCGReg src, int flags) -+{ -+ tcg_wasm_out_op_global_get_r(s, src); // ABCDEFGH -+ tcg_wasm_out_op_i64_const(s, 32); -+ tcg_wasm_out_op_i64_rotr(s); -+ tcg_wasm_out_op_local_set(s, TMP64_0_IDX); // EFGHABCD -+ -+ tcg_wasm_out_op_local_get(s, TMP64_0_IDX); -+ tcg_wasm_out_op_i64_const(s, 0xff000000ff000000); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_i64_const(s, 24); -+ tcg_wasm_out_op_i64_shr_u(s); // ___E___A -+ -+ tcg_wasm_out_op_local_get(s, TMP64_0_IDX); -+ tcg_wasm_out_op_i64_const(s, 0x00ff000000ff0000); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_i64_const(s, 8); -+ tcg_wasm_out_op_i64_shr_u(s); // __F___B_ -+ -+ tcg_wasm_out_op_i64_or(s); -+ -+ tcg_wasm_out_op_local_get(s, TMP64_0_IDX); -+ tcg_wasm_out_op_i64_const(s, 0x0000ff000000ff00); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_i64_const(s, 8); -+ tcg_wasm_out_op_i64_shl(s); // _G___C__ -+ -+ tcg_wasm_out_op_local_get(s, TMP64_0_IDX); -+ tcg_wasm_out_op_i64_const(s, 0x000000ff000000ff); -+ tcg_wasm_out_op_i64_and(s); -+ tcg_wasm_out_op_i64_const(s, 24); -+ tcg_wasm_out_op_i64_shl(s); // H___D___ -+ -+ tcg_wasm_out_op_i64_or(s); -+ -+ tcg_wasm_out_op_i64_or(s); // HGFEDCBA -+ tcg_wasm_out_op_global_set_r(s, dest); -+} -+ -+static void tcg_wasm_out_bswap32(TCGContext *s, TCGReg dest, TCGReg src, int flags) -+{ -+ tcg_wasm_out_op_global_get_r(s, src); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_local_set(s, TMP32_LOCAL_0_IDX); -+ -+ tcg_wasm_out_op_local_get(s, TMP32_LOCAL_0_IDX); // ABCD -+ tcg_wasm_out_op_i32_const(s, 16); -+ tcg_wasm_out_op_i32_rotr(s); -+ tcg_wasm_out_op_local_set(s, TMP32_LOCAL_0_IDX); // CDAB -+ -+ tcg_wasm_out_op_local_get(s, TMP32_LOCAL_0_IDX); -+ tcg_wasm_out_op_i32_const(s, 0xff00ff00); -+ tcg_wasm_out_op_i32_and(s); -+ tcg_wasm_out_op_i32_const(s, 8); -+ tcg_wasm_out_op_i32_shr_u(s); // _C_A -+ -+ tcg_wasm_out_op_local_get(s, TMP32_LOCAL_0_IDX); -+ tcg_wasm_out_op_i32_const(s, 0x00ff00ff); -+ tcg_wasm_out_op_i32_and(s); -+ tcg_wasm_out_op_i32_const(s, 8); -+ tcg_wasm_out_op_i32_shl(s); // D_B_ -+ -+ tcg_wasm_out_op_i32_or(s); // DCBA -+ tcg_wasm_out_op_i64_extend_i32_u(s); -+ tcg_wasm_out_op_global_set_r(s, dest); -+} -+ -+static void tcg_wasm_out_bswap16(TCGContext *s, TCGReg dest, TCGReg src, int flags) -+{ -+ tcg_wasm_out_op_global_get_r(s, src); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_local_set(s, TMP32_LOCAL_0_IDX); -+ -+ tcg_wasm_out_op_local_get(s, TMP32_LOCAL_0_IDX); // __AB -+ tcg_wasm_out_op_i32_const(s, 8); -+ tcg_wasm_out_op_i32_rotr(s); -+ tcg_wasm_out_op_local_set(s, TMP32_LOCAL_0_IDX); // B__A -+ -+ tcg_wasm_out_op_local_get(s, TMP32_LOCAL_0_IDX); -+ tcg_wasm_out_op_i32_const(s, 0x000000ff); -+ tcg_wasm_out_op_i32_and(s); // ___A -+ -+ tcg_wasm_out_op_local_get(s, TMP32_LOCAL_0_IDX); -+ tcg_wasm_out_op_i32_const(s, 0xff000000); -+ tcg_wasm_out_op_i32_and(s); -+ tcg_wasm_out_op_i32_const(s, 16); -+ if (flags & TCG_BSWAP_OS) { -+ tcg_wasm_out_op_i32_shr_s(s); // SSB_ -+ } else { -+ tcg_wasm_out_op_i32_shr_u(s); // 00B_ -+ } -+ -+ tcg_wasm_out_op_i32_or(s); // **BA -+ tcg_wasm_out_op_i64_extend_i32_u(s); -+ tcg_wasm_out_op_global_set_r(s, dest); -+} -+ -+static void tcg_wasm_out_ctx_i32_store_const(TCGContext *s, int off, int32_t v) -+{ -+ tcg_wasm_out_op_local_get(s, CTX_IDX); -+ tcg_wasm_out_op_i32_const(s, v); -+ tcg_wasm_out_op_i32_store(s, 0, off); -+} -+ -+static void tcg_wasm_out_ctx_i32_store_r(TCGContext *s, int off, TCGReg r0) -+{ -+ tcg_wasm_out_op_local_get(s, CTX_IDX); -+ tcg_wasm_out_op_global_get_r(s, r0); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i32_store(s, 0, off); -+} -+ -+static void tcg_wasm_out_ctx_i32_load(TCGContext *s, int off) -+{ -+ tcg_wasm_out_op_local_get(s, CTX_IDX); -+ tcg_wasm_out_op_i32_load(s, 0, off); -+} -+ -+static void tcg_wasm_out_label_idx(TCGContext *s, int label) -+{ -+ int block_idx = wasm_alloc_block_idx(s); -+ wasm_add_label_context(s, label, block_idx); -+ -+ tcg_wasm_out_op_end(s); // end if of the previous block -+ -+ // following block -+ tcg_wasm_out_op_global_get(s, BLOCK_PTR_IDX); -+ tcg_wasm_out_op_i64_const(s, block_idx); -+ tcg_wasm_out_op_i64_le_u(s); -+ tcg_wasm_out_op_if_noret(s); -+ env_cached = false; -+} -+ -+__thread int current_label[100]; -+__thread int current_label_pos; -+ -+static void tcg_out_label_cb(TCGContext *s, TCGLabel *l) -+{ -+ current_label[current_label_pos++] = l->id; -+ tcg_debug_assert(current_label_pos < 100); -+ tcg_wasm_out_label_idx(s, l->id + 1); -+} -+ -+static void tcg_wasm_out_op_br_to_label(TCGContext *s, TCGLabel *l, bool br_if) -+{ -+ int toploop_depth = 1; -+ if (br_if) { -+ tcg_wasm_out_op_if_noret(s); -+ toploop_depth++; -+ } -+ tcg_wasm_out8(s, 0x42); // i64.const -+ wasm_add_label_block_ptr_placeholder(l->id + 1, cur_wasm_ptr(s)); -+ tcg_wasm_out8(s, 0x80); // filled before instantiation -+ tcg_wasm_out8(s, 0x80); -+ tcg_wasm_out8(s, 0x80); -+ tcg_wasm_out8(s, 0x80); -+ tcg_wasm_out8(s, 0x00); -+ tcg_wasm_out_op_global_set(s, BLOCK_PTR_IDX); -+ bool found = false; -+ for (int i = 0; i < current_label_pos; i++) { -+ if (current_label[i] == l->id) { -+ found = true; -+ break; -+ } -+ } -+ if (found) { -+ tcg_wasm_out_op_br(s, toploop_depth); // br to the top of loop -+ } else { -+ tcg_wasm_out_op_br(s, toploop_depth - 1); // br to the end of the current block -+ } -+ if (br_if) { -+ tcg_wasm_out_op_end(s); -+ } -+} -+ -+static void tcg_wasm_out_br(TCGContext *s, TCGLabel *l) -+{ -+ tcg_wasm_out_op_br_to_label(s, l, false); -+} -+ -+static void tcg_wasm_out_brcond_i32(TCGContext *s, TCGCond cond, TCGReg arg1, -+ TCGReg arg2, TCGLabel *l) -+{ -+ tcg_wasm_out_op_cond_i32(s, cond, arg1, arg2); -+ tcg_wasm_out_op_br_to_label(s, l, true); -+} -+ -+static void tcg_wasm_out_brcond_i64(TCGContext *s, TCGCond cond, TCGReg arg1, -+ TCGReg arg2, TCGLabel *l) -+{ -+ tcg_wasm_out_op_cond_i64(s, cond, arg1, arg2); -+ tcg_wasm_out_op_br_to_label(s, l, true); -+} -+ -+static void tcg_wasm_out_exit_tb(TCGContext *s, uintptr_t arg) -+{ -+ tcg_wasm_out_ctx_i32_store_const(s, TB_PTR_OFF, 0); -+ tcg_wasm_out_op_i32_const(s, (int32_t)arg); -+ tcg_wasm_out_op_return(s); -+} -+ -+static void tcg_wasm_out_goto_ptr(TCGContext *s, TCGReg arg) -+{ -+ tcg_wasm_out_op_global_get_r(s, arg); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_ctx_i32_load(s, TB_PTR_OFF); -+ tcg_wasm_out_op_i32_eq(s); -+ tcg_wasm_out_op_if_noret(s); -+ tcg_wasm_out_op_i64_const(s, 0); -+ tcg_wasm_out_op_global_set(s, BLOCK_PTR_IDX); -+ tcg_wasm_out_op_br(s, 2); // br to the top of loop -+ tcg_wasm_out_op_end(s); -+ -+ tcg_wasm_out_ctx_i32_store_r(s, TB_PTR_OFF, arg); -+ tcg_wasm_out_ctx_i32_store_const(s, DO_INIT_OFF, 1); -+ tcg_wasm_out_op_i32_const(s, 0); -+ tcg_wasm_out_op_return(s); -+} -+ -+static void tcg_wasm_out_goto_tb(TCGContext *s, int which) -+{ -+ tcg_wasm_out_op_i32_const(s, (int32_t)get_jmp_target_addr(s, which)); -+ tcg_wasm_out_op_i32_load(s, 0, 0); -+ tcg_wasm_out_op_local_set(s, TMP32_LOCAL_0_IDX); -+ -+ tcg_wasm_out_op_local_get(s, TMP32_LOCAL_0_IDX); -+ tcg_wasm_out_op_i32_const(s, 0); -+ tcg_wasm_out_op_i32_ne(s); -+ tcg_wasm_out_op_if_noret(s); -+ -+ tcg_wasm_out_op_local_get(s, TMP32_LOCAL_0_IDX); -+ tcg_wasm_out_ctx_i32_load(s, TB_PTR_OFF); -+ tcg_wasm_out_op_i32_eq(s); -+ tcg_wasm_out_op_if_noret(s); -+ tcg_wasm_out_op_i64_const(s, 0); -+ tcg_wasm_out_op_global_set(s, BLOCK_PTR_IDX); -+ tcg_wasm_out_op_br(s, 3); // br to the top of loop -+ tcg_wasm_out_op_end(s); -+ -+ // store jmp target address to buf -+ tcg_wasm_out_op_local_get(s, CTX_IDX); -+ tcg_wasm_out_op_local_get(s, TMP32_LOCAL_0_IDX); -+ tcg_wasm_out_op_i32_store(s, 0, TB_PTR_OFF); -+ tcg_wasm_out_ctx_i32_store_const(s, DO_INIT_OFF, 1); -+ -+ tcg_wasm_out_op_i32_const(s, 0); -+ tcg_wasm_out_op_return(s); -+ tcg_wasm_out_op_end(s); -+} -+ -+static void push_arg_i64(TCGContext *s, int *reg_idx, int *stack_offset) { -+ if (*reg_idx < NUM_OF_IARG_REGS) { -+ tcg_wasm_out_op_global_get_r(s, REG_INDEX_IARG_BASE + *reg_idx); // arg register -+ int addend = 1; -+ *reg_idx = *reg_idx + addend; -+ } else { -+ tcg_wasm_out_op_global_get_r(s, TCG_REG_CALL_STACK); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_load(s, 0, *stack_offset); -+ int addend = 8; -+ *stack_offset = *stack_offset + addend; -+ } -+} -+ -+void gen_func_wrapper_code(TCGContext *s, const tcg_insn_unit *func, const TCGHelperInfo *info, int func_idx) -+{ -+ int nargs; -+ unsigned typemask = info->typemask; -+ int rettype = typemask & 7; -+ -+ if (rettype == dh_typecode_i128) { -+ // receive 128bit return value via the stack buffer -+ tcg_wasm_out_op_global_get_r(s, TCG_REG_CALL_STACK); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ } -+ -+ nargs = 32 - clz32(typemask >> 3); -+ nargs = DIV_ROUND_UP(nargs, 3); -+ int stack_offset = 0; -+ int reg_idx = 0; -+ int stack128_base = 0; -+ bool cached_128base = false; -+ for (int j = 0; j < nargs; ++j) { -+ int typecode = extract32(typemask, (j + 1) * 3, 3); -+ if (typecode == dh_typecode_void) { -+ continue; -+ } -+ switch (typecode) { -+ case dh_typecode_i32: -+ case dh_typecode_s32: -+ case dh_typecode_ptr: -+ push_arg_i64(s, ®_idx, &stack_offset); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ break; -+ case dh_typecode_i64: -+ case dh_typecode_s64: -+ push_arg_i64(s, ®_idx, &stack_offset); -+ break; -+ case dh_typecode_i128: -+ // copy data to 128stack -+ if (!cached_128base) { -+ tcg_wasm_out_ctx_i32_load(s, STACK128_OFF); -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ tcg_wasm_out_op_local_set(s, TMP64_0_IDX); -+ cached_128base = true; -+ } -+ -+ // push current 128stack pointer -+ tcg_wasm_out_op_local_get(s, TMP64_0_IDX); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i32_const(s, stack128_base); -+ tcg_wasm_out_op_i32_add(s); -+ -+ tcg_wasm_out_op_local_get(s, TMP64_0_IDX); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ push_arg_i64(s, ®_idx, &stack_offset); -+ tcg_wasm_out_op_i64_store(s, 0, stack128_base); -+ stack128_base += 8; -+ -+ tcg_wasm_out_op_local_get(s, TMP64_0_IDX); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ push_arg_i64(s, ®_idx, &stack_offset); -+ tcg_wasm_out_op_i64_store(s, 0, stack128_base); -+ stack128_base += 8; -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ } -+ -+ tcg_wasm_out_op_call(s, func_idx); -+ -+ stack_offset = 0; -+ if (rettype != dh_typecode_void) { -+ switch (rettype) { -+ case dh_typecode_i32: -+ case dh_typecode_s32: -+ case dh_typecode_ptr: -+ tcg_wasm_out_op_i64_extend_i32_s(s); -+ tcg_wasm_out_op_global_set_r(s, TCG_REG_R0); -+ break; -+ case dh_typecode_i64: -+ case dh_typecode_s64: -+ tcg_wasm_out_op_global_set_r(s, TCG_REG_R0); -+ break; -+ case dh_typecode_i128: -+ tcg_wasm_out_op_global_get_r(s, TCG_REG_CALL_STACK); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_load(s, 0, stack_offset); -+ tcg_wasm_out_op_global_set_r(s, TCG_REG_R0); -+ stack_offset += 8; -+ -+ tcg_wasm_out_op_global_get_r(s, TCG_REG_CALL_STACK); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_load(s, 0, stack_offset); -+ tcg_wasm_out_op_global_set_r(s, TCG_REG_R1); -+ stack_offset += 8; -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ } -+ -+ return; -+} -+ -+static void gen_func_type(TCGContext *s, const TCGHelperInfo *info) -+{ -+ int nargs; -+ unsigned typemask = info->typemask; -+ int rettype = typemask & 7; -+ uint8_t * buf_start = wasm_get_helper_types_begin(s); -+ uint8_t * buf_ptr = buf_start; -+ nargs = 32 - clz32(typemask >> 3); -+ nargs = DIV_ROUND_UP(nargs, 3); -+ -+ *buf_ptr++ = 0x60; -+ uint8_t * buf_ptr_vec_size = buf_ptr; -+ *buf_ptr += 0x80; -+ *buf_ptr += 0x80; -+ *buf_ptr += 0x80; -+ *buf_ptr += 0x80; -+ *buf_ptr += 0x00; -+ *buf_ptr++ = 0; // vector size (placeholder) -+ -+ int vec_size = 0; -+ -+ if (rettype == dh_typecode_i128) { -+ *buf_ptr++ = 0x7f; // i32 (stack buffer pointer) -+ vec_size++; -+ } -+ -+ for (int j = 0; j < nargs; ++j) { -+ int typecode = extract32(typemask, (j + 1) * 3, 3); -+ if (typecode == dh_typecode_void) { -+ continue; -+ } -+ switch (typecode) { -+ case dh_typecode_i32: -+ case dh_typecode_s32: -+ case dh_typecode_ptr: -+ *buf_ptr++ = 0x7f; -+ vec_size++; -+ break; -+ case dh_typecode_i64: -+ case dh_typecode_s64: -+ *buf_ptr++ = 0x7e; -+ vec_size++; -+ break; -+ case dh_typecode_i128: -+ *buf_ptr++ = 0x7f; -+ vec_size++; -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ } -+ fill_uint32_leb128((uintptr_t)buf_ptr_vec_size, vec_size); // fill size -+ -+ if ((rettype == dh_typecode_void) || (rettype == dh_typecode_i128)) { -+ *buf_ptr++ = 0x0; // no return value -+ } else { -+ *buf_ptr++ = 0x1; -+ switch (rettype) { -+ case dh_typecode_i32: -+ case dh_typecode_s32: -+ case dh_typecode_ptr: -+ *buf_ptr++ = 0x7f; -+ break; -+ case dh_typecode_i64: -+ case dh_typecode_s64: -+ *buf_ptr++ = 0x7e; -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ } -+ int sz = (uint32_t)(buf_ptr - buf_start); -+ wasm_add_helper_types_pos(s, sz); -+ return; -+} -+ -+static void gen_func_type_qemu_ld(TCGContext *s, uint32_t oi) -+{ -+ uint8_t * buf_start = wasm_get_helper_types_begin(s); -+ uint8_t * buf_ptr = buf_start; -+ *buf_ptr++ = 0x60; -+ *buf_ptr++ = 0x4; -+ *buf_ptr++ = 0x7f; -+ *buf_ptr++ = 0x7e; -+ *buf_ptr++ = 0x7f; -+ *buf_ptr++ = 0x7f; -+ *buf_ptr++ = 0x1; -+ MemOp mop = get_memop(oi); -+ switch (mop & MO_SSIZE) { -+ case MO_UQ: -+ *buf_ptr++ = 0x7e; -+ break; -+ default: -+ *buf_ptr++ = 0x7e; -+ break; -+ } -+ int sz = (uint32_t)(buf_ptr - buf_start); -+ wasm_add_helper_types_pos(s, sz); -+} -+ -+static void gen_func_type_qemu_st(TCGContext *s, uint32_t oi) -+{ -+ uint8_t * buf_start = wasm_get_helper_types_begin(s); -+ uint8_t * buf_ptr = buf_start; -+ *buf_ptr++ = 0x60; -+ *buf_ptr++ = 0x5; -+ *buf_ptr++ = 0x7f; -+ *buf_ptr++ = 0x7e; -+ MemOp mop = get_memop(oi); -+ switch (mop & MO_SSIZE) { -+ case MO_UQ: -+ *buf_ptr++ = 0x7e; -+ break; -+ default: -+ *buf_ptr++ = 0x7f; -+ break; -+ } -+ *buf_ptr++ = 0x7f; -+ *buf_ptr++ = 0x7f; -+ *buf_ptr++ = 0x0; -+ int sz = (uint32_t)(buf_ptr - buf_start); -+ wasm_add_helper_types_pos(s, sz); -+} -+ -+static void tcg_wasm_out_call(TCGContext *s, const tcg_insn_unit *func, -+ const TCGHelperInfo *info) -+{ -+ // set return position -+ tcg_wasm_out_ctx_i32_load(s, HELPER_RET_TB_PTR_OFF); -+ tcg_wasm_out_op_i32_const(s, (int32_t)s->code_ptr); -+ -+ tcg_wasm_out_op_i32_store(s, 0, 0); -+ -+ int func_idx = get_wasm_helper_idx(s, (int)func); -+ if (func_idx < 0) { -+ func_idx = wasm_register_helper_alloc_num(s); -+ tcg_debug_assert(func >= 0); -+ wasm_register_helper(s, func_idx, (int)func); -+ gen_func_type(s, info); -+ } -+ -+ int target_block_idx = wasm_block_current_idx(s) + 1; -+ tcg_wasm_out_op_i64_const(s, target_block_idx); -+ tcg_wasm_out_op_global_set(s, BLOCK_PTR_IDX); -+ tcg_wasm_out_op_end(s); // close if of this block (rewind skips this) -+ env_cached = false; -+ -+ int block_idx = wasm_alloc_block_idx(s); -+ tcg_wasm_out_op_global_get(s, BLOCK_PTR_IDX); -+ tcg_wasm_out_op_i64_const(s, block_idx); -+ tcg_wasm_out_op_i64_le_u(s); -+ tcg_wasm_out_op_if_noret(s); -+ tcg_wasm_out_ctx_i32_store_const(s, UNWINDING_OFF, 0); -+ gen_func_wrapper_code(s, func, info, func_idx); -+ -+ tcg_wasm_out_op_i32_const(s, 1); -+ tcg_wasm_out_ctx_i32_load(s, UNWINDING_OFF); -+ tcg_wasm_out_op_i32_eq(s); -+ tcg_wasm_out_op_if_noret(s); -+ tcg_wasm_out_op_i32_const(s, 0); -+ tcg_wasm_out_op_return(s); -+ tcg_wasm_out_op_end(s); -+} -+ -+void tb_target_set_jmp_target(const TranslationBlock *tb, int n, -+ uintptr_t jmp_rx, uintptr_t jmp_rw) -+{ -+ /* Always indirect, nothing to do */ -+} -+ -+static uint8_t tcg_wasm_out_tlb_load(TCGContext *s, TCGReg addr, MemOpIdx oi, bool is_ld) -+{ -+ MemOp opc = get_memop(oi); -+ TCGAtomAlign aa; -+ unsigned a_mask; -+ -+ aa = atom_and_align_for_opc(s, opc, MO_ATOM_IFALIGN, false); -+ a_mask = (1u << aa.align) - 1; -+ -+ unsigned s_bits = opc & MO_SIZE; -+ unsigned s_mask = (1u << s_bits) - 1; -+ tcg_target_long compare_mask; -+ int mem_index = get_mmuidx(oi); -+ int fast_ofs = tlb_mask_table_ofs(s, mem_index); -+ int mask_ofs = fast_ofs + offsetof(CPUTLBDescFast, mask); -+ int table_ofs = fast_ofs + offsetof(CPUTLBDescFast, table); -+ int add_off = offsetof(CPUTLBEntry, addend); -+ -+ tcg_wasm_out_op_global_get_r(s, addr); -+ tcg_wasm_out_op_i64_const(s, s->page_bits - CPU_TLB_ENTRY_BITS); -+ tcg_wasm_out_op_i64_shr_u(s); -+ -+ tcg_wasm_out_op_global_get_r_i32(s, TCG_AREG0); -+ int off = mask_ofs; -+ if ((int64_t)off < 0) { -+ tcg_wasm_out_op_i32_const(s, (int64_t)off); -+ tcg_wasm_out_op_i32_add(s); -+ off = 0; -+ } -+ tcg_wasm_out_op_i64_load(s, 0, (uint64_t)off); -+ tcg_wasm_out_op_local_set(s, TMP64_2_IDX); -+ -+ tcg_wasm_out_op_local_get(s, TMP64_2_IDX); -+ -+ tcg_wasm_out_op_i64_and(s); -+ -+ tcg_wasm_out_op_global_get_r_i32(s, TCG_AREG0); -+ off = table_ofs; -+ if ((int64_t)off < 0) { -+ tcg_wasm_out_op_i32_const(s, (int64_t)off); -+ tcg_wasm_out_op_i32_add(s); -+ off = 0; -+ } -+ tcg_wasm_out_op_i64_load(s, 0, (uint64_t)off); -+ tcg_wasm_out_op_i64_add(s); -+ -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_local_tee(s, TMP32_LOCAL_0_IDX); -+ -+ off = is_ld ? offsetof(CPUTLBEntry, addr_read) -+ : offsetof(CPUTLBEntry, addr_write); -+ if ((int64_t)off < 0) { -+ tcg_wasm_out_op_i32_const(s, (int64_t)off); -+ tcg_wasm_out_op_i32_add(s); -+ off = 0; -+ } -+ tcg_wasm_out_op_i64_load(s, 0, (uint64_t)off); -+ -+ tcg_wasm_out_op_global_get_r(s, addr); -+ if (a_mask < s_mask) { -+ tcg_wasm_out_op_i64_const(s, s_mask - a_mask); -+ tcg_wasm_out_op_i64_add(s); -+ } -+ compare_mask = (uint64_t)s->page_mask | a_mask; -+ tcg_wasm_out_op_i64_const(s, compare_mask); -+ tcg_wasm_out_op_i64_and(s); -+ -+ tcg_wasm_out_op_i64_eq(s); -+ -+ tcg_wasm_out_op_i64_const(s, 0); -+ tcg_wasm_out_op_local_set(s, TMP64_0_IDX); -+ -+ tcg_wasm_out_op_if_noret(s); -+ tcg_wasm_out_op_local_get(s, TMP32_LOCAL_0_IDX); -+ off = add_off; -+ if ((int64_t)off < 0) { -+ tcg_wasm_out_op_i32_const(s, (int64_t)off); -+ tcg_wasm_out_op_i32_add(s); -+ off = 0; -+ } -+ tcg_wasm_out_op_i32_load(s, 0, (uint64_t)off); -+ tcg_wasm_out_op_i64_extend_i32_u(s); -+ tcg_wasm_out_op_global_get_r(s, addr); -+ tcg_wasm_out_op_i64_add(s); -+ tcg_wasm_out_op_local_set(s, TMP64_0_IDX); -+ -+ tcg_wasm_out_op_end(s); -+ -+ -+ return TMP64_0_IDX; -+} -+ -+static void tcg_wasm_out_qemu_ld_direct(TCGContext *s, TCGReg r, uint8_t base, MemOp opc) -+{ -+ /* Byte swapping is left to middle-end expansion. */ -+ tcg_debug_assert((opc & MO_BSWAP) == 0); -+ -+ switch (opc & (MO_SSIZE)) { -+ case MO_UB: -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_load8_u(s, 0, 0); -+ tcg_wasm_out_op_global_set_r(s, r); -+ break; -+ case MO_SB: -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_load8_s(s, 0, 0); -+ tcg_wasm_out_op_global_set_r(s, r); -+ break; -+ case MO_UW: -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_load16_u(s, 0, 0); -+ tcg_wasm_out_op_global_set_r(s, r); -+ break; -+ case MO_SW: -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_load16_s(s, 0, 0); -+ tcg_wasm_out_op_global_set_r(s, r); -+ break; -+ case MO_UL: -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_load32_u(s, 0, 0); -+ tcg_wasm_out_op_global_set_r(s, r); -+ break; -+ case MO_SL: -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_load32_s(s, 0, 0); -+ tcg_wasm_out_op_global_set_r(s, r); -+ break; -+ case MO_UQ: -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_i64_load(s, 0, 0); -+ tcg_wasm_out_op_global_set_r(s, r); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void* qemu_ld_helper_ptr(uint32_t oi) -+{ -+ MemOp mop = get_memop(oi); -+ switch (mop & MO_SSIZE) { -+ case MO_UB: -+ return helper_ldub_mmu; -+ case MO_SB: -+ return helper_ldsb_mmu; -+ case MO_UW: -+ return helper_lduw_mmu; -+ case MO_SW: -+ return helper_ldsw_mmu; -+ case MO_UL: -+ return helper_ldul_mmu; -+ case MO_SL: -+ return helper_ldsl_mmu; -+ case MO_UQ: -+ return helper_ldq_mmu; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64) -+{ -+ TCGReg addr_reg; -+ TCGReg data_reg; -+ MemOpIdx oi; -+ MemOp opc; -+ -+ data_reg = *args++; -+ addr_reg = *args++; -+ oi = *args++; -+ opc = get_memop(oi); -+ -+ uint8_t base = tcg_wasm_out_tlb_load(s, addr_reg, oi, true); -+ -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i64_eqz(s); -+ tcg_wasm_out_op_if_noret(s); -+ -+ // path for miss case -+ int helper_func_idx = (uint32_t)qemu_ld_helper_ptr(oi); -+ int func_idx = get_wasm_helper_idx(s, helper_func_idx); -+ if (func_idx < 0) { -+ func_idx = wasm_register_helper_alloc_num(s); -+ tcg_debug_assert(helper_func_idx >= 0); -+ wasm_register_helper(s, func_idx, helper_func_idx); -+ gen_func_type_qemu_ld(s, oi); -+ } -+ -+ // save function pointer -+ tcg_wasm_out_ctx_i32_store_const(s, DONE_FLAG_OFF, 0); -+ -+ tcg_wasm_out_op_else(s); -+ -+ // fast path -+ tcg_wasm_out_qemu_ld_direct(s, data_reg, base, opc); -+ -+ tcg_wasm_out_op_end(s); -+ -+ int target_block_idx = wasm_block_current_idx(s) + 1; -+ tcg_wasm_out_op_i64_const(s, target_block_idx); -+ tcg_wasm_out_op_global_set(s, BLOCK_PTR_IDX); -+ -+ tcg_wasm_out_op_end(s); // close if of this block (rewind skips this) -+ env_cached = false; -+ -+ // block for calling helper (+1) -+ int block_idx = wasm_alloc_block_idx(s); -+ tcg_wasm_out_op_global_get(s, BLOCK_PTR_IDX); -+ tcg_wasm_out_op_i64_const(s, block_idx); -+ tcg_wasm_out_op_i64_le_u(s); -+ tcg_wasm_out_op_if_noret(s); -+ -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i64_eqz(s); -+ tcg_wasm_out_op_if_noret(s); -+ -+ // call helper -+ tcg_wasm_out_op_global_get_r(s, TCG_AREG0); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_global_get_r(s, addr_reg); -+ tcg_wasm_out_op_i32_const(s, oi); -+ tcg_wasm_out_op_i32_const(s, (int32_t)s->code_ptr); -+ -+ tcg_wasm_out_op_call(s, func_idx); -+ tcg_wasm_out_op_global_set_r(s, data_reg); -+ tcg_wasm_out_ctx_i32_load(s, DONE_FLAG_OFF); -+ tcg_wasm_out_op_i32_eqz(s); -+ -+ tcg_wasm_out_op_if_noret(s); -+ tcg_wasm_out_op_i32_const(s, 0); -+ tcg_wasm_out_op_return(s); -+ tcg_wasm_out_op_end(s); -+ tcg_wasm_out_op_end(s); -+} -+ -+static void tcg_wasm_out_qemu_st_direct(TCGContext *s, TCGReg lo, uint8_t base, MemOp opc) -+{ -+ /* Byte swapping is left to middle-end expansion. */ -+ tcg_debug_assert((opc & MO_BSWAP) == 0); -+ -+ switch (opc & (MO_SSIZE)) { -+ case MO_8: -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_global_get_r(s, lo); -+ tcg_wasm_out_op_i64_store8(s, 0, 0); -+ break; -+ case MO_16: -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_global_get_r(s, lo); -+ tcg_wasm_out_op_i64_store16(s, 0, 0); -+ break; -+ case MO_32: -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_global_get_r(s, lo); -+ tcg_wasm_out_op_i64_store32(s, 0, 0); -+ break; -+ case MO_64: -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_global_get_r(s, lo); -+ tcg_wasm_out_op_i64_store(s, 0, 0); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void* qemu_st_helper_ptr(uint32_t oi) -+{ -+ MemOp mop = get_memop(oi); -+ switch (mop & MO_SIZE) { -+ case MO_8: -+ return helper_stb_mmu; -+ case MO_16: -+ return helper_stw_mmu; -+ case MO_32: -+ return helper_stl_mmu; -+ case MO_64: -+ return helper_stq_mmu; -+ case MO_128: -+ return helper_st16_mmu; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_wasm_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64) -+{ -+ TCGReg addr_reg; -+ TCGReg data_reg; -+ MemOpIdx oi; -+ MemOp opc; -+ -+ data_reg = *args++; -+ addr_reg = *args++; -+ oi = *args++; -+ opc = get_memop(oi); -+ -+ uint8_t base = tcg_wasm_out_tlb_load(s, addr_reg, oi, false); -+ -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i64_eqz(s); -+ tcg_wasm_out_op_if_noret(s); -+ -+ // path for miss case -+ int helper_func_idx = (uint32_t)qemu_st_helper_ptr(oi); -+ int func_idx = get_wasm_helper_idx(s, helper_func_idx); -+ if (func_idx < 0) { -+ func_idx = wasm_register_helper_alloc_num(s); -+ tcg_debug_assert(helper_func_idx >= 0); -+ wasm_register_helper(s, func_idx, helper_func_idx); -+ gen_func_type_qemu_st(s, oi); -+ } -+ -+ // save function pointer -+ tcg_wasm_out_ctx_i32_store_const(s, DONE_FLAG_OFF, 0); -+ -+ tcg_wasm_out_op_else(s); -+ -+ // fast path -+ tcg_wasm_out_qemu_st_direct(s, data_reg, base, opc); -+ -+ tcg_wasm_out_op_end(s); -+ -+ int target_block_idx = wasm_block_current_idx(s) + 1; -+ tcg_wasm_out_op_i64_const(s, target_block_idx); -+ tcg_wasm_out_op_global_set(s, BLOCK_PTR_IDX); -+ -+ tcg_wasm_out_op_end(s); // close if of this block (rewind skips this) -+ env_cached = false; -+ -+ // block for calling helper (+1) -+ int block_idx = wasm_alloc_block_idx(s); -+ tcg_wasm_out_op_global_get(s, BLOCK_PTR_IDX); -+ tcg_wasm_out_op_i64_const(s, block_idx); -+ tcg_wasm_out_op_i64_le_u(s); -+ tcg_wasm_out_op_if_noret(s); -+ -+ tcg_wasm_out_op_local_get(s, base); -+ tcg_wasm_out_op_i64_eqz(s); -+ tcg_wasm_out_op_if_noret(s); -+ -+ // call helper -+ tcg_wasm_out_op_global_get_r(s, TCG_AREG0); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ tcg_wasm_out_op_global_get_r(s, addr_reg); -+ MemOp mop = get_memop(oi); -+ switch (mop & MO_SSIZE) { -+ case MO_UQ: -+ tcg_wasm_out_op_global_get_r(s, data_reg); -+ break; -+ default: -+ tcg_wasm_out_op_global_get_r(s, data_reg); -+ tcg_wasm_out_op_i32_wrap_i64(s); -+ break; -+ } -+ tcg_wasm_out_op_i32_const(s, oi); -+ tcg_wasm_out_op_i32_const(s, (int32_t)s->code_ptr); -+ -+ tcg_wasm_out_op_call(s, func_idx); -+ -+ tcg_wasm_out_ctx_i32_load(s, DONE_FLAG_OFF); -+ tcg_wasm_out_op_i32_eqz(s); -+ tcg_wasm_out_op_if_noret(s); -+ tcg_wasm_out_op_i32_const(s, 0); -+ tcg_wasm_out_op_return(s); -+ tcg_wasm_out_op_end(s); -+ tcg_wasm_out_op_end(s); -+} -+ -+static bool patch_reloc(tcg_insn_unit *code_ptr_i, int type, -+ intptr_t value, intptr_t addend) -+{ -+ int32_t *code_ptr = (int32_t*)code_ptr_i; -+ intptr_t diff = value - (intptr_t)(code_ptr + 1); -+ -+ tcg_debug_assert(addend == 0); -+ tcg_debug_assert(type == 20); -+ -+ if (diff == sextract32(diff, 0, type)) { -+ tcg_patch32(code_ptr, deposit32(*code_ptr, 32 - type, type, diff)); -+ return true; -+ } -+ return false; -+} -+ -+static void stack_bounds_check(TCGReg base, intptr_t offset) -+{ -+ if (base == TCG_REG_CALL_STACK) { -+ tcg_debug_assert(offset >= 0); -+ tcg_debug_assert(offset < (TCG_STATIC_CALL_ARGS_SIZE + -+ TCG_STATIC_FRAME_SIZE)); -+ } -+} -+ -+static inline void tcg_tci_out32(TCGContext *s, uint32_t v) -+{ -+ tcg_out32(s, v); -+} -+ -+static uintptr_t cur_tci_ptr(TCGContext *s) -+{ -+ return (uintptr_t)s->code_ptr; -+} -+ -+static void tcg_tci_out_op_l(TCGContext *s, TCGOpcode op, TCGLabel *l0) -+{ -+ uint32_t insn = 0; -+ -+ tcg_out_reloc(s, (void*)cur_tci_ptr(s), 20, l0, 0); -+ insn = deposit32(insn, 0, 8, op); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_p(TCGContext *s, TCGOpcode op, void *p0) -+{ -+ uint32_t insn = 0; -+ intptr_t diff; -+ -+ /* Special case for exit_tb: map null -> 0. */ -+ if (p0 == NULL) { -+ diff = 0; -+ } else { -+ diff = p0 - (void *)((uint8_t*)cur_tci_ptr(s) + 4); -+ tcg_debug_assert(diff != 0); -+ if (diff != sextract32(diff, 0, 20)) { -+ tcg_raise_tb_overflow(s); -+ } -+ } -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 12, 20, diff); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_r(TCGContext *s, TCGOpcode op, TCGReg r0) -+{ -+ uint32_t insn = 0; -+ -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_v(TCGContext *s, TCGOpcode op) -+{ -+ tcg_tci_out32(s, (uint8_t)op); -+} -+ -+static void tcg_tci_out_op_ri(TCGContext *s, TCGOpcode op, TCGReg r0, int32_t i1) -+{ -+ uint32_t insn = 0; -+ -+ tcg_debug_assert(i1 == sextract32(i1, 0, 20)); -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ insn = deposit32(insn, 12, 20, i1); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_rl(TCGContext *s, TCGOpcode op, TCGReg r0, TCGLabel *l1) -+{ -+ uint32_t insn = 0; -+ -+ tcg_out_reloc(s, (void*)cur_tci_ptr(s), 20, l1, 0); -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_rr(TCGContext *s, TCGOpcode op, TCGReg r0, TCGReg r1) -+{ -+ uint32_t insn = 0; -+ -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ insn = deposit32(insn, 12, 4, r1); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_rrm(TCGContext *s, TCGOpcode op, -+ TCGReg r0, TCGReg r1, TCGArg m2) -+{ -+ uint32_t insn = 0; -+ -+ tcg_debug_assert(m2 == extract32(m2, 0, 16)); -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ insn = deposit32(insn, 12, 4, r1); -+ insn = deposit32(insn, 16, 16, m2); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_rrr(TCGContext *s, TCGOpcode op, -+ TCGReg r0, TCGReg r1, TCGReg r2) -+{ -+ uint32_t insn = 0; -+ -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ insn = deposit32(insn, 12, 4, r1); -+ insn = deposit32(insn, 16, 4, r2); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_rrs(TCGContext *s, TCGOpcode op, -+ TCGReg r0, TCGReg r1, intptr_t i2) -+{ -+ uint32_t insn = 0; -+ -+ tcg_debug_assert(i2 == sextract32(i2, 0, 16)); -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ insn = deposit32(insn, 12, 4, r1); -+ insn = deposit32(insn, 16, 16, i2); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_rrbb(TCGContext *s, TCGOpcode op, TCGReg r0, -+ TCGReg r1, uint8_t b2, uint8_t b3) -+{ -+ uint32_t insn = 0; -+ -+ tcg_debug_assert(b2 == extract32(b2, 0, 6)); -+ tcg_debug_assert(b3 == extract32(b3, 0, 6)); -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ insn = deposit32(insn, 12, 4, r1); -+ insn = deposit32(insn, 16, 6, b2); -+ insn = deposit32(insn, 22, 6, b3); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_rrrc(TCGContext *s, TCGOpcode op, -+ TCGReg r0, TCGReg r1, TCGReg r2, TCGCond c3) -+{ -+ uint32_t insn = 0; -+ -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ insn = deposit32(insn, 12, 4, r1); -+ insn = deposit32(insn, 16, 4, r2); -+ insn = deposit32(insn, 20, 4, c3); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_rrrbb(TCGContext *s, TCGOpcode op, TCGReg r0, -+ TCGReg r1, TCGReg r2, uint8_t b3, uint8_t b4) -+{ -+ uint32_t insn = 0; -+ -+ tcg_debug_assert(b3 == extract32(b3, 0, 6)); -+ tcg_debug_assert(b4 == extract32(b4, 0, 6)); -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ insn = deposit32(insn, 12, 4, r1); -+ insn = deposit32(insn, 16, 4, r2); -+ insn = deposit32(insn, 20, 6, b3); -+ insn = deposit32(insn, 26, 6, b4); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_rrrrr(TCGContext *s, TCGOpcode op, TCGReg r0, -+ TCGReg r1, TCGReg r2, TCGReg r3, TCGReg r4) -+{ -+ uint32_t insn = 0; -+ -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ insn = deposit32(insn, 12, 4, r1); -+ insn = deposit32(insn, 16, 4, r2); -+ insn = deposit32(insn, 20, 4, r3); -+ insn = deposit32(insn, 24, 4, r4); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_rrrr(TCGContext *s, TCGOpcode op, -+ TCGReg r0, TCGReg r1, TCGReg r2, TCGReg r3) -+{ -+ uint32_t insn = 0; -+ -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ insn = deposit32(insn, 12, 4, r1); -+ insn = deposit32(insn, 16, 4, r2); -+ insn = deposit32(insn, 20, 4, r3); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_rrrrrc(TCGContext *s, TCGOpcode op, -+ TCGReg r0, TCGReg r1, TCGReg r2, -+ TCGReg r3, TCGReg r4, TCGCond c5) -+{ -+ uint32_t insn = 0; -+ -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ insn = deposit32(insn, 12, 4, r1); -+ insn = deposit32(insn, 16, 4, r2); -+ insn = deposit32(insn, 20, 4, r3); -+ insn = deposit32(insn, 24, 4, r4); -+ insn = deposit32(insn, 28, 4, c5); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_op_rrrrrr(TCGContext *s, TCGOpcode op, -+ TCGReg r0, TCGReg r1, TCGReg r2, -+ TCGReg r3, TCGReg r4, TCGReg r5) -+{ -+ uint32_t insn = 0; -+ -+ insn = deposit32(insn, 0, 8, op); -+ insn = deposit32(insn, 8, 4, r0); -+ insn = deposit32(insn, 12, 4, r1); -+ insn = deposit32(insn, 16, 4, r2); -+ insn = deposit32(insn, 20, 4, r3); -+ insn = deposit32(insn, 24, 4, r4); -+ insn = deposit32(insn, 28, 4, r5); -+ tcg_tci_out32(s, insn); -+} -+ -+static void tcg_tci_out_movi(TCGContext *s, TCGType type, -+ TCGReg ret, tcg_target_long arg) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+#if TCG_TARGET_REG_BITS == 64 -+ arg = (int32_t)arg; -+ /* fall through */ -+ case TCG_TYPE_I64: -+#endif -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ -+ if (arg == sextract32(arg, 0, 20)) { -+ tcg_tci_out_op_ri(s, INDEX_op_tci_movi, ret, arg); -+ } else { -+ uint32_t insn = 0; -+ -+ new_pool_label(s, arg, 20, (void*)cur_tci_ptr(s), 0); -+ insn = deposit32(insn, 0, 8, INDEX_op_tci_movl); -+ insn = deposit32(insn, 8, 4, ret); -+ tcg_tci_out32(s, insn); -+ } -+} -+ -+static void tcg_tci_out_ldst(TCGContext *s, TCGOpcode op, TCGReg val, -+ TCGReg base, intptr_t offset) -+{ -+ stack_bounds_check(base, offset); -+ if (offset != sextract32(offset, 0, 16)) { -+ tcg_tci_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP, offset); -+ tcg_tci_out_op_rrr(s, (TCG_TARGET_REG_BITS == 32 -+ ? INDEX_op_add_i32 : INDEX_op_add_i64), -+ TCG_REG_TMP, TCG_REG_TMP, base); -+ base = TCG_REG_TMP; -+ offset = 0; -+ } -+ tcg_tci_out_op_rrs(s, op, val, base, offset); -+} -+ -+static bool tcg_tci_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_tci_out_op_rr(s, INDEX_op_mov_i32, ret, arg); -+ break; -+#if TCG_TARGET_REG_BITS == 64 -+ case TCG_TYPE_I64: -+ tcg_tci_out_op_rr(s, INDEX_op_mov_i64, ret, arg); -+ break; -+#endif -+ default: -+ g_assert_not_reached(); -+ } -+ return true; -+} -+ -+static void tcg_tci_out_ext8s(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_debug_assert(TCG_TARGET_HAS_ext8s_i32); -+ tcg_tci_out_op_rr(s, INDEX_op_ext8s_i32, rd, rs); -+ break; -+#if TCG_TARGET_REG_BITS == 64 -+ case TCG_TYPE_I64: -+ tcg_debug_assert(TCG_TARGET_HAS_ext8s_i64); -+ tcg_tci_out_op_rr(s, INDEX_op_ext8s_i64, rd, rs); -+ break; -+#endif -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_tci_out_ext8u(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ if (TCG_TARGET_REG_BITS == 64) { -+ tcg_debug_assert(TCG_TARGET_HAS_ext8u_i64); -+ tcg_tci_out_op_rr(s, INDEX_op_ext8u_i64, rd, rs); -+ } else { -+ tcg_debug_assert(TCG_TARGET_HAS_ext8u_i32); -+ tcg_tci_out_op_rr(s, INDEX_op_ext8u_i32, rd, rs); -+ } -+} -+ -+static void tcg_tci_out_ext16s(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_debug_assert(TCG_TARGET_HAS_ext16s_i32); -+ tcg_tci_out_op_rr(s, INDEX_op_ext16s_i32, rd, rs); -+ break; -+#if TCG_TARGET_REG_BITS == 64 -+ case TCG_TYPE_I64: -+ tcg_debug_assert(TCG_TARGET_HAS_ext16s_i64); -+ tcg_tci_out_op_rr(s, INDEX_op_ext16s_i64, rd, rs); -+ break; -+#endif -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_tci_out_ext16u(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ if (TCG_TARGET_REG_BITS == 64) { -+ tcg_debug_assert(TCG_TARGET_HAS_ext16u_i64); -+ tcg_tci_out_op_rr(s, INDEX_op_ext16u_i64, rd, rs); -+ } else { -+ tcg_debug_assert(TCG_TARGET_HAS_ext16u_i32); -+ tcg_tci_out_op_rr(s, INDEX_op_ext16u_i32, rd, rs); -+ } -+} -+ -+static void tcg_tci_out_ext32s(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_debug_assert(TCG_TARGET_REG_BITS == 64); -+ tcg_debug_assert(TCG_TARGET_HAS_ext32s_i64); -+ tcg_tci_out_op_rr(s, INDEX_op_ext32s_i64, rd, rs); -+} -+ -+static void tcg_tci_out_ext32u(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_debug_assert(TCG_TARGET_REG_BITS == 64); -+ tcg_debug_assert(TCG_TARGET_HAS_ext32u_i64); -+ tcg_tci_out_op_rr(s, INDEX_op_ext32u_i64, rd, rs); -+} -+ -+static void tcg_tci_out_exts_i32_i64(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_tci_out_ext32s(s, rd, rs); -+} -+ -+static void tcg_tci_out_extu_i32_i64(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_tci_out_ext32u(s, rd, rs); -+} -+ -+static void tcg_tci_out_extrl_i64_i32(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_debug_assert(TCG_TARGET_REG_BITS == 64); -+ tcg_tci_out_mov(s, TCG_TYPE_I32, rd, rs); -+} -+ -+static void tcg_tci_out_call(TCGContext *s, const tcg_insn_unit *func, -+ const TCGHelperInfo *info) -+{ -+ ffi_cif *cif = info->cif; -+ uint32_t insn = 0; -+ uint8_t which; -+ -+ if (cif->rtype == &ffi_type_void) { -+ which = 0; -+ } else { -+ tcg_debug_assert(cif->rtype->size == 4 || -+ cif->rtype->size == 8 || -+ cif->rtype->size == 16); -+ which = ctz32(cif->rtype->size) - 1; -+ } -+ new_pool_l2(s, 20, (void*)cur_tci_ptr(s), 0, (uintptr_t)func, (uintptr_t)cif); -+ insn = deposit32(insn, 0, 8, INDEX_op_call); -+ insn = deposit32(insn, 8, 4, which); -+ tcg_tci_out32(s, insn); -+} -+ -+#if TCG_TARGET_REG_BITS == 64 -+# define CASE_32_64(x) \ -+ case glue(glue(INDEX_op_, x), _i64): \ -+ case glue(glue(INDEX_op_, x), _i32): -+# define CASE_64(x) \ -+ case glue(glue(INDEX_op_, x), _i64): -+#else -+# define CASE_32_64(x) \ -+ case glue(glue(INDEX_op_, x), _i32): -+# define CASE_64(x) -+#endif -+ -+static void tcg_tci_out_exit_tb(TCGContext *s, uintptr_t arg) -+{ -+ tcg_tci_out_op_p(s, INDEX_op_exit_tb, (void *)arg); -+} -+ -+static void tcg_tci_out_goto_tb(TCGContext *s, int which) -+{ -+ /* indirect jump method. */ -+ tcg_tci_out_op_p(s, INDEX_op_goto_tb, (void *)get_jmp_target_addr(s, which)); -+ set_jmp_reset_offset(s, which); -+} -+ -+static void tcg_out_nop_fill(tcg_insn_unit *p, int count) -+{ -+ int32_t *p2 = (int32_t*)p; -+ memset(p2, 0, sizeof(*p2) * count); -+} -+ -+static void tcg_out_goto_ptr(TCGContext *s, TCGOpcode opc, TCGReg arg) -+{ -+ tcg_tci_out_op_r(s, opc, arg); -+ tcg_wasm_out_goto_ptr(s, arg); -+} -+static void tcg_out_br(TCGContext *s, TCGOpcode opc, TCGLabel *l) -+{ -+ tcg_tci_out_op_l(s, opc, l); -+ tcg_wasm_out_br(s, l); -+} -+static void tcg_out_setcond_i32(TCGContext *s, TCGOpcode opc, TCGCond cond, TCGReg ret, -+ TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrrc(s, opc, ret, arg1, arg2, cond); -+ tcg_wasm_out_setcond_i32(s, cond, ret, arg1, arg2); -+} -+static void tcg_out_setcond_i64(TCGContext *s, TCGOpcode opc, TCGCond cond, TCGReg ret, -+ TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrrc(s, opc, ret, arg1, arg2, cond); -+ tcg_wasm_out_setcond_i64(s, cond, ret, arg1, arg2); -+} -+static void tcg_out_movcond_i32(TCGContext *s, TCGOpcode opc, TCGCond cond, TCGReg ret, -+ TCGReg c1, TCGReg c2, TCGReg v1, TCGReg v2) -+{ -+ tcg_tci_out_op_rrrrrc(s, opc, ret, c1, c2, v1, v2, cond); -+ tcg_wasm_out_movcond_i32(s, cond, ret, c1, c2, v1, v2); -+} -+static void tcg_out_movcond_i64(TCGContext *s, TCGOpcode opc, TCGCond cond, TCGReg ret, -+ TCGReg c1, TCGReg c2, TCGReg v1, TCGReg v2) -+{ -+ tcg_tci_out_op_rrrrrc(s, opc, ret, c1, c2, v1, v2, cond); -+ tcg_wasm_out_movcond_i64(s, cond, ret, c1, c2, v1, v2); -+} -+static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_tci_out_ldst(s, INDEX_op_ld_i32, val, base, offset); -+ break; -+ case TCG_TYPE_I64: -+ tcg_tci_out_ldst(s, INDEX_op_ld_i64, val, base, offset); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ tcg_wasm_out_ld(s, type, val, base, offset); -+} -+static void tcg_out_ld8s(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ tcg_tci_out_ldst(s, opc, val, base, offset); -+ tcg_wasm_out_ld8s(s, type, val, base, offset); -+} -+static void tcg_out_ld8u(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ tcg_tci_out_ldst(s, opc, val, base, offset); -+ tcg_wasm_out_ld8u(s, type, val, base, offset); -+} -+static void tcg_out_ld16s(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ tcg_tci_out_ldst(s, opc, val, base, offset); -+ tcg_wasm_out_ld16s(s, type, val, base, offset); -+} -+static void tcg_out_ld16u(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ tcg_tci_out_ldst(s, opc, val, base, offset); -+ tcg_wasm_out_ld16u(s, type, val, base, offset); -+} -+static void tcg_out_ld32s(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ tcg_tci_out_ldst(s, opc, val, base, offset); -+ tcg_wasm_out_ld32s(s, type, val, base, offset); -+} -+static void tcg_out_ld32u(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ tcg_tci_out_ldst(s, opc, val, base, offset); -+ tcg_wasm_out_ld32u(s, type, val, base, offset); -+} -+static void tcg_out_st(TCGContext *s, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ switch (type) { -+ case TCG_TYPE_I32: -+ tcg_tci_out_ldst(s, INDEX_op_st_i32, val, base, offset); -+ break; -+ case TCG_TYPE_I64: -+ tcg_tci_out_ldst(s, INDEX_op_st_i64, val, base, offset); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+ tcg_wasm_out_st(s, type, val, base, offset); -+} -+static void tcg_out_st8(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ tcg_tci_out_ldst(s, opc, val, base, offset); -+ tcg_wasm_out_st8(s, type, val, base, offset); -+} -+static void tcg_out_st16(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ tcg_tci_out_ldst(s, opc, val, base, offset); -+ tcg_wasm_out_st16(s, type, val, base, offset); -+} -+static void tcg_out_st32(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg val, TCGReg base, -+ intptr_t offset) -+{ -+ tcg_tci_out_ldst(s, opc, val, base, offset); -+ tcg_wasm_out_st32(s, type, val, base, offset); -+} -+static void tcg_out_i64_calc_add(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_i64_calc_add(s, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_sub(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_i64_calc_sub(s, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_mul(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_i64_calc_mul(s, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_and(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_i64_calc_and(s, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_or(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_i64_calc_or(s, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_xor(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_i64_calc_xor(s, ret, arg1, arg2); -+} -+static void tcg_out_shl(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_shl(s, type, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_shl(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_i64_calc_shl(s, ret, arg1, arg2); -+} -+static void tcg_out_shr_u(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_shr_u(s, type, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_shr_u(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_i64_calc_shr_u(s, ret, arg1, arg2); -+} -+static void tcg_out_shr_s(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_shr_s(s, type, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_shr_s(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_i64_calc_shr_s(s, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_rotl(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_i64_calc_rotl(s, ret, arg1, arg2); -+} -+static void tcg_out_i32_rotl(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_i32_rotl(s, ret, arg1, arg2); -+} -+static void tcg_out_i32_rotr(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_i32_rotr(s, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_rotr(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_i64_calc_rotr(s, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_div_s(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_div_s(s, type, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_div_u(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_div_u(s, type, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_rem_s(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_rem_s(s, type, ret, arg1, arg2); -+} -+static void tcg_out_i64_calc_rem_u(TCGContext *s, TCGOpcode opc, TCGType type, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_rem_u(s, type, ret, arg1, arg2); -+} -+static void tcg_out_andc(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_andc(s, ret, arg1, arg2); -+} -+static void tcg_out_orc(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_orc(s, ret, arg1, arg2); -+} -+static void tcg_out_eqv(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_eqv(s, ret, arg1, arg2); -+} -+static void tcg_out_nand(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_nand(s, ret, arg1, arg2); -+} -+static void tcg_out_nor(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_nor(s, ret, arg1, arg2); -+} -+static void tcg_out_clz32(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_clz32(s, ret, arg1, arg2); -+} -+static void tcg_out_clz64(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_clz64(s, ret, arg1, arg2); -+} -+static void tcg_out_ctz32(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_ctz32(s, ret, arg1, arg2); -+} -+static void tcg_out_ctz64(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrr(s, opc, ret, arg1, arg2); -+ tcg_wasm_out_ctz64(s, ret, arg1, arg2); -+} -+static void tcg_out_brcond_i32(TCGContext *s, TCGOpcode opc, TCGCond cond, TCGReg arg1, -+ TCGReg arg2, TCGLabel *l) -+{ -+ tcg_tci_out_op_rrrc(s, (opc == INDEX_op_brcond_i32 ? INDEX_op_setcond_i32 : INDEX_op_setcond_i64), TCG_REG_TMP, arg1, arg2, cond); -+ tcg_tci_out_op_rl(s, opc, TCG_REG_TMP, l); -+ tcg_wasm_out_brcond_i32(s, cond, arg1, arg2, l); -+ -+} -+static void tcg_out_brcond_i64(TCGContext *s, TCGOpcode opc, TCGCond cond, TCGReg arg1, -+ TCGReg arg2, TCGLabel *l) -+{ -+ tcg_tci_out_op_rrrc(s, (opc == INDEX_op_brcond_i32 ? INDEX_op_setcond_i32 : INDEX_op_setcond_i64), TCG_REG_TMP, arg1, arg2, cond); -+ tcg_tci_out_op_rl(s, opc, TCG_REG_TMP, l); -+ tcg_wasm_out_brcond_i64(s, cond, arg1, arg2, l); -+ -+} -+static void tcg_out_neg(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg) -+{ -+ tcg_tci_out_op_rr(s, opc, ret, arg); -+ tcg_wasm_out_neg(s, ret, arg); -+} -+static void tcg_out_not(TCGContext *s, TCGOpcode opc, TCGReg ret, TCGReg arg) -+{ -+ tcg_tci_out_op_rr(s, opc, ret, arg); -+ tcg_wasm_out_not(s, ret, arg); -+} -+static void tcg_out_ctpop_i32(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg src) -+{ -+ tcg_tci_out_op_rr(s, opc, dest, src); -+ tcg_wasm_out_ctpop_i32(s, dest, src); -+} -+static void tcg_out_ctpop_i64(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg src) -+{ -+ tcg_tci_out_op_rr(s, opc, dest, src); -+ tcg_wasm_out_ctpop_i64(s, dest, src); -+} -+static void tcg_out_add2(TCGContext *s, TCGOpcode opc, TCGReg retl, TCGReg reth, -+ TCGReg al, TCGReg ah, TCGReg bl, TCGReg bh) -+{ -+ tcg_tci_out_op_rrrrrr(s, opc, retl, reth, al, ah, bl, bh); -+ tcg_wasm_out_add2(s, retl, reth, al, ah, bl, bh); -+} -+static void tcg_out_sub2(TCGContext *s, TCGOpcode opc, TCGReg retl, TCGReg reth, -+ TCGReg al, TCGReg ah, TCGReg bl, TCGReg bh) -+{ -+ tcg_tci_out_op_rrrrrr(s, opc, retl, reth, al, ah, bl, bh); -+ tcg_wasm_out_sub2(s, retl, reth, al, ah, bl, bh); -+} -+static void tcg_out_mulu2_i32(TCGContext *s, TCGOpcode opc, TCGReg retl, TCGReg reth, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrrr(s, opc, retl, reth, arg1, arg2); -+ tcg_wasm_out_mulu2_i32(s, retl, reth, arg1, arg2); -+} -+static void tcg_out_muls2_i32(TCGContext *s, TCGOpcode opc, TCGReg retl, TCGReg reth, TCGReg arg1, TCGReg arg2) -+{ -+ tcg_tci_out_op_rrrr(s, opc, retl, reth, arg1, arg2); -+ tcg_wasm_out_muls2_i32(s, retl, reth, arg1, arg2); -+} -+ -+static void tcg_out_bswap16_i32(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg src, int flags) -+{ -+ tcg_tci_out_op_rr(s, opc, dest, src); -+ if (flags & TCG_BSWAP_OS) { -+ tcg_tci_out_op_rr(s, INDEX_op_ext16s_i32, dest, dest); -+ } -+ tcg_wasm_out_bswap16(s, dest, src, flags); -+ if (flags & TCG_BSWAP_OS) { -+ tcg_wasm_out_ext16s(s, TCG_TYPE_I32, dest, dest); -+ } -+} -+static void tcg_out_bswap16_i64(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg src, int flags) -+{ -+ tcg_tci_out_op_rr(s, opc, dest, src); -+ if (flags & TCG_BSWAP_OS) { -+ tcg_tci_out_op_rr(s, INDEX_op_ext16s_i64, dest, dest); -+ } -+ tcg_wasm_out_bswap16(s, dest, src, flags); -+ if (flags & TCG_BSWAP_OS) { -+ tcg_wasm_out_ext16s(s, TCG_TYPE_I64, dest, dest); -+ } -+} -+ -+static void tcg_out_bswap32_i32(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg src, int flags) -+{ -+ tcg_tci_out_op_rr(s, opc, dest, src); -+ tcg_wasm_out_bswap32(s, dest, src, flags); -+} -+static void tcg_out_bswap32_i64(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg src, int flags) -+{ -+ tcg_tci_out_op_rr(s, opc, dest, src); -+ if (flags & TCG_BSWAP_OS) { -+ tcg_tci_out_op_rr(s, INDEX_op_ext32s_i64, dest, dest); -+ } -+ tcg_wasm_out_bswap32(s, dest, src, flags); -+ if (flags & TCG_BSWAP_OS) { -+ tcg_wasm_out_ext32s(s, dest, dest); -+ } -+} -+static void tcg_out_bswap64_i64(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg src, int flags) -+{ -+ tcg_tci_out_op_rr(s, opc, dest, src); -+ tcg_wasm_out_bswap64(s, dest, src, flags); -+} -+static uint8_t tcg_tci_out_qemu_ldst(TCGContext *s, TCGOpcode opc, const TCGArg *args) -+{ -+ TCGReg addr_reg = args[1]; -+ MemOpIdx oi = args[2]; -+ -+ MemOp mopc = get_memop(oi); -+ TCGAtomAlign aa = atom_and_align_for_opc(s, mopc, MO_ATOM_IFALIGN, false); -+ unsigned a_mask = (1u << aa.align) - 1; -+ -+ int mem_index = get_mmuidx(oi); -+ int fast_ofs = tlb_mask_table_ofs(s, mem_index); -+ int mask_ofs = fast_ofs + offsetof(CPUTLBDescFast, mask); -+ int table_ofs = fast_ofs + offsetof(CPUTLBDescFast, table); -+ -+ new_pool_l8(s, 20, (void*)cur_tci_ptr(s), 0, -+ (TCGReg)args[0], (TCGReg)args[1], (TCGArg)args[2], (int32_t)a_mask, (int32_t)mask_ofs, (uint64_t)s->page_bits, s->page_mask, table_ofs); -+ -+ uint32_t insn = 0; -+ insn = deposit32(insn, 0, 8, opc); -+ tcg_tci_out32(s, insn); -+} -+static void tcg_out_qemu_ld(TCGContext *s, TCGOpcode opc, const TCGArg *args, bool is_64) -+{ -+ tcg_tci_out_qemu_ldst(s, opc, args); -+ tcg_wasm_out_qemu_ld(s, args, is_64); -+} -+static void tcg_out_qemu_st(TCGContext *s, TCGOpcode opc, const TCGArg *args, bool is_64) -+{ -+ wasm_tci_only_tb = true; -+ tcg_tci_out_qemu_ldst(s, opc, args); -+ tcg_wasm_out_qemu_st(s, args, is_64); -+} -+static void tcg_out_deposit_i32(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg arg1, TCGReg arg2, int pos, int len) -+{ -+ TCGArg max = opc == INDEX_op_deposit_i32 ? 32 : 64; -+ tcg_tci_out_op_rrrbb(s, opc, dest, arg1, arg2, pos, len); -+ tcg_wasm_out_deposit_i32(s, dest, arg1, arg2, pos, len); -+} -+static void tcg_out_deposit_i64(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg arg1, TCGReg arg2, int pos, int len) -+{ -+ TCGArg max = opc == INDEX_op_deposit_i32 ? 32 : 64; -+ tcg_tci_out_op_rrrbb(s, opc, dest, arg1, arg2, pos, len); -+ tcg_wasm_out_deposit_i64(s, dest, arg1, arg2, pos, len); -+} -+static void tcg_out_extract_i32(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg arg1, int pos, int len) -+{ -+ TCGArg max = tcg_op_defs[opc].flags & TCG_OPF_64BIT ? 64 : 32; -+ tcg_tci_out_op_rrbb(s, opc, dest, arg1, pos, len); -+ tcg_wasm_out_extract(s, dest, arg1, pos, len, TCG_TYPE_I32, false); -+} -+static void tcg_out_extract_i64(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg arg1, int pos, int len) -+{ -+ TCGArg max = tcg_op_defs[opc].flags & TCG_OPF_64BIT ? 64 : 32; -+ tcg_tci_out_op_rrbb(s, opc, dest, arg1, pos, len); -+ tcg_wasm_out_extract(s, dest, arg1, pos, len, TCG_TYPE_I64, false); -+} -+static void tcg_out_sextract_i32(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg arg1, int pos, int len) -+{ -+ TCGArg max = tcg_op_defs[opc].flags & TCG_OPF_64BIT ? 64 : 32; -+ tcg_tci_out_op_rrbb(s, opc, dest, arg1, pos, len); -+ tcg_wasm_out_extract(s, dest, arg1, pos, len, TCG_TYPE_I32, true); -+} -+static void tcg_out_sextract_i64(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg arg1, int pos, int len) -+{ -+ TCGArg max = tcg_op_defs[opc].flags & TCG_OPF_64BIT ? 64 : 32; -+ tcg_tci_out_op_rrbb(s, opc, dest, arg1, pos, len); -+ tcg_wasm_out_extract(s, dest, arg1, pos, len, TCG_TYPE_I64, true); -+} -+static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) -+{ -+ tcg_tci_out_ext8s(s, type, ret, arg); -+ tcg_wasm_out_ext8s(s, type, ret, arg); -+} -+static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) -+{ -+ tcg_tci_out_ext16s(s, type, ret, arg); -+ tcg_wasm_out_ext16s(s, type, ret, arg); -+} -+static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_tci_out_ext8u(s, ret, arg); -+ tcg_wasm_out_ext8u(s, ret, arg); -+} -+static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_tci_out_ext16u(s, ret, arg); -+ tcg_wasm_out_ext16u(s, ret, arg); -+} -+static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_tci_out_ext32s(s, ret, arg); -+ tcg_wasm_out_ext32s(s, ret, arg); -+} -+static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_tci_out_ext32u(s, ret, arg); -+ tcg_wasm_out_ext32u(s, ret, arg); -+} -+static void tcg_out_exts_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_tci_out_exts_i32_i64(s, ret, arg); -+ tcg_wasm_out_exts_i32_i64(s, ret, arg); -+} -+static void tcg_out_extu_i32_i64(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_tci_out_extu_i32_i64(s, ret, arg); -+ tcg_wasm_out_extu_i32_i64(s, ret, arg); -+} -+ -+static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg rd, TCGReg rs) -+{ -+ tcg_tci_out_extrl_i64_i32(s, rd, rs); -+ tcg_wasm_out_extrl_i64_i32(s, rd, rs); -+} -+ -+static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) -+{ -+ tcg_tci_out_mov(s, type, ret, arg); -+ tcg_wasm_out_mov(s, type, ret, arg); -+ return true; -+} -+static void tcg_out_movi(TCGContext *s, TCGType type, -+ TCGReg ret, tcg_target_long arg) -+{ -+ tcg_tci_out_movi(s, type, ret, arg); -+ tcg_wasm_out_movi(s, type, ret, arg); -+} -+static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs, -+ tcg_target_long imm) -+{ -+ g_assert_not_reached(); -+} -+static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2) -+{ -+ return false; -+} -+static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) -+{ -+ tcg_tci_out_exit_tb(s, arg); -+ tcg_wasm_out_exit_tb(s, arg); -+} -+static void tcg_out_goto_tb(TCGContext *s, int which) -+{ -+ tcg_tci_out_goto_tb(s, which); -+ tcg_wasm_out_goto_tb(s, which); -+} -+static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, -+ TCGReg base, intptr_t ofs) -+{ -+ return false; -+} -+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, -+ const TCGHelperInfo *info) -+{ -+ tcg_tci_out_call(s, target, info); -+ tcg_wasm_out_call(s, target, info); -+} -+ -+static void tcg_out_op(TCGContext *s, TCGOpcode opc, -+ const TCGArg args[TCG_MAX_OP_ARGS], -+ const int const_args[TCG_MAX_OP_ARGS]) -+{ -+ switch (opc) { -+ case INDEX_op_goto_ptr: -+ tcg_out_goto_ptr(s, opc, args[0]); -+ break; -+ case INDEX_op_br: -+ tcg_out_br(s, opc, arg_label(args[0])); -+ break; -+ case INDEX_op_setcond_i32: -+ tcg_out_setcond_i32(s, opc, args[3], args[0], args[1], args[2]);// -+ break; -+ case INDEX_op_setcond_i64: -+ tcg_out_setcond_i64(s, opc, args[3], args[0], args[1], args[2]);// -+ break; -+ case INDEX_op_movcond_i32: -+ tcg_out_movcond_i32(s, opc, args[5], args[0], args[1], args[2], args[3], args[4]);// -+ break; -+ case INDEX_op_movcond_i64: -+ tcg_out_movcond_i64(s, opc, args[5], args[0], args[1], args[2], args[3], args[4]);// -+ break; -+ case INDEX_op_ld_i64: -+ tcg_out_ld(s, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_ld8s_i32: -+ case INDEX_op_ld8s_i64: -+ tcg_out_ld8s(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_ld8u_i32: -+ case INDEX_op_ld8u_i64: -+ tcg_out_ld8u(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_ld16s_i32: -+ case INDEX_op_ld16s_i64: -+ tcg_out_ld16s(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_ld16u_i32: -+ case INDEX_op_ld16u_i64: -+ tcg_out_ld16u(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_ld32u_i64: -+ tcg_out_ld32u(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_ld_i32: -+ case INDEX_op_ld32s_i64: -+ tcg_out_ld32s(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_st_i64: -+ tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_st8_i32: -+ case INDEX_op_st8_i64: -+ tcg_out_st8(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_st16_i32: -+ case INDEX_op_st16_i64: -+ tcg_out_st16(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_st_i32: -+ case INDEX_op_st32_i64: -+ tcg_out_st32(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_add_i32: -+ case INDEX_op_add_i64: -+ tcg_out_i64_calc_add(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_sub_i32: -+ case INDEX_op_sub_i64: -+ tcg_out_i64_calc_sub(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_mul_i32: -+ case INDEX_op_mul_i64: -+ tcg_out_i64_calc_mul(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_and_i32: -+ case INDEX_op_and_i64: -+ tcg_out_i64_calc_and(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_or_i32: -+ case INDEX_op_or_i64: -+ tcg_out_i64_calc_or(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_xor_i32: -+ case INDEX_op_xor_i64: -+ tcg_out_i64_calc_xor(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_shl_i32: -+ tcg_out_shl(s, opc, TCG_TYPE_I32, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_shl_i64: -+ tcg_out_shl(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_shr_i32: -+ tcg_out_shr_u(s, opc, TCG_TYPE_I32, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_shr_i64: -+ tcg_out_shr_u(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_sar_i32: -+ tcg_out_shr_s(s, opc, TCG_TYPE_I32, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_sar_i64: -+ tcg_out_shr_s(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_rotl_i32: -+ tcg_out_i32_rotl(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_rotl_i64: -+ tcg_out_i64_calc_rotl(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_rotr_i32: -+ tcg_out_i32_rotr(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_rotr_i64: -+ tcg_out_i64_calc_rotr(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_div_i32: -+ tcg_out_i64_calc_div_s(s, opc, TCG_TYPE_I32, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_div_i64: -+ tcg_out_i64_calc_div_s(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_divu_i32: -+ tcg_out_i64_calc_div_u(s, opc, TCG_TYPE_I32, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_divu_i64: -+ tcg_out_i64_calc_div_u(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_rem_i32: -+ tcg_out_i64_calc_rem_s(s, opc, TCG_TYPE_I32, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_rem_i64: -+ tcg_out_i64_calc_rem_s(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_remu_i32: -+ tcg_out_i64_calc_rem_u(s, opc, TCG_TYPE_I32, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_remu_i64: -+ tcg_out_i64_calc_rem_u(s, opc, TCG_TYPE_I64, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_andc_i32: -+ case INDEX_op_andc_i64: -+ tcg_out_andc(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_orc_i32: -+ case INDEX_op_orc_i64: -+ tcg_out_orc(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_eqv_i32: -+ case INDEX_op_eqv_i64: -+ tcg_out_eqv(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_nand_i32: -+ case INDEX_op_nand_i64: -+ tcg_out_nand(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_nor_i32: -+ case INDEX_op_nor_i64: -+ tcg_out_nor(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_clz_i32: -+ tcg_out_clz32(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_clz_i64: -+ tcg_out_clz64(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_ctz_i32: -+ tcg_out_ctz32(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_ctz_i64: -+ tcg_out_ctz64(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_brcond_i32: -+ tcg_out_brcond_i32(s, opc, args[2], args[0], args[1], arg_label(args[3])); -+ break; -+ case INDEX_op_brcond_i64: -+ tcg_out_brcond_i64(s, opc, args[2], args[0], args[1], arg_label(args[3])); -+ break; -+ case INDEX_op_neg_i32: -+ case INDEX_op_neg_i64: -+ tcg_out_neg(s, opc, args[0], args[1]); -+ break; -+ case INDEX_op_not_i32: -+ case INDEX_op_not_i64: -+ tcg_out_not(s, opc, args[0], args[1]); -+ break; -+ case INDEX_op_ctpop_i32: -+ tcg_out_ctpop_i32(s, opc, args[1], args[2]); -+ break; -+ case INDEX_op_ctpop_i64: -+ tcg_out_ctpop_i64(s, opc, args[1], args[2]); -+ break; -+ case INDEX_op_add2_i32: -+ case INDEX_op_add2_i64: -+ tcg_out_add2(s, opc, args[0], args[1], args[2], args[3], args[4], args[5]); -+ break; -+ case INDEX_op_sub2_i32: -+ case INDEX_op_sub2_i64: -+ tcg_out_sub2(s, opc, args[0], args[1], args[2], args[3], args[4], args[5]); -+ break; -+ case INDEX_op_qemu_ld_a32_i32: -+ case INDEX_op_qemu_ld_a64_i32: -+ tcg_out_qemu_ld(s, opc, args, false); -+ break; -+ case INDEX_op_qemu_st_a32_i32: -+ case INDEX_op_qemu_st_a64_i32: -+ tcg_out_qemu_st(s, opc, args, false); -+ break; -+ case INDEX_op_qemu_ld_a32_i64: -+ case INDEX_op_qemu_ld_a64_i64: -+ tcg_out_qemu_ld(s, opc, args, true); -+ break; -+ case INDEX_op_qemu_st_a32_i64: -+ case INDEX_op_qemu_st_a64_i64: -+ tcg_out_qemu_st(s, opc, args, true); -+ break; -+ case INDEX_op_extrl_i64_i32: -+ tcg_out_extrl_i64_i32(s, args[0], args[1]); -+ break; -+ case INDEX_op_mb: -+ tcg_tci_out_op_v(s, opc); -+ tcg_wasm_out8(s, 0x01); // nop -+ break; -+ case INDEX_op_extract_i32: -+ tcg_out_extract_i32(s, opc, args[0], args[1], args[2], args[3]); -+ break; -+ case INDEX_op_extract_i64: -+ tcg_out_extract_i64(s, opc, args[0], args[1], args[2], args[3]); -+ break; -+ case INDEX_op_sextract_i32: -+ tcg_out_sextract_i32(s, opc, args[0], args[1], args[2], args[3]); -+ break; -+ case INDEX_op_sextract_i64: -+ tcg_out_sextract_i64(s, opc, args[0], args[1], args[2], args[3]); -+ break; -+ case INDEX_op_deposit_i32: -+ tcg_out_deposit_i32(s, opc, args[0], args[1], args[2], args[3], args[4]); -+ break; -+ case INDEX_op_deposit_i64: -+ tcg_out_deposit_i64(s, opc, args[0], args[1], args[2], args[3], args[4]); -+ break; -+ case INDEX_op_bswap16_i32: -+ tcg_out_bswap16_i32(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_bswap16_i64: -+ tcg_out_bswap16_i64(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_bswap32_i32: -+ tcg_out_bswap32_i32(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_bswap32_i64: -+ tcg_out_bswap32_i64(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_bswap64_i64: -+ tcg_out_bswap64_i64(s, opc, args[0], args[1], args[2]); -+ break; -+ case INDEX_op_muls2_i32: -+ tcg_out_muls2_i32(s, opc, args[0], args[1], args[2], args[3]); -+ break; -+ case INDEX_op_mulu2_i32: -+ tcg_out_mulu2_i32(s, opc, args[0], args[1], args[2], args[3]); -+ break; -+ default: -+ g_assert_not_reached(); -+ break; -+ } -+ return; -+} -+ -+void tcg_out_init() { -+ current_label_pos = 0; -+ env_cached = false; -+ wasm_tci_only_tb = false; -+} -+ -+/* Test if a constant matches the constraint. */ -+static bool tcg_target_const_match(int64_t val, int ct, TCGType type, -+ TCGCond cond, int vece) -+{ -+ return ct & TCG_CT_CONST; -+} -+ -+static void tcg_out_tb_start(TCGContext *s) -+{ -+ /* nothing to do */ -+} -+ -+bool tcg_target_has_memory_bswap(MemOp memop) -+{ -+ return false; -+} -+ -+static void tcg_target_init(TCGContext *s) -+{ -+ /* The current code uses uint8_t for tcg operations. */ -+ tcg_debug_assert(tcg_op_defs_max <= UINT8_MAX); -+ -+ /* Registers available for 32 bit operations. */ -+ tcg_target_available_regs[TCG_TYPE_I64] = BIT(TCG_TARGET_NB_REGS) - 1; -+ tcg_target_available_regs[TCG_TYPE_I32] = BIT(TCG_TARGET_NB_REGS) - 1; -+ /* -+ * The interpreter "registers" are in the local stack frame and -+ * cannot be clobbered by the called helper functions. However, -+ * the interpreter assumes a 64-bit return value and assigns to -+ * the return value registers. -+ */ -+ tcg_target_call_clobber_regs = -+ MAKE_64BIT_MASK(TCG_REG_R0, 128 / TCG_TARGET_REG_BITS); -+ -+ s->reserved_regs = 0; -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK); -+ -+ /* The call arguments come first, followed by the temp storage. */ -+ tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE, -+ TCG_STATIC_FRAME_SIZE); -+} -+ -+/* Generate global QEMU prologue and epilogue code. */ -+static inline void tcg_target_qemu_prologue(TCGContext *s) -+{ -+} -diff --git c/tcg/wasm32/tcg-target.h w/tcg/wasm32/tcg-target.h -new file mode 100644 -index 0000000000..7346c3a76e ---- /dev/null -+++ w/tcg/wasm32/tcg-target.h -@@ -0,0 +1,153 @@ -+/* -+ * Tiny Code Generator for QEMU -+ * -+ * Copyright (c) 2009, 2011 Stefan Weil -+ * -+ * Based on tci/tcg-target.h -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#ifndef TCG_TARGET_H -+#define TCG_TARGET_H -+ -+#define TCG_TARGET_INSN_UNIT_SIZE 1 -+#define TCG_TARGET_TLB_DISPLACEMENT_BITS 32 -+#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1) -+ -+/* Optional instructions. */ -+ -+#define TCG_TARGET_HAS_bswap16_i32 1 -+#define TCG_TARGET_HAS_bswap32_i32 1 -+#define TCG_TARGET_HAS_div_i32 1 -+#define TCG_TARGET_HAS_rem_i32 1 -+#define TCG_TARGET_HAS_ext8s_i32 1 -+#define TCG_TARGET_HAS_ext16s_i32 1 -+#define TCG_TARGET_HAS_ext8u_i32 1 -+#define TCG_TARGET_HAS_ext16u_i32 1 -+#define TCG_TARGET_HAS_andc_i32 1 -+#define TCG_TARGET_HAS_deposit_i32 1 -+#define TCG_TARGET_HAS_extract_i32 1 -+#define TCG_TARGET_HAS_sextract_i32 1 -+#define TCG_TARGET_HAS_extract2_i32 0 -+#define TCG_TARGET_HAS_eqv_i32 1 -+#define TCG_TARGET_HAS_nand_i32 1 -+#define TCG_TARGET_HAS_nor_i32 1 -+#define TCG_TARGET_HAS_clz_i32 1 -+#define TCG_TARGET_HAS_ctz_i32 1 -+#define TCG_TARGET_HAS_ctpop_i32 1 -+#define TCG_TARGET_HAS_neg_i32 1 -+#define TCG_TARGET_HAS_not_i32 1 -+#define TCG_TARGET_HAS_orc_i32 1 -+#define TCG_TARGET_HAS_rot_i32 1 -+#define TCG_TARGET_HAS_movcond_i32 1 -+#define TCG_TARGET_HAS_negsetcond_i32 0 -+#define TCG_TARGET_HAS_muls2_i32 1 -+#define TCG_TARGET_HAS_muluh_i32 0 -+#define TCG_TARGET_HAS_mulsh_i32 0 -+#define TCG_TARGET_HAS_qemu_st8_i32 0 -+ -+#define TCG_TARGET_HAS_extr_i64_i32 0 -+#define TCG_TARGET_HAS_extrl_i64_i32 1 -+#define TCG_TARGET_HAS_extrh_i64_i32 0 -+#define TCG_TARGET_HAS_bswap16_i64 1 -+#define TCG_TARGET_HAS_bswap32_i64 1 -+#define TCG_TARGET_HAS_bswap64_i64 1 -+#define TCG_TARGET_HAS_deposit_i64 1 -+#define TCG_TARGET_HAS_extract_i64 1 -+#define TCG_TARGET_HAS_sextract_i64 1 -+#define TCG_TARGET_HAS_extract2_i64 0 -+#define TCG_TARGET_HAS_div_i64 1 -+#define TCG_TARGET_HAS_rem_i64 1 -+#define TCG_TARGET_HAS_ext8s_i64 1 -+#define TCG_TARGET_HAS_ext16s_i64 1 -+#define TCG_TARGET_HAS_ext32s_i64 1 -+#define TCG_TARGET_HAS_ext8u_i64 1 -+#define TCG_TARGET_HAS_ext16u_i64 1 -+#define TCG_TARGET_HAS_ext32u_i64 1 -+#define TCG_TARGET_HAS_andc_i64 1 -+#define TCG_TARGET_HAS_eqv_i64 1 -+#define TCG_TARGET_HAS_nand_i64 1 -+#define TCG_TARGET_HAS_nor_i64 1 -+#define TCG_TARGET_HAS_clz_i64 1 -+#define TCG_TARGET_HAS_ctz_i64 1 -+#define TCG_TARGET_HAS_ctpop_i64 1 -+#define TCG_TARGET_HAS_neg_i64 1 -+#define TCG_TARGET_HAS_not_i64 1 -+#define TCG_TARGET_HAS_orc_i64 1 -+#define TCG_TARGET_HAS_rot_i64 1 -+#define TCG_TARGET_HAS_negsetcond_i64 0 -+#define TCG_TARGET_HAS_tst 0 -+#define TCG_TARGET_HAS_tst_vec 0 -+#define TCG_TARGET_HAS_movcond_i64 1 -+#define TCG_TARGET_HAS_muls2_i64 0 -+#define TCG_TARGET_HAS_add2_i32 1 -+#define TCG_TARGET_HAS_sub2_i32 1 -+#define TCG_TARGET_HAS_mulu2_i32 1 -+#define TCG_TARGET_HAS_add2_i64 1 -+#define TCG_TARGET_HAS_sub2_i64 1 -+#define TCG_TARGET_HAS_mulu2_i64 0 -+#define TCG_TARGET_HAS_muluh_i64 0 -+#define TCG_TARGET_HAS_mulsh_i64 0 -+ -+#define TCG_TARGET_HAS_qemu_ldst_i128 0 -+ -+/* Number of registers available. */ -+#define TCG_TARGET_NB_REGS 16 -+ -+/* List of registers which are used by TCG. */ -+typedef enum { -+ TCG_REG_R0 = 0, -+ TCG_REG_R1, -+ TCG_REG_R2, -+ TCG_REG_R3, -+ TCG_REG_R4, -+ TCG_REG_R5, -+ TCG_REG_R6, -+ TCG_REG_R7, -+ TCG_REG_R8, -+ TCG_REG_R9, -+ TCG_REG_R10, -+ TCG_REG_R11, -+ TCG_REG_R12, -+ TCG_REG_R13, -+ TCG_REG_R14, -+ TCG_REG_R15, -+ -+ TCG_REG_TMP = TCG_REG_R13, -+ TCG_AREG0 = TCG_REG_R14, -+ TCG_REG_CALL_STACK = TCG_REG_R15, -+} TCGReg; -+ -+/* Used for function call generation. */ -+#define TCG_TARGET_CALL_STACK_OFFSET 0 -+#define TCG_TARGET_STACK_ALIGN 8 -+#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL -+#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL -+#define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_NORMAL -+#define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_NORMAL -+ -+#define HAVE_TCG_QEMU_TB_EXEC -+#define TCG_TARGET_NEED_POOL_LABELS -+ -+#define TCG_TARGET_DEFAULT_MO (0) -+ -+#define TCG_TARGET_HAS_MEMORY_BSWAP 0 -+ -+#endif /* TCG_TARGET_H */ -diff --git c/util/cacheflush.c w/util/cacheflush.c -index a08906155a..babbb644e5 100644 ---- c/util/cacheflush.c -+++ w/util/cacheflush.c -@@ -225,7 +225,7 @@ static void __attribute__((constructor)) init_cache_info(void) - * Architecture (+ OS) specific cache flushing mechanisms. - */ - --#if defined(__i386__) || defined(__x86_64__) || defined(__s390__) -+#if defined(__i386__) || defined(__x86_64__) || defined(__s390__) || defined(EMSCRIPTEN) - - /* Caches are coherent and do not require flushing; symbol inline. */ - -diff --git c/util/coroutine-fiber.c w/util/coroutine-fiber.c -new file mode 100644 -index 0000000000..2ce1575362 ---- /dev/null -+++ w/util/coroutine-fiber.c -@@ -0,0 +1,123 @@ -+/* -+ * emscripten fiber coroutine initialization code -+ * based on coroutine-ucontext.c -+ * -+ * Copyright (C) 2006 Anthony Liguori -+ * Copyright (C) 2011 Kevin Wolf -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.0 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see . -+ */ -+ -+#include "qemu/osdep.h" -+#include "qemu/coroutine_int.h" -+#include "qemu/coroutine-tls.h" -+ -+#include -+ -+typedef struct { -+ Coroutine base; -+ -+ void *asyncify_stack; -+ size_t asyncify_stack_size; -+ -+ CoroutineAction action; -+ -+ emscripten_fiber_t fiber; -+} CoroutineEmscripten; -+ -+/** -+ * Per-thread coroutine bookkeeping -+ */ -+QEMU_DEFINE_STATIC_CO_TLS(Coroutine *, current); -+QEMU_DEFINE_STATIC_CO_TLS(CoroutineEmscripten *, leader); -+size_t leader_asyncify_stack_size = COROUTINE_STACK_SIZE; -+ -+static void coroutine_trampoline(void *co_) -+{ -+ Coroutine *co = co_; -+ -+ while (true) { -+ co->entry(co->entry_arg); -+ qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE); -+ } -+} -+ -+Coroutine *qemu_coroutine_new(void) -+{ -+ CoroutineEmscripten *co; -+ -+ co = g_malloc0(sizeof(*co)); -+ -+ size_t stack_size = COROUTINE_STACK_SIZE; -+ char *stack = qemu_alloc_stack(&stack_size); -+ -+ co->asyncify_stack_size = COROUTINE_STACK_SIZE; -+ co->asyncify_stack = g_malloc0(co->asyncify_stack_size); -+ emscripten_fiber_init(&co->fiber, coroutine_trampoline, &co->base, -+ stack, stack_size, co->asyncify_stack, co->asyncify_stack_size); -+ -+ return &co->base; -+} -+ -+void qemu_coroutine_delete(Coroutine *co_) -+{ -+ CoroutineEmscripten *co = DO_UPCAST(CoroutineEmscripten, base, co_); -+ -+ g_free(co->asyncify_stack); -+ g_free(co); -+} -+ -+#include "../tcg/wasm32.h" -+ -+CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, -+ CoroutineAction action) -+{ -+ CoroutineEmscripten *from = DO_UPCAST(CoroutineEmscripten, base, from_); -+ CoroutineEmscripten *to = DO_UPCAST(CoroutineEmscripten, base, to_); -+ -+#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) -+ set_unwinding_flag(); -+#endif -+ -+ set_current(to_); -+ to->action = action; -+ emscripten_fiber_swap(&from->fiber, &to->fiber); -+ return from->action; -+} -+ -+Coroutine *qemu_coroutine_self(void) -+{ -+ Coroutine *self = get_current(); -+ -+ if (!self) { -+ CoroutineEmscripten *leaderp = get_leader(); -+ if (!leaderp) { -+ leaderp = g_malloc0(sizeof(*leaderp)); -+ leaderp->asyncify_stack = g_malloc0(leader_asyncify_stack_size); -+ leaderp->asyncify_stack_size = leader_asyncify_stack_size; -+ emscripten_fiber_init_from_current_context(&leaderp->fiber, leaderp->asyncify_stack, leaderp->asyncify_stack_size); -+ set_leader(leaderp); -+ } -+ self = &leaderp->base; -+ set_current(self); -+ } -+ return self; -+} -+ -+bool qemu_in_coroutine(void) -+{ -+ Coroutine *self = get_current(); -+ -+ return self && self->caller; -+} -diff --git c/util/int128.c w/util/int128.c -index df6c6331bd..c442ff4da8 100644 ---- c/util/int128.c -+++ w/util/int128.c -@@ -144,7 +144,7 @@ Int128 int128_rems(Int128 a, Int128 b) - return r; - } - --#elif defined(CONFIG_TCG_INTERPRETER) -+#elif defined(CONFIG_TCG_INTERPRETER) || defined(EMSCRIPTEN) - - Int128 int128_divu(Int128 a_s, Int128 b_s) - { -diff --git c/util/meson.build w/util/meson.build -index 5d8bef9891..e107fbfb69 100644 ---- c/util/meson.build -+++ w/util/meson.build -@@ -11,7 +11,9 @@ if host_os != 'windows' - endif - util_ss.add(files('compatfd.c')) - util_ss.add(files('event_notifier-posix.c')) -- util_ss.add(files('mmap-alloc.c')) -+ if host_os != 'emscripten' -+ util_ss.add(files('mmap-alloc.c')) -+ endif - freebsd_dep = [] - if host_os == 'freebsd' - freebsd_dep = util -diff --git c/util/mmap-alloc.c w/util/mmap-alloc.c -index ed14f9c64d..8c8708ca4d 100644 ---- c/util/mmap-alloc.c -+++ w/util/mmap-alloc.c -@@ -250,6 +250,11 @@ void *qemu_ram_mmap(int fd, - uint32_t qemu_map_flags, - off_t map_offset) - { -+#if defined(EMSCRIPTEN) -+ void *ptr; -+ ptr = mmap_activate(0, size + align, fd, qemu_map_flags, map_offset); -+ return (void *)QEMU_ALIGN_UP((uintptr_t)ptr, align); -+#else - const size_t guard_pagesize = mmap_guard_pagesize(fd); - size_t offset, total; - void *ptr, *guardptr; -@@ -292,6 +297,7 @@ void *qemu_ram_mmap(int fd, - } - - return ptr; -+#endif - } - - void qemu_ram_munmap(int fd, void *ptr, size_t size) -diff --git c/util/oslib-posix.c w/util/oslib-posix.c -index 11b35e48fb..760c3d4f4c 100644 ---- c/util/oslib-posix.c -+++ w/util/oslib-posix.c -@@ -58,6 +58,7 @@ - #include - #endif - -+#include "qemu/memalign.h" - #include "qemu/mmap-alloc.h" - - #define MAX_MEM_PREALLOC_THREAD_COUNT 16 -@@ -192,14 +193,18 @@ fail_close: - void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared, - bool noreserve) - { -+ size_t align = QEMU_VMALLOC_ALIGN; -+#ifndef EMSCRIPTEN - const uint32_t qemu_map_flags = (shared ? QEMU_MAP_SHARED : 0) | - (noreserve ? QEMU_MAP_NORESERVE : 0); -- size_t align = QEMU_VMALLOC_ALIGN; - void *ptr = qemu_ram_mmap(-1, size, align, qemu_map_flags, 0); - - if (ptr == MAP_FAILED) { - return NULL; - } -+#else -+ void *ptr = qemu_memalign(align, size); -+#endif - - if (alignment) { - *alignment = align; -@@ -212,7 +217,11 @@ void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared, - void qemu_anon_ram_free(void *ptr, size_t size) - { - trace_qemu_anon_ram_free(ptr, size); -+#ifndef EMSCRIPTEN - qemu_ram_munmap(-1, ptr, size); -+#else -+ qemu_vfree(ptr); -+#endif - } - - void qemu_socket_set_block(int fd) -@@ -573,7 +582,11 @@ bool qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads, - { - static gsize initialized; - int ret; -+#ifndef EMSCRIPTEN - size_t hpagesize = qemu_fd_getpagesize(fd); -+#else -+ size_t hpagesize = qemu_real_host_page_size(); -+#endif - size_t numpages = DIV_ROUND_UP(sz, hpagesize); - bool use_madv_populate_write; - struct sigaction act; diff --git a/scripts/build-qemu-wasm.sh b/scripts/build-qemu-wasm.sh index e611844..5a3b34c 100755 --- a/scripts/build-qemu-wasm.sh +++ b/scripts/build-qemu-wasm.sh @@ -2,13 +2,12 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" -SRC="${QEMU_WASM_SRC:-$ROOT/_scratch/qemu-wasm-src}" +# QEMU source is the third_party/qemu submodule (fork with the xteink machine + +# wasm32 backend). Edit it in place; builds compile incrementally, no patching. +SRC="${QEMU_WASM_SRC:-$ROOT/third_party/qemu}" OUT="${WASM_OUT:-$ROOT/dist/wasm}" [[ "$SRC" = /* ]] || SRC="$ROOT/$SRC" [[ "$OUT" = /* ]] || OUT="$ROOT/$OUT" -TAG="esp-develop-9.2.2-20260417" -COMMIT="40edccac415693c5130f91c01d84176ae6008566" -QEMU_WASM_COMMIT="0ef7b4e2814b231705d8371dd7997f5b72e70baf" IMAGE="xteink-qemu-wasm-build" JOBS="${JOBS:-$(nproc 2>/dev/null || echo 2)}" @@ -20,35 +19,13 @@ else ENGINE=docker fi -# Dev Mode - Build directly out of an already-patched working tree (e.g. _scratch/qemu-fix-src); -# skip clone/commit-check/patch so edits compile incrementally without the patch round-trip. -if [ -n "${QEMU_WASM_DEV:-}" ]; then - cd "$SRC" -else - if [ ! -d "$SRC/.git" ]; then - git clone --depth 1 --branch "$TAG" https://github.com/espressif/qemu "$SRC" - fi - - cd "$SRC" - if [ "$(git rev-parse HEAD)" != "$COMMIT" ]; then - echo "QEMU source must be $COMMIT ($TAG)" >&2 - exit 1 - fi - - # Re-apply Patches On Drift - The source tree is a build artifact of the patches; reset and re-apply whenever a patch is newer than the last apply so `make web` never silently rebuilds stale sources. - STAMP=".xteink-patch-stamp" - if [ ! -f hw/display/xteink_x3_eink.c ] || [ ! -f tcg/wasm32.c ] \ - || [ "$ROOT/qemu/patches/0001-xteink-machine.patch" -nt "$STAMP" ] \ - || [ "$ROOT/qemu/patches/0002-qemu-wasm.patch" -nt "$STAMP" ]; then - git reset --hard "$COMMIT" - git clean -fdx -e build - git apply "$ROOT/qemu/patches/0001-xteink-machine.patch" - git apply --whitespace=nowarn "$ROOT/qemu/patches/0002-qemu-wasm.patch" - touch "$STAMP" - fi +if [ ! -f "$SRC/tcg/wasm32.c" ]; then + echo "third_party/qemu submodule not checked out; run: git submodule update --init" >&2 + exit 1 fi +cd "$SRC" -printf 'Building Emscripten environment (qemu-wasm %s)\n' "$QEMU_WASM_COMMIT" +printf 'Building Emscripten environment for %s\n' "$SRC" "$ENGINE" build -t "$IMAGE" -f "$ROOT/qemu/wasm/Dockerfile" "$ROOT/qemu/wasm" FLAGS="-O3 -Wno-error=unused-command-line-argument -matomics -mbulk-memory -DNDEBUG -DG_DISABLE_ASSERT -D_GNU_SOURCE -sASYNCIFY=1 -pthread -sPROXY_TO_PTHREAD=1 -sFORCE_FILESYSTEM -sALLOW_TABLE_GROWTH -sINITIAL_MEMORY=64MB -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=1GB -sSTACK_SIZE=1048576 -sWASM_BIGINT -sMALLOC=mimalloc -sEXPORT_ES6=1 -sASYNCIFY_IMPORTS=ffi_call_js" diff --git a/third_party/qemu b/third_party/qemu new file mode 160000 index 0000000..13b9231 --- /dev/null +++ b/third_party/qemu @@ -0,0 +1 @@ +Subproject commit 13b9231f6eea9a88fc83ef7395ae0909ba6f67b1