Skip to content

Commit

Permalink
target-alpha: Set fpcr_exc_status even for disabled exceptions
Browse files Browse the repository at this point in the history
The qualifiers can suppress the raising of exceptions, but real
hardware still records that the exceptions occurred.

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 f3d3aad commit 471d493
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 29 deletions.
35 changes: 21 additions & 14 deletions target-alpha/fpu_helper.c
Expand Up @@ -57,27 +57,31 @@ static uint32_t soft_to_fpcr_exc(CPUAlphaState *env)
static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr,
uint32_t exc, uint32_t regno)
{
if (exc) {
uint32_t hw_exc = 0;
uint32_t hw_exc = 0;

hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV);
hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE);
hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV);
hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF);
hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE);
hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV);
hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV);
hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE);
hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV);
hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF);
hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE);
hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV);

arith_excp(env, retaddr, hw_exc, 1ull << regno);
}
arith_excp(env, retaddr, hw_exc, 1ull << regno);
}

/* Raise exceptions for ieee fp insns without software completion.
In that case there are no exceptions that don't trap; the mask
doesn't apply. */
void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
{
uint32_t exc = env->error_code & ~ignore;
fp_exc_raise1(env, GETPC(), exc, regno);
uint32_t exc = env->error_code;
if (exc) {
env->fpcr |= exc;
exc &= ~ignore;
if (exc) {
fp_exc_raise1(env, GETPC(), exc, regno);
}
}
}

/* Raise exceptions for ieee fp insns with software completion. */
Expand All @@ -86,8 +90,11 @@ void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
uint32_t exc = env->error_code & ~ignore;
if (exc) {
env->fpcr |= exc;
exc &= env->fpcr_exc_enable;
fp_exc_raise1(env, GETPC(), exc, regno);
exc &= ~ignore;
if (exc) {
exc &= env->fpcr_exc_enable;
fp_exc_raise1(env, GETPC(), exc, regno);
}
}
}

Expand Down
28 changes: 13 additions & 15 deletions target-alpha/translate.c
Expand Up @@ -663,23 +663,31 @@ static TCGv gen_ieee_input(DisasContext *ctx, int reg, int fn11, int is_cmp)
return val;
}

static void gen_fp_exc_raise_ignore(int rc, int fn11, int ignore)
static void gen_fp_exc_raise(int rc, int fn11)
{
/* ??? We ought to be able to do something with imprecise exceptions.
E.g. notice we're still in the trap shadow of something within the
TB and do not generate the code to signal the exception; end the TB
when an exception is forced to arrive, either by consumption of a
register value or TRAPB or EXCB. */
TCGv_i32 ign = tcg_const_i32(ignore);
TCGv_i32 reg;
TCGv_i32 reg, ign;
uint32_t ignore = 0;

if (!(fn11 & QUAL_U)) {
/* Note that QUAL_U == QUAL_V, so ignore either. */
ignore |= FPCR_UNF | FPCR_IOV;
}
if (!(fn11 & QUAL_I)) {
ignore |= FPCR_INE;
}
ign = tcg_const_i32(ignore);

/* ??? Pass in the regno of the destination so that the helper can
set EXC_MASK, which contains a bitmask of destination registers
that have caused arithmetic traps. A simple userspace emulation
does not require this. We do need it for a guest kernel's entArith,
or if we were to do something clever with imprecise exceptions. */
reg = tcg_const_i32(rc + 32);

if (fn11 & QUAL_S) {
gen_helper_fp_exc_raise_s(cpu_env, ign, reg);
} else {
Expand All @@ -690,11 +698,6 @@ static void gen_fp_exc_raise_ignore(int rc, int fn11, int ignore)
tcg_temp_free_i32(ign);
}

static inline void gen_fp_exc_raise(int rc, int fn11)
{
gen_fp_exc_raise_ignore(rc, fn11, fn11 & QUAL_I ? 0 : FPCR_INE);
}

static void gen_cvtlq(TCGv vc, TCGv vb)
{
TCGv tmp = tcg_temp_new();
Expand Down Expand Up @@ -752,7 +755,6 @@ IEEE_ARITH2(cvtts)
static void gen_cvttq(DisasContext *ctx, int rb, int rc, int fn11)
{
TCGv vb, vc;
int ignore = 0;

/* No need to set flushzero, since we have an integer output. */
vb = gen_ieee_input(ctx, rb, fn11, 0);
Expand All @@ -766,20 +768,16 @@ static void gen_cvttq(DisasContext *ctx, int rb, int rc, int fn11)
break;
case QUAL_V | QUAL_RM_C:
case QUAL_S | QUAL_V | QUAL_RM_C:
ignore = FPCR_INE;
/* FALLTHRU */
case QUAL_S | QUAL_V | QUAL_I | QUAL_RM_C:
gen_helper_cvttq_svic(vc, cpu_env, vb);
break;
default:
gen_qual_roundmode(ctx, fn11);
gen_helper_cvttq(vc, cpu_env, vb);
ignore |= (fn11 & QUAL_V ? 0 : FPCR_IOV);
ignore |= (fn11 & QUAL_I ? 0 : FPCR_INE);
break;
}

gen_fp_exc_raise_ignore(rc, fn11, ignore);
gen_fp_exc_raise(rc, fn11);
}

static void gen_ieee_intcvt(DisasContext *ctx,
Expand Down

0 comments on commit 471d493

Please sign in to comment.