xref: /illumos-gate/usr/src/lib/libc/port/fp/pack_float.c (revision dd51520e127b452179a2ce4ea3bd8dee949f9afe)
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 2008 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 "lint.h"
30 #include "base_conversion.h"
31 
32 static void
33 __fp_rightshift(unpacked *pu, int n)
34 
35 /* Right shift significand sticky by n bits.  */
36 
37 {
38 	int		i;
39 
40 	if (n >= (32 * UNPACKED_SIZE)) {	/* drastic */
41 		for (i = 0; (pu->significand[i] == 0) && (i < UNPACKED_SIZE);
42 				i++);
43 		if (i >= UNPACKED_SIZE) {
44 			pu->fpclass = fp_zero;
45 			return;
46 		} else {
47 			for (i = 0; i < (UNPACKED_SIZE - 1); i++)
48 				pu->significand[i] = 0;
49 			pu->significand[UNPACKED_SIZE - 1] = 1;
50 			return;
51 		}
52 	}
53 	while (n >= 32) {	/* big shift */
54 		if (pu->significand[UNPACKED_SIZE - 1] != 0)
55 			pu->significand[UNPACKED_SIZE - 2] |= 1;
56 		for (i = UNPACKED_SIZE - 2; i >= 0; i--)
57 			pu->significand[i + 1] = pu->significand[i];
58 		pu->significand[0] = 0;
59 		n -= 32;
60 	}
61 	if (n >= 1) {		/* small shift */
62 		unsigned int   high, low, shiftout = 0;
63 		for (i = 0; i < UNPACKED_SIZE; i++) {
64 			high = pu->significand[i] >> n;
65 			low = pu->significand[i] << (32 - n);
66 			pu->significand[i] = shiftout | high;
67 			shiftout = low;
68 		}
69 		if (shiftout != 0)
70 			pu->significand[UNPACKED_SIZE - 1] |= 1;
71 	}
72 }
73 
74 static int
75 overflow_to_infinity(int sign, enum fp_direction_type rd)
76 
77 /* Returns 1 if overflow should go to infinity, 0 if to max finite. */
78 
79 {
80 	int		inf;
81 
82 	switch (rd) {
83 	case fp_nearest:
84 		inf = 1;
85 		break;
86 	case fp_tozero:
87 		inf = 0;
88 		break;
89 	case fp_positive:
90 		inf = !sign;
91 		break;
92 	case fp_negative:
93 		inf = sign;
94 		break;
95 	}
96 	return (inf);
97 }
98 
99 static void
100 round(unpacked *pu, int roundword, enum fp_direction_type rd, int *ex)
101 /*
102  * Round according to current rounding mode. pu must be shifted to so that
103  * the roundbit is pu->significand[roundword] & 0x80000000
104  */
105 {
106 	int		increment;	/* boolean to indicate round up */
107 	int		is;
108 	unsigned	msw;		/* msw before increment */
109 
110 	for (is = (roundword + 1); is < UNPACKED_SIZE; is++)
111 		if (pu->significand[is] != 0) {
112 		/* Condense extra bits into sticky bottom of roundword. */
113 			pu->significand[roundword] |= 1;
114 			break;
115 		}
116 	if (pu->significand[roundword] == 0)
117 		return;
118 	*ex |= (1 << fp_inexact);
119 	switch (rd) {
120 	case fp_nearest:
121 		increment = pu->significand[roundword] >= 0x80000000;
122 		break;
123 	case fp_tozero:
124 		increment = 0;
125 		break;
126 	case fp_positive:
127 		increment = (pu->sign == 0) & (pu->significand[roundword] != 0);
128 		break;
129 	case fp_negative:
130 		increment = (pu->sign != 0) & (pu->significand[roundword] != 0);
131 		break;
132 	}
133 	if (increment) {
134 		msw = pu->significand[0];	/* save msw before round */
135 		is = roundword;
136 		do {
137 			is--;
138 			pu->significand[is]++;
139 		}
140 		while ((pu->significand[is] == 0) && (is > 0));
141 		if (pu->significand[0] < msw) {	/* rounding carried out */
142 			pu->exponent++;
143 			pu->significand[0] = 0x80000000;
144 		}
145 	}
146 	if ((rd == fp_nearest) &&
147 		(pu->significand[roundword] == 0x80000000)) {
148 		/* ambiguous case */
149 		pu->significand[roundword - 1] &= ~1; /* force round to even */
150 	}
151 }
152 
153 void
154 __pack_single(unpacked *pu, single *px, enum fp_direction_type rd,
155 	fp_exception_field_type *ex)
156 {
157 	single_equivalence kluge;
158 	int		e;
159 
160 	e = 0;
161 	kluge.f.msw.sign = pu->sign;
162 	switch (pu->fpclass) {
163 	case fp_zero:
164 		kluge.f.msw.exponent = 0;
165 		kluge.f.msw.significand = 0;
166 		break;
167 	case fp_infinity:
168 infinity:
169 		kluge.f.msw.exponent = 0xff;
170 		kluge.f.msw.significand = 0;
171 		break;
172 	case fp_quiet:
173 		kluge.f.msw.exponent = 0xff;
174 		kluge.f.msw.significand = 0x400000 |
175 		    (0x3fffff & (pu->significand[0] >> 8));
176 		break;
177 	case fp_normal:
178 		__fp_rightshift(pu, 8);
179 		pu->exponent += SINGLE_BIAS;
180 		if (pu->exponent <= 0) {
181 			kluge.f.msw.exponent = 0;
182 			__fp_rightshift(pu, 1 - pu->exponent);
183 			round(pu, 1, rd, &e);
184 			if (pu->significand[0] == 0x800000) {
185 				/* rounded back up to normal */
186 				kluge.f.msw.exponent = 1;
187 				kluge.f.msw.significand = 0;
188 				e |= (1 << fp_underflow);
189 				goto ret;
190 			}
191 			if (e & (1 << fp_inexact))
192 				e |= (1 << fp_underflow);
193 			kluge.f.msw.significand = 0x7fffff & pu->significand[0];
194 			goto ret;
195 		}
196 		round(pu, 1, rd, &e);
197 		if (pu->significand[0] == 0x1000000) {	/* rounding overflow */
198 			pu->significand[0] = 0x800000;
199 			pu->exponent += 1;
200 		}
201 		if (pu->exponent >= 0xff) {
202 			e |= (1 << fp_overflow) | (1 << fp_inexact);
203 			if (overflow_to_infinity(pu->sign, rd))
204 				goto infinity;
205 			kluge.f.msw.exponent = 0xfe;
206 			kluge.f.msw.significand = 0x7fffff;
207 			goto ret;
208 		}
209 		kluge.f.msw.exponent = pu->exponent;
210 		kluge.f.msw.significand = 0x7fffff & pu->significand[0];
211 	}
212 ret:
213 	*px = kluge.x;
214 	*ex = (fp_exception_field_type)e;
215 }
216 
217 void
218 __pack_double(unpacked *pu, double *px, enum fp_direction_type rd,
219 	fp_exception_field_type *ex)
220 {
221 	double_equivalence kluge;
222 	int		e;
223 
224 	e = 0;
225 	kluge.f.msw.sign = pu->sign;
226 	switch (pu->fpclass) {
227 	case fp_zero:
228 		kluge.f.msw.exponent = 0;
229 		kluge.f.msw.significand = 0;
230 		kluge.f.significand2 = 0;
231 		break;
232 	case fp_infinity:
233 infinity:
234 		kluge.f.msw.exponent = 0x7ff;
235 		kluge.f.msw.significand = 0;
236 		kluge.f.significand2 = 0;
237 		break;
238 	case fp_quiet:
239 		kluge.f.msw.exponent = 0x7ff;
240 		__fp_rightshift(pu, 11);
241 		kluge.f.msw.significand = 0x80000 |
242 		    (0x7ffff & pu->significand[0]);
243 		kluge.f.significand2 = pu->significand[1];
244 		break;
245 	case fp_normal:
246 		__fp_rightshift(pu, 11);
247 		pu->exponent += DOUBLE_BIAS;
248 		if (pu->exponent <= 0) {	/* underflow */
249 			__fp_rightshift(pu, 1 - pu->exponent);
250 			round(pu, 2, rd, &e);
251 			if (pu->significand[0] == 0x100000) {
252 				/* rounded back up to normal */
253 				kluge.f.msw.exponent = 1;
254 				kluge.f.msw.significand = 0;
255 				kluge.f.significand2 = 0;
256 				e |= (1 << fp_underflow);
257 				goto ret;
258 			}
259 			if (e & (1 << fp_inexact))
260 				e |= (1 << fp_underflow);
261 			kluge.f.msw.exponent = 0;
262 			kluge.f.msw.significand = 0xfffff & pu->significand[0];
263 			kluge.f.significand2 = pu->significand[1];
264 			goto ret;
265 		}
266 		round(pu, 2, rd, &e);
267 		if (pu->significand[0] == 0x200000) {	/* rounding overflow */
268 			pu->significand[0] = 0x100000;
269 			pu->exponent += 1;
270 		}
271 		if (pu->exponent >= 0x7ff) {	/* overflow */
272 			e |= (1 << fp_overflow) | (1 << fp_inexact);
273 			if (overflow_to_infinity(pu->sign, rd))
274 				goto infinity;
275 			kluge.f.msw.exponent = 0x7fe;
276 			kluge.f.msw.significand = 0xfffff;
277 			kluge.f.significand2 = 0xffffffff;
278 			goto ret;
279 		}
280 		kluge.f.msw.exponent = pu->exponent;
281 		kluge.f.msw.significand = 0xfffff & pu->significand[0];
282 		kluge.f.significand2 = pu->significand[1];
283 		break;
284 	}
285 ret:
286 	*px = kluge.x;
287 	*ex = (fp_exception_field_type)e;
288 }
289 
290 void
291 __pack_extended(unpacked *pu, extended *px, enum fp_direction_type rd,
292 	fp_exception_field_type *ex)
293 {
294 	extended_equivalence kluge;
295 	int		e;
296 
297 	e = 0;
298 	kluge.f.msw.sign = pu->sign;
299 	switch (pu->fpclass) {
300 	case fp_zero:
301 		kluge.f.msw.exponent = 0;
302 		kluge.f.significand = 0;
303 		kluge.f.significand2 = 0;
304 		break;
305 	case fp_infinity:
306 infinity:
307 		kluge.f.msw.exponent = 0x7fff;
308 		kluge.f.significand = 0x80000000;
309 		kluge.f.significand2 = 0;
310 		break;
311 	case fp_quiet:
312 		kluge.f.msw.exponent = 0x7fff;
313 		kluge.f.significand = 0x40000000 | pu->significand[0];
314 		kluge.f.significand2 = pu->significand[1];
315 		break;
316 	case fp_normal:
317 		pu->exponent += EXTENDED_BIAS;
318 		if (pu->exponent <= 0) {	/* underflow */
319 			__fp_rightshift(pu, 1 - pu->exponent);
320 			round(pu, 2, rd, &e);
321 			if (pu->significand[0] == 0x80000000u) {
322 				/* rounded back up to normal */
323 				kluge.f.msw.exponent = 1;
324 				kluge.f.significand = 0x80000000u;
325 				kluge.f.significand2 = 0;
326 				e |= (1 << fp_underflow);
327 				goto ret;
328 			}
329 			if (e & (1 << fp_inexact))
330 				e |= (1 << fp_underflow);
331 			kluge.f.msw.exponent = 0;
332 			kluge.f.significand = pu->significand[0];
333 			kluge.f.significand2 = pu->significand[1];
334 			goto ret;
335 		}
336 		round(pu, 2, rd, &e);
337 		if (pu->exponent >= 0x7fff) {	/* overflow */
338 			e |= (1 << fp_overflow) | (1 << fp_inexact);
339 			if (overflow_to_infinity(pu->sign, rd))
340 				goto infinity;
341 			kluge.f.msw.exponent = 0x7ffe;
342 			kluge.f.significand = 0xffffffff;
343 			kluge.f.significand2 = 0xffffffff;
344 			goto ret;
345 		}
346 		kluge.f.msw.exponent = pu->exponent;
347 		kluge.f.significand = pu->significand[0];
348 		kluge.f.significand2 = pu->significand[1];
349 		break;
350 	}
351 ret:
352 	(*px)[0] = kluge.x[0];
353 	(*px)[1] = kluge.x[1];
354 	(*px)[2] = kluge.x[2];
355 	*ex = (fp_exception_field_type)e;
356 }
357 
358 void
359 __pack_quadruple(unpacked *pu, quadruple *px, enum fp_direction_type rd,
360 	fp_exception_field_type *ex)
361 {
362 	quadruple_equivalence kluge;
363 	int		e;
364 
365 	e = 0;
366 	kluge.f.msw.sign = pu->sign;
367 	switch (pu->fpclass) {
368 	case fp_zero:
369 		kluge.f.msw.exponent = 0;
370 		kluge.f.msw.significand = 0;
371 		kluge.f.significand2 = 0;
372 		kluge.f.significand3 = 0;
373 		kluge.f.significand4 = 0;
374 		break;
375 	case fp_infinity:
376 infinity:
377 		kluge.f.msw.exponent = 0x7fff;
378 		kluge.f.msw.significand = 0;
379 		kluge.f.significand2 = 0;
380 		kluge.f.significand3 = 0;
381 		kluge.f.significand4 = 0;
382 		break;
383 	case fp_quiet:
384 		kluge.f.msw.exponent = 0x7fff;
385 		__fp_rightshift(pu, 15);
386 		kluge.f.msw.significand = 0x8000 |
387 		    (0xffff & pu->significand[0]);
388 		kluge.f.significand2 = pu->significand[1];
389 		kluge.f.significand3 = pu->significand[2];
390 		kluge.f.significand4 = pu->significand[3];
391 		break;
392 	case fp_normal:
393 		__fp_rightshift(pu, 15);
394 		pu->exponent += QUAD_BIAS;
395 		if (pu->exponent <= 0) {	/* underflow */
396 			__fp_rightshift(pu, 1 - pu->exponent);
397 			round(pu, 4, rd, &e);
398 			if (pu->significand[0] == 0x10000) {
399 				/* rounded back up to normal */
400 				kluge.f.msw.exponent = 1;
401 				kluge.f.msw.significand = 0;
402 				kluge.f.significand2 = 0;
403 				kluge.f.significand3 = 0;
404 				kluge.f.significand4 = 0;
405 				e |= (1 << fp_underflow);
406 				goto ret;
407 			}
408 			if (e & (1 << fp_inexact))
409 				e |= (1 << fp_underflow);
410 			kluge.f.msw.exponent = 0;
411 			kluge.f.msw.significand = 0xffff & pu->significand[0];
412 			kluge.f.significand2 = pu->significand[1];
413 			kluge.f.significand3 = pu->significand[2];
414 			kluge.f.significand4 = pu->significand[3];
415 			goto ret;
416 		}
417 		round(pu, 4, rd, &e);
418 		if (pu->significand[0] == 0x20000) {	/* rounding overflow */
419 			pu->significand[0] = 0x10000;
420 			pu->exponent += 1;
421 		}
422 		if (pu->exponent >= 0x7fff) {	/* overflow */
423 			e |= (1 << fp_overflow) | (1 << fp_inexact);
424 			if (overflow_to_infinity(pu->sign, rd))
425 				goto infinity;
426 			kluge.f.msw.exponent = 0x7ffe;
427 			kluge.f.msw.significand = 0xffff;
428 			kluge.f.significand2 = 0xffffffff;
429 			kluge.f.significand3 = 0xffffffff;
430 			kluge.f.significand4 = 0xffffffff;
431 			goto ret;
432 		}
433 		kluge.f.msw.exponent = pu->exponent;
434 		kluge.f.msw.significand = pu->significand[0] & 0xffff;
435 		kluge.f.significand2 = pu->significand[1];
436 		kluge.f.significand3 = pu->significand[2];
437 		kluge.f.significand4 = pu->significand[3];
438 		break;
439 	}
440 ret:
441 	*px = kluge.x;
442 	*ex = (fp_exception_field_type)e;
443 }
444