125c28e83SPiotr Jasiukajtis /*
225c28e83SPiotr Jasiukajtis  * CDDL HEADER START
325c28e83SPiotr Jasiukajtis  *
425c28e83SPiotr Jasiukajtis  * The contents of this file are subject to the terms of the
525c28e83SPiotr Jasiukajtis  * Common Development and Distribution License (the "License").
625c28e83SPiotr Jasiukajtis  * You may not use this file except in compliance with the License.
725c28e83SPiotr Jasiukajtis  *
825c28e83SPiotr Jasiukajtis  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925c28e83SPiotr Jasiukajtis  * or http://www.opensolaris.org/os/licensing.
1025c28e83SPiotr Jasiukajtis  * See the License for the specific language governing permissions
1125c28e83SPiotr Jasiukajtis  * and limitations under the License.
1225c28e83SPiotr Jasiukajtis  *
1325c28e83SPiotr Jasiukajtis  * When distributing Covered Code, include this CDDL HEADER in each
1425c28e83SPiotr Jasiukajtis  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525c28e83SPiotr Jasiukajtis  * If applicable, add the following below this CDDL HEADER, with the
1625c28e83SPiotr Jasiukajtis  * fields enclosed by brackets "[]" replaced with your own identifying
1725c28e83SPiotr Jasiukajtis  * information: Portions Copyright [yyyy] [name of copyright owner]
1825c28e83SPiotr Jasiukajtis  *
1925c28e83SPiotr Jasiukajtis  * CDDL HEADER END
2025c28e83SPiotr Jasiukajtis  */
2125c28e83SPiotr Jasiukajtis 
2225c28e83SPiotr Jasiukajtis /*
2325c28e83SPiotr Jasiukajtis  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
2425c28e83SPiotr Jasiukajtis  */
2525c28e83SPiotr Jasiukajtis /*
2625c28e83SPiotr Jasiukajtis  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2725c28e83SPiotr Jasiukajtis  * Use is subject to license terms.
2825c28e83SPiotr Jasiukajtis  */
2925c28e83SPiotr Jasiukajtis 
3025c28e83SPiotr Jasiukajtis #include <stdio.h>
3125c28e83SPiotr Jasiukajtis #include <unistd.h>
3225c28e83SPiotr Jasiukajtis #include <stdlib.h>
3325c28e83SPiotr Jasiukajtis #include <string.h>
3425c28e83SPiotr Jasiukajtis #include <signal.h>
3525c28e83SPiotr Jasiukajtis #include <siginfo.h>
3625c28e83SPiotr Jasiukajtis #include <ucontext.h>
3725c28e83SPiotr Jasiukajtis #include <thread.h>
3825c28e83SPiotr Jasiukajtis #include <math.h>
3925c28e83SPiotr Jasiukajtis #if defined(__SUNPRO_C)
4025c28e83SPiotr Jasiukajtis #include <sunmath.h>
4125c28e83SPiotr Jasiukajtis #endif
4225c28e83SPiotr Jasiukajtis #include <fenv.h>
4325c28e83SPiotr Jasiukajtis #include "fex_handler.h"
4425c28e83SPiotr Jasiukajtis #include "fenv_inlines.h"
4525c28e83SPiotr Jasiukajtis 
4625c28e83SPiotr Jasiukajtis #if defined(__amd64)
4725c28e83SPiotr Jasiukajtis #define test_sse_hw	1
4825c28e83SPiotr Jasiukajtis #else
4925c28e83SPiotr Jasiukajtis /*
5025c28e83SPiotr Jasiukajtis  * The following variable lives in libc on Solaris 10, where it
5125c28e83SPiotr Jasiukajtis  * gets set to a nonzero value at startup time on systems with SSE.
5225c28e83SPiotr Jasiukajtis  */
53f665a76fSRichard Lowe extern int _sse_hw;
54f665a76fSRichard Lowe #define test_sse_hw	_sse_hw
5525c28e83SPiotr Jasiukajtis #endif
5625c28e83SPiotr Jasiukajtis 
5725c28e83SPiotr Jasiukajtis static int accrued = 0;
5825c28e83SPiotr Jasiukajtis static thread_key_t accrued_key;
5925c28e83SPiotr Jasiukajtis static mutex_t accrued_key_lock = DEFAULTMUTEX;
6025c28e83SPiotr Jasiukajtis 
6125c28e83SPiotr Jasiukajtis int *
__fex_accrued()6225c28e83SPiotr Jasiukajtis __fex_accrued()
6325c28e83SPiotr Jasiukajtis {
6425c28e83SPiotr Jasiukajtis 	int		*p;
6525c28e83SPiotr Jasiukajtis 
6625c28e83SPiotr Jasiukajtis 	if (thr_main())
6725c28e83SPiotr Jasiukajtis 		return &accrued;
6825c28e83SPiotr Jasiukajtis 	else {
6925c28e83SPiotr Jasiukajtis 		p = NULL;
7025c28e83SPiotr Jasiukajtis 		mutex_lock(&accrued_key_lock);
7125c28e83SPiotr Jasiukajtis 		if (thr_getspecific(accrued_key, (void **)&p) != 0 &&
7225c28e83SPiotr Jasiukajtis 			thr_keycreate(&accrued_key, free) != 0) {
7325c28e83SPiotr Jasiukajtis 			mutex_unlock(&accrued_key_lock);
7425c28e83SPiotr Jasiukajtis 			return NULL;
7525c28e83SPiotr Jasiukajtis 		}
7625c28e83SPiotr Jasiukajtis 		mutex_unlock(&accrued_key_lock);
7725c28e83SPiotr Jasiukajtis 		if (!p) {
7825c28e83SPiotr Jasiukajtis 			if ((p = (int*) malloc(sizeof(int))) == NULL)
7925c28e83SPiotr Jasiukajtis 				return NULL;
8025c28e83SPiotr Jasiukajtis 			if (thr_setspecific(accrued_key, (void *)p) != 0) {
8125c28e83SPiotr Jasiukajtis 				(void)free(p);
8225c28e83SPiotr Jasiukajtis 				return NULL;
8325c28e83SPiotr Jasiukajtis 			}
8425c28e83SPiotr Jasiukajtis 			*p = 0;
8525c28e83SPiotr Jasiukajtis 		}
8625c28e83SPiotr Jasiukajtis 		return p;
8725c28e83SPiotr Jasiukajtis 	}
8825c28e83SPiotr Jasiukajtis }
8925c28e83SPiotr Jasiukajtis 
9025c28e83SPiotr Jasiukajtis void
__fenv_getfsr(unsigned long * fsr)9125c28e83SPiotr Jasiukajtis __fenv_getfsr(unsigned long *fsr)
9225c28e83SPiotr Jasiukajtis {
9325c28e83SPiotr Jasiukajtis 	unsigned int	cwsw, mxcsr;
9425c28e83SPiotr Jasiukajtis 
9525c28e83SPiotr Jasiukajtis 	__fenv_getcwsw(&cwsw);
9625c28e83SPiotr Jasiukajtis 	/* clear reserved bits for no particularly good reason */
9725c28e83SPiotr Jasiukajtis 	cwsw &= ~0xe0c00000u;
9825c28e83SPiotr Jasiukajtis 	if (test_sse_hw) {
9925c28e83SPiotr Jasiukajtis 		/* pick up exception flags (excluding denormal operand
10025c28e83SPiotr Jasiukajtis 		   flag) from mxcsr */
10125c28e83SPiotr Jasiukajtis 		__fenv_getmxcsr(&mxcsr);
10225c28e83SPiotr Jasiukajtis 		cwsw |= (mxcsr & 0x3d);
10325c28e83SPiotr Jasiukajtis 	}
10425c28e83SPiotr Jasiukajtis 	cwsw |= *__fex_accrued();
10525c28e83SPiotr Jasiukajtis 	*fsr = cwsw ^ 0x003f0000u;
10625c28e83SPiotr Jasiukajtis }
10725c28e83SPiotr Jasiukajtis 
10825c28e83SPiotr Jasiukajtis void
__fenv_setfsr(const unsigned long * fsr)10925c28e83SPiotr Jasiukajtis __fenv_setfsr(const unsigned long *fsr)
11025c28e83SPiotr Jasiukajtis {
11125c28e83SPiotr Jasiukajtis 	unsigned int	cwsw, mxcsr;
11225c28e83SPiotr Jasiukajtis 	int				te;
11325c28e83SPiotr Jasiukajtis 
11425c28e83SPiotr Jasiukajtis 	/* save accrued exception flags corresponding to enabled exceptions */
11525c28e83SPiotr Jasiukajtis 	cwsw = (unsigned int)*fsr;
11625c28e83SPiotr Jasiukajtis 	te = __fenv_get_te(cwsw);
11725c28e83SPiotr Jasiukajtis 	*__fex_accrued() = cwsw & te;
11825c28e83SPiotr Jasiukajtis 	cwsw = (cwsw & ~te) ^ 0x003f0000;
11925c28e83SPiotr Jasiukajtis 	if (test_sse_hw) {
12025c28e83SPiotr Jasiukajtis 		/* propagate rounding direction, masks, and exception flags
12125c28e83SPiotr Jasiukajtis 		   (excluding denormal operand mask and flag) to mxcsr */
12225c28e83SPiotr Jasiukajtis 		__fenv_getmxcsr(&mxcsr);
12325c28e83SPiotr Jasiukajtis 		mxcsr = (mxcsr & ~0x7ebd) | ((cwsw >> 13) & 0x6000) |
12425c28e83SPiotr Jasiukajtis 			((cwsw >> 9) & 0x1e80) | (cwsw & 0x3d);
12525c28e83SPiotr Jasiukajtis 		__fenv_setmxcsr(&mxcsr);
12625c28e83SPiotr Jasiukajtis 	}
12725c28e83SPiotr Jasiukajtis 	__fenv_setcwsw(&cwsw);
12825c28e83SPiotr Jasiukajtis }
12925c28e83SPiotr Jasiukajtis 
13025c28e83SPiotr Jasiukajtis /* Offsets into the fp environment save area (assumes 32-bit protected mode) */
13125c28e83SPiotr Jasiukajtis #define CW	0	/* control word */
13225c28e83SPiotr Jasiukajtis #define SW	1	/* status word */
13325c28e83SPiotr Jasiukajtis #define TW	2	/* tag word */
13425c28e83SPiotr Jasiukajtis #define IP	3	/* instruction pointer */
13525c28e83SPiotr Jasiukajtis #define OP	4	/* opcode */
13625c28e83SPiotr Jasiukajtis #define EA	5	/* operand address */
13725c28e83SPiotr Jasiukajtis 
13825c28e83SPiotr Jasiukajtis /* macro for accessing fp registers in the save area */
13925c28e83SPiotr Jasiukajtis #if defined(__amd64)
14025c28e83SPiotr Jasiukajtis #define fpreg(u,x)	*(long double *)(10*(x)+(char*)&(u)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.st)
14125c28e83SPiotr Jasiukajtis #else
14225c28e83SPiotr Jasiukajtis #define fpreg(u,x)	*(long double *)(10*(x)+(char*)&(u)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[7])
14325c28e83SPiotr Jasiukajtis #endif
14425c28e83SPiotr Jasiukajtis 
14525c28e83SPiotr Jasiukajtis /*
14625c28e83SPiotr Jasiukajtis *  Fix sip->si_code; the Solaris x86 kernel can get it wrong
14725c28e83SPiotr Jasiukajtis */
14825c28e83SPiotr Jasiukajtis void
__fex_get_x86_exc(siginfo_t * sip,ucontext_t * uap)14925c28e83SPiotr Jasiukajtis __fex_get_x86_exc(siginfo_t *sip, ucontext_t *uap)
15025c28e83SPiotr Jasiukajtis {
15125c28e83SPiotr Jasiukajtis 	unsigned	sw, cw;
15225c28e83SPiotr Jasiukajtis 
15325c28e83SPiotr Jasiukajtis 	sw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status;
15425c28e83SPiotr Jasiukajtis #if defined(__amd64)
15525c28e83SPiotr Jasiukajtis 	cw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw;
15625c28e83SPiotr Jasiukajtis #else
15725c28e83SPiotr Jasiukajtis 	cw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[CW];
15825c28e83SPiotr Jasiukajtis #endif
15925c28e83SPiotr Jasiukajtis 	if ((sw & FE_INVALID) && !(cw & (1 << fp_trap_invalid)))
16025c28e83SPiotr Jasiukajtis 		/* store 0 for stack fault, FPE_FLTINV for IEEE invalid op */
16125c28e83SPiotr Jasiukajtis 		sip->si_code = ((sw & 0x40)? 0 : FPE_FLTINV);
16225c28e83SPiotr Jasiukajtis 	else if ((sw & FE_DIVBYZERO) && !(cw & (1 << fp_trap_division)))
16325c28e83SPiotr Jasiukajtis 		sip->si_code = FPE_FLTDIV;
16425c28e83SPiotr Jasiukajtis 	else if ((sw & FE_OVERFLOW) && !(cw & (1 << fp_trap_overflow)))
16525c28e83SPiotr Jasiukajtis 		sip->si_code = FPE_FLTOVF;
16625c28e83SPiotr Jasiukajtis 	else if ((sw & FE_UNDERFLOW) && !(cw & (1 << fp_trap_underflow)))
16725c28e83SPiotr Jasiukajtis 		sip->si_code = FPE_FLTUND;
16825c28e83SPiotr Jasiukajtis 	else if ((sw & FE_INEXACT) && !(cw & (1 << fp_trap_inexact)))
16925c28e83SPiotr Jasiukajtis 		sip->si_code = FPE_FLTRES;
17025c28e83SPiotr Jasiukajtis 	else
17125c28e83SPiotr Jasiukajtis 		sip->si_code = 0;
17225c28e83SPiotr Jasiukajtis }
17325c28e83SPiotr Jasiukajtis 
17425c28e83SPiotr Jasiukajtis static enum fp_class_type
my_fp_classf(float * x)17525c28e83SPiotr Jasiukajtis my_fp_classf(float *x)
17625c28e83SPiotr Jasiukajtis {
17725c28e83SPiotr Jasiukajtis 	int		i = *(int*)x & ~0x80000000;
17825c28e83SPiotr Jasiukajtis 
17925c28e83SPiotr Jasiukajtis 	if (i < 0x7f800000) {
18025c28e83SPiotr Jasiukajtis 		if (i < 0x00800000)
18125c28e83SPiotr Jasiukajtis 			return ((i == 0)? fp_zero : fp_subnormal);
18225c28e83SPiotr Jasiukajtis 		return fp_normal;
18325c28e83SPiotr Jasiukajtis 	}
18425c28e83SPiotr Jasiukajtis 	else if (i == 0x7f800000)
18525c28e83SPiotr Jasiukajtis 		return fp_infinity;
18625c28e83SPiotr Jasiukajtis 	else if (i & 0x400000)
18725c28e83SPiotr Jasiukajtis 		return fp_quiet;
18825c28e83SPiotr Jasiukajtis 	else
18925c28e83SPiotr Jasiukajtis 		return fp_signaling;
19025c28e83SPiotr Jasiukajtis }
19125c28e83SPiotr Jasiukajtis 
19225c28e83SPiotr Jasiukajtis static enum fp_class_type
my_fp_class(double * x)19325c28e83SPiotr Jasiukajtis my_fp_class(double *x)
19425c28e83SPiotr Jasiukajtis {
19525c28e83SPiotr Jasiukajtis 	int		i = *(1+(int*)x) & ~0x80000000;
19625c28e83SPiotr Jasiukajtis 
19725c28e83SPiotr Jasiukajtis 	if (i < 0x7ff00000) {
19825c28e83SPiotr Jasiukajtis 		if (i < 0x00100000)
19925c28e83SPiotr Jasiukajtis 			return (((i | *(int*)x) == 0)? fp_zero : fp_subnormal);
20025c28e83SPiotr Jasiukajtis 		return fp_normal;
20125c28e83SPiotr Jasiukajtis 	}
20225c28e83SPiotr Jasiukajtis 	else if (i == 0x7ff00000 && *(int*)x == 0)
20325c28e83SPiotr Jasiukajtis 		return fp_infinity;
20425c28e83SPiotr Jasiukajtis 	else if (i & 0x80000)
20525c28e83SPiotr Jasiukajtis 		return fp_quiet;
20625c28e83SPiotr Jasiukajtis 	else
20725c28e83SPiotr Jasiukajtis 		return fp_signaling;
20825c28e83SPiotr Jasiukajtis }
20925c28e83SPiotr Jasiukajtis 
21025c28e83SPiotr Jasiukajtis static enum fp_class_type
my_fp_classl(long double * x)21125c28e83SPiotr Jasiukajtis my_fp_classl(long double *x)
21225c28e83SPiotr Jasiukajtis {
21325c28e83SPiotr Jasiukajtis 	int		i = *(2+(int*)x) & 0x7fff;
21425c28e83SPiotr Jasiukajtis 
21525c28e83SPiotr Jasiukajtis 	if (i < 0x7fff) {
21625c28e83SPiotr Jasiukajtis 		if (i < 1) {
21725c28e83SPiotr Jasiukajtis 			if (*(1+(int*)x) < 0) return fp_normal; /* pseudo-denormal */
218f665a76fSRichard Lowe 			return (((*(1+(int*)x) | *(int*)x) == 0)?
21925c28e83SPiotr Jasiukajtis 				fp_zero : fp_subnormal);
22025c28e83SPiotr Jasiukajtis 		}
22125c28e83SPiotr Jasiukajtis 		return ((*(1+(int*)x) < 0)? fp_normal :
22225c28e83SPiotr Jasiukajtis 			(enum fp_class_type) -1); /* unsupported format */
22325c28e83SPiotr Jasiukajtis 	}
22425c28e83SPiotr Jasiukajtis 	else if (*(1+(int*)x) == 0x80000000 && *(int*)x == 0)
22525c28e83SPiotr Jasiukajtis 		return fp_infinity;
22625c28e83SPiotr Jasiukajtis 	else if (*(1+(unsigned*)x) >= 0xc0000000)
22725c28e83SPiotr Jasiukajtis 		return fp_quiet;
22825c28e83SPiotr Jasiukajtis 	else if (*(1+(int*)x) < 0)
22925c28e83SPiotr Jasiukajtis 		return fp_signaling;
23025c28e83SPiotr Jasiukajtis 	else
23125c28e83SPiotr Jasiukajtis 		return (enum fp_class_type) -1; /* unsupported format */
23225c28e83SPiotr Jasiukajtis }
23325c28e83SPiotr Jasiukajtis 
23425c28e83SPiotr Jasiukajtis /*
23525c28e83SPiotr Jasiukajtis *  Determine which type of invalid operation exception occurred
23625c28e83SPiotr Jasiukajtis */
23725c28e83SPiotr Jasiukajtis enum fex_exception
__fex_get_invalid_type(siginfo_t * sip,ucontext_t * uap)23825c28e83SPiotr Jasiukajtis __fex_get_invalid_type(siginfo_t *sip, ucontext_t *uap)
23925c28e83SPiotr Jasiukajtis {
24025c28e83SPiotr Jasiukajtis 	unsigned			op;
24125c28e83SPiotr Jasiukajtis 	unsigned long			ea;
24225c28e83SPiotr Jasiukajtis 	enum fp_class_type	t1, t2;
24325c28e83SPiotr Jasiukajtis 
24425c28e83SPiotr Jasiukajtis 	/* get the opcode and data address */
24525c28e83SPiotr Jasiukajtis #if defined(__amd64)
24625c28e83SPiotr Jasiukajtis 	op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
24725c28e83SPiotr Jasiukajtis 	ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp;
24825c28e83SPiotr Jasiukajtis #else
24925c28e83SPiotr Jasiukajtis 	op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
25025c28e83SPiotr Jasiukajtis 	ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
25125c28e83SPiotr Jasiukajtis #endif
25225c28e83SPiotr Jasiukajtis 
25325c28e83SPiotr Jasiukajtis 	/* if the instruction is fld, the source must be snan (it can't be
25425c28e83SPiotr Jasiukajtis 	   an unsupported format, since fldt doesn't raise any exceptions) */
25525c28e83SPiotr Jasiukajtis 	switch (op & 0x7f8) {
25625c28e83SPiotr Jasiukajtis 	case 0x100:
25725c28e83SPiotr Jasiukajtis 	case 0x140:
25825c28e83SPiotr Jasiukajtis 	case 0x180:
25925c28e83SPiotr Jasiukajtis 	case 0x500:
26025c28e83SPiotr Jasiukajtis 	case 0x540:
26125c28e83SPiotr Jasiukajtis 	case 0x580:
26225c28e83SPiotr Jasiukajtis 		return fex_inv_snan;
26325c28e83SPiotr Jasiukajtis 	}
26425c28e83SPiotr Jasiukajtis 
26525c28e83SPiotr Jasiukajtis 	/* otherwise st is one of the operands; see if it's snan */
26625c28e83SPiotr Jasiukajtis 	t1 = my_fp_classl(&fpreg(uap, 0));
26725c28e83SPiotr Jasiukajtis 	if (t1 == fp_signaling)
26825c28e83SPiotr Jasiukajtis 		return fex_inv_snan;
26925c28e83SPiotr Jasiukajtis 	else if (t1 == (enum fp_class_type) -1)
27025c28e83SPiotr Jasiukajtis 		return (enum fex_exception) -1;
27125c28e83SPiotr Jasiukajtis 
27225c28e83SPiotr Jasiukajtis 	/* determine the class of the second operand if there is one */
27325c28e83SPiotr Jasiukajtis 	t2 = fp_normal;
27425c28e83SPiotr Jasiukajtis 	switch (op & 0x7e0) {
27525c28e83SPiotr Jasiukajtis 	case 0x600:
27625c28e83SPiotr Jasiukajtis 	case 0x620:
27725c28e83SPiotr Jasiukajtis 	case 0x640:
27825c28e83SPiotr Jasiukajtis 	case 0x660:
27925c28e83SPiotr Jasiukajtis 	case 0x680:
28025c28e83SPiotr Jasiukajtis 	case 0x6a0:
28125c28e83SPiotr Jasiukajtis 		/* short memory operand */
28225c28e83SPiotr Jasiukajtis 		if (!ea)
28325c28e83SPiotr Jasiukajtis 			return (enum fex_exception) -1;
28425c28e83SPiotr Jasiukajtis 		if (*(short *)ea == 0)
28525c28e83SPiotr Jasiukajtis 			t2 = fp_zero;
28625c28e83SPiotr Jasiukajtis 		break;
28725c28e83SPiotr Jasiukajtis 
28825c28e83SPiotr Jasiukajtis 	case 0x200:
28925c28e83SPiotr Jasiukajtis 	case 0x220:
29025c28e83SPiotr Jasiukajtis 	case 0x240:
29125c28e83SPiotr Jasiukajtis 	case 0x260:
29225c28e83SPiotr Jasiukajtis 	case 0x280:
29325c28e83SPiotr Jasiukajtis 	case 0x2a0:
29425c28e83SPiotr Jasiukajtis 		/* int memory operand */
29525c28e83SPiotr Jasiukajtis 		if (!ea)
29625c28e83SPiotr Jasiukajtis 			return (enum fex_exception) -1;
29725c28e83SPiotr Jasiukajtis 		if (*(int *)ea == 0)
29825c28e83SPiotr Jasiukajtis 			t2 = fp_zero;
29925c28e83SPiotr Jasiukajtis 		break;
30025c28e83SPiotr Jasiukajtis 
30125c28e83SPiotr Jasiukajtis 	case 0x000:
30225c28e83SPiotr Jasiukajtis 	case 0x020:
30325c28e83SPiotr Jasiukajtis 	case 0x040:
30425c28e83SPiotr Jasiukajtis 	case 0x060:
30525c28e83SPiotr Jasiukajtis 	case 0x080:
30625c28e83SPiotr Jasiukajtis 	case 0x0a0:
30725c28e83SPiotr Jasiukajtis 		/* single precision memory operand */
30825c28e83SPiotr Jasiukajtis 		if (!ea)
30925c28e83SPiotr Jasiukajtis 			return (enum fex_exception) -1;
31025c28e83SPiotr Jasiukajtis 		t2 = my_fp_classf((float *)ea);
31125c28e83SPiotr Jasiukajtis 		break;
31225c28e83SPiotr Jasiukajtis 
31325c28e83SPiotr Jasiukajtis 	case 0x400:
31425c28e83SPiotr Jasiukajtis 	case 0x420:
31525c28e83SPiotr Jasiukajtis 	case 0x440:
31625c28e83SPiotr Jasiukajtis 	case 0x460:
31725c28e83SPiotr Jasiukajtis 	case 0x480:
31825c28e83SPiotr Jasiukajtis 	case 0x4a0:
31925c28e83SPiotr Jasiukajtis 		/* double precision memory operand */
32025c28e83SPiotr Jasiukajtis 		if (!ea)
32125c28e83SPiotr Jasiukajtis 			return (enum fex_exception) -1;
32225c28e83SPiotr Jasiukajtis 		t2 = my_fp_class((double *)ea);
32325c28e83SPiotr Jasiukajtis 		break;
32425c28e83SPiotr Jasiukajtis 
32525c28e83SPiotr Jasiukajtis 	case 0x0c0:
32625c28e83SPiotr Jasiukajtis 	case 0x0e0:
32725c28e83SPiotr Jasiukajtis 	case 0x3e0:
32825c28e83SPiotr Jasiukajtis 	case 0x4c0:
32925c28e83SPiotr Jasiukajtis 	case 0x4e0:
33025c28e83SPiotr Jasiukajtis 	case 0x5e0:
33125c28e83SPiotr Jasiukajtis 	case 0x6c0:
33225c28e83SPiotr Jasiukajtis 	case 0x6e0:
33325c28e83SPiotr Jasiukajtis 	case 0x7e0:
33425c28e83SPiotr Jasiukajtis 		/* register operand determined by opcode */
33525c28e83SPiotr Jasiukajtis 		switch (op & 0x7f8) {
33625c28e83SPiotr Jasiukajtis 		case 0x3e0:
33725c28e83SPiotr Jasiukajtis 		case 0x3f8:
33825c28e83SPiotr Jasiukajtis 		case 0x5f0:
33925c28e83SPiotr Jasiukajtis 		case 0x5f8:
34025c28e83SPiotr Jasiukajtis 		case 0x7e0:
34125c28e83SPiotr Jasiukajtis 		case 0x7f8:
34225c28e83SPiotr Jasiukajtis 			/* weed out nonexistent opcodes */
34325c28e83SPiotr Jasiukajtis 			break;
34425c28e83SPiotr Jasiukajtis 
34525c28e83SPiotr Jasiukajtis 		default:
34625c28e83SPiotr Jasiukajtis 			t2 = my_fp_classl(&fpreg(uap, op & 7));
34725c28e83SPiotr Jasiukajtis 		}
34825c28e83SPiotr Jasiukajtis 		break;
34925c28e83SPiotr Jasiukajtis 
35025c28e83SPiotr Jasiukajtis 	case 0x1e0:
35125c28e83SPiotr Jasiukajtis 	case 0x2e0:
35225c28e83SPiotr Jasiukajtis 		/* special forms */
35325c28e83SPiotr Jasiukajtis 		switch (op) {
35425c28e83SPiotr Jasiukajtis 		case 0x1f1: /* fyl2x */
35525c28e83SPiotr Jasiukajtis 		case 0x1f3: /* fpatan */
35625c28e83SPiotr Jasiukajtis 		case 0x1f5: /* fprem1 */
35725c28e83SPiotr Jasiukajtis 		case 0x1f8: /* fprem */
35825c28e83SPiotr Jasiukajtis 		case 0x1f9: /* fyl2xp1 */
35925c28e83SPiotr Jasiukajtis 		case 0x1fd: /* fscale */
36025c28e83SPiotr Jasiukajtis 		case 0x2e9: /* fucompp */
36125c28e83SPiotr Jasiukajtis 			t2 = my_fp_classl(&fpreg(uap, 1));
36225c28e83SPiotr Jasiukajtis 			break;
36325c28e83SPiotr Jasiukajtis 		}
36425c28e83SPiotr Jasiukajtis 		break;
36525c28e83SPiotr Jasiukajtis 	}
36625c28e83SPiotr Jasiukajtis 
36725c28e83SPiotr Jasiukajtis 	/* see if the second op is snan */
36825c28e83SPiotr Jasiukajtis 	if (t2 == fp_signaling)
36925c28e83SPiotr Jasiukajtis 		return fex_inv_snan;
37025c28e83SPiotr Jasiukajtis 	else if (t2 == (enum fp_class_type) -1)
37125c28e83SPiotr Jasiukajtis 		return (enum fex_exception) -1;
37225c28e83SPiotr Jasiukajtis 
37325c28e83SPiotr Jasiukajtis 	/* determine the type of operation */
37425c28e83SPiotr Jasiukajtis 	switch (op & 0x7f8) {
37525c28e83SPiotr Jasiukajtis 	case 0x000:
37625c28e83SPiotr Jasiukajtis 	case 0x020:
37725c28e83SPiotr Jasiukajtis 	case 0x028:
37825c28e83SPiotr Jasiukajtis 	case 0x040:
37925c28e83SPiotr Jasiukajtis 	case 0x060:
38025c28e83SPiotr Jasiukajtis 	case 0x068:
38125c28e83SPiotr Jasiukajtis 	case 0x080:
38225c28e83SPiotr Jasiukajtis 	case 0x0a0:
38325c28e83SPiotr Jasiukajtis 	case 0x0a8:
38425c28e83SPiotr Jasiukajtis 	case 0x0c0:
38525c28e83SPiotr Jasiukajtis 	case 0x0e0:
38625c28e83SPiotr Jasiukajtis 	case 0x0e8:
38725c28e83SPiotr Jasiukajtis 	case 0x400:
38825c28e83SPiotr Jasiukajtis 	case 0x420:
38925c28e83SPiotr Jasiukajtis 	case 0x428:
39025c28e83SPiotr Jasiukajtis 	case 0x440:
39125c28e83SPiotr Jasiukajtis 	case 0x460:
39225c28e83SPiotr Jasiukajtis 	case 0x468:
39325c28e83SPiotr Jasiukajtis 	case 0x480:
39425c28e83SPiotr Jasiukajtis 	case 0x4a0:
39525c28e83SPiotr Jasiukajtis 	case 0x4a8:
39625c28e83SPiotr Jasiukajtis 	case 0x4c0:
39725c28e83SPiotr Jasiukajtis 	case 0x4e0:
39825c28e83SPiotr Jasiukajtis 	case 0x4e8:
39925c28e83SPiotr Jasiukajtis 	case 0x6c0:
40025c28e83SPiotr Jasiukajtis 	case 0x6e0:
40125c28e83SPiotr Jasiukajtis 	case 0x6e8:
40225c28e83SPiotr Jasiukajtis 		/* fadd, fsub, fsubr */
40325c28e83SPiotr Jasiukajtis 		if (t1 == fp_infinity && t2 == fp_infinity)
40425c28e83SPiotr Jasiukajtis 			return fex_inv_isi;
40525c28e83SPiotr Jasiukajtis 		break;
40625c28e83SPiotr Jasiukajtis 
40725c28e83SPiotr Jasiukajtis 	case 0x008:
40825c28e83SPiotr Jasiukajtis 	case 0x048:
40925c28e83SPiotr Jasiukajtis 	case 0x088:
41025c28e83SPiotr Jasiukajtis 	case 0x0c8:
41125c28e83SPiotr Jasiukajtis 	case 0x208:
41225c28e83SPiotr Jasiukajtis 	case 0x248:
41325c28e83SPiotr Jasiukajtis 	case 0x288:
41425c28e83SPiotr Jasiukajtis 	case 0x408:
41525c28e83SPiotr Jasiukajtis 	case 0x448:
41625c28e83SPiotr Jasiukajtis 	case 0x488:
41725c28e83SPiotr Jasiukajtis 	case 0x4c8:
41825c28e83SPiotr Jasiukajtis 	case 0x608:
41925c28e83SPiotr Jasiukajtis 	case 0x648:
42025c28e83SPiotr Jasiukajtis 	case 0x688:
42125c28e83SPiotr Jasiukajtis 	case 0x6c8:
42225c28e83SPiotr Jasiukajtis 		/* fmul */
42325c28e83SPiotr Jasiukajtis 		if ((t1 == fp_zero && t2 == fp_infinity) || (t2 == fp_zero &&
42425c28e83SPiotr Jasiukajtis 		  t1 == fp_infinity))
42525c28e83SPiotr Jasiukajtis 			return fex_inv_zmi;
42625c28e83SPiotr Jasiukajtis 		break;
42725c28e83SPiotr Jasiukajtis 
42825c28e83SPiotr Jasiukajtis 	case 0x030:
42925c28e83SPiotr Jasiukajtis 	case 0x038:
43025c28e83SPiotr Jasiukajtis 	case 0x070:
43125c28e83SPiotr Jasiukajtis 	case 0x078:
43225c28e83SPiotr Jasiukajtis 	case 0x0b0:
43325c28e83SPiotr Jasiukajtis 	case 0x0b8:
43425c28e83SPiotr Jasiukajtis 	case 0x0f0:
43525c28e83SPiotr Jasiukajtis 	case 0x0f8:
43625c28e83SPiotr Jasiukajtis 	case 0x230:
43725c28e83SPiotr Jasiukajtis 	case 0x238:
43825c28e83SPiotr Jasiukajtis 	case 0x270:
43925c28e83SPiotr Jasiukajtis 	case 0x278:
44025c28e83SPiotr Jasiukajtis 	case 0x2b0:
44125c28e83SPiotr Jasiukajtis 	case 0x2b8:
44225c28e83SPiotr Jasiukajtis 	case 0x430:
44325c28e83SPiotr Jasiukajtis 	case 0x438:
44425c28e83SPiotr Jasiukajtis 	case 0x470:
44525c28e83SPiotr Jasiukajtis 	case 0x478:
44625c28e83SPiotr Jasiukajtis 	case 0x4b0:
44725c28e83SPiotr Jasiukajtis 	case 0x4b8:
44825c28e83SPiotr Jasiukajtis 	case 0x4f0:
44925c28e83SPiotr Jasiukajtis 	case 0x4f8:
45025c28e83SPiotr Jasiukajtis 	case 0x630:
45125c28e83SPiotr Jasiukajtis 	case 0x638:
45225c28e83SPiotr Jasiukajtis 	case 0x670:
45325c28e83SPiotr Jasiukajtis 	case 0x678:
45425c28e83SPiotr Jasiukajtis 	case 0x6b0:
45525c28e83SPiotr Jasiukajtis 	case 0x6b8:
45625c28e83SPiotr Jasiukajtis 	case 0x6f0:
45725c28e83SPiotr Jasiukajtis 	case 0x6f8:
45825c28e83SPiotr Jasiukajtis 		/* fdiv */
45925c28e83SPiotr Jasiukajtis 		if (t1 == fp_zero && t2 == fp_zero)
46025c28e83SPiotr Jasiukajtis 			return fex_inv_zdz;
46125c28e83SPiotr Jasiukajtis 		else if (t1 == fp_infinity && t2 == fp_infinity)
46225c28e83SPiotr Jasiukajtis 			return fex_inv_idi;
46325c28e83SPiotr Jasiukajtis 		break;
46425c28e83SPiotr Jasiukajtis 
46525c28e83SPiotr Jasiukajtis 	case 0x1f0:
46625c28e83SPiotr Jasiukajtis 	case 0x1f8:
46725c28e83SPiotr Jasiukajtis 		/* fsqrt, other special ops */
46825c28e83SPiotr Jasiukajtis 		return fex_inv_sqrt;
46925c28e83SPiotr Jasiukajtis 
47025c28e83SPiotr Jasiukajtis 	case 0x010:
47125c28e83SPiotr Jasiukajtis 	case 0x018:
47225c28e83SPiotr Jasiukajtis 	case 0x050:
47325c28e83SPiotr Jasiukajtis 	case 0x058:
47425c28e83SPiotr Jasiukajtis 	case 0x090:
47525c28e83SPiotr Jasiukajtis 	case 0x098:
47625c28e83SPiotr Jasiukajtis 	case 0x0d0:
47725c28e83SPiotr Jasiukajtis 	case 0x0d8:
47825c28e83SPiotr Jasiukajtis 	case 0x210:
47925c28e83SPiotr Jasiukajtis 	case 0x218:
48025c28e83SPiotr Jasiukajtis 	case 0x250:
48125c28e83SPiotr Jasiukajtis 	case 0x258:
48225c28e83SPiotr Jasiukajtis 	case 0x290:
48325c28e83SPiotr Jasiukajtis 	case 0x298:
48425c28e83SPiotr Jasiukajtis 	case 0x2e8:
48525c28e83SPiotr Jasiukajtis 	case 0x3f0:
48625c28e83SPiotr Jasiukajtis 	case 0x410:
48725c28e83SPiotr Jasiukajtis 	case 0x418:
48825c28e83SPiotr Jasiukajtis 	case 0x450:
48925c28e83SPiotr Jasiukajtis 	case 0x458:
49025c28e83SPiotr Jasiukajtis 	case 0x490:
49125c28e83SPiotr Jasiukajtis 	case 0x498:
49225c28e83SPiotr Jasiukajtis 	case 0x4d0:
49325c28e83SPiotr Jasiukajtis 	case 0x4d8:
49425c28e83SPiotr Jasiukajtis 	case 0x5e0:
49525c28e83SPiotr Jasiukajtis 	case 0x5e8:
49625c28e83SPiotr Jasiukajtis 	case 0x610:
49725c28e83SPiotr Jasiukajtis 	case 0x618:
49825c28e83SPiotr Jasiukajtis 	case 0x650:
49925c28e83SPiotr Jasiukajtis 	case 0x658:
50025c28e83SPiotr Jasiukajtis 	case 0x690:
50125c28e83SPiotr Jasiukajtis 	case 0x698:
50225c28e83SPiotr Jasiukajtis 	case 0x6d0:
50325c28e83SPiotr Jasiukajtis 	case 0x6d8:
50425c28e83SPiotr Jasiukajtis 	case 0x7f0:
50525c28e83SPiotr Jasiukajtis 		/* fcom */
50625c28e83SPiotr Jasiukajtis 		if (t1 == fp_quiet || t2 == fp_quiet)
50725c28e83SPiotr Jasiukajtis 			return fex_inv_cmp;
50825c28e83SPiotr Jasiukajtis 		break;
50925c28e83SPiotr Jasiukajtis 
51025c28e83SPiotr Jasiukajtis 	case 0x1e0:
51125c28e83SPiotr Jasiukajtis 		/* ftst */
51225c28e83SPiotr Jasiukajtis 		if (op == 0x1e4 && t1 == fp_quiet)
51325c28e83SPiotr Jasiukajtis 			return fex_inv_cmp;
51425c28e83SPiotr Jasiukajtis 		break;
51525c28e83SPiotr Jasiukajtis 
51625c28e83SPiotr Jasiukajtis 	case 0x310:
51725c28e83SPiotr Jasiukajtis 	case 0x318:
51825c28e83SPiotr Jasiukajtis 	case 0x350:
51925c28e83SPiotr Jasiukajtis 	case 0x358:
52025c28e83SPiotr Jasiukajtis 	case 0x390:
52125c28e83SPiotr Jasiukajtis 	case 0x398:
52225c28e83SPiotr Jasiukajtis 	case 0x710:
52325c28e83SPiotr Jasiukajtis 	case 0x718:
52425c28e83SPiotr Jasiukajtis 	case 0x730:
52525c28e83SPiotr Jasiukajtis 	case 0x738:
52625c28e83SPiotr Jasiukajtis 	case 0x750:
52725c28e83SPiotr Jasiukajtis 	case 0x758:
52825c28e83SPiotr Jasiukajtis 	case 0x770:
52925c28e83SPiotr Jasiukajtis 	case 0x778:
53025c28e83SPiotr Jasiukajtis 	case 0x790:
53125c28e83SPiotr Jasiukajtis 	case 0x798:
53225c28e83SPiotr Jasiukajtis 	case 0x7b0:
53325c28e83SPiotr Jasiukajtis 	case 0x7b8:
53425c28e83SPiotr Jasiukajtis 		/* fist, fbst */
53525c28e83SPiotr Jasiukajtis 		return fex_inv_int;
53625c28e83SPiotr Jasiukajtis 	}
53725c28e83SPiotr Jasiukajtis 
53825c28e83SPiotr Jasiukajtis 	return (enum fex_exception) -1;
53925c28e83SPiotr Jasiukajtis }
54025c28e83SPiotr Jasiukajtis 
54125c28e83SPiotr Jasiukajtis /* scale factors for exponent unwrapping */
54225c28e83SPiotr Jasiukajtis static const long double
54325c28e83SPiotr Jasiukajtis 	two12288 = 1.139165225263043370845938579315932009e+3699l,	/* 2^12288 */
54425c28e83SPiotr Jasiukajtis 	twom12288 = 8.778357852076208839765066529179033145e-3700l,	/* 2^-12288 */
54525c28e83SPiotr Jasiukajtis 	twom12288mulp = 8.778357852076208839289190796475222545e-3700l;
54625c28e83SPiotr Jasiukajtis 		/* (")*(1-2^-64) */
54725c28e83SPiotr Jasiukajtis 
54825c28e83SPiotr Jasiukajtis /* inline templates */
54925c28e83SPiotr Jasiukajtis extern long double f2xm1(long double);
55025c28e83SPiotr Jasiukajtis extern long double fyl2x(long double, long double);
55125c28e83SPiotr Jasiukajtis extern long double fptan(long double);
55225c28e83SPiotr Jasiukajtis extern long double fpatan(long double, long double);
55325c28e83SPiotr Jasiukajtis extern long double fxtract(long double);
55425c28e83SPiotr Jasiukajtis extern long double fprem1(long double, long double);
55525c28e83SPiotr Jasiukajtis extern long double fprem(long double, long double);
55625c28e83SPiotr Jasiukajtis extern long double fyl2xp1(long double, long double);
55725c28e83SPiotr Jasiukajtis extern long double fsqrt(long double);
55825c28e83SPiotr Jasiukajtis extern long double fsincos(long double);
55925c28e83SPiotr Jasiukajtis extern long double frndint(long double);
56025c28e83SPiotr Jasiukajtis extern long double fscale(long double, long double);
56125c28e83SPiotr Jasiukajtis extern long double fsin(long double);
56225c28e83SPiotr Jasiukajtis extern long double fcos(long double);
56325c28e83SPiotr Jasiukajtis 
56425c28e83SPiotr Jasiukajtis /*
56525c28e83SPiotr Jasiukajtis *  Get the operands, generate the default untrapped result with
56625c28e83SPiotr Jasiukajtis *  exceptions, and set a code indicating the type of operation
56725c28e83SPiotr Jasiukajtis */
56825c28e83SPiotr Jasiukajtis void
__fex_get_op(siginfo_t * sip,ucontext_t * uap,fex_info_t * info)56925c28e83SPiotr Jasiukajtis __fex_get_op(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
57025c28e83SPiotr Jasiukajtis {
57125c28e83SPiotr Jasiukajtis 	fex_numeric_t			t;
57225c28e83SPiotr Jasiukajtis 	long double			op2v, x;
57325c28e83SPiotr Jasiukajtis 	unsigned int			cwsw, ex, sw, op;
57425c28e83SPiotr Jasiukajtis 	unsigned long			ea;
575*862246c1SToomas Soome 	volatile int			c __unused;
57625c28e83SPiotr Jasiukajtis 
57725c28e83SPiotr Jasiukajtis 	/* get the exception type, status word, opcode, and data address */
57825c28e83SPiotr Jasiukajtis 	ex = sip->si_code;
57925c28e83SPiotr Jasiukajtis 	sw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status;
58025c28e83SPiotr Jasiukajtis #if defined(__amd64)
58125c28e83SPiotr Jasiukajtis 	op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
58225c28e83SPiotr Jasiukajtis 	ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp;
58325c28e83SPiotr Jasiukajtis #else
58425c28e83SPiotr Jasiukajtis 	op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
58525c28e83SPiotr Jasiukajtis 	ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
58625c28e83SPiotr Jasiukajtis #endif
58725c28e83SPiotr Jasiukajtis 
58825c28e83SPiotr Jasiukajtis 	/* initialize res to the default untrapped result and ex to the
58925c28e83SPiotr Jasiukajtis 	   corresponding flags (assume trapping is disabled and flags
59025c28e83SPiotr Jasiukajtis 	   are clear) */
59125c28e83SPiotr Jasiukajtis 
59225c28e83SPiotr Jasiukajtis 	/* single operand instructions */
59325c28e83SPiotr Jasiukajtis 	info->op = fex_cnvt;
59425c28e83SPiotr Jasiukajtis 	info->op2.type = fex_nodata;
59525c28e83SPiotr Jasiukajtis 	switch (op & 0x7f8) {
59625c28e83SPiotr Jasiukajtis 	/* load instructions */
59725c28e83SPiotr Jasiukajtis 	case 0x100:
59825c28e83SPiotr Jasiukajtis 	case 0x140:
59925c28e83SPiotr Jasiukajtis 	case 0x180:
60025c28e83SPiotr Jasiukajtis 		if (!ea) {
60125c28e83SPiotr Jasiukajtis 			info->op = fex_other;
60225c28e83SPiotr Jasiukajtis 			info->op1.type = info->op2.type = info->res.type = fex_nodata;
60325c28e83SPiotr Jasiukajtis 			info->flags = 0;
60425c28e83SPiotr Jasiukajtis 			return;
60525c28e83SPiotr Jasiukajtis 		}
60625c28e83SPiotr Jasiukajtis 		info->op1.type = fex_float;
60725c28e83SPiotr Jasiukajtis 		info->op1.val.f = *(float *)ea;
60825c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
60925c28e83SPiotr Jasiukajtis 		info->res.val.q = (long double) info->op1.val.f;
61025c28e83SPiotr Jasiukajtis 		goto done;
61125c28e83SPiotr Jasiukajtis 
61225c28e83SPiotr Jasiukajtis 	case 0x500:
61325c28e83SPiotr Jasiukajtis 	case 0x540:
61425c28e83SPiotr Jasiukajtis 	case 0x580:
61525c28e83SPiotr Jasiukajtis 		if (!ea) {
61625c28e83SPiotr Jasiukajtis 			info->op = fex_other;
61725c28e83SPiotr Jasiukajtis 			info->op1.type = info->op2.type = info->res.type = fex_nodata;
61825c28e83SPiotr Jasiukajtis 			info->flags = 0;
61925c28e83SPiotr Jasiukajtis 			return;
62025c28e83SPiotr Jasiukajtis 		}
62125c28e83SPiotr Jasiukajtis 		info->op1.type = fex_double;
62225c28e83SPiotr Jasiukajtis 		info->op1.val.d = *(double *)ea;
62325c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
62425c28e83SPiotr Jasiukajtis 		info->res.val.q = (long double) info->op1.val.d;
62525c28e83SPiotr Jasiukajtis 		goto done;
62625c28e83SPiotr Jasiukajtis 
62725c28e83SPiotr Jasiukajtis 	/* store instructions */
62825c28e83SPiotr Jasiukajtis 	case 0x110:
62925c28e83SPiotr Jasiukajtis 	case 0x118:
63025c28e83SPiotr Jasiukajtis 	case 0x150:
63125c28e83SPiotr Jasiukajtis 	case 0x158:
63225c28e83SPiotr Jasiukajtis 	case 0x190:
63325c28e83SPiotr Jasiukajtis 	case 0x198:
63425c28e83SPiotr Jasiukajtis 		info->res.type = fex_float;
63525c28e83SPiotr Jasiukajtis 		if (ex == FPE_FLTRES && (op & 8) != 0) {
63625c28e83SPiotr Jasiukajtis 			/* inexact, stack popped */
63725c28e83SPiotr Jasiukajtis 			if (!ea) {
63825c28e83SPiotr Jasiukajtis 				info->op = fex_other;
63925c28e83SPiotr Jasiukajtis 				info->op1.type = info->op2.type = info->res.type = fex_nodata;
64025c28e83SPiotr Jasiukajtis 				info->flags = 0;
64125c28e83SPiotr Jasiukajtis 				return;
64225c28e83SPiotr Jasiukajtis 			}
64325c28e83SPiotr Jasiukajtis 			info->op1.type = fex_nodata;
64425c28e83SPiotr Jasiukajtis 			info->res.val.f = *(float *)ea;
64525c28e83SPiotr Jasiukajtis 			info->flags = FE_INEXACT;
64625c28e83SPiotr Jasiukajtis 			return;
64725c28e83SPiotr Jasiukajtis 		}
64825c28e83SPiotr Jasiukajtis 		info->op1.type = fex_ldouble;
64925c28e83SPiotr Jasiukajtis 		info->op1.val.q = fpreg(uap, 0);
65025c28e83SPiotr Jasiukajtis 		info->res.val.f = (float) info->op1.val.q;
65125c28e83SPiotr Jasiukajtis 		goto done;
65225c28e83SPiotr Jasiukajtis 
65325c28e83SPiotr Jasiukajtis 	case 0x310:
65425c28e83SPiotr Jasiukajtis 	case 0x318:
65525c28e83SPiotr Jasiukajtis 	case 0x350:
65625c28e83SPiotr Jasiukajtis 	case 0x358:
65725c28e83SPiotr Jasiukajtis 	case 0x390:
65825c28e83SPiotr Jasiukajtis 	case 0x398:
65925c28e83SPiotr Jasiukajtis 		info->res.type = fex_int;
66025c28e83SPiotr Jasiukajtis 		if (ex == FPE_FLTRES && (op & 8) != 0) {
66125c28e83SPiotr Jasiukajtis 			/* inexact, stack popped */
66225c28e83SPiotr Jasiukajtis 			if (!ea) {
66325c28e83SPiotr Jasiukajtis 				info->op = fex_other;
66425c28e83SPiotr Jasiukajtis 				info->op1.type = info->op2.type = info->res.type = fex_nodata;
66525c28e83SPiotr Jasiukajtis 				info->flags = 0;
66625c28e83SPiotr Jasiukajtis 				return;
66725c28e83SPiotr Jasiukajtis 			}
66825c28e83SPiotr Jasiukajtis 			info->op1.type = fex_nodata;
66925c28e83SPiotr Jasiukajtis 			info->res.val.i = *(int *)ea;
67025c28e83SPiotr Jasiukajtis 			info->flags = FE_INEXACT;
67125c28e83SPiotr Jasiukajtis 			return;
67225c28e83SPiotr Jasiukajtis 		}
67325c28e83SPiotr Jasiukajtis 		info->op1.type = fex_ldouble;
67425c28e83SPiotr Jasiukajtis 		info->op1.val.q = fpreg(uap, 0);
67525c28e83SPiotr Jasiukajtis 		info->res.val.i = (int) info->op1.val.q;
67625c28e83SPiotr Jasiukajtis 		goto done;
67725c28e83SPiotr Jasiukajtis 
67825c28e83SPiotr Jasiukajtis 	case 0x510:
67925c28e83SPiotr Jasiukajtis 	case 0x518:
68025c28e83SPiotr Jasiukajtis 	case 0x550:
68125c28e83SPiotr Jasiukajtis 	case 0x558:
68225c28e83SPiotr Jasiukajtis 	case 0x590:
68325c28e83SPiotr Jasiukajtis 	case 0x598:
68425c28e83SPiotr Jasiukajtis 		info->res.type = fex_double;
68525c28e83SPiotr Jasiukajtis 		if (ex == FPE_FLTRES && (op & 8) != 0) {
68625c28e83SPiotr Jasiukajtis 			/* inexact, stack popped */
68725c28e83SPiotr Jasiukajtis 			if (!ea) {
68825c28e83SPiotr Jasiukajtis 				info->op = fex_other;
68925c28e83SPiotr Jasiukajtis 				info->op1.type = info->op2.type = info->res.type = fex_nodata;
69025c28e83SPiotr Jasiukajtis 				info->flags = 0;
69125c28e83SPiotr Jasiukajtis 				return;
69225c28e83SPiotr Jasiukajtis 			}
69325c28e83SPiotr Jasiukajtis 			info->op1.type = fex_nodata;
69425c28e83SPiotr Jasiukajtis 			info->res.val.d = *(double *)ea;
69525c28e83SPiotr Jasiukajtis 			info->flags = FE_INEXACT;
69625c28e83SPiotr Jasiukajtis 			return;
69725c28e83SPiotr Jasiukajtis 		}
69825c28e83SPiotr Jasiukajtis 		info->op1.type = fex_ldouble;
69925c28e83SPiotr Jasiukajtis 		info->op1.val.q = fpreg(uap, 0);
70025c28e83SPiotr Jasiukajtis 		info->res.val.d = (double) info->op1.val.q;
70125c28e83SPiotr Jasiukajtis 		goto done;
70225c28e83SPiotr Jasiukajtis 
70325c28e83SPiotr Jasiukajtis 	case 0x710:
70425c28e83SPiotr Jasiukajtis 	case 0x718:
70525c28e83SPiotr Jasiukajtis 	case 0x750:
70625c28e83SPiotr Jasiukajtis 	case 0x758:
70725c28e83SPiotr Jasiukajtis 	case 0x790:
70825c28e83SPiotr Jasiukajtis 	case 0x798:
70925c28e83SPiotr Jasiukajtis 		info->res.type = fex_int;
71025c28e83SPiotr Jasiukajtis 		if (ex == FPE_FLTRES && (op & 8) != 0) {
71125c28e83SPiotr Jasiukajtis 			/* inexact, stack popped */
71225c28e83SPiotr Jasiukajtis 			if (!ea) {
71325c28e83SPiotr Jasiukajtis 				info->op = fex_other;
71425c28e83SPiotr Jasiukajtis 				info->op1.type = info->op2.type = info->res.type = fex_nodata;
71525c28e83SPiotr Jasiukajtis 				info->flags = 0;
71625c28e83SPiotr Jasiukajtis 				return;
71725c28e83SPiotr Jasiukajtis 			}
71825c28e83SPiotr Jasiukajtis 			info->op1.type = fex_nodata;
71925c28e83SPiotr Jasiukajtis 			info->res.val.i = *(short *)ea;
72025c28e83SPiotr Jasiukajtis 			info->flags = FE_INEXACT;
72125c28e83SPiotr Jasiukajtis 			return;
72225c28e83SPiotr Jasiukajtis 		}
72325c28e83SPiotr Jasiukajtis 		info->op1.type = fex_ldouble;
72425c28e83SPiotr Jasiukajtis 		info->op1.val.q = fpreg(uap, 0);
72525c28e83SPiotr Jasiukajtis 		info->res.val.i = (short) info->op1.val.q;
72625c28e83SPiotr Jasiukajtis 		goto done;
72725c28e83SPiotr Jasiukajtis 
72825c28e83SPiotr Jasiukajtis 	case 0x730:
72925c28e83SPiotr Jasiukajtis 	case 0x770:
73025c28e83SPiotr Jasiukajtis 	case 0x7b0:
73125c28e83SPiotr Jasiukajtis 		/* fbstp; don't bother */
73225c28e83SPiotr Jasiukajtis 		info->op = fex_other;
73325c28e83SPiotr Jasiukajtis 		info->op1.type = info->res.type = fex_nodata;
73425c28e83SPiotr Jasiukajtis 		info->flags = 0;
73525c28e83SPiotr Jasiukajtis 		return;
73625c28e83SPiotr Jasiukajtis 
73725c28e83SPiotr Jasiukajtis 	case 0x738:
73825c28e83SPiotr Jasiukajtis 	case 0x778:
73925c28e83SPiotr Jasiukajtis 	case 0x7b8:
74025c28e83SPiotr Jasiukajtis 		info->res.type = fex_llong;
74125c28e83SPiotr Jasiukajtis 		if (ex == FPE_FLTRES) {
74225c28e83SPiotr Jasiukajtis 			/* inexact, stack popped */
74325c28e83SPiotr Jasiukajtis 			if (!ea) {
74425c28e83SPiotr Jasiukajtis 				info->op = fex_other;
74525c28e83SPiotr Jasiukajtis 				info->op1.type = info->op2.type = info->res.type = fex_nodata;
74625c28e83SPiotr Jasiukajtis 				info->flags = 0;
74725c28e83SPiotr Jasiukajtis 				return;
74825c28e83SPiotr Jasiukajtis 			}
74925c28e83SPiotr Jasiukajtis 			info->op1.type = fex_nodata;
75025c28e83SPiotr Jasiukajtis 			info->res.val.l = *(long long *)ea;
75125c28e83SPiotr Jasiukajtis 			info->flags = FE_INEXACT;
75225c28e83SPiotr Jasiukajtis 			return;
75325c28e83SPiotr Jasiukajtis 		}
75425c28e83SPiotr Jasiukajtis 		info->op1.type = fex_ldouble;
75525c28e83SPiotr Jasiukajtis 		info->op1.val.q = fpreg(uap, 0);
75625c28e83SPiotr Jasiukajtis 		info->res.val.l = (long long) info->op1.val.q;
75725c28e83SPiotr Jasiukajtis 		goto done;
75825c28e83SPiotr Jasiukajtis 	}
75925c28e83SPiotr Jasiukajtis 
76025c28e83SPiotr Jasiukajtis 	/* all other ops (except compares) have destinations on the stack
76125c28e83SPiotr Jasiukajtis 	   so overflow, underflow, and inexact will stomp their operands */
76225c28e83SPiotr Jasiukajtis 	if (ex == FPE_FLTOVF || ex == FPE_FLTUND || ex == FPE_FLTRES) {
76325c28e83SPiotr Jasiukajtis 		/* find the trapped result */
76425c28e83SPiotr Jasiukajtis 		info->op1.type = info->op2.type = fex_nodata;
76525c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
76625c28e83SPiotr Jasiukajtis 		switch (op & 0x7f8) {
76725c28e83SPiotr Jasiukajtis 		case 0x1f0:
76825c28e83SPiotr Jasiukajtis 			/* fptan pushes 1.0 afterward, so result is in st(1) */
76925c28e83SPiotr Jasiukajtis 			info->res.val.q = ((op == 0x1f2)? fpreg(uap, 1) :
77025c28e83SPiotr Jasiukajtis 				fpreg(uap, 0));
77125c28e83SPiotr Jasiukajtis 			break;
77225c28e83SPiotr Jasiukajtis 
77325c28e83SPiotr Jasiukajtis 		case 0x4c0:
77425c28e83SPiotr Jasiukajtis 		case 0x4c8:
77525c28e83SPiotr Jasiukajtis 		case 0x4e0:
77625c28e83SPiotr Jasiukajtis 		case 0x4e8:
77725c28e83SPiotr Jasiukajtis 		case 0x4f0:
77825c28e83SPiotr Jasiukajtis 		case 0x4f8:
77925c28e83SPiotr Jasiukajtis 			info->res.val.q = fpreg(uap, op & 7);
78025c28e83SPiotr Jasiukajtis 			break;
78125c28e83SPiotr Jasiukajtis 
78225c28e83SPiotr Jasiukajtis 		case 0x6c0:
78325c28e83SPiotr Jasiukajtis 		case 0x6c8:
78425c28e83SPiotr Jasiukajtis 		case 0x6e0:
78525c28e83SPiotr Jasiukajtis 		case 0x6e8:
78625c28e83SPiotr Jasiukajtis 		case 0x6f0:
78725c28e83SPiotr Jasiukajtis 		case 0x6f8:
78825c28e83SPiotr Jasiukajtis 			/* stack was popped afterward */
78925c28e83SPiotr Jasiukajtis 			info->res.val.q = fpreg(uap, (op - 1) & 7);
79025c28e83SPiotr Jasiukajtis 			break;
79125c28e83SPiotr Jasiukajtis 
79225c28e83SPiotr Jasiukajtis 		default:
79325c28e83SPiotr Jasiukajtis 			info->res.val.q = fpreg(uap, 0);
79425c28e83SPiotr Jasiukajtis 		}
79525c28e83SPiotr Jasiukajtis 
79625c28e83SPiotr Jasiukajtis 		/* reconstruct default untrapped result */
79725c28e83SPiotr Jasiukajtis 		if (ex == FPE_FLTOVF) {
79825c28e83SPiotr Jasiukajtis 			/* generate an overflow with the sign of the result */
79925c28e83SPiotr Jasiukajtis 			x = two12288;
80025c28e83SPiotr Jasiukajtis 			*(4+(short*)&x) |= (*(4+(short*)&info->res.val.q) & 0x8000);
80125c28e83SPiotr Jasiukajtis 			info->res.val.q = x * two12288;
80225c28e83SPiotr Jasiukajtis 			info->flags = FE_OVERFLOW | FE_INEXACT;
80325c28e83SPiotr Jasiukajtis 			__fenv_getcwsw(&cwsw);
80425c28e83SPiotr Jasiukajtis 			cwsw &= ~FE_ALL_EXCEPT;
80525c28e83SPiotr Jasiukajtis 			__fenv_setcwsw(&cwsw);
80625c28e83SPiotr Jasiukajtis 		}
80725c28e83SPiotr Jasiukajtis 		else if (ex == FPE_FLTUND) {
80825c28e83SPiotr Jasiukajtis 			/* undo the scaling; we can't distinguish a chopped result
80925c28e83SPiotr Jasiukajtis 			   from an exact one without futzing around to trap all in-
81025c28e83SPiotr Jasiukajtis 			   exact exceptions so as to keep the flag clear, so we just
81125c28e83SPiotr Jasiukajtis 			   punt */
81225c28e83SPiotr Jasiukajtis 			if (sw & 0x200) /* result was rounded up */
81325c28e83SPiotr Jasiukajtis 				info->res.val.q = (info->res.val.q * twom12288) * twom12288mulp;
81425c28e83SPiotr Jasiukajtis 			else
81525c28e83SPiotr Jasiukajtis 				info->res.val.q = (info->res.val.q * twom12288) * twom12288;
81625c28e83SPiotr Jasiukajtis 			__fenv_getcwsw(&cwsw);
81725c28e83SPiotr Jasiukajtis 			info->flags = (cwsw & FE_INEXACT) | FE_UNDERFLOW;
81825c28e83SPiotr Jasiukajtis 			cwsw &= ~FE_ALL_EXCEPT;
81925c28e83SPiotr Jasiukajtis 			__fenv_setcwsw(&cwsw);
82025c28e83SPiotr Jasiukajtis 		}
82125c28e83SPiotr Jasiukajtis 		else
82225c28e83SPiotr Jasiukajtis 			info->flags = FE_INEXACT;
82325c28e83SPiotr Jasiukajtis 
82425c28e83SPiotr Jasiukajtis 		/* determine the operation code */
82525c28e83SPiotr Jasiukajtis 		switch (op) {
82625c28e83SPiotr Jasiukajtis 		case 0x1f0: /* f2xm1 */
82725c28e83SPiotr Jasiukajtis 		case 0x1f1: /* fyl2x */
82825c28e83SPiotr Jasiukajtis 		case 0x1f2: /* fptan */
82925c28e83SPiotr Jasiukajtis 		case 0x1f3: /* fpatan */
83025c28e83SPiotr Jasiukajtis 		case 0x1f5: /* fprem1 */
83125c28e83SPiotr Jasiukajtis 		case 0x1f8: /* fprem */
83225c28e83SPiotr Jasiukajtis 		case 0x1f9: /* fyl2xp1 */
83325c28e83SPiotr Jasiukajtis 		case 0x1fb: /* fsincos */
83425c28e83SPiotr Jasiukajtis 		case 0x1fc: /* frndint */
83525c28e83SPiotr Jasiukajtis 		case 0x1fd: /* fscale */
83625c28e83SPiotr Jasiukajtis 		case 0x1fe: /* fsin */
83725c28e83SPiotr Jasiukajtis 		case 0x1ff: /* fcos */
83825c28e83SPiotr Jasiukajtis 			info->op = fex_other;
83925c28e83SPiotr Jasiukajtis 			return;
84025c28e83SPiotr Jasiukajtis 
84125c28e83SPiotr Jasiukajtis 		case 0x1fa: /* fsqrt */
84225c28e83SPiotr Jasiukajtis 			info->op = fex_sqrt;
84325c28e83SPiotr Jasiukajtis 			return;
84425c28e83SPiotr Jasiukajtis 		}
84525c28e83SPiotr Jasiukajtis 
84625c28e83SPiotr Jasiukajtis 		info->op = fex_other;
84725c28e83SPiotr Jasiukajtis 		switch (op & 0x7c0) {
84825c28e83SPiotr Jasiukajtis 		case 0x000:
84925c28e83SPiotr Jasiukajtis 		case 0x040:
85025c28e83SPiotr Jasiukajtis 		case 0x080:
85125c28e83SPiotr Jasiukajtis 		case 0x0c0:
85225c28e83SPiotr Jasiukajtis 		case 0x200:
85325c28e83SPiotr Jasiukajtis 		case 0x240:
85425c28e83SPiotr Jasiukajtis 		case 0x280:
85525c28e83SPiotr Jasiukajtis 		case 0x400:
85625c28e83SPiotr Jasiukajtis 		case 0x440:
85725c28e83SPiotr Jasiukajtis 		case 0x480:
85825c28e83SPiotr Jasiukajtis 		case 0x4c0:
85925c28e83SPiotr Jasiukajtis 		case 0x600:
86025c28e83SPiotr Jasiukajtis 		case 0x640:
86125c28e83SPiotr Jasiukajtis 		case 0x680:
86225c28e83SPiotr Jasiukajtis 		case 0x6c0:
86325c28e83SPiotr Jasiukajtis 			switch (op & 0x38) {
86425c28e83SPiotr Jasiukajtis 			case 0x00:
86525c28e83SPiotr Jasiukajtis 				info->op = fex_add;
86625c28e83SPiotr Jasiukajtis 				break;
86725c28e83SPiotr Jasiukajtis 
86825c28e83SPiotr Jasiukajtis 			case 0x08:
86925c28e83SPiotr Jasiukajtis 				info->op = fex_mul;
87025c28e83SPiotr Jasiukajtis 				break;
87125c28e83SPiotr Jasiukajtis 
87225c28e83SPiotr Jasiukajtis 			case 0x20:
87325c28e83SPiotr Jasiukajtis 			case 0x28:
87425c28e83SPiotr Jasiukajtis 				info->op = fex_sub;
87525c28e83SPiotr Jasiukajtis 				break;
87625c28e83SPiotr Jasiukajtis 
87725c28e83SPiotr Jasiukajtis 			case 0x30:
87825c28e83SPiotr Jasiukajtis 			case 0x38:
87925c28e83SPiotr Jasiukajtis 				info->op = fex_div;
88025c28e83SPiotr Jasiukajtis 				break;
88125c28e83SPiotr Jasiukajtis 			}
88225c28e83SPiotr Jasiukajtis 		}
88325c28e83SPiotr Jasiukajtis 		return;
88425c28e83SPiotr Jasiukajtis 	}
88525c28e83SPiotr Jasiukajtis 
88625c28e83SPiotr Jasiukajtis 	/* for other exceptions, the operands are preserved, so we can
88725c28e83SPiotr Jasiukajtis 	   just emulate the operation with traps disabled */
88825c28e83SPiotr Jasiukajtis 
88925c28e83SPiotr Jasiukajtis 	/* one operand is always in st */
89025c28e83SPiotr Jasiukajtis 	info->op1.type = fex_ldouble;
89125c28e83SPiotr Jasiukajtis 	info->op1.val.q = fpreg(uap, 0);
89225c28e83SPiotr Jasiukajtis 
89325c28e83SPiotr Jasiukajtis 	/* oddball instructions */
89425c28e83SPiotr Jasiukajtis 	info->op = fex_other;
89525c28e83SPiotr Jasiukajtis 	switch (op) {
89625c28e83SPiotr Jasiukajtis 	case 0x1e4: /* ftst */
89725c28e83SPiotr Jasiukajtis 		info->op = fex_cmp;
89825c28e83SPiotr Jasiukajtis 		info->op2.type = fex_ldouble;
89925c28e83SPiotr Jasiukajtis 		info->op2.val.q = 0.0l;
90025c28e83SPiotr Jasiukajtis 		info->res.type = fex_nodata;
90125c28e83SPiotr Jasiukajtis 		c = (info->op1.val.q < info->op2.val.q);
90225c28e83SPiotr Jasiukajtis 		goto done;
90325c28e83SPiotr Jasiukajtis 
90425c28e83SPiotr Jasiukajtis 	case 0x1f0: /* f2xm1 */
90525c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
90625c28e83SPiotr Jasiukajtis 		info->res.val.q = f2xm1(info->op1.val.q);
90725c28e83SPiotr Jasiukajtis 		goto done;
90825c28e83SPiotr Jasiukajtis 
90925c28e83SPiotr Jasiukajtis 	case 0x1f1: /* fyl2x */
91025c28e83SPiotr Jasiukajtis 		info->op2.type = fex_ldouble;
91125c28e83SPiotr Jasiukajtis 		info->op2.val.q = fpreg(uap, 1);
91225c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
91325c28e83SPiotr Jasiukajtis 		info->res.val.q = fyl2x(info->op1.val.q, info->op2.val.q);
91425c28e83SPiotr Jasiukajtis 		goto done;
91525c28e83SPiotr Jasiukajtis 
91625c28e83SPiotr Jasiukajtis 	case 0x1f2: /* fptan */
91725c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
91825c28e83SPiotr Jasiukajtis 		info->res.val.q = fptan(info->op1.val.q);
91925c28e83SPiotr Jasiukajtis 		goto done;
92025c28e83SPiotr Jasiukajtis 
92125c28e83SPiotr Jasiukajtis 	case 0x1f3: /* fpatan */
92225c28e83SPiotr Jasiukajtis 		info->op2.type = fex_ldouble;
92325c28e83SPiotr Jasiukajtis 		info->op2.val.q = fpreg(uap, 1);
92425c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
92525c28e83SPiotr Jasiukajtis 		info->res.val.q = fpatan(info->op1.val.q, info->op2.val.q);
92625c28e83SPiotr Jasiukajtis 		goto done;
92725c28e83SPiotr Jasiukajtis 
92825c28e83SPiotr Jasiukajtis 	case 0x1f4: /* fxtract */
92925c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
93025c28e83SPiotr Jasiukajtis 		info->res.val.q = fxtract(info->op1.val.q);
93125c28e83SPiotr Jasiukajtis 		goto done;
93225c28e83SPiotr Jasiukajtis 
93325c28e83SPiotr Jasiukajtis 	case 0x1f5: /* fprem1 */
93425c28e83SPiotr Jasiukajtis 		info->op2.type = fex_ldouble;
93525c28e83SPiotr Jasiukajtis 		info->op2.val.q = fpreg(uap, 1);
93625c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
93725c28e83SPiotr Jasiukajtis 		info->res.val.q = fprem1(info->op1.val.q, info->op2.val.q);
93825c28e83SPiotr Jasiukajtis 		goto done;
93925c28e83SPiotr Jasiukajtis 
94025c28e83SPiotr Jasiukajtis 	case 0x1f8: /* fprem */
94125c28e83SPiotr Jasiukajtis 		info->op2.type = fex_ldouble;
94225c28e83SPiotr Jasiukajtis 		info->op2.val.q = fpreg(uap, 1);
94325c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
94425c28e83SPiotr Jasiukajtis 		info->res.val.q = fprem(info->op1.val.q, info->op2.val.q);
94525c28e83SPiotr Jasiukajtis 		goto done;
94625c28e83SPiotr Jasiukajtis 
94725c28e83SPiotr Jasiukajtis 	case 0x1f9: /* fyl2xp1 */
94825c28e83SPiotr Jasiukajtis 		info->op2.type = fex_ldouble;
94925c28e83SPiotr Jasiukajtis 		info->op2.val.q = fpreg(uap, 1);
95025c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
95125c28e83SPiotr Jasiukajtis 		info->res.val.q = fyl2xp1(info->op1.val.q, info->op2.val.q);
95225c28e83SPiotr Jasiukajtis 		goto done;
95325c28e83SPiotr Jasiukajtis 
95425c28e83SPiotr Jasiukajtis 	case 0x1fa: /* fsqrt */
95525c28e83SPiotr Jasiukajtis 		info->op = fex_sqrt;
95625c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
95725c28e83SPiotr Jasiukajtis 		info->res.val.q = fsqrt(info->op1.val.q);
95825c28e83SPiotr Jasiukajtis 		goto done;
95925c28e83SPiotr Jasiukajtis 
96025c28e83SPiotr Jasiukajtis 	case 0x1fb: /* fsincos */
96125c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
96225c28e83SPiotr Jasiukajtis 		info->res.val.q = fsincos(info->op1.val.q);
96325c28e83SPiotr Jasiukajtis 		goto done;
96425c28e83SPiotr Jasiukajtis 
96525c28e83SPiotr Jasiukajtis 	case 0x1fc: /* frndint */
96625c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
96725c28e83SPiotr Jasiukajtis 		info->res.val.q = frndint(info->op1.val.q);
96825c28e83SPiotr Jasiukajtis 		goto done;
96925c28e83SPiotr Jasiukajtis 
97025c28e83SPiotr Jasiukajtis 	case 0x1fd: /* fscale */
97125c28e83SPiotr Jasiukajtis 		info->op2.type = fex_ldouble;
97225c28e83SPiotr Jasiukajtis 		info->op2.val.q = fpreg(uap, 1);
97325c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
97425c28e83SPiotr Jasiukajtis 		info->res.val.q = fscale(info->op1.val.q, info->op2.val.q);
97525c28e83SPiotr Jasiukajtis 		goto done;
97625c28e83SPiotr Jasiukajtis 
97725c28e83SPiotr Jasiukajtis 	case 0x1fe: /* fsin */
97825c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
97925c28e83SPiotr Jasiukajtis 		info->res.val.q = fsin(info->op1.val.q);
98025c28e83SPiotr Jasiukajtis 		goto done;
98125c28e83SPiotr Jasiukajtis 
98225c28e83SPiotr Jasiukajtis 	case 0x1ff: /* fcos */
98325c28e83SPiotr Jasiukajtis 		info->res.type = fex_ldouble;
98425c28e83SPiotr Jasiukajtis 		info->res.val.q = fcos(info->op1.val.q);
98525c28e83SPiotr Jasiukajtis 		goto done;
98625c28e83SPiotr Jasiukajtis 
98725c28e83SPiotr Jasiukajtis 	case 0x2e9: /* fucompp */
98825c28e83SPiotr Jasiukajtis 		info->op = fex_cmp;
98925c28e83SPiotr Jasiukajtis 		info->op2.type = fex_ldouble;
99025c28e83SPiotr Jasiukajtis 		info->op2.val.q = fpreg(uap, 1);
99125c28e83SPiotr Jasiukajtis 		info->res.type = fex_nodata;
99225c28e83SPiotr Jasiukajtis 		c = (info->op1.val.q == info->op2.val.q);
99325c28e83SPiotr Jasiukajtis 		goto done;
99425c28e83SPiotr Jasiukajtis 	}
99525c28e83SPiotr Jasiukajtis 
99625c28e83SPiotr Jasiukajtis 	/* fucom[p], fcomi[p], fucomi[p] */
99725c28e83SPiotr Jasiukajtis 	switch (op & 0x7f8) {
99825c28e83SPiotr Jasiukajtis 	case 0x3e8:
99925c28e83SPiotr Jasiukajtis 	case 0x5e0:
100025c28e83SPiotr Jasiukajtis 	case 0x5e8:
100125c28e83SPiotr Jasiukajtis 	case 0x7e8: /* unordered compares */
100225c28e83SPiotr Jasiukajtis 		info->op = fex_cmp;
100325c28e83SPiotr Jasiukajtis 		info->op2.type = fex_ldouble;
100425c28e83SPiotr Jasiukajtis 		info->op2.val.q = fpreg(uap, op & 7);
100525c28e83SPiotr Jasiukajtis 		info->res.type = fex_nodata;
100625c28e83SPiotr Jasiukajtis 		c = (info->op1.val.q == info->op2.val.q);
100725c28e83SPiotr Jasiukajtis 		goto done;
100825c28e83SPiotr Jasiukajtis 
100925c28e83SPiotr Jasiukajtis 	case 0x3f0:
101025c28e83SPiotr Jasiukajtis 	case 0x7f0: /* ordered compares */
101125c28e83SPiotr Jasiukajtis 		info->op = fex_cmp;
101225c28e83SPiotr Jasiukajtis 		info->op2.type = fex_ldouble;
101325c28e83SPiotr Jasiukajtis 		info->op2.val.q = fpreg(uap, op & 7);
101425c28e83SPiotr Jasiukajtis 		info->res.type = fex_nodata;
101525c28e83SPiotr Jasiukajtis 		c = (info->op1.val.q < info->op2.val.q);
101625c28e83SPiotr Jasiukajtis 		goto done;
101725c28e83SPiotr Jasiukajtis 	}
101825c28e83SPiotr Jasiukajtis 
101925c28e83SPiotr Jasiukajtis 	/* all other instructions come in groups of the form
102025c28e83SPiotr Jasiukajtis 	   fadd, fmul, fcom, fcomp, fsub, fsubr, fdiv, fdivr */
102125c28e83SPiotr Jasiukajtis 
102225c28e83SPiotr Jasiukajtis 	/* get the second operand */
102325c28e83SPiotr Jasiukajtis 	switch (op & 0x7c0) {
102425c28e83SPiotr Jasiukajtis 	case 0x000:
102525c28e83SPiotr Jasiukajtis 	case 0x040:
102625c28e83SPiotr Jasiukajtis 	case 0x080:
102725c28e83SPiotr Jasiukajtis 		if (!ea) {
102825c28e83SPiotr Jasiukajtis 			info->op = fex_other;
102925c28e83SPiotr Jasiukajtis 			info->op1.type = info->op2.type = info->res.type = fex_nodata;
103025c28e83SPiotr Jasiukajtis 			info->flags = 0;
103125c28e83SPiotr Jasiukajtis 			return;
103225c28e83SPiotr Jasiukajtis 		}
103325c28e83SPiotr Jasiukajtis 		info->op2.type = fex_float;
103425c28e83SPiotr Jasiukajtis 		info->op2.val.f = *(float *)ea;
103525c28e83SPiotr Jasiukajtis 		op2v = (long double) info->op2.val.f;
103625c28e83SPiotr Jasiukajtis 		break;
103725c28e83SPiotr Jasiukajtis 
103825c28e83SPiotr Jasiukajtis 	case 0x0c0:
103925c28e83SPiotr Jasiukajtis 		info->op2.type = fex_ldouble;
104025c28e83SPiotr Jasiukajtis 		op2v = info->op2.val.q = fpreg(uap, op & 7);
104125c28e83SPiotr Jasiukajtis 		break;
104225c28e83SPiotr Jasiukajtis 
104325c28e83SPiotr Jasiukajtis 	case 0x200:
104425c28e83SPiotr Jasiukajtis 	case 0x240:
104525c28e83SPiotr Jasiukajtis 	case 0x280:
104625c28e83SPiotr Jasiukajtis 		if (!ea) {
104725c28e83SPiotr Jasiukajtis 			info->op = fex_other;
104825c28e83SPiotr Jasiukajtis 			info->op1.type = info->op2.type = info->res.type = fex_nodata;
104925c28e83SPiotr Jasiukajtis 			info->flags = 0;
105025c28e83SPiotr Jasiukajtis 			return;
105125c28e83SPiotr Jasiukajtis 		}
105225c28e83SPiotr Jasiukajtis 		info->op2.type = fex_int;
105325c28e83SPiotr Jasiukajtis 		info->op2.val.i = *(int *)ea;
105425c28e83SPiotr Jasiukajtis 		op2v = (long double) info->op2.val.i;
105525c28e83SPiotr Jasiukajtis 		break;
105625c28e83SPiotr Jasiukajtis 
105725c28e83SPiotr Jasiukajtis 	case 0x400:
105825c28e83SPiotr Jasiukajtis 	case 0x440:
105925c28e83SPiotr Jasiukajtis 	case 0x480:
106025c28e83SPiotr Jasiukajtis 		if (!ea) {
106125c28e83SPiotr Jasiukajtis 			info->op = fex_other;
106225c28e83SPiotr Jasiukajtis 			info->op1.type = info->op2.type = info->res.type = fex_nodata;
106325c28e83SPiotr Jasiukajtis 			info->flags = 0;
106425c28e83SPiotr Jasiukajtis 			return;
106525c28e83SPiotr Jasiukajtis 		}
106625c28e83SPiotr Jasiukajtis 		info->op2.type = fex_double;
106725c28e83SPiotr Jasiukajtis 		info->op2.val.d = *(double *)ea;
106825c28e83SPiotr Jasiukajtis 		op2v = (long double) info->op2.val.d;
106925c28e83SPiotr Jasiukajtis 		break;
107025c28e83SPiotr Jasiukajtis 
107125c28e83SPiotr Jasiukajtis 	case 0x4c0:
107225c28e83SPiotr Jasiukajtis 	case 0x6c0:
107325c28e83SPiotr Jasiukajtis 		info->op2.type = fex_ldouble;
107425c28e83SPiotr Jasiukajtis 		info->op2.val.q = fpreg(uap, op & 7);
107525c28e83SPiotr Jasiukajtis 		t = info->op1;
107625c28e83SPiotr Jasiukajtis 		info->op1 = info->op2;
107725c28e83SPiotr Jasiukajtis 		info->op2 = t;
107825c28e83SPiotr Jasiukajtis 		op2v = info->op2.val.q;
107925c28e83SPiotr Jasiukajtis 		break;
108025c28e83SPiotr Jasiukajtis 
108125c28e83SPiotr Jasiukajtis 	case 0x600:
108225c28e83SPiotr Jasiukajtis 	case 0x640:
108325c28e83SPiotr Jasiukajtis 	case 0x680:
108425c28e83SPiotr Jasiukajtis 		if (!ea) {
108525c28e83SPiotr Jasiukajtis 			info->op = fex_other;
108625c28e83SPiotr Jasiukajtis 			info->op1.type = info->op2.type = info->res.type = fex_nodata;
108725c28e83SPiotr Jasiukajtis 			info->flags = 0;
108825c28e83SPiotr Jasiukajtis 			return;
108925c28e83SPiotr Jasiukajtis 		}
109025c28e83SPiotr Jasiukajtis 		info->op2.type = fex_int;
109125c28e83SPiotr Jasiukajtis 		info->op2.val.i = *(short *)ea;
109225c28e83SPiotr Jasiukajtis 		op2v = (long double) info->op2.val.i;
109325c28e83SPiotr Jasiukajtis 		break;
109425c28e83SPiotr Jasiukajtis 
109525c28e83SPiotr Jasiukajtis 	default:
109625c28e83SPiotr Jasiukajtis 		info->op = fex_other;
109725c28e83SPiotr Jasiukajtis 		info->op1.type = info->op2.type = info->res.type = fex_nodata;
109825c28e83SPiotr Jasiukajtis 		info->flags = 0;
109925c28e83SPiotr Jasiukajtis 		return;
110025c28e83SPiotr Jasiukajtis 	}
110125c28e83SPiotr Jasiukajtis 
110225c28e83SPiotr Jasiukajtis 	/* distinguish different operations in the group */
110325c28e83SPiotr Jasiukajtis 	info->res.type = fex_ldouble;
110425c28e83SPiotr Jasiukajtis 	switch (op & 0x38) {
110525c28e83SPiotr Jasiukajtis 	case 0x00:
110625c28e83SPiotr Jasiukajtis 		info->op = fex_add;
110725c28e83SPiotr Jasiukajtis 		info->res.val.q = info->op1.val.q + op2v;
110825c28e83SPiotr Jasiukajtis 		break;
110925c28e83SPiotr Jasiukajtis 
111025c28e83SPiotr Jasiukajtis 	case 0x08:
111125c28e83SPiotr Jasiukajtis 		info->op = fex_mul;
111225c28e83SPiotr Jasiukajtis 		info->res.val.q = info->op1.val.q * op2v;
111325c28e83SPiotr Jasiukajtis 		break;
111425c28e83SPiotr Jasiukajtis 
111525c28e83SPiotr Jasiukajtis 	case 0x10:
111625c28e83SPiotr Jasiukajtis 	case 0x18:
111725c28e83SPiotr Jasiukajtis 		info->op = fex_cmp;
111825c28e83SPiotr Jasiukajtis 		info->res.type = fex_nodata;
111925c28e83SPiotr Jasiukajtis 		c = (info->op1.val.q < op2v);
112025c28e83SPiotr Jasiukajtis 		break;
112125c28e83SPiotr Jasiukajtis 
112225c28e83SPiotr Jasiukajtis 	case 0x20:
112325c28e83SPiotr Jasiukajtis 		info->op = fex_sub;
112425c28e83SPiotr Jasiukajtis 		info->res.val.q = info->op1.val.q - op2v;
112525c28e83SPiotr Jasiukajtis 		break;
112625c28e83SPiotr Jasiukajtis 
112725c28e83SPiotr Jasiukajtis 	case 0x28:
112825c28e83SPiotr Jasiukajtis 		info->op = fex_sub;
112925c28e83SPiotr Jasiukajtis 		info->res.val.q = op2v - info->op1.val.q;
113025c28e83SPiotr Jasiukajtis 		t = info->op1;
113125c28e83SPiotr Jasiukajtis 		info->op1 = info->op2;
113225c28e83SPiotr Jasiukajtis 		info->op2 = t;
113325c28e83SPiotr Jasiukajtis 		break;
113425c28e83SPiotr Jasiukajtis 
113525c28e83SPiotr Jasiukajtis 	case 0x30:
113625c28e83SPiotr Jasiukajtis 		info->op = fex_div;
113725c28e83SPiotr Jasiukajtis 		info->res.val.q = info->op1.val.q / op2v;
113825c28e83SPiotr Jasiukajtis 		break;
113925c28e83SPiotr Jasiukajtis 
114025c28e83SPiotr Jasiukajtis 	case 0x38:
114125c28e83SPiotr Jasiukajtis 		info->op = fex_div;
114225c28e83SPiotr Jasiukajtis 		info->res.val.q = op2v / info->op1.val.q;
114325c28e83SPiotr Jasiukajtis 		t = info->op1;
114425c28e83SPiotr Jasiukajtis 		info->op1 = info->op2;
114525c28e83SPiotr Jasiukajtis 		info->op2 = t;
114625c28e83SPiotr Jasiukajtis 		break;
114725c28e83SPiotr Jasiukajtis 
114825c28e83SPiotr Jasiukajtis 	default:
114925c28e83SPiotr Jasiukajtis 		info->op = fex_other;
115025c28e83SPiotr Jasiukajtis 		info->op1.type = info->op2.type = info->res.type = fex_nodata;
115125c28e83SPiotr Jasiukajtis 		info->flags = 0;
115225c28e83SPiotr Jasiukajtis 		return;
115325c28e83SPiotr Jasiukajtis 	}
115425c28e83SPiotr Jasiukajtis 
115525c28e83SPiotr Jasiukajtis done:
115625c28e83SPiotr Jasiukajtis 	__fenv_getcwsw(&cwsw);
115725c28e83SPiotr Jasiukajtis 	info->flags = cwsw & FE_ALL_EXCEPT;
115825c28e83SPiotr Jasiukajtis 	cwsw &= ~FE_ALL_EXCEPT;
115925c28e83SPiotr Jasiukajtis 	__fenv_setcwsw(&cwsw);
116025c28e83SPiotr Jasiukajtis }
116125c28e83SPiotr Jasiukajtis 
116225c28e83SPiotr Jasiukajtis /* pop the saved stack */
pop(ucontext_t * uap)116325c28e83SPiotr Jasiukajtis static void pop(ucontext_t *uap)
116425c28e83SPiotr Jasiukajtis {
116525c28e83SPiotr Jasiukajtis 	unsigned top;
116625c28e83SPiotr Jasiukajtis 
116725c28e83SPiotr Jasiukajtis 	fpreg(uap, 0) = fpreg(uap, 1);
116825c28e83SPiotr Jasiukajtis 	fpreg(uap, 1) = fpreg(uap, 2);
116925c28e83SPiotr Jasiukajtis 	fpreg(uap, 2) = fpreg(uap, 3);
117025c28e83SPiotr Jasiukajtis 	fpreg(uap, 3) = fpreg(uap, 4);
117125c28e83SPiotr Jasiukajtis 	fpreg(uap, 4) = fpreg(uap, 5);
117225c28e83SPiotr Jasiukajtis 	fpreg(uap, 5) = fpreg(uap, 6);
117325c28e83SPiotr Jasiukajtis 	fpreg(uap, 6) = fpreg(uap, 7);
117425c28e83SPiotr Jasiukajtis #if defined(__amd64)
117525c28e83SPiotr Jasiukajtis 	top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw >> 10)
117625c28e83SPiotr Jasiukajtis 		& 0xe;
117725c28e83SPiotr Jasiukajtis 	uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fctw |= (3 << top);
117825c28e83SPiotr Jasiukajtis 	top = (top + 2) & 0xe;
117925c28e83SPiotr Jasiukajtis 	uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw =
118025c28e83SPiotr Jasiukajtis 		(uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw & ~0x3800)
118125c28e83SPiotr Jasiukajtis 		| (top << 10);
118225c28e83SPiotr Jasiukajtis #else
118325c28e83SPiotr Jasiukajtis 	top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] >> 10)
118425c28e83SPiotr Jasiukajtis 		& 0xe;
118525c28e83SPiotr Jasiukajtis 	uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[TW] |= (3 << top);
118625c28e83SPiotr Jasiukajtis 	top = (top + 2) & 0xe;
118725c28e83SPiotr Jasiukajtis 	uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] =
118825c28e83SPiotr Jasiukajtis 		(uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] & ~0x3800)
118925c28e83SPiotr Jasiukajtis 		| (top << 10);
119025c28e83SPiotr Jasiukajtis #endif
119125c28e83SPiotr Jasiukajtis }
119225c28e83SPiotr Jasiukajtis 
119325c28e83SPiotr Jasiukajtis /* push x onto the saved stack */
push(long double x,ucontext_t * uap)119425c28e83SPiotr Jasiukajtis static void push(long double x, ucontext_t *uap)
119525c28e83SPiotr Jasiukajtis {
119625c28e83SPiotr Jasiukajtis 	unsigned top;
119725c28e83SPiotr Jasiukajtis 
119825c28e83SPiotr Jasiukajtis 	fpreg(uap, 7) = fpreg(uap, 6);
119925c28e83SPiotr Jasiukajtis 	fpreg(uap, 6) = fpreg(uap, 5);
120025c28e83SPiotr Jasiukajtis 	fpreg(uap, 5) = fpreg(uap, 4);
120125c28e83SPiotr Jasiukajtis 	fpreg(uap, 4) = fpreg(uap, 3);
120225c28e83SPiotr Jasiukajtis 	fpreg(uap, 3) = fpreg(uap, 2);
120325c28e83SPiotr Jasiukajtis 	fpreg(uap, 2) = fpreg(uap, 1);
120425c28e83SPiotr Jasiukajtis 	fpreg(uap, 1) = fpreg(uap, 0);
120525c28e83SPiotr Jasiukajtis 	fpreg(uap, 0) = x;
120625c28e83SPiotr Jasiukajtis #if defined(__amd64)
120725c28e83SPiotr Jasiukajtis 	top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw >> 10)
120825c28e83SPiotr Jasiukajtis 		& 0xe;
120925c28e83SPiotr Jasiukajtis 	top = (top - 2) & 0xe;
121025c28e83SPiotr Jasiukajtis 	uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fctw &= ~(3 << top);
121125c28e83SPiotr Jasiukajtis 	uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw =
121225c28e83SPiotr Jasiukajtis 		(uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw & ~0x3800)
121325c28e83SPiotr Jasiukajtis 		| (top << 10);
121425c28e83SPiotr Jasiukajtis #else
121525c28e83SPiotr Jasiukajtis 	top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] >> 10)
121625c28e83SPiotr Jasiukajtis 		& 0xe;
121725c28e83SPiotr Jasiukajtis 	top = (top - 2) & 0xe;
121825c28e83SPiotr Jasiukajtis 	uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[TW] &= ~(3 << top);
121925c28e83SPiotr Jasiukajtis 	uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] =
122025c28e83SPiotr Jasiukajtis 		(uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] & ~0x3800)
122125c28e83SPiotr Jasiukajtis 		| (top << 10);
122225c28e83SPiotr Jasiukajtis #endif
122325c28e83SPiotr Jasiukajtis }
122425c28e83SPiotr Jasiukajtis 
122525c28e83SPiotr Jasiukajtis /* scale factors for exponent wrapping */
122625c28e83SPiotr Jasiukajtis static const float
122725c28e83SPiotr Jasiukajtis 	fun = 7.922816251e+28f,	/* 2^96 */
122825c28e83SPiotr Jasiukajtis 	fov = 1.262177448e-29f;	/* 2^-96 */
122925c28e83SPiotr Jasiukajtis static const double
123025c28e83SPiotr Jasiukajtis 	dun = 1.552518092300708935e+231,	/* 2^768 */
123125c28e83SPiotr Jasiukajtis 	dov = 6.441148769597133308e-232;	/* 2^-768 */
123225c28e83SPiotr Jasiukajtis 
123325c28e83SPiotr Jasiukajtis /*
123425c28e83SPiotr Jasiukajtis *  Store the specified result; if no result is given but the exception
123525c28e83SPiotr Jasiukajtis *  is underflow or overflow, use the default trapped result
123625c28e83SPiotr Jasiukajtis */
123725c28e83SPiotr Jasiukajtis void
__fex_st_result(siginfo_t * sip,ucontext_t * uap,fex_info_t * info)123825c28e83SPiotr Jasiukajtis __fex_st_result(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
123925c28e83SPiotr Jasiukajtis {
124025c28e83SPiotr Jasiukajtis 	fex_numeric_t	r;
124125c28e83SPiotr Jasiukajtis 	unsigned long		ex, op, ea, stack;
124225c28e83SPiotr Jasiukajtis 
124325c28e83SPiotr Jasiukajtis 	/* get the exception type, opcode, and data address */
124425c28e83SPiotr Jasiukajtis 	ex = sip->si_code;
124525c28e83SPiotr Jasiukajtis #if defined(__amd64)
124625c28e83SPiotr Jasiukajtis 	op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
124725c28e83SPiotr Jasiukajtis 	ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp; /*???*/
124825c28e83SPiotr Jasiukajtis #else
124925c28e83SPiotr Jasiukajtis 	op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
125025c28e83SPiotr Jasiukajtis 	ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
125125c28e83SPiotr Jasiukajtis #endif
125225c28e83SPiotr Jasiukajtis 
125325c28e83SPiotr Jasiukajtis 	/* if the instruction is a compare, set the condition codes
125425c28e83SPiotr Jasiukajtis 	   to unordered and update the stack */
125525c28e83SPiotr Jasiukajtis 	switch (op & 0x7f8) {
125625c28e83SPiotr Jasiukajtis 	case 0x010:
125725c28e83SPiotr Jasiukajtis 	case 0x050:
125825c28e83SPiotr Jasiukajtis 	case 0x090:
125925c28e83SPiotr Jasiukajtis 	case 0x0d0:
126025c28e83SPiotr Jasiukajtis 	case 0x210:
126125c28e83SPiotr Jasiukajtis 	case 0x250:
126225c28e83SPiotr Jasiukajtis 	case 0x290:
126325c28e83SPiotr Jasiukajtis 	case 0x410:
126425c28e83SPiotr Jasiukajtis 	case 0x450:
126525c28e83SPiotr Jasiukajtis 	case 0x490:
126625c28e83SPiotr Jasiukajtis 	case 0x4d0:
126725c28e83SPiotr Jasiukajtis 	case 0x5e0:
126825c28e83SPiotr Jasiukajtis 	case 0x610:
126925c28e83SPiotr Jasiukajtis 	case 0x650:
127025c28e83SPiotr Jasiukajtis 	case 0x690:
127125c28e83SPiotr Jasiukajtis 		/* f[u]com */
127225c28e83SPiotr Jasiukajtis #if defined(__amd64)
127325c28e83SPiotr Jasiukajtis 		uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
127425c28e83SPiotr Jasiukajtis #else
127525c28e83SPiotr Jasiukajtis 		uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 0x4500;
127625c28e83SPiotr Jasiukajtis #endif
127725c28e83SPiotr Jasiukajtis 		return;
127825c28e83SPiotr Jasiukajtis 
127925c28e83SPiotr Jasiukajtis 	case 0x018:
128025c28e83SPiotr Jasiukajtis 	case 0x058:
128125c28e83SPiotr Jasiukajtis 	case 0x098:
128225c28e83SPiotr Jasiukajtis 	case 0x0d8:
128325c28e83SPiotr Jasiukajtis 	case 0x218:
128425c28e83SPiotr Jasiukajtis 	case 0x258:
128525c28e83SPiotr Jasiukajtis 	case 0x298:
128625c28e83SPiotr Jasiukajtis 	case 0x418:
128725c28e83SPiotr Jasiukajtis 	case 0x458:
128825c28e83SPiotr Jasiukajtis 	case 0x498:
128925c28e83SPiotr Jasiukajtis 	case 0x4d8:
129025c28e83SPiotr Jasiukajtis 	case 0x5e8:
129125c28e83SPiotr Jasiukajtis 	case 0x618:
129225c28e83SPiotr Jasiukajtis 	case 0x658:
129325c28e83SPiotr Jasiukajtis 	case 0x698:
129425c28e83SPiotr Jasiukajtis 	case 0x6d0:
129525c28e83SPiotr Jasiukajtis 		/* f[u]comp */
129625c28e83SPiotr Jasiukajtis #if defined(__amd64)
129725c28e83SPiotr Jasiukajtis 		uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
129825c28e83SPiotr Jasiukajtis #else
129925c28e83SPiotr Jasiukajtis 		uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 0x4500;
130025c28e83SPiotr Jasiukajtis #endif
130125c28e83SPiotr Jasiukajtis 		pop(uap);
130225c28e83SPiotr Jasiukajtis 		return;
130325c28e83SPiotr Jasiukajtis 
130425c28e83SPiotr Jasiukajtis 	case 0x2e8:
130525c28e83SPiotr Jasiukajtis 	case 0x6d8:
130625c28e83SPiotr Jasiukajtis 		/* f[u]compp */
130725c28e83SPiotr Jasiukajtis #if defined(__amd64)
130825c28e83SPiotr Jasiukajtis 		uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
130925c28e83SPiotr Jasiukajtis #else
131025c28e83SPiotr Jasiukajtis 		uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 0x4500;
131125c28e83SPiotr Jasiukajtis #endif
131225c28e83SPiotr Jasiukajtis 		pop(uap);
131325c28e83SPiotr Jasiukajtis 		pop(uap);
131425c28e83SPiotr Jasiukajtis 		return;
131525c28e83SPiotr Jasiukajtis 
131625c28e83SPiotr Jasiukajtis 	case 0x1e0:
131725c28e83SPiotr Jasiukajtis 		if (op == 0x1e4) { /* ftst */
131825c28e83SPiotr Jasiukajtis #if defined(__amd64)
131925c28e83SPiotr Jasiukajtis 			uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
132025c28e83SPiotr Jasiukajtis #else
132125c28e83SPiotr Jasiukajtis 			uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 0x4500;
132225c28e83SPiotr Jasiukajtis #endif
132325c28e83SPiotr Jasiukajtis 			return;
132425c28e83SPiotr Jasiukajtis 		}
132525c28e83SPiotr Jasiukajtis 		break;
132625c28e83SPiotr Jasiukajtis 
132725c28e83SPiotr Jasiukajtis 	case 0x3e8:
132825c28e83SPiotr Jasiukajtis 	case 0x3f0:
132925c28e83SPiotr Jasiukajtis 		/* f[u]comi */
133025c28e83SPiotr Jasiukajtis #if defined(__amd64)
133125c28e83SPiotr Jasiukajtis 		uap->uc_mcontext.gregs[REG_PS] |= 0x45;
133225c28e83SPiotr Jasiukajtis #else
133325c28e83SPiotr Jasiukajtis 		uap->uc_mcontext.gregs[EFL] |= 0x45;
133425c28e83SPiotr Jasiukajtis #endif
133525c28e83SPiotr Jasiukajtis 		return;
133625c28e83SPiotr Jasiukajtis 
133725c28e83SPiotr Jasiukajtis 	case 0x7e8:
133825c28e83SPiotr Jasiukajtis 	case 0x7f0:
133925c28e83SPiotr Jasiukajtis 		/* f[u]comip */
134025c28e83SPiotr Jasiukajtis #if defined(__amd64)
134125c28e83SPiotr Jasiukajtis 		uap->uc_mcontext.gregs[REG_PS] |= 0x45;
134225c28e83SPiotr Jasiukajtis #else
134325c28e83SPiotr Jasiukajtis 		uap->uc_mcontext.gregs[EFL] |= 0x45;
134425c28e83SPiotr Jasiukajtis #endif
134525c28e83SPiotr Jasiukajtis 		pop(uap);
134625c28e83SPiotr Jasiukajtis 		return;
134725c28e83SPiotr Jasiukajtis 	}
134825c28e83SPiotr Jasiukajtis 
134925c28e83SPiotr Jasiukajtis 	/* if there is no result available and the exception is overflow
135025c28e83SPiotr Jasiukajtis 	   or underflow, use the wrapped result */
135125c28e83SPiotr Jasiukajtis 	r = info->res;
135225c28e83SPiotr Jasiukajtis 	if (r.type == fex_nodata) {
135325c28e83SPiotr Jasiukajtis 		if (ex == FPE_FLTOVF || ex == FPE_FLTUND) {
135425c28e83SPiotr Jasiukajtis 			/* for store instructions, do the scaling and store */
135525c28e83SPiotr Jasiukajtis 			switch (op & 0x7f8) {
135625c28e83SPiotr Jasiukajtis 			case 0x110:
135725c28e83SPiotr Jasiukajtis 			case 0x118:
135825c28e83SPiotr Jasiukajtis 			case 0x150:
135925c28e83SPiotr Jasiukajtis 			case 0x158:
136025c28e83SPiotr Jasiukajtis 			case 0x190:
136125c28e83SPiotr Jasiukajtis 			case 0x198:
136225c28e83SPiotr Jasiukajtis 				if (!ea)
136325c28e83SPiotr Jasiukajtis 					return;
136425c28e83SPiotr Jasiukajtis 				if (ex == FPE_FLTOVF)
136525c28e83SPiotr Jasiukajtis 					*(float *)ea = (fpreg(uap, 0) * fov) * fov;
136625c28e83SPiotr Jasiukajtis 				else
136725c28e83SPiotr Jasiukajtis 					*(float *)ea = (fpreg(uap, 0) * fun) * fun;
136825c28e83SPiotr Jasiukajtis 				if ((op & 8) != 0)
136925c28e83SPiotr Jasiukajtis 					pop(uap);
137025c28e83SPiotr Jasiukajtis 				break;
137125c28e83SPiotr Jasiukajtis 
137225c28e83SPiotr Jasiukajtis 			case 0x510:
137325c28e83SPiotr Jasiukajtis 			case 0x518:
137425c28e83SPiotr Jasiukajtis 			case 0x550:
137525c28e83SPiotr Jasiukajtis 			case 0x558:
137625c28e83SPiotr Jasiukajtis 			case 0x590:
137725c28e83SPiotr Jasiukajtis 			case 0x598:
137825c28e83SPiotr Jasiukajtis 				if (!ea)
137925c28e83SPiotr Jasiukajtis 					return;
138025c28e83SPiotr Jasiukajtis 				if (ex == FPE_FLTOVF)
138125c28e83SPiotr Jasiukajtis 					*(double *)ea = (fpreg(uap, 0) * dov) * dov;
138225c28e83SPiotr Jasiukajtis 				else
138325c28e83SPiotr Jasiukajtis 					*(double *)ea = (fpreg(uap, 0) * dun) * dun;
138425c28e83SPiotr Jasiukajtis 				if ((op & 8) != 0)
138525c28e83SPiotr Jasiukajtis 					pop(uap);
138625c28e83SPiotr Jasiukajtis 				break;
138725c28e83SPiotr Jasiukajtis 			}
138825c28e83SPiotr Jasiukajtis 		}
138925c28e83SPiotr Jasiukajtis #ifdef DEBUG
139025c28e83SPiotr Jasiukajtis 		else if (ex != FPE_FLTRES)
139125c28e83SPiotr Jasiukajtis 			printf("No result supplied, stack may be hosed\n");
139225c28e83SPiotr Jasiukajtis #endif
139325c28e83SPiotr Jasiukajtis 		return;
139425c28e83SPiotr Jasiukajtis 	}
139525c28e83SPiotr Jasiukajtis 
139625c28e83SPiotr Jasiukajtis 	/* otherwise convert the supplied result to the correct type,
139725c28e83SPiotr Jasiukajtis 	   put it in the destination, and update the stack as need be */
139825c28e83SPiotr Jasiukajtis 
139925c28e83SPiotr Jasiukajtis 	/* store instructions */
140025c28e83SPiotr Jasiukajtis 	switch (op & 0x7f8) {
140125c28e83SPiotr Jasiukajtis 	case 0x110:
140225c28e83SPiotr Jasiukajtis 	case 0x118:
140325c28e83SPiotr Jasiukajtis 	case 0x150:
140425c28e83SPiotr Jasiukajtis 	case 0x158:
140525c28e83SPiotr Jasiukajtis 	case 0x190:
140625c28e83SPiotr Jasiukajtis 	case 0x198:
140725c28e83SPiotr Jasiukajtis 		if (!ea)
140825c28e83SPiotr Jasiukajtis 			return;
140925c28e83SPiotr Jasiukajtis 		switch (r.type) {
141025c28e83SPiotr Jasiukajtis 		case fex_int:
141125c28e83SPiotr Jasiukajtis 			*(float *)ea = (float) r.val.i;
141225c28e83SPiotr Jasiukajtis 			break;
141325c28e83SPiotr Jasiukajtis 
141425c28e83SPiotr Jasiukajtis 		case fex_llong:
141525c28e83SPiotr Jasiukajtis 			*(float *)ea = (float) r.val.l;
141625c28e83SPiotr Jasiukajtis 			break;
141725c28e83SPiotr Jasiukajtis 
141825c28e83SPiotr Jasiukajtis 		case fex_float:
141925c28e83SPiotr Jasiukajtis 			*(float *)ea = r.val.f;
142025c28e83SPiotr Jasiukajtis 			break;
142125c28e83SPiotr Jasiukajtis 
142225c28e83SPiotr Jasiukajtis 		case fex_double:
142325c28e83SPiotr Jasiukajtis 			*(float *)ea = (float) r.val.d;
142425c28e83SPiotr Jasiukajtis 			break;
142525c28e83SPiotr Jasiukajtis 
142625c28e83SPiotr Jasiukajtis 		case fex_ldouble:
142725c28e83SPiotr Jasiukajtis 			*(float *)ea = (float) r.val.q;
142825c28e83SPiotr Jasiukajtis 			break;
142925c28e83SPiotr Jasiukajtis 
143025c28e83SPiotr Jasiukajtis 		default:
143125c28e83SPiotr Jasiukajtis 			break;
143225c28e83SPiotr Jasiukajtis 		}
143325c28e83SPiotr Jasiukajtis 		if (ex != FPE_FLTRES && (op & 8) != 0)
143425c28e83SPiotr Jasiukajtis 			pop(uap);
143525c28e83SPiotr Jasiukajtis 		return;
143625c28e83SPiotr Jasiukajtis 
143725c28e83SPiotr Jasiukajtis 	case 0x310:
143825c28e83SPiotr Jasiukajtis 	case 0x318:
143925c28e83SPiotr Jasiukajtis 	case 0x350:
144025c28e83SPiotr Jasiukajtis 	case 0x358:
144125c28e83SPiotr Jasiukajtis 	case 0x390:
144225c28e83SPiotr Jasiukajtis 	case 0x398:
144325c28e83SPiotr Jasiukajtis 		if (!ea)
144425c28e83SPiotr Jasiukajtis 			return;
144525c28e83SPiotr Jasiukajtis 		switch (r.type) {
144625c28e83SPiotr Jasiukajtis 		case fex_int:
144725c28e83SPiotr Jasiukajtis 			*(int *)ea = r.val.i;
144825c28e83SPiotr Jasiukajtis 			break;
144925c28e83SPiotr Jasiukajtis 
145025c28e83SPiotr Jasiukajtis 		case fex_llong:
145125c28e83SPiotr Jasiukajtis 			*(int *)ea = (int) r.val.l;
145225c28e83SPiotr Jasiukajtis 			break;
145325c28e83SPiotr Jasiukajtis 
145425c28e83SPiotr Jasiukajtis 		case fex_float:
145525c28e83SPiotr Jasiukajtis 			*(int *)ea = (int) r.val.f;
145625c28e83SPiotr Jasiukajtis 			break;
145725c28e83SPiotr Jasiukajtis 
145825c28e83SPiotr Jasiukajtis 		case fex_double:
145925c28e83SPiotr Jasiukajtis 			*(int *)ea = (int) r.val.d;
146025c28e83SPiotr Jasiukajtis 			break;
146125c28e83SPiotr Jasiukajtis 
146225c28e83SPiotr Jasiukajtis 		case fex_ldouble:
146325c28e83SPiotr Jasiukajtis 			*(int *)ea = (int) r.val.q;
146425c28e83SPiotr Jasiukajtis 			break;
146525c28e83SPiotr Jasiukajtis 
146625c28e83SPiotr Jasiukajtis 		default:
146725c28e83SPiotr Jasiukajtis 			break;
146825c28e83SPiotr Jasiukajtis 		}
146925c28e83SPiotr Jasiukajtis 		if (ex != FPE_FLTRES && (op & 8) != 0)
147025c28e83SPiotr Jasiukajtis 			pop(uap);
147125c28e83SPiotr Jasiukajtis 		return;
147225c28e83SPiotr Jasiukajtis 
147325c28e83SPiotr Jasiukajtis 	case 0x510:
147425c28e83SPiotr Jasiukajtis 	case 0x518:
147525c28e83SPiotr Jasiukajtis 	case 0x550:
147625c28e83SPiotr Jasiukajtis 	case 0x558:
147725c28e83SPiotr Jasiukajtis 	case 0x590:
147825c28e83SPiotr Jasiukajtis 	case 0x598:
147925c28e83SPiotr Jasiukajtis 		if (!ea)
148025c28e83SPiotr Jasiukajtis 			return;
148125c28e83SPiotr Jasiukajtis 		switch (r.type) {
148225c28e83SPiotr Jasiukajtis 		case fex_int:
148325c28e83SPiotr Jasiukajtis 			*(double *)ea = (double) r.val.i;
148425c28e83SPiotr Jasiukajtis 			break;
148525c28e83SPiotr Jasiukajtis 
148625c28e83SPiotr Jasiukajtis 		case fex_llong:
148725c28e83SPiotr Jasiukajtis 			*(double *)ea = (double) r.val.l;
148825c28e83SPiotr Jasiukajtis 			break;
148925c28e83SPiotr Jasiukajtis 
149025c28e83SPiotr Jasiukajtis 		case fex_float:
149125c28e83SPiotr Jasiukajtis 			*(double *)ea = (double) r.val.f;
149225c28e83SPiotr Jasiukajtis 			break;
149325c28e83SPiotr Jasiukajtis 
149425c28e83SPiotr Jasiukajtis 		case fex_double:
149525c28e83SPiotr Jasiukajtis 			*(double *)ea = r.val.d;
149625c28e83SPiotr Jasiukajtis 			break;
149725c28e83SPiotr Jasiukajtis 
149825c28e83SPiotr Jasiukajtis 		case fex_ldouble:
149925c28e83SPiotr Jasiukajtis 			*(double *)ea = (double) r.val.q;
150025c28e83SPiotr Jasiukajtis 			break;
150125c28e83SPiotr Jasiukajtis 
150225c28e83SPiotr Jasiukajtis 		default:
150325c28e83SPiotr Jasiukajtis 			break;
150425c28e83SPiotr Jasiukajtis 		}
150525c28e83SPiotr Jasiukajtis 		if (ex != FPE_FLTRES && (op & 8) != 0)
150625c28e83SPiotr Jasiukajtis 			pop(uap);
150725c28e83SPiotr Jasiukajtis 		return;
150825c28e83SPiotr Jasiukajtis 
150925c28e83SPiotr Jasiukajtis 	case 0x710:
151025c28e83SPiotr Jasiukajtis 	case 0x718:
151125c28e83SPiotr Jasiukajtis 	case 0x750:
151225c28e83SPiotr Jasiukajtis 	case 0x758:
151325c28e83SPiotr Jasiukajtis 	case 0x790:
151425c28e83SPiotr Jasiukajtis 	case 0x798:
151525c28e83SPiotr Jasiukajtis 		if (!ea)
151625c28e83SPiotr Jasiukajtis 			return;
151725c28e83SPiotr Jasiukajtis 		switch (r.type) {
151825c28e83SPiotr Jasiukajtis 		case fex_int:
151925c28e83SPiotr Jasiukajtis 			*(short *)ea = (short) r.val.i;
152025c28e83SPiotr Jasiukajtis 			break;
152125c28e83SPiotr Jasiukajtis 
152225c28e83SPiotr Jasiukajtis 		case fex_llong:
152325c28e83SPiotr Jasiukajtis 			*(short *)ea = (short) r.val.l;
152425c28e83SPiotr Jasiukajtis 			break;
152525c28e83SPiotr Jasiukajtis 
152625c28e83SPiotr Jasiukajtis 		case fex_float:
152725c28e83SPiotr Jasiukajtis 			*(short *)ea = (short) r.val.f;
152825c28e83SPiotr Jasiukajtis 			break;
152925c28e83SPiotr Jasiukajtis 
153025c28e83SPiotr Jasiukajtis 		case fex_double:
153125c28e83SPiotr Jasiukajtis 			*(short *)ea = (short) r.val.d;
153225c28e83SPiotr Jasiukajtis 			break;
153325c28e83SPiotr Jasiukajtis 
153425c28e83SPiotr Jasiukajtis 		case fex_ldouble:
153525c28e83SPiotr Jasiukajtis 			*(short *)ea = (short) r.val.q;
153625c28e83SPiotr Jasiukajtis 			break;
153725c28e83SPiotr Jasiukajtis 
153825c28e83SPiotr Jasiukajtis 		default:
153925c28e83SPiotr Jasiukajtis 			break;
154025c28e83SPiotr Jasiukajtis 		}
154125c28e83SPiotr Jasiukajtis 		if (ex != FPE_FLTRES && (op & 8) != 0)
154225c28e83SPiotr Jasiukajtis 			pop(uap);
154325c28e83SPiotr Jasiukajtis 		return;
154425c28e83SPiotr Jasiukajtis 
154525c28e83SPiotr Jasiukajtis 	case 0x730:
154625c28e83SPiotr Jasiukajtis 	case 0x770:
154725c28e83SPiotr Jasiukajtis 	case 0x7b0:
154825c28e83SPiotr Jasiukajtis 		/* fbstp; don't bother */
154925c28e83SPiotr Jasiukajtis 		if (ea && ex != FPE_FLTRES)
155025c28e83SPiotr Jasiukajtis 			pop(uap);
155125c28e83SPiotr Jasiukajtis 		return;
155225c28e83SPiotr Jasiukajtis 
155325c28e83SPiotr Jasiukajtis 	case 0x738:
155425c28e83SPiotr Jasiukajtis 	case 0x778:
155525c28e83SPiotr Jasiukajtis 	case 0x7b8:
155625c28e83SPiotr Jasiukajtis 		if (!ea)
155725c28e83SPiotr Jasiukajtis 			return;
155825c28e83SPiotr Jasiukajtis 		switch (r.type) {
155925c28e83SPiotr Jasiukajtis 		case fex_int:
156025c28e83SPiotr Jasiukajtis 			*(long long *)ea = (long long) r.val.i;
156125c28e83SPiotr Jasiukajtis 			break;
156225c28e83SPiotr Jasiukajtis 
156325c28e83SPiotr Jasiukajtis 		case fex_llong:
156425c28e83SPiotr Jasiukajtis 			*(long long *)ea = r.val.l;
156525c28e83SPiotr Jasiukajtis 			break;
156625c28e83SPiotr Jasiukajtis 
156725c28e83SPiotr Jasiukajtis 		case fex_float:
156825c28e83SPiotr Jasiukajtis 			*(long long *)ea = (long long) r.val.f;
156925c28e83SPiotr Jasiukajtis 			break;
157025c28e83SPiotr Jasiukajtis 
157125c28e83SPiotr Jasiukajtis 		case fex_double:
157225c28e83SPiotr Jasiukajtis 			*(long long *)ea = (long long) r.val.d;
157325c28e83SPiotr Jasiukajtis 			break;
157425c28e83SPiotr Jasiukajtis 
157525c28e83SPiotr Jasiukajtis 		case fex_ldouble:
157625c28e83SPiotr Jasiukajtis 			*(long long *)ea = (long long) r.val.q;
157725c28e83SPiotr Jasiukajtis 			break;
157825c28e83SPiotr Jasiukajtis 
157925c28e83SPiotr Jasiukajtis 		default:
158025c28e83SPiotr Jasiukajtis 			break;
158125c28e83SPiotr Jasiukajtis 		}
158225c28e83SPiotr Jasiukajtis 		if (ex != FPE_FLTRES)
158325c28e83SPiotr Jasiukajtis 			pop(uap);
158425c28e83SPiotr Jasiukajtis 		return;
158525c28e83SPiotr Jasiukajtis 	}
158625c28e83SPiotr Jasiukajtis 
158725c28e83SPiotr Jasiukajtis 	/* for all other instructions, the result goes into a register */
158825c28e83SPiotr Jasiukajtis 	switch (r.type) {
158925c28e83SPiotr Jasiukajtis 	case fex_int:
159025c28e83SPiotr Jasiukajtis 		r.val.q = (long double) r.val.i;
159125c28e83SPiotr Jasiukajtis 		break;
159225c28e83SPiotr Jasiukajtis 
159325c28e83SPiotr Jasiukajtis 	case fex_llong:
159425c28e83SPiotr Jasiukajtis 		r.val.q = (long double) r.val.l;
159525c28e83SPiotr Jasiukajtis 		break;
159625c28e83SPiotr Jasiukajtis 
159725c28e83SPiotr Jasiukajtis 	case fex_float:
159825c28e83SPiotr Jasiukajtis 		r.val.q = (long double) r.val.f;
159925c28e83SPiotr Jasiukajtis 		break;
160025c28e83SPiotr Jasiukajtis 
160125c28e83SPiotr Jasiukajtis 	case fex_double:
160225c28e83SPiotr Jasiukajtis 		r.val.q = (long double) r.val.d;
160325c28e83SPiotr Jasiukajtis 		break;
160425c28e83SPiotr Jasiukajtis 
160525c28e83SPiotr Jasiukajtis 	default:
160625c28e83SPiotr Jasiukajtis 		break;
160725c28e83SPiotr Jasiukajtis 	}
160825c28e83SPiotr Jasiukajtis 
160925c28e83SPiotr Jasiukajtis 	/* for load instructions, push the result onto the stack */
161025c28e83SPiotr Jasiukajtis 	switch (op & 0x7f8) {
161125c28e83SPiotr Jasiukajtis 	case 0x100:
161225c28e83SPiotr Jasiukajtis 	case 0x140:
161325c28e83SPiotr Jasiukajtis 	case 0x180:
161425c28e83SPiotr Jasiukajtis 	case 0x500:
161525c28e83SPiotr Jasiukajtis 	case 0x540:
161625c28e83SPiotr Jasiukajtis 	case 0x580:
161725c28e83SPiotr Jasiukajtis 		if (ea)
161825c28e83SPiotr Jasiukajtis 			push(r.val.q, uap);
161925c28e83SPiotr Jasiukajtis 		return;
162025c28e83SPiotr Jasiukajtis 	}
162125c28e83SPiotr Jasiukajtis 
162225c28e83SPiotr Jasiukajtis 	/* for all other instructions, if the exception is overflow,
162325c28e83SPiotr Jasiukajtis 	   underflow, or inexact, the stack has already been updated */
162425c28e83SPiotr Jasiukajtis 	stack = (ex == FPE_FLTOVF || ex == FPE_FLTUND || ex == FPE_FLTRES);
162525c28e83SPiotr Jasiukajtis 	switch (op & 0x7f8) {
162625c28e83SPiotr Jasiukajtis 	case 0x1f0: /* oddballs */
162725c28e83SPiotr Jasiukajtis 		switch (op) {
162825c28e83SPiotr Jasiukajtis 		case 0x1f1: /* fyl2x */
162925c28e83SPiotr Jasiukajtis 		case 0x1f3: /* fpatan */
163025c28e83SPiotr Jasiukajtis 		case 0x1f9: /* fyl2xp1 */
163125c28e83SPiotr Jasiukajtis 			/* pop the stack, leaving the result in st */
163225c28e83SPiotr Jasiukajtis 			if (!stack)
163325c28e83SPiotr Jasiukajtis 				pop(uap);
163425c28e83SPiotr Jasiukajtis 			fpreg(uap, 0) = r.val.q;
163525c28e83SPiotr Jasiukajtis 			return;
163625c28e83SPiotr Jasiukajtis 
163725c28e83SPiotr Jasiukajtis 		case 0x1f2: /* fpatan */
163825c28e83SPiotr Jasiukajtis 			/* fptan pushes 1.0 afterward */
163925c28e83SPiotr Jasiukajtis 			if (stack)
164025c28e83SPiotr Jasiukajtis 				fpreg(uap, 1) = r.val.q;
164125c28e83SPiotr Jasiukajtis 			else {
164225c28e83SPiotr Jasiukajtis 				fpreg(uap, 0) = r.val.q;
164325c28e83SPiotr Jasiukajtis 				push(1.0L, uap);
164425c28e83SPiotr Jasiukajtis 			}
164525c28e83SPiotr Jasiukajtis 			return;
164625c28e83SPiotr Jasiukajtis 
164725c28e83SPiotr Jasiukajtis 		case 0x1f4: /* fxtract */
164825c28e83SPiotr Jasiukajtis 		case 0x1fb: /* fsincos */
164925c28e83SPiotr Jasiukajtis 			/* leave the supplied result in st */
165025c28e83SPiotr Jasiukajtis 			if (stack)
165125c28e83SPiotr Jasiukajtis 				fpreg(uap, 0) = r.val.q;
165225c28e83SPiotr Jasiukajtis 			else {
165325c28e83SPiotr Jasiukajtis 				fpreg(uap, 0) = 0.0; /* punt */
165425c28e83SPiotr Jasiukajtis 				push(r.val.q, uap);
165525c28e83SPiotr Jasiukajtis 			}
165625c28e83SPiotr Jasiukajtis 			return;
165725c28e83SPiotr Jasiukajtis 		}
165825c28e83SPiotr Jasiukajtis 
165925c28e83SPiotr Jasiukajtis 		/* all others leave the stack alone and the result in st */
166025c28e83SPiotr Jasiukajtis 		fpreg(uap, 0) = r.val.q;
166125c28e83SPiotr Jasiukajtis 		return;
166225c28e83SPiotr Jasiukajtis 
166325c28e83SPiotr Jasiukajtis 	case 0x4c0:
166425c28e83SPiotr Jasiukajtis 	case 0x4c8:
166525c28e83SPiotr Jasiukajtis 	case 0x4e0:
166625c28e83SPiotr Jasiukajtis 	case 0x4e8:
166725c28e83SPiotr Jasiukajtis 	case 0x4f0:
166825c28e83SPiotr Jasiukajtis 	case 0x4f8:
166925c28e83SPiotr Jasiukajtis 		fpreg(uap, op & 7) = r.val.q;
167025c28e83SPiotr Jasiukajtis 		return;
167125c28e83SPiotr Jasiukajtis 
167225c28e83SPiotr Jasiukajtis 	case 0x6c0:
167325c28e83SPiotr Jasiukajtis 	case 0x6c8:
167425c28e83SPiotr Jasiukajtis 	case 0x6e0:
167525c28e83SPiotr Jasiukajtis 	case 0x6e8:
167625c28e83SPiotr Jasiukajtis 	case 0x6f0:
167725c28e83SPiotr Jasiukajtis 	case 0x6f8:
167825c28e83SPiotr Jasiukajtis 		/* stack is popped afterward */
167925c28e83SPiotr Jasiukajtis 		if (stack)
168025c28e83SPiotr Jasiukajtis 			fpreg(uap, (op - 1) & 7) = r.val.q;
168125c28e83SPiotr Jasiukajtis 		else {
168225c28e83SPiotr Jasiukajtis 			fpreg(uap, op & 7) = r.val.q;
168325c28e83SPiotr Jasiukajtis 			pop(uap);
168425c28e83SPiotr Jasiukajtis 		}
168525c28e83SPiotr Jasiukajtis 		return;
168625c28e83SPiotr Jasiukajtis 
168725c28e83SPiotr Jasiukajtis 	default:
168825c28e83SPiotr Jasiukajtis 		fpreg(uap, 0) = r.val.q;
168925c28e83SPiotr Jasiukajtis 		return;
169025c28e83SPiotr Jasiukajtis 	}
169125c28e83SPiotr Jasiukajtis }
1692