summaryrefslogtreecommitdiff
path: root/tcg
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2014-04-15 09:27:40 -0700
committerRichard Henderson <rth@twiddle.net>2014-05-24 08:45:56 -0700
commit1c4182687e20a4255ea827fe05081578d9c518f9 (patch)
tree4ddac31b079b58048e3a3b8754701c3beb12a648 /tcg
parentf216a35f364df893519656648677a7629a36de9e (diff)
downloadqemu-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.c60
-rw-r--r--tcg/mips/tcg-target.h4
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