target/sparc: Split out fp ldst functions with asi precomputed
Take the operation size from the MemOp instead of a separate parameter. Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
5458fd3153
commit
3259b9e2fd
@ -2320,35 +2320,41 @@ static void gen_ldstub_asi(DisasContext *dc, DisasASI *da, TCGv dst, TCGv addr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __attribute__((unused))
|
static void gen_ldf_asi0(DisasContext *dc, DisasASI *da, MemOp orig_size,
|
||||||
gen_ldf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd)
|
TCGv addr, int rd)
|
||||||
{
|
{
|
||||||
DisasASI da = get_asi(dc, insn, (size == 4 ? MO_TEUL : MO_TEUQ));
|
MemOp memop = da->memop;
|
||||||
|
MemOp size = memop & MO_SIZE;
|
||||||
TCGv_i32 d32;
|
TCGv_i32 d32;
|
||||||
TCGv_i64 d64;
|
TCGv_i64 d64;
|
||||||
|
|
||||||
switch (da.type) {
|
/* TODO: Use 128-bit load/store below. */
|
||||||
|
if (size == MO_128) {
|
||||||
|
memop = (memop & ~MO_SIZE) | MO_64;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (da->type) {
|
||||||
case GET_ASI_EXCP:
|
case GET_ASI_EXCP:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GET_ASI_DIRECT:
|
case GET_ASI_DIRECT:
|
||||||
gen_address_mask(dc, addr);
|
memop |= MO_ALIGN_4;
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 4:
|
case MO_32:
|
||||||
d32 = gen_dest_fpr_F(dc);
|
d32 = gen_dest_fpr_F(dc);
|
||||||
tcg_gen_qemu_ld_i32(d32, addr, da.mem_idx, da.memop | MO_ALIGN);
|
tcg_gen_qemu_ld_i32(d32, addr, da->mem_idx, memop);
|
||||||
gen_store_fpr_F(dc, rd, d32);
|
gen_store_fpr_F(dc, rd, d32);
|
||||||
break;
|
break;
|
||||||
case 8:
|
|
||||||
tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da.mem_idx,
|
case MO_64:
|
||||||
da.memop | MO_ALIGN_4);
|
tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da->mem_idx, memop);
|
||||||
break;
|
break;
|
||||||
case 16:
|
|
||||||
|
case MO_128:
|
||||||
d64 = tcg_temp_new_i64();
|
d64 = tcg_temp_new_i64();
|
||||||
tcg_gen_qemu_ld_i64(d64, addr, da.mem_idx, da.memop | MO_ALIGN_4);
|
tcg_gen_qemu_ld_i64(d64, addr, da->mem_idx, memop);
|
||||||
tcg_gen_addi_tl(addr, addr, 8);
|
tcg_gen_addi_tl(addr, addr, 8);
|
||||||
tcg_gen_qemu_ld_i64(cpu_fpr[rd/2+1], addr, da.mem_idx,
|
tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2 + 1], addr, da->mem_idx, memop);
|
||||||
da.memop | MO_ALIGN_4);
|
|
||||||
tcg_gen_mov_i64(cpu_fpr[rd / 2], d64);
|
tcg_gen_mov_i64(cpu_fpr[rd / 2], d64);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -2358,24 +2364,19 @@ gen_ldf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd)
|
|||||||
|
|
||||||
case GET_ASI_BLOCK:
|
case GET_ASI_BLOCK:
|
||||||
/* Valid for lddfa on aligned registers only. */
|
/* Valid for lddfa on aligned registers only. */
|
||||||
if (size == 8 && (rd & 7) == 0) {
|
if (orig_size == MO_64 && (rd & 7) == 0) {
|
||||||
MemOp memop;
|
|
||||||
TCGv eight;
|
TCGv eight;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
gen_address_mask(dc, addr);
|
|
||||||
|
|
||||||
/* The first operation checks required alignment. */
|
/* The first operation checks required alignment. */
|
||||||
memop = da.memop | MO_ALIGN_64;
|
|
||||||
eight = tcg_constant_tl(8);
|
eight = tcg_constant_tl(8);
|
||||||
for (i = 0; ; ++i) {
|
for (i = 0; ; ++i) {
|
||||||
tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2 + i], addr,
|
tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2 + i], addr, da->mem_idx,
|
||||||
da.mem_idx, memop);
|
memop | (i == 0 ? MO_ALIGN_64 : 0));
|
||||||
if (i == 7) {
|
if (i == 7) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tcg_gen_add_tl(addr, addr, eight);
|
tcg_gen_add_tl(addr, addr, eight);
|
||||||
memop = da.memop;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gen_exception(dc, TT_ILL_INSN);
|
gen_exception(dc, TT_ILL_INSN);
|
||||||
@ -2384,10 +2385,9 @@ gen_ldf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd)
|
|||||||
|
|
||||||
case GET_ASI_SHORT:
|
case GET_ASI_SHORT:
|
||||||
/* Valid for lddfa only. */
|
/* Valid for lddfa only. */
|
||||||
if (size == 8) {
|
if (orig_size == MO_64) {
|
||||||
gen_address_mask(dc, addr);
|
tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da->mem_idx,
|
||||||
tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da.mem_idx,
|
memop | MO_ALIGN);
|
||||||
da.memop | MO_ALIGN);
|
|
||||||
} else {
|
} else {
|
||||||
gen_exception(dc, TT_ILL_INSN);
|
gen_exception(dc, TT_ILL_INSN);
|
||||||
}
|
}
|
||||||
@ -2395,8 +2395,8 @@ gen_ldf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd)
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
TCGv_i32 r_asi = tcg_constant_i32(da.asi);
|
TCGv_i32 r_asi = tcg_constant_i32(da->asi);
|
||||||
TCGv_i32 r_mop = tcg_constant_i32(da.memop | MO_ALIGN);
|
TCGv_i32 r_mop = tcg_constant_i32(memop | MO_ALIGN);
|
||||||
|
|
||||||
save_state(dc);
|
save_state(dc);
|
||||||
/* According to the table in the UA2011 manual, the only
|
/* According to the table in the UA2011 manual, the only
|
||||||
@ -2404,21 +2404,23 @@ gen_ldf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd)
|
|||||||
the NO_FAULT asis. We still need a helper for these,
|
the NO_FAULT asis. We still need a helper for these,
|
||||||
but we can just use the integer asi helper for them. */
|
but we can just use the integer asi helper for them. */
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 4:
|
case MO_32:
|
||||||
d64 = tcg_temp_new_i64();
|
d64 = tcg_temp_new_i64();
|
||||||
gen_helper_ld_asi(d64, tcg_env, addr, r_asi, r_mop);
|
gen_helper_ld_asi(d64, tcg_env, addr, r_asi, r_mop);
|
||||||
d32 = gen_dest_fpr_F(dc);
|
d32 = gen_dest_fpr_F(dc);
|
||||||
tcg_gen_extrl_i64_i32(d32, d64);
|
tcg_gen_extrl_i64_i32(d32, d64);
|
||||||
gen_store_fpr_F(dc, rd, d32);
|
gen_store_fpr_F(dc, rd, d32);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case MO_64:
|
||||||
gen_helper_ld_asi(cpu_fpr[rd / 2], tcg_env, addr, r_asi, r_mop);
|
gen_helper_ld_asi(cpu_fpr[rd / 2], tcg_env, addr,
|
||||||
|
r_asi, r_mop);
|
||||||
break;
|
break;
|
||||||
case 16:
|
case MO_128:
|
||||||
d64 = tcg_temp_new_i64();
|
d64 = tcg_temp_new_i64();
|
||||||
gen_helper_ld_asi(d64, tcg_env, addr, r_asi, r_mop);
|
gen_helper_ld_asi(d64, tcg_env, addr, r_asi, r_mop);
|
||||||
tcg_gen_addi_tl(addr, addr, 8);
|
tcg_gen_addi_tl(addr, addr, 8);
|
||||||
gen_helper_ld_asi(cpu_fpr[rd/2+1], tcg_env, addr, r_asi, r_mop);
|
gen_helper_ld_asi(cpu_fpr[rd / 2 + 1], tcg_env, addr,
|
||||||
|
r_asi, r_mop);
|
||||||
tcg_gen_mov_i64(cpu_fpr[rd / 2], d64);
|
tcg_gen_mov_i64(cpu_fpr[rd / 2], d64);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -2430,36 +2432,52 @@ gen_ldf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void __attribute__((unused))
|
static void __attribute__((unused))
|
||||||
gen_stf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd)
|
gen_ldf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd)
|
||||||
{
|
{
|
||||||
DisasASI da = get_asi(dc, insn, (size == 4 ? MO_TEUL : MO_TEUQ));
|
MemOp sz = ctz32(size);
|
||||||
|
DisasASI da = get_asi(dc, insn, MO_TE | sz);
|
||||||
|
|
||||||
|
gen_address_mask(dc, addr);
|
||||||
|
gen_ldf_asi0(dc, &da, sz, addr, rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_stf_asi0(DisasContext *dc, DisasASI *da, MemOp orig_size,
|
||||||
|
TCGv addr, int rd)
|
||||||
|
{
|
||||||
|
MemOp memop = da->memop;
|
||||||
|
MemOp size = memop & MO_SIZE;
|
||||||
TCGv_i32 d32;
|
TCGv_i32 d32;
|
||||||
|
|
||||||
switch (da.type) {
|
/* TODO: Use 128-bit load/store below. */
|
||||||
|
if (size == MO_128) {
|
||||||
|
memop = (memop & ~MO_SIZE) | MO_64;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (da->type) {
|
||||||
case GET_ASI_EXCP:
|
case GET_ASI_EXCP:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GET_ASI_DIRECT:
|
case GET_ASI_DIRECT:
|
||||||
gen_address_mask(dc, addr);
|
memop |= MO_ALIGN_4;
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 4:
|
case MO_32:
|
||||||
d32 = gen_load_fpr_F(dc, rd);
|
d32 = gen_load_fpr_F(dc, rd);
|
||||||
tcg_gen_qemu_st_i32(d32, addr, da.mem_idx, da.memop | MO_ALIGN);
|
tcg_gen_qemu_st_i32(d32, addr, da->mem_idx, memop | MO_ALIGN);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case MO_64:
|
||||||
tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da.mem_idx,
|
tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da->mem_idx,
|
||||||
da.memop | MO_ALIGN_4);
|
memop | MO_ALIGN_4);
|
||||||
break;
|
break;
|
||||||
case 16:
|
case MO_128:
|
||||||
/* Only 4-byte alignment required. However, it is legal for the
|
/* Only 4-byte alignment required. However, it is legal for the
|
||||||
cpu to signal the alignment fault, and the OS trap handler is
|
cpu to signal the alignment fault, and the OS trap handler is
|
||||||
required to fix it up. Requiring 16-byte alignment here avoids
|
required to fix it up. Requiring 16-byte alignment here avoids
|
||||||
having to probe the second page before performing the first
|
having to probe the second page before performing the first
|
||||||
write. */
|
write. */
|
||||||
tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da.mem_idx,
|
tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da->mem_idx,
|
||||||
da.memop | MO_ALIGN_16);
|
memop | MO_ALIGN_16);
|
||||||
tcg_gen_addi_tl(addr, addr, 8);
|
tcg_gen_addi_tl(addr, addr, 8);
|
||||||
tcg_gen_qemu_st_i64(cpu_fpr[rd/2+1], addr, da.mem_idx, da.memop);
|
tcg_gen_qemu_st_i64(cpu_fpr[rd / 2 + 1], addr, da->mem_idx, memop);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
@ -2468,24 +2486,19 @@ gen_stf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd)
|
|||||||
|
|
||||||
case GET_ASI_BLOCK:
|
case GET_ASI_BLOCK:
|
||||||
/* Valid for stdfa on aligned registers only. */
|
/* Valid for stdfa on aligned registers only. */
|
||||||
if (size == 8 && (rd & 7) == 0) {
|
if (orig_size == MO_64 && (rd & 7) == 0) {
|
||||||
MemOp memop;
|
|
||||||
TCGv eight;
|
TCGv eight;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
gen_address_mask(dc, addr);
|
|
||||||
|
|
||||||
/* The first operation checks required alignment. */
|
/* The first operation checks required alignment. */
|
||||||
memop = da.memop | MO_ALIGN_64;
|
|
||||||
eight = tcg_constant_tl(8);
|
eight = tcg_constant_tl(8);
|
||||||
for (i = 0; ; ++i) {
|
for (i = 0; ; ++i) {
|
||||||
tcg_gen_qemu_st_i64(cpu_fpr[rd / 2 + i], addr,
|
tcg_gen_qemu_st_i64(cpu_fpr[rd / 2 + i], addr, da->mem_idx,
|
||||||
da.mem_idx, memop);
|
memop | (i == 0 ? MO_ALIGN_64 : 0));
|
||||||
if (i == 7) {
|
if (i == 7) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tcg_gen_add_tl(addr, addr, eight);
|
tcg_gen_add_tl(addr, addr, eight);
|
||||||
memop = da.memop;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gen_exception(dc, TT_ILL_INSN);
|
gen_exception(dc, TT_ILL_INSN);
|
||||||
@ -2494,10 +2507,9 @@ gen_stf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd)
|
|||||||
|
|
||||||
case GET_ASI_SHORT:
|
case GET_ASI_SHORT:
|
||||||
/* Valid for stdfa only. */
|
/* Valid for stdfa only. */
|
||||||
if (size == 8) {
|
if (orig_size == MO_64) {
|
||||||
gen_address_mask(dc, addr);
|
tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da->mem_idx,
|
||||||
tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da.mem_idx,
|
memop | MO_ALIGN);
|
||||||
da.memop | MO_ALIGN);
|
|
||||||
} else {
|
} else {
|
||||||
gen_exception(dc, TT_ILL_INSN);
|
gen_exception(dc, TT_ILL_INSN);
|
||||||
}
|
}
|
||||||
@ -2512,6 +2524,16 @@ gen_stf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __attribute__((unused))
|
||||||
|
gen_stf_asi(DisasContext *dc, TCGv addr, int insn, int size, int rd)
|
||||||
|
{
|
||||||
|
MemOp sz = ctz32(size);
|
||||||
|
DisasASI da = get_asi(dc, insn, MO_TE | sz);
|
||||||
|
|
||||||
|
gen_address_mask(dc, addr);
|
||||||
|
gen_stf_asi0(dc, &da, sz, addr, rd);
|
||||||
|
}
|
||||||
|
|
||||||
static void gen_ldda_asi(DisasContext *dc, DisasASI *da, TCGv addr, int rd)
|
static void gen_ldda_asi(DisasContext *dc, DisasASI *da, TCGv addr, int rd)
|
||||||
{
|
{
|
||||||
TCGv hi = gen_dest_gpr(dc, rd);
|
TCGv hi = gen_dest_gpr(dc, rd);
|
||||||
|
Loading…
Reference in New Issue
Block a user