GNU Linux-libre 4.14.266-gnu1
[releases.git] / arch / x86 / math-emu / fpu_trig.c
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
21 static 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 */
34 static 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 */
152 static 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
180 static 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
192 static 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
233 static 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
276 static 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
355 static 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
436 static void fdecstp(void)
437 {
438         clear_C1();
439         top--;
440 }
441
442 static void fincstp(void)
443 {
444         clear_C1();
445         top++;
446 }
447
448 static 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
506 static 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
550 static int fsin(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
611 static int f_cos(FPU_REG *st0_ptr, u_char tag)
612 {
613         u_char st0_sign;
614
615         st0_sign = getsign(st0_ptr);
616
617         if (tag == TAG_Valid) {
618                 int q;
619
620                 if (exponent(st0_ptr) > -40) {
621                         if ((exponent(st0_ptr) < 0)
622                             || ((exponent(st0_ptr) == 0)
623                                 && (significand(st0_ptr) <=
624                                     0xc90fdaa22168c234LL))) {
625                                 poly_cos(st0_ptr);
626
627                                 /* We do not really know if up or down */
628                                 set_precision_flag_down();
629
630                                 return 0;
631                         } else if ((q = trig_arg(st0_ptr, FCOS)) != -1) {
632                                 poly_sine(st0_ptr);
633
634                                 if ((q + 1) & 2)
635                                         changesign(st0_ptr);
636
637                                 /* We do not really know if up or down */
638                                 set_precision_flag_down();
639
640                                 return 0;
641                         } else {
642                                 /* Operand is out of range */
643                                 return 1;
644                         }
645                 } else {
646                       denormal_arg:
647
648                         setcc(0);
649                         FPU_copy_to_reg0(&CONST_1, TAG_Valid);
650 #ifdef PECULIAR_486
651                         set_precision_flag_down();      /* 80486 appears to do this. */
652 #else
653                         set_precision_flag_up();        /* Must be up. */
654 #endif /* PECULIAR_486 */
655                         return 0;
656                 }
657         } else if (tag == TAG_Zero) {
658                 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
659                 setcc(0);
660                 return 0;
661         }
662
663         if (tag == TAG_Special)
664                 tag = FPU_Special(st0_ptr);
665
666         if (tag == TW_Denormal) {
667                 if (denormal_operand() < 0)
668                         return 1;
669
670                 goto denormal_arg;
671         } else if (tag == TW_Infinity) {
672                 /* The 80486 treats infinity as an invalid operand */
673                 arith_invalid(0);
674                 return 1;
675         } else {
676                 single_arg_error(st0_ptr, tag); /* requires st0_ptr == &st(0) */
677                 return 1;
678         }
679 }
680
681 static void fcos(FPU_REG *st0_ptr, u_char st0_tag)
682 {
683         f_cos(st0_ptr, st0_tag);
684 }
685
686 static void fsincos(FPU_REG *st0_ptr, u_char st0_tag)
687 {
688         FPU_REG *st_new_ptr;
689         FPU_REG arg;
690         u_char tag;
691
692         /* Stack underflow has higher priority */
693         if (st0_tag == TAG_Empty) {
694                 FPU_stack_underflow();  /* Puts a QNaN in st(0) */
695                 if (control_word & CW_Invalid) {
696                         st_new_ptr = &st(-1);
697                         push();
698                         FPU_stack_underflow();  /* Puts a QNaN in the new st(0) */
699                 }
700                 return;
701         }
702
703         if (STACK_OVERFLOW) {
704                 FPU_stack_overflow();
705                 return;
706         }
707
708         if (st0_tag == TAG_Special)
709                 tag = FPU_Special(st0_ptr);
710         else
711                 tag = st0_tag;
712
713         if (tag == TW_NaN) {
714                 single_arg_2_error(st0_ptr, TW_NaN);
715                 return;
716         } else if (tag == TW_Infinity) {
717                 /* The 80486 treats infinity as an invalid operand */
718                 if (arith_invalid(0) >= 0) {
719                         /* Masked response */
720                         push();
721                         arith_invalid(0);
722                 }
723                 return;
724         }
725
726         reg_copy(st0_ptr, &arg);
727         if (!fsin(st0_ptr, st0_tag)) {
728                 push();
729                 FPU_copy_to_reg0(&arg, st0_tag);
730                 f_cos(&st(0), st0_tag);
731         } else {
732                 /* An error, so restore st(0) */
733                 FPU_copy_to_reg0(&arg, st0_tag);
734         }
735 }
736
737 /*---------------------------------------------------------------------------*/
738 /* The following all require two arguments: st(0) and st(1) */
739
740 /* A lean, mean kernel for the fprem instructions. This relies upon
741    the division and rounding to an integer in do_fprem giving an
742    exact result. Because of this, rem_kernel() needs to deal only with
743    the least significant 64 bits, the more significant bits of the
744    result must be zero.
745  */
746 static void rem_kernel(unsigned long long st0, unsigned long long *y,
747                        unsigned long long st1, unsigned long long q, int n)
748 {
749         int dummy;
750         unsigned long long x;
751
752         x = st0 << n;
753
754         /* Do the required multiplication and subtraction in the one operation */
755
756         /* lsw x -= lsw st1 * lsw q */
757         asm volatile ("mull %4; subl %%eax,%0; sbbl %%edx,%1":"=m"
758                       (((unsigned *)&x)[0]), "=m"(((unsigned *)&x)[1]),
759                       "=a"(dummy)
760                       :"2"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[0])
761                       :"%dx");
762         /* msw x -= msw st1 * lsw q */
763         asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]),
764                       "=a"(dummy)
765                       :"1"(((unsigned *)&st1)[1]), "m"(((unsigned *)&q)[0])
766                       :"%dx");
767         /* msw x -= lsw st1 * msw q */
768         asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]),
769                       "=a"(dummy)
770                       :"1"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[1])
771                       :"%dx");
772
773         *y = x;
774 }
775
776 /* Remainder of st(0) / st(1) */
777 /* This routine produces exact results, i.e. there is never any
778    rounding or truncation, etc of the result. */
779 static void do_fprem(FPU_REG *st0_ptr, u_char st0_tag, int round)
780 {
781         FPU_REG *st1_ptr = &st(1);
782         u_char st1_tag = FPU_gettagi(1);
783
784         if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
785                 FPU_REG tmp, st0, st1;
786                 u_char st0_sign, st1_sign;
787                 u_char tmptag;
788                 int tag;
789                 int old_cw;
790                 int expdif;
791                 long long q;
792                 unsigned short saved_status;
793                 int cc;
794
795               fprem_valid:
796                 /* Convert registers for internal use. */
797                 st0_sign = FPU_to_exp16(st0_ptr, &st0);
798                 st1_sign = FPU_to_exp16(st1_ptr, &st1);
799                 expdif = exponent16(&st0) - exponent16(&st1);
800
801                 old_cw = control_word;
802                 cc = 0;
803
804                 /* We want the status following the denorm tests, but don't want
805                    the status changed by the arithmetic operations. */
806                 saved_status = partial_status;
807                 control_word &= ~CW_RC;
808                 control_word |= RC_CHOP;
809
810                 if (expdif < 64) {
811                         /* This should be the most common case */
812
813                         if (expdif > -2) {
814                                 u_char sign = st0_sign ^ st1_sign;
815                                 tag = FPU_u_div(&st0, &st1, &tmp,
816                                                 PR_64_BITS | RC_CHOP | 0x3f,
817                                                 sign);
818                                 setsign(&tmp, sign);
819
820                                 if (exponent(&tmp) >= 0) {
821                                         FPU_round_to_int(&tmp, tag);    /* Fortunately, this can't
822                                                                            overflow to 2^64 */
823                                         q = significand(&tmp);
824
825                                         rem_kernel(significand(&st0),
826                                                    &significand(&tmp),
827                                                    significand(&st1),
828                                                    q, expdif);
829
830                                         setexponent16(&tmp, exponent16(&st1));
831                                 } else {
832                                         reg_copy(&st0, &tmp);
833                                         q = 0;
834                                 }
835
836                                 if ((round == RC_RND)
837                                     && (tmp.sigh & 0xc0000000)) {
838                                         /* We may need to subtract st(1) once more,
839                                            to get a result <= 1/2 of st(1). */
840                                         unsigned long long x;
841                                         expdif =
842                                             exponent16(&st1) - exponent16(&tmp);
843                                         if (expdif <= 1) {
844                                                 if (expdif == 0)
845                                                         x = significand(&st1) -
846                                                             significand(&tmp);
847                                                 else    /* expdif is 1 */
848                                                         x = (significand(&st1)
849                                                              << 1) -
850                                                             significand(&tmp);
851                                                 if ((x < significand(&tmp)) ||
852                                                     /* or equi-distant (from 0 & st(1)) and q is odd */
853                                                     ((x == significand(&tmp))
854                                                      && (q & 1))) {
855                                                         st0_sign = !st0_sign;
856                                                         significand(&tmp) = x;
857                                                         q++;
858                                                 }
859                                         }
860                                 }
861
862                                 if (q & 4)
863                                         cc |= SW_C0;
864                                 if (q & 2)
865                                         cc |= SW_C3;
866                                 if (q & 1)
867                                         cc |= SW_C1;
868                         } else {
869                                 control_word = old_cw;
870                                 setcc(0);
871                                 return;
872                         }
873                 } else {
874                         /* There is a large exponent difference ( >= 64 ) */
875                         /* To make much sense, the code in this section should
876                            be done at high precision. */
877                         int exp_1, N;
878                         u_char sign;
879
880                         /* prevent overflow here */
881                         /* N is 'a number between 32 and 63' (p26-113) */
882                         reg_copy(&st0, &tmp);
883                         tmptag = st0_tag;
884                         N = (expdif & 0x0000001f) + 32; /* This choice gives results
885                                                            identical to an AMD 486 */
886                         setexponent16(&tmp, N);
887                         exp_1 = exponent16(&st1);
888                         setexponent16(&st1, 0);
889                         expdif -= N;
890
891                         sign = getsign(&tmp) ^ st1_sign;
892                         tag =
893                             FPU_u_div(&tmp, &st1, &tmp,
894                                       PR_64_BITS | RC_CHOP | 0x3f, sign);
895                         setsign(&tmp, sign);
896
897                         FPU_round_to_int(&tmp, tag);    /* Fortunately, this can't
898                                                            overflow to 2^64 */
899
900                         rem_kernel(significand(&st0),
901                                    &significand(&tmp),
902                                    significand(&st1),
903                                    significand(&tmp), exponent(&tmp)
904                             );
905                         setexponent16(&tmp, exp_1 + expdif);
906
907                         /* It is possible for the operation to be complete here.
908                            What does the IEEE standard say? The Intel 80486 manual
909                            implies that the operation will never be completed at this
910                            point, and the behaviour of a real 80486 confirms this.
911                          */
912                         if (!(tmp.sigh | tmp.sigl)) {
913                                 /* The result is zero */
914                                 control_word = old_cw;
915                                 partial_status = saved_status;
916                                 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
917                                 setsign(&st0, st0_sign);
918 #ifdef PECULIAR_486
919                                 setcc(SW_C2);
920 #else
921                                 setcc(0);
922 #endif /* PECULIAR_486 */
923                                 return;
924                         }
925                         cc = SW_C2;
926                 }
927
928                 control_word = old_cw;
929                 partial_status = saved_status;
930                 tag = FPU_normalize_nuo(&tmp);
931                 reg_copy(&tmp, st0_ptr);
932
933                 /* The only condition to be looked for is underflow,
934                    and it can occur here only if underflow is unmasked. */
935                 if ((exponent16(&tmp) <= EXP_UNDER) && (tag != TAG_Zero)
936                     && !(control_word & CW_Underflow)) {
937                         setcc(cc);
938                         tag = arith_underflow(st0_ptr);
939                         setsign(st0_ptr, st0_sign);
940                         FPU_settag0(tag);
941                         return;
942                 } else if ((exponent16(&tmp) > EXP_UNDER) || (tag == TAG_Zero)) {
943                         stdexp(st0_ptr);
944                         setsign(st0_ptr, st0_sign);
945                 } else {
946                         tag =
947                             FPU_round(st0_ptr, 0, 0, FULL_PRECISION, st0_sign);
948                 }
949                 FPU_settag0(tag);
950                 setcc(cc);
951
952                 return;
953         }
954
955         if (st0_tag == TAG_Special)
956                 st0_tag = FPU_Special(st0_ptr);
957         if (st1_tag == TAG_Special)
958                 st1_tag = FPU_Special(st1_ptr);
959
960         if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
961             || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
962             || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
963                 if (denormal_operand() < 0)
964                         return;
965                 goto fprem_valid;
966         } else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
967                 FPU_stack_underflow();
968                 return;
969         } else if (st0_tag == TAG_Zero) {
970                 if (st1_tag == TAG_Valid) {
971                         setcc(0);
972                         return;
973                 } else if (st1_tag == TW_Denormal) {
974                         if (denormal_operand() < 0)
975                                 return;
976                         setcc(0);
977                         return;
978                 } else if (st1_tag == TAG_Zero) {
979                         arith_invalid(0);
980                         return;
981                 } /* fprem(?,0) always invalid */
982                 else if (st1_tag == TW_Infinity) {
983                         setcc(0);
984                         return;
985                 }
986         } else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
987                 if (st1_tag == TAG_Zero) {
988                         arith_invalid(0);       /* fprem(Valid,Zero) is invalid */
989                         return;
990                 } else if (st1_tag != TW_NaN) {
991                         if (((st0_tag == TW_Denormal)
992                              || (st1_tag == TW_Denormal))
993                             && (denormal_operand() < 0))
994                                 return;
995
996                         if (st1_tag == TW_Infinity) {
997                                 /* fprem(Valid,Infinity) is o.k. */
998                                 setcc(0);
999                                 return;
1000                         }
1001                 }
1002         } else if (st0_tag == TW_Infinity) {
1003                 if (st1_tag != TW_NaN) {
1004                         arith_invalid(0);       /* fprem(Infinity,?) is invalid */
1005                         return;
1006                 }
1007         }
1008
1009         /* One of the registers must contain a NaN if we got here. */
1010
1011 #ifdef PARANOID
1012         if ((st0_tag != TW_NaN) && (st1_tag != TW_NaN))
1013                 EXCEPTION(EX_INTERNAL | 0x118);
1014 #endif /* PARANOID */
1015
1016         real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr);
1017
1018 }
1019
1020 /* ST(1) <- ST(1) * log ST;  pop ST */
1021 static void fyl2x(FPU_REG *st0_ptr, u_char st0_tag)
1022 {
1023         FPU_REG *st1_ptr = &st(1), exponent;
1024         u_char st1_tag = FPU_gettagi(1);
1025         u_char sign;
1026         int e, tag;
1027
1028         clear_C1();
1029
1030         if ((st0_tag == TAG_Valid) && (st1_tag == TAG_Valid)) {
1031               both_valid:
1032                 /* Both regs are Valid or Denormal */
1033                 if (signpositive(st0_ptr)) {
1034                         if (st0_tag == TW_Denormal)
1035                                 FPU_to_exp16(st0_ptr, st0_ptr);
1036                         else
1037                                 /* Convert st(0) for internal use. */
1038                                 setexponent16(st0_ptr, exponent(st0_ptr));
1039
1040                         if ((st0_ptr->sigh == 0x80000000)
1041                             && (st0_ptr->sigl == 0)) {
1042                                 /* Special case. The result can be precise. */
1043                                 u_char esign;
1044                                 e = exponent16(st0_ptr);
1045                                 if (e >= 0) {
1046                                         exponent.sigh = e;
1047                                         esign = SIGN_POS;
1048                                 } else {
1049                                         exponent.sigh = -e;
1050                                         esign = SIGN_NEG;
1051                                 }
1052                                 exponent.sigl = 0;
1053                                 setexponent16(&exponent, 31);
1054                                 tag = FPU_normalize_nuo(&exponent);
1055                                 stdexp(&exponent);
1056                                 setsign(&exponent, esign);
1057                                 tag =
1058                                     FPU_mul(&exponent, tag, 1, FULL_PRECISION);
1059                                 if (tag >= 0)
1060                                         FPU_settagi(1, tag);
1061                         } else {
1062                                 /* The usual case */
1063                                 sign = getsign(st1_ptr);
1064                                 if (st1_tag == TW_Denormal)
1065                                         FPU_to_exp16(st1_ptr, st1_ptr);
1066                                 else
1067                                         /* Convert st(1) for internal use. */
1068                                         setexponent16(st1_ptr,
1069                                                       exponent(st1_ptr));
1070                                 poly_l2(st0_ptr, st1_ptr, sign);
1071                         }
1072                 } else {
1073                         /* negative */
1074                         if (arith_invalid(1) < 0)
1075                                 return;
1076                 }
1077
1078                 FPU_pop();
1079
1080                 return;
1081         }
1082
1083         if (st0_tag == TAG_Special)
1084                 st0_tag = FPU_Special(st0_ptr);
1085         if (st1_tag == TAG_Special)
1086                 st1_tag = FPU_Special(st1_ptr);
1087
1088         if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
1089                 FPU_stack_underflow_pop(1);
1090                 return;
1091         } else if ((st0_tag <= TW_Denormal) && (st1_tag <= TW_Denormal)) {
1092                 if (st0_tag == TAG_Zero) {
1093                         if (st1_tag == TAG_Zero) {
1094                                 /* Both args zero is invalid */
1095                                 if (arith_invalid(1) < 0)
1096                                         return;
1097                         } else {
1098                                 u_char sign;
1099                                 sign = getsign(st1_ptr) ^ SIGN_NEG;
1100                                 if (FPU_divide_by_zero(1, sign) < 0)
1101                                         return;
1102
1103                                 setsign(st1_ptr, sign);
1104                         }
1105                 } else if (st1_tag == TAG_Zero) {
1106                         /* st(1) contains zero, st(0) valid <> 0 */
1107                         /* Zero is the valid answer */
1108                         sign = getsign(st1_ptr);
1109
1110                         if (signnegative(st0_ptr)) {
1111                                 /* log(negative) */
1112                                 if (arith_invalid(1) < 0)
1113                                         return;
1114                         } else if ((st0_tag == TW_Denormal)
1115                                    && (denormal_operand() < 0))
1116                                 return;
1117                         else {
1118                                 if (exponent(st0_ptr) < 0)
1119                                         sign ^= SIGN_NEG;
1120
1121                                 FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
1122                                 setsign(st1_ptr, sign);
1123                         }
1124                 } else {
1125                         /* One or both operands are denormals. */
1126                         if (denormal_operand() < 0)
1127                                 return;
1128                         goto both_valid;
1129                 }
1130         } else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
1131                 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1132                         return;
1133         }
1134         /* One or both arg must be an infinity */
1135         else if (st0_tag == TW_Infinity) {
1136                 if ((signnegative(st0_ptr)) || (st1_tag == TAG_Zero)) {
1137                         /* log(-infinity) or 0*log(infinity) */
1138                         if (arith_invalid(1) < 0)
1139                                 return;
1140                 } else {
1141                         u_char sign = getsign(st1_ptr);
1142
1143                         if ((st1_tag == TW_Denormal)
1144                             && (denormal_operand() < 0))
1145                                 return;
1146
1147                         FPU_copy_to_reg1(&CONST_INF, TAG_Special);
1148                         setsign(st1_ptr, sign);
1149                 }
1150         }
1151         /* st(1) must be infinity here */
1152         else if (((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal))
1153                  && (signpositive(st0_ptr))) {
1154                 if (exponent(st0_ptr) >= 0) {
1155                         if ((exponent(st0_ptr) == 0) &&
1156                             (st0_ptr->sigh == 0x80000000) &&
1157                             (st0_ptr->sigl == 0)) {
1158                                 /* st(0) holds 1.0 */
1159                                 /* infinity*log(1) */
1160                                 if (arith_invalid(1) < 0)
1161                                         return;
1162                         }
1163                         /* else st(0) is positive and > 1.0 */
1164                 } else {
1165                         /* st(0) is positive and < 1.0 */
1166
1167                         if ((st0_tag == TW_Denormal)
1168                             && (denormal_operand() < 0))
1169                                 return;
1170
1171                         changesign(st1_ptr);
1172                 }
1173         } else {
1174                 /* st(0) must be zero or negative */
1175                 if (st0_tag == TAG_Zero) {
1176                         /* This should be invalid, but a real 80486 is happy with it. */
1177
1178 #ifndef PECULIAR_486
1179                         sign = getsign(st1_ptr);
1180                         if (FPU_divide_by_zero(1, sign) < 0)
1181                                 return;
1182 #endif /* PECULIAR_486 */
1183
1184                         changesign(st1_ptr);
1185                 } else if (arith_invalid(1) < 0)        /* log(negative) */
1186                         return;
1187         }
1188
1189         FPU_pop();
1190 }
1191
1192 static void fpatan(FPU_REG *st0_ptr, u_char st0_tag)
1193 {
1194         FPU_REG *st1_ptr = &st(1);
1195         u_char st1_tag = FPU_gettagi(1);
1196         int tag;
1197
1198         clear_C1();
1199         if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1200               valid_atan:
1201
1202                 poly_atan(st0_ptr, st0_tag, st1_ptr, st1_tag);
1203
1204                 FPU_pop();
1205
1206                 return;
1207         }
1208
1209         if (st0_tag == TAG_Special)
1210                 st0_tag = FPU_Special(st0_ptr);
1211         if (st1_tag == TAG_Special)
1212                 st1_tag = FPU_Special(st1_ptr);
1213
1214         if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
1215             || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
1216             || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
1217                 if (denormal_operand() < 0)
1218                         return;
1219
1220                 goto valid_atan;
1221         } else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
1222                 FPU_stack_underflow_pop(1);
1223                 return;
1224         } else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
1225                 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) >= 0)
1226                         FPU_pop();
1227                 return;
1228         } else if ((st0_tag == TW_Infinity) || (st1_tag == TW_Infinity)) {
1229                 u_char sign = getsign(st1_ptr);
1230                 if (st0_tag == TW_Infinity) {
1231                         if (st1_tag == TW_Infinity) {
1232                                 if (signpositive(st0_ptr)) {
1233                                         FPU_copy_to_reg1(&CONST_PI4, TAG_Valid);
1234                                 } else {
1235                                         setpositive(st1_ptr);
1236                                         tag =
1237                                             FPU_u_add(&CONST_PI4, &CONST_PI2,
1238                                                       st1_ptr, FULL_PRECISION,
1239                                                       SIGN_POS,
1240                                                       exponent(&CONST_PI4),
1241                                                       exponent(&CONST_PI2));
1242                                         if (tag >= 0)
1243                                                 FPU_settagi(1, tag);
1244                                 }
1245                         } else {
1246                                 if ((st1_tag == TW_Denormal)
1247                                     && (denormal_operand() < 0))
1248                                         return;
1249
1250                                 if (signpositive(st0_ptr)) {
1251                                         FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
1252                                         setsign(st1_ptr, sign); /* An 80486 preserves the sign */
1253                                         FPU_pop();
1254                                         return;
1255                                 } else {
1256                                         FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
1257                                 }
1258                         }
1259                 } else {
1260                         /* st(1) is infinity, st(0) not infinity */
1261                         if ((st0_tag == TW_Denormal)
1262                             && (denormal_operand() < 0))
1263                                 return;
1264
1265                         FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
1266                 }
1267                 setsign(st1_ptr, sign);
1268         } else if (st1_tag == TAG_Zero) {
1269                 /* st(0) must be valid or zero */
1270                 u_char sign = getsign(st1_ptr);
1271
1272                 if ((st0_tag == TW_Denormal) && (denormal_operand() < 0))
1273                         return;
1274
1275                 if (signpositive(st0_ptr)) {
1276                         /* An 80486 preserves the sign */
1277                         FPU_pop();
1278                         return;
1279                 }
1280
1281                 FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
1282                 setsign(st1_ptr, sign);
1283         } else if (st0_tag == TAG_Zero) {
1284                 /* st(1) must be TAG_Valid here */
1285                 u_char sign = getsign(st1_ptr);
1286
1287                 if ((st1_tag == TW_Denormal) && (denormal_operand() < 0))
1288                         return;
1289
1290                 FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
1291                 setsign(st1_ptr, sign);
1292         }
1293 #ifdef PARANOID
1294         else
1295                 EXCEPTION(EX_INTERNAL | 0x125);
1296 #endif /* PARANOID */
1297
1298         FPU_pop();
1299         set_precision_flag_up();        /* We do not really know if up or down */
1300 }
1301
1302 static void fprem(FPU_REG *st0_ptr, u_char st0_tag)
1303 {
1304         do_fprem(st0_ptr, st0_tag, RC_CHOP);
1305 }
1306
1307 static void fprem1(FPU_REG *st0_ptr, u_char st0_tag)
1308 {
1309         do_fprem(st0_ptr, st0_tag, RC_RND);
1310 }
1311
1312 static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag)
1313 {
1314         u_char sign, sign1;
1315         FPU_REG *st1_ptr = &st(1), a, b;
1316         u_char st1_tag = FPU_gettagi(1);
1317
1318         clear_C1();
1319         if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1320               valid_yl2xp1:
1321
1322                 sign = getsign(st0_ptr);
1323                 sign1 = getsign(st1_ptr);
1324
1325                 FPU_to_exp16(st0_ptr, &a);
1326                 FPU_to_exp16(st1_ptr, &b);
1327
1328                 if (poly_l2p1(sign, sign1, &a, &b, st1_ptr))
1329                         return;
1330
1331                 FPU_pop();
1332                 return;
1333         }
1334
1335         if (st0_tag == TAG_Special)
1336                 st0_tag = FPU_Special(st0_ptr);
1337         if (st1_tag == TAG_Special)
1338                 st1_tag = FPU_Special(st1_ptr);
1339
1340         if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
1341             || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
1342             || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
1343                 if (denormal_operand() < 0)
1344                         return;
1345
1346                 goto valid_yl2xp1;
1347         } else if ((st0_tag == TAG_Empty) | (st1_tag == TAG_Empty)) {
1348                 FPU_stack_underflow_pop(1);
1349                 return;
1350         } else if (st0_tag == TAG_Zero) {
1351                 switch (st1_tag) {
1352                 case TW_Denormal:
1353                         if (denormal_operand() < 0)
1354                                 return;
1355
1356                 case TAG_Zero:
1357                 case TAG_Valid:
1358                         setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr));
1359                         FPU_copy_to_reg1(st0_ptr, st0_tag);
1360                         break;
1361
1362                 case TW_Infinity:
1363                         /* Infinity*log(1) */
1364                         if (arith_invalid(1) < 0)
1365                                 return;
1366                         break;
1367
1368                 case TW_NaN:
1369                         if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1370                                 return;
1371                         break;
1372
1373                 default:
1374 #ifdef PARANOID
1375                         EXCEPTION(EX_INTERNAL | 0x116);
1376                         return;
1377 #endif /* PARANOID */
1378                         break;
1379                 }
1380         } else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
1381                 switch (st1_tag) {
1382                 case TAG_Zero:
1383                         if (signnegative(st0_ptr)) {
1384                                 if (exponent(st0_ptr) >= 0) {
1385                                         /* st(0) holds <= -1.0 */
1386 #ifdef PECULIAR_486             /* Stupid 80486 doesn't worry about log(negative). */
1387                                         changesign(st1_ptr);
1388 #else
1389                                         if (arith_invalid(1) < 0)
1390                                                 return;
1391 #endif /* PECULIAR_486 */
1392                                 } else if ((st0_tag == TW_Denormal)
1393                                            && (denormal_operand() < 0))
1394                                         return;
1395                                 else
1396                                         changesign(st1_ptr);
1397                         } else if ((st0_tag == TW_Denormal)
1398                                    && (denormal_operand() < 0))
1399                                 return;
1400                         break;
1401
1402                 case TW_Infinity:
1403                         if (signnegative(st0_ptr)) {
1404                                 if ((exponent(st0_ptr) >= 0) &&
1405                                     !((st0_ptr->sigh == 0x80000000) &&
1406                                       (st0_ptr->sigl == 0))) {
1407                                         /* st(0) holds < -1.0 */
1408 #ifdef PECULIAR_486             /* Stupid 80486 doesn't worry about log(negative). */
1409                                         changesign(st1_ptr);
1410 #else
1411                                         if (arith_invalid(1) < 0)
1412                                                 return;
1413 #endif /* PECULIAR_486 */
1414                                 } else if ((st0_tag == TW_Denormal)
1415                                            && (denormal_operand() < 0))
1416                                         return;
1417                                 else
1418                                         changesign(st1_ptr);
1419                         } else if ((st0_tag == TW_Denormal)
1420                                    && (denormal_operand() < 0))
1421                                 return;
1422                         break;
1423
1424                 case TW_NaN:
1425                         if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1426                                 return;
1427                 }
1428
1429         } else if (st0_tag == TW_NaN) {
1430                 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1431                         return;
1432         } else if (st0_tag == TW_Infinity) {
1433                 if (st1_tag == TW_NaN) {
1434                         if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1435                                 return;
1436                 } else if (signnegative(st0_ptr)) {
1437 #ifndef PECULIAR_486
1438                         /* This should have higher priority than denormals, but... */
1439                         if (arith_invalid(1) < 0)       /* log(-infinity) */
1440                                 return;
1441 #endif /* PECULIAR_486 */
1442                         if ((st1_tag == TW_Denormal)
1443                             && (denormal_operand() < 0))
1444                                 return;
1445 #ifdef PECULIAR_486
1446                         /* Denormal operands actually get higher priority */
1447                         if (arith_invalid(1) < 0)       /* log(-infinity) */
1448                                 return;
1449 #endif /* PECULIAR_486 */
1450                 } else if (st1_tag == TAG_Zero) {
1451                         /* log(infinity) */
1452                         if (arith_invalid(1) < 0)
1453                                 return;
1454                 }
1455
1456                 /* st(1) must be valid here. */
1457
1458                 else if ((st1_tag == TW_Denormal) && (denormal_operand() < 0))
1459                         return;
1460
1461                 /* The Manual says that log(Infinity) is invalid, but a real
1462                    80486 sensibly says that it is o.k. */
1463                 else {
1464                         u_char sign = getsign(st1_ptr);
1465                         FPU_copy_to_reg1(&CONST_INF, TAG_Special);
1466                         setsign(st1_ptr, sign);
1467                 }
1468         }
1469 #ifdef PARANOID
1470         else {
1471                 EXCEPTION(EX_INTERNAL | 0x117);
1472                 return;
1473         }
1474 #endif /* PARANOID */
1475
1476         FPU_pop();
1477         return;
1478
1479 }
1480
1481 static void fscale(FPU_REG *st0_ptr, u_char st0_tag)
1482 {
1483         FPU_REG *st1_ptr = &st(1);
1484         u_char st1_tag = FPU_gettagi(1);
1485         int old_cw = control_word;
1486         u_char sign = getsign(st0_ptr);
1487
1488         clear_C1();
1489         if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1490                 long scale;
1491                 FPU_REG tmp;
1492
1493                 /* Convert register for internal use. */
1494                 setexponent16(st0_ptr, exponent(st0_ptr));
1495
1496               valid_scale:
1497
1498                 if (exponent(st1_ptr) > 30) {
1499                         /* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */
1500
1501                         if (signpositive(st1_ptr)) {
1502                                 EXCEPTION(EX_Overflow);
1503                                 FPU_copy_to_reg0(&CONST_INF, TAG_Special);
1504                         } else {
1505                                 EXCEPTION(EX_Underflow);
1506                                 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
1507                         }
1508                         setsign(st0_ptr, sign);
1509                         return;
1510                 }
1511
1512                 control_word &= ~CW_RC;
1513                 control_word |= RC_CHOP;
1514                 reg_copy(st1_ptr, &tmp);
1515                 FPU_round_to_int(&tmp, st1_tag);        /* This can never overflow here */
1516                 control_word = old_cw;
1517                 scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl;
1518                 scale += exponent16(st0_ptr);
1519
1520                 setexponent16(st0_ptr, scale);
1521
1522                 /* Use FPU_round() to properly detect under/overflow etc */
1523                 FPU_round(st0_ptr, 0, 0, control_word, sign);
1524
1525                 return;
1526         }
1527
1528         if (st0_tag == TAG_Special)
1529                 st0_tag = FPU_Special(st0_ptr);
1530         if (st1_tag == TAG_Special)
1531                 st1_tag = FPU_Special(st1_ptr);
1532
1533         if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
1534                 switch (st1_tag) {
1535                 case TAG_Valid:
1536                         /* st(0) must be a denormal */
1537                         if ((st0_tag == TW_Denormal)
1538                             && (denormal_operand() < 0))
1539                                 return;
1540
1541                         FPU_to_exp16(st0_ptr, st0_ptr); /* Will not be left on stack */
1542                         goto valid_scale;
1543
1544                 case TAG_Zero:
1545                         if (st0_tag == TW_Denormal)
1546                                 denormal_operand();
1547                         return;
1548
1549                 case TW_Denormal:
1550                         denormal_operand();
1551                         return;
1552
1553                 case TW_Infinity:
1554                         if ((st0_tag == TW_Denormal)
1555                             && (denormal_operand() < 0))
1556                                 return;
1557
1558                         if (signpositive(st1_ptr))
1559                                 FPU_copy_to_reg0(&CONST_INF, TAG_Special);
1560                         else
1561                                 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
1562                         setsign(st0_ptr, sign);
1563                         return;
1564
1565                 case TW_NaN:
1566                         real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1567                         return;
1568                 }
1569         } else if (st0_tag == TAG_Zero) {
1570                 switch (st1_tag) {
1571                 case TAG_Valid:
1572                 case TAG_Zero:
1573                         return;
1574
1575                 case TW_Denormal:
1576                         denormal_operand();
1577                         return;
1578
1579                 case TW_Infinity:
1580                         if (signpositive(st1_ptr))
1581                                 arith_invalid(0);       /* Zero scaled by +Infinity */
1582                         return;
1583
1584                 case TW_NaN:
1585                         real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1586                         return;
1587                 }
1588         } else if (st0_tag == TW_Infinity) {
1589                 switch (st1_tag) {
1590                 case TAG_Valid:
1591                 case TAG_Zero:
1592                         return;
1593
1594                 case TW_Denormal:
1595                         denormal_operand();
1596                         return;
1597
1598                 case TW_Infinity:
1599                         if (signnegative(st1_ptr))
1600                                 arith_invalid(0);       /* Infinity scaled by -Infinity */
1601                         return;
1602
1603                 case TW_NaN:
1604                         real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1605                         return;
1606                 }
1607         } else if (st0_tag == TW_NaN) {
1608                 if (st1_tag != TAG_Empty) {
1609                         real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1610                         return;
1611                 }
1612         }
1613 #ifdef PARANOID
1614         if (!((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty))) {
1615                 EXCEPTION(EX_INTERNAL | 0x115);
1616                 return;
1617         }
1618 #endif
1619
1620         /* At least one of st(0), st(1) must be empty */
1621         FPU_stack_underflow();
1622
1623 }
1624
1625 /*---------------------------------------------------------------------------*/
1626
1627 static FUNC_ST0 const trig_table_a[] = {
1628         f2xm1, fyl2x, fptan, fpatan,
1629         fxtract, fprem1, (FUNC_ST0) fdecstp, (FUNC_ST0) fincstp
1630 };
1631
1632 void FPU_triga(void)
1633 {
1634         (trig_table_a[FPU_rm]) (&st(0), FPU_gettag0());
1635 }
1636
1637 static FUNC_ST0 const trig_table_b[] = {
1638         fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, (FUNC_ST0) fsin, fcos
1639 };
1640
1641 void FPU_trigb(void)
1642 {
1643         (trig_table_b[FPU_rm]) (&st(0), FPU_gettag0());
1644 }