Print this page
11210 libm should be cstyle(1ONBLD) clean


   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 __unused;
 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;


 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;


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 }


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  28  * Use is subject to license terms.
  29  */
  30 
  31 #include <stdio.h>
  32 #include <unistd.h>
  33 #include <stdlib.h>
  34 #include <string.h>
  35 #include <signal.h>
  36 #include <siginfo.h>
  37 #include <ucontext.h>
  38 #include <thread.h>
  39 #include <math.h>
  40 #if defined(__SUNPRO_C)
  41 #include <sunmath.h>
  42 #endif
  43 #include <fenv.h>
  44 #include "fex_handler.h"
  45 #include "fenv_inlines.h"
  46 
  47 #if defined(__amd64)
  48 #define test_sse_hw             1
  49 #else
  50 /*
  51  * The following variable lives in libc on Solaris 10, where it
  52  * gets set to a nonzero value at startup time on systems with SSE.
  53  */
  54 extern int _sse_hw;
  55 
  56 #define test_sse_hw             _sse_hw
  57 #endif
  58 
  59 static int accrued = 0;
  60 static thread_key_t accrued_key;
  61 static mutex_t accrued_key_lock = DEFAULTMUTEX;

  62 int *
  63 __fex_accrued()
  64 {
  65         int *p;
  66 
  67         if (thr_main()) {
  68                 return (&accrued);
  69         } else {
  70                 p = NULL;
  71                 mutex_lock(&accrued_key_lock);
  72 
  73                 if (thr_getspecific(accrued_key, (void **)&p) != 0 &&
  74                     thr_keycreate(&accrued_key, free) != 0) {
  75                         mutex_unlock(&accrued_key_lock);
  76                         return (NULL);
  77                 }
  78 
  79                 mutex_unlock(&accrued_key_lock);
  80 
  81                 if (!p) {
  82                         if ((p = (int *)malloc(sizeof (int))) == NULL)
  83                                 return (NULL);
  84 
  85                         if (thr_setspecific(accrued_key, (void *)p) != 0) {
  86                                 (void) free(p);
  87                                 return (NULL);
  88                         }
  89 
  90                         *p = 0;
  91                 }
  92 
  93                 return (p);
  94         }
  95 }
  96 
  97 void
  98 __fenv_getfsr(unsigned long *fsr)
  99 {
 100         unsigned int cwsw, mxcsr;
 101 
 102         __fenv_getcwsw(&cwsw);
 103         /* clear reserved bits for no particularly good reason */
 104         cwsw &= ~0xe0c00000u;
 105 
 106         if (test_sse_hw) {
 107                 /*
 108                  * pick up exception flags (excluding denormal operand flag)
 109                  * from mxcsr
 110                  */
 111                 __fenv_getmxcsr(&mxcsr);
 112                 cwsw |= (mxcsr & 0x3d);
 113         }
 114 
 115         cwsw |= *__fex_accrued();
 116         *fsr = cwsw ^ 0x003f0000u;
 117 }
 118 
 119 void
 120 __fenv_setfsr(const unsigned long *fsr)
 121 {
 122         unsigned int cwsw, mxcsr;
 123         int te;
 124 
 125         /* save accrued exception flags corresponding to enabled exceptions */
 126         cwsw = (unsigned int)*fsr;
 127         te = __fenv_get_te(cwsw);
 128         *__fex_accrued() = cwsw & te;
 129         cwsw = (cwsw & ~te) ^ 0x003f0000;
 130 
 131         if (test_sse_hw) {
 132                 /*
 133                  * propagate rounding direction, masks, and exception flags
 134                  * (excluding denormal operand mask and flag) to mxcsr
 135                  */
 136                 __fenv_getmxcsr(&mxcsr);
 137                 mxcsr = (mxcsr & ~0x7ebd) | ((cwsw >> 13) & 0x6000) | ((cwsw >>
 138                     9) & 0x1e80) | (cwsw & 0x3d);
 139                 __fenv_setmxcsr(&mxcsr);
 140         }
 141 
 142         __fenv_setcwsw(&cwsw);
 143 }
 144 
 145 /* Offsets into the fp environment save area (assumes 32-bit protected mode) */
 146 #define CW                      0       /* control word */
 147 #define SW                      1       /* status word */
 148 #define TW                      2       /* tag word */
 149 #define IP                      3       /* instruction pointer */
 150 #define OP                      4       /* opcode */
 151 #define EA                      5       /* operand address */
 152 
 153 /* macro for accessing fp registers in the save area */
 154 #if defined(__amd64)
 155 #define fpreg(u, x)             *(long double *)(10 * (x) + \
 156         (char *)&(u)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.st)
 157 #else
 158 #define fpreg(u, x)             *(long double *)(10 * (x) + \
 159         (char *)&(u)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[7])
 160 #endif
 161 
 162 /*
 163  *  Fix sip->si_code; the Solaris x86 kernel can get it wrong
 164  */
 165 void
 166 __fex_get_x86_exc(siginfo_t *sip, ucontext_t *uap)
 167 {
 168         unsigned sw, cw;
 169 
 170         sw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status;
 171 #if defined(__amd64)
 172         cw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw;
 173 #else
 174         cw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[CW];
 175 #endif
 176 
 177         if ((sw & FE_INVALID) && !(cw & (1 << fp_trap_invalid)))
 178                 /* store 0 for stack fault, FPE_FLTINV for IEEE invalid op */
 179                 sip->si_code = ((sw & 0x40) ? 0 : FPE_FLTINV);
 180         else if ((sw & FE_DIVBYZERO) && !(cw & (1 << fp_trap_division)))
 181                 sip->si_code = FPE_FLTDIV;
 182         else if ((sw & FE_OVERFLOW) && !(cw & (1 << fp_trap_overflow)))
 183                 sip->si_code = FPE_FLTOVF;
 184         else if ((sw & FE_UNDERFLOW) && !(cw & (1 << fp_trap_underflow)))
 185                 sip->si_code = FPE_FLTUND;
 186         else if ((sw & FE_INEXACT) && !(cw & (1 << fp_trap_inexact)))
 187                 sip->si_code = FPE_FLTRES;
 188         else
 189                 sip->si_code = 0;
 190 }
 191 
 192 static enum fp_class_type
 193 my_fp_classf(float *x)
 194 {
 195         int i = *(int *)x & ~0x80000000;
 196 
 197         if (i < 0x7f800000) {
 198                 if (i < 0x00800000)
 199                         return ((i == 0) ? fp_zero : fp_subnormal);
 200 
 201                 return (fp_normal);
 202         } else if (i == 0x7f800000) {
 203                 return (fp_infinity);
 204         } else if (i & 0x400000) {
 205                 return (fp_quiet);
 206         } else {
 207                 return (fp_signaling);
 208         }






 209 }
 210 
 211 static enum fp_class_type
 212 my_fp_class(double *x)
 213 {
 214         int i = *(1 + (int *)x) & ~0x80000000;
 215 
 216         if (i < 0x7ff00000) {
 217                 if (i < 0x00100000)
 218                         return (((i | *(int *)x) == 0) ? fp_zero :
 219                             fp_subnormal);
 220 
 221                 return (fp_normal);
 222         } else if (i == 0x7ff00000 && *(int *)x == 0) {
 223                 return (fp_infinity);
 224         } else if (i & 0x80000) {
 225                 return (fp_quiet);
 226         } else {
 227                 return (fp_signaling);
 228         }






 229 }
 230 
 231 static enum fp_class_type
 232 my_fp_classl(long double *x)
 233 {
 234         int i = *(2 + (int *)x) & 0x7fff;
 235 
 236         if (i < 0x7fff) {
 237                 if (i < 1) {
 238                         if (*(1 + (int *)x) < 0)
 239                                 return (fp_normal);     /* pseudo-denormal */
 240 
 241                         return (((*(1 + (int *)x) | *(int *)x) == 0) ? fp_zero :
 242                             fp_subnormal);
 243                 }
 244 
 245                 return ((*(1 + (int *)x) < 0) ? fp_normal :
 246                     (enum fp_class_type)-1);    /* unsupported format */
 247         } else if (*(1 + (int *)x) == 0x80000000 && *(int *)x == 0) {
 248                 return (fp_infinity);
 249         } else if (*(1 + (unsigned *)x) >= 0xc0000000) {
 250                 return (fp_quiet);
 251         } else if (*(1 + (int *)x) < 0) {
 252                 return (fp_signaling);
 253         } else {
 254                 return ((enum fp_class_type)-1);        /* unsupported format */
 255         }
 256 }
 257 
 258 /*
 259  *  Determine which type of invalid operation exception occurred
 260  */
 261 enum fex_exception
 262 __fex_get_invalid_type(siginfo_t *sip, ucontext_t *uap)
 263 {
 264         unsigned op;
 265         unsigned long ea;
 266         enum fp_class_type t1, t2;
 267 
 268         /* get the opcode and data address */
 269 #if defined(__amd64)
 270         op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
 271         ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp;
 272 #else
 273         op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
 274         ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
 275 #endif
 276 
 277         /*
 278          * if the instruction is fld, the source must be snan (it can't be
 279          * an unsupported format, since fldt doesn't raise any exceptions)
 280          */
 281         switch (op & 0x7f8) {
 282         case 0x100:
 283         case 0x140:
 284         case 0x180:
 285         case 0x500:
 286         case 0x540:
 287         case 0x580:
 288                 return (fex_inv_snan);
 289         }
 290 
 291         /* otherwise st is one of the operands; see if it's snan */
 292         t1 = my_fp_classl(&fpreg(uap, 0));
 293 
 294         if (t1 == fp_signaling)
 295                 return (fex_inv_snan);
 296         else if (t1 == (enum fp_class_type)-1)
 297                 return ((enum fex_exception)-1);
 298 
 299         /* determine the class of the second operand if there is one */
 300         t2 = fp_normal;
 301 
 302         switch (op & 0x7e0) {
 303         case 0x600:
 304         case 0x620:
 305         case 0x640:
 306         case 0x660:
 307         case 0x680:
 308         case 0x6a0:
 309 
 310                 /* short memory operand */
 311                 if (!ea)
 312                         return ((enum fex_exception)-1);
 313 
 314                 if (*(short *)ea == 0)
 315                         t2 = fp_zero;
 316 
 317                 break;
 318 
 319         case 0x200:
 320         case 0x220:
 321         case 0x240:
 322         case 0x260:
 323         case 0x280:
 324         case 0x2a0:
 325 
 326                 /* int memory operand */
 327                 if (!ea)
 328                         return ((enum fex_exception)-1);
 329 
 330                 if (*(int *)ea == 0)
 331                         t2 = fp_zero;
 332 
 333                 break;
 334 
 335         case 0x000:
 336         case 0x020:
 337         case 0x040:
 338         case 0x060:
 339         case 0x080:
 340         case 0x0a0:
 341 
 342                 /* single precision memory operand */
 343                 if (!ea)
 344                         return ((enum fex_exception)-1);
 345 
 346                 t2 = my_fp_classf((float *)ea);
 347                 break;
 348 
 349         case 0x400:
 350         case 0x420:
 351         case 0x440:
 352         case 0x460:
 353         case 0x480:
 354         case 0x4a0:
 355 
 356                 /* double precision memory operand */
 357                 if (!ea)
 358                         return ((enum fex_exception)-1);
 359 
 360                 t2 = my_fp_class((double *)ea);
 361                 break;
 362 
 363         case 0x0c0:
 364         case 0x0e0:
 365         case 0x3e0:
 366         case 0x4c0:
 367         case 0x4e0:
 368         case 0x5e0:
 369         case 0x6c0:
 370         case 0x6e0:
 371         case 0x7e0:
 372 
 373                 /* register operand determined by opcode */
 374                 switch (op & 0x7f8) {
 375                 case 0x3e0:
 376                 case 0x3f8:
 377                 case 0x5f0:
 378                 case 0x5f8:
 379                 case 0x7e0:
 380                 case 0x7f8:
 381                         /* weed out nonexistent opcodes */
 382                         break;
 383 
 384                 default:
 385                         t2 = my_fp_classl(&fpreg(uap, op & 7));
 386                 }
 387 
 388                 break;
 389 
 390         case 0x1e0:
 391         case 0x2e0:
 392 
 393                 /* special forms */
 394                 switch (op) {
 395                 case 0x1f1:             /* fyl2x */
 396                 case 0x1f3:             /* fpatan */
 397                 case 0x1f5:             /* fprem1 */
 398                 case 0x1f8:             /* fprem */
 399                 case 0x1f9:             /* fyl2xp1 */
 400                 case 0x1fd:             /* fscale */
 401                 case 0x2e9:             /* fucompp */
 402                         t2 = my_fp_classl(&fpreg(uap, 1));
 403                         break;
 404                 }
 405 
 406                 break;
 407         }
 408 
 409         /* see if the second op is snan */
 410         if (t2 == fp_signaling)
 411                 return (fex_inv_snan);
 412         else if (t2 == (enum fp_class_type)-1)
 413                 return ((enum fex_exception)-1);
 414 
 415         /* determine the type of operation */
 416         switch (op & 0x7f8) {
 417         case 0x000:
 418         case 0x020:
 419         case 0x028:
 420         case 0x040:
 421         case 0x060:
 422         case 0x068:
 423         case 0x080:
 424         case 0x0a0:
 425         case 0x0a8:
 426         case 0x0c0:
 427         case 0x0e0:
 428         case 0x0e8:
 429         case 0x400:
 430         case 0x420:
 431         case 0x428:
 432         case 0x440:
 433         case 0x460:
 434         case 0x468:
 435         case 0x480:
 436         case 0x4a0:
 437         case 0x4a8:
 438         case 0x4c0:
 439         case 0x4e0:
 440         case 0x4e8:
 441         case 0x6c0:
 442         case 0x6e0:
 443         case 0x6e8:
 444 
 445                 /* fadd, fsub, fsubr */
 446                 if (t1 == fp_infinity && t2 == fp_infinity)
 447                         return (fex_inv_isi);
 448 
 449                 break;
 450 
 451         case 0x008:
 452         case 0x048:
 453         case 0x088:
 454         case 0x0c8:
 455         case 0x208:
 456         case 0x248:
 457         case 0x288:
 458         case 0x408:
 459         case 0x448:
 460         case 0x488:
 461         case 0x4c8:
 462         case 0x608:
 463         case 0x648:
 464         case 0x688:
 465         case 0x6c8:
 466 
 467                 /* fmul */
 468                 if ((t1 == fp_zero && t2 == fp_infinity) || (t2 == fp_zero &&
 469                     t1 == fp_infinity))
 470                         return (fex_inv_zmi);
 471 
 472                 break;
 473 
 474         case 0x030:
 475         case 0x038:
 476         case 0x070:
 477         case 0x078:
 478         case 0x0b0:
 479         case 0x0b8:
 480         case 0x0f0:
 481         case 0x0f8:
 482         case 0x230:
 483         case 0x238:
 484         case 0x270:
 485         case 0x278:
 486         case 0x2b0:
 487         case 0x2b8:
 488         case 0x430:
 489         case 0x438:
 490         case 0x470:
 491         case 0x478:
 492         case 0x4b0:
 493         case 0x4b8:
 494         case 0x4f0:
 495         case 0x4f8:
 496         case 0x630:
 497         case 0x638:
 498         case 0x670:
 499         case 0x678:
 500         case 0x6b0:
 501         case 0x6b8:
 502         case 0x6f0:
 503         case 0x6f8:
 504 
 505                 /* fdiv */
 506                 if (t1 == fp_zero && t2 == fp_zero)
 507                         return (fex_inv_zdz);
 508                 else if (t1 == fp_infinity && t2 == fp_infinity)
 509                         return (fex_inv_idi);
 510 
 511                 break;
 512 
 513         case 0x1f0:
 514         case 0x1f8:
 515                 /* fsqrt, other special ops */
 516                 return (fex_inv_sqrt);
 517 
 518         case 0x010:
 519         case 0x018:
 520         case 0x050:
 521         case 0x058:
 522         case 0x090:
 523         case 0x098:
 524         case 0x0d0:
 525         case 0x0d8:
 526         case 0x210:
 527         case 0x218:
 528         case 0x250:
 529         case 0x258:
 530         case 0x290:
 531         case 0x298:
 532         case 0x2e8:
 533         case 0x3f0:
 534         case 0x410:
 535         case 0x418:
 536         case 0x450:
 537         case 0x458:
 538         case 0x490:
 539         case 0x498:
 540         case 0x4d0:
 541         case 0x4d8:
 542         case 0x5e0:
 543         case 0x5e8:
 544         case 0x610:
 545         case 0x618:
 546         case 0x650:
 547         case 0x658:
 548         case 0x690:
 549         case 0x698:
 550         case 0x6d0:
 551         case 0x6d8:
 552         case 0x7f0:
 553 
 554                 /* fcom */
 555                 if (t1 == fp_quiet || t2 == fp_quiet)
 556                         return (fex_inv_cmp);
 557 
 558                 break;
 559 
 560         case 0x1e0:
 561 
 562                 /* ftst */
 563                 if (op == 0x1e4 && t1 == fp_quiet)
 564                         return (fex_inv_cmp);
 565 
 566                 break;
 567 
 568         case 0x310:
 569         case 0x318:
 570         case 0x350:
 571         case 0x358:
 572         case 0x390:
 573         case 0x398:
 574         case 0x710:
 575         case 0x718:
 576         case 0x730:
 577         case 0x738:
 578         case 0x750:
 579         case 0x758:
 580         case 0x770:
 581         case 0x778:
 582         case 0x790:
 583         case 0x798:
 584         case 0x7b0:
 585         case 0x7b8:
 586                 /* fist, fbst */
 587                 return (fex_inv_int);
 588         }
 589 
 590         return ((enum fex_exception)-1);
 591 }
 592 
 593 /* scale factors for exponent unwrapping */
 594 /* 2^12288 */
 595 static const long double
 596     two12288 = 1.139165225263043370845938579315932009e+3699l;
 597 /* 2^-12288 */
 598 static const long double
 599     twom12288 = 8.778357852076208839765066529179033145e-3700l;
 600 /* (")*(1-2^-64) */
 601 static const long double


 602     twom12288mulp = 8.778357852076208839289190796475222545e-3700l;

 603 
 604 /* inline templates */
 605 extern long double f2xm1(long double);
 606 extern long double fyl2x(long double, long double);
 607 extern long double fptan(long double);
 608 extern long double fpatan(long double, long double);
 609 extern long double fxtract(long double);
 610 extern long double fprem1(long double, long double);
 611 extern long double fprem(long double, long double);
 612 extern long double fyl2xp1(long double, long double);
 613 extern long double fsqrt(long double);
 614 extern long double fsincos(long double);
 615 extern long double frndint(long double);
 616 extern long double fscale(long double, long double);
 617 extern long double fsin(long double);
 618 extern long double fcos(long double);
 619 
 620 /*
 621  *  Get the operands, generate the default untrapped result with
 622  *  exceptions, and set a code indicating the type of operation
 623  */
 624 void
 625 __fex_get_op(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
 626 {
 627         fex_numeric_t t;
 628         long double op2v, x;
 629         unsigned int cwsw, ex, sw, op;
 630         unsigned long ea;
 631         volatile int c __unused;
 632 
 633         /* get the exception type, status word, opcode, and data address */
 634         ex = sip->si_code;
 635         sw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status;
 636 #if defined(__amd64)
 637         op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
 638         ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp;
 639 #else
 640         op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
 641         ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
 642 #endif
 643 
 644         /*
 645          * initialize res to the default untrapped result and ex to the
 646          * corresponding flags (assume trapping is disabled and flags are
 647          * clear)
 648          */
 649 
 650         /* single operand instructions */
 651         info->op = fex_cnvt;
 652         info->op2.type = fex_nodata;
 653 
 654         switch (op & 0x7f8) {
 655         /* load instructions */
 656         case 0x100:
 657         case 0x140:
 658         case 0x180:
 659 
 660                 if (!ea) {
 661                         info->op = fex_other;
 662                         info->op1.type = info->op2.type = info->res.type =
 663                             fex_nodata;
 664                         info->flags = 0;
 665                         return;
 666                 }
 667 
 668                 info->op1.type = fex_float;
 669                 info->op1.val.f = *(float *)ea;
 670                 info->res.type = fex_ldouble;
 671                 info->res.val.q = (long double)info->op1.val.f;
 672                 goto done;
 673 
 674         case 0x500:
 675         case 0x540:
 676         case 0x580:
 677 
 678                 if (!ea) {
 679                         info->op = fex_other;
 680                         info->op1.type = info->op2.type = info->res.type =
 681                             fex_nodata;
 682                         info->flags = 0;
 683                         return;
 684                 }
 685 
 686                 info->op1.type = fex_double;
 687                 info->op1.val.d = *(double *)ea;
 688                 info->res.type = fex_ldouble;
 689                 info->res.val.q = (long double)info->op1.val.d;
 690                 goto done;
 691 
 692         /* store instructions */
 693         case 0x110:
 694         case 0x118:
 695         case 0x150:
 696         case 0x158:
 697         case 0x190:
 698         case 0x198:
 699                 info->res.type = fex_float;
 700 
 701                 if (ex == FPE_FLTRES && (op & 8) != 0) {
 702                         /* inexact, stack popped */
 703                         if (!ea) {
 704                                 info->op = fex_other;
 705                                 info->op1.type = info->op2.type =
 706                                     info->res.type = fex_nodata;
 707                                 info->flags = 0;
 708                                 return;
 709                         }
 710 
 711                         info->op1.type = fex_nodata;
 712                         info->res.val.f = *(float *)ea;
 713                         info->flags = FE_INEXACT;
 714                         return;
 715                 }
 716 
 717                 info->op1.type = fex_ldouble;
 718                 info->op1.val.q = fpreg(uap, 0);
 719                 info->res.val.f = (float)info->op1.val.q;
 720                 goto done;
 721 
 722         case 0x310:
 723         case 0x318:
 724         case 0x350:
 725         case 0x358:
 726         case 0x390:
 727         case 0x398:
 728                 info->res.type = fex_int;
 729 
 730                 if (ex == FPE_FLTRES && (op & 8) != 0) {
 731                         /* inexact, stack popped */
 732                         if (!ea) {
 733                                 info->op = fex_other;
 734                                 info->op1.type = info->op2.type =
 735                                     info->res.type = fex_nodata;
 736                                 info->flags = 0;
 737                                 return;
 738                         }
 739 
 740                         info->op1.type = fex_nodata;
 741                         info->res.val.i = *(int *)ea;
 742                         info->flags = FE_INEXACT;
 743                         return;
 744                 }
 745 
 746                 info->op1.type = fex_ldouble;
 747                 info->op1.val.q = fpreg(uap, 0);
 748                 info->res.val.i = (int)info->op1.val.q;
 749                 goto done;
 750 
 751         case 0x510:
 752         case 0x518:
 753         case 0x550:
 754         case 0x558:
 755         case 0x590:
 756         case 0x598:
 757                 info->res.type = fex_double;
 758 
 759                 if (ex == FPE_FLTRES && (op & 8) != 0) {
 760                         /* inexact, stack popped */
 761                         if (!ea) {
 762                                 info->op = fex_other;
 763                                 info->op1.type = info->op2.type =
 764                                     info->res.type = fex_nodata;
 765                                 info->flags = 0;
 766                                 return;
 767                         }
 768 
 769                         info->op1.type = fex_nodata;
 770                         info->res.val.d = *(double *)ea;
 771                         info->flags = FE_INEXACT;
 772                         return;
 773                 }
 774 
 775                 info->op1.type = fex_ldouble;
 776                 info->op1.val.q = fpreg(uap, 0);
 777                 info->res.val.d = (double)info->op1.val.q;
 778                 goto done;
 779 
 780         case 0x710:
 781         case 0x718:
 782         case 0x750:
 783         case 0x758:
 784         case 0x790:
 785         case 0x798:
 786                 info->res.type = fex_int;
 787 
 788                 if (ex == FPE_FLTRES && (op & 8) != 0) {
 789                         /* inexact, stack popped */
 790                         if (!ea) {
 791                                 info->op = fex_other;
 792                                 info->op1.type = info->op2.type =
 793                                     info->res.type = fex_nodata;
 794                                 info->flags = 0;
 795                                 return;
 796                         }
 797 
 798                         info->op1.type = fex_nodata;
 799                         info->res.val.i = *(short *)ea;
 800                         info->flags = FE_INEXACT;
 801                         return;
 802                 }
 803 
 804                 info->op1.type = fex_ldouble;
 805                 info->op1.val.q = fpreg(uap, 0);
 806                 info->res.val.i = (short)info->op1.val.q;
 807                 goto done;
 808 
 809         case 0x730:
 810         case 0x770:
 811         case 0x7b0:
 812                 /* fbstp; don't bother */
 813                 info->op = fex_other;
 814                 info->op1.type = info->res.type = fex_nodata;
 815                 info->flags = 0;
 816                 return;
 817 
 818         case 0x738:
 819         case 0x778:
 820         case 0x7b8:
 821                 info->res.type = fex_llong;
 822 
 823                 if (ex == FPE_FLTRES) {
 824                         /* inexact, stack popped */
 825                         if (!ea) {
 826                                 info->op = fex_other;
 827                                 info->op1.type = info->op2.type =
 828                                     info->res.type = fex_nodata;
 829                                 info->flags = 0;
 830                                 return;
 831                         }
 832 
 833                         info->op1.type = fex_nodata;
 834                         info->res.val.l = *(long long *)ea;
 835                         info->flags = FE_INEXACT;
 836                         return;
 837                 }
 838 
 839                 info->op1.type = fex_ldouble;
 840                 info->op1.val.q = fpreg(uap, 0);
 841                 info->res.val.l = (long long)info->op1.val.q;
 842                 goto done;
 843         }
 844 
 845         /*
 846          * all other ops (except compares) have destinations on the stack so
 847          * overflow, underflow, and inexact will stomp their operands
 848          */
 849         if (ex == FPE_FLTOVF || ex == FPE_FLTUND || ex == FPE_FLTRES) {
 850                 /* find the trapped result */
 851                 info->op1.type = info->op2.type = fex_nodata;
 852                 info->res.type = fex_ldouble;
 853 
 854                 switch (op & 0x7f8) {
 855                 case 0x1f0:
 856                         /* fptan pushes 1.0 afterward, so result is in st(1) */
 857                         info->res.val.q = ((op == 0x1f2) ? fpreg(uap, 1) :
 858                             fpreg(uap, 0));
 859                         break;
 860 
 861                 case 0x4c0:
 862                 case 0x4c8:
 863                 case 0x4e0:
 864                 case 0x4e8:
 865                 case 0x4f0:
 866                 case 0x4f8:
 867                         info->res.val.q = fpreg(uap, op & 7);
 868                         break;
 869 
 870                 case 0x6c0:
 871                 case 0x6c8:
 872                 case 0x6e0:
 873                 case 0x6e8:
 874                 case 0x6f0:
 875                 case 0x6f8:
 876                         /* stack was popped afterward */
 877                         info->res.val.q = fpreg(uap, (op - 1) & 7);
 878                         break;
 879 
 880                 default:
 881                         info->res.val.q = fpreg(uap, 0);
 882                 }
 883 
 884                 /* reconstruct default untrapped result */
 885                 if (ex == FPE_FLTOVF) {
 886                         /* generate an overflow with the sign of the result */
 887                         x = two12288;
 888                         *(4 + (short *)&x) |= (*(4 +
 889                             (short *)&info->res.val.q) & 0x8000);
 890                         info->res.val.q = x * two12288;
 891                         info->flags = FE_OVERFLOW | FE_INEXACT;
 892                         __fenv_getcwsw(&cwsw);
 893                         cwsw &= ~FE_ALL_EXCEPT;
 894                         __fenv_setcwsw(&cwsw);
 895                 } else if (ex == FPE_FLTUND) {
 896                         /*
 897                          * undo the scaling; we can't distinguish a chopped
 898                          * result from an exact one without futzing around to
 899                          * trap all in- exact exceptions so as to keep the
 900                          * flag clear, so we just punt
 901                          */
 902                         if (sw & 0x200)     /* result was rounded up */
 903                                 info->res.val.q = (info->res.val.q *
 904                                     twom12288) * twom12288mulp;
 905                         else
 906                                 info->res.val.q = (info->res.val.q *
 907                                     twom12288) * twom12288;
 908 
 909                         __fenv_getcwsw(&cwsw);
 910                         info->flags = (cwsw & FE_INEXACT) | FE_UNDERFLOW;
 911                         cwsw &= ~FE_ALL_EXCEPT;
 912                         __fenv_setcwsw(&cwsw);
 913                 } else {

 914                         info->flags = FE_INEXACT;
 915                 }
 916 
 917                 /* determine the operation code */
 918                 switch (op) {
 919                 case 0x1f0:             /* f2xm1 */
 920                 case 0x1f1:             /* fyl2x */
 921                 case 0x1f2:             /* fptan */
 922                 case 0x1f3:             /* fpatan */
 923                 case 0x1f5:             /* fprem1 */
 924                 case 0x1f8:             /* fprem */
 925                 case 0x1f9:             /* fyl2xp1 */
 926                 case 0x1fb:             /* fsincos */
 927                 case 0x1fc:             /* frndint */
 928                 case 0x1fd:             /* fscale */
 929                 case 0x1fe:             /* fsin */
 930                 case 0x1ff:             /* fcos */
 931                         info->op = fex_other;
 932                         return;
 933 
 934                 case 0x1fa:             /* fsqrt */
 935                         info->op = fex_sqrt;
 936                         return;
 937                 }
 938 
 939                 info->op = fex_other;
 940 
 941                 switch (op & 0x7c0) {
 942                 case 0x000:
 943                 case 0x040:
 944                 case 0x080:
 945                 case 0x0c0:
 946                 case 0x200:
 947                 case 0x240:
 948                 case 0x280:
 949                 case 0x400:
 950                 case 0x440:
 951                 case 0x480:
 952                 case 0x4c0:
 953                 case 0x600:
 954                 case 0x640:
 955                 case 0x680:
 956                 case 0x6c0:
 957 
 958                         switch (op & 0x38) {
 959                         case 0x00:
 960                                 info->op = fex_add;
 961                                 break;
 962 
 963                         case 0x08:
 964                                 info->op = fex_mul;
 965                                 break;
 966 
 967                         case 0x20:
 968                         case 0x28:
 969                                 info->op = fex_sub;
 970                                 break;
 971 
 972                         case 0x30:
 973                         case 0x38:
 974                                 info->op = fex_div;
 975                                 break;
 976                         }
 977                 }
 978 
 979                 return;
 980         }
 981 
 982         /*
 983          * for other exceptions, the operands are preserved, so we can just
 984          * emulate the operation with traps disabled
 985          */
 986 
 987         /* one operand is always in st */
 988         info->op1.type = fex_ldouble;
 989         info->op1.val.q = fpreg(uap, 0);
 990 
 991         /* oddball instructions */
 992         info->op = fex_other;
 993 
 994         switch (op) {
 995         case 0x1e4:                     /* ftst */
 996                 info->op = fex_cmp;
 997                 info->op2.type = fex_ldouble;
 998                 info->op2.val.q = 0.0l;
 999                 info->res.type = fex_nodata;
1000                 c = (info->op1.val.q < info->op2.val.q);
1001                 goto done;
1002 
1003         case 0x1f0:                     /* f2xm1 */
1004                 info->res.type = fex_ldouble;
1005                 info->res.val.q = f2xm1(info->op1.val.q);
1006                 goto done;
1007 
1008         case 0x1f1:                     /* fyl2x */
1009                 info->op2.type = fex_ldouble;
1010                 info->op2.val.q = fpreg(uap, 1);
1011                 info->res.type = fex_ldouble;
1012                 info->res.val.q = fyl2x(info->op1.val.q, info->op2.val.q);
1013                 goto done;


1098         case 0x5e0:
1099         case 0x5e8:
1100         case 0x7e8:                     /* unordered compares */
1101                 info->op = fex_cmp;
1102                 info->op2.type = fex_ldouble;
1103                 info->op2.val.q = fpreg(uap, op & 7);
1104                 info->res.type = fex_nodata;
1105                 c = (info->op1.val.q == info->op2.val.q);
1106                 goto done;
1107 
1108         case 0x3f0:
1109         case 0x7f0:                     /* ordered compares */
1110                 info->op = fex_cmp;
1111                 info->op2.type = fex_ldouble;
1112                 info->op2.val.q = fpreg(uap, op & 7);
1113                 info->res.type = fex_nodata;
1114                 c = (info->op1.val.q < info->op2.val.q);
1115                 goto done;
1116         }
1117 
1118         /*
1119          * all other instructions come in groups of the form
1120          * fadd, fmul, fcom, fcomp, fsub, fsubr, fdiv, fdivr
1121          */
1122 
1123         /* get the second operand */
1124         switch (op & 0x7c0) {
1125         case 0x000:
1126         case 0x040:
1127         case 0x080:
1128 
1129                 if (!ea) {
1130                         info->op = fex_other;
1131                         info->op1.type = info->op2.type = info->res.type =
1132                             fex_nodata;
1133                         info->flags = 0;
1134                         return;
1135                 }
1136 
1137                 info->op2.type = fex_float;
1138                 info->op2.val.f = *(float *)ea;
1139                 op2v = (long double)info->op2.val.f;
1140                 break;
1141 
1142         case 0x0c0:
1143                 info->op2.type = fex_ldouble;
1144                 op2v = info->op2.val.q = fpreg(uap, op & 7);
1145                 break;
1146 
1147         case 0x200:
1148         case 0x240:
1149         case 0x280:
1150 
1151                 if (!ea) {
1152                         info->op = fex_other;
1153                         info->op1.type = info->op2.type = info->res.type =
1154                             fex_nodata;
1155                         info->flags = 0;
1156                         return;
1157                 }
1158 
1159                 info->op2.type = fex_int;
1160                 info->op2.val.i = *(int *)ea;
1161                 op2v = (long double)info->op2.val.i;
1162                 break;
1163 
1164         case 0x400:
1165         case 0x440:
1166         case 0x480:
1167 
1168                 if (!ea) {
1169                         info->op = fex_other;
1170                         info->op1.type = info->op2.type = info->res.type =
1171                             fex_nodata;
1172                         info->flags = 0;
1173                         return;
1174                 }
1175 
1176                 info->op2.type = fex_double;
1177                 info->op2.val.d = *(double *)ea;
1178                 op2v = (long double)info->op2.val.d;
1179                 break;
1180 
1181         case 0x4c0:
1182         case 0x6c0:
1183                 info->op2.type = fex_ldouble;
1184                 info->op2.val.q = fpreg(uap, op & 7);
1185                 t = info->op1;
1186                 info->op1 = info->op2;
1187                 info->op2 = t;
1188                 op2v = info->op2.val.q;
1189                 break;
1190 
1191         case 0x600:
1192         case 0x640:
1193         case 0x680:
1194 
1195                 if (!ea) {
1196                         info->op = fex_other;
1197                         info->op1.type = info->op2.type = info->res.type =
1198                             fex_nodata;
1199                         info->flags = 0;
1200                         return;
1201                 }
1202 
1203                 info->op2.type = fex_int;
1204                 info->op2.val.i = *(short *)ea;
1205                 op2v = (long double)info->op2.val.i;
1206                 break;
1207 
1208         default:
1209                 info->op = fex_other;
1210                 info->op1.type = info->op2.type = info->res.type = fex_nodata;
1211                 info->flags = 0;
1212                 return;
1213         }
1214 
1215         /* distinguish different operations in the group */
1216         info->res.type = fex_ldouble;
1217 
1218         switch (op & 0x38) {
1219         case 0x00:
1220                 info->op = fex_add;
1221                 info->res.val.q = info->op1.val.q + op2v;
1222                 break;
1223 
1224         case 0x08:
1225                 info->op = fex_mul;
1226                 info->res.val.q = info->op1.val.q * op2v;
1227                 break;
1228 
1229         case 0x10:
1230         case 0x18:
1231                 info->op = fex_cmp;
1232                 info->res.type = fex_nodata;
1233                 c = (info->op1.val.q < op2v);
1234                 break;
1235 
1236         case 0x20:
1237                 info->op = fex_sub;


1257                 t = info->op1;
1258                 info->op1 = info->op2;
1259                 info->op2 = t;
1260                 break;
1261 
1262         default:
1263                 info->op = fex_other;
1264                 info->op1.type = info->op2.type = info->res.type = fex_nodata;
1265                 info->flags = 0;
1266                 return;
1267         }
1268 
1269 done:
1270         __fenv_getcwsw(&cwsw);
1271         info->flags = cwsw & FE_ALL_EXCEPT;
1272         cwsw &= ~FE_ALL_EXCEPT;
1273         __fenv_setcwsw(&cwsw);
1274 }
1275 
1276 /* pop the saved stack */
1277 static void
1278 pop(ucontext_t *uap)
1279 {
1280         unsigned top;
1281 
1282         fpreg(uap, 0) = fpreg(uap, 1);
1283         fpreg(uap, 1) = fpreg(uap, 2);
1284         fpreg(uap, 2) = fpreg(uap, 3);
1285         fpreg(uap, 3) = fpreg(uap, 4);
1286         fpreg(uap, 4) = fpreg(uap, 5);
1287         fpreg(uap, 5) = fpreg(uap, 6);
1288         fpreg(uap, 6) = fpreg(uap, 7);
1289 #if defined(__amd64)
1290         top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw >> 10) & 0xe;

1291         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fctw |= (3 << top);
1292         top = (top + 2) & 0xe;
1293         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw =
1294             (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw & ~0x3800) |
1295             (top << 10);
1296 #else
1297         top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] >>
1298             10) & 0xe;
1299         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[TW] |= (3 << top);
1300         top = (top + 2) & 0xe;
1301         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] =
1302             (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] &
1303             ~0x3800) | (top << 10);
1304 #endif
1305 }
1306 
1307 /* push x onto the saved stack */
1308 static void
1309 push(long double x, ucontext_t *uap)
1310 {
1311         unsigned top;
1312 
1313         fpreg(uap, 7) = fpreg(uap, 6);
1314         fpreg(uap, 6) = fpreg(uap, 5);
1315         fpreg(uap, 5) = fpreg(uap, 4);
1316         fpreg(uap, 4) = fpreg(uap, 3);
1317         fpreg(uap, 3) = fpreg(uap, 2);
1318         fpreg(uap, 2) = fpreg(uap, 1);
1319         fpreg(uap, 1) = fpreg(uap, 0);
1320         fpreg(uap, 0) = x;
1321 #if defined(__amd64)
1322         top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw >> 10) & 0xe;

1323         top = (top - 2) & 0xe;
1324         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fctw &= ~(3 << top);
1325         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw =
1326             (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw & ~0x3800) |
1327             (top << 10);
1328 #else
1329         top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] >>
1330             10) & 0xe;
1331         top = (top - 2) & 0xe;
1332         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[TW] &= ~(3 <<
1333             top);
1334         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] =
1335             (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] &
1336             ~0x3800) | (top << 10);
1337 #endif
1338 }
1339 
1340 /* scale factors for exponent wrapping */
1341 static const float fun = 7.922816251e+28f,              /* 2^96 */

1342         fov = 1.262177448e-29f;                         /* 2^-96 */
1343 static const double dun = 1.552518092300708935e+231,    /* 2^768 */

1344         dov = 6.441148769597133308e-232;                /* 2^-768 */
1345 
1346 /*
1347  *  Store the specified result; if no result is given but the exception
1348  *  is underflow or overflow, use the default trapped result
1349  */
1350 void
1351 __fex_st_result(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
1352 {
1353         fex_numeric_t r;
1354         unsigned long ex, op, ea, stack;
1355 
1356         /* get the exception type, opcode, and data address */
1357         ex = sip->si_code;
1358 #if defined(__amd64)
1359         op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
1360         ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp; /* ??? */
1361 #else
1362         op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
1363         ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
1364 #endif
1365 
1366         /*
1367          * if the instruction is a compare, set the condition codes
1368          * to unordered and update the stack
1369          */
1370         switch (op & 0x7f8) {
1371         case 0x010:
1372         case 0x050:
1373         case 0x090:
1374         case 0x0d0:
1375         case 0x210:
1376         case 0x250:
1377         case 0x290:
1378         case 0x410:
1379         case 0x450:
1380         case 0x490:
1381         case 0x4d0:
1382         case 0x5e0:
1383         case 0x610:
1384         case 0x650:
1385         case 0x690:
1386                 /* f[u]com */
1387 #if defined(__amd64)
1388                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
1389 #else
1390                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |=
1391                     0x4500;
1392 #endif
1393                 return;
1394 
1395         case 0x018:
1396         case 0x058:
1397         case 0x098:
1398         case 0x0d8:
1399         case 0x218:
1400         case 0x258:
1401         case 0x298:
1402         case 0x418:
1403         case 0x458:
1404         case 0x498:
1405         case 0x4d8:
1406         case 0x5e8:
1407         case 0x618:
1408         case 0x658:
1409         case 0x698:
1410         case 0x6d0:
1411                 /* f[u]comp */
1412 #if defined(__amd64)
1413                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
1414 #else
1415                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |=
1416                     0x4500;
1417 #endif
1418                 pop(uap);
1419                 return;
1420 
1421         case 0x2e8:
1422         case 0x6d8:
1423                 /* f[u]compp */
1424 #if defined(__amd64)
1425                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
1426 #else
1427                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |=
1428                     0x4500;
1429 #endif
1430                 pop(uap);
1431                 pop(uap);
1432                 return;
1433 
1434         case 0x1e0:
1435 
1436                 if (op == 0x1e4) {      /* ftst */
1437 #if defined(__amd64)
1438                         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |=
1439                             0x4500;
1440 #else
1441                         uap->uc_mcontext.fpregs.fp_reg_set.
1442                             fpchip_state.state[SW] |= 0x4500;
1443 #endif
1444                         return;
1445                 }
1446 
1447                 break;
1448 
1449         case 0x3e8:
1450         case 0x3f0:
1451                 /* f[u]comi */
1452 #if defined(__amd64)
1453                 uap->uc_mcontext.gregs[REG_PS] |= 0x45;
1454 #else
1455                 uap->uc_mcontext.gregs[EFL] |= 0x45;
1456 #endif
1457                 return;
1458 
1459         case 0x7e8:
1460         case 0x7f0:
1461                 /* f[u]comip */
1462 #if defined(__amd64)
1463                 uap->uc_mcontext.gregs[REG_PS] |= 0x45;
1464 #else
1465                 uap->uc_mcontext.gregs[EFL] |= 0x45;
1466 #endif
1467                 pop(uap);
1468                 return;
1469         }
1470 
1471         /*
1472          * if there is no result available and the exception is overflow
1473          * or underflow, use the wrapped result
1474          */
1475         r = info->res;
1476 
1477         if (r.type == fex_nodata) {
1478                 if (ex == FPE_FLTOVF || ex == FPE_FLTUND) {
1479                         /* for store instructions, do the scaling and store */
1480                         switch (op & 0x7f8) {
1481                         case 0x110:
1482                         case 0x118:
1483                         case 0x150:
1484                         case 0x158:
1485                         case 0x190:
1486                         case 0x198:
1487 
1488                                 if (!ea)
1489                                         return;
1490 
1491                                 if (ex == FPE_FLTOVF)
1492                                         *(float *)ea = (fpreg(uap, 0) * fov) *
1493                                             fov;
1494                                 else
1495                                         *(float *)ea = (fpreg(uap, 0) * fun) *
1496                                             fun;
1497 
1498                                 if ((op & 8) != 0)
1499                                         pop(uap);
1500 
1501                                 break;
1502 
1503                         case 0x510:
1504                         case 0x518:
1505                         case 0x550:
1506                         case 0x558:
1507                         case 0x590:
1508                         case 0x598:
1509 
1510                                 if (!ea)
1511                                         return;
1512 
1513                                 if (ex == FPE_FLTOVF)
1514                                         *(double *)ea = (fpreg(uap, 0) * dov) *
1515                                             dov;
1516                                 else
1517                                         *(double *)ea = (fpreg(uap, 0) * dun) *
1518                                             dun;
1519 
1520                                 if ((op & 8) != 0)
1521                                         pop(uap);
1522 
1523                                 break;
1524                         }
1525                 }
1526 
1527 #ifdef DEBUG
1528                 else if (ex != FPE_FLTRES) {
1529                         printf("No result supplied, stack may be hosed\n");
1530                 }
1531 #endif
1532                 return;
1533         }
1534 
1535         /*
1536          * otherwise convert the supplied result to the correct type, put it
1537          * in the destination, and update the stack as need be
1538          */
1539 
1540         /* store instructions */
1541         switch (op & 0x7f8) {
1542         case 0x110:
1543         case 0x118:
1544         case 0x150:
1545         case 0x158:
1546         case 0x190:
1547         case 0x198:
1548 
1549                 if (!ea)
1550                         return;
1551 
1552                 switch (r.type) {
1553                 case fex_int:
1554                         *(float *)ea = (float)r.val.i;
1555                         break;
1556 
1557                 case fex_llong:
1558                         *(float *)ea = (float)r.val.l;
1559                         break;
1560 
1561                 case fex_float:
1562                         *(float *)ea = r.val.f;
1563                         break;
1564 
1565                 case fex_double:
1566                         *(float *)ea = (float)r.val.d;
1567                         break;
1568 
1569                 case fex_ldouble:
1570                         *(float *)ea = (float)r.val.q;
1571                         break;
1572 
1573                 default:
1574                         break;
1575                 }
1576 
1577                 if (ex != FPE_FLTRES && (op & 8) != 0)
1578                         pop(uap);
1579 
1580                 return;
1581 
1582         case 0x310:
1583         case 0x318:
1584         case 0x350:
1585         case 0x358:
1586         case 0x390:
1587         case 0x398:
1588 
1589                 if (!ea)
1590                         return;
1591 
1592                 switch (r.type) {
1593                 case fex_int:
1594                         *(int *)ea = r.val.i;
1595                         break;
1596 
1597                 case fex_llong:
1598                         *(int *)ea = (int)r.val.l;
1599                         break;
1600 
1601                 case fex_float:
1602                         *(int *)ea = (int)r.val.f;
1603                         break;
1604 
1605                 case fex_double:
1606                         *(int *)ea = (int)r.val.d;
1607                         break;
1608 
1609                 case fex_ldouble:
1610                         *(int *)ea = (int)r.val.q;
1611                         break;
1612 
1613                 default:
1614                         break;
1615                 }
1616 
1617                 if (ex != FPE_FLTRES && (op & 8) != 0)
1618                         pop(uap);
1619 
1620                 return;
1621 
1622         case 0x510:
1623         case 0x518:
1624         case 0x550:
1625         case 0x558:
1626         case 0x590:
1627         case 0x598:
1628 
1629                 if (!ea)
1630                         return;
1631 
1632                 switch (r.type) {
1633                 case fex_int:
1634                         *(double *)ea = (double)r.val.i;
1635                         break;
1636 
1637                 case fex_llong:
1638                         *(double *)ea = (double)r.val.l;
1639                         break;
1640 
1641                 case fex_float:
1642                         *(double *)ea = (double)r.val.f;
1643                         break;
1644 
1645                 case fex_double:
1646                         *(double *)ea = r.val.d;
1647                         break;
1648 
1649                 case fex_ldouble:
1650                         *(double *)ea = (double)r.val.q;
1651                         break;
1652 
1653                 default:
1654                         break;
1655                 }
1656 
1657                 if (ex != FPE_FLTRES && (op & 8) != 0)
1658                         pop(uap);
1659 
1660                 return;
1661 
1662         case 0x710:
1663         case 0x718:
1664         case 0x750:
1665         case 0x758:
1666         case 0x790:
1667         case 0x798:
1668 
1669                 if (!ea)
1670                         return;
1671 
1672                 switch (r.type) {
1673                 case fex_int:
1674                         *(short *)ea = (short)r.val.i;
1675                         break;
1676 
1677                 case fex_llong:
1678                         *(short *)ea = (short)r.val.l;
1679                         break;
1680 
1681                 case fex_float:
1682                         *(short *)ea = (short)r.val.f;
1683                         break;
1684 
1685                 case fex_double:
1686                         *(short *)ea = (short)r.val.d;
1687                         break;
1688 
1689                 case fex_ldouble:
1690                         *(short *)ea = (short)r.val.q;
1691                         break;
1692 
1693                 default:
1694                         break;
1695                 }
1696 
1697                 if (ex != FPE_FLTRES && (op & 8) != 0)
1698                         pop(uap);
1699 
1700                 return;
1701 
1702         case 0x730:
1703         case 0x770:
1704         case 0x7b0:
1705 
1706                 /* fbstp; don't bother */
1707                 if (ea && ex != FPE_FLTRES)
1708                         pop(uap);
1709 
1710                 return;
1711 
1712         case 0x738:
1713         case 0x778:
1714         case 0x7b8:
1715 
1716                 if (!ea)
1717                         return;
1718 
1719                 switch (r.type) {
1720                 case fex_int:
1721                         *(long long *)ea = (long long)r.val.i;
1722                         break;
1723 
1724                 case fex_llong:
1725                         *(long long *)ea = r.val.l;
1726                         break;
1727 
1728                 case fex_float:
1729                         *(long long *)ea = (long long)r.val.f;
1730                         break;
1731 
1732                 case fex_double:
1733                         *(long long *)ea = (long long)r.val.d;
1734                         break;
1735 
1736                 case fex_ldouble:
1737                         *(long long *)ea = (long long)r.val.q;
1738                         break;
1739 
1740                 default:
1741                         break;
1742                 }
1743 
1744                 if (ex != FPE_FLTRES)
1745                         pop(uap);
1746 
1747                 return;
1748         }
1749 
1750         /* for all other instructions, the result goes into a register */
1751         switch (r.type) {
1752         case fex_int:
1753                 r.val.q = (long double)r.val.i;
1754                 break;
1755 
1756         case fex_llong:
1757                 r.val.q = (long double)r.val.l;
1758                 break;
1759 
1760         case fex_float:
1761                 r.val.q = (long double)r.val.f;
1762                 break;
1763 
1764         case fex_double:
1765                 r.val.q = (long double)r.val.d;
1766                 break;
1767 
1768         default:
1769                 break;
1770         }
1771 
1772         /* for load instructions, push the result onto the stack */
1773         switch (op & 0x7f8) {
1774         case 0x100:
1775         case 0x140:
1776         case 0x180:
1777         case 0x500:
1778         case 0x540:
1779         case 0x580:
1780 
1781                 if (ea)
1782                         push(r.val.q, uap);
1783 
1784                 return;
1785         }
1786 
1787         /*
1788          * for all other instructions, if the exception is overflow,
1789          * underflow, or inexact, the stack has already been updated
1790          */
1791         stack = (ex == FPE_FLTOVF || ex == FPE_FLTUND || ex == FPE_FLTRES);
1792 
1793         switch (op & 0x7f8) {
1794         case 0x1f0:                     /* oddballs */
1795 
1796                 switch (op) {
1797                 case 0x1f1:             /* fyl2x */
1798                 case 0x1f3:             /* fpatan */
1799                 case 0x1f9:             /* fyl2xp1 */
1800 
1801                         /* pop the stack, leaving the result in st */
1802                         if (!stack)
1803                                 pop(uap);
1804 
1805                         fpreg(uap, 0) = r.val.q;
1806                         return;
1807 
1808                 case 0x1f2:             /* fpatan */
1809 
1810                         /* fptan pushes 1.0 afterward */
1811                         if (stack) {
1812                                 fpreg(uap, 1) = r.val.q;
1813                         } else {
1814                                 fpreg(uap, 0) = r.val.q;
1815                                 push(1.0L, uap);
1816                         }
1817 
1818                         return;
1819 
1820                 case 0x1f4:             /* fxtract */
1821                 case 0x1fb:             /* fsincos */
1822 
1823                         /* leave the supplied result in st */
1824                         if (stack) {
1825                                 fpreg(uap, 0) = r.val.q;
1826                         } else {
1827                                 fpreg(uap, 0) = 0.0;    /* punt */
1828                                 push(r.val.q, uap);
1829                         }
1830 
1831                         return;
1832                 }
1833 
1834                 /* all others leave the stack alone and the result in st */
1835                 fpreg(uap, 0) = r.val.q;
1836                 return;
1837 
1838         case 0x4c0:
1839         case 0x4c8:
1840         case 0x4e0:
1841         case 0x4e8:
1842         case 0x4f0:
1843         case 0x4f8:
1844                 fpreg(uap, op & 7) = r.val.q;
1845                 return;
1846 
1847         case 0x6c0:
1848         case 0x6c8:
1849         case 0x6e0:
1850         case 0x6e8:
1851         case 0x6f0:
1852         case 0x6f8:
1853 
1854                 /* stack is popped afterward */
1855                 if (stack) {
1856                         fpreg(uap, (op - 1) & 7) = r.val.q;
1857                 } else {
1858                         fpreg(uap, op & 7) = r.val.q;
1859                         pop(uap);
1860                 }
1861 
1862                 return;
1863 
1864         default:
1865                 fpreg(uap, 0) = r.val.q;
1866                 return;
1867         }
1868 }