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