Message ID | 20211118132502.984059-2-lucas.araujo@eldorado.org.br (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Fix mtfsf, mtfsfi and mtfsb1 bug | expand |
On 11/18/21 2:25 PM, Lucas Mateus Castro (alqotel) wrote: > + if ((fpscr & FP_VXSOFT) && (fpscr_ve != 0)) { > + error = POWERPC_EXCP_FP_VXSOFT; > + } else if ((fpscr & FP_OX) && (fpscr & FP_OE)) { > + error = POWERPC_EXCP_FP_OX; > + } else if ((fpscr & FP_UX) && (fpscr & FP_UE)) { > + error = POWERPC_EXCP_FP_UX; > + } else if ((fpscr & FP_XX) && (fpscr & FP_XE)) { > + error = POWERPC_EXCP_FP_XX; > + } else if ((fpscr & FP_ZX) && (fpscr & FP_ZE)) { > + error = POWERPC_EXCP_FP_ZX; > + } else if ((fpscr & FP_VXSNAN) && (fpscr_ve != 0)) { > + error = POWERPC_EXCP_FP_VXSNAN; > + } else if ((fpscr & FP_VXISI) && (fpscr_ve != 0)) { > + error = POWERPC_EXCP_FP_VXISI; > + } else if ((fpscr & FP_VXIDI) && (fpscr_ve != 0)) { > + error = POWERPC_EXCP_FP_VXIDI; > + } else if ((fpscr & FP_VXZDZ) && (fpscr_ve != 0)) { > + error = POWERPC_EXCP_FP_VXZDZ; > + } else if ((fpscr & FP_VXIMZ) && (fpscr_ve != 0)) { > + error = POWERPC_EXCP_FP_VXIMZ; > + } else if ((fpscr & FP_VXVC) && (fpscr_ve != 0)) { > + error = POWERPC_EXCP_FP_VXVC; > + } Is there a defined order for these in the manual? I couldn't find it quickly if so. If there is no defined order, I think you should test VE only once. Drop the use of fpscr_ve and use fpscr & FP_VE instead. (I think these hidden uses of *env are evil and should be banished, but that's a bit of a job.) You could say } else { return; } > + > + if (error) { and then remove this test. The rest of it looks good. r~
On 11/19/21 10:18, Richard Henderson wrote: > On 11/18/21 2:25 PM, Lucas Mateus Castro (alqotel) wrote: >> + if ((fpscr & FP_VXSOFT) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXSOFT; >> + } else if ((fpscr & FP_OX) && (fpscr & FP_OE)) { >> + error = POWERPC_EXCP_FP_OX; >> + } else if ((fpscr & FP_UX) && (fpscr & FP_UE)) { >> + error = POWERPC_EXCP_FP_UX; >> + } else if ((fpscr & FP_XX) && (fpscr & FP_XE)) { >> + error = POWERPC_EXCP_FP_XX; >> + } else if ((fpscr & FP_ZX) && (fpscr & FP_ZE)) { >> + error = POWERPC_EXCP_FP_ZX; >> + } else if ((fpscr & FP_VXSNAN) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXSNAN; >> + } else if ((fpscr & FP_VXISI) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXISI; >> + } else if ((fpscr & FP_VXIDI) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXIDI; >> + } else if ((fpscr & FP_VXZDZ) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXZDZ; >> + } else if ((fpscr & FP_VXIMZ) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXIMZ; >> + } else if ((fpscr & FP_VXVC) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXVC; >> + } > > Is there a defined order for these in the manual? I couldn't find it quickly if so. If there is no defined order, I think you should test VE only once. > > Drop the use of fpscr_ve and use fpscr & FP_VE instead. (I think these hidden uses of *env are evil and should be banished, but that's a bit of a job.) you mean all the msr_* macros ? I agree. It's huge and I wonder how we could automate parts of it. Thanks, C. > > You could say > > } else { > return; > } > >> + >> + if (error) { > > and then remove this test. > > The rest of it looks good. > > > r~
On 11/19/21 10:24 AM, Cédric Le Goater wrote: >>> + } else if ((fpscr & FP_VXVC) && (fpscr_ve != 0)) { >>> + error = POWERPC_EXCP_FP_VXVC; >>> + } >> >> Is there a defined order for these in the manual? I couldn't find it quickly if so. If >> there is no defined order, I think you should test VE only once. >> >> Drop the use of fpscr_ve and use fpscr & FP_VE instead. (I think these hidden uses of >> *env are evil and should be banished, but that's a bit of a job.) > > you mean all the msr_* macros ? I agree. It's huge and I wonder how we could automate > parts of it. Well, those too. But fpscr_ve is the one that caught my eye here. r~
On 19/11/2021 06:18, Richard Henderson wrote: > On 11/18/21 2:25 PM, Lucas Mateus Castro (alqotel) wrote: >> + if ((fpscr & FP_VXSOFT) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXSOFT; >> + } else if ((fpscr & FP_OX) && (fpscr & FP_OE)) { >> + error = POWERPC_EXCP_FP_OX; >> + } else if ((fpscr & FP_UX) && (fpscr & FP_UE)) { >> + error = POWERPC_EXCP_FP_UX; >> + } else if ((fpscr & FP_XX) && (fpscr & FP_XE)) { >> + error = POWERPC_EXCP_FP_XX; >> + } else if ((fpscr & FP_ZX) && (fpscr & FP_ZE)) { >> + error = POWERPC_EXCP_FP_ZX; >> + } else if ((fpscr & FP_VXSNAN) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXSNAN; >> + } else if ((fpscr & FP_VXISI) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXISI; >> + } else if ((fpscr & FP_VXIDI) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXIDI; >> + } else if ((fpscr & FP_VXZDZ) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXZDZ; >> + } else if ((fpscr & FP_VXIMZ) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXIMZ; >> + } else if ((fpscr & FP_VXVC) && (fpscr_ve != 0)) { >> + error = POWERPC_EXCP_FP_VXVC; >> + } > > Is there a defined order for these in the manual? I couldn't find it > quickly if so. If > there is no defined order, I think you should test VE only once. I also couldn't find a defined order, so I chose to prioritize VXSOFT then go by ascending order of the bit number. In the v3 I'll move VXSOFT with the others invalid operation bits to check VE once then. > > Drop the use of fpscr_ve and use fpscr & FP_VE instead. (I think these > hidden uses of *env > are evil and should be banished, but that's a bit of a job.) > > You could say > > } else { > return; > } > >> + >> + if (error) { > > and then remove this test. Ok, I'll do these in v3. > > The rest of it looks good. > > > r~
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index c4896cecc8..f086cb503f 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -414,6 +414,47 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t val, uint32_t nibbles) ppc_store_fpscr(env, val); } +void helper_fpscr_check_status(CPUPPCState *env) +{ + CPUState *cs = env_cpu(env); + target_ulong fpscr = env->fpscr; + int error = 0; + + if ((fpscr & FP_VXSOFT) && (fpscr_ve != 0)) { + error = POWERPC_EXCP_FP_VXSOFT; + } else if ((fpscr & FP_OX) && (fpscr & FP_OE)) { + error = POWERPC_EXCP_FP_OX; + } else if ((fpscr & FP_UX) && (fpscr & FP_UE)) { + error = POWERPC_EXCP_FP_UX; + } else if ((fpscr & FP_XX) && (fpscr & FP_XE)) { + error = POWERPC_EXCP_FP_XX; + } else if ((fpscr & FP_ZX) && (fpscr & FP_ZE)) { + error = POWERPC_EXCP_FP_ZX; + } else if ((fpscr & FP_VXSNAN) && (fpscr_ve != 0)) { + error = POWERPC_EXCP_FP_VXSNAN; + } else if ((fpscr & FP_VXISI) && (fpscr_ve != 0)) { + error = POWERPC_EXCP_FP_VXISI; + } else if ((fpscr & FP_VXIDI) && (fpscr_ve != 0)) { + error = POWERPC_EXCP_FP_VXIDI; + } else if ((fpscr & FP_VXZDZ) && (fpscr_ve != 0)) { + error = POWERPC_EXCP_FP_VXZDZ; + } else if ((fpscr & FP_VXIMZ) && (fpscr_ve != 0)) { + error = POWERPC_EXCP_FP_VXIMZ; + } else if ((fpscr & FP_VXVC) && (fpscr_ve != 0)) { + error = POWERPC_EXCP_FP_VXVC; + } + + if (error) { + cs->exception_index = POWERPC_EXCP_PROGRAM; + env->error_code = error | POWERPC_EXCP_FP; + /* Deferred floating-point exception after target FPSCR update */ + if (fp_exceptions_enabled(env)) { + raise_exception_err_ra(env, cs->exception_index, + env->error_code, GETPC()); + } + } +} + static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) { CPUState *cs = env_cpu(env); diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 627811cefc..632a81c676 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -63,6 +63,7 @@ DEF_HELPER_FLAGS_1(cntlzw32, TCG_CALL_NO_RWG_SE, i32, i32) DEF_HELPER_FLAGS_2(brinc, TCG_CALL_NO_RWG_SE, tl, tl, tl) DEF_HELPER_1(float_check_status, void, env) +DEF_HELPER_1(fpscr_check_status, void, env) DEF_HELPER_1(reset_fpstatus, void, env) DEF_HELPER_2(compute_fprf_float64, void, env, i64) DEF_HELPER_3(store_fpscr, void, env, i64, i32) diff --git a/target/ppc/translate/fp-impl.c.inc b/target/ppc/translate/fp-impl.c.inc index d1dbb1b96b..ca195fd9d2 100644 --- a/target/ppc/translate/fp-impl.c.inc +++ b/target/ppc/translate/fp-impl.c.inc @@ -769,7 +769,6 @@ static void gen_mtfsb1(DisasContext *ctx) return; } crb = 31 - crbD(ctx->opcode); - gen_reset_fpstatus(); /* XXX: we pretend we can only do IEEE floating-point computations */ if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) { TCGv_i32 t0; @@ -782,7 +781,7 @@ static void gen_mtfsb1(DisasContext *ctx) tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); } /* We can raise a deferred exception */ - gen_helper_float_check_status(cpu_env); + gen_helper_fpscr_check_status(cpu_env); } /* mtfsf */ @@ -803,7 +802,6 @@ static void gen_mtfsf(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); return; } - gen_reset_fpstatus(); if (l) { t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff); } else { @@ -818,7 +816,7 @@ static void gen_mtfsf(DisasContext *ctx) tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); } /* We can raise a deferred exception */ - gen_helper_float_check_status(cpu_env); + gen_helper_fpscr_check_status(cpu_env); tcg_temp_free_i64(t1); } @@ -840,7 +838,6 @@ static void gen_mtfsfi(DisasContext *ctx) return; } sh = (8 * w) + 7 - bf; - gen_reset_fpstatus(); t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh)); t1 = tcg_const_i32(1 << sh); gen_helper_store_fpscr(cpu_env, t0, t1); @@ -851,7 +848,7 @@ static void gen_mtfsfi(DisasContext *ctx) tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); } /* We can raise a deferred exception */ - gen_helper_float_check_status(cpu_env); + gen_helper_fpscr_check_status(cpu_env); } static void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 dest, TCGv addr)
mtfsf, mtfsfi and mtfsb1 instructions call helper_float_check_status after updating the value of FPSCR, but helper_float_check_status checks fp_status and fp_status isn't updated based on FPSCR and since the value of fp_status is reset earlier in the instruction, it's always 0. Because of this helper_float_check_status would change the FI bit to 0 as this bit checks if the last operation was inexact and float_flag_inexact is always 0. These instructions also don't throw exceptions correctly since helper_float_check_status throw exceptions based on fp_status. This commit created a new helper, helper_fpscr_check_status that checks FPSCR value instead of fp_status and checks for a larger variety of exceptions than do_float_check_status. Since fp_status isn't used, gen_reset_fpstatus() was removed. The hardware used to compare QEMU's behavior to was a Power9. Signed-off-by: Lucas Mateus Castro (alqotel) <lucas.araujo@eldorado.org.br> --- target/ppc/fpu_helper.c | 41 ++++++++++++++++++++++++++++++ target/ppc/helper.h | 1 + target/ppc/translate/fp-impl.c.inc | 9 +++---- 3 files changed, 45 insertions(+), 6 deletions(-)