tcg-sparc: Convert to new ldst helpers

All of the helpers with the explicit big/little endian option
require the return address as a parameter.  Acquire this via
a trampoline.

Move the load of areg0 into the trampoline.

Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2014-03-05 09:42:08 -08:00
parent a8b12c108c
commit 7ea5d7256d

View File

@ -806,6 +806,98 @@ static inline void tcg_out_calli(TCGContext *s, uintptr_t dest)
}
}
#ifdef CONFIG_SOFTMMU
static uintptr_t qemu_ld_trampoline[16];
static uintptr_t qemu_st_trampoline[16];
static void build_trampolines(TCGContext *s)
{
static uintptr_t const qemu_ld_helpers[16] = {
[MO_UB] = (uintptr_t)helper_ret_ldub_mmu,
[MO_SB] = (uintptr_t)helper_ret_ldsb_mmu,
[MO_LEUW] = (uintptr_t)helper_le_lduw_mmu,
[MO_LESW] = (uintptr_t)helper_le_ldsw_mmu,
[MO_LEUL] = (uintptr_t)helper_le_ldul_mmu,
[MO_LEQ] = (uintptr_t)helper_le_ldq_mmu,
[MO_BEUW] = (uintptr_t)helper_be_lduw_mmu,
[MO_BESW] = (uintptr_t)helper_be_ldsw_mmu,
[MO_BEUL] = (uintptr_t)helper_be_ldul_mmu,
[MO_BEQ] = (uintptr_t)helper_be_ldq_mmu,
};
static uintptr_t const qemu_st_helpers[16] = {
[MO_UB] = (uintptr_t)helper_ret_stb_mmu,
[MO_LEUW] = (uintptr_t)helper_le_stw_mmu,
[MO_LEUL] = (uintptr_t)helper_le_stl_mmu,
[MO_LEQ] = (uintptr_t)helper_le_stq_mmu,
[MO_BEUW] = (uintptr_t)helper_be_stw_mmu,
[MO_BEUL] = (uintptr_t)helper_be_stl_mmu,
[MO_BEQ] = (uintptr_t)helper_be_stq_mmu,
};
int i;
TCGReg ra;
uintptr_t tramp;
for (i = 0; i < 16; ++i) {
if (qemu_ld_helpers[i] == 0) {
continue;
}
/* May as well align the trampoline. */
tramp = (uintptr_t)s->code_ptr;
while (tramp & 15) {
tcg_out_nop(s);
tramp += 4;
}
qemu_ld_trampoline[i] = tramp;
/* Find the retaddr argument register. */
ra = TCG_REG_O3 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS);
/* Set the retaddr operand. */
tcg_out_mov(s, TCG_TYPE_PTR, ra, TCG_REG_O7);
/* Set the env operand. */
tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O0, TCG_AREG0);
/* Tail call. */
tcg_out_calli(s, qemu_ld_helpers[i]);
tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O7, ra);
}
for (i = 0; i < 16; ++i) {
if (qemu_st_helpers[i] == 0) {
continue;
}
/* May as well align the trampoline. */
tramp = (uintptr_t)s->code_ptr;
while (tramp & 15) {
tcg_out_nop(s);
tramp += 4;
}
qemu_st_trampoline[i] = tramp;
/* Find the retaddr argument. For 32-bit, this may be past the
last argument register, and need passing on the stack. */
ra = (TCG_REG_O4
+ (TARGET_LONG_BITS > TCG_TARGET_REG_BITS)
+ (TCG_TARGET_REG_BITS == 32 && (i & MO_SIZE) == MO_64));
/* Set the retaddr operand. */
if (ra >= TCG_REG_O6) {
tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_O7, TCG_REG_CALL_STACK,
TCG_TARGET_CALL_STACK_OFFSET);
ra = TCG_REG_G1;
}
tcg_out_mov(s, TCG_TYPE_PTR, ra, TCG_REG_O7);
/* Set the env operand. */
tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O0, TCG_AREG0);
/* Tail call. */
tcg_out_calli(s, qemu_st_helpers[i]);
tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O7, ra);
}
}
#endif
/* Generate global QEMU prologue and epilogue code */
static void tcg_target_qemu_prologue(TCGContext *s)
{
@ -838,28 +930,13 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_nop(s);
/* No epilogue required. We issue ret + restore directly in the TB. */
#ifdef CONFIG_SOFTMMU
build_trampolines(s);
#endif
}
#if defined(CONFIG_SOFTMMU)
/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
int mmu_idx) */
static const void * const qemu_ld_helpers[4] = {
helper_ldb_mmu,
helper_ldw_mmu,
helper_ldl_mmu,
helper_ldq_mmu,
};
/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
uintxx_t val, int mmu_idx) */
static const void * const qemu_st_helpers[4] = {
helper_stb_mmu,
helper_stw_mmu,
helper_stl_mmu,
helper_stq_mmu,
};
/* Perform the TLB load and compare.
Inputs:
@ -966,8 +1043,9 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, TCGMemOp memop)
TCGReg addrlo, datalo, datahi, addr_reg;
TCGMemOp s_bits = memop & MO_SIZE;
#if defined(CONFIG_SOFTMMU)
TCGReg addrhi;
int memi, n;
TCGReg addrhi, param;
uintptr_t func;
int memi;
uint32_t *label_ptr[2];
#endif
@ -1025,46 +1103,39 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, TCGMemOp memop)
*label_ptr[0] |= INSN_OFF19((unsigned long)s->code_ptr -
(unsigned long)label_ptr[0]);
}
n = 0;
tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[n++], TCG_AREG0);
param = TCG_REG_O1;
if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], addrhi);
tcg_out_mov(s, TCG_TYPE_REG, param++, addrhi);
}
tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], addrlo);
tcg_out_mov(s, TCG_TYPE_REG, param++, addrlo);
/* qemu_ld_helper[s_bits](arg0, arg1) */
tcg_out_calli(s, (uintptr_t)qemu_ld_helpers[s_bits]);
/* We use the helpers to extend SB and SW data, leaving the case
of SL needing explicit extending below. */
if ((memop & ~MO_BSWAP) == MO_SL) {
func = qemu_ld_trampoline[memop & ~MO_SIGN];
} else {
func = qemu_ld_trampoline[memop];
}
assert(func != 0);
tcg_out_calli(s, func);
/* delay slot */
tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[n], memi);
tcg_out_movi(s, TCG_TYPE_I32, param, memi);
n = tcg_target_call_oarg_regs[0];
/* datalo = sign_extend(arg0) */
switch (memop & MO_SSIZE) {
case MO_SB:
/* Recall that SRA sign extends from bit 31 through bit 63. */
tcg_out_arithi(s, datalo, n, 24, SHIFT_SLL);
tcg_out_arithi(s, datalo, datalo, 24, SHIFT_SRA);
break;
case MO_SW:
tcg_out_arithi(s, datalo, n, 16, SHIFT_SLL);
tcg_out_arithi(s, datalo, datalo, 16, SHIFT_SRA);
break;
switch (memop & ~MO_BSWAP) {
case MO_SL:
tcg_out_arithi(s, datalo, n, 0, SHIFT_SRA);
tcg_out_arithi(s, datalo, TCG_REG_O0, 0, SHIFT_SRA);
break;
case MO_Q:
if (TCG_TARGET_REG_BITS == 32) {
tcg_out_mov(s, TCG_TYPE_REG, datahi, n);
tcg_out_mov(s, TCG_TYPE_REG, datalo, n + 1);
tcg_out_mov(s, TCG_TYPE_REG, datahi, TCG_REG_O0);
tcg_out_mov(s, TCG_TYPE_REG, datalo, TCG_REG_O1);
break;
}
/* FALLTHRU */
case MO_UB:
case MO_UW:
case MO_UL:
default:
/* mov */
tcg_out_mov(s, TCG_TYPE_REG, datalo, n);
tcg_out_mov(s, TCG_TYPE_REG, datalo, TCG_REG_O0);
break;
}
@ -1099,8 +1170,9 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, TCGMemOp memop)
TCGReg addrlo, datalo, datahi, addr_reg;
TCGMemOp s_bits = memop & MO_SIZE;
#if defined(CONFIG_SOFTMMU)
TCGReg addrhi, datafull;
int memi, n;
TCGReg addrhi, datafull, param;
uintptr_t func;
int memi;
uint32_t *label_ptr;
#endif
@ -1135,21 +1207,21 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, TCGMemOp memop)
/* TLB Miss. */
n = 0;
tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[n++], TCG_AREG0);
param = TCG_REG_O1;
if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], addrhi);
tcg_out_mov(s, TCG_TYPE_REG, param++, addrhi);
}
tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], addrlo);
tcg_out_mov(s, TCG_TYPE_REG, param++, addrlo);
if (TCG_TARGET_REG_BITS == 32 && s_bits == MO_64) {
tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], datahi);
tcg_out_mov(s, TCG_TYPE_REG, param++, datahi);
}
tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], datalo);
tcg_out_mov(s, TCG_TYPE_REG, param++, datalo);
/* qemu_st_helper[s_bits](arg0, arg1, arg2) */
tcg_out_calli(s, (uintptr_t)qemu_st_helpers[s_bits]);
func = qemu_st_trampoline[memop];
assert(func != 0);
tcg_out_calli(s, func);
/* delay slot */
tcg_out_movi(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n], memi);
tcg_out_movi(s, TCG_TYPE_REG, param, memi);
*label_ptr |= INSN_OFF19((unsigned long)s->code_ptr -
(unsigned long)label_ptr);