This commit implements and, or and xor operations using Wasm
instructions. Each TCG variable is mapped to a 64bit Wasm variable. In Wasm,
and/or/xor instructions operate on values by first pushing the operands into
the Wasm's stack using get instructions. The result is left on the stack and
this can be assigned to a variable by popping it using a set instruction.
The Wasm binary format is documented at [1]. In this backend, TCI
instructions are emitted to s->code_ptr, while the corresponding Wasm
instructions are generated into a separated buffer allocated via
tcg_malloc(). These two code buffers must be merged into the final code
buffer before tcg_gen_code returns.
[1] https://webassembly.github.io/spec/core/binary/index.html
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
---
tcg/wasm32/tcg-target.c.inc | 137 +++++++++++++++++++++++++++++++++++-
1 file changed, 136 insertions(+), 1 deletion(-)
diff --git a/tcg/wasm32/tcg-target.c.inc b/tcg/wasm32/tcg-target.c.inc
index 126f9c0de7..e3a35c8415 100644
--- a/tcg/wasm32/tcg-target.c.inc
+++ b/tcg/wasm32/tcg-target.c.inc
@@ -98,6 +98,138 @@ static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
};
#endif
+/* converts a TCG register to a wasm variable index */
+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 BUF_SIZE 1024
+typedef struct LinkedBuf {
+ struct LinkedBuf *next;
+ uint8_t data[BUF_SIZE];
+ uint32_t size;
+} LinkedBuf;
+
+static LinkedBuf *new_linked_buf(void)
+{
+ LinkedBuf *p = tcg_malloc(sizeof(LinkedBuf));
+ p->size = 0;
+ p->next = NULL;
+ return p;
+}
+
+static inline LinkedBuf *linked_buf_out8(LinkedBuf *buf, uint8_t v)
+{
+ if (buf->size == BUF_SIZE) {
+ buf->next = new_linked_buf();
+ buf = buf->next;
+ }
+ buf->data[buf->size++] = v;
+ return buf;
+}
+
+static inline int linked_buf_len(LinkedBuf *buf)
+{
+ int total = 0;
+ for (LinkedBuf *p = buf; p; p = p->next) {
+ total += p->size;
+ }
+ return total;
+}
+
+static inline void linked_buf_write(LinkedBuf *buf, void *dst)
+{
+ for (LinkedBuf *p = buf; p; p = p->next) {
+ memcpy(dst, p->data, p->size);
+ dst += p->size;
+ }
+}
+
+/*
+ * wasm code is generataed in the dynamically allocated buffer which
+ * are managed as a linked list.
+ */
+__thread LinkedBuf *sub_buf_root;
+__thread LinkedBuf *sub_buf_cur;
+
+static void init_sub_buf(void)
+{
+ sub_buf_root = new_linked_buf();
+ sub_buf_cur = sub_buf_root;
+}
+
+static inline int sub_buf_len(void)
+{
+ return linked_buf_len(sub_buf_root);
+}
+
+static inline void tcg_wasm_out8(TCGContext *s, uint32_t v)
+{
+ sub_buf_cur = linked_buf_out8(sub_buf_cur, v);
+}
+
+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_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_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)
+{
+ tcg_wasm_out_op_var(s, 0x24, i);
+}
+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]);
+}
+
+#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);
+
static bool patch_reloc(tcg_insn_unit *code_ptr_i, int type,
intptr_t value, intptr_t addend)
{
@@ -557,6 +689,7 @@ static void tgen_and(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out_op_rrr(s, INDEX_op_and, a0, a1, a2);
+ tcg_wasm_out_i64_calc_and(s, a0, a1, a2);
}
static const TCGOutOpBinary outop_and = {
@@ -747,6 +880,7 @@ static void tgen_or(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out_op_rrr(s, INDEX_op_or, a0, a1, a2);
+ tcg_wasm_out_i64_calc_or(s, a0, a1, a2);
}
static const TCGOutOpBinary outop_or = {
@@ -918,6 +1052,7 @@ static void tgen_xor(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out_op_rrr(s, INDEX_op_xor, a0, a1, a2);
+ tcg_wasm_out_i64_calc_xor(s, a0, a1, a2);
}
static const TCGOutOpBinary outop_xor = {
@@ -1305,7 +1440,7 @@ static inline void tcg_target_qemu_prologue(TCGContext *s)
static void tcg_out_tb_start(TCGContext *s)
{
- /* nothing to do */
+ init_sub_buf();
}
bool tcg_target_has_memory_bswap(MemOp memop)
--
2.43.0