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