These TCG instructions are implemented by using Wasm's if and else
instructions. Support for TCG_COND_TSTEQ and TCG_COND_TSTNE is not yet
implemented, so TCG_TARGET_HAS_tst is set to 0.
The tgen_setcond function was used by several other functions
(e.g. tgen_negsetcond) and intended specifically for emitting TCI code. So
it has been renamed to tgen_negsetcond_tci.
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
---
tcg/wasm/tcg-target-has.h | 2 +-
tcg/wasm/tcg-target.c.inc | 166 +++++++++++++++++++++++++++++++++++++-
2 files changed, 163 insertions(+), 5 deletions(-)
diff --git a/tcg/wasm/tcg-target-has.h b/tcg/wasm/tcg-target-has.h
index ab07ce1fcb..1eaa8f65f6 100644
--- a/tcg/wasm/tcg-target-has.h
+++ b/tcg/wasm/tcg-target-has.h
@@ -13,7 +13,7 @@
#define TCG_TARGET_HAS_qemu_ldst_i128 0
-#define TCG_TARGET_HAS_tst 1
+#define TCG_TARGET_HAS_tst 0
#define TCG_TARGET_extract_valid(type, ofs, len) 1
#define TCG_TARGET_sextract_valid(type, ofs, len) 1
diff --git a/tcg/wasm/tcg-target.c.inc b/tcg/wasm/tcg-target.c.inc
index 81e83a8bdf..03cb3b2f46 100644
--- a/tcg/wasm/tcg-target.c.inc
+++ b/tcg/wasm/tcg-target.c.inc
@@ -117,9 +117,37 @@ static const uint8_t tcg_target_reg_index[TCG_TARGET_NB_REGS] = {
#define REG_IDX(r) tcg_target_reg_index[r]
typedef enum {
+ OPC_IF = 0x04,
+ OPC_ELSE = 0x05,
+ OPC_END = 0x0b,
OPC_GLOBAL_GET = 0x23,
OPC_GLOBAL_SET = 0x24,
+ OPC_I32_CONST = 0x41,
+ OPC_I64_CONST = 0x42,
+
+ OPC_I32_EQ = 0x46,
+ OPC_I32_NE = 0x47,
+ OPC_I32_LT_S = 0x48,
+ OPC_I32_LT_U = 0x49,
+ OPC_I32_GT_S = 0x4a,
+ OPC_I32_GT_U = 0x4b,
+ OPC_I32_LE_S = 0x4c,
+ OPC_I32_LE_U = 0x4d,
+ OPC_I32_GE_S = 0x4e,
+ OPC_I32_GE_U = 0x4f,
+
+ OPC_I64_EQ = 0x51,
+ OPC_I64_NE = 0x52,
+ OPC_I64_LT_S = 0x53,
+ OPC_I64_LT_U = 0x54,
+ OPC_I64_GT_S = 0x55,
+ OPC_I64_GT_U = 0x56,
+ OPC_I64_LE_S = 0x57,
+ OPC_I64_LE_U = 0x58,
+ OPC_I64_GE_S = 0x59,
+ OPC_I64_GE_U = 0x5a,
+
OPC_I32_SHL = 0x74,
OPC_I32_SHR_S = 0x75,
OPC_I32_SHR_U = 0x76,
@@ -138,6 +166,12 @@ typedef enum {
OPC_I64_EXTEND_I32_U = 0xad,
} WasmInsn;
+typedef enum {
+ BLOCK_NORET = 0x40,
+ BLOCK_I64 = 0x7e,
+ BLOCK_I32 = 0x7f,
+} WasmBlockType;
+
#define BUF_SIZE 1024
typedef struct LinkedBufEntry {
uint8_t data[BUF_SIZE];
@@ -172,6 +206,23 @@ static void linked_buf_out_leb128(LinkedBuf *p, uint64_t v)
} while (v != 0);
}
+static void linked_buf_out_sleb128(LinkedBuf *p, int64_t v)
+{
+ bool more = true;
+ uint8_t b;
+ while (more) {
+ b = v & 0x7f;
+ v >>= 7;
+ if (((v == 0) && ((b & 0x40) == 0)) ||
+ ((v == -1) && ((b & 0x40) != 0))) {
+ more = false;
+ } else {
+ b |= 0x80;
+ }
+ linked_buf_out8(p, b);
+ }
+}
+
/*
* wasm code is generataed in the dynamically allocated buffer which
* are managed as a linked list.
@@ -190,6 +241,10 @@ static void tcg_wasm_out_leb128(TCGContext *s, uint64_t v)
{
linked_buf_out_leb128(&sub_buf, v);
}
+static void tcg_wasm_out_sleb128(TCGContext *s, int64_t v)
+{
+ linked_buf_out_sleb128(&sub_buf, v);
+}
static void tcg_wasm_out_op(TCGContext *s, WasmInsn opc)
{
@@ -200,6 +255,30 @@ 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_op_block(TCGContext *s, WasmInsn opc, WasmBlockType t)
+{
+ tcg_wasm_out8(s, opc);
+ tcg_wasm_out8(s, t);
+}
+static void tcg_wasm_out_op_const(TCGContext *s, WasmInsn opc, int64_t v)
+{
+ tcg_wasm_out8(s, opc);
+ switch (opc) {
+ case OPC_I32_CONST:
+ tcg_wasm_out_sleb128(s, (int32_t)v);
+ break;
+ case OPC_I64_CONST:
+ tcg_wasm_out_sleb128(s, v);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+static void tcg_wasm_out_op_not(TCGContext *s)
+{
+ tcg_wasm_out_op_const(s, OPC_I64_CONST, -1);
+ tcg_wasm_out_op(s, OPC_I64_XOR);
+}
static void tcg_wasm_out_o1_i2(
TCGContext *s, WasmInsn opc, TCGReg ret, TCGReg arg1, TCGReg arg2)
@@ -231,6 +310,76 @@ static void tcg_wasm_out_o1_i2_type(
}
}
+static const struct {
+ WasmInsn i32;
+ WasmInsn i64;
+} tcg_cond_to_inst[] = {
+ [TCG_COND_EQ] = { OPC_I32_EQ, OPC_I64_EQ },
+ [TCG_COND_NE] = { OPC_I32_NE, OPC_I64_NE },
+ [TCG_COND_LT] = { OPC_I32_LT_S, OPC_I64_LT_S },
+ [TCG_COND_GE] = { OPC_I32_GE_S, OPC_I64_GE_S },
+ [TCG_COND_LE] = { OPC_I32_LE_S, OPC_I64_LE_S },
+ [TCG_COND_GT] = { OPC_I32_GT_S, OPC_I64_GT_S },
+ [TCG_COND_LTU] = { OPC_I32_LT_U, OPC_I64_LT_U },
+ [TCG_COND_GEU] = { OPC_I32_GE_U, OPC_I64_GE_U },
+ [TCG_COND_LEU] = { OPC_I32_LE_U, OPC_I64_LE_U },
+ [TCG_COND_GTU] = { OPC_I32_GT_U, OPC_I64_GT_U }
+};
+
+static void tcg_wasm_out_cond(
+ TCGContext *s, TCGType type, TCGCond cond, 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_idx(s, OPC_GLOBAL_GET, REG_IDX(arg2));
+ tcg_wasm_out_op(s, OPC_I32_WRAP_I64);
+ tcg_wasm_out_op(s, tcg_cond_to_inst[cond].i32);
+ break;
+ case TCG_TYPE_I64:
+ 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, tcg_cond_to_inst[cond].i64);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void tcg_wasm_out_setcond(TCGContext *s, TCGType type, TCGReg ret,
+ TCGReg arg1, TCGReg arg2, TCGCond cond)
+{
+ tcg_wasm_out_cond(s, type, cond, arg1, arg2);
+ tcg_wasm_out_op(s, OPC_I64_EXTEND_I32_U);
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_SET, REG_IDX(ret));
+}
+
+static void tcg_wasm_out_negsetcond(TCGContext *s, TCGType type, TCGReg ret,
+ TCGReg arg1, TCGReg arg2, TCGCond cond)
+{
+ tcg_wasm_out_cond(s, type, cond, arg1, arg2);
+ tcg_wasm_out_op(s, OPC_I64_EXTEND_I32_U);
+ tcg_wasm_out_op_not(s);
+ tcg_wasm_out_op_const(s, OPC_I64_CONST, 1);
+ tcg_wasm_out_op(s, OPC_I64_ADD);
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_SET, REG_IDX(ret));
+}
+
+static void tcg_wasm_out_movcond(TCGContext *s, TCGType type, TCGReg ret,
+ TCGReg c1, TCGReg c2,
+ TCGReg v1, TCGReg v2,
+ TCGCond cond)
+{
+ tcg_wasm_out_cond(s, type, cond, c1, c2);
+ tcg_wasm_out_op_block(s, OPC_IF, BLOCK_I64);
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(v1));
+ tcg_wasm_out_op(s, OPC_ELSE);
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_GET, REG_IDX(v2));
+ tcg_wasm_out_op(s, OPC_END);
+ tcg_wasm_out_op_idx(s, OPC_GLOBAL_SET, REG_IDX(ret));
+}
+
static bool patch_reloc(tcg_insn_unit *code_ptr_i, int type,
intptr_t value, intptr_t addend)
{
@@ -1147,8 +1296,8 @@ static const TCGOutOpUnary outop_not = {
.out_rr = tgen_not,
};
-static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond,
- TCGReg dest, TCGReg arg1, TCGReg arg2)
+static void tgen_setcond_tci(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg dest, TCGReg arg1, TCGReg arg2)
{
TCGOpcode opc = (type == TCG_TYPE_I32
? INDEX_op_tci_setcond32
@@ -1156,6 +1305,13 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond,
tcg_out_op_rrrc(s, opc, dest, arg1, arg2, cond);
}
+static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg dest, TCGReg arg1, TCGReg arg2)
+{
+ tgen_setcond_tci(s, type, cond, dest, arg1, arg2);
+ tcg_wasm_out_setcond(s, type, dest, arg1, arg2, cond);
+}
+
static const TCGOutOpSetcond outop_setcond = {
.base.static_constraint = C_O1_I2(r, r, r),
.out_rrr = tgen_setcond,
@@ -1164,8 +1320,9 @@ static const TCGOutOpSetcond outop_setcond = {
static void tgen_negsetcond(TCGContext *s, TCGType type, TCGCond cond,
TCGReg dest, TCGReg arg1, TCGReg arg2)
{
- tgen_setcond(s, type, cond, dest, arg1, arg2);
+ tgen_setcond_tci(s, type, cond, dest, arg1, arg2);
tgen_neg(s, type, dest, dest);
+ tcg_wasm_out_negsetcond(s, type, dest, arg1, arg2, cond);
}
static const TCGOutOpSetcond outop_negsetcond = {
@@ -1176,7 +1333,7 @@ static const TCGOutOpSetcond outop_negsetcond = {
static void tgen_brcond(TCGContext *s, TCGType type, TCGCond cond,
TCGReg arg0, TCGReg arg1, TCGLabel *l)
{
- tgen_setcond(s, type, cond, TCG_REG_TMP, arg0, arg1);
+ tgen_setcond_tci(s, type, cond, TCG_REG_TMP, arg0, arg1);
tcg_out_op_rl(s, INDEX_op_brcond, TCG_REG_TMP, l);
}
@@ -1193,6 +1350,7 @@ static void tgen_movcond(TCGContext *s, TCGType type, TCGCond cond,
? INDEX_op_tci_movcond32
: INDEX_op_movcond);
tcg_out_op_rrrrrc(s, opc, ret, c1, c2, vt, vf, cond);
+ tcg_wasm_out_movcond(s, type, ret, c1, c2, vt, vf, cond);
}
static const TCGOutOpMovcond outop_movcond = {
--
2.43.0