tcg/mips: Handle clz opcode

Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2016-11-16 15:34:03 +01:00
parent cc0fec8a4d
commit 2a1d9d41ae
2 changed files with 51 additions and 2 deletions

View file

@ -121,8 +121,6 @@ extern bool use_mips32r2_instructions;
#define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_rem_i32 1
#define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_not_i32 1
#define TCG_TARGET_HAS_nor_i32 1 #define TCG_TARGET_HAS_nor_i32 1
#define TCG_TARGET_HAS_clz_i32 0
#define TCG_TARGET_HAS_ctz_i32 0
#define TCG_TARGET_HAS_andc_i32 0 #define TCG_TARGET_HAS_andc_i32 0
#define TCG_TARGET_HAS_orc_i32 0 #define TCG_TARGET_HAS_orc_i32 0
#define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_eqv_i32 0
@ -165,6 +163,8 @@ extern bool use_mips32r2_instructions;
#define TCG_TARGET_HAS_ext8s_i32 use_mips32r2_instructions #define TCG_TARGET_HAS_ext8s_i32 use_mips32r2_instructions
#define TCG_TARGET_HAS_ext16s_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_rot_i32 use_mips32r2_instructions
#define TCG_TARGET_HAS_clz_i32 use_mips32r2_instructions
#define TCG_TARGET_HAS_ctz_i32 0
#if TCG_TARGET_REG_BITS == 64 #if TCG_TARGET_REG_BITS == 64
#define TCG_TARGET_HAS_movcond_i64 use_movnz_instructions #define TCG_TARGET_HAS_movcond_i64 use_movnz_instructions
@ -177,6 +177,8 @@ extern bool use_mips32r2_instructions;
#define TCG_TARGET_HAS_ext8s_i64 use_mips32r2_instructions #define TCG_TARGET_HAS_ext8s_i64 use_mips32r2_instructions
#define TCG_TARGET_HAS_ext16s_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_rot_i64 use_mips32r2_instructions
#define TCG_TARGET_HAS_clz_i64 use_mips32r2_instructions
#define TCG_TARGET_HAS_ctz_i64 0
#endif #endif
/* optional instructions automatically implemented */ /* optional instructions automatically implemented */

View file

@ -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_S16 0x400 /* Signed 16-bit: -32768 - 32767 */
#define TCG_CT_CONST_P2M1 0x800 /* Power of 2 minus 1. */ #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_N16 0x1000 /* "Negatable" 16-bit: -32767 - 32767 */
#define TCG_CT_CONST_WSZ 0x2000 /* word size */
static inline bool is_p2m1(tcg_target_long val) static inline bool is_p2m1(tcg_target_long val)
{ {
@ -229,6 +230,9 @@ static const char *target_parse_constraint(TCGArgConstraint *ct,
case 'N': case 'N':
ct->ct |= TCG_CT_CONST_N16; ct->ct |= TCG_CT_CONST_N16;
break; break;
case 'W':
ct->ct |= TCG_CT_CONST_WSZ;
break;
case 'Z': case 'Z':
/* We are cheating a bit here, using the fact that the register /* We are cheating a bit here, using the fact that the register
ZERO is also the register number 0. Hence there is no need ZERO is also the register number 0. Hence there is no need
@ -260,6 +264,9 @@ static inline int tcg_target_const_match(tcg_target_long val, TCGType type,
} else if ((ct & TCG_CT_CONST_P2M1) } else if ((ct & TCG_CT_CONST_P2M1)
&& use_mips32r2_instructions && is_p2m1(val)) { && use_mips32r2_instructions && is_p2m1(val)) {
return 1; return 1;
} else if ((ct & TCG_CT_CONST_WSZ)
&& val == (type == TCG_TYPE_I32 ? 32 : 64)) {
return 1;
} }
return 0; return 0;
} }
@ -356,6 +363,8 @@ typedef enum {
OPC_DSRL32 = OPC_SPECIAL | 076, OPC_DSRL32 = OPC_SPECIAL | 076,
OPC_DROTR32 = OPC_SPECIAL | 076 | (1 << 21), OPC_DROTR32 = OPC_SPECIAL | 076 | (1 << 21),
OPC_DSRA32 = OPC_SPECIAL | 077, OPC_DSRA32 = OPC_SPECIAL | 077,
OPC_CLZ_R6 = OPC_SPECIAL | 0120,
OPC_DCLZ_R6 = OPC_SPECIAL | 0122,
OPC_REGIMM = 001 << 26, OPC_REGIMM = 001 << 26,
OPC_BLTZ = OPC_REGIMM | (000 << 16), OPC_BLTZ = OPC_REGIMM | (000 << 16),
@ -363,6 +372,8 @@ typedef enum {
OPC_SPECIAL2 = 034 << 26, OPC_SPECIAL2 = 034 << 26,
OPC_MUL_R5 = OPC_SPECIAL2 | 002, OPC_MUL_R5 = OPC_SPECIAL2 | 002,
OPC_CLZ = OPC_SPECIAL2 | 040,
OPC_DCLZ = OPC_SPECIAL2 | 044,
OPC_SPECIAL3 = 037 << 26, OPC_SPECIAL3 = 037 << 26,
OPC_EXT = OPC_SPECIAL3 | 000, OPC_EXT = OPC_SPECIAL3 | 000,
@ -1664,6 +1675,33 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
tcg_out32(s, sync[a0 & TCG_MO_ALL]); 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, static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
const TCGArg *args, const int *const_args) const TCGArg *args, const int *const_args)
{ {
@ -2040,6 +2078,13 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
} }
break; 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: case INDEX_op_deposit_i32:
tcg_out_opc_bf(s, OPC_INS, a0, a2, args[3] + args[4] - 1, args[3]); tcg_out_opc_bf(s, OPC_INS, a0, a2, args[3] + args[4] - 1, args[3]);
break; break;
@ -2150,6 +2195,7 @@ static const TCGTargetOpDef mips_op_defs[] = {
{ INDEX_op_sar_i32, { "r", "rZ", "ri" } }, { INDEX_op_sar_i32, { "r", "rZ", "ri" } },
{ INDEX_op_rotr_i32, { "r", "rZ", "ri" } }, { INDEX_op_rotr_i32, { "r", "rZ", "ri" } },
{ INDEX_op_rotl_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_bswap16_i32, { "r", "r" } },
{ INDEX_op_bswap32_i32, { "r", "r" } }, { INDEX_op_bswap32_i32, { "r", "r" } },
@ -2213,6 +2259,7 @@ static const TCGTargetOpDef mips_op_defs[] = {
{ INDEX_op_sar_i64, { "r", "rZ", "ri" } }, { INDEX_op_sar_i64, { "r", "rZ", "ri" } },
{ INDEX_op_rotr_i64, { "r", "rZ", "ri" } }, { INDEX_op_rotr_i64, { "r", "rZ", "ri" } },
{ INDEX_op_rotl_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_bswap16_i64, { "r", "r" } },
{ INDEX_op_bswap32_i64, { "r", "r" } }, { INDEX_op_bswap32_i64, { "r", "r" } },