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