root/arch/mips/math-emu/ieee754dp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ieee754dp_class
  2. ieee754dp_isnan
  3. ieee754dp_issnan
  4. ieee754dp_nanxcpt
  5. ieee754dp_get_rounding
  6. ieee754dp_format

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /* IEEE754 floating point arithmetic
   3  * double precision: common utilities
   4  */
   5 /*
   6  * MIPS floating point support
   7  * Copyright (C) 1994-2000 Algorithmics Ltd.
   8  */
   9 
  10 #include <linux/compiler.h>
  11 
  12 #include "ieee754dp.h"
  13 
  14 int ieee754dp_class(union ieee754dp x)
  15 {
  16         COMPXDP;
  17         EXPLODEXDP;
  18         return xc;
  19 }
  20 
  21 static inline int ieee754dp_isnan(union ieee754dp x)
  22 {
  23         return ieee754_class_nan(ieee754dp_class(x));
  24 }
  25 
  26 static inline int ieee754dp_issnan(union ieee754dp x)
  27 {
  28         int qbit;
  29 
  30         assert(ieee754dp_isnan(x));
  31         qbit = (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1);
  32         return ieee754_csr.nan2008 ^ qbit;
  33 }
  34 
  35 
  36 /*
  37  * Raise the Invalid Operation IEEE 754 exception
  38  * and convert the signaling NaN supplied to a quiet NaN.
  39  */
  40 union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp r)
  41 {
  42         assert(ieee754dp_issnan(r));
  43 
  44         ieee754_setcx(IEEE754_INVALID_OPERATION);
  45         if (ieee754_csr.nan2008) {
  46                 DPMANT(r) |= DP_MBIT(DP_FBITS - 1);
  47         } else {
  48                 DPMANT(r) &= ~DP_MBIT(DP_FBITS - 1);
  49                 if (!ieee754dp_isnan(r))
  50                         DPMANT(r) |= DP_MBIT(DP_FBITS - 2);
  51         }
  52 
  53         return r;
  54 }
  55 
  56 static u64 ieee754dp_get_rounding(int sn, u64 xm)
  57 {
  58         /* inexact must round of 3 bits
  59          */
  60         if (xm & (DP_MBIT(3) - 1)) {
  61                 switch (ieee754_csr.rm) {
  62                 case FPU_CSR_RZ:
  63                         break;
  64                 case FPU_CSR_RN:
  65                         xm += 0x3 + ((xm >> 3) & 1);
  66                         /* xm += (xm&0x8)?0x4:0x3 */
  67                         break;
  68                 case FPU_CSR_RU:        /* toward +Infinity */
  69                         if (!sn)        /* ?? */
  70                                 xm += 0x8;
  71                         break;
  72                 case FPU_CSR_RD:        /* toward -Infinity */
  73                         if (sn) /* ?? */
  74                                 xm += 0x8;
  75                         break;
  76                 }
  77         }
  78         return xm;
  79 }
  80 
  81 
  82 /* generate a normal/denormal number with over,under handling
  83  * sn is sign
  84  * xe is an unbiased exponent
  85  * xm is 3bit extended precision value.
  86  */
  87 union ieee754dp ieee754dp_format(int sn, int xe, u64 xm)
  88 {
  89         assert(xm);             /* we don't gen exact zeros (probably should) */
  90 
  91         assert((xm >> (DP_FBITS + 1 + 3)) == 0);        /* no excess */
  92         assert(xm & (DP_HIDDEN_BIT << 3));
  93 
  94         if (xe < DP_EMIN) {
  95                 /* strip lower bits */
  96                 int es = DP_EMIN - xe;
  97 
  98                 if (ieee754_csr.nod) {
  99                         ieee754_setcx(IEEE754_UNDERFLOW);
 100                         ieee754_setcx(IEEE754_INEXACT);
 101 
 102                         switch(ieee754_csr.rm) {
 103                         case FPU_CSR_RN:
 104                         case FPU_CSR_RZ:
 105                                 return ieee754dp_zero(sn);
 106                         case FPU_CSR_RU:    /* toward +Infinity */
 107                                 if (sn == 0)
 108                                         return ieee754dp_min(0);
 109                                 else
 110                                         return ieee754dp_zero(1);
 111                         case FPU_CSR_RD:    /* toward -Infinity */
 112                                 if (sn == 0)
 113                                         return ieee754dp_zero(0);
 114                                 else
 115                                         return ieee754dp_min(1);
 116                         }
 117                 }
 118 
 119                 if (xe == DP_EMIN - 1 &&
 120                     ieee754dp_get_rounding(sn, xm) >> (DP_FBITS + 1 + 3))
 121                 {
 122                         /* Not tiny after rounding */
 123                         ieee754_setcx(IEEE754_INEXACT);
 124                         xm = ieee754dp_get_rounding(sn, xm);
 125                         xm >>= 1;
 126                         /* Clear grs bits */
 127                         xm &= ~(DP_MBIT(3) - 1);
 128                         xe++;
 129                 }
 130                 else {
 131                         /* sticky right shift es bits
 132                          */
 133                         xm = XDPSRS(xm, es);
 134                         xe += es;
 135                         assert((xm & (DP_HIDDEN_BIT << 3)) == 0);
 136                         assert(xe == DP_EMIN);
 137                 }
 138         }
 139         if (xm & (DP_MBIT(3) - 1)) {
 140                 ieee754_setcx(IEEE754_INEXACT);
 141                 if ((xm & (DP_HIDDEN_BIT << 3)) == 0) {
 142                         ieee754_setcx(IEEE754_UNDERFLOW);
 143                 }
 144 
 145                 /* inexact must round of 3 bits
 146                  */
 147                 xm = ieee754dp_get_rounding(sn, xm);
 148                 /* adjust exponent for rounding add overflowing
 149                  */
 150                 if (xm >> (DP_FBITS + 3 + 1)) {
 151                         /* add causes mantissa overflow */
 152                         xm >>= 1;
 153                         xe++;
 154                 }
 155         }
 156         /* strip grs bits */
 157         xm >>= 3;
 158 
 159         assert((xm >> (DP_FBITS + 1)) == 0);    /* no excess */
 160         assert(xe >= DP_EMIN);
 161 
 162         if (xe > DP_EMAX) {
 163                 ieee754_setcx(IEEE754_OVERFLOW);
 164                 ieee754_setcx(IEEE754_INEXACT);
 165                 /* -O can be table indexed by (rm,sn) */
 166                 switch (ieee754_csr.rm) {
 167                 case FPU_CSR_RN:
 168                         return ieee754dp_inf(sn);
 169                 case FPU_CSR_RZ:
 170                         return ieee754dp_max(sn);
 171                 case FPU_CSR_RU:        /* toward +Infinity */
 172                         if (sn == 0)
 173                                 return ieee754dp_inf(0);
 174                         else
 175                                 return ieee754dp_max(1);
 176                 case FPU_CSR_RD:        /* toward -Infinity */
 177                         if (sn == 0)
 178                                 return ieee754dp_max(0);
 179                         else
 180                                 return ieee754dp_inf(1);
 181                 }
 182         }
 183         /* gen norm/denorm/zero */
 184 
 185         if ((xm & DP_HIDDEN_BIT) == 0) {
 186                 /* we underflow (tiny/zero) */
 187                 assert(xe == DP_EMIN);
 188                 if (ieee754_csr.mx & IEEE754_UNDERFLOW)
 189                         ieee754_setcx(IEEE754_UNDERFLOW);
 190                 return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm);
 191         } else {
 192                 assert((xm >> (DP_FBITS + 1)) == 0);    /* no excess */
 193                 assert(xm & DP_HIDDEN_BIT);
 194 
 195                 return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
 196         }
 197 }

/* [<][>][^][v][top][bottom][index][help] */