* [Qemu-devel] [PATCH] Bug in target-i386/helper.c:helper_fxam_ST0
@ 2006-06-19 12:25 Julian Seward
2006-06-19 14:55 ` Julian Seward
0 siblings, 1 reply; 2+ messages in thread
From: Julian Seward @ 2006-06-19 12:25 UTC (permalink / raw)
To: qemu-devel
I've been doing some instruction set testing on i386-softmmu,
with the aim of seeing if I can find any anomalies which might
be the cause the of Win2K SP4 installation failure.
helper_fxam_ST0 doesn't correctly distinguish infinities from
nans, and thereby causes programs that use the x86 'fxam'
instruction to occasionally produce incorrect results. That
instruction is quite often used as part of transcendentals, for
example pow, exp, log.
On a Linux guest, it for example causes the libc call pow(0.6, inf)
to produce inf when it should produce zero, and causes about 20
cases in the FP correctness suite I'm using to fail.
The test case below shows the problem. It should produce
0x4000: 0.000000
0x4200: -0.000000
0x0500: inf
0x0700: -inf
0x0300: nan
0x0100: nan
0x0400: 0.000000
0x0600: -0.000000
0x0400: 1.230000
0x0600: -1.230000
but instead produces (omitting the correct cases)
0x0100: inf
0x0300: -inf
What's strange is the logic in helper_fxam_ST0 looks correct.
The distinguish-nans-from-infinities part is
if (expdif == MAXEXPD) {
if (MANTD(temp) == 0)
env->fpus |= 0x500 /*Infinity*/;
else
env->fpus |= 0x100 /*NaN*/;
}
I suspect the check is correct for 52-bit mantissas (64-bit floats)
but not for 64-bit mantissas (80-bit floats), as per these notes:
/* 80 and 64-bit floating point formats:
80-bit:
S 0 0-------0 zero
S 0 0X------X denormals
S 1-7FFE 1X------X normals (all normals have leading 1)
S 7FFF 10------0 infinity
S 7FFF 10X-----X snan
S 7FFF 11X-----X qnan
S is the sign bit. For runs X----X, at least one of the Xs must be
nonzero. Exponent is 15 bits, fractional part is 63 bits, and
there is an explicitly represented leading 1, and a sign bit,
giving 80 in total.
64-bit avoids the confusion of an explicitly represented leading 1
and so is simpler:
S 0 0------0 zero
S 0 X------X denormals
S 1-7FE any normals
S 7FF 0------0 infinity
S 7FF 0X-----X snan
S 7FF 1X-----X qnan
Exponent is 11 bits, fractional part is 52 bits, and there is a
sign bit, giving 64 in total.
*/
For 52-bit mantissas, the mantissa zero-vs-nonzero check is correct.
But for 64-bit mantissas, the check needs to be
if (MANTD(temp) == 0x8000000000000000ULL)
and indeed setting it to that makes the test program run correctly.
Patch and testcase follow.
I'm still seeing cases where x87-based computation on qemu winds
up with a NaN when it shouldn't. I think that's a separate problem.
Will investigate.
J
-------------------------------------------------------------------------
Index: target-i386/helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-i386/helper.c,v
retrieving revision 1.65
diff -r1.65 helper.c
2952a2953,2955
> # ifdef USE_X86LDOUBLE
> if (MANTD(temp) == 0x8000000000000000ULL)
> # else
2953a2957
> # endif
-------------------------------------------------------------------------
#include <stdio.h>
#include <math.h>
/* FPU flag masks */
#define X86G_FC_SHIFT_C3 14
#define X86G_FC_SHIFT_C2 10
#define X86G_FC_SHIFT_C1 9
#define X86G_FC_SHIFT_C0 8
#define X86G_FC_MASK_C3 (1 << X86G_FC_SHIFT_C3)
#define X86G_FC_MASK_C2 (1 << X86G_FC_SHIFT_C2)
#define X86G_FC_MASK_C1 (1 << X86G_FC_SHIFT_C1)
#define X86G_FC_MASK_C0 (1 << X86G_FC_SHIFT_C0)
#define MASK_C3210 (X86G_FC_MASK_C3 | X86G_FC_MASK_C2 | X86G_FC_MASK_C1 |
X86G_FC_MASK_C0)
double d;
int i;
extern void do_fxam ( void );
asm(
"\n"
"do_fxam:\n"
"\txorl %eax,%eax\n"
"\tfldl d\n"
"\tfxam\n"
"\tfnstsw %ax\n"
"\tffree %st(0)\n"
"\tmovl %eax, i\n"
"\tret\n"
);
double inf ( void ) { return 1.0 / 0.0; }
double nAn ( void ) { return 0.0 / 0.0; }
double den ( void ) { return 9.1e-220 / 1e100; }
double nor ( void ) { return 1.23; }
/* Try positive and negative variants of: zero, infinity,
nAn, denorm and normal */
int main ( void )
{
d = 0.0; do_fxam(); printf("0x%04x: %f\n", i & MASK_C3210, d );
d = -0.0; do_fxam(); printf("0x%04x: %f\n", i & MASK_C3210, d );
d = inf(); do_fxam(); printf("0x%04x: %f\n", i & MASK_C3210, d );
d = -inf(); do_fxam(); printf("0x%04x: %f\n", i & MASK_C3210, d );
d = nAn(); do_fxam(); printf("0x%04x: %f\n", i & MASK_C3210, d );
d = -nAn(); do_fxam(); printf("0x%04x: %f\n", i & MASK_C3210, d );
d = den(); do_fxam(); printf("0x%04x: %f\n", i & MASK_C3210, d );
d = -den(); do_fxam(); printf("0x%04x: %f\n", i & MASK_C3210, d );
d = nor(); do_fxam(); printf("0x%04x: %f\n", i & MASK_C3210, d );
d = -nor(); do_fxam(); printf("0x%04x: %f\n", i & MASK_C3210, d );
return 0;
}
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [Qemu-devel] [PATCH] Bug in target-i386/helper.c:helper_fxam_ST0
2006-06-19 12:25 [Qemu-devel] [PATCH] Bug in target-i386/helper.c:helper_fxam_ST0 Julian Seward
@ 2006-06-19 14:55 ` Julian Seward
0 siblings, 0 replies; 2+ messages in thread
From: Julian Seward @ 2006-06-19 14:55 UTC (permalink / raw)
To: qemu-devel
> be the cause the of Win2K SP4 installation failure.
This doesn't seem to help alas.
Here's a context diff of the same patch (easier to make sense of).
J
===================================================================
RCS file: /sources/qemu/qemu/target-i386/helper.c,v
retrieving revision 1.65
diff -C5 -r1.65 helper.c
*** target-i386/helper.c 3 May 2006 19:17:26 -0000 1.65
--- target-i386/helper.c 19 Jun 2006 14:32:44 -0000
***************
*** 2948,2958 ****
--- 2948,2962 ----
if (SIGND(temp))
env->fpus |= 0x200; /* C1 <-- 1 */
expdif = EXPD(temp);
if (expdif == MAXEXPD) {
+ # ifdef USE_X86LDOUBLE
+ if (MANTD(temp) == 0x8000000000000000ULL)
+ # else
if (MANTD(temp) == 0)
+ # endif
env->fpus |= 0x500 /*Infinity*/;
else
env->fpus |= 0x100 /*NaN*/;
} else if (expdif == 0) {
if (MANTD(temp) == 0)
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2006-06-19 14:55 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-06-19 12:25 [Qemu-devel] [PATCH] Bug in target-i386/helper.c:helper_fxam_ST0 Julian Seward
2006-06-19 14:55 ` Julian Seward
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).