summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tcg/mips/tcg-target.c158
1 files changed, 99 insertions, 59 deletions
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index 393ba07f25..1006e28000 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -217,6 +217,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
tcg_regset_set(ct->u.regs, 0xffffffff);
#if defined(CONFIG_SOFTMMU)
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
+# if defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64)
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
+# endif
#endif
break;
case 'S': /* qemu_st constraint */
@@ -224,10 +227,14 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
tcg_regset_set(ct->u.regs, 0xffffffff);
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
#if defined(CONFIG_SOFTMMU)
-# if TARGET_LONG_BITS == 64
+# if (defined(CONFIG_TCG_PASS_AREG0) && TARGET_LONG_BITS == 32) || \
+ (!defined(CONFIG_TCG_PASS_AREG0) && TARGET_LONG_BITS == 64)
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1);
# endif
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
+# if defined(CONFIG_TCG_PASS_AREG0) && TARGET_LONG_BITS == 64
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_A3);
+# endif
#endif
break;
case 'I':
@@ -382,7 +389,10 @@ static inline void tcg_out_nop(TCGContext *s)
static inline void tcg_out_mov(TCGContext *s, TCGType type,
TCGReg ret, TCGReg arg)
{
- tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO);
+ /* Simple reg-reg move, optimising out the 'do nothing' case */
+ if (ret != arg) {
+ tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO);
+ }
}
static inline void tcg_out_movi(TCGContext *s, TCGType type,
@@ -503,6 +513,67 @@ static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
}
}
+/* Helper routines for marshalling helper function arguments into
+ * the correct registers and stack.
+ * arg_num is where we want to put this argument, and is updated to be ready
+ * for the next call. arg is the argument itself. Note that arg_num 0..3 is
+ * real registers, 4+ on stack.
+ *
+ * We provide routines for arguments which are: immediate, 32 bit
+ * value in register, 16 and 8 bit values in register (which must be zero
+ * extended before use) and 64 bit value in a lo:hi register pair.
+ */
+#define DEFINE_TCG_OUT_CALL_IARG(NAME, ARGPARAM) \
+ static inline void NAME(TCGContext *s, int *arg_num, ARGPARAM) \
+ { \
+ if (*arg_num < 4) { \
+ DEFINE_TCG_OUT_CALL_IARG_GET_ARG(tcg_target_call_iarg_regs[*arg_num]); \
+ } else { \
+ DEFINE_TCG_OUT_CALL_IARG_GET_ARG(TCG_REG_AT); \
+ tcg_out_st(s, TCG_TYPE_I32, TCG_REG_AT, TCG_REG_SP, 4 * (*arg_num)); \
+ } \
+ (*arg_num)++; \
+}
+#define DEFINE_TCG_OUT_CALL_IARG_GET_ARG(A) \
+ tcg_out_opc_imm(s, OPC_ANDI, A, arg, 0xff);
+DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_reg8, TCGReg arg)
+#undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG
+#define DEFINE_TCG_OUT_CALL_IARG_GET_ARG(A) \
+ tcg_out_opc_imm(s, OPC_ANDI, A, arg, 0xffff);
+DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_reg16, TCGReg arg)
+#undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG
+#define DEFINE_TCG_OUT_CALL_IARG_GET_ARG(A) \
+ tcg_out_movi(s, TCG_TYPE_I32, A, arg);
+DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_imm32, uint32_t arg)
+#undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG
+
+/* We don't use the macro for this one to avoid an unnecessary reg-reg
+ move when storing to the stack. */
+static inline void tcg_out_call_iarg_reg32(TCGContext *s, int *arg_num,
+ TCGReg arg)
+{
+ if (*arg_num < 4) {
+ tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[*arg_num], arg);
+ } else {
+ tcg_out_st(s, TCG_TYPE_I32, arg, TCG_REG_SP, 4 * (*arg_num));
+ }
+ (*arg_num)++;
+}
+
+static inline void tcg_out_call_iarg_reg64(TCGContext *s, int *arg_num,
+ TCGReg arg_low, TCGReg arg_high)
+{
+ (*arg_num) = (*arg_num + 1) & ~1;
+
+#if defined(TCG_TARGET_WORDS_BIGENDIAN)
+ tcg_out_call_iarg_reg32(s, arg_num, arg_high);
+ tcg_out_call_iarg_reg32(s, arg_num, arg_low);
+#else
+ tcg_out_call_iarg_reg32(s, arg_num, arg_low);
+ tcg_out_call_iarg_reg32(s, arg_num, arg_high);
+#endif
+}
+
static void tcg_out_brcond(TCGContext *s, TCGCond cond, int arg1,
int arg2, int label_index)
{
@@ -792,18 +863,18 @@ static void *qemu_st_helpers[4] = {
static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
int opc)
{
- int addr_regl, addr_reg1, addr_meml;
+ int addr_regl, addr_meml;
int data_regl, data_regh, data_reg1, data_reg2;
int mem_index, s_bits;
#if defined(CONFIG_SOFTMMU)
void *label1_ptr, *label2_ptr;
- int sp_args;
+ int arg_num;
#endif
#if TARGET_LONG_BITS == 64
# if defined(CONFIG_SOFTMMU)
uint8_t *label3_ptr;
# endif
- int addr_regh, addr_reg2, addr_memh;
+ int addr_regh, addr_memh;
#endif
data_regl = *args++;
if (opc == 3)
@@ -831,18 +902,13 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
}
#if TARGET_LONG_BITS == 64
# if defined(TCG_TARGET_WORDS_BIGENDIAN)
- addr_reg1 = addr_regh;
- addr_reg2 = addr_regl;
addr_memh = 0;
addr_meml = 4;
# else
- addr_reg1 = addr_regl;
- addr_reg2 = addr_regh;
addr_memh = 4;
addr_meml = 0;
# endif
#else
- addr_reg1 = addr_regl;
addr_meml = 0;
#endif
@@ -875,22 +941,17 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
# endif
/* slow path */
- sp_args = TCG_REG_A0;
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg1);
+ arg_num = 0;
+# ifdef CONFIG_TCG_PASS_AREG0
+ tcg_out_call_iarg_reg32(s, &arg_num, TCG_AREG0);
+# endif
# if TARGET_LONG_BITS == 64
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg2);
+ tcg_out_call_iarg_reg64(s, &arg_num, addr_regl, addr_regh);
+# else
+ tcg_out_call_iarg_reg32(s, &arg_num, addr_regl);
# endif
- tcg_out_movi(s, TCG_TYPE_I32, sp_args++, mem_index);
+ tcg_out_call_iarg_imm32(s, &arg_num, mem_index);
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_ld_helpers[s_bits]);
-#ifdef CONFIG_TCG_PASS_AREG0
- /* XXX/FIXME: suboptimal and incorrect for 64 on 32 bit */
- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2],
- tcg_target_call_iarg_regs[1]);
- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
- tcg_target_call_iarg_regs[0]);
- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
- TCG_AREG0);
-#endif
tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
tcg_out_nop(s);
@@ -991,18 +1052,18 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
int opc)
{
- int addr_regl, addr_reg1, addr_meml;
+ int addr_regl, addr_meml;
int data_regl, data_regh, data_reg1, data_reg2;
int mem_index, s_bits;
#if defined(CONFIG_SOFTMMU)
uint8_t *label1_ptr, *label2_ptr;
- int sp_args;
+ int arg_num;
#endif
#if TARGET_LONG_BITS == 64
# if defined(CONFIG_SOFTMMU)
uint8_t *label3_ptr;
# endif
- int addr_regh, addr_reg2, addr_memh;
+ int addr_regh, addr_memh;
#endif
data_regl = *args++;
@@ -1024,18 +1085,13 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
#if TARGET_LONG_BITS == 64
addr_regh = *args++;
# if defined(TCG_TARGET_WORDS_BIGENDIAN)
- addr_reg1 = addr_regh;
- addr_reg2 = addr_regl;
addr_memh = 0;
addr_meml = 4;
# else
- addr_reg1 = addr_regl;
- addr_reg2 = addr_regh;
addr_memh = 4;
addr_meml = 0;
# endif
#else
- addr_reg1 = addr_regl;
addr_meml = 0;
#endif
mem_index = *args;
@@ -1070,49 +1126,33 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
# endif
/* slow path */
- sp_args = TCG_REG_A0;
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg1);
+ arg_num = 0;
+# ifdef CONFIG_TCG_PASS_AREG0
+ tcg_out_call_iarg_reg32(s, &arg_num, TCG_AREG0);
+# endif
# if TARGET_LONG_BITS == 64
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg2);
+ tcg_out_call_iarg_reg64(s, &arg_num, addr_regl, addr_regh);
+# else
+ tcg_out_call_iarg_reg32(s, &arg_num, addr_regl);
# endif
switch(opc) {
case 0:
- tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xff);
+ tcg_out_call_iarg_reg8(s, &arg_num, data_regl);
break;
case 1:
- tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xffff);
+ tcg_out_call_iarg_reg16(s, &arg_num, data_regl);
break;
case 2:
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg1);
+ tcg_out_call_iarg_reg32(s, &arg_num, data_regl);
break;
case 3:
- sp_args = (sp_args + 1) & ~1;
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg1);
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg2);
+ tcg_out_call_iarg_reg64(s, &arg_num, data_regl, data_regh);
break;
default:
tcg_abort();
}
- if (sp_args > TCG_REG_A3) {
- /* Push mem_index on the stack */
- tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, mem_index);
- tcg_out_st(s, TCG_TYPE_I32, TCG_REG_AT, TCG_REG_SP, 16);
- } else {
- tcg_out_movi(s, TCG_TYPE_I32, sp_args, mem_index);
- }
-
+ tcg_out_call_iarg_imm32(s, &arg_num, mem_index);
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_st_helpers[s_bits]);
-#ifdef CONFIG_TCG_PASS_AREG0
- /* XXX/FIXME: suboptimal and incorrect for 64 on 32 bit */
- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
- tcg_target_call_iarg_regs[2]);
- tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
- tcg_target_call_iarg_regs[1]);
- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
- tcg_target_call_iarg_regs[0]);
- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
- TCG_AREG0);
-#endif
tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
tcg_out_nop(s);