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