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 #include <stdio.h> 32 #include <unistd.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <signal.h> 36 #include <siginfo.h> 37 #include <ucontext.h> 38 #include <thread.h> 39 #include <math.h> 40 #if defined(__SUNPRO_C) 41 #include <sunmath.h> 42 #endif 43 #include <fenv.h> 44 #include "fex_handler.h" 45 #include "fenv_inlines.h" 46 47 #if defined(__amd64) 48 #define test_sse_hw 1 49 #else 50 /* 51 * The following variable lives in libc on Solaris 10, where it 52 * gets set to a nonzero value at startup time on systems with SSE. 53 */ 54 extern int _sse_hw; 55 56 #define test_sse_hw _sse_hw 57 #endif 58 59 static int accrued = 0; 60 static thread_key_t accrued_key; 61 static mutex_t accrued_key_lock = DEFAULTMUTEX; 62 int * 63 __fex_accrued() 64 { 65 int *p; 66 67 if (thr_main()) { 68 return (&accrued); 69 } else { 70 p = NULL; 71 mutex_lock(&accrued_key_lock); 72 73 if (thr_getspecific(accrued_key, (void **)&p) != 0 && 74 thr_keycreate(&accrued_key, free) != 0) { 75 mutex_unlock(&accrued_key_lock); 76 return (NULL); 77 } 78 79 mutex_unlock(&accrued_key_lock); 80 81 if (!p) { 82 if ((p = (int *)malloc(sizeof (int))) == NULL) 83 return (NULL); 84 85 if (thr_setspecific(accrued_key, (void *)p) != 0) { 86 (void) free(p); 87 return (NULL); 88 } 89 90 *p = 0; 91 } 92 93 return (p); 94 } 95 } 96 97 void 98 __fenv_getfsr(unsigned long *fsr) 99 { 100 unsigned int cwsw, mxcsr; 101 102 __fenv_getcwsw(&cwsw); 103 /* clear reserved bits for no particularly good reason */ 104 cwsw &= ~0xe0c00000u; 105 106 if (test_sse_hw) { 107 /* 108 * pick up exception flags (excluding denormal operand flag) 109 * from mxcsr 110 */ 111 __fenv_getmxcsr(&mxcsr); 112 cwsw |= (mxcsr & 0x3d); 113 } 114 115 cwsw |= *__fex_accrued(); 116 *fsr = cwsw ^ 0x003f0000u; 117 } 118 119 void 120 __fenv_setfsr(const unsigned long *fsr) 121 { 122 unsigned int cwsw, mxcsr; 123 int te; 124 125 /* save accrued exception flags corresponding to enabled exceptions */ 126 cwsw = (unsigned int)*fsr; 127 te = __fenv_get_te(cwsw); 128 *__fex_accrued() = cwsw & te; 129 cwsw = (cwsw & ~te) ^ 0x003f0000; 130 131 if (test_sse_hw) { 132 /* 133 * propagate rounding direction, masks, and exception flags 134 * (excluding denormal operand mask and flag) to mxcsr 135 */ 136 __fenv_getmxcsr(&mxcsr); 137 mxcsr = (mxcsr & ~0x7ebd) | ((cwsw >> 13) & 0x6000) | ((cwsw >> 138 9) & 0x1e80) | (cwsw & 0x3d); 139 __fenv_setmxcsr(&mxcsr); 140 } 141 142 __fenv_setcwsw(&cwsw); 143 } 144 145 /* Offsets into the fp environment save area (assumes 32-bit protected mode) */ 146 #define CW 0 /* control word */ 147 #define SW 1 /* status word */ 148 #define TW 2 /* tag word */ 149 #define IP 3 /* instruction pointer */ 150 #define OP 4 /* opcode */ 151 #define EA 5 /* operand address */ 152 153 /* macro for accessing fp registers in the save area */ 154 #if defined(__amd64) 155 #define fpreg(u, x) *(long double *)(10 * (x) + \ 156 (char *)&(u)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.st) 157 #else 158 #define fpreg(u, x) *(long double *)(10 * (x) + \ 159 (char *)&(u)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[7]) 160 #endif 161 162 /* 163 * Fix sip->si_code; the Solaris x86 kernel can get it wrong 164 */ 165 void 166 __fex_get_x86_exc(siginfo_t *sip, ucontext_t *uap) 167 { 168 unsigned sw, cw; 169 170 sw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status; 171 #if defined(__amd64) 172 cw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw; 173 #else 174 cw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[CW]; 175 #endif 176 177 if ((sw & FE_INVALID) && !(cw & (1 << fp_trap_invalid))) 178 /* store 0 for stack fault, FPE_FLTINV for IEEE invalid op */ 179 sip->si_code = ((sw & 0x40) ? 0 : FPE_FLTINV); 180 else if ((sw & FE_DIVBYZERO) && !(cw & (1 << fp_trap_division))) 181 sip->si_code = FPE_FLTDIV; 182 else if ((sw & FE_OVERFLOW) && !(cw & (1 << fp_trap_overflow))) 183 sip->si_code = FPE_FLTOVF; 184 else if ((sw & FE_UNDERFLOW) && !(cw & (1 << fp_trap_underflow))) 185 sip->si_code = FPE_FLTUND; 186 else if ((sw & FE_INEXACT) && !(cw & (1 << fp_trap_inexact))) 187 sip->si_code = FPE_FLTRES; 188 else 189 sip->si_code = 0; 190 } 191 192 static enum fp_class_type 193 my_fp_classf(float *x) 194 { 195 int i = *(int *)x & ~0x80000000; 196 197 if (i < 0x7f800000) { 198 if (i < 0x00800000) 199 return ((i == 0) ? fp_zero : fp_subnormal); 200 201 return (fp_normal); 202 } else if (i == 0x7f800000) { 203 return (fp_infinity); 204 } else if (i & 0x400000) { 205 return (fp_quiet); 206 } else { 207 return (fp_signaling); 208 } 209 } 210 211 static enum fp_class_type 212 my_fp_class(double *x) 213 { 214 int i = *(1 + (int *)x) & ~0x80000000; 215 216 if (i < 0x7ff00000) { 217 if (i < 0x00100000) 218 return (((i | *(int *)x) == 0) ? fp_zero : 219 fp_subnormal); 220 221 return (fp_normal); 222 } else if (i == 0x7ff00000 && *(int *)x == 0) { 223 return (fp_infinity); 224 } else if (i & 0x80000) { 225 return (fp_quiet); 226 } else { 227 return (fp_signaling); 228 } 229 } 230 231 static enum fp_class_type 232 my_fp_classl(long double *x) 233 { 234 int i = *(2 + (int *)x) & 0x7fff; 235 236 if (i < 0x7fff) { 237 if (i < 1) { 238 if (*(1 + (int *)x) < 0) 239 return (fp_normal); /* pseudo-denormal */ 240 241 return (((*(1 + (int *)x) | *(int *)x) == 0) ? fp_zero : 242 fp_subnormal); 243 } 244 245 return ((*(1 + (int *)x) < 0) ? fp_normal : 246 (enum fp_class_type)-1); /* unsupported format */ 247 } else if (*(1 + (int *)x) == 0x80000000 && *(int *)x == 0) { 248 return (fp_infinity); 249 } else if (*(1 + (unsigned *)x) >= 0xc0000000) { 250 return (fp_quiet); 251 } else if (*(1 + (int *)x) < 0) { 252 return (fp_signaling); 253 } else { 254 return ((enum fp_class_type)-1); /* unsupported format */ 255 } 256 } 257 258 /* 259 * Determine which type of invalid operation exception occurred 260 */ 261 enum fex_exception 262 __fex_get_invalid_type(siginfo_t *sip, ucontext_t *uap) 263 { 264 unsigned op; 265 unsigned long ea; 266 enum fp_class_type t1, t2; 267 268 /* get the opcode and data address */ 269 #if defined(__amd64) 270 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16; 271 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp; 272 #else 273 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16; 274 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA]; 275 #endif 276 277 /* 278 * if the instruction is fld, the source must be snan (it can't be 279 * an unsupported format, since fldt doesn't raise any exceptions) 280 */ 281 switch (op & 0x7f8) { 282 case 0x100: 283 case 0x140: 284 case 0x180: 285 case 0x500: 286 case 0x540: 287 case 0x580: 288 return (fex_inv_snan); 289 } 290 291 /* otherwise st is one of the operands; see if it's snan */ 292 t1 = my_fp_classl(&fpreg(uap, 0)); 293 294 if (t1 == fp_signaling) 295 return (fex_inv_snan); 296 else if (t1 == (enum fp_class_type)-1) 297 return ((enum fex_exception)-1); 298 299 /* determine the class of the second operand if there is one */ 300 t2 = fp_normal; 301 302 switch (op & 0x7e0) { 303 case 0x600: 304 case 0x620: 305 case 0x640: 306 case 0x660: 307 case 0x680: 308 case 0x6a0: 309 310 /* short memory operand */ 311 if (!ea) 312 return ((enum fex_exception)-1); 313 314 if (*(short *)ea == 0) 315 t2 = fp_zero; 316 317 break; 318 319 case 0x200: 320 case 0x220: 321 case 0x240: 322 case 0x260: 323 case 0x280: 324 case 0x2a0: 325 326 /* int memory operand */ 327 if (!ea) 328 return ((enum fex_exception)-1); 329 330 if (*(int *)ea == 0) 331 t2 = fp_zero; 332 333 break; 334 335 case 0x000: 336 case 0x020: 337 case 0x040: 338 case 0x060: 339 case 0x080: 340 case 0x0a0: 341 342 /* single precision memory operand */ 343 if (!ea) 344 return ((enum fex_exception)-1); 345 346 t2 = my_fp_classf((float *)ea); 347 break; 348 349 case 0x400: 350 case 0x420: 351 case 0x440: 352 case 0x460: 353 case 0x480: 354 case 0x4a0: 355 356 /* double precision memory operand */ 357 if (!ea) 358 return ((enum fex_exception)-1); 359 360 t2 = my_fp_class((double *)ea); 361 break; 362 363 case 0x0c0: 364 case 0x0e0: 365 case 0x3e0: 366 case 0x4c0: 367 case 0x4e0: 368 case 0x5e0: 369 case 0x6c0: 370 case 0x6e0: 371 case 0x7e0: 372 373 /* register operand determined by opcode */ 374 switch (op & 0x7f8) { 375 case 0x3e0: 376 case 0x3f8: 377 case 0x5f0: 378 case 0x5f8: 379 case 0x7e0: 380 case 0x7f8: 381 /* weed out nonexistent opcodes */ 382 break; 383 384 default: 385 t2 = my_fp_classl(&fpreg(uap, op & 7)); 386 } 387 388 break; 389 390 case 0x1e0: 391 case 0x2e0: 392 393 /* special forms */ 394 switch (op) { 395 case 0x1f1: /* fyl2x */ 396 case 0x1f3: /* fpatan */ 397 case 0x1f5: /* fprem1 */ 398 case 0x1f8: /* fprem */ 399 case 0x1f9: /* fyl2xp1 */ 400 case 0x1fd: /* fscale */ 401 case 0x2e9: /* fucompp */ 402 t2 = my_fp_classl(&fpreg(uap, 1)); 403 break; 404 } 405 406 break; 407 } 408 409 /* see if the second op is snan */ 410 if (t2 == fp_signaling) 411 return (fex_inv_snan); 412 else if (t2 == (enum fp_class_type)-1) 413 return ((enum fex_exception)-1); 414 415 /* determine the type of operation */ 416 switch (op & 0x7f8) { 417 case 0x000: 418 case 0x020: 419 case 0x028: 420 case 0x040: 421 case 0x060: 422 case 0x068: 423 case 0x080: 424 case 0x0a0: 425 case 0x0a8: 426 case 0x0c0: 427 case 0x0e0: 428 case 0x0e8: 429 case 0x400: 430 case 0x420: 431 case 0x428: 432 case 0x440: 433 case 0x460: 434 case 0x468: 435 case 0x480: 436 case 0x4a0: 437 case 0x4a8: 438 case 0x4c0: 439 case 0x4e0: 440 case 0x4e8: 441 case 0x6c0: 442 case 0x6e0: 443 case 0x6e8: 444 445 /* fadd, fsub, fsubr */ 446 if (t1 == fp_infinity && t2 == fp_infinity) 447 return (fex_inv_isi); 448 449 break; 450 451 case 0x008: 452 case 0x048: 453 case 0x088: 454 case 0x0c8: 455 case 0x208: 456 case 0x248: 457 case 0x288: 458 case 0x408: 459 case 0x448: 460 case 0x488: 461 case 0x4c8: 462 case 0x608: 463 case 0x648: 464 case 0x688: 465 case 0x6c8: 466 467 /* fmul */ 468 if ((t1 == fp_zero && t2 == fp_infinity) || (t2 == fp_zero && 469 t1 == fp_infinity)) 470 return (fex_inv_zmi); 471 472 break; 473 474 case 0x030: 475 case 0x038: 476 case 0x070: 477 case 0x078: 478 case 0x0b0: 479 case 0x0b8: 480 case 0x0f0: 481 case 0x0f8: 482 case 0x230: 483 case 0x238: 484 case 0x270: 485 case 0x278: 486 case 0x2b0: 487 case 0x2b8: 488 case 0x430: 489 case 0x438: 490 case 0x470: 491 case 0x478: 492 case 0x4b0: 493 case 0x4b8: 494 case 0x4f0: 495 case 0x4f8: 496 case 0x630: 497 case 0x638: 498 case 0x670: 499 case 0x678: 500 case 0x6b0: 501 case 0x6b8: 502 case 0x6f0: 503 case 0x6f8: 504 505 /* fdiv */ 506 if (t1 == fp_zero && t2 == fp_zero) 507 return (fex_inv_zdz); 508 else if (t1 == fp_infinity && t2 == fp_infinity) 509 return (fex_inv_idi); 510 511 break; 512 513 case 0x1f0: 514 case 0x1f8: 515 /* fsqrt, other special ops */ 516 return (fex_inv_sqrt); 517 518 case 0x010: 519 case 0x018: 520 case 0x050: 521 case 0x058: 522 case 0x090: 523 case 0x098: 524 case 0x0d0: 525 case 0x0d8: 526 case 0x210: 527 case 0x218: 528 case 0x250: 529 case 0x258: 530 case 0x290: 531 case 0x298: 532 case 0x2e8: 533 case 0x3f0: 534 case 0x410: 535 case 0x418: 536 case 0x450: 537 case 0x458: 538 case 0x490: 539 case 0x498: 540 case 0x4d0: 541 case 0x4d8: 542 case 0x5e0: 543 case 0x5e8: 544 case 0x610: 545 case 0x618: 546 case 0x650: 547 case 0x658: 548 case 0x690: 549 case 0x698: 550 case 0x6d0: 551 case 0x6d8: 552 case 0x7f0: 553 554 /* fcom */ 555 if (t1 == fp_quiet || t2 == fp_quiet) 556 return (fex_inv_cmp); 557 558 break; 559 560 case 0x1e0: 561 562 /* ftst */ 563 if (op == 0x1e4 && t1 == fp_quiet) 564 return (fex_inv_cmp); 565 566 break; 567 568 case 0x310: 569 case 0x318: 570 case 0x350: 571 case 0x358: 572 case 0x390: 573 case 0x398: 574 case 0x710: 575 case 0x718: 576 case 0x730: 577 case 0x738: 578 case 0x750: 579 case 0x758: 580 case 0x770: 581 case 0x778: 582 case 0x790: 583 case 0x798: 584 case 0x7b0: 585 case 0x7b8: 586 /* fist, fbst */ 587 return (fex_inv_int); 588 } 589 590 return ((enum fex_exception)-1); 591 } 592 593 /* scale factors for exponent unwrapping */ 594 /* 2^12288 */ 595 static const long double 596 two12288 = 1.139165225263043370845938579315932009e+3699l; 597 /* 2^-12288 */ 598 static const long double 599 twom12288 = 8.778357852076208839765066529179033145e-3700l; 600 /* (")*(1-2^-64) */ 601 static const long double 602 twom12288mulp = 8.778357852076208839289190796475222545e-3700l; 603 604 /* inline templates */ 605 extern long double f2xm1(long double); 606 extern long double fyl2x(long double, long double); 607 extern long double fptan(long double); 608 extern long double fpatan(long double, long double); 609 extern long double fxtract(long double); 610 extern long double fprem1(long double, long double); 611 extern long double fprem(long double, long double); 612 extern long double fyl2xp1(long double, long double); 613 extern long double fsqrt(long double); 614 extern long double fsincos(long double); 615 extern long double frndint(long double); 616 extern long double fscale(long double, long double); 617 extern long double fsin(long double); 618 extern long double fcos(long double); 619 620 /* 621 * Get the operands, generate the default untrapped result with 622 * exceptions, and set a code indicating the type of operation 623 */ 624 void 625 __fex_get_op(siginfo_t *sip, ucontext_t *uap, fex_info_t *info) 626 { 627 fex_numeric_t t; 628 long double op2v, x; 629 unsigned int cwsw, ex, sw, op; 630 unsigned long ea; 631 volatile int c __unused; 632 633 /* get the exception type, status word, opcode, and data address */ 634 ex = sip->si_code; 635 sw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status; 636 #if defined(__amd64) 637 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16; 638 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp; 639 #else 640 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16; 641 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA]; 642 #endif 643 644 /* 645 * initialize res to the default untrapped result and ex to the 646 * corresponding flags (assume trapping is disabled and flags are 647 * clear) 648 */ 649 650 /* single operand instructions */ 651 info->op = fex_cnvt; 652 info->op2.type = fex_nodata; 653 654 switch (op & 0x7f8) { 655 /* load instructions */ 656 case 0x100: 657 case 0x140: 658 case 0x180: 659 660 if (!ea) { 661 info->op = fex_other; 662 info->op1.type = info->op2.type = info->res.type = 663 fex_nodata; 664 info->flags = 0; 665 return; 666 } 667 668 info->op1.type = fex_float; 669 info->op1.val.f = *(float *)ea; 670 info->res.type = fex_ldouble; 671 info->res.val.q = (long double)info->op1.val.f; 672 goto done; 673 674 case 0x500: 675 case 0x540: 676 case 0x580: 677 678 if (!ea) { 679 info->op = fex_other; 680 info->op1.type = info->op2.type = info->res.type = 681 fex_nodata; 682 info->flags = 0; 683 return; 684 } 685 686 info->op1.type = fex_double; 687 info->op1.val.d = *(double *)ea; 688 info->res.type = fex_ldouble; 689 info->res.val.q = (long double)info->op1.val.d; 690 goto done; 691 692 /* store instructions */ 693 case 0x110: 694 case 0x118: 695 case 0x150: 696 case 0x158: 697 case 0x190: 698 case 0x198: 699 info->res.type = fex_float; 700 701 if (ex == FPE_FLTRES && (op & 8) != 0) { 702 /* inexact, stack popped */ 703 if (!ea) { 704 info->op = fex_other; 705 info->op1.type = info->op2.type = 706 info->res.type = fex_nodata; 707 info->flags = 0; 708 return; 709 } 710 711 info->op1.type = fex_nodata; 712 info->res.val.f = *(float *)ea; 713 info->flags = FE_INEXACT; 714 return; 715 } 716 717 info->op1.type = fex_ldouble; 718 info->op1.val.q = fpreg(uap, 0); 719 info->res.val.f = (float)info->op1.val.q; 720 goto done; 721 722 case 0x310: 723 case 0x318: 724 case 0x350: 725 case 0x358: 726 case 0x390: 727 case 0x398: 728 info->res.type = fex_int; 729 730 if (ex == FPE_FLTRES && (op & 8) != 0) { 731 /* inexact, stack popped */ 732 if (!ea) { 733 info->op = fex_other; 734 info->op1.type = info->op2.type = 735 info->res.type = fex_nodata; 736 info->flags = 0; 737 return; 738 } 739 740 info->op1.type = fex_nodata; 741 info->res.val.i = *(int *)ea; 742 info->flags = FE_INEXACT; 743 return; 744 } 745 746 info->op1.type = fex_ldouble; 747 info->op1.val.q = fpreg(uap, 0); 748 info->res.val.i = (int)info->op1.val.q; 749 goto done; 750 751 case 0x510: 752 case 0x518: 753 case 0x550: 754 case 0x558: 755 case 0x590: 756 case 0x598: 757 info->res.type = fex_double; 758 759 if (ex == FPE_FLTRES && (op & 8) != 0) { 760 /* inexact, stack popped */ 761 if (!ea) { 762 info->op = fex_other; 763 info->op1.type = info->op2.type = 764 info->res.type = fex_nodata; 765 info->flags = 0; 766 return; 767 } 768 769 info->op1.type = fex_nodata; 770 info->res.val.d = *(double *)ea; 771 info->flags = FE_INEXACT; 772 return; 773 } 774 775 info->op1.type = fex_ldouble; 776 info->op1.val.q = fpreg(uap, 0); 777 info->res.val.d = (double)info->op1.val.q; 778 goto done; 779 780 case 0x710: 781 case 0x718: 782 case 0x750: 783 case 0x758: 784 case 0x790: 785 case 0x798: 786 info->res.type = fex_int; 787 788 if (ex == FPE_FLTRES && (op & 8) != 0) { 789 /* inexact, stack popped */ 790 if (!ea) { 791 info->op = fex_other; 792 info->op1.type = info->op2.type = 793 info->res.type = fex_nodata; 794 info->flags = 0; 795 return; 796 } 797 798 info->op1.type = fex_nodata; 799 info->res.val.i = *(short *)ea; 800 info->flags = FE_INEXACT; 801 return; 802 } 803 804 info->op1.type = fex_ldouble; 805 info->op1.val.q = fpreg(uap, 0); 806 info->res.val.i = (short)info->op1.val.q; 807 goto done; 808 809 case 0x730: 810 case 0x770: 811 case 0x7b0: 812 /* fbstp; don't bother */ 813 info->op = fex_other; 814 info->op1.type = info->res.type = fex_nodata; 815 info->flags = 0; 816 return; 817 818 case 0x738: 819 case 0x778: 820 case 0x7b8: 821 info->res.type = fex_llong; 822 823 if (ex == FPE_FLTRES) { 824 /* inexact, stack popped */ 825 if (!ea) { 826 info->op = fex_other; 827 info->op1.type = info->op2.type = 828 info->res.type = fex_nodata; 829 info->flags = 0; 830 return; 831 } 832 833 info->op1.type = fex_nodata; 834 info->res.val.l = *(long long *)ea; 835 info->flags = FE_INEXACT; 836 return; 837 } 838 839 info->op1.type = fex_ldouble; 840 info->op1.val.q = fpreg(uap, 0); 841 info->res.val.l = (long long)info->op1.val.q; 842 goto done; 843 } 844 845 /* 846 * all other ops (except compares) have destinations on the stack so 847 * overflow, underflow, and inexact will stomp their operands 848 */ 849 if (ex == FPE_FLTOVF || ex == FPE_FLTUND || ex == FPE_FLTRES) { 850 /* find the trapped result */ 851 info->op1.type = info->op2.type = fex_nodata; 852 info->res.type = fex_ldouble; 853 854 switch (op & 0x7f8) { 855 case 0x1f0: 856 /* fptan pushes 1.0 afterward, so result is in st(1) */ 857 info->res.val.q = ((op == 0x1f2) ? fpreg(uap, 1) : 858 fpreg(uap, 0)); 859 break; 860 861 case 0x4c0: 862 case 0x4c8: 863 case 0x4e0: 864 case 0x4e8: 865 case 0x4f0: 866 case 0x4f8: 867 info->res.val.q = fpreg(uap, op & 7); 868 break; 869 870 case 0x6c0: 871 case 0x6c8: 872 case 0x6e0: 873 case 0x6e8: 874 case 0x6f0: 875 case 0x6f8: 876 /* stack was popped afterward */ 877 info->res.val.q = fpreg(uap, (op - 1) & 7); 878 break; 879 880 default: 881 info->res.val.q = fpreg(uap, 0); 882 } 883 884 /* reconstruct default untrapped result */ 885 if (ex == FPE_FLTOVF) { 886 /* generate an overflow with the sign of the result */ 887 x = two12288; 888 *(4 + (short *)&x) |= (*(4 + 889 (short *)&info->res.val.q) & 0x8000); 890 info->res.val.q = x * two12288; 891 info->flags = FE_OVERFLOW | FE_INEXACT; 892 __fenv_getcwsw(&cwsw); 893 cwsw &= ~FE_ALL_EXCEPT; 894 __fenv_setcwsw(&cwsw); 895 } else if (ex == FPE_FLTUND) { 896 /* 897 * undo the scaling; we can't distinguish a chopped 898 * result from an exact one without futzing around to 899 * trap all in- exact exceptions so as to keep the 900 * flag clear, so we just punt 901 */ 902 if (sw & 0x200) /* result was rounded up */ 903 info->res.val.q = (info->res.val.q * 904 twom12288) * twom12288mulp; 905 else 906 info->res.val.q = (info->res.val.q * 907 twom12288) * twom12288; 908 909 __fenv_getcwsw(&cwsw); 910 info->flags = (cwsw & FE_INEXACT) | FE_UNDERFLOW; 911 cwsw &= ~FE_ALL_EXCEPT; 912 __fenv_setcwsw(&cwsw); 913 } else { 914 info->flags = FE_INEXACT; 915 } 916 917 /* determine the operation code */ 918 switch (op) { 919 case 0x1f0: /* f2xm1 */ 920 case 0x1f1: /* fyl2x */ 921 case 0x1f2: /* fptan */ 922 case 0x1f3: /* fpatan */ 923 case 0x1f5: /* fprem1 */ 924 case 0x1f8: /* fprem */ 925 case 0x1f9: /* fyl2xp1 */ 926 case 0x1fb: /* fsincos */ 927 case 0x1fc: /* frndint */ 928 case 0x1fd: /* fscale */ 929 case 0x1fe: /* fsin */ 930 case 0x1ff: /* fcos */ 931 info->op = fex_other; 932 return; 933 934 case 0x1fa: /* fsqrt */ 935 info->op = fex_sqrt; 936 return; 937 } 938 939 info->op = fex_other; 940 941 switch (op & 0x7c0) { 942 case 0x000: 943 case 0x040: 944 case 0x080: 945 case 0x0c0: 946 case 0x200: 947 case 0x240: 948 case 0x280: 949 case 0x400: 950 case 0x440: 951 case 0x480: 952 case 0x4c0: 953 case 0x600: 954 case 0x640: 955 case 0x680: 956 case 0x6c0: 957 958 switch (op & 0x38) { 959 case 0x00: 960 info->op = fex_add; 961 break; 962 963 case 0x08: 964 info->op = fex_mul; 965 break; 966 967 case 0x20: 968 case 0x28: 969 info->op = fex_sub; 970 break; 971 972 case 0x30: 973 case 0x38: 974 info->op = fex_div; 975 break; 976 } 977 } 978 979 return; 980 } 981 982 /* 983 * for other exceptions, the operands are preserved, so we can just 984 * emulate the operation with traps disabled 985 */ 986 987 /* one operand is always in st */ 988 info->op1.type = fex_ldouble; 989 info->op1.val.q = fpreg(uap, 0); 990 991 /* oddball instructions */ 992 info->op = fex_other; 993 994 switch (op) { 995 case 0x1e4: /* ftst */ 996 info->op = fex_cmp; 997 info->op2.type = fex_ldouble; 998 info->op2.val.q = 0.0l; 999 info->res.type = fex_nodata; 1000 c = (info->op1.val.q < info->op2.val.q); 1001 goto done; 1002 1003 case 0x1f0: /* f2xm1 */ 1004 info->res.type = fex_ldouble; 1005 info->res.val.q = f2xm1(info->op1.val.q); 1006 goto done; 1007 1008 case 0x1f1: /* fyl2x */ 1009 info->op2.type = fex_ldouble; 1010 info->op2.val.q = fpreg(uap, 1); 1011 info->res.type = fex_ldouble; 1012 info->res.val.q = fyl2x(info->op1.val.q, info->op2.val.q); 1013 goto done; 1014 1015 case 0x1f2: /* fptan */ 1016 info->res.type = fex_ldouble; 1017 info->res.val.q = fptan(info->op1.val.q); 1018 goto done; 1019 1020 case 0x1f3: /* fpatan */ 1021 info->op2.type = fex_ldouble; 1022 info->op2.val.q = fpreg(uap, 1); 1023 info->res.type = fex_ldouble; 1024 info->res.val.q = fpatan(info->op1.val.q, info->op2.val.q); 1025 goto done; 1026 1027 case 0x1f4: /* fxtract */ 1028 info->res.type = fex_ldouble; 1029 info->res.val.q = fxtract(info->op1.val.q); 1030 goto done; 1031 1032 case 0x1f5: /* fprem1 */ 1033 info->op2.type = fex_ldouble; 1034 info->op2.val.q = fpreg(uap, 1); 1035 info->res.type = fex_ldouble; 1036 info->res.val.q = fprem1(info->op1.val.q, info->op2.val.q); 1037 goto done; 1038 1039 case 0x1f8: /* fprem */ 1040 info->op2.type = fex_ldouble; 1041 info->op2.val.q = fpreg(uap, 1); 1042 info->res.type = fex_ldouble; 1043 info->res.val.q = fprem(info->op1.val.q, info->op2.val.q); 1044 goto done; 1045 1046 case 0x1f9: /* fyl2xp1 */ 1047 info->op2.type = fex_ldouble; 1048 info->op2.val.q = fpreg(uap, 1); 1049 info->res.type = fex_ldouble; 1050 info->res.val.q = fyl2xp1(info->op1.val.q, info->op2.val.q); 1051 goto done; 1052 1053 case 0x1fa: /* fsqrt */ 1054 info->op = fex_sqrt; 1055 info->res.type = fex_ldouble; 1056 info->res.val.q = fsqrt(info->op1.val.q); 1057 goto done; 1058 1059 case 0x1fb: /* fsincos */ 1060 info->res.type = fex_ldouble; 1061 info->res.val.q = fsincos(info->op1.val.q); 1062 goto done; 1063 1064 case 0x1fc: /* frndint */ 1065 info->res.type = fex_ldouble; 1066 info->res.val.q = frndint(info->op1.val.q); 1067 goto done; 1068 1069 case 0x1fd: /* fscale */ 1070 info->op2.type = fex_ldouble; 1071 info->op2.val.q = fpreg(uap, 1); 1072 info->res.type = fex_ldouble; 1073 info->res.val.q = fscale(info->op1.val.q, info->op2.val.q); 1074 goto done; 1075 1076 case 0x1fe: /* fsin */ 1077 info->res.type = fex_ldouble; 1078 info->res.val.q = fsin(info->op1.val.q); 1079 goto done; 1080 1081 case 0x1ff: /* fcos */ 1082 info->res.type = fex_ldouble; 1083 info->res.val.q = fcos(info->op1.val.q); 1084 goto done; 1085 1086 case 0x2e9: /* fucompp */ 1087 info->op = fex_cmp; 1088 info->op2.type = fex_ldouble; 1089 info->op2.val.q = fpreg(uap, 1); 1090 info->res.type = fex_nodata; 1091 c = (info->op1.val.q == info->op2.val.q); 1092 goto done; 1093 } 1094 1095 /* fucom[p], fcomi[p], fucomi[p] */ 1096 switch (op & 0x7f8) { 1097 case 0x3e8: 1098 case 0x5e0: 1099 case 0x5e8: 1100 case 0x7e8: /* unordered compares */ 1101 info->op = fex_cmp; 1102 info->op2.type = fex_ldouble; 1103 info->op2.val.q = fpreg(uap, op & 7); 1104 info->res.type = fex_nodata; 1105 c = (info->op1.val.q == info->op2.val.q); 1106 goto done; 1107 1108 case 0x3f0: 1109 case 0x7f0: /* ordered compares */ 1110 info->op = fex_cmp; 1111 info->op2.type = fex_ldouble; 1112 info->op2.val.q = fpreg(uap, op & 7); 1113 info->res.type = fex_nodata; 1114 c = (info->op1.val.q < info->op2.val.q); 1115 goto done; 1116 } 1117 1118 /* 1119 * all other instructions come in groups of the form 1120 * fadd, fmul, fcom, fcomp, fsub, fsubr, fdiv, fdivr 1121 */ 1122 1123 /* get the second operand */ 1124 switch (op & 0x7c0) { 1125 case 0x000: 1126 case 0x040: 1127 case 0x080: 1128 1129 if (!ea) { 1130 info->op = fex_other; 1131 info->op1.type = info->op2.type = info->res.type = 1132 fex_nodata; 1133 info->flags = 0; 1134 return; 1135 } 1136 1137 info->op2.type = fex_float; 1138 info->op2.val.f = *(float *)ea; 1139 op2v = (long double)info->op2.val.f; 1140 break; 1141 1142 case 0x0c0: 1143 info->op2.type = fex_ldouble; 1144 op2v = info->op2.val.q = fpreg(uap, op & 7); 1145 break; 1146 1147 case 0x200: 1148 case 0x240: 1149 case 0x280: 1150 1151 if (!ea) { 1152 info->op = fex_other; 1153 info->op1.type = info->op2.type = info->res.type = 1154 fex_nodata; 1155 info->flags = 0; 1156 return; 1157 } 1158 1159 info->op2.type = fex_int; 1160 info->op2.val.i = *(int *)ea; 1161 op2v = (long double)info->op2.val.i; 1162 break; 1163 1164 case 0x400: 1165 case 0x440: 1166 case 0x480: 1167 1168 if (!ea) { 1169 info->op = fex_other; 1170 info->op1.type = info->op2.type = info->res.type = 1171 fex_nodata; 1172 info->flags = 0; 1173 return; 1174 } 1175 1176 info->op2.type = fex_double; 1177 info->op2.val.d = *(double *)ea; 1178 op2v = (long double)info->op2.val.d; 1179 break; 1180 1181 case 0x4c0: 1182 case 0x6c0: 1183 info->op2.type = fex_ldouble; 1184 info->op2.val.q = fpreg(uap, op & 7); 1185 t = info->op1; 1186 info->op1 = info->op2; 1187 info->op2 = t; 1188 op2v = info->op2.val.q; 1189 break; 1190 1191 case 0x600: 1192 case 0x640: 1193 case 0x680: 1194 1195 if (!ea) { 1196 info->op = fex_other; 1197 info->op1.type = info->op2.type = info->res.type = 1198 fex_nodata; 1199 info->flags = 0; 1200 return; 1201 } 1202 1203 info->op2.type = fex_int; 1204 info->op2.val.i = *(short *)ea; 1205 op2v = (long double)info->op2.val.i; 1206 break; 1207 1208 default: 1209 info->op = fex_other; 1210 info->op1.type = info->op2.type = info->res.type = fex_nodata; 1211 info->flags = 0; 1212 return; 1213 } 1214 1215 /* distinguish different operations in the group */ 1216 info->res.type = fex_ldouble; 1217 1218 switch (op & 0x38) { 1219 case 0x00: 1220 info->op = fex_add; 1221 info->res.val.q = info->op1.val.q + op2v; 1222 break; 1223 1224 case 0x08: 1225 info->op = fex_mul; 1226 info->res.val.q = info->op1.val.q * op2v; 1227 break; 1228 1229 case 0x10: 1230 case 0x18: 1231 info->op = fex_cmp; 1232 info->res.type = fex_nodata; 1233 c = (info->op1.val.q < op2v); 1234 break; 1235 1236 case 0x20: 1237 info->op = fex_sub; 1238 info->res.val.q = info->op1.val.q - op2v; 1239 break; 1240 1241 case 0x28: 1242 info->op = fex_sub; 1243 info->res.val.q = op2v - info->op1.val.q; 1244 t = info->op1; 1245 info->op1 = info->op2; 1246 info->op2 = t; 1247 break; 1248 1249 case 0x30: 1250 info->op = fex_div; 1251 info->res.val.q = info->op1.val.q / op2v; 1252 break; 1253 1254 case 0x38: 1255 info->op = fex_div; 1256 info->res.val.q = op2v / info->op1.val.q; 1257 t = info->op1; 1258 info->op1 = info->op2; 1259 info->op2 = t; 1260 break; 1261 1262 default: 1263 info->op = fex_other; 1264 info->op1.type = info->op2.type = info->res.type = fex_nodata; 1265 info->flags = 0; 1266 return; 1267 } 1268 1269 done: 1270 __fenv_getcwsw(&cwsw); 1271 info->flags = cwsw & FE_ALL_EXCEPT; 1272 cwsw &= ~FE_ALL_EXCEPT; 1273 __fenv_setcwsw(&cwsw); 1274 } 1275 1276 /* pop the saved stack */ 1277 static void 1278 pop(ucontext_t *uap) 1279 { 1280 unsigned top; 1281 1282 fpreg(uap, 0) = fpreg(uap, 1); 1283 fpreg(uap, 1) = fpreg(uap, 2); 1284 fpreg(uap, 2) = fpreg(uap, 3); 1285 fpreg(uap, 3) = fpreg(uap, 4); 1286 fpreg(uap, 4) = fpreg(uap, 5); 1287 fpreg(uap, 5) = fpreg(uap, 6); 1288 fpreg(uap, 6) = fpreg(uap, 7); 1289 #if defined(__amd64) 1290 top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw >> 10) & 0xe; 1291 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fctw |= (3 << top); 1292 top = (top + 2) & 0xe; 1293 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw = 1294 (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw & ~0x3800) | 1295 (top << 10); 1296 #else 1297 top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] >> 1298 10) & 0xe; 1299 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[TW] |= (3 << top); 1300 top = (top + 2) & 0xe; 1301 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] = 1302 (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] & 1303 ~0x3800) | (top << 10); 1304 #endif 1305 } 1306 1307 /* push x onto the saved stack */ 1308 static void 1309 push(long double x, ucontext_t *uap) 1310 { 1311 unsigned top; 1312 1313 fpreg(uap, 7) = fpreg(uap, 6); 1314 fpreg(uap, 6) = fpreg(uap, 5); 1315 fpreg(uap, 5) = fpreg(uap, 4); 1316 fpreg(uap, 4) = fpreg(uap, 3); 1317 fpreg(uap, 3) = fpreg(uap, 2); 1318 fpreg(uap, 2) = fpreg(uap, 1); 1319 fpreg(uap, 1) = fpreg(uap, 0); 1320 fpreg(uap, 0) = x; 1321 #if defined(__amd64) 1322 top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw >> 10) & 0xe; 1323 top = (top - 2) & 0xe; 1324 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fctw &= ~(3 << top); 1325 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw = 1326 (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw & ~0x3800) | 1327 (top << 10); 1328 #else 1329 top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] >> 1330 10) & 0xe; 1331 top = (top - 2) & 0xe; 1332 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[TW] &= ~(3 << 1333 top); 1334 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] = 1335 (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] & 1336 ~0x3800) | (top << 10); 1337 #endif 1338 } 1339 1340 /* scale factors for exponent wrapping */ 1341 static const float fun = 7.922816251e+28f, /* 2^96 */ 1342 fov = 1.262177448e-29f; /* 2^-96 */ 1343 static const double dun = 1.552518092300708935e+231, /* 2^768 */ 1344 dov = 6.441148769597133308e-232; /* 2^-768 */ 1345 1346 /* 1347 * Store the specified result; if no result is given but the exception 1348 * is underflow or overflow, use the default trapped result 1349 */ 1350 void 1351 __fex_st_result(siginfo_t *sip, ucontext_t *uap, fex_info_t *info) 1352 { 1353 fex_numeric_t r; 1354 unsigned long ex, op, ea, stack; 1355 1356 /* get the exception type, opcode, and data address */ 1357 ex = sip->si_code; 1358 #if defined(__amd64) 1359 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16; 1360 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp; /* ??? */ 1361 #else 1362 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16; 1363 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA]; 1364 #endif 1365 1366 /* 1367 * if the instruction is a compare, set the condition codes 1368 * to unordered and update the stack 1369 */ 1370 switch (op & 0x7f8) { 1371 case 0x010: 1372 case 0x050: 1373 case 0x090: 1374 case 0x0d0: 1375 case 0x210: 1376 case 0x250: 1377 case 0x290: 1378 case 0x410: 1379 case 0x450: 1380 case 0x490: 1381 case 0x4d0: 1382 case 0x5e0: 1383 case 0x610: 1384 case 0x650: 1385 case 0x690: 1386 /* f[u]com */ 1387 #if defined(__amd64) 1388 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500; 1389 #else 1390 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 1391 0x4500; 1392 #endif 1393 return; 1394 1395 case 0x018: 1396 case 0x058: 1397 case 0x098: 1398 case 0x0d8: 1399 case 0x218: 1400 case 0x258: 1401 case 0x298: 1402 case 0x418: 1403 case 0x458: 1404 case 0x498: 1405 case 0x4d8: 1406 case 0x5e8: 1407 case 0x618: 1408 case 0x658: 1409 case 0x698: 1410 case 0x6d0: 1411 /* f[u]comp */ 1412 #if defined(__amd64) 1413 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500; 1414 #else 1415 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 1416 0x4500; 1417 #endif 1418 pop(uap); 1419 return; 1420 1421 case 0x2e8: 1422 case 0x6d8: 1423 /* f[u]compp */ 1424 #if defined(__amd64) 1425 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500; 1426 #else 1427 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 1428 0x4500; 1429 #endif 1430 pop(uap); 1431 pop(uap); 1432 return; 1433 1434 case 0x1e0: 1435 1436 if (op == 0x1e4) { /* ftst */ 1437 #if defined(__amd64) 1438 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 1439 0x4500; 1440 #else 1441 uap->uc_mcontext.fpregs.fp_reg_set. 1442 fpchip_state.state[SW] |= 0x4500; 1443 #endif 1444 return; 1445 } 1446 1447 break; 1448 1449 case 0x3e8: 1450 case 0x3f0: 1451 /* f[u]comi */ 1452 #if defined(__amd64) 1453 uap->uc_mcontext.gregs[REG_PS] |= 0x45; 1454 #else 1455 uap->uc_mcontext.gregs[EFL] |= 0x45; 1456 #endif 1457 return; 1458 1459 case 0x7e8: 1460 case 0x7f0: 1461 /* f[u]comip */ 1462 #if defined(__amd64) 1463 uap->uc_mcontext.gregs[REG_PS] |= 0x45; 1464 #else 1465 uap->uc_mcontext.gregs[EFL] |= 0x45; 1466 #endif 1467 pop(uap); 1468 return; 1469 } 1470 1471 /* 1472 * if there is no result available and the exception is overflow 1473 * or underflow, use the wrapped result 1474 */ 1475 r = info->res; 1476 1477 if (r.type == fex_nodata) { 1478 if (ex == FPE_FLTOVF || ex == FPE_FLTUND) { 1479 /* for store instructions, do the scaling and store */ 1480 switch (op & 0x7f8) { 1481 case 0x110: 1482 case 0x118: 1483 case 0x150: 1484 case 0x158: 1485 case 0x190: 1486 case 0x198: 1487 1488 if (!ea) 1489 return; 1490 1491 if (ex == FPE_FLTOVF) 1492 *(float *)ea = (fpreg(uap, 0) * fov) * 1493 fov; 1494 else 1495 *(float *)ea = (fpreg(uap, 0) * fun) * 1496 fun; 1497 1498 if ((op & 8) != 0) 1499 pop(uap); 1500 1501 break; 1502 1503 case 0x510: 1504 case 0x518: 1505 case 0x550: 1506 case 0x558: 1507 case 0x590: 1508 case 0x598: 1509 1510 if (!ea) 1511 return; 1512 1513 if (ex == FPE_FLTOVF) 1514 *(double *)ea = (fpreg(uap, 0) * dov) * 1515 dov; 1516 else 1517 *(double *)ea = (fpreg(uap, 0) * dun) * 1518 dun; 1519 1520 if ((op & 8) != 0) 1521 pop(uap); 1522 1523 break; 1524 } 1525 } 1526 1527 #ifdef DEBUG 1528 else if (ex != FPE_FLTRES) { 1529 printf("No result supplied, stack may be hosed\n"); 1530 } 1531 #endif 1532 return; 1533 } 1534 1535 /* 1536 * otherwise convert the supplied result to the correct type, put it 1537 * in the destination, and update the stack as need be 1538 */ 1539 1540 /* store instructions */ 1541 switch (op & 0x7f8) { 1542 case 0x110: 1543 case 0x118: 1544 case 0x150: 1545 case 0x158: 1546 case 0x190: 1547 case 0x198: 1548 1549 if (!ea) 1550 return; 1551 1552 switch (r.type) { 1553 case fex_int: 1554 *(float *)ea = (float)r.val.i; 1555 break; 1556 1557 case fex_llong: 1558 *(float *)ea = (float)r.val.l; 1559 break; 1560 1561 case fex_float: 1562 *(float *)ea = r.val.f; 1563 break; 1564 1565 case fex_double: 1566 *(float *)ea = (float)r.val.d; 1567 break; 1568 1569 case fex_ldouble: 1570 *(float *)ea = (float)r.val.q; 1571 break; 1572 1573 default: 1574 break; 1575 } 1576 1577 if (ex != FPE_FLTRES && (op & 8) != 0) 1578 pop(uap); 1579 1580 return; 1581 1582 case 0x310: 1583 case 0x318: 1584 case 0x350: 1585 case 0x358: 1586 case 0x390: 1587 case 0x398: 1588 1589 if (!ea) 1590 return; 1591 1592 switch (r.type) { 1593 case fex_int: 1594 *(int *)ea = r.val.i; 1595 break; 1596 1597 case fex_llong: 1598 *(int *)ea = (int)r.val.l; 1599 break; 1600 1601 case fex_float: 1602 *(int *)ea = (int)r.val.f; 1603 break; 1604 1605 case fex_double: 1606 *(int *)ea = (int)r.val.d; 1607 break; 1608 1609 case fex_ldouble: 1610 *(int *)ea = (int)r.val.q; 1611 break; 1612 1613 default: 1614 break; 1615 } 1616 1617 if (ex != FPE_FLTRES && (op & 8) != 0) 1618 pop(uap); 1619 1620 return; 1621 1622 case 0x510: 1623 case 0x518: 1624 case 0x550: 1625 case 0x558: 1626 case 0x590: 1627 case 0x598: 1628 1629 if (!ea) 1630 return; 1631 1632 switch (r.type) { 1633 case fex_int: 1634 *(double *)ea = (double)r.val.i; 1635 break; 1636 1637 case fex_llong: 1638 *(double *)ea = (double)r.val.l; 1639 break; 1640 1641 case fex_float: 1642 *(double *)ea = (double)r.val.f; 1643 break; 1644 1645 case fex_double: 1646 *(double *)ea = r.val.d; 1647 break; 1648 1649 case fex_ldouble: 1650 *(double *)ea = (double)r.val.q; 1651 break; 1652 1653 default: 1654 break; 1655 } 1656 1657 if (ex != FPE_FLTRES && (op & 8) != 0) 1658 pop(uap); 1659 1660 return; 1661 1662 case 0x710: 1663 case 0x718: 1664 case 0x750: 1665 case 0x758: 1666 case 0x790: 1667 case 0x798: 1668 1669 if (!ea) 1670 return; 1671 1672 switch (r.type) { 1673 case fex_int: 1674 *(short *)ea = (short)r.val.i; 1675 break; 1676 1677 case fex_llong: 1678 *(short *)ea = (short)r.val.l; 1679 break; 1680 1681 case fex_float: 1682 *(short *)ea = (short)r.val.f; 1683 break; 1684 1685 case fex_double: 1686 *(short *)ea = (short)r.val.d; 1687 break; 1688 1689 case fex_ldouble: 1690 *(short *)ea = (short)r.val.q; 1691 break; 1692 1693 default: 1694 break; 1695 } 1696 1697 if (ex != FPE_FLTRES && (op & 8) != 0) 1698 pop(uap); 1699 1700 return; 1701 1702 case 0x730: 1703 case 0x770: 1704 case 0x7b0: 1705 1706 /* fbstp; don't bother */ 1707 if (ea && ex != FPE_FLTRES) 1708 pop(uap); 1709 1710 return; 1711 1712 case 0x738: 1713 case 0x778: 1714 case 0x7b8: 1715 1716 if (!ea) 1717 return; 1718 1719 switch (r.type) { 1720 case fex_int: 1721 *(long long *)ea = (long long)r.val.i; 1722 break; 1723 1724 case fex_llong: 1725 *(long long *)ea = r.val.l; 1726 break; 1727 1728 case fex_float: 1729 *(long long *)ea = (long long)r.val.f; 1730 break; 1731 1732 case fex_double: 1733 *(long long *)ea = (long long)r.val.d; 1734 break; 1735 1736 case fex_ldouble: 1737 *(long long *)ea = (long long)r.val.q; 1738 break; 1739 1740 default: 1741 break; 1742 } 1743 1744 if (ex != FPE_FLTRES) 1745 pop(uap); 1746 1747 return; 1748 } 1749 1750 /* for all other instructions, the result goes into a register */ 1751 switch (r.type) { 1752 case fex_int: 1753 r.val.q = (long double)r.val.i; 1754 break; 1755 1756 case fex_llong: 1757 r.val.q = (long double)r.val.l; 1758 break; 1759 1760 case fex_float: 1761 r.val.q = (long double)r.val.f; 1762 break; 1763 1764 case fex_double: 1765 r.val.q = (long double)r.val.d; 1766 break; 1767 1768 default: 1769 break; 1770 } 1771 1772 /* for load instructions, push the result onto the stack */ 1773 switch (op & 0x7f8) { 1774 case 0x100: 1775 case 0x140: 1776 case 0x180: 1777 case 0x500: 1778 case 0x540: 1779 case 0x580: 1780 1781 if (ea) 1782 push(r.val.q, uap); 1783 1784 return; 1785 } 1786 1787 /* 1788 * for all other instructions, if the exception is overflow, 1789 * underflow, or inexact, the stack has already been updated 1790 */ 1791 stack = (ex == FPE_FLTOVF || ex == FPE_FLTUND || ex == FPE_FLTRES); 1792 1793 switch (op & 0x7f8) { 1794 case 0x1f0: /* oddballs */ 1795 1796 switch (op) { 1797 case 0x1f1: /* fyl2x */ 1798 case 0x1f3: /* fpatan */ 1799 case 0x1f9: /* fyl2xp1 */ 1800 1801 /* pop the stack, leaving the result in st */ 1802 if (!stack) 1803 pop(uap); 1804 1805 fpreg(uap, 0) = r.val.q; 1806 return; 1807 1808 case 0x1f2: /* fpatan */ 1809 1810 /* fptan pushes 1.0 afterward */ 1811 if (stack) { 1812 fpreg(uap, 1) = r.val.q; 1813 } else { 1814 fpreg(uap, 0) = r.val.q; 1815 push(1.0L, uap); 1816 } 1817 1818 return; 1819 1820 case 0x1f4: /* fxtract */ 1821 case 0x1fb: /* fsincos */ 1822 1823 /* leave the supplied result in st */ 1824 if (stack) { 1825 fpreg(uap, 0) = r.val.q; 1826 } else { 1827 fpreg(uap, 0) = 0.0; /* punt */ 1828 push(r.val.q, uap); 1829 } 1830 1831 return; 1832 } 1833 1834 /* all others leave the stack alone and the result in st */ 1835 fpreg(uap, 0) = r.val.q; 1836 return; 1837 1838 case 0x4c0: 1839 case 0x4c8: 1840 case 0x4e0: 1841 case 0x4e8: 1842 case 0x4f0: 1843 case 0x4f8: 1844 fpreg(uap, op & 7) = r.val.q; 1845 return; 1846 1847 case 0x6c0: 1848 case 0x6c8: 1849 case 0x6e0: 1850 case 0x6e8: 1851 case 0x6f0: 1852 case 0x6f8: 1853 1854 /* stack is popped afterward */ 1855 if (stack) { 1856 fpreg(uap, (op - 1) & 7) = r.val.q; 1857 } else { 1858 fpreg(uap, op & 7) = r.val.q; 1859 pop(uap); 1860 } 1861 1862 return; 1863 1864 default: 1865 fpreg(uap, 0) = r.val.q; 1866 return; 1867 } 1868 }