linux/arch/mips/math-emu/ieee754sp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* IEEE754 floating point arithmetic
   3 * single precision
   4 */
   5/*
   6 * MIPS floating point support
   7 * Copyright (C) 1994-2000 Algorithmics Ltd.
   8 */
   9
  10#include <linux/compiler.h>
  11
  12#include "ieee754sp.h"
  13
  14int ieee754sp_class(union ieee754sp x)
  15{
  16        COMPXSP;
  17        EXPLODEXSP;
  18        return xc;
  19}
  20
  21static inline int ieee754sp_isnan(union ieee754sp x)
  22{
  23        return ieee754_class_nan(ieee754sp_class(x));
  24}
  25
  26static inline int ieee754sp_issnan(union ieee754sp x)
  27{
  28        int qbit;
  29
  30        assert(ieee754sp_isnan(x));
  31        qbit = (SPMANT(x) & SP_MBIT(SP_FBITS - 1)) == SP_MBIT(SP_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 */
  40union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r)
  41{
  42        assert(ieee754sp_issnan(r));
  43
  44        ieee754_setcx(IEEE754_INVALID_OPERATION);
  45        if (ieee754_csr.nan2008) {
  46                SPMANT(r) |= SP_MBIT(SP_FBITS - 1);
  47        } else {
  48                SPMANT(r) &= ~SP_MBIT(SP_FBITS - 1);
  49                if (!ieee754sp_isnan(r))
  50                        SPMANT(r) |= SP_MBIT(SP_FBITS - 2);
  51        }
  52
  53        return r;
  54}
  55
  56static unsigned int ieee754sp_get_rounding(int sn, unsigned int xm)
  57{
  58        /* inexact must round of 3 bits
  59         */
  60        if (xm & (SP_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 */
  87union ieee754sp ieee754sp_format(int sn, int xe, unsigned int xm)
  88{
  89        assert(xm);             /* we don't gen exact zeros (probably should) */
  90
  91        assert((xm >> (SP_FBITS + 1 + 3)) == 0);        /* no excess */
  92        assert(xm & (SP_HIDDEN_BIT << 3));
  93
  94        if (xe < SP_EMIN) {
  95                /* strip lower bits */
  96                int es = SP_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 ieee754sp_zero(sn);
 106                        case FPU_CSR_RU:      /* toward +Infinity */
 107                                if (sn == 0)
 108                                        return ieee754sp_min(0);
 109                                else
 110                                        return ieee754sp_zero(1);
 111                        case FPU_CSR_RD:      /* toward -Infinity */
 112                                if (sn == 0)
 113                                        return ieee754sp_zero(0);
 114                                else
 115                                        return ieee754sp_min(1);
 116                        }
 117                }
 118
 119                if (xe == SP_EMIN - 1 &&
 120                    ieee754sp_get_rounding(sn, xm) >> (SP_FBITS + 1 + 3))
 121                {
 122                        /* Not tiny after rounding */
 123                        ieee754_setcx(IEEE754_INEXACT);
 124                        xm = ieee754sp_get_rounding(sn, xm);
 125                        xm >>= 1;
 126                        /* Clear grs bits */
 127                        xm &= ~(SP_MBIT(3) - 1);
 128                        xe++;
 129                } else {
 130                        /* sticky right shift es bits
 131                         */
 132                        xm = XSPSRS(xm, es);
 133                        xe += es;
 134                        assert((xm & (SP_HIDDEN_BIT << 3)) == 0);
 135                        assert(xe == SP_EMIN);
 136                }
 137        }
 138        if (xm & (SP_MBIT(3) - 1)) {
 139                ieee754_setcx(IEEE754_INEXACT);
 140                if ((xm & (SP_HIDDEN_BIT << 3)) == 0) {
 141                        ieee754_setcx(IEEE754_UNDERFLOW);
 142                }
 143
 144                /* inexact must round of 3 bits
 145                 */
 146                xm = ieee754sp_get_rounding(sn, xm);
 147                /* adjust exponent for rounding add overflowing
 148                 */
 149                if (xm >> (SP_FBITS + 1 + 3)) {
 150                        /* add causes mantissa overflow */
 151                        xm >>= 1;
 152                        xe++;
 153                }
 154        }
 155        /* strip grs bits */
 156        xm >>= 3;
 157
 158        assert((xm >> (SP_FBITS + 1)) == 0);    /* no excess */
 159        assert(xe >= SP_EMIN);
 160
 161        if (xe > SP_EMAX) {
 162                ieee754_setcx(IEEE754_OVERFLOW);
 163                ieee754_setcx(IEEE754_INEXACT);
 164                /* -O can be table indexed by (rm,sn) */
 165                switch (ieee754_csr.rm) {
 166                case FPU_CSR_RN:
 167                        return ieee754sp_inf(sn);
 168                case FPU_CSR_RZ:
 169                        return ieee754sp_max(sn);
 170                case FPU_CSR_RU:        /* toward +Infinity */
 171                        if (sn == 0)
 172                                return ieee754sp_inf(0);
 173                        else
 174                                return ieee754sp_max(1);
 175                case FPU_CSR_RD:        /* toward -Infinity */
 176                        if (sn == 0)
 177                                return ieee754sp_max(0);
 178                        else
 179                                return ieee754sp_inf(1);
 180                }
 181        }
 182        /* gen norm/denorm/zero */
 183
 184        if ((xm & SP_HIDDEN_BIT) == 0) {
 185                /* we underflow (tiny/zero) */
 186                assert(xe == SP_EMIN);
 187                if (ieee754_csr.mx & IEEE754_UNDERFLOW)
 188                        ieee754_setcx(IEEE754_UNDERFLOW);
 189                return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm);
 190        } else {
 191                assert((xm >> (SP_FBITS + 1)) == 0);    /* no excess */
 192                assert(xm & SP_HIDDEN_BIT);
 193
 194                return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
 195        }
 196}
 197