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