diff options
| author | Peter Maydell <peter.maydell@linaro.org> | 2025-02-21 19:09:55 +0000 |
|---|---|---|
| committer | Peter Maydell <peter.maydell@linaro.org> | 2025-02-25 15:32:58 +0000 |
| commit | b9d3dc45532e696f5ee566edd227a4f46bad0f35 (patch) | |
| tree | d36bc6e93361c98de9d8289bc144d0c1a59ecae8 /target/arm/vfp_helper.c | |
| parent | e34cfba5e8d7bd631398a09d658dee40b1aef085 (diff) | |
| download | focaccia-qemu-b9d3dc45532e696f5ee566edd227a4f46bad0f35.tar.gz focaccia-qemu-b9d3dc45532e696f5ee566edd227a4f46bad0f35.zip | |
target/arm: Move softfloat specific FPCR/FPSR handling to tcg/
The softfloat (i.e. TCG) specific handling for the FPCR and FPSR is abstracted behind five functions: arm_set_default_fp_behaviours arm_set_ah_fp_behaviours vfp_get_fpsr_from_host vfp_clear_float_status_exc_flags vfp_set_fpsr_to_host Currently we rely on the first two calling softfloat functions that work even in a KVM-only compile because they're defined as inline in the softfloat header file, and we provide stub versions of the last three in arm/vfp_helper.c if CONFIG_TCG isn't defined. Move the softfloat-specific versions of these functions to tcg/vfp_helper.c, and provide the non-TCG stub versions in tcg-stubs.c. This lets us drop the softfloat header include and the last set of CONFIG_TCG ifdefs from arm/vfp_helper.c. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20250221190957.811948-4-peter.maydell@linaro.org
Diffstat (limited to 'target/arm/vfp_helper.c')
| -rw-r--r-- | target/arm/vfp_helper.c | 248 |
1 files changed, 0 insertions, 248 deletions
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c index 0919acb7b8..cc0f055ef0 100644 --- a/target/arm/vfp_helper.c +++ b/target/arm/vfp_helper.c @@ -21,254 +21,6 @@ #include "cpu.h" #include "internals.h" #include "cpu-features.h" -#include "fpu/softfloat.h" - -/* - * Set the float_status behaviour to match the Arm defaults: - * * tininess-before-rounding - * * 2-input NaN propagation prefers SNaN over QNaN, and then - * operand A over operand B (see FPProcessNaNs() pseudocode) - * * 3-input NaN propagation prefers SNaN over QNaN, and then - * operand C over A over B (see FPProcessNaNs3() pseudocode, - * but note that for QEMU muladd is a * b + c, whereas for - * the pseudocode function the arguments are in the order c, a, b. - * * 0 * Inf + NaN returns the default NaN if the input NaN is quiet, - * and the input NaN if it is signalling - * * Default NaN has sign bit clear, msb frac bit set - */ -void arm_set_default_fp_behaviours(float_status *s) -{ - set_float_detect_tininess(float_tininess_before_rounding, s); - set_float_ftz_detection(float_ftz_before_rounding, s); - set_float_2nan_prop_rule(float_2nan_prop_s_ab, s); - set_float_3nan_prop_rule(float_3nan_prop_s_cab, s); - set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s); - set_float_default_nan_pattern(0b01000000, s); -} - -/* - * Set the float_status behaviour to match the FEAT_AFP - * FPCR.AH=1 requirements: - * * tininess-after-rounding - * * 2-input NaN propagation prefers the first NaN - * * 3-input NaN propagation prefers a over b over c - * * 0 * Inf + NaN always returns the input NaN and doesn't - * set Invalid for a QNaN - * * default NaN has sign bit set, msb frac bit set - */ -void arm_set_ah_fp_behaviours(float_status *s) -{ - set_float_detect_tininess(float_tininess_after_rounding, s); - set_float_ftz_detection(float_ftz_after_rounding, s); - set_float_2nan_prop_rule(float_2nan_prop_ab, s); - set_float_3nan_prop_rule(float_3nan_prop_abc, s); - set_float_infzeronan_rule(float_infzeronan_dnan_never | - float_infzeronan_suppress_invalid, s); - set_float_default_nan_pattern(0b11000000, s); -} - -#ifdef CONFIG_TCG - -/* Convert host exception flags to vfp form. */ -static inline uint32_t vfp_exceptbits_from_host(int host_bits, bool ah) -{ - uint32_t target_bits = 0; - - if (host_bits & float_flag_invalid) { - target_bits |= FPSR_IOC; - } - if (host_bits & float_flag_divbyzero) { - target_bits |= FPSR_DZC; - } - if (host_bits & float_flag_overflow) { - target_bits |= FPSR_OFC; - } - if (host_bits & (float_flag_underflow | float_flag_output_denormal_flushed)) { - target_bits |= FPSR_UFC; - } - if (host_bits & float_flag_inexact) { - target_bits |= FPSR_IXC; - } - 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; -} - -static uint32_t vfp_get_fpsr_from_host(CPUARMState *env) -{ - uint32_t a32_flags = 0, a64_flags = 0; - - a32_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_A32]); - a32_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_STD]); - /* FZ16 does not generate an input denormal exception. */ - a32_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_A32_F16]) - & ~float_flag_input_denormal_flushed); - a32_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_STD_F16]) - & ~float_flag_input_denormal_flushed); - - a64_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_A64]); - a64_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_A64_F16]) - & ~(float_flag_input_denormal_flushed | float_flag_input_denormal_used)); - /* - * We do not merge in flags from FPST_AH or FPST_AH_F16, because - * they are used for insns that must not set the cumulative exception bits. - */ - - /* - * Flushing an input denormal *only* because FPCR.FIZ == 1 does - * not set FPSR.IDC; if FPCR.FZ is also set then this takes - * precedence and IDC is set (see the FPUnpackBase pseudocode). - * So squash it unless (FPCR.AH == 0 && FPCR.FZ == 1). - * We only do this for the a64 flags because FIZ has no effect - * on AArch32 even if it is set. - */ - if ((env->vfp.fpcr & (FPCR_FZ | FPCR_AH)) != FPCR_FZ) { - a64_flags &= ~float_flag_input_denormal_flushed; - } - 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) -{ - /* - * Clear out all the exception-flag information in the float_status - * values. The caller should have arranged for env->vfp.fpsr to - * be the architecturally up-to-date exception flag information first. - */ - set_float_exception_flags(0, &env->vfp.fp_status[FPST_A32]); - set_float_exception_flags(0, &env->vfp.fp_status[FPST_A64]); - set_float_exception_flags(0, &env->vfp.fp_status[FPST_A32_F16]); - set_float_exception_flags(0, &env->vfp.fp_status[FPST_A64_F16]); - set_float_exception_flags(0, &env->vfp.fp_status[FPST_STD]); - set_float_exception_flags(0, &env->vfp.fp_status[FPST_STD_F16]); - set_float_exception_flags(0, &env->vfp.fp_status[FPST_AH]); - set_float_exception_flags(0, &env->vfp.fp_status[FPST_AH_F16]); -} - -static void vfp_sync_and_clear_float_status_exc_flags(CPUARMState *env) -{ - /* - * Synchronize any pending exception-flag information in the - * float_status values into env->vfp.fpsr, and then clear out - * the float_status data. - */ - env->vfp.fpsr |= vfp_get_fpsr_from_host(env); - vfp_clear_float_status_exc_flags(env); -} - -static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask) -{ - uint64_t changed = env->vfp.fpcr; - - changed ^= val; - changed &= mask; - if (changed & (3 << 22)) { - int i = (val >> 22) & 3; - switch (i) { - case FPROUNDING_TIEEVEN: - i = float_round_nearest_even; - break; - case FPROUNDING_POSINF: - i = float_round_up; - break; - case FPROUNDING_NEGINF: - i = float_round_down; - break; - case FPROUNDING_ZERO: - i = float_round_to_zero; - break; - } - set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A32]); - set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A64]); - set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A32_F16]); - set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A64_F16]); - } - if (changed & FPCR_FZ16) { - bool ftz_enabled = val & FPCR_FZ16; - set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32_F16]); - set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64_F16]); - set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_STD_F16]); - set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_AH_F16]); - set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32_F16]); - set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64_F16]); - set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_STD_F16]); - set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_AH_F16]); - } - if (changed & FPCR_FZ) { - bool ftz_enabled = val & FPCR_FZ; - set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32]); - set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64]); - /* FIZ is A64 only so FZ always makes A32 code flush inputs to zero */ - set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32]); - } - if (changed & (FPCR_FZ | FPCR_AH | FPCR_FIZ)) { - /* - * A64: Flush denormalized inputs to zero if FPCR.FIZ = 1, or - * both FPCR.AH = 0 and FPCR.FZ = 1. - */ - bool fitz_enabled = (val & FPCR_FIZ) || - (val & (FPCR_FZ | FPCR_AH)) == FPCR_FZ; - set_flush_inputs_to_zero(fitz_enabled, &env->vfp.fp_status[FPST_A64]); - } - if (changed & FPCR_DN) { - bool dnan_enabled = val & FPCR_DN; - set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A32]); - set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A64]); - set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A32_F16]); - set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A64_F16]); - set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_AH]); - set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_AH_F16]); - } - if (changed & FPCR_AH) { - bool ah_enabled = val & FPCR_AH; - - if (ah_enabled) { - /* Change behaviours for A64 FP operations */ - arm_set_ah_fp_behaviours(&env->vfp.fp_status[FPST_A64]); - arm_set_ah_fp_behaviours(&env->vfp.fp_status[FPST_A64_F16]); - } else { - arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A64]); - arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A64_F16]); - } - } - /* - * If any bits changed that we look at in vfp_get_fpsr_from_host(), - * we must sync the float_status flags into vfp.fpsr now (under the - * old regime) before we update vfp.fpcr. - */ - if (changed & (FPCR_FZ | FPCR_AH | FPCR_FIZ)) { - vfp_sync_and_clear_float_status_exc_flags(env); - } -} - -#else - -static uint32_t vfp_get_fpsr_from_host(CPUARMState *env) -{ - return 0; -} - -static void vfp_clear_float_status_exc_flags(CPUARMState *env) -{ -} - -static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask) -{ -} - -#endif uint32_t vfp_get_fpcr(CPUARMState *env) { |