2005-04-17 02:20:36 +04:00
/* IEEE754 floating point arithmetic
* double precision : common utilities
*/
/*
* MIPS floating point support
* Copyright ( C ) 1994 - 2000 Algorithmics Ltd .
*
* This program is free software ; you can distribute it and / or modify it
* under the terms of the GNU General Public License ( Version 2 ) as
* published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
2014-04-26 03:49:14 +04:00
* 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA .
2005-04-17 02:20:36 +04:00
*/
2014-04-16 02:47:59 +04:00
# include <linux/compiler.h>
2005-04-17 02:20:36 +04:00
# include "ieee754dp.h"
2014-04-16 03:31:11 +04:00
int ieee754dp_class ( union ieee754dp x )
2005-04-17 02:20:36 +04:00
{
COMPXDP ;
EXPLODEXDP ;
return xc ;
}
2015-04-04 01:25:57 +03:00
static inline int ieee754dp_isnan ( union ieee754dp x )
2005-04-17 02:20:36 +04:00
{
2015-04-04 01:25:38 +03:00
return ieee754_class_nan ( ieee754dp_class ( x ) ) ;
2005-04-17 02:20:36 +04:00
}
2014-04-25 02:40:42 +04:00
static inline int ieee754dp_issnan ( union ieee754dp x )
2005-04-17 02:20:36 +04:00
{
2015-11-13 03:47:28 +03:00
int qbit ;
2005-04-17 02:20:36 +04:00
assert ( ieee754dp_isnan ( x ) ) ;
2015-11-13 03:47:28 +03:00
qbit = ( DPMANT ( x ) & DP_MBIT ( DP_FBITS - 1 ) ) = = DP_MBIT ( DP_FBITS - 1 ) ;
return ieee754_csr . nan2008 ^ qbit ;
2005-04-17 02:20:36 +04:00
}
2015-04-04 01:25:34 +03:00
/*
* Raise the Invalid Operation IEEE 754 exception
* and convert the signaling NaN supplied to a quiet NaN .
*/
2014-04-25 05:19:57 +04:00
union ieee754dp __cold ieee754dp_nanxcpt ( union ieee754dp r )
2005-04-17 02:20:36 +04:00
{
2015-04-04 01:25:34 +03:00
assert ( ieee754dp_issnan ( r ) ) ;
2005-04-17 02:20:36 +04:00
2015-04-04 01:25:34 +03:00
ieee754_setcx ( IEEE754_INVALID_OPERATION ) ;
2015-11-13 03:48:48 +03:00
if ( ieee754_csr . nan2008 ) {
2015-11-13 03:47:28 +03:00
DPMANT ( r ) | = DP_MBIT ( DP_FBITS - 1 ) ;
2015-11-13 03:48:48 +03:00
} else {
DPMANT ( r ) & = ~ DP_MBIT ( DP_FBITS - 1 ) ;
if ( ! ieee754dp_isnan ( r ) )
DPMANT ( r ) | = DP_MBIT ( DP_FBITS - 2 ) ;
}
2015-11-13 03:47:28 +03:00
return r ;
2005-04-17 02:20:36 +04:00
}
2014-04-25 12:54:06 +04:00
static u64 ieee754dp_get_rounding ( int sn , u64 xm )
2005-04-17 02:20:36 +04:00
{
/* inexact must round of 3 bits
*/
if ( xm & ( DP_MBIT ( 3 ) - 1 ) ) {
switch ( ieee754_csr . rm ) {
2014-04-30 13:21:55 +04:00
case FPU_CSR_RZ :
2005-04-17 02:20:36 +04:00
break ;
2014-04-30 13:21:55 +04:00
case FPU_CSR_RN :
2005-04-17 02:20:36 +04:00
xm + = 0x3 + ( ( xm > > 3 ) & 1 ) ;
/* xm += (xm&0x8)?0x4:0x3 */
break ;
2014-04-30 13:21:55 +04:00
case FPU_CSR_RU : /* toward +Infinity */
2005-04-17 02:20:36 +04:00
if ( ! sn ) /* ?? */
xm + = 0x8 ;
break ;
2014-04-30 13:21:55 +04:00
case FPU_CSR_RD : /* toward -Infinity */
2013-01-22 15:59:30 +04:00
if ( sn ) /* ?? */
2005-04-17 02:20:36 +04:00
xm + = 0x8 ;
break ;
}
}
return xm ;
}
/* generate a normal/denormal number with over,under handling
* sn is sign
* xe is an unbiased exponent
* xm is 3 bit extended precision value .
*/
2014-04-16 03:31:11 +04:00
union ieee754dp ieee754dp_format ( int sn , int xe , u64 xm )
2005-04-17 02:20:36 +04:00
{
assert ( xm ) ; /* we don't gen exact zeros (probably should) */
2016-02-25 11:44:58 +03:00
assert ( ( xm > > ( DP_FBITS + 1 + 3 ) ) = = 0 ) ; /* no excess */
2005-04-17 02:20:36 +04:00
assert ( xm & ( DP_HIDDEN_BIT < < 3 ) ) ;
if ( xe < DP_EMIN ) {
/* strip lower bits */
int es = DP_EMIN - xe ;
if ( ieee754_csr . nod ) {
2014-04-19 02:36:32 +04:00
ieee754_setcx ( IEEE754_UNDERFLOW ) ;
ieee754_setcx ( IEEE754_INEXACT ) ;
2005-04-17 02:20:36 +04:00
switch ( ieee754_csr . rm ) {
2014-04-30 13:21:55 +04:00
case FPU_CSR_RN :
case FPU_CSR_RZ :
2005-04-17 02:20:36 +04:00
return ieee754dp_zero ( sn ) ;
2014-04-30 13:21:55 +04:00
case FPU_CSR_RU : /* toward +Infinity */
2014-04-16 13:00:12 +04:00
if ( sn = = 0 )
2005-04-17 02:20:36 +04:00
return ieee754dp_min ( 0 ) ;
else
return ieee754dp_zero ( 1 ) ;
2014-04-30 13:21:55 +04:00
case FPU_CSR_RD : /* toward -Infinity */
2014-04-16 13:00:12 +04:00
if ( sn = = 0 )
2005-04-17 02:20:36 +04:00
return ieee754dp_zero ( 0 ) ;
else
return ieee754dp_min ( 1 ) ;
}
}
2014-04-25 12:54:06 +04:00
if ( xe = = DP_EMIN - 1 & &
ieee754dp_get_rounding ( sn , xm ) > > ( DP_FBITS + 1 + 3 ) )
2005-04-17 02:20:36 +04:00
{
/* Not tiny after rounding */
2014-04-19 02:36:32 +04:00
ieee754_setcx ( IEEE754_INEXACT ) ;
2014-04-25 12:54:06 +04:00
xm = ieee754dp_get_rounding ( sn , xm ) ;
2005-04-17 02:20:36 +04:00
xm > > = 1 ;
/* Clear grs bits */
xm & = ~ ( DP_MBIT ( 3 ) - 1 ) ;
xe + + ;
}
else {
/* sticky right shift es bits
*/
xm = XDPSRS ( xm , es ) ;
xe + = es ;
assert ( ( xm & ( DP_HIDDEN_BIT < < 3 ) ) = = 0 ) ;
assert ( xe = = DP_EMIN ) ;
}
}
if ( xm & ( DP_MBIT ( 3 ) - 1 ) ) {
2014-04-19 02:36:32 +04:00
ieee754_setcx ( IEEE754_INEXACT ) ;
2005-04-17 02:20:36 +04:00
if ( ( xm & ( DP_HIDDEN_BIT < < 3 ) ) = = 0 ) {
2014-04-19 02:36:32 +04:00
ieee754_setcx ( IEEE754_UNDERFLOW ) ;
2005-04-17 02:20:36 +04:00
}
/* inexact must round of 3 bits
*/
2014-04-25 12:54:06 +04:00
xm = ieee754dp_get_rounding ( sn , xm ) ;
2005-04-17 02:20:36 +04:00
/* adjust exponent for rounding add overflowing
*/
2014-04-22 17:51:55 +04:00
if ( xm > > ( DP_FBITS + 3 + 1 ) ) {
2005-04-17 02:20:36 +04:00
/* add causes mantissa overflow */
xm > > = 1 ;
xe + + ;
}
}
/* strip grs bits */
xm > > = 3 ;
2016-02-25 11:44:58 +03:00
assert ( ( xm > > ( DP_FBITS + 1 ) ) = = 0 ) ; /* no excess */
2005-04-17 02:20:36 +04:00
assert ( xe > = DP_EMIN ) ;
if ( xe > DP_EMAX ) {
2014-04-19 02:36:32 +04:00
ieee754_setcx ( IEEE754_OVERFLOW ) ;
ieee754_setcx ( IEEE754_INEXACT ) ;
2005-04-17 02:20:36 +04:00
/* -O can be table indexed by (rm,sn) */
switch ( ieee754_csr . rm ) {
2014-04-30 13:21:55 +04:00
case FPU_CSR_RN :
2005-04-17 02:20:36 +04:00
return ieee754dp_inf ( sn ) ;
2014-04-30 13:21:55 +04:00
case FPU_CSR_RZ :
2005-04-17 02:20:36 +04:00
return ieee754dp_max ( sn ) ;
2014-04-30 13:21:55 +04:00
case FPU_CSR_RU : /* toward +Infinity */
2005-04-17 02:20:36 +04:00
if ( sn = = 0 )
return ieee754dp_inf ( 0 ) ;
else
return ieee754dp_max ( 1 ) ;
2014-04-30 13:21:55 +04:00
case FPU_CSR_RD : /* toward -Infinity */
2005-04-17 02:20:36 +04:00
if ( sn = = 0 )
return ieee754dp_max ( 0 ) ;
else
return ieee754dp_inf ( 1 ) ;
}
}
/* gen norm/denorm/zero */
if ( ( xm & DP_HIDDEN_BIT ) = = 0 ) {
/* we underflow (tiny/zero) */
assert ( xe = = DP_EMIN ) ;
if ( ieee754_csr . mx & IEEE754_UNDERFLOW )
2014-04-19 02:36:32 +04:00
ieee754_setcx ( IEEE754_UNDERFLOW ) ;
2005-04-17 02:20:36 +04:00
return builddp ( sn , DP_EMIN - 1 + DP_EBIAS , xm ) ;
} else {
2016-02-25 11:44:58 +03:00
assert ( ( xm > > ( DP_FBITS + 1 ) ) = = 0 ) ; /* no excess */
2005-04-17 02:20:36 +04:00
assert ( xm & DP_HIDDEN_BIT ) ;
return builddp ( sn , xe + DP_EBIAS , xm & ~ DP_HIDDEN_BIT ) ;
}
}