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 default: 667 break; 668 } 669 *(int*)FPreg(rd) = info->res.val.i; 670 return; 671 } 672 673 switch (opf & 0xc) { 674 case 0: /* result is long long */ 675 switch (info->res.type) { 676 case fex_int: 677 info->res.val.l = (long long) info->res.val.i; 678 break; 679 680 case fex_float: 681 info->res.val.l = (long long) info->res.val.f; 682 break; 683 684 case fex_double: 685 info->res.val.l = (long long) info->res.val.d; 686 break; 687 688 case fex_ldouble: 689 info->res.val.l = (long long) info->res.val.q; 690 break; 691 692 default: 693 break; 694 } 695 *(long long*)FPREG(rd) = info->res.val.l; 696 break; 697 698 case 0x4: /* result is float */ 699 switch (info->res.type) { 700 case fex_int: 701 info->res.val.f = (float) info->res.val.i; 702 break; 703 704 case fex_llong: 705 info->res.val.f = (float) info->res.val.l; 706 break; 707 708 case fex_double: 709 info->res.val.f = (float) info->res.val.d; 710 break; 711 712 case fex_ldouble: 713 info->res.val.f = (float) info->res.val.q; 714 break; 715 716 default: 717 break; 718 } 719 *(float*)FPreg(rd) = info->res.val.f; 720 break; 721 722 case 0x8: /* result is double */ 723 switch (info->res.type) { 724 case fex_int: 725 info->res.val.d = (double) info->res.val.i; 726 break; 727 728 case fex_llong: 729 info->res.val.d = (double) info->res.val.l; 730 break; 731 732 case fex_float: 733 info->res.val.d = (double) info->res.val.f; 734 break; 735 736 case fex_ldouble: 737 info->res.val.d = (double) info->res.val.q; 738 break; 739 740 default: 741 break; 742 } 743 *(double*)FPREG(rd) = info->res.val.d; 744 break; 745 746 case 0xc: /* result is long double */ 747 switch (info->res.type) { 748 case fex_int: 749 info->res.val.q = (long double) info->res.val.i; 750 break; 751 752 case fex_llong: 753 info->res.val.q = (long double) info->res.val.l; 754 break; 755 756 case fex_float: 757 info->res.val.q = (long double) info->res.val.f; 758 break; 759 760 case fex_double: 761 info->res.val.q = (long double) info->res.val.d; 762 break; 763 764 default: 765 break; 766 } 767 *(long double*)FPREG(rd) = info->res.val.q; 768 break; 769 } 770 return; 771 } 772 773 if ((opf & 0xf0) == 0x60) { /* fsmuld, fdmulq */ 774 switch (opf & 0xc0) { 775 case 0x8: /* result is double */ 776 switch (info->res.type) { 777 case fex_int: 778 info->res.val.d = (double) info->res.val.i; 779 break; 780 781 case fex_llong: 782 info->res.val.d = (double) info->res.val.l; 783 break; 784 785 case fex_float: 786 info->res.val.d = (double) info->res.val.f; 787 break; 788 789 case fex_ldouble: 790 info->res.val.d = (double) info->res.val.q; 791 break; 792 793 default: 794 break; 795 } 796 *(double*)FPREG(rd) = info->res.val.d; 797 break; 798 799 case 0xc: /* result is long double */ 800 switch (info->res.type) { 801 case fex_int: 802 info->res.val.q = (long double) info->res.val.i; 803 break; 804 805 case fex_llong: 806 info->res.val.q = (long double) info->res.val.l; 807 break; 808 809 case fex_float: 810 info->res.val.q = (long double) info->res.val.f; 811 break; 812 813 case fex_double: 814 info->res.val.q = (long double) info->res.val.d; 815 break; 816 817 default: 818 break; 819 } 820 *(long double*)FPREG(rd) = info->res.val.q; 821 break; 822 } 823 return; 824 } 825 826 switch (opf & 3) { /* other arithmetic op */ 827 case 1: /* result is float */ 828 switch (info->res.type) { 829 case fex_int: 830 info->res.val.f = (float) info->res.val.i; 831 break; 832 833 case fex_llong: 834 info->res.val.f = (float) info->res.val.l; 835 break; 836 837 case fex_double: 838 info->res.val.f = (float) info->res.val.d; 839 break; 840 841 case fex_ldouble: 842 info->res.val.f = (float) info->res.val.q; 843 break; 844 845 default: 846 break; 847 } 848 *(float*)FPreg(rd) = info->res.val.f; 849 break; 850 851 case 2: /* result is double */ 852 switch (info->res.type) { 853 case fex_int: 854 info->res.val.d = (double) info->res.val.i; 855 break; 856 857 case fex_llong: 858 info->res.val.d = (double) info->res.val.l; 859 break; 860 861 case fex_float: 862 info->res.val.d = (double) info->res.val.f; 863 break; 864 865 case fex_ldouble: 866 info->res.val.d = (double) info->res.val.q; 867 break; 868 869 default: 870 break; 871 } 872 *(double*)FPREG(rd) = info->res.val.d; 873 break; 874 875 case 3: /* result is long double */ 876 switch (info->res.type) { 877 case fex_int: 878 info->res.val.q = (long double) info->res.val.i; 879 break; 880 881 case fex_llong: 882 info->res.val.q = (long double) info->res.val.l; 883 break; 884 885 case fex_float: 886 info->res.val.q = (long double) info->res.val.f; 887 break; 888 889 case fex_double: 890 info->res.val.q = (long double) info->res.val.d; 891 break; 892 893 default: 894 break; 895 } 896 *(long double*)FPREG(rd) = info->res.val.q; 897 break; 898 } 899 } 900 #endif /* defined(__sparc) */ 901