Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* IEEE754 floating point arithmetic
0003  * single precision
0004  */
0005 /*
0006  * MIPS floating point support
0007  * Copyright (C) 1994-2000 Algorithmics Ltd.
0008  */
0009 
0010 #include <linux/compiler.h>
0011 
0012 #include "ieee754sp.h"
0013 
0014 int ieee754sp_class(union ieee754sp x)
0015 {
0016     COMPXSP;
0017     EXPLODEXSP;
0018     return xc;
0019 }
0020 
0021 static inline int ieee754sp_isnan(union ieee754sp x)
0022 {
0023     return ieee754_class_nan(ieee754sp_class(x));
0024 }
0025 
0026 static inline int ieee754sp_issnan(union ieee754sp x)
0027 {
0028     int qbit;
0029 
0030     assert(ieee754sp_isnan(x));
0031     qbit = (SPMANT(x) & SP_MBIT(SP_FBITS - 1)) == SP_MBIT(SP_FBITS - 1);
0032     return ieee754_csr.nan2008 ^ qbit;
0033 }
0034 
0035 
0036 /*
0037  * Raise the Invalid Operation IEEE 754 exception
0038  * and convert the signaling NaN supplied to a quiet NaN.
0039  */
0040 union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r)
0041 {
0042     assert(ieee754sp_issnan(r));
0043 
0044     ieee754_setcx(IEEE754_INVALID_OPERATION);
0045     if (ieee754_csr.nan2008) {
0046         SPMANT(r) |= SP_MBIT(SP_FBITS - 1);
0047     } else {
0048         SPMANT(r) &= ~SP_MBIT(SP_FBITS - 1);
0049         if (!ieee754sp_isnan(r))
0050             SPMANT(r) |= SP_MBIT(SP_FBITS - 2);
0051     }
0052 
0053     return r;
0054 }
0055 
0056 static unsigned int ieee754sp_get_rounding(int sn, unsigned int xm)
0057 {
0058     /* inexact must round of 3 bits
0059      */
0060     if (xm & (SP_MBIT(3) - 1)) {
0061         switch (ieee754_csr.rm) {
0062         case FPU_CSR_RZ:
0063             break;
0064         case FPU_CSR_RN:
0065             xm += 0x3 + ((xm >> 3) & 1);
0066             /* xm += (xm&0x8)?0x4:0x3 */
0067             break;
0068         case FPU_CSR_RU:    /* toward +Infinity */
0069             if (!sn)    /* ?? */
0070                 xm += 0x8;
0071             break;
0072         case FPU_CSR_RD:    /* toward -Infinity */
0073             if (sn) /* ?? */
0074                 xm += 0x8;
0075             break;
0076         }
0077     }
0078     return xm;
0079 }
0080 
0081 
0082 /* generate a normal/denormal number with over,under handling
0083  * sn is sign
0084  * xe is an unbiased exponent
0085  * xm is 3bit extended precision value.
0086  */
0087 union ieee754sp ieee754sp_format(int sn, int xe, unsigned int xm)
0088 {
0089     assert(xm);     /* we don't gen exact zeros (probably should) */
0090 
0091     assert((xm >> (SP_FBITS + 1 + 3)) == 0);    /* no excess */
0092     assert(xm & (SP_HIDDEN_BIT << 3));
0093 
0094     if (xe < SP_EMIN) {
0095         /* strip lower bits */
0096         int es = SP_EMIN - xe;
0097 
0098         if (ieee754_csr.nod) {
0099             ieee754_setcx(IEEE754_UNDERFLOW);
0100             ieee754_setcx(IEEE754_INEXACT);
0101 
0102             switch(ieee754_csr.rm) {
0103             case FPU_CSR_RN:
0104             case FPU_CSR_RZ:
0105                 return ieee754sp_zero(sn);
0106             case FPU_CSR_RU:      /* toward +Infinity */
0107                 if (sn == 0)
0108                     return ieee754sp_min(0);
0109                 else
0110                     return ieee754sp_zero(1);
0111             case FPU_CSR_RD:      /* toward -Infinity */
0112                 if (sn == 0)
0113                     return ieee754sp_zero(0);
0114                 else
0115                     return ieee754sp_min(1);
0116             }
0117         }
0118 
0119         if (xe == SP_EMIN - 1 &&
0120             ieee754sp_get_rounding(sn, xm) >> (SP_FBITS + 1 + 3))
0121         {
0122             /* Not tiny after rounding */
0123             ieee754_setcx(IEEE754_INEXACT);
0124             xm = ieee754sp_get_rounding(sn, xm);
0125             xm >>= 1;
0126             /* Clear grs bits */
0127             xm &= ~(SP_MBIT(3) - 1);
0128             xe++;
0129         } else {
0130             /* sticky right shift es bits
0131              */
0132             xm = XSPSRS(xm, es);
0133             xe += es;
0134             assert((xm & (SP_HIDDEN_BIT << 3)) == 0);
0135             assert(xe == SP_EMIN);
0136         }
0137     }
0138     if (xm & (SP_MBIT(3) - 1)) {
0139         ieee754_setcx(IEEE754_INEXACT);
0140         if ((xm & (SP_HIDDEN_BIT << 3)) == 0) {
0141             ieee754_setcx(IEEE754_UNDERFLOW);
0142         }
0143 
0144         /* inexact must round of 3 bits
0145          */
0146         xm = ieee754sp_get_rounding(sn, xm);
0147         /* adjust exponent for rounding add overflowing
0148          */
0149         if (xm >> (SP_FBITS + 1 + 3)) {
0150             /* add causes mantissa overflow */
0151             xm >>= 1;
0152             xe++;
0153         }
0154     }
0155     /* strip grs bits */
0156     xm >>= 3;
0157 
0158     assert((xm >> (SP_FBITS + 1)) == 0);    /* no excess */
0159     assert(xe >= SP_EMIN);
0160 
0161     if (xe > SP_EMAX) {
0162         ieee754_setcx(IEEE754_OVERFLOW);
0163         ieee754_setcx(IEEE754_INEXACT);
0164         /* -O can be table indexed by (rm,sn) */
0165         switch (ieee754_csr.rm) {
0166         case FPU_CSR_RN:
0167             return ieee754sp_inf(sn);
0168         case FPU_CSR_RZ:
0169             return ieee754sp_max(sn);
0170         case FPU_CSR_RU:    /* toward +Infinity */
0171             if (sn == 0)
0172                 return ieee754sp_inf(0);
0173             else
0174                 return ieee754sp_max(1);
0175         case FPU_CSR_RD:    /* toward -Infinity */
0176             if (sn == 0)
0177                 return ieee754sp_max(0);
0178             else
0179                 return ieee754sp_inf(1);
0180         }
0181     }
0182     /* gen norm/denorm/zero */
0183 
0184     if ((xm & SP_HIDDEN_BIT) == 0) {
0185         /* we underflow (tiny/zero) */
0186         assert(xe == SP_EMIN);
0187         if (ieee754_csr.mx & IEEE754_UNDERFLOW)
0188             ieee754_setcx(IEEE754_UNDERFLOW);
0189         return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm);
0190     } else {
0191         assert((xm >> (SP_FBITS + 1)) == 0);    /* no excess */
0192         assert(xm & SP_HIDDEN_BIT);
0193 
0194         return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
0195     }
0196 }