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