qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Kohei Tokunaga <ktokunaga.mail@gmail.com>
To: qemu-devel@nongnu.org
Cc: "Alex Bennée" <alex.bennee@linaro.org>,
	"Philippe Mathieu-Daudé" <philmd@linaro.org>,
	"Thomas Huth" <thuth@redhat.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Richard Henderson" <richard.henderson@linaro.org>,
	"Marc-André Lureau" <marcandre.lureau@redhat.com>,
	"Daniel P . Berrangé" <berrange@redhat.com>,
	"WANG Xuerui" <git@xen0n.name>,
	"Aurelien Jarno" <aurelien@aurel32.net>,
	"Huacai Chen" <chenhuacai@kernel.org>,
	"Jiaxun Yang" <jiaxun.yang@flygoat.com>,
	"Aleksandar Rikalo" <arikalo@gmail.com>,
	"Palmer Dabbelt" <palmer@dabbelt.com>,
	"Alistair Francis" <Alistair.Francis@wdc.com>,
	"Stefan Weil" <sw@weilnetz.de>,
	qemu-arm@nongnu.org, qemu-riscv@nongnu.org,
	"Stefan Hajnoczi" <stefanha@redhat.com>,
	"Pierrick Bouvier" <pierrick.bouvier@linaro.org>,
	ktokunaga.mail@gmail.com
Subject: [PATCH v2 09/35] tcg/wasm: Add and/or/xor instructions
Date: Wed, 27 Aug 2025 01:10:14 +0900	[thread overview]
Message-ID: <f8cb9a61b63a69cce422b2964659b0e0472347bc.1756216429.git.ktokunaga.mail@gmail.com> (raw)
In-Reply-To: <cover.1756216429.git.ktokunaga.mail@gmail.com>

This commit adds support for generateing the and, or and xor operations. The
generated Wasm codes will be instantiated and executed in the browser.

Browsers tipycally limit the number of active Wasm instances and the
instantiating Wasm modules introduces overhead. As a result, instantiating
TBs that are rarely called is undesirable. To address this, the Wasm backend
relies on the a forked subset of the TCI interpreter (tcg_qemu_tb_exec_tci
function in tcg/wasm.c) for executing such TBs.

The Wasm backend emits both Wasm and TCI instructions. TCI instructions are
emitted to s->code_ptr, while the corresponding Wasm instructions are
generated into a separate buffer allocated via tcg_malloc(). This buffer
intends to be merged into the TB before tcg_gen_code returns.

In the Wasm code, each TCG variable is mapped to a 64bit Wasm
variable. Execution works 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].

Additionally, since the Wasm instuction's index operand must be
LEB128-encoded, this commit introduces an encoder function implemented
following [2].

[1] https://webassembly.github.io/spec/core/binary/index.html
[2] https://en.wikipedia.org/wiki/LEB128

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
---
 MAINTAINERS               |   1 +
 tcg/wasm.c                |  66 ++++++++++++++++
 tcg/wasm/tcg-target.c.inc | 160 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 227 insertions(+)
 create mode 100644 tcg/wasm.c

V2:
- This commit generates both Wasm and TCI instrucitons.
- Although checkpatch.pl reports the following error in tcg/wasm.c,
  this file is based on the TCI code so it is preserved as-is.
  > New file 'tcg/wasm.c' must not have license boilerplate header text,
  > only the SPDX-License-Identifier, unless this file was copied from
  > existing code already having such text.

diff --git a/MAINTAINERS b/MAINTAINERS
index 89e4b51e22..217bf2066c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4003,6 +4003,7 @@ WebAssembly TCG target
 M: Kohei Tokunaga <ktokunaga.mail@gmail.com>
 S: Maintained
 F: tcg/wasm/
+F: tcg/wasm.c
 
 Block drivers
 -------------
