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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24 */
25 /*
26 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29
30 #if defined(ELFOBJ)
31 #pragma weak nexttowardf = __nexttowardf
32 #endif
33
34 #include "libm.h"
35
36 static union {
37 unsigned i;
38 float f;
39 } C[] = {
40 0x00800000,
41 0x7f000000,
42 0x7fffffff
43 };
44
45 #define tiny C[0].f
46 #define huge C[1].f
47 #define qnan C[2].f
48
49 #if defined(__sparc)
50
51 enum fcc_type {
52 fcc_equal = 0,
53 fcc_less = 1,
54 fcc_greater = 2,
55 fcc_unordered = 3
56 };
57
58 #ifdef __sparcv9
59 #define _Q_cmp _Qp_cmp
60 #endif
61
62 extern enum fcc_type _Q_cmp(const long double *, const long double *);
63
64 float
65 __nexttowardf(float x, long double y) {
66 union {
67 unsigned i;
68 float f;
69 } xx;
70 union {
71 unsigned i[4];
72 long double q;
73 } yy;
74 long double lx;
75 unsigned hx;
76 volatile float dummy;
77 enum fcc_type rel;
78
79 /*
80 * It would be somewhat more efficient to check for NaN and
81 * zero operands before converting x to long double and then
82 * to code the comparison in line rather than calling _Q_cmp.
83 * However, since this code probably won't get used much,
84 * I'm opting in favor of simplicity instead.
85 */
86 lx = xx.f = x;
87 hx = xx.i & ~0x80000000;
88
89 /* check for each of four possible orderings */
90 rel = _Q_cmp(&lx, &y);
91 if (rel == fcc_unordered)
92 return (qnan);
93
94 if (rel == fcc_equal) {
95 if (hx == 0) { /* x is zero; return zero with y's sign */
96 yy.q = y;
97 xx.i = yy.i[0];
98 return (xx.f);
99 }
100 return (x);
101 }
102
103 if (rel == fcc_less) {
104 if (hx == 0) /* x is zero */
105 xx.i = 0x00000001;
106 else if ((int) xx.i >= 0) /* x is positive */
107 xx.i++;
108 else
109 xx.i--;
110 } else {
111 if (hx == 0) /* x is zero */
112 xx.i = 0x80000001;
113 else if ((int) xx.i >= 0) /* x is positive */
114 xx.i--;
115 else
116 xx.i++;
117 }
118
119 /* raise exceptions as needed */
120 hx = xx.i & ~0x80000000;
121 if (hx == 0x7f800000) {
122 dummy = huge;
123 dummy *= huge;
124 } else if (hx < 0x00800000) {
125 dummy = tiny;
126 dummy *= tiny;
127 }
128
129 return (xx.f);
130 }
131
132 #elif defined(__x86)
133
134 float
135 __nexttowardf(float x, long double y) {
136 union {
137 unsigned i;
138 float f;
139 } xx;
140 unsigned hx;
141 long double lx;
142 volatile float dummy;
143
144 lx = xx.f = x;
145 hx = xx.i & ~0x80000000;
146
147 /* check for each of four possible orderings */
148 if (isunordered(lx, y))
149 return ((float) (lx + y));
150
151 if (lx == y)
152 return ((float) y);
153
154 if (lx < y) {
155 if (hx == 0) /* x is zero */
156 xx.i = 0x00000001;
157 else if ((int) xx.i >= 0) /* x is positive */
158 xx.i++;
159 else
160 xx.i--;
161 } else {
162 if (hx == 0) /* x is zero */
163 xx.i = 0x80000001;
164 else if ((int) xx.i >= 0) /* x is positive */
165 xx.i--;
166 else
167 xx.i++;
168 }
169
170 /* raise exceptions as needed */
171 hx = xx.i & ~0x80000000;
172 if (hx == 0x7f800000) {
173 dummy = huge;
174 dummy *= huge;
175 } else if (hx < 0x00800000) {
176 dummy = tiny;
177 dummy *= tiny;
178 }
179
180 return (xx.f);
181 }
182
183 #else
184 #error Unknown architecture
185 #endif