/*++ 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 #include #include #include #include #include #include #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); }