1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 /*
27 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <signal.h>
36 #include <siginfo.h>
37 #include <ucontext.h>
38 #include <thread.h>
39 #include <math.h>
40 #if defined(__SUNPRO_C)
41 #include <sunmath.h>
42 #endif
43 #include <fenv.h>
44 #include "fex_handler.h"
45 #include "fenv_inlines.h"
46
47 #if defined(__amd64)
48 #define test_sse_hw 1
49 #else
50 /*
51 * The following variable lives in libc on Solaris 10, where it
52 * gets set to a nonzero value at startup time on systems with SSE.
53 */
54 extern int _sse_hw;
55
56 #define test_sse_hw _sse_hw
57 #endif
58
59 static int accrued = 0;
60 static thread_key_t accrued_key;
61 static mutex_t accrued_key_lock = DEFAULTMUTEX;
62 int *
63 __fex_accrued()
64 {
65 int *p;
66
67 if (thr_main()) {
68 return (&accrued);
69 } else {
70 p = NULL;
71 mutex_lock(&accrued_key_lock);
72
73 if (thr_getspecific(accrued_key, (void **)&p) != 0 &&
74 thr_keycreate(&accrued_key, free) != 0) {
75 mutex_unlock(&accrued_key_lock);
76 return (NULL);
77 }
78
79 mutex_unlock(&accrued_key_lock);
80
81 if (!p) {
82 if ((p = (int *)malloc(sizeof (int))) == NULL)
83 return (NULL);
84
85 if (thr_setspecific(accrued_key, (void *)p) != 0) {
86 (void) free(p);
87 return (NULL);
88 }
89
90 *p = 0;
91 }
92
93 return (p);
94 }
95 }
96
97 void
98 __fenv_getfsr(unsigned long *fsr)
99 {
100 unsigned int cwsw, mxcsr;
101
102 __fenv_getcwsw(&cwsw);
103 /* clear reserved bits for no particularly good reason */
104 cwsw &= ~0xe0c00000u;
105
106 if (test_sse_hw) {
107 /*
108 * pick up exception flags (excluding denormal operand flag)
109 * from mxcsr
110 */
111 __fenv_getmxcsr(&mxcsr);
112 cwsw |= (mxcsr & 0x3d);
113 }
114
115 cwsw |= *__fex_accrued();
116 *fsr = cwsw ^ 0x003f0000u;
117 }
118
119 void
120 __fenv_setfsr(const unsigned long *fsr)
121 {
122 unsigned int cwsw, mxcsr;
123 int te;
124
125 /* save accrued exception flags corresponding to enabled exceptions */
126 cwsw = (unsigned int)*fsr;
127 te = __fenv_get_te(cwsw);
128 *__fex_accrued() = cwsw & te;
129 cwsw = (cwsw & ~te) ^ 0x003f0000;
130
131 if (test_sse_hw) {
132 /*
133 * propagate rounding direction, masks, and exception flags
134 * (excluding denormal operand mask and flag) to mxcsr
135 */
136 __fenv_getmxcsr(&mxcsr);
137 mxcsr = (mxcsr & ~0x7ebd) | ((cwsw >> 13) & 0x6000) | ((cwsw >>
138 9) & 0x1e80) | (cwsw & 0x3d);
139 __fenv_setmxcsr(&mxcsr);
140 }
141
142 __fenv_setcwsw(&cwsw);
143 }
144
145 /* Offsets into the fp environment save area (assumes 32-bit protected mode) */
146 #define CW 0 /* control word */
147 #define SW 1 /* status word */
148 #define TW 2 /* tag word */
149 #define IP 3 /* instruction pointer */
150 #define OP 4 /* opcode */
151 #define EA 5 /* operand address */
152
153 /* macro for accessing fp registers in the save area */
154 #if defined(__amd64)
155 #define fpreg(u, x) *(long double *)(10 * (x) + \
156 (char *)&(u)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.st)
157 #else
158 #define fpreg(u, x) *(long double *)(10 * (x) + \
159 (char *)&(u)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[7])
160 #endif
161
162 /*
163 * Fix sip->si_code; the Solaris x86 kernel can get it wrong
164 */
165 void
166 __fex_get_x86_exc(siginfo_t *sip, ucontext_t *uap)
167 {
168 unsigned sw, cw;
169
170 sw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status;
171 #if defined(__amd64)
172 cw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw;
173 #else
174 cw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[CW];
175 #endif
176
177 if ((sw & FE_INVALID) && !(cw & (1 << fp_trap_invalid)))
178 /* store 0 for stack fault, FPE_FLTINV for IEEE invalid op */
179 sip->si_code = ((sw & 0x40) ? 0 : FPE_FLTINV);
180 else if ((sw & FE_DIVBYZERO) && !(cw & (1 << fp_trap_division)))
181 sip->si_code = FPE_FLTDIV;
182 else if ((sw & FE_OVERFLOW) && !(cw & (1 << fp_trap_overflow)))
183 sip->si_code = FPE_FLTOVF;
184 else if ((sw & FE_UNDERFLOW) && !(cw & (1 << fp_trap_underflow)))
185 sip->si_code = FPE_FLTUND;
186 else if ((sw & FE_INEXACT) && !(cw & (1 << fp_trap_inexact)))
187 sip->si_code = FPE_FLTRES;
188 else
189 sip->si_code = 0;
190 }
191
192 static enum fp_class_type
193 my_fp_classf(float *x)
194 {
195 int i = *(int *)x & ~0x80000000;
196
197 if (i < 0x7f800000) {
198 if (i < 0x00800000)
199 return ((i == 0) ? fp_zero : fp_subnormal);
200
201 return (fp_normal);
202 } else if (i == 0x7f800000) {
203 return (fp_infinity);
204 } else if (i & 0x400000) {
205 return (fp_quiet);
206 } else {
207 return (fp_signaling);
208 }
209 }
210
211 static enum fp_class_type
212 my_fp_class(double *x)
213 {
214 int i = *(1 + (int *)x) & ~0x80000000;
215
216 if (i < 0x7ff00000) {
217 if (i < 0x00100000)
218 return (((i | *(int *)x) == 0) ? fp_zero :
219 fp_subnormal);
220
221 return (fp_normal);
222 } else if (i == 0x7ff00000 && *(int *)x == 0) {
223 return (fp_infinity);
224 } else if (i & 0x80000) {
225 return (fp_quiet);
226 } else {
227 return (fp_signaling);
228 }
229 }
230
231 static enum fp_class_type
232 my_fp_classl(long double *x)
233 {
234 int i = *(2 + (int *)x) & 0x7fff;
235
236 if (i < 0x7fff) {
237 if (i < 1) {
238 if (*(1 + (int *)x) < 0)
239 return (fp_normal); /* pseudo-denormal */
240
241 return (((*(1 + (int *)x) | *(int *)x) == 0) ? fp_zero :
242 fp_subnormal);
243 }
244
245 return ((*(1 + (int *)x) < 0) ? fp_normal :
246 (enum fp_class_type)-1); /* unsupported format */
247 } else if (*(1 + (int *)x) == 0x80000000 && *(int *)x == 0) {
248 return (fp_infinity);
249 } else if (*(1 + (unsigned *)x) >= 0xc0000000) {
250 return (fp_quiet);
251 } else if (*(1 + (int *)x) < 0) {
252 return (fp_signaling);
253 } else {
254 return ((enum fp_class_type)-1); /* unsupported format */
255 }
256 }
257
258 /*
259 * Determine which type of invalid operation exception occurred
260 */
261 enum fex_exception
262 __fex_get_invalid_type(siginfo_t *sip, ucontext_t *uap)
263 {
264 unsigned op;
265 unsigned long ea;
266 enum fp_class_type t1, t2;
267
268 /* get the opcode and data address */
269 #if defined(__amd64)
270 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
271 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp;
272 #else
273 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
274 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
275 #endif
276
277 /*
278 * if the instruction is fld, the source must be snan (it can't be
279 * an unsupported format, since fldt doesn't raise any exceptions)
280 */
281 switch (op & 0x7f8) {
282 case 0x100:
283 case 0x140:
284 case 0x180:
285 case 0x500:
286 case 0x540:
287 case 0x580:
288 return (fex_inv_snan);
289 }
290
291 /* otherwise st is one of the operands; see if it's snan */
292 t1 = my_fp_classl(&fpreg(uap, 0));
293
294 if (t1 == fp_signaling)
295 return (fex_inv_snan);
296 else if (t1 == (enum fp_class_type)-1)
297 return ((enum fex_exception)-1);
298
299 /* determine the class of the second operand if there is one */
300 t2 = fp_normal;
301
302 switch (op & 0x7e0) {
303 case 0x600:
304 case 0x620:
305 case 0x640:
306 case 0x660:
307 case 0x680:
308 case 0x6a0:
309
310 /* short memory operand */
311 if (!ea)
312 return ((enum fex_exception)-1);
313
314 if (*(short *)ea == 0)
315 t2 = fp_zero;
316
317 break;
318
319 case 0x200:
320 case 0x220:
321 case 0x240:
322 case 0x260:
323 case 0x280:
324 case 0x2a0:
325
326 /* int memory operand */
327 if (!ea)
328 return ((enum fex_exception)-1);
329
330 if (*(int *)ea == 0)
331 t2 = fp_zero;
332
333 break;
334
335 case 0x000:
336 case 0x020:
337 case 0x040:
338 case 0x060:
339 case 0x080:
340 case 0x0a0:
341
342 /* single precision memory operand */
343 if (!ea)
344 return ((enum fex_exception)-1);
345
346 t2 = my_fp_classf((float *)ea);
347 break;
348
349 case 0x400:
350 case 0x420:
351 case 0x440:
352 case 0x460:
353 case 0x480:
354 case 0x4a0:
355
356 /* double precision memory operand */
357 if (!ea)
358 return ((enum fex_exception)-1);
359
360 t2 = my_fp_class((double *)ea);
361 break;
362
363 case 0x0c0:
364 case 0x0e0:
365 case 0x3e0:
366 case 0x4c0:
367 case 0x4e0:
368 case 0x5e0:
369 case 0x6c0:
370 case 0x6e0:
371 case 0x7e0:
372
373 /* register operand determined by opcode */
374 switch (op & 0x7f8) {
375 case 0x3e0:
376 case 0x3f8:
377 case 0x5f0:
378 case 0x5f8:
379 case 0x7e0:
380 case 0x7f8:
381 /* weed out nonexistent opcodes */
382 break;
383
384 default:
385 t2 = my_fp_classl(&fpreg(uap, op & 7));
386 }
387
388 break;
389
390 case 0x1e0:
391 case 0x2e0:
392
393 /* special forms */
394 switch (op) {
395 case 0x1f1: /* fyl2x */
396 case 0x1f3: /* fpatan */
397 case 0x1f5: /* fprem1 */
398 case 0x1f8: /* fprem */
399 case 0x1f9: /* fyl2xp1 */
400 case 0x1fd: /* fscale */
401 case 0x2e9: /* fucompp */
402 t2 = my_fp_classl(&fpreg(uap, 1));
403 break;
404 }
405
406 break;
407 }
408
409 /* see if the second op is snan */
410 if (t2 == fp_signaling)
411 return (fex_inv_snan);
412 else if (t2 == (enum fp_class_type)-1)
413 return ((enum fex_exception)-1);
414
415 /* determine the type of operation */
416 switch (op & 0x7f8) {
417 case 0x000:
418 case 0x020:
419 case 0x028:
420 case 0x040:
421 case 0x060:
422 case 0x068:
423 case 0x080:
424 case 0x0a0:
425 case 0x0a8:
426 case 0x0c0:
427 case 0x0e0:
428 case 0x0e8:
429 case 0x400:
430 case 0x420:
431 case 0x428:
432 case 0x440:
433 case 0x460:
434 case 0x468:
435 case 0x480:
436 case 0x4a0:
437 case 0x4a8:
438 case 0x4c0:
439 case 0x4e0:
440 case 0x4e8:
441 case 0x6c0:
442 case 0x6e0:
443 case 0x6e8:
444
445 /* fadd, fsub, fsubr */
446 if (t1 == fp_infinity && t2 == fp_infinity)
447 return (fex_inv_isi);
448
449 break;
450
451 case 0x008:
452 case 0x048:
453 case 0x088:
454 case 0x0c8:
455 case 0x208:
456 case 0x248:
457 case 0x288:
458 case 0x408:
459 case 0x448:
460 case 0x488:
461 case 0x4c8:
462 case 0x608:
463 case 0x648:
464 case 0x688:
465 case 0x6c8:
466
467 /* fmul */
468 if ((t1 == fp_zero && t2 == fp_infinity) || (t2 == fp_zero &&
469 t1 == fp_infinity))
470 return (fex_inv_zmi);
471
472 break;
473
474 case 0x030:
475 case 0x038:
476 case 0x070:
477 case 0x078:
478 case 0x0b0:
479 case 0x0b8:
480 case 0x0f0:
481 case 0x0f8:
482 case 0x230:
483 case 0x238:
484 case 0x270:
485 case 0x278:
486 case 0x2b0:
487 case 0x2b8:
488 case 0x430:
489 case 0x438:
490 case 0x470:
491 case 0x478:
492 case 0x4b0:
493 case 0x4b8:
494 case 0x4f0:
495 case 0x4f8:
496 case 0x630:
497 case 0x638:
498 case 0x670:
499 case 0x678:
500 case 0x6b0:
501 case 0x6b8:
502 case 0x6f0:
503 case 0x6f8:
504
505 /* fdiv */
506 if (t1 == fp_zero && t2 == fp_zero)
507 return (fex_inv_zdz);
508 else if (t1 == fp_infinity && t2 == fp_infinity)
509 return (fex_inv_idi);
510
511 break;
512
513 case 0x1f0:
514 case 0x1f8:
515 /* fsqrt, other special ops */
516 return (fex_inv_sqrt);
517
518 case 0x010:
519 case 0x018:
520 case 0x050:
521 case 0x058:
522 case 0x090:
523 case 0x098:
524 case 0x0d0:
525 case 0x0d8:
526 case 0x210:
527 case 0x218:
528 case 0x250:
529 case 0x258:
530 case 0x290:
531 case 0x298:
532 case 0x2e8:
533 case 0x3f0:
534 case 0x410:
535 case 0x418:
536 case 0x450:
537 case 0x458:
538 case 0x490:
539 case 0x498:
540 case 0x4d0:
541 case 0x4d8:
542 case 0x5e0:
543 case 0x5e8:
544 case 0x610:
545 case 0x618:
546 case 0x650:
547 case 0x658:
548 case 0x690:
549 case 0x698:
550 case 0x6d0:
551 case 0x6d8:
552 case 0x7f0:
553
554 /* fcom */
555 if (t1 == fp_quiet || t2 == fp_quiet)
556 return (fex_inv_cmp);
557
558 break;
559
560 case 0x1e0:
561
562 /* ftst */
563 if (op == 0x1e4 && t1 == fp_quiet)
564 return (fex_inv_cmp);
565
566 break;
567
568 case 0x310:
569 case 0x318:
570 case 0x350:
571 case 0x358:
572 case 0x390:
573 case 0x398:
574 case 0x710:
575 case 0x718:
576 case 0x730:
577 case 0x738:
578 case 0x750:
579 case 0x758:
580 case 0x770:
581 case 0x778:
582 case 0x790:
583 case 0x798:
584 case 0x7b0:
585 case 0x7b8:
586 /* fist, fbst */
587 return (fex_inv_int);
588 }
589
590 return ((enum fex_exception)-1);
591 }
592
593 /* scale factors for exponent unwrapping */
594 /* 2^12288 */
595 static const long double
596 two12288 = 1.139165225263043370845938579315932009e+3699l;
597 /* 2^-12288 */
598 static const long double
599 twom12288 = 8.778357852076208839765066529179033145e-3700l;
600 /* (")*(1-2^-64) */
601 static const long double
602 twom12288mulp = 8.778357852076208839289190796475222545e-3700l;
603
604 /* inline templates */
605 extern long double f2xm1(long double);
606 extern long double fyl2x(long double, long double);
607 extern long double fptan(long double);
608 extern long double fpatan(long double, long double);
609 extern long double fxtract(long double);
610 extern long double fprem1(long double, long double);
611 extern long double fprem(long double, long double);
612 extern long double fyl2xp1(long double, long double);
613 extern long double fsqrt(long double);
614 extern long double fsincos(long double);
615 extern long double frndint(long double);
616 extern long double fscale(long double, long double);
617 extern long double fsin(long double);
618 extern long double fcos(long double);
619
620 /*
621 * Get the operands, generate the default untrapped result with
622 * exceptions, and set a code indicating the type of operation
623 */
624 void
625 __fex_get_op(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
626 {
627 fex_numeric_t t;
628 long double op2v, x;
629 unsigned int cwsw, ex, sw, op;
630 unsigned long ea;
631 volatile int c __unused;
632
633 /* get the exception type, status word, opcode, and data address */
634 ex = sip->si_code;
635 sw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status;
636 #if defined(__amd64)
637 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
638 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp;
639 #else
640 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
641 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
642 #endif
643
644 /*
645 * initialize res to the default untrapped result and ex to the
646 * corresponding flags (assume trapping is disabled and flags are
647 * clear)
648 */
649
650 /* single operand instructions */
651 info->op = fex_cnvt;
652 info->op2.type = fex_nodata;
653
654 switch (op & 0x7f8) {
655 /* load instructions */
656 case 0x100:
657 case 0x140:
658 case 0x180:
659
660 if (!ea) {
661 info->op = fex_other;
662 info->op1.type = info->op2.type = info->res.type =
663 fex_nodata;
664 info->flags = 0;
665 return;
666 }
667
668 info->op1.type = fex_float;
669 info->op1.val.f = *(float *)ea;
670 info->res.type = fex_ldouble;
671 info->res.val.q = (long double)info->op1.val.f;
672 goto done;
673
674 case 0x500:
675 case 0x540:
676 case 0x580:
677
678 if (!ea) {
679 info->op = fex_other;
680 info->op1.type = info->op2.type = info->res.type =
681 fex_nodata;
682 info->flags = 0;
683 return;
684 }
685
686 info->op1.type = fex_double;
687 info->op1.val.d = *(double *)ea;
688 info->res.type = fex_ldouble;
689 info->res.val.q = (long double)info->op1.val.d;
690 goto done;
691
692 /* store instructions */
693 case 0x110:
694 case 0x118:
695 case 0x150:
696 case 0x158:
697 case 0x190:
698 case 0x198:
699 info->res.type = fex_float;
700
701 if (ex == FPE_FLTRES && (op & 8) != 0) {
702 /* inexact, stack popped */
703 if (!ea) {
704 info->op = fex_other;
705 info->op1.type = info->op2.type =
706 info->res.type = fex_nodata;
707 info->flags = 0;
708 return;
709 }
710
711 info->op1.type = fex_nodata;
712 info->res.val.f = *(float *)ea;
713 info->flags = FE_INEXACT;
714 return;
715 }
716
717 info->op1.type = fex_ldouble;
718 info->op1.val.q = fpreg(uap, 0);
719 info->res.val.f = (float)info->op1.val.q;
720 goto done;
721
722 case 0x310:
723 case 0x318:
724 case 0x350:
725 case 0x358:
726 case 0x390:
727 case 0x398:
728 info->res.type = fex_int;
729
730 if (ex == FPE_FLTRES && (op & 8) != 0) {
731 /* inexact, stack popped */
732 if (!ea) {
733 info->op = fex_other;
734 info->op1.type = info->op2.type =
735 info->res.type = fex_nodata;
736 info->flags = 0;
737 return;
738 }
739
740 info->op1.type = fex_nodata;
741 info->res.val.i = *(int *)ea;
742 info->flags = FE_INEXACT;
743 return;
744 }
745
746 info->op1.type = fex_ldouble;
747 info->op1.val.q = fpreg(uap, 0);
748 info->res.val.i = (int)info->op1.val.q;
749 goto done;
750
751 case 0x510:
752 case 0x518:
753 case 0x550:
754 case 0x558:
755 case 0x590:
756 case 0x598:
757 info->res.type = fex_double;
758
759 if (ex == FPE_FLTRES && (op & 8) != 0) {
760 /* inexact, stack popped */
761 if (!ea) {
762 info->op = fex_other;
763 info->op1.type = info->op2.type =
764 info->res.type = fex_nodata;
765 info->flags = 0;
766 return;
767 }
768
769 info->op1.type = fex_nodata;
770 info->res.val.d = *(double *)ea;
771 info->flags = FE_INEXACT;
772 return;
773 }
774
775 info->op1.type = fex_ldouble;
776 info->op1.val.q = fpreg(uap, 0);
777 info->res.val.d = (double)info->op1.val.q;
778 goto done;
779
780 case 0x710:
781 case 0x718:
782 case 0x750:
783 case 0x758:
784 case 0x790:
785 case 0x798:
786 info->res.type = fex_int;
787
788 if (ex == FPE_FLTRES && (op & 8) != 0) {
789 /* inexact, stack popped */
790 if (!ea) {
791 info->op = fex_other;
792 info->op1.type = info->op2.type =
793 info->res.type = fex_nodata;
794 info->flags = 0;
795 return;
796 }
797
798 info->op1.type = fex_nodata;
799 info->res.val.i = *(short *)ea;
800 info->flags = FE_INEXACT;
801 return;
802 }
803
804 info->op1.type = fex_ldouble;
805 info->op1.val.q = fpreg(uap, 0);
806 info->res.val.i = (short)info->op1.val.q;
807 goto done;
808
809 case 0x730:
810 case 0x770:
811 case 0x7b0:
812 /* fbstp; don't bother */
813 info->op = fex_other;
814 info->op1.type = info->res.type = fex_nodata;
815 info->flags = 0;
816 return;
817
818 case 0x738:
819 case 0x778:
820 case 0x7b8:
821 info->res.type = fex_llong;
822
823 if (ex == FPE_FLTRES) {
824 /* inexact, stack popped */
825 if (!ea) {
826 info->op = fex_other;
827 info->op1.type = info->op2.type =
828 info->res.type = fex_nodata;
829 info->flags = 0;
830 return;
831 }
832
833 info->op1.type = fex_nodata;
834 info->res.val.l = *(long long *)ea;
835 info->flags = FE_INEXACT;
836 return;
837 }
838
839 info->op1.type = fex_ldouble;
840 info->op1.val.q = fpreg(uap, 0);
841 info->res.val.l = (long long)info->op1.val.q;
842 goto done;
843 }
844
845 /*
846 * all other ops (except compares) have destinations on the stack so
847 * overflow, underflow, and inexact will stomp their operands
848 */
849 if (ex == FPE_FLTOVF || ex == FPE_FLTUND || ex == FPE_FLTRES) {
850 /* find the trapped result */
851 info->op1.type = info->op2.type = fex_nodata;
852 info->res.type = fex_ldouble;
853
854 switch (op & 0x7f8) {
855 case 0x1f0:
856 /* fptan pushes 1.0 afterward, so result is in st(1) */
857 info->res.val.q = ((op == 0x1f2) ? fpreg(uap, 1) :
858 fpreg(uap, 0));
859 break;
860
861 case 0x4c0:
862 case 0x4c8:
863 case 0x4e0:
864 case 0x4e8:
865 case 0x4f0:
866 case 0x4f8:
867 info->res.val.q = fpreg(uap, op & 7);
868 break;
869
870 case 0x6c0:
871 case 0x6c8:
872 case 0x6e0:
873 case 0x6e8:
874 case 0x6f0:
875 case 0x6f8:
876 /* stack was popped afterward */
877 info->res.val.q = fpreg(uap, (op - 1) & 7);
878 break;
879
880 default:
881 info->res.val.q = fpreg(uap, 0);
882 }
883
884 /* reconstruct default untrapped result */
885 if (ex == FPE_FLTOVF) {
886 /* generate an overflow with the sign of the result */
887 x = two12288;
888 *(4 + (short *)&x) |= (*(4 +
889 (short *)&info->res.val.q) & 0x8000);
890 info->res.val.q = x * two12288;
891 info->flags = FE_OVERFLOW | FE_INEXACT;
892 __fenv_getcwsw(&cwsw);
893 cwsw &= ~FE_ALL_EXCEPT;
894 __fenv_setcwsw(&cwsw);
895 } else if (ex == FPE_FLTUND) {
896 /*
897 * undo the scaling; we can't distinguish a chopped
898 * result from an exact one without futzing around to
899 * trap all in- exact exceptions so as to keep the
900 * flag clear, so we just punt
901 */
902 if (sw & 0x200) /* result was rounded up */
903 info->res.val.q = (info->res.val.q *
904 twom12288) * twom12288mulp;
905 else
906 info->res.val.q = (info->res.val.q *
907 twom12288) * twom12288;
908
909 __fenv_getcwsw(&cwsw);
910 info->flags = (cwsw & FE_INEXACT) | FE_UNDERFLOW;
911 cwsw &= ~FE_ALL_EXCEPT;
912 __fenv_setcwsw(&cwsw);
913 } else {
914 info->flags = FE_INEXACT;
915 }
916
917 /* determine the operation code */
918 switch (op) {
919 case 0x1f0: /* f2xm1 */
920 case 0x1f1: /* fyl2x */
921 case 0x1f2: /* fptan */
922 case 0x1f3: /* fpatan */
923 case 0x1f5: /* fprem1 */
924 case 0x1f8: /* fprem */
925 case 0x1f9: /* fyl2xp1 */
926 case 0x1fb: /* fsincos */
927 case 0x1fc: /* frndint */
928 case 0x1fd: /* fscale */
929 case 0x1fe: /* fsin */
930 case 0x1ff: /* fcos */
931 info->op = fex_other;
932 return;
933
934 case 0x1fa: /* fsqrt */
935 info->op = fex_sqrt;
936 return;
937 }
938
939 info->op = fex_other;
940
941 switch (op & 0x7c0) {
942 case 0x000:
943 case 0x040:
944 case 0x080:
945 case 0x0c0:
946 case 0x200:
947 case 0x240:
948 case 0x280:
949 case 0x400:
950 case 0x440:
951 case 0x480:
952 case 0x4c0:
953 case 0x600:
954 case 0x640:
955 case 0x680:
956 case 0x6c0:
957
958 switch (op & 0x38) {
959 case 0x00:
960 info->op = fex_add;
961 break;
962
963 case 0x08:
964 info->op = fex_mul;
965 break;
966
967 case 0x20:
968 case 0x28:
969 info->op = fex_sub;
970 break;
971
972 case 0x30:
973 case 0x38:
974 info->op = fex_div;
975 break;
976 }
977 }
978
979 return;
980 }
981
982 /*
983 * for other exceptions, the operands are preserved, so we can just
984 * emulate the operation with traps disabled
985 */
986
987 /* one operand is always in st */
988 info->op1.type = fex_ldouble;
989 info->op1.val.q = fpreg(uap, 0);
990
991 /* oddball instructions */
992 info->op = fex_other;
993
994 switch (op) {
995 case 0x1e4: /* ftst */
996 info->op = fex_cmp;
997 info->op2.type = fex_ldouble;
998 info->op2.val.q = 0.0l;
999 info->res.type = fex_nodata;
1000 c = (info->op1.val.q < info->op2.val.q);
1001 goto done;
1002
1003 case 0x1f0: /* f2xm1 */
1004 info->res.type = fex_ldouble;
1005 info->res.val.q = f2xm1(info->op1.val.q);
1006 goto done;
1007
1008 case 0x1f1: /* fyl2x */
1009 info->op2.type = fex_ldouble;
1010 info->op2.val.q = fpreg(uap, 1);
1011 info->res.type = fex_ldouble;
1012 info->res.val.q = fyl2x(info->op1.val.q, info->op2.val.q);
1013 goto done;
1014
1015 case 0x1f2: /* fptan */
1016 info->res.type = fex_ldouble;
1017 info->res.val.q = fptan(info->op1.val.q);
1018 goto done;
1019
1020 case 0x1f3: /* fpatan */
1021 info->op2.type = fex_ldouble;
1022 info->op2.val.q = fpreg(uap, 1);
1023 info->res.type = fex_ldouble;
1024 info->res.val.q = fpatan(info->op1.val.q, info->op2.val.q);
1025 goto done;
1026
1027 case 0x1f4: /* fxtract */
1028 info->res.type = fex_ldouble;
1029 info->res.val.q = fxtract(info->op1.val.q);
1030 goto done;
1031
1032 case 0x1f5: /* fprem1 */
1033 info->op2.type = fex_ldouble;
1034 info->op2.val.q = fpreg(uap, 1);
1035 info->res.type = fex_ldouble;
1036 info->res.val.q = fprem1(info->op1.val.q, info->op2.val.q);
1037 goto done;
1038
1039 case 0x1f8: /* fprem */
1040 info->op2.type = fex_ldouble;
1041 info->op2.val.q = fpreg(uap, 1);
1042 info->res.type = fex_ldouble;
1043 info->res.val.q = fprem(info->op1.val.q, info->op2.val.q);
1044 goto done;
1045
1046 case 0x1f9: /* fyl2xp1 */
1047 info->op2.type = fex_ldouble;
1048 info->op2.val.q = fpreg(uap, 1);
1049 info->res.type = fex_ldouble;
1050 info->res.val.q = fyl2xp1(info->op1.val.q, info->op2.val.q);
1051 goto done;
1052
1053 case 0x1fa: /* fsqrt */
1054 info->op = fex_sqrt;
1055 info->res.type = fex_ldouble;
1056 info->res.val.q = fsqrt(info->op1.val.q);
1057 goto done;
1058
1059 case 0x1fb: /* fsincos */
1060 info->res.type = fex_ldouble;
1061 info->res.val.q = fsincos(info->op1.val.q);
1062 goto done;
1063
1064 case 0x1fc: /* frndint */
1065 info->res.type = fex_ldouble;
1066 info->res.val.q = frndint(info->op1.val.q);
1067 goto done;
1068
1069 case 0x1fd: /* fscale */
1070 info->op2.type = fex_ldouble;
1071 info->op2.val.q = fpreg(uap, 1);
1072 info->res.type = fex_ldouble;
1073 info->res.val.q = fscale(info->op1.val.q, info->op2.val.q);
1074 goto done;
1075
1076 case 0x1fe: /* fsin */
1077 info->res.type = fex_ldouble;
1078 info->res.val.q = fsin(info->op1.val.q);
1079 goto done;
1080
1081 case 0x1ff: /* fcos */
1082 info->res.type = fex_ldouble;
1083 info->res.val.q = fcos(info->op1.val.q);
1084 goto done;
1085
1086 case 0x2e9: /* fucompp */
1087 info->op = fex_cmp;
1088 info->op2.type = fex_ldouble;
1089 info->op2.val.q = fpreg(uap, 1);
1090 info->res.type = fex_nodata;
1091 c = (info->op1.val.q == info->op2.val.q);
1092 goto done;
1093 }
1094
1095 /* fucom[p], fcomi[p], fucomi[p] */
1096 switch (op & 0x7f8) {
1097 case 0x3e8:
1098 case 0x5e0:
1099 case 0x5e8:
1100 case 0x7e8: /* unordered compares */
1101 info->op = fex_cmp;
1102 info->op2.type = fex_ldouble;
1103 info->op2.val.q = fpreg(uap, op & 7);
1104 info->res.type = fex_nodata;
1105 c = (info->op1.val.q == info->op2.val.q);
1106 goto done;
1107
1108 case 0x3f0:
1109 case 0x7f0: /* ordered compares */
1110 info->op = fex_cmp;
1111 info->op2.type = fex_ldouble;
1112 info->op2.val.q = fpreg(uap, op & 7);
1113 info->res.type = fex_nodata;
1114 c = (info->op1.val.q < info->op2.val.q);
1115 goto done;
1116 }
1117
1118 /*
1119 * all other instructions come in groups of the form
1120 * fadd, fmul, fcom, fcomp, fsub, fsubr, fdiv, fdivr
1121 */
1122
1123 /* get the second operand */
1124 switch (op & 0x7c0) {
1125 case 0x000:
1126 case 0x040:
1127 case 0x080:
1128
1129 if (!ea) {
1130 info->op = fex_other;
1131 info->op1.type = info->op2.type = info->res.type =
1132 fex_nodata;
1133 info->flags = 0;
1134 return;
1135 }
1136
1137 info->op2.type = fex_float;
1138 info->op2.val.f = *(float *)ea;
1139 op2v = (long double)info->op2.val.f;
1140 break;
1141
1142 case 0x0c0:
1143 info->op2.type = fex_ldouble;
1144 op2v = info->op2.val.q = fpreg(uap, op & 7);
1145 break;
1146
1147 case 0x200:
1148 case 0x240:
1149 case 0x280:
1150
1151 if (!ea) {
1152 info->op = fex_other;
1153 info->op1.type = info->op2.type = info->res.type =
1154 fex_nodata;
1155 info->flags = 0;
1156 return;
1157 }
1158
1159 info->op2.type = fex_int;
1160 info->op2.val.i = *(int *)ea;
1161 op2v = (long double)info->op2.val.i;
1162 break;
1163
1164 case 0x400:
1165 case 0x440:
1166 case 0x480:
1167
1168 if (!ea) {
1169 info->op = fex_other;
1170 info->op1.type = info->op2.type = info->res.type =
1171 fex_nodata;
1172 info->flags = 0;
1173 return;
1174 }
1175
1176 info->op2.type = fex_double;
1177 info->op2.val.d = *(double *)ea;
1178 op2v = (long double)info->op2.val.d;
1179 break;
1180
1181 case 0x4c0:
1182 case 0x6c0:
1183 info->op2.type = fex_ldouble;
1184 info->op2.val.q = fpreg(uap, op & 7);
1185 t = info->op1;
1186 info->op1 = info->op2;
1187 info->op2 = t;
1188 op2v = info->op2.val.q;
1189 break;
1190
1191 case 0x600:
1192 case 0x640:
1193 case 0x680:
1194
1195 if (!ea) {
1196 info->op = fex_other;
1197 info->op1.type = info->op2.type = info->res.type =
1198 fex_nodata;
1199 info->flags = 0;
1200 return;
1201 }
1202
1203 info->op2.type = fex_int;
1204 info->op2.val.i = *(short *)ea;
1205 op2v = (long double)info->op2.val.i;
1206 break;
1207
1208 default:
1209 info->op = fex_other;
1210 info->op1.type = info->op2.type = info->res.type = fex_nodata;
1211 info->flags = 0;
1212 return;
1213 }
1214
1215 /* distinguish different operations in the group */
1216 info->res.type = fex_ldouble;
1217
1218 switch (op & 0x38) {
1219 case 0x00:
1220 info->op = fex_add;
1221 info->res.val.q = info->op1.val.q + op2v;
1222 break;
1223
1224 case 0x08:
1225 info->op = fex_mul;
1226 info->res.val.q = info->op1.val.q * op2v;
1227 break;
1228
1229 case 0x10:
1230 case 0x18:
1231 info->op = fex_cmp;
1232 info->res.type = fex_nodata;
1233 c = (info->op1.val.q < op2v);
1234 break;
1235
1236 case 0x20:
1237 info->op = fex_sub;
1238 info->res.val.q = info->op1.val.q - op2v;
1239 break;
1240
1241 case 0x28:
1242 info->op = fex_sub;
1243 info->res.val.q = op2v - info->op1.val.q;
1244 t = info->op1;
1245 info->op1 = info->op2;
1246 info->op2 = t;
1247 break;
1248
1249 case 0x30:
1250 info->op = fex_div;
1251 info->res.val.q = info->op1.val.q / op2v;
1252 break;
1253
1254 case 0x38:
1255 info->op = fex_div;
1256 info->res.val.q = op2v / info->op1.val.q;
1257 t = info->op1;
1258 info->op1 = info->op2;
1259 info->op2 = t;
1260 break;
1261
1262 default:
1263 info->op = fex_other;
1264 info->op1.type = info->op2.type = info->res.type = fex_nodata;
1265 info->flags = 0;
1266 return;
1267 }
1268
1269 done:
1270 __fenv_getcwsw(&cwsw);
1271 info->flags = cwsw & FE_ALL_EXCEPT;
1272 cwsw &= ~FE_ALL_EXCEPT;
1273 __fenv_setcwsw(&cwsw);
1274 }
1275
1276 /* pop the saved stack */
1277 static void
1278 pop(ucontext_t *uap)
1279 {
1280 unsigned top;
1281
1282 fpreg(uap, 0) = fpreg(uap, 1);
1283 fpreg(uap, 1) = fpreg(uap, 2);
1284 fpreg(uap, 2) = fpreg(uap, 3);
1285 fpreg(uap, 3) = fpreg(uap, 4);
1286 fpreg(uap, 4) = fpreg(uap, 5);
1287 fpreg(uap, 5) = fpreg(uap, 6);
1288 fpreg(uap, 6) = fpreg(uap, 7);
1289 #if defined(__amd64)
1290 top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw >> 10) & 0xe;
1291 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fctw |= (3 << top);
1292 top = (top + 2) & 0xe;
1293 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw =
1294 (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw & ~0x3800) |
1295 (top << 10);
1296 #else
1297 top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] >>
1298 10) & 0xe;
1299 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[TW] |= (3 << top);
1300 top = (top + 2) & 0xe;
1301 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] =
1302 (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] &
1303 ~0x3800) | (top << 10);
1304 #endif
1305 }
1306
1307 /* push x onto the saved stack */
1308 static void
1309 push(long double x, ucontext_t *uap)
1310 {
1311 unsigned top;
1312
1313 fpreg(uap, 7) = fpreg(uap, 6);
1314 fpreg(uap, 6) = fpreg(uap, 5);
1315 fpreg(uap, 5) = fpreg(uap, 4);
1316 fpreg(uap, 4) = fpreg(uap, 3);
1317 fpreg(uap, 3) = fpreg(uap, 2);
1318 fpreg(uap, 2) = fpreg(uap, 1);
1319 fpreg(uap, 1) = fpreg(uap, 0);
1320 fpreg(uap, 0) = x;
1321 #if defined(__amd64)
1322 top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw >> 10) & 0xe;
1323 top = (top - 2) & 0xe;
1324 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fctw &= ~(3 << top);
1325 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw =
1326 (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw & ~0x3800) |
1327 (top << 10);
1328 #else
1329 top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] >>
1330 10) & 0xe;
1331 top = (top - 2) & 0xe;
1332 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[TW] &= ~(3 <<
1333 top);
1334 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] =
1335 (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] &
1336 ~0x3800) | (top << 10);
1337 #endif
1338 }
1339
1340 /* scale factors for exponent wrapping */
1341 static const float fun = 7.922816251e+28f, /* 2^96 */
1342 fov = 1.262177448e-29f; /* 2^-96 */
1343 static const double dun = 1.552518092300708935e+231, /* 2^768 */
1344 dov = 6.441148769597133308e-232; /* 2^-768 */
1345
1346 /*
1347 * Store the specified result; if no result is given but the exception
1348 * is underflow or overflow, use the default trapped result
1349 */
1350 void
1351 __fex_st_result(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
1352 {
1353 fex_numeric_t r;
1354 unsigned long ex, op, ea, stack;
1355
1356 /* get the exception type, opcode, and data address */
1357 ex = sip->si_code;
1358 #if defined(__amd64)
1359 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
1360 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp; /* ??? */
1361 #else
1362 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
1363 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
1364 #endif
1365
1366 /*
1367 * if the instruction is a compare, set the condition codes
1368 * to unordered and update the stack
1369 */
1370 switch (op & 0x7f8) {
1371 case 0x010:
1372 case 0x050:
1373 case 0x090:
1374 case 0x0d0:
1375 case 0x210:
1376 case 0x250:
1377 case 0x290:
1378 case 0x410:
1379 case 0x450:
1380 case 0x490:
1381 case 0x4d0:
1382 case 0x5e0:
1383 case 0x610:
1384 case 0x650:
1385 case 0x690:
1386 /* f[u]com */
1387 #if defined(__amd64)
1388 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
1389 #else
1390 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |=
1391 0x4500;
1392 #endif
1393 return;
1394
1395 case 0x018:
1396 case 0x058:
1397 case 0x098:
1398 case 0x0d8:
1399 case 0x218:
1400 case 0x258:
1401 case 0x298:
1402 case 0x418:
1403 case 0x458:
1404 case 0x498:
1405 case 0x4d8:
1406 case 0x5e8:
1407 case 0x618:
1408 case 0x658:
1409 case 0x698:
1410 case 0x6d0:
1411 /* f[u]comp */
1412 #if defined(__amd64)
1413 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
1414 #else
1415 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |=
1416 0x4500;
1417 #endif
1418 pop(uap);
1419 return;
1420
1421 case 0x2e8:
1422 case 0x6d8:
1423 /* f[u]compp */
1424 #if defined(__amd64)
1425 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
1426 #else
1427 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |=
1428 0x4500;
1429 #endif
1430 pop(uap);
1431 pop(uap);
1432 return;
1433
1434 case 0x1e0:
1435
1436 if (op == 0x1e4) { /* ftst */
1437 #if defined(__amd64)
1438 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |=
1439 0x4500;
1440 #else
1441 uap->uc_mcontext.fpregs.fp_reg_set.
1442 fpchip_state.state[SW] |= 0x4500;
1443 #endif
1444 return;
1445 }
1446
1447 break;
1448
1449 case 0x3e8:
1450 case 0x3f0:
1451 /* f[u]comi */
1452 #if defined(__amd64)
1453 uap->uc_mcontext.gregs[REG_PS] |= 0x45;
1454 #else
1455 uap->uc_mcontext.gregs[EFL] |= 0x45;
1456 #endif
1457 return;
1458
1459 case 0x7e8:
1460 case 0x7f0:
1461 /* f[u]comip */
1462 #if defined(__amd64)
1463 uap->uc_mcontext.gregs[REG_PS] |= 0x45;
1464 #else
1465 uap->uc_mcontext.gregs[EFL] |= 0x45;
1466 #endif
1467 pop(uap);
1468 return;
1469 }
1470
1471 /*
1472 * if there is no result available and the exception is overflow
1473 * or underflow, use the wrapped result
1474 */
1475 r = info->res;
1476
1477 if (r.type == fex_nodata) {
1478 if (ex == FPE_FLTOVF || ex == FPE_FLTUND) {
1479 /* for store instructions, do the scaling and store */
1480 switch (op & 0x7f8) {
1481 case 0x110:
1482 case 0x118:
1483 case 0x150:
1484 case 0x158:
1485 case 0x190:
1486 case 0x198:
1487
1488 if (!ea)
1489 return;
1490
1491 if (ex == FPE_FLTOVF)
1492 *(float *)ea = (fpreg(uap, 0) * fov) *
1493 fov;
1494 else
1495 *(float *)ea = (fpreg(uap, 0) * fun) *
1496 fun;
1497
1498 if ((op & 8) != 0)
1499 pop(uap);
1500
1501 break;
1502
1503 case 0x510:
1504 case 0x518:
1505 case 0x550:
1506 case 0x558:
1507 case 0x590:
1508 case 0x598:
1509
1510 if (!ea)
1511 return;
1512
1513 if (ex == FPE_FLTOVF)
1514 *(double *)ea = (fpreg(uap, 0) * dov) *
1515 dov;
1516 else
1517 *(double *)ea = (fpreg(uap, 0) * dun) *
1518 dun;
1519
1520 if ((op & 8) != 0)
1521 pop(uap);
1522
1523 break;
1524 }
1525 }
1526
1527 #ifdef DEBUG
1528 else if (ex != FPE_FLTRES) {
1529 printf("No result supplied, stack may be hosed\n");
1530 }
1531 #endif
1532 return;
1533 }
1534
1535 /*
1536 * otherwise convert the supplied result to the correct type, put it
1537 * in the destination, and update the stack as need be
1538 */
1539
1540 /* store instructions */
1541 switch (op & 0x7f8) {
1542 case 0x110:
1543 case 0x118:
1544 case 0x150:
1545 case 0x158:
1546 case 0x190:
1547 case 0x198:
1548
1549 if (!ea)
1550 return;
1551
1552 switch (r.type) {
1553 case fex_int:
1554 *(float *)ea = (float)r.val.i;
1555 break;
1556
1557 case fex_llong:
1558 *(float *)ea = (float)r.val.l;
1559 break;
1560
1561 case fex_float:
1562 *(float *)ea = r.val.f;
1563 break;
1564
1565 case fex_double:
1566 *(float *)ea = (float)r.val.d;
1567 break;
1568
1569 case fex_ldouble:
1570 *(float *)ea = (float)r.val.q;
1571 break;
1572
1573 default:
1574 break;
1575 }
1576
1577 if (ex != FPE_FLTRES && (op & 8) != 0)
1578 pop(uap);
1579
1580 return;
1581
1582 case 0x310:
1583 case 0x318:
1584 case 0x350:
1585 case 0x358:
1586 case 0x390:
1587 case 0x398:
1588
1589 if (!ea)
1590 return;
1591
1592 switch (r.type) {
1593 case fex_int:
1594 *(int *)ea = r.val.i;
1595 break;
1596
1597 case fex_llong:
1598 *(int *)ea = (int)r.val.l;
1599 break;
1600
1601 case fex_float:
1602 *(int *)ea = (int)r.val.f;
1603 break;
1604
1605 case fex_double:
1606 *(int *)ea = (int)r.val.d;
1607 break;
1608
1609 case fex_ldouble:
1610 *(int *)ea = (int)r.val.q;
1611 break;
1612
1613 default:
1614 break;
1615 }
1616
1617 if (ex != FPE_FLTRES && (op & 8) != 0)
1618 pop(uap);
1619
1620 return;
1621
1622 case 0x510:
1623 case 0x518:
1624 case 0x550:
1625 case 0x558:
1626 case 0x590:
1627 case 0x598:
1628
1629 if (!ea)
1630 return;
1631
1632 switch (r.type) {
1633 case fex_int:
1634 *(double *)ea = (double)r.val.i;
1635 break;
1636
1637 case fex_llong:
1638 *(double *)ea = (double)r.val.l;
1639 break;
1640
1641 case fex_float:
1642 *(double *)ea = (double)r.val.f;
1643 break;
1644
1645 case fex_double:
1646 *(double *)ea = r.val.d;
1647 break;
1648
1649 case fex_ldouble:
1650 *(double *)ea = (double)r.val.q;
1651 break;
1652
1653 default:
1654 break;
1655 }
1656
1657 if (ex != FPE_FLTRES && (op & 8) != 0)
1658 pop(uap);
1659
1660 return;
1661
1662 case 0x710:
1663 case 0x718:
1664 case 0x750:
1665 case 0x758:
1666 case 0x790:
1667 case 0x798:
1668
1669 if (!ea)
1670 return;
1671
1672 switch (r.type) {
1673 case fex_int:
1674 *(short *)ea = (short)r.val.i;
1675 break;
1676
1677 case fex_llong:
1678 *(short *)ea = (short)r.val.l;
1679 break;
1680
1681 case fex_float:
1682 *(short *)ea = (short)r.val.f;
1683 break;
1684
1685 case fex_double:
1686 *(short *)ea = (short)r.val.d;
1687 break;
1688
1689 case fex_ldouble:
1690 *(short *)ea = (short)r.val.q;
1691 break;
1692
1693 default:
1694 break;
1695 }
1696
1697 if (ex != FPE_FLTRES && (op & 8) != 0)
1698 pop(uap);
1699
1700 return;
1701
1702 case 0x730:
1703 case 0x770:
1704 case 0x7b0:
1705
1706 /* fbstp; don't bother */
1707 if (ea && ex != FPE_FLTRES)
1708 pop(uap);
1709
1710 return;
1711
1712 case 0x738:
1713 case 0x778:
1714 case 0x7b8:
1715
1716 if (!ea)
1717 return;
1718
1719 switch (r.type) {
1720 case fex_int:
1721 *(long long *)ea = (long long)r.val.i;
1722 break;
1723
1724 case fex_llong:
1725 *(long long *)ea = r.val.l;
1726 break;
1727
1728 case fex_float:
1729 *(long long *)ea = (long long)r.val.f;
1730 break;
1731
1732 case fex_double:
1733 *(long long *)ea = (long long)r.val.d;
1734 break;
1735
1736 case fex_ldouble:
1737 *(long long *)ea = (long long)r.val.q;
1738 break;
1739
1740 default:
1741 break;
1742 }
1743
1744 if (ex != FPE_FLTRES)
1745 pop(uap);
1746
1747 return;
1748 }
1749
1750 /* for all other instructions, the result goes into a register */
1751 switch (r.type) {
1752 case fex_int:
1753 r.val.q = (long double)r.val.i;
1754 break;
1755
1756 case fex_llong:
1757 r.val.q = (long double)r.val.l;
1758 break;
1759
1760 case fex_float:
1761 r.val.q = (long double)r.val.f;
1762 break;
1763
1764 case fex_double:
1765 r.val.q = (long double)r.val.d;
1766 break;
1767
1768 default:
1769 break;
1770 }
1771
1772 /* for load instructions, push the result onto the stack */
1773 switch (op & 0x7f8) {
1774 case 0x100:
1775 case 0x140:
1776 case 0x180:
1777 case 0x500:
1778 case 0x540:
1779 case 0x580:
1780
1781 if (ea)
1782 push(r.val.q, uap);
1783
1784 return;
1785 }
1786
1787 /*
1788 * for all other instructions, if the exception is overflow,
1789 * underflow, or inexact, the stack has already been updated
1790 */
1791 stack = (ex == FPE_FLTOVF || ex == FPE_FLTUND || ex == FPE_FLTRES);
1792
1793 switch (op & 0x7f8) {
1794 case 0x1f0: /* oddballs */
1795
1796 switch (op) {
1797 case 0x1f1: /* fyl2x */
1798 case 0x1f3: /* fpatan */
1799 case 0x1f9: /* fyl2xp1 */
1800
1801 /* pop the stack, leaving the result in st */
1802 if (!stack)
1803 pop(uap);
1804
1805 fpreg(uap, 0) = r.val.q;
1806 return;
1807
1808 case 0x1f2: /* fpatan */
1809
1810 /* fptan pushes 1.0 afterward */
1811 if (stack) {
1812 fpreg(uap, 1) = r.val.q;
1813 } else {
1814 fpreg(uap, 0) = r.val.q;
1815 push(1.0L, uap);
1816 }
1817
1818 return;
1819
1820 case 0x1f4: /* fxtract */
1821 case 0x1fb: /* fsincos */
1822
1823 /* leave the supplied result in st */
1824 if (stack) {
1825 fpreg(uap, 0) = r.val.q;
1826 } else {
1827 fpreg(uap, 0) = 0.0; /* punt */
1828 push(r.val.q, uap);
1829 }
1830
1831 return;
1832 }
1833
1834 /* all others leave the stack alone and the result in st */
1835 fpreg(uap, 0) = r.val.q;
1836 return;
1837
1838 case 0x4c0:
1839 case 0x4c8:
1840 case 0x4e0:
1841 case 0x4e8:
1842 case 0x4f0:
1843 case 0x4f8:
1844 fpreg(uap, op & 7) = r.val.q;
1845 return;
1846
1847 case 0x6c0:
1848 case 0x6c8:
1849 case 0x6e0:
1850 case 0x6e8:
1851 case 0x6f0:
1852 case 0x6f8:
1853
1854 /* stack is popped afterward */
1855 if (stack) {
1856 fpreg(uap, (op - 1) & 7) = r.val.q;
1857 } else {
1858 fpreg(uap, op & 7) = r.val.q;
1859 pop(uap);
1860 }
1861
1862 return;
1863
1864 default:
1865 fpreg(uap, 0) = r.val.q;
1866 return;
1867 }
1868 }