target/sparc: Move simple fp load/store to decodetree

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:
Richard Henderson 2023-10-05 01:38:50 -07:00
parent 3259b9e2fd
commit 06c060d9e5
2 changed files with 113 additions and 100 deletions

View File

@ -238,8 +238,16 @@ NCP 10 ----- 110111 ----- --------- ----- # v8 CPop2
## Major Opcode 11 -- load and store instructions ## Major Opcode 11 -- load and store instructions
## ##
%dfp_rd 25:5 !function=extract_dfpreg
%qfp_rd 25:5 !function=extract_qfpreg
&r_r_ri_asi rd rs1 rs2_or_imm asi imm:bool &r_r_ri_asi rd rs1 rs2_or_imm asi imm:bool
@r_r_ri_na .. rd:5 ...... rs1:5 imm:1 rs2_or_imm:s13 &r_r_ri_asi asi=-1 @r_r_ri_na .. rd:5 ...... rs1:5 imm:1 rs2_or_imm:s13 &r_r_ri_asi asi=-1
@d_r_ri_na .. ..... ...... rs1:5 imm:1 rs2_or_imm:s13 \
&r_r_ri_asi rd=%dfp_rd asi=-1
@q_r_ri_na .. ..... ...... rs1:5 imm:1 rs2_or_imm:s13 \
&r_r_ri_asi rd=%qfp_rd asi=-1
@r_r_r_asi .. rd:5 ...... rs1:5 0 asi:8 rs2_or_imm:5 &r_r_ri_asi imm=0 @r_r_r_asi .. rd:5 ...... rs1:5 0 asi:8 rs2_or_imm:5 &r_r_ri_asi imm=0
@r_r_i_asi .. rd:5 ...... rs1:5 1 rs2_or_imm:s13 \ @r_r_i_asi .. rd:5 ...... rs1:5 1 rs2_or_imm:s13 \
&r_r_ri_asi imm=1 asi=-2 &r_r_ri_asi imm=1 asi=-2
@ -289,6 +297,17 @@ STD 11 ..... 010111 ..... . ............. @r_r_i_asi # STDA
STX 11 ..... 011110 ..... . ............. @r_r_r_asi # STXA STX 11 ..... 011110 ..... . ............. @r_r_r_asi # STXA
STX 11 ..... 011110 ..... . ............. @r_r_i_asi # STXA STX 11 ..... 011110 ..... . ............. @r_r_i_asi # STXA
LDF 11 ..... 100000 ..... . ............. @r_r_ri_na
LDQF 11 ..... 100010 ..... . ............. @q_r_ri_na
LDDF 11 ..... 100011 ..... . ............. @d_r_ri_na
STF 11 ..... 100100 ..... . ............. @r_r_ri_na
{
STQF 11 ..... 100110 ..... . ............. @q_r_ri_na
STDFQ 11 ----- 100110 ----- - -------------
}
STDF 11 ..... 100111 ..... . ............. @d_r_ri_na
LDSTUB 11 ..... 001101 ..... . ............. @r_r_ri_na LDSTUB 11 ..... 001101 ..... . ............. @r_r_ri_na
LDSTUB 11 ..... 011101 ..... . ............. @r_r_r_asi # LDSTUBA LDSTUB 11 ..... 011101 ..... . ............. @r_r_r_asi # LDSTUBA
LDSTUB 11 ..... 011101 ..... . ............. @r_r_i_asi # LDSTUBA LDSTUB 11 ..... 011101 ..... . ............. @r_r_i_asi # LDSTUBA

View File

