cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ieee754dp.c (4338B)


      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}