mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-11 03:24:58 -06:00
target/i386: Set 2-NaN propagation rule explicitly
Set the NaN propagation rule explicitly for the float_status words used in the x86 target. This is a no-behaviour-change commit, so we retain the existing behaviour of using the x87-style "prefer QNaN over SNaN, then prefer the NaN with the larger significand" for MMX and SSE. This is however not the documented hardware behaviour, so we leave a TODO note about what we should be doing instead. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20241025141254.2141506-16-peter.maydell@linaro.org
This commit is contained in:
parent
8d988eb44c
commit
62d39b28ef
4 changed files with 49 additions and 1 deletions
|
@ -405,7 +405,8 @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls,
|
||||||
|| defined(TARGET_TRICORE) || defined(TARGET_ARM) || defined(TARGET_MIPS) \
|
|| defined(TARGET_TRICORE) || defined(TARGET_ARM) || defined(TARGET_MIPS) \
|
||||||
|| defined(TARGET_LOONGARCH64) || defined(TARGET_HPPA) \
|
|| defined(TARGET_LOONGARCH64) || defined(TARGET_HPPA) \
|
||||||
|| defined(TARGET_S390X) || defined(TARGET_PPC) || defined(TARGET_M68K) \
|
|| defined(TARGET_S390X) || defined(TARGET_PPC) || defined(TARGET_M68K) \
|
||||||
|| defined(TARGET_SPARC) || defined(TARGET_XTENSA)
|
|| defined(TARGET_SPARC) || defined(TARGET_XTENSA) \
|
||||||
|
|| defined(TARGET_I386)
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
#else
|
#else
|
||||||
rule = float_2nan_prop_x87;
|
rule = float_2nan_prop_x87;
|
||||||
|
|
|
@ -7200,6 +7200,10 @@ static void x86_cpu_reset_hold(Object *obj, ResetType type)
|
||||||
|
|
||||||
memset(env, 0, offsetof(CPUX86State, end_reset_fields));
|
memset(env, 0, offsetof(CPUX86State, end_reset_fields));
|
||||||
|
|
||||||
|
if (tcg_enabled()) {
|
||||||
|
cpu_init_fp_statuses(env);
|
||||||
|
}
|
||||||
|
|
||||||
env->old_exception = -1;
|
env->old_exception = -1;
|
||||||
|
|
||||||
/* init to reset state */
|
/* init to reset state */
|
||||||
|
|
|
@ -2614,6 +2614,9 @@ static inline bool cpu_vmx_maybe_enabled(CPUX86State *env)
|
||||||
int get_pg_mode(CPUX86State *env);
|
int get_pg_mode(CPUX86State *env);
|
||||||
|
|
||||||
/* fpu_helper.c */
|
/* fpu_helper.c */
|
||||||
|
|
||||||
|
/* Set all non-runtime-variable float_status fields to x86 handling */
|
||||||
|
void cpu_init_fp_statuses(CPUX86State *env);
|
||||||
void update_fp_status(CPUX86State *env);
|
void update_fp_status(CPUX86State *env);
|
||||||
void update_mxcsr_status(CPUX86State *env);
|
void update_mxcsr_status(CPUX86State *env);
|
||||||
void update_mxcsr_from_sse_status(CPUX86State *env);
|
void update_mxcsr_from_sse_status(CPUX86State *env);
|
||||||
|
|
|
@ -135,6 +135,46 @@ static void fpu_set_exception(CPUX86State *env, int mask)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cpu_init_fp_statuses(CPUX86State *env)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Initialise the non-runtime-varying fields of the various
|
||||||
|
* float_status words to x86 behaviour. This must be called at
|
||||||
|
* CPU reset because the float_status words are in the
|
||||||
|
* "zeroed on reset" portion of the CPU state struct.
|
||||||
|
* Fields in float_status that vary under guest control are set
|
||||||
|
* via the codepath for setting that register, eg cpu_set_fpuc().
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Use x87 NaN propagation rules:
|
||||||
|
* SNaN + QNaN => return the QNaN
|
||||||
|
* two SNaNs => return the one with the larger significand, silenced
|
||||||
|
* two QNaNs => return the one with the larger significand
|
||||||
|
* SNaN and a non-NaN => return the SNaN, silenced
|
||||||
|
* QNaN and a non-NaN => return the QNaN
|
||||||
|
*
|
||||||
|
* If we get down to comparing significands and they are the same,
|
||||||
|
* return the NaN with the positive sign bit (if any).
|
||||||
|
*/
|
||||||
|
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
|
||||||
|
/*
|
||||||
|
* TODO: These are incorrect: the x86 Software Developer's Manual vol 1
|
||||||
|
* section 4.8.3.5 "Operating on SNaNs and QNaNs" says that the
|
||||||
|
* "larger significand" behaviour is only used for x87 FPU operations.
|
||||||
|
* For SSE the required behaviour is to always return the first NaN,
|
||||||
|
* which is float_2nan_prop_ab.
|
||||||
|
*
|
||||||
|
* mmx_status is used only for the AMD 3DNow! instructions, which
|
||||||
|
* are documented in the "3DNow! Technology Manual" as not supporting
|
||||||
|
* NaNs or infinities as inputs. The result of passing two NaNs is
|
||||||
|
* documented as "undefined", so we can do what we choose.
|
||||||
|
* (Strictly there is some behaviour we don't implement correctly
|
||||||
|
* for these "unsupported" NaN and Inf values, like "NaN * 0 == 0".)
|
||||||
|
*/
|
||||||
|
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->mmx_status);
|
||||||
|
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->sse_status);
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint8_t save_exception_flags(CPUX86State *env)
|
static inline uint8_t save_exception_flags(CPUX86State *env)
|
||||||
{
|
{
|
||||||
uint8_t old_flags = get_float_exception_flags(&env->fp_status);
|
uint8_t old_flags = get_float_exception_flags(&env->fp_status);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue