From cb50df6aae0ecb0673ef124a542c81447e602b62 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 15 Jun 2020 13:10:22 -0400 Subject: [PATCH] target/i386: fix fisttpl, fisttpll handling of out-of-range values The fist / fistt family of instructions should all store the most negative integer in the destination format when the rounded / truncated integer result is out of range or the input is an invalid encoding, infinity or NaN. The fisttpl and fisttpll implementations (32-bit and 64-bit results, truncate towards zero) failed to do this, producing the most positive integer in some cases instead. Fix this by copying the code used to handle this issue for fistpl and fistpll, adjusted to use the _round_to_zero functions for the actual conversion (but without any other changes to that code). Backports commit c8af85b10c818709755f5dc8061c69920611fd4c from qemu --- qemu/target/i386/fpu_helper.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/qemu/target/i386/fpu_helper.c b/qemu/target/i386/fpu_helper.c index eb0004c3..791afa2e 100644 --- a/qemu/target/i386/fpu_helper.c +++ b/qemu/target/i386/fpu_helper.c @@ -304,12 +304,36 @@ int32_t helper_fistt_ST0(CPUX86State *env) int32_t helper_fisttl_ST0(CPUX86State *env) { - return floatx80_to_int32_round_to_zero(ST0, &env->fp_status); + int32_t val; + signed char old_exp_flags; + + old_exp_flags = get_float_exception_flags(&env->fp_status); + set_float_exception_flags(0, &env->fp_status); + + val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status); + if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) { + val = 0x80000000; + } + set_float_exception_flags(get_float_exception_flags(&env->fp_status) + | old_exp_flags, &env->fp_status); + return val; } int64_t helper_fisttll_ST0(CPUX86State *env) { - return floatx80_to_int64_round_to_zero(ST0, &env->fp_status); + int64_t val; + signed char old_exp_flags; + + old_exp_flags = get_float_exception_flags(&env->fp_status); + set_float_exception_flags(0, &env->fp_status); + + val = floatx80_to_int64_round_to_zero(ST0, &env->fp_status); + if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) { + val = 0x8000000000000000ULL; + } + set_float_exception_flags(get_float_exception_flags(&env->fp_status) + | old_exp_flags, &env->fp_status); + return val; } void helper_fldt_ST0(CPUX86State *env, target_ulong ptr)