From: Simon Scherer <[email protected]> FXTRACT writes two registers: the old ST(0) gets the exponent (it becomes ST(1) after the push), and the new ST(0) gets the significand. Both should end up marked valid in the FPU tag word.
helper_fxtract() only marks the new one valid, via fpush(). The old ST(0) just keeps whatever tag it had before the instruction, even though it was just written with the exponent. So if it happened to be tagged empty beforehand, it is still (wrongly) tagged empty afterwards. Add a fpush_fxtract() helper that does the usual fpush() and also marks the old ST(0) (now ST(1)) valid, and use it in place of plain fpush() at all previous call sites in helper_fxtract(). Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4395 Signed-off-by: Simon Scherer <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Paolo Bonzini <[email protected]> --- target/i386/tcg/fpu_helper.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index 56fb94c957b..df16c54c208 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -1814,6 +1814,13 @@ void helper_fpatan(CPUX86State *env) merge_exception_flags(env, old_flags); } +/* fpush() only validates the new top. FXTRACT also needs ST(1) validated. */ +static inline void fpush_fxtract(CPUX86State *env) +{ + fpush(env); + env->fptags[(env->fpstt + 1) & 7] = 0; +} + void helper_fxtract(CPUX86State *env) { int old_flags = save_exception_flags(env); @@ -1825,22 +1832,22 @@ void helper_fxtract(CPUX86State *env) /* Easy way to generate -inf and raising division by 0 exception */ ST0 = floatx80_div(floatx80_chs(floatx80_one), floatx80_zero, &env->fp_status); - fpush(env); + fpush_fxtract(env); ST0 = temp.d; } else if (floatx80_invalid_encoding(ST0, &env->fp_status)) { float_raise(float_flag_invalid, &env->fp_status); ST0 = floatx80_default_nan(&env->fp_status); - fpush(env); + fpush_fxtract(env); ST0 = ST1; } else if (floatx80_is_any_nan(ST0)) { if (floatx80_is_signaling_nan(ST0, &env->fp_status)) { float_raise(float_flag_invalid, &env->fp_status); ST0 = floatx80_silence_nan(ST0, &env->fp_status); } - fpush(env); + fpush_fxtract(env); ST0 = ST1; } else if (floatx80_is_infinity(ST0, &env->fp_status)) { - fpush(env); + fpush_fxtract(env); ST0 = ST1; ST1 = floatx80_default_inf(0, &env->fp_status); } else { @@ -1856,7 +1863,7 @@ void helper_fxtract(CPUX86State *env) } /* DP exponent bias */ ST0 = int32_to_floatx80(expdif, &env->fp_status); - fpush(env); + fpush_fxtract(env); BIASEXPONENT(temp); ST0 = temp.d; } -- 2.55.0
