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