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.mayd...@linaro.org> --- target/arm/vfp_helper.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c index 7507ff24bc0..2eb75bd7ecc 100644 --- a/target/arm/vfp_helper.c +++ b/target/arm/vfp_helper.c @@ -78,7 +78,7 @@ static void arm_set_ah_fp_behaviours(float_status *s) #ifdef CONFIG_TCG /* 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; @@ -100,6 +100,16 @@ static inline uint32_t vfp_exceptbits_from_host(int host_bits) if (host_bits & float_flag_input_denormal_flushed) { 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; } @@ -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_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 * not set FPSR.IDC. So squash it unless (FPCR.AH == 0 && FPCR.FZ == 1). @@ -127,7 +137,8 @@ static uint32_t vfp_get_fpsr_from_host(CPUARMState *env) if ((env->vfp.fpcr & (FPCR_FZ | FPCR_AH)) != FPCR_FZ) { 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) -- 2.34.1