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 #if defined(__sparc)
31*25c28e83SPiotr Jasiukajtis #include <stdio.h>
32*25c28e83SPiotr Jasiukajtis #include <unistd.h>
33*25c28e83SPiotr Jasiukajtis #include <string.h>
34*25c28e83SPiotr Jasiukajtis #include <signal.h>
35*25c28e83SPiotr Jasiukajtis #include <siginfo.h>
36*25c28e83SPiotr Jasiukajtis #include <thread.h>
37*25c28e83SPiotr Jasiukajtis #include <ucontext.h>
38*25c28e83SPiotr Jasiukajtis #include <math.h>
39*25c28e83SPiotr Jasiukajtis #if defined(__SUNPRO_C)
40*25c28e83SPiotr Jasiukajtis #include <sunmath.h>
41*25c28e83SPiotr Jasiukajtis #endif
42*25c28e83SPiotr Jasiukajtis #include <fenv.h>
43*25c28e83SPiotr Jasiukajtis 
44*25c28e83SPiotr Jasiukajtis #include "fenv_inlines.h"
45*25c28e83SPiotr Jasiukajtis #include "libm_inlines.h"
46*25c28e83SPiotr Jasiukajtis 
47*25c28e83SPiotr Jasiukajtis #ifdef __sparcv9
48*25c28e83SPiotr Jasiukajtis 
49*25c28e83SPiotr Jasiukajtis #define FPreg(X)	&uap->uc_mcontext.fpregs.fpu_fr.fpu_regs[X]
50*25c28e83SPiotr Jasiukajtis 
51*25c28e83SPiotr Jasiukajtis #define FPREG(X)	&uap->uc_mcontext.fpregs.fpu_fr.fpu_dregs[(X>>1)| \
52*25c28e83SPiotr Jasiukajtis 					((X&1)<<4)]
53*25c28e83SPiotr Jasiukajtis 
54*25c28e83SPiotr Jasiukajtis #else
55*25c28e83SPiotr Jasiukajtis 
56*25c28e83SPiotr Jasiukajtis #include <sys/procfs.h>
57*25c28e83SPiotr Jasiukajtis 
58*25c28e83SPiotr Jasiukajtis #define FPxreg(X)	&((prxregset_t*)uap->uc_mcontext.xrs.xrs_ptr)->pr_un.pr_v8p.pr_xfr.pr_regs[X]
59*25c28e83SPiotr Jasiukajtis 
60*25c28e83SPiotr Jasiukajtis #define FPreg(X)	&uap->uc_mcontext.fpregs.fpu_fr.fpu_regs[X]
61*25c28e83SPiotr Jasiukajtis 
62*25c28e83SPiotr Jasiukajtis #define FPREG(X)	((X & 1)? FPxreg(X - 1) : FPreg(X))
63*25c28e83SPiotr Jasiukajtis 
64*25c28e83SPiotr Jasiukajtis #endif	/* __sparcv9 */
65*25c28e83SPiotr Jasiukajtis 
66*25c28e83SPiotr Jasiukajtis #include "fex_handler.h"
67*25c28e83SPiotr Jasiukajtis 
68*25c28e83SPiotr Jasiukajtis /* avoid dependence on libsunmath */
69*25c28e83SPiotr Jasiukajtis static enum fp_class_type
my_fp_classl(long double * a)70*25c28e83SPiotr Jasiukajtis my_fp_classl(long double *a)
71*25c28e83SPiotr Jasiukajtis {
72*25c28e83SPiotr Jasiukajtis 	int		msw = *(int*)a & ~0x80000000;
73*25c28e83SPiotr Jasiukajtis 
74*25c28e83SPiotr Jasiukajtis 	if (msw >= 0x7fff0000) {
75*25c28e83SPiotr Jasiukajtis 		if (((msw & 0xffff) | *(1+(int*)a) | *(2+(int*)a) | *(3+(int*)a)) == 0)
76*25c28e83SPiotr Jasiukajtis 			return fp_infinity;
77*25c28e83SPiotr Jasiukajtis 		else if (msw & 0x8000)
78*25c28e83SPiotr Jasiukajtis 			return fp_quiet;
79*25c28e83SPiotr Jasiukajtis 		else
80*25c28e83SPiotr Jasiukajtis 			return fp_signaling;
81*25c28e83SPiotr Jasiukajtis 	} else if (msw < 0x10000) {
82*25c28e83SPiotr Jasiukajtis 		if ((msw | *(1+(int*)a) | *(2+(int*)a) | *(3+(int*)a)) == 0)
83*25c28e83SPiotr Jasiukajtis 			return fp_zero;
84*25c28e83SPiotr Jasiukajtis 		else
85*25c28e83SPiotr Jasiukajtis 			return fp_subnormal;
86*25c28e83SPiotr Jasiukajtis 	} else
87*25c28e83SPiotr Jasiukajtis 		return fp_normal;
88*25c28e83SPiotr Jasiukajtis }
89*25c28e83SPiotr Jasiukajtis 
90*25c28e83SPiotr Jasiukajtis /*
91*25c28e83SPiotr Jasiukajtis *  Determine which type of invalid operation exception occurred
92*25c28e83SPiotr Jasiukajtis */
93*25c28e83SPiotr Jasiukajtis enum fex_exception
__fex_get_invalid_type(siginfo_t * sip,ucontext_t * uap)94*25c28e83SPiotr Jasiukajtis __fex_get_invalid_type(siginfo_t *sip, ucontext_t *uap)
95*25c28e83SPiotr Jasiukajtis {
96*25c28e83SPiotr Jasiukajtis 	unsigned			instr, opf, rs1, rs2;
97*25c28e83SPiotr Jasiukajtis 	enum fp_class_type	t1, t2;
98*25c28e83SPiotr Jasiukajtis 
99*25c28e83SPiotr Jasiukajtis 	/* parse the instruction which caused the exception */
100*25c28e83SPiotr Jasiukajtis 	instr = uap->uc_mcontext.fpregs.fpu_q->FQu.fpq.fpq_instr;
101*25c28e83SPiotr Jasiukajtis 	opf = (instr >> 5) & 0x1ff;
102*25c28e83SPiotr Jasiukajtis 	rs1 = (instr >> 14) & 0x1f;
103*25c28e83SPiotr Jasiukajtis 	rs2 = instr & 0x1f;
104*25c28e83SPiotr Jasiukajtis 
105*25c28e83SPiotr Jasiukajtis 	/* determine the classes of the operands */
106*25c28e83SPiotr Jasiukajtis 	switch (opf & 3) {
107*25c28e83SPiotr Jasiukajtis 	case 1: /* single */
108*25c28e83SPiotr Jasiukajtis 		t1 = fp_classf(*(float*)FPreg(rs1));
109*25c28e83SPiotr Jasiukajtis 		t2 = fp_classf(*(float*)FPreg(rs2));
110*25c28e83SPiotr Jasiukajtis 		break;
111*25c28e83SPiotr Jasiukajtis 
112*25c28e83SPiotr Jasiukajtis 	case 2: /* double */
113*25c28e83SPiotr Jasiukajtis 		t1 = fp_class(*(double*)FPREG(rs1));
114*25c28e83SPiotr Jasiukajtis 		t2 = fp_class(*(double*)FPREG(rs2));
115*25c28e83SPiotr Jasiukajtis 		break;
116*25c28e83SPiotr Jasiukajtis 
117*25c28e83SPiotr Jasiukajtis 	case 3: /* quad */
118*25c28e83SPiotr Jasiukajtis 		t1 = my_fp_classl((long double*)FPREG(rs1));
119*25c28e83SPiotr Jasiukajtis 		t2 = my_fp_classl((long double*)FPREG(rs2));
120*25c28e83SPiotr Jasiukajtis 		break;
121*25c28e83SPiotr Jasiukajtis 
122*25c28e83SPiotr Jasiukajtis 	default: /* integer operands never cause an invalid operation */
123*25c28e83SPiotr Jasiukajtis 		return (enum fex_exception) -1;
124*25c28e83SPiotr Jasiukajtis 	}
125*25c28e83SPiotr Jasiukajtis 
126*25c28e83SPiotr Jasiukajtis 	/* if rs2 is snan, return immediately */
127*25c28e83SPiotr Jasiukajtis 	if (t2 == fp_signaling)
128*25c28e83SPiotr Jasiukajtis 		return fex_inv_snan;
129*25c28e83SPiotr Jasiukajtis 
130*25c28e83SPiotr Jasiukajtis 	/* determine the type of operation */
131*25c28e83SPiotr Jasiukajtis 	switch ((instr >> 19) & 0x183f) {
132*25c28e83SPiotr Jasiukajtis 	case 0x1034: /* add, subtract, multiply, divide, square root, convert */
133*25c28e83SPiotr Jasiukajtis 		switch (opf & 0x1fc) {
134*25c28e83SPiotr Jasiukajtis 		case 0x40:
135*25c28e83SPiotr Jasiukajtis 		case 0x44: /* add or subtract */
136*25c28e83SPiotr Jasiukajtis 			if (t1 == fp_signaling)
137*25c28e83SPiotr Jasiukajtis 				return fex_inv_snan;
138*25c28e83SPiotr Jasiukajtis 			else
139*25c28e83SPiotr Jasiukajtis 				return fex_inv_isi;
140*25c28e83SPiotr Jasiukajtis 
141*25c28e83SPiotr Jasiukajtis 		case 0x48:
142*25c28e83SPiotr Jasiukajtis 		case 0x68:
143*25c28e83SPiotr Jasiukajtis 		case 0x6c: /* multiply */
144*25c28e83SPiotr Jasiukajtis 			if (t1 == fp_signaling)
145*25c28e83SPiotr Jasiukajtis 				return fex_inv_snan;
146*25c28e83SPiotr Jasiukajtis 			else
147*25c28e83SPiotr Jasiukajtis 				return fex_inv_zmi;
148*25c28e83SPiotr Jasiukajtis 
149*25c28e83SPiotr Jasiukajtis 		case 0x4c: /* divide */
150*25c28e83SPiotr Jasiukajtis 			if (t1 == fp_signaling)
151*25c28e83SPiotr Jasiukajtis 				return fex_inv_snan;
152*25c28e83SPiotr Jasiukajtis 			else if (t1 == fp_zero)
153*25c28e83SPiotr Jasiukajtis 				return fex_inv_zdz;
154*25c28e83SPiotr Jasiukajtis 			else
155*25c28e83SPiotr Jasiukajtis 				return fex_inv_idi;
156*25c28e83SPiotr Jasiukajtis 
157*25c28e83SPiotr Jasiukajtis 		case 0x28: /* square root */
158*25c28e83SPiotr Jasiukajtis 			return fex_inv_sqrt;
159*25c28e83SPiotr Jasiukajtis 
160*25c28e83SPiotr Jasiukajtis 		case 0x80:
161*25c28e83SPiotr Jasiukajtis 		case 0xd0: /* convert to integer */
162*25c28e83SPiotr Jasiukajtis 			return fex_inv_int;
163*25c28e83SPiotr Jasiukajtis 		}
164*25c28e83SPiotr Jasiukajtis 		break;
165*25c28e83SPiotr Jasiukajtis 
166*25c28e83SPiotr Jasiukajtis 	case 0x1035: /* compare */
167*25c28e83SPiotr Jasiukajtis 		if (t1 == fp_signaling)
168*25c28e83SPiotr Jasiukajtis 			return fex_inv_snan;
169*25c28e83SPiotr Jasiukajtis 		else
170*25c28e83SPiotr Jasiukajtis 			return fex_inv_cmp;
171*25c28e83SPiotr Jasiukajtis 	}
172*25c28e83SPiotr Jasiukajtis 
173*25c28e83SPiotr Jasiukajtis 	return (enum fex_exception) -1;
174*25c28e83SPiotr Jasiukajtis }
175*25c28e83SPiotr Jasiukajtis 
176*25c28e83SPiotr Jasiukajtis #ifdef __sparcv9
177*25c28e83SPiotr Jasiukajtis extern void _Qp_sqrt(long double *, const long double *);
178*25c28e83SPiotr Jasiukajtis #else
179*25c28e83SPiotr Jasiukajtis extern long double _Q_sqrt(long double);
180*25c28e83SPiotr Jasiukajtis #endif
181*25c28e83SPiotr Jasiukajtis 
182*25c28e83SPiotr Jasiukajtis /*
183*25c28e83SPiotr Jasiukajtis *  Get the operands, generate the default untrapped result with
184*25c28e83SPiotr Jasiukajtis *  exceptions, and set a code indicating the type of operation
185*25c28e83SPiotr Jasiukajtis */
186*25c28e83SPiotr Jasiukajtis void
__fex_get_op(siginfo_t * sip,ucontext_t * uap,fex_info_t * info)187*25c28e83SPiotr Jasiukajtis __fex_get_op(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
188*25c28e83SPiotr Jasiukajtis {
189*25c28e83SPiotr Jasiukajtis 	unsigned long	fsr;
190*25c28e83SPiotr Jasiukajtis 	unsigned		instr, opf, rs1, rs2;
191*25c28e83SPiotr Jasiukajtis 	volatile int	c;
192*25c28e83SPiotr Jasiukajtis 
193*25c28e83SPiotr Jasiukajtis 	/* parse the instruction which caused the exception */
194*25c28e83SPiotr Jasiukajtis 	instr = uap->uc_mcontext.fpregs.fpu_q->FQu.fpq.fpq_instr;
195*25c28e83SPiotr Jasiukajtis 	opf = (instr >> 5) & 0x1ff;
196*25c28e83SPiotr Jasiukajtis 	rs1 = (instr >> 14) & 0x1f;
197*25c28e83SPiotr Jasiukajtis 	rs2 = instr & 0x1f;
198*25c28e83SPiotr Jasiukajtis 
199*25c28e83SPiotr Jasiukajtis 	/* get the operands */
200*25c28e83SPiotr Jasiukajtis 	switch (opf & 3) {
201*25c28e83SPiotr Jasiukajtis 	case 0: /* integer */
202*25c28e83SPiotr Jasiukajtis 		info->op1.type = fex_nodata;
203*25c28e83SPiotr Jasiukajtis 		if (opf & 0x40) {
204*25c28e83SPiotr Jasiukajtis 			info->op2.type = fex_int;
205*25c28e83SPiotr Jasiukajtis 			info->op2.val.i = *(int*)FPreg(rs2);
206*25c28e83SPiotr Jasiukajtis 		}
207*25c28e83SPiotr Jasiukajtis 		else {
208*25c28e83SPiotr Jasiukajtis 			info->op2.type = fex_llong;
209*25c28e83SPiotr Jasiukajtis 			info->op2.val.l = *(long long*)FPREG(rs2);
210*25c28e83SPiotr Jasiukajtis 		}
211*25c28e83SPiotr Jasiukajtis 		break;
212*25c28e83SPiotr Jasiukajtis 
213*25c28e83SPiotr Jasiukajtis 	case 1: /* single */
214*25c28e83SPiotr Jasiukajtis 		info->op1.type = info->op2.type = fex_float;
215*25c28e83SPiotr Jasiukajtis 		info->op1.val.f = *(float*)FPreg(rs1);
216*25c28e83SPiotr Jasiukajtis 		info->op2.val.f = *(float*)FPreg(rs2);
217*25c28e83SPiotr Jasiukajtis 		break;
218*25c28e83SPiotr Jasiukajtis 
219*25c28e83SPiotr Jasiukajtis 	case 2: /* double */
220*25c28e83SPiotr Jasiukajtis 		info->op1.type = info->op2.type = fex_double;
221*25c28e83SPiotr Jasiukajtis 		info->op1.val.d = *(double*)FPREG(rs1);
222*25c28e83SPiotr Jasiukajtis 		info->op2.val.d = *(double*)FPREG(rs2);
223*25c28e83SPiotr Jasiukajtis 		break;
224*25c28e83SPiotr Jasiukajtis 
225*25c28e83SPiotr Jasiukajtis 	case 3: /* quad */
226*25c28e83SPiotr Jasiukajtis 		info->op1.type = info->op2.type = fex_ldouble;
227*25c28e83SPiotr Jasiukajtis 		info->op1.val.q = *(long double*)FPREG(rs1);
228*25c28e83SPiotr Jasiukajtis 		info->op2.val.q = *(long double*)FPREG(rs2);
229*25c28e83SPiotr Jasiukajtis 		break;
230*25c28e83SPiotr Jasiukajtis 	}
231*25c28e83SPiotr Jasiukajtis 
232*25c28e83SPiotr Jasiukajtis 	/* initialize res to the default untrapped result and ex to the
233*25c28e83SPiotr Jasiukajtis 	   corresponding flags (assume trapping is disabled and flags
234*25c28e83SPiotr Jasiukajtis 	   are clear) */
235*25c28e83SPiotr Jasiukajtis 	info->op = fex_other;
236*25c28e83SPiotr Jasiukajtis 	info->res.type = fex_nodata;
237*25c28e83SPiotr Jasiukajtis 	switch ((instr >> 19) & 0x183f) {
238*25c28e83SPiotr Jasiukajtis 	case 0x1035: /* compare */
239*25c28e83SPiotr Jasiukajtis 		info->op = fex_cmp;
240*25c28e83SPiotr Jasiukajtis 		switch (opf) {
241*25c28e83SPiotr Jasiukajtis 		case 0x51: /* compare single */
242*25c28e83SPiotr Jasiukajtis 			c = (info->op1.val.f == info->op2.val.f);
243*25c28e83SPiotr Jasiukajtis 			break;
244*25c28e83SPiotr Jasiukajtis 
245*25c28e83SPiotr Jasiukajtis 		case 0x52: /* compare double */
246*25c28e83SPiotr Jasiukajtis 			c = (info->op1.val.d == info->op2.val.d);
247*25c28e83SPiotr Jasiukajtis 			break;
248*25c28e83SPiotr Jasiukajtis 
249*25c28e83SPiotr Jasiukajtis 		case 0x53: /* compare quad */
250*25c28e83SPiotr Jasiukajtis 			c = (info->op1.val.q == info->op2.val.q);
251*25c28e83SPiotr Jasiukajtis 			break;
252*25c28e83SPiotr Jasiukajtis 
253*25c28e83SPiotr Jasiukajtis 		case 0x55: /* compare single with exception */
254*25c28e83SPiotr Jasiukajtis 			c = (info->op1.val.f < info->op2.val.f);
255*25c28e83SPiotr Jasiukajtis 			break;
256*25c28e83SPiotr Jasiukajtis 
257*25c28e83SPiotr Jasiukajtis 		case 0x56: /* compare double with exception */
258*25c28e83SPiotr Jasiukajtis 			c = (info->op1.val.d < info->op2.val.d);
259*25c28e83SPiotr Jasiukajtis 			break;
260*25c28e83SPiotr Jasiukajtis 
261*25c28e83SPiotr Jasiukajtis 		case 0x57: /* compare quad with exception */
262*25c28e83SPiotr Jasiukajtis 			c = (info->op1.val.q < info->op2.val.q);
263*25c28e83SPiotr Jasiukajtis 			break;
264*25c28e83SPiotr Jasiukajtis 		}
265*25c28e83SPiotr Jasiukajtis 		break;
266*25c28e83SPiotr Jasiukajtis 
267*25c28e83SPiotr Jasiukajtis 	case 0x1034: /* add, subtract, multiply, divide, square root, convert */
268*25c28e83SPiotr Jasiukajtis 		switch (opf) {
269*25c28e83SPiotr Jasiukajtis 		case 0x41: /* add single */
270*25c28e83SPiotr Jasiukajtis 			info->op = fex_add;
271*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_float;
272*25c28e83SPiotr Jasiukajtis 			info->res.val.f = info->op1.val.f + info->op2.val.f;
273*25c28e83SPiotr Jasiukajtis 			break;
274*25c28e83SPiotr Jasiukajtis 
275*25c28e83SPiotr Jasiukajtis 		case 0x42: /* add double */
276*25c28e83SPiotr Jasiukajtis 			info->op = fex_add;
277*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_double;
278*25c28e83SPiotr Jasiukajtis 			info->res.val.d = info->op1.val.d + info->op2.val.d;
279*25c28e83SPiotr Jasiukajtis 			break;
280*25c28e83SPiotr Jasiukajtis 
281*25c28e83SPiotr Jasiukajtis 		case 0x43: /* add quad */
282*25c28e83SPiotr Jasiukajtis 			info->op = fex_add;
283*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_ldouble;
284*25c28e83SPiotr Jasiukajtis 			info->res.val.q = info->op1.val.q + info->op2.val.q;
285*25c28e83SPiotr Jasiukajtis 			break;
286*25c28e83SPiotr Jasiukajtis 
287*25c28e83SPiotr Jasiukajtis 		case 0x45: /* subtract single */
288*25c28e83SPiotr Jasiukajtis 			info->op = fex_sub;
289*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_float;
290*25c28e83SPiotr Jasiukajtis 			info->res.val.f = info->op1.val.f - info->op2.val.f;
291*25c28e83SPiotr Jasiukajtis 			break;
292*25c28e83SPiotr Jasiukajtis 
293*25c28e83SPiotr Jasiukajtis 		case 0x46: /* subtract double */
294*25c28e83SPiotr Jasiukajtis 			info->op = fex_sub;
295*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_double;
296*25c28e83SPiotr Jasiukajtis 			info->res.val.d = info->op1.val.d - info->op2.val.d;
297*25c28e83SPiotr Jasiukajtis 			break;
298*25c28e83SPiotr Jasiukajtis 
299*25c28e83SPiotr Jasiukajtis 		case 0x47: /* subtract quad */
300*25c28e83SPiotr Jasiukajtis 			info->op = fex_sub;
301*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_ldouble;
302*25c28e83SPiotr Jasiukajtis 			info->res.val.q = info->op1.val.q - info->op2.val.q;
303*25c28e83SPiotr Jasiukajtis 			break;
304*25c28e83SPiotr Jasiukajtis 
305*25c28e83SPiotr Jasiukajtis 		case 0x49: /* multiply single */
306*25c28e83SPiotr Jasiukajtis 			info->op = fex_mul;
307*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_float;
308*25c28e83SPiotr Jasiukajtis 			info->res.val.f = info->op1.val.f * info->op2.val.f;
309*25c28e83SPiotr Jasiukajtis 			break;
310*25c28e83SPiotr Jasiukajtis 
311*25c28e83SPiotr Jasiukajtis 		case 0x4a: /* multiply double */
312*25c28e83SPiotr Jasiukajtis 			info->op = fex_mul;
313*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_double;
314*25c28e83SPiotr Jasiukajtis 			info->res.val.d = info->op1.val.d * info->op2.val.d;
315*25c28e83SPiotr Jasiukajtis 			break;
316*25c28e83SPiotr Jasiukajtis 
317*25c28e83SPiotr Jasiukajtis 		case 0x4b: /* multiply quad */
318*25c28e83SPiotr Jasiukajtis 			info->op = fex_mul;
319*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_ldouble;
320*25c28e83SPiotr Jasiukajtis 			info->res.val.q = info->op1.val.q * info->op2.val.q;
321*25c28e83SPiotr Jasiukajtis 			break;
322*25c28e83SPiotr Jasiukajtis 
323*25c28e83SPiotr Jasiukajtis 		case 0x69: /* fsmuld */
324*25c28e83SPiotr Jasiukajtis 			info->op = fex_mul;
325*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_double;
326*25c28e83SPiotr Jasiukajtis 			info->res.val.d = (double)info->op1.val.f * (double)info->op2.val.f;
327*25c28e83SPiotr Jasiukajtis 			break;
328*25c28e83SPiotr Jasiukajtis 
329*25c28e83SPiotr Jasiukajtis 		case 0x6e: /* fdmulq */
330*25c28e83SPiotr Jasiukajtis 			info->op = fex_mul;
331*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_ldouble;
332*25c28e83SPiotr Jasiukajtis 			info->res.val.q = (long double)info->op1.val.d *
333*25c28e83SPiotr Jasiukajtis 				(long double)info->op2.val.d;
334*25c28e83SPiotr Jasiukajtis 			break;
335*25c28e83SPiotr Jasiukajtis 
336*25c28e83SPiotr Jasiukajtis 		case 0x4d: /* divide single */
337*25c28e83SPiotr Jasiukajtis 			info->op = fex_div;
338*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_float;
339*25c28e83SPiotr Jasiukajtis 			info->res.val.f = info->op1.val.f / info->op2.val.f;
340*25c28e83SPiotr Jasiukajtis 			break;
341*25c28e83SPiotr Jasiukajtis 
342*25c28e83SPiotr Jasiukajtis 		case 0x4e: /* divide double */
343*25c28e83SPiotr Jasiukajtis 			info->op = fex_div;
344*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_double;
345*25c28e83SPiotr Jasiukajtis 			info->res.val.d = info->op1.val.d / info->op2.val.d;
346*25c28e83SPiotr Jasiukajtis 			break;
347*25c28e83SPiotr Jasiukajtis 
348*25c28e83SPiotr Jasiukajtis 		case 0x4f: /* divide quad */
349*25c28e83SPiotr Jasiukajtis 			info->op = fex_div;
350*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_ldouble;
351*25c28e83SPiotr Jasiukajtis 			info->res.val.q = info->op1.val.q / info->op2.val.q;
352*25c28e83SPiotr Jasiukajtis 			break;
353*25c28e83SPiotr Jasiukajtis 
354*25c28e83SPiotr Jasiukajtis 		case 0x29: /* square root single */
355*25c28e83SPiotr Jasiukajtis 			info->op = fex_sqrt;
356*25c28e83SPiotr Jasiukajtis 			info->op1 = info->op2;
357*25c28e83SPiotr Jasiukajtis 			info->op2.type = fex_nodata;
358*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_float;
359*25c28e83SPiotr Jasiukajtis 			info->res.val.f = sqrtf(info->op1.val.f);
360*25c28e83SPiotr Jasiukajtis 			break;
361*25c28e83SPiotr Jasiukajtis 
362*25c28e83SPiotr Jasiukajtis 		case 0x2a: /* square root double */
363*25c28e83SPiotr Jasiukajtis 			info->op = fex_sqrt;
364*25c28e83SPiotr Jasiukajtis 			info->op1 = info->op2;
365*25c28e83SPiotr Jasiukajtis 			info->op2.type = fex_nodata;
366*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_double;
367*25c28e83SPiotr Jasiukajtis 			info->res.val.d = sqrt(info->op1.val.d);
368*25c28e83SPiotr Jasiukajtis 			break;
369*25c28e83SPiotr Jasiukajtis 
370*25c28e83SPiotr Jasiukajtis 		case 0x2b: /* square root quad */
371*25c28e83SPiotr Jasiukajtis 			info->op = fex_sqrt;
372*25c28e83SPiotr Jasiukajtis 			info->op1 = info->op2;
373*25c28e83SPiotr Jasiukajtis 			info->op2.type = fex_nodata;
374*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_ldouble;
375*25c28e83SPiotr Jasiukajtis #ifdef __sparcv9
376*25c28e83SPiotr Jasiukajtis 			_Qp_sqrt(&info->res.val.q, &info->op1.val.q);
377*25c28e83SPiotr Jasiukajtis #else
378*25c28e83SPiotr Jasiukajtis 			info->res.val.q = _Q_sqrt(info->op1.val.q);
379*25c28e83SPiotr Jasiukajtis #endif
380*25c28e83SPiotr Jasiukajtis 			break;
381*25c28e83SPiotr Jasiukajtis 
382*25c28e83SPiotr Jasiukajtis 		default: /* conversions */
383*25c28e83SPiotr Jasiukajtis 			info->op = fex_cnvt;
384*25c28e83SPiotr Jasiukajtis 			info->op1 = info->op2;
385*25c28e83SPiotr Jasiukajtis 			info->op2.type = fex_nodata;
386*25c28e83SPiotr Jasiukajtis 			switch (opf) {
387*25c28e83SPiotr Jasiukajtis 			case 0xd1: /* convert single to int */
388*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_int;
389*25c28e83SPiotr Jasiukajtis 				info->res.val.i = (int) info->op1.val.f;
390*25c28e83SPiotr Jasiukajtis 				break;
391*25c28e83SPiotr Jasiukajtis 
392*25c28e83SPiotr Jasiukajtis 			case 0xd2: /* convert double to int */
393*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_int;
394*25c28e83SPiotr Jasiukajtis 				info->res.val.i = (int) info->op1.val.d;
395*25c28e83SPiotr Jasiukajtis 				break;
396*25c28e83SPiotr Jasiukajtis 
397*25c28e83SPiotr Jasiukajtis 			case 0xd3: /* convert quad to int */
398*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_int;
399*25c28e83SPiotr Jasiukajtis 				info->res.val.i = (int) info->op1.val.q;
400*25c28e83SPiotr Jasiukajtis 				break;
401*25c28e83SPiotr Jasiukajtis 
402*25c28e83SPiotr Jasiukajtis 			case 0x81: /* convert single to long long */
403*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_llong;
404*25c28e83SPiotr Jasiukajtis 				info->res.val.l = (long long) info->op1.val.f;
405*25c28e83SPiotr Jasiukajtis 				break;
406*25c28e83SPiotr Jasiukajtis 
407*25c28e83SPiotr Jasiukajtis 			case 0x82: /* convert double to long long */
408*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_llong;
409*25c28e83SPiotr Jasiukajtis 				info->res.val.l = (long long) info->op1.val.d;
410*25c28e83SPiotr Jasiukajtis 				break;
411*25c28e83SPiotr Jasiukajtis 
412*25c28e83SPiotr Jasiukajtis 			case 0x83: /* convert quad to long long */
413*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_llong;
414*25c28e83SPiotr Jasiukajtis 				info->res.val.l = (long long) info->op1.val.q;
415*25c28e83SPiotr Jasiukajtis 				break;
416*25c28e83SPiotr Jasiukajtis 
417*25c28e83SPiotr Jasiukajtis 			case 0xc4: /* convert int to single */
418*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_float;
419*25c28e83SPiotr Jasiukajtis 				info->res.val.f = (float) info->op1.val.i;
420*25c28e83SPiotr Jasiukajtis 				break;
421*25c28e83SPiotr Jasiukajtis 
422*25c28e83SPiotr Jasiukajtis 			case 0x84: /* convert long long to single */
423*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_float;
424*25c28e83SPiotr Jasiukajtis 				info->res.val.f = (float) info->op1.val.l;
425*25c28e83SPiotr Jasiukajtis 				break;
426*25c28e83SPiotr Jasiukajtis 
427*25c28e83SPiotr Jasiukajtis 			case 0x88: /* convert long long to double */
428*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_double;
429*25c28e83SPiotr Jasiukajtis 				info->res.val.d = (double) info->op1.val.l;
430*25c28e83SPiotr Jasiukajtis 				break;
431*25c28e83SPiotr Jasiukajtis 
432*25c28e83SPiotr Jasiukajtis 			case 0xc6: /* convert double to single */
433*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_float;
434*25c28e83SPiotr Jasiukajtis 				info->res.val.f = (float) info->op1.val.d;
435*25c28e83SPiotr Jasiukajtis 				break;
436*25c28e83SPiotr Jasiukajtis 
437*25c28e83SPiotr Jasiukajtis 			case 0xc7: /* convert quad to single */
438*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_float;
439*25c28e83SPiotr Jasiukajtis 				info->res.val.f = (float) info->op1.val.q;
440*25c28e83SPiotr Jasiukajtis 				break;
441*25c28e83SPiotr Jasiukajtis 
442*25c28e83SPiotr Jasiukajtis 			case 0xc9: /* convert single to double */
443*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_double;
444*25c28e83SPiotr Jasiukajtis 				info->res.val.d = (double) info->op1.val.f;
445*25c28e83SPiotr Jasiukajtis 				break;
446*25c28e83SPiotr Jasiukajtis 
447*25c28e83SPiotr Jasiukajtis 			case 0xcb: /* convert quad to double */
448*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_double;
449*25c28e83SPiotr Jasiukajtis 				info->res.val.d = (double) info->op1.val.q;
450*25c28e83SPiotr Jasiukajtis 				break;
451*25c28e83SPiotr Jasiukajtis 
452*25c28e83SPiotr Jasiukajtis 			case 0xcd: /* convert single to quad */
453*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_ldouble;
454*25c28e83SPiotr Jasiukajtis 				info->res.val.q = (long double) info->op1.val.f;
455*25c28e83SPiotr Jasiukajtis 				break;
456*25c28e83SPiotr Jasiukajtis 
457*25c28e83SPiotr Jasiukajtis 			case 0xce: /* convert double to quad */
458*25c28e83SPiotr Jasiukajtis 				info->res.type = fex_ldouble;
459*25c28e83SPiotr Jasiukajtis 				info->res.val.q = (long double) info->op1.val.d;
460*25c28e83SPiotr Jasiukajtis 				break;
461*25c28e83SPiotr Jasiukajtis 			}
462*25c28e83SPiotr Jasiukajtis 		}
463*25c28e83SPiotr Jasiukajtis 		break;
464*25c28e83SPiotr Jasiukajtis 	}
465*25c28e83SPiotr Jasiukajtis 	__fenv_getfsr(&fsr);
466*25c28e83SPiotr Jasiukajtis 	info->flags = (int)__fenv_get_ex(fsr);
467*25c28e83SPiotr Jasiukajtis 	__fenv_set_ex(fsr, 0);
468*25c28e83SPiotr Jasiukajtis 	__fenv_setfsr(&fsr);
469*25c28e83SPiotr Jasiukajtis }
470*25c28e83SPiotr Jasiukajtis 
471*25c28e83SPiotr Jasiukajtis /*
472*25c28e83SPiotr Jasiukajtis *  Store the specified result; if no result is given but the exception
473*25c28e83SPiotr Jasiukajtis *  is underflow or overflow, supply the default trapped result
474*25c28e83SPiotr Jasiukajtis */
475*25c28e83SPiotr Jasiukajtis void
__fex_st_result(siginfo_t * sip,ucontext_t * uap,fex_info_t * info)476*25c28e83SPiotr Jasiukajtis __fex_st_result(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
477*25c28e83SPiotr Jasiukajtis {
478*25c28e83SPiotr Jasiukajtis 	unsigned		instr, opf, rs1, rs2, rd;
479*25c28e83SPiotr Jasiukajtis 	long double		qscl;
480*25c28e83SPiotr Jasiukajtis 	double			dscl;
481*25c28e83SPiotr Jasiukajtis 	float			fscl;
482*25c28e83SPiotr Jasiukajtis 
483*25c28e83SPiotr Jasiukajtis 	/* parse the instruction which caused the exception */
484*25c28e83SPiotr Jasiukajtis 	instr = uap->uc_mcontext.fpregs.fpu_q->FQu.fpq.fpq_instr;
485*25c28e83SPiotr Jasiukajtis 	opf = (instr >> 5) & 0x1ff;
486*25c28e83SPiotr Jasiukajtis 	rs1 = (instr >> 14) & 0x1f;
487*25c28e83SPiotr Jasiukajtis 	rs2 = instr & 0x1f;
488*25c28e83SPiotr Jasiukajtis 	rd = (instr >> 25) & 0x1f;
489*25c28e83SPiotr Jasiukajtis 
490*25c28e83SPiotr Jasiukajtis 	/* if the instruction is a compare, just set fcc to unordered */
491*25c28e83SPiotr Jasiukajtis 	if (((instr >> 19) & 0x183f) == 0x1035) {
492*25c28e83SPiotr Jasiukajtis 		if (rd == 0)
493*25c28e83SPiotr Jasiukajtis 			uap->uc_mcontext.fpregs.fpu_fsr |= 0xc00;
494*25c28e83SPiotr Jasiukajtis 		else {
495*25c28e83SPiotr Jasiukajtis #ifdef __sparcv9
496*25c28e83SPiotr Jasiukajtis 			uap->uc_mcontext.fpregs.fpu_fsr |= (3l << ((rd << 1) + 30));
497*25c28e83SPiotr Jasiukajtis #else
498*25c28e83SPiotr Jasiukajtis 			((prxregset_t*)uap->uc_mcontext.xrs.xrs_ptr)->pr_un.pr_v8p.pr_xfsr |= (3 << ((rd - 1) << 1));
499*25c28e83SPiotr Jasiukajtis #endif
500*25c28e83SPiotr Jasiukajtis 		}
501*25c28e83SPiotr Jasiukajtis 		return;
502*25c28e83SPiotr Jasiukajtis 	}
503*25c28e83SPiotr Jasiukajtis 
504*25c28e83SPiotr Jasiukajtis 	/* if there is no result available, try to generate the untrapped
505*25c28e83SPiotr Jasiukajtis 	   default */
506*25c28e83SPiotr Jasiukajtis 	if (info->res.type == fex_nodata) {
507*25c28e83SPiotr Jasiukajtis 		/* set scale factors for exponent wrapping */
508*25c28e83SPiotr Jasiukajtis 		switch (sip->si_code) {
509*25c28e83SPiotr Jasiukajtis 		case FPE_FLTOVF:
510*25c28e83SPiotr Jasiukajtis 			fscl = 1.262177448e-29f;	/* 2^-96 */
511*25c28e83SPiotr Jasiukajtis 			dscl = 6.441148769597133308e-232;	/* 2^-768 */
512*25c28e83SPiotr Jasiukajtis 			qscl = 8.778357852076208839765066529179033145e-3700l;/* 2^-12288 */
513*25c28e83SPiotr Jasiukajtis 			break;
514*25c28e83SPiotr Jasiukajtis 
515*25c28e83SPiotr Jasiukajtis 		case FPE_FLTUND:
516*25c28e83SPiotr Jasiukajtis 			fscl = 7.922816251e+28f;	/* 2^96 */
517*25c28e83SPiotr Jasiukajtis 			dscl = 1.552518092300708935e+231;	/* 2^768 */
518*25c28e83SPiotr Jasiukajtis 			qscl = 1.139165225263043370845938579315932009e+3699l;/* 2^12288 */
519*25c28e83SPiotr Jasiukajtis 			break;
520*25c28e83SPiotr Jasiukajtis 
521*25c28e83SPiotr Jasiukajtis 		default:
522*25c28e83SPiotr Jasiukajtis 			/* user may have blown away the default result by mistake,
523*25c28e83SPiotr Jasiukajtis 			   so try to regenerate it */
524*25c28e83SPiotr Jasiukajtis 			(void) __fex_get_op(sip, uap, info);
525*25c28e83SPiotr Jasiukajtis 			if (info->res.type != fex_nodata)
526*25c28e83SPiotr Jasiukajtis 				goto stuff;
527*25c28e83SPiotr Jasiukajtis 			/* couldn't do it */
528*25c28e83SPiotr Jasiukajtis 			return;
529*25c28e83SPiotr Jasiukajtis 		}
530*25c28e83SPiotr Jasiukajtis 
531*25c28e83SPiotr Jasiukajtis 		/* get the operands */
532*25c28e83SPiotr Jasiukajtis 		switch (opf & 3) {
533*25c28e83SPiotr Jasiukajtis 		case 1: /* single */
534*25c28e83SPiotr Jasiukajtis 			info->op1.val.f = *(float*)FPreg(rs1);
535*25c28e83SPiotr Jasiukajtis 			info->op2.val.f = *(float*)FPreg(rs2);
536*25c28e83SPiotr Jasiukajtis 			break;
537*25c28e83SPiotr Jasiukajtis 
538*25c28e83SPiotr Jasiukajtis 		case 2: /* double */
539*25c28e83SPiotr Jasiukajtis 			info->op1.val.d = *(double*)FPREG(rs1);
540*25c28e83SPiotr Jasiukajtis 			info->op2.val.d = *(double*)FPREG(rs2);
541*25c28e83SPiotr Jasiukajtis 			break;
542*25c28e83SPiotr Jasiukajtis 
543*25c28e83SPiotr Jasiukajtis 		case 3: /* quad */
544*25c28e83SPiotr Jasiukajtis 			info->op1.val.q = *(long double*)FPREG(rs1);
545*25c28e83SPiotr Jasiukajtis 			info->op2.val.q = *(long double*)FPREG(rs2);
546*25c28e83SPiotr Jasiukajtis 			break;
547*25c28e83SPiotr Jasiukajtis 		}
548*25c28e83SPiotr Jasiukajtis 
549*25c28e83SPiotr Jasiukajtis 		/* generate the wrapped result */
550*25c28e83SPiotr Jasiukajtis 		switch (opf) {
551*25c28e83SPiotr Jasiukajtis 		case 0x41: /* add single */
552*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_float;
553*25c28e83SPiotr Jasiukajtis 			info->res.val.f = fscl * (fscl * info->op1.val.f +
554*25c28e83SPiotr Jasiukajtis 				fscl * info->op2.val.f);
555*25c28e83SPiotr Jasiukajtis 			break;
556*25c28e83SPiotr Jasiukajtis 
557*25c28e83SPiotr Jasiukajtis 		case 0x42: /* add double */
558*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_double;
559*25c28e83SPiotr Jasiukajtis 			info->res.val.d = dscl * (dscl * info->op1.val.d +
560*25c28e83SPiotr Jasiukajtis 				dscl * info->op2.val.d);
561*25c28e83SPiotr Jasiukajtis 			break;
562*25c28e83SPiotr Jasiukajtis 
563*25c28e83SPiotr Jasiukajtis 		case 0x43: /* add quad */
564*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_ldouble;
565*25c28e83SPiotr Jasiukajtis 			info->res.val.q = qscl * (qscl * info->op1.val.q +
566*25c28e83SPiotr Jasiukajtis 				qscl * info->op2.val.q);
567*25c28e83SPiotr Jasiukajtis 			break;
568*25c28e83SPiotr Jasiukajtis 
569*25c28e83SPiotr Jasiukajtis 		case 0x45: /* subtract single */
570*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_float;
571*25c28e83SPiotr Jasiukajtis 			info->res.val.f = fscl * (fscl * info->op1.val.f -
572*25c28e83SPiotr Jasiukajtis 				fscl * info->op2.val.f);
573*25c28e83SPiotr Jasiukajtis 			break;
574*25c28e83SPiotr Jasiukajtis 
575*25c28e83SPiotr Jasiukajtis 		case 0x46: /* subtract double */
576*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_double;
577*25c28e83SPiotr Jasiukajtis 			info->res.val.d = dscl * (dscl * info->op1.val.d -
578*25c28e83SPiotr Jasiukajtis 				dscl * info->op2.val.d);
579*25c28e83SPiotr Jasiukajtis 			break;
580*25c28e83SPiotr Jasiukajtis 
581*25c28e83SPiotr Jasiukajtis 		case 0x47: /* subtract quad */
582*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_ldouble;
583*25c28e83SPiotr Jasiukajtis 			info->res.val.q = qscl * (qscl * info->op1.val.q -
584*25c28e83SPiotr Jasiukajtis 				qscl * info->op2.val.q);
585*25c28e83SPiotr Jasiukajtis 			break;
586*25c28e83SPiotr Jasiukajtis 
587*25c28e83SPiotr Jasiukajtis 		case 0x49: /* multiply single */
588*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_float;
589*25c28e83SPiotr Jasiukajtis 			info->res.val.f = (fscl * info->op1.val.f) *
590*25c28e83SPiotr Jasiukajtis 				(fscl * info->op2.val.f);
591*25c28e83SPiotr Jasiukajtis 			break;
592*25c28e83SPiotr Jasiukajtis 
593*25c28e83SPiotr Jasiukajtis 		case 0x4a: /* multiply double */
594*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_double;
595*25c28e83SPiotr Jasiukajtis 			info->res.val.d = (dscl * info->op1.val.d) *
596*25c28e83SPiotr Jasiukajtis 				(dscl * info->op2.val.d);
597*25c28e83SPiotr Jasiukajtis 			break;
598*25c28e83SPiotr Jasiukajtis 
599*25c28e83SPiotr Jasiukajtis 		case 0x4b: /* multiply quad */
600*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_ldouble;
601*25c28e83SPiotr Jasiukajtis 			info->res.val.q = (qscl * info->op1.val.q) *
602*25c28e83SPiotr Jasiukajtis 				(qscl * info->op2.val.q);
603*25c28e83SPiotr Jasiukajtis 			break;
604*25c28e83SPiotr Jasiukajtis 
605*25c28e83SPiotr Jasiukajtis 		case 0x4d: /* divide single */
606*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_float;
607*25c28e83SPiotr Jasiukajtis 			info->res.val.f = (fscl * info->op1.val.f) /
608*25c28e83SPiotr Jasiukajtis 				(info->op2.val.f / fscl);
609*25c28e83SPiotr Jasiukajtis 			break;
610*25c28e83SPiotr Jasiukajtis 
611*25c28e83SPiotr Jasiukajtis 		case 0x4e: /* divide double */
612*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_double;
613*25c28e83SPiotr Jasiukajtis 			info->res.val.d = (dscl * info->op1.val.d) /
614*25c28e83SPiotr Jasiukajtis 				(info->op2.val.d / dscl);
615*25c28e83SPiotr Jasiukajtis 			break;
616*25c28e83SPiotr Jasiukajtis 
617*25c28e83SPiotr Jasiukajtis 		case 0x4f: /* divide quad */
618*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_ldouble;
619*25c28e83SPiotr Jasiukajtis 			info->res.val.q = (qscl * info->op1.val.q) /
620*25c28e83SPiotr Jasiukajtis 				(info->op2.val.q / qscl);
621*25c28e83SPiotr Jasiukajtis 			break;
622*25c28e83SPiotr Jasiukajtis 
623*25c28e83SPiotr Jasiukajtis 		case 0xc6: /* convert double to single */
624*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_float;
625*25c28e83SPiotr Jasiukajtis 			info->res.val.f = (float) (fscl * (fscl * info->op1.val.d));
626*25c28e83SPiotr Jasiukajtis 			break;
627*25c28e83SPiotr Jasiukajtis 
628*25c28e83SPiotr Jasiukajtis 		case 0xc7: /* convert quad to single */
629*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_float;
630*25c28e83SPiotr Jasiukajtis 			info->res.val.f = (float) (fscl * (fscl * info->op1.val.q));
631*25c28e83SPiotr Jasiukajtis 			break;
632*25c28e83SPiotr Jasiukajtis 
633*25c28e83SPiotr Jasiukajtis 		case 0xcb: /* convert quad to double */
634*25c28e83SPiotr Jasiukajtis 			info->res.type = fex_double;
635*25c28e83SPiotr Jasiukajtis 			info->res.val.d = (double) (dscl * (dscl * info->op1.val.q));
636*25c28e83SPiotr Jasiukajtis 			break;
637*25c28e83SPiotr Jasiukajtis 		}
638*25c28e83SPiotr Jasiukajtis 
639*25c28e83SPiotr Jasiukajtis 		if (info->res.type == fex_nodata)
640*25c28e83SPiotr Jasiukajtis 			/* couldn't do it */
641*25c28e83SPiotr Jasiukajtis 			return;
642*25c28e83SPiotr Jasiukajtis 	}
643*25c28e83SPiotr Jasiukajtis 
644*25c28e83SPiotr Jasiukajtis stuff:
645*25c28e83SPiotr Jasiukajtis 	/* stick the result in the destination */
646*25c28e83SPiotr Jasiukajtis 	if (opf & 0x80) { /* conversion */
647*25c28e83SPiotr Jasiukajtis 		if (opf & 0x10) { /* result is an int */
648*25c28e83SPiotr Jasiukajtis 			switch (info->res.type) {
649*25c28e83SPiotr Jasiukajtis 			case fex_llong:
650*25c28e83SPiotr Jasiukajtis 				info->res.val.i = (int) info->res.val.l;
651*25c28e83SPiotr Jasiukajtis 				break;
652*25c28e83SPiotr Jasiukajtis 
653*25c28e83SPiotr Jasiukajtis 			case fex_float:
654*25c28e83SPiotr Jasiukajtis 				info->res.val.i = (int) info->res.val.f;
655*25c28e83SPiotr Jasiukajtis 				break;
656*25c28e83SPiotr Jasiukajtis 
657*25c28e83SPiotr Jasiukajtis 			case fex_double:
658*25c28e83SPiotr Jasiukajtis 				info->res.val.i = (int) info->res.val.d;
659*25c28e83SPiotr Jasiukajtis 				break;
660*25c28e83SPiotr Jasiukajtis 
661*25c28e83SPiotr Jasiukajtis 			case fex_ldouble:
662*25c28e83SPiotr Jasiukajtis 				info->res.val.i = (int) info->res.val.q;
663*25c28e83SPiotr Jasiukajtis 				break;
664*25c28e83SPiotr Jasiukajtis 
665*25c28e83SPiotr Jasiukajtis 			default:
666*25c28e83SPiotr Jasiukajtis 				break;
667*25c28e83SPiotr Jasiukajtis 			}
668*25c28e83SPiotr Jasiukajtis 			*(int*)FPreg(rd) = info->res.val.i;
669*25c28e83SPiotr Jasiukajtis 			return;
670*25c28e83SPiotr Jasiukajtis 		}
671*25c28e83SPiotr Jasiukajtis 
672*25c28e83SPiotr Jasiukajtis 		switch (opf & 0xc) {
673*25c28e83SPiotr Jasiukajtis 		case 0: /* result is long long */
674*25c28e83SPiotr Jasiukajtis 			switch (info->res.type) {
675*25c28e83SPiotr Jasiukajtis 			case fex_int:
676*25c28e83SPiotr Jasiukajtis 				info->res.val.l = (long long) info->res.val.i;
677*25c28e83SPiotr Jasiukajtis 				break;
678*25c28e83SPiotr Jasiukajtis 
679*25c28e83SPiotr Jasiukajtis 			case fex_float:
680*25c28e83SPiotr Jasiukajtis 				info->res.val.l = (long long) info->res.val.f;
681*25c28e83SPiotr Jasiukajtis 				break;
682*25c28e83SPiotr Jasiukajtis 
683*25c28e83SPiotr Jasiukajtis 			case fex_double:
684*25c28e83SPiotr Jasiukajtis 				info->res.val.l = (long long) info->res.val.d;
685*25c28e83SPiotr Jasiukajtis 				break;
686*25c28e83SPiotr Jasiukajtis 
687*25c28e83SPiotr Jasiukajtis 			case fex_ldouble:
688*25c28e83SPiotr Jasiukajtis 				info->res.val.l = (long long) info->res.val.q;
689*25c28e83SPiotr Jasiukajtis 				break;
690*25c28e83SPiotr Jasiukajtis 
691*25c28e83SPiotr Jasiukajtis 			default:
692*25c28e83SPiotr Jasiukajtis 				break;
693*25c28e83SPiotr Jasiukajtis 			}
694*25c28e83SPiotr Jasiukajtis 			*(long long*)FPREG(rd) = info->res.val.l;
695*25c28e83SPiotr Jasiukajtis 			break;
696*25c28e83SPiotr Jasiukajtis 
697*25c28e83SPiotr Jasiukajtis 		case 0x4: /* result is float */
698*25c28e83SPiotr Jasiukajtis 			switch (info->res.type) {
699*25c28e83SPiotr Jasiukajtis 			case fex_int:
700*25c28e83SPiotr Jasiukajtis 				info->res.val.f = (float) info->res.val.i;
701*25c28e83SPiotr Jasiukajtis 				break;
702*25c28e83SPiotr Jasiukajtis 
703*25c28e83SPiotr Jasiukajtis 			case fex_llong:
704*25c28e83SPiotr Jasiukajtis 				info->res.val.f = (float) info->res.val.l;
705*25c28e83SPiotr Jasiukajtis 				break;
706*25c28e83SPiotr Jasiukajtis 
707*25c28e83SPiotr Jasiukajtis 			case fex_double:
708*25c28e83SPiotr Jasiukajtis 				info->res.val.f = (float) info->res.val.d;
709*25c28e83SPiotr Jasiukajtis 				break;
710*25c28e83SPiotr Jasiukajtis 
711*25c28e83SPiotr Jasiukajtis 			case fex_ldouble:
712*25c28e83SPiotr Jasiukajtis 				info->res.val.f = (float) info->res.val.q;
713*25c28e83SPiotr Jasiukajtis 				break;
714*25c28e83SPiotr Jasiukajtis 
715*25c28e83SPiotr Jasiukajtis 			default:
716*25c28e83SPiotr Jasiukajtis 				break;
717*25c28e83SPiotr Jasiukajtis 			}
718*25c28e83SPiotr Jasiukajtis 			*(float*)FPreg(rd) = info->res.val.f;
719*25c28e83SPiotr Jasiukajtis 			break;
720*25c28e83SPiotr Jasiukajtis 
721*25c28e83SPiotr Jasiukajtis 		case 0x8: /* result is double */
722*25c28e83SPiotr Jasiukajtis 			switch (info->res.type) {
723*25c28e83SPiotr Jasiukajtis 			case fex_int:
724*25c28e83SPiotr Jasiukajtis 				info->res.val.d = (double) info->res.val.i;
725*25c28e83SPiotr Jasiukajtis 				break;
726*25c28e83SPiotr Jasiukajtis 
727*25c28e83SPiotr Jasiukajtis 			case fex_llong:
728*25c28e83SPiotr Jasiukajtis 				info->res.val.d = (double) info->res.val.l;
729*25c28e83SPiotr Jasiukajtis 				break;
730*25c28e83SPiotr Jasiukajtis 
731*25c28e83SPiotr Jasiukajtis 			case fex_float:
732*25c28e83SPiotr Jasiukajtis 				info->res.val.d = (double) info->res.val.f;
733*25c28e83SPiotr Jasiukajtis 				break;
734*25c28e83SPiotr Jasiukajtis 
735*25c28e83SPiotr Jasiukajtis 			case fex_ldouble:
736*25c28e83SPiotr Jasiukajtis 				info->res.val.d = (double) info->res.val.q;
737*25c28e83SPiotr Jasiukajtis 				break;
738*25c28e83SPiotr Jasiukajtis 
739*25c28e83SPiotr Jasiukajtis 			default:
740*25c28e83SPiotr Jasiukajtis 				break;
741*25c28e83SPiotr Jasiukajtis 			}
742*25c28e83SPiotr Jasiukajtis 			*(double*)FPREG(rd) = info->res.val.d;
743*25c28e83SPiotr Jasiukajtis 			break;
744*25c28e83SPiotr Jasiukajtis 
745*25c28e83SPiotr Jasiukajtis 		case 0xc: /* result is long double */
746*25c28e83SPiotr Jasiukajtis 			switch (info->res.type) {
747*25c28e83SPiotr Jasiukajtis 			case fex_int:
748*25c28e83SPiotr Jasiukajtis 				info->res.val.q = (long double) info->res.val.i;
749*25c28e83SPiotr Jasiukajtis 				break;
750*25c28e83SPiotr Jasiukajtis 
751*25c28e83SPiotr Jasiukajtis 			case fex_llong:
752*25c28e83SPiotr Jasiukajtis 				info->res.val.q = (long double) info->res.val.l;
753*25c28e83SPiotr Jasiukajtis 				break;
754*25c28e83SPiotr Jasiukajtis 
755*25c28e83SPiotr Jasiukajtis 			case fex_float:
756*25c28e83SPiotr Jasiukajtis 				info->res.val.q = (long double) info->res.val.f;
757*25c28e83SPiotr Jasiukajtis 				break;
758*25c28e83SPiotr Jasiukajtis 
759*25c28e83SPiotr Jasiukajtis 			case fex_double:
760*25c28e83SPiotr Jasiukajtis 				info->res.val.q = (long double) info->res.val.d;
761*25c28e83SPiotr Jasiukajtis 				break;
762*25c28e83SPiotr Jasiukajtis 
763*25c28e83SPiotr Jasiukajtis 			default:
764*25c28e83SPiotr Jasiukajtis 				break;
765*25c28e83SPiotr Jasiukajtis 			}
766*25c28e83SPiotr Jasiukajtis 			*(long double*)FPREG(rd) = info->res.val.q;
767*25c28e83SPiotr Jasiukajtis 			break;
768*25c28e83SPiotr Jasiukajtis 		}
769*25c28e83SPiotr Jasiukajtis 		return;
770*25c28e83SPiotr Jasiukajtis 	}
771*25c28e83SPiotr Jasiukajtis 
772*25c28e83SPiotr Jasiukajtis 	if ((opf & 0xf0) == 0x60) { /* fsmuld, fdmulq */
773*25c28e83SPiotr Jasiukajtis 		switch (opf & 0xc0) {
774*25c28e83SPiotr Jasiukajtis 		case 0x8: /* result is double */
775*25c28e83SPiotr Jasiukajtis 			switch (info->res.type) {
776*25c28e83SPiotr Jasiukajtis 			case fex_int:
777*25c28e83SPiotr Jasiukajtis 				info->res.val.d = (double) info->res.val.i;
778*25c28e83SPiotr Jasiukajtis 				break;
779*25c28e83SPiotr Jasiukajtis 
780*25c28e83SPiotr Jasiukajtis 			case fex_llong:
781*25c28e83SPiotr Jasiukajtis 				info->res.val.d = (double) info->res.val.l;
782*25c28e83SPiotr Jasiukajtis 				break;
783*25c28e83SPiotr Jasiukajtis 
784*25c28e83SPiotr Jasiukajtis 			case fex_float:
785*25c28e83SPiotr Jasiukajtis 				info->res.val.d = (double) info->res.val.f;
786*25c28e83SPiotr Jasiukajtis 				break;
787*25c28e83SPiotr Jasiukajtis 
788*25c28e83SPiotr Jasiukajtis 			case fex_ldouble:
789*25c28e83SPiotr Jasiukajtis 				info->res.val.d = (double) info->res.val.q;
790*25c28e83SPiotr Jasiukajtis 				break;
791*25c28e83SPiotr Jasiukajtis 
792*25c28e83SPiotr Jasiukajtis 			default:
793*25c28e83SPiotr Jasiukajtis 				break;
794*25c28e83SPiotr Jasiukajtis 			}
795*25c28e83SPiotr Jasiukajtis 			*(double*)FPREG(rd) = info->res.val.d;
796*25c28e83SPiotr Jasiukajtis 			break;
797*25c28e83SPiotr Jasiukajtis 
798*25c28e83SPiotr Jasiukajtis 		case 0xc: /* result is long double */
799*25c28e83SPiotr Jasiukajtis 			switch (info->res.type) {
800*25c28e83SPiotr Jasiukajtis 			case fex_int:
801*25c28e83SPiotr Jasiukajtis 				info->res.val.q = (long double) info->res.val.i;
802*25c28e83SPiotr Jasiukajtis 				break;
803*25c28e83SPiotr Jasiukajtis 
804*25c28e83SPiotr Jasiukajtis 			case fex_llong:
805*25c28e83SPiotr Jasiukajtis 				info->res.val.q = (long double) info->res.val.l;
806*25c28e83SPiotr Jasiukajtis 				break;
807*25c28e83SPiotr Jasiukajtis 
808*25c28e83SPiotr Jasiukajtis 			case fex_float:
809*25c28e83SPiotr Jasiukajtis 				info->res.val.q = (long double) info->res.val.f;
810*25c28e83SPiotr Jasiukajtis 				break;
811*25c28e83SPiotr Jasiukajtis 
812*25c28e83SPiotr Jasiukajtis 			case fex_double:
813*25c28e83SPiotr Jasiukajtis 				info->res.val.q = (long double) info->res.val.d;
814*25c28e83SPiotr Jasiukajtis 				break;
815*25c28e83SPiotr Jasiukajtis 
816*25c28e83SPiotr Jasiukajtis 			default:
817*25c28e83SPiotr Jasiukajtis 				break;
818*25c28e83SPiotr Jasiukajtis 			}
819*25c28e83SPiotr Jasiukajtis 			*(long double*)FPREG(rd) = info->res.val.q;
820*25c28e83SPiotr Jasiukajtis 			break;
821*25c28e83SPiotr Jasiukajtis 		}
822*25c28e83SPiotr Jasiukajtis 		return;
823*25c28e83SPiotr Jasiukajtis 	}
824*25c28e83SPiotr Jasiukajtis 
825*25c28e83SPiotr Jasiukajtis 	switch (opf & 3) { /* other arithmetic op */
826*25c28e83SPiotr Jasiukajtis 	case 1: /* result is float */
827*25c28e83SPiotr Jasiukajtis 		switch (info->res.type) {
828*25c28e83SPiotr Jasiukajtis 		case fex_int:
829*25c28e83SPiotr Jasiukajtis 			info->res.val.f = (float) info->res.val.i;
830*25c28e83SPiotr Jasiukajtis 			break;
831*25c28e83SPiotr Jasiukajtis 
832*25c28e83SPiotr Jasiukajtis 		case fex_llong:
833*25c28e83SPiotr Jasiukajtis 			info->res.val.f = (float) info->res.val.l;
834*25c28e83SPiotr Jasiukajtis 			break;
835*25c28e83SPiotr Jasiukajtis 
836*25c28e83SPiotr Jasiukajtis 		case fex_double:
837*25c28e83SPiotr Jasiukajtis 			info->res.val.f = (float) info->res.val.d;
838*25c28e83SPiotr Jasiukajtis 			break;
839*25c28e83SPiotr Jasiukajtis 
840*25c28e83SPiotr Jasiukajtis 		case fex_ldouble:
841*25c28e83SPiotr Jasiukajtis 			info->res.val.f = (float) info->res.val.q;
842*25c28e83SPiotr Jasiukajtis 			break;
843*25c28e83SPiotr Jasiukajtis 
844*25c28e83SPiotr Jasiukajtis 		default:
845*25c28e83SPiotr Jasiukajtis 			break;
846*25c28e83SPiotr Jasiukajtis 		}
847*25c28e83SPiotr Jasiukajtis 		*(float*)FPreg(rd) = info->res.val.f;
848*25c28e83SPiotr Jasiukajtis 		break;
849*25c28e83SPiotr Jasiukajtis 
850*25c28e83SPiotr Jasiukajtis 	case 2: /* result is double */
851*25c28e83SPiotr Jasiukajtis 		switch (info->res.type) {
852*25c28e83SPiotr Jasiukajtis 		case fex_int:
853*25c28e83SPiotr Jasiukajtis 			info->res.val.d = (double) info->res.val.i;
854*25c28e83SPiotr Jasiukajtis 			break;
855*25c28e83SPiotr Jasiukajtis 
856*25c28e83SPiotr Jasiukajtis 		case fex_llong:
857*25c28e83SPiotr Jasiukajtis 			info->res.val.d = (double) info->res.val.l;
858*25c28e83SPiotr Jasiukajtis 			break;
859*25c28e83SPiotr Jasiukajtis 
860*25c28e83SPiotr Jasiukajtis 		case fex_float:
861*25c28e83SPiotr Jasiukajtis 			info->res.val.d = (double) info->res.val.f;
862*25c28e83SPiotr Jasiukajtis 			break;
863*25c28e83SPiotr Jasiukajtis 
864*25c28e83SPiotr Jasiukajtis 		case fex_ldouble:
865*25c28e83SPiotr Jasiukajtis 			info->res.val.d = (double) info->res.val.q;
866*25c28e83SPiotr Jasiukajtis 			break;
867*25c28e83SPiotr Jasiukajtis 
868*25c28e83SPiotr Jasiukajtis 		default:
869*25c28e83SPiotr Jasiukajtis 			break;
870*25c28e83SPiotr Jasiukajtis 		}
871*25c28e83SPiotr Jasiukajtis 		*(double*)FPREG(rd) = info->res.val.d;
872*25c28e83SPiotr Jasiukajtis 		break;
873*25c28e83SPiotr Jasiukajtis 
874*25c28e83SPiotr Jasiukajtis 	case 3: /* result is long double */
875*25c28e83SPiotr Jasiukajtis 		switch (info->res.type) {
876*25c28e83SPiotr Jasiukajtis 		case fex_int:
877*25c28e83SPiotr Jasiukajtis 			info->res.val.q = (long double) info->res.val.i;
878*25c28e83SPiotr Jasiukajtis 			break;
879*25c28e83SPiotr Jasiukajtis 
880*25c28e83SPiotr Jasiukajtis 		case fex_llong:
881*25c28e83SPiotr Jasiukajtis 			info->res.val.q = (long double) info->res.val.l;
882*25c28e83SPiotr Jasiukajtis 			break;
883*25c28e83SPiotr Jasiukajtis 
884*25c28e83SPiotr Jasiukajtis 		case fex_float:
885*25c28e83SPiotr Jasiukajtis 			info->res.val.q = (long double) info->res.val.f;
886*25c28e83SPiotr Jasiukajtis 			break;
887*25c28e83SPiotr Jasiukajtis 
888*25c28e83SPiotr Jasiukajtis 		case fex_double:
889*25c28e83SPiotr Jasiukajtis 			info->res.val.q = (long double) info->res.val.d;
890*25c28e83SPiotr Jasiukajtis 			break;
891*25c28e83SPiotr Jasiukajtis 
892*25c28e83SPiotr Jasiukajtis 		default:
893*25c28e83SPiotr Jasiukajtis 			break;
894*25c28e83SPiotr Jasiukajtis 		}
895*25c28e83SPiotr Jasiukajtis 		*(long double*)FPREG(rd) = info->res.val.q;
896*25c28e83SPiotr Jasiukajtis 		break;
897*25c28e83SPiotr Jasiukajtis 	}
898*25c28e83SPiotr Jasiukajtis }
899*25c28e83SPiotr Jasiukajtis #endif	/* defined(__sparc) */
900