diff options
author | Joseph Myers <joseph@codesourcery.com> | 2020-05-13 23:51:09 +0000 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2020-06-10 12:10:25 -0400 |
commit | 18c53e1e73197a24f9f4b66b1276eb9868db5bf0 (patch) | |
tree | bee7345ba6b19eafcb2e87e38cffc02ee8107445 | |
parent | 34b9cc076ff423023a779a04a9f7cd7c17372cbf (diff) | |
download | qemu-18c53e1e73197a24f9f4b66b1276eb9868db5bf0.zip |
target/i386: fix fbstp handling of negative zero
The fbstp implementation stores +0 when the rounded result should be
-0 because it compares an integer value with 0 to determine the sign.
Fix this by checking the sign bit of the operand instead.
Signed-off-by: Joseph Myers <joseph@codesourcery.com>
Message-Id: <alpine.DEB.2.21.2005132350230.11687@digraph.polyomino.org.uk>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | target/i386/fpu_helper.c | 5 | ||||
-rw-r--r-- | tests/tcg/i386/test-i386-fbstp.c | 25 |
2 files changed, 29 insertions, 1 deletions
diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 185493db8e..f0a57099ca 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -726,11 +726,14 @@ void helper_fbst_ST0(CPUX86State *env, target_ulong ptr) int v; target_ulong mem_ref, mem_end; int64_t val; + CPU_LDoubleU temp; + + temp.d = ST0; val = floatx80_to_int64(ST0, &env->fp_status); mem_ref = ptr; mem_end = mem_ref + 9; - if (val < 0) { + if (SIGND(temp)) { cpu_stb_data_ra(env, mem_end, 0x80, GETPC()); val = -val; } else { diff --git a/tests/tcg/i386/test-i386-fbstp.c b/tests/tcg/i386/test-i386-fbstp.c new file mode 100644 index 0000000000..d368949188 --- /dev/null +++ b/tests/tcg/i386/test-i386-fbstp.c @@ -0,0 +1,25 @@ +/* Test fbstp instruction. */ + +#include <stdio.h> +#include <string.h> + +int main(void) +{ + int ret = 0; + unsigned char out[10]; + memset(out, 0xfe, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-0.0L) : "st"); + out[9] &= 0x80; + if (memcmp(out, "\0\0\0\0\0\0\0\0\0\x80", sizeof out) != 0) { + printf("FAIL: fbstp -0\n"); + ret = 1; + } + memset(out, 0x12, sizeof out); + __asm__ volatile ("fbstp %0" : "=m" (out) : "t" (-0.1L) : "st"); + out[9] &= 0x80; + if (memcmp(out, "\0\0\0\0\0\0\0\0\0\x80", sizeof out) != 0) { + printf("FAIL: fbstp -0.1\n"); + ret = 1; + } + return ret; +} |