summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAurelien Jarno2012-09-21 18:20:26 +0200
committerAurelien Jarno2012-09-22 15:10:20 +0200
commit9a152519a9f767297c92b5840c91a22235295c8d (patch)
tree51b4843de8404c7180737216b340c1d9a8a1a76a
parenttcg/mips: optimize bswap{16,16s,32} on MIPS32R2 (diff)
downloadqemu-9a152519a9f767297c92b5840c91a22235295c8d.tar.gz
qemu-9a152519a9f767297c92b5840c91a22235295c8d.tar.xz
qemu-9a152519a9f767297c92b5840c91a22235295c8d.zip
tcg/mips: implement rotl/rotr ops on MIPS32R2
rotr operations can be optimized on MIPS32 Release 2 using the ROTR and ROTRV instructions. Also implemented rotl operations by subtracting the shift from 32. Reviewed-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
-rw-r--r--tcg/mips/tcg-target.c20
-rw-r--r--tcg/mips/tcg-target.h3
2 files changed, 22 insertions, 1 deletions
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index 8b2f9fc7d6..592e42a2bc 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -300,9 +300,11 @@ enum {
OPC_SPECIAL = 0x00 << 26,
OPC_SLL = OPC_SPECIAL | 0x00,
OPC_SRL = OPC_SPECIAL | 0x02,
+ OPC_ROTR = OPC_SPECIAL | (0x01 << 21) | 0x02,
OPC_SRA = OPC_SPECIAL | 0x03,
OPC_SLLV = OPC_SPECIAL | 0x04,
OPC_SRLV = OPC_SPECIAL | 0x06,
+ OPC_ROTRV = OPC_SPECIAL | (0x01 << 6) | 0x06,
OPC_SRAV = OPC_SPECIAL | 0x07,
OPC_JR = OPC_SPECIAL | 0x08,
OPC_JALR = OPC_SPECIAL | 0x09,
@@ -1420,6 +1422,22 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
tcg_out_opc_reg(s, OPC_SRLV, args[0], args[2], args[1]);
}
break;
+ case INDEX_op_rotl_i32:
+ if (const_args[2]) {
+ tcg_out_opc_sa(s, OPC_ROTR, args[0], args[1], 0x20 - args[2]);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, 32);
+ tcg_out_opc_reg(s, OPC_SUBU, TCG_REG_AT, TCG_REG_AT, args[2]);
+ tcg_out_opc_reg(s, OPC_ROTRV, args[0], TCG_REG_AT, args[1]);
+ }
+ break;
+ case INDEX_op_rotr_i32:
+ if (const_args[2]) {
+ tcg_out_opc_sa(s, OPC_ROTR, args[0], args[1], args[2]);
+ } else {
+ tcg_out_opc_reg(s, OPC_ROTRV, args[0], args[2], args[1]);
+ }
+ break;
/* The bswap routines do not work on non-R2 CPU. In that case
we let TCG generating the corresponding code. */
@@ -1523,6 +1541,8 @@ static const TCGTargetOpDef mips_op_defs[] = {
{ INDEX_op_shl_i32, { "r", "rZ", "ri" } },
{ INDEX_op_shr_i32, { "r", "rZ", "ri" } },
{ INDEX_op_sar_i32, { "r", "rZ", "ri" } },
+ { INDEX_op_rotr_i32, { "r", "rZ", "ri" } },
+ { INDEX_op_rotl_i32, { "r", "rZ", "ri" } },
{ INDEX_op_bswap16_i32, { "r", "r" } },
{ INDEX_op_bswap32_i32, { "r", "r" } },
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index c5c13f71d3..470314cc99 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -80,7 +80,6 @@ typedef enum {
#define TCG_TARGET_HAS_div_i32 1
#define TCG_TARGET_HAS_not_i32 1
#define TCG_TARGET_HAS_nor_i32 1
-#define TCG_TARGET_HAS_rot_i32 0
#define TCG_TARGET_HAS_ext8s_i32 1
#define TCG_TARGET_HAS_ext16s_i32 1
#define TCG_TARGET_HAS_andc_i32 0
@@ -94,9 +93,11 @@ typedef enum {
#ifdef _MIPS_ARCH_MIPS32R2
#define TCG_TARGET_HAS_bswap16_i32 1
#define TCG_TARGET_HAS_bswap32_i32 1
+#define TCG_TARGET_HAS_rot_i32 1
#else
#define TCG_TARGET_HAS_bswap16_i32 0
#define TCG_TARGET_HAS_bswap32_i32 0
+#define TCG_TARGET_HAS_rot_i32 0
#endif
/* optional instructions automatically implemented */