__fex_sparc.c revision 25c28e83beb90e7c80452a7c818c5e6f73a07dc8
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#if defined(__sparc)
#include "fenv_synonyms.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <siginfo.h>
#include <thread.h>
#include <ucontext.h>
#include <math.h>
#if defined(__SUNPRO_C)
#include <sunmath.h>
#endif
#include <fenv.h>
#include "fenv_inlines.h"
#include "libm_inlines.h"
#ifdef __sparcv9
((X&1)<<4)]
#else
#endif /* __sparcv9 */
#include "fex_handler.h"
/* avoid dependence on libsunmath */
static enum fp_class_type
my_fp_classl(long double *a)
{
int msw = *(int*)a & ~0x80000000;
if (msw >= 0x7fff0000) {
return fp_infinity;
else if (msw & 0x8000)
return fp_quiet;
else
return fp_signaling;
} else if (msw < 0x10000) {
return fp_zero;
else
return fp_subnormal;
} else
return fp_normal;
}
/*
* Determine which type of invalid operation exception occurred
*/
enum fex_exception
{
/* parse the instruction which caused the exception */
/* determine the classes of the operands */
switch (opf & 3) {
case 1: /* single */
break;
case 2: /* double */
break;
case 3: /* quad */
break;
default: /* integer operands never cause an invalid operation */
return (enum fex_exception) -1;
}
/* if rs2 is snan, return immediately */
if (t2 == fp_signaling)
return fex_inv_snan;
/* determine the type of operation */
case 0x1034: /* add, subtract, multiply, divide, square root, convert */
switch (opf & 0x1fc) {
case 0x40:
case 0x44: /* add or subtract */
if (t1 == fp_signaling)
return fex_inv_snan;
else
return fex_inv_isi;
case 0x48:
case 0x68:
case 0x6c: /* multiply */
if (t1 == fp_signaling)
return fex_inv_snan;
else
return fex_inv_zmi;
case 0x4c: /* divide */
if (t1 == fp_signaling)
return fex_inv_snan;
return fex_inv_zdz;
else
return fex_inv_idi;
case 0x28: /* square root */
return fex_inv_sqrt;
case 0x80:
case 0xd0: /* convert to integer */
return fex_inv_int;
}
break;
case 0x1035: /* compare */
if (t1 == fp_signaling)
return fex_inv_snan;
else
return fex_inv_cmp;
}
return (enum fex_exception) -1;
}
#ifdef __sparcv9
extern void _Qp_sqrt(long double *, const long double *);
#else
extern long double _Q_sqrt(long double);
#endif
/*
* Get the operands, generate the default untrapped result with
* exceptions, and set a code indicating the type of operation
*/
void
{
unsigned long fsr;
volatile int c;
/* parse the instruction which caused the exception */
/* get the operands */
switch (opf & 3) {
case 0: /* integer */
if (opf & 0x40) {
}
else {
}
break;
case 1: /* single */
break;
case 2: /* double */
break;
case 3: /* quad */
break;
}
/* initialize res to the default untrapped result and ex to the
corresponding flags (assume trapping is disabled and flags
are clear) */
case 0x1035: /* compare */
switch (opf) {
case 0x51: /* compare single */
break;
case 0x52: /* compare double */
break;
case 0x53: /* compare quad */
break;
case 0x55: /* compare single with exception */
break;
case 0x56: /* compare double with exception */
break;
case 0x57: /* compare quad with exception */
break;
}
break;
case 0x1034: /* add, subtract, multiply, divide, square root, convert */
switch (opf) {
case 0x41: /* add single */
break;
case 0x42: /* add double */
break;
case 0x43: /* add quad */
break;
case 0x45: /* subtract single */
break;
case 0x46: /* subtract double */
break;
case 0x47: /* subtract quad */
break;
case 0x49: /* multiply single */
break;
case 0x4a: /* multiply double */
break;
case 0x4b: /* multiply quad */
break;
case 0x69: /* fsmuld */
break;
case 0x6e: /* fdmulq */
break;
case 0x4d: /* divide single */
break;
case 0x4e: /* divide double */
break;
case 0x4f: /* divide quad */
break;
case 0x29: /* square root single */
break;
case 0x2a: /* square root double */
break;
case 0x2b: /* square root quad */
#ifdef __sparcv9
#else
#endif
break;
default: /* conversions */
switch (opf) {
case 0xd1: /* convert single to int */
break;
case 0xd2: /* convert double to int */
break;
case 0xd3: /* convert quad to int */
break;
case 0x81: /* convert single to long long */
break;
case 0x82: /* convert double to long long */
break;
case 0x83: /* convert quad to long long */
break;
case 0xc4: /* convert int to single */
break;
case 0x84: /* convert long long to single */
break;
case 0x88: /* convert long long to double */
break;
case 0xc6: /* convert double to single */
break;
case 0xc7: /* convert quad to single */
break;
case 0xc9: /* convert single to double */
break;
case 0xcb: /* convert quad to double */
break;
case 0xcd: /* convert single to quad */
break;
case 0xce: /* convert double to quad */
break;
}
}
break;
}
__fenv_getfsr(&fsr);
__fenv_set_ex(fsr, 0);
__fenv_setfsr(&fsr);
}
/*
* Store the specified result; if no result is given but the exception
* is underflow or overflow, supply the default trapped result
*/
void
{
long double qscl;
double dscl;
float fscl;
/* parse the instruction which caused the exception */
/* if the instruction is a compare, just set fcc to unordered */
if (rd == 0)
else {
#ifdef __sparcv9
#else
#endif
}
return;
}
/* if there is no result available, try to generate the untrapped
default */
/* set scale factors for exponent wrapping */
case FPE_FLTOVF:
break;
case FPE_FLTUND:
break;
default:
/* user may have blown away the default result by mistake,
so try to regenerate it */
goto stuff;
/* couldn't do it */
return;
}
/* get the operands */
switch (opf & 3) {
case 1: /* single */
break;
case 2: /* double */
break;
case 3: /* quad */
break;
}
/* generate the wrapped result */
switch (opf) {
case 0x41: /* add single */
break;
case 0x42: /* add double */
break;
case 0x43: /* add quad */
break;
case 0x45: /* subtract single */
break;
case 0x46: /* subtract double */
break;
case 0x47: /* subtract quad */
break;
case 0x49: /* multiply single */
break;
case 0x4a: /* multiply double */
break;
case 0x4b: /* multiply quad */
break;
case 0x4d: /* divide single */
break;
case 0x4e: /* divide double */
break;
case 0x4f: /* divide quad */
break;
case 0xc6: /* convert double to single */
break;
case 0xc7: /* convert quad to single */
break;
case 0xcb: /* convert quad to double */
break;
}
/* couldn't do it */
return;
}
/* stick the result in the destination */
case fex_llong:
break;
case fex_float:
break;
case fex_double:
break;
case fex_ldouble:
break;
default:
break;
}
return;
}
switch (opf & 0xc) {
case 0: /* result is long long */
case fex_int:
break;
case fex_float:
break;
case fex_double:
break;
case fex_ldouble:
break;
default:
break;
}
break;
case 0x4: /* result is float */
case fex_int:
break;
case fex_llong:
break;
case fex_double:
break;
case fex_ldouble:
break;
default:
break;
}
break;
case 0x8: /* result is double */
case fex_int:
break;
case fex_llong:
break;
case fex_float:
break;
case fex_ldouble:
break;
default:
break;
}
break;
case 0xc: /* result is long double */
case fex_int:
break;
case fex_llong:
break;
case fex_float:
break;
case fex_double:
break;
default:
break;
}
break;
}
return;
}
switch (opf & 0xc0) {
case 0x8: /* result is double */
case fex_int:
break;
case fex_llong:
break;
case fex_float:
break;
case fex_ldouble:
break;
default:
break;
}
break;
case 0xc: /* result is long double */
case fex_int:
break;
case fex_llong:
break;
case fex_float:
break;
case fex_double:
break;
default:
break;
}
break;
}
return;
}
case 1: /* result is float */
case fex_int:
break;
case fex_llong:
break;
case fex_double:
break;
case fex_ldouble:
break;
default:
break;
}
break;
case 2: /* result is double */
case fex_int:
break;
case fex_llong:
break;
case fex_float:
break;
case fex_ldouble:
break;
default:
break;
}
break;
case 3: /* result is long double */
case fex_int:
break;
case fex_llong:
break;
case fex_float:
break;
case fex_double:
break;
default:
break;
}
break;
}
}
#endif /* defined(__sparc) */