|
|
/*++
Copyright (c) 1995-2000 Microsoft Corporation
Module Name:
fputrig.c
Abstract:
Floating point trig and transcendental functions
Author:
05-Oct-1995 BarryBo
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
#include "wx86.h"
#include "cpuassrt.h"
#include "fragp.h"
#include "fpufragp.h"
ASSERTNAME;
//
// Forward declarations
//
NPXFUNC1(FCOS_VALID); NPXFUNC1(FCOS_ZERO); NPXFUNC1(FCOS_SPECIAL); NPXFUNC1(FCOS_EMPTY); NPXFUNC2(FPATAN_VALID_VALID); NPXFUNC2(FPATAN_VALID_SPECIAL); NPXFUNC2(FPATAN_SPECIAL_VALID); NPXFUNC2(FPATAN_SPECIAL_SPECIAL); NPXFUNC2(FPATAN_EMPTY_ALL); NPXFUNC2(FPATAN_ALL_EMPTY); NPXFUNC0(FPTAN_VALID); NPXFUNC0(FPTAN_ZERO); NPXFUNC0(FPTAN_SPECIAL); NPXFUNC0(FSIN_VALID); NPXFUNC0(FSIN_ZERO); NPXFUNC0(FSIN_SPECIAL); NPXFUNC0(FSIN_EMPTY); NPXFUNC0(FSINCOS_VALID); NPXFUNC0(FSINCOS_ZERO); NPXFUNC0(FSINCOS_SPECIAL); NPXFUNC2(FYL2X_VALID_VALID); NPXFUNC2(FYL2X_VALID_ZERO); NPXFUNC2(FYL2X_ZERO_VALID); NPXFUNC2(FYL2X_ZERO_ZERO); NPXFUNC2(FYL2X_SPECIAL_VALIDORZERO); NPXFUNC2(FYL2X_VALIDORZERO_SPECIAL); NPXFUNC2(FYL2X_SPECIAL_SPECIAL); NPXFUNC2(FYL2X_ANY_EMPTY); NPXFUNC2(FYL2X_EMPTY_ANY); NPXFUNC2(FYL2XP1_VALIDORZERO_ZERO); NPXFUNC2(FYL2XP1_VALIDORZERO_VALID); NPXFUNC2(FYL2XP1_SPECIAL_VALIDORZERO); NPXFUNC2(FYL2XP1_VALIDORZERO_SPECIAL); NPXFUNC2(FYL2XP1_SPECIAL_SPECIAL); NPXFUNC2(FYL2XP1_ANY_EMPTY); NPXFUNC2(FYL2XP1_EMPTY_ANY); NPXFUNC1(F2XM1_VALID); NPXFUNC1(F2XM1_ZERO); NPXFUNC1(F2XM1_SPECIAL); NPXFUNC1(F2XM1_EMPTY);
//
// Jump tables
//
const NpxFunc1 FCOSTable[TAG_MAX] = { FCOS_VALID, FCOS_ZERO, FCOS_SPECIAL, FCOS_EMPTY };
const NpxFunc2 FPATANTable[TAG_MAX][TAG_MAX] = { // left = TAG_VALID, right is ...
{ FPATAN_VALID_VALID, FPATAN_VALID_VALID, FPATAN_VALID_SPECIAL, FPATAN_ALL_EMPTY }, // left = TAG_ZERO, right is ...
{ FPATAN_VALID_VALID, FPATAN_VALID_VALID, FPATAN_VALID_SPECIAL, FPATAN_ALL_EMPTY }, // left = TAG_SPECIAL, right is ...
{ FPATAN_SPECIAL_VALID, FPATAN_SPECIAL_VALID, FPATAN_SPECIAL_SPECIAL, FPATAN_ALL_EMPTY }, // left = TAG_EMPTY, right is ...
{ FPATAN_EMPTY_ALL, FPATAN_EMPTY_ALL, FPATAN_EMPTY_ALL, FPATAN_EMPTY_ALL } };
const NpxFunc0 FPTANTable[TAG_MAX-1] = { FPTAN_VALID, FPTAN_ZERO, FPTAN_SPECIAL };
const NpxFunc0 FSINTable[TAG_MAX] = { FSIN_VALID, FSIN_ZERO, FSIN_SPECIAL, FSIN_EMPTY };
const NpxFunc0 FSINCOSTable[TAG_MAX-1] = { FSINCOS_VALID, FSINCOS_ZERO, FSINCOS_SPECIAL };
// In the functions, l == ST(0), r = ST(1)
// r = r*log(l), l must be > 0
const NpxFunc2 FYL2XTable[TAG_MAX][TAG_MAX] = { // left is TAG_VALID, right is ...
{ FYL2X_VALID_VALID, FYL2X_VALID_ZERO, FYL2X_VALIDORZERO_SPECIAL, FYL2X_ANY_EMPTY }, // left is TAG_ZERO, right is ...
{ FYL2X_ZERO_VALID, FYL2X_ZERO_ZERO, FYL2X_VALIDORZERO_SPECIAL, FYL2X_ANY_EMPTY }, // left is TAG_SPECIAL, right is ...
{ FYL2X_SPECIAL_VALIDORZERO, FYL2X_SPECIAL_VALIDORZERO, FYL2X_SPECIAL_SPECIAL, FYL2X_ANY_EMPTY }, // left is TAG_EMPTY, right is ...
{ FYL2X_EMPTY_ANY, FYL2X_EMPTY_ANY, FYL2X_EMPTY_ANY, FYL2X_EMPTY_ANY} };
// In the functions, l == ST(0), r = ST(1)
// r = r*(logl+1), l must be > 1
const NpxFunc2 FYL2XP1Table[TAG_MAX][TAG_MAX] = { // left is TAG_VALID, right is ...
{ FYL2XP1_VALIDORZERO_VALID, FYL2XP1_VALIDORZERO_ZERO, FYL2XP1_VALIDORZERO_SPECIAL, FYL2XP1_ANY_EMPTY }, // left is TAG_ZERO, right is ...
{ FYL2XP1_VALIDORZERO_VALID, FYL2XP1_VALIDORZERO_ZERO, FYL2XP1_VALIDORZERO_SPECIAL, FYL2X_ANY_EMPTY }, // left is TAG_SPECIAL, right is ...
{ FYL2XP1_SPECIAL_VALIDORZERO, FYL2XP1_SPECIAL_VALIDORZERO, FYL2XP1_SPECIAL_SPECIAL, FYL2XP1_ANY_EMPTY }, // left is TAG_EMPTY, right is ...
{ FYL2XP1_EMPTY_ANY, FYL2XP1_EMPTY_ANY, FYL2XP1_EMPTY_ANY, FYL2XP1_EMPTY_ANY} };
const NpxFunc1 F2XM1Table[TAG_MAX] = { F2XM1_VALID, F2XM1_ZERO, F2XM1_SPECIAL, F2XM1_EMPTY };
NPXFUNC1(FCOS_VALID) { Fp->r64 = cos(Fp->r64); SetTag(Fp); }
NPXFUNC1(FCOS_ZERO) { Fp->Tag = TAG_VALID; Fp->r64 = 1.0; }
NPXFUNC1(FCOS_SPECIAL) { switch (Fp->TagSpecial) { case TAG_SPECIAL_DENORM: FCOS_VALID(cpu, Fp); break;
case TAG_SPECIAL_INFINITY: cpu->FpStatusC2 = 1; SetIndefinite(Fp); break;
case TAG_SPECIAL_SNAN: HandleSnan(cpu, Fp); break;
case TAG_SPECIAL_QNAN: case TAG_SPECIAL_INDEF: HandleInvalidOp(cpu); break; } }
NPXFUNC1(FCOS_EMPTY) { HandleStackEmpty(cpu, Fp); }
FRAG0(FCOS) { PFPREG ST0; FpArithPreamble(cpu);
cpu->FpStatusC2 = 0; ST0 = cpu->FpST0; (*FCOSTable[ST0->Tag])(cpu, ST0); }
NPXFUNC2(FPATAN_VALID_VALID) { l->r64 = Proxyatan2(l->r64, r->r64); SetTag(l); POPFLT; }
NPXFUNC2(FPATAN_VALID_SPECIAL) { switch (r->TagSpecial) { case TAG_SPECIAL_DENORM: case TAG_SPECIAL_INFINITY: FPATAN_VALID_VALID(cpu, l, r); break;
case TAG_SPECIAL_SNAN: if (HandleSnan(cpu, r)) { break; } // else fall into QNAN
case TAG_SPECIAL_QNAN: case TAG_SPECIAL_INDEF: // return the QNAN as the result
l->r64 = r->r64; l->Tag = TAG_SPECIAL; l->TagSpecial = r->TagSpecial; POPFLT; break; } }
NPXFUNC2(FPATAN_SPECIAL_VALID) { switch (l->TagSpecial) { case TAG_SPECIAL_DENORM: case TAG_SPECIAL_INFINITY: FPATAN_VALID_VALID(cpu, l, r); break;
case TAG_SPECIAL_SNAN: if (HandleSnan(cpu, l)) { break; } // else fall into QNAN
case TAG_SPECIAL_QNAN: case TAG_SPECIAL_INDEF: // The QNAN is already in l, so nothing to do.
POPFLT; break; } }
NPXFUNC2(FPATAN_SPECIAL_SPECIAL) { if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, l)) { return; } if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, r)) { return; } if (IS_TAG_NAN(l)) { if (IS_TAG_NAN(r)) { //
// Return the larger of the two NANs
//
l->r64 = l->r64 + r->r64; SetTag(l); } //
// else l is a NAN and r isn't - return the NAN in l
//
POPFLT; return; } if (IS_TAG_NAN(r)) { // r is a NAN and l isn't - return the NAN in l
l->r64 = r->r64; l->Tag = TAG_SPECIAL; l->TagSpecial = r->TagSpecial; POPFLT; }
// Otherwise, l and r are both INFINITY. Return INDEFINITE
CPUASSERT(l->TagSpecial == TAG_SPECIAL_INFINITY && r->TagSpecial == TAG_SPECIAL_INFINITY); SetIndefinite(l); POPFLT; }
NPXFUNC2(FPATAN_EMPTY_ALL) { if (!HandleStackEmpty(cpu, l)) { (*FPATANTable[TAG_SPECIAL][r->Tag])(cpu, l, r); } }
NPXFUNC2(FPATAN_ALL_EMPTY) { if (!HandleStackEmpty(cpu, r)) { (*FPATANTable[l->Tag][TAG_SPECIAL])(cpu, l, r); } }
FRAG0(FPATAN) { PFPREG l = &cpu->FpStack[ST(1)]; PFPREG r = cpu->FpST0;
FpArithPreamble(cpu); (*FPATANTable[l->Tag][r->Tag])(cpu, l, r); }
NPXFUNC0(FPTAN_VALID) { int Exponent; PFPREG ST0;
// get the exponent and make sure it is < 63
ST0 = cpu->FpST0; Exponent = (int)((ST0->rdw[1] >> 20) & 0x7ff) - 1023; if (Exponent >= 63) { cpu->FpStatusC2 = 1; return; } ST0->r64 = tan(ST0->r64); SetTag(ST0); PUSHFLT(ST0); ST0->Tag = TAG_VALID; ST0->r64 = 1.0; }
NPXFUNC0(FPTAN_ZERO) { PFPREG ST0;
ST0=cpu->FpST0; ST0->r64 = 0.0; ST0->Tag = TAG_ZERO; PUSHFLT(ST0); ST0->r64 = 1.0; ST0->Tag = TAG_VALID; }
NPXFUNC0(FPTAN_SPECIAL) { if (cpu->FpST0->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, cpu->FpST0)) { return; } else if (cpu->FpST0->TagSpecial == TAG_SPECIAL_DENORM) { FPTAN_VALID(cpu); } cpu->FpStatusC2 = 1; }
FRAG0(FPTAN) { PFPREG ST0;
FpArithPreamble(cpu);
ST0 = cpu->FpST0;
//
// TAG_EMPTY is handled first so that we can check ST(7) before
// anything else has a chance to raise an exception.
//
if (ST0->Tag == TAG_EMPTY && HandleStackEmpty(cpu, ST0)) { return; }
if (cpu->FpStack[ST(7)].Tag != TAG_EMPTY) { HandleStackFull(cpu, &cpu->FpStack[ST(7)]); return; }
// assume no error
cpu->FpStatusC2 = 0;
// calculate the value
CPUASSERT(ST0->Tag < TAG_EMPTY); // EMPTY was already handled
(*FPTANTable[ST0->Tag])(cpu); }
NPXFUNC0(FSIN_VALID) { PFPREG ST0;
ST0 = cpu->FpST0; ST0->r64 = sin(ST0->r64); SetTag(ST0); }
NPXFUNC0(FSIN_ZERO) { // sin(0.0) == 0.0, so there is nothing to do
}
NPXFUNC0(FSIN_SPECIAL) { if (cpu->FpST0->TagSpecial == TAG_SPECIAL_SNAN && HandleSnan(cpu, cpu->FpST0)) { return; } else if (cpu->FpST0->TagSpecial == TAG_SPECIAL_DENORM) { FSIN_VALID(cpu); } cpu->FpStatusC2 = 1; }
NPXFUNC0(FSIN_EMPTY) { if (!HandleStackEmpty(cpu, cpu->FpST0)) { cpu->FpStatusC2 = 1; } }
FRAG0(FSIN) { FpArithPreamble(cpu);
// assume no error
cpu->FpStatusC2 = 0;
// calculate the value
(*FSINTable[cpu->FpST0->Tag])(cpu); }
NPXFUNC0(FSINCOS_VALID) { DOUBLE Val; PFPREG ST0;
ST0 = cpu->FpST0; Val = ST0->r64; ST0->r64 = sin(Val); SetTag(ST0); PUSHFLT(ST0); ST0->r64 = cos(Val); SetTag(ST0); }
NPXFUNC0(FSINCOS_ZERO) { PFPREG ST0;
ST0=cpu->FpST0; ST0->r64 = 0.0; ST0->Tag = TAG_ZERO; PUSHFLT(ST0); ST0->r64 = 1.0; ST0->Tag = TAG_VALID; }
NPXFUNC0(FSINCOS_SPECIAL) { switch (cpu->FpST0->TagSpecial) { case TAG_SPECIAL_DENORM: FSINCOS_VALID(cpu); break;
case TAG_SPECIAL_INFINITY: cpu->FpStatusC2 = 1; SetIndefinite(cpu->FpST0); break;
case TAG_SPECIAL_SNAN: if (HandleSnan(cpu, cpu->FpST0)) { return; } // else fall into TAG_SPECIAL_QNAN
case TAG_SPECIAL_QNAN: case TAG_SPECIAL_INDEF: cpu->FpStatusC2 = 1; break; } }
FRAG0(FSINCOS) { PFPREG ST0;
FpArithPreamble(cpu);
// assume no errors
cpu->FpStatusC2 = 0;
ST0 = cpu->FpST0; if (ST0->Tag == TAG_EMPTY && HandleStackEmpty(cpu, ST0)) { return; }
if (cpu->FpStack[ST(7)].Tag != TAG_EMPTY) { HandleStackFull(cpu, &cpu->FpStack[ST(7)]); return; }
CPUASSERT(ST0->Tag < TAG_EMPTY); // EMPTY was already handled
(*FSINCOSTable[ST0->Tag])(cpu); }
NPXFUNC2(FYL2X_VALID_VALID) { if (l->r64 < 0.0) { // ST0 is negative - invalid operation
if (!HandleInvalidOp(cpu)) { SetIndefinite(r); POPFLT; } return; } // r = r * log10(l->r64) / log10(2)
//
r->r64 *= Proxylog10(l->r64) / (0.301029995664); SetTag(r); POPFLT; }
NPXFUNC2(FYL2X_VALID_ZERO) { if (l->r64 < 0.0) { // ST0 is negative - invalid operation
if (!HandleInvalidOp(cpu)) { SetIndefinite(r); POPFLT; } return; } // r = r*log2(l), but r=0, so the answer is 0.
r->r64 = 0; r->Tag = TAG_ZERO; POPFLT; }
NPXFUNC2(FYL2X_ZERO_VALID) { // Divide-by-zero error
cpu->FpStatusExceptions |= FPCONTROL_ZM; if (cpu->FpControlMask & FPCONTROL_ZM) { // Zero-divide exception is masked - return -INFINITY
r->r64 = R8NegativeInfinity; r->Tag = TAG_SPECIAL; r->TagSpecial = TAG_SPECIAL_INFINITY; POPFLT; } else { cpu->FpStatusES = 1; } }
NPXFUNC2(FYL2X_ZERO_ZERO) { if (!HandleInvalidOp(cpu)) { SetIndefinite(r); POPFLT; } }
NPXFUNC2(FYL2X_SPECIAL_VALIDORZERO) { switch (l->TagSpecial) { case TAG_SPECIAL_DENORM: (*FYL2XTable[TAG_VALID][r->Tag])(cpu, l, r); break;
case TAG_SPECIAL_INFINITY: if (r->Tag == TAG_ZERO || r->rb[7] & 0x80) { // 0*infinity, or anything*-infinity
SetIndefinite(r); } else { // return -infinity
r->rb[7] |= 0x80; } POPFLT; break;
case TAG_SPECIAL_SNAN: if (HandleSnan(cpu, l)) { return; } // else fall into TAG_SPECIAL_QNAN
case TAG_SPECIAL_QNAN: case TAG_SPECIAL_INDEF: // l is a NAN and r is VALID or ZERO - return the NAN
r->r64 = l->r64; r->Tag = l->Tag; r->TagSpecial = r->TagSpecial; POPFLT; break; } }
NPXFUNC2(FYL2X_VALIDORZERO_SPECIAL) { switch (r->TagSpecial) { case TAG_SPECIAL_DENORM: (*FYL2XTable[l->Tag][TAG_VALID])(cpu, l, r); break;
case TAG_SPECIAL_INFINITY: // log(x)*infinity
if (l->r64 > 1.0) { // return the original infinity - nothing to do
} else if (l->r64 < 0.0 || l->r64 == 1.0) { if (HandleInvalidOp(cpu)) { return; } SetIndefinite(r); } else { // return infinity with sign flipped
r->rb[7] ^= 0x80; }
POPFLT; break;
case TAG_SPECIAL_SNAN: if (HandleSnan(cpu, r)) { return; } // else fall into TAG_SPECIAL_QNAN
case TAG_SPECIAL_QNAN: case TAG_SPECIAL_INDEF: // r is a NAN and l is VALID or ZERO - return the NAN
POPFLT; break; } }
NPXFUNC2(FYL2X_SPECIAL_SPECIAL) { if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleStackEmpty(cpu, l)) { return; } if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleStackEmpty(cpu, r)) { return; }
if (l->TagSpecial == TAG_SPECIAL_DENORM) { (*FYL2XTable[TAG_VALID][r->Tag])(cpu, l, r); return; } if (r->TagSpecial == TAG_SPECIAL_DENORM) { (*FYL2XTable[l->Tag][TAG_VALID])(cpu, l, r); return; }
if (l->Tag == TAG_SPECIAL_INFINITY) {
if (r->Tag == TAG_SPECIAL_INFINITY) {
// two infinities - return INDEFINITE
SetIndefinite(r);
} else { CPUASSERT(IS_TAG_NAN(r));
// r already has the NAN to return
} } else { CPUASSERT(IS_TAG_NAN(l));
if (r->Tag == TAG_SPECIAL_INFINITY) { //
// Return the NAN from l
//
r->r64 = l->r64; r->TagSpecial = l->TagSpecial; } else { //
// Return the largest of the two NANs
//
r->r64 = l->r64 + r->r64; SetTag(r); } } POPFLT; }
NPXFUNC2(FYL2X_ANY_EMPTY) { if (!HandleStackEmpty(cpu, r)) { (*FYL2XTable[l->Tag][TAG_SPECIAL])(cpu, l, r); } }
NPXFUNC2(FYL2X_EMPTY_ANY) { if (!HandleStackEmpty(cpu, l)) { (*FYL2XTable[TAG_SPECIAL][r->Tag])(cpu, l, r); } }
FRAG0(FYL2X) { PFPREG l, r;
FpArithPreamble(cpu);
l = cpu->FpST0; r = &cpu->FpStack[ST(1)];
// In the functions, l == ST(0), r = ST(1)
(*FYL2XTable[l->Tag][r->Tag])(cpu, l, r); }
NPXFUNC2(FYL2XP1_VALIDORZERO_VALID) { if (l->r64 < -1.0) { if (!HandleInvalidOp(cpu)) { SetIndefinite(r); POPFLT; } return; } else if (l->r64 == -1.0) { // Divide-by-zero error
cpu->FpStatusExceptions |= FPCONTROL_ZM; if (cpu->FpControlMask & FPCONTROL_ZM) { // Zero-divide exception is masked - return -INFINITY
r->r64 = R8NegativeInfinity; r->Tag = TAG_SPECIAL; r->TagSpecial = TAG_SPECIAL_INFINITY; POPFLT; } else { cpu->FpStatusES = 1; } return; } // r = r * log10(l+1) / log10(2)
//
r->r64 *= Proxylog10(l->r64 + 1.0) / (0.301029995664); SetTag(r); POPFLT; }
NPXFUNC2(FYL2XP1_VALIDORZERO_ZERO) { if (l->r64 < -1.0) { if (!HandleInvalidOp(cpu)) { SetIndefinite(r); POPFLT; } return; } // r = r*log2(l), but r=0, so the answer is 0.
r->r64 = 0; r->Tag = TAG_ZERO; POPFLT; }
NPXFUNC2(FYL2XP1_SPECIAL_VALIDORZERO) { switch (l->TagSpecial) { case TAG_SPECIAL_DENORM: (*FYL2XP1Table[TAG_VALID][r->Tag])(cpu, l, r); break;
case TAG_SPECIAL_INFINITY: if (r->Tag == TAG_ZERO || r->rb[7] & 0x80) { if (HandleInvalidOp(cpu)) { return; }
// 0*infinity, or anything*-infinity
SetIndefinite(r); } else { // return -infinity
r->rb[7] |= 0x80; } POPFLT; break;
case TAG_SPECIAL_SNAN: if (HandleSnan(cpu, l)) { return; } // else fall into TAG_SPECIAL_QNAN
case TAG_SPECIAL_QNAN: case TAG_SPECIAL_INDEF: // l is a NAN and r is VALID or ZERO - return the NAN
r->r64 = l->r64; r->Tag = l->Tag; r->TagSpecial = r->TagSpecial; POPFLT; break; } }
NPXFUNC2(FYL2XP1_VALIDORZERO_SPECIAL) { switch (r->TagSpecial) { case TAG_SPECIAL_DENORM: (*FYL2XP1Table[l->Tag][TAG_VALID])(cpu, l, r); break;
case TAG_SPECIAL_INFINITY: // log(x)*infinity
if (l->r64 > 1.0) { // return the original infinity - nothing to do
} else if (l->r64 < 0.0 || l->r64 == 1.0) { if (HandleInvalidOp(cpu)) { return; } SetIndefinite(r); } else { // return infinity with sign flipped
r->rb[7] ^= 0x80; }
POPFLT; break;
case TAG_SPECIAL_SNAN: if (HandleSnan(cpu, r)) { return; } // else fall into TAG_SPECIAL_QNAN
case TAG_SPECIAL_QNAN: case TAG_SPECIAL_INDEF: // r is a NAN and l is VALID or ZERO - return the NAN
POPFLT; break; } }
NPXFUNC2(FYL2XP1_SPECIAL_SPECIAL) { if (l->TagSpecial == TAG_SPECIAL_SNAN && HandleStackEmpty(cpu, l)) { return; } if (r->TagSpecial == TAG_SPECIAL_SNAN && HandleStackEmpty(cpu, r)) { return; }
if (l->TagSpecial == TAG_SPECIAL_DENORM) { (*FYL2XP1Table[TAG_VALID][r->Tag])(cpu, l, r); return; } if (r->TagSpecial == TAG_SPECIAL_DENORM) { (*FYL2XP1Table[l->Tag][TAG_VALID])(cpu, l, r); return; }
if (l->Tag == TAG_SPECIAL_INFINITY) {
if (r->Tag == TAG_SPECIAL_INFINITY) {
if (l->rb[7] & 0x80) { // l is negative infinity. Invalid op
if (HandleInvalidOp(cpu)) { return; } SetIndefinite(r); }
} else { CPUASSERT(IS_TAG_NAN(r));
// r already has the NAN to return
} } else { CPUASSERT(IS_TAG_NAN(l));
if (r->Tag == TAG_SPECIAL_INFINITY) { //
// Return the NAN from l
//
r->r64 = l->r64; r->TagSpecial = l->TagSpecial; } else { //
// Return the largest of the two NANs
//
r->r64 = l->r64 + r->r64; SetTag(r); } } POPFLT; }
NPXFUNC2(FYL2XP1_ANY_EMPTY) { if (!HandleStackEmpty(cpu, r)) { (*FYL2XP1Table[l->Tag][TAG_SPECIAL])(cpu, l, r); } }
NPXFUNC2(FYL2XP1_EMPTY_ANY) { if (!HandleStackEmpty(cpu, l)) { (*FYL2XP1Table[TAG_SPECIAL][r->Tag])(cpu, l, r); } }
FRAG0(FYL2XP1) { PFPREG l, r;
FpArithPreamble(cpu);
l = cpu->FpST0; r = &cpu->FpStack[ST(1)];
// In the functions, l == ST(0), r = ST(1)
(*FYL2XP1Table[l->Tag][r->Tag])(cpu, l, r); }
NPXFUNC1(F2XM1_VALID) { Fp->r64 = pow(2.0, Fp->r64) - 1.0; SetTag(Fp); }
NPXFUNC1(F2XM1_ZERO) { // nothing to do - return the same zero
}
NPXFUNC1(F2XM1_SPECIAL) { switch (Fp->TagSpecial) { case TAG_SPECIAL_DENORM: F2XM1_VALID(cpu, Fp); break;
case TAG_SPECIAL_INFINITY: if (Fp->rb[7] & 0x80) { // -infinity - return 1
Fp->r64 = 1.0; Fp->Tag = TAG_VALID; } // else +infinity - return +infinity
break;
case TAG_SPECIAL_SNAN: HandleSnan(cpu, Fp); // fall into TAG_SPECIAL_QNAN
case TAG_SPECIAL_QNAN: case TAG_SPECIAL_INDEF: // return the NAN
break; } }
NPXFUNC1(F2XM1_EMPTY) { HandleStackEmpty(cpu, Fp); }
FRAG0(F2XM1) { PFPREG ST0;
FpArithPreamble(cpu); ST0 = cpu->FpST0; (*F2XM1Table[ST0->Tag])(cpu, ST0); }
|