xref: /openbmc/linux/arch/mips/math-emu/dp_rint.c (revision 0edff03d)
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 }
90