Files
xteink-web-emulator/qemu/patches/0002-qemu-wasm.patch
T
2026-07-20 18:00:59 -04:00

7874 lines
260 KiB
Diff

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 <sys/diskslice.h>
#endif
+#ifdef EMSCRIPTEN
+#include <sys/ioctl.h>
+#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 <emscripten/emscripten.h>
+
+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 <emscripten/emscripten.h>
+#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 <setjmp.h>
#include <signal.h>
-#ifdef CONFIG_IOVEC
+#if defined(CONFIG_IOVEC) || defined(EMSCRIPTEN)
#include <sys/uio.h>
#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 <ffi.h>
#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 <glib.h>
#include <unistd.h>
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <string.h>
+#include <emscripten.h>
+#include <emscripten/threading.h>
+#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_<arguments>
+ * 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] = &regs[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(&regs[TCG_REG_R0], stack, 8);
+ break;
+ case 3: /* Int128 */
+ memcpy(&regs[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(&regs[r0], &regs[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(&regs[r0], &regs[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 <n> outputs and <m> 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 <arnaud.patard@rtp-net.org>
+ * Copyright (c) 2009 Aurelien Jarno <aurelien@aurel32.net>
+ * 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 <emscripten.h>
+#include <ffi.h>
+#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<<len)-1)<<pos;
+ tcg_wasm_out_op_global_get_r(s, arg1);
+ tcg_wasm_out_op_i32_wrap_i64(s);
+ tcg_wasm_out_op_i32_const(s, ~mask);
+ tcg_wasm_out_op_i32_and(s);
+
+ tcg_wasm_out_op_global_get_r(s, arg2);
+ tcg_wasm_out_op_i32_wrap_i64(s);
+ tcg_wasm_out_op_i32_const(s, pos);
+ tcg_wasm_out_op_i32_shl(s);
+ tcg_wasm_out_op_i32_const(s, mask);
+ tcg_wasm_out_op_i32_and(s);
+
+ tcg_wasm_out_op_i32_or(s);
+
+ tcg_wasm_out_op_i64_extend_i32_u(s);
+ tcg_wasm_out_op_global_set_r(s, dest);
+}
+
+static void tcg_wasm_out_deposit_i64(TCGContext *s, TCGReg dest, TCGReg arg1, TCGReg arg2, int pos, int len)
+{
+ int64_t mask = (((int64_t)1<<len)-1)<<pos;
+ tcg_wasm_out_op_global_get_r(s, arg1);
+ tcg_wasm_out_op_i64_const(s, ~mask);
+ tcg_wasm_out_op_i64_and(s);
+
+ tcg_wasm_out_op_global_get_r(s, arg2);
+ tcg_wasm_out_op_i64_const(s, pos);
+ tcg_wasm_out_op_i64_shl(s);
+ tcg_wasm_out_op_i64_const(s, mask);
+ tcg_wasm_out_op_i64_and(s);
+
+ tcg_wasm_out_op_i64_or(s);
+
+ tcg_wasm_out_op_global_set_r(s, dest);
+}
+
+static void tcg_wasm_out_extract(TCGContext *s, TCGReg dest, TCGReg arg1, int pos, int len, TCGType type, bool sign)
+{
+ int rs;
+ switch (type) {
+ case TCG_TYPE_I32:
+ rs = 32 - len;
+ break;
+ case TCG_TYPE_I64:
+ rs = 64 - len;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ int sl = rs - pos;
+ tcg_wasm_out_op_global_get_r(s, arg1);
+ if (sl > 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, &reg_idx, &stack_offset);
+ tcg_wasm_out_op_i32_wrap_i64(s);
+ break;
+ case dh_typecode_i64:
+ case dh_typecode_s64:
+ push_arg_i64(s, &reg_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, &reg_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, &reg_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 <anthony@codemonkey.ws>
+ * Copyright (C) 2011 Kevin Wolf <kwolf@redhat.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/coroutine_int.h"
+#include "qemu/coroutine-tls.h"
+
+#include <emscripten/fiber.h>
+
+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 <lwp.h>
#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;