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