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