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 }
1694