diff options
author | Joseph Myers <joseph@codesourcery.com> | 2020-05-07 00:43:30 +0000 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2020-06-10 12:10:16 -0400 |
commit | c415f2c58296d86e9abb7e4a133111acf7031da3 (patch) | |
tree | 9acea46806827e7ea693b48d7f55a1471c0e28bc /target | |
parent | 2b151297e44655e45c18f57ae0232780ee4ad45a (diff) | |
download | qemu-c415f2c58296d86e9abb7e4a133111acf7031da3.zip qemu-c415f2c58296d86e9abb7e4a133111acf7031da3.tar.gz qemu-c415f2c58296d86e9abb7e4a133111acf7031da3.tar.bz2 |
target/i386: implement special cases for fxtract
The implementation of the fxtract instruction treats all nonzero
operands as normal numbers, so yielding incorrect results for invalid
formats, infinities, NaNs and subnormal and pseudo-denormal operands.
Implement appropriate handling of all those cases.
Signed-off-by: Joseph Myers <joseph@codesourcery.com>
Acked-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <alpine.DEB.2.21.2005070042360.18350@digraph.polyomino.org.uk>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'target')
-rw-r--r-- | target/i386/fpu_helper.c | 25 |
1 files changed, 24 insertions, 1 deletions
diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index b34fa78..568bd3b 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -767,10 +767,33 @@ void helper_fxtract(CPUX86State *env) &env->fp_status); fpush(env); ST0 = temp.d; + } else if (floatx80_invalid_encoding(ST0)) { + float_raise(float_flag_invalid, &env->fp_status); + ST0 = floatx80_default_nan(&env->fp_status); + fpush(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); + ST0 = ST1; + } else if (floatx80_is_infinity(ST0)) { + fpush(env); + ST0 = ST1; + ST1 = floatx80_infinity; } else { int expdif; - expdif = EXPD(temp) - EXPBIAS; + if (EXPD(temp) == 0) { + int shift = clz64(temp.l.lower); + temp.l.lower <<= shift; + expdif = 1 - EXPBIAS - shift; + float_raise(float_flag_input_denormal, &env->fp_status); + } else { + expdif = EXPD(temp) - EXPBIAS; + } /* DP exponent bias */ ST0 = int32_to_floatx80(expdif, &env->fp_status); fpush(env); |