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 *
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
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
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
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
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
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
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
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
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;
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;
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 */
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 */
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
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 }
|
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;
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;
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 }
|