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