This commit implements addc and subb operations using Wasm instructions. A
carry flag is introduced as the 16th variable in the module following other
15 variables that represent TCG variables.
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
---
tcg/wasm32/tcg-target.c.inc | 151 ++++++++++++++++++++++++++++++++++++
1 file changed, 151 insertions(+)
diff --git a/tcg/wasm32/tcg-target.c.inc b/tcg/wasm32/tcg-target.c.inc
index 75e47f8c8c..167850ea7c 100644
--- a/tcg/wasm32/tcg-target.c.inc
+++ b/tcg/wasm32/tcg-target.c.inc
@@ -118,6 +118,11 @@ static const uint8_t tcg_target_reg_index[TCG_TARGET_NB_REGS] = {
15, /* TCG_REG_R15 */
};
+/*
+ * Global variable to store the carry flag
+ */
+#define CARRY_IDX 16
+
/* Temporary local variables */
#define TMP32_LOCAL_0_IDX 1
#define TMP32_LOCAL_1_IDX 2
@@ -324,10 +329,23 @@ static void tcg_wasm_out_op_i32_eqz(TCGContext *s)
{
tcg_wasm_out8(s, 0x45);
}
+static void tcg_wasm_out_op_i64_lt_u(TCGContext *s)
+{
+ tcg_wasm_out8(s, 0x54);
+}
+static void tcg_wasm_out_op_i64_le_u(TCGContext *s)
+{
+ tcg_wasm_out8(s, 0x58);
+}
static void tcg_wasm_out_op_i64_eqz(TCGContext *s)
{
tcg_wasm_out8(s, 0x50);
}
+static void tcg_wasm_out_op_if_noret(TCGContext *s)
+{
+ tcg_wasm_out8(s, 0x04);
+ tcg_wasm_out8(s, 0x40);
+}
static void tcg_wasm_out_op_if_ret_i64(TCGContext *s)
{
@@ -1789,10 +1807,28 @@ static TCGConstraintSetIndex cset_addsubcarry(TCGType type, unsigned flags)
return type == TCG_TYPE_REG ? C_O1_I2(r, r, r) : C_NotImplemented;
}
+static void tcg_wasm_out_addco(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_wasm_out_op_global_get_r(s, a1);
+ tcg_wasm_out_op_global_get_r(s, a2);
+ tcg_wasm_out_op_i64_add(s);
+ tcg_wasm_out_op_global_set_r(s, a0);
+ tcg_wasm_out_op_global_get_r(s, a0);
+ if (a0 == a1) {
+ tcg_wasm_out_op_global_get_r(s, a2);
+ } else {
+ tcg_wasm_out_op_global_get_r(s, a1);
+ }
+ tcg_wasm_out_op_i64_lt_u(s);
+ tcg_wasm_out_op_i64_extend_i32_s(s);
+ tcg_wasm_out_op_global_set(s, CARRY_IDX);
+}
+
static void tgen_addco(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out_op_rrr(s, INDEX_op_addco, a0, a1, a2);
+ tcg_wasm_out_addco(s, a0, a1, a2);
}
static const TCGOutOpBinary outop_addco = {
@@ -1801,10 +1837,21 @@ static const TCGOutOpBinary outop_addco = {
.out_rrr = tgen_addco,
};
+static void tcg_wasm_out_addci(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_wasm_out_op_global_get_r(s, a1);
+ tcg_wasm_out_op_global_get_r(s, a2);
+ tcg_wasm_out_op_i64_add(s);
+ tcg_wasm_out_op_global_get(s, CARRY_IDX);
+ tcg_wasm_out_op_i64_add(s);
+ tcg_wasm_out_op_global_set_r(s, a0);
+}
+
static void tgen_addci(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out_op_rrr(s, INDEX_op_addci, a0, a1, a2);
+ tcg_wasm_out_addci(s, a0, a1, a2);
}
static const TCGOutOpAddSubCarry outop_addci = {
@@ -1813,10 +1860,51 @@ static const TCGOutOpAddSubCarry outop_addci = {
.out_rrr = tgen_addci,
};
+static void tcg_wasm_out_addcio(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_wasm_out_op_global_get(s, CARRY_IDX);
+ tcg_wasm_out_op_if_noret(s);
+
+ tcg_wasm_out_op_global_get_r(s, a1);
+ tcg_wasm_out_op_global_get_r(s, a2);
+ tcg_wasm_out_op_i64_add(s);
+ tcg_wasm_out_op_i64_const(s, 1);
+ tcg_wasm_out_op_i64_add(s);
+ tcg_wasm_out_op_global_set_r(s, a0);
+ tcg_wasm_out_op_global_get_r(s, a0);
+ if (a0 == a1) {
+ tcg_wasm_out_op_global_get_r(s, a2);
+ } else {
+ tcg_wasm_out_op_global_get_r(s, a1);
+ }
+ tcg_wasm_out_op_i64_le_u(s);
+ tcg_wasm_out_op_i64_extend_i32_s(s);
+ tcg_wasm_out_op_global_set(s, CARRY_IDX);
+
+ tcg_wasm_out_op_else(s);
+
+ tcg_wasm_out_op_global_get_r(s, a1);
+ tcg_wasm_out_op_global_get_r(s, a2);
+ tcg_wasm_out_op_i64_add(s);
+ tcg_wasm_out_op_global_set_r(s, a0);
+ tcg_wasm_out_op_global_get_r(s, a0);
+ if (a0 == a1) {
+ tcg_wasm_out_op_global_get_r(s, a2);
+ } else {
+ tcg_wasm_out_op_global_get_r(s, a1);
+ }
+ tcg_wasm_out_op_i64_lt_u(s);
+ tcg_wasm_out_op_i64_extend_i32_s(s);
+ tcg_wasm_out_op_global_set(s, CARRY_IDX);
+
+ tcg_wasm_out_op_end(s);
+}
+
static void tgen_addcio(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out_op_rrr(s, INDEX_op_addcio, a0, a1, a2);
+ tcg_wasm_out_addcio(s, a0, a1, a2);
}
static const TCGOutOpBinary outop_addcio = {
@@ -1828,6 +1916,8 @@ static const TCGOutOpBinary outop_addcio = {
static void tcg_out_set_carry(TCGContext *s)
{
tcg_out_op_v(s, INDEX_op_tci_setcarry);
+ tcg_wasm_out_op_i64_const(s, 1);
+ tcg_wasm_out_op_global_set(s, CARRY_IDX);
}
static void tgen_and(TCGContext *s, TCGType type,
@@ -2182,10 +2272,25 @@ static const TCGOutOpSubtract outop_sub = {
.out_rrr = tgen_sub,
};
+static void tcg_wasm_out_subbo(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_wasm_out_op_global_get_r(s, a1);
+ tcg_wasm_out_op_global_get_r(s, a2);
+ tcg_wasm_out_op_i64_lt_u(s);
+ tcg_wasm_out_op_i64_extend_i32_s(s);
+ tcg_wasm_out_op_global_set(s, CARRY_IDX);
+
+ tcg_wasm_out_op_global_get_r(s, a1);
+ tcg_wasm_out_op_global_get_r(s, a2);
+ tcg_wasm_out_op_i64_sub(s);
+ tcg_wasm_out_op_global_set_r(s, a0);
+}
+
static void tgen_subbo(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out_op_rrr(s, INDEX_op_subbo, a0, a1, a2);
+ tcg_wasm_out_subbo(s, a0, a1, a2);
}
static const TCGOutOpAddSubCarry outop_subbo = {
@@ -2194,10 +2299,21 @@ static const TCGOutOpAddSubCarry outop_subbo = {
.out_rrr = tgen_subbo,
};
+static void tcg_wasm_out_subbi(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_wasm_out_op_global_get_r(s, a1);
+ tcg_wasm_out_op_global_get_r(s, a2);
+ tcg_wasm_out_op_i64_sub(s);
+ tcg_wasm_out_op_global_get(s, CARRY_IDX);
+ tcg_wasm_out_op_i64_sub(s);
+ tcg_wasm_out_op_global_set_r(s, a0);
+}
+
static void tgen_subbi(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out_op_rrr(s, INDEX_op_subbi, a0, a1, a2);
+ tcg_wasm_out_subbi(s, a0, a1, a2);
}
static const TCGOutOpAddSubCarry outop_subbi = {
@@ -2206,10 +2322,43 @@ static const TCGOutOpAddSubCarry outop_subbi = {
.out_rrr = tgen_subbi,
};
+static void tcg_wasm_out_subbio(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_wasm_out_op_global_get(s, CARRY_IDX);
+ tcg_wasm_out_op_if_noret(s);
+
+ tcg_wasm_out_op_global_get_r(s, a1);
+ tcg_wasm_out_op_global_get_r(s, a2);
+ tcg_wasm_out_op_i64_le_u(s);
+ tcg_wasm_out_op_i64_extend_i32_s(s);
+ tcg_wasm_out_op_global_set(s, CARRY_IDX);
+ tcg_wasm_out_op_global_get_r(s, a1);
+ tcg_wasm_out_op_global_get_r(s, a2);
+ tcg_wasm_out_op_i64_sub(s);
+ tcg_wasm_out_op_i64_const(s, 1);
+ tcg_wasm_out_op_i64_sub(s);
+ tcg_wasm_out_op_global_set_r(s, a0);
+
+ tcg_wasm_out_op_else(s);
+
+ tcg_wasm_out_op_global_get_r(s, a1);
+ tcg_wasm_out_op_global_get_r(s, a2);
+ tcg_wasm_out_op_i64_lt_u(s);
+ tcg_wasm_out_op_i64_extend_i32_s(s);
+ tcg_wasm_out_op_global_set(s, CARRY_IDX);
+ tcg_wasm_out_op_global_get_r(s, a1);
+ tcg_wasm_out_op_global_get_r(s, a2);
+ tcg_wasm_out_op_i64_sub(s);
+ tcg_wasm_out_op_global_set_r(s, a0);
+
+ tcg_wasm_out_op_end(s);
+}
+
static void tgen_subbio(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out_op_rrr(s, INDEX_op_subbio, a0, a1, a2);
+ tcg_wasm_out_subbio(s, a0, a1, a2);
}
static const TCGOutOpAddSubCarry outop_subbio = {
@@ -2221,6 +2370,8 @@ static const TCGOutOpAddSubCarry outop_subbio = {
static void tcg_out_set_borrow(TCGContext *s)
{
tcg_out_op_v(s, INDEX_op_tci_setcarry); /* borrow == carry */
+ tcg_wasm_out_op_i64_const(s, 1);
+ tcg_wasm_out_op_global_set(s, CARRY_IDX);
}
static void tgen_xor(TCGContext *s, TCGType type,
--
2.43.0