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) */