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