linux/arch/mips/math-emu/ieee754dp.c
<<
>>
Prefs
   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
  14int ieee754dp_class(union ieee754dp x)
  15{
  16        COMPXDP;
  17        EXPLODEXDP;
  18        return xc;
  19}
  20
  21static inline int ieee754dp_isnan(union ieee754dp x)
  22{
  23        return ieee754_class_nan(ieee754dp_class(x));
  24}
  25
  26static 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 */
  40union 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
  56static 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 */
  87union 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}
 198