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.m...@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