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 #if defined(__sparc)
  31 #include "fenv_synonyms.h"
  32 #include <stdio.h>
  33 #include <unistd.h>
  34 #include <string.h>
  35 #include <signal.h>
  36 #include <siginfo.h>
  37 #include <thread.h>
  38 #include <ucontext.h>
  39 #include <math.h>
  40 #if defined(__SUNPRO_C)
  41 #include <sunmath.h>
  42 #endif
  43 #include <fenv.h>
  44 
  45 #include "fenv_inlines.h"
  46 #include "libm_inlines.h"
  47 
  48 #ifdef __sparcv9
  49 
  50 #define FPreg(X)        &uap->uc_mcontext.fpregs.fpu_fr.fpu_regs[X]
  51 
  52 #define FPREG(X)        &uap->uc_mcontext.fpregs.fpu_fr.fpu_dregs[(X>>1)| \
  53                                         ((X&1)<<4)]
  54 
  55 #else
  56 
  57 #include <sys/procfs.h>
  58 
  59 #define FPxreg(X)       &((prxregset_t*)uap->uc_mcontext.xrs.xrs_ptr)->pr_un.pr_v8p.pr_xfr.pr_regs[X]
  60 
  61 #define FPreg(X)        &uap->uc_mcontext.fpregs.fpu_fr.fpu_regs[X]
  62 
  63 #define FPREG(X)        ((X & 1)? FPxreg(X - 1) : FPreg(X))
  64 
  65 #endif  /* __sparcv9 */
  66 
  67 #include "fex_handler.h"
  68 
  69 /* avoid dependence on libsunmath */
  70 static enum fp_class_type
  71 my_fp_classl(long double *a)
  72 {
  73         int             msw = *(int*)a & ~0x80000000;
  74 
  75         if (msw >= 0x7fff0000) {
  76                 if (((msw & 0xffff) | *(1+(int*)a) | *(2+(int*)a) | *(3+(int*)a)) == 0)
  77                         return fp_infinity;
  78                 else if (msw & 0x8000)
  79                         return fp_quiet;
  80                 else
  81                         return fp_signaling;
  82         } else if (msw < 0x10000) {
  83                 if ((msw | *(1+(int*)a) | *(2+(int*)a) | *(3+(int*)a)) == 0)
  84                         return fp_zero;
  85                 else
  86                         return fp_subnormal;
  87         } else
  88                 return fp_normal;
  89 }
  90 
  91 /*
  92 *  Determine which type of invalid operation exception occurred
  93 */
  94 enum fex_exception
  95 __fex_get_invalid_type(siginfo_t *sip, ucontext_t *uap)
  96 {
  97         unsigned                        instr, opf, rs1, rs2;
  98         enum fp_class_type      t1, t2;
  99 
 100         /* parse the instruction which caused the exception */
 101         instr = uap->uc_mcontext.fpregs.fpu_q->FQu.fpq.fpq_instr;
 102         opf = (instr >> 5) & 0x1ff;
 103         rs1 = (instr >> 14) & 0x1f;
 104         rs2 = instr & 0x1f;
 105 
 106         /* determine the classes of the operands */
 107         switch (opf & 3) {
 108         case 1: /* single */
 109                 t1 = fp_classf(*(float*)FPreg(rs1));
 110                 t2 = fp_classf(*(float*)FPreg(rs2));
 111                 break;
 112 
 113         case 2: /* double */
 114                 t1 = fp_class(*(double*)FPREG(rs1));
 115                 t2 = fp_class(*(double*)FPREG(rs2));
 116                 break;
 117 
 118         case 3: /* quad */
 119                 t1 = my_fp_classl((long double*)FPREG(rs1));
 120                 t2 = my_fp_classl((long double*)FPREG(rs2));
 121                 break;
 122 
 123         default: /* integer operands never cause an invalid operation */
 124                 return (enum fex_exception) -1;
 125         }
 126 
 127         /* if rs2 is snan, return immediately */
 128         if (t2 == fp_signaling)
 129                 return fex_inv_snan;
 130 
 131         /* determine the type of operation */
 132         switch ((instr >> 19) & 0x183f) {
 133         case 0x1034: /* add, subtract, multiply, divide, square root, convert */
 134                 switch (opf & 0x1fc) {
 135                 case 0x40:
 136                 case 0x44: /* add or subtract */
 137                         if (t1 == fp_signaling)
 138                                 return fex_inv_snan;
 139                         else
 140                                 return fex_inv_isi;
 141 
 142                 case 0x48:
 143                 case 0x68:
 144                 case 0x6c: /* multiply */
 145                         if (t1 == fp_signaling)
 146                                 return fex_inv_snan;
 147                         else
 148                                 return fex_inv_zmi;
 149 
 150                 case 0x4c: /* divide */
 151                         if (t1 == fp_signaling)
 152                                 return fex_inv_snan;
 153                         else if (t1 == fp_zero)
 154                                 return fex_inv_zdz;
 155                         else
 156                                 return fex_inv_idi;
 157 
 158                 case 0x28: /* square root */
 159                         return fex_inv_sqrt;
 160 
 161                 case 0x80:
 162                 case 0xd0: /* convert to integer */
 163                         return fex_inv_int;
 164                 }
 165                 break;
 166 
 167         case 0x1035: /* compare */
 168                 if (t1 == fp_signaling)
 169                         return fex_inv_snan;
 170                 else
 171                         return fex_inv_cmp;
 172         }
 173 
 174         return (enum fex_exception) -1;
 175 }
 176 
 177 #ifdef __sparcv9
 178 extern void _Qp_sqrt(long double *, const long double *);
 179 #else
 180 extern long double _Q_sqrt(long double);
 181 #endif
 182 
 183 /*
 184 *  Get the operands, generate the default untrapped result with
 185 *  exceptions, and set a code indicating the type of operation
 186 */
 187 void
 188 __fex_get_op(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
 189 {
 190         unsigned long   fsr;
 191         unsigned                instr, opf, rs1, rs2;
 192         volatile int    c;
 193 
 194         /* parse the instruction which caused the exception */
 195         instr = uap->uc_mcontext.fpregs.fpu_q->FQu.fpq.fpq_instr;
 196         opf = (instr >> 5) & 0x1ff;
 197         rs1 = (instr >> 14) & 0x1f;
 198         rs2 = instr & 0x1f;
 199 
 200         /* get the operands */
 201         switch (opf & 3) {
 202         case 0: /* integer */
 203                 info->op1.type = fex_nodata;
 204                 if (opf & 0x40) {
 205                         info->op2.type = fex_int;
 206                         info->op2.val.i = *(int*)FPreg(rs2);
 207                 }
 208                 else {
 209                         info->op2.type = fex_llong;
 210                         info->op2.val.l = *(long long*)FPREG(rs2);
 211                 }
 212                 break;
 213 
 214         case 1: /* single */
 215                 info->op1.type = info->op2.type = fex_float;
 216                 info->op1.val.f = *(float*)FPreg(rs1);
 217                 info->op2.val.f = *(float*)FPreg(rs2);
 218                 break;
 219 
 220         case 2: /* double */
 221                 info->op1.type = info->op2.type = fex_double;
 222                 info->op1.val.d = *(double*)FPREG(rs1);
 223                 info->op2.val.d = *(double*)FPREG(rs2);
 224                 break;
 225 
 226         case 3: /* quad */
 227                 info->op1.type = info->op2.type = fex_ldouble;
 228                 info->op1.val.q = *(long double*)FPREG(rs1);
 229                 info->op2.val.q = *(long double*)FPREG(rs2);
 230                 break;
 231         }
 232 
 233         /* initialize res to the default untrapped result and ex to the
 234            corresponding flags (assume trapping is disabled and flags
 235            are clear) */
 236         info->op = fex_other;
 237         info->res.type = fex_nodata;
 238         switch ((instr >> 19) & 0x183f) {
 239         case 0x1035: /* compare */
 240                 info->op = fex_cmp;
 241                 switch (opf) {
 242                 case 0x51: /* compare single */
 243                         c = (info->op1.val.f == info->op2.val.f);
 244                         break;
 245 
 246                 case 0x52: /* compare double */
 247                         c = (info->op1.val.d == info->op2.val.d);
 248                         break;
 249 
 250                 case 0x53: /* compare quad */
 251                         c = (info->op1.val.q == info->op2.val.q);
 252                         break;
 253 
 254                 case 0x55: /* compare single with exception */
 255                         c = (info->op1.val.f < info->op2.val.f);
 256                         break;
 257 
 258                 case 0x56: /* compare double with exception */
 259                         c = (info->op1.val.d < info->op2.val.d);
 260                         break;
 261 
 262                 case 0x57: /* compare quad with exception */
 263                         c = (info->op1.val.q < info->op2.val.q);
 264                         break;
 265                 }
 266                 break;
 267 
 268         case 0x1034: /* add, subtract, multiply, divide, square root, convert */
 269                 switch (opf) {
 270                 case 0x41: /* add single */
 271                         info->op = fex_add;
 272                         info->res.type = fex_float;
 273                         info->res.val.f = info->op1.val.f + info->op2.val.f;
 274                         break;
 275 
 276                 case 0x42: /* add double */
 277                         info->op = fex_add;
 278                         info->res.type = fex_double;
 279                         info->res.val.d = info->op1.val.d + info->op2.val.d;
 280                         break;
 281 
 282                 case 0x43: /* add quad */
 283                         info->op = fex_add;
 284                         info->res.type = fex_ldouble;
 285                         info->res.val.q = info->op1.val.q + info->op2.val.q;
 286                         break;
 287 
 288                 case 0x45: /* subtract single */
 289                         info->op = fex_sub;
 290                         info->res.type = fex_float;
 291                         info->res.val.f = info->op1.val.f - info->op2.val.f;
 292                         break;
 293 
 294                 case 0x46: /* subtract double */
 295                         info->op = fex_sub;
 296                         info->res.type = fex_double;
 297                         info->res.val.d = info->op1.val.d - info->op2.val.d;
 298                         break;
 299 
 300                 case 0x47: /* subtract quad */
 301                         info->op = fex_sub;
 302                         info->res.type = fex_ldouble;
 303                         info->res.val.q = info->op1.val.q - info->op2.val.q;
 304                         break;
 305 
 306                 case 0x49: /* multiply single */
 307                         info->op = fex_mul;
 308                         info->res.type = fex_float;
 309                         info->res.val.f = info->op1.val.f * info->op2.val.f;
 310                         break;
 311 
 312                 case 0x4a: /* multiply double */
 313                         info->op = fex_mul;
 314                         info->res.type = fex_double;
 315                         info->res.val.d = info->op1.val.d * info->op2.val.d;
 316                         break;
 317 
 318                 case 0x4b: /* multiply quad */
 319                         info->op = fex_mul;
 320                         info->res.type = fex_ldouble;
 321                         info->res.val.q = info->op1.val.q * info->op2.val.q;
 322                         break;
 323 
 324                 case 0x69: /* fsmuld */
 325                         info->op = fex_mul;
 326                         info->res.type = fex_double;
 327                         info->res.val.d = (double)info->op1.val.f * (double)info->op2.val.f;
 328                         break;
 329 
 330                 case 0x6e: /* fdmulq */
 331                         info->op = fex_mul;
 332                         info->res.type = fex_ldouble;
 333                         info->res.val.q = (long double)info->op1.val.d *
 334                                 (long double)info->op2.val.d;
 335                         break;
 336 
 337                 case 0x4d: /* divide single */
 338                         info->op = fex_div;
 339                         info->res.type = fex_float;
 340                         info->res.val.f = info->op1.val.f / info->op2.val.f;
 341                         break;
 342 
 343                 case 0x4e: /* divide double */
 344                         info->op = fex_div;
 345                         info->res.type = fex_double;
 346                         info->res.val.d = info->op1.val.d / info->op2.val.d;
 347                         break;
 348 
 349                 case 0x4f: /* divide quad */
 350                         info->op = fex_div;
 351                         info->res.type = fex_ldouble;
 352                         info->res.val.q = info->op1.val.q / info->op2.val.q;
 353                         break;
 354 
 355                 case 0x29: /* square root single */
 356                         info->op = fex_sqrt;
 357                         info->op1 = info->op2;
 358                         info->op2.type = fex_nodata;
 359                         info->res.type = fex_float;
 360                         info->res.val.f = sqrtf(info->op1.val.f);
 361                         break;
 362 
 363                 case 0x2a: /* square root double */
 364                         info->op = fex_sqrt;
 365                         info->op1 = info->op2;
 366                         info->op2.type = fex_nodata;
 367                         info->res.type = fex_double;
 368                         info->res.val.d = sqrt(info->op1.val.d);
 369                         break;
 370 
 371                 case 0x2b: /* square root quad */
 372                         info->op = fex_sqrt;
 373                         info->op1 = info->op2;
 374                         info->op2.type = fex_nodata;
 375                         info->res.type = fex_ldouble;
 376 #ifdef __sparcv9
 377                         _Qp_sqrt(&info->res.val.q, &info->op1.val.q);
 378 #else
 379                         info->res.val.q = _Q_sqrt(info->op1.val.q);
 380 #endif
 381                         break;
 382 
 383                 default: /* conversions */
 384                         info->op = fex_cnvt;
 385                         info->op1 = info->op2;
 386                         info->op2.type = fex_nodata;
 387                         switch (opf) {
 388                         case 0xd1: /* convert single to int */
 389                                 info->res.type = fex_int;
 390                                 info->res.val.i = (int) info->op1.val.f;
 391                                 break;
 392 
 393                         case 0xd2: /* convert double to int */
 394                                 info->res.type = fex_int;
 395                                 info->res.val.i = (int) info->op1.val.d;
 396                                 break;
 397 
 398                         case 0xd3: /* convert quad to int */
 399                                 info->res.type = fex_int;
 400                                 info->res.val.i = (int) info->op1.val.q;
 401                                 break;
 402 
 403                         case 0x81: /* convert single to long long */
 404                                 info->res.type = fex_llong;
 405                                 info->res.val.l = (long long) info->op1.val.f;
 406                                 break;
 407 
 408                         case 0x82: /* convert double to long long */
 409                                 info->res.type = fex_llong;
 410                                 info->res.val.l = (long long) info->op1.val.d;
 411                                 break;
 412 
 413                         case 0x83: /* convert quad to long long */
 414                                 info->res.type = fex_llong;
 415                                 info->res.val.l = (long long) info->op1.val.q;
 416                                 break;
 417 
 418                         case 0xc4: /* convert int to single */
 419                                 info->res.type = fex_float;
 420                                 info->res.val.f = (float) info->op1.val.i;
 421                                 break;
 422 
 423                         case 0x84: /* convert long long to single */
 424                                 info->res.type = fex_float;
 425                                 info->res.val.f = (float) info->op1.val.l;
 426                                 break;
 427 
 428                         case 0x88: /* convert long long to double */
 429                                 info->res.type = fex_double;
 430                                 info->res.val.d = (double) info->op1.val.l;
 431                                 break;
 432 
 433                         case 0xc6: /* convert double to single */
 434                                 info->res.type = fex_float;
 435                                 info->res.val.f = (float) info->op1.val.d;
 436                                 break;
 437 
 438                         case 0xc7: /* convert quad to single */
 439                                 info->res.type = fex_float;
 440                                 info->res.val.f = (float) info->op1.val.q;
 441                                 break;
 442 
 443                         case 0xc9: /* convert single to double */
 444                                 info->res.type = fex_double;
 445                                 info->res.val.d = (double) info->op1.val.f;
 446                                 break;
 447 
 448                         case 0xcb: /* convert quad to double */
 449                                 info->res.type = fex_double;
 450                                 info->res.val.d = (double) info->op1.val.q;
 451                                 break;
 452 
 453                         case 0xcd: /* convert single to quad */
 454                                 info->res.type = fex_ldouble;
 455                                 info->res.val.q = (long double) info->op1.val.f;
 456                                 break;
 457 
 458                         case 0xce: /* convert double to quad */
 459                                 info->res.type = fex_ldouble;
 460                                 info->res.val.q = (long double) info->op1.val.d;
 461                                 break;
 462                         }
 463                 }
 464                 break;
 465         }
 466         __fenv_getfsr(&fsr);
 467         info->flags = (int)__fenv_get_ex(fsr);
 468         __fenv_set_ex(fsr, 0);
 469         __fenv_setfsr(&fsr);
 470 }
 471 
 472 /*
 473 *  Store the specified result; if no result is given but the exception
 474 *  is underflow or overflow, supply the default trapped result
 475 */
 476 void
 477 __fex_st_result(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
 478 {
 479         unsigned                instr, opf, rs1, rs2, rd;
 480         long double             qscl;
 481         double                  dscl;
 482         float                   fscl;
 483 
 484         /* parse the instruction which caused the exception */
 485         instr = uap->uc_mcontext.fpregs.fpu_q->FQu.fpq.fpq_instr;
 486         opf = (instr >> 5) & 0x1ff;
 487         rs1 = (instr >> 14) & 0x1f;
 488         rs2 = instr & 0x1f;
 489         rd = (instr >> 25) & 0x1f;
 490 
 491         /* if the instruction is a compare, just set fcc to unordered */
 492         if (((instr >> 19) & 0x183f) == 0x1035) {
 493                 if (rd == 0)
 494                         uap->uc_mcontext.fpregs.fpu_fsr |= 0xc00;
 495                 else {
 496 #ifdef __sparcv9
 497                         uap->uc_mcontext.fpregs.fpu_fsr |= (3l << ((rd << 1) + 30));
 498 #else
 499                         ((prxregset_t*)uap->uc_mcontext.xrs.xrs_ptr)->pr_un.pr_v8p.pr_xfsr |= (3 << ((rd - 1) << 1));
 500 #endif
 501                 }
 502                 return;
 503         }
 504 
 505         /* if there is no result available, try to generate the untrapped
 506            default */
 507         if (info->res.type == fex_nodata) {
 508                 /* set scale factors for exponent wrapping */
 509                 switch (sip->si_code) {
 510                 case FPE_FLTOVF:
 511                         fscl = 1.262177448e-29f;        /* 2^-96 */
 512                         dscl = 6.441148769597133308e-232;       /* 2^-768 */
 513                         qscl = 8.778357852076208839765066529179033145e-3700l;/* 2^-12288 */
 514                         break;
 515 
 516                 case FPE_FLTUND:
 517                         fscl = 7.922816251e+28f;        /* 2^96 */
 518                         dscl = 1.552518092300708935e+231;       /* 2^768 */
 519                         qscl = 1.139165225263043370845938579315932009e+3699l;/* 2^12288 */
 520                         break;
 521 
 522                 default:
 523                         /* user may have blown away the default result by mistake,
 524                            so try to regenerate it */
 525                         (void) __fex_get_op(sip, uap, info);
 526                         if (info->res.type != fex_nodata)
 527                                 goto stuff;
 528                         /* couldn't do it */
 529                         return;
 530                 }
 531 
 532                 /* get the operands */
 533                 switch (opf & 3) {
 534                 case 1: /* single */
 535                         info->op1.val.f = *(float*)FPreg(rs1);
 536                         info->op2.val.f = *(float*)FPreg(rs2);
 537                         break;
 538 
 539                 case 2: /* double */
 540                         info->op1.val.d = *(double*)FPREG(rs1);
 541                         info->op2.val.d = *(double*)FPREG(rs2);
 542                         break;
 543 
 544                 case 3: /* quad */
 545                         info->op1.val.q = *(long double*)FPREG(rs1);
 546                         info->op2.val.q = *(long double*)FPREG(rs2);
 547                         break;
 548                 }
 549 
 550                 /* generate the wrapped result */
 551                 switch (opf) {
 552                 case 0x41: /* add single */
 553                         info->res.type = fex_float;
 554                         info->res.val.f = fscl * ( fscl * info->op1.val.f +
 555                                 fscl * info->op2.val.f );
 556                         break;
 557 
 558                 case 0x42: /* add double */
 559                         info->res.type = fex_double;
 560                         info->res.val.d = dscl * ( dscl * info->op1.val.d +
 561                                 dscl * info->op2.val.d );
 562                         break;
 563 
 564                 case 0x43: /* add quad */
 565                         info->res.type = fex_ldouble;
 566                         info->res.val.q = qscl * ( qscl * info->op1.val.q +
 567                                 qscl * info->op2.val.q );
 568                         break;
 569 
 570                 case 0x45: /* subtract single */
 571                         info->res.type = fex_float;
 572                         info->res.val.f = fscl * ( fscl * info->op1.val.f -
 573                                 fscl * info->op2.val.f );
 574                         break;
 575 
 576                 case 0x46: /* subtract double */
 577                         info->res.type = fex_double;
 578                         info->res.val.d = dscl * ( dscl * info->op1.val.d -
 579                                 dscl * info->op2.val.d );
 580                         break;
 581 
 582                 case 0x47: /* subtract quad */
 583                         info->res.type = fex_ldouble;
 584                         info->res.val.q = qscl * ( qscl * info->op1.val.q -
 585                                 qscl * info->op2.val.q );
 586                         break;
 587 
 588                 case 0x49: /* multiply single */
 589                         info->res.type = fex_float;
 590                         info->res.val.f = ( fscl * info->op1.val.f ) *
 591                                 ( fscl * info->op2.val.f );
 592                         break;
 593 
 594                 case 0x4a: /* multiply double */
 595                         info->res.type = fex_double;
 596                         info->res.val.d = ( dscl * info->op1.val.d ) *
 597                                 ( dscl * info->op2.val.d );
 598                         break;
 599 
 600                 case 0x4b: /* multiply quad */
 601                         info->res.type = fex_ldouble;
 602                         info->res.val.q = ( qscl * info->op1.val.q ) *
 603                                 ( qscl * info->op2.val.q );
 604                         break;
 605 
 606                 case 0x4d: /* divide single */
 607                         info->res.type = fex_float;
 608                         info->res.val.f = ( fscl * info->op1.val.f ) /
 609                                 ( info->op2.val.f / fscl );
 610                         break;
 611 
 612                 case 0x4e: /* divide double */
 613                         info->res.type = fex_double;
 614                         info->res.val.d = ( dscl * info->op1.val.d ) /
 615                                 ( info->op2.val.d / dscl );
 616                         break;
 617 
 618                 case 0x4f: /* divide quad */
 619                         info->res.type = fex_ldouble;
 620                         info->res.val.q = ( qscl * info->op1.val.q ) /
 621                                 ( info->op2.val.q / qscl );
 622                         break;
 623 
 624                 case 0xc6: /* convert double to single */
 625                         info->res.type = fex_float;
 626                         info->res.val.f = (float) ( fscl * ( fscl * info->op1.val.d ) );
 627                         break;
 628 
 629                 case 0xc7: /* convert quad to single */
 630                         info->res.type = fex_float;
 631                         info->res.val.f = (float) ( fscl * ( fscl * info->op1.val.q ) );
 632                         break;
 633 
 634                 case 0xcb: /* convert quad to double */
 635                         info->res.type = fex_double;
 636                         info->res.val.d = (double) ( dscl * ( dscl * info->op1.val.q ) );
 637                         break;
 638                 }
 639 
 640                 if (info->res.type == fex_nodata)
 641                         /* couldn't do it */
 642                         return;
 643         }
 644 
 645 stuff:
 646         /* stick the result in the destination */
 647         if (opf & 0x80) { /* conversion */
 648                 if (opf & 0x10) { /* result is an int */
 649                         switch (info->res.type) {
 650                         case fex_llong:
 651                                 info->res.val.i = (int) info->res.val.l;
 652                                 break;
 653 
 654                         case fex_float:
 655                                 info->res.val.i = (int) info->res.val.f;
 656                                 break;
 657 
 658                         case fex_double:
 659                                 info->res.val.i = (int) info->res.val.d;
 660                                 break;
 661 
 662                         case fex_ldouble:
 663                                 info->res.val.i = (int) info->res.val.q;
 664                                 break;
 665                         }
 666                         *(int*)FPreg(rd) = info->res.val.i;
 667                         return;
 668                 }
 669 
 670                 switch (opf & 0xc) {
 671                 case 0: /* result is long long */
 672                         switch (info->res.type) {
 673                         case fex_int:
 674                                 info->res.val.l = (long long) info->res.val.i;
 675                                 break;
 676 
 677                         case fex_float:
 678                                 info->res.val.l = (long long) info->res.val.f;
 679                                 break;
 680 
 681                         case fex_double:
 682                                 info->res.val.l = (long long) info->res.val.d;
 683                                 break;
 684 
 685                         case fex_ldouble:
 686                                 info->res.val.l = (long long) info->res.val.q;
 687                                 break;
 688                         }
 689                         *(long long*)FPREG(rd) = info->res.val.l;
 690                         break;
 691 
 692                 case 0x4: /* result is float */
 693                         switch (info->res.type) {
 694                         case fex_int:
 695                                 info->res.val.f = (float) info->res.val.i;
 696                                 break;
 697 
 698                         case fex_llong:
 699                                 info->res.val.f = (float) info->res.val.l;
 700                                 break;
 701 
 702                         case fex_double:
 703                                 info->res.val.f = (float) info->res.val.d;
 704                                 break;
 705 
 706                         case fex_ldouble:
 707                                 info->res.val.f = (float) info->res.val.q;
 708                                 break;
 709                         }
 710                         *(float*)FPreg(rd) = info->res.val.f;
 711                         break;
 712 
 713                 case 0x8: /* result is double */
 714                         switch (info->res.type) {
 715                         case fex_int:
 716                                 info->res.val.d = (double) info->res.val.i;
 717                                 break;
 718 
 719                         case fex_llong:
 720                                 info->res.val.d = (double) info->res.val.l;
 721                                 break;
 722 
 723                         case fex_float:
 724                                 info->res.val.d = (double) info->res.val.f;
 725                                 break;
 726 
 727                         case fex_ldouble:
 728                                 info->res.val.d = (double) info->res.val.q;
 729                                 break;
 730                         }
 731                         *(double*)FPREG(rd) = info->res.val.d;
 732                         break;
 733 
 734                 case 0xc: /* result is long double */
 735                         switch (info->res.type) {
 736                         case fex_int:
 737                                 info->res.val.q = (long double) info->res.val.i;
 738                                 break;
 739 
 740                         case fex_llong:
 741                                 info->res.val.q = (long double) info->res.val.l;
 742                                 break;
 743 
 744                         case fex_float:
 745                                 info->res.val.q = (long double) info->res.val.f;
 746                                 break;
 747 
 748                         case fex_double:
 749                                 info->res.val.q = (long double) info->res.val.d;
 750                                 break;
 751                         }
 752                         *(long double*)FPREG(rd) = info->res.val.q;
 753                         break;
 754                 }
 755                 return;
 756         }
 757 
 758         if ((opf & 0xf0) == 0x60) { /* fsmuld, fdmulq */
 759                 switch (opf & 0xc0) {
 760                 case 0x8: /* result is double */
 761                         switch (info->res.type) {
 762                         case fex_int:
 763                                 info->res.val.d = (double) info->res.val.i;
 764                                 break;
 765 
 766                         case fex_llong:
 767                                 info->res.val.d = (double) info->res.val.l;
 768                                 break;
 769 
 770                         case fex_float:
 771                                 info->res.val.d = (double) info->res.val.f;
 772                                 break;
 773 
 774                         case fex_ldouble:
 775                                 info->res.val.d = (double) info->res.val.q;
 776                                 break;
 777                         }
 778                         *(double*)FPREG(rd) = info->res.val.d;
 779                         break;
 780 
 781                 case 0xc: /* result is long double */
 782                         switch (info->res.type) {
 783                         case fex_int:
 784                                 info->res.val.q = (long double) info->res.val.i;
 785                                 break;
 786 
 787                         case fex_llong:
 788                                 info->res.val.q = (long double) info->res.val.l;
 789                                 break;
 790 
 791                         case fex_float:
 792                                 info->res.val.q = (long double) info->res.val.f;
 793                                 break;
 794 
 795                         case fex_double:
 796                                 info->res.val.q = (long double) info->res.val.d;
 797                                 break;
 798                         }
 799                         *(long double*)FPREG(rd) = info->res.val.q;
 800                         break;
 801                 }
 802                 return;
 803         }
 804 
 805         switch (opf & 3) { /* other arithmetic op */
 806         case 1: /* result is float */
 807                 switch (info->res.type) {
 808                 case fex_int:
 809                         info->res.val.f = (float) info->res.val.i;
 810                         break;
 811 
 812                 case fex_llong:
 813                         info->res.val.f = (float) info->res.val.l;
 814                         break;
 815 
 816                 case fex_double:
 817                         info->res.val.f = (float) info->res.val.d;
 818                         break;
 819 
 820                 case fex_ldouble:
 821                         info->res.val.f = (float) info->res.val.q;
 822                         break;
 823                 }
 824                 *(float*)FPreg(rd) = info->res.val.f;
 825                 break;
 826 
 827         case 2: /* result is double */
 828                 switch (info->res.type) {
 829                 case fex_int:
 830                         info->res.val.d = (double) info->res.val.i;
 831                         break;
 832 
 833                 case fex_llong:
 834                         info->res.val.d = (double) info->res.val.l;
 835                         break;
 836 
 837                 case fex_float:
 838                         info->res.val.d = (double) info->res.val.f;
 839                         break;
 840 
 841                 case fex_ldouble:
 842                         info->res.val.d = (double) info->res.val.q;
 843                         break;
 844                 }
 845                 *(double*)FPREG(rd) = info->res.val.d;
 846                 break;
 847 
 848         case 3: /* result is long double */
 849                 switch (info->res.type) {
 850                 case fex_int:
 851                         info->res.val.q = (long double) info->res.val.i;
 852                         break;
 853 
 854                 case fex_llong:
 855                         info->res.val.q = (long double) info->res.val.l;
 856                         break;
 857 
 858                 case fex_float:
 859                         info->res.val.q = (long double) info->res.val.f;
 860                         break;
 861 
 862                 case fex_double:
 863                         info->res.val.q = (long double) info->res.val.d;
 864                         break;
 865                 }
 866                 *(long double*)FPREG(rd) = info->res.val.q;
 867                 break;
 868         }
 869 }
 870 #endif  /* defined(__sparc) */