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