GNU Linux-libre 4.14.266-gnu1
[releases.git] / arch / mips / math-emu / dp_rint.c
1 /* IEEE754 floating point arithmetic
2  * double precision: common utilities
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 "ieee754dp.h"
24
25 union ieee754dp ieee754dp_rint(union ieee754dp x)
26 {
27         union ieee754dp ret;
28         u64 residue;
29         int sticky;
30         int round;
31         int odd;
32
33         COMPXDP;
34
35         ieee754_clearcx();
36
37         EXPLODEXDP;
38         FLUSHXDP;
39
40         if (xc == IEEE754_CLASS_SNAN)
41                 return ieee754dp_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 >= DP_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 << (64 - DP_FBITS + xe);
58                 round = (residue >> 63) != 0;
59                 sticky = (residue << 1) != 0;
60                 xm >>= DP_FBITS - xe;
61         }
62
63         odd = (xm & 0x1) != 0x0;
64
65         switch (ieee754_csr.rm) {
66         case FPU_CSR_RN:        /* toward nearest */
67                 if (round && (sticky || odd))
68                         xm++;
69                 break;
70         case FPU_CSR_RZ:        /* toward zero */
71                 break;
72         case FPU_CSR_RU:        /* toward +infinity */
73                 if ((round || sticky) && !xs)
74                         xm++;
75                 break;
76         case FPU_CSR_RD:        /* toward -infinity */
77                 if ((round || sticky) && xs)
78                         xm++;
79                 break;
80         }
81
82         if (round || sticky)
83                 ieee754_setcx(IEEE754_INEXACT);
84
85         ret = ieee754dp_flong(xm);
86         DPSIGN(ret) = xs;
87
88         return ret;
89 }