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:
parent
e82c42b7c5
commit
ae13018d79
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user