diff options
author | Richard Henderson <rth@twiddle.net> | 2014-04-15 09:27:40 -0700 |
---|---|---|
committer | Richard Henderson <rth@twiddle.net> | 2014-05-24 08:45:56 -0700 |
commit | 1c4182687e20a4255ea827fe05081578d9c518f9 (patch) | |
tree | 4ddac31b079b58048e3a3b8754701c3beb12a648 /tcg | |
parent | f216a35f364df893519656648677a7629a36de9e (diff) | |
download | qemu-1c4182687e20a4255ea827fe05081578d9c518f9.tar.gz qemu-1c4182687e20a4255ea827fe05081578d9c518f9.tar.bz2 qemu-1c4182687e20a4255ea827fe05081578d9c518f9.zip |
tcg-mips: Use EXT for AND on mips32r2
At the same time, tidy deposit by introducing tcg_out_opc_bf.
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'tcg')
-rw-r--r-- | tcg/mips/tcg-target.c | 60 | ||||
-rw-r--r-- | tcg/mips/tcg-target.h | 4 |
2 files changed, 50 insertions, 14 deletions
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 78caf25c3a..54571fb07a 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -155,6 +155,16 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type, reloc_pc16(code_ptr, (tcg_insn_unit *)value); } +#define TCG_CT_CONST_ZERO 0x100 +#define TCG_CT_CONST_U16 0x200 +#define TCG_CT_CONST_S16 0x400 +#define TCG_CT_CONST_P2M1 0x800 + +static inline bool is_p2m1(tcg_target_long val) +{ + return val && ((val + 1) & val) == 0; +} + /* parse target specific constraints */ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) { @@ -200,6 +210,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) case 'J': ct->ct |= TCG_CT_CONST_S16; break; + case 'K': + ct->ct |= TCG_CT_CONST_P2M1; + 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 @@ -220,16 +233,19 @@ static inline int tcg_target_const_match(tcg_target_long val, TCGType type, { int ct; ct = arg_ct->ct; - if (ct & TCG_CT_CONST) + if (ct & TCG_CT_CONST) { return 1; - else if ((ct & TCG_CT_CONST_ZERO) && val == 0) + } else if ((ct & TCG_CT_CONST_ZERO) && val == 0) { return 1; - else if ((ct & TCG_CT_CONST_U16) && val == (uint16_t)val) + } else if ((ct & TCG_CT_CONST_U16) && val == (uint16_t)val) { return 1; - else if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val) + } else if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val) { return 1; - else - return 0; + } else if ((ct & TCG_CT_CONST_P2M1) + && use_mips32r2_instructions && is_p2m1(val)) { + return 1; + } + return 0; } /* instruction opcodes */ @@ -293,6 +309,7 @@ enum { OPC_MUL = OPC_SPECIAL2 | 0x002, OPC_SPECIAL3 = 0x1f << 26, + OPC_EXT = OPC_SPECIAL3 | 0x000, OPC_INS = OPC_SPECIAL3 | 0x004, OPC_WSBH = OPC_SPECIAL3 | 0x0a0, OPC_SEB = OPC_SPECIAL3 | 0x420, @@ -330,6 +347,22 @@ static inline void tcg_out_opc_imm(TCGContext *s, int opc, } /* + * Type bitfield + */ +static inline void tcg_out_opc_bf(TCGContext *s, int opc, TCGReg rt, + TCGReg rs, int msb, int lsb) +{ + int32_t inst; + + inst = opc; + inst |= (rs & 0x1F) << 21; + inst |= (rt & 0x1F) << 16; + inst |= (msb & 0x1F) << 11; + inst |= (lsb & 0x1F) << 6; + tcg_out32(s, inst); +} + +/* * Type branch */ static inline void tcg_out_opc_br(TCGContext *s, int opc, @@ -1455,7 +1488,14 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_and_i32: if (const_args[2]) { - tcg_out_opc_imm(s, OPC_ANDI, args[0], args[1], args[2]); + if (args[2] == (uint16_t)args[2]) { + tcg_out_opc_imm(s, OPC_ANDI, args[0], args[1], args[2]); + } else { + int msb = ctz32(~args[2]) - 1; + assert(use_mips32r2_instructions); + assert(is_p2m1(args[2])); + tcg_out_opc_bf(s, OPC_EXT, args[0], args[1], msb, 0); + } } else { tcg_out_opc_reg(s, OPC_AND, args[0], args[1], args[2]); } @@ -1535,8 +1575,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_deposit_i32: - tcg_out_opc_imm(s, OPC_INS, args[0], args[2], - ((args[3] + args[4] - 1) << 11) | (args[3] << 6)); + tcg_out_opc_bf(s, OPC_INS, args[0], args[2], + args[3] + args[4] - 1, args[3]); break; case INDEX_op_brcond_i32: @@ -1604,7 +1644,7 @@ static const TCGTargetOpDef mips_op_defs[] = { { INDEX_op_remu_i32, { "r", "rZ", "rZ" } }, { INDEX_op_sub_i32, { "r", "rZ", "rJ" } }, - { INDEX_op_and_i32, { "r", "rZ", "rI" } }, + { INDEX_op_and_i32, { "r", "rZ", "rIK" } }, { INDEX_op_nor_i32, { "r", "rZ", "rZ" } }, { INDEX_op_not_i32, { "r", "rZ" } }, { INDEX_op_or_i32, { "r", "rZ", "rIZ" } }, diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index c959d1c959..b5face8b4d 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -67,10 +67,6 @@ typedef enum { TCG_AREG0 = TCG_REG_S0, } TCGReg; -#define TCG_CT_CONST_ZERO 0x100 -#define TCG_CT_CONST_U16 0x200 -#define TCG_CT_CONST_S16 0x400 - /* used for function call generation */ #define TCG_TARGET_STACK_ALIGN 8 #define TCG_TARGET_CALL_STACK_OFFSET 16 |