GNU Linux-libre 4.19.286-gnu1
[releases.git] / arch / mips / math-emu / sp_rint.c
1 /* IEEE754 floating point arithmetic
2  * single precision
3  */
4 /*
5  * MIPS floating point support
6  * Copyright (C) 1994-2000 Algorithmics Ltd.
7  * Copyright (C) 2017 Imagination Technologies, Ltd.
8  * Author: Aleksandar Markovic <aleksandar.markovic@imgtec.com>
9  *
10  *  This program is free software; you can distribute it and/or modify it
11  *  under the terms of the GNU General Public License (Version 2) as
12  *  published by the Free Software Foundation.
13  *
14  *  This program is distributed in the hope it will be useful, but WITHOUT
15  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17  *  for more details.
18  *
19  *  You should have received a copy of the GNU General Public License along
20  *  with this program.
21  */
22
23 #include "ieee754sp.h"
24
25 union ieee754sp ieee754sp_rint(union ieee754sp x)
26 {
27         union ieee754sp ret;
28         u32 residue;
29         int sticky;
30         int round;
31         int odd;
32
33         COMPXDP;                /* <-- DP needed for 64-bit mantissa tmp */
34
35         ieee754_clearcx();
36
37         EXPLODEXSP;
38         FLUSHXSP;
39
40         if (xc == IEEE754_CLASS_SNAN)
41                 return ieee754sp_nanxcpt(x);
42
43         if ((xc == IEEE754_CLASS_QNAN) ||
44             (xc == IEEE754_CLASS_INF) ||
45             (xc == IEEE754_CLASS_ZERO))
46                 return x;
47
48         if (xe >= SP_FBITS)
49                 return x;
50
51         if (xe < -1) {
52                 residue = xm;
53                 round = 0;
54                 sticky = residue != 0;
55                 xm = 0;
56         } else {
57                 residue = xm << (xe + 1);
58                 residue <<= 31 - SP_FBITS;
59                 round = (residue >> 31) != 0;
60                 sticky = (residue << 1) != 0;
61                 xm >>= SP_FBITS - xe;
62         }
63
64         odd = (xm & 0x1) != 0x0;
65
66         switch (ieee754_csr.rm) {
67         case FPU_CSR_RN:        /* toward nearest */
68                 if (round && (sticky || odd))
69                         xm++;
70                 break;
71         case FPU_CSR_RZ:        /* toward zero */
72                 break;
73         case FPU_CSR_RU:        /* toward +infinity */
74                 if ((round || sticky) && !xs)
75                         xm++;
76                 break;
77         case FPU_CSR_RD:        /* toward -infinity */
78                 if ((round || sticky) && xs)
79                         xm++;
80                 break;
81         }
82
83         if (round || sticky)
84                 ieee754_setcx(IEEE754_INEXACT);
85
86         ret = ieee754sp_flong(xm);
87         SPSIGN(ret) = xs;
88
89         return ret;
90 }