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