TCG opcodes for extract, clz, ctz, ctpop
-----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJYdZSZAAoJEK0ScMxN0CebMqAIAIxrZVlc46OUDDawEUNE5sZZ jq+FVWkopvj+Wn5m1YPf8tjBIuIuSnJuXAPT4JI3HpzZ6C0za68Qh55Yo/SVIOgF /DtIqVxKNudE8oCVLrx3Fhqzc2/Vy7m+WrPr8XQn/dLv1ngul6uTeeMW+AZASkbL PSQ+Ri3UlhVs//kOBw16R2dklGfwaGg2gZsUzoVUSDF6V4SVXgwPWzyuIwRch2L3 Qf1VvCfIaKJKBZjE/SA6hlMnok99BZFagVM7ZdWTJX8+LljjTX2zlIfl+6anemcO oK0CPydWiwDz3GAfAL9TcHBRFTl8QpKTpS7Xgo7JqTLf6UkVI6EXMihIhAnX/kU= =ldlb -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20170110' into staging TCG opcodes for extract, clz, ctz, ctpop # gpg: Signature made Wed 11 Jan 2017 02:12:41 GMT # gpg: using RSA key 0xAD1270CC4DD0279B # gpg: Good signature from "Richard Henderson <rth7680@gmail.com>" # gpg: aka "Richard Henderson <rth@redhat.com>" # gpg: aka "Richard Henderson <rth@twiddle.net>" # Primary key fingerprint: 9CB1 8DDA F8E8 49AD 2AFC 16A4 AD12 70CC 4DD0 279B * remotes/rth/tags/pull-tcg-20170110: (65 commits) tcg/i386: Handle ctpop opcode tcg/ppc: Handle ctpop opcode tcg: Use ctpop to generate ctz if needed tests: New test-bitcnt qemu/host-utils.h: Reduce the operation count in the fallback ctpop target-i386: Use ctpop helper target-tilegx: Use ctpop helper target-sparc: Use ctpop helper target-s390x: Avoid a loop for popcnt target-ppc: Use ctpop helper target-alpha: Use ctpop helper tcg: Add opcode for ctpop target-xtensa: Use clrsb helper target-tricore: Use clrsb helper target-arm: Use clrsb helper tcg: Add helpers for clrsb tcg/i386: Rely on undefined/undocumented behaviour of BSF/BSR tcg/i386: Handle ctz and clz opcodes tcg/i386: Allow bmi2 shiftx to have non-matching operands tcg/i386: Hoist common arguments in tcg_out_op ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
0f2d17c1a5
12
disas/i386.c
12
disas/i386.c
|
@ -682,6 +682,7 @@ fetch_data(struct disassemble_info *info, bfd_byte *addr)
|
|||
#define PREGRP104 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 104 } }
|
||||
#define PREGRP105 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 105 } }
|
||||
#define PREGRP106 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 106 } }
|
||||
#define PREGRP107 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 107 } }
|
||||
|
||||
#define X86_64_0 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 0 } }
|
||||
#define X86_64_1 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 1 } }
|
||||
|
@ -1247,7 +1248,7 @@ static const struct dis386 dis386_twobyte[] = {
|
|||
{ "ud2b", { XX } },
|
||||
{ GRP8 },
|
||||
{ "btcS", { Ev, Gv } },
|
||||
{ "bsfS", { Gv, Ev } },
|
||||
{ PREGRP107 },
|
||||
{ PREGRP36 },
|
||||
{ "movs{bR|x|bR|x}", { Gv, Eb } },
|
||||
{ "movs{wR|x|wR|x}", { Gv, Ew } }, /* yes, there really is movsww ! */
|
||||
|
@ -1431,7 +1432,7 @@ static const unsigned char twobyte_uses_REPZ_prefix[256] = {
|
|||
/* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
|
||||
/* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
|
||||
/* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
|
||||
/* b0 */ 0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, /* bf */
|
||||
/* b0 */ 0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0, /* bf */
|
||||
/* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
|
||||
/* d0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */
|
||||
/* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */
|
||||
|
@ -2800,6 +2801,13 @@ static const struct dis386 prefix_user_table[][4] = {
|
|||
{ "shrxS", { Gv, Ev, Bv } },
|
||||
},
|
||||
|
||||
/* PREGRP107 */
|
||||
{
|
||||
{ "bsfS", { Gv, Ev } },
|
||||
{ "tzcntS", { Gv, Ev } },
|
||||
{ "bsfS", { Gv, Ev } },
|
||||
{ "(bad)", { XX } },
|
||||
},
|
||||
};
|
||||
|
||||
static const struct dis386 x86_64_table[][2] = {
|
||||
|
|
10
disas/ppc.c
10
disas/ppc.c
|
@ -1955,6 +1955,9 @@ extract_tbr (unsigned long insn,
|
|||
#define POWER4 PPC_OPCODE_POWER4
|
||||
#define POWER5 PPC_OPCODE_POWER5
|
||||
#define POWER6 PPC_OPCODE_POWER6
|
||||
/* Documentation purposes only; we don't actually check the isa for disas. */
|
||||
#define POWER7 PPC_OPCODE_POWER6
|
||||
#define POWER9 PPC_OPCODE_POWER6
|
||||
#define CELL PPC_OPCODE_CELL
|
||||
#define PPC32 PPC_OPCODE_32 | PPC_OPCODE_PPC
|
||||
#define PPC64 PPC_OPCODE_64 | PPC_OPCODE_PPC
|
||||
|
@ -3589,6 +3592,13 @@ const struct powerpc_opcode powerpc_opcodes[] = {
|
|||
{ "lbzux", X(31,119), X_MASK, COM, { RT, RAL, RB } },
|
||||
|
||||
{ "popcntb", X(31,122), XRB_MASK, POWER5, { RA, RS } },
|
||||
{ "popcntw", X(31,378), XRB_MASK, POWER7, { RA, RS } },
|
||||
{ "popcntd", X(31,506), XRB_MASK, POWER7, { RA, RS } },
|
||||
|
||||
{ "cnttzw", XRC(31,538,0), XRB_MASK, POWER9, { RA, RS } },
|
||||
{ "cnttzw.", XRC(31,538,1), XRB_MASK, POWER9, { RA, RS } },
|
||||
{ "cnttzd", XRC(31,570,0), XRB_MASK, POWER9, { RA, RS } },
|
||||
{ "cnttzd.", XRC(31,570,1), XRB_MASK, POWER9, { RA, RS } },
|
||||
|
||||
{ "not", XRC(31,124,0), X_MASK, COM, { RA, RS, RBS } },
|
||||
{ "nor", XRC(31,124,0), X_MASK, COM, { RA, RS, RB } },
|
||||
|
|
|
@ -327,7 +327,7 @@ static inline int ctpop8(uint8_t val)
|
|||
#else
|
||||
val = (val & 0x55) + ((val >> 1) & 0x55);
|
||||
val = (val & 0x33) + ((val >> 2) & 0x33);
|
||||
val = (val & 0x0f) + ((val >> 4) & 0x0f);
|
||||
val = (val + (val >> 4)) & 0x0f;
|
||||
|
||||
return val;
|
||||
#endif
|
||||
|
@ -344,8 +344,8 @@ static inline int ctpop16(uint16_t val)
|
|||
#else
|
||||
val = (val & 0x5555) + ((val >> 1) & 0x5555);
|
||||
val = (val & 0x3333) + ((val >> 2) & 0x3333);
|
||||
val = (val & 0x0f0f) + ((val >> 4) & 0x0f0f);
|
||||
val = (val & 0x00ff) + ((val >> 8) & 0x00ff);
|
||||
val = (val + (val >> 4)) & 0x0f0f;
|
||||
val = (val + (val >> 8)) & 0x00ff;
|
||||
|
||||
return val;
|
||||
#endif
|
||||
|
@ -362,9 +362,8 @@ static inline int ctpop32(uint32_t val)
|
|||
#else
|
||||
val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
|
||||
val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
|
||||
val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
|
||||
val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff);
|
||||
val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
|
||||
val = (val + (val >> 4)) & 0x0f0f0f0f;
|
||||
val = (val * 0x01010101) >> 24;
|
||||
|
||||
return val;
|
||||
#endif
|
||||
|
@ -381,10 +380,8 @@ static inline int ctpop64(uint64_t val)
|
|||
#else
|
||||
val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL);
|
||||
val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL);
|
||||
val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL);
|
||||
val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) & 0x00ff00ff00ff00ffULL);
|
||||
val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) & 0x0000ffff0000ffffULL);
|
||||
val = (val & 0x00000000ffffffffULL) + ((val >> 32) & 0x00000000ffffffffULL);
|
||||
val = (val + (val >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
|
||||
val = (val * 0x0101010101010101ULL) >> 56;
|
||||
|
||||
return val;
|
||||
#endif
|
||||
|
|
|
@ -3,10 +3,6 @@ DEF_HELPER_FLAGS_1(load_pcc, TCG_CALL_NO_RWG_SE, i64, env)
|
|||
|
||||
DEF_HELPER_FLAGS_3(check_overflow, TCG_CALL_NO_WG, void, env, i64, i64)
|
||||
|
||||
DEF_HELPER_FLAGS_1(ctpop, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(ctlz, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(cttz, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
|
||||
DEF_HELPER_FLAGS_2(zap, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(zapnot, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
|
||||
|
|
|
@ -24,21 +24,6 @@
|
|||
#include "qemu/host-utils.h"
|
||||
|
||||
|
||||
uint64_t helper_ctpop(uint64_t arg)
|
||||
{
|
||||
return ctpop64(arg);
|
||||
}
|
||||
|
||||
uint64_t helper_ctlz(uint64_t arg)
|
||||
{
|
||||
return clz64(arg);
|
||||
}
|
||||
|
||||
uint64_t helper_cttz(uint64_t arg)
|
||||
{
|
||||
return ctz64(arg);
|
||||
}
|
||||
|
||||
uint64_t helper_zapnot(uint64_t val, uint64_t mskb)
|
||||
{
|
||||
uint64_t mask;
|
||||
|
|
|
@ -949,7 +949,13 @@ static void gen_ext_h(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit,
|
|||
uint8_t lit, uint8_t byte_mask)
|
||||
{
|
||||
if (islit) {
|
||||
tcg_gen_shli_i64(vc, va, (64 - lit * 8) & 0x3f);
|
||||
int pos = (64 - lit * 8) & 0x3f;
|
||||
int len = cto32(byte_mask) * 8;
|
||||
if (pos < len) {
|
||||
tcg_gen_deposit_z_i64(vc, va, pos, len - pos);
|
||||
} else {
|
||||
tcg_gen_movi_i64(vc, 0);
|
||||
}
|
||||
} else {
|
||||
TCGv tmp = tcg_temp_new();
|
||||
tcg_gen_shli_i64(tmp, load_gpr(ctx, rb), 3);
|
||||
|
@ -966,38 +972,44 @@ static void gen_ext_l(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit,
|
|||
uint8_t lit, uint8_t byte_mask)
|
||||
{
|
||||
if (islit) {
|
||||
tcg_gen_shri_i64(vc, va, (lit & 7) * 8);
|
||||
int pos = (lit & 7) * 8;
|
||||
int len = cto32(byte_mask) * 8;
|
||||
if (pos + len >= 64) {
|
||||
len = 64 - pos;
|
||||
}
|
||||
tcg_gen_extract_i64(vc, va, pos, len);
|
||||
} else {
|
||||
TCGv tmp = tcg_temp_new();
|
||||
tcg_gen_andi_i64(tmp, load_gpr(ctx, rb), 7);
|
||||
tcg_gen_shli_i64(tmp, tmp, 3);
|
||||
tcg_gen_shr_i64(vc, va, tmp);
|
||||
tcg_temp_free(tmp);
|
||||
}
|
||||
gen_zapnoti(vc, vc, byte_mask);
|
||||
}
|
||||
}
|
||||
|
||||
/* INSWH, INSLH, INSQH */
|
||||
static void gen_ins_h(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit,
|
||||
uint8_t lit, uint8_t byte_mask)
|
||||
{
|
||||
TCGv tmp = tcg_temp_new();
|
||||
|
||||
/* The instruction description has us left-shift the byte mask and extract
|
||||
bits <15:8> and apply that zap at the end. This is equivalent to simply
|
||||
performing the zap first and shifting afterward. */
|
||||
gen_zapnoti(tmp, va, byte_mask);
|
||||
|
||||
if (islit) {
|
||||
lit &= 7;
|
||||
if (unlikely(lit == 0)) {
|
||||
tcg_gen_movi_i64(vc, 0);
|
||||
int pos = 64 - (lit & 7) * 8;
|
||||
int len = cto32(byte_mask) * 8;
|
||||
if (pos < len) {
|
||||
tcg_gen_extract_i64(vc, va, pos, len - pos);
|
||||
} else {
|
||||
tcg_gen_shri_i64(vc, tmp, 64 - lit * 8);
|
||||
tcg_gen_movi_i64(vc, 0);
|
||||
}
|
||||
} else {
|
||||
TCGv tmp = tcg_temp_new();
|
||||
TCGv shift = tcg_temp_new();
|
||||
|
||||
/* The instruction description has us left-shift the byte mask
|
||||
and extract bits <15:8> and apply that zap at the end. This
|
||||
is equivalent to simply performing the zap first and shifting
|
||||
afterward. */
|
||||
gen_zapnoti(tmp, va, byte_mask);
|
||||
|
||||
/* If (B & 7) == 0, we need to shift by 64 and leave a zero. Do this
|
||||
portably by splitting the shift into two parts: shift_count-1 and 1.
|
||||
Arrange for the -1 by using ones-complement instead of
|
||||
|
@ -1010,33 +1022,38 @@ static void gen_ins_h(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit,
|
|||
tcg_gen_shr_i64(vc, tmp, shift);
|
||||
tcg_gen_shri_i64(vc, vc, 1);
|
||||
tcg_temp_free(shift);
|
||||
}
|
||||
tcg_temp_free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* INSBL, INSWL, INSLL, INSQL */
|
||||
static void gen_ins_l(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit,
|
||||
uint8_t lit, uint8_t byte_mask)
|
||||
{
|
||||
if (islit) {
|
||||
int pos = (lit & 7) * 8;
|
||||
int len = cto32(byte_mask) * 8;
|
||||
if (pos + len > 64) {
|
||||
len = 64 - pos;
|
||||
}
|
||||
tcg_gen_deposit_z_i64(vc, va, pos, len);
|
||||
} else {
|
||||
TCGv tmp = tcg_temp_new();
|
||||
TCGv shift = tcg_temp_new();
|
||||
|
||||
/* The instruction description has us left-shift the byte mask
|
||||
the same number of byte slots as the data and apply the zap
|
||||
at the end. This is equivalent to simply performing the zap
|
||||
first and shifting afterward. */
|
||||
and extract bits <15:8> and apply that zap at the end. This
|
||||
is equivalent to simply performing the zap first and shifting
|
||||
afterward. */
|
||||
gen_zapnoti(tmp, va, byte_mask);
|
||||
|
||||
if (islit) {
|
||||
tcg_gen_shli_i64(vc, tmp, (lit & 7) * 8);
|
||||
} else {
|
||||
TCGv shift = tcg_temp_new();
|
||||
tcg_gen_andi_i64(shift, load_gpr(ctx, rb), 7);
|
||||
tcg_gen_shli_i64(shift, shift, 3);
|
||||
tcg_gen_shl_i64(vc, tmp, shift);
|
||||
tcg_temp_free(shift);
|
||||
}
|
||||
tcg_temp_free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* MSKWH, MSKLH, MSKQH */
|
||||
static void gen_msk_h(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit,
|
||||
|
@ -2524,7 +2541,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
|||
REQUIRE_TB_FLAG(TB_FLAGS_AMASK_CIX);
|
||||
REQUIRE_REG_31(ra);
|
||||
REQUIRE_NO_LIT;
|
||||
gen_helper_ctpop(vc, vb);
|
||||
tcg_gen_ctpop_i64(vc, vb);
|
||||
break;
|
||||
case 0x31:
|
||||
/* PERR */
|
||||
|
@ -2538,14 +2555,14 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
|||
REQUIRE_TB_FLAG(TB_FLAGS_AMASK_CIX);
|
||||
REQUIRE_REG_31(ra);
|
||||
REQUIRE_NO_LIT;
|
||||
gen_helper_ctlz(vc, vb);
|
||||
tcg_gen_clzi_i64(vc, vb, 64);
|
||||
break;
|
||||
case 0x33:
|
||||
/* CTTZ */
|
||||
REQUIRE_TB_FLAG(TB_FLAGS_AMASK_CIX);
|
||||
REQUIRE_REG_31(ra);
|
||||
REQUIRE_NO_LIT;
|
||||
gen_helper_cttz(vc, vb);
|
||||
tcg_gen_ctzi_i64(vc, vb, 64);
|
||||
break;
|
||||
case 0x34:
|
||||
/* UNPKBW */
|
||||
|
|
|
@ -54,26 +54,6 @@ int64_t HELPER(sdiv64)(int64_t num, int64_t den)
|
|||
return num / den;
|
||||
}
|
||||
|
||||
uint64_t HELPER(clz64)(uint64_t x)
|
||||
{
|
||||
return clz64(x);
|
||||
}
|
||||
|
||||
uint64_t HELPER(cls64)(uint64_t x)
|
||||
{
|
||||
return clrsb64(x);
|
||||
}
|
||||
|
||||
uint32_t HELPER(cls32)(uint32_t x)
|
||||
{
|
||||
return clrsb32(x);
|
||||
}
|
||||
|
||||
uint32_t HELPER(clz32)(uint32_t x)
|
||||
{
|
||||
return clz32(x);
|
||||
}
|
||||
|
||||
uint64_t HELPER(rbit64)(uint64_t x)
|
||||
{
|
||||
return revbit64(x);
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
*/
|
||||
DEF_HELPER_FLAGS_2(udiv64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(sdiv64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
|
||||
DEF_HELPER_FLAGS_1(clz64, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(cls64, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(cls32, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(clz32, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(rbit64, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_3(vfp_cmps_a64, i64, f32, f32, ptr)
|
||||
DEF_HELPER_3(vfp_cmpes_a64, i64, f32, f32, ptr)
|
||||
|
|
|
@ -5725,11 +5725,6 @@ uint32_t HELPER(uxtb16)(uint32_t x)
|
|||
return res;
|
||||
}
|
||||
|
||||
uint32_t HELPER(clz)(uint32_t x)
|
||||
{
|
||||
return clz32(x);
|
||||
}
|
||||
|
||||
int32_t HELPER(sdiv)(int32_t num, int32_t den)
|
||||
{
|
||||
if (den == 0)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(sxtb16, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(uxtb16, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
|
||||
|
|
|
@ -3216,67 +3216,44 @@ static void disas_bitfield(DisasContext *s, uint32_t insn)
|
|||
low 32-bits anyway. */
|
||||
tcg_tmp = read_cpu_reg(s, rn, 1);
|
||||
|
||||
/* Recognize the common aliases. */
|
||||
if (opc == 0) { /* SBFM */
|
||||
if (ri == 0) {
|
||||
if (si == 7) { /* SXTB */
|
||||
tcg_gen_ext8s_i64(tcg_rd, tcg_tmp);
|
||||
goto done;
|
||||
} else if (si == 15) { /* SXTH */
|
||||
tcg_gen_ext16s_i64(tcg_rd, tcg_tmp);
|
||||
goto done;
|
||||
} else if (si == 31) { /* SXTW */
|
||||
tcg_gen_ext32s_i64(tcg_rd, tcg_tmp);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (si == 63 || (si == 31 && ri <= si)) { /* ASR */
|
||||
if (si == 31) {
|
||||
tcg_gen_ext32s_i64(tcg_tmp, tcg_tmp);
|
||||
}
|
||||
tcg_gen_sari_i64(tcg_rd, tcg_tmp, ri);
|
||||
goto done;
|
||||
}
|
||||
} else if (opc == 2) { /* UBFM */
|
||||
if (ri == 0) { /* UXTB, UXTH, plus non-canonical AND */
|
||||
tcg_gen_andi_i64(tcg_rd, tcg_tmp, bitmask64(si + 1));
|
||||
return;
|
||||
}
|
||||
if (si == 63 || (si == 31 && ri <= si)) { /* LSR */
|
||||
if (si == 31) {
|
||||
tcg_gen_ext32u_i64(tcg_tmp, tcg_tmp);
|
||||
}
|
||||
tcg_gen_shri_i64(tcg_rd, tcg_tmp, ri);
|
||||
return;
|
||||
}
|
||||
if (si + 1 == ri && si != bitsize - 1) { /* LSL */
|
||||
int shift = bitsize - 1 - si;
|
||||
tcg_gen_shli_i64(tcg_rd, tcg_tmp, shift);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (opc != 1) { /* SBFM or UBFM */
|
||||
tcg_gen_movi_i64(tcg_rd, 0);
|
||||
}
|
||||
|
||||
/* do the bit move operation */
|
||||
if (si >= ri) {
|
||||
/* Recognize simple(r) extractions. */
|
||||
if (si <= ri) {
|
||||
/* Wd<s-r:0> = Wn<s:r> */
|
||||
tcg_gen_shri_i64(tcg_tmp, tcg_tmp, ri);
|
||||
pos = 0;
|
||||
len = (si - ri) + 1;
|
||||
if (opc == 0) { /* SBFM: ASR, SBFX, SXTB, SXTH, SXTW */
|
||||
tcg_gen_sextract_i64(tcg_rd, tcg_tmp, ri, len);
|
||||
goto done;
|
||||
} else if (opc == 2) { /* UBFM: UBFX, LSR, UXTB, UXTH */
|
||||
tcg_gen_extract_i64(tcg_rd, tcg_tmp, ri, len);
|
||||
return;
|
||||
}
|
||||
/* opc == 1, BXFIL fall through to deposit */
|
||||
tcg_gen_extract_i64(tcg_tmp, tcg_tmp, ri, len);
|
||||
pos = 0;
|
||||
} else {
|
||||
/* Wd<32+s-r,32-r> = Wn<s:0> */
|
||||
pos = bitsize - ri;
|
||||
/* Handle the ri > si case with a deposit
|
||||
* Wd<32+s-r,32-r> = Wn<s:0>
|
||||
*/
|
||||
len = si + 1;
|
||||
pos = (bitsize - ri) & (bitsize - 1);
|
||||
}
|
||||
|
||||
tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, pos, len);
|
||||
if (opc == 0 && len < ri) {
|
||||
/* SBFM: sign extend the destination field from len to fill
|
||||
the balance of the word. Let the deposit below insert all
|
||||
of those sign bits. */
|
||||
tcg_gen_sextract_i64(tcg_tmp, tcg_tmp, 0, len);
|
||||
len = ri;
|
||||
}
|
||||
|
||||
if (opc == 0) { /* SBFM - sign extend the destination field */
|
||||
tcg_gen_shli_i64(tcg_rd, tcg_rd, 64 - (pos + len));
|
||||
tcg_gen_sari_i64(tcg_rd, tcg_rd, 64 - (pos + len));
|
||||
if (opc == 1) { /* BFM, BXFIL */
|
||||
tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, pos, len);
|
||||
} else {
|
||||
/* SBFM or UBFM: We start with zero, and we haven't modified
|
||||
any bits outside bitsize, therefore the zero-extension
|
||||
below is unneeded. */
|
||||
tcg_gen_deposit_z_i64(tcg_rd, tcg_tmp, pos, len);
|
||||
return;
|
||||
}
|
||||
|
||||
done:
|
||||
|
@ -3977,11 +3954,11 @@ static void handle_clz(DisasContext *s, unsigned int sf,
|
|||
tcg_rn = cpu_reg(s, rn);
|
||||
|
||||
if (sf) {
|
||||
gen_helper_clz64(tcg_rd, tcg_rn);
|
||||
tcg_gen_clzi_i64(tcg_rd, tcg_rn, 64);
|
||||
} else {
|
||||
TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
|
||||
tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
|
||||
gen_helper_clz(tcg_tmp32, tcg_tmp32);
|
||||
tcg_gen_clzi_i32(tcg_tmp32, tcg_tmp32, 32);
|
||||
tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
|
||||
tcg_temp_free_i32(tcg_tmp32);
|
||||
}
|
||||
|
@ -3995,11 +3972,11 @@ static void handle_cls(DisasContext *s, unsigned int sf,
|
|||
tcg_rn = cpu_reg(s, rn);
|
||||
|
||||
if (sf) {
|
||||
gen_helper_cls64(tcg_rd, tcg_rn);
|
||||
tcg_gen_clrsb_i64(tcg_rd, tcg_rn);
|
||||
} else {
|
||||
TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
|
||||
tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
|
||||
gen_helper_cls32(tcg_tmp32, tcg_tmp32);
|
||||
tcg_gen_clrsb_i32(tcg_tmp32, tcg_tmp32);
|
||||
tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
|
||||
tcg_temp_free_i32(tcg_tmp32);
|
||||
}
|
||||
|
@ -7614,9 +7591,9 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u,
|
|||
switch (opcode) {
|
||||
case 0x4: /* CLS, CLZ */
|
||||
if (u) {
|
||||
gen_helper_clz64(tcg_rd, tcg_rn);
|
||||
tcg_gen_clzi_i64(tcg_rd, tcg_rn, 64);
|
||||
} else {
|
||||
gen_helper_cls64(tcg_rd, tcg_rn);
|
||||
tcg_gen_clrsb_i64(tcg_rd, tcg_rn);
|
||||
}
|
||||
break;
|
||||
case 0x5: /* NOT */
|
||||
|
@ -10284,9 +10261,9 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
|
|||
goto do_cmop;
|
||||
case 0x4: /* CLS */
|
||||
if (u) {
|
||||
gen_helper_clz32(tcg_res, tcg_op);
|
||||
tcg_gen_clzi_i32(tcg_res, tcg_op, 32);
|
||||
} else {
|
||||
gen_helper_cls32(tcg_res, tcg_op);
|
||||
tcg_gen_clrsb_i32(tcg_res, tcg_op);
|
||||
}
|
||||
break;
|
||||
case 0x7: /* SQABS, SQNEG */
|
||||
|
|
|
@ -288,29 +288,6 @@ static void gen_revsh(TCGv_i32 var)
|
|||
tcg_gen_ext16s_i32(var, var);
|
||||
}
|
||||
|
||||
/* Unsigned bitfield extract. */
|
||||
static void gen_ubfx(TCGv_i32 var, int shift, uint32_t mask)
|
||||
{
|
||||
if (shift)
|
||||
tcg_gen_shri_i32(var, var, shift);
|
||||
tcg_gen_andi_i32(var, var, mask);
|
||||
}
|
||||
|
||||
/* Signed bitfield extract. */
|
||||
static void gen_sbfx(TCGv_i32 var, int shift, int width)
|
||||
{
|
||||
uint32_t signbit;
|
||||
|
||||
if (shift)
|
||||
tcg_gen_sari_i32(var, var, shift);
|
||||
if (shift + width < 32) {
|
||||
signbit = 1u << (width - 1);
|
||||
tcg_gen_andi_i32(var, var, (1u << width) - 1);
|
||||
tcg_gen_xori_i32(var, var, signbit);
|
||||
tcg_gen_subi_i32(var, var, signbit);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return (b << 32) + a. Mark inputs as dead */
|
||||
static TCGv_i64 gen_addq_msw(TCGv_i64 a, TCGv_i32 b)
|
||||
{
|
||||
|
@ -7060,7 +7037,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
|||
switch (size) {
|
||||
case 0: gen_helper_neon_clz_u8(tmp, tmp); break;
|
||||
case 1: gen_helper_neon_clz_u16(tmp, tmp); break;
|
||||
case 2: gen_helper_clz(tmp, tmp); break;
|
||||
case 2: tcg_gen_clzi_i32(tmp, tmp, 32); break;
|
||||
default: abort();
|
||||
}
|
||||
break;
|
||||
|
@ -8242,7 +8219,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
|||
ARCH(5);
|
||||
rd = (insn >> 12) & 0xf;
|
||||
tmp = load_reg(s, rm);
|
||||
gen_helper_clz(tmp, tmp);
|
||||
tcg_gen_clzi_i32(tmp, tmp, 32);
|
||||
store_reg(s, rd, tmp);
|
||||
} else {
|
||||
goto illegal_op;
|
||||
|
@ -9178,9 +9155,9 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
|||
goto illegal_op;
|
||||
if (i < 32) {
|
||||
if (op1 & 0x20) {
|
||||
gen_ubfx(tmp, shift, (1u << i) - 1);
|
||||
tcg_gen_extract_i32(tmp, tmp, shift, i);
|
||||
} else {
|
||||
gen_sbfx(tmp, shift, i);
|
||||
tcg_gen_sextract_i32(tmp, tmp, shift, i);
|
||||
}
|
||||
}
|
||||
store_reg(s, rd, tmp);
|
||||
|
@ -10015,7 +9992,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
|
|||
tcg_temp_free_i32(tmp2);
|
||||
break;
|
||||
case 0x18: /* clz */
|
||||
gen_helper_clz(tmp, tmp);
|
||||
tcg_gen_clzi_i32(tmp, tmp, 32);
|
||||
break;
|
||||
case 0x20:
|
||||
case 0x21:
|
||||
|
@ -10497,15 +10474,17 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
|
|||
imm++;
|
||||
if (shift + imm > 32)
|
||||
goto illegal_op;
|
||||
if (imm < 32)
|
||||
gen_sbfx(tmp, shift, imm);
|
||||
if (imm < 32) {
|
||||
tcg_gen_sextract_i32(tmp, tmp, shift, imm);
|
||||
}
|
||||
break;
|
||||
case 6: /* Unsigned bitfield extract. */
|
||||
imm++;
|
||||
if (shift + imm > 32)
|
||||
goto illegal_op;
|
||||
if (imm < 32)
|
||||
gen_ubfx(tmp, shift, (1u << imm) - 1);
|
||||
if (imm < 32) {
|
||||
tcg_gen_extract_i32(tmp, tmp, shift, imm);
|
||||
}
|
||||
break;
|
||||
case 3: /* Bitfield insert/clear. */
|
||||
if (imm < shift)
|
||||
|
|
|
@ -7,7 +7,6 @@ DEF_HELPER_1(rfn, void, env)
|
|||
DEF_HELPER_3(movl_sreg_reg, void, env, i32, i32)
|
||||
DEF_HELPER_3(movl_reg_sreg, void, env, i32, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_1(lz, TCG_CALL_NO_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_4(btst, TCG_CALL_NO_SE, i32, env, i32, i32, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(evaluate_flags_muls, TCG_CALL_NO_SE, i32, env, i32, i32, i32)
|
||||
|
|
|
@ -230,11 +230,6 @@ void helper_rfn(CPUCRISState *env)
|
|||
env->pregs[PR_CCS] |= M_FLAG_V32;
|
||||
}
|
||||
|
||||
uint32_t helper_lz(uint32_t t0)
|
||||
{
|
||||
return clz32(t0);
|
||||
}
|
||||
|
||||
uint32_t helper_btst(CPUCRISState *env, uint32_t t0, uint32_t t1, uint32_t ccs)
|
||||
{
|
||||
/* FIXME: clean this up. */
|
||||
|
|
|
@ -767,7 +767,7 @@ static void cris_alu_op_exec(DisasContext *dc, int op,
|
|||
t_gen_subx_carry(dc, dst);
|
||||
break;
|
||||
case CC_OP_LZ:
|
||||
gen_helper_lz(dst, b);
|
||||
tcg_gen_clzi_tl(dst, b, TARGET_LONG_BITS);
|
||||
break;
|
||||
case CC_OP_MULS:
|
||||
tcg_gen_muls2_tl(dst, cpu_PR[PR_MOF], a, b);
|
||||
|
|
|
@ -105,6 +105,8 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1,
|
|||
return src1;
|
||||
case CC_OP_CLR:
|
||||
return CC_Z | CC_P;
|
||||
case CC_OP_POPCNT:
|
||||
return src1 ? 0 : CC_Z;
|
||||
|
||||
case CC_OP_MULB:
|
||||
return compute_all_mulb(dst, src1);
|
||||
|
@ -232,6 +234,7 @@ target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1,
|
|||
case CC_OP_LOGICL:
|
||||
case CC_OP_LOGICQ:
|
||||
case CC_OP_CLR:
|
||||
case CC_OP_POPCNT:
|
||||
return 0;
|
||||
|
||||
case CC_OP_EFLAGS:
|
||||
|
|
|
@ -777,6 +777,7 @@ typedef enum {
|
|||
CC_OP_ADCOX, /* CC_DST = C, CC_SRC2 = O, CC_SRC = rest. */
|
||||
|
||||
CC_OP_CLR, /* Z set, all other flags clear. */
|
||||
CC_OP_POPCNT, /* Z via CC_SRC, all other flags clear. */
|
||||
|
||||
CC_OP_NB,
|
||||
} CCOp;
|
||||
|
|
|
@ -202,8 +202,6 @@ DEF_HELPER_FLAGS_3(xsetbv, TCG_CALL_NO_WG, void, env, i32, i64)
|
|||
DEF_HELPER_FLAGS_2(rdpkru, TCG_CALL_NO_WG, i64, env, i32)
|
||||
DEF_HELPER_FLAGS_3(wrpkru, TCG_CALL_NO_WG, void, env, i32, i64)
|
||||
|
||||
DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(ctz, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_2(pdep, TCG_CALL_NO_RWG_SE, tl, tl, tl)
|
||||
DEF_HELPER_FLAGS_2(pext, TCG_CALL_NO_RWG_SE, tl, tl, tl)
|
||||
|
||||
|
|
|
@ -417,17 +417,6 @@ void helper_idivq_EAX(CPUX86State *env, target_ulong t0)
|
|||
# define clztl clz64
|
||||
#endif
|
||||
|
||||
/* bit operations */
|
||||
target_ulong helper_ctz(target_ulong t0)
|
||||
{
|
||||
return ctztl(t0);
|
||||
}
|
||||
|
||||
target_ulong helper_clz(target_ulong t0)
|
||||
{
|
||||
return clztl(t0);
|
||||
}
|
||||
|
||||
target_ulong helper_pdep(target_ulong src, target_ulong mask)
|
||||
{
|
||||
target_ulong dest = 0;
|
||||
|
|
|
@ -2157,32 +2157,6 @@ target_ulong helper_crc32(uint32_t crc1, target_ulong msg, uint32_t len)
|
|||
return crc;
|
||||
}
|
||||
|
||||
#define POPMASK(i) ((target_ulong) -1 / ((1LL << (1 << i)) + 1))
|
||||
#define POPCOUNT(n, i) ((n & POPMASK(i)) + ((n >> (1 << i)) & POPMASK(i)))
|
||||
target_ulong helper_popcnt(CPUX86State *env, target_ulong n, uint32_t type)
|
||||
{
|
||||
CC_SRC = n ? 0 : CC_Z;
|
||||
|
||||
n = POPCOUNT(n, 0);
|
||||
n = POPCOUNT(n, 1);
|
||||
n = POPCOUNT(n, 2);
|
||||
n = POPCOUNT(n, 3);
|
||||
if (type == 1) {
|
||||
return n & 0xff;
|
||||
}
|
||||
|
||||
n = POPCOUNT(n, 4);
|
||||
#ifndef TARGET_X86_64
|
||||
return n;
|
||||
#else
|
||||
if (type == 2) {
|
||||
return n & 0xff;
|
||||
}
|
||||
|
||||
return POPCOUNT(n, 5);
|
||||
#endif
|
||||
}
|
||||
|
||||
void glue(helper_pclmulqdq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
|
||||
uint32_t ctrl)
|
||||
{
|
||||
|
|
|
@ -333,7 +333,6 @@ DEF_HELPER_4(glue(pcmpestrm, SUFFIX), void, env, Reg, Reg, i32)
|
|||
DEF_HELPER_4(glue(pcmpistri, SUFFIX), void, env, Reg, Reg, i32)
|
||||
DEF_HELPER_4(glue(pcmpistrm, SUFFIX), void, env, Reg, Reg, i32)
|
||||
DEF_HELPER_3(crc32, tl, i32, tl, i32)
|
||||
DEF_HELPER_3(popcnt, tl, env, tl, i32)
|
||||
#endif
|
||||
|
||||
/* AES-NI op helpers */
|
||||
|
|
|
@ -222,6 +222,7 @@ static const uint8_t cc_op_live[CC_OP_NB] = {
|
|||
[CC_OP_ADOX] = USES_CC_SRC | USES_CC_SRC2,
|
||||
[CC_OP_ADCOX] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
|
||||
[CC_OP_CLR] = 0,
|
||||
[CC_OP_POPCNT] = USES_CC_SRC,
|
||||
};
|
||||
|
||||
static void set_cc_op(DisasContext *s, CCOp op)
|
||||
|
@ -383,8 +384,7 @@ static void gen_op_mov_reg_v(TCGMemOp ot, int reg, TCGv t0)
|
|||
static inline void gen_op_mov_v_reg(TCGMemOp ot, TCGv t0, int reg)
|
||||
{
|
||||
if (ot == MO_8 && byte_reg_is_xH(reg)) {
|
||||
tcg_gen_shri_tl(t0, cpu_regs[reg - 4], 8);
|
||||
tcg_gen_ext8u_tl(t0, t0);
|
||||
tcg_gen_extract_tl(t0, cpu_regs[reg - 4], 8, 8);
|
||||
} else {
|
||||
tcg_gen_mov_tl(t0, cpu_regs[reg]);
|
||||
}
|
||||
|
@ -758,6 +758,7 @@ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg)
|
|||
|
||||
case CC_OP_LOGICB ... CC_OP_LOGICQ:
|
||||
case CC_OP_CLR:
|
||||
case CC_OP_POPCNT:
|
||||
return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 };
|
||||
|
||||
case CC_OP_INCB ... CC_OP_INCQ:
|
||||
|
@ -825,6 +826,7 @@ static CCPrepare gen_prepare_eflags_s(DisasContext *s, TCGv reg)
|
|||
return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
|
||||
.mask = CC_S };
|
||||
case CC_OP_CLR:
|
||||
case CC_OP_POPCNT:
|
||||
return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 };
|
||||
default:
|
||||
{
|
||||
|
@ -844,6 +846,7 @@ static CCPrepare gen_prepare_eflags_o(DisasContext *s, TCGv reg)
|
|||
return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src2,
|
||||
.mask = -1, .no_setcond = true };
|
||||
case CC_OP_CLR:
|
||||
case CC_OP_POPCNT:
|
||||
return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 };
|
||||
default:
|
||||
gen_compute_eflags(s);
|
||||
|
@ -867,6 +870,9 @@ static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg)
|
|||
.mask = CC_Z };
|
||||
case CC_OP_CLR:
|
||||
return (CCPrepare) { .cond = TCG_COND_ALWAYS, .mask = -1 };
|
||||
case CC_OP_POPCNT:
|
||||
return (CCPrepare) { .cond = TCG_COND_EQ, .reg = cpu_cc_src,
|
||||
.mask = -1 };
|
||||
default:
|
||||
{
|
||||
TCGMemOp size = (s->cc_op - CC_OP_ADDB) & 3;
|
||||
|
@ -3768,8 +3774,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||
|
||||
/* Extract the LEN into a mask. Lengths larger than
|
||||
operand size get all ones. */
|
||||
tcg_gen_shri_tl(cpu_A0, cpu_regs[s->vex_v], 8);
|
||||
tcg_gen_ext8u_tl(cpu_A0, cpu_A0);
|
||||
tcg_gen_extract_tl(cpu_A0, cpu_regs[s->vex_v], 8, 8);
|
||||
tcg_gen_movcond_tl(TCG_COND_LEU, cpu_A0, cpu_A0, bound,
|
||||
cpu_A0, bound);
|
||||
tcg_temp_free(bound);
|
||||
|
@ -3920,9 +3925,8 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||
gen_compute_eflags(s);
|
||||
}
|
||||
carry_in = cpu_tmp0;
|
||||
tcg_gen_shri_tl(carry_in, cpu_cc_src,
|
||||
ctz32(b == 0x1f6 ? CC_C : CC_O));
|
||||
tcg_gen_andi_tl(carry_in, carry_in, 1);
|
||||
tcg_gen_extract_tl(carry_in, cpu_cc_src,
|
||||
ctz32(b == 0x1f6 ? CC_C : CC_O), 1);
|
||||
}
|
||||
|
||||
switch (ot) {
|
||||
|
@ -5447,6 +5451,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
rm = (modrm & 7) | REX_B(s);
|
||||
|
||||
if (mod == 3) {
|
||||
if (s_ot == MO_SB && byte_reg_is_xH(rm)) {
|
||||
tcg_gen_sextract_tl(cpu_T0, cpu_regs[rm - 4], 8, 8);
|
||||
} else {
|
||||
gen_op_mov_v_reg(ot, cpu_T0, rm);
|
||||
switch (s_ot) {
|
||||
case MO_UB:
|
||||
|
@ -5463,6 +5470,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
tcg_gen_ext16s_tl(cpu_T0, cpu_T0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
gen_op_mov_reg_v(d_ot, reg, cpu_T0);
|
||||
} else {
|
||||
gen_lea_modrm(env, s, modrm);
|
||||
|
@ -6806,21 +6814,18 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
? s->cpuid_ext3_features & CPUID_EXT3_ABM
|
||||
: s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1)) {
|
||||
int size = 8 << ot;
|
||||
/* For lzcnt/tzcnt, C bit is defined related to the input. */
|
||||
tcg_gen_mov_tl(cpu_cc_src, cpu_T0);
|
||||
if (b & 1) {
|
||||
/* For lzcnt, reduce the target_ulong result by the
|
||||
number of zeros that we expect to find at the top. */
|
||||
gen_helper_clz(cpu_T0, cpu_T0);
|
||||
tcg_gen_clzi_tl(cpu_T0, cpu_T0, TARGET_LONG_BITS);
|
||||
tcg_gen_subi_tl(cpu_T0, cpu_T0, TARGET_LONG_BITS - size);
|
||||
} else {
|
||||
/* For tzcnt, a zero input must return the operand size:
|
||||
force all bits outside the operand size to 1. */
|
||||
target_ulong mask = (target_ulong)-2 << (size - 1);
|
||||
tcg_gen_ori_tl(cpu_T0, cpu_T0, mask);
|
||||
gen_helper_ctz(cpu_T0, cpu_T0);
|
||||
/* For tzcnt, a zero input must return the operand size. */
|
||||
tcg_gen_ctzi_tl(cpu_T0, cpu_T0, size);
|
||||
}
|
||||
/* For lzcnt/tzcnt, C and Z bits are defined and are
|
||||
related to the result. */
|
||||
/* For lzcnt/tzcnt, Z bit is defined related to the result. */
|
||||
gen_op_update1_cc();
|
||||
set_cc_op(s, CC_OP_BMILGB + ot);
|
||||
} else {
|
||||
|
@ -6828,20 +6833,20 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
to the input and not the result. */
|
||||
tcg_gen_mov_tl(cpu_cc_dst, cpu_T0);
|
||||
set_cc_op(s, CC_OP_LOGICB + ot);
|
||||
|
||||
/* ??? The manual says that the output is undefined when the
|
||||
input is zero, but real hardware leaves it unchanged, and
|
||||
real programs appear to depend on that. Accomplish this
|
||||
by passing the output as the value to return upon zero. */
|
||||
if (b & 1) {
|
||||
/* For bsr, return the bit index of the first 1 bit,
|
||||
not the count of leading zeros. */
|
||||
gen_helper_clz(cpu_T0, cpu_T0);
|
||||
tcg_gen_xori_tl(cpu_T1, cpu_regs[reg], TARGET_LONG_BITS - 1);
|
||||
tcg_gen_clz_tl(cpu_T0, cpu_T0, cpu_T1);
|
||||
tcg_gen_xori_tl(cpu_T0, cpu_T0, TARGET_LONG_BITS - 1);
|
||||
} else {
|
||||
gen_helper_ctz(cpu_T0, cpu_T0);
|
||||
tcg_gen_ctz_tl(cpu_T0, cpu_T0, cpu_regs[reg]);
|
||||
}
|
||||
/* ??? The manual says that the output is undefined when the
|
||||
input is zero, but real hardware leaves it unchanged, and
|
||||
real programs appear to depend on that. */
|
||||
tcg_gen_movi_tl(cpu_tmp0, 0);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, cpu_T0, cpu_cc_dst, cpu_tmp0,
|
||||
cpu_regs[reg], cpu_T0);
|
||||
}
|
||||
gen_op_mov_reg_v(ot, reg, cpu_T0);
|
||||
break;
|
||||
|
@ -8207,10 +8212,12 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
}
|
||||
|
||||
gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
|
||||
gen_helper_popcnt(cpu_T0, cpu_env, cpu_T0, tcg_const_i32(ot));
|
||||
gen_extu(ot, cpu_T0);
|
||||
tcg_gen_mov_tl(cpu_cc_src, cpu_T0);
|
||||
tcg_gen_ctpop_tl(cpu_T0, cpu_T0);
|
||||
gen_op_mov_reg_v(ot, reg, cpu_T0);
|
||||
|
||||
set_cc_op(s, CC_OP_EFLAGS);
|
||||
set_cc_op(s, CC_OP_POPCNT);
|
||||
break;
|
||||
case 0x10e ... 0x10f:
|
||||
/* 3DNow! instructions, ignore prefixes */
|
||||
|
|
|
@ -3,7 +3,6 @@ DEF_HELPER_1(debug, void, env)
|
|||
DEF_HELPER_FLAGS_3(carry, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32)
|
||||
DEF_HELPER_2(cmp, i32, i32, i32)
|
||||
DEF_HELPER_2(cmpu, i32, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
|
||||
DEF_HELPER_3(divs, i32, env, i32, i32)
|
||||
DEF_HELPER_3(divu, i32, env, i32, i32)
|
||||
|
|
|
@ -145,11 +145,6 @@ uint32_t helper_cmpu(uint32_t a, uint32_t b)
|
|||
return t;
|
||||
}
|
||||
|
||||
uint32_t helper_clz(uint32_t t0)
|
||||
{
|
||||
return clz32(t0);
|
||||
}
|
||||
|
||||
uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf)
|
||||
{
|
||||
return compute_carry(a, b, cf);
|
||||
|
|
|
@ -768,7 +768,7 @@ static void dec_bit(DisasContext *dc)
|
|||
t_gen_raise_exception(dc, EXCP_HW_EXCP);
|
||||
}
|
||||
if (dc->cpu->env.pvr.regs[2] & PVR2_USE_PCMP_INSTR) {
|
||||
gen_helper_clz(cpu_R[dc->rd], cpu_R[dc->ra]);
|
||||
tcg_gen_clzi_i32(cpu_R[dc->rd], cpu_R[dc->ra], 32);
|
||||
}
|
||||
break;
|
||||
case 0x1e0:
|
||||
|
|
|
@ -20,13 +20,6 @@ DEF_HELPER_4(scd, tl, env, tl, tl, int)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
DEF_HELPER_FLAGS_1(clo, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
#ifdef TARGET_MIPS64
|
||||
DEF_HELPER_FLAGS_1(dclo, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(dclz, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
#endif
|
||||
|
||||
DEF_HELPER_3(muls, tl, env, tl, tl)
|
||||
DEF_HELPER_3(mulsu, tl, env, tl, tl)
|
||||
DEF_HELPER_3(macc, tl, env, tl, tl)
|
||||
|
|
|
@ -103,28 +103,6 @@ HELPER_ST(sd, stq, uint64_t)
|
|||
#endif
|
||||
#undef HELPER_ST
|
||||
|
||||
target_ulong helper_clo (target_ulong arg1)
|
||||
{
|
||||
return clo32(arg1);
|
||||
}
|
||||
|
||||
target_ulong helper_clz (target_ulong arg1)
|
||||
{
|
||||
return clz32(arg1);
|
||||
}
|
||||
|
||||
#if defined(TARGET_MIPS64)
|
||||
target_ulong helper_dclo (target_ulong arg1)
|
||||
{
|
||||
return clo64(arg1);
|
||||
}
|
||||
|
||||
target_ulong helper_dclz (target_ulong arg1)
|
||||
{
|
||||
return clz64(arg1);
|
||||
}
|
||||
#endif /* TARGET_MIPS64 */
|
||||
|
||||
/* 64 bits arithmetic for 32 bits hosts */
|
||||
static inline uint64_t get_HILO(CPUMIPSState *env)
|
||||
{
|
||||
|
|
|
@ -3626,29 +3626,38 @@ static void gen_cl (DisasContext *ctx, uint32_t opc,
|
|||
/* Treat as NOP. */
|
||||
return;
|
||||
}
|
||||
t0 = tcg_temp_new();
|
||||
t0 = cpu_gpr[rd];
|
||||
gen_load_gpr(t0, rs);
|
||||
|
||||
switch (opc) {
|
||||
case OPC_CLO:
|
||||
case R6_OPC_CLO:
|
||||
gen_helper_clo(cpu_gpr[rd], t0);
|
||||
#if defined(TARGET_MIPS64)
|
||||
case OPC_DCLO:
|
||||
case R6_OPC_DCLO:
|
||||
#endif
|
||||
tcg_gen_not_tl(t0, t0);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (opc) {
|
||||
case OPC_CLO:
|
||||
case R6_OPC_CLO:
|
||||
case OPC_CLZ:
|
||||
case R6_OPC_CLZ:
|
||||
gen_helper_clz(cpu_gpr[rd], t0);
|
||||
tcg_gen_ext32u_tl(t0, t0);
|
||||
tcg_gen_clzi_tl(t0, t0, TARGET_LONG_BITS);
|
||||
tcg_gen_subi_tl(t0, t0, TARGET_LONG_BITS - 32);
|
||||
break;
|
||||
#if defined(TARGET_MIPS64)
|
||||
case OPC_DCLO:
|
||||
case R6_OPC_DCLO:
|
||||
gen_helper_dclo(cpu_gpr[rd], t0);
|
||||
break;
|
||||
case OPC_DCLZ:
|
||||
case R6_OPC_DCLZ:
|
||||
gen_helper_dclz(cpu_gpr[rd], t0);
|
||||
tcg_gen_clzi_i64(t0, t0, 64);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
tcg_temp_free(t0);
|
||||
}
|
||||
|
||||
/* Godson integer instructions */
|
||||
|
@ -4488,11 +4497,12 @@ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
|
|||
if (lsb + msb > 31) {
|
||||
goto fail;
|
||||
}
|
||||
tcg_gen_shri_tl(t0, t1, lsb);
|
||||
if (msb != 31) {
|
||||
tcg_gen_andi_tl(t0, t0, (1U << (msb + 1)) - 1);
|
||||
tcg_gen_extract_tl(t0, t1, lsb, msb + 1);
|
||||
} else {
|
||||
tcg_gen_ext32s_tl(t0, t0);
|
||||
/* The two checks together imply that lsb == 0,
|
||||
so this is a simple sign-extension. */
|
||||
tcg_gen_ext32s_tl(t0, t1);
|
||||
}
|
||||
break;
|
||||
#if defined(TARGET_MIPS64)
|
||||
|
@ -4507,10 +4517,7 @@ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
|
|||
if (lsb + msb > 63) {
|
||||
goto fail;
|
||||
}
|
||||
tcg_gen_shri_tl(t0, t1, lsb);
|
||||
if (msb != 63) {
|
||||
tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
|
||||
}
|
||||
tcg_gen_extract_tl(t0, t1, lsb, msb + 1);
|
||||
break;
|
||||
#endif
|
||||
case OPC_INS:
|
||||
|
|
|
@ -54,8 +54,6 @@ FOP_CMP(ge)
|
|||
#undef FOP_CMP
|
||||
|
||||
/* int */
|
||||
DEF_HELPER_FLAGS_1(ff1, 0, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(fl1, 0, tl, tl)
|
||||
DEF_HELPER_FLAGS_3(mul32, 0, i32, env, i32, i32)
|
||||
|
||||
/* interrupt */
|
||||
|
|
|
@ -24,25 +24,6 @@
|
|||
#include "exception.h"
|
||||
#include "qemu/host-utils.h"
|
||||
|
||||
target_ulong HELPER(ff1)(target_ulong x)
|
||||
{
|
||||
/*#ifdef TARGET_OPENRISC64
|
||||
return x ? ctz64(x) + 1 : 0;
|
||||
#else*/
|
||||
return x ? ctz32(x) + 1 : 0;
|
||||
/*#endif*/
|
||||
}
|
||||
|
||||
target_ulong HELPER(fl1)(target_ulong x)
|
||||
{
|
||||
/* not used yet, open it when we need or64. */
|
||||
/*#ifdef TARGET_OPENRISC64
|
||||
return 64 - clz64(x);
|
||||
#else*/
|
||||
return 32 - clz32(x);
|
||||
/*#endif*/
|
||||
}
|
||||
|
||||
uint32_t HELPER(mul32)(CPUOpenRISCState *env,
|
||||
uint32_t ra, uint32_t rb)
|
||||
{
|
||||
|
|
|
@ -602,11 +602,13 @@ static void dec_calc(DisasContext *dc, uint32_t insn)
|
|||
switch (op1) {
|
||||
case 0x00: /* l.ff1 */
|
||||
LOG_DIS("l.ff1 r%d, r%d, r%d\n", rd, ra, rb);
|
||||
gen_helper_ff1(cpu_R[rd], cpu_R[ra]);
|
||||
tcg_gen_ctzi_tl(cpu_R[rd], cpu_R[ra], -1);
|
||||
tcg_gen_addi_tl(cpu_R[rd], cpu_R[rd], 1);
|
||||
break;
|
||||
case 0x01: /* l.fl1 */
|
||||
LOG_DIS("l.fl1 r%d, r%d, r%d\n", rd, ra, rb);
|
||||
gen_helper_fl1(cpu_R[rd], cpu_R[ra]);
|
||||
tcg_gen_clzi_tl(cpu_R[rd], cpu_R[ra], TARGET_LONG_BITS);
|
||||
tcg_gen_subfi_tl(cpu_R[rd], TARGET_LONG_BITS, cpu_R[rd]);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -38,17 +38,12 @@ DEF_HELPER_4(divde, i64, env, i64, i64, i32)
|
|||
DEF_HELPER_4(divweu, tl, env, tl, tl, i32)
|
||||
DEF_HELPER_4(divwe, tl, env, tl, tl, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(cnttzw, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_2(cmpb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
|
||||
DEF_HELPER_3(sraw, tl, env, tl, tl)
|
||||
#if defined(TARGET_PPC64)
|
||||
DEF_HELPER_FLAGS_2(cmpeqb, TCG_CALL_NO_RWG_SE, i32, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(cnttzd, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_2(bpermd, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_3(srad, tl, env, tl, tl)
|
||||
DEF_HELPER_0(darn32, tl)
|
||||
|
|
|
@ -141,16 +141,6 @@ uint64_t helper_divde(CPUPPCState *env, uint64_t rau, uint64_t rbu, uint32_t oe)
|
|||
#endif
|
||||
|
||||
|
||||
target_ulong helper_cntlzw(target_ulong t)
|
||||
{
|
||||
return clz32(t);
|
||||
}
|
||||
|
||||
target_ulong helper_cnttzw(target_ulong t)
|
||||
{
|
||||
return ctz32(t);
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
/* if x = 0xab, returns 0xababababababababa */
|
||||
#define pattern(x) (((x) & 0xff) * (~(target_ulong)0 / 0xff))
|
||||
|
@ -174,16 +164,6 @@ uint32_t helper_cmpeqb(target_ulong ra, target_ulong rb)
|
|||
#undef haszero
|
||||
#undef hasvalue
|
||||
|
||||
target_ulong helper_cntlzd(target_ulong t)
|
||||
{
|
||||
return clz64(t);
|
||||
}
|
||||
|
||||
target_ulong helper_cnttzd(target_ulong t)
|
||||
{
|
||||
return ctz64(t);
|
||||
}
|
||||
|
||||
/* Return invalid random number.
|
||||
*
|
||||
* FIXME: Add rng backend or other mechanism to get cryptographically suitable
|
||||
|
@ -292,6 +272,7 @@ target_ulong helper_srad(CPUPPCState *env, target_ulong value,
|
|||
#if defined(TARGET_PPC64)
|
||||
target_ulong helper_popcntb(target_ulong val)
|
||||
{
|
||||
/* Note that we don't fold past bytes */
|
||||
val = (val & 0x5555555555555555ULL) + ((val >> 1) &
|
||||
0x5555555555555555ULL);
|
||||
val = (val & 0x3333333333333333ULL) + ((val >> 2) &
|
||||
|
@ -303,6 +284,7 @@ target_ulong helper_popcntb(target_ulong val)
|
|||
|
||||
target_ulong helper_popcntw(target_ulong val)
|
||||
{
|
||||
/* Note that we don't fold past words. */
|
||||
val = (val & 0x5555555555555555ULL) + ((val >> 1) &
|
||||
0x5555555555555555ULL);
|
||||
val = (val & 0x3333333333333333ULL) + ((val >> 2) &
|
||||
|
@ -315,29 +297,15 @@ target_ulong helper_popcntw(target_ulong val)
|
|||
0x0000ffff0000ffffULL);
|
||||
return val;
|
||||
}
|
||||
|
||||
target_ulong helper_popcntd(target_ulong val)
|
||||
{
|
||||
return ctpop64(val);
|
||||
}
|
||||
#else
|
||||
target_ulong helper_popcntb(target_ulong val)
|
||||
{
|
||||
/* Note that we don't fold past bytes */
|
||||
val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
|
||||
val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
|
||||
val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
|
||||
return val;
|
||||
}
|
||||
|
||||
target_ulong helper_popcntw(target_ulong val)
|
||||
{
|
||||
val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
|
||||
val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
|
||||
val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
|
||||
val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff);
|
||||
val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
@ -1641,7 +1641,13 @@ static void gen_andis_(DisasContext *ctx)
|
|||
/* cntlzw */
|
||||
static void gen_cntlzw(DisasContext *ctx)
|
||||
{
|
||||
gen_helper_cntlzw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
|
||||
TCGv_i32 t = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_trunc_tl_i32(t, cpu_gpr[rS(ctx->opcode)]);
|
||||
tcg_gen_clzi_i32(t, t, 32);
|
||||
tcg_gen_extu_i32_tl(cpu_gpr[rA(ctx->opcode)], t);
|
||||
tcg_temp_free_i32(t);
|
||||
|
||||
if (unlikely(Rc(ctx->opcode) != 0))
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
|
@ -1649,7 +1655,13 @@ static void gen_cntlzw(DisasContext *ctx)
|
|||
/* cnttzw */
|
||||
static void gen_cnttzw(DisasContext *ctx)
|
||||
{
|
||||
gen_helper_cnttzw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
|
||||
TCGv_i32 t = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_trunc_tl_i32(t, cpu_gpr[rS(ctx->opcode)]);
|
||||
tcg_gen_ctzi_i32(t, t, 32);
|
||||
tcg_gen_extu_i32_tl(cpu_gpr[rA(ctx->opcode)], t);
|
||||
tcg_temp_free_i32(t);
|
||||
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
|
@ -1832,14 +1844,18 @@ static void gen_popcntb(DisasContext *ctx)
|
|||
|
||||
static void gen_popcntw(DisasContext *ctx)
|
||||
{
|
||||
#if defined(TARGET_PPC64)
|
||||
gen_helper_popcntw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
|
||||
#else
|
||||
tcg_gen_ctpop_i32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
/* popcntd: PowerPC 2.06 specification */
|
||||
static void gen_popcntd(DisasContext *ctx)
|
||||
{
|
||||
gen_helper_popcntd(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
|
||||
tcg_gen_ctpop_i64(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1891,7 +1907,7 @@ GEN_LOGICAL1(extsw, tcg_gen_ext32s_tl, 0x1E, PPC_64B);
|
|||
/* cntlzd */
|
||||
static void gen_cntlzd(DisasContext *ctx)
|
||||
{
|
||||
gen_helper_cntlzd(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
|
||||
tcg_gen_clzi_i64(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], 64);
|
||||
if (unlikely(Rc(ctx->opcode) != 0))
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
|
@ -1899,7 +1915,7 @@ static void gen_cntlzd(DisasContext *ctx)
|
|||
/* cnttzd */
|
||||
static void gen_cnttzd(DisasContext *ctx)
|
||||
{
|
||||
gen_helper_cnttzd(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
|
||||
tcg_gen_ctzi_i64(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], 64);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
|
||||
}
|
||||
|
@ -1975,16 +1991,16 @@ static void gen_rlwinm(DisasContext *ctx)
|
|||
{
|
||||
TCGv t_ra = cpu_gpr[rA(ctx->opcode)];
|
||||
TCGv t_rs = cpu_gpr[rS(ctx->opcode)];
|
||||
uint32_t sh = SH(ctx->opcode);
|
||||
uint32_t mb = MB(ctx->opcode);
|
||||
uint32_t me = ME(ctx->opcode);
|
||||
int sh = SH(ctx->opcode);
|
||||
int mb = MB(ctx->opcode);
|
||||
int me = ME(ctx->opcode);
|
||||
int len = me - mb + 1;
|
||||
int rsh = (32 - sh) & 31;
|
||||
|
||||
if (mb == 0 && me == (31 - sh)) {
|
||||
tcg_gen_shli_tl(t_ra, t_rs, sh);
|
||||
tcg_gen_ext32u_tl(t_ra, t_ra);
|
||||
} else if (sh != 0 && me == 31 && sh == (32 - mb)) {
|
||||
tcg_gen_ext32u_tl(t_ra, t_rs);
|
||||
tcg_gen_shri_tl(t_ra, t_ra, mb);
|
||||
if (sh != 0 && len > 0 && me == (31 - sh)) {
|
||||
tcg_gen_deposit_z_tl(t_ra, t_rs, sh, len);
|
||||
} else if (me == 31 && rsh + len <= 32) {
|
||||
tcg_gen_extract_tl(t_ra, t_rs, rsh, len);
|
||||
} else {
|
||||
target_ulong mask;
|
||||
#if defined(TARGET_PPC64)
|
||||
|
@ -1992,8 +2008,9 @@ static void gen_rlwinm(DisasContext *ctx)
|
|||
me += 32;
|
||||
#endif
|
||||
mask = MASK(mb, me);
|
||||
|
||||
if (mask <= 0xffffffffu) {
|
||||
if (sh == 0) {
|
||||
tcg_gen_andi_tl(t_ra, t_rs, mask);
|
||||
} else if (mask <= 0xffffffffu) {
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
tcg_gen_trunc_tl_i32(t0, t_rs);
|
||||
tcg_gen_rotli_i32(t0, t0, sh);
|
||||
|
@ -2096,11 +2113,13 @@ static void gen_rldinm(DisasContext *ctx, int mb, int me, int sh)
|
|||
{
|
||||
TCGv t_ra = cpu_gpr[rA(ctx->opcode)];
|
||||
TCGv t_rs = cpu_gpr[rS(ctx->opcode)];
|
||||
int len = me - mb + 1;
|
||||
int rsh = (64 - sh) & 63;
|
||||
|
||||
if (sh != 0 && mb == 0 && me == (63 - sh)) {
|
||||
tcg_gen_shli_tl(t_ra, t_rs, sh);
|
||||
} else if (sh != 0 && me == 63 && sh == (64 - mb)) {
|
||||
tcg_gen_shri_tl(t_ra, t_rs, mb);
|
||||
if (sh != 0 && len > 0 && me == (63 - sh)) {
|
||||
tcg_gen_deposit_z_tl(t_ra, t_rs, sh, len);
|
||||
} else if (me == 63 && rsh + len <= 64) {
|
||||
tcg_gen_extract_tl(t_ra, t_rs, rsh, len);
|
||||
} else {
|
||||
tcg_gen_rotli_tl(t_ra, t_rs, sh);
|
||||
tcg_gen_andi_tl(t_ra, t_ra, MASK(mb, me));
|
||||
|
|
|
@ -70,7 +70,6 @@ DEF_HELPER_FLAGS_4(msdb, TCG_CALL_NO_WG, i64, env, i64, i64, i64)
|
|||
DEF_HELPER_FLAGS_3(tceb, TCG_CALL_NO_RWG_SE, i32, env, i64, i64)
|
||||
DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_RWG_SE, i32, env, i64, i64)
|
||||
DEF_HELPER_FLAGS_4(tcxb, TCG_CALL_NO_RWG_SE, i32, env, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(sqeb, TCG_CALL_NO_WG, i64, env, i64)
|
||||
DEF_HELPER_FLAGS_2(sqdb, TCG_CALL_NO_WG, i64, env, i64)
|
||||
DEF_HELPER_FLAGS_3(sqxb, TCG_CALL_NO_WG, i64, env, i64, i64)
|
||||
|
|
|
@ -117,12 +117,6 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* count leading zeros, for find leftmost one */
|
||||
uint64_t HELPER(clz)(uint64_t v)
|
||||
{
|
||||
return clz64(v);
|
||||
}
|
||||
|
||||
uint64_t HELPER(cvd)(int32_t reg)
|
||||
{
|
||||
/* positive 0 */
|
||||
|
@ -143,14 +137,11 @@ uint64_t HELPER(cvd)(int32_t reg)
|
|||
return dec;
|
||||
}
|
||||
|
||||
uint64_t HELPER(popcnt)(uint64_t r2)
|
||||
uint64_t HELPER(popcnt)(uint64_t val)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 64; i += 8) {
|
||||
uint64_t t = ctpop32((r2 >> i) & 0xff);
|
||||
ret |= t << i;
|
||||
}
|
||||
return ret;
|
||||
/* Note that we don't fold past bytes. */
|
||||
val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL);
|
||||
val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL);
|
||||
val = (val + (val >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
|
||||
return val;
|
||||
}
|
||||
|
|
|
@ -2249,7 +2249,7 @@ static ExitStatus op_flogr(DisasContext *s, DisasOps *o)
|
|||
gen_op_update1_cc_i64(s, CC_OP_FLOGR, o->in2);
|
||||
|
||||
/* R1 = IN ? CLZ(IN) : 64. */
|
||||
gen_helper_clz(o->out, o->in2);
|
||||
tcg_gen_clzi_i64(o->out, o->in2, 64);
|
||||
|
||||
/* R1+1 = IN & ~(found bit). Note that we may attempt to shift this
|
||||
value by 64, which is undefined. But since the shift is 64 iff the
|
||||
|
@ -3134,20 +3134,26 @@ static ExitStatus op_risbg(DisasContext *s, DisasOps *o)
|
|||
}
|
||||
}
|
||||
|
||||
/* In some cases we can implement this with deposit, which can be more
|
||||
efficient on some hosts. */
|
||||
if (~mask == imask && i3 <= i4) {
|
||||
if (s->fields->op2 == 0x5d) {
|
||||
i3 += 32, i4 += 32;
|
||||
}
|
||||
/* Note that we rotate the bits to be inserted to the lsb, not to
|
||||
the position as described in the PoO. */
|
||||
len = i4 - i3 + 1;
|
||||
pos = 63 - i4;
|
||||
rot = (i5 - pos) & 63;
|
||||
} else {
|
||||
pos = len = -1;
|
||||
rot = i5 & 63;
|
||||
if (s->fields->op2 == 0x5d) {
|
||||
pos += 32;
|
||||
}
|
||||
|
||||
/* In some cases we can implement this with extract. */
|
||||
if (imask == 0 && pos == 0 && len > 0 && rot + len <= 64) {
|
||||
tcg_gen_extract_i64(o->out, o->in2, rot, len);
|
||||
return NO_EXIT;
|
||||
}
|
||||
|
||||
/* In some cases we can implement this with deposit. */
|
||||
if (len > 0 && (imask == 0 || ~mask == imask)) {
|
||||
/* Note that we rotate the bits to be inserted to the lsb, not to
|
||||
the position as described in the PoO. */
|
||||
rot = (rot - pos) & 63;
|
||||
} else {
|
||||
pos = -1;
|
||||
}
|
||||
|
||||
/* Rotate the input as necessary. */
|
||||
|
@ -3155,7 +3161,11 @@ static ExitStatus op_risbg(DisasContext *s, DisasOps *o)
|
|||
|
||||
/* Insert the selected bits into the output. */
|
||||
if (pos >= 0) {
|
||||
if (imask == 0) {
|
||||
tcg_gen_deposit_z_i64(o->out, o->in2, pos, len);
|
||||
} else {
|
||||
tcg_gen_deposit_i64(o->out, o->out, o->in2, pos, len);
|
||||
}
|
||||
} else if (imask == 0) {
|
||||
tcg_gen_andi_i64(o->out, o->in2, mask);
|
||||
} else {
|
||||
|
|
|
@ -49,11 +49,6 @@ void helper_debug(CPUSPARCState *env)
|
|||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
target_ulong helper_popc(target_ulong val)
|
||||
{
|
||||
return ctpop64(val);
|
||||
}
|
||||
|
||||
void helper_tick_set_count(void *opaque, uint64_t count)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
|
|
@ -16,7 +16,6 @@ DEF_HELPER_2(wrccr, void, env, tl)
|
|||
DEF_HELPER_1(rdcwp, tl, env)
|
||||
DEF_HELPER_2(wrcwp, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(array8, TCG_CALL_NO_RWG_SE, tl, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(popc, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_2(set_softint, TCG_CALL_NO_RWG, void, env, i64)
|
||||
DEF_HELPER_FLAGS_2(clear_softint, TCG_CALL_NO_RWG, void, env, i64)
|
||||
DEF_HELPER_FLAGS_2(write_softint, TCG_CALL_NO_RWG, void, env, i64)
|
||||
|
|
|
@ -4647,7 +4647,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
|
|||
gen_store_gpr(dc, rd, cpu_dst);
|
||||
break;
|
||||
case 0x2e: /* V9 popc */
|
||||
gen_helper_popc(cpu_dst, cpu_src2);
|
||||
tcg_gen_ctpop_tl(cpu_dst, cpu_src2);
|
||||
gen_store_gpr(dc, rd, cpu_dst);
|
||||
break;
|
||||
case 0x2f: /* V9 movr */
|
||||
|
|
|
@ -55,21 +55,6 @@ void helper_ext01_ics(CPUTLGState *env)
|
|||
}
|
||||
}
|
||||
|
||||
uint64_t helper_cntlz(uint64_t arg)
|
||||
{
|
||||
return clz64(arg);
|
||||
}
|
||||
|
||||
uint64_t helper_cnttz(uint64_t arg)
|
||||
{
|
||||
return ctz64(arg);
|
||||
}
|
||||
|
||||
uint64_t helper_pcnt(uint64_t arg)
|
||||
{
|
||||
return ctpop64(arg);
|
||||
}
|
||||
|
||||
uint64_t helper_revbits(uint64_t arg)
|
||||
{
|
||||
return revbit64(arg);
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
DEF_HELPER_2(exception, noreturn, env, i32)
|
||||
DEF_HELPER_1(ext01_ics, void, env)
|
||||
DEF_HELPER_FLAGS_1(cntlz, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(cnttz, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(pcnt, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(revbits, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_3(shufflebytes, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(crc32_8, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
|
|
|
@ -608,12 +608,12 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
|
|||
switch (opext) {
|
||||
case OE_RR_X0(CNTLZ):
|
||||
case OE_RR_Y0(CNTLZ):
|
||||
gen_helper_cntlz(tdest, tsrca);
|
||||
tcg_gen_clzi_tl(tdest, tsrca, TARGET_LONG_BITS);
|
||||
mnemonic = "cntlz";
|
||||
break;
|
||||
case OE_RR_X0(CNTTZ):
|
||||
case OE_RR_Y0(CNTTZ):
|
||||
gen_helper_cnttz(tdest, tsrca);
|
||||
tcg_gen_ctzi_tl(tdest, tsrca, TARGET_LONG_BITS);
|
||||
mnemonic = "cnttz";
|
||||
break;
|
||||
case OE_RR_X0(FSINGLE_PACK1):
|
||||
|
@ -697,7 +697,7 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
|
|||
break;
|
||||
case OE_RR_X0(PCNT):
|
||||
case OE_RR_Y0(PCNT):
|
||||
gen_helper_pcnt(tdest, tsrca);
|
||||
tcg_gen_ctpop_tl(tdest, tsrca);
|
||||
mnemonic = "pcnt";
|
||||
break;
|
||||
case OE_RR_X0(REVBITS):
|
||||
|
|
|
@ -87,11 +87,8 @@ DEF_HELPER_FLAGS_2(min_hu, TCG_CALL_NO_RWG_SE, i32, i32, i32)
|
|||
DEF_HELPER_FLAGS_2(ixmin, TCG_CALL_NO_RWG_SE, i64, i64, i32)
|
||||
DEF_HELPER_FLAGS_2(ixmin_u, TCG_CALL_NO_RWG_SE, i64, i64, i32)
|
||||
/* count leading ... */
|
||||
DEF_HELPER_FLAGS_1(clo, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(clo_h, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(clz_h, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(cls, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(cls_h, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
/* sh */
|
||||
DEF_HELPER_FLAGS_2(sh, TCG_CALL_NO_RWG_SE, i32, i32, i32)
|
||||
|
|
|
@ -1733,11 +1733,6 @@ EXTREMA_H_B(min, <)
|
|||
|
||||
#undef EXTREMA_H_B
|
||||
|
||||
uint32_t helper_clo(target_ulong r1)
|
||||
{
|
||||
return clo32(r1);
|
||||
}
|
||||
|
||||
uint32_t helper_clo_h(target_ulong r1)
|
||||
{
|
||||
uint32_t ret_hw0 = extract32(r1, 0, 16);
|
||||
|
@ -1756,11 +1751,6 @@ uint32_t helper_clo_h(target_ulong r1)
|
|||
return ret_hw0 | (ret_hw1 << 16);
|
||||
}
|
||||
|
||||
uint32_t helper_clz(target_ulong r1)
|
||||
{
|
||||
return clz32(r1);
|
||||
}
|
||||
|
||||
uint32_t helper_clz_h(target_ulong r1)
|
||||
{
|
||||
uint32_t ret_hw0 = extract32(r1, 0, 16);
|
||||
|
@ -1779,11 +1769,6 @@ uint32_t helper_clz_h(target_ulong r1)
|
|||
return ret_hw0 | (ret_hw1 << 16);
|
||||
}
|
||||
|
||||
uint32_t helper_cls(target_ulong r1)
|
||||
{
|
||||
return clrsb32(r1);
|
||||
}
|
||||
|
||||
uint32_t helper_cls_h(target_ulong r1)
|
||||
{
|
||||
uint32_t ret_hw0 = extract32(r1, 0, 16);
|
||||
|
|
|
@ -6367,19 +6367,20 @@ static void decode_rr_logical_shift(CPUTriCoreState *env, DisasContext *ctx)
|
|||
tcg_gen_andc_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
|
||||
break;
|
||||
case OPC2_32_RR_CLO:
|
||||
gen_helper_clo(cpu_gpr_d[r3], cpu_gpr_d[r1]);
|
||||
tcg_gen_not_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]);
|
||||
tcg_gen_clzi_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], TARGET_LONG_BITS);
|
||||
break;
|
||||
case OPC2_32_RR_CLO_H:
|
||||
gen_helper_clo_h(cpu_gpr_d[r3], cpu_gpr_d[r1]);
|
||||
break;
|
||||
case OPC2_32_RR_CLS:
|
||||
gen_helper_cls(cpu_gpr_d[r3], cpu_gpr_d[r1]);
|
||||
tcg_gen_clrsb_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]);
|
||||
break;
|
||||
case OPC2_32_RR_CLS_H:
|
||||
gen_helper_cls_h(cpu_gpr_d[r3], cpu_gpr_d[r1]);
|
||||
break;
|
||||
case OPC2_32_RR_CLZ:
|
||||
gen_helper_clz(cpu_gpr_d[r3], cpu_gpr_d[r1]);
|
||||
tcg_gen_clzi_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], TARGET_LONG_BITS);
|
||||
break;
|
||||
case OPC2_32_RR_CLZ_H:
|
||||
gen_helper_clz_h(cpu_gpr_d[r3], cpu_gpr_d[r1]);
|
||||
|
|
|
@ -32,16 +32,6 @@ UniCore32CPU *uc32_cpu_init(const char *cpu_model)
|
|||
return UNICORE32_CPU(cpu_generic_init(TYPE_UNICORE32_CPU, cpu_model));
|
||||
}
|
||||
|
||||
uint32_t HELPER(clo)(uint32_t x)
|
||||
{
|
||||
return clo32(x);
|
||||
}
|
||||
|
||||
uint32_t HELPER(clz)(uint32_t x)
|
||||
{
|
||||
return clz32(x);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
void helper_cp0_set(CPUUniCore32State *env, uint32_t val, uint32_t creg,
|
||||
uint32_t cop)
|
||||
|
|
|
@ -13,9 +13,6 @@ DEF_HELPER_3(cp0_get, i32, env, i32, i32)
|
|||
DEF_HELPER_1(cp1_putc, void, i32)
|
||||
#endif
|
||||
|
||||
DEF_HELPER_1(clz, i32, i32)
|
||||
DEF_HELPER_1(clo, i32, i32)
|
||||
|
||||
DEF_HELPER_2(exception, void, env, i32)
|
||||
|
||||
DEF_HELPER_3(asr_write, void, env, i32, i32)
|
||||
|
|
|
@ -1479,10 +1479,10 @@ static void do_misc(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
|
|||
/* clz */
|
||||
tmp = load_reg(s, UCOP_REG_M);
|
||||
if (UCOP_SET(26)) {
|
||||
gen_helper_clo(tmp, tmp);
|
||||
} else {
|
||||
gen_helper_clz(tmp, tmp);
|
||||
/* clo */
|
||||
tcg_gen_not_i32(tmp, tmp);
|
||||
}
|
||||
tcg_gen_clzi_i32(tmp, tmp, 32);
|
||||
store_reg(s, UCOP_REG_D, tmp);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ DEF_HELPER_3(exception_cause, noreturn, env, i32, i32)
|
|||
DEF_HELPER_4(exception_cause_vaddr, noreturn, env, i32, i32, i32)
|
||||
DEF_HELPER_3(debug_exception, noreturn, env, i32, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_1(nsa, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(nsau, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_2(wsr_windowbase, void, env, i32)
|
||||
DEF_HELPER_4(entry, void, env, i32, i32, i32)
|
||||
DEF_HELPER_2(retw, i32, env, i32)
|
||||
|
|
|
@ -161,19 +161,6 @@ void HELPER(debug_exception)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
|
|||
HELPER(exception)(env, EXC_DEBUG);
|
||||
}
|
||||
|
||||
uint32_t HELPER(nsa)(uint32_t v)
|
||||
{
|
||||
if (v & 0x80000000) {
|
||||
v = ~v;
|
||||
}
|
||||
return v ? clz32(v) - 1 : 31;
|
||||
}
|
||||
|
||||
uint32_t HELPER(nsau)(uint32_t v)
|
||||
{
|
||||
return v ? clz32(v) : 32;
|
||||
}
|
||||
|
||||
static void copy_window_from_phys(CPUXtensaState *env,
|
||||
uint32_t window, uint32_t phys, uint32_t n)
|
||||
{
|
||||
|
|
|
@ -1372,14 +1372,14 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
|
|||
case 14: /*NSAu*/
|
||||
HAS_OPTION(XTENSA_OPTION_MISC_OP_NSA);
|
||||
if (gen_window_check2(dc, RRR_S, RRR_T)) {
|
||||
gen_helper_nsa(cpu_R[RRR_T], cpu_R[RRR_S]);
|
||||
tcg_gen_clrsb_i32(cpu_R[RRR_T], cpu_R[RRR_S]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 15: /*NSAUu*/
|
||||
HAS_OPTION(XTENSA_OPTION_MISC_OP_NSA);
|
||||
if (gen_window_check2(dc, RRR_S, RRR_T)) {
|
||||
gen_helper_nsau(cpu_R[RRR_T], cpu_R[RRR_S]);
|
||||
tcg_gen_clzi_i32(cpu_R[RRR_T], cpu_R[RRR_S], 32);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -101,6 +101,46 @@ int64_t HELPER(mulsh_i64)(int64_t arg1, int64_t arg2)
|
|||
return h;
|
||||
}
|
||||
|
||||
uint32_t HELPER(clz_i32)(uint32_t arg, uint32_t zero_val)
|
||||
{
|
||||
return arg ? clz32(arg) : zero_val;
|
||||
}
|
||||
|
||||
uint32_t HELPER(ctz_i32)(uint32_t arg, uint32_t zero_val)
|
||||
{
|
||||
return arg ? ctz32(arg) : zero_val;
|
||||
}
|
||||
|
||||
uint64_t HELPER(clz_i64)(uint64_t arg, uint64_t zero_val)
|
||||
{
|
||||
return arg ? clz64(arg) : zero_val;
|
||||
}
|
||||
|
||||
uint64_t HELPER(ctz_i64)(uint64_t arg, uint64_t zero_val)
|
||||
{
|
||||
return arg ? ctz64(arg) : zero_val;
|
||||
}
|
||||
|
||||
uint32_t HELPER(clrsb_i32)(uint32_t arg)
|
||||
{
|
||||
return clrsb32(arg);
|
||||
}
|
||||
|
||||
uint64_t HELPER(clrsb_i64)(uint64_t arg)
|
||||
{
|
||||
return clrsb64(arg);
|
||||
}
|
||||
|
||||
uint32_t HELPER(ctpop_i32)(uint32_t arg)
|
||||
{
|
||||
return ctpop32(arg);
|
||||
}
|
||||
|
||||
uint64_t HELPER(ctpop_i64)(uint64_t arg)
|
||||
{
|
||||
return ctpop64(arg);
|
||||
}
|
||||
|
||||
void HELPER(exit_atomic)(CPUArchState *env)
|
||||
{
|
||||
cpu_loop_exit_atomic(ENV_GET_CPU(env), GETPC());
|
||||
|
|
41
tcg/README
41
tcg/README
|
@ -246,6 +246,14 @@ t0=~(t1|t2)
|
|||
|
||||
t0=t1|~t2
|
||||
|
||||
* clz_i32/i64 t0, t1, t2
|
||||
|
||||
t0 = t1 ? clz(t1) : t2
|
||||
|
||||
* ctz_i32/i64 t0, t1, t2
|
||||
|
||||
t0 = t1 ? ctz(t1) : t2
|
||||
|
||||
********* Shifts/Rotates
|
||||
|
||||
* shl_i32/i64 t0, t1, t2
|
||||
|
@ -314,11 +322,27 @@ The bitfield is described by POS/LEN, which are immediate values:
|
|||
LEN - the length of the bitfield
|
||||
POS - the position of the first bit, counting from the LSB
|
||||
|
||||
For example, pos=8, len=4 indicates a 4-bit field at bit 8.
|
||||
This operation would be equivalent to
|
||||
For example, "deposit_i32 dest, t1, t2, 8, 4" indicates a 4-bit field
|
||||
at bit 8. This operation would be equivalent to
|
||||
|
||||
dest = (t1 & ~0x0f00) | ((t2 << 8) & 0x0f00)
|
||||
|
||||
* extract_i32/i64 dest, t1, pos, len
|
||||
* sextract_i32/i64 dest, t1, pos, len
|
||||
|
||||
Extract a bitfield from T1, placing the result in DEST.
|
||||
The bitfield is described by POS/LEN, which are immediate values,
|
||||
as above for deposit. For extract_*, the result will be extended
|
||||
to the left with zeros; for sextract_*, the result will be extended
|
||||
to the left with copies of the bitfield sign bit at pos + len - 1.
|
||||
|
||||
For example, "sextract_i32 dest, t1, 8, 4" indicates a 4-bit field
|
||||
at bit 8. This operation would be equivalent to
|
||||
|
||||
dest = (t1 << 20) >> 28
|
||||
|
||||
(using an arithmetic right shift).
|
||||
|
||||
* extrl_i64_i32 t0, t1
|
||||
|
||||
For 64-bit hosts only, extract the low 32-bits of input T1 and place it
|
||||
|
@ -523,24 +547,29 @@ version. Aliases are specified in the input operands as for GCC.
|
|||
The same register may be used for both an input and an output, even when
|
||||
they are not explicitly aliased. If an op expands to multiple target
|
||||
instructions then care must be taken to avoid clobbering input values.
|
||||
GCC style "early clobber" outputs are not currently supported.
|
||||
GCC style "early clobber" outputs are supported, with '&'.
|
||||
|
||||
A target can define specific register or constant constraints. If an
|
||||
operation uses a constant input constraint which does not allow all
|
||||
constants, it must also accept registers in order to have a fallback.
|
||||
The constraint 'i' is defined generically to accept any constant.
|
||||
The constraint 'r' is not defined generically, but is consistently
|
||||
used by each backend to indicate all registers.
|
||||
|
||||
The movi_i32 and movi_i64 operations must accept any constants.
|
||||
|
||||
The mov_i32 and mov_i64 operations must accept any registers of the
|
||||
same type.
|
||||
|
||||
The ld/st instructions must accept signed 32 bit constant offsets. It
|
||||
can be implemented by reserving a specific register to compute the
|
||||
address if the offset is too big.
|
||||
The ld/st/sti instructions must accept signed 32 bit constant offsets.
|
||||
This can be implemented by reserving a specific register in which to
|
||||
compute the address if the offset is too big.
|
||||
|
||||
The ld/st instructions must accept any destination (ld) or source (st)
|
||||
register.
|
||||
|
||||
The sti instruction may fail if it cannot store the given constant.
|
||||
|
||||
4.3) Function call assumptions
|
||||
|
||||
- The only supported types for parameters and return value are: 32 and
|
||||
|
|
|
@ -62,7 +62,12 @@ typedef enum {
|
|||
#define TCG_TARGET_HAS_eqv_i32 1
|
||||
#define TCG_TARGET_HAS_nand_i32 0
|
||||
#define TCG_TARGET_HAS_nor_i32 0
|
||||
#define TCG_TARGET_HAS_clz_i32 1
|
||||
#define TCG_TARGET_HAS_ctz_i32 1
|
||||
#define TCG_TARGET_HAS_ctpop_i32 0
|
||||
#define TCG_TARGET_HAS_deposit_i32 1
|
||||
#define TCG_TARGET_HAS_extract_i32 1
|
||||
#define TCG_TARGET_HAS_sextract_i32 1
|
||||
#define TCG_TARGET_HAS_movcond_i32 1
|
||||
#define TCG_TARGET_HAS_add2_i32 1
|
||||
#define TCG_TARGET_HAS_sub2_i32 1
|
||||
|
@ -92,7 +97,12 @@ typedef enum {
|
|||
#define TCG_TARGET_HAS_eqv_i64 1
|
||||
#define TCG_TARGET_HAS_nand_i64 0
|
||||
#define TCG_TARGET_HAS_nor_i64 0
|
||||
#define TCG_TARGET_HAS_clz_i64 1
|
||||
#define TCG_TARGET_HAS_ctz_i64 1
|
||||
#define TCG_TARGET_HAS_ctpop_i64 0
|
||||
#define TCG_TARGET_HAS_deposit_i64 1
|
||||
#define TCG_TARGET_HAS_extract_i64 1
|
||||
#define TCG_TARGET_HAS_sextract_i64 1
|
||||
#define TCG_TARGET_HAS_movcond_i64 1
|
||||
#define TCG_TARGET_HAS_add2_i64 1
|
||||
#define TCG_TARGET_HAS_sub2_i64 1
|
||||
|
|
|
@ -115,12 +115,10 @@ static inline void patch_reloc(tcg_insn_unit *code_ptr, int type,
|
|||
#define TCG_CT_CONST_MONE 0x800
|
||||
|
||||
/* parse target specific constraints */
|
||||
static int target_parse_constraint(TCGArgConstraint *ct,
|
||||
const char **pct_str)
|
||||
static const char *target_parse_constraint(TCGArgConstraint *ct,
|
||||
const char *ct_str, TCGType type)
|
||||
{
|
||||
const char *ct_str = *pct_str;
|
||||
|
||||
switch (ct_str[0]) {
|
||||
switch (*ct_str++) {
|
||||
case 'r':
|
||||
ct->ct |= TCG_CT_REG;
|
||||
tcg_regset_set32(ct->u.regs, 0, (1ULL << TCG_TARGET_NB_REGS) - 1);
|
||||
|
@ -150,12 +148,9 @@ static int target_parse_constraint(TCGArgConstraint *ct,
|
|||
ct->ct |= TCG_CT_CONST_ZERO;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ct_str++;
|
||||
*pct_str = ct_str;
|
||||
return 0;
|
||||
return ct_str;
|
||||
}
|
||||
|
||||
static inline bool is_aimm(uint64_t val)
|
||||
|
@ -344,8 +339,12 @@ typedef enum {
|
|||
/* Conditional select instructions. */
|
||||
I3506_CSEL = 0x1a800000,
|
||||
I3506_CSINC = 0x1a800400,
|
||||
I3506_CSINV = 0x5a800000,
|
||||
I3506_CSNEG = 0x5a800400,
|
||||
|
||||
/* Data-processing (1 source) instructions. */
|
||||
I3507_CLZ = 0x5ac01000,
|
||||
I3507_RBIT = 0x5ac00000,
|
||||
I3507_REV16 = 0x5ac00400,
|
||||
I3507_REV32 = 0x5ac00800,
|
||||
I3507_REV64 = 0x5ac00c00,
|
||||
|
@ -998,6 +997,37 @@ static inline void tcg_out_mb(TCGContext *s, TCGArg a0)
|
|||
tcg_out32(s, sync[a0 & TCG_MO_ALL]);
|
||||
}
|
||||
|
||||
static void tcg_out_cltz(TCGContext *s, TCGType ext, TCGReg d,
|
||||
TCGReg a0, TCGArg b, bool const_b, bool is_ctz)
|
||||
{
|
||||
TCGReg a1 = a0;
|
||||
if (is_ctz) {
|
||||
a1 = TCG_REG_TMP;
|
||||
tcg_out_insn(s, 3507, RBIT, ext, a1, a0);
|
||||
}
|
||||
if (const_b && b == (ext ? 64 : 32)) {
|
||||
tcg_out_insn(s, 3507, CLZ, ext, d, a1);
|
||||
} else {
|
||||
AArch64Insn sel = I3506_CSEL;
|
||||
|
||||
tcg_out_cmp(s, ext, a0, 0, 1);
|
||||
tcg_out_insn(s, 3507, CLZ, ext, TCG_REG_TMP, a1);
|
||||
|
||||
if (const_b) {
|
||||
if (b == -1) {
|
||||
b = TCG_REG_XZR;
|
||||
sel = I3506_CSINV;
|
||||
} else if (b == 0) {
|
||||
b = TCG_REG_XZR;
|
||||
} else {
|
||||
tcg_out_movi(s, ext, d, b);
|
||||
b = d;
|
||||
}
|
||||
}
|
||||
tcg_out_insn_3506(s, sel, ext, d, TCG_REG_TMP, b, TCG_COND_NE);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
/* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
|
||||
* TCGMemOpIdx oi, uintptr_t ra)
|
||||
|
@ -1564,6 +1594,15 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
|||
}
|
||||
break;
|
||||
|
||||
case INDEX_op_clz_i64:
|
||||
case INDEX_op_clz_i32:
|
||||
tcg_out_cltz(s, ext, a0, a1, a2, c2, false);
|
||||
break;
|
||||
case INDEX_op_ctz_i64:
|
||||
case INDEX_op_ctz_i32:
|
||||
tcg_out_cltz(s, ext, a0, a1, a2, c2, true);
|
||||
break;
|
||||
|
||||
case INDEX_op_brcond_i32:
|
||||
a1 = (int32_t)a1;
|
||||
/* FALLTHRU */
|
||||
|
@ -1640,6 +1679,16 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
|||
tcg_out_dep(s, ext, a0, REG0(2), args[3], args[4]);
|
||||
break;
|
||||
|
||||
case INDEX_op_extract_i64:
|
||||
case INDEX_op_extract_i32:
|
||||
tcg_out_ubfm(s, ext, a0, a1, a2, a2 + args[3] - 1);
|
||||
break;
|
||||
|
||||
case INDEX_op_sextract_i64:
|
||||
case INDEX_op_sextract_i32:
|
||||
tcg_out_sbfm(s, ext, a0, a1, a2, a2 + args[3] - 1);
|
||||
break;
|
||||
|
||||
case INDEX_op_add2_i32:
|
||||
tcg_out_addsub2(s, TCG_TYPE_I32, a0, a1, REG0(2), REG0(3),
|
||||
(int32_t)args[4], args[5], const_args[4],
|
||||
|
@ -1745,11 +1794,15 @@ static const TCGTargetOpDef aarch64_op_defs[] = {
|
|||
{ INDEX_op_sar_i32, { "r", "r", "ri" } },
|
||||
{ INDEX_op_rotl_i32, { "r", "r", "ri" } },
|
||||
{ INDEX_op_rotr_i32, { "r", "r", "ri" } },
|
||||
{ INDEX_op_clz_i32, { "r", "r", "rAL" } },
|
||||
{ INDEX_op_ctz_i32, { "r", "r", "rAL" } },
|
||||
{ INDEX_op_shl_i64, { "r", "r", "ri" } },
|
||||
{ INDEX_op_shr_i64, { "r", "r", "ri" } },
|
||||
{ INDEX_op_sar_i64, { "r", "r", "ri" } },
|
||||
{ INDEX_op_rotl_i64, { "r", "r", "ri" } },
|
||||
{ INDEX_op_rotr_i64, { "r", "r", "ri" } },
|
||||
{ INDEX_op_clz_i64, { "r", "r", "rAL" } },
|
||||
{ INDEX_op_ctz_i64, { "r", "r", "rAL" } },
|
||||
|
||||
{ INDEX_op_brcond_i32, { "r", "rA" } },
|
||||
{ INDEX_op_brcond_i64, { "r", "rA" } },
|
||||
|
@ -1785,6 +1838,10 @@ static const TCGTargetOpDef aarch64_op_defs[] = {
|
|||
|
||||
{ INDEX_op_deposit_i32, { "r", "0", "rZ" } },
|
||||
{ INDEX_op_deposit_i64, { "r", "0", "rZ" } },
|
||||
{ INDEX_op_extract_i32, { "r", "r" } },
|
||||
{ INDEX_op_extract_i64, { "r", "r" } },
|
||||
{ INDEX_op_sextract_i32, { "r", "r" } },
|
||||
{ INDEX_op_sextract_i64, { "r", "r" } },
|
||||
|
||||
{ INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rA", "rMZ" } },
|
||||
{ INDEX_op_add2_i64, { "r", "r", "rZ", "rZ", "rA", "rMZ" } },
|
||||
|
@ -1798,6 +1855,18 @@ static const TCGTargetOpDef aarch64_op_defs[] = {
|
|||
{ -1 },
|
||||
};
|
||||
|
||||
static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
||||
{
|
||||
int i, n = ARRAY_SIZE(aarch64_op_defs);
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (aarch64_op_defs[i].op == op) {
|
||||
return &aarch64_op_defs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void tcg_target_init(TCGContext *s)
|
||||
{
|
||||
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
|
||||
|
@ -1820,8 +1889,6 @@ static void tcg_target_init(TCGContext *s)
|
|||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_FP);
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP);
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_X18); /* platform register */
|
||||
|
||||
tcg_add_target_add_op_defs(aarch64_op_defs);
|
||||
}
|
||||
|
||||
/* Saving pairs: (X19, X20) .. (X27, X28), (X29(fp), X30(lr)). */
|
||||
|
|
|
@ -26,6 +26,37 @@
|
|||
#ifndef ARM_TCG_TARGET_H
|
||||
#define ARM_TCG_TARGET_H
|
||||
|
||||
/* The __ARM_ARCH define is provided by gcc 4.8. Construct it otherwise. */
|
||||
#ifndef __ARM_ARCH
|
||||
# if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
|
||||
|| defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
|
||||
|| defined(__ARM_ARCH_7EM__)
|
||||
# define __ARM_ARCH 7
|
||||
# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|
||||
|| defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) \
|
||||
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__)
|
||||
# define __ARM_ARCH 6
|
||||
# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5E__) \
|
||||
|| defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5TE__) \
|
||||
|| defined(__ARM_ARCH_5TEJ__)
|
||||
# define __ARM_ARCH 5
|
||||
# else
|
||||
# define __ARM_ARCH 4
|
||||
# endif
|
||||
#endif
|
||||
|
||||
extern int arm_arch;
|
||||
|
||||
#if defined(__ARM_ARCH_5T__) \
|
||||
|| defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__)
|
||||
# define use_armv5t_instructions 1
|
||||
#else
|
||||
# define use_armv5t_instructions use_armv6_instructions
|
||||
#endif
|
||||
|
||||
#define use_armv6_instructions (__ARM_ARCH >= 6 || arm_arch >= 6)
|
||||
#define use_armv7_instructions (__ARM_ARCH >= 7 || arm_arch >= 7)
|
||||
|
||||
#undef TCG_TARGET_STACK_GROWSUP
|
||||
#define TCG_TARGET_INSN_UNIT_SIZE 4
|
||||
#define TCG_TARGET_TLB_DISPLACEMENT_BITS 16
|
||||
|
@ -79,7 +110,12 @@ extern bool use_idiv_instructions;
|
|||
#define TCG_TARGET_HAS_eqv_i32 0
|
||||
#define TCG_TARGET_HAS_nand_i32 0
|
||||
#define TCG_TARGET_HAS_nor_i32 0
|
||||
#define TCG_TARGET_HAS_deposit_i32 1
|
||||
#define TCG_TARGET_HAS_clz_i32 use_armv5t_instructions
|
||||
#define TCG_TARGET_HAS_ctz_i32 use_armv7_instructions
|
||||
#define TCG_TARGET_HAS_ctpop_i32 0
|
||||
#define TCG_TARGET_HAS_deposit_i32 use_armv7_instructions
|
||||
#define TCG_TARGET_HAS_extract_i32 use_armv7_instructions
|
||||
#define TCG_TARGET_HAS_sextract_i32 use_armv7_instructions
|
||||
#define TCG_TARGET_HAS_movcond_i32 1
|
||||
#define TCG_TARGET_HAS_mulu2_i32 1
|
||||
#define TCG_TARGET_HAS_muls2_i32 1
|
||||
|
@ -88,9 +124,6 @@ extern bool use_idiv_instructions;
|
|||
#define TCG_TARGET_HAS_div_i32 use_idiv_instructions
|
||||
#define TCG_TARGET_HAS_rem_i32 0
|
||||
|
||||
extern bool tcg_target_deposit_valid(int ofs, int len);
|
||||
#define TCG_TARGET_deposit_i32_valid tcg_target_deposit_valid
|
||||
|
||||
enum {
|
||||
TCG_AREG0 = TCG_REG_R6,
|
||||
};
|
||||
|
|
|
@ -25,36 +25,7 @@
|
|||
#include "elf.h"
|
||||
#include "tcg-be-ldst.h"
|
||||
|
||||
/* The __ARM_ARCH define is provided by gcc 4.8. Construct it otherwise. */
|
||||
#ifndef __ARM_ARCH
|
||||
# if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
|
||||
|| defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
|
||||
|| defined(__ARM_ARCH_7EM__)
|
||||
# define __ARM_ARCH 7
|
||||
# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|
||||
|| defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) \
|
||||
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__)
|
||||
# define __ARM_ARCH 6
|
||||
# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5E__) \
|
||||
|| defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5TE__) \
|
||||
|| defined(__ARM_ARCH_5TEJ__)
|
||||
# define __ARM_ARCH 5
|
||||
# else
|
||||
# define __ARM_ARCH 4
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static int arm_arch = __ARM_ARCH;
|
||||
|
||||
#if defined(__ARM_ARCH_5T__) \
|
||||
|| defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__)
|
||||
# define use_armv5t_instructions 1
|
||||
#else
|
||||
# define use_armv5t_instructions use_armv6_instructions
|
||||
#endif
|
||||
|
||||
#define use_armv6_instructions (__ARM_ARCH >= 6 || arm_arch >= 6)
|
||||
#define use_armv7_instructions (__ARM_ARCH >= 7 || arm_arch >= 7)
|
||||
int arm_arch = __ARM_ARCH;
|
||||
|
||||
#ifndef use_idiv_instructions
|
||||
bool use_idiv_instructions;
|
||||
|
@ -143,12 +114,10 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
|
|||
#define TCG_CT_CONST_ZERO 0x800
|
||||
|
||||
/* parse target specific constraints */
|
||||
static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
||||
static const char *target_parse_constraint(TCGArgConstraint *ct,
|
||||
const char *ct_str, TCGType type)
|
||||
{
|
||||
const char *ct_str;
|
||||
|
||||
ct_str = *pct_str;
|
||||
switch (ct_str[0]) {
|
||||
switch (*ct_str++) {
|
||||
case 'I':
|
||||
ct->ct |= TCG_CT_CONST_ARM;
|
||||
break;
|
||||
|
@ -201,12 +170,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
|||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
ct_str++;
|
||||
*pct_str = ct_str;
|
||||
|
||||
return 0;
|
||||
return ct_str;
|
||||
}
|
||||
|
||||
static inline uint32_t rotl(uint32_t val, int n)
|
||||
|
@ -290,6 +256,9 @@ typedef enum {
|
|||
ARITH_BIC = 0xe << 21,
|
||||
ARITH_MVN = 0xf << 21,
|
||||
|
||||
INSN_CLZ = 0x016f0f10,
|
||||
INSN_RBIT = 0x06ff0f30,
|
||||
|
||||
INSN_LDR_IMM = 0x04100000,
|
||||
INSN_LDR_REG = 0x06100000,
|
||||
INSN_STR_IMM = 0x04000000,
|
||||
|
@ -730,16 +699,6 @@ static inline void tcg_out_bswap32(TCGContext *s, int cond, int rd, int rn)
|
|||
}
|
||||
}
|
||||
|
||||
bool tcg_target_deposit_valid(int ofs, int len)
|
||||
{
|
||||
/* ??? Without bfi, we could improve over generic code by combining
|
||||
the right-shift from a non-zero ofs with the orr. We do run into
|
||||
problems when rd == rs, and the mask generated from ofs+len doesn't
|
||||
fit into an immediate. We would have to be careful not to pessimize
|
||||
wrt the optimizations performed on the expanded code. */
|
||||
return use_armv7_instructions;
|
||||
}
|
||||
|
||||
static inline void tcg_out_deposit(TCGContext *s, int cond, TCGReg rd,
|
||||
TCGArg a1, int ofs, int len, bool const_a1)
|
||||
{
|
||||
|
@ -752,6 +711,22 @@ static inline void tcg_out_deposit(TCGContext *s, int cond, TCGReg rd,
|
|||
| (ofs << 7) | ((ofs + len - 1) << 16));
|
||||
}
|
||||
|
||||
static inline void tcg_out_extract(TCGContext *s, int cond, TCGReg rd,
|
||||
TCGArg a1, int ofs, int len)
|
||||
{
|
||||
/* ubfx */
|
||||
tcg_out32(s, 0x07e00050 | (cond << 28) | (rd << 12) | a1
|
||||
| (ofs << 7) | ((len - 1) << 16));
|
||||
}
|
||||
|
||||
static inline void tcg_out_sextract(TCGContext *s, int cond, TCGReg rd,
|
||||
TCGArg a1, int ofs, int len)
|
||||
{
|
||||
/* sbfx */
|
||||
tcg_out32(s, 0x07a00050 | (cond << 28) | (rd << 12) | a1
|
||||
| (ofs << 7) | ((len - 1) << 16));
|
||||
}
|
||||
|
||||
/* Note that this routine is used for both LDR and LDRH formats, so we do
|
||||
not wish to include an immediate shift at this point. */
|
||||
static void tcg_out_memop_r(TCGContext *s, int cond, ARMInsn opc, TCGReg rt,
|
||||
|
@ -1857,6 +1832,28 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
|||
}
|
||||
break;
|
||||
|
||||
case INDEX_op_ctz_i32:
|
||||
tcg_out_dat_reg(s, COND_AL, INSN_RBIT, TCG_REG_TMP, 0, args[1], 0);
|
||||
a1 = TCG_REG_TMP;
|
||||
goto do_clz;
|
||||
|
||||
case INDEX_op_clz_i32:
|
||||
a1 = args[1];
|
||||
do_clz:
|
||||
a0 = args[0];
|
||||
a2 = args[2];
|
||||
c = const_args[2];
|
||||
if (c && a2 == 32) {
|
||||
tcg_out_dat_reg(s, COND_AL, INSN_CLZ, a0, 0, a1, 0);
|
||||
break;
|
||||
}
|
||||
tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0, a1, 0);
|
||||
tcg_out_dat_reg(s, COND_NE, INSN_CLZ, a0, 0, a1, 0);
|
||||
if (c || a0 != a2) {
|
||||
tcg_out_dat_rIK(s, COND_EQ, ARITH_MOV, ARITH_MVN, a0, 0, a2, c);
|
||||
}
|
||||
break;
|
||||
|
||||
case INDEX_op_brcond_i32:
|
||||
tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0,
|
||||
args[0], args[1], const_args[1]);
|
||||
|
@ -1933,6 +1930,12 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
|||
tcg_out_deposit(s, COND_AL, args[0], args[2],
|
||||
args[3], args[4], const_args[2]);
|
||||
break;
|
||||
case INDEX_op_extract_i32:
|
||||
tcg_out_extract(s, COND_AL, args[0], args[1], args[2], args[3]);
|
||||
break;
|
||||
case INDEX_op_sextract_i32:
|
||||
tcg_out_sextract(s, COND_AL, args[0], args[1], args[2], args[3]);
|
||||
break;
|
||||
|
||||
case INDEX_op_div_i32:
|
||||
tcg_out_sdiv(s, COND_AL, args[0], args[1], args[2]);
|
||||
|
@ -1985,6 +1988,8 @@ static const TCGTargetOpDef arm_op_defs[] = {
|
|||
{ INDEX_op_sar_i32, { "r", "r", "ri" } },
|
||||
{ INDEX_op_rotl_i32, { "r", "r", "ri" } },
|
||||
{ INDEX_op_rotr_i32, { "r", "r", "ri" } },
|
||||
{ INDEX_op_clz_i32, { "r", "r", "rIK" } },
|
||||
{ INDEX_op_ctz_i32, { "r", "r", "rIK" } },
|
||||
|
||||
{ INDEX_op_brcond_i32, { "r", "rIN" } },
|
||||
{ INDEX_op_setcond_i32, { "r", "r", "rIN" } },
|
||||
|
@ -2015,6 +2020,8 @@ static const TCGTargetOpDef arm_op_defs[] = {
|
|||
{ INDEX_op_ext16u_i32, { "r", "r" } },
|
||||
|
||||
{ INDEX_op_deposit_i32, { "r", "0", "rZ" } },
|
||||
{ INDEX_op_extract_i32, { "r", "r" } },
|
||||
{ INDEX_op_sextract_i32, { "r", "r" } },
|
||||
|
||||
{ INDEX_op_div_i32, { "r", "r", "r" } },
|
||||
{ INDEX_op_divu_i32, { "r", "r", "r" } },
|
||||
|
@ -2023,6 +2030,18 @@ static const TCGTargetOpDef arm_op_defs[] = {
|
|||
{ -1 },
|
||||
};
|
||||
|
||||
static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
||||
{
|
||||
int i, n = ARRAY_SIZE(arm_op_defs);
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (arm_op_defs[i].op == op) {
|
||||
return &arm_op_defs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void tcg_target_init(TCGContext *s)
|
||||
{
|
||||
/* Only probe for the platform and capabilities if we havn't already
|
||||
|
@ -2053,8 +2072,6 @@ static void tcg_target_init(TCGContext *s)
|
|||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP);
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_PC);
|
||||
|
||||
tcg_add_target_add_op_defs(arm_op_defs);
|
||||
}
|
||||
|
||||
static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
|
||||
|
|
|
@ -76,6 +76,7 @@ typedef enum {
|
|||
#endif
|
||||
|
||||
extern bool have_bmi1;
|
||||
extern bool have_popcnt;
|
||||
|
||||
/* optional instructions */
|
||||
#define TCG_TARGET_HAS_div2_i32 1
|
||||
|
@ -93,7 +94,12 @@ extern bool have_bmi1;
|
|||
#define TCG_TARGET_HAS_eqv_i32 0
|
||||
#define TCG_TARGET_HAS_nand_i32 0
|
||||
#define TCG_TARGET_HAS_nor_i32 0
|
||||
#define TCG_TARGET_HAS_clz_i32 1
|
||||
#define TCG_TARGET_HAS_ctz_i32 1
|
||||
#define TCG_TARGET_HAS_ctpop_i32 have_popcnt
|
||||
#define TCG_TARGET_HAS_deposit_i32 1
|
||||
#define TCG_TARGET_HAS_extract_i32 1
|
||||
#define TCG_TARGET_HAS_sextract_i32 1
|
||||
#define TCG_TARGET_HAS_movcond_i32 1
|
||||
#define TCG_TARGET_HAS_add2_i32 1
|
||||
#define TCG_TARGET_HAS_sub2_i32 1
|
||||
|
@ -123,7 +129,12 @@ extern bool have_bmi1;
|
|||
#define TCG_TARGET_HAS_eqv_i64 0
|
||||
#define TCG_TARGET_HAS_nand_i64 0
|
||||
#define TCG_TARGET_HAS_nor_i64 0
|
||||
#define TCG_TARGET_HAS_clz_i64 1
|
||||
#define TCG_TARGET_HAS_ctz_i64 1
|
||||
#define TCG_TARGET_HAS_ctpop_i64 have_popcnt
|
||||
#define TCG_TARGET_HAS_deposit_i64 1
|
||||
#define TCG_TARGET_HAS_extract_i64 1
|
||||
#define TCG_TARGET_HAS_sextract_i64 0
|
||||
#define TCG_TARGET_HAS_movcond_i64 1
|
||||
#define TCG_TARGET_HAS_add2_i64 1
|
||||
#define TCG_TARGET_HAS_sub2_i64 1
|
||||
|
@ -138,6 +149,12 @@ extern bool have_bmi1;
|
|||
((ofs) == 0 && (len) == 16))
|
||||
#define TCG_TARGET_deposit_i64_valid TCG_TARGET_deposit_i32_valid
|
||||
|
||||
/* Check for the possibility of high-byte extraction and, for 64-bit,
|
||||
zero-extending 32-bit right-shift. */
|
||||
#define TCG_TARGET_extract_i32_valid(ofs, len) ((ofs) == 8 && (len) == 8)
|
||||
#define TCG_TARGET_extract_i64_valid(ofs, len) \
|
||||
(((ofs) == 8 && (len) == 8) || ((ofs) + (len)) == 32)
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
# define TCG_AREG0 TCG_REG_R14
|
||||
#else
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -140,6 +140,12 @@ typedef enum {
|
|||
#define TCG_TARGET_HAS_nand_i32 1
|
||||
#define TCG_TARGET_HAS_nand_i64 1
|
||||
#define TCG_TARGET_HAS_nor_i32 1
|
||||
#define TCG_TARGET_HAS_clz_i32 0
|
||||
#define TCG_TARGET_HAS_clz_i64 0
|
||||
#define TCG_TARGET_HAS_ctz_i32 0
|
||||
#define TCG_TARGET_HAS_ctz_i64 0
|
||||
#define TCG_TARGET_HAS_ctpop_i32 0
|
||||
#define TCG_TARGET_HAS_ctpop_i64 0
|
||||
#define TCG_TARGET_HAS_nor_i64 1
|
||||
#define TCG_TARGET_HAS_orc_i32 1
|
||||
#define TCG_TARGET_HAS_orc_i64 1
|
||||
|
@ -149,6 +155,10 @@ typedef enum {
|
|||
#define TCG_TARGET_HAS_movcond_i64 1
|
||||
#define TCG_TARGET_HAS_deposit_i32 1
|
||||
#define TCG_TARGET_HAS_deposit_i64 1
|
||||
#define TCG_TARGET_HAS_extract_i32 0
|
||||
#define TCG_TARGET_HAS_extract_i64 0
|
||||
#define TCG_TARGET_HAS_sextract_i32 0
|
||||
#define TCG_TARGET_HAS_sextract_i64 0
|
||||
#define TCG_TARGET_HAS_add2_i32 0
|
||||
#define TCG_TARGET_HAS_add2_i64 0
|
||||
#define TCG_TARGET_HAS_sub2_i32 0
|
||||
|
|
|
@ -721,12 +721,10 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
|
|||
*/
|
||||
|
||||
/* parse target specific constraints */
|
||||
static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
||||
static const char *target_parse_constraint(TCGArgConstraint *ct,
|
||||
const char *ct_str, TCGType type)
|
||||
{
|
||||
const char *ct_str;
|
||||
|
||||
ct_str = *pct_str;
|
||||
switch(ct_str[0]) {
|
||||
switch(*ct_str++) {
|
||||
case 'r':
|
||||
ct->ct |= TCG_CT_REG;
|
||||
tcg_regset_set(ct->u.regs, 0xffffffffffffffffull);
|
||||
|
@ -750,11 +748,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
|||
ct->ct |= TCG_CT_CONST_ZERO;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
ct_str++;
|
||||
*pct_str = ct_str;
|
||||
return 0;
|
||||
return ct_str;
|
||||
}
|
||||
|
||||
/* test if a constant matches the constraint */
|
||||
|
@ -2352,6 +2348,18 @@ static const TCGTargetOpDef ia64_op_defs[] = {
|
|||
{ -1 },
|
||||
};
|
||||
|
||||
static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
||||
{
|
||||
int i, n = ARRAY_SIZE(ia64_op_defs);
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (ia64_op_defs[i].op == op) {
|
||||
return &ia64_op_defs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Generate global QEMU prologue and epilogue code */
|
||||
static void tcg_target_qemu_prologue(TCGContext *s)
|
||||
{
|
||||
|
@ -2471,6 +2479,4 @@ static void tcg_target_init(TCGContext *s)
|
|||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R5);
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R6);
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R7);
|
||||
|
||||
tcg_add_target_add_op_defs(ia64_op_defs);
|
||||
}
|
||||
|
|
|
@ -158,9 +158,14 @@ extern bool use_mips32r2_instructions;
|
|||
#define TCG_TARGET_HAS_movcond_i32 use_movnz_instructions
|
||||
#define TCG_TARGET_HAS_bswap16_i32 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_deposit_i32 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_extract_i32 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_sextract_i32 0
|
||||
#define TCG_TARGET_HAS_ext8s_i32 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_ext16s_i32 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_rot_i32 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_clz_i32 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_ctz_i32 0
|
||||
#define TCG_TARGET_HAS_ctpop_i32 0
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
#define TCG_TARGET_HAS_movcond_i64 use_movnz_instructions
|
||||
|
@ -168,9 +173,14 @@ extern bool use_mips32r2_instructions;
|
|||
#define TCG_TARGET_HAS_bswap32_i64 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_bswap64_i64 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_deposit_i64 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_extract_i64 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_sextract_i64 0
|
||||
#define TCG_TARGET_HAS_ext8s_i64 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_ext16s_i64 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_rot_i64 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_clz_i64 use_mips32r2_instructions
|
||||
#define TCG_TARGET_HAS_ctz_i64 0
|
||||
#define TCG_TARGET_HAS_ctpop_i64 0
|
||||
#endif
|
||||
|
||||
/* optional instructions automatically implemented */
|
||||
|
|
|
@ -179,6 +179,7 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
|
|||
#define TCG_CT_CONST_S16 0x400 /* Signed 16-bit: -32768 - 32767 */
|
||||
#define TCG_CT_CONST_P2M1 0x800 /* Power of 2 minus 1. */
|
||||
#define TCG_CT_CONST_N16 0x1000 /* "Negatable" 16-bit: -32767 - 32767 */
|
||||
#define TCG_CT_CONST_WSZ 0x2000 /* word size */
|
||||
|
||||
static inline bool is_p2m1(tcg_target_long val)
|
||||
{
|
||||
|
@ -186,12 +187,10 @@ static inline bool is_p2m1(tcg_target_long val)
|
|||
}
|
||||
|
||||
/* parse target specific constraints */
|
||||
static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
||||
static const char *target_parse_constraint(TCGArgConstraint *ct,
|
||||
const char *ct_str, TCGType type)
|
||||
{
|
||||
const char *ct_str;
|
||||
|
||||
ct_str = *pct_str;
|
||||
switch(ct_str[0]) {
|
||||
switch(*ct_str++) {
|
||||
case 'r':
|
||||
ct->ct |= TCG_CT_REG;
|
||||
tcg_regset_set(ct->u.regs, 0xffffffff);
|
||||
|
@ -231,6 +230,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
|||
case 'N':
|
||||
ct->ct |= TCG_CT_CONST_N16;
|
||||
break;
|
||||
case 'W':
|
||||
ct->ct |= TCG_CT_CONST_WSZ;
|
||||
break;
|
||||
case 'Z':
|
||||
/* We are cheating a bit here, using the fact that the register
|
||||
ZERO is also the register number 0. Hence there is no need
|
||||
|
@ -238,11 +240,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
|||
ct->ct |= TCG_CT_CONST_ZERO;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
ct_str++;
|
||||
*pct_str = ct_str;
|
||||
return 0;
|
||||
return ct_str;
|
||||
}
|
||||
|
||||
/* test if a constant matches the constraint */
|
||||
|
@ -264,6 +264,9 @@ static inline int tcg_target_const_match(tcg_target_long val, TCGType type,
|
|||
} else if ((ct & TCG_CT_CONST_P2M1)
|
||||
&& use_mips32r2_instructions && is_p2m1(val)) {
|
||||
return 1;
|
||||
} else if ((ct & TCG_CT_CONST_WSZ)
|
||||
&& val == (type == TCG_TYPE_I32 ? 32 : 64)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -360,6 +363,8 @@ typedef enum {
|
|||
OPC_DSRL32 = OPC_SPECIAL | 076,
|
||||
OPC_DROTR32 = OPC_SPECIAL | 076 | (1 << 21),
|
||||
OPC_DSRA32 = OPC_SPECIAL | 077,
|
||||
OPC_CLZ_R6 = OPC_SPECIAL | 0120,
|
||||
OPC_DCLZ_R6 = OPC_SPECIAL | 0122,
|
||||
|
||||
OPC_REGIMM = 001 << 26,
|
||||
OPC_BLTZ = OPC_REGIMM | (000 << 16),
|
||||
|
@ -367,6 +372,8 @@ typedef enum {
|
|||
|
||||
OPC_SPECIAL2 = 034 << 26,
|
||||
OPC_MUL_R5 = OPC_SPECIAL2 | 002,
|
||||
OPC_CLZ = OPC_SPECIAL2 | 040,
|
||||
OPC_DCLZ = OPC_SPECIAL2 | 044,
|
||||
|
||||
OPC_SPECIAL3 = 037 << 26,
|
||||
OPC_EXT = OPC_SPECIAL3 | 000,
|
||||
|
@ -1668,6 +1675,33 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
|
|||
tcg_out32(s, sync[a0 & TCG_MO_ALL]);
|
||||
}
|
||||
|
||||
static void tcg_out_clz(TCGContext *s, MIPSInsn opcv2, MIPSInsn opcv6,
|
||||
int width, TCGReg a0, TCGReg a1, TCGArg a2)
|
||||
{
|
||||
if (use_mips32r6_instructions) {
|
||||
if (a2 == width) {
|
||||
tcg_out_opc_reg(s, opcv6, a0, a1, 0);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, opcv6, TCG_TMP0, a1, 0);
|
||||
tcg_out_movcond(s, TCG_COND_EQ, a0, a1, 0, a2, TCG_TMP0);
|
||||
}
|
||||
} else {
|
||||
if (a2 == width) {
|
||||
tcg_out_opc_reg(s, opcv2, a0, a1, a1);
|
||||
} else if (a0 == a2) {
|
||||
tcg_out_opc_reg(s, opcv2, TCG_TMP0, a1, a1);
|
||||
tcg_out_opc_reg(s, OPC_MOVN, a0, TCG_TMP0, a1);
|
||||
} else if (a0 != a1) {
|
||||
tcg_out_opc_reg(s, opcv2, a0, a1, a1);
|
||||
tcg_out_opc_reg(s, OPC_MOVZ, a0, a2, a1);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, opcv2, TCG_TMP0, a1, a1);
|
||||
tcg_out_opc_reg(s, OPC_MOVZ, TCG_TMP0, a2, a1);
|
||||
tcg_out_mov(s, TCG_TYPE_REG, a0, TCG_TMP0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
const TCGArg *args, const int *const_args)
|
||||
{
|
||||
|
@ -2044,6 +2078,13 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
|||
}
|
||||
break;
|
||||
|
||||
case INDEX_op_clz_i32:
|
||||
tcg_out_clz(s, OPC_CLZ, OPC_CLZ_R6, 32, a0, a1, a2);
|
||||
break;
|
||||
case INDEX_op_clz_i64:
|
||||
tcg_out_clz(s, OPC_DCLZ, OPC_DCLZ_R6, 64, a0, a1, a2);
|
||||
break;
|
||||
|
||||
case INDEX_op_deposit_i32:
|
||||
tcg_out_opc_bf(s, OPC_INS, a0, a2, args[3] + args[4] - 1, args[3]);
|
||||
break;
|
||||
|
@ -2051,6 +2092,13 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
|||
tcg_out_opc_bf64(s, OPC_DINS, OPC_DINSM, OPC_DINSU, a0, a2,
|
||||
args[3] + args[4] - 1, args[3]);
|
||||
break;
|
||||
case INDEX_op_extract_i32:
|
||||
tcg_out_opc_bf(s, OPC_EXT, a0, a1, a2 + args[3] - 1, a2);
|
||||
break;
|
||||
case INDEX_op_extract_i64:
|
||||
tcg_out_opc_bf64(s, OPC_DEXT, OPC_DEXTM, OPC_DEXTU, a0, a1,
|
||||
a2 + args[3] - 1, a2);
|
||||
break;
|
||||
|
||||
case INDEX_op_brcond_i32:
|
||||
case INDEX_op_brcond_i64:
|
||||
|
@ -2147,6 +2195,7 @@ static const TCGTargetOpDef mips_op_defs[] = {
|
|||
{ INDEX_op_sar_i32, { "r", "rZ", "ri" } },
|
||||
{ INDEX_op_rotr_i32, { "r", "rZ", "ri" } },
|
||||
{ INDEX_op_rotl_i32, { "r", "rZ", "ri" } },
|
||||
{ INDEX_op_clz_i32, { "r", "r", "rWZ" } },
|
||||
|
||||
{ INDEX_op_bswap16_i32, { "r", "r" } },
|
||||
{ INDEX_op_bswap32_i32, { "r", "r" } },
|
||||
|
@ -2155,6 +2204,7 @@ static const TCGTargetOpDef mips_op_defs[] = {
|
|||
{ INDEX_op_ext16s_i32, { "r", "rZ" } },
|
||||
|
||||
{ INDEX_op_deposit_i32, { "r", "0", "rZ" } },
|
||||
{ INDEX_op_extract_i32, { "r", "r" } },
|
||||
|
||||
{ INDEX_op_brcond_i32, { "rZ", "rZ" } },
|
||||
#if use_mips32r6_instructions
|
||||
|
@ -2209,6 +2259,7 @@ static const TCGTargetOpDef mips_op_defs[] = {
|
|||
{ INDEX_op_sar_i64, { "r", "rZ", "ri" } },
|
||||
{ INDEX_op_rotr_i64, { "r", "rZ", "ri" } },
|
||||
{ INDEX_op_rotl_i64, { "r", "rZ", "ri" } },
|
||||
{ INDEX_op_clz_i64, { "r", "r", "rWZ" } },
|
||||
|
||||
{ INDEX_op_bswap16_i64, { "r", "r" } },
|
||||
{ INDEX_op_bswap32_i64, { "r", "r" } },
|
||||
|
@ -2224,6 +2275,7 @@ static const TCGTargetOpDef mips_op_defs[] = {
|
|||
{ INDEX_op_extrh_i64_i32, { "r", "rZ" } },
|
||||
|
||||
{ INDEX_op_deposit_i64, { "r", "0", "rZ" } },
|
||||
{ INDEX_op_extract_i64, { "r", "r" } },
|
||||
|
||||
{ INDEX_op_brcond_i64, { "rZ", "rZ" } },
|
||||
#if use_mips32r6_instructions
|
||||
|
@ -2253,6 +2305,18 @@ static const TCGTargetOpDef mips_op_defs[] = {
|
|||
{ -1 },
|
||||
};
|
||||
|
||||
static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
||||
{
|
||||
int i, n = ARRAY_SIZE(mips_op_defs);
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (mips_op_defs[i].op == op) {
|
||||
return &mips_op_defs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int tcg_target_callee_save_regs[] = {
|
||||
TCG_REG_S0, /* used for the global env (TCG_AREG0) */
|
||||
TCG_REG_S1,
|
||||
|
@ -2554,8 +2618,6 @@ static void tcg_target_init(TCGContext *s)
|
|||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); /* return address */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_GP); /* global pointer */
|
||||
|
||||
tcg_add_target_add_op_defs(mips_op_defs);
|
||||
}
|
||||
|
||||
void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr)
|
||||
|
|
|
@ -296,6 +296,24 @@ static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y)
|
|||
CASE_OP_32_64(nor):
|
||||
return ~(x | y);
|
||||
|
||||
case INDEX_op_clz_i32:
|
||||
return (uint32_t)x ? clz32(x) : y;
|
||||
|
||||
case INDEX_op_clz_i64:
|
||||
return x ? clz64(x) : y;
|
||||
|
||||
case INDEX_op_ctz_i32:
|
||||
return (uint32_t)x ? ctz32(x) : y;
|
||||
|
||||
case INDEX_op_ctz_i64:
|
||||
return x ? ctz64(x) : y;
|
||||
|
||||
case INDEX_op_ctpop_i32:
|
||||
return ctpop32(x);
|
||||
|
||||
case INDEX_op_ctpop_i64:
|
||||
return ctpop64(x);
|
||||
|
||||
CASE_OP_32_64(ext8s):
|
||||
return (int8_t)x;
|
||||
|
||||
|
@ -878,11 +896,41 @@ void tcg_optimize(TCGContext *s)
|
|||
temps[args[2]].mask);
|
||||
break;
|
||||
|
||||
CASE_OP_32_64(extract):
|
||||
mask = extract64(temps[args[1]].mask, args[2], args[3]);
|
||||
if (args[2] == 0) {
|
||||
affected = temps[args[1]].mask & ~mask;
|
||||
}
|
||||
break;
|
||||
CASE_OP_32_64(sextract):
|
||||
mask = sextract64(temps[args[1]].mask, args[2], args[3]);
|
||||
if (args[2] == 0 && (tcg_target_long)mask >= 0) {
|
||||
affected = temps[args[1]].mask & ~mask;
|
||||
}
|
||||
break;
|
||||
|
||||
CASE_OP_32_64(or):
|
||||
CASE_OP_32_64(xor):
|
||||
mask = temps[args[1]].mask | temps[args[2]].mask;
|
||||
break;
|
||||
|
||||
case INDEX_op_clz_i32:
|
||||
case INDEX_op_ctz_i32:
|
||||
mask = temps[args[2]].mask | 31;
|
||||
break;
|
||||
|
||||
case INDEX_op_clz_i64:
|
||||
case INDEX_op_ctz_i64:
|
||||
mask = temps[args[2]].mask | 63;
|
||||
break;
|
||||
|
||||
case INDEX_op_ctpop_i32:
|
||||
mask = 32 | 31;
|
||||
break;
|
||||
case INDEX_op_ctpop_i64:
|
||||
mask = 64 | 63;
|
||||
break;
|
||||
|
||||
CASE_OP_32_64(setcond):
|
||||
case INDEX_op_setcond2_i32:
|
||||
mask = 1;
|
||||
|
@ -996,6 +1044,7 @@ void tcg_optimize(TCGContext *s)
|
|||
CASE_OP_32_64(ext8u):
|
||||
CASE_OP_32_64(ext16s):
|
||||
CASE_OP_32_64(ext16u):
|
||||
CASE_OP_32_64(ctpop):
|
||||
case INDEX_op_ext32s_i64:
|
||||
case INDEX_op_ext32u_i64:
|
||||
case INDEX_op_ext_i32_i64:
|
||||
|
@ -1039,6 +1088,20 @@ void tcg_optimize(TCGContext *s)
|
|||
}
|
||||
goto do_default;
|
||||
|
||||
CASE_OP_32_64(clz):
|
||||
CASE_OP_32_64(ctz):
|
||||
if (temp_is_const(args[1])) {
|
||||
TCGArg v = temps[args[1]].val;
|
||||
if (v != 0) {
|
||||
tmp = do_constant_folding(opc, v, 0);
|
||||
tcg_opt_gen_movi(s, op, args, args[0], tmp);
|
||||
} else {
|
||||
tcg_opt_gen_mov(s, op, args, args[0], args[2]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
goto do_default;
|
||||
|
||||
CASE_OP_32_64(deposit):
|
||||
if (temp_is_const(args[1]) && temp_is_const(args[2])) {
|
||||
tmp = deposit64(temps[args[1]].val, args[3], args[4],
|
||||
|
@ -1048,6 +1111,22 @@ void tcg_optimize(TCGContext *s)
|
|||
}
|
||||
goto do_default;
|
||||
|
||||
CASE_OP_32_64(extract):
|
||||
if (temp_is_const(args[1])) {
|
||||
tmp = extract64(temps[args[1]].val, args[2], args[3]);
|
||||
tcg_opt_gen_movi(s, op, args, args[0], tmp);
|
||||
break;
|
||||
}
|
||||
goto do_default;
|
||||
|
||||
CASE_OP_32_64(sextract):
|
||||
if (temp_is_const(args[1])) {
|
||||
tmp = sextract64(temps[args[1]].val, args[2], args[3]);
|
||||
tcg_opt_gen_movi(s, op, args, args[0], tmp);
|
||||
break;
|
||||
}
|
||||
goto do_default;
|
||||
|
||||
CASE_OP_32_64(setcond):
|
||||
tmp = do_constant_folding_cond(opc, args[1], args[2], args[3]);
|
||||
if (tmp != 2) {
|
||||
|
@ -1076,6 +1155,21 @@ void tcg_optimize(TCGContext *s)
|
|||
tcg_opt_gen_mov(s, op, args, args[0], args[4-tmp]);
|
||||
break;
|
||||
}
|
||||
if (temp_is_const(args[3]) && temp_is_const(args[4])) {
|
||||
tcg_target_ulong tv = temps[args[3]].val;
|
||||
tcg_target_ulong fv = temps[args[4]].val;
|
||||
TCGCond cond = args[5];
|
||||
if (fv == 1 && tv == 0) {
|
||||
cond = tcg_invert_cond(cond);
|
||||
} else if (!(tv == 1 && fv == 0)) {
|
||||
goto do_default;
|
||||
}
|
||||
args[3] = cond;
|
||||
op->opc = opc = (opc == INDEX_op_movcond_i32
|
||||
? INDEX_op_setcond_i32
|
||||
: INDEX_op_setcond_i64);
|
||||
nb_iargs = 2;
|
||||
}
|
||||
goto do_default;
|
||||
|
||||
case INDEX_op_add2_i32:
|
||||
|
|
|
@ -49,6 +49,9 @@ typedef enum {
|
|||
TCG_AREG0 = TCG_REG_R27
|
||||
} TCGReg;
|
||||
|
||||
extern bool have_isa_2_06;
|
||||
extern bool have_isa_3_00;
|
||||
|
||||
/* optional instructions automatically implemented */
|
||||
#define TCG_TARGET_HAS_ext8u_i32 0 /* andi */
|
||||
#define TCG_TARGET_HAS_ext16u_i32 0
|
||||
|
@ -68,7 +71,12 @@ typedef enum {
|
|||
#define TCG_TARGET_HAS_eqv_i32 1
|
||||
#define TCG_TARGET_HAS_nand_i32 1
|
||||
#define TCG_TARGET_HAS_nor_i32 1
|
||||
#define TCG_TARGET_HAS_clz_i32 1
|
||||
#define TCG_TARGET_HAS_ctz_i32 have_isa_3_00
|
||||
#define TCG_TARGET_HAS_ctpop_i32 have_isa_2_06
|
||||
#define TCG_TARGET_HAS_deposit_i32 1
|
||||
#define TCG_TARGET_HAS_extract_i32 1
|
||||
#define TCG_TARGET_HAS_sextract_i32 0
|
||||
#define TCG_TARGET_HAS_movcond_i32 1
|
||||
#define TCG_TARGET_HAS_mulu2_i32 0
|
||||
#define TCG_TARGET_HAS_muls2_i32 0
|
||||
|
@ -99,7 +107,12 @@ typedef enum {
|
|||
#define TCG_TARGET_HAS_eqv_i64 1
|
||||
#define TCG_TARGET_HAS_nand_i64 1
|
||||
#define TCG_TARGET_HAS_nor_i64 1
|
||||
#define TCG_TARGET_HAS_clz_i64 1
|
||||
#define TCG_TARGET_HAS_ctz_i64 have_isa_3_00
|
||||
#define TCG_TARGET_HAS_ctpop_i64 have_isa_2_06
|
||||
#define TCG_TARGET_HAS_deposit_i64 1
|
||||
#define TCG_TARGET_HAS_extract_i64 1
|
||||
#define TCG_TARGET_HAS_sextract_i64 0
|
||||
#define TCG_TARGET_HAS_movcond_i64 1
|
||||
#define TCG_TARGET_HAS_add2_i64 1
|
||||
#define TCG_TARGET_HAS_sub2_i64 1
|
||||
|
|
|
@ -77,11 +77,15 @@
|
|||
#define TCG_CT_CONST_U32 0x800
|
||||
#define TCG_CT_CONST_ZERO 0x1000
|
||||
#define TCG_CT_CONST_MONE 0x2000
|
||||
#define TCG_CT_CONST_WSZ 0x4000
|
||||
|
||||
static tcg_insn_unit *tb_ret_addr;
|
||||
|
||||
#include "elf.h"
|
||||
static bool have_isa_2_06;
|
||||
|
||||
bool have_isa_2_06;
|
||||
bool have_isa_3_00;
|
||||
|
||||
#define HAVE_ISA_2_06 have_isa_2_06
|
||||
#define HAVE_ISEL have_isa_2_06
|
||||
|
||||
|
@ -259,12 +263,10 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
|
|||
}
|
||||
|
||||
/* parse target specific constraints */
|
||||
static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
||||
static const char *target_parse_constraint(TCGArgConstraint *ct,
|
||||
const char *ct_str, TCGType type)
|
||||
{
|
||||
const char *ct_str;
|
||||
|
||||
ct_str = *pct_str;
|
||||
switch (ct_str[0]) {
|
||||
switch (*ct_str++) {
|
||||
case 'A': case 'B': case 'C': case 'D':
|
||||
ct->ct |= TCG_CT_REG;
|
||||
tcg_regset_set_reg(ct->u.regs, 3 + ct_str[0] - 'A');
|
||||
|
@ -307,15 +309,16 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
|||
case 'U':
|
||||
ct->ct |= TCG_CT_CONST_U32;
|
||||
break;
|
||||
case 'W':
|
||||
ct->ct |= TCG_CT_CONST_WSZ;
|
||||
break;
|
||||
case 'Z':
|
||||
ct->ct |= TCG_CT_CONST_ZERO;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
ct_str++;
|
||||
*pct_str = ct_str;
|
||||
return 0;
|
||||
return ct_str;
|
||||
}
|
||||
|
||||
/* test if a constant matches the constraint */
|
||||
|
@ -345,6 +348,9 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type,
|
|||
return 1;
|
||||
} else if ((ct & TCG_CT_CONST_MONE) && val == -1) {
|
||||
return 1;
|
||||
} else if ((ct & TCG_CT_CONST_WSZ)
|
||||
&& val == (type == TCG_TYPE_I32 ? 32 : 64)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -449,6 +455,10 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type,
|
|||
#define NOR XO31(124)
|
||||
#define CNTLZW XO31( 26)
|
||||
#define CNTLZD XO31( 58)
|
||||
#define CNTTZW XO31(538)
|
||||
#define CNTTZD XO31(570)
|
||||
#define CNTPOPW XO31(378)
|
||||
#define CNTPOPD XO31(506)
|
||||
#define ANDC XO31( 60)
|
||||
#define ORC XO31(412)
|
||||
#define EQV XO31(284)
|
||||
|
@ -1170,6 +1180,32 @@ static void tcg_out_movcond(TCGContext *s, TCGType type, TCGCond cond,
|
|||
}
|
||||
}
|
||||
|
||||
static void tcg_out_cntxz(TCGContext *s, TCGType type, uint32_t opc,
|
||||
TCGArg a0, TCGArg a1, TCGArg a2, bool const_a2)
|
||||
{
|
||||
if (const_a2 && a2 == (type == TCG_TYPE_I32 ? 32 : 64)) {
|
||||
tcg_out32(s, opc | RA(a0) | RS(a1));
|
||||
} else {
|
||||
tcg_out_cmp(s, TCG_COND_EQ, a1, 0, 1, 7, type);
|
||||
/* Note that the only other valid constant for a2 is 0. */
|
||||
if (HAVE_ISEL) {
|
||||
tcg_out32(s, opc | RA(TCG_REG_R0) | RS(a1));
|
||||
tcg_out32(s, tcg_to_isel[TCG_COND_EQ] | TAB(a0, a2, TCG_REG_R0));
|
||||
} else if (!const_a2 && a0 == a2) {
|
||||
tcg_out32(s, tcg_to_bc[TCG_COND_EQ] | 8);
|
||||
tcg_out32(s, opc | RA(a0) | RS(a1));
|
||||
} else {
|
||||
tcg_out32(s, opc | RA(a0) | RS(a1));
|
||||
tcg_out32(s, tcg_to_bc[TCG_COND_NE] | 8);
|
||||
if (const_a2) {
|
||||
tcg_out_movi(s, type, a0, 0);
|
||||
} else {
|
||||
tcg_out_mov(s, type, a0, a2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_out_cmp2(TCGContext *s, const TCGArg *args,
|
||||
const int *const_args)
|
||||
{
|
||||
|
@ -2107,6 +2143,30 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
|
|||
tcg_out32(s, NOR | SAB(args[1], args[0], args[2]));
|
||||
break;
|
||||
|
||||
case INDEX_op_clz_i32:
|
||||
tcg_out_cntxz(s, TCG_TYPE_I32, CNTLZW, args[0], args[1],
|
||||
args[2], const_args[2]);
|
||||
break;
|
||||
case INDEX_op_ctz_i32:
|
||||
tcg_out_cntxz(s, TCG_TYPE_I32, CNTTZW, args[0], args[1],
|
||||
args[2], const_args[2]);
|
||||
break;
|
||||
case INDEX_op_ctpop_i32:
|
||||
tcg_out32(s, CNTPOPW | SAB(args[1], args[0], 0));
|
||||
break;
|
||||
|
||||
case INDEX_op_clz_i64:
|
||||
tcg_out_cntxz(s, TCG_TYPE_I64, CNTLZD, args[0], args[1],
|
||||
args[2], const_args[2]);
|
||||
break;
|
||||
case INDEX_op_ctz_i64:
|
||||
tcg_out_cntxz(s, TCG_TYPE_I64, CNTTZD, args[0], args[1],
|
||||
args[2], const_args[2]);
|
||||
break;
|
||||
case INDEX_op_ctpop_i64:
|
||||
tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0));
|
||||
break;
|
||||
|
||||
case INDEX_op_mul_i32:
|
||||
a0 = args[0], a1 = args[1], a2 = args[2];
|
||||
if (const_args[2]) {
|
||||
|
@ -2396,6 +2456,14 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
|
|||
}
|
||||
break;
|
||||
|
||||
case INDEX_op_extract_i32:
|
||||
tcg_out_rlw(s, RLWINM, args[0], args[1],
|
||||
32 - args[2], 32 - args[3], 31);
|
||||
break;
|
||||
case INDEX_op_extract_i64:
|
||||
tcg_out_rld(s, RLDICL, args[0], args[1], 64 - args[2], 64 - args[3]);
|
||||
break;
|
||||
|
||||
case INDEX_op_movcond_i32:
|
||||
tcg_out_movcond(s, TCG_TYPE_I32, args[5], args[0], args[1], args[2],
|
||||
args[3], args[4], const_args[2]);
|
||||
|
@ -2511,6 +2579,9 @@ static const TCGTargetOpDef ppc_op_defs[] = {
|
|||
{ INDEX_op_eqv_i32, { "r", "r", "ri" } },
|
||||
{ INDEX_op_nand_i32, { "r", "r", "r" } },
|
||||
{ INDEX_op_nor_i32, { "r", "r", "r" } },
|
||||
{ INDEX_op_clz_i32, { "r", "r", "rZW" } },
|
||||
{ INDEX_op_ctz_i32, { "r", "r", "rZW" } },
|
||||
{ INDEX_op_ctpop_i32, { "r", "r" } },
|
||||
|
||||
{ INDEX_op_shl_i32, { "r", "r", "ri" } },
|
||||
{ INDEX_op_shr_i32, { "r", "r", "ri" } },
|
||||
|
@ -2530,6 +2601,7 @@ static const TCGTargetOpDef ppc_op_defs[] = {
|
|||
{ INDEX_op_movcond_i32, { "r", "r", "ri", "rZ", "rZ" } },
|
||||
|
||||
{ INDEX_op_deposit_i32, { "r", "0", "rZ" } },
|
||||
{ INDEX_op_extract_i32, { "r", "r" } },
|
||||
|
||||
{ INDEX_op_muluh_i32, { "r", "r", "r" } },
|
||||
{ INDEX_op_mulsh_i32, { "r", "r", "r" } },
|
||||
|
@ -2558,6 +2630,9 @@ static const TCGTargetOpDef ppc_op_defs[] = {
|
|||
{ INDEX_op_eqv_i64, { "r", "r", "r" } },
|
||||
{ INDEX_op_nand_i64, { "r", "r", "r" } },
|
||||
{ INDEX_op_nor_i64, { "r", "r", "r" } },
|
||||
{ INDEX_op_clz_i64, { "r", "r", "rZW" } },
|
||||
{ INDEX_op_ctz_i64, { "r", "r", "rZW" } },
|
||||
{ INDEX_op_ctpop_i64, { "r", "r" } },
|
||||
|
||||
{ INDEX_op_shl_i64, { "r", "r", "ri" } },
|
||||
{ INDEX_op_shr_i64, { "r", "r", "ri" } },
|
||||
|
@ -2585,6 +2660,7 @@ static const TCGTargetOpDef ppc_op_defs[] = {
|
|||
{ INDEX_op_movcond_i64, { "r", "r", "ri", "rZ", "rZ" } },
|
||||
|
||||
{ INDEX_op_deposit_i64, { "r", "0", "rZ" } },
|
||||
{ INDEX_op_extract_i64, { "r", "r" } },
|
||||
|
||||
{ INDEX_op_mulsh_i64, { "r", "r", "r" } },
|
||||
{ INDEX_op_muluh_i64, { "r", "r", "r" } },
|
||||
|
@ -2624,12 +2700,31 @@ static const TCGTargetOpDef ppc_op_defs[] = {
|
|||
{ -1 },
|
||||
};
|
||||
|
||||
static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
||||
{
|
||||
int i, n = ARRAY_SIZE(ppc_op_defs);
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (ppc_op_defs[i].op == op) {
|
||||
return &ppc_op_defs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void tcg_target_init(TCGContext *s)
|
||||
{
|
||||
unsigned long hwcap = qemu_getauxval(AT_HWCAP);
|
||||
unsigned long hwcap2 = qemu_getauxval(AT_HWCAP2);
|
||||
|
||||
if (hwcap & PPC_FEATURE_ARCH_2_06) {
|
||||
have_isa_2_06 = true;
|
||||
}
|
||||
#ifdef PPC_FEATURE2_ARCH_3_00
|
||||
if (hwcap2 & PPC_FEATURE2_ARCH_3_00) {
|
||||
have_isa_3_00 = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
|
||||
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
|
||||
|
@ -2660,8 +2755,6 @@ static void tcg_target_init(TCGContext *s)
|
|||
if (USE_REG_RA) {
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); /* return addr */
|
||||
}
|
||||
|
||||
tcg_add_target_add_op_defs(ppc_op_defs);
|
||||
}
|
||||
|
||||
#ifdef __ELF__
|
||||
|
|
|
@ -49,6 +49,18 @@ typedef enum TCGReg {
|
|||
|
||||
#define TCG_TARGET_NB_REGS 16
|
||||
|
||||
/* A list of relevant facilities used by this translator. Some of these
|
||||
are required for proper operation, and these are checked at startup. */
|
||||
|
||||
#define FACILITY_ZARCH_ACTIVE (1ULL << (63 - 2))
|
||||
#define FACILITY_LONG_DISP (1ULL << (63 - 18))
|
||||
#define FACILITY_EXT_IMM (1ULL << (63 - 21))
|
||||
#define FACILITY_GEN_INST_EXT (1ULL << (63 - 34))
|
||||
#define FACILITY_LOAD_ON_COND (1ULL << (63 - 45))
|
||||
#define FACILITY_FAST_BCR_SER FACILITY_LOAD_ON_COND
|
||||
|
||||
extern uint64_t s390_facilities;
|
||||
|
||||
/* optional instructions */
|
||||
#define TCG_TARGET_HAS_div2_i32 1
|
||||
#define TCG_TARGET_HAS_rot_i32 1
|
||||
|
@ -65,7 +77,12 @@ typedef enum TCGReg {
|
|||
#define TCG_TARGET_HAS_eqv_i32 0
|
||||
#define TCG_TARGET_HAS_nand_i32 0
|
||||
#define TCG_TARGET_HAS_nor_i32 0
|
||||
#define TCG_TARGET_HAS_deposit_i32 1
|
||||
#define TCG_TARGET_HAS_clz_i32 0
|
||||
#define TCG_TARGET_HAS_ctz_i32 0
|
||||
#define TCG_TARGET_HAS_ctpop_i32 0
|
||||
#define TCG_TARGET_HAS_deposit_i32 (s390_facilities & FACILITY_GEN_INST_EXT)
|
||||
#define TCG_TARGET_HAS_extract_i32 (s390_facilities & FACILITY_GEN_INST_EXT)
|
||||
#define TCG_TARGET_HAS_sextract_i32 0
|
||||
#define TCG_TARGET_HAS_movcond_i32 1
|
||||
#define TCG_TARGET_HAS_add2_i32 1
|
||||
#define TCG_TARGET_HAS_sub2_i32 1
|
||||
|
@ -94,7 +111,12 @@ typedef enum TCGReg {
|
|||
#define TCG_TARGET_HAS_eqv_i64 0
|
||||
#define TCG_TARGET_HAS_nand_i64 0
|
||||
#define TCG_TARGET_HAS_nor_i64 0
|
||||
#define TCG_TARGET_HAS_deposit_i64 1
|
||||
#define TCG_TARGET_HAS_clz_i64 (s390_facilities & FACILITY_EXT_IMM)
|
||||
#define TCG_TARGET_HAS_ctz_i64 0
|
||||
#define TCG_TARGET_HAS_ctpop_i64 0
|
||||
#define TCG_TARGET_HAS_deposit_i64 (s390_facilities & FACILITY_GEN_INST_EXT)
|
||||
#define TCG_TARGET_HAS_extract_i64 (s390_facilities & FACILITY_GEN_INST_EXT)
|
||||
#define TCG_TARGET_HAS_sextract_i64 0
|
||||
#define TCG_TARGET_HAS_movcond_i64 1
|
||||
#define TCG_TARGET_HAS_add2_i64 1
|
||||
#define TCG_TARGET_HAS_sub2_i64 1
|
||||
|
@ -103,10 +125,6 @@ typedef enum TCGReg {
|
|||
#define TCG_TARGET_HAS_muluh_i64 0
|
||||
#define TCG_TARGET_HAS_mulsh_i64 0
|
||||
|
||||
extern bool tcg_target_deposit_valid(int ofs, int len);
|
||||
#define TCG_TARGET_deposit_i32_valid tcg_target_deposit_valid
|
||||
#define TCG_TARGET_deposit_i64_valid tcg_target_deposit_valid
|
||||
|
||||
/* used for function call generation */
|
||||
#define TCG_REG_CALL_STACK TCG_REG_R15
|
||||
#define TCG_TARGET_STACK_ALIGN 8
|
||||
|
|
|
@ -43,13 +43,14 @@
|
|||
#define TCG_CT_CONST_XORI 0x400
|
||||
#define TCG_CT_CONST_CMPI 0x800
|
||||
#define TCG_CT_CONST_ADLI 0x1000
|
||||
#define TCG_CT_CONST_ZERO 0x2000
|
||||
|
||||
/* Several places within the instruction set 0 means "no register"
|
||||
rather than TCG_REG_R0. */
|
||||
#define TCG_REG_NONE 0
|
||||
|
||||
/* A scratch register that may be be used throughout the backend. */
|
||||
#define TCG_TMP0 TCG_REG_R14
|
||||
#define TCG_TMP0 TCG_REG_R1
|
||||
|
||||
#ifndef CONFIG_SOFTMMU
|
||||
#define TCG_GUEST_BASE_REG TCG_REG_R13
|
||||
|
@ -132,6 +133,7 @@ typedef enum S390Opcode {
|
|||
RRE_DLR = 0xb997,
|
||||
RRE_DSGFR = 0xb91d,
|
||||
RRE_DSGR = 0xb90d,
|
||||
RRE_FLOGR = 0xb983,
|
||||
RRE_LGBR = 0xb906,
|
||||
RRE_LCGR = 0xb903,
|
||||
RRE_LGFR = 0xb914,
|
||||
|
@ -334,18 +336,7 @@ static void * const qemu_st_helpers[16] = {
|
|||
#endif
|
||||
|
||||
static tcg_insn_unit *tb_ret_addr;
|
||||
|
||||
/* A list of relevant facilities used by this translator. Some of these
|
||||
are required for proper operation, and these are checked at startup. */
|
||||
|
||||
#define FACILITY_ZARCH_ACTIVE (1ULL << (63 - 2))
|
||||
#define FACILITY_LONG_DISP (1ULL << (63 - 18))
|
||||
#define FACILITY_EXT_IMM (1ULL << (63 - 21))
|
||||
#define FACILITY_GEN_INST_EXT (1ULL << (63 - 34))
|
||||
#define FACILITY_LOAD_ON_COND (1ULL << (63 - 45))
|
||||
#define FACILITY_FAST_BCR_SER FACILITY_LOAD_ON_COND
|
||||
|
||||
static uint64_t facilities;
|
||||
uint64_t s390_facilities;
|
||||
|
||||
static void patch_reloc(tcg_insn_unit *code_ptr, int type,
|
||||
intptr_t value, intptr_t addend)
|
||||
|
@ -369,11 +360,10 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
|
|||
}
|
||||
|
||||
/* parse target specific constraints */
|
||||
static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
||||
static const char *target_parse_constraint(TCGArgConstraint *ct,
|
||||
const char *ct_str, TCGType type)
|
||||
{
|
||||
const char *ct_str = *pct_str;
|
||||
|
||||
switch (ct_str[0]) {
|
||||
switch (*ct_str++) {
|
||||
case 'r': /* all registers */
|
||||
ct->ct |= TCG_CT_REG;
|
||||
tcg_regset_set32(ct->u.regs, 0, 0xffff);
|
||||
|
@ -410,13 +400,13 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
|||
case 'C':
|
||||
ct->ct |= TCG_CT_CONST_CMPI;
|
||||
break;
|
||||
case 'Z':
|
||||
ct->ct |= TCG_CT_CONST_ZERO;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
ct_str++;
|
||||
*pct_str = ct_str;
|
||||
|
||||
return 0;
|
||||
return ct_str;
|
||||
}
|
||||
|
||||
/* Immediates to be used with logical OR. This is an optimization only,
|
||||
|
@ -427,7 +417,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
|||
|
||||
static int tcg_match_ori(TCGType type, tcg_target_long val)
|
||||
{
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
if (type == TCG_TYPE_I32) {
|
||||
/* All 32-bit ORs can be performed with 1 48-bit insn. */
|
||||
return 1;
|
||||
|
@ -439,7 +429,7 @@ static int tcg_match_ori(TCGType type, tcg_target_long val)
|
|||
if (val == (int16_t)val) {
|
||||
return 0;
|
||||
}
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
if (val == (int32_t)val) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -456,7 +446,7 @@ static int tcg_match_ori(TCGType type, tcg_target_long val)
|
|||
|
||||
static int tcg_match_xori(TCGType type, tcg_target_long val)
|
||||
{
|
||||
if ((facilities & FACILITY_EXT_IMM) == 0) {
|
||||
if ((s390_facilities & FACILITY_EXT_IMM) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -477,7 +467,7 @@ static int tcg_match_xori(TCGType type, tcg_target_long val)
|
|||
|
||||
static int tcg_match_cmpi(TCGType type, tcg_target_long val)
|
||||
{
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
/* The COMPARE IMMEDIATE instruction is available. */
|
||||
if (type == TCG_TYPE_I32) {
|
||||
/* We have a 32-bit immediate and can compare against anything. */
|
||||
|
@ -506,7 +496,7 @@ static int tcg_match_cmpi(TCGType type, tcg_target_long val)
|
|||
|
||||
static int tcg_match_add2i(TCGType type, tcg_target_long val)
|
||||
{
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
if (type == TCG_TYPE_I32) {
|
||||
return 1;
|
||||
} else if (val >= -0xffffffffll && val <= 0xffffffffll) {
|
||||
|
@ -536,7 +526,7 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type,
|
|||
general-instruction-extensions, then we have MULTIPLY SINGLE
|
||||
IMMEDIATE with a signed 32-bit, otherwise we have only
|
||||
MULTIPLY HALFWORD IMMEDIATE, with a signed 16-bit. */
|
||||
if (facilities & FACILITY_GEN_INST_EXT) {
|
||||
if (s390_facilities & FACILITY_GEN_INST_EXT) {
|
||||
return val == (int32_t)val;
|
||||
} else {
|
||||
return val == (int16_t)val;
|
||||
|
@ -549,6 +539,8 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type,
|
|||
return tcg_match_xori(type, val);
|
||||
} else if (ct & TCG_CT_CONST_CMPI) {
|
||||
return tcg_match_cmpi(type, val);
|
||||
} else if (ct & TCG_CT_CONST_ZERO) {
|
||||
return val == 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -663,7 +655,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
|
|||
}
|
||||
|
||||
/* Try all 48-bit insns that can load it in one go. */
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
if (sval == (int32_t)sval) {
|
||||
tcg_out_insn(s, RIL, LGFI, ret, sval);
|
||||
return;
|
||||
|
@ -689,7 +681,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
|
|||
|
||||
/* If extended immediates are not present, then we may have to issue
|
||||
several instructions to load the low 32 bits. */
|
||||
if (!(facilities & FACILITY_EXT_IMM)) {
|
||||
if (!(s390_facilities & FACILITY_EXT_IMM)) {
|
||||
/* A 32-bit unsigned value can be loaded in 2 insns. And given
|
||||
that the lli_insns loop above did not succeed, we know that
|
||||
both insns are required. */
|
||||
|
@ -722,7 +714,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
|
|||
|
||||
/* Insert data into the high 32-bits. */
|
||||
uval = uval >> 31 >> 1;
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
if (uval < 0x10000) {
|
||||
tcg_out_insn(s, RI, IIHL, ret, uval);
|
||||
} else if ((uval & 0xffff) == 0) {
|
||||
|
@ -805,7 +797,7 @@ static void tcg_out_ld_abs(TCGContext *s, TCGType type, TCGReg dest, void *abs)
|
|||
{
|
||||
intptr_t addr = (intptr_t)abs;
|
||||
|
||||
if ((facilities & FACILITY_GEN_INST_EXT) && !(addr & 1)) {
|
||||
if ((s390_facilities & FACILITY_GEN_INST_EXT) && !(addr & 1)) {
|
||||
ptrdiff_t disp = tcg_pcrel_diff(s, abs) >> 1;
|
||||
if (disp == (int32_t)disp) {
|
||||
if (type == TCG_TYPE_I32) {
|
||||
|
@ -832,7 +824,7 @@ static inline void tcg_out_risbg(TCGContext *s, TCGReg dest, TCGReg src,
|
|||
|
||||
static void tgen_ext8s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
|
||||
{
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
tcg_out_insn(s, RRE, LGBR, dest, src);
|
||||
return;
|
||||
}
|
||||
|
@ -852,7 +844,7 @@ static void tgen_ext8s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
|
|||
|
||||
static void tgen_ext8u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
|
||||
{
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
tcg_out_insn(s, RRE, LLGCR, dest, src);
|
||||
return;
|
||||
}
|
||||
|
@ -872,7 +864,7 @@ static void tgen_ext8u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
|
|||
|
||||
static void tgen_ext16s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
|
||||
{
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
tcg_out_insn(s, RRE, LGHR, dest, src);
|
||||
return;
|
||||
}
|
||||
|
@ -892,7 +884,7 @@ static void tgen_ext16s(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
|
|||
|
||||
static void tgen_ext16u(TCGContext *s, TCGType type, TCGReg dest, TCGReg src)
|
||||
{
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
tcg_out_insn(s, RRE, LLGHR, dest, src);
|
||||
return;
|
||||
}
|
||||
|
@ -980,7 +972,7 @@ static void tgen_andi(TCGContext *s, TCGType type, TCGReg dest, uint64_t val)
|
|||
tgen_ext32u(s, dest, dest);
|
||||
return;
|
||||
}
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
if ((val & valid) == 0xff) {
|
||||
tgen_ext8u(s, TCG_TYPE_I64, dest, dest);
|
||||
return;
|
||||
|
@ -1001,7 +993,7 @@ static void tgen_andi(TCGContext *s, TCGType type, TCGReg dest, uint64_t val)
|
|||
}
|
||||
|
||||
/* Try all 48-bit insns that can perform it in one go. */
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
tcg_target_ulong mask = ~(0xffffffffull << i*32);
|
||||
if (((val | ~valid) & mask) == mask) {
|
||||
|
@ -1010,7 +1002,7 @@ static void tgen_andi(TCGContext *s, TCGType type, TCGReg dest, uint64_t val)
|
|||
}
|
||||
}
|
||||
}
|
||||
if ((facilities & FACILITY_GEN_INST_EXT) && risbg_mask(val)) {
|
||||
if ((s390_facilities & FACILITY_GEN_INST_EXT) && risbg_mask(val)) {
|
||||
tgen_andi_risbg(s, dest, dest, val);
|
||||
return;
|
||||
}
|
||||
|
@ -1040,7 +1032,7 @@ static void tgen64_ori(TCGContext *s, TCGReg dest, tcg_target_ulong val)
|
|||
return;
|
||||
}
|
||||
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
/* Try all 32-bit insns that can perform it in one go. */
|
||||
for (i = 0; i < 4; i++) {
|
||||
tcg_target_ulong mask = (0xffffull << i*16);
|
||||
|
@ -1225,7 +1217,7 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond,
|
|||
}
|
||||
|
||||
cc = tgen_cmp(s, type, cond, c1, c2, c2const, false);
|
||||
if (facilities & FACILITY_LOAD_ON_COND) {
|
||||
if (s390_facilities & FACILITY_LOAD_ON_COND) {
|
||||
/* Emit: d = 0, t = 1, d = (cc ? t : d). */
|
||||
tcg_out_movi(s, TCG_TYPE_I64, dest, 0);
|
||||
tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 1);
|
||||
|
@ -1242,7 +1234,7 @@ static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest,
|
|||
TCGReg c1, TCGArg c2, int c2const, TCGReg r3)
|
||||
{
|
||||
int cc;
|
||||
if (facilities & FACILITY_LOAD_ON_COND) {
|
||||
if (s390_facilities & FACILITY_LOAD_ON_COND) {
|
||||
cc = tgen_cmp(s, type, c, c1, c2, c2const, false);
|
||||
tcg_out_insn(s, RRF, LOCGR, dest, r3, cc);
|
||||
} else {
|
||||
|
@ -1255,17 +1247,45 @@ static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest,
|
|||
}
|
||||
}
|
||||
|
||||
bool tcg_target_deposit_valid(int ofs, int len)
|
||||
static void tgen_clz(TCGContext *s, TCGReg dest, TCGReg a1,
|
||||
TCGArg a2, int a2const)
|
||||
{
|
||||
return (facilities & FACILITY_GEN_INST_EXT) != 0;
|
||||
/* Since this sets both R and R+1, we have no choice but to store the
|
||||
result into R0, allowing R1 == TCG_TMP0 to be clobbered as well. */
|
||||
QEMU_BUILD_BUG_ON(TCG_TMP0 != TCG_REG_R1);
|
||||
tcg_out_insn(s, RRE, FLOGR, TCG_REG_R0, a1);
|
||||
|
||||
if (a2const && a2 == 64) {
|
||||
tcg_out_mov(s, TCG_TYPE_I64, dest, TCG_REG_R0);
|
||||
} else {
|
||||
if (a2const) {
|
||||
tcg_out_movi(s, TCG_TYPE_I64, dest, a2);
|
||||
} else {
|
||||
tcg_out_mov(s, TCG_TYPE_I64, dest, a2);
|
||||
}
|
||||
if (s390_facilities & FACILITY_LOAD_ON_COND) {
|
||||
/* Emit: if (one bit found) dest = r0. */
|
||||
tcg_out_insn(s, RRF, LOCGR, dest, TCG_REG_R0, 2);
|
||||
} else {
|
||||
/* Emit: if (no one bit found) goto over; dest = r0; over: */
|
||||
tcg_out_insn(s, RI, BRC, 8, (4 + 4) >> 1);
|
||||
tcg_out_insn(s, RRE, LGR, dest, TCG_REG_R0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tgen_deposit(TCGContext *s, TCGReg dest, TCGReg src,
|
||||
int ofs, int len)
|
||||
int ofs, int len, int z)
|
||||
{
|
||||
int lsb = (63 - ofs);
|
||||
int msb = lsb - (len - 1);
|
||||
tcg_out_risbg(s, dest, src, msb, lsb, ofs, 0);
|
||||
tcg_out_risbg(s, dest, src, msb, lsb, ofs, z);
|
||||
}
|
||||
|
||||
static void tgen_extract(TCGContext *s, TCGReg dest, TCGReg src,
|
||||
int ofs, int len)
|
||||
{
|
||||
tcg_out_risbg(s, dest, src, 64 - len, 63, 64 - ofs, 1);
|
||||
}
|
||||
|
||||
static void tgen_gotoi(TCGContext *s, int cc, tcg_insn_unit *dest)
|
||||
|
@ -1337,7 +1357,7 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c,
|
|||
{
|
||||
int cc;
|
||||
|
||||
if (facilities & FACILITY_GEN_INST_EXT) {
|
||||
if (s390_facilities & FACILITY_GEN_INST_EXT) {
|
||||
bool is_unsigned = is_unsigned_cond(c);
|
||||
bool in_range;
|
||||
S390Opcode opc;
|
||||
|
@ -1524,7 +1544,7 @@ static TCGReg tcg_out_tlb_read(TCGContext* s, TCGReg addr_reg, TCGMemOp opc,
|
|||
a_off = (a_bits >= s_bits ? 0 : s_mask - a_mask);
|
||||
tlb_mask = (uint64_t)TARGET_PAGE_MASK | a_mask;
|
||||
|
||||
if (facilities & FACILITY_GEN_INST_EXT) {
|
||||
if (s390_facilities & FACILITY_GEN_INST_EXT) {
|
||||
tcg_out_risbg(s, TCG_REG_R2, addr_reg,
|
||||
64 - CPU_TLB_BITS - CPU_TLB_ENTRY_BITS,
|
||||
63 - CPU_TLB_ENTRY_BITS,
|
||||
|
@ -1795,7 +1815,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
|||
tcg_out_insn(s, RI, AHI, a0, a2);
|
||||
break;
|
||||
}
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
tcg_out_insn(s, RIL, AFI, a0, a2);
|
||||
break;
|
||||
}
|
||||
|
@ -1991,7 +2011,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
|||
tcg_out_insn(s, RI, AGHI, a0, a2);
|
||||
break;
|
||||
}
|
||||
if (facilities & FACILITY_EXT_IMM) {
|
||||
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||
if (a2 == (int32_t)a2) {
|
||||
tcg_out_insn(s, RIL, AGFI, a0, a2);
|
||||
break;
|
||||
|
@ -2172,7 +2192,30 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
|||
break;
|
||||
|
||||
OP_32_64(deposit):
|
||||
tgen_deposit(s, args[0], args[2], args[3], args[4]);
|
||||
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) {
|
||||
TCGType type = (opc == INDEX_op_deposit_i64);
|
||||
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;
|
||||
|
||||
OP_32_64(extract):
|
||||
tgen_extract(s, args[0], args[1], args[2], args[3]);
|
||||
break;
|
||||
|
||||
case INDEX_op_clz_i64:
|
||||
tgen_clz(s, args[0], args[1], args[2], const_args[2]);
|
||||
break;
|
||||
|
||||
case INDEX_op_mb:
|
||||
|
@ -2180,7 +2223,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
|||
serialize the instruction stream. */
|
||||
if (args[0] & TCG_MO_ST_LD) {
|
||||
tcg_out_insn(s, RR, BCR,
|
||||
facilities & FACILITY_FAST_BCR_SER ? 14 : 15, 0);
|
||||
s390_facilities & FACILITY_FAST_BCR_SER ? 14 : 15, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2242,7 +2285,8 @@ static const TCGTargetOpDef s390_op_defs[] = {
|
|||
{ INDEX_op_brcond_i32, { "r", "rC" } },
|
||||
{ INDEX_op_setcond_i32, { "r", "r", "rC" } },
|
||||
{ INDEX_op_movcond_i32, { "r", "r", "rC", "r", "0" } },
|
||||
{ INDEX_op_deposit_i32, { "r", "0", "r" } },
|
||||
{ INDEX_op_deposit_i32, { "r", "rZ", "r" } },
|
||||
{ INDEX_op_extract_i32, { "r", "r" } },
|
||||
|
||||
{ INDEX_op_qemu_ld_i32, { "r", "L" } },
|
||||
{ INDEX_op_qemu_ld_i64, { "r", "L" } },
|
||||
|
@ -2297,6 +2341,8 @@ static const TCGTargetOpDef s390_op_defs[] = {
|
|||
{ INDEX_op_bswap32_i64, { "r", "r" } },
|
||||
{ INDEX_op_bswap64_i64, { "r", "r" } },
|
||||
|
||||
{ INDEX_op_clz_i64, { "r", "r", "ri" } },
|
||||
|
||||
{ INDEX_op_add2_i64, { "r", "r", "0", "1", "rA", "r" } },
|
||||
{ INDEX_op_sub2_i64, { "r", "r", "0", "1", "rA", "r" } },
|
||||
|
||||
|
@ -2304,12 +2350,25 @@ static const TCGTargetOpDef s390_op_defs[] = {
|
|||
{ INDEX_op_setcond_i64, { "r", "r", "rC" } },
|
||||
{ INDEX_op_movcond_i64, { "r", "r", "rC", "r", "0" } },
|
||||
{ INDEX_op_deposit_i64, { "r", "0", "r" } },
|
||||
{ INDEX_op_extract_i64, { "r", "r" } },
|
||||
|
||||
{ INDEX_op_mb, { } },
|
||||
{ -1 },
|
||||
};
|
||||
|
||||
static void query_facilities(void)
|
||||
static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
||||
{
|
||||
int i, n = ARRAY_SIZE(s390_op_defs);
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (s390_op_defs[i].op == op) {
|
||||
return &s390_op_defs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void query_s390_facilities(void)
|
||||
{
|
||||
unsigned long hwcap = qemu_getauxval(AT_HWCAP);
|
||||
|
||||
|
@ -2320,7 +2379,7 @@ static void query_facilities(void)
|
|||
register void *r1 __asm__("1");
|
||||
|
||||
/* stfle 0(%r1) */
|
||||
r1 = &facilities;
|
||||
r1 = &s390_facilities;
|
||||
asm volatile(".word 0xb2b0,0x1000"
|
||||
: "=r"(r0) : "0"(0), "r"(r1) : "memory", "cc");
|
||||
}
|
||||
|
@ -2328,7 +2387,7 @@ static void query_facilities(void)
|
|||
|
||||
static void tcg_target_init(TCGContext *s)
|
||||
{
|
||||
query_facilities();
|
||||
query_s390_facilities();
|
||||
|
||||
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
|
||||
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff);
|
||||
|
@ -2351,8 +2410,6 @@ static void tcg_target_init(TCGContext *s)
|
|||
/* XXX many insns can't be used with R0, so we better avoid it for now */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0);
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
|
||||
|
||||
tcg_add_target_add_op_defs(s390_op_defs);
|
||||
}
|
||||
|
||||
#define FRAME_SIZE ((int)(TCG_TARGET_CALL_STACK_OFFSET \
|
||||
|
|
|
@ -110,7 +110,12 @@ extern bool use_vis3_instructions;
|
|||
#define TCG_TARGET_HAS_eqv_i32 0
|
||||
#define TCG_TARGET_HAS_nand_i32 0
|
||||
#define TCG_TARGET_HAS_nor_i32 0
|
||||
#define TCG_TARGET_HAS_clz_i32 0
|
||||
#define TCG_TARGET_HAS_ctz_i32 0
|
||||
#define TCG_TARGET_HAS_ctpop_i32 0
|
||||
#define TCG_TARGET_HAS_deposit_i32 0
|
||||
#define TCG_TARGET_HAS_extract_i32 0
|
||||
#define TCG_TARGET_HAS_sextract_i32 0
|
||||
#define TCG_TARGET_HAS_movcond_i32 1
|
||||
#define TCG_TARGET_HAS_add2_i32 1
|
||||
#define TCG_TARGET_HAS_sub2_i32 1
|
||||
|
@ -140,7 +145,12 @@ extern bool use_vis3_instructions;
|
|||
#define TCG_TARGET_HAS_eqv_i64 0
|
||||
#define TCG_TARGET_HAS_nand_i64 0
|
||||
#define TCG_TARGET_HAS_nor_i64 0
|
||||
#define TCG_TARGET_HAS_clz_i64 0
|
||||
#define TCG_TARGET_HAS_ctz_i64 0
|
||||
#define TCG_TARGET_HAS_ctpop_i64 0
|
||||
#define TCG_TARGET_HAS_deposit_i64 0
|
||||
#define TCG_TARGET_HAS_extract_i64 0
|
||||
#define TCG_TARGET_HAS_sextract_i64 0
|
||||
#define TCG_TARGET_HAS_movcond_i64 1
|
||||
#define TCG_TARGET_HAS_add2_i64 1
|
||||
#define TCG_TARGET_HAS_sub2_i64 1
|
||||
|
|
|
@ -319,12 +319,10 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
|
|||
}
|
||||
|
||||
/* parse target specific constraints */
|
||||
static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
||||
static const char *target_parse_constraint(TCGArgConstraint *ct,
|
||||
const char *ct_str, TCGType type)
|
||||
{
|
||||
const char *ct_str;
|
||||
|
||||
ct_str = *pct_str;
|
||||
switch (ct_str[0]) {
|
||||
switch (*ct_str++) {
|
||||
case 'r':
|
||||
ct->ct |= TCG_CT_REG;
|
||||
tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
|
||||
|
@ -360,11 +358,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
|||
ct->ct |= TCG_CT_CONST_ZERO;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
ct_str++;
|
||||
*pct_str = ct_str;
|
||||
return 0;
|
||||
return ct_str;
|
||||
}
|
||||
|
||||
/* test if a constant matches the constraint */
|
||||
|
@ -1583,6 +1579,18 @@ static const TCGTargetOpDef sparc_op_defs[] = {
|
|||
{ -1 },
|
||||
};
|
||||
|
||||
static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
||||
{
|
||||
int i, n = ARRAY_SIZE(sparc_op_defs);
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (sparc_op_defs[i].op == op) {
|
||||
return &sparc_op_defs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void tcg_target_init(TCGContext *s)
|
||||
{
|
||||
/* Only probe for the platform and capabilities if we havn't already
|
||||
|
@ -1622,8 +1630,6 @@ static void tcg_target_init(TCGContext *s)
|
|||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_O6); /* stack pointer */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_T1); /* for internal use */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_T2); /* for internal use */
|
||||
|
||||
tcg_add_target_add_op_defs(sparc_op_defs);
|
||||
}
|
||||
|
||||
#if SPARC64
|
||||
|
|
692
tcg/tcg-op.c
692
tcg/tcg-op.c
|
@ -457,6 +457,117 @@ void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
|
|||
}
|
||||
}
|
||||
|
||||
void tcg_gen_clz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
|
||||
{
|
||||
if (TCG_TARGET_HAS_clz_i32) {
|
||||
tcg_gen_op3_i32(INDEX_op_clz_i32, ret, arg1, arg2);
|
||||
} else if (TCG_TARGET_HAS_clz_i64) {
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
tcg_gen_extu_i32_i64(t1, arg1);
|
||||
tcg_gen_extu_i32_i64(t2, arg2);
|
||||
tcg_gen_addi_i64(t2, t2, 32);
|
||||
tcg_gen_clz_i64(t1, t1, t2);
|
||||
tcg_gen_extrl_i64_i32(ret, t1);
|
||||
tcg_temp_free_i64(t1);
|
||||
tcg_temp_free_i64(t2);
|
||||
tcg_gen_subi_i32(ret, ret, 32);
|
||||
} else {
|
||||
gen_helper_clz_i32(ret, arg1, arg2);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_clzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2)
|
||||
{
|
||||
TCGv_i32 t = tcg_const_i32(arg2);
|
||||
tcg_gen_clz_i32(ret, arg1, t);
|
||||
tcg_temp_free_i32(t);
|
||||
}
|
||||
|
||||
void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
|
||||
{
|
||||
if (TCG_TARGET_HAS_ctz_i32) {
|
||||
tcg_gen_op3_i32(INDEX_op_ctz_i32, ret, arg1, arg2);
|
||||
} else if (TCG_TARGET_HAS_ctz_i64) {
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
tcg_gen_extu_i32_i64(t1, arg1);
|
||||
tcg_gen_extu_i32_i64(t2, arg2);
|
||||
tcg_gen_ctz_i64(t1, t1, t2);
|
||||
tcg_gen_extrl_i64_i32(ret, t1);
|
||||
tcg_temp_free_i64(t1);
|
||||
tcg_temp_free_i64(t2);
|
||||
} else if (TCG_TARGET_HAS_ctpop_i32
|
||||
|| TCG_TARGET_HAS_ctpop_i64
|
||||
|| TCG_TARGET_HAS_clz_i32
|
||||
|| TCG_TARGET_HAS_clz_i64) {
|
||||
TCGv_i32 z, t = tcg_temp_new_i32();
|
||||
|
||||
if (TCG_TARGET_HAS_ctpop_i32 || TCG_TARGET_HAS_ctpop_i64) {
|
||||
tcg_gen_subi_i32(t, arg1, 1);
|
||||
tcg_gen_andc_i32(t, t, arg1);
|
||||
tcg_gen_ctpop_i32(t, t);
|
||||
} else {
|
||||
/* Since all non-x86 hosts have clz(0) == 32, don't fight it. */
|
||||
tcg_gen_neg_i32(t, arg1);
|
||||
tcg_gen_and_i32(t, t, arg1);
|
||||
tcg_gen_clzi_i32(t, t, 32);
|
||||
tcg_gen_xori_i32(t, t, 31);
|
||||
}
|
||||
z = tcg_const_i32(0);
|
||||
tcg_gen_movcond_i32(TCG_COND_EQ, ret, arg1, z, arg2, t);
|
||||
tcg_temp_free_i32(t);
|
||||
tcg_temp_free_i32(z);
|
||||
} else {
|
||||
gen_helper_ctz_i32(ret, arg1, arg2);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2)
|
||||
{
|
||||
if (!TCG_TARGET_HAS_ctz_i32 && TCG_TARGET_HAS_ctpop_i32 && arg2 == 32) {
|
||||
/* This equivalence has the advantage of not requiring a fixup. */
|
||||
TCGv_i32 t = tcg_temp_new_i32();
|
||||
tcg_gen_subi_i32(t, arg1, 1);
|
||||
tcg_gen_andc_i32(t, t, arg1);
|
||||
tcg_gen_ctpop_i32(ret, t);
|
||||
tcg_temp_free_i32(t);
|
||||
} else {
|
||||
TCGv_i32 t = tcg_const_i32(arg2);
|
||||
tcg_gen_ctz_i32(ret, arg1, t);
|
||||
tcg_temp_free_i32(t);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_clrsb_i32(TCGv_i32 ret, TCGv_i32 arg)
|
||||
{
|
||||
if (TCG_TARGET_HAS_clz_i32) {
|
||||
TCGv_i32 t = tcg_temp_new_i32();
|
||||
tcg_gen_sari_i32(t, arg, 31);
|
||||
tcg_gen_xor_i32(t, t, arg);
|
||||
tcg_gen_clzi_i32(t, t, 32);
|
||||
tcg_gen_subi_i32(ret, t, 1);
|
||||
tcg_temp_free_i32(t);
|
||||
} else {
|
||||
gen_helper_clrsb_i32(ret, arg);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_ctpop_i32(TCGv_i32 ret, TCGv_i32 arg1)
|
||||
{
|
||||
if (TCG_TARGET_HAS_ctpop_i32) {
|
||||
tcg_gen_op2_i32(INDEX_op_ctpop_i32, ret, arg1);
|
||||
} else if (TCG_TARGET_HAS_ctpop_i64) {
|
||||
TCGv_i64 t = tcg_temp_new_i64();
|
||||
tcg_gen_extu_i32_i64(t, arg1);
|
||||
tcg_gen_ctpop_i64(t, t);
|
||||
tcg_gen_extrl_i64_i32(ret, t);
|
||||
tcg_temp_free_i64(t);
|
||||
} else {
|
||||
gen_helper_ctpop_i32(ret, arg1);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
|
||||
{
|
||||
if (TCG_TARGET_HAS_rot_i32) {
|
||||
|
@ -533,10 +644,11 @@ void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2,
|
|||
TCGv_i32 t1;
|
||||
|
||||
tcg_debug_assert(ofs < 32);
|
||||
tcg_debug_assert(len > 0);
|
||||
tcg_debug_assert(len <= 32);
|
||||
tcg_debug_assert(ofs + len <= 32);
|
||||
|
||||
if (ofs == 0 && len == 32) {
|
||||
if (len == 32) {
|
||||
tcg_gen_mov_i32(ret, arg2);
|
||||
return;
|
||||
}
|
||||
|
@ -560,6 +672,189 @@ void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2,
|
|||
tcg_temp_free_i32(t1);
|
||||
}
|
||||
|
||||
void tcg_gen_deposit_z_i32(TCGv_i32 ret, TCGv_i32 arg,
|
||||
unsigned int ofs, unsigned int len)
|
||||
{
|
||||
tcg_debug_assert(ofs < 32);
|
||||
tcg_debug_assert(len > 0);
|
||||
tcg_debug_assert(len <= 32);
|
||||
tcg_debug_assert(ofs + len <= 32);
|
||||
|
||||
if (ofs + len == 32) {
|
||||
tcg_gen_shli_i32(ret, arg, ofs);
|
||||
} else if (ofs == 0) {
|
||||
tcg_gen_andi_i32(ret, arg, (1u << len) - 1);
|
||||
} else if (TCG_TARGET_HAS_deposit_i32
|
||||
&& TCG_TARGET_deposit_i32_valid(ofs, len)) {
|
||||
TCGv_i32 zero = tcg_const_i32(0);
|
||||
tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, zero, arg, ofs, len);
|
||||
tcg_temp_free_i32(zero);
|
||||
} else {
|
||||
/* To help two-operand hosts we prefer to zero-extend first,
|
||||
which allows ARG to stay live. */
|
||||
switch (len) {
|
||||
case 16:
|
||||
if (TCG_TARGET_HAS_ext16u_i32) {
|
||||
tcg_gen_ext16u_i32(ret, arg);
|
||||
tcg_gen_shli_i32(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (TCG_TARGET_HAS_ext8u_i32) {
|
||||
tcg_gen_ext8u_i32(ret, arg);
|
||||
tcg_gen_shli_i32(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Otherwise prefer zero-extension over AND for code size. */
|
||||
switch (ofs + len) {
|
||||
case 16:
|
||||
if (TCG_TARGET_HAS_ext16u_i32) {
|
||||
tcg_gen_shli_i32(ret, arg, ofs);
|
||||
tcg_gen_ext16u_i32(ret, ret);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (TCG_TARGET_HAS_ext8u_i32) {
|
||||
tcg_gen_shli_i32(ret, arg, ofs);
|
||||
tcg_gen_ext8u_i32(ret, ret);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tcg_gen_andi_i32(ret, arg, (1u << len) - 1);
|
||||
tcg_gen_shli_i32(ret, ret, ofs);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_extract_i32(TCGv_i32 ret, TCGv_i32 arg,
|
||||
unsigned int ofs, unsigned int len)
|
||||
{
|
||||
tcg_debug_assert(ofs < 32);
|
||||
tcg_debug_assert(len > 0);
|
||||
tcg_debug_assert(len <= 32);
|
||||
tcg_debug_assert(ofs + len <= 32);
|
||||
|
||||
/* Canonicalize certain special cases, even if extract is supported. */
|
||||
if (ofs + len == 32) {
|
||||
tcg_gen_shri_i32(ret, arg, 32 - len);
|
||||
return;
|
||||
}
|
||||
if (ofs == 0) {
|
||||
tcg_gen_andi_i32(ret, arg, (1u << len) - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (TCG_TARGET_HAS_extract_i32
|
||||
&& TCG_TARGET_extract_i32_valid(ofs, len)) {
|
||||
tcg_gen_op4ii_i32(INDEX_op_extract_i32, ret, arg, ofs, len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Assume that zero-extension, if available, is cheaper than a shift. */
|
||||
switch (ofs + len) {
|
||||
case 16:
|
||||
if (TCG_TARGET_HAS_ext16u_i32) {
|
||||
tcg_gen_ext16u_i32(ret, arg);
|
||||
tcg_gen_shri_i32(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (TCG_TARGET_HAS_ext8u_i32) {
|
||||
tcg_gen_ext8u_i32(ret, arg);
|
||||
tcg_gen_shri_i32(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* ??? Ideally we'd know what values are available for immediate AND.
|
||||
Assume that 8 bits are available, plus the special case of 16,
|
||||
so that we get ext8u, ext16u. */
|
||||
switch (len) {
|
||||
case 1 ... 8: case 16:
|
||||
tcg_gen_shri_i32(ret, arg, ofs);
|
||||
tcg_gen_andi_i32(ret, ret, (1u << len) - 1);
|
||||
break;
|
||||
default:
|
||||
tcg_gen_shli_i32(ret, arg, 32 - len - ofs);
|
||||
tcg_gen_shri_i32(ret, ret, 32 - len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_sextract_i32(TCGv_i32 ret, TCGv_i32 arg,
|
||||
unsigned int ofs, unsigned int len)
|
||||
{
|
||||
tcg_debug_assert(ofs < 32);
|
||||
tcg_debug_assert(len > 0);
|
||||
tcg_debug_assert(len <= 32);
|
||||
tcg_debug_assert(ofs + len <= 32);
|
||||
|
||||
/* Canonicalize certain special cases, even if extract is supported. */
|
||||
if (ofs + len == 32) {
|
||||
tcg_gen_sari_i32(ret, arg, 32 - len);
|
||||
return;
|
||||
}
|
||||
if (ofs == 0) {
|
||||
switch (len) {
|
||||
case 16:
|
||||
tcg_gen_ext16s_i32(ret, arg);
|
||||
return;
|
||||
case 8:
|
||||
tcg_gen_ext8s_i32(ret, arg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (TCG_TARGET_HAS_sextract_i32
|
||||
&& TCG_TARGET_extract_i32_valid(ofs, len)) {
|
||||
tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, arg, ofs, len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Assume that sign-extension, if available, is cheaper than a shift. */
|
||||
switch (ofs + len) {
|
||||
case 16:
|
||||
if (TCG_TARGET_HAS_ext16s_i32) {
|
||||
tcg_gen_ext16s_i32(ret, arg);
|
||||
tcg_gen_sari_i32(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (TCG_TARGET_HAS_ext8s_i32) {
|
||||
tcg_gen_ext8s_i32(ret, arg);
|
||||
tcg_gen_sari_i32(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (len) {
|
||||
case 16:
|
||||
if (TCG_TARGET_HAS_ext16s_i32) {
|
||||
tcg_gen_shri_i32(ret, arg, ofs);
|
||||
tcg_gen_ext16s_i32(ret, ret);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (TCG_TARGET_HAS_ext8s_i32) {
|
||||
tcg_gen_shri_i32(ret, arg, ofs);
|
||||
tcg_gen_ext8s_i32(ret, ret);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
tcg_gen_shli_i32(ret, arg, 32 - len - ofs);
|
||||
tcg_gen_sari_i32(ret, ret, 32 - len);
|
||||
}
|
||||
|
||||
void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 c1,
|
||||
TCGv_i32 c2, TCGv_i32 v1, TCGv_i32 v2)
|
||||
{
|
||||
|
@ -1519,6 +1814,115 @@ void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
|
|||
}
|
||||
}
|
||||
|
||||
void tcg_gen_clz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
|
||||
{
|
||||
if (TCG_TARGET_HAS_clz_i64) {
|
||||
tcg_gen_op3_i64(INDEX_op_clz_i64, ret, arg1, arg2);
|
||||
} else {
|
||||
gen_helper_clz_i64(ret, arg1, arg2);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_clzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2)
|
||||
{
|
||||
if (TCG_TARGET_REG_BITS == 32
|
||||
&& TCG_TARGET_HAS_clz_i32
|
||||
&& arg2 <= 0xffffffffu) {
|
||||
TCGv_i32 t = tcg_const_i32((uint32_t)arg2 - 32);
|
||||
tcg_gen_clz_i32(t, TCGV_LOW(arg1), t);
|
||||
tcg_gen_addi_i32(t, t, 32);
|
||||
tcg_gen_clz_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), t);
|
||||
tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
|
||||
tcg_temp_free_i32(t);
|
||||
} else {
|
||||
TCGv_i64 t = tcg_const_i64(arg2);
|
||||
tcg_gen_clz_i64(ret, arg1, t);
|
||||
tcg_temp_free_i64(t);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_ctz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
|
||||
{
|
||||
if (TCG_TARGET_HAS_ctz_i64) {
|
||||
tcg_gen_op3_i64(INDEX_op_ctz_i64, ret, arg1, arg2);
|
||||
} else if (TCG_TARGET_HAS_ctpop_i64 || TCG_TARGET_HAS_clz_i64) {
|
||||
TCGv_i64 z, t = tcg_temp_new_i64();
|
||||
|
||||
if (TCG_TARGET_HAS_ctpop_i64) {
|
||||
tcg_gen_subi_i64(t, arg1, 1);
|
||||
tcg_gen_andc_i64(t, t, arg1);
|
||||
tcg_gen_ctpop_i64(t, t);
|
||||
} else {
|
||||
/* Since all non-x86 hosts have clz(0) == 64, don't fight it. */
|
||||
tcg_gen_neg_i64(t, arg1);
|
||||
tcg_gen_and_i64(t, t, arg1);
|
||||
tcg_gen_clzi_i64(t, t, 64);
|
||||
tcg_gen_xori_i64(t, t, 63);
|
||||
}
|
||||
z = tcg_const_i64(0);
|
||||
tcg_gen_movcond_i64(TCG_COND_EQ, ret, arg1, z, arg2, t);
|
||||
tcg_temp_free_i64(t);
|
||||
tcg_temp_free_i64(z);
|
||||
} else {
|
||||
gen_helper_ctz_i64(ret, arg1, arg2);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2)
|
||||
{
|
||||
if (TCG_TARGET_REG_BITS == 32
|
||||
&& TCG_TARGET_HAS_ctz_i32
|
||||
&& arg2 <= 0xffffffffu) {
|
||||
TCGv_i32 t32 = tcg_const_i32((uint32_t)arg2 - 32);
|
||||
tcg_gen_ctz_i32(t32, TCGV_HIGH(arg1), t32);
|
||||
tcg_gen_addi_i32(t32, t32, 32);
|
||||
tcg_gen_ctz_i32(TCGV_LOW(ret), TCGV_LOW(arg1), t32);
|
||||
tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
|
||||
tcg_temp_free_i32(t32);
|
||||
} else if (!TCG_TARGET_HAS_ctz_i64
|
||||
&& TCG_TARGET_HAS_ctpop_i64
|
||||
&& arg2 == 64) {
|
||||
/* This equivalence has the advantage of not requiring a fixup. */
|
||||
TCGv_i64 t = tcg_temp_new_i64();
|
||||
tcg_gen_subi_i64(t, arg1, 1);
|
||||
tcg_gen_andc_i64(t, t, arg1);
|
||||
tcg_gen_ctpop_i64(ret, t);
|
||||
tcg_temp_free_i64(t);
|
||||
} else {
|
||||
TCGv_i64 t64 = tcg_const_i64(arg2);
|
||||
tcg_gen_ctz_i64(ret, arg1, t64);
|
||||
tcg_temp_free_i64(t64);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_clrsb_i64(TCGv_i64 ret, TCGv_i64 arg)
|
||||
{
|
||||
if (TCG_TARGET_HAS_clz_i64 || TCG_TARGET_HAS_clz_i32) {
|
||||
TCGv_i64 t = tcg_temp_new_i64();
|
||||
tcg_gen_sari_i64(t, arg, 63);
|
||||
tcg_gen_xor_i64(t, t, arg);
|
||||
tcg_gen_clzi_i64(t, t, 64);
|
||||
tcg_gen_subi_i64(ret, t, 1);
|
||||
tcg_temp_free_i64(t);
|
||||
} else {
|
||||
gen_helper_clrsb_i64(ret, arg);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_ctpop_i64(TCGv_i64 ret, TCGv_i64 arg1)
|
||||
{
|
||||
if (TCG_TARGET_HAS_ctpop_i64) {
|
||||
tcg_gen_op2_i64(INDEX_op_ctpop_i64, ret, arg1);
|
||||
} else if (TCG_TARGET_REG_BITS == 32 && TCG_TARGET_HAS_ctpop_i32) {
|
||||
tcg_gen_ctpop_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
|
||||
tcg_gen_ctpop_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
|
||||
tcg_gen_add_i32(TCGV_LOW(ret), TCGV_LOW(ret), TCGV_HIGH(ret));
|
||||
tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
|
||||
} else {
|
||||
gen_helper_ctpop_i64(ret, arg1);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
|
||||
{
|
||||
if (TCG_TARGET_HAS_rot_i64) {
|
||||
|
@ -1593,10 +1997,11 @@ void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2,
|
|||
TCGv_i64 t1;
|
||||
|
||||
tcg_debug_assert(ofs < 64);
|
||||
tcg_debug_assert(len > 0);
|
||||
tcg_debug_assert(len <= 64);
|
||||
tcg_debug_assert(ofs + len <= 64);
|
||||
|
||||
if (ofs == 0 && len == 64) {
|
||||
if (len == 64) {
|
||||
tcg_gen_mov_i64(ret, arg2);
|
||||
return;
|
||||
}
|
||||
|
@ -1635,6 +2040,289 @@ void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2,
|
|||
tcg_temp_free_i64(t1);
|
||||
}
|
||||
|
||||
void tcg_gen_deposit_z_i64(TCGv_i64 ret, TCGv_i64 arg,
|
||||
unsigned int ofs, unsigned int len)
|
||||
{
|
||||
tcg_debug_assert(ofs < 64);
|
||||
tcg_debug_assert(len > 0);
|
||||
tcg_debug_assert(len <= 64);
|
||||
tcg_debug_assert(ofs + len <= 64);
|
||||
|
||||
if (ofs + len == 64) {
|
||||
tcg_gen_shli_i64(ret, arg, ofs);
|
||||
} else if (ofs == 0) {
|
||||
tcg_gen_andi_i64(ret, arg, (1ull << len) - 1);
|
||||
} else if (TCG_TARGET_HAS_deposit_i64
|
||||
&& TCG_TARGET_deposit_i64_valid(ofs, len)) {
|
||||
TCGv_i64 zero = tcg_const_i64(0);
|
||||
tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, zero, arg, ofs, len);
|
||||
tcg_temp_free_i64(zero);
|
||||
} else {
|
||||
if (TCG_TARGET_REG_BITS == 32) {
|
||||
if (ofs >= 32) {
|
||||
tcg_gen_deposit_z_i32(TCGV_HIGH(ret), TCGV_LOW(arg),
|
||||
ofs - 32, len);
|
||||
tcg_gen_movi_i32(TCGV_LOW(ret), 0);
|
||||
return;
|
||||
}
|
||||
if (ofs + len <= 32) {
|
||||
tcg_gen_deposit_z_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len);
|
||||
tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* To help two-operand hosts we prefer to zero-extend first,
|
||||
which allows ARG to stay live. */
|
||||
switch (len) {
|
||||
case 32:
|
||||
if (TCG_TARGET_HAS_ext32u_i64) {
|
||||
tcg_gen_ext32u_i64(ret, arg);
|
||||
tcg_gen_shli_i64(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
if (TCG_TARGET_HAS_ext16u_i64) {
|
||||
tcg_gen_ext16u_i64(ret, arg);
|
||||
tcg_gen_shli_i64(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (TCG_TARGET_HAS_ext8u_i64) {
|
||||
tcg_gen_ext8u_i64(ret, arg);
|
||||
tcg_gen_shli_i64(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Otherwise prefer zero-extension over AND for code size. */
|
||||
switch (ofs + len) {
|
||||
case 32:
|
||||
if (TCG_TARGET_HAS_ext32u_i64) {
|
||||
tcg_gen_shli_i64(ret, arg, ofs);
|
||||
tcg_gen_ext32u_i64(ret, ret);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
if (TCG_TARGET_HAS_ext16u_i64) {
|
||||
tcg_gen_shli_i64(ret, arg, ofs);
|
||||
tcg_gen_ext16u_i64(ret, ret);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (TCG_TARGET_HAS_ext8u_i64) {
|
||||
tcg_gen_shli_i64(ret, arg, ofs);
|
||||
tcg_gen_ext8u_i64(ret, ret);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tcg_gen_andi_i64(ret, arg, (1ull << len) - 1);
|
||||
tcg_gen_shli_i64(ret, ret, ofs);
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg,
|
||||
unsigned int ofs, unsigned int len)
|
||||
{
|
||||
tcg_debug_assert(ofs < 64);
|
||||
tcg_debug_assert(len > 0);
|
||||
tcg_debug_assert(len <= 64);
|
||||
tcg_debug_assert(ofs + len <= 64);
|
||||
|
||||
/* Canonicalize certain special cases, even if extract is supported. */
|
||||
if (ofs + len == 64) {
|
||||
tcg_gen_shri_i64(ret, arg, 64 - len);
|
||||
return;
|
||||
}
|
||||
if (ofs == 0) {
|
||||
tcg_gen_andi_i64(ret, arg, (1ull << len) - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (TCG_TARGET_REG_BITS == 32) {
|
||||
/* Look for a 32-bit extract within one of the two words. */
|
||||
if (ofs >= 32) {
|
||||
tcg_gen_extract_i32(TCGV_LOW(ret), TCGV_HIGH(arg), ofs - 32, len);
|
||||
tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
|
||||
return;
|
||||
}
|
||||
if (ofs + len <= 32) {
|
||||
tcg_gen_extract_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len);
|
||||
tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
|
||||
return;
|
||||
}
|
||||
/* The field is split across two words. One double-word
|
||||
shift is better than two double-word shifts. */
|
||||
goto do_shift_and;
|
||||
}
|
||||
|
||||
if (TCG_TARGET_HAS_extract_i64
|
||||
&& TCG_TARGET_extract_i64_valid(ofs, len)) {
|
||||
tcg_gen_op4ii_i64(INDEX_op_extract_i64, ret, arg, ofs, len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Assume that zero-extension, if available, is cheaper than a shift. */
|
||||
switch (ofs + len) {
|
||||
case 32:
|
||||
if (TCG_TARGET_HAS_ext32u_i64) {
|
||||
tcg_gen_ext32u_i64(ret, arg);
|
||||
tcg_gen_shri_i64(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
if (TCG_TARGET_HAS_ext16u_i64) {
|
||||
tcg_gen_ext16u_i64(ret, arg);
|
||||
tcg_gen_shri_i64(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (TCG_TARGET_HAS_ext8u_i64) {
|
||||
tcg_gen_ext8u_i64(ret, arg);
|
||||
tcg_gen_shri_i64(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* ??? Ideally we'd know what values are available for immediate AND.
|
||||
Assume that 8 bits are available, plus the special cases of 16 and 32,
|
||||
so that we get ext8u, ext16u, and ext32u. */
|
||||
switch (len) {
|
||||
case 1 ... 8: case 16: case 32:
|
||||
do_shift_and:
|
||||
tcg_gen_shri_i64(ret, arg, ofs);
|
||||
tcg_gen_andi_i64(ret, ret, (1ull << len) - 1);
|
||||
break;
|
||||
default:
|
||||
tcg_gen_shli_i64(ret, arg, 64 - len - ofs);
|
||||
tcg_gen_shri_i64(ret, ret, 64 - len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void tcg_gen_sextract_i64(TCGv_i64 ret, TCGv_i64 arg,
|
||||
unsigned int ofs, unsigned int len)
|
||||
{
|
||||
tcg_debug_assert(ofs < 64);
|
||||
tcg_debug_assert(len > 0);
|
||||
tcg_debug_assert(len <= 64);
|
||||
tcg_debug_assert(ofs + len <= 64);
|
||||
|
||||
/* Canonicalize certain special cases, even if sextract is supported. */
|
||||
if (ofs + len == 64) {
|
||||
tcg_gen_sari_i64(ret, arg, 64 - len);
|
||||
return;
|
||||
}
|
||||
if (ofs == 0) {
|
||||
switch (len) {
|
||||
case 32:
|
||||
tcg_gen_ext32s_i64(ret, arg);
|
||||
return;
|
||||
case 16:
|
||||
tcg_gen_ext16s_i64(ret, arg);
|
||||
return;
|
||||
case 8:
|
||||
tcg_gen_ext8s_i64(ret, arg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (TCG_TARGET_REG_BITS == 32) {
|
||||
/* Look for a 32-bit extract within one of the two words. */
|
||||
if (ofs >= 32) {
|
||||
tcg_gen_sextract_i32(TCGV_LOW(ret), TCGV_HIGH(arg), ofs - 32, len);
|
||||
} else if (ofs + len <= 32) {
|
||||
tcg_gen_sextract_i32(TCGV_LOW(ret), TCGV_LOW(arg), ofs, len);
|
||||
} else if (ofs == 0) {
|
||||
tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
|
||||
tcg_gen_sextract_i32(TCGV_HIGH(ret), TCGV_HIGH(arg), 0, len - 32);
|
||||
return;
|
||||
} else if (len > 32) {
|
||||
TCGv_i32 t = tcg_temp_new_i32();
|
||||
/* Extract the bits for the high word normally. */
|
||||
tcg_gen_sextract_i32(t, TCGV_HIGH(arg), ofs + 32, len - 32);
|
||||
/* Shift the field down for the low part. */
|
||||
tcg_gen_shri_i64(ret, arg, ofs);
|
||||
/* Overwrite the shift into the high part. */
|
||||
tcg_gen_mov_i32(TCGV_HIGH(ret), t);
|
||||
tcg_temp_free_i32(t);
|
||||
return;
|
||||
} else {
|
||||
/* Shift the field down for the low part, such that the
|
||||
field sits at the MSB. */
|
||||
tcg_gen_shri_i64(ret, arg, ofs + len - 32);
|
||||
/* Shift the field down from the MSB, sign extending. */
|
||||
tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_LOW(ret), 32 - len);
|
||||
}
|
||||
/* Sign-extend the field from 32 bits. */
|
||||
tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
|
||||
return;
|
||||
}
|
||||
|
||||
if (TCG_TARGET_HAS_sextract_i64
|
||||
&& TCG_TARGET_extract_i64_valid(ofs, len)) {
|
||||
tcg_gen_op4ii_i64(INDEX_op_sextract_i64, ret, arg, ofs, len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Assume that sign-extension, if available, is cheaper than a shift. */
|
||||
switch (ofs + len) {
|
||||
case 32:
|
||||
if (TCG_TARGET_HAS_ext32s_i64) {
|
||||
tcg_gen_ext32s_i64(ret, arg);
|
||||
tcg_gen_sari_i64(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
if (TCG_TARGET_HAS_ext16s_i64) {
|
||||
tcg_gen_ext16s_i64(ret, arg);
|
||||
tcg_gen_sari_i64(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (TCG_TARGET_HAS_ext8s_i64) {
|
||||
tcg_gen_ext8s_i64(ret, arg);
|
||||
tcg_gen_sari_i64(ret, ret, ofs);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (len) {
|
||||
case 32:
|
||||
if (TCG_TARGET_HAS_ext32s_i64) {
|
||||
tcg_gen_shri_i64(ret, arg, ofs);
|
||||
tcg_gen_ext32s_i64(ret, ret);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
if (TCG_TARGET_HAS_ext16s_i64) {
|
||||
tcg_gen_shri_i64(ret, arg, ofs);
|
||||
tcg_gen_ext16s_i64(ret, ret);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (TCG_TARGET_HAS_ext8s_i64) {
|
||||
tcg_gen_shri_i64(ret, arg, ofs);
|
||||
tcg_gen_ext8s_i64(ret, ret);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tcg_gen_shli_i64(ret, arg, 64 - len - ofs);
|
||||
tcg_gen_sari_i64(ret, ret, 64 - len);
|
||||
}
|
||||
|
||||
void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 c1,
|
||||
TCGv_i64 c2, TCGv_i64 v1, TCGv_i64 v2)
|
||||
{
|
||||
|
|
42
tcg/tcg-op.h
42
tcg/tcg-op.h
|
@ -286,12 +286,24 @@ void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2);
|
|||
void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2);
|
||||
void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2);
|
||||
void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2);
|
||||
void tcg_gen_clz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2);
|
||||
void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2);
|
||||
void tcg_gen_clzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2);
|
||||
void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2);
|
||||
void tcg_gen_clrsb_i32(TCGv_i32 ret, TCGv_i32 arg);
|
||||
void tcg_gen_ctpop_i32(TCGv_i32 a1, TCGv_i32 a2);
|
||||
void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2);
|
||||
void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2);
|
||||
void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2);
|
||||
void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, unsigned arg2);
|
||||
void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2,
|
||||
unsigned int ofs, unsigned int len);
|
||||
void tcg_gen_deposit_z_i32(TCGv_i32 ret, TCGv_i32 arg,
|
||||
unsigned int ofs, unsigned int len);
|
||||
void tcg_gen_extract_i32(TCGv_i32 ret, TCGv_i32 arg,
|
||||
unsigned int ofs, unsigned int len);
|
||||
void tcg_gen_sextract_i32(TCGv_i32 ret, TCGv_i32 arg,
|
||||
unsigned int ofs, unsigned int len);
|
||||
void tcg_gen_brcond_i32(TCGCond cond, TCGv_i32 arg1, TCGv_i32 arg2, TCGLabel *);
|
||||
void tcg_gen_brcondi_i32(TCGCond cond, TCGv_i32 arg1, int32_t arg2, TCGLabel *);
|
||||
void tcg_gen_setcond_i32(TCGCond cond, TCGv_i32 ret,
|
||||
|
@ -463,12 +475,24 @@ void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2);
|
|||
void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2);
|
||||
void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2);
|
||||
void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2);
|
||||
void tcg_gen_clz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2);
|
||||
void tcg_gen_ctz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2);
|
||||
void tcg_gen_clzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2);
|
||||
void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2);
|
||||
void tcg_gen_clrsb_i64(TCGv_i64 ret, TCGv_i64 arg);
|
||||
void tcg_gen_ctpop_i64(TCGv_i64 a1, TCGv_i64 a2);
|
||||
void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2);
|
||||
void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2);
|
||||
void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2);
|
||||
void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, unsigned arg2);
|
||||
void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2,
|
||||
unsigned int ofs, unsigned int len);
|
||||
void tcg_gen_deposit_z_i64(TCGv_i64 ret, TCGv_i64 arg,
|
||||
unsigned int ofs, unsigned int len);
|
||||
void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg,
|
||||
unsigned int ofs, unsigned int len);
|
||||
void tcg_gen_sextract_i64(TCGv_i64 ret, TCGv_i64 arg,
|
||||
unsigned int ofs, unsigned int len);
|
||||
void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1, TCGv_i64 arg2, TCGLabel *);
|
||||
void tcg_gen_brcondi_i64(TCGCond cond, TCGv_i64 arg1, int64_t arg2, TCGLabel *);
|
||||
void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret,
|
||||
|
@ -946,11 +970,20 @@ void tcg_gen_atomic_xor_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
|
|||
#define tcg_gen_nand_tl tcg_gen_nand_i64
|
||||
#define tcg_gen_nor_tl tcg_gen_nor_i64
|
||||
#define tcg_gen_orc_tl tcg_gen_orc_i64
|
||||
#define tcg_gen_clz_tl tcg_gen_clz_i64
|
||||
#define tcg_gen_ctz_tl tcg_gen_ctz_i64
|
||||
#define tcg_gen_clzi_tl tcg_gen_clzi_i64
|
||||
#define tcg_gen_ctzi_tl tcg_gen_ctzi_i64
|
||||
#define tcg_gen_clrsb_tl tcg_gen_clrsb_i64
|
||||
#define tcg_gen_ctpop_tl tcg_gen_ctpop_i64
|
||||
#define tcg_gen_rotl_tl tcg_gen_rotl_i64
|
||||
#define tcg_gen_rotli_tl tcg_gen_rotli_i64
|
||||
#define tcg_gen_rotr_tl tcg_gen_rotr_i64
|
||||
#define tcg_gen_rotri_tl tcg_gen_rotri_i64
|
||||
#define tcg_gen_deposit_tl tcg_gen_deposit_i64
|
||||
#define tcg_gen_deposit_z_tl tcg_gen_deposit_z_i64
|
||||
#define tcg_gen_extract_tl tcg_gen_extract_i64
|
||||
#define tcg_gen_sextract_tl tcg_gen_sextract_i64
|
||||
#define tcg_const_tl tcg_const_i64
|
||||
#define tcg_const_local_tl tcg_const_local_i64
|
||||
#define tcg_gen_movcond_tl tcg_gen_movcond_i64
|
||||
|
@ -1034,11 +1067,20 @@ void tcg_gen_atomic_xor_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
|
|||
#define tcg_gen_nand_tl tcg_gen_nand_i32
|
||||
#define tcg_gen_nor_tl tcg_gen_nor_i32
|
||||
#define tcg_gen_orc_tl tcg_gen_orc_i32
|
||||
#define tcg_gen_clz_tl tcg_gen_clz_i32
|
||||
#define tcg_gen_ctz_tl tcg_gen_ctz_i32
|
||||
#define tcg_gen_clzi_tl tcg_gen_clzi_i32
|
||||
#define tcg_gen_ctzi_tl tcg_gen_ctzi_i32
|
||||
#define tcg_gen_clrsb_tl tcg_gen_clrsb_i32
|
||||
#define tcg_gen_ctpop_tl tcg_gen_ctpop_i32
|
||||
#define tcg_gen_rotl_tl tcg_gen_rotl_i32
|
||||
#define tcg_gen_rotli_tl tcg_gen_rotli_i32
|
||||
#define tcg_gen_rotr_tl tcg_gen_rotr_i32
|
||||
#define tcg_gen_rotri_tl tcg_gen_rotri_i32
|
||||
#define tcg_gen_deposit_tl tcg_gen_deposit_i32
|
||||
#define tcg_gen_deposit_z_tl tcg_gen_deposit_z_i32
|
||||
#define tcg_gen_extract_tl tcg_gen_extract_i32
|
||||
#define tcg_gen_sextract_tl tcg_gen_sextract_i32
|
||||
#define tcg_const_tl tcg_const_i32
|
||||
#define tcg_const_local_tl tcg_const_local_i32
|
||||
#define tcg_gen_movcond_tl tcg_gen_movcond_i32
|
||||
|
|
|
@ -77,6 +77,8 @@ DEF(sar_i32, 1, 2, 0, 0)
|
|||
DEF(rotl_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_rot_i32))
|
||||
DEF(rotr_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_rot_i32))
|
||||
DEF(deposit_i32, 1, 2, 2, IMPL(TCG_TARGET_HAS_deposit_i32))
|
||||
DEF(extract_i32, 1, 1, 2, IMPL(TCG_TARGET_HAS_extract_i32))
|
||||
DEF(sextract_i32, 1, 1, 2, IMPL(TCG_TARGET_HAS_sextract_i32))
|
||||
|
||||
DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END)
|
||||
|
||||
|
@ -102,6 +104,9 @@ DEF(orc_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_orc_i32))
|
|||
DEF(eqv_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_eqv_i32))
|
||||
DEF(nand_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_nand_i32))
|
||||
DEF(nor_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_nor_i32))
|
||||
DEF(clz_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_clz_i32))
|
||||
DEF(ctz_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_ctz_i32))
|
||||
DEF(ctpop_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_ctpop_i32))
|
||||
|
||||
DEF(mov_i64, 1, 1, 0, TCG_OPF_64BIT | TCG_OPF_NOT_PRESENT)
|
||||
DEF(movi_i64, 1, 0, 1, TCG_OPF_64BIT | TCG_OPF_NOT_PRESENT)
|
||||
|
@ -139,6 +144,8 @@ DEF(sar_i64, 1, 2, 0, IMPL64)
|
|||
DEF(rotl_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rot_i64))
|
||||
DEF(rotr_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rot_i64))
|
||||
DEF(deposit_i64, 1, 2, 2, IMPL64 | IMPL(TCG_TARGET_HAS_deposit_i64))
|
||||
DEF(extract_i64, 1, 1, 2, IMPL64 | IMPL(TCG_TARGET_HAS_extract_i64))
|
||||
DEF(sextract_i64, 1, 1, 2, IMPL64 | IMPL(TCG_TARGET_HAS_sextract_i64))
|
||||
|
||||
/* size changing ops */
|
||||
DEF(ext_i32_i64, 1, 1, 0, IMPL64)
|
||||
|
@ -167,6 +174,9 @@ DEF(orc_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_orc_i64))
|
|||
DEF(eqv_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_eqv_i64))
|
||||
DEF(nand_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_nand_i64))
|
||||
DEF(nor_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_nor_i64))
|
||||
DEF(clz_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_clz_i64))
|
||||
DEF(ctz_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ctz_i64))
|
||||
DEF(ctpop_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ctpop_i64))
|
||||
|
||||
DEF(add2_i64, 2, 4, 0, IMPL64 | IMPL(TCG_TARGET_HAS_add2_i64))
|
||||
DEF(sub2_i64, 2, 4, 0, IMPL64 | IMPL(TCG_TARGET_HAS_sub2_i64))
|
||||
|
|
|
@ -15,6 +15,15 @@ DEF_HELPER_FLAGS_2(sar_i64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
|
|||
DEF_HELPER_FLAGS_2(mulsh_i64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
|
||||
DEF_HELPER_FLAGS_2(muluh_i64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
|
||||
DEF_HELPER_FLAGS_2(clz_i32, TCG_CALL_NO_RWG_SE, i32, i32, i32)
|
||||
DEF_HELPER_FLAGS_2(ctz_i32, TCG_CALL_NO_RWG_SE, i32, i32, i32)
|
||||
DEF_HELPER_FLAGS_2(clz_i64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(ctz_i64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(clrsb_i32, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(clrsb_i64, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(ctpop_i32, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(ctpop_i64, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
|
||||
DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env)
|
||||
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
|
|
147
tcg/tcg.c
147
tcg/tcg.c
|
@ -62,6 +62,7 @@
|
|||
/* Forward declarations for functions declared in tcg-target.inc.c and
|
||||
used here. */
|
||||
static void tcg_target_init(TCGContext *s);
|
||||
static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
|
||||
static void tcg_target_qemu_prologue(TCGContext *s);
|
||||
static void patch_reloc(tcg_insn_unit *code_ptr, int type,
|
||||
intptr_t value, intptr_t addend);
|
||||
|
@ -95,7 +96,8 @@ static void tcg_register_jit_int(void *buf, size_t size,
|
|||
__attribute__((unused));
|
||||
|
||||
/* Forward declarations for functions declared and used in tcg-target.inc.c. */
|
||||
static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str);
|
||||
static const char *target_parse_constraint(TCGArgConstraint *ct,
|
||||
const char *ct_str, TCGType type);
|
||||
static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
|
||||
intptr_t arg2);
|
||||
static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
|
||||
|
@ -319,6 +321,7 @@ static const TCGHelperInfo all_helpers[] = {
|
|||
};
|
||||
|
||||
static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
|
||||
static void process_op_defs(TCGContext *s);
|
||||
|
||||
void tcg_context_init(TCGContext *s)
|
||||
{
|
||||
|
@ -362,6 +365,7 @@ void tcg_context_init(TCGContext *s)
|
|||
}
|
||||
|
||||
tcg_target_init(s);
|
||||
process_op_defs(s);
|
||||
|
||||
/* Reverse the order of the saved registers, assuming they're all at
|
||||
the start of tcg_target_reg_alloc_order. */
|
||||
|
@ -1221,59 +1225,68 @@ static void sort_constraints(TCGOpDef *def, int start, int n)
|
|||
}
|
||||
}
|
||||
|
||||
void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
|
||||
static void process_op_defs(TCGContext *s)
|
||||
{
|
||||
TCGOpcode op;
|
||||
TCGOpDef *def;
|
||||
const char *ct_str;
|
||||
|
||||
for (op = 0; op < NB_OPS; op++) {
|
||||
TCGOpDef *def = &tcg_op_defs[op];
|
||||
const TCGTargetOpDef *tdefs;
|
||||
TCGType type;
|
||||
int i, nb_args;
|
||||
|
||||
for(;;) {
|
||||
if (tdefs->op == (TCGOpcode)-1)
|
||||
break;
|
||||
op = tdefs->op;
|
||||
tcg_debug_assert((unsigned)op < NB_OPS);
|
||||
def = &tcg_op_defs[op];
|
||||
#if defined(CONFIG_DEBUG_TCG)
|
||||
/* Duplicate entry in op definitions? */
|
||||
tcg_debug_assert(!def->used);
|
||||
def->used = 1;
|
||||
#endif
|
||||
if (def->flags & TCG_OPF_NOT_PRESENT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nb_args = def->nb_iargs + def->nb_oargs;
|
||||
if (nb_args == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tdefs = tcg_target_op_def(op);
|
||||
/* Missing TCGTargetOpDef entry. */
|
||||
tcg_debug_assert(tdefs != NULL);
|
||||
|
||||
type = (def->flags & TCG_OPF_64BIT ? TCG_TYPE_I64 : TCG_TYPE_I32);
|
||||
for (i = 0; i < nb_args; i++) {
|
||||
ct_str = tdefs->args_ct_str[i];
|
||||
/* Incomplete TCGTargetOpDef entry? */
|
||||
const char *ct_str = tdefs->args_ct_str[i];
|
||||
/* Incomplete TCGTargetOpDef entry. */
|
||||
tcg_debug_assert(ct_str != NULL);
|
||||
|
||||
tcg_regset_clear(def->args_ct[i].u.regs);
|
||||
def->args_ct[i].ct = 0;
|
||||
if (ct_str[0] >= '0' && ct_str[0] <= '9') {
|
||||
int oarg;
|
||||
oarg = ct_str[0] - '0';
|
||||
while (*ct_str != '\0') {
|
||||
switch(*ct_str) {
|
||||
case '0' ... '9':
|
||||
{
|
||||
int oarg = *ct_str - '0';
|
||||
tcg_debug_assert(ct_str == tdefs->args_ct_str[i]);
|
||||
tcg_debug_assert(oarg < def->nb_oargs);
|
||||
tcg_debug_assert(def->args_ct[oarg].ct & TCG_CT_REG);
|
||||
/* TCG_CT_ALIAS is for the output arguments. The input
|
||||
argument is tagged with TCG_CT_IALIAS. */
|
||||
/* TCG_CT_ALIAS is for the output arguments.
|
||||
The input is tagged with TCG_CT_IALIAS. */
|
||||
def->args_ct[i] = def->args_ct[oarg];
|
||||
def->args_ct[oarg].ct = TCG_CT_ALIAS;
|
||||
def->args_ct[oarg].ct |= TCG_CT_ALIAS;
|
||||
def->args_ct[oarg].alias_index = i;
|
||||
def->args_ct[i].ct |= TCG_CT_IALIAS;
|
||||
def->args_ct[i].alias_index = oarg;
|
||||
} else {
|
||||
for(;;) {
|
||||
if (*ct_str == '\0')
|
||||
}
|
||||
ct_str++;
|
||||
break;
|
||||
case '&':
|
||||
def->args_ct[i].ct |= TCG_CT_NEWREG;
|
||||
ct_str++;
|
||||
break;
|
||||
switch(*ct_str) {
|
||||
case 'i':
|
||||
def->args_ct[i].ct |= TCG_CT_CONST;
|
||||
ct_str++;
|
||||
break;
|
||||
default:
|
||||
if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
|
||||
fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
|
||||
ct_str, i, def->name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
ct_str = target_parse_constraint(&def->args_ct[i],
|
||||
ct_str, type);
|
||||
/* Typo in TCGTargetOpDef constraint. */
|
||||
tcg_debug_assert(ct_str != NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1284,42 +1297,7 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
|
|||
/* sort the constraints (XXX: this is just an heuristic) */
|
||||
sort_constraints(def, 0, def->nb_oargs);
|
||||
sort_constraints(def, def->nb_oargs, def->nb_iargs);
|
||||
|
||||
#if 0
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("%s: sorted=", def->name);
|
||||
for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
|
||||
printf(" %d", def->sorted_args[i]);
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
tdefs++;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DEBUG_TCG)
|
||||
i = 0;
|
||||
for (op = 0; op < tcg_op_defs_max; op++) {
|
||||
const TCGOpDef *def = &tcg_op_defs[op];
|
||||
if (def->flags & TCG_OPF_NOT_PRESENT) {
|
||||
/* Wrong entry in op definitions? */
|
||||
if (def->used) {
|
||||
fprintf(stderr, "Invalid op definition for %s\n", def->name);
|
||||
i = 1;
|
||||
}
|
||||
} else {
|
||||
/* Missing entry in op definitions? */
|
||||
if (!def->used) {
|
||||
fprintf(stderr, "Missing op definition for %s\n", def->name);
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == 1) {
|
||||
tcg_abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void tcg_op_remove(TCGContext *s, TCGOp *op)
|
||||
|
@ -2208,7 +2186,8 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
|||
const TCGOpDef *def, TCGOpcode opc,
|
||||
const TCGArg *args, TCGLifeData arg_life)
|
||||
{
|
||||
TCGRegSet allocated_regs;
|
||||
TCGRegSet i_allocated_regs;
|
||||
TCGRegSet o_allocated_regs;
|
||||
int i, k, nb_iargs, nb_oargs;
|
||||
TCGReg reg;
|
||||
TCGArg arg;
|
||||
|
@ -2225,8 +2204,10 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
|||
args + nb_oargs + nb_iargs,
|
||||
sizeof(TCGArg) * def->nb_cargs);
|
||||
|
||||
tcg_regset_set(i_allocated_regs, s->reserved_regs);
|
||||
tcg_regset_set(o_allocated_regs, s->reserved_regs);
|
||||
|
||||
/* satisfy input constraints */
|
||||
tcg_regset_set(allocated_regs, s->reserved_regs);
|
||||
for(k = 0; k < nb_iargs; k++) {
|
||||
i = def->sorted_args[nb_oargs + k];
|
||||
arg = args[i];
|
||||
|
@ -2241,7 +2222,7 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
|||
goto iarg_end;
|
||||
}
|
||||
|
||||
temp_load(s, ts, arg_ct->u.regs, allocated_regs);
|
||||
temp_load(s, ts, arg_ct->u.regs, i_allocated_regs);
|
||||
|
||||
if (arg_ct->ct & TCG_CT_IALIAS) {
|
||||
if (ts->fixed_reg) {
|
||||
|
@ -2275,13 +2256,13 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
|||
allocate_in_reg:
|
||||
/* allocate a new register matching the constraint
|
||||
and move the temporary register into it */
|
||||
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs,
|
||||
reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs,
|
||||
ts->indirect_base);
|
||||
tcg_out_mov(s, ts->type, reg, ts->reg);
|
||||
}
|
||||
new_args[i] = reg;
|
||||
const_args[i] = 0;
|
||||
tcg_regset_set_reg(allocated_regs, reg);
|
||||
tcg_regset_set_reg(i_allocated_regs, reg);
|
||||
iarg_end: ;
|
||||
}
|
||||
|
||||
|
@ -2293,31 +2274,35 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
|||
}
|
||||
|
||||
if (def->flags & TCG_OPF_BB_END) {
|
||||
tcg_reg_alloc_bb_end(s, allocated_regs);
|
||||
tcg_reg_alloc_bb_end(s, i_allocated_regs);
|
||||
} else {
|
||||
if (def->flags & TCG_OPF_CALL_CLOBBER) {
|
||||
/* XXX: permit generic clobber register list ? */
|
||||
for (i = 0; i < TCG_TARGET_NB_REGS; i++) {
|
||||
if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) {
|
||||
tcg_reg_free(s, i, allocated_regs);
|
||||
tcg_reg_free(s, i, i_allocated_regs);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (def->flags & TCG_OPF_SIDE_EFFECTS) {
|
||||
/* sync globals if the op has side effects and might trigger
|
||||
an exception. */
|
||||
sync_globals(s, allocated_regs);
|
||||
sync_globals(s, i_allocated_regs);
|
||||
}
|
||||
|
||||
/* satisfy the output constraints */
|
||||
tcg_regset_set(allocated_regs, s->reserved_regs);
|
||||
for(k = 0; k < nb_oargs; k++) {
|
||||
i = def->sorted_args[k];
|
||||
arg = args[i];
|
||||
arg_ct = &def->args_ct[i];
|
||||
ts = &s->temps[arg];
|
||||
if (arg_ct->ct & TCG_CT_ALIAS) {
|
||||
if ((arg_ct->ct & TCG_CT_ALIAS)
|
||||
&& !const_args[arg_ct->alias_index]) {
|
||||
reg = new_args[arg_ct->alias_index];
|
||||
} else if (arg_ct->ct & TCG_CT_NEWREG) {
|
||||
reg = tcg_reg_alloc(s, arg_ct->u.regs,
|
||||
i_allocated_regs | o_allocated_regs,
|
||||
ts->indirect_base);
|
||||
} else {
|
||||
/* if fixed register, we try to use it */
|
||||
reg = ts->reg;
|
||||
|
@ -2325,10 +2310,10 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
|||
tcg_regset_test_reg(arg_ct->u.regs, reg)) {
|
||||
goto oarg_end;
|
||||
}
|
||||
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs,
|
||||
reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs,
|
||||
ts->indirect_base);
|
||||
}
|
||||
tcg_regset_set_reg(allocated_regs, reg);
|
||||
tcg_regset_set_reg(o_allocated_regs, reg);
|
||||
/* if a fixed register is used, then a move will be done afterwards */
|
||||
if (!ts->fixed_reg) {
|
||||
if (ts->val_type == TEMP_VAL_REG) {
|
||||
|
@ -2357,7 +2342,7 @@ static void tcg_reg_alloc_op(TCGContext *s,
|
|||
tcg_out_mov(s, ts->type, ts->reg, reg);
|
||||
}
|
||||
if (NEED_SYNC_ARG(i)) {
|
||||
temp_sync(s, ts, allocated_regs, IS_DEAD_ARG(i));
|
||||
temp_sync(s, ts, o_allocated_regs, IS_DEAD_ARG(i));
|
||||
} else if (IS_DEAD_ARG(i)) {
|
||||
temp_dead(s, ts);
|
||||
}
|
||||
|
|
14
tcg/tcg.h
14
tcg/tcg.h
|
@ -111,7 +111,12 @@ typedef uint64_t TCGRegSet;
|
|||
#define TCG_TARGET_HAS_eqv_i64 0
|
||||
#define TCG_TARGET_HAS_nand_i64 0
|
||||
#define TCG_TARGET_HAS_nor_i64 0
|
||||
#define TCG_TARGET_HAS_clz_i64 0
|
||||
#define TCG_TARGET_HAS_ctz_i64 0
|
||||
#define TCG_TARGET_HAS_ctpop_i64 0
|
||||
#define TCG_TARGET_HAS_deposit_i64 0
|
||||
#define TCG_TARGET_HAS_extract_i64 0
|
||||
#define TCG_TARGET_HAS_sextract_i64 0
|
||||
#define TCG_TARGET_HAS_movcond_i64 0
|
||||
#define TCG_TARGET_HAS_add2_i64 0
|
||||
#define TCG_TARGET_HAS_sub2_i64 0
|
||||
|
@ -130,6 +135,12 @@ typedef uint64_t TCGRegSet;
|
|||
#ifndef TCG_TARGET_deposit_i64_valid
|
||||
#define TCG_TARGET_deposit_i64_valid(ofs, len) 1
|
||||
#endif
|
||||
#ifndef TCG_TARGET_extract_i32_valid
|
||||
#define TCG_TARGET_extract_i32_valid(ofs, len) 1
|
||||
#endif
|
||||
#ifndef TCG_TARGET_extract_i64_valid
|
||||
#define TCG_TARGET_extract_i64_valid(ofs, len) 1
|
||||
#endif
|
||||
|
||||
/* Only one of DIV or DIV2 should be defined. */
|
||||
#if defined(TCG_TARGET_HAS_div_i32)
|
||||
|
@ -843,6 +854,7 @@ void tcg_dump_op_count(FILE *f, fprintf_function cpu_fprintf);
|
|||
|
||||
#define TCG_CT_ALIAS 0x80
|
||||
#define TCG_CT_IALIAS 0x40
|
||||
#define TCG_CT_NEWREG 0x20 /* output requires a new register */
|
||||
#define TCG_CT_REG 0x01
|
||||
#define TCG_CT_CONST 0x02 /* any constant of register size */
|
||||
|
||||
|
@ -897,8 +909,6 @@ do {\
|
|||
abort();\
|
||||
} while (0)
|
||||
|
||||
void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs);
|
||||
|
||||
#if UINTPTR_MAX == UINT32_MAX
|
||||
#define TCGV_NAT_TO_PTR(n) MAKE_TCGV_PTR(GET_TCGV_I32(n))
|
||||
#define TCGV_PTR_TO_NAT(n) MAKE_TCGV_I32(GET_TCGV_PTR(n))
|
||||
|
|
|
@ -69,9 +69,14 @@
|
|||
#define TCG_TARGET_HAS_ext16u_i32 1
|
||||
#define TCG_TARGET_HAS_andc_i32 0
|
||||
#define TCG_TARGET_HAS_deposit_i32 1
|
||||
#define TCG_TARGET_HAS_extract_i32 0
|
||||
#define TCG_TARGET_HAS_sextract_i32 0
|
||||
#define TCG_TARGET_HAS_eqv_i32 0
|
||||
#define TCG_TARGET_HAS_nand_i32 0
|
||||
#define TCG_TARGET_HAS_nor_i32 0
|
||||
#define TCG_TARGET_HAS_clz_i32 0
|
||||
#define TCG_TARGET_HAS_ctz_i32 0
|
||||
#define TCG_TARGET_HAS_ctpop_i32 0
|
||||
#define TCG_TARGET_HAS_neg_i32 1
|
||||
#define TCG_TARGET_HAS_not_i32 1
|
||||
#define TCG_TARGET_HAS_orc_i32 0
|
||||
|
@ -88,6 +93,8 @@
|
|||
#define TCG_TARGET_HAS_bswap32_i64 1
|
||||
#define TCG_TARGET_HAS_bswap64_i64 1
|
||||
#define TCG_TARGET_HAS_deposit_i64 1
|
||||
#define TCG_TARGET_HAS_extract_i64 0
|
||||
#define TCG_TARGET_HAS_sextract_i64 0
|
||||
#define TCG_TARGET_HAS_div_i64 0
|
||||
#define TCG_TARGET_HAS_rem_i64 0
|
||||
#define TCG_TARGET_HAS_ext8s_i64 1
|
||||
|
@ -100,6 +107,9 @@
|
|||
#define TCG_TARGET_HAS_eqv_i64 0
|
||||
#define TCG_TARGET_HAS_nand_i64 0
|
||||
#define TCG_TARGET_HAS_nor_i64 0
|
||||
#define TCG_TARGET_HAS_clz_i64 0
|
||||
#define TCG_TARGET_HAS_ctz_i64 0
|
||||
#define TCG_TARGET_HAS_ctpop_i64 0
|
||||
#define TCG_TARGET_HAS_neg_i64 1
|
||||
#define TCG_TARGET_HAS_not_i64 1
|
||||
#define TCG_TARGET_HAS_orc_i64 0
|
||||
|
|
|
@ -259,6 +259,18 @@ static const TCGTargetOpDef tcg_target_op_defs[] = {
|
|||
{ -1 },
|
||||
};
|
||||
|
||||
static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
||||
{
|
||||
int i, n = ARRAY_SIZE(tcg_target_op_defs);
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (tcg_target_op_defs[i].op == op) {
|
||||
return &tcg_target_op_defs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const int tcg_target_reg_alloc_order[] = {
|
||||
TCG_REG_R0,
|
||||
TCG_REG_R1,
|
||||
|
@ -372,10 +384,10 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
|
|||
}
|
||||
|
||||
/* Parse target specific constraints. */
|
||||
static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
||||
static const char *target_parse_constraint(TCGArgConstraint *ct,
|
||||
const char *ct_str, TCGType type)
|
||||
{
|
||||
const char *ct_str = *pct_str;
|
||||
switch (ct_str[0]) {
|
||||
switch (*ct_str++) {
|
||||
case 'r':
|
||||
case 'L': /* qemu_ld constraint */
|
||||
case 'S': /* qemu_st constraint */
|
||||
|
@ -383,11 +395,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
|||
tcg_regset_set32(ct->u.regs, 0, BIT(TCG_TARGET_NB_REGS) - 1);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
ct_str++;
|
||||
*pct_str = ct_str;
|
||||
return 0;
|
||||
return ct_str;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DEBUG_TCG_INTERPRETER)
|
||||
|
@ -875,7 +885,6 @@ static void tcg_target_init(TCGContext *s)
|
|||
|
||||
tcg_regset_clear(s->reserved_regs);
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
|
||||
tcg_add_target_add_op_defs(tcg_target_op_defs);
|
||||
|
||||
/* We use negative offsets from "sp" so that we can distinguish
|
||||
stores that might pretend to be call arguments. */
|
||||
|
|
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
|
@ -13,6 +13,7 @@ rcutorture
|
|||
test-aio
|
||||
test-base64
|
||||
test-bitops
|
||||
test-bitcnt
|
||||
test-blockjob
|
||||
test-blockjob-txn
|
||||
test-bufferiszero
|
||||
|
|
|
@ -81,6 +81,7 @@ gcov-files-test-qht-y = util/qht.c
|
|||
check-unit-y += tests/test-qht-par$(EXESUF)
|
||||
gcov-files-test-qht-par-y = util/qht.c
|
||||
check-unit-y += tests/test-bitops$(EXESUF)
|
||||
check-unit-y += tests/test-bitcnt$(EXESUF)
|
||||
check-unit-$(CONFIG_HAS_GLIB_SUBPROCESS_TESTS) += tests/test-qdev-global-props$(EXESUF)
|
||||
check-unit-y += tests/check-qom-interface$(EXESUF)
|
||||
gcov-files-check-qom-interface-y = qom/object.c
|
||||
|
@ -571,6 +572,7 @@ tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y)
|
|||
|
||||
tests/test-mul64$(EXESUF): tests/test-mul64.o $(test-util-obj-y)
|
||||
tests/test-bitops$(EXESUF): tests/test-bitops.o $(test-util-obj-y)
|
||||
tests/test-bitcnt$(EXESUF): tests/test-bitcnt.o $(test-util-obj-y)
|
||||
tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o $(test-crypto-obj-y)
|
||||
tests/test-crypto-hmac$(EXESUF): tests/test-crypto-hmac.o $(test-crypto-obj-y)
|
||||
tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.o $(test-crypto-obj-y)
|
||||
|
|
140
tests/test-bitcnt.c
Normal file
140
tests/test-bitcnt.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Test bit count routines
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/host-utils.h"
|
||||
|
||||
struct bitcnt_test_data {
|
||||
/* value to count */
|
||||
union {
|
||||
uint8_t w8;
|
||||
uint16_t w16;
|
||||
uint32_t w32;
|
||||
uint64_t w64;
|
||||
} value;
|
||||
/* expected result */
|
||||
int popct;
|
||||
};
|
||||
|
||||
struct bitcnt_test_data eight_bit_data[] = {
|
||||
{ { .w8 = 0x00 }, .popct=0 },
|
||||
{ { .w8 = 0x01 }, .popct=1 },
|
||||
{ { .w8 = 0x03 }, .popct=2 },
|
||||
{ { .w8 = 0x04 }, .popct=1 },
|
||||
{ { .w8 = 0x0f }, .popct=4 },
|
||||
{ { .w8 = 0x3f }, .popct=6 },
|
||||
{ { .w8 = 0x40 }, .popct=1 },
|
||||
{ { .w8 = 0xf0 }, .popct=4 },
|
||||
{ { .w8 = 0x7f }, .popct=7 },
|
||||
{ { .w8 = 0x80 }, .popct=1 },
|
||||
{ { .w8 = 0xf1 }, .popct=5 },
|
||||
{ { .w8 = 0xfe }, .popct=7 },
|
||||
{ { .w8 = 0xff }, .popct=8 },
|
||||
};
|
||||
|
||||
static void test_ctpop8(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(eight_bit_data); i++) {
|
||||
struct bitcnt_test_data *d = &eight_bit_data[i];
|
||||
g_assert(ctpop8(d->value.w8)==d->popct);
|
||||
}
|
||||
}
|
||||
|
||||
struct bitcnt_test_data sixteen_bit_data[] = {
|
||||
{ { .w16 = 0x0000 }, .popct=0 },
|
||||
{ { .w16 = 0x0001 }, .popct=1 },
|
||||
{ { .w16 = 0x0003 }, .popct=2 },
|
||||
{ { .w16 = 0x000f }, .popct=4 },
|
||||
{ { .w16 = 0x003f }, .popct=6 },
|
||||
{ { .w16 = 0x00f0 }, .popct=4 },
|
||||
{ { .w16 = 0x0f0f }, .popct=8 },
|
||||
{ { .w16 = 0x1f1f }, .popct=10 },
|
||||
{ { .w16 = 0x4000 }, .popct=1 },
|
||||
{ { .w16 = 0x4001 }, .popct=2 },
|
||||
{ { .w16 = 0x7000 }, .popct=3 },
|
||||
{ { .w16 = 0x7fff }, .popct=15 },
|
||||
};
|
||||
|
||||
static void test_ctpop16(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sixteen_bit_data); i++) {
|
||||
struct bitcnt_test_data *d = &sixteen_bit_data[i];
|
||||
g_assert(ctpop16(d->value.w16)==d->popct);
|
||||
}
|
||||
}
|
||||
|
||||
struct bitcnt_test_data thirtytwo_bit_data[] = {
|
||||
{ { .w32 = 0x00000000 }, .popct=0 },
|
||||
{ { .w32 = 0x00000001 }, .popct=1 },
|
||||
{ { .w32 = 0x0000000f }, .popct=4 },
|
||||
{ { .w32 = 0x00000f0f }, .popct=8 },
|
||||
{ { .w32 = 0x00001f1f }, .popct=10 },
|
||||
{ { .w32 = 0x00004001 }, .popct=2 },
|
||||
{ { .w32 = 0x00007000 }, .popct=3 },
|
||||
{ { .w32 = 0x00007fff }, .popct=15 },
|
||||
{ { .w32 = 0x55555555 }, .popct=16 },
|
||||
{ { .w32 = 0xaaaaaaaa }, .popct=16 },
|
||||
{ { .w32 = 0xff000000 }, .popct=8 },
|
||||
{ { .w32 = 0xc0c0c0c0 }, .popct=8 },
|
||||
{ { .w32 = 0x0ffffff0 }, .popct=24 },
|
||||
{ { .w32 = 0x80000000 }, .popct=1 },
|
||||
{ { .w32 = 0xffffffff }, .popct=32 },
|
||||
};
|
||||
|
||||
static void test_ctpop32(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(thirtytwo_bit_data); i++) {
|
||||
struct bitcnt_test_data *d = &thirtytwo_bit_data[i];
|
||||
g_assert(ctpop32(d->value.w32)==d->popct);
|
||||
}
|
||||
}
|
||||
|
||||
struct bitcnt_test_data sixtyfour_bit_data[] = {
|
||||
{ { .w64 = 0x0000000000000000ULL }, .popct=0 },
|
||||
{ { .w64 = 0x0000000000000001ULL }, .popct=1 },
|
||||
{ { .w64 = 0x000000000000000fULL }, .popct=4 },
|
||||
{ { .w64 = 0x0000000000000f0fULL }, .popct=8 },
|
||||
{ { .w64 = 0x0000000000001f1fULL }, .popct=10 },
|
||||
{ { .w64 = 0x0000000000004001ULL }, .popct=2 },
|
||||
{ { .w64 = 0x0000000000007000ULL }, .popct=3 },
|
||||
{ { .w64 = 0x0000000000007fffULL }, .popct=15 },
|
||||
{ { .w64 = 0x0000005500555555ULL }, .popct=16 },
|
||||
{ { .w64 = 0x00aa0000aaaa00aaULL }, .popct=16 },
|
||||
{ { .w64 = 0x000f000000f00000ULL }, .popct=8 },
|
||||
{ { .w64 = 0x0c0c0000c0c0c0c0ULL }, .popct=12 },
|
||||
{ { .w64 = 0xf00f00f0f0f0f000ULL }, .popct=24 },
|
||||
{ { .w64 = 0x8000000000000000ULL }, .popct=1 },
|
||||
{ { .w64 = 0xf0f0f0f0f0f0f0f0ULL }, .popct=32 },
|
||||
{ { .w64 = 0xffffffffffffffffULL }, .popct=64 },
|
||||
};
|
||||
|
||||
static void test_ctpop64(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sixtyfour_bit_data); i++) {
|
||||
struct bitcnt_test_data *d = &sixtyfour_bit_data[i];
|
||||
g_assert(ctpop64(d->value.w64)==d->popct);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
g_test_add_func("/bitcnt/ctpop8", test_ctpop8);
|
||||
g_test_add_func("/bitcnt/ctpop16", test_ctpop16);
|
||||
g_test_add_func("/bitcnt/ctpop32", test_ctpop32);
|
||||
g_test_add_func("/bitcnt/ctpop64", test_ctpop64);
|
||||
return g_test_run();
|
||||
}
|
Loading…
Reference in a new issue