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 <ucontext.h>
  32 #include <fenv.h>
  33 #if defined(__SUNPRO_C)
  34 #include <sunmath.h>
  35 #else
  36 #include <sys/ieeefp.h>
  37 #endif
  38 #include "fex_handler.h"
  39 #include "fenv_inlines.h"
  40 
  41 #if !defined(REG_PC)
  42 #define REG_PC  EIP
  43 #endif
  44 
  45 #if !defined(REG_PS)
  46 #define REG_PS  EFL
  47 #endif
  48 
  49 #ifdef __amd64
  50 #define regno(X)        ((X < 4)? REG_RAX - X : \
  51                         ((X > 4)? REG_RAX + 1 - X : REG_RSP))
  52 #else
  53 #define regno(X)        (EAX - X)
  54 #endif
  55 
  56 /*
  57  * Support for SSE instructions
  58  */
  59 
  60 /*
  61  * Decode an SSE instruction.  Fill in *inst and return the length of the
  62  * instruction in bytes.  Return 0 if the instruction is not recognized.
  63  */
  64 int
  65 __fex_parse_sse(ucontext_t *uap, sseinst_t *inst)
  66 {
  67         unsigned char   *ip;
  68         char            *addr;
  69         int             i, dbl, simd, rex, modrm, sib, r;
  70 
  71         i = 0;
  72         ip = (unsigned char *)uap->uc_mcontext.gregs[REG_PC];
  73 
  74         /* look for pseudo-prefixes */
  75         dbl = 0;
  76         simd = SIMD;
  77         if (ip[i] == 0xF3) {
  78                 simd = 0;
  79                 i++;
  80         } else if (ip[i] == 0x66) {
  81                 dbl = DOUBLE;
  82                 i++;
  83         } else if (ip[i] == 0xF2) {
  84                 dbl = DOUBLE;
  85                 simd = 0;
  86                 i++;
  87         }
  88 
  89         /* look for AMD64 REX prefix */
  90         rex = 0;
  91         if (ip[i] >= 0x40 && ip[i] <= 0x4F) {
  92                 rex = ip[i];
  93                 i++;
  94         }
  95 
  96         /* parse opcode */
  97         if (ip[i++] != 0x0F)
  98                 return 0;
  99         switch (ip[i++]) {
 100         case 0x2A:
 101                 inst->op = (int)cvtsi2ss + simd + dbl;
 102                 if (!simd)
 103                         inst->op = (int)inst->op + (rex & 8);
 104                 break;
 105 
 106         case 0x2C:
 107                 inst->op = (int)cvttss2si + simd + dbl;
 108                 if (!simd)
 109                         inst->op = (int)inst->op + (rex & 8);
 110                 break;
 111 
 112         case 0x2D:
 113                 inst->op = (int)cvtss2si + simd + dbl;
 114                 if (!simd)
 115                         inst->op = (int)inst->op + (rex & 8);
 116                 break;
 117 
 118         case 0x2E:
 119                 /* oddball: scalar instruction in a SIMD opcode group */
 120                 if (!simd)
 121                         return 0;
 122                 inst->op = (int)ucomiss + dbl;
 123                 break;
 124 
 125         case 0x2F:
 126                 /* oddball: scalar instruction in a SIMD opcode group */
 127                 if (!simd)
 128                         return 0;
 129                 inst->op = (int)comiss + dbl;
 130                 break;
 131 
 132         case 0x51:
 133                 inst->op = (int)sqrtss + simd + dbl;
 134                 break;
 135 
 136         case 0x58:
 137                 inst->op = (int)addss + simd + dbl;
 138                 break;
 139 
 140         case 0x59:
 141                 inst->op = (int)mulss + simd + dbl;
 142                 break;
 143 
 144         case 0x5A:
 145                 inst->op = (int)cvtss2sd + simd + dbl;
 146                 break;
 147 
 148         case 0x5B:
 149                 if (dbl) {
 150                         if (simd)
 151                                 inst->op = cvtps2dq;
 152                         else
 153                                 return 0;
 154                 } else {
 155                         inst->op = (simd)? cvtdq2ps : cvttps2dq;
 156                 }
 157                 break;
 158 
 159         case 0x5C:
 160                 inst->op = (int)subss + simd + dbl;
 161                 break;
 162 
 163         case 0x5D:
 164                 inst->op = (int)minss + simd + dbl;
 165                 break;
 166 
 167         case 0x5E:
 168                 inst->op = (int)divss + simd + dbl;
 169                 break;
 170 
 171         case 0x5F:
 172                 inst->op = (int)maxss + simd + dbl;
 173                 break;
 174 
 175         case 0xC2:
 176                 inst->op = (int)cmpss + simd + dbl;
 177                 break;
 178 
 179         case 0xE6:
 180                 if (simd) {
 181                         if (dbl)
 182                                 inst->op = cvttpd2dq;
 183                         else
 184                                 return 0;
 185                 } else {
 186                         inst->op = (dbl)? cvtpd2dq : cvtdq2pd;
 187                 }
 188                 break;
 189 
 190         default:
 191                 return 0;
 192         }
 193 
 194         /* locate operands */
 195         modrm = ip[i++];
 196 
 197         if (inst->op == cvtss2si || inst->op == cvttss2si ||
 198             inst->op == cvtsd2si || inst->op == cvttsd2si ||
 199             inst->op == cvtss2siq || inst->op == cvttss2siq ||
 200             inst->op == cvtsd2siq || inst->op == cvttsd2siq) {
 201                 /* op1 is a gp register */
 202                 r = ((rex & 4) << 1) | ((modrm >> 3) & 7);
 203                 inst->op1 = (sseoperand_t *)&uap->uc_mcontext.gregs[regno(r)];
 204         } else if (inst->op == cvtps2pi || inst->op == cvttps2pi ||
 205             inst->op == cvtpd2pi || inst->op == cvttpd2pi) {
 206                 /* op1 is a mmx register */
 207 #ifdef __amd64
 208                 inst->op1 = (sseoperand_t *)&uap->uc_mcontext.fpregs.fp_reg_set.
 209                     fpchip_state.st[(modrm >> 3) & 7];
 210 #else
 211                 inst->op1 = (sseoperand_t *)(10 * ((modrm >> 3) & 7) +
 212                     (char *)&uap->uc_mcontext.fpregs.fp_reg_set.
 213                     fpchip_state.state[7]);
 214 #endif
 215         } else {
 216                 /* op1 is a xmm register */
 217                 r = ((rex & 4) << 1) | ((modrm >> 3) & 7);
 218                 inst->op1 = (sseoperand_t *)&uap->uc_mcontext.fpregs.
 219                     fp_reg_set.fpchip_state.xmm[r];
 220         }
 221 
 222         if ((modrm >> 6) == 3) {
 223                 if (inst->op == cvtsi2ss || inst->op == cvtsi2sd ||
 224                     inst->op == cvtsi2ssq || inst->op == cvtsi2sdq) {
 225                         /* op2 is a gp register */
 226                         r = ((rex & 1) << 3) | (modrm & 7);
 227                         inst->op2 = (sseoperand_t *)&uap->uc_mcontext.
 228                             gregs[regno(r)];
 229                 } else if (inst->op == cvtpi2ps || inst->op == cvtpi2pd) {
 230                         /* op2 is a mmx register */
 231 #ifdef __amd64
 232                         inst->op2 = (sseoperand_t *)&uap->uc_mcontext.fpregs.
 233                             fp_reg_set.fpchip_state.st[modrm & 7];
 234 #else
 235                         inst->op2 = (sseoperand_t *)(10 * (modrm & 7) +
 236                             (char *)&uap->uc_mcontext.fpregs.fp_reg_set.
 237                             fpchip_state.state[7]);
 238 #endif
 239                 } else {
 240                         /* op2 is a xmm register */
 241                         r = ((rex & 1) << 3) | (modrm & 7);
 242                         inst->op2 = (sseoperand_t *)&uap->uc_mcontext.fpregs.
 243                             fp_reg_set.fpchip_state.xmm[r];
 244                 }
 245         } else if ((modrm & 0xc7) == 0x05) {
 246 #ifdef __amd64
 247                 /* address of next instruction + offset */
 248                 r = i + 4;
 249                 if (inst->op == cmpss || inst->op == cmpps ||
 250                     inst->op == cmpsd || inst->op == cmppd)
 251                         r++;
 252                 inst->op2 = (sseoperand_t *)(ip + r + *(int *)(ip + i));
 253 #else
 254                 /* absolute address */
 255                 inst->op2 = (sseoperand_t *)(*(int *)(ip + i));
 256 #endif
 257                 i += 4;
 258         } else {
 259                 /* complex address */
 260                 if ((modrm & 7) == 4) {
 261                         /* parse sib byte */
 262                         sib = ip[i++];
 263                         if ((sib & 7) == 5 && (modrm >> 6) == 0) {
 264                                 /* start with absolute address */
 265                                 addr = (char *)(uintptr_t)(*(int *)(ip + i));
 266                                 i += 4;
 267                         } else {
 268                                 /* start with base */
 269                                 r = ((rex & 1) << 3) | (sib & 7);
 270                                 addr = (char *)uap->uc_mcontext.gregs[regno(r)];
 271                         }
 272                         r = ((rex & 2) << 2) | ((sib >> 3) & 7);
 273                         if (r != 4) {
 274                                 /* add scaled index */
 275                                 addr += uap->uc_mcontext.gregs[regno(r)]
 276                                     << (sib >> 6);
 277                         }
 278                 } else {
 279                         r = ((rex & 1) << 3) | (modrm & 7);
 280                         addr = (char *)uap->uc_mcontext.gregs[regno(r)];
 281                 }
 282 
 283                 /* add displacement, if any */
 284                 if ((modrm >> 6) == 1) {
 285                         addr += (char)ip[i++];
 286                 } else if ((modrm >> 6) == 2) {
 287                         addr += *(int *)(ip + i);
 288                         i += 4;
 289                 }
 290                 inst->op2 = (sseoperand_t *)addr;
 291         }
 292 
 293         if (inst->op == cmpss || inst->op == cmpps || inst->op == cmpsd ||
 294             inst->op == cmppd) {
 295                 /* get the immediate operand */
 296                 inst->imm = ip[i++];
 297         }
 298 
 299         return i;
 300 }
 301 
 302 static enum fp_class_type
 303 my_fp_classf(float *x)
 304 {
 305         int     i = *(int *)x & ~0x80000000;
 306 
 307         if (i < 0x7f800000) {
 308                 if (i < 0x00800000)
 309                         return ((i == 0)? fp_zero : fp_subnormal);
 310                 return fp_normal;
 311         }
 312         else if (i == 0x7f800000)
 313                 return fp_infinity;
 314         else if (i & 0x400000)
 315                 return fp_quiet;
 316         else
 317                 return fp_signaling;
 318 }
 319 
 320 static enum fp_class_type
 321 my_fp_class(double *x)
 322 {
 323         int     i = *(1+(int *)x) & ~0x80000000;
 324 
 325         if (i < 0x7ff00000) {
 326                 if (i < 0x00100000)
 327                         return (((i | *(int *)x) == 0)? fp_zero : fp_subnormal);
 328                 return fp_normal;
 329         }
 330         else if (i == 0x7ff00000 && *(int *)x == 0)
 331                 return fp_infinity;
 332         else if (i & 0x80000)
 333                 return fp_quiet;
 334         else
 335                 return fp_signaling;
 336 }
 337 
 338 /*
 339  * Inspect a scalar SSE instruction that incurred an invalid operation
 340  * exception to determine which type of exception it was.
 341  */
 342 static enum fex_exception
 343 __fex_get_sse_invalid_type(sseinst_t *inst)
 344 {
 345         enum fp_class_type      t1, t2;
 346 
 347         /* check op2 for signaling nan */
 348         t2 = ((int)inst->op & DOUBLE)? my_fp_class(&inst->op2->d[0]) :
 349             my_fp_classf(&inst->op2->f[0]);
 350         if (t2 == fp_signaling)
 351                 return fex_inv_snan;
 352 
 353         /* eliminate all single-operand instructions */
 354         switch (inst->op) {
 355         case cvtsd2ss:
 356         case cvtss2sd:
 357                 /* hmm, this shouldn't have happened */
 358                 return (enum fex_exception) -1;
 359 
 360         case sqrtss:
 361         case sqrtsd:
 362                 return fex_inv_sqrt;
 363 
 364         case cvtss2si:
 365         case cvtsd2si:
 366         case cvttss2si:
 367         case cvttsd2si:
 368         case cvtss2siq:
 369         case cvtsd2siq:
 370         case cvttss2siq:
 371         case cvttsd2siq:
 372                 return fex_inv_int;
 373         }
 374 
 375         /* check op1 for signaling nan */
 376         t1 = ((int)inst->op & DOUBLE)? my_fp_class(&inst->op1->d[0]) :
 377             my_fp_classf(&inst->op1->f[0]);
 378         if (t1 == fp_signaling)
 379                 return fex_inv_snan;
 380 
 381         /* check two-operand instructions for other cases */
 382         switch (inst->op) {
 383         case cmpss:
 384         case cmpsd:
 385         case minss:
 386         case minsd:
 387         case maxss:
 388         case maxsd:
 389         case comiss:
 390         case comisd:
 391                 return fex_inv_cmp;
 392 
 393         case addss:
 394         case addsd:
 395         case subss:
 396         case subsd:
 397                 if (t1 == fp_infinity && t2 == fp_infinity)
 398                         return fex_inv_isi;
 399                 break;
 400 
 401         case mulss:
 402         case mulsd:
 403                 if ((t1 == fp_zero && t2 == fp_infinity) ||
 404                     (t2 == fp_zero && t1 == fp_infinity))
 405                         return fex_inv_zmi;
 406                 break;
 407 
 408         case divss:
 409         case divsd:
 410                 if (t1 == fp_zero && t2 == fp_zero)
 411                         return fex_inv_zdz;
 412                 if (t1 == fp_infinity && t2 == fp_infinity)
 413                         return fex_inv_idi;
 414         }
 415 
 416         return (enum fex_exception)-1;
 417 }
 418 
 419 /* inline templates */
 420 extern void sse_cmpeqss(float *, float *, int *);
 421 extern void sse_cmpltss(float *, float *, int *);
 422 extern void sse_cmpless(float *, float *, int *);
 423 extern void sse_cmpunordss(float *, float *, int *);
 424 extern void sse_minss(float *, float *, float *);
 425 extern void sse_maxss(float *, float *, float *);
 426 extern void sse_addss(float *, float *, float *);
 427 extern void sse_subss(float *, float *, float *);
 428 extern void sse_mulss(float *, float *, float *);
 429 extern void sse_divss(float *, float *, float *);
 430 extern void sse_sqrtss(float *, float *);
 431 extern void sse_ucomiss(float *, float *);
 432 extern void sse_comiss(float *, float *);
 433 extern void sse_cvtss2sd(float *, double *);
 434 extern void sse_cvtsi2ss(int *, float *);
 435 extern void sse_cvttss2si(float *, int *);
 436 extern void sse_cvtss2si(float *, int *);
 437 #ifdef __amd64
 438 extern void sse_cvtsi2ssq(long long *, float *);
 439 extern void sse_cvttss2siq(float *, long long *);
 440 extern void sse_cvtss2siq(float *, long long *);
 441 #endif
 442 extern void sse_cmpeqsd(double *, double *, long long *);
 443 extern void sse_cmpltsd(double *, double *, long long *);
 444 extern void sse_cmplesd(double *, double *, long long *);
 445 extern void sse_cmpunordsd(double *, double *, long long *);
 446 extern void sse_minsd(double *, double *, double *);
 447 extern void sse_maxsd(double *, double *, double *);
 448 extern void sse_addsd(double *, double *, double *);
 449 extern void sse_subsd(double *, double *, double *);
 450 extern void sse_mulsd(double *, double *, double *);
 451 extern void sse_divsd(double *, double *, double *);
 452 extern void sse_sqrtsd(double *, double *);
 453 extern void sse_ucomisd(double *, double *);
 454 extern void sse_comisd(double *, double *);
 455 extern void sse_cvtsd2ss(double *, float *);
 456 extern void sse_cvtsi2sd(int *, double *);
 457 extern void sse_cvttsd2si(double *, int *);
 458 extern void sse_cvtsd2si(double *, int *);
 459 #ifdef __amd64
 460 extern void sse_cvtsi2sdq(long long *, double *);
 461 extern void sse_cvttsd2siq(double *, long long *);
 462 extern void sse_cvtsd2siq(double *, long long *);
 463 #endif
 464 
 465 /*
 466  * Fill in *info with the operands, default untrapped result, and
 467  * flags produced by a scalar SSE instruction, and return the type
 468  * of trapped exception (if any).  On entry, the mxcsr must have
 469  * all exceptions masked and all flags clear.  The same conditions
 470  * will hold on exit.
 471  *
 472  * This routine does not work if the instruction specified by *inst
 473  * is not a scalar instruction.
 474  */
 475 enum fex_exception
 476 __fex_get_sse_op(ucontext_t *uap, sseinst_t *inst, fex_info_t *info)
 477 {
 478         unsigned int    e, te, mxcsr, oldmxcsr, subnorm;
 479 
 480         /*
 481          * Perform the operation with traps disabled and check the
 482          * exception flags.  If the underflow trap was enabled, also
 483          * check for an exact subnormal result.
 484          */
 485         __fenv_getmxcsr(&oldmxcsr);
 486         subnorm = 0;
 487         if ((int)inst->op & DOUBLE) {
 488                 if (inst->op == cvtsi2sd) {
 489                         info->op1.type = fex_int;
 490                         info->op1.val.i = inst->op2->i[0];
 491                         info->op2.type = fex_nodata;
 492                 } else if (inst->op == cvtsi2sdq) {
 493                         info->op1.type = fex_llong;
 494                         info->op1.val.l = inst->op2->l[0];
 495                         info->op2.type = fex_nodata;
 496                 } else if (inst->op == sqrtsd || inst->op == cvtsd2ss ||
 497                     inst->op == cvttsd2si || inst->op == cvtsd2si ||
 498                     inst->op == cvttsd2siq || inst->op == cvtsd2siq) {
 499                         info->op1.type = fex_double;
 500                         info->op1.val.d = inst->op2->d[0];
 501                         info->op2.type = fex_nodata;
 502                 } else {
 503                         info->op1.type = fex_double;
 504                         info->op1.val.d = inst->op1->d[0];
 505                         info->op2.type = fex_double;
 506                         info->op2.val.d = inst->op2->d[0];
 507                 }
 508                 info->res.type = fex_double;
 509                 switch (inst->op) {
 510                 case cmpsd:
 511                         info->op = fex_cmp;
 512                         info->res.type = fex_llong;
 513                         switch (inst->imm & 3) {
 514                         case 0:
 515                                 sse_cmpeqsd(&info->op1.val.d, &info->op2.val.d,
 516                                     &info->res.val.l);
 517                                 break;
 518 
 519                         case 1:
 520                                 sse_cmpltsd(&info->op1.val.d, &info->op2.val.d,
 521                                     &info->res.val.l);
 522                                 break;
 523 
 524                         case 2:
 525                                 sse_cmplesd(&info->op1.val.d, &info->op2.val.d,
 526                                     &info->res.val.l);
 527                                 break;
 528 
 529                         case 3:
 530                                 sse_cmpunordsd(&info->op1.val.d,
 531                                     &info->op2.val.d, &info->res.val.l);
 532                         }
 533                         if (inst->imm & 4)
 534                                 info->res.val.l ^= 0xffffffffffffffffull;
 535                         break;
 536 
 537                 case minsd:
 538                         info->op = fex_other;
 539                         sse_minsd(&info->op1.val.d, &info->op2.val.d,
 540                             &info->res.val.d);
 541                         break;
 542 
 543                 case maxsd:
 544                         info->op = fex_other;
 545                         sse_maxsd(&info->op1.val.d, &info->op2.val.d,
 546                             &info->res.val.d);
 547                         break;
 548 
 549                 case addsd:
 550                         info->op = fex_add;
 551                         sse_addsd(&info->op1.val.d, &info->op2.val.d,
 552                             &info->res.val.d);
 553                         if (my_fp_class(&info->res.val.d) == fp_subnormal)
 554                                 subnorm = 1;
 555                         break;
 556 
 557                 case subsd:
 558                         info->op = fex_sub;
 559                         sse_subsd(&info->op1.val.d, &info->op2.val.d,
 560                             &info->res.val.d);
 561                         if (my_fp_class(&info->res.val.d) == fp_subnormal)
 562                                 subnorm = 1;
 563                         break;
 564 
 565                 case mulsd:
 566                         info->op = fex_mul;
 567                         sse_mulsd(&info->op1.val.d, &info->op2.val.d,
 568                             &info->res.val.d);
 569                         if (my_fp_class(&info->res.val.d) == fp_subnormal)
 570                                 subnorm = 1;
 571                         break;
 572 
 573                 case divsd:
 574                         info->op = fex_div;
 575                         sse_divsd(&info->op1.val.d, &info->op2.val.d,
 576                             &info->res.val.d);
 577                         if (my_fp_class(&info->res.val.d) == fp_subnormal)
 578                                 subnorm = 1;
 579                         break;
 580 
 581                 case sqrtsd:
 582                         info->op = fex_sqrt;
 583                         sse_sqrtsd(&info->op1.val.d, &info->res.val.d);
 584                         break;
 585 
 586                 case cvtsd2ss:
 587                         info->op = fex_cnvt;
 588                         info->res.type = fex_float;
 589                         sse_cvtsd2ss(&info->op1.val.d, &info->res.val.f);
 590                         if (my_fp_classf(&info->res.val.f) == fp_subnormal)
 591                                 subnorm = 1;
 592                         break;
 593 
 594                 case cvtsi2sd:
 595                         info->op = fex_cnvt;
 596                         sse_cvtsi2sd(&info->op1.val.i, &info->res.val.d);
 597                         break;
 598 
 599                 case cvttsd2si:
 600                         info->op = fex_cnvt;
 601                         info->res.type = fex_int;
 602                         sse_cvttsd2si(&info->op1.val.d, &info->res.val.i);
 603                         break;
 604 
 605                 case cvtsd2si:
 606                         info->op = fex_cnvt;
 607                         info->res.type = fex_int;
 608                         sse_cvtsd2si(&info->op1.val.d, &info->res.val.i);
 609                         break;
 610 
 611 #ifdef __amd64
 612                 case cvtsi2sdq:
 613                         info->op = fex_cnvt;
 614                         sse_cvtsi2sdq(&info->op1.val.l, &info->res.val.d);
 615                         break;
 616 
 617                 case cvttsd2siq:
 618                         info->op = fex_cnvt;
 619                         info->res.type = fex_llong;
 620                         sse_cvttsd2siq(&info->op1.val.d, &info->res.val.l);
 621                         break;
 622 
 623                 case cvtsd2siq:
 624                         info->op = fex_cnvt;
 625                         info->res.type = fex_llong;
 626                         sse_cvtsd2siq(&info->op1.val.d, &info->res.val.l);
 627                         break;
 628 #endif
 629 
 630                 case ucomisd:
 631                         info->op = fex_cmp;
 632                         info->res.type = fex_nodata;
 633                         sse_ucomisd(&info->op1.val.d, &info->op2.val.d);
 634                         break;
 635 
 636                 case comisd:
 637                         info->op = fex_cmp;
 638                         info->res.type = fex_nodata;
 639                         sse_comisd(&info->op1.val.d, &info->op2.val.d);
 640                         break;
 641                 }
 642         } else {
 643                 if (inst->op == cvtsi2ss) {
 644                         info->op1.type = fex_int;
 645                         info->op1.val.i = inst->op2->i[0];
 646                         info->op2.type = fex_nodata;
 647                 } else if (inst->op == cvtsi2ssq) {
 648                         info->op1.type = fex_llong;
 649                         info->op1.val.l = inst->op2->l[0];
 650                         info->op2.type = fex_nodata;
 651                 } else if (inst->op == sqrtss || inst->op == cvtss2sd ||
 652                     inst->op == cvttss2si || inst->op == cvtss2si ||
 653                     inst->op == cvttss2siq || inst->op == cvtss2siq) {
 654                         info->op1.type = fex_float;
 655                         info->op1.val.f = inst->op2->f[0];
 656                         info->op2.type = fex_nodata;
 657                 } else {
 658                         info->op1.type = fex_float;
 659                         info->op1.val.f = inst->op1->f[0];
 660                         info->op2.type = fex_float;
 661                         info->op2.val.f = inst->op2->f[0];
 662                 }
 663                 info->res.type = fex_float;
 664                 switch (inst->op) {
 665                 case cmpss:
 666                         info->op = fex_cmp;
 667                         info->res.type = fex_int;
 668                         switch (inst->imm & 3) {
 669                         case 0:
 670                                 sse_cmpeqss(&info->op1.val.f, &info->op2.val.f,
 671                                     &info->res.val.i);
 672                                 break;
 673 
 674                         case 1:
 675                                 sse_cmpltss(&info->op1.val.f, &info->op2.val.f,
 676                                     &info->res.val.i);
 677                                 break;
 678 
 679                         case 2:
 680                                 sse_cmpless(&info->op1.val.f, &info->op2.val.f,
 681                                     &info->res.val.i);
 682                                 break;
 683 
 684                         case 3:
 685                                 sse_cmpunordss(&info->op1.val.f,
 686                                     &info->op2.val.f, &info->res.val.i);
 687                         }
 688                         if (inst->imm & 4)
 689                                 info->res.val.i ^= 0xffffffffu;
 690                         break;
 691 
 692                 case minss:
 693                         info->op = fex_other;
 694                         sse_minss(&info->op1.val.f, &info->op2.val.f,
 695                             &info->res.val.f);
 696                         break;
 697 
 698                 case maxss:
 699                         info->op = fex_other;
 700                         sse_maxss(&info->op1.val.f, &info->op2.val.f,
 701                             &info->res.val.f);
 702                         break;
 703 
 704                 case addss:
 705                         info->op = fex_add;
 706                         sse_addss(&info->op1.val.f, &info->op2.val.f,
 707                             &info->res.val.f);
 708                         if (my_fp_classf(&info->res.val.f) == fp_subnormal)
 709                                 subnorm = 1;
 710                         break;
 711 
 712                 case subss:
 713                         info->op = fex_sub;
 714                         sse_subss(&info->op1.val.f, &info->op2.val.f,
 715                             &info->res.val.f);
 716                         if (my_fp_classf(&info->res.val.f) == fp_subnormal)
 717                                 subnorm = 1;
 718                         break;
 719 
 720                 case mulss:
 721                         info->op = fex_mul;
 722                         sse_mulss(&info->op1.val.f, &info->op2.val.f,
 723                             &info->res.val.f);
 724                         if (my_fp_classf(&info->res.val.f) == fp_subnormal)
 725                                 subnorm = 1;
 726                         break;
 727 
 728                 case divss:
 729                         info->op = fex_div;
 730                         sse_divss(&info->op1.val.f, &info->op2.val.f,
 731                             &info->res.val.f);
 732                         if (my_fp_classf(&info->res.val.f) == fp_subnormal)
 733                                 subnorm = 1;
 734                         break;
 735 
 736                 case sqrtss:
 737                         info->op = fex_sqrt;
 738                         sse_sqrtss(&info->op1.val.f, &info->res.val.f);
 739                         break;
 740 
 741                 case cvtss2sd:
 742                         info->op = fex_cnvt;
 743                         info->res.type = fex_double;
 744                         sse_cvtss2sd(&info->op1.val.f, &info->res.val.d);
 745                         break;
 746 
 747                 case cvtsi2ss:
 748                         info->op = fex_cnvt;
 749                         sse_cvtsi2ss(&info->op1.val.i, &info->res.val.f);
 750                         break;
 751 
 752                 case cvttss2si:
 753                         info->op = fex_cnvt;
 754                         info->res.type = fex_int;
 755                         sse_cvttss2si(&info->op1.val.f, &info->res.val.i);
 756                         break;
 757 
 758                 case cvtss2si:
 759                         info->op = fex_cnvt;
 760                         info->res.type = fex_int;
 761                         sse_cvtss2si(&info->op1.val.f, &info->res.val.i);
 762                         break;
 763 
 764 #ifdef __amd64
 765                 case cvtsi2ssq:
 766                         info->op = fex_cnvt;
 767                         sse_cvtsi2ssq(&info->op1.val.l, &info->res.val.f);
 768                         break;
 769 
 770                 case cvttss2siq:
 771                         info->op = fex_cnvt;
 772                         info->res.type = fex_llong;
 773                         sse_cvttss2siq(&info->op1.val.f, &info->res.val.l);
 774                         break;
 775 
 776                 case cvtss2siq:
 777                         info->op = fex_cnvt;
 778                         info->res.type = fex_llong;
 779                         sse_cvtss2siq(&info->op1.val.f, &info->res.val.l);
 780                         break;
 781 #endif
 782 
 783                 case ucomiss:
 784                         info->op = fex_cmp;
 785                         info->res.type = fex_nodata;
 786                         sse_ucomiss(&info->op1.val.f, &info->op2.val.f);
 787                         break;
 788 
 789                 case comiss:
 790                         info->op = fex_cmp;
 791                         info->res.type = fex_nodata;
 792                         sse_comiss(&info->op1.val.f, &info->op2.val.f);
 793                         break;
 794                 }
 795         }
 796         __fenv_getmxcsr(&mxcsr);
 797         info->flags = mxcsr & 0x3d;
 798         __fenv_setmxcsr(&oldmxcsr);
 799 
 800         /* determine which exception would have been trapped */
 801         te = ~(uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr
 802             >> 7) & 0x3d;
 803         e = mxcsr & te;
 804         if (e & FE_INVALID)
 805                 return __fex_get_sse_invalid_type(inst);
 806         if (e & FE_DIVBYZERO)
 807                 return fex_division;
 808         if (e & FE_OVERFLOW)
 809                 return fex_overflow;
 810         if ((e & FE_UNDERFLOW) || (subnorm && (te & FE_UNDERFLOW)))
 811                 return fex_underflow;
 812         if (e & FE_INEXACT)
 813                 return fex_inexact;
 814         return (enum fex_exception)-1;
 815 }
 816 
 817 /*
 818  * Emulate a SIMD SSE instruction to determine which exceptions occur
 819  * in each part.  For i = 0, 1, 2, and 3, set e[i] to indicate the
 820  * trapped exception that would occur if the i-th part of the SIMD
 821  * instruction were executed in isolation; set e[i] to -1 if no
 822  * trapped exception would occur in this part.  Also fill in info[i]
 823  * with the corresponding operands, default untrapped result, and
 824  * flags.
 825  *
 826  * This routine does not work if the instruction specified by *inst
 827  * is not a SIMD instruction.
 828  */
 829 void
 830 __fex_get_simd_op(ucontext_t *uap, sseinst_t *inst, enum fex_exception *e,
 831     fex_info_t *info)
 832 {
 833         sseinst_t       dummy;
 834         int             i;
 835 
 836         e[0] = e[1] = e[2] = e[3] = -1;
 837 
 838         /* perform each part of the SIMD operation */
 839         switch (inst->op) {
 840         case cmpps:
 841                 dummy.op = cmpss;
 842                 dummy.imm = inst->imm;
 843                 for (i = 0; i < 4; i++) {
 844                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
 845                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
 846                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 847                 }
 848                 break;
 849 
 850         case minps:
 851                 dummy.op = minss;
 852                 for (i = 0; i < 4; i++) {
 853                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
 854                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
 855                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 856                 }
 857                 break;
 858 
 859         case maxps:
 860                 dummy.op = maxss;
 861                 for (i = 0; i < 4; i++) {
 862                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
 863                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
 864                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 865                 }
 866                 break;
 867 
 868         case addps:
 869                 dummy.op = addss;
 870                 for (i = 0; i < 4; i++) {
 871                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
 872                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
 873                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 874                 }
 875                 break;
 876 
 877         case subps:
 878                 dummy.op = subss;
 879                 for (i = 0; i < 4; i++) {
 880                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
 881                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
 882                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 883                 }
 884                 break;
 885 
 886         case mulps:
 887                 dummy.op = mulss;
 888                 for (i = 0; i < 4; i++) {
 889                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
 890                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
 891                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 892                 }
 893                 break;
 894 
 895         case divps:
 896                 dummy.op = divss;
 897                 for (i = 0; i < 4; i++) {
 898                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
 899                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
 900                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 901                 }
 902                 break;
 903 
 904         case sqrtps:
 905                 dummy.op = sqrtss;
 906                 for (i = 0; i < 4; i++) {
 907                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
 908                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
 909                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 910                 }
 911                 break;
 912 
 913         case cvtdq2ps:
 914                 dummy.op = cvtsi2ss;
 915                 for (i = 0; i < 4; i++) {
 916                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
 917                         dummy.op2 = (sseoperand_t *)&inst->op2->i[i];
 918                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 919                 }
 920                 break;
 921 
 922         case cvttps2dq:
 923                 dummy.op = cvttss2si;
 924                 for (i = 0; i < 4; i++) {
 925                         dummy.op1 = (sseoperand_t *)&inst->op1->i[i];
 926                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
 927                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 928                 }
 929                 break;
 930 
 931         case cvtps2dq:
 932                 dummy.op = cvtss2si;
 933                 for (i = 0; i < 4; i++) {
 934                         dummy.op1 = (sseoperand_t *)&inst->op1->i[i];
 935                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
 936                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 937                 }
 938                 break;
 939 
 940         case cvtpi2ps:
 941                 dummy.op = cvtsi2ss;
 942                 for (i = 0; i < 2; i++) {
 943                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
 944                         dummy.op2 = (sseoperand_t *)&inst->op2->i[i];
 945                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 946                 }
 947                 break;
 948 
 949         case cvttps2pi:
 950                 dummy.op = cvttss2si;
 951                 for (i = 0; i < 2; i++) {
 952                         dummy.op1 = (sseoperand_t *)&inst->op1->i[i];
 953                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
 954                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 955                 }
 956                 break;
 957 
 958         case cvtps2pi:
 959                 dummy.op = cvtss2si;
 960                 for (i = 0; i < 2; i++) {
 961                         dummy.op1 = (sseoperand_t *)&inst->op1->i[i];
 962                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
 963                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 964                 }
 965                 break;
 966 
 967         case cmppd:
 968                 dummy.op = cmpsd;
 969                 dummy.imm = inst->imm;
 970                 for (i = 0; i < 2; i++) {
 971                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
 972                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
 973                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 974                 }
 975                 break;
 976 
 977         case minpd:
 978                 dummy.op = minsd;
 979                 for (i = 0; i < 2; i++) {
 980                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
 981                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
 982                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 983                 }
 984                 break;
 985 
 986         case maxpd:
 987                 dummy.op = maxsd;
 988                 for (i = 0; i < 2; i++) {
 989                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
 990                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
 991                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
 992                 }
 993                 break;
 994 
 995         case addpd:
 996                 dummy.op = addsd;
 997                 for (i = 0; i < 2; i++) {
 998                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
 999                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1000                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
1001                 }
1002                 break;
1003 
1004         case subpd:
1005                 dummy.op = subsd;
1006                 for (i = 0; i < 2; i++) {
1007                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1008                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1009                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
1010                 }
1011                 break;
1012 
1013         case mulpd:
1014                 dummy.op = mulsd;
1015                 for (i = 0; i < 2; i++) {
1016                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1017                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1018                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
1019                 }
1020                 break;
1021 
1022         case divpd:
1023                 dummy.op = divsd;
1024                 for (i = 0; i < 2; i++) {
1025                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1026                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1027                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
1028                 }
1029                 break;
1030 
1031         case sqrtpd:
1032                 dummy.op = sqrtsd;
1033                 for (i = 0; i < 2; i++) {
1034                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1035                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1036                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
1037                 }
1038                 break;
1039 
1040         case cvtpi2pd:
1041         case cvtdq2pd:
1042                 dummy.op = cvtsi2sd;
1043                 for (i = 0; i < 2; i++) {
1044                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1045                         dummy.op2 = (sseoperand_t *)&inst->op2->i[i];
1046                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
1047                 }
1048                 break;
1049 
1050         case cvttpd2pi:
1051         case cvttpd2dq:
1052                 dummy.op = cvttsd2si;
1053                 for (i = 0; i < 2; i++) {
1054                         dummy.op1 = (sseoperand_t *)&inst->op1->i[i];
1055                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1056                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
1057                 }
1058                 break;
1059 
1060         case cvtpd2pi:
1061         case cvtpd2dq:
1062                 dummy.op = cvtsd2si;
1063                 for (i = 0; i < 2; i++) {
1064                         dummy.op1 = (sseoperand_t *)&inst->op1->i[i];
1065                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1066                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
1067                 }
1068                 break;
1069 
1070         case cvtps2pd:
1071                 dummy.op = cvtss2sd;
1072                 for (i = 0; i < 2; i++) {
1073                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1074                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1075                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
1076                 }
1077                 break;
1078 
1079         case cvtpd2ps:
1080                 dummy.op = cvtsd2ss;
1081                 for (i = 0; i < 2; i++) {
1082                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
1083                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1084                         e[i] = __fex_get_sse_op(uap, &dummy, &info[i]);
1085                 }
1086         }
1087 }
1088 
1089 /*
1090  * Store the result value from *info in the destination of the scalar
1091  * SSE instruction specified by *inst.  If no result is given but the
1092  * exception is underflow or overflow, supply the default trapped result.
1093  *
1094  * This routine does not work if the instruction specified by *inst
1095  * is not a scalar instruction.
1096  */
1097 void
1098 __fex_st_sse_result(ucontext_t *uap, sseinst_t *inst, enum fex_exception e,
1099     fex_info_t *info)
1100 {
1101         int             i;
1102         long long       l;
1103         float           f, fscl;
1104         double          d, dscl;
1105 
1106         /* for compares that write eflags, just set the flags
1107            to indicate "unordered" */
1108         if (inst->op == ucomiss || inst->op == comiss ||
1109             inst->op == ucomisd || inst->op == comisd) {
1110                 uap->uc_mcontext.gregs[REG_PS] |= 0x45;
1111                 return;
1112         }
1113 
1114         /* if info doesn't specify a result value, try to generate
1115            the default trapped result */
1116         if (info->res.type == fex_nodata) {
1117                 /* set scale factors for exponent wrapping */
1118                 switch (e) {
1119                 case fex_overflow:
1120                         fscl = 1.262177448e-29f; /* 2^-96 */
1121                         dscl = 6.441148769597133308e-232; /* 2^-768 */
1122                         break;
1123 
1124                 case fex_underflow:
1125                         fscl = 7.922816251e+28f; /* 2^96 */
1126                         dscl = 1.552518092300708935e+231; /* 2^768 */
1127                         break;
1128 
1129                 default:
1130                         (void) __fex_get_sse_op(uap, inst, info);
1131                         if (info->res.type == fex_nodata)
1132                                 return;
1133                         goto stuff;
1134                 }
1135 
1136                 /* generate the wrapped result */
1137                 if (inst->op == cvtsd2ss) {
1138                         info->op1.type = fex_double;
1139                         info->op1.val.d = inst->op2->d[0];
1140                         info->op2.type = fex_nodata;
1141                         info->res.type = fex_float;
1142                         info->res.val.f = (float)(fscl * (fscl *
1143                             info->op1.val.d));
1144                 } else if ((int)inst->op & DOUBLE) {
1145                         info->op1.type = fex_double;
1146                         info->op1.val.d = inst->op1->d[0];
1147                         info->op2.type = fex_double;
1148                         info->op2.val.d = inst->op2->d[0];
1149                         info->res.type = fex_double;
1150                         switch (inst->op) {
1151                         case addsd:
1152                                 info->res.val.d = dscl * (dscl *
1153                                     info->op1.val.d + dscl * info->op2.val.d);
1154                                 break;
1155 
1156                         case subsd:
1157                                 info->res.val.d = dscl * (dscl *
1158                                     info->op1.val.d - dscl * info->op2.val.d);
1159                                 break;
1160 
1161                         case mulsd:
1162                                 info->res.val.d = (dscl * info->op1.val.d) *
1163                                     (dscl * info->op2.val.d);
1164                                 break;
1165 
1166                         case divsd:
1167                                 info->res.val.d = (dscl * info->op1.val.d) /
1168                                     (info->op2.val.d / dscl);
1169                                 break;
1170 
1171                         default:
1172                                 return;
1173                         }
1174                 } else {
1175                         info->op1.type = fex_float;
1176                         info->op1.val.f = inst->op1->f[0];
1177                         info->op2.type = fex_float;
1178                         info->op2.val.f = inst->op2->f[0];
1179                         info->res.type = fex_float;
1180                         switch (inst->op) {
1181                         case addss:
1182                                 info->res.val.f = fscl * (fscl *
1183                                     info->op1.val.f + fscl * info->op2.val.f);
1184                                 break;
1185 
1186                         case subss:
1187                                 info->res.val.f = fscl * (fscl *
1188                                     info->op1.val.f - fscl * info->op2.val.f);
1189                                 break;
1190 
1191                         case mulss:
1192                                 info->res.val.f = (fscl * info->op1.val.f) *
1193                                     (fscl * info->op2.val.f);
1194                                 break;
1195 
1196                         case divss:
1197                                 info->res.val.f = (fscl * info->op1.val.f) /
1198                                     (info->op2.val.f / fscl);
1199                                 break;
1200 
1201                         default:
1202                                 return;
1203                         }
1204                 }
1205         }
1206 
1207         /* put the result in the destination */
1208 stuff:
1209         if (inst->op == cmpss || inst->op == cvttss2si || inst->op == cvtss2si
1210             || inst->op == cvttsd2si || inst->op == cvtsd2si) {
1211                 switch (info->res.type) {
1212                 case fex_int:
1213                         i = info->res.val.i;
1214                         break;
1215 
1216                 case fex_llong:
1217                         i = info->res.val.l;
1218                         break;
1219 
1220                 case fex_float:
1221                         i = info->res.val.f;
1222                         break;
1223 
1224                 case fex_double:
1225                         i = info->res.val.d;
1226                         break;
1227 
1228                 case fex_ldouble:
1229                         i = info->res.val.q;
1230                         break;
1231                 }
1232                 inst->op1->i[0] = i;
1233         } else if (inst->op == cmpsd || inst->op == cvttss2siq ||
1234             inst->op == cvtss2siq || inst->op == cvttsd2siq ||
1235             inst->op == cvtsd2siq) {
1236                 switch (info->res.type) {
1237                 case fex_int:
1238                         l = info->res.val.i;
1239                         break;
1240 
1241                 case fex_llong:
1242                         l = info->res.val.l;
1243                         break;
1244 
1245                 case fex_float:
1246                         l = info->res.val.f;
1247                         break;
1248 
1249                 case fex_double:
1250                         l = info->res.val.d;
1251                         break;
1252 
1253                 case fex_ldouble:
1254                         l = info->res.val.q;
1255                         break;
1256                 }
1257                 inst->op1->l[0] = l;
1258         } else if ((((int)inst->op & DOUBLE) && inst->op != cvtsd2ss) ||
1259             inst->op == cvtss2sd) {
1260                 switch (info->res.type) {
1261                 case fex_int:
1262                         d = info->res.val.i;
1263                         break;
1264 
1265                 case fex_llong:
1266                         d = info->res.val.l;
1267                         break;
1268 
1269                 case fex_float:
1270                         d = info->res.val.f;
1271                         break;
1272 
1273                 case fex_double:
1274                         d = info->res.val.d;
1275                         break;
1276 
1277                 case fex_ldouble:
1278                         d = info->res.val.q;
1279                         break;
1280                 }
1281                 inst->op1->d[0] = d;
1282         } else {
1283                 switch (info->res.type) {
1284                 case fex_int:
1285                         f = info->res.val.i;
1286                         break;
1287 
1288                 case fex_llong:
1289                         f = info->res.val.l;
1290                         break;
1291 
1292                 case fex_float:
1293                         f = info->res.val.f;
1294                         break;
1295 
1296                 case fex_double:
1297                         f = info->res.val.d;
1298                         break;
1299 
1300                 case fex_ldouble:
1301                         f = info->res.val.q;
1302                         break;
1303                 }
1304                 inst->op1->f[0] = f;
1305         }
1306 }
1307 
1308 /*
1309  * Store the results from a SIMD instruction.  For each i, store
1310  * the result value from info[i] in the i-th part of the destination
1311  * of the SIMD SSE instruction specified by *inst.  If no result
1312  * is given but the exception indicated by e[i] is underflow or
1313  * overflow, supply the default trapped result.
1314  *
1315  * This routine does not work if the instruction specified by *inst
1316  * is not a SIMD instruction.
1317  */
1318 void
1319 __fex_st_simd_result(ucontext_t *uap, sseinst_t *inst, enum fex_exception *e,
1320     fex_info_t *info)
1321 {
1322         sseinst_t       dummy;
1323         int             i;
1324 
1325         /* store each part */
1326         switch (inst->op) {
1327         case cmpps:
1328                 dummy.op = cmpss;
1329                 dummy.imm = inst->imm;
1330                 for (i = 0; i < 4; i++) {
1331                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
1332                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1333                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1334                 }
1335                 break;
1336 
1337         case minps:
1338                 dummy.op = minss;
1339                 for (i = 0; i < 4; i++) {
1340                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
1341                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1342                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1343                 }
1344                 break;
1345 
1346         case maxps:
1347                 dummy.op = maxss;
1348                 for (i = 0; i < 4; i++) {
1349                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
1350                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1351                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1352                 }
1353                 break;
1354 
1355         case addps:
1356                 dummy.op = addss;
1357                 for (i = 0; i < 4; i++) {
1358                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
1359                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1360                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1361                 }
1362                 break;
1363 
1364         case subps:
1365                 dummy.op = subss;
1366                 for (i = 0; i < 4; i++) {
1367                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
1368                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1369                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1370                 }
1371                 break;
1372 
1373         case mulps:
1374                 dummy.op = mulss;
1375                 for (i = 0; i < 4; i++) {
1376                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
1377                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1378                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1379                 }
1380                 break;
1381 
1382         case divps:
1383                 dummy.op = divss;
1384                 for (i = 0; i < 4; i++) {
1385                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
1386                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1387                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1388                 }
1389                 break;
1390 
1391         case sqrtps:
1392                 dummy.op = sqrtss;
1393                 for (i = 0; i < 4; i++) {
1394                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
1395                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1396                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1397                 }
1398                 break;
1399 
1400         case cvtdq2ps:
1401                 dummy.op = cvtsi2ss;
1402                 for (i = 0; i < 4; i++) {
1403                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
1404                         dummy.op2 = (sseoperand_t *)&inst->op2->i[i];
1405                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1406                 }
1407                 break;
1408 
1409         case cvttps2dq:
1410                 dummy.op = cvttss2si;
1411                 for (i = 0; i < 4; i++) {
1412                         dummy.op1 = (sseoperand_t *)&inst->op1->i[i];
1413                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1414                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1415                 }
1416                 break;
1417 
1418         case cvtps2dq:
1419                 dummy.op = cvtss2si;
1420                 for (i = 0; i < 4; i++) {
1421                         dummy.op1 = (sseoperand_t *)&inst->op1->i[i];
1422                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1423                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1424                 }
1425                 break;
1426 
1427         case cvtpi2ps:
1428                 dummy.op = cvtsi2ss;
1429                 for (i = 0; i < 2; i++) {
1430                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
1431                         dummy.op2 = (sseoperand_t *)&inst->op2->i[i];
1432                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1433                 }
1434                 break;
1435 
1436         case cvttps2pi:
1437                 dummy.op = cvttss2si;
1438                 for (i = 0; i < 2; i++) {
1439                         dummy.op1 = (sseoperand_t *)&inst->op1->i[i];
1440                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1441                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1442                 }
1443                 break;
1444 
1445         case cvtps2pi:
1446                 dummy.op = cvtss2si;
1447                 for (i = 0; i < 2; i++) {
1448                         dummy.op1 = (sseoperand_t *)&inst->op1->i[i];
1449                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1450                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1451                 }
1452                 break;
1453 
1454         case cmppd:
1455                 dummy.op = cmpsd;
1456                 dummy.imm = inst->imm;
1457                 for (i = 0; i < 2; i++) {
1458                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1459                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1460                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1461                 }
1462                 break;
1463 
1464         case minpd:
1465                 dummy.op = minsd;
1466                 for (i = 0; i < 2; i++) {
1467                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1468                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1469                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1470                 }
1471                 break;
1472 
1473         case maxpd:
1474                 dummy.op = maxsd;
1475                 for (i = 0; i < 2; i++) {
1476                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1477                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1478                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1479                 }
1480                 break;
1481 
1482         case addpd:
1483                 dummy.op = addsd;
1484                 for (i = 0; i < 2; i++) {
1485                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1486                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1487                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1488                 }
1489                 break;
1490 
1491         case subpd:
1492                 dummy.op = subsd;
1493                 for (i = 0; i < 2; i++) {
1494                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1495                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1496                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1497                 }
1498                 break;
1499 
1500         case mulpd:
1501                 dummy.op = mulsd;
1502                 for (i = 0; i < 2; i++) {
1503                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1504                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1505                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1506                 }
1507                 break;
1508 
1509         case divpd:
1510                 dummy.op = divsd;
1511                 for (i = 0; i < 2; i++) {
1512                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1513                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1514                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1515                 }
1516                 break;
1517 
1518         case sqrtpd:
1519                 dummy.op = sqrtsd;
1520                 for (i = 0; i < 2; i++) {
1521                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1522                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1523                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1524                 }
1525                 break;
1526 
1527         case cvtpi2pd:
1528         case cvtdq2pd:
1529                 dummy.op = cvtsi2sd;
1530                 for (i = 0; i < 2; i++) {
1531                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1532                         dummy.op2 = (sseoperand_t *)&inst->op2->i[i];
1533                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1534                 }
1535                 break;
1536 
1537         case cvttpd2pi:
1538         case cvttpd2dq:
1539                 dummy.op = cvttsd2si;
1540                 for (i = 0; i < 2; i++) {
1541                         dummy.op1 = (sseoperand_t *)&inst->op1->i[i];
1542                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1543                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1544                 }
1545                 /* for cvttpd2dq, zero the high 64 bits of the destination */
1546                 if (inst->op == cvttpd2dq)
1547                         inst->op1->l[1] = 0ll;
1548                 break;
1549 
1550         case cvtpd2pi:
1551         case cvtpd2dq:
1552                 dummy.op = cvtsd2si;
1553                 for (i = 0; i < 2; i++) {
1554                         dummy.op1 = (sseoperand_t *)&inst->op1->i[i];
1555                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1556                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1557                 }
1558                 /* for cvtpd2dq, zero the high 64 bits of the destination */
1559                 if (inst->op == cvtpd2dq)
1560                         inst->op1->l[1] = 0ll;
1561                 break;
1562 
1563         case cvtps2pd:
1564                 dummy.op = cvtss2sd;
1565                 for (i = 0; i < 2; i++) {
1566                         dummy.op1 = (sseoperand_t *)&inst->op1->d[i];
1567                         dummy.op2 = (sseoperand_t *)&inst->op2->f[i];
1568                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1569                 }
1570                 break;
1571 
1572         case cvtpd2ps:
1573                 dummy.op = cvtsd2ss;
1574                 for (i = 0; i < 2; i++) {
1575                         dummy.op1 = (sseoperand_t *)&inst->op1->f[i];
1576                         dummy.op2 = (sseoperand_t *)&inst->op2->d[i];
1577                         __fex_st_sse_result(uap, &dummy, e[i], &info[i]);
1578                 }
1579                 /* zero the high 64 bits of the destination */
1580                 inst->op1->l[1] = 0ll;
1581         }
1582 }