This commit adds qemu_ld and qemu_st by calling the helper functions
corresponding to MemOp.
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
---
tcg/wasm.c | 70 ++++++++++++++++++
tcg/wasm/tcg-target-has.h | 1 +
tcg/wasm/tcg-target.c.inc | 145 ++++++++++++++++++++++++++++++++++++++
3 files changed, 216 insertions(+)
V2:
- This commit generates both Wasm and TCI instrucitons.
diff --git a/tcg/wasm.c b/tcg/wasm.c
index db0c213d92..793c1807c2 100644
--- a/tcg/wasm.c
+++ b/tcg/wasm.c
@@ -63,6 +63,14 @@ static void tci_args_ri(uint32_t insn, TCGReg *r0, tcg_target_ulong *i1)
*i1 = sextract32(insn, 12, 20);
}
+static void tci_args_rrm(uint32_t insn, TCGReg *r0,
+ TCGReg *r1, MemOpIdx *m2)
+{
+ *r0 = extract32(insn, 8, 4);
+ *r1 = extract32(insn, 12, 4);
+ *m2 = extract32(insn, 16, 16);
+}
+
static void tci_args_rrr(uint32_t insn, TCGReg *r0, TCGReg *r1, TCGReg *r2)
{
*r0 = extract32(insn, 8, 4);
@@ -190,6 +198,56 @@ static bool tci_compare64(uint64_t u0, uint64_t u1, TCGCond condition)
return result;
}
+static uint64_t tci_qemu_ld(CPUArchState *env, uint64_t taddr,
+ MemOpIdx oi, const void *tb_ptr)
+{
+ MemOp mop = get_memop(oi);
+ uintptr_t ra = (uintptr_t)tb_ptr;
+
+ 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)
+{
+ MemOp mop = get_memop(oi);
+ uintptr_t ra = (uintptr_t)tb_ptr;
+
+ 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();
+ }
+}
+
static uintptr_t tcg_qemu_tb_exec_tci(CPUArchState *env, const void *v_tb_ptr)
{
const uint32_t *tb_ptr = v_tb_ptr;
@@ -208,6 +266,8 @@ static uintptr_t tcg_qemu_tb_exec_tci(CPUArchState *env, const void *v_tb_ptr)
uint8_t pos, len;
TCGCond condition;
uint32_t tmp32;
+ uint64_t taddr;
+ MemOpIdx oi;
int32_t ofs;
void *ptr;
@@ -496,6 +556,16 @@ static uintptr_t tcg_qemu_tb_exec_tci(CPUArchState *env, const void *v_tb_ptr)
}
tb_ptr = ptr;
break;
+ case INDEX_op_qemu_ld:
+ tci_args_rrm(insn, &r0, &r1, &oi);
+ taddr = regs[r1];
+ regs[r0] = tci_qemu_ld(env, taddr, oi, tb_ptr);
+ break;
+ case INDEX_op_qemu_st:
+ tci_args_rrm(insn, &r0, &r1, &oi);
+ taddr = regs[r1];
+ tci_qemu_st(env, taddr, regs[r0], oi, tb_ptr);
+ break;
default:
g_assert_not_reached();
}
diff --git a/tcg/wasm/tcg-target-has.h b/tcg/wasm/tcg-target-has.h
index a29ceb2ea5..8fe9b45403 100644
--- a/tcg/wasm/tcg-target-has.h
+++ b/tcg/wasm/tcg-target-has.h
@@ -4,6 +4,7 @@
#define TCG_TARGET_HAS_tst 0
#define TCG_TARGET_HAS_extr_i64_i32 0
+#define TCG_TARGET_HAS_qemu_ldst_i128 0
#define TCG_TARGET_extract_valid(type, ofs, len) 0
#define TCG_TARGET_sextract_valid(type, ofs, len) \
diff --git a/tcg/wasm/tcg-target.c.inc b/tcg/wasm/tcg-target.c.inc
index 0606b7de79..e1ee2f6485 100644
--- a/tcg/wasm/tcg-target.c.inc
+++ b/tcg/wasm/tcg-target.c.inc
@@ -985,6 +985,99 @@ static void tcg_wasm_out_call(TCGContext *s, intptr_t func,
gen_call(s, info, func_idx);
}
+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, TCGReg data_reg,
+ TCGReg addr_reg, MemOpIdx oi)
+{
+ intptr_t helper_idx;
+ int64_t func_idx;
+
+ helper_idx = (intptr_t)qemu_ld_helper_ptr(oi);
+ func_idx = get_helper_idx(s, helper_idx);
+ if (func_idx < 0) {
+ func_idx = register_helper(s, helper_idx);
+ }
+
+ /* call the target helper */
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(TCG_AREG0));
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(addr_reg));
+ tcg_wasm_out_op_const(s, OPC_I32_CONST, oi);
+ tcg_wasm_out_op_const(s, OPC_I64_CONST, (intptr_t)s->code_ptr);
+
+ tcg_wasm_out_op_idx(s, OPC_CALL, func_idx);
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_SET, REG_IDX(data_reg));
+}
+
+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;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void tcg_wasm_out_qemu_st(TCGContext *s, TCGReg data_reg,
+ TCGReg addr_reg, MemOpIdx oi)
+{
+ intptr_t helper_idx;
+ int64_t func_idx;
+ MemOp mop = get_memop(oi);
+
+ helper_idx = (intptr_t)qemu_st_helper_ptr(oi);
+ func_idx = get_helper_idx(s, helper_idx);
+ if (func_idx < 0) {
+ func_idx = register_helper(s, helper_idx);
+ }
+
+ /* call the target helper */
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(TCG_AREG0));
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(addr_reg));
+ switch (mop & MO_SSIZE) {
+ case MO_UQ:
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(data_reg));
+ break;
+ default:
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(data_reg));
+ tcg_wasm_out_op(s, OPC_I32_WRAP_I64);
+ break;
+ }
+ tcg_wasm_out_op_const(s, OPC_I32_CONST, oi);
+ tcg_wasm_out_op_const(s, OPC_I64_CONST, (intptr_t)s->code_ptr);
+
+ tcg_wasm_out_op_idx(s, OPC_CALL, func_idx);
+}
+
static void tcg_out_op_l(TCGContext *s, TCGOpcode op, TCGLabel *l0)
{
tcg_insn_unit_tci insn = 0;
@@ -1054,6 +1147,19 @@ static void tcg_out_op_rr(TCGContext *s, TCGOpcode op, TCGReg r0, TCGReg r1)
tcg_out32(s, insn);
}
+static void tcg_out_op_rrm(TCGContext *s, TCGOpcode op,
+ TCGReg r0, TCGReg r1, TCGArg m2)
+{
+ tcg_insn_unit_tci 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_out32(s, insn);
+}
+
static void tcg_out_op_rrr(TCGContext *s, TCGOpcode op,
TCGReg r0, TCGReg r1, TCGReg r2)
{
@@ -1786,6 +1892,45 @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *func,
tcg_wasm_out_call(s, (intptr_t)func, info);
}
+static void tgen_qemu_ld(TCGContext *s, TCGType type, TCGReg data,
+ TCGReg addr, MemOpIdx oi)
+{
+ tcg_out_op_rrm(s, INDEX_op_qemu_ld, data, addr, oi);
+ tcg_wasm_out_qemu_ld(s, data, addr, oi);
+}
+
+static const TCGOutOpQemuLdSt outop_qemu_ld = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_qemu_ld,
+};
+
+static void tgen_qemu_st(TCGContext *s, TCGType type, TCGReg data,
+ TCGReg addr, MemOpIdx oi)
+{
+ tcg_out_op_rrm(s, INDEX_op_qemu_st, data, addr, oi);
+ tcg_wasm_out_qemu_st(s, data, addr, oi);
+}
+
+static const TCGOutOpQemuLdSt outop_qemu_st = {
+ .base.static_constraint = C_O0_I2(r, r),
+ .out = tgen_qemu_st,
+};
+
+bool tcg_target_has_memory_bswap(MemOp memop)
+{
+ return true;
+}
+
+static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ g_assert_not_reached();
+}
+
+static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ g_assert_not_reached();
+}
+
static void tcg_out_tb_start(TCGContext *s)
{
init_sub_buf();
--
2.43.0