aboutsummaryrefslogtreecommitdiff
path: root/target/ppc
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2018-07-03 08:17:27 -0700
committerDavid Gibson <david@gibson.dropbear.id.au>2018-08-21 14:28:45 +1000
commitae13018d79fb4db7c6a648617bfa0d5976f6e47d (patch)
treef40672d98a99d47db423bcdad90f2ba0bcd828e5 /target/ppc
parente82c42b7c5c1acbcfd5e5fe2b1b850c56e619c0d (diff)
downloadqemu-ae13018d79fb4db7c6a648617bfa0d5976f6e47d.zip
qemu-ae13018d79fb4db7c6a648617bfa0d5976f6e47d.tar.gz
qemu-ae13018d79fb4db7c6a648617bfa0d5976f6e47d.tar.bz2
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>
Diffstat (limited to 'target/ppc')
-rw-r--r--target/ppc/fpu_helper.c50
-rw-r--r--target/ppc/helper.h2
2 files changed, 29 insertions, 23 deletions
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index 9b39c4b..c20b9ae 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -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;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
+ float64 ret = float64_div(arg1, arg2, &env->fp_status);
+ int status = get_float_exception_flags(&env->fp_status);
- 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;
}
@@ -1929,6 +1929,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
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) { \
xt.fld = helper_frsp(env, xt.fld); \
@@ -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);
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 5706c24..1c453fa 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -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)