xref: /illumos-gate/usr/src/lib/libc/sparc/fp/_Q_add.c (revision 069e6b7e31ba5dcbc5441b98af272714d9a5455c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "quad.h"
30 
31 #ifdef __sparcv9
32 
33 /*
34  * _Qp_add(pz, ox, oy) sets *pz = *ox + *oy.
35  */
36 void
37 _Qp_add(union longdouble *pz, const union longdouble *ox,
38 	const union longdouble *oy)
39 
40 #else
41 
42 /*
43  * _Q_add(ox, oy) returns *ox + *oy.
44  */
45 union longdouble
46 _Q_add(const union longdouble *ox, const union longdouble *oy)
47 
48 #endif	/* __sparcv9 */
49 
50 {
51 	union longdouble	z;
52 	const union longdouble	*x, *y;
53 	unsigned int		xm, ym, tm, fsr;
54 
55 	/* sort so |x| >= |y| */
56 	xm = ox->l.msw & 0x7fffffff;
57 	ym = oy->l.msw & 0x7fffffff;
58 	if (ym > xm || ym == xm && (oy->l.frac2 > ox->l.frac2 ||
59 	    oy->l.frac2 == ox->l.frac2 && (oy->l.frac3 > ox->l.frac3 ||
60 	    oy->l.frac3 == ox->l.frac3 && oy->l.frac4 > ox->l.frac4))) {
61 		y = ox;
62 		x = oy;
63 		tm = xm;
64 		xm = ym;
65 		ym = tm;
66 	} else {
67 		x = ox;
68 		y = oy;
69 	}
70 
71 	/* get the fsr */
72 	__quad_getfsrp(&fsr);
73 
74 	/* handle nan and inf cases */
75 	if (xm >= 0x7fff0000) {
76 		/* x is nan or inf */
77 		if (ym >= 0x7fff0000) {
78 			/* y is nan or inf */
79 			if ((ym & 0xffff) | y->l.frac2 | y->l.frac3 |
80 			    y->l.frac4) {
81 				/* y is nan; x must be nan too */
82 				/* the following logic implements V9 app. B */
83 				if (!(ym & 0x8000)) {
84 					/* y is snan, signal invalid */
85 					if (fsr & FSR_NVM) {
86 						__quad_faddq(ox, oy, &Z);
87 					} else {
88 						Z = (xm & 0x8000)? *y : *oy;
89 						Z.l.msw |= 0x8000;
90 						fsr = (fsr & ~FSR_CEXC) |
91 						    FSR_NVA | FSR_NVC;
92 						__quad_setfsrp(&fsr);
93 					}
94 					QUAD_RETURN(Z);
95 				}
96 				/* x and y are both qnan */
97 				Z = *oy;
98 				QUAD_RETURN(Z);
99 			}
100 			if (!((xm & 0xffff) | x->l.frac2 | x->l.frac3 |
101 			    x->l.frac4)) {
102 				/* x and y are both inf */
103 				if ((x->l.msw ^ y->l.msw) & 0x80000000) {
104 					/* inf - inf, signal invalid */
105 					if (fsr & FSR_NVM) {
106 						__quad_faddq(ox, oy, &Z);
107 					} else {
108 						Z.l.msw = 0x7fffffff;
109 						Z.l.frac2 = Z.l.frac3 =
110 						    Z.l.frac4 = 0xffffffff;
111 						fsr = (fsr & ~FSR_CEXC) |
112 						    FSR_NVA | FSR_NVC;
113 						__quad_setfsrp(&fsr);
114 					}
115 					QUAD_RETURN(Z);
116 				}
117 				/* inf + inf, return inf */
118 				Z = *x;
119 				QUAD_RETURN(Z);
120 			}
121 		}
122 		if ((xm & 0xffff) | x->l.frac2 | x->l.frac3 | x->l.frac4) {
123 			/* x is nan */
124 			if (!(xm & 0x8000)) {
125 				/* snan, signal invalid */
126 				if (fsr & FSR_NVM) {
127 					__quad_faddq(ox, oy, &Z);
128 				} else {
129 					Z = *x;
130 					Z.l.msw |= 0x8000;
131 					fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
132 					    FSR_NVC;
133 					__quad_setfsrp(&fsr);
134 				}
135 				QUAD_RETURN(Z);
136 			}
137 			Z = *x;
138 			QUAD_RETURN(Z);
139 		}
140 		/* x is inf */
141 		Z = *x;
142 		QUAD_RETURN(Z);
143 	}
144 
145 	/* now x and y are finite and |x| >= |y| */
146 	fsr &= ~FSR_CEXC;
147 	z.l.msw = (x->l.msw & 0x80000000);
148 	if ((x->l.msw ^ y->l.msw) & 0x80000000)
149 		__quad_mag_sub(x, y, &z, &fsr);
150 	else
151 		__quad_mag_add(x, y, &z, &fsr);
152 	if ((fsr & FSR_CEXC) & (fsr >> 23)) {
153 		__quad_setfsrp(&fsr);
154 		__quad_faddq(ox, oy, &Z);
155 	} else {
156 		Z = z;
157 		fsr |= (fsr & 0x1f) << 5;
158 		__quad_setfsrp(&fsr);
159 	}
160 	QUAD_RETURN(Z);
161 }
162