Skip to content

Commit

Permalink
target-alpha: Raise EXC_M_INV properly for fp inputs
Browse files Browse the repository at this point in the history
Ignore DNZ if software completion isn't used.  Raise INV for
denormals in system mode so the OS completion handler sees them.

Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Richard Henderson <rth@twiddle.net>
  • Loading branch information
rth7680 committed May 18, 2015
1 parent ed08513 commit b99e806
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 10 deletions.
32 changes: 22 additions & 10 deletions target-alpha/fpu_helper.c
Expand Up @@ -104,16 +104,14 @@ void helper_ieee_input(CPUAlphaState *env, uint64_t val)
uint64_t frac = val & 0xfffffffffffffull;

if (exp == 0) {
/* Denormals without DNZ set raise an exception. */
if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
arith_excp(env, GETPC(), EXC_M_UNF, 0);
/* Denormals without /S raise an exception. */
if (frac != 0) {
arith_excp(env, GETPC(), EXC_M_INV, 0);
}
} else if (exp == 0x7ff) {
/* Infinity or NaN. */
/* ??? I'm not sure these exception bit flags are correct. I do
know that the Linux kernel, at least, doesn't rely on them and
just emulates the insn to figure out what exception to use. */
arith_excp(env, GETPC(), frac ? EXC_M_INV : EXC_M_FOV, 0);
env->fpcr |= FPCR_INV;
arith_excp(env, GETPC(), EXC_M_INV, 0);
}
}

Expand All @@ -124,16 +122,30 @@ void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
uint64_t frac = val & 0xfffffffffffffull;

if (exp == 0) {
/* Denormals without DNZ set raise an exception. */
if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
arith_excp(env, GETPC(), EXC_M_UNF, 0);
/* Denormals without /S raise an exception. */
if (frac != 0) {
arith_excp(env, GETPC(), EXC_M_INV, 0);
}
} else if (exp == 0x7ff && frac) {
/* NaN. */
env->fpcr |= FPCR_INV;
arith_excp(env, GETPC(), EXC_M_INV, 0);
}
}

/* Input handing with software completion. Trap for denorms, unless DNZ
is set. If we try to support DNOD (which none of the produced hardware
did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set;
then the code downstream of that will need to cope with denorms sans
flush_input_to_zero. Most of it should work sanely, but there's
nothing to compare with. */
void helper_ieee_input_s(CPUAlphaState *env, uint64_t val)
{
if (unlikely(2 * val - 1 < 0x1fffffffffffffull)
&& !env->fp_status.flush_inputs_to_zero) {
arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0);
}
}

/* S floating (single) */

Expand Down
1 change: 1 addition & 0 deletions target-alpha/helper.h
Expand Up @@ -86,6 +86,7 @@ DEF_HELPER_FLAGS_3(fp_exc_raise_s, TCG_CALL_NO_WG, void, env, i32, i32)

DEF_HELPER_FLAGS_2(ieee_input, TCG_CALL_NO_WG, void, env, i64)
DEF_HELPER_FLAGS_2(ieee_input_cmp, TCG_CALL_NO_WG, void, env, i64)
DEF_HELPER_FLAGS_2(ieee_input_s, TCG_CALL_NO_WG, void, env, i64)
DEF_HELPER_FLAGS_2(cvtql_v_input, TCG_CALL_NO_WG, void, env, i64)

#if !defined (CONFIG_USER_ONLY)
Expand Down
7 changes: 7 additions & 0 deletions target-alpha/translate.c
Expand Up @@ -658,6 +658,13 @@ static TCGv gen_ieee_input(DisasContext *ctx, int reg, int fn11, int is_cmp)
} else {
gen_helper_ieee_input(cpu_env, val);
}
} else {
#ifndef CONFIG_USER_ONLY
/* In system mode, raise exceptions for denormals like real
hardware. In user mode, proceed as if the OS completion
handler is handling the denormal as per spec. */
gen_helper_ieee_input_s(cpu_env, val);
#endif
}
}
return val;
Expand Down

0 comments on commit b99e806

Please sign in to comment.