@ -254,29 +254,7 @@ static void gen_op_store_QT0_fpr(unsigned int dst)
offsetof(CPU_QuadU, ll.lower)); offsetof(CPU_QuadU, ll.lower));
} }
static void gen_store_fpr_Q(DisasContext *dc, unsigned int dst,
TCGv_i64 v1, TCGv_i64 v2)
{
dst = QFPREG(dst);
tcg_gen_mov_i64(cpu_fpr[dst / 2], v1);
tcg_gen_mov_i64(cpu_fpr[dst / 2 + 1], v2);
gen_update_fprs_dirty(dc, dst);
}
#ifdef TARGET_SPARC64 #ifdef TARGET_SPARC64
static TCGv_i64 gen_load_fpr_Q0(DisasContext *dc, unsigned int src)
{
src = QFPREG(src);
return cpu_fpr[src / 2];
}
static TCGv_i64 gen_load_fpr_Q1(DisasContext *dc, unsigned int src)
{
src = QFPREG(src);
return cpu_fpr[src / 2 + 1];
}
static void gen_move_Q(DisasContext *dc, unsigned int rd, unsigned int rs) static void gen_move_Q(DisasContext *dc, unsigned int rd, unsigned int rs)
{ {
rd = QFPREG(rd); rd = QFPREG(rd);
@ -2900,6 +2878,16 @@ static void gen_faligndata(TCGv dst, TCGv gsr, TCGv s1, TCGv s2)
} }
#endif #endif
static int extract_dfpreg(DisasContext *dc, int x)
{
return DFPREG(x);
}
static int extract_qfpreg(DisasContext *dc, int x)
{
return QFPREG(x);
}
/* Include the auto-generated decoder. */ /* Include the auto-generated decoder. */
#include "decode-insns.c.inc" #include "decode-insns.c.inc"
@ -3035,6 +3023,20 @@ static bool raise_priv(DisasContext *dc)
return true; return true;
} }
static bool raise_unimpfpop(DisasContext *dc)
{
gen_op_fpexception_im(dc, FSR_FTT_UNIMPFPOP);
return true;
}
static bool gen_trap_float128(DisasContext *dc)
{
if (dc->def->features & CPU_FEATURE_FLOAT128) {
return false;
}
return raise_unimpfpop(dc);
}
static bool do_bpcc(DisasContext *dc, arg_bcc *a) static bool do_bpcc(DisasContext *dc, arg_bcc *a)
{ {
target_long target = address_mask_i(dc, dc->pc + a->i * 4); target_long target = address_mask_i(dc, dc->pc + a->i * 4);
@ -4633,6 +4635,68 @@ static bool do_casa(DisasContext *dc, arg_r_r_ri_asi *a, MemOp mop)
TRANS(CASA, CASA, do_casa, a, MO_TEUL) TRANS(CASA, CASA, do_casa, a, MO_TEUL)
TRANS(CASXA, 64, do_casa, a, MO_TEUQ) TRANS(CASXA, 64, do_casa, a, MO_TEUQ)
static bool do_ld_fpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp sz)
{
TCGv addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
DisasASI da;
if (addr == NULL) {
return false;
}
if (gen_trap_ifnofpu(dc)) {
return true;
}
if (sz == MO_128 && gen_trap_float128(dc)) {
return true;
}
da = resolve_asi(dc, a->asi, MO_TE | sz);
gen_ldf_asi0(dc, &da, sz, addr, a->rd);
gen_update_fprs_dirty(dc, a->rd);
return advance_pc(dc);
}
TRANS(LDF, ALL, do_ld_fpr, a, MO_32)
TRANS(LDDF, ALL, do_ld_fpr, a, MO_64)
TRANS(LDQF, ALL, do_ld_fpr, a, MO_128)
static bool do_st_fpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp sz)
{
TCGv addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
DisasASI da;
if (addr == NULL) {
return false;
}
if (gen_trap_ifnofpu(dc)) {
return true;
}
if (sz == MO_128 && gen_trap_float128(dc)) {
return true;
}
da = resolve_asi(dc, a->asi, MO_TE | sz);
gen_stf_asi0(dc, &da, sz, addr, a->rd);
return advance_pc(dc);
}
TRANS(STF, ALL, do_st_fpr, a, MO_32)
TRANS(STDF, ALL, do_st_fpr, a, MO_64)
TRANS(STQF, ALL, do_st_fpr, a, MO_128)
static bool trans_STDFQ(DisasContext *dc, arg_STDFQ *a)
{
if (!avail_32(dc)) {
return false;
}
if (!supervisor(dc)) {
return raise_priv(dc);
}
if (gen_trap_ifnofpu(dc)) {
return true;
}
gen_op_fpexception_im(dc, FSR_FTT_SEQ_ERROR);
return true;
}
#define CHECK_IU_FEATURE(dc, FEATURE) \ #define CHECK_IU_FEATURE(dc, FEATURE) \
if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE)) \ if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE)) \
goto illegal_insn; goto illegal_insn;
@ -4647,7 +4711,8 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
TCGv cpu_src1 __attribute__((unused)); TCGv cpu_src1 __attribute__((unused));
TCGv cpu_src2 __attribute__((unused)); TCGv cpu_src2 __attribute__((unused));
TCGv_i32 cpu_src1_32, cpu_src2_32, cpu_dst_32; TCGv_i32 cpu_src1_32, cpu_src2_32, cpu_dst_32;
TCGv_i64 cpu_src1_64, cpu_src2_64, cpu_dst_64; TCGv_i64 cpu_src1_64, cpu_src2_64;
TCGv_i64 cpu_dst_64 __attribute__((unused));
target_long simm; target_long simm;
opc = GET_FIELD(insn, 0, 1); opc = GET_FIELD(insn, 0, 1);
@ -5514,12 +5579,9 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
} }
switch (xop) { switch (xop) {
case 0x20: /* ldf, load fpreg */ case 0x20: /* ldf, load fpreg */
gen_address_mask(dc, cpu_addr); case 0x22: /* ldqf, load quad fpreg */
cpu_dst_32 = gen_dest_fpr_F(dc); case 0x23: /* lddf, load double fpreg */
tcg_gen_qemu_ld_i32(cpu_dst_32, cpu_addr, g_assert_not_reached(); /* in decodetree */
dc->mem_idx, MO_TEUL | MO_ALIGN);
gen_store_fpr_F(dc, rd, cpu_dst_32);
break;
case 0x21: /* ldfsr, V9 ldxfsr */ case 0x21: /* ldfsr, V9 ldxfsr */
#ifdef TARGET_SPARC64 #ifdef TARGET_SPARC64
gen_address_mask(dc, cpu_addr); gen_address_mask(dc, cpu_addr);
@ -5536,25 +5598,6 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
dc->mem_idx, MO_TEUL | MO_ALIGN); dc->mem_idx, MO_TEUL | MO_ALIGN);
gen_helper_ldfsr(cpu_fsr, tcg_env, cpu_fsr, cpu_dst_32); gen_helper_ldfsr(cpu_fsr, tcg_env, cpu_fsr, cpu_dst_32);
break; break;
case 0x22: /* ldqf, load quad fpreg */
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_address_mask(dc, cpu_addr);
cpu_src1_64 = tcg_temp_new_i64();
tcg_gen_qemu_ld_i64(cpu_src1_64, cpu_addr, dc->mem_idx,
MO_TEUQ | MO_ALIGN_4);
tcg_gen_addi_tl(cpu_addr, cpu_addr, 8);
cpu_src2_64 = tcg_temp_new_i64();
tcg_gen_qemu_ld_i64(cpu_src2_64, cpu_addr, dc->mem_idx,
MO_TEUQ | MO_ALIGN_4);
gen_store_fpr_Q(dc, rd, cpu_src1_64, cpu_src2_64);
break;
case 0x23: /* lddf, load double fpreg */
gen_address_mask(dc, cpu_addr);
cpu_dst_64 = gen_dest_fpr_D(dc, rd);
tcg_gen_qemu_ld_i64(cpu_dst_64, cpu_addr, dc->mem_idx,
MO_TEUQ | MO_ALIGN_4);
gen_store_fpr_D(dc, rd, cpu_dst_64);
break;
default: default:
goto illegal_insn; goto illegal_insn;
} }
@ -5564,11 +5607,9 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
} }
switch (xop) { switch (xop) {
case 0x24: /* stf, store fpreg */ case 0x24: /* stf, store fpreg */
gen_address_mask(dc, cpu_addr); case 0x26: /* v9 stqf, v8 stdfq */
cpu_src1_32 = gen_load_fpr_F(dc, rd); case 0x27: /* stdf, store double fpreg */
tcg_gen_qemu_st_i32(cpu_src1_32, cpu_addr, g_assert_not_reached();
dc->mem_idx, MO_TEUL | MO_ALIGN);
break;
case 0x25: /* stfsr, V9 stxfsr */ case 0x25: /* stfsr, V9 stxfsr */
{ {
#ifdef TARGET_SPARC64 #ifdef TARGET_SPARC64
@ -5583,43 +5624,6 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
dc->mem_idx, MO_TEUL | MO_ALIGN); dc->mem_idx, MO_TEUL | MO_ALIGN);
} }
break; break;
case 0x26:
#ifdef TARGET_SPARC64
/* V9 stqf, store quad fpreg */
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_address_mask(dc, cpu_addr);
/* ??? While stqf only requires 4-byte alignment, it is
legal for the cpu to signal the unaligned exception.
The OS trap handler is then required to fix it up.
For qemu, this avoids having to probe the second page
before performing the first write. */
cpu_src1_64 = gen_load_fpr_Q0(dc, rd);
tcg_gen_qemu_st_i64(cpu_src1_64, cpu_addr,
dc->mem_idx, MO_TEUQ | MO_ALIGN_16);
tcg_gen_addi_tl(cpu_addr, cpu_addr, 8);
cpu_src2_64 = gen_load_fpr_Q1(dc, rd);
tcg_gen_qemu_st_i64(cpu_src1_64, cpu_addr,
dc->mem_idx, MO_TEUQ);
break;
#else /* !TARGET_SPARC64 */
/* stdfq, store floating point queue */
#if defined(CONFIG_USER_ONLY)
goto illegal_insn;
#else
if (!supervisor(dc))
goto priv_insn;
if (gen_trap_ifnofpu(dc)) {
goto jmp_insn;
}
goto nfq_insn;
#endif
#endif
case 0x27: /* stdf, store double fpreg */
gen_address_mask(dc, cpu_addr);
cpu_src1_64 = gen_load_fpr_D(dc, rd);
tcg_gen_qemu_st_i64(cpu_src1_64, cpu_addr, dc->mem_idx,
MO_TEUQ | MO_ALIGN_4);
break;
default: default:
goto illegal_insn; goto illegal_insn;
} }
@ -5666,19 +5670,9 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
illegal_insn: illegal_insn:
gen_exception(dc, TT_ILL_INSN); gen_exception(dc, TT_ILL_INSN);
return; return;
#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
priv_insn:
gen_exception(dc, TT_PRIV_INSN);
return;
#endif
nfpu_insn: nfpu_insn:
gen_op_fpexception_im(dc, FSR_FTT_UNIMPFPOP); gen_op_fpexception_im(dc, FSR_FTT_UNIMPFPOP);
return; return;
#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
nfq_insn:
gen_op_fpexception_im(dc, FSR_FTT_SEQ_ERROR);
return;
#endif
} }
static void sparc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) static void sparc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)