Fix _control87, the old implementation was terribly wrong and broken.

svn path=/trunk/; revision=11607
This commit is contained in:
Gregor Anich 2004-11-09 23:15:17 +00:00
parent 9e12bbeae6
commit d5b047feae
2 changed files with 269 additions and 7 deletions

View file

@ -2,19 +2,149 @@
#include <msvcrt/float.h>
#define X87_CW_IM (1<<0) /* Invalid operation mask */
#define X87_CW_DM (1<<1) /* Denormal operand mask */
#define X87_CW_ZM (1<<2) /* Zero divide mask */
#define X87_CW_OM (1<<3) /* Overflow mask */
#define X87_CW_UM (1<<4) /* Underflow mask */
#define X87_CW_PM (1<<5) /* Precision mask */
#define X87_CW_PC_MASK (3<<8) /* precision control mask */
#define X87_CW_PC24 (0<<8) /* 24 bit precision */
#define X87_CW_PC53 (2<<8) /* 53 bit precision */
#define X87_CW_PC64 (3<<8) /* 64 bit precision */
#define X87_CW_RC_MASK (3<<10) /* rounding control mask */
#define X87_CW_RC_NEAREST (0<<10) /* round to nearest */
#define X87_CW_RC_DOWN (1<<10) /* round down */
#define X87_CW_RC_UP (2<<10) /* round up */
#define X87_CW_RC_ZERO (3<<10) /* round toward zero (chop) */
#define X87_CW_IC (1<<12) /* infinity control flag */
/*
* @implemented
*/
unsigned int _controlfp (unsigned int unNew, unsigned int unMask)
{
return _control87(unNew,unMask);
unsigned int _controlfp(unsigned int unNew, unsigned int unMask)
{
return _control87(unNew,unMask);
}
/*
* @implemented
*/
unsigned int _control87 (unsigned int unNew, unsigned int unMask)
{
unsigned int _control87(unsigned int unNew, unsigned int unMask)
{
unsigned int FpuCw;
unsigned int DummyCw = 0;
/* get the controlword */
asm volatile("fstcw %0\n\t" : "=m"(FpuCw));
FpuCw &= 0x0000ffff;
/* translate it into _control87 format */
if (FpuCw & X87_CW_IM)
DummyCw |= _EM_INVALID;
if (FpuCw & X87_CW_DM)
DummyCw |= _EM_DENORMAL;
if (FpuCw & X87_CW_ZM)
DummyCw |= _EM_ZERODIVIDE;
if (FpuCw & X87_CW_OM)
DummyCw |= _EM_OVERFLOW;
if (FpuCw & X87_CW_UM)
DummyCw |= _EM_UNDERFLOW;
if (FpuCw & X87_CW_PM)
DummyCw |= _EM_INEXACT;
switch (FpuCw & X87_CW_PC_MASK)
{
case X87_CW_PC24:
DummyCw |= _PC_24;
break;
case X87_CW_PC53:
DummyCw |= _PC_53;
break;
case X87_CW_PC64:
DummyCw |= _PC_64;
break;
}
switch (FpuCw & X87_CW_RC_MASK)
{
case X87_CW_RC_NEAREST:
DummyCw |= _RC_NEAR;
break;
case X87_CW_RC_DOWN:
DummyCw |= _RC_DOWN;
break;
case X87_CW_RC_UP:
DummyCw |= _RC_UP;
break;
case X87_CW_RC_ZERO:
DummyCw |= _RC_CHOP;
break;
}
/* unset (un)masked bits */
DummyCw &= ~unMask;
unNew &= unMask;
/* set new bits */
DummyCw |= unNew;
/* translate back into x87 format
* FIXME: translate infinity control!
*/
FpuCw = 0;
if (DummyCw & _EM_INVALID)
FpuCw |= X87_CW_IM;
if (DummyCw & _EM_DENORMAL)
FpuCw |= X87_CW_DM;
if (DummyCw & _EM_ZERODIVIDE)
FpuCw |= X87_CW_ZM;
if (DummyCw & _EM_OVERFLOW)
FpuCw |= X87_CW_OM;
if (DummyCw & _EM_UNDERFLOW)
FpuCw |= X87_CW_UM;
if (DummyCw & _EM_INEXACT)
FpuCw |= X87_CW_PM;
switch (DummyCw & _MCW_PC)
{
case _PC_24:
FpuCw |= X87_CW_PC24;
break;
case _PC_53:
FpuCw |= X87_CW_PC53;
break;
case _PC_64:
default:
FpuCw |= X87_CW_PC64;
break;
}
switch (DummyCw & _MCW_RC)
{
case _RC_NEAR:
FpuCw |= X87_CW_RC_NEAREST;
break;
case _RC_DOWN:
FpuCw |= X87_CW_RC_DOWN;
break;
case _RC_UP:
FpuCw |= X87_CW_RC_UP;
break;
case _RC_CHOP:
FpuCw |= X87_CW_RC_ZERO;
break;
}
/* set controlword */
asm volatile("fldcw %0" : : "m"(FpuCw));
return DummyCw;
#if 0 /* The follwing is the original code, broken I think! -blight */
register unsigned int __res;
#ifdef __GNUC__
__asm__ __volatile__ (
@ -36,8 +166,9 @@ __asm__ __volatile__ (
"fldcw (%%esp) \n\t"
"popl %%edx \n\t"
:"=r" (__res):"r" (unNew),"r" (unMask): "ax", "dx", "cx");
:"=a" (__res):"r" (unNew),"r" (unMask): "dx", "cx");
#else
#endif /*__GNUC__*/
return __res;
#endif
}

View file

@ -2,6 +2,26 @@
#include <msvcrt/float.h>
#define X87_CW_IM (1<<0) /* Invalid operation mask */
#define X87_CW_DM (1<<1) /* Denormal operand mask */
#define X87_CW_ZM (1<<2) /* Zero divide mask */
#define X87_CW_OM (1<<3) /* Overflow mask */
#define X87_CW_UM (1<<4) /* Underflow mask */
#define X87_CW_PM (1<<5) /* Precision mask */
#define X87_CW_PC_MASK (3<<8) /* precision control mask */
#define X87_CW_PC24 (0<<8) /* 24 bit precision */
#define X87_CW_PC53 (2<<8) /* 53 bit precision */
#define X87_CW_PC64 (3<<8) /* 64 bit precision */
#define X87_CW_RC_MASK (3<<10) /* rounding control mask */
#define X87_CW_RC_NEAREST (0<<10) /* round to nearest */
#define X87_CW_RC_DOWN (1<<10) /* round down */
#define X87_CW_RC_UP (2<<10) /* round up */
#define X87_CW_RC_ZERO (3<<10) /* round toward zero (chop) */
#define X87_CW_IC (1<<12) /* infinity control flag */
/*
* @implemented
*/
@ -15,6 +35,116 @@ unsigned int _controlfp(unsigned int unNew, unsigned int unMask)
*/
unsigned int _control87(unsigned int unNew, unsigned int unMask)
{
unsigned int FpuCw;
unsigned int DummyCw = 0;
/* get the controlword */
asm volatile("fstcw %0\n\t" : "=m"(FpuCw));
FpuCw &= 0x0000ffff;
/* translate it into _control87 format */
if (FpuCw & X87_CW_IM)
DummyCw |= _EM_INVALID;
if (FpuCw & X87_CW_DM)
DummyCw |= _EM_DENORMAL;
if (FpuCw & X87_CW_ZM)
DummyCw |= _EM_ZERODIVIDE;
if (FpuCw & X87_CW_OM)
DummyCw |= _EM_OVERFLOW;
if (FpuCw & X87_CW_UM)
DummyCw |= _EM_UNDERFLOW;
if (FpuCw & X87_CW_PM)
DummyCw |= _EM_INEXACT;
switch (FpuCw & X87_CW_PC_MASK)
{
case X87_CW_PC24:
DummyCw |= _PC_24;
break;
case X87_CW_PC53:
DummyCw |= _PC_53;
break;
case X87_CW_PC64:
DummyCw |= _PC_64;
break;
}
switch (FpuCw & X87_CW_RC_MASK)
{
case X87_CW_RC_NEAREST:
DummyCw |= _RC_NEAR;
break;
case X87_CW_RC_DOWN:
DummyCw |= _RC_DOWN;
break;
case X87_CW_RC_UP:
DummyCw |= _RC_UP;
break;
case X87_CW_RC_ZERO:
DummyCw |= _RC_CHOP;
break;
}
/* unset (un)masked bits */
DummyCw &= ~unMask;
unNew &= unMask;
/* set new bits */
DummyCw |= unNew;
/* translate back into x87 format
* FIXME: translate infinity control!
*/
FpuCw = 0;
if (DummyCw & _EM_INVALID)
FpuCw |= X87_CW_IM;
if (DummyCw & _EM_DENORMAL)
FpuCw |= X87_CW_DM;
if (DummyCw & _EM_ZERODIVIDE)
FpuCw |= X87_CW_ZM;
if (DummyCw & _EM_OVERFLOW)
FpuCw |= X87_CW_OM;
if (DummyCw & _EM_UNDERFLOW)
FpuCw |= X87_CW_UM;
if (DummyCw & _EM_INEXACT)
FpuCw |= X87_CW_PM;
switch (DummyCw & _MCW_PC)
{
case _PC_24:
FpuCw |= X87_CW_PC24;
break;
case _PC_53:
FpuCw |= X87_CW_PC53;
break;
case _PC_64:
default:
FpuCw |= X87_CW_PC64;
break;
}
switch (DummyCw & _MCW_RC)
{
case _RC_NEAR:
FpuCw |= X87_CW_RC_NEAREST;
break;
case _RC_DOWN:
FpuCw |= X87_CW_RC_DOWN;
break;
case _RC_UP:
FpuCw |= X87_CW_RC_UP;
break;
case _RC_CHOP:
FpuCw |= X87_CW_RC_ZERO;
break;
}
/* set controlword */
asm volatile("fldcw %0" : : "m"(FpuCw));
return DummyCw;
#if 0 /* The follwing is the original code, broken I think! -blight */
register unsigned int __res;
#ifdef __GNUC__
__asm__ __volatile__ (
@ -36,8 +166,9 @@ __asm__ __volatile__ (
"fldcw (%%esp) \n\t"
"popl %%edx \n\t"
:"=r" (__res):"r" (unNew),"r" (unMask): "ax", "dx", "cx");
:"=a" (__res):"r" (unNew),"r" (unMask): "dx", "cx");
#else
#endif /*__GNUC__*/
return __res;
#endif
}