2019-05-31 01:09:55 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2005-04-16 15:20:36 -07:00
/* IEEE754 floating point arithmetic
* double precision : common utilities
*/
/*
* MIPS floating point support
* Copyright ( C ) 1994 - 2000 Algorithmics Ltd .
*/
# include "ieee754dp.h"
2014-04-16 01:31:11 +02:00
union ieee754dp ieee754dp_sub ( union ieee754dp x , union ieee754dp y )
2005-04-16 15:20:36 -07:00
{
2014-04-26 01:49:14 +02:00
int s ;
2005-04-16 15:20:36 -07:00
COMPXDP ;
COMPYDP ;
EXPLODEXDP ;
EXPLODEYDP ;
2014-04-19 00:36:32 +02:00
ieee754_clearcx ( ) ;
2005-04-16 15:20:36 -07:00
FLUSHXDP ;
FLUSHYDP ;
switch ( CLPAIR ( xc , yc ) ) {
case CLPAIR ( IEEE754_CLASS_QNAN , IEEE754_CLASS_SNAN ) :
case CLPAIR ( IEEE754_CLASS_ZERO , IEEE754_CLASS_SNAN ) :
case CLPAIR ( IEEE754_CLASS_NORM , IEEE754_CLASS_SNAN ) :
case CLPAIR ( IEEE754_CLASS_DNORM , IEEE754_CLASS_SNAN ) :
case CLPAIR ( IEEE754_CLASS_INF , IEEE754_CLASS_SNAN ) :
2015-04-03 23:25:34 +01:00
return ieee754dp_nanxcpt ( y ) ;
case CLPAIR ( IEEE754_CLASS_SNAN , IEEE754_CLASS_SNAN ) :
case CLPAIR ( IEEE754_CLASS_SNAN , IEEE754_CLASS_QNAN ) :
2005-04-16 15:20:36 -07:00
case CLPAIR ( IEEE754_CLASS_SNAN , IEEE754_CLASS_ZERO ) :
case CLPAIR ( IEEE754_CLASS_SNAN , IEEE754_CLASS_NORM ) :
case CLPAIR ( IEEE754_CLASS_SNAN , IEEE754_CLASS_DNORM ) :
case CLPAIR ( IEEE754_CLASS_SNAN , IEEE754_CLASS_INF ) :
2015-04-03 23:25:34 +01:00
return ieee754dp_nanxcpt ( x ) ;
2005-04-16 15:20:36 -07:00
case CLPAIR ( IEEE754_CLASS_ZERO , IEEE754_CLASS_QNAN ) :
case CLPAIR ( IEEE754_CLASS_NORM , IEEE754_CLASS_QNAN ) :
case CLPAIR ( IEEE754_CLASS_DNORM , IEEE754_CLASS_QNAN ) :
case CLPAIR ( IEEE754_CLASS_INF , IEEE754_CLASS_QNAN ) :
return y ;
case CLPAIR ( IEEE754_CLASS_QNAN , IEEE754_CLASS_QNAN ) :
case CLPAIR ( IEEE754_CLASS_QNAN , IEEE754_CLASS_ZERO ) :
case CLPAIR ( IEEE754_CLASS_QNAN , IEEE754_CLASS_NORM ) :
case CLPAIR ( IEEE754_CLASS_QNAN , IEEE754_CLASS_DNORM ) :
case CLPAIR ( IEEE754_CLASS_QNAN , IEEE754_CLASS_INF ) :
return x ;
2014-04-26 01:49:14 +02:00
/*
* Infinity handling
*/
2005-04-16 15:20:36 -07:00
case CLPAIR ( IEEE754_CLASS_INF , IEEE754_CLASS_INF ) :
if ( xs ! = ys )
return x ;
2014-04-19 00:36:32 +02:00
ieee754_setcx ( IEEE754_INVALID_OPERATION ) ;
2014-04-25 03:19:57 +02:00
return ieee754dp_indef ( ) ;
2005-04-16 15:20:36 -07:00
case CLPAIR ( IEEE754_CLASS_ZERO , IEEE754_CLASS_INF ) :
case CLPAIR ( IEEE754_CLASS_DNORM , IEEE754_CLASS_INF ) :
case CLPAIR ( IEEE754_CLASS_NORM , IEEE754_CLASS_INF ) :
return ieee754dp_inf ( ys ^ 1 ) ;
case CLPAIR ( IEEE754_CLASS_INF , IEEE754_CLASS_ZERO ) :
case CLPAIR ( IEEE754_CLASS_INF , IEEE754_CLASS_NORM ) :
case CLPAIR ( IEEE754_CLASS_INF , IEEE754_CLASS_DNORM ) :
return x ;
2014-04-26 01:49:14 +02:00
/*
* Zero handling
*/
2005-04-16 15:20:36 -07:00
case CLPAIR ( IEEE754_CLASS_ZERO , IEEE754_CLASS_ZERO ) :
if ( xs ! = ys )
return x ;
else
2014-04-30 11:21:55 +02:00
return ieee754dp_zero ( ieee754_csr . rm = = FPU_CSR_RD ) ;
2005-04-16 15:20:36 -07:00
case CLPAIR ( IEEE754_CLASS_NORM , IEEE754_CLASS_ZERO ) :
case CLPAIR ( IEEE754_CLASS_DNORM , IEEE754_CLASS_ZERO ) :
return x ;
case CLPAIR ( IEEE754_CLASS_ZERO , IEEE754_CLASS_NORM ) :
case CLPAIR ( IEEE754_CLASS_ZERO , IEEE754_CLASS_DNORM ) :
/* quick fix up */
DPSIGN ( y ) ^ = 1 ;
return y ;
case CLPAIR ( IEEE754_CLASS_DNORM , IEEE754_CLASS_DNORM ) :
DPDNORMX ;
2020-05-04 16:51:29 +08:00
fallthrough ;
2005-04-16 15:20:36 -07:00
case CLPAIR ( IEEE754_CLASS_NORM , IEEE754_CLASS_DNORM ) :
/* normalize ym,ye */
DPDNORMY ;
break ;
case CLPAIR ( IEEE754_CLASS_DNORM , IEEE754_CLASS_NORM ) :
/* normalize xm,xe */
DPDNORMX ;
break ;
case CLPAIR ( IEEE754_CLASS_NORM , IEEE754_CLASS_NORM ) :
break ;
}
/* flip sign of y and handle as add */
ys ^ = 1 ;
assert ( xm & DP_HIDDEN_BIT ) ;
assert ( ym & DP_HIDDEN_BIT ) ;
/* provide guard,round and stick bit dpace */
xm < < = 3 ;
ym < < = 3 ;
if ( xe > ye ) {
2014-04-26 01:49:14 +02:00
/*
* Have to shift y fraction right to align
2005-04-16 15:20:36 -07:00
*/
2014-04-26 01:49:14 +02:00
s = xe - ye ;
2005-04-16 15:20:36 -07:00
ym = XDPSRS ( ym , s ) ;
ye + = s ;
} else if ( ye > xe ) {
2014-04-26 01:49:14 +02:00
/*
* Have to shift x fraction right to align
2005-04-16 15:20:36 -07:00
*/
2014-04-26 01:49:14 +02:00
s = ye - xe ;
2005-04-16 15:20:36 -07:00
xm = XDPSRS ( xm , s ) ;
xe + = s ;
}
assert ( xe = = ye ) ;
assert ( xe < = DP_EMAX ) ;
if ( xs = = ys ) {
/* generate 28 bit result of adding two 27 bit numbers
*/
xm = xm + ym ;
2014-04-22 15:51:55 +02:00
if ( xm > > ( DP_FBITS + 1 + 3 ) ) { /* carry out */
2005-04-16 15:20:36 -07:00
xm = XDPSRS1 ( xm ) ; /* shift preserving sticky */
xe + + ;
}
} else {
if ( xm > = ym ) {
xm = xm - ym ;
} else {
xm = ym - xm ;
xs = ys ;
}
if ( xm = = 0 ) {
2014-04-30 11:21:55 +02:00
if ( ieee754_csr . rm = = FPU_CSR_RD )
2005-04-16 15:20:36 -07:00
return ieee754dp_zero ( 1 ) ; /* round negative inf. => sign = -1 */
else
return ieee754dp_zero ( 0 ) ; /* other round modes => sign = 1 */
}
/* normalize to rounding precision
*/
2014-04-22 15:51:55 +02:00
while ( ( xm > > ( DP_FBITS + 3 ) ) = = 0 ) {
2005-04-16 15:20:36 -07:00
xm < < = 1 ;
xe - - ;
}
}
2014-04-25 03:19:57 +02:00
return ieee754dp_format ( xs , xe , xm ) ;
2005-04-16 15:20:36 -07:00
}