xref: /titanic_51/usr/src/lib/libbc/libc/gen/common/_Qfpack.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
23 
24 /*
25  * Copyright (c) 1988 by Sun Microsystems, Inc.
26  */
27 
28 /* Pack procedures for Sparc FPU simulator. */
29 
30 #include "_Qquad.h"
31 #include "_Qglobals.h"
32 
33 PRIVATE int
34 overflow_to_infinity(sign)
35 	int             sign;
36 
37 /* Returns 1 if overflow should go to infinity, 0 if to max finite. */
38 
39 {
40 	int             inf;
41 
42 	switch (fp_direction) {
43 	case fp_nearest:
44 		inf = 1;
45 		break;
46 	case fp_tozero:
47 		inf = 0;
48 		break;
49 	case fp_positive:
50 		inf = !sign;
51 		break;
52 	case fp_negative:
53 		inf = sign;
54 		break;
55 	}
56 	return (inf);
57 }
58 
59 PRIVATE void
60 round(pu)
61 	unpacked       *pu;
62 
63 /* Round according to current rounding mode.	 */
64 
65 {
66 	int             increment;	/* boolean to indicate round up */
67 	int sr;
68 	sr = pu->sticky|pu->rounded;
69 
70 	if (sr == 0)
71 		return;
72 	fpu_set_exception(fp_inexact);
73 	switch (fp_direction) {
74 	case fp_nearest:
75 		increment = pu->rounded;
76 		break;
77 	case fp_tozero:
78 		increment = 0;
79 		break;
80 	case fp_positive:
81 		increment = (pu->sign == 0) & (sr != 0);
82 		break;
83 	case fp_negative:
84 		increment = (pu->sign != 0) & (sr != 0);
85 		break;
86 	}
87 	if (increment) {
88 	    pu->significand[3]++;
89 	    if (pu->significand[3] == 0) {
90 		pu->significand[2]++;
91 		if (pu->significand[2] == 0) {
92 		    pu->significand[1]++;
93 		    if (pu->significand[1] == 0) {
94 			pu->significand[0]++;	/* rounding carried out */
95 			if( pu->significand[0] == 0x20000) {
96 			    pu->exponent++;
97 			    pu->significand[0] = 0x10000;
98 			}
99 		    }
100 		}
101 	    }
102 	}
103 	if ((fp_direction == fp_nearest) &&
104 		(pu->sticky == 0) && increment!=0) {	/* ambiguous case */
105 		pu->significand[3] &= 0xfffffffe;	/* force round to even */
106 	}
107 }
108 
109 PRIVATE void
110 packinteger(pu, px)
111 	unpacked       *pu;	/* unpacked result */
112 	int            *px;	/* packed integer */
113 {
114 	switch (pu->fpclass) {
115 	case fp_zero:
116 		*px = 0;
117 		break;
118 	case fp_normal:
119 		if (pu->exponent >= 32)
120 			goto overflow;
121 		fpu_rightshift(pu, 112 - pu->exponent);
122 		round(pu);
123 		if (pu->significand[3] >= 0x80000000)
124 			if ((pu->sign == 0)||(pu->significand[3] > 0x80000000))
125 				goto overflow;
126 		*px = pu->significand[3];
127 		if (pu->sign)
128 			*px = -*px;
129 		break;
130 	case fp_infinity:
131 	case fp_quiet:
132 	case fp_signaling:
133 overflow:
134 		if (pu->sign)
135 			*px = 0x80000000;
136 		else
137 			*px = 0x7fffffff;
138 		_fp_current_exceptions &= ~(1 << (int) fp_inexact);
139 		fpu_set_exception(fp_invalid);
140 		break;
141 	}
142 }
143 
144 PRIVATE void
145 packsingle(pu, px)
146 	unpacked       *pu;	/* unpacked result */
147 	single_type    *px;	/* packed single */
148 {
149 	px->sign = pu->sign;
150 	switch (pu->fpclass) {
151 	case fp_zero:
152 		px->exponent = 0;
153 		px->significand = 0;
154 		break;
155 	case fp_infinity:
156 infinity:
157 		px->exponent = 0xff;
158 		px->significand = 0;
159 		break;
160 	case fp_quiet:
161 	case fp_signaling:
162 		fpu_rightshift(pu, 113-24);
163 		px->exponent = 0xff;
164 		px->significand = 0x400000|(0x3fffff&pu->significand[3]);
165 		break;
166 	case fp_normal:
167 		fpu_rightshift(pu, 113-24);
168 		pu->exponent += SINGLE_BIAS;
169 		if (pu->exponent <= 0) {
170 			px->exponent = 0;
171 			fpu_rightshift(pu, 1 - pu->exponent);
172 			round(pu);
173 			if (pu->significand[3] == 0x800000) {	/* rounded
174 								 * back up to
175 								 * normal */
176 				px->exponent = 1;
177 				px->significand = 0;
178 				return;
179 			}
180 			if (_fp_current_exceptions & (1 << fp_inexact))
181 				fpu_set_exception(fp_underflow);
182 			px->significand = 0x7fffff & pu->significand[3];
183 			return;
184 		}
185 		round(pu);
186 		if (pu->significand[3] == 0x1000000) {	/* rounding overflow */
187 			pu->significand[3] = 0x800000;
188 			pu->exponent += 1;
189 		}
190 		if (pu->exponent >= 0xff) {
191 			fpu_set_exception(fp_overflow);
192 			fpu_set_exception(fp_inexact);
193 			if (overflow_to_infinity(pu->sign))
194 				goto infinity;
195 			px->exponent = 0xfe;
196 			px->significand = 0x7fffff;
197 			return;
198 		}
199 		px->exponent = pu->exponent;
200 		px->significand = 0x7fffff & pu->significand[3];
201 	}
202 }
203 
204 PRIVATE void
205 packdouble(pu, px, py)
206 	unpacked       *pu;	/* unpacked result */
207 	double_type    *px;	/* packed double */
208 	unsigned       *py;
209 {
210 	px->sign = pu->sign;
211 	switch (pu->fpclass) {
212 	case fp_zero:
213 		px->exponent = 0;
214 		px->significand = 0;
215 		*py = 0;
216 		break;
217 	case fp_infinity:
218 infinity:
219 		px->exponent = 0x7ff;
220 		px->significand = 0;
221 		*py = 0;
222 		break;
223 	case fp_quiet:
224 	case fp_signaling:
225 		fpu_rightshift(pu, 113-53);
226 		px->exponent = 0x7ff;
227 		px->significand = 0x80000 | (0x7ffff & pu->significand[2]);
228 		*py = pu->significand[3];
229 		break;
230 	case fp_normal:
231 		fpu_rightshift(pu, 113-53);
232 		pu->exponent += DOUBLE_BIAS;
233 		if (pu->exponent <= 0) {	/* underflow */
234 			px->exponent = 0;
235 			fpu_rightshift(pu, 1 - pu->exponent);
236 			round(pu);
237 			if (pu->significand[2] == 0x100000) {	/* rounded
238 								 * back up to
239 								 * normal */
240 				px->exponent = 1;
241 				px->significand = 0;
242 				*py = 0;
243 				return;
244 			}
245 			if (_fp_current_exceptions & (1 << fp_inexact))
246 				fpu_set_exception(fp_underflow);
247 			px->exponent = 0;
248 			px->significand = 0xfffff & pu->significand[2];
249 			*py = pu->significand[3];
250 			return;
251 		}
252 		round(pu);
253 		if (pu->significand[2] == 0x200000) {	/* rounding overflow */
254 			pu->significand[2] = 0x100000;
255 			pu->exponent += 1;
256 		}
257 		if (pu->exponent >= 0x7ff) {	/* overflow */
258 			fpu_set_exception(fp_overflow);
259 			fpu_set_exception(fp_inexact);
260 			if (overflow_to_infinity(pu->sign))
261 				goto infinity;
262 			px->exponent = 0x7fe;
263 			px->significand = 0xfffff;
264 			*py = 0xffffffff;
265 			return;
266 		}
267 		px->exponent = pu->exponent;
268 		px->significand = 0xfffff & pu->significand[2];
269 		*py = pu->significand[3];
270 		break;
271 	}
272 }
273 
274 PRIVATE void
275 packextended(pu, px, py, pz, pw)
276 	unpacked       *pu;	/* unpacked result */
277 	extended_type  *px;	/* packed extended */
278 	unsigned       *py, *pz, *pw;
279 {
280 	px->sign = pu->sign;
281 	switch (pu->fpclass) {
282 	case fp_zero:
283 		px->exponent = 0;
284 		px->significand = 0;
285 		*pz = 0;
286 		*py = 0;
287 		*pw = 0;
288 		break;
289 	case fp_infinity:
290 infinity:
291 		px->exponent = 0x7fff;
292 		px->significand = 0;
293 		*pz = 0;
294 		*py = 0;
295 		*pw = 0;
296 		break;
297 	case fp_quiet:
298 	case fp_signaling:
299 		px->exponent = 0x7fff;
300 		px->significand = 0x8000 | pu->significand[0];	/* Insure quiet
301 								 * nan. */
302 		*py = pu->significand[1];
303 		*pz = pu->significand[2];
304 		*pw = pu->significand[3];
305 		break;
306 	case fp_normal:
307 		pu->exponent += EXTENDED_BIAS;
308 		if (pu->exponent <= 0) {	/* underflow */
309 			fpu_rightshift(pu, 1-pu->exponent);
310 			round(pu);
311 			if (pu->significand[0] < 0x00010000) {	/* not rounded
312 								 * back up
313 								 * to normal */
314 				if (_fp_current_exceptions & (1 << fp_inexact))
315 					fpu_set_exception(fp_underflow);
316 				px->exponent = 0;
317 			} else
318 				px->exponent = 1;
319 			px->significand = pu->significand[0];
320 			*py = pu->significand[1];
321 			*pz = pu->significand[2];
322 			*pw = pu->significand[3];
323 			return;
324 		}
325 		round(pu);	/* rounding overflow handled in round() */
326 		if (pu->exponent >= 0x7fff) {	/* overflow */
327 			fpu_set_exception(fp_overflow);
328 			fpu_set_exception(fp_inexact);
329 			if (overflow_to_infinity(pu->sign))
330 				goto infinity;
331 			px->exponent = 0x7ffe;	/* overflow to max norm */
332 			px->significand = 0xffff;
333 			*py = 0xffffffff;
334 			*pz = 0xffffffff;
335 			*pw = 0xffffffff;
336 			return;
337 		}
338 		px->exponent = pu->exponent;
339 		px->significand = pu->significand[0];
340 		*py = pu->significand[1];
341 		*pz = pu->significand[2];
342 		*pw = pu->significand[3];
343 		break;
344 	}
345 }
346 
347 void
348 _fp_pack(pu, n, type)
349 	unpacked       *pu;	/* unpacked operand */
350 	int 		*n;	/* output result's address */
351 	enum fp_op_type type;	/* type of datum */
352 
353 {
354 	switch (type) {
355 	case fp_op_integer:
356 		{
357 			packinteger(pu, n);
358 			break;
359 		}
360 	case fp_op_single:
361 		{
362 			single_type     x;
363 			packsingle(pu, &x);
364 			n[0] = *(int*)&x;
365 			break;
366 		}
367 	case fp_op_double:
368 		{
369 			double_type     x;
370 			double		t=1.0;
371 			int		i0,i1;
372 			if((*(int*)&t)!=0) {i0=0;i1=1;} else {i0=1;i1=0;}
373 			packdouble(pu, &x,&n[i1]);
374 			n[i0] = *(int*)&x;
375 			break;
376 		}
377 	case fp_op_extended:
378 		{
379 			extended_type   x;
380 			unsigned        y, z, w;
381 			unpacked        u;
382 			int		k;
383 			switch (fp_precision) {	/* Implement extended
384 						 * rounding precision mode. */
385 			case fp_single:
386 				{
387 					single_type     tx;
388 					packsingle(pu, &tx);
389 					pu = &u;
390 					unpacksingle(pu, tx);
391 					break;
392 				}
393 			case fp_double:
394 				{
395 					double_type     tx;
396 					unsigned        ty;
397 					packdouble(pu, &tx, &ty);
398 					pu = &u;
399 					unpackdouble(pu, tx, ty);
400 					break;
401 				}
402 			case fp_precision_3:	/* rounded to 64 bits */
403 				{
404 					k = pu->exponent+ EXTENDED_BIAS;
405 					if(k>=0) k = 113-64;
406 					else     k = 113-64-k;
407 					fpu_rightshift(pu,113-64);
408 					round(pu);
409 					pu->sticky=pu->rounded=0;
410 					pu->exponent += k;
411 					fpu_normalize(pu);
412 					break;
413 				}
414 			}
415 			{
416 			int		i0,i1,i2,i3;
417 			double t = 1.0;
418 			if((*(int*)&t)!=0) {i0=0;i1=1;i2=2;i3=3;}
419 			else {i0=3;i1=2;i2=1;i3=0;}
420 			packextended(pu, &x, &n[i1], &n[i2], &n[i3]);
421 			n[i0] = *(int*)&x;
422 			}
423 
424 			break;
425 		}
426 	}
427 }
428 
429