|
@@ -217,6 +217,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
|
|
tcg_regset_set(ct->u.regs, 0xffffffff);
|
|
tcg_regset_set(ct->u.regs, 0xffffffff);
|
|
#if defined(CONFIG_SOFTMMU)
|
|
#if defined(CONFIG_SOFTMMU)
|
|
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
|
|
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
|
|
#endif
|
|
break;
|
|
break;
|
|
case 'S': /* qemu_st constraint */
|
|
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_set(ct->u.regs, 0xffffffff);
|
|
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
|
|
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
|
|
#if defined(CONFIG_SOFTMMU)
|
|
#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);
|
|
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1);
|
|
# endif
|
|
# endif
|
|
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
|
|
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
|
|
#endif
|
|
break;
|
|
break;
|
|
case 'I':
|
|
case 'I':
|
|
@@ -382,7 +389,10 @@ static inline void tcg_out_nop(TCGContext *s)
|
|
static inline void tcg_out_mov(TCGContext *s, TCGType type,
|
|
static inline void tcg_out_mov(TCGContext *s, TCGType type,
|
|
TCGReg ret, TCGReg arg)
|
|
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,
|
|
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,
|
|
static void tcg_out_brcond(TCGContext *s, TCGCond cond, int arg1,
|
|
int arg2, int label_index)
|
|
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,
|
|
static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
|
int opc)
|
|
int opc)
|
|
{
|
|
{
|
|
- int addr_regl, addr_reg1, addr_meml;
|
|
|
|
|
|
+ int addr_regl, addr_meml;
|
|
int data_regl, data_regh, data_reg1, data_reg2;
|
|
int data_regl, data_regh, data_reg1, data_reg2;
|
|
int mem_index, s_bits;
|
|
int mem_index, s_bits;
|
|
#if defined(CONFIG_SOFTMMU)
|
|
#if defined(CONFIG_SOFTMMU)
|
|
void *label1_ptr, *label2_ptr;
|
|
void *label1_ptr, *label2_ptr;
|
|
- int sp_args;
|
|
|
|
|
|
+ int arg_num;
|
|
#endif
|
|
#endif
|
|
#if TARGET_LONG_BITS == 64
|
|
#if TARGET_LONG_BITS == 64
|
|
# if defined(CONFIG_SOFTMMU)
|
|
# if defined(CONFIG_SOFTMMU)
|
|
uint8_t *label3_ptr;
|
|
uint8_t *label3_ptr;
|
|
# endif
|
|
# endif
|
|
- int addr_regh, addr_reg2, addr_memh;
|
|
|
|
|
|
+ int addr_regh, addr_memh;
|
|
#endif
|
|
#endif
|
|
data_regl = *args++;
|
|
data_regl = *args++;
|
|
if (opc == 3)
|
|
if (opc == 3)
|
|
@@ -831,18 +902,13 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
|
}
|
|
}
|
|
#if TARGET_LONG_BITS == 64
|
|
#if TARGET_LONG_BITS == 64
|
|
# if defined(TCG_TARGET_WORDS_BIGENDIAN)
|
|
# if defined(TCG_TARGET_WORDS_BIGENDIAN)
|
|
- addr_reg1 = addr_regh;
|
|
|
|
- addr_reg2 = addr_regl;
|
|
|
|
addr_memh = 0;
|
|
addr_memh = 0;
|
|
addr_meml = 4;
|
|
addr_meml = 4;
|
|
# else
|
|
# else
|
|
- addr_reg1 = addr_regl;
|
|
|
|
- addr_reg2 = addr_regh;
|
|
|
|
addr_memh = 4;
|
|
addr_memh = 4;
|
|
addr_meml = 0;
|
|
addr_meml = 0;
|
|
# endif
|
|
# endif
|
|
#else
|
|
#else
|
|
- addr_reg1 = addr_regl;
|
|
|
|
addr_meml = 0;
|
|
addr_meml = 0;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
@@ -875,22 +941,17 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
|
# endif
|
|
# endif
|
|
|
|
|
|
/* slow path */
|
|
/* 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
|
|
# 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
|
|
# 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]);
|
|
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_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
|
|
tcg_out_nop(s);
|
|
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,
|
|
static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
|
int opc)
|
|
int opc)
|
|
{
|
|
{
|
|
- int addr_regl, addr_reg1, addr_meml;
|
|
|
|
|
|
+ int addr_regl, addr_meml;
|
|
int data_regl, data_regh, data_reg1, data_reg2;
|
|
int data_regl, data_regh, data_reg1, data_reg2;
|
|
int mem_index, s_bits;
|
|
int mem_index, s_bits;
|
|
#if defined(CONFIG_SOFTMMU)
|
|
#if defined(CONFIG_SOFTMMU)
|
|
uint8_t *label1_ptr, *label2_ptr;
|
|
uint8_t *label1_ptr, *label2_ptr;
|
|
- int sp_args;
|
|
|
|
|
|
+ int arg_num;
|
|
#endif
|
|
#endif
|
|
#if TARGET_LONG_BITS == 64
|
|
#if TARGET_LONG_BITS == 64
|
|
# if defined(CONFIG_SOFTMMU)
|
|
# if defined(CONFIG_SOFTMMU)
|
|
uint8_t *label3_ptr;
|
|
uint8_t *label3_ptr;
|
|
# endif
|
|
# endif
|
|
- int addr_regh, addr_reg2, addr_memh;
|
|
|
|
|
|
+ int addr_regh, addr_memh;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
data_regl = *args++;
|
|
data_regl = *args++;
|
|
@@ -1024,18 +1085,13 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
|
#if TARGET_LONG_BITS == 64
|
|
#if TARGET_LONG_BITS == 64
|
|
addr_regh = *args++;
|
|
addr_regh = *args++;
|
|
# if defined(TCG_TARGET_WORDS_BIGENDIAN)
|
|
# if defined(TCG_TARGET_WORDS_BIGENDIAN)
|
|
- addr_reg1 = addr_regh;
|
|
|
|
- addr_reg2 = addr_regl;
|
|
|
|
addr_memh = 0;
|
|
addr_memh = 0;
|
|
addr_meml = 4;
|
|
addr_meml = 4;
|
|
# else
|
|
# else
|
|
- addr_reg1 = addr_regl;
|
|
|
|
- addr_reg2 = addr_regh;
|
|
|
|
addr_memh = 4;
|
|
addr_memh = 4;
|
|
addr_meml = 0;
|
|
addr_meml = 0;
|
|
# endif
|
|
# endif
|
|
#else
|
|
#else
|
|
- addr_reg1 = addr_regl;
|
|
|
|
addr_meml = 0;
|
|
addr_meml = 0;
|
|
#endif
|
|
#endif
|
|
mem_index = *args;
|
|
mem_index = *args;
|
|
@@ -1070,49 +1126,33 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
|
# endif
|
|
# endif
|
|
|
|
|
|
/* slow path */
|
|
/* 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
|
|
# 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
|
|
# endif
|
|
switch(opc) {
|
|
switch(opc) {
|
|
case 0:
|
|
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;
|
|
break;
|
|
case 1:
|
|
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;
|
|
break;
|
|
case 2:
|
|
case 2:
|
|
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg1);
|
|
|
|
|
|
+ tcg_out_call_iarg_reg32(s, &arg_num, data_regl);
|
|
break;
|
|
break;
|
|
case 3:
|
|
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;
|
|
break;
|
|
default:
|
|
default:
|
|
tcg_abort();
|
|
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]);
|
|
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_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
|
|
tcg_out_nop(s);
|
|
tcg_out_nop(s);
|
|
|
|
|