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