This commit implements rot, clz and ctz operations using Wasm instructions.
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
---
tcg/wasm/tcg-target.c.inc | 48 +++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/tcg/wasm/tcg-target.c.inc b/tcg/wasm/tcg-target.c.inc
index 0ba16e8dce..74f3177753 100644
--- a/tcg/wasm/tcg-target.c.inc
+++ b/tcg/wasm/tcg-target.c.inc
@@ -146,6 +146,7 @@ typedef enum {
OPC_I32_CONST = 0x41,
OPC_I64_CONST = 0x42,
+ OPC_I32_EQZ = 0x45,
OPC_I32_EQ = 0x46,
OPC_I32_NE = 0x47,
OPC_I32_LT_S = 0x48,
@@ -157,6 +158,7 @@ typedef enum {
OPC_I32_GE_S = 0x4e,
OPC_I32_GE_U = 0x4f,
+ OPC_I64_EQZ = 0x50,
OPC_I64_EQ = 0x51,
OPC_I64_NE = 0x52,
OPC_I64_LT_S = 0x53,
@@ -168,6 +170,8 @@ typedef enum {
OPC_I64_GE_S = 0x59,
OPC_I64_GE_U = 0x5a,
+ OPC_I32_CLZ = 0x67,
+ OPC_I32_CTZ = 0x68,
OPC_I32_ADD = 0x6a,
OPC_I32_DIV_S = 0x6d,
OPC_I32_DIV_U = 0x6e,
@@ -178,8 +182,11 @@ typedef enum {
OPC_I32_SHL = 0x74,
OPC_I32_SHR_S = 0x75,
OPC_I32_SHR_U = 0x76,
+ OPC_I32_ROTL = 0x77,
OPC_I32_ROTR = 0x78,
+ OPC_I64_CLZ = 0x79,
+ OPC_I64_CTZ = 0x7a,
OPC_I64_POPCNT = 0x7b,
OPC_I64_ADD = 0x7c,
OPC_I64_SUB = 0x7d,
@@ -194,6 +201,7 @@ typedef enum {
OPC_I64_SHL = 0x86,
OPC_I64_SHR_S = 0x87,
OPC_I64_SHR_U = 0x88,
+ OPC_I64_ROTL = 0x89,
OPC_I64_ROTR = 0x8a,
OPC_I32_WRAP_I64 = 0xa7,
@@ -720,6 +728,42 @@ static void tcg_wasm_out_bswap16(
tcg_wasm_out_op_idx(s, OPC_GLOBAL_SET, REG_IDX(dest));
}
+static void tcg_wasm_out_cz(
+ TCGContext *s, TCGType type, WasmInsn opc32, WasmInsn opc64,
+ TCGReg ret, TCGReg arg1, TCGReg arg2)
+{
+ switch (type) {
+ case TCG_TYPE_I32:
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(arg1));
+ tcg_wasm_out_op(s, OPC_I32_WRAP_I64);
+ tcg_wasm_out_op(s, OPC_I32_EQZ);
+ tcg_wasm_out_op_block(s, OPC_IF, BLOCK_I32);
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(arg2));
+ tcg_wasm_out_op(s, OPC_I32_WRAP_I64);
+ tcg_wasm_out_op(s, OPC_ELSE);
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(arg1));
+ tcg_wasm_out_op(s, OPC_I32_WRAP_I64);
+ tcg_wasm_out_op(s, opc32);
+ tcg_wasm_out_op(s, OPC_END);
+ tcg_wasm_out_op(s, OPC_I64_EXTEND_I32_U);
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_SET, REG_IDX(ret));
+ break;
+ case TCG_TYPE_I64:
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(arg1));
+ tcg_wasm_out_op(s, OPC_I64_EQZ);
+ tcg_wasm_out_op_block(s, OPC_IF, BLOCK_I64);
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(arg2));
+ tcg_wasm_out_op(s, OPC_ELSE);
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(arg1));
+ tcg_wasm_out_op(s, opc64);
+ tcg_wasm_out_op(s, OPC_END);
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_SET, REG_IDX(ret));
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
static void tcg_wasm_out_mov(TCGContext *s, TCGReg ret, TCGReg arg)
{
tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(arg));
@@ -1266,6 +1310,7 @@ static void tgen_clz(TCGContext *s, TCGType type,
? INDEX_op_tci_clz32
: INDEX_op_clz);
tcg_out_op_rrr(s, opc, a0, a1, a2);
+ tcg_wasm_out_cz(s, type, OPC_I32_CLZ, OPC_I64_CLZ, a0, a1, a2);
}
static const TCGOutOpBinary outop_clz = {
@@ -1280,6 +1325,7 @@ static void tgen_ctz(TCGContext *s, TCGType type,
? INDEX_op_tci_ctz32
: INDEX_op_ctz);
tcg_out_op_rrr(s, opc, a0, a1, a2);
+ tcg_wasm_out_cz(s, type, OPC_I32_CTZ, OPC_I64_CTZ, a0, a1, a2);
}
static const TCGOutOpBinary outop_ctz = {
@@ -1496,6 +1542,7 @@ static void tgen_rotl(TCGContext *s, TCGType type,
? INDEX_op_tci_rotl32
: INDEX_op_rotl);
tcg_out_op_rrr(s, opc, a0, a1, a2);
+ tcg_wasm_out_o1_i2_type(s, type, OPC_I32_ROTL, OPC_I64_ROTL, a0, a1, a2);
}
static const TCGOutOpBinary outop_rotl = {
@@ -1510,6 +1557,7 @@ static void tgen_rotr(TCGContext *s, TCGType type,
? INDEX_op_tci_rotr32
: INDEX_op_rotr);
tcg_out_op_rrr(s, opc, a0, a1, a2);
+ tcg_wasm_out_o1_i2_type(s, type, OPC_I32_ROTR, OPC_I64_ROTL, a0, a1, a2);
}
static const TCGOutOpBinary outop_rotr = {
--
2.43.0