target/arm: Adjust exception flag handling for AH = 1
When FPCR.AH = 1, some of the cumulative exception flags in the FPSR behave slightly differently for A64 operations: * IDC is set when a denormal input is used without flushing * IXC (Inexact) is set when an output denormal is flushed to zero Update vfp_get_fpsr_from_host() to do this. Note that because half-precision operations never set IDC, we now need to add float_flag_input_denormal_used to the set we mask out of fp_status_f16_a64. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
b3d00d0a44
commit
a4550b7be9
@ -78,7 +78,7 @@ static void arm_set_ah_fp_behaviours(float_status *s)
|
|||||||
#ifdef CONFIG_TCG
|
#ifdef CONFIG_TCG
|
||||||
|
|
||||||
/* Convert host exception flags to vfp form. */
|
/* Convert host exception flags to vfp form. */
|
||||||
static inline uint32_t vfp_exceptbits_from_host(int host_bits)
|
static inline uint32_t vfp_exceptbits_from_host(int host_bits, bool ah)
|
||||||
{
|
{
|
||||||
uint32_t target_bits = 0;
|
uint32_t target_bits = 0;
|
||||||
|
|
||||||
@ -100,6 +100,16 @@ static inline uint32_t vfp_exceptbits_from_host(int host_bits)
|
|||||||
if (host_bits & float_flag_input_denormal_flushed) {
|
if (host_bits & float_flag_input_denormal_flushed) {
|
||||||
target_bits |= FPSR_IDC;
|
target_bits |= FPSR_IDC;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* With FPCR.AH, IDC is set when an input denormal is used,
|
||||||
|
* and flushing an output denormal to zero sets both IXC and UFC.
|
||||||
|
*/
|
||||||
|
if (ah && (host_bits & float_flag_input_denormal_used)) {
|
||||||
|
target_bits |= FPSR_IDC;
|
||||||
|
}
|
||||||
|
if (ah && (host_bits & float_flag_output_denormal_flushed)) {
|
||||||
|
target_bits |= FPSR_IXC;
|
||||||
|
}
|
||||||
return target_bits;
|
return target_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +127,7 @@ static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
|
|||||||
|
|
||||||
a64_flags |= get_float_exception_flags(&env->vfp.fp_status_a64);
|
a64_flags |= get_float_exception_flags(&env->vfp.fp_status_a64);
|
||||||
a64_flags |= (get_float_exception_flags(&env->vfp.fp_status_f16_a64)
|
a64_flags |= (get_float_exception_flags(&env->vfp.fp_status_f16_a64)
|
||||||
& ~float_flag_input_denormal_flushed);
|
& ~(float_flag_input_denormal_flushed | float_flag_input_denormal_used));
|
||||||
/*
|
/*
|
||||||
* Flushing an input denormal *only* because FPCR.FIZ == 1 does
|
* Flushing an input denormal *only* because FPCR.FIZ == 1 does
|
||||||
* not set FPSR.IDC; if FPCR.FZ is also set then this takes
|
* not set FPSR.IDC; if FPCR.FZ is also set then this takes
|
||||||
@ -129,7 +139,8 @@ static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
|
|||||||
if ((env->vfp.fpcr & (FPCR_FZ | FPCR_AH)) != FPCR_FZ) {
|
if ((env->vfp.fpcr & (FPCR_FZ | FPCR_AH)) != FPCR_FZ) {
|
||||||
a64_flags &= ~float_flag_input_denormal_flushed;
|
a64_flags &= ~float_flag_input_denormal_flushed;
|
||||||
}
|
}
|
||||||
return vfp_exceptbits_from_host(a32_flags | a64_flags);
|
return vfp_exceptbits_from_host(a64_flags, env->vfp.fpcr & FPCR_AH) |
|
||||||
|
vfp_exceptbits_from_host(a32_flags, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfp_clear_float_status_exc_flags(CPUARMState *env)
|
static void vfp_clear_float_status_exc_flags(CPUARMState *env)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user