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