aboutsummaryrefslogtreecommitdiff
path: root/tcg
diff options
context:
space:
mode:
Diffstat (limited to 'tcg')
-rw-r--r--tcg/arm/tcg-target.c237
-rw-r--r--tcg/ia64/tcg-target.c58
-rw-r--r--tcg/mips/tcg-target.c158
3 files changed, 276 insertions, 177 deletions
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 4d59a6385..cf0ca3d0b 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -176,6 +176,13 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
so don't use these. */
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+#if defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64)
+ /* If we're passing env to the helper as r0 and need a regpair
+ * for the address then r2 will be overwritten as we're setting
+ * up the args to the helper.
+ */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
+#endif
#endif
break;
case 'L':
@@ -197,6 +204,12 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
use these. */
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+#if defined(CONFIG_SOFTMMU) && \
+ defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64)
+ /* Avoid clashes with registers being used for helper args */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+#endif
break;
/* qemu_st64 data_reg2 */
case 'S':
@@ -210,6 +223,10 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
#ifdef CONFIG_SOFTMMU
/* r2 is still needed to load data_reg, so don't use it. */
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
+#if defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64)
+ /* Avoid clashes with registers being used for helper args */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+#endif
#endif
break;
@@ -388,6 +405,14 @@ static inline void tcg_out_dat_reg(TCGContext *s,
(rn << 16) | (rd << 12) | shift | rm);
}
+static inline void tcg_out_mov_reg(TCGContext *s, int cond, int rd, int rm)
+{
+ /* Simple reg-reg move, optimising out the 'do nothing' case */
+ if (rd != rm) {
+ tcg_out_dat_reg(s, cond, ARITH_MOV, rd, 0, rm, SHIFT_IMM_LSL(0));
+ }
+}
+
static inline void tcg_out_dat_reg2(TCGContext *s,
int cond, int opc0, int opc1, int rd0, int rd1,
int rn0, int rn1, int rm0, int rm1, int shift)
@@ -966,6 +991,90 @@ static void *qemu_st_helpers[4] = {
__stq_mmu,
};
#endif
+
+/* Helper routines for marshalling helper function arguments into
+ * the correct registers and stack.
+ * argreg is where we want to put this argument, arg is the argument itself.
+ * Return value is the updated argreg ready for the next call.
+ * Note that argreg 0..3 is real registers, 4+ on stack.
+ * When we reach the first stacked argument, we allocate space for it
+ * and the following stacked arguments using "str r8, [sp, #-0x10]!".
+ * Following arguments are filled in with "str r8, [sp, #0xNN]".
+ * For more than 4 stacked arguments we'd need to know how much
+ * space to allocate when we pushed the first stacked argument.
+ * We don't need this, so don't implement it (and will assert if you try it.)
+ *
+ * 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_ARG(NAME, ARGPARAM) \
+ static TCGReg NAME(TCGContext *s, TCGReg argreg, ARGPARAM) \
+ { \
+ if (argreg < 4) { \
+ TCG_OUT_ARG_GET_ARG(argreg); \
+ } else if (argreg == 4) { \
+ TCG_OUT_ARG_GET_ARG(TCG_REG_R8); \
+ tcg_out32(s, (COND_AL << 28) | 0x052d8010); \
+ } else { \
+ assert(argreg < 8); \
+ TCG_OUT_ARG_GET_ARG(TCG_REG_R8); \
+ tcg_out32(s, (COND_AL << 28) | 0x058d8000 | (argreg - 4) * 4); \
+ } \
+ return argreg + 1; \
+ }
+
+#define TCG_OUT_ARG_GET_ARG(A) tcg_out_dat_imm(s, COND_AL, ARITH_MOV, A, 0, arg)
+DEFINE_TCG_OUT_ARG(tcg_out_arg_imm32, uint32_t arg)
+#undef TCG_OUT_ARG_GET_ARG
+#define TCG_OUT_ARG_GET_ARG(A) tcg_out_ext8u(s, COND_AL, A, arg)
+DEFINE_TCG_OUT_ARG(tcg_out_arg_reg8, TCGReg arg)
+#undef TCG_OUT_ARG_GET_ARG
+#define TCG_OUT_ARG_GET_ARG(A) tcg_out_ext16u(s, COND_AL, A, arg)
+DEFINE_TCG_OUT_ARG(tcg_out_arg_reg16, TCGReg arg)
+#undef TCG_OUT_ARG_GET_ARG
+
+/* We don't use the macro for this one to avoid an unnecessary reg-reg
+ * move when storing to the stack.
+ */
+static TCGReg tcg_out_arg_reg32(TCGContext *s, TCGReg argreg, TCGReg arg)
+{
+ if (argreg < 4) {
+ tcg_out_mov_reg(s, COND_AL, argreg, arg);
+ } else if (argreg == 4) {
+ /* str arg, [sp, #-0x10]! */
+ tcg_out32(s, (COND_AL << 28) | 0x052d0010 | (arg << 12));
+ } else {
+ assert(argreg < 8);
+ /* str arg, [sp, #0xNN] */
+ tcg_out32(s, (COND_AL << 28) | 0x058d0000 |
+ (arg << 12) | (argreg - 4) * 4);
+ }
+ return argreg + 1;
+}
+
+static inline TCGReg tcg_out_arg_reg64(TCGContext *s, TCGReg argreg,
+ TCGReg arglo, TCGReg arghi)
+{
+ /* 64 bit arguments must go in even/odd register pairs
+ * and in 8-aligned stack slots.
+ */
+ if (argreg & 1) {
+ argreg++;
+ }
+ argreg = tcg_out_arg_reg32(s, argreg, arglo);
+ argreg = tcg_out_arg_reg32(s, argreg, arghi);
+ return argreg;
+}
+
+static inline void tcg_out_arg_stacktidy(TCGContext *s, TCGReg argreg)
+{
+ /* Output any necessary post-call cleanup of the stack */
+ if (argreg > 4) {
+ tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
+ }
+}
+
#endif
#define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)
@@ -975,6 +1084,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
int addr_reg, data_reg, data_reg2, bswap;
#ifdef CONFIG_SOFTMMU
int mem_index, s_bits;
+ TCGReg argreg;
# if TARGET_LONG_BITS == 64
int addr_reg2;
# endif
@@ -1088,31 +1198,22 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
tcg_out_b_noaddr(s, COND_EQ);
/* TODO: move this code to where the constants pool will be */
- if (addr_reg != TCG_REG_R0) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R0, 0, addr_reg, SHIFT_IMM_LSL(0));
- }
-# if TARGET_LONG_BITS == 32
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R1, 0, mem_index);
-# else
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
-# endif
+ /* Note that this code relies on the constraints we set in arm_op_defs[]
+ * to ensure that later arguments are not passed to us in registers we
+ * trash by moving the earlier arguments into them.
+ */
+ argreg = TCG_REG_R0;
#ifdef CONFIG_TCG_PASS_AREG0
- /* XXX/FIXME: suboptimal and incorrect for 64 bit */
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[2], 0,
- tcg_target_call_iarg_regs[1], SHIFT_IMM_LSL(0));
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[1], 0,
- tcg_target_call_iarg_regs[0], SHIFT_IMM_LSL(0));
-
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[0], 0, TCG_AREG0,
- SHIFT_IMM_LSL(0));
+ argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0);
#endif
+#if TARGET_LONG_BITS == 64
+ argreg = tcg_out_arg_reg64(s, argreg, addr_reg, addr_reg2);
+#else
+ argreg = tcg_out_arg_reg32(s, argreg, addr_reg);
+#endif
+ argreg = tcg_out_arg_imm32(s, argreg, mem_index);
tcg_out_call(s, (tcg_target_long) qemu_ld_helpers[s_bits]);
+ tcg_out_arg_stacktidy(s, argreg);
switch (opc) {
case 0 | 4:
@@ -1211,6 +1312,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
int addr_reg, data_reg, data_reg2, bswap;
#ifdef CONFIG_SOFTMMU
int mem_index, s_bits;
+ TCGReg argreg;
# if TARGET_LONG_BITS == 64
int addr_reg2;
# endif
@@ -1314,89 +1416,38 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
tcg_out_b_noaddr(s, COND_EQ);
/* TODO: move this code to where the constants pool will be */
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R0, 0, addr_reg, SHIFT_IMM_LSL(0));
-# if TARGET_LONG_BITS == 32
- switch (opc) {
- case 0:
- tcg_out_ext8u(s, COND_AL, TCG_REG_R1, data_reg);
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
- break;
- case 1:
- tcg_out_ext16u(s, COND_AL, TCG_REG_R1, data_reg);
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
- break;
- case 2:
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R1, 0, data_reg, SHIFT_IMM_LSL(0));
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
- break;
- case 3:
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R8, 0, mem_index);
- tcg_out32(s, (COND_AL << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
- if (data_reg != TCG_REG_R2) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
- }
- if (data_reg2 != TCG_REG_R3) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R3, 0, data_reg2, SHIFT_IMM_LSL(0));
- }
- break;
- }
-# else
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
+ /* Note that this code relies on the constraints we set in arm_op_defs[]
+ * to ensure that later arguments are not passed to us in registers we
+ * trash by moving the earlier arguments into them.
+ */
+ argreg = TCG_REG_R0;
+#ifdef CONFIG_TCG_PASS_AREG0
+ argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0);
+#endif
+#if TARGET_LONG_BITS == 64
+ argreg = tcg_out_arg_reg64(s, argreg, addr_reg, addr_reg2);
+#else
+ argreg = tcg_out_arg_reg32(s, argreg, addr_reg);
+#endif
+
switch (opc) {
case 0:
- tcg_out_ext8u(s, COND_AL, TCG_REG_R2, data_reg);
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+ argreg = tcg_out_arg_reg8(s, argreg, data_reg);
break;
case 1:
- tcg_out_ext16u(s, COND_AL, TCG_REG_R2, data_reg);
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+ argreg = tcg_out_arg_reg16(s, argreg, data_reg);
break;
case 2:
- if (data_reg != TCG_REG_R2) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
- }
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+ argreg = tcg_out_arg_reg32(s, argreg, data_reg);
break;
case 3:
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R8, 0, mem_index);
- tcg_out32(s, (COND_AL << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
- if (data_reg != TCG_REG_R2) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
- }
- if (data_reg2 != TCG_REG_R3) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R3, 0, data_reg2, SHIFT_IMM_LSL(0));
- }
+ argreg = tcg_out_arg_reg64(s, argreg, data_reg, data_reg2);
break;
}
-# endif
-
-#ifdef CONFIG_TCG_PASS_AREG0
- /* XXX/FIXME: suboptimal and incorrect for 64 bit */
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[3], 0,
- tcg_target_call_iarg_regs[2], SHIFT_IMM_LSL(0));
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[2], 0,
- tcg_target_call_iarg_regs[1], SHIFT_IMM_LSL(0));
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[1], 0,
- tcg_target_call_iarg_regs[0], SHIFT_IMM_LSL(0));
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[0], 0, TCG_AREG0,
- SHIFT_IMM_LSL(0));
-#endif
+ argreg = tcg_out_arg_imm32(s, argreg, mem_index);
tcg_out_call(s, (tcg_target_long) qemu_st_helpers[s_bits]);
- if (opc == 3)
- tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
+ tcg_out_arg_stacktidy(s, argreg);
reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);
#else /* !CONFIG_SOFTMMU */
diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index e02dacc84..dc588dbea 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -107,7 +107,7 @@ enum {
};
static const int tcg_target_reg_alloc_order[] = {
- TCG_REG_R34,
+ TCG_REG_R33,
TCG_REG_R35,
TCG_REG_R36,
TCG_REG_R37,
@@ -1532,12 +1532,13 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
}
#ifdef CONFIG_TCG_PASS_AREG0
/* XXX/FIXME: suboptimal */
- 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);
+ tcg_out_bundle(s, mII,
+ tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R58,
+ mem_index, TCG_REG_R0),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R57, 0, TCG_REG_R56),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R56, 0, TCG_AREG0));
#endif
if (!bswap || s_bits == 0) {
tcg_out_bundle(s, miB,
@@ -1659,15 +1660,21 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
#ifdef CONFIG_TCG_PASS_AREG0
/* XXX/FIXME: suboptimal */
- 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_bundle(s, mII,
+ tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R59,
+ mem_index, TCG_REG_R0),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R58, 0, TCG_REG_R57),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R57, 0, TCG_REG_R56));
+ tcg_out_bundle(s, miB,
+ tcg_opc_m4 (TCG_REG_P6, opc_st_m4[opc],
+ data_reg, TCG_REG_R3),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R56, 0, TCG_AREG0),
+ tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
+ TCG_REG_B0, TCG_REG_B6));
+#else
tcg_out_bundle(s, miB,
tcg_opc_m4 (TCG_REG_P6, opc_st_m4[opc],
data_reg, TCG_REG_R3),
@@ -1675,6 +1682,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
mem_index, TCG_REG_R0),
tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
TCG_REG_B0, TCG_REG_B6));
+#endif
}
#else /* !CONFIG_SOFTMMU */
@@ -2314,13 +2322,13 @@ static void tcg_target_qemu_prologue(TCGContext *s)
s->code_ptr += 16; /* skip GP */
/* prologue */
- tcg_out_bundle(s, mII,
+ tcg_out_bundle(s, miI,
tcg_opc_m34(TCG_REG_P0, OPC_ALLOC_M34,
- TCG_REG_R33, 32, 24, 0),
+ TCG_REG_R34, 32, 24, 0),
+ tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
+ TCG_AREG0, 0, TCG_REG_R32),
tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21,
- TCG_REG_B6, TCG_REG_R33, 0),
- tcg_opc_i22(TCG_REG_P0, OPC_MOV_I22,
- TCG_REG_R32, TCG_REG_B0));
+ TCG_REG_B6, TCG_REG_R33, 0));
/* ??? If GUEST_BASE < 0x200000, we could load the register via
an ADDL in the M slot of the next bundle. */
@@ -2335,9 +2343,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_bundle(s, miB,
tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
- TCG_AREG0, 0, TCG_REG_R32),
- tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
TCG_REG_R12, -frame_size, TCG_REG_R12),
+ tcg_opc_i22(TCG_REG_P0, OPC_MOV_I22,
+ TCG_REG_R32, TCG_REG_B0),
tcg_opc_b4 (TCG_REG_P0, OPC_BR_SPTK_MANY_B4, TCG_REG_B6));
/* epilogue */
@@ -2351,7 +2359,7 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_bundle(s, miB,
tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
tcg_opc_i26(TCG_REG_P0, OPC_MOV_I_I26,
- TCG_REG_PFS, TCG_REG_R33),
+ TCG_REG_PFS, TCG_REG_R34),
tcg_opc_b4 (TCG_REG_P0, OPC_BR_RET_SPTK_MANY_B4,
TCG_REG_B0));
}
@@ -2403,7 +2411,7 @@ static void tcg_target_init(TCGContext *s)
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R12); /* stack pointer */
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13); /* thread pointer */
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R32); /* return address */
- tcg_regset_set_reg(s->reserved_regs, TCG_REG_R33); /* PFS */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R34); /* PFS */
/* The following 3 are not in use, are call-saved, but *not* saved
by the prologue. Therefore we cannot use them without modifying
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index 393ba07f2..1006e2800 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);