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