target/ppc: Honor fpscr_ze semantics and tidy fdiv

Divide by zero, exception taken, leaves the destination register
unmodified.  Therefore we must raise the exception before returning
from helper_fdiv.  Move the check from do_float_check_status into
helper_fdiv.

At the same time, tidy the invalid exception checking so that we
rely on softfloat for initial argument validation, and select the
kind of invalid operand exception only when we know we must.

At the same time, pass and return float64 values directly rather
than bounce through the CPU_DoubleU union.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
Richard Henderson 2018-07-03 08:17:27 -07:00 committed by David Gibson
parent e82c42b7c5
commit ae13018d79
2 changed files with 29 additions and 23 deletions

View File

@ -545,9 +545,7 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr)
int status = get_float_exception_flags(&env->fp_status);
bool inexact_happened = false;
if (status & float_flag_divbyzero) {
float_zero_divide_excp(env, raddr);
} else if (status & float_flag_overflow) {
if (status & float_flag_overflow) {
float_overflow_excp(env);
} else if (status & float_flag_underflow) {
float_underflow_excp(env);
@ -661,30 +659,32 @@ uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
}
/* fdiv - fdiv. */
uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
float64 helper_fdiv(CPUPPCState *env, float64 arg1, float64 arg2)
{
CPU_DoubleU farg1, farg2;
float64 ret = float64_div(arg1, arg2, &env->fp_status);
int status = get_float_exception_flags(&env->fp_status);
farg1.ll = arg1;
farg2.ll = arg2;
if (unlikely(float64_is_infinity(farg1.d) &&
float64_is_infinity(farg2.d))) {
/* Division of infinity by infinity */
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
} else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
/* Division of zero by zero */
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
float64_is_signaling_nan(farg2.d, &env->fp_status))) {
/* sNaN division */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
if (unlikely(status)) {
if (status & float_flag_invalid) {
/* Determine what kind of invalid operation was seen. */
if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) {
/* Division of infinity by infinity */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
} else if (float64_is_zero(arg1) && float64_is_zero(arg2)) {
/* Division of zero by zero */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
} else if (float64_is_signaling_nan(arg1, &env->fp_status) ||
float64_is_signaling_nan(arg2, &env->fp_status)) {
/* sNaN division */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
}
if (status & float_flag_divbyzero) {
float_zero_divide_excp(env, GETPC());
}
farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
}
return farg1.ll;
return ret;
}
@ -1928,6 +1928,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
tp##_is_signaling_nan(xb.fld, &tstat)) { \
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
} \
} \
if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { \
float_zero_divide_excp(env, GETPC()); \
} \
\
if (r2sp) { \
@ -1978,6 +1981,9 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode)
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
}
if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) {
float_zero_divide_excp(env, GETPC());
}
helper_compute_fprf_float128(env, xt.f128);
putVSR(rD(opcode) + 32, &xt, env);

View File

@ -88,7 +88,7 @@ DEF_HELPER_2(frim, i64, env, i64)
DEF_HELPER_3(fadd, i64, env, i64, i64)
DEF_HELPER_3(fsub, i64, env, i64, i64)
DEF_HELPER_3(fmul, i64, env, i64, i64)
DEF_HELPER_3(fdiv, i64, env, i64, i64)
DEF_HELPER_3(fdiv, f64, env, f64, f64)
DEF_HELPER_4(fmadd, i64, env, i64, i64, i64)
DEF_HELPER_4(fmsub, i64, env, i64, i64, i64)
DEF_HELPER_4(fnmadd, i64, env, i64, i64, i64)