~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/math-emu/fpu_trig.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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(FPU_REG *st0_ptr, u_char st0_tag)
437 {
438         clear_C1();
439         top--;
440 }
441 
442 static void fincstp(FPU_REG *st0_ptr, u_char st0_tag)
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 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 
611 static void fsin(FPU_REG *st0_ptr, u_char tag)
612 {
613         f_sin(st0_ptr, tag);
614 }
615 
616 static 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 
686 static void fcos(FPU_REG *st0_ptr, u_char st0_tag)
687 {
688         f_cos(st0_ptr, st0_tag);
689 }
690 
691 static 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  */
751 static 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. */
784 static 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 */
1026 static 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 
1197 static 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 
1307 static void fprem(FPU_REG *st0_ptr, u_char st0_tag)
1308 {
1309         do_fprem(st0_ptr, st0_tag, RC_CHOP);
1310 }
1311 
1312 static void fprem1(FPU_REG *st0_ptr, u_char st0_tag)
1313 {
1314         do_fprem(st0_ptr, st0_tag, RC_RND);
1315 }
1316 
1317 static 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 
1486 static 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 
1632 static FUNC_ST0 const trig_table_a[] = {
1633         f2xm1, fyl2x, fptan, fpatan,
1634         fxtract, fprem1, fdecstp, fincstp,
1635 };
1636 
1637 void FPU_triga(void)
1638 {
1639         (trig_table_a[FPU_rm]) (&st(0), FPU_gettag0());
1640 }
1641 
1642 static FUNC_ST0 const trig_table_b[] = {
1643         fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos
1644 };
1645 
1646 void FPU_trigb(void)
1647 {
1648         (trig_table_b[FPU_rm]) (&st(0), FPU_gettag0());
1649 }
1650 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php