^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* IEEE754 floating point arithmetic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * double precision: common utilities
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * MIPS floating point support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 1994-2000 Algorithmics Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "ieee754dp.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) s64 ieee754dp_tlong(union ieee754dp x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) u64 residue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) int round;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) int sticky;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) int odd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) COMPXDP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) ieee754_clearcx();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) EXPLODEXDP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) FLUSHXDP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) switch (xc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) case IEEE754_CLASS_SNAN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) case IEEE754_CLASS_QNAN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) ieee754_setcx(IEEE754_INVALID_OPERATION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) return ieee754di_indef();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) case IEEE754_CLASS_INF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) ieee754_setcx(IEEE754_INVALID_OPERATION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return ieee754di_overflow(xs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) case IEEE754_CLASS_ZERO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) case IEEE754_CLASS_DNORM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) case IEEE754_CLASS_NORM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) if (xe >= 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* look for valid corner case */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (xe == 63 && xs && xm == DP_HIDDEN_BIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) return -0x8000000000000000LL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /* Set invalid. We will only use overflow for floating
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) point overflow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) ieee754_setcx(IEEE754_INVALID_OPERATION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return ieee754di_overflow(xs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /* oh gawd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (xe > DP_FBITS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) xm <<= xe - DP_FBITS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) } else if (xe < DP_FBITS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (xe < -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) residue = xm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) round = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) sticky = residue != 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) xm = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* Shifting a u64 64 times does not work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * so we do it in two steps. Be aware that xe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * may be -1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) residue = xm << (xe + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) residue <<= 63 - DP_FBITS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) round = (residue >> 63) != 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) sticky = (residue << 1) != 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) xm >>= DP_FBITS - xe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) odd = (xm & 0x1) != 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) switch (ieee754_csr.rm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) case FPU_CSR_RN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (round && (sticky || odd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) xm++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) case FPU_CSR_RZ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) case FPU_CSR_RU: /* toward +Infinity */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if ((round || sticky) && !xs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) xm++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) case FPU_CSR_RD: /* toward -Infinity */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if ((round || sticky) && xs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) xm++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if ((xm >> 63) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /* This can happen after rounding */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) ieee754_setcx(IEEE754_INVALID_OPERATION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return ieee754di_overflow(xs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (round || sticky)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) ieee754_setcx(IEEE754_INEXACT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (xs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return -xm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return xm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }