root/arch/i386/math-emu/fpu_trig.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. trig_arg
  2. convert_l2reg
  3. single_arg_error
  4. single_arg_2_error
  5. f2xm1
  6. fptan
  7. fxtract
  8. fdecstp
  9. fincstp
  10. fsqrt_
  11. frndint_
  12. fsin
  13. f_cos
  14. fcos
  15. fsincos
  16. rem_kernel
  17. do_fprem
  18. fyl2x
  19. fpatan
  20. fprem
  21. fprem1
  22. fyl2xp1
  23. fscale
  24. trig_a
  25. trig_b

   1 /*---------------------------------------------------------------------------+
   2  |  fpu_trig.c                                                               |
   3  |                                                                           |
   4  | Implementation of the FPU "transcendental" functions.                     |
   5  |                                                                           |
   6  | Copyright (C) 1992,1993,1994                                              |
   7  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   8  |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
   9  |                                                                           |
  10  |                                                                           |
  11  +---------------------------------------------------------------------------*/
  12 
  13 #include "fpu_system.h"
  14 #include "exception.h"
  15 #include "fpu_emu.h"
  16 #include "status_w.h"
  17 #include "control_w.h"
  18 #include "reg_constant.h"       
  19 
  20 
  21 static void rem_kernel(unsigned long long st0, unsigned long long *y,
  22                        unsigned long long st1,
  23                        unsigned long long q, int n);
  24 
  25 #define BETTER_THAN_486
  26 
  27 #define FCOS  4
  28 /* Not needed now with new code
  29 #define FPTAN 1
  30  */
  31 
  32 /* Used only by fptan, fsin, fcos, and fsincos. */
  33 /* This routine produces very accurate results, similar to
  34    using a value of pi with more than 128 bits precision. */
  35 /* Limited measurements show no results worse than 64 bit precision
  36    except for the results for arguments close to 2^63, where the
  37    precision of the result sometimes degrades to about 63.9 bits */
  38 static int trig_arg(FPU_REG *X, int even)
     /* [previous][next][first][last][top][bottom][index][help] */
  39 {
  40   FPU_REG tmp;
  41   unsigned long long q;
  42   int old_cw = control_word, saved_status = partial_status;
  43 
  44   if ( X->exp >= EXP_BIAS + 63 )
  45     {
  46       partial_status |= SW_C2;     /* Reduction incomplete. */
  47       return -1;
  48     }
  49 
  50   control_word &= ~CW_RC;
  51   control_word |= RC_CHOP;
  52 
  53   reg_div(X, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
  54   round_to_int(&tmp);  /* Fortunately, this can't overflow
  55                           to 2^64 */
  56   q = significand(&tmp);
  57   if ( q )
  58     {
  59       rem_kernel(significand(X),
  60                  &significand(&tmp),
  61                  significand(&CONST_PI2),
  62                  q, X->exp - CONST_PI2.exp);
  63       tmp.exp = CONST_PI2.exp;
  64       normalize(&tmp);
  65       reg_move(&tmp, X);
  66     }
  67 
  68 #ifdef FPTAN
  69   if ( even == FPTAN )
  70     {
  71       if ( ((X->exp >= EXP_BIAS) ||
  72             ((X->exp == EXP_BIAS-1)
  73              && (X->sigh >= 0xc90fdaa2))) ^ (q & 1) )
  74         even = FCOS;
  75       else
  76         even = 0;
  77     }
  78 #endif FPTAN
  79 
  80   if ( (even && !(q & 1)) || (!even && (q & 1)) )
  81     {
  82       reg_sub(&CONST_PI2, X, X, FULL_PRECISION);
  83 #ifdef BETTER_THAN_486
  84       /* So far, the results are exact but based upon a 64 bit
  85          precision approximation to pi/2. The technique used
  86          now is equivalent to using an approximation to pi/2 which
  87          is accurate to about 128 bits. */
  88       if ( (X->exp <= CONST_PI2extra.exp + 64) || (q > 1) )
  89         {
  90           /* This code gives the effect of having p/2 to better than
  91              128 bits precision. */
  92           significand(&tmp) = q + 1;
  93           tmp.exp = EXP_BIAS + 63;
  94           tmp.tag = TW_Valid;
  95           normalize(&tmp);
  96           reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
  97           reg_add(X, &tmp,  X, FULL_PRECISION);
  98           if ( X->sign == SIGN_NEG )
  99             {
 100               /* CONST_PI2extra is negative, so the result of the addition
 101                  can be negative. This means that the argument is actually
 102                  in a different quadrant. The correction is always < pi/2,
 103                  so it can't overflow into yet another quadrant. */
 104               X->sign = SIGN_POS;
 105               q++;
 106             }
 107         }
 108 #endif BETTER_THAN_486
 109     }
 110 #ifdef BETTER_THAN_486
 111   else
 112     {
 113       /* So far, the results are exact but based upon a 64 bit
 114          precision approximation to pi/2. The technique used
 115          now is equivalent to using an approximation to pi/2 which
 116          is accurate to about 128 bits. */
 117       if ( ((q > 0) && (X->exp <= CONST_PI2extra.exp + 64)) || (q > 1) )
 118         {
 119           /* This code gives the effect of having p/2 to better than
 120              128 bits precision. */
 121           significand(&tmp) = q;
 122           tmp.exp = EXP_BIAS + 63;
 123           tmp.tag = TW_Valid;
 124           normalize(&tmp);
 125           reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
 126           reg_sub(X, &tmp, X, FULL_PRECISION);
 127           if ( (X->exp == CONST_PI2.exp) &&
 128               ((X->sigh > CONST_PI2.sigh)
 129                || ((X->sigh == CONST_PI2.sigh)
 130                    && (X->sigl > CONST_PI2.sigl))) )
 131             {
 132               /* CONST_PI2extra is negative, so the result of the
 133                  subtraction can be larger than pi/2. This means
 134                  that the argument is actually in a different quadrant.
 135                  The correction is always < pi/2, so it can't overflow
 136                  into yet another quadrant. */
 137               reg_sub(&CONST_PI, X, X, FULL_PRECISION);
 138               q++;
 139             }
 140         }
 141     }
 142 #endif BETTER_THAN_486
 143 
 144   control_word = old_cw;
 145   partial_status = saved_status & ~SW_C2;     /* Reduction complete. */
 146 
 147   return (q & 3) | even;
 148 }
 149 
 150 
 151 /* Convert a long to register */
 152 void convert_l2reg(long const *arg, FPU_REG *dest)
     /* [previous][next][first][last][top][bottom][index][help] */
 153 {
 154   long num = *arg;
 155 
 156   if (num == 0)
 157     { reg_move(&CONST_Z, dest); return; }
 158 
 159   if (num > 0)
 160     dest->sign = SIGN_POS;
 161   else
 162     { num = -num; dest->sign = SIGN_NEG; }
 163 
 164   dest->sigh = num;
 165   dest->sigl = 0;
 166   dest->exp = EXP_BIAS + 31;
 167   dest->tag = TW_Valid;
 168   normalize(dest);
 169 }
 170 
 171 
 172 static void single_arg_error(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 173 {
 174   switch ( st0_ptr->tag )
 175     {
 176     case TW_NaN:
 177       if ( !(st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
 178         {
 179           EXCEPTION(EX_Invalid);
 180           if ( control_word & CW_Invalid )
 181             st0_ptr->sigh |= 0x40000000;          /* Convert to a QNaN */
 182         }
 183       break;              /* return with a NaN in st(0) */
 184     case TW_Empty:
 185       stack_underflow();  /* Puts a QNaN in st(0) */
 186       break;
 187 #ifdef PARANOID
 188     default:
 189       EXCEPTION(EX_INTERNAL|0x0112);
 190 #endif PARANOID
 191     }
 192 }
 193 
 194 
 195 static void single_arg_2_error(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 196 {
 197   FPU_REG *st_new_ptr;
 198 
 199   switch ( st0_ptr->tag )
 200     {
 201     case TW_NaN:
 202       if ( !(st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
 203         {
 204           EXCEPTION(EX_Invalid);
 205           if ( control_word & CW_Invalid )
 206             {
 207               /* The masked response */
 208               /* Convert to a QNaN */
 209               st0_ptr->sigh |= 0x40000000;
 210               st_new_ptr = &st(-1);
 211               push();
 212               reg_move(&st(1), st_new_ptr);
 213             }
 214         }
 215       else
 216         {
 217           /* A QNaN */
 218           st_new_ptr = &st(-1);
 219           push();
 220           reg_move(&st(1), st_new_ptr);
 221         }
 222       break;              /* return with a NaN in st(0) */
 223 #ifdef PARANOID
 224     default:
 225       EXCEPTION(EX_INTERNAL|0x0112);
 226 #endif PARANOID
 227     }
 228 }
 229 
 230 
 231 /*---------------------------------------------------------------------------*/
 232 
 233 static void f2xm1(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 234 {
 235   clear_C1();
 236   switch ( st0_ptr->tag )
 237     {
 238     case TW_Valid:
 239       {
 240         if ( st0_ptr->exp >= 0 )
 241           {
 242             /* For an 80486 FPU, the result is undefined. */
 243           }
 244 #ifdef DENORM_OPERAND
 245         else if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 246           return;
 247 #endif DENORM_OPERAND
 248         else
 249           {
 250             /* poly_2xm1(x) requires 0 < x < 1. */
 251             poly_2xm1(st0_ptr, st0_ptr);
 252           }
 253         if ( st0_ptr->exp <= EXP_UNDER )
 254           {
 255             /* A denormal result has been produced.
 256                Precision must have been lost, this is always
 257                an underflow. */
 258             arith_underflow(st0_ptr);
 259           }
 260         set_precision_flag_up();   /* 80486 appears to always do this */
 261         return;
 262       }
 263     case TW_Zero:
 264       return;
 265     case TW_Infinity:
 266       if ( st0_ptr->sign == SIGN_NEG )
 267         {
 268           /* -infinity gives -1 (p16-10) */
 269           reg_move(&CONST_1, st0_ptr);
 270           st0_ptr->sign = SIGN_NEG;
 271         }
 272       return;
 273     default:
 274       single_arg_error(st0_ptr);
 275     }
 276 }
 277 
 278 
 279 static void fptan(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 280 {
 281   char st0_tag = st0_ptr->tag;
 282   FPU_REG *st_new_ptr;
 283   int q;
 284   char arg_sign = st0_ptr->sign;
 285 
 286   /* Stack underflow has higher priority */
 287   if ( st0_tag == TW_Empty )
 288     {
 289       stack_underflow();  /* Puts a QNaN in st(0) */
 290       if ( control_word & CW_Invalid )
 291         {
 292           st_new_ptr = &st(-1);
 293           push();
 294           stack_underflow();  /* Puts a QNaN in the new st(0) */
 295         }
 296       return;
 297     }
 298 
 299   if ( STACK_OVERFLOW )
 300     { stack_overflow(); return; }
 301 
 302   switch ( st0_tag )
 303     {
 304     case TW_Valid:
 305       if ( st0_ptr->exp > EXP_BIAS - 40 )
 306         {
 307           st0_ptr->sign = SIGN_POS;
 308           if ( (q = trig_arg(st0_ptr, 0)) != -1 )
 309             {
 310               poly_tan(st0_ptr, st0_ptr);
 311               st0_ptr->sign = (q & 1) ^ arg_sign;
 312             }
 313           else
 314             {
 315               /* Operand is out of range */
 316               st0_ptr->sign = arg_sign;         /* restore st(0) */
 317               return;
 318             }
 319           set_precision_flag_up();  /* We do not really know if up or down */
 320         }
 321       else
 322         {
 323           /* For a small arg, the result == the argument */
 324           /* Underflow may happen */
 325 
 326           if ( st0_ptr->exp <= EXP_UNDER )
 327             {
 328 #ifdef DENORM_OPERAND
 329               if ( denormal_operand() )
 330                 return;
 331 #endif DENORM_OPERAND
 332               /* A denormal result has been produced.
 333                  Precision must have been lost, this is always
 334                  an underflow. */
 335               if ( arith_underflow(st0_ptr) )
 336                 return;
 337             }
 338           set_precision_flag_down();  /* Must be down. */
 339         }
 340       push();
 341       reg_move(&CONST_1, st_new_ptr);
 342       return;
 343       break;
 344     case TW_Infinity:
 345       /* The 80486 treats infinity as an invalid operand */
 346       arith_invalid(st0_ptr);
 347       if ( control_word & CW_Invalid )
 348         {
 349           st_new_ptr = &st(-1);
 350           push();
 351           arith_invalid(st_new_ptr);
 352         }
 353       return;
 354     case TW_Zero:
 355       push();
 356       reg_move(&CONST_1, st_new_ptr);
 357       setcc(0);
 358       break;
 359     default:
 360       single_arg_2_error(st0_ptr);
 361       break;
 362     }
 363 }
 364 
 365 
 366 static void fxtract(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 367 {
 368   char st0_tag = st0_ptr->tag;
 369   FPU_REG *st_new_ptr;
 370   register FPU_REG *st1_ptr = st0_ptr;  /* anticipate */
 371 
 372   if ( STACK_OVERFLOW )
 373     {  stack_overflow(); return; }
 374   clear_C1();
 375   if ( !(st0_tag ^ TW_Valid) )
 376     {
 377       long e;
 378 
 379 #ifdef DENORM_OPERAND
 380       if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 381         return;
 382 #endif DENORM_OPERAND
 383           
 384       push();
 385       reg_move(st1_ptr, st_new_ptr);
 386       st_new_ptr->exp = EXP_BIAS;
 387       e = st1_ptr->exp - EXP_BIAS;
 388       convert_l2reg(&e, st1_ptr);
 389       return;
 390     }
 391   else if ( st0_tag == TW_Zero )
 392     {
 393       char sign = st0_ptr->sign;
 394       if ( divide_by_zero(SIGN_NEG, st0_ptr) )
 395         return;
 396       push();
 397       reg_move(&CONST_Z, st_new_ptr);
 398       st_new_ptr->sign = sign;
 399       return;
 400     }
 401   else if ( st0_tag == TW_Infinity )
 402     {
 403       char sign = st0_ptr->sign;
 404       st0_ptr->sign = SIGN_POS;
 405       push();
 406       reg_move(&CONST_INF, st_new_ptr);
 407       st_new_ptr->sign = sign;
 408       return;
 409     }
 410   else if ( st0_tag == TW_NaN )
 411     {
 412       if ( real_2op_NaN(st0_ptr, st0_ptr, st0_ptr) )
 413         return;
 414       push();
 415       reg_move(st1_ptr, st_new_ptr);
 416       return;
 417     }
 418   else if ( st0_tag == TW_Empty )
 419     {
 420       /* Is this the correct behaviour? */
 421       if ( control_word & EX_Invalid )
 422         {
 423           stack_underflow();
 424           push();
 425           stack_underflow();
 426         }
 427       else
 428         EXCEPTION(EX_StackUnder);
 429     }
 430 #ifdef PARANOID
 431   else
 432     EXCEPTION(EX_INTERNAL | 0x119);
 433 #endif PARANOID
 434 }
 435 
 436 
 437 static void fdecstp(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 438 {
 439   clear_C1();
 440   top--;  /* st0_ptr will be fixed in math_emulate() before the next instr */
 441 }
 442 
 443 static void fincstp(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 444 {
 445   clear_C1();
 446   top++;  /* st0_ptr will be fixed in math_emulate() before the next instr */
 447 }
 448 
 449 
 450 static void fsqrt_(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 451 {
 452   char st0_tag = st0_ptr->tag;
 453 
 454   clear_C1();
 455   if ( !(st0_tag ^ TW_Valid) )
 456     {
 457       int expon;
 458       
 459       if (st0_ptr->sign == SIGN_NEG)
 460         {
 461           arith_invalid(st0_ptr);  /* sqrt(negative) is invalid */
 462           return;
 463         }
 464 
 465 #ifdef DENORM_OPERAND
 466       if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 467         return;
 468 #endif DENORM_OPERAND
 469 
 470       expon = st0_ptr->exp - EXP_BIAS;
 471       st0_ptr->exp = EXP_BIAS + (expon & 1);  /* make st(0) in  [1.0 .. 4.0) */
 472       
 473       wm_sqrt(st0_ptr, control_word);   /* Do the computation */
 474       
 475       st0_ptr->exp += expon >> 1;
 476       st0_ptr->sign = SIGN_POS;
 477     }
 478   else if ( st0_tag == TW_Zero )
 479     return;
 480   else if ( st0_tag == TW_Infinity )
 481     {
 482       if ( st0_ptr->sign == SIGN_NEG )
 483         arith_invalid(st0_ptr);  /* sqrt(-Infinity) is invalid */
 484       return;
 485     }
 486   else
 487     { single_arg_error(st0_ptr); return; }
 488 
 489 }
 490 
 491 
 492 static void frndint_(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 493 {
 494   char st0_tag = st0_ptr->tag;
 495   int flags;
 496 
 497   if ( !(st0_tag ^ TW_Valid) )
 498     {
 499       if (st0_ptr->exp > EXP_BIAS+63)
 500         return;
 501 
 502 #ifdef DENORM_OPERAND
 503       if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 504         return;
 505 #endif DENORM_OPERAND
 506 
 507       /* Fortunately, this can't overflow to 2^64 */
 508       if ( (flags = round_to_int(st0_ptr)) )
 509         set_precision_flag(flags);
 510 
 511       st0_ptr->exp = EXP_BIAS + 63;
 512       normalize(st0_ptr);
 513       return;
 514     }
 515   else if ( (st0_tag == TW_Zero) || (st0_tag == TW_Infinity) )
 516     return;
 517   else
 518     single_arg_error(st0_ptr);
 519 }
 520 
 521 
 522 static void fsin(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 523 {
 524   char st0_tag = st0_ptr->tag;
 525   char arg_sign = st0_ptr->sign;
 526 
 527   if ( st0_tag == TW_Valid )
 528     {
 529       FPU_REG rv;
 530       int q;
 531 
 532       if ( st0_ptr->exp > EXP_BIAS - 40 )
 533         {
 534           st0_ptr->sign = SIGN_POS;
 535           if ( (q = trig_arg(st0_ptr, 0)) != -1 )
 536             {
 537 
 538               poly_sine(st0_ptr, &rv);
 539 
 540               if (q & 2)
 541                 rv.sign ^= SIGN_POS ^ SIGN_NEG;
 542               rv.sign ^= arg_sign;
 543               reg_move(&rv, st0_ptr);
 544 
 545               /* We do not really know if up or down */
 546               set_precision_flag_up();
 547               return;
 548             }
 549           else
 550             {
 551               /* Operand is out of range */
 552               st0_ptr->sign = arg_sign;         /* restore st(0) */
 553               return;
 554             }
 555         }
 556       else
 557         {
 558           /* For a small arg, the result == the argument */
 559           /* Underflow may happen */
 560 
 561           if ( st0_ptr->exp <= EXP_UNDER )
 562             {
 563 #ifdef DENORM_OPERAND
 564               if ( denormal_operand() )
 565                 return;
 566 #endif DENORM_OPERAND
 567               /* A denormal result has been produced.
 568                  Precision must have been lost, this is always
 569                  an underflow. */
 570               arith_underflow(st0_ptr);
 571               return;
 572             }
 573 
 574           set_precision_flag_up();  /* Must be up. */
 575         }
 576     }
 577   else if ( st0_tag == TW_Zero )
 578     {
 579       setcc(0);
 580       return;
 581     }
 582   else if ( st0_tag == TW_Infinity )
 583     {
 584       /* The 80486 treats infinity as an invalid operand */
 585       arith_invalid(st0_ptr);
 586       return;
 587     }
 588   else
 589     single_arg_error(st0_ptr);
 590 }
 591 
 592 
 593 static int f_cos(FPU_REG *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 594 {
 595   char arg_sign = arg->sign;
 596 
 597   if ( arg->tag == TW_Valid )
 598     {
 599       FPU_REG rv;
 600       int q;
 601 
 602       if ( arg->exp > EXP_BIAS - 40 )
 603         {
 604           arg->sign = SIGN_POS;
 605           if ( (arg->exp < EXP_BIAS)
 606               || ((arg->exp == EXP_BIAS)
 607                   && (significand(arg) <= 0xc90fdaa22168c234LL)) )
 608             {
 609               poly_cos(arg, &rv);
 610               reg_move(&rv, arg);
 611 
 612               /* We do not really know if up or down */
 613               set_precision_flag_down();
 614           
 615               return 0;
 616             }
 617           else if ( (q = trig_arg(arg, FCOS)) != -1 )
 618             {
 619               poly_sine(arg, &rv);
 620 
 621               if ((q+1) & 2)
 622                 rv.sign ^= SIGN_POS ^ SIGN_NEG;
 623               reg_move(&rv, arg);
 624 
 625               /* We do not really know if up or down */
 626               set_precision_flag_down();
 627           
 628               return 0;
 629             }
 630           else
 631             {
 632               /* Operand is out of range */
 633               arg->sign = arg_sign;         /* restore st(0) */
 634               return 1;
 635             }
 636         }
 637       else
 638         {
 639 #ifdef DENORM_OPERAND
 640           if ( (arg->exp <= EXP_UNDER) && (denormal_operand()) )
 641             return 1;
 642 #endif DENORM_OPERAND
 643 
 644           setcc(0);
 645           reg_move(&CONST_1, arg);
 646 #ifdef PECULIAR_486
 647           set_precision_flag_down();  /* 80486 appears to do this. */
 648 #else
 649           set_precision_flag_up();  /* Must be up. */
 650 #endif PECULIAR_486
 651           return 0;
 652         }
 653     }
 654   else if ( arg->tag == TW_Zero )
 655     {
 656       reg_move(&CONST_1, arg);
 657       setcc(0);
 658       return 0;
 659     }
 660   else if ( arg->tag == TW_Infinity )
 661     {
 662       /* The 80486 treats infinity as an invalid operand */
 663       arith_invalid(arg);
 664       return 1;
 665     }
 666   else
 667     {
 668       single_arg_error(arg);  /* requires arg == &st(0) */
 669       return 1;
 670     }
 671 }
 672 
 673 
 674 static void fcos(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 675 {
 676   f_cos(st0_ptr);
 677 }
 678 
 679 
 680 static void fsincos(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 681 {
 682   char st0_tag = st0_ptr->tag;
 683   FPU_REG *st_new_ptr;
 684   FPU_REG arg;
 685 
 686   /* Stack underflow has higher priority */
 687   if ( st0_tag == TW_Empty )
 688     {
 689       stack_underflow();  /* Puts a QNaN in st(0) */
 690       if ( control_word & CW_Invalid )
 691         {
 692           st_new_ptr = &st(-1);
 693           push();
 694           stack_underflow();  /* Puts a QNaN in the new st(0) */
 695         }
 696       return;
 697     }
 698 
 699   if ( STACK_OVERFLOW )
 700     { stack_overflow(); return; }
 701 
 702   if ( st0_tag == TW_NaN )
 703     {
 704       single_arg_2_error(st0_ptr);
 705       return;
 706     }
 707   else if ( st0_tag == TW_Infinity )
 708     {
 709       /* The 80486 treats infinity as an invalid operand */
 710       if ( !arith_invalid(st0_ptr) )
 711         {
 712           /* unmasked response */
 713           push();
 714           arith_invalid(st_new_ptr);
 715         }
 716       return;
 717     }
 718 
 719   reg_move(st0_ptr,&arg);
 720   if ( !f_cos(&arg) )
 721     {
 722       fsin(st0_ptr);
 723       push();
 724       reg_move(&arg,st_new_ptr);
 725     }
 726 
 727 }
 728 
 729 
 730 /*---------------------------------------------------------------------------*/
 731 /* The following all require two arguments: st(0) and st(1) */
 732 
 733 /* A lean, mean kernel for the fprem instructions. This relies upon
 734    the division and rounding to an integer in do_fprem giving an
 735    exact result. Because of this, rem_kernel() needs to deal only with
 736    the least significant 64 bits, the more significant bits of the
 737    result must be zero.
 738  */
 739 static void rem_kernel(unsigned long long st0, unsigned long long *y,
     /* [previous][next][first][last][top][bottom][index][help] */
 740                        unsigned long long st1,
 741                        unsigned long long q, int n)
 742 {
 743   unsigned long long x;
 744 
 745   x = st0 << n;
 746 
 747   /* Do the required multiplication and subtraction in the one operation */
 748   asm volatile ("movl %2,%%eax; mull %4; subl %%eax,%0; sbbl %%edx,%1;
 749                  movl %3,%%eax; mull %4; subl %%eax,%1;
 750                  movl %2,%%eax; mull %5; subl %%eax,%1;"
 751                 :"=m" (x), "=m" (((unsigned *)&x)[1])
 752                 :"m" (st1),"m" (((unsigned *)&st1)[1]),
 753                  "m" (q),"m" (((unsigned *)&q)[1])
 754                 :"%ax","%dx");
 755 
 756   *y = x;
 757 }
 758 
 759 
 760 /* Remainder of st(0) / st(1) */
 761 /* This routine produces exact results, i.e. there is never any
 762    rounding or truncation, etc of the result. */
 763 static void do_fprem(FPU_REG *st0_ptr, int round)
     /* [previous][next][first][last][top][bottom][index][help] */
 764 {
 765   FPU_REG *st1_ptr = &st(1);
 766   char st1_tag = st1_ptr->tag;
 767   char st0_tag = st0_ptr->tag;
 768   char sign = st0_ptr->sign;
 769 
 770   if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
 771     {
 772       FPU_REG tmp;
 773       int old_cw = control_word;
 774       int expdif = st0_ptr->exp - st1_ptr->exp;
 775       long long q;
 776       unsigned short saved_status;
 777       int cc = 0;
 778 
 779 #ifdef DENORM_OPERAND
 780       if ( ((st0_ptr->exp <= EXP_UNDER) ||
 781             (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
 782         return;
 783 #endif DENORM_OPERAND
 784       
 785       /* We want the status following the denorm tests, but don't want
 786          the status changed by the arithmetic operations. */
 787       saved_status = partial_status;
 788       control_word &= ~CW_RC;
 789       control_word |= RC_CHOP;
 790 
 791       if (expdif < 64)
 792         {
 793           /* This should be the most common case */
 794 
 795           if ( expdif > -2 )
 796             {
 797               reg_div(st0_ptr, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
 798 
 799               if ( tmp.exp >= EXP_BIAS )
 800                 {
 801                   round_to_int(&tmp);  /* Fortunately, this can't overflow
 802                                           to 2^64 */
 803                   q = significand(&tmp);
 804 
 805                   rem_kernel(significand(st0_ptr),
 806                              &significand(&tmp),
 807                              significand(st1_ptr),
 808                              q, expdif);
 809 
 810                   tmp.exp = st1_ptr->exp;
 811                 }
 812               else
 813                 {
 814                   reg_move(st0_ptr, &tmp);
 815                   q = 0;
 816                 }
 817               tmp.sign = sign;
 818 
 819               if ( (round == RC_RND) && (tmp.sigh & 0xc0000000) )
 820                 {
 821                   /* We may need to subtract st(1) once more,
 822                      to get a result <= 1/2 of st(1). */
 823                   unsigned long long x;
 824                   expdif = st1_ptr->exp - tmp.exp;
 825                   if ( expdif <= 1 )
 826                     {
 827                       if ( expdif == 0 )
 828                         x = significand(st1_ptr) - significand(&tmp);
 829                       else /* expdif is 1 */
 830                         x = (significand(st1_ptr) << 1) - significand(&tmp);
 831                       if ( (x < significand(&tmp)) ||
 832                           /* or equi-distant (from 0 & st(1)) and q is odd */
 833                           ((x == significand(&tmp)) && (q & 1) ) )
 834                         {
 835                           tmp.sign ^= (SIGN_POS^SIGN_NEG);
 836                           significand(&tmp) = x;
 837                           q++;
 838                         }
 839                     }
 840                 }
 841 
 842               if (q & 4) cc |= SW_C0;
 843               if (q & 2) cc |= SW_C3;
 844               if (q & 1) cc |= SW_C1;
 845             }
 846           else
 847             {
 848               control_word = old_cw;
 849               setcc(0);
 850               return;
 851             }
 852         }
 853       else
 854         {
 855           /* There is a large exponent difference ( >= 64 ) */
 856           /* To make much sense, the code in this section should
 857              be done at high precision. */
 858           int exp_1;
 859 
 860           /* prevent overflow here */
 861           /* N is 'a number between 32 and 63' (p26-113) */
 862           reg_move(st0_ptr, &tmp);
 863           tmp.exp = EXP_BIAS + 56;
 864           exp_1 = st1_ptr->exp;      st1_ptr->exp = EXP_BIAS;
 865           expdif -= 56;
 866 
 867           reg_div(&tmp, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
 868           st1_ptr->exp = exp_1;
 869 
 870           round_to_int(&tmp);  /* Fortunately, this can't overflow to 2^64 */
 871 
 872           rem_kernel(significand(st0_ptr),
 873                      &significand(&tmp),
 874                      significand(st1_ptr),
 875                      significand(&tmp),
 876                      tmp.exp - EXP_BIAS
 877                      ); 
 878           tmp.exp = exp_1 + expdif;
 879           tmp.sign = sign;
 880 
 881           /* It is possible for the operation to be complete here.
 882              What does the IEEE standard say? The Intel 80486 manual
 883              implies that the operation will never be completed at this
 884              point, and the behaviour of a real 80486 confirms this.
 885            */
 886           if ( !(tmp.sigh | tmp.sigl) )
 887             {
 888               /* The result is zero */
 889               control_word = old_cw;
 890               partial_status = saved_status;
 891               reg_move(&CONST_Z, st0_ptr);
 892               st0_ptr->sign = sign;
 893 #ifdef PECULIAR_486
 894               setcc(SW_C2);
 895 #else
 896               setcc(0);
 897 #endif PECULIAR_486
 898               return;
 899             }
 900           cc = SW_C2;
 901         }
 902 
 903       control_word = old_cw;
 904       partial_status = saved_status;
 905       normalize_nuo(&tmp);
 906       reg_move(&tmp, st0_ptr);
 907       setcc(cc);
 908 
 909       /* The only condition to be looked for is underflow,
 910          and it can occur here only if underflow is unmasked. */
 911       if ( (st0_ptr->exp <= EXP_UNDER) && (st0_ptr->tag != TW_Zero)
 912           && !(control_word & CW_Underflow) )
 913         arith_underflow(st0_ptr);
 914 
 915       return;
 916     }
 917   else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
 918     {
 919       stack_underflow();
 920       return;
 921     }
 922   else if ( st0_tag == TW_Zero )
 923     {
 924       if ( st1_tag == TW_Valid )
 925         {
 926 #ifdef DENORM_OPERAND
 927           if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 928             return;
 929 #endif DENORM_OPERAND
 930 
 931           setcc(0); return;
 932         }
 933       else if ( st1_tag == TW_Zero )
 934         { arith_invalid(st0_ptr); return; } /* fprem(?,0) always invalid */
 935       else if ( st1_tag == TW_Infinity )
 936         { setcc(0); return; }
 937     }
 938   else if ( st0_tag == TW_Valid )
 939     {
 940       if ( st1_tag == TW_Zero )
 941         {
 942           arith_invalid(st0_ptr); /* fprem(Valid,Zero) is invalid */
 943           return;
 944         }
 945       else if ( st1_tag != TW_NaN )
 946         {
 947 #ifdef DENORM_OPERAND
 948           if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 949             return;
 950 #endif DENORM_OPERAND
 951 
 952           if ( st1_tag == TW_Infinity )
 953             {
 954               /* fprem(Valid,Infinity) is o.k. */
 955               setcc(0); return;
 956             }
 957         }
 958     }
 959   else if ( st0_tag == TW_Infinity )
 960     {
 961       if ( st1_tag != TW_NaN )
 962         {
 963           arith_invalid(st0_ptr); /* fprem(Infinity,?) is invalid */
 964           return;
 965         }
 966     }
 967 
 968   /* One of the registers must contain a NaN is we got here. */
 969 
 970 #ifdef PARANOID
 971   if ( (st0_tag != TW_NaN) && (st1_tag != TW_NaN) )
 972       EXCEPTION(EX_INTERNAL | 0x118);
 973 #endif PARANOID
 974 
 975   real_2op_NaN(st1_ptr, st0_ptr, st0_ptr);
 976 
 977 }
 978 
 979 
 980 /* ST(1) <- ST(1) * log ST;  pop ST */
 981 static void fyl2x(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 982 {
 983   char st0_tag = st0_ptr->tag;
 984   FPU_REG *st1_ptr = &st(1), exponent;
 985   char st1_tag = st1_ptr->tag;
 986   int e;
 987 
 988   clear_C1();
 989   if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
 990     {
 991       if ( st0_ptr->sign == SIGN_POS )
 992         {
 993 #ifdef DENORM_OPERAND
 994           if ( ((st0_ptr->exp <= EXP_UNDER) ||
 995                 (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
 996             return;
 997 #endif DENORM_OPERAND
 998 
 999           if ( (st0_ptr->sigh == 0x80000000) && (st0_ptr->sigl == 0) )
1000             {
1001               /* Special case. The result can be precise. */
1002               e = st0_ptr->exp - EXP_BIAS;
1003               if ( e > 0 )
1004                 {
1005                   exponent.sigh = e;
1006                   exponent.sign = SIGN_POS;
1007                 }
1008               else
1009                 {
1010                   exponent.sigh = -e;
1011                   exponent.sign = SIGN_NEG;
1012                 }
1013               exponent.sigl = 0;
1014               exponent.exp = EXP_BIAS + 31;
1015               exponent.tag = TW_Valid;
1016               normalize_nuo(&exponent);
1017               reg_mul(&exponent, st1_ptr, st1_ptr, FULL_PRECISION);
1018             }
1019           else
1020             {
1021               /* The usual case */
1022               poly_l2(st0_ptr, st1_ptr, st1_ptr);
1023               if ( st1_ptr->exp <= EXP_UNDER )
1024                 {
1025                   /* A denormal result has been produced.
1026                      Precision must have been lost, this is always
1027                      an underflow. */
1028                   arith_underflow(st1_ptr);
1029                 }
1030               else
1031                 set_precision_flag_up();  /* 80486 appears to always do this */
1032             }
1033           pop();
1034           return;
1035         }
1036       else
1037         {
1038           /* negative */
1039           if ( !arith_invalid(st1_ptr) )
1040             pop();
1041           return;
1042         }
1043     }
1044   else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
1045     {
1046       stack_underflow_pop(1);
1047       return;
1048     }
1049   else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
1050     {
1051       if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
1052         pop();
1053       return;
1054     }
1055   else if ( (st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) )
1056     {
1057       /* one of the args is zero, the other valid, or both zero */
1058       if ( st0_tag == TW_Zero )
1059         {
1060           if ( st1_tag == TW_Zero )
1061             {
1062               /* Both args zero is invalid */
1063               if ( !arith_invalid(st1_ptr) )
1064                 pop();
1065             }
1066 #ifdef PECULIAR_486
1067           /* This case is not specifically covered in the manual,
1068              but divide-by-zero would seem to be the best response.
1069              However, a real 80486 does it this way... */
1070           else if ( st0_ptr->tag == TW_Infinity )
1071             {
1072               reg_move(&CONST_INF, st1_ptr);
1073               pop();
1074             }
1075 #endif PECULIAR_486
1076           else
1077             {
1078               if ( !divide_by_zero(st1_ptr->sign^SIGN_NEG^SIGN_POS, st1_ptr) )
1079                 pop();
1080             }
1081           return;
1082         }
1083       else
1084         {
1085           /* st(1) contains zero, st(0) valid <> 0 */
1086           /* Zero is the valid answer */
1087           char sign = st1_ptr->sign;
1088 
1089           if ( st0_ptr->sign == SIGN_NEG )
1090             {
1091               /* log(negative) */
1092               if ( !arith_invalid(st1_ptr) )
1093                 pop();
1094               return;
1095             }
1096 
1097 #ifdef DENORM_OPERAND
1098           if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1099             return;
1100 #endif DENORM_OPERAND
1101 
1102           if ( st0_ptr->exp < EXP_BIAS ) sign ^= SIGN_NEG^SIGN_POS;
1103           pop(); st0_ptr = &st(0);
1104           reg_move(&CONST_Z, st0_ptr);
1105           st0_ptr->sign = sign;
1106           return;
1107         }
1108     }
1109   /* One or both arg must be an infinity */
1110   else if ( st0_tag == TW_Infinity )
1111     {
1112       if ( (st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) )
1113         {
1114           /* log(-infinity) or 0*log(infinity) */
1115           if ( !arith_invalid(st1_ptr) )
1116             pop();
1117           return;
1118         }
1119       else
1120         {
1121           char sign = st1_ptr->sign;
1122 
1123 #ifdef DENORM_OPERAND
1124           if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1125             return;
1126 #endif DENORM_OPERAND
1127 
1128           pop(); st0_ptr = &st(0);
1129           reg_move(&CONST_INF, st0_ptr);
1130           st0_ptr->sign = sign;
1131           return;
1132         }
1133     }
1134   /* st(1) must be infinity here */
1135   else if ( (st0_tag == TW_Valid) && (st0_ptr->sign == SIGN_POS) )
1136     {
1137       if ( st0_ptr->exp >= EXP_BIAS )
1138         {
1139           if ( (st0_ptr->exp == EXP_BIAS) &&
1140               (st0_ptr->sigh == 0x80000000) &&
1141               (st0_ptr->sigl == 0) )
1142             {
1143               /* st(0) holds 1.0 */
1144               /* infinity*log(1) */
1145               if ( !arith_invalid(st1_ptr) )
1146                 pop();
1147               return;
1148             }
1149           /* st(0) is positive and > 1.0 */
1150           pop();
1151         }
1152       else
1153         {
1154           /* st(0) is positive and < 1.0 */
1155 
1156 #ifdef DENORM_OPERAND
1157           if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1158             return;
1159 #endif DENORM_OPERAND
1160 
1161           st1_ptr->sign ^= SIGN_NEG;
1162           pop();
1163         }
1164       return;
1165     }
1166   else
1167     {
1168       /* st(0) must be zero or negative */
1169       if ( st0_ptr->tag == TW_Zero )
1170         {
1171           /* This should be invalid, but a real 80486 is happy with it. */
1172 #ifndef PECULIAR_486
1173           if ( !divide_by_zero(st1_ptr->sign, st1_ptr) )
1174 #endif PECULIAR_486
1175             {
1176               st1_ptr->sign ^= SIGN_NEG^SIGN_POS;
1177               pop();
1178             }
1179         }
1180       else
1181         {
1182           /* log(negative) */
1183           if ( !arith_invalid(st1_ptr) )
1184             pop();
1185         }
1186       return;
1187     }
1188 }
1189 
1190 
1191 static void fpatan(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1192 {
1193   char st0_tag = st0_ptr->tag;
1194   FPU_REG *st1_ptr = &st(1);
1195   char st1_tag = st1_ptr->tag;
1196 
1197   clear_C1();
1198   if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
1199     {
1200 #ifdef DENORM_OPERAND
1201       if ( ((st0_ptr->exp <= EXP_UNDER) ||
1202             (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
1203         return;
1204 #endif DENORM_OPERAND
1205 
1206       poly_atan(st0_ptr, st1_ptr, st1_ptr);
1207 
1208       if ( st1_ptr->exp <= EXP_UNDER )
1209         {
1210           /* A denormal result has been produced.
1211              Precision must have been lost.
1212              This is by definition an underflow. */
1213           arith_underflow(st1_ptr);
1214           pop();
1215           return;
1216         }
1217     }
1218   else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
1219     {
1220       stack_underflow_pop(1);
1221       return;
1222     }
1223   else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
1224     {
1225       if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
1226           pop();
1227       return;
1228     }
1229   else if ( (st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
1230     {
1231       char sign = st1_ptr->sign;
1232       if ( st0_tag == TW_Infinity )
1233         {
1234           if ( st1_tag == TW_Infinity )
1235             {
1236               if ( st0_ptr->sign == SIGN_POS )
1237                 { reg_move(&CONST_PI4, st1_ptr); }
1238               else
1239                 reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION);
1240             }
1241           else
1242             {
1243 #ifdef DENORM_OPERAND
1244               if ( st1_tag != TW_Zero )
1245                 {
1246                   if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1247                     return;
1248                 }
1249 #endif DENORM_OPERAND
1250 
1251               if ( st0_ptr->sign == SIGN_POS )
1252                 {
1253                   reg_move(&CONST_Z, st1_ptr);
1254                   st1_ptr->sign = sign;   /* An 80486 preserves the sign */
1255                   pop();
1256                   return;
1257                 }
1258               else
1259                 reg_move(&CONST_PI, st1_ptr);
1260             }
1261         }
1262       else
1263         {
1264           /* st(1) is infinity, st(0) not infinity */
1265 #ifdef DENORM_OPERAND
1266           if ( st0_tag != TW_Zero )
1267             {
1268               if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1269                 return;
1270             }
1271 #endif DENORM_OPERAND
1272 
1273           reg_move(&CONST_PI2, st1_ptr);
1274         }
1275       st1_ptr->sign = sign;
1276     }
1277   else if ( st1_tag == TW_Zero )
1278     {
1279       /* st(0) must be valid or zero */
1280       char sign = st1_ptr->sign;
1281 
1282 #ifdef DENORM_OPERAND
1283       if ( st0_tag != TW_Zero )
1284         {
1285           if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1286             return;
1287         }
1288 #endif DENORM_OPERAND
1289 
1290       if ( st0_ptr->sign == SIGN_POS )
1291         { /* An 80486 preserves the sign */ pop(); return; }
1292       else
1293         reg_move(&CONST_PI, st1_ptr);
1294       st1_ptr->sign = sign;
1295     }
1296   else if ( st0_tag == TW_Zero )
1297     {
1298       /* st(1) must be TW_Valid here */
1299       char sign = st1_ptr->sign;
1300 
1301 #ifdef DENORM_OPERAND
1302       if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1303         return;
1304 #endif DENORM_OPERAND
1305 
1306       reg_move(&CONST_PI2, st1_ptr);
1307       st1_ptr->sign = sign;
1308     }
1309 #ifdef PARANOID
1310   else
1311     EXCEPTION(EX_INTERNAL | 0x125);
1312 #endif PARANOID
1313 
1314   pop();
1315   set_precision_flag_up();  /* We do not really know if up or down */
1316 }
1317 
1318 
1319 static void fprem(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1320 {
1321   do_fprem(st0_ptr, RC_CHOP);
1322 }
1323 
1324 
1325 static void fprem1(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1326 {
1327   do_fprem(st0_ptr, RC_RND);
1328 }
1329 
1330 
1331 static void fyl2xp1(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1332 {
1333   char st0_tag = st0_ptr->tag, sign;
1334   FPU_REG *st1_ptr = &st(1);
1335   char st1_tag = st1_ptr->tag;
1336 
1337   clear_C1();
1338   if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
1339     {
1340 #ifdef DENORM_OPERAND
1341       if ( ((st0_ptr->exp <= EXP_UNDER) ||
1342             (st1_ptr->exp <= EXP_UNDER)) && denormal_operand() )
1343         return;
1344 #endif DENORM_OPERAND
1345 
1346       if ( poly_l2p1(st0_ptr, st1_ptr, st1_ptr) )
1347         {
1348 #ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
1349           st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
1350 #else
1351           if ( arith_invalid(st1_ptr) )  /* poly_l2p1() returned invalid */
1352             return;
1353 #endif PECULIAR_486
1354         }
1355       if ( st1_ptr->exp <= EXP_UNDER )
1356         {
1357           /* A denormal result has been produced.
1358              Precision must have been lost, this is always
1359              an underflow. */
1360           sign = st1_ptr->sign;
1361           arith_underflow(st1_ptr);
1362           st1_ptr->sign = sign;
1363         }
1364       else
1365         set_precision_flag_up();   /* 80486 appears to always do this */
1366       pop();
1367       return;
1368     }
1369   else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
1370     {
1371       stack_underflow_pop(1);
1372       return;
1373     }
1374   else if ( st0_tag == TW_Zero )
1375     {
1376       if ( st1_tag <= TW_Zero )
1377         {
1378 #ifdef DENORM_OPERAND
1379           if ( (st1_tag == TW_Valid) && (st1_ptr->exp <= EXP_UNDER) &&
1380               (denormal_operand()) )
1381             return;
1382 #endif DENORM_OPERAND
1383           
1384           st0_ptr->sign ^= st1_ptr->sign;
1385           reg_move(st0_ptr, st1_ptr);
1386         }
1387       else if ( st1_tag == TW_Infinity )
1388         {
1389           /* Infinity*log(1) */
1390           if ( !arith_invalid(st1_ptr) )
1391             pop();
1392           return;
1393         }
1394       else if ( st1_tag == TW_NaN )
1395         {
1396           if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
1397             pop();
1398           return;
1399         }
1400 #ifdef PARANOID
1401       else
1402         {
1403           EXCEPTION(EX_INTERNAL | 0x116);
1404           return;
1405         }
1406 #endif PARANOID
1407       pop(); return;
1408     }
1409   else if ( st0_tag == TW_Valid )
1410     {
1411       if ( st1_tag == TW_Zero )
1412         {
1413           if ( st0_ptr->sign == SIGN_NEG )
1414             {
1415               if ( st0_ptr->exp >= EXP_BIAS )
1416                 {
1417                   /* st(0) holds <= -1.0 */
1418 #ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
1419                   st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
1420 #else
1421                   if ( arith_invalid(st1_ptr) ) return;
1422 #endif PECULIAR_486
1423                   pop(); return;
1424                 }
1425 #ifdef DENORM_OPERAND
1426               if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1427                 return;
1428 #endif DENORM_OPERAND
1429               st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
1430               pop(); return;
1431             }
1432 #ifdef DENORM_OPERAND
1433           if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1434             return;
1435 #endif DENORM_OPERAND
1436           pop(); return;
1437         }
1438       if ( st1_tag == TW_Infinity )
1439         {
1440           if ( st0_ptr->sign == SIGN_NEG )
1441             {
1442               if ( (st0_ptr->exp >= EXP_BIAS) &&
1443                   !((st0_ptr->sigh == 0x80000000) &&
1444                     (st0_ptr->sigl == 0)) )
1445                 {
1446                   /* st(0) holds < -1.0 */
1447 #ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
1448                   st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
1449 #else
1450                   if ( arith_invalid(st1_ptr) ) return;
1451 #endif PECULIAR_486
1452                   pop(); return;
1453                 }
1454 #ifdef DENORM_OPERAND
1455               if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1456                 return;
1457 #endif DENORM_OPERAND
1458               st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
1459               pop(); return;
1460             }
1461 #ifdef DENORM_OPERAND
1462           if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1463             return;
1464 #endif DENORM_OPERAND
1465           pop(); return;
1466         }
1467       if ( st1_tag == TW_NaN )
1468         {
1469           if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
1470             pop();
1471           return;
1472         }
1473     }
1474   else if ( st0_tag == TW_NaN )
1475     {
1476       if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
1477         pop();
1478       return;
1479     }
1480   else if ( st0_tag == TW_Infinity )
1481     {
1482       if ( st1_tag == TW_NaN )
1483         {
1484           if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
1485             pop();
1486           return;
1487         }
1488       else if ( st0_ptr->sign == SIGN_NEG )
1489         {
1490           int exponent = st1_ptr->exp;
1491 #ifndef PECULIAR_486
1492           /* This should have higher priority than denormals, but... */
1493           if ( arith_invalid(st1_ptr) )  /* log(-infinity) */
1494             return;
1495 #endif PECULIAR_486
1496 #ifdef DENORM_OPERAND
1497           if ( st1_tag != TW_Zero )
1498             {
1499               if ( (exponent <= EXP_UNDER) && (denormal_operand()) )
1500                 return;
1501             }
1502 #endif DENORM_OPERAND
1503 #ifdef PECULIAR_486
1504           /* Denormal operands actually get higher priority */
1505           if ( arith_invalid(st1_ptr) )  /* log(-infinity) */
1506             return;
1507 #endif PECULIAR_486
1508           pop();
1509           return;
1510         }
1511       else if ( st1_tag == TW_Zero )
1512         {
1513           /* log(infinity) */
1514           if ( !arith_invalid(st1_ptr) )
1515             pop();
1516           return;
1517         }
1518         
1519       /* st(1) must be valid here. */
1520 
1521 #ifdef DENORM_OPERAND
1522       if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1523         return;
1524 #endif DENORM_OPERAND
1525 
1526       /* The Manual says that log(Infinity) is invalid, but a real
1527          80486 sensibly says that it is o.k. */
1528       { char sign = st1_ptr->sign;
1529         reg_move(&CONST_INF, st1_ptr);
1530         st1_ptr->sign = sign;
1531       }
1532       pop();
1533       return;
1534     }
1535 #ifdef PARANOID
1536   else
1537     {
1538       EXCEPTION(EX_INTERNAL | 0x117);
1539     }
1540 #endif PARANOID
1541 }
1542 
1543 
1544 static void fscale(FPU_REG *st0_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1545 {
1546   char st0_tag = st0_ptr->tag;
1547   FPU_REG *st1_ptr = &st(1);
1548   char st1_tag = st1_ptr->tag;
1549   int old_cw = control_word;
1550   char sign = st0_ptr->sign;
1551 
1552   clear_C1();
1553   if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
1554     {
1555       long scale;
1556       FPU_REG tmp;
1557 
1558 #ifdef DENORM_OPERAND
1559       if ( ((st0_ptr->exp <= EXP_UNDER) ||
1560             (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
1561         return;
1562 #endif DENORM_OPERAND
1563 
1564       if ( st1_ptr->exp > EXP_BIAS + 30 )
1565         {
1566           /* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */
1567           char sign;
1568 
1569           if ( st1_ptr->sign == SIGN_POS )
1570             {
1571               EXCEPTION(EX_Overflow);
1572               sign = st0_ptr->sign;
1573               reg_move(&CONST_INF, st0_ptr);
1574               st0_ptr->sign = sign;
1575             }
1576           else
1577             {
1578               EXCEPTION(EX_Underflow);
1579               sign = st0_ptr->sign;
1580               reg_move(&CONST_Z, st0_ptr);
1581               st0_ptr->sign = sign;
1582             }
1583           return;
1584         }
1585 
1586       control_word &= ~CW_RC;
1587       control_word |= RC_CHOP;
1588       reg_move(st1_ptr, &tmp);
1589       round_to_int(&tmp);               /* This can never overflow here */
1590       control_word = old_cw;
1591       scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl;
1592       scale += st0_ptr->exp;
1593       st0_ptr->exp = scale;
1594 
1595       /* Use round_reg() to properly detect under/overflow etc */
1596       round_reg(st0_ptr, 0, control_word);
1597 
1598       return;
1599     }
1600   else if ( st0_tag == TW_Valid )
1601     {
1602       if ( st1_tag == TW_Zero )
1603         {
1604 
1605 #ifdef DENORM_OPERAND
1606           if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1607             return;
1608 #endif DENORM_OPERAND
1609 
1610           return;
1611         }
1612       if ( st1_tag == TW_Infinity )
1613         {
1614 #ifdef DENORM_OPERAND
1615           if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1616             return;
1617 #endif DENORM_OPERAND
1618 
1619           if ( st1_ptr->sign == SIGN_POS )
1620             { reg_move(&CONST_INF, st0_ptr); }
1621           else
1622               reg_move(&CONST_Z, st0_ptr);
1623           st0_ptr->sign = sign;
1624           return;
1625         }
1626       if ( st1_tag == TW_NaN )
1627         { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
1628     }
1629   else if ( st0_tag == TW_Zero )
1630     {
1631       if ( st1_tag == TW_Valid )
1632         {
1633 
1634 #ifdef DENORM_OPERAND
1635           if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1636             return;
1637 #endif DENORM_OPERAND
1638 
1639           return;
1640         }
1641       else if ( st1_tag == TW_Zero ) { return; }
1642       else if ( st1_tag == TW_Infinity )
1643         {
1644           if ( st1_ptr->sign == SIGN_NEG )
1645             return;
1646           else
1647             {
1648               arith_invalid(st0_ptr); /* Zero scaled by +Infinity */
1649               return;
1650             }
1651         }
1652       else if ( st1_tag == TW_NaN )
1653         { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
1654     }
1655   else if ( st0_tag == TW_Infinity )
1656     {
1657       if ( st1_tag == TW_Valid )
1658         {
1659 
1660 #ifdef DENORM_OPERAND
1661           if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
1662             return;
1663 #endif DENORM_OPERAND
1664 
1665           return;
1666         }
1667       if ( ((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS))
1668           || (st1_tag == TW_Zero) )
1669         return;
1670       else if ( st1_tag == TW_Infinity )
1671         {
1672           arith_invalid(st0_ptr); /* Infinity scaled by -Infinity */
1673           return;
1674         }
1675       else if ( st1_tag == TW_NaN )
1676         { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
1677     }
1678   else if ( st0_tag == TW_NaN )
1679     {
1680       if ( st1_tag != TW_Empty )
1681         { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
1682     }
1683 
1684 #ifdef PARANOID
1685   if ( !((st0_tag == TW_Empty) || (st1_tag == TW_Empty)) )
1686     {
1687       EXCEPTION(EX_INTERNAL | 0x115);
1688       return;
1689     }
1690 #endif
1691 
1692   /* At least one of st(0), st(1) must be empty */
1693   stack_underflow();
1694 
1695 }
1696 
1697 
1698 /*---------------------------------------------------------------------------*/
1699 
1700 static FUNC_ST0 const trig_table_a[] = {
1701   f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
1702 };
1703 
1704 void trig_a(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1705 {
1706   (trig_table_a[FPU_rm])(&st(0));
1707 }
1708 
1709 
1710 static FUNC_ST0 const trig_table_b[] =
1711   {
1712     fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos
1713   };
1714 
1715 void trig_b(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1716 {
1717   (trig_table_b[FPU_rm])(&st(0));
1718 }

/* [previous][next][first][last][top][bottom][index][help] */