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