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
32static 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
74static int
75overflow_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
99static void
100round(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
153void
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:
168infinity:
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	}
212ret:
213	*px = kluge.x;
214	*ex = (fp_exception_field_type)e;
215}
216
217void
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:
233infinity:
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	}
285ret:
286	*px = kluge.x;
287	*ex = (fp_exception_field_type)e;
288}
289
290void
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:
306infinity:
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	}
351ret:
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
358void
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:
376infinity:
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	}
440ret:
441	*px = kluge.x;
442	*ex = (fp_exception_field_type)e;
443}
444