diff --git a/tcg/wasm.c b/tcg/wasm.c
new file mode 100644
index 0000000000..9f3b1344d6
--- /dev/null
+++ b/tcg/wasm.c
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * WebAssembly backend with forked TCI, based on 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/>.
+ */
+
+#include "qemu/osdep.h"
+#include "tcg/tcg.h"
+
+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 uintptr_t tcg_qemu_tb_exec_tci(CPUArchState *env, const void *v_tb_ptr)
+{
+    const uint32_t *tb_ptr = v_tb_ptr;
+    tcg_target_ulong regs[TCG_TARGET_NB_REGS];
+    uint64_t stack[(TCG_STATIC_CALL_ARGS_SIZE + TCG_STATIC_FRAME_SIZE)
+                   / sizeof(uint64_t)];
+
+    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;
+
+        insn = *tb_ptr++;
+        opc = extract32(insn, 0, 8);
+
+        switch (opc) {
+        case INDEX_op_and:
+            tci_args_rrr(insn, &r0, &r1, &r2);
+            regs[r0] = regs[r1] & regs[r2];
+            break;
+        case INDEX_op_or:
+            tci_args_rrr(insn, &r0, &r1, &r2);
+            regs[r0] = regs[r1] | regs[r2];
+            break;
+        case INDEX_op_xor:
+            tci_args_rrr(insn, &r0, &r1, &r2);
+            regs[r0] = regs[r1] ^ regs[r2];
+            break;
+        default:
+            g_assert_not_reached();
+        }
+    }
+}
diff --git a/tcg/wasm/tcg-target.c.inc b/tcg/wasm/tcg-target.c.inc
index 4bcb594360..a1757b4db7 100644
--- a/tcg/wasm/tcg-target.c.inc
+++ b/tcg/wasm/tcg-target.c.inc
@@ -25,6 +25,10 @@
  * THE SOFTWARE.
  */
 
+#include "qemu/queue.h"
+
+typedef uint32_t tcg_insn_unit_tci;
+
 static const int tcg_target_reg_alloc_order[] = {
     TCG_REG_R2,
     TCG_REG_R3,
@@ -109,3 +113,159 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
     }
     return false;
 }
+
+/* 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 REG_IDX(r) tcg_target_reg_index[r]
+
+typedef enum {
+    OPC_GLOBAL_GET = 0x23,
+    OPC_GLOBAL_SET = 0x24,
+
+    OPC_I64_AND = 0x83,
+    OPC_I64_OR = 0x84,
+    OPC_I64_XOR = 0x85,
+} WasmInsn;
+
+#define BUF_SIZE 1024
+typedef struct LinkedBufEntry {
+    uint8_t data[BUF_SIZE];
+    uint32_t size;
+    QSIMPLEQ_ENTRY(LinkedBufEntry) entry;
+} LinkedBufEntry;
+
+typedef QSIMPLEQ_HEAD(, LinkedBufEntry) LinkedBuf;
+
+static void linked_buf_out8(LinkedBuf *linked_buf, uint8_t v)
+{
+    LinkedBufEntry *buf = QSIMPLEQ_LAST(linked_buf, LinkedBufEntry, entry);
+    if (!buf || (buf->size == BUF_SIZE)) {
+        LinkedBufEntry *e = tcg_malloc(sizeof(LinkedBufEntry));
+        e->size = 0;
+        QSIMPLEQ_INSERT_TAIL(linked_buf, e, entry);
+        buf = e;
+    }
+    buf->data[buf->size++] = v;
+}
+
+static void linked_buf_out_leb128(LinkedBuf *p, uint64_t v)
+{
+    uint8_t b;
+    do {
+        b = v & 0x7f;
+        v >>= 7;
+        if (v != 0) {
+            b |= 0x80;
+        }
+        linked_buf_out8(p, b);
+    } while (v != 0);
+}
+
+/*
+ * wasm code is generataed in the dynamically allocated buffer which
+ * are managed as a linked list.
+ */
+static __thread LinkedBuf sub_buf;
+
+static void init_sub_buf(void)
+{
+    QSIMPLEQ_INIT(&sub_buf);
+}
+static void tcg_wasm_out8(TCGContext *s, uint8_t v)
+{
+    linked_buf_out8(&sub_buf, v);
+}
+static void tcg_wasm_out_leb128(TCGContext *s, uint64_t v)
+{
+    linked_buf_out_leb128(&sub_buf, v);
+}
+
+static void tcg_wasm_out_op(TCGContext *s, WasmInsn opc)
+{
+    tcg_wasm_out8(s, opc);
+}
+static void tcg_wasm_out_op_idx(TCGContext *s, WasmInsn opc, uint32_t idx)
+{
+    tcg_wasm_out8(s, opc);
+    tcg_wasm_out_leb128(s, idx);
+}
+
+static void tcg_wasm_out_o1_i2(
+    TCGContext *s, WasmInsn opc, TCGReg ret, TCGReg arg1, TCGReg arg2)
+{
+    tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(arg1));
+    tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(arg2));
+    tcg_wasm_out_op(s, opc);
+    tcg_wasm_out_op_idx(s, OPC_GLOBAL_SET, REG_IDX(ret));
+}
+
+static void tcg_out_op_rrr(TCGContext *s, TCGOpcode op,
+                           TCGReg r0, TCGReg r1, TCGReg r2)
+{
+    tcg_insn_unit_tci 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_out32(s, insn);
+}
+
+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_o1_i2(s, OPC_I64_AND, a0, a1, a2);
+}
+
+static const TCGOutOpBinary outop_and = {
+    .base.static_constraint = C_O1_I2(r, r, r),
+    .out_rrr = tgen_and,
+};
+
+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_o1_i2(s, OPC_I64_OR, a0, a1, a2);
+}
+
+static const TCGOutOpBinary outop_or = {
+    .base.static_constraint = C_O1_I2(r, r, r),
+    .out_rrr = tgen_or,
+};
+
+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_o1_i2(s, OPC_I64_XOR, a0, a1, a2);
+}
+
+static const TCGOutOpBinary outop_xor = {
+    .base.static_constraint = C_O1_I2(r, r, r),
+    .out_rrr = tgen_xor,
+};
+
+static void tcg_out_tb_start(TCGContext *s)
+{
+    init_sub_buf();
+}
-- 
2.43.0



  parent reply	other threads:[~2025-08-26 16:13 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-26 16:10 [PATCH v2 00/35] wasm: Add Wasm TCG backend based on wasm64 Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 01/35] meson: Add wasm64 support to the --cpu flag Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 02/35] configure: Enable to propagate -sMEMORY64 flag to Emscripten Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 03/35] dockerfiles: Add support for wasm64 to the wasm Dockerfile Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 04/35] .gitlab-ci.d: Add build tests for wasm64 Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 05/35] tcg/wasm: Add tcg-target.h and tcg-target-reg-bits.h Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 06/35] tcg/wasm: Add register-related definitions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 07/35] tcg/wasm: Add constraint definitions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 08/35] tcg/wasm: Add relocation callbacks Kohei Tokunaga
2025-08-26 16:10 ` Kohei Tokunaga [this message]
2025-08-26 16:10 ` [PATCH v2 10/35] tcg/wasm: Add add/sub/mul instructions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 11/35] tcg/wasm: Add shl/shr/sar instructions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 12/35] tcg/wasm: Add setcond/negsetcond/movcond instructions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 13/35] tcg/wasm: Add sextract instruction Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 14/35] tcg/wasm: Add load and store instructions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 15/35] tcg/wasm: Add mov/movi instructions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 16/35] tcg/wasm: Add ext instructions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 17/35] tcg/wasm: Add div/rem instructions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 18/35] tcg/wasm: Add neg/ctpop instructions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 19/35] tcg/wasm: Add rot/clz/ctz instructions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 20/35] tcg/wasm: Add br/brcond instructions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 21/35] tcg/wasm: Add exit_tb/goto_tb/goto_ptr instructions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 22/35] tcg/wasm: Add call instruction Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 23/35] tcg/wasm: Add qemu_ld/qemu_st instructions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 24/35] tcg/wasm: Add mb instruction Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 25/35] tcg/wasm: Mark unimplemented instructions Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 26/35] tcg/wasm: Add initialization of fundamental registers Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 27/35] tcg/wasm: Write wasm binary to TB Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 28/35] tcg/wasm: Implement instantiation of Wasm binary Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 29/35] tcg/wasm: Allow switching coroutine from a helper Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 30/35] tcg/wasm: Enable instantiation of TBs executed many times Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 31/35] tcg/wasm: Enable TLB lookup Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 32/35] tcg/wasm: Add tcg_target_init function Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 33/35] meson.build: enable to build Wasm backend Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 34/35] meson.build: Propagate optimization flag for linking on Emscripten Kohei Tokunaga
2025-08-26 16:10 ` [PATCH v2 35/35] .gitlab-ci.d: build wasm backend in CI Kohei Tokunaga

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f8cb9a61b63a69cce422b2964659b0e0472347bc.1756216429.git.ktokunaga.mail@gmail.com \
    --to=ktokunaga.mail@gmail.com \
    --cc=Alistair.Francis@wdc.com \
    --cc=alex.bennee@linaro.org \
    --cc=arikalo@gmail.com \
    --cc=aurelien@aurel32.net \
    --cc=berrange@redhat.com \
    --cc=chenhuacai@kernel.org \
    --cc=git@xen0n.name \
    --cc=jiaxun.yang@flygoat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=palmer@dabbelt.com \
    --cc=pbonzini@redhat.com \
    --cc=philmd@linaro.org \
    --cc=pierrick.bouvier@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-riscv@nongnu.org \
    --cc=richard.henderson@linaro.org \
    --cc=stefanha@redhat.com \
    --cc=sw@weilnetz.de \
    --cc=thuth@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).