Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* IEEE754 floating point arithmetic
0003  * double precision: common utilities
0004  */
0005 /*
0006  * MIPS floating point support
0007  * Copyright (C) 1994-2000 Algorithmics Ltd.
0008  */
0009 
0010 #include <linux/compiler.h>
0011 
0012 #include "ieee754dp.h"
0013 
0014 int ieee754dp_class(union ieee754dp x)
0015 {
0016     COMPXDP;
0017     EXPLODEXDP;
0018     return xc;
0019 }
0020 
0021 static inline int ieee754dp_isnan(union ieee754dp x)
0022 {
0023     return ieee754_class_nan(ieee754dp_class(x));
0024 }
0025 
0026 static inline int ieee754dp_issnan(union ieee754dp x)
0027 {
0028     int qbit;
0029 
0030     assert(ieee754dp_isnan(x));
0031     qbit = (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_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 ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp r)
0041 {
0042     assert(ieee754dp_issnan(r));
0043 
0044     ieee754_setcx(IEEE754_INVALID_OPERATION);
0045     if (ieee754_csr.nan2008) {
0046         DPMANT(r) |= DP_MBIT(DP_FBITS - 1);
0047     } else {
0048         DPMANT(r) &= ~DP_MBIT(DP_FBITS - 1);
0049         if (!ieee754dp_isnan(r))
0050             DPMANT(r) |= DP_MBIT(DP_FBITS - 2);
0051     }
0052 
0053     return r;
0054 }
0055 
0056 static u64 ieee754dp_get_rounding(int sn, u64 xm)
0057 {
0058     /* inexact must round of 3 bits
0059      */
0060     if (xm & (DP_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 ieee754dp ieee754dp_format(int sn, int xe, u64 xm)
0088 {
0089     assert(xm);     /* we don't gen exact zeros (probably should) */
0090 
0091     assert((xm >> (DP_FBITS + 1 + 3)) == 0);    /* no excess */
0092     assert(xm & (DP_HIDDEN_BIT << 3));
0093 
0094     if (xe < DP_EMIN) {
0095         /* strip lower bits */
0096         int es = DP_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 ieee754dp_zero(sn);
0106             case FPU_CSR_RU:    /* toward +Infinity */
0107                 if (sn == 0)
0108                     return ieee754dp_min(0);
0109                 else
0110                     return ieee754dp_zero(1);
0111             case FPU_CSR_RD:    /* toward -Infinity */
0112                 if (sn == 0)
0113                     return ieee754dp_zero(0);
0114                 else
0115                     return ieee754dp_min(1);
0116             }
0117         }
0118 
0119         if (xe == DP_EMIN - 1 &&
0120             ieee754dp_get_rounding(sn, xm) >> (DP_FBITS + 1 + 3))
0121         {
0122             /* Not tiny after rounding */
0123             ieee754_setcx(IEEE754_INEXACT);
0124             xm = ieee754dp_get_rounding(sn, xm);
0125             xm >>= 1;
0126             /* Clear grs bits */
0127             xm &= ~(DP_MBIT(3) - 1);
0128             xe++;
0129         }
0130         else {
0131             /* sticky right shift es bits
0132              */
0133             xm = XDPSRS(xm, es);
0134             xe += es;
0135             assert((xm & (DP_HIDDEN_BIT << 3)) == 0);
0136             assert(xe == DP_EMIN);
0137         }
0138     }
0139     if (xm & (DP_MBIT(3) - 1)) {
0140         ieee754_setcx(IEEE754_INEXACT);
0141         if ((xm & (DP_HIDDEN_BIT << 3)) == 0) {
0142             ieee754_setcx(IEEE754_UNDERFLOW);
0143         }
0144 
0145         /* inexact must round of 3 bits
0146          */
0147         xm = ieee754dp_get_rounding(sn, xm);
0148         /* adjust exponent for rounding add overflowing
0149          */
0150         if (xm >> (DP_FBITS + 3 + 1)) {
0151             /* add causes mantissa overflow */
0152             xm >>= 1;
0153             xe++;
0154         }
0155     }
0156     /* strip grs bits */
0157     xm >>= 3;
0158 
0159     assert((xm >> (DP_FBITS + 1)) == 0);    /* no excess */
0160     assert(xe >= DP_EMIN);
0161 
0162     if (xe > DP_EMAX) {
0163         ieee754_setcx(IEEE754_OVERFLOW);
0164         ieee754_setcx(IEEE754_INEXACT);
0165         /* -O can be table indexed by (rm,sn) */
0166         switch (ieee754_csr.rm) {
0167         case FPU_CSR_RN:
0168             return ieee754dp_inf(sn);
0169         case FPU_CSR_RZ:
0170             return ieee754dp_max(sn);
0171         case FPU_CSR_RU:    /* toward +Infinity */
0172             if (sn == 0)
0173                 return ieee754dp_inf(0);
0174             else
0175                 return ieee754dp_max(1);
0176         case FPU_CSR_RD:    /* toward -Infinity */
0177             if (sn == 0)
0178                 return ieee754dp_max(0);
0179             else
0180                 return ieee754dp_inf(1);
0181         }
0182     }
0183     /* gen norm/denorm/zero */
0184 
0185     if ((xm & DP_HIDDEN_BIT) == 0) {
0186         /* we underflow (tiny/zero) */
0187         assert(xe == DP_EMIN);
0188         if (ieee754_csr.mx & IEEE754_UNDERFLOW)
0189             ieee754_setcx(IEEE754_UNDERFLOW);
0190         return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm);
0191     } else {
0192         assert((xm >> (DP_FBITS + 1)) == 0);    /* no excess */
0193         assert(xm & DP_HIDDEN_BIT);
0194 
0195         return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
0196     }
0197 }