xref: /illumos-gate/usr/src/lib/libc/sparc/fp/_Q_sub.c (revision eb0cc229f19c437a6b538d3ac0d0443268290b7e)
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_sub(pz, ox, oy) sets *pz = *ox - *oy.
35  */
36 void
37 _Qp_sub(union longdouble *pz, const union longdouble *ox,
38 	const union longdouble *oy)
39 
40 #else
41 
42 /*
43  * _Q_sub(ox, oy) returns *ox - *oy.
44  */
45 union longdouble
46 _Q_sub(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 	int			flip;
55 
56 	/* sort so |x| >= |y| */
57 	xm = ox->l.msw & 0x7fffffff;
58 	ym = oy->l.msw & 0x7fffffff;
59 	if (ym > xm || ym == xm && (oy->l.frac2 > ox->l.frac2 ||
60 	    oy->l.frac2 == ox->l.frac2 && (oy->l.frac3 > ox->l.frac3 ||
61 	    oy->l.frac3 == ox->l.frac3 && oy->l.frac4 > ox->l.frac4))) {
62 		y = ox;
63 		x = oy;
64 		tm = xm;
65 		xm = ym;
66 		ym = tm;
67 		flip = 0x80000000;
68 	} else {
69 		x = ox;
70 		y = oy;
71 		flip = 0;
72 	}
73 
74 	/* get the fsr */
75 	__quad_getfsrp(&fsr);
76 
77 	/* handle nan and inf cases */
78 	if (xm >= 0x7fff0000) {
79 		/* x is nan or inf */
80 		if (ym >= 0x7fff0000) {
81 			/* y is nan or inf */
82 			if ((ym & 0xffff) | y->l.frac2 | y->l.frac3 |
83 			    y->l.frac4) {
84 				/* y is nan; x must be nan too */
85 				/* the following logic implements V9 app. B */
86 				if (!(ym & 0x8000)) {
87 					/* y is snan, signal invalid */
88 					if (fsr & FSR_NVM) {
89 						__quad_fsubq(ox, oy, &Z);
90 					} else {
91 						Z = (xm & 0x8000)? *y : *oy;
92 						Z.l.msw |= 0x8000;
93 						fsr = (fsr & ~FSR_CEXC) |
94 						    FSR_NVA | FSR_NVC;
95 						__quad_setfsrp(&fsr);
96 					}
97 					QUAD_RETURN(Z);
98 				}
99 				/* x and y are both qnan */
100 				Z = *oy;
101 				QUAD_RETURN(Z);
102 			}
103 			if (!((xm & 0xffff) | x->l.frac2 | x->l.frac3 |
104 			    x->l.frac4)) {
105 				/* x and y are both inf */
106 				if (!((x->l.msw ^ y->l.msw) & 0x80000000)) {
107 					/* inf - inf, signal invalid */
108 					if (fsr & FSR_NVM) {
109 						__quad_fsubq(ox, oy, &Z);
110 					} else {
111 						Z.l.msw = 0x7fffffff;
112 						Z.l.frac2 = Z.l.frac3 =
113 						    Z.l.frac4 = 0xffffffff;
114 						fsr = (fsr & ~FSR_CEXC) |
115 						    FSR_NVA | FSR_NVC;
116 						__quad_setfsrp(&fsr);
117 					}
118 					QUAD_RETURN(Z);
119 				}
120 				/* inf + inf, return inf */
121 				Z = *x;
122 				Z.l.msw ^= flip;
123 				QUAD_RETURN(Z);
124 			}
125 		}
126 		if ((xm & 0xffff) | x->l.frac2 | x->l.frac3 | x->l.frac4) {
127 			/* x is nan */
128 			if (!(xm & 0x8000)) {
129 				/* snan, signal invalid */
130 				if (fsr & FSR_NVM) {
131 					__quad_fsubq(ox, oy, &Z);
132 				} else {
133 					Z = *x;
134 					Z.l.msw |= 0x8000;
135 					fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
136 					    FSR_NVC;
137 					__quad_setfsrp(&fsr);
138 				}
139 				QUAD_RETURN(Z);
140 			}
141 			Z = *x;
142 			QUAD_RETURN(Z);
143 		}
144 		/* x is inf */
145 		Z = *x;
146 		Z.l.msw ^= flip;
147 		QUAD_RETURN(Z);
148 	}
149 
150 	/* now x and y are finite and |x| >= |y| */
151 	fsr &= ~FSR_CEXC;
152 	z.l.msw = (x->l.msw & 0x80000000) ^ flip;
153 	if ((x->l.msw ^ y->l.msw) & 0x80000000)
154 		__quad_mag_add(x, y, &z, &fsr);
155 	else
156 		__quad_mag_sub(x, y, &z, &fsr);
157 	if ((fsr & FSR_CEXC) & (fsr >> 23)) {
158 		__quad_setfsrp(&fsr);
159 		__quad_fsubq(ox, oy, &Z);
160 	} else {
161 		Z = z;
162 		fsr |= (fsr & 0x1f) << 5;
163 		__quad_setfsrp(&fsr);
164 	}
165 	QUAD_RETURN(Z);
166 }
167