mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-09 10:34:58 -06:00
tcg: Convert deposit to TCGOutOpDeposit
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
b3b1397664
commit
cf4905c031
12 changed files with 206 additions and 155 deletions
|
@ -1347,15 +1347,6 @@ static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd,
|
||||||
tcg_out_insn(s, 3403, EXTR, ext, rd, rn, rm, a);
|
tcg_out_insn(s, 3403, EXTR, ext, rd, rn, rm, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void tcg_out_dep(TCGContext *s, TCGType ext, TCGReg rd,
|
|
||||||
TCGReg rn, unsigned lsb, unsigned width)
|
|
||||||
{
|
|
||||||
unsigned size = ext ? 64 : 32;
|
|
||||||
unsigned a = (size - lsb) & (size - 1);
|
|
||||||
unsigned b = width - 1;
|
|
||||||
tcg_out_bfm(s, ext, rd, rn, a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tgen_cmp(TCGContext *s, TCGType ext, TCGCond cond,
|
static void tgen_cmp(TCGContext *s, TCGType ext, TCGCond cond,
|
||||||
TCGReg a, TCGReg b)
|
TCGReg a, TCGReg b)
|
||||||
{
|
{
|
||||||
|
@ -2577,6 +2568,18 @@ static const TCGOutOpMovcond outop_movcond = {
|
||||||
.out = tgen_movcond,
|
.out = tgen_movcond,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
|
TCGReg a2, unsigned ofs, unsigned len)
|
||||||
|
{
|
||||||
|
unsigned mask = type == TCG_TYPE_I32 ? 31 : 63;
|
||||||
|
tcg_out_bfm(s, type, a0, a2, -ofs & mask, len - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TCGOutOpDeposit outop_deposit = {
|
||||||
|
.base.static_constraint = C_O1_I2(r, 0, rz),
|
||||||
|
.out_rrr = tgen_deposit,
|
||||||
|
};
|
||||||
|
|
||||||
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
unsigned ofs, unsigned len)
|
unsigned ofs, unsigned len)
|
||||||
{
|
{
|
||||||
|
@ -2684,11 +2687,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext,
|
||||||
tcg_out_qemu_ldst_i128(s, a0, a1, a2, args[3], false);
|
tcg_out_qemu_ldst_i128(s, a0, a1, a2, args[3], false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INDEX_op_deposit_i64:
|
|
||||||
case INDEX_op_deposit_i32:
|
|
||||||
tcg_out_dep(s, ext, a0, a2, args[3], args[4]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INDEX_op_extract2_i64:
|
case INDEX_op_extract2_i64:
|
||||||
case INDEX_op_extract2_i32:
|
case INDEX_op_extract2_i32:
|
||||||
tcg_out_extr(s, ext, a0, a2, a1, args[3]);
|
tcg_out_extr(s, ext, a0, a2, a1, args[3]);
|
||||||
|
@ -3206,10 +3204,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
|
||||||
case INDEX_op_qemu_st_i128:
|
case INDEX_op_qemu_st_i128:
|
||||||
return C_O0_I3(rz, rz, r);
|
return C_O0_I3(rz, rz, r);
|
||||||
|
|
||||||
case INDEX_op_deposit_i32:
|
|
||||||
case INDEX_op_deposit_i64:
|
|
||||||
return C_O1_I2(r, 0, rz);
|
|
||||||
|
|
||||||
case INDEX_op_extract2_i32:
|
case INDEX_op_extract2_i32:
|
||||||
case INDEX_op_extract2_i64:
|
case INDEX_op_extract2_i64:
|
||||||
return C_O1_I2(r, rz, rz);
|
return C_O1_I2(r, rz, rz);
|
||||||
|
|
|
@ -969,18 +969,27 @@ static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg rd, TCGReg rn)
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tcg_out_deposit(TCGContext *s, ARMCond cond, TCGReg rd,
|
static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
TCGArg a1, int ofs, int len, bool const_a1)
|
TCGReg a2, unsigned ofs, unsigned len)
|
||||||
{
|
{
|
||||||
if (const_a1) {
|
|
||||||
/* bfi becomes bfc with rn == 15. */
|
|
||||||
a1 = 15;
|
|
||||||
}
|
|
||||||
/* bfi/bfc */
|
/* bfi/bfc */
|
||||||
tcg_out32(s, 0x07c00010 | (cond << 28) | (rd << 12) | a1
|
tcg_out32(s, 0x07c00010 | (COND_AL << 28) | (a0 << 12) | a1
|
||||||
| (ofs << 7) | ((ofs + len - 1) << 16));
|
| (ofs << 7) | ((ofs + len - 1) << 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tgen_depositi(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
|
tcg_target_long a2, unsigned ofs, unsigned len)
|
||||||
|
{
|
||||||
|
/* bfi becomes bfc with rn == 15. */
|
||||||
|
tgen_deposit(s, type, a0, a1, 15, ofs, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TCGOutOpDeposit outop_deposit = {
|
||||||
|
.base.static_constraint = C_O1_I2(r, 0, rZ),
|
||||||
|
.out_rrr = tgen_deposit,
|
||||||
|
.out_rri = tgen_depositi,
|
||||||
|
};
|
||||||
|
|
||||||
static void tgen_extract(TCGContext *s, TCGType type, TCGReg rd, TCGReg rn,
|
static void tgen_extract(TCGContext *s, TCGType type, TCGReg rd, TCGReg rn,
|
||||||
unsigned ofs, unsigned len)
|
unsigned ofs, unsigned len)
|
||||||
{
|
{
|
||||||
|
@ -2402,10 +2411,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
|
||||||
tcg_out_qemu_st(s, args[0], args[1], args[2], args[3], TCG_TYPE_I64);
|
tcg_out_qemu_st(s, args[0], args[1], args[2], args[3], TCG_TYPE_I64);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INDEX_op_deposit_i32:
|
|
||||||
tcg_out_deposit(s, COND_AL, args[0], args[2],
|
|
||||||
args[3], args[4], const_args[2]);
|
|
||||||
break;
|
|
||||||
case INDEX_op_extract2_i32:
|
case INDEX_op_extract2_i32:
|
||||||
/* ??? These optimization vs zero should be generic. */
|
/* ??? These optimization vs zero should be generic. */
|
||||||
/* ??? But we can't substitute 2 for 1 in the opcode stream yet. */
|
/* ??? But we can't substitute 2 for 1 in the opcode stream yet. */
|
||||||
|
@ -2459,8 +2464,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
|
||||||
case INDEX_op_st_i32:
|
case INDEX_op_st_i32:
|
||||||
return C_O0_I2(r, r);
|
return C_O0_I2(r, r);
|
||||||
|
|
||||||
case INDEX_op_deposit_i32:
|
|
||||||
return C_O1_I2(r, 0, rZ);
|
|
||||||
case INDEX_op_extract2_i32:
|
case INDEX_op_extract2_i32:
|
||||||
return C_O1_I2(r, rZ, rZ);
|
return C_O1_I2(r, rZ, rZ);
|
||||||
case INDEX_op_add2_i32:
|
case INDEX_op_add2_i32:
|
||||||
|
|
|
@ -3150,6 +3150,43 @@ static const TCGOutOpUnary outop_not = {
|
||||||
.out_rr = tgen_not,
|
.out_rr = tgen_not,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
|
TCGReg a2, unsigned ofs, unsigned len)
|
||||||
|
{
|
||||||
|
if (ofs == 0 && len == 8) {
|
||||||
|
tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM, a2, a0);
|
||||||
|
} else if (ofs == 0 && len == 16) {
|
||||||
|
tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, a2, a0);
|
||||||
|
} else if (TCG_TARGET_REG_BITS == 32 && ofs == 8 && len == 8) {
|
||||||
|
tcg_out_modrm(s, OPC_MOVB_EvGv, a2, a0 + 4);
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tgen_depositi(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
|
tcg_target_long a2, unsigned ofs, unsigned len)
|
||||||
|
{
|
||||||
|
if (ofs == 0 && len == 8) {
|
||||||
|
tcg_out_opc(s, OPC_MOVB_Ib | P_REXB_RM | LOWREGMASK(a0), 0, a0, 0);
|
||||||
|
tcg_out8(s, a2);
|
||||||
|
} else if (ofs == 0 && len == 16) {
|
||||||
|
tcg_out_opc(s, OPC_MOVL_Iv | P_DATA16 | LOWREGMASK(a0), 0, a0, 0);
|
||||||
|
tcg_out16(s, a2);
|
||||||
|
} else if (TCG_TARGET_REG_BITS == 32 && ofs == 8 && len == 8) {
|
||||||
|
tcg_out8(s, OPC_MOVB_Ib + a0 + 4);
|
||||||
|
tcg_out8(s, a2);
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TCGOutOpDeposit outop_deposit = {
|
||||||
|
.base.static_constraint = C_O1_I2(q, 0, qi),
|
||||||
|
.out_rrr = tgen_deposit,
|
||||||
|
.out_rri = tgen_depositi,
|
||||||
|
};
|
||||||
|
|
||||||
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
unsigned ofs, unsigned len)
|
unsigned ofs, unsigned len)
|
||||||
{
|
{
|
||||||
|
@ -3230,7 +3267,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
|
||||||
const int const_args[TCG_MAX_OP_ARGS])
|
const int const_args[TCG_MAX_OP_ARGS])
|
||||||
{
|
{
|
||||||
TCGArg a0, a1, a2;
|
TCGArg a0, a1, a2;
|
||||||
int const_a2, rexw;
|
int rexw;
|
||||||
|
|
||||||
#if TCG_TARGET_REG_BITS == 64
|
#if TCG_TARGET_REG_BITS == 64
|
||||||
# define OP_32_64(x) \
|
# define OP_32_64(x) \
|
||||||
|
@ -3245,7 +3282,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
|
||||||
a0 = args[0];
|
a0 = args[0];
|
||||||
a1 = args[1];
|
a1 = args[1];
|
||||||
a2 = args[2];
|
a2 = args[2];
|
||||||
const_a2 = const_args[2];
|
|
||||||
rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
|
rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
|
||||||
|
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
|
@ -3378,38 +3414,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
OP_32_64(deposit):
|
|
||||||
if (args[3] == 0 && args[4] == 8) {
|
|
||||||
/* load bits 0..7 */
|
|
||||||
if (const_a2) {
|
|
||||||
tcg_out_opc(s, OPC_MOVB_Ib | P_REXB_RM | LOWREGMASK(a0),
|
|
||||||
0, a0, 0);
|
|
||||||
tcg_out8(s, a2);
|
|
||||||
} else {
|
|
||||||
tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM, a2, a0);
|
|
||||||
}
|
|
||||||
} else if (TCG_TARGET_REG_BITS == 32 && args[3] == 8 && args[4] == 8) {
|
|
||||||
/* load bits 8..15 */
|
|
||||||
if (const_a2) {
|
|
||||||
tcg_out8(s, OPC_MOVB_Ib + a0 + 4);
|
|
||||||
tcg_out8(s, a2);
|
|
||||||
} else {
|
|
||||||
tcg_out_modrm(s, OPC_MOVB_EvGv, a2, a0 + 4);
|
|
||||||
}
|
|
||||||
} else if (args[3] == 0 && args[4] == 16) {
|
|
||||||
/* load bits 0..15 */
|
|
||||||
if (const_a2) {
|
|
||||||
tcg_out_opc(s, OPC_MOVL_Iv | P_DATA16 | LOWREGMASK(a0),
|
|
||||||
0, a0, 0);
|
|
||||||
tcg_out16(s, a2);
|
|
||||||
} else {
|
|
||||||
tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, a2, a0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
OP_32_64(extract2):
|
OP_32_64(extract2):
|
||||||
/* Note that SHRD outputs to the r/m operand. */
|
/* Note that SHRD outputs to the r/m operand. */
|
||||||
tcg_out_modrm(s, OPC_SHRD_Ib + rexw, a2, a0);
|
tcg_out_modrm(s, OPC_SHRD_Ib + rexw, a2, a0);
|
||||||
|
@ -4008,10 +4012,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
|
||||||
case INDEX_op_extract2_i64:
|
case INDEX_op_extract2_i64:
|
||||||
return C_O1_I2(r, 0, r);
|
return C_O1_I2(r, 0, r);
|
||||||
|
|
||||||
case INDEX_op_deposit_i32:
|
|
||||||
case INDEX_op_deposit_i64:
|
|
||||||
return C_O1_I2(q, 0, qi);
|
|
||||||
|
|
||||||
case INDEX_op_add2_i32:
|
case INDEX_op_add2_i32:
|
||||||
case INDEX_op_add2_i64:
|
case INDEX_op_add2_i64:
|
||||||
case INDEX_op_sub2_i32:
|
case INDEX_op_sub2_i32:
|
||||||
|
|
|
@ -1809,6 +1809,21 @@ static const TCGOutOpUnary outop_not = {
|
||||||
.out_rr = tgen_not,
|
.out_rr = tgen_not,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
|
TCGReg a2, unsigned ofs, unsigned len)
|
||||||
|
{
|
||||||
|
if (type == TCG_TYPE_I32) {
|
||||||
|
tcg_out_opc_bstrins_w(s, a0, a2, ofs, ofs + len - 1);
|
||||||
|
} else {
|
||||||
|
tcg_out_opc_bstrins_d(s, a0, a2, ofs, ofs + len - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TCGOutOpDeposit outop_deposit = {
|
||||||
|
.base.static_constraint = C_O1_I2(r, 0, rz),
|
||||||
|
.out_rrr = tgen_deposit,
|
||||||
|
};
|
||||||
|
|
||||||
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
unsigned ofs, unsigned len)
|
unsigned ofs, unsigned len)
|
||||||
{
|
{
|
||||||
|
@ -1877,13 +1892,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
|
||||||
tcg_out_opc_b(s, 0);
|
tcg_out_opc_b(s, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INDEX_op_deposit_i32:
|
|
||||||
tcg_out_opc_bstrins_w(s, a0, a2, args[3], args[3] + args[4] - 1);
|
|
||||||
break;
|
|
||||||
case INDEX_op_deposit_i64:
|
|
||||||
tcg_out_opc_bstrins_d(s, a0, a2, args[3], args[3] + args[4] - 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INDEX_op_ld8s_i32:
|
case INDEX_op_ld8s_i32:
|
||||||
case INDEX_op_ld8s_i64:
|
case INDEX_op_ld8s_i64:
|
||||||
tcg_out_ldst(s, OPC_LD_B, a0, a1, a2);
|
tcg_out_ldst(s, OPC_LD_B, a0, a1, a2);
|
||||||
|
@ -2484,11 +2492,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
|
||||||
case INDEX_op_qemu_ld_i64:
|
case INDEX_op_qemu_ld_i64:
|
||||||
return C_O1_I1(r, r);
|
return C_O1_I1(r, r);
|
||||||
|
|
||||||
case INDEX_op_deposit_i32:
|
|
||||||
case INDEX_op_deposit_i64:
|
|
||||||
/* Must deposit into the same register as input */
|
|
||||||
return C_O1_I2(r, 0, rz);
|
|
||||||
|
|
||||||
case INDEX_op_ld_vec:
|
case INDEX_op_ld_vec:
|
||||||
case INDEX_op_dupm_vec:
|
case INDEX_op_dupm_vec:
|
||||||
case INDEX_op_dup_vec:
|
case INDEX_op_dup_vec:
|
||||||
|
|
|
@ -2215,6 +2215,22 @@ static const TCGOutOpUnary outop_not = {
|
||||||
.out_rr = tgen_not,
|
.out_rr = tgen_not,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
|
TCGReg a2, unsigned ofs, unsigned len)
|
||||||
|
{
|
||||||
|
if (type == TCG_TYPE_I32) {
|
||||||
|
tcg_out_opc_bf(s, OPC_INS, a0, a2, ofs + len - 1, ofs);
|
||||||
|
} else {
|
||||||
|
tcg_out_opc_bf64(s, OPC_DINS, OPC_DINSM, OPC_DINSU, a0, a2,
|
||||||
|
ofs + len - 1, ofs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TCGOutOpDeposit outop_deposit = {
|
||||||
|
.base.static_constraint = C_O1_I2(r, 0, rz),
|
||||||
|
.out_rrr = tgen_deposit,
|
||||||
|
};
|
||||||
|
|
||||||
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
unsigned ofs, unsigned len)
|
unsigned ofs, unsigned len)
|
||||||
{
|
{
|
||||||
|
@ -2327,14 +2343,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
|
||||||
tcg_out_ldst(s, i1, a0, a1, a2);
|
tcg_out_ldst(s, i1, a0, a1, a2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INDEX_op_deposit_i32:
|
|
||||||
tcg_out_opc_bf(s, OPC_INS, a0, a2, args[3] + args[4] - 1, args[3]);
|
|
||||||
break;
|
|
||||||
case INDEX_op_deposit_i64:
|
|
||||||
tcg_out_opc_bf64(s, OPC_DINS, OPC_DINSM, OPC_DINSU, a0, a2,
|
|
||||||
args[3] + args[4] - 1, args[3]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INDEX_op_qemu_ld_i32:
|
case INDEX_op_qemu_ld_i32:
|
||||||
tcg_out_qemu_ld(s, a0, 0, a1, a2, TCG_TYPE_I32);
|
tcg_out_qemu_ld(s, a0, 0, a1, a2, TCG_TYPE_I32);
|
||||||
break;
|
break;
|
||||||
|
@ -2407,9 +2415,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
|
||||||
case INDEX_op_st_i64:
|
case INDEX_op_st_i64:
|
||||||
return C_O0_I2(rz, r);
|
return C_O0_I2(rz, r);
|
||||||
|
|
||||||
case INDEX_op_deposit_i32:
|
|
||||||
case INDEX_op_deposit_i64:
|
|
||||||
return C_O1_I2(r, 0, rz);
|
|
||||||
case INDEX_op_add2_i32:
|
case INDEX_op_add2_i32:
|
||||||
case INDEX_op_sub2_i32:
|
case INDEX_op_sub2_i32:
|
||||||
return C_O2_I4(r, r, rz, rz, rN, rN);
|
return C_O2_I4(r, r, rz, rz, rN, rN);
|
||||||
|
|
|
@ -3429,6 +3429,28 @@ static const TCGOutOpUnary outop_not = {
|
||||||
.out_rr = tgen_not,
|
.out_rr = tgen_not,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
|
TCGReg a2, unsigned ofs, unsigned len)
|
||||||
|
{
|
||||||
|
if (type == TCG_TYPE_I32) {
|
||||||
|
tcg_out_rlw(s, RLWIMI, a0, a2, ofs, 32 - ofs - len, 31 - ofs);
|
||||||
|
} else {
|
||||||
|
tcg_out_rld(s, RLDIMI, a0, a2, ofs, 64 - ofs - len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tgen_depositi(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
|
tcg_target_long a2, unsigned ofs, unsigned len)
|
||||||
|
{
|
||||||
|
tgen_andi(s, type, a0, a1, ~MAKE_64BIT_MASK(ofs, len));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TCGOutOpDeposit outop_deposit = {
|
||||||
|
.base.static_constraint = C_O1_I2(r, 0, rZ),
|
||||||
|
.out_rrr = tgen_deposit,
|
||||||
|
.out_rri = tgen_depositi,
|
||||||
|
};
|
||||||
|
|
||||||
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
unsigned ofs, unsigned len)
|
unsigned ofs, unsigned len)
|
||||||
{
|
{
|
||||||
|
@ -3575,25 +3597,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
|
||||||
tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false);
|
tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INDEX_op_deposit_i32:
|
|
||||||
if (const_args[2]) {
|
|
||||||
uint32_t mask = ((2u << (args[4] - 1)) - 1) << args[3];
|
|
||||||
tcg_out_andi32(s, args[0], args[0], ~mask);
|
|
||||||
} else {
|
|
||||||
tcg_out_rlw(s, RLWIMI, args[0], args[2], args[3],
|
|
||||||
32 - args[3] - args[4], 31 - args[3]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case INDEX_op_deposit_i64:
|
|
||||||
if (const_args[2]) {
|
|
||||||
uint64_t mask = ((2ull << (args[4] - 1)) - 1) << args[3];
|
|
||||||
tcg_out_andi64(s, args[0], args[0], ~mask);
|
|
||||||
} else {
|
|
||||||
tcg_out_rld(s, RLDIMI, args[0], args[2], args[3],
|
|
||||||
64 - args[3] - args[4]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if TCG_TARGET_REG_BITS == 64
|
#if TCG_TARGET_REG_BITS == 64
|
||||||
case INDEX_op_add2_i64:
|
case INDEX_op_add2_i64:
|
||||||
#else
|
#else
|
||||||
|
@ -4290,9 +4293,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
|
||||||
case INDEX_op_st_i64:
|
case INDEX_op_st_i64:
|
||||||
return C_O0_I2(r, r);
|
return C_O0_I2(r, r);
|
||||||
|
|
||||||
case INDEX_op_deposit_i32:
|
|
||||||
case INDEX_op_deposit_i64:
|
|
||||||
return C_O1_I2(r, 0, rZ);
|
|
||||||
case INDEX_op_add2_i64:
|
case INDEX_op_add2_i64:
|
||||||
case INDEX_op_add2_i32:
|
case INDEX_op_add2_i32:
|
||||||
return C_O2_I4(r, r, r, r, rI, rZM);
|
return C_O2_I4(r, r, r, r, rI, rZM);
|
||||||
|
|
|
@ -2482,6 +2482,10 @@ static const TCGOutOpUnary outop_not = {
|
||||||
.out_rr = tgen_not,
|
.out_rr = tgen_not,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const TCGOutOpDeposit outop_deposit = {
|
||||||
|
.base.static_constraint = C_NotImplemented,
|
||||||
|
};
|
||||||
|
|
||||||
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
unsigned ofs, unsigned len)
|
unsigned ofs, unsigned len)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1555,14 +1555,40 @@ static const TCGOutOpMovcond outop_movcond = {
|
||||||
.out = tgen_movcond,
|
.out = tgen_movcond,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void tgen_deposit(TCGContext *s, TCGReg dest, TCGReg src,
|
static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
int ofs, int len, int z)
|
TCGReg a2, unsigned ofs, unsigned len)
|
||||||
{
|
{
|
||||||
int lsb = (63 - ofs);
|
unsigned lsb = (63 - ofs);
|
||||||
int msb = lsb - (len - 1);
|
unsigned msb = lsb - (len - 1);
|
||||||
tcg_out_risbg(s, dest, src, msb, lsb, ofs, z);
|
|
||||||
|
/*
|
||||||
|
* Since we can't support "0Z" as a constraint, we allow a1 in
|
||||||
|
* any register. Fix things up as if a matching constraint.
|
||||||
|
*/
|
||||||
|
if (a0 != a1) {
|
||||||
|
if (a0 == a2) {
|
||||||
|
tcg_out_mov(s, type, TCG_TMP0, a2);
|
||||||
|
a2 = TCG_TMP0;
|
||||||
|
}
|
||||||
|
tcg_out_mov(s, type, a0, a1);
|
||||||
|
}
|
||||||
|
tcg_out_risbg(s, a0, a2, msb, lsb, ofs, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tgen_depositz(TCGContext *s, TCGType type, TCGReg a0, TCGReg a2,
|
||||||
|
unsigned ofs, unsigned len)
|
||||||
|
{
|
||||||
|
unsigned lsb = (63 - ofs);
|
||||||
|
unsigned msb = lsb - (len - 1);
|
||||||
|
tcg_out_risbg(s, a0, a2, msb, lsb, ofs, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TCGOutOpDeposit outop_deposit = {
|
||||||
|
.base.static_constraint = C_O1_I2(r, rZ, r),
|
||||||
|
.out_rrr = tgen_deposit,
|
||||||
|
.out_rzr = tgen_depositz,
|
||||||
|
};
|
||||||
|
|
||||||
static void tgen_extract(TCGContext *s, TCGType type, TCGReg dest,
|
static void tgen_extract(TCGContext *s, TCGType type, TCGReg dest,
|
||||||
TCGReg src, unsigned ofs, unsigned len)
|
TCGReg src, unsigned ofs, unsigned len)
|
||||||
{
|
{
|
||||||
|
@ -2845,7 +2871,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
|
||||||
const TCGArg args[TCG_MAX_OP_ARGS],
|
const TCGArg args[TCG_MAX_OP_ARGS],
|
||||||
const int const_args[TCG_MAX_OP_ARGS])
|
const int const_args[TCG_MAX_OP_ARGS])
|
||||||
{
|
{
|
||||||
TCGArg a0, a1, a2;
|
TCGArg a0;
|
||||||
|
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
case INDEX_op_goto_ptr:
|
case INDEX_op_goto_ptr:
|
||||||
|
@ -2977,24 +3003,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
|
||||||
tcg_out_insn(s, RRE, SLBGR, args[1], args[5]);
|
tcg_out_insn(s, RRE, SLBGR, args[1], args[5]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
OP_32_64(deposit):
|
|
||||||
a0 = args[0], a1 = args[1], a2 = args[2];
|
|
||||||
if (const_args[1]) {
|
|
||||||
tgen_deposit(s, a0, a2, args[3], args[4], 1);
|
|
||||||
} else {
|
|
||||||
/* Since we can't support "0Z" as a constraint, we allow a1 in
|
|
||||||
any register. Fix things up as if a matching constraint. */
|
|
||||||
if (a0 != a1) {
|
|
||||||
if (a0 == a2) {
|
|
||||||
tcg_out_mov(s, type, TCG_TMP0, a2);
|
|
||||||
a2 = TCG_TMP0;
|
|
||||||
}
|
|
||||||
tcg_out_mov(s, type, a0, a1);
|
|
||||||
}
|
|
||||||
tgen_deposit(s, a0, a2, args[3], args[4], 0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INDEX_op_mb:
|
case INDEX_op_mb:
|
||||||
/* The host memory model is quite strong, we simply need to
|
/* The host memory model is quite strong, we simply need to
|
||||||
serialize the instruction stream. */
|
serialize the instruction stream. */
|
||||||
|
@ -3489,10 +3497,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
|
||||||
case INDEX_op_qemu_st_i128:
|
case INDEX_op_qemu_st_i128:
|
||||||
return C_O0_I3(o, m, r);
|
return C_O0_I3(o, m, r);
|
||||||
|
|
||||||
case INDEX_op_deposit_i32:
|
|
||||||
case INDEX_op_deposit_i64:
|
|
||||||
return C_O1_I2(r, rZ, r);
|
|
||||||
|
|
||||||
case INDEX_op_add2_i32:
|
case INDEX_op_add2_i32:
|
||||||
case INDEX_op_sub2_i32:
|
case INDEX_op_sub2_i32:
|
||||||
return C_N1_O1_I4(r, r, 0, 1, ri, r);
|
return C_N1_O1_I4(r, r, 0, 1, ri, r);
|
||||||
|
|
|
@ -1767,6 +1767,10 @@ static const TCGOutOpUnary outop_not = {
|
||||||
.out_rr = tgen_not,
|
.out_rr = tgen_not,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const TCGOutOpDeposit outop_deposit = {
|
||||||
|
.base.static_constraint = C_NotImplemented,
|
||||||
|
};
|
||||||
|
|
||||||
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
unsigned ofs, unsigned len)
|
unsigned ofs, unsigned len)
|
||||||
{
|
{
|
||||||
|
|
33
tcg/tcg.c
33
tcg/tcg.c
|
@ -1007,6 +1007,16 @@ typedef struct TCGOutOpBswap {
|
||||||
TCGReg a0, TCGReg a1, unsigned flags);
|
TCGReg a0, TCGReg a1, unsigned flags);
|
||||||
} TCGOutOpBswap;
|
} TCGOutOpBswap;
|
||||||
|
|
||||||
|
typedef struct TCGOutOpDeposit {
|
||||||
|
TCGOutOp base;
|
||||||
|
void (*out_rrr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
|
TCGReg a2, unsigned ofs, unsigned len);
|
||||||
|
void (*out_rri)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
|
tcg_target_long a2, unsigned ofs, unsigned len);
|
||||||
|
void (*out_rzr)(TCGContext *s, TCGType type, TCGReg a0,
|
||||||
|
TCGReg a2, unsigned ofs, unsigned len);
|
||||||
|
} TCGOutOpDeposit;
|
||||||
|
|
||||||
typedef struct TCGOutOpDivRem {
|
typedef struct TCGOutOpDivRem {
|
||||||
TCGOutOp base;
|
TCGOutOp base;
|
||||||
void (*out_rr01r)(TCGContext *s, TCGType type,
|
void (*out_rr01r)(TCGContext *s, TCGType type,
|
||||||
|
@ -1123,6 +1133,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = {
|
||||||
OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz),
|
OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz),
|
||||||
OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop),
|
OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop),
|
||||||
OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz),
|
OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz),
|
||||||
|
OUTOP(INDEX_op_deposit_i32, TCGOutOpDeposit, outop_deposit),
|
||||||
|
OUTOP(INDEX_op_deposit_i64, TCGOutOpDeposit, outop_deposit),
|
||||||
OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs),
|
OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs),
|
||||||
OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu),
|
OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu),
|
||||||
OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2),
|
OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2),
|
||||||
|
@ -5537,6 +5549,27 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INDEX_op_deposit_i32:
|
||||||
|
case INDEX_op_deposit_i64:
|
||||||
|
{
|
||||||
|
const TCGOutOpDeposit *out = &outop_deposit;
|
||||||
|
|
||||||
|
if (const_args[2]) {
|
||||||
|
tcg_debug_assert(!const_args[1]);
|
||||||
|
out->out_rri(s, type, new_args[0], new_args[1],
|
||||||
|
new_args[2], new_args[3], new_args[4]);
|
||||||
|
} else if (const_args[1]) {
|
||||||
|
tcg_debug_assert(new_args[1] == 0);
|
||||||
|
tcg_debug_assert(!const_args[2]);
|
||||||
|
out->out_rzr(s, type, new_args[0], new_args[2],
|
||||||
|
new_args[3], new_args[4]);
|
||||||
|
} else {
|
||||||
|
out->out_rrr(s, type, new_args[0], new_args[1],
|
||||||
|
new_args[2], new_args[3], new_args[4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case INDEX_op_divs2:
|
case INDEX_op_divs2:
|
||||||
case INDEX_op_divu2:
|
case INDEX_op_divu2:
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
|
|
||||||
#define ctpop_tr glue(ctpop, TCG_TARGET_REG_BITS)
|
#define ctpop_tr glue(ctpop, TCG_TARGET_REG_BITS)
|
||||||
|
#define deposit_tr glue(deposit, TCG_TARGET_REG_BITS)
|
||||||
#define extract_tr glue(extract, TCG_TARGET_REG_BITS)
|
#define extract_tr glue(extract, TCG_TARGET_REG_BITS)
|
||||||
#define sextract_tr glue(sextract, TCG_TARGET_REG_BITS)
|
#define sextract_tr glue(sextract, TCG_TARGET_REG_BITS)
|
||||||
|
|
||||||
|
@ -655,8 +656,9 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
|
||||||
regs[r0] = ror32(regs[r1], regs[r2] & 31);
|
regs[r0] = ror32(regs[r1], regs[r2] & 31);
|
||||||
break;
|
break;
|
||||||
case INDEX_op_deposit_i32:
|
case INDEX_op_deposit_i32:
|
||||||
|
case INDEX_op_deposit_i64:
|
||||||
tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len);
|
tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len);
|
||||||
regs[r0] = deposit32(regs[r1], pos, len, regs[r2]);
|
regs[r0] = deposit_tr(regs[r1], pos, len, regs[r2]);
|
||||||
break;
|
break;
|
||||||
case INDEX_op_extract:
|
case INDEX_op_extract:
|
||||||
tci_args_rrbb(insn, &r0, &r1, &pos, &len);
|
tci_args_rrbb(insn, &r0, &r1, &pos, &len);
|
||||||
|
@ -770,10 +772,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
|
||||||
tci_args_rrr(insn, &r0, &r1, &r2);
|
tci_args_rrr(insn, &r0, &r1, &r2);
|
||||||
regs[r0] = ror64(regs[r1], regs[r2] & 63);
|
regs[r0] = ror64(regs[r1], regs[r2] & 63);
|
||||||
break;
|
break;
|
||||||
case INDEX_op_deposit_i64:
|
|
||||||
tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len);
|
|
||||||
regs[r0] = deposit64(regs[r1], pos, len, regs[r2]);
|
|
||||||
break;
|
|
||||||
case INDEX_op_ext_i32_i64:
|
case INDEX_op_ext_i32_i64:
|
||||||
tci_args_rr(insn, &r0, &r1);
|
tci_args_rr(insn, &r0, &r1);
|
||||||
regs[r0] = (int32_t)regs[r1];
|
regs[r0] = (int32_t)regs[r1];
|
||||||
|
|
|
@ -66,10 +66,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
|
||||||
case INDEX_op_st_i64:
|
case INDEX_op_st_i64:
|
||||||
return C_O0_I2(r, r);
|
return C_O0_I2(r, r);
|
||||||
|
|
||||||
case INDEX_op_deposit_i32:
|
|
||||||
case INDEX_op_deposit_i64:
|
|
||||||
return C_O1_I2(r, r, r);
|
|
||||||
|
|
||||||
case INDEX_op_add2_i32:
|
case INDEX_op_add2_i32:
|
||||||
case INDEX_op_add2_i64:
|
case INDEX_op_add2_i64:
|
||||||
case INDEX_op_sub2_i32:
|
case INDEX_op_sub2_i32:
|
||||||
|
@ -623,6 +619,17 @@ static const TCGOutOpBinary outop_ctz = {
|
||||||
.out_rrr = tgen_ctz,
|
.out_rrr = tgen_ctz,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
|
||||||
|
TCGReg a2, unsigned ofs, unsigned len)
|
||||||
|
{
|
||||||
|
tcg_out_op_rrrbb(s, INDEX_op_deposit_i64, a0, a1, a2, ofs, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TCGOutOpDeposit outop_deposit = {
|
||||||
|
.base.static_constraint = C_O1_I2(r, r, r),
|
||||||
|
.out_rrr = tgen_deposit,
|
||||||
|
};
|
||||||
|
|
||||||
static void tgen_divs(TCGContext *s, TCGType type,
|
static void tgen_divs(TCGContext *s, TCGType type,
|
||||||
TCGReg a0, TCGReg a1, TCGReg a2)
|
TCGReg a0, TCGReg a1, TCGReg a2)
|
||||||
{
|
{
|
||||||
|
@ -1084,10 +1091,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
|
||||||
tcg_out_ldst(s, opc, args[0], args[1], args[2]);
|
tcg_out_ldst(s, opc, args[0], args[1], args[2]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
CASE_32_64(deposit)
|
|
||||||
tcg_out_op_rrrbb(s, opc, args[0], args[1], args[2], args[3], args[4]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
CASE_32_64(add2)
|
CASE_32_64(add2)
|
||||||
CASE_32_64(sub2)
|
CASE_32_64(sub2)
|
||||||
tcg_out_op_rrrrrr(s, opc, args[0], args[1], args[2],
|
tcg_out_op_rrrrrr(s, opc, args[0], args[1], args[2],
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue