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