xref: /titanic_51/usr/src/lib/libnsl/rpc/xdr_float.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  * Copyright 1998 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
27 /*
28  * Portions of this source code were derived from Berkeley
29  * 4.3 BSD under license from the Regents of the University of
30  * California.
31  */
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 
35 /*
36  * xdr_float.c, Generic XDR routines impelmentation.
37  *
38  * These are the "floating point" xdr routines used to (de)serialize
39  * most common data items.  See xdr.h for more info on the interface to
40  * xdr.
41  */
42 
43 #include <sys/types.h>
44 #include <rpc/trace.h>
45 #ifdef _KERNEL
46 #include <sys/param.h>
47 #else
48 #include <stdio.h>
49 #endif
50 
51 #include <rpc/types.h>
52 #include <rpc/xdr.h>
53 
54 /*
55  * This routine works on Suns, 3b2, 68000s, 386 and Vaxen in a manner
56  * which is very efficient as bit twiddling is all that is needed.  All
57  * other machines can use this code but the code is inefficient as
58  * various mathematical operations are used to generate the ieee format.
59  * In addition rounding errors may occur due to the calculations involved.
60  * To be most efficient, new machines should have their own ifdefs.
61  * The encoding routines will fail if the machines try to encode a
62  * float/double whose value can not be represented by the ieee format,
63  * e.g. the exponent is too big/small.
64  *	ieee largest  float  = (2 ^ 128)  * 0x1.fffff
65  *	ieee smallest float  = (2 ^ -127) * 0x1.00000
66  *	ieee largest  double = (2 ^ 1024)  * 0x1.fffff
67  *	ieee smallest double = (2 ^ -1023) * 0x1.00000
68  * The decoding routines assumes that the receiving machine can handle
69  * floats/doubles as large/small as the values stated above.  If you
70  * use a machine which can not represent these values, you will need
71  * to put ifdefs in the decode sections to identify areas of failure.
72  */
73 
74 #if defined(vax)
75 
76 /*
77  * What IEEE single precision floating point looks like this on a
78  * vax.
79  */
80 
81 struct	ieee_single {
82 	unsigned int	mantissa: 23;
83 	unsigned int	exp	: 8;
84 	unsigned int	sign    : 1;
85 };
86 
87 #define	IEEE_SNG_BIAS	0x7f
88 #define	VAX_SNG_BIAS    0x81
89 
90 
91 /* Vax single precision floating point */
92 struct	vax_single {
93 	unsigned int	mantissa1 : 7;
94 	unsigned int	exp	: 8;
95 	unsigned int	sign	: 1;
96 	unsigned int	mantissa2 : 16;
97 };
98 
99 #define	VAX_SNG_BIAS	0x81
100 
101 static struct sgl_limits {
102 	struct vax_single s;
103 	struct ieee_single ieee;
104 } sgl_limits[2] = {
105 	{{ 0x7f, 0xff, 0x0, 0xffff },	/* Max Vax */
106 	{ 0x0, 0xff, 0x0 }},		/* Max IEEE */
107 	{{ 0x0, 0x0, 0x0, 0x0 },	/* Min Vax */
108 	{ 0x0, 0x0, 0x0 }}		/* Min IEEE */
109 };
110 #endif /* vax */
111 
112 bool_t
113 xdr_float(XDR *xdrs, float *fp)
114 {
115 	bool_t dummy;
116 #if defined(vax)
117 	struct ieee_single is;
118 	struct vax_single vs, *vsp;
119 	struct sgl_limits *lim;
120 	size_t i;
121 #endif
122 
123 	trace1(TR_xdr_float, 0);
124 	switch (xdrs->x_op) {
125 
126 	case XDR_ENCODE:
127 #if defined(mc68000) || defined(sparc) || defined(u3b2) || \
128 	defined(u3b15) || defined(i386)
129 		dummy = XDR_PUTINT32(xdrs, (int *)fp);
130 		trace1(TR_xdr_float, 1);
131 		return (dummy);
132 #else
133 #if defined(vax)
134 		vs = *((struct vax_single *)fp);
135 		if ((vs.exp == 1) || (vs.exp == 2)) {
136 			/* map these to subnormals */
137 			is.exp = 0;
138 			is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
139 			/* lose some precision */
140 			is.mantissa >>= 3 - vs.exp;
141 			is.mantissa += (1 << (20 + vs.exp));
142 			goto shipit;
143 		}
144 		for (i = 0, lim = sgl_limits;
145 			i < (int)(sizeof (sgl_limits) /
146 					sizeof (struct sgl_limits));
147 			i++, lim++) {
148 			if ((vs.mantissa2 == lim->s.mantissa2) &&
149 				(vs.exp == lim->s.exp) &&
150 				(vs.mantissa1 == lim->s.mantissa1)) {
151 				is = lim->ieee;
152 				goto shipit;
153 			}
154 		}
155 		is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS;
156 		is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
157 	shipit:
158 		is.sign = vs.sign;
159 		dummy = XDR_PUTINT32(xdrs, (int32_t *)&is);
160 		trace1(TR_xdr_float, 1);
161 		return (dummy);
162 #else
163 		{
164 		/*
165 		 * Every machine can do this, its just not very efficient.
166 		 * In addtion, some rounding errors may occur do to the
167 		 * calculations involved.
168 		 */
169 		float f;
170 		int neg = 0;
171 		int exp = 0;
172 		int32_t val;
173 
174 		f = *fp;
175 		if (f == 0) {
176 			val = 0;
177 			dummy = XDR_PUTINT32(xdrs, &val);
178 			trace1(TR_xdr_float, 1);
179 			return (dummy);
180 		}
181 		if (f < 0) {
182 			f = 0 - f;
183 			neg = 1;
184 		}
185 		while (f < 1) {
186 			f = f * 2;
187 			--exp;
188 		}
189 		while (f >= 2) {
190 			f = f/2;
191 			++exp;
192 		}
193 		if ((exp > 128) || (exp < -127)) {
194 			/* over or under flowing ieee exponent */
195 			trace1(TR_xdr_float, 1);
196 			return (FALSE);
197 		}
198 		val = neg;
199 		val = val << 8;		/* for the exponent */
200 		val += 127 + exp;	/* 127 is the bias */
201 		val = val << 23;	/* for the mantissa */
202 		val += (int32_t)((f - 1) * 8388608);	/* 2 ^ 23 */
203 		dummy = XDR_PUTINT32(xdrs, &val);
204 		trace1(TR_xdr_float, 1);
205 		return (dummy);
206 		}
207 #endif
208 #endif
209 
210 	case XDR_DECODE:
211 #if defined(mc68000) || defined(sparc) || defined(u3b2) || \
212 	defined(u3b15) || defined(i386)
213 		dummy = XDR_GETINT32(xdrs, (int *)fp);
214 		trace1(TR_xdr_float, 1);
215 		return (dummy);
216 #else
217 #if defined(vax)
218 		vsp = (struct vax_single *)fp;
219 		if (!XDR_GETINT32(xdrs, (int32_t *)&is)) {
220 			trace1(TR_xdr_float, 1);
221 			return (FALSE);
222 		}
223 
224 		for (i = 0, lim = sgl_limits;
225 			i < (int)(sizeof (sgl_limits) /
226 					sizeof (struct sgl_limits));
227 			i++, lim++) {
228 			if ((is.exp == lim->ieee.exp) &&
229 				(is.mantissa == lim->ieee.mantissa)) {
230 				*vsp = lim->s;
231 				goto doneit;
232 			} else if ((is.exp == 0) && (lim->ieee.exp == 0)) {
233 			    /* Special Case */
234 			    unsigned tmp = is.mantissa >> 20;
235 			    if (tmp >= 4) {
236 			    vsp->exp = 2;
237 			    } else if (tmp >= 2) {
238 			    vsp->exp = 1;
239 			    } else {
240 				*vsp = min.s;
241 				break;
242 			    }	/* else */
243 			    tmp = is.mantissa - (1 << (20 + vsp->exp));
244 			    tmp <<= 3 - vsp->exp;
245 			    vsp->mantissa2 = tmp;
246 			    vsp->mantissa1 = (tmp >> 16);
247 			    goto doneit;
248 		    }
249 		vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS;
250 		vsp->mantissa2 = is.mantissa;
251 		vsp->mantissa1 = (is.mantissa >> 16);
252 	doneit:
253 		vsp->sign = is.sign;
254 		trace1(TR_xdr_float, 1);
255 		return (TRUE);
256 #else
257 		{
258 		/*
259 		 * Every machine can do this, its just not very
260 		 * efficient.  It assumes that the decoding machine's
261 		 * float can represent any value in the range of
262 		 *	ieee largest  float  = (2 ^ 128)  * 0x1.fffff
263 		 *	to
264 		 *	ieee smallest float  = (2 ^ -127) * 0x1.00000
265 		 * In addtion, some rounding errors may occur do to the
266 		 * calculations involved.
267 		 */
268 		float f;
269 		int neg = 0;
270 		int exp = 0;
271 		int32_t val;
272 
273 		if (!XDR_GETINT32(xdrs, (int32_t *)&val)) {
274 			trace1(TR_xdr_float, 1);
275 			return (FALSE);
276 		}
277 		neg = val & 0x80000000;
278 		exp = (val & 0x7f800000) >> 23;
279 		exp -= 127;		/* subtract exponent base */
280 		f = (val & 0x007fffff) * 0.00000011920928955078125;
281 		/* 2 ^ -23 */
282 		f++;
283 		while (exp != 0) {
284 			if (exp < 0) {
285 				f = f/2.0;
286 				++exp;
287 			} else {
288 				f = f * 2.0;
289 				--exp;
290 			}
291 		}
292 		if (neg)
293 			f = 0 - f;
294 		*fp = f;
295 		}
296 #endif
297 #endif
298 
299 	case XDR_FREE:
300 		trace1(TR_xdr_float, 1);
301 		return (TRUE);
302 	}
303 	trace1(TR_xdr_float, 1);
304 	return (FALSE);
305 }
306 
307 /*
308  * This routine works on Suns (Sky / 68000's) and Vaxen.
309  */
310 
311 #if defined(vax)
312 /* What IEEE double precision floating point looks like on a Vax */
313 struct	ieee_double {
314 	unsigned int	mantissa1 : 20;
315 	unsigned int	exp	  : 11;
316 	unsigned int	sign	  : 1;
317 	unsigned int	mantissa2 : 32;
318 };
319 
320 /* Vax double precision floating point */
321 struct  vax_double {
322 	unsigned int	mantissa1 : 7;
323 	unsigned int	exp	  : 8;
324 	unsigned int	sign	  : 1;
325 	unsigned int	mantissa2 : 16;
326 	unsigned int	mantissa3 : 16;
327 	unsigned int	mantissa4 : 16;
328 };
329 
330 #define	VAX_DBL_BIAS	0x81
331 #define	IEEE_DBL_BIAS	0x3ff
332 #define	MASK(nbits)	((1 << nbits) - 1)
333 
334 static struct dbl_limits {
335 	struct	vax_double d;
336 	struct	ieee_double ieee;
337 } dbl_limits[2] = {
338 	{{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff },	/* Max Vax */
339 	{ 0x0, 0x7ff, 0x0, 0x0 }},			/* Max IEEE */
340 	{{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},		/* Min Vax */
341 	{ 0x0, 0x0, 0x0, 0x0 }}				/* Min IEEE */
342 };
343 
344 #endif /* vax */
345 
346 
347 bool_t
348 xdr_double(XDR *xdrs, double *dp)
349 {
350 	bool_t dummy;
351 	register int *lp;
352 #if defined(vax)
353 	struct	ieee_double id;
354 	struct	vax_double vd;
355 	register struct dbl_limits *lim;
356 	size_t i;
357 #endif
358 
359 	trace1(TR_xdr_double, 0);
360 	switch (xdrs->x_op) {
361 
362 	case XDR_ENCODE:
363 #if defined(mc68000) || defined(u3b2) || defined(u3b15) || \
364 	defined(_LONG_LONG_HTOL)
365 		lp = (int *)dp;
366 		dummy = XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp);
367 		trace1(TR_xdr_double, 1);
368 		return (dummy);
369 #else
370 #if defined(_LONG_LONG_LTOH)
371 		lp = (int *)dp;
372 		lp++;
373 		dummy = XDR_PUTINT32(xdrs, lp--) && XDR_PUTINT32(xdrs, lp);
374 		trace1(TR_xdr_double, 1);
375 		return (dummy);
376 #else
377 #if defined(vax)
378 		vd = *((struct vax_double *)dp);
379 		for (i = 0, lim = dbl_limits;
380 			i < (int)(sizeof (dbl_limits) /
381 					sizeof (struct dbl_limits));
382 			i++, lim++) {
383 			if ((vd.mantissa4 == lim->d.mantissa4) &&
384 				(vd.mantissa3 == lim->d.mantissa3) &&
385 				(vd.mantissa2 == lim->d.mantissa2) &&
386 				(vd.mantissa1 == lim->d.mantissa1) &&
387 				(vd.exp == lim->d.exp)) {
388 				id = lim->ieee;
389 				goto shipit;
390 			}
391 		}
392 		id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS;
393 		id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3);
394 		id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) |
395 				(vd.mantissa3 << 13) |
396 				((vd.mantissa4 >> 3) & MASK(13));
397 	shipit:
398 		id.sign = vd.sign;
399 		lp = (int32_t *)&id;
400 #else
401 		{
402 		/*
403 		 * Every machine can do this, its just not very efficient.
404 		 * In addtion, some rounding errors may occur do to the
405 		 * calculations involved.
406 		 */
407 		double d;
408 		int neg = 0;
409 		int exp = 0;
410 		int32_t val[2];
411 
412 		d = *dp;
413 		if (d == 0) {
414 			val[0] = 0;
415 			val[1] = 0;
416 			lp = val;
417 			dummy = XDR_PUTINT32(xdrs, lp++) &&
418 				XDR_PUTINT32(xdrs, lp);
419 			trace1(TR_xdr_double, 1);
420 			return (dummy);
421 		}
422 		if (d < 0) {
423 			d = 0 - d;
424 			neg = 1;
425 		}
426 		while (d < 1) {
427 			d = d * 2;
428 			--exp;
429 		}
430 		while (d >= 2) {
431 			d = d/2;
432 			++exp;
433 		}
434 		if ((exp > 1024) || (exp < -1023)) {
435 			/* over or under flowing ieee exponent */
436 			trace1(TR_xdr_double, 1);
437 			return (FALSE);
438 		}
439 		val[0] = neg;
440 		val[0] = val[0] << 11;	/* for the exponent */
441 		val[0] += 1023 + exp;	/* 1023 is the bias */
442 		val[0] = val[0] << 20;	/* for the mantissa */
443 		val[0] += (int32_t)((d - 1) * 1048576);	/* 2 ^ 20 */
444 		val[1] += (int32_t)((((d - 1) * 1048576) - val[0])
445 							* 4294967296);
446 		/* 2 ^ 32 */
447 		lp = val;
448 		}
449 #endif
450 		dummy = XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp);
451 		trace1(TR_xdr_double, 1);
452 		return (dummy);
453 #endif
454 #endif
455 
456 	case XDR_DECODE:
457 #if defined(mc68000) || defined(u3b2) || defined(u3b15) || \
458 	defined(_LONG_LONG_HTOL)
459 		lp = (int *)dp;
460 		dummy = XDR_GETINT32(xdrs, lp++) && XDR_GETINT32(xdrs, lp);
461 		trace1(TR_xdr_double, 1);
462 		return (dummy);
463 #else
464 #if defined(_LONG_LONG_LTOH)
465 		lp = (int *)dp;
466 		lp++;
467 		dummy = XDR_GETINT32(xdrs, lp--) && XDR_GETINT32(xdrs, lp);
468 		trace1(TR_xdr_double, 1);
469 		return (dummy);
470 #else
471 #if defined(vax)
472 		lp = (int32_t *)&id;
473 		if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp)) {
474 			trace1(TR_xdr_double, 1);
475 			return (FALSE);
476 		}
477 		for (i = 0, lim = dbl_limits;
478 			i < sizeof (dbl_limits)/sizeof (struct dbl_limits);
479 			i++, lim++) {
480 			if ((id.mantissa2 == lim->ieee.mantissa2) &&
481 				(id.mantissa1 == lim->ieee.mantissa1) &&
482 				(id.exp == lim->ieee.exp)) {
483 				vd = lim->d;
484 				goto doneit;
485 			}
486 		}
487 		vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS;
488 		vd.mantissa1 = (id.mantissa1 >> 13);
489 		vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) |
490 				(id.mantissa2 >> 29);
491 		vd.mantissa3 = (id.mantissa2 >> 13);
492 		vd.mantissa4 = (id.mantissa2 << 3);
493 	doneit:
494 		vd.sign = id.sign;
495 		*dp = *((double *)&vd);
496 		trace1(TR_xdr_double, 1);
497 		return (TRUE);
498 #else
499 		{
500 		/*
501 		 * Every machine can do this, its just not very
502 		 * efficient.  It assumes that the decoding machine's
503 		 * double can represent any value in the range of
504 		 *	ieee largest  double  = (2 ^ 1024)  * 0x1.fffffffffffff
505 		 *	to
506 		 *	ieee smallest double  = (2 ^ -1023) * 0x1.0000000000000
507 		 * In addtion, some rounding errors may occur do to the
508 		 * calculations involved.
509 		 */
510 		double d;
511 		int neg = 0;
512 		int exp = 0;
513 		int32_t val[2];
514 
515 		lp = val;
516 		if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp)) {
517 			trace1(TR_xdr_double, 1);
518 			return (FALSE);
519 		}
520 		neg = val[0] & 0x80000000;
521 		exp = (val[0] & 0x7ff00000) >> 20;
522 		exp -= 1023;		/* subtract exponent base */
523 		d = (val[0] & 0x000fffff) * 0.00000095367431640625;
524 		/* 2 ^ -20 */
525 		d += (val[1] * 0.0000000000000002220446049250313);
526 		/* 2 ^ -52 */
527 		d++;
528 		while (exp != 0) {
529 			if (exp < 0) {
530 				d = d/2.0;
531 				++exp;
532 			} else {
533 				d = d * 2.0;
534 				--exp;
535 			}
536 		}
537 		if (neg)
538 			d = 0 - d;
539 		*dp = d;
540 		}
541 #endif
542 #endif
543 #endif
544 
545 	case XDR_FREE:
546 		trace1(TR_xdr_double, 1);
547 		return (TRUE);
548 	}
549 	trace1(TR_xdr_double, 1);
550 	return (FALSE);
551 }
552 
553 bool_t
554 xdr_quadruple(XDR *xdrs, long double *fp)
555 {
556 	bool_t dummy;
557 /*
558  * The Sparc uses IEEE FP encoding, so just do a byte copy
559  */
560 
561 	trace1(TR_xdr_quadruple, 0);
562 	switch (xdrs->x_op) {
563 	case XDR_ENCODE:
564 #if defined(sparc)
565 		dummy = XDR_PUTBYTES(xdrs, (char *)fp, sizeof (long double));
566 		trace1(TR_xdr_quadruple, 1);
567 		return (dummy);
568 #else
569 		trace1(TR_xdr_quadruple, 1);
570 		return (FALSE);
571 
572 #endif
573 	case XDR_DECODE:
574 #if defined(sparc)
575 		dummy = XDR_GETBYTES(xdrs, (char *)fp, sizeof (long double));
576 		trace1(TR_xdr_quadruple, 1);
577 		return (dummy);
578 #else
579 		trace1(TR_xdr_quadruple, 1);
580 		return (FALSE);
581 
582 #endif
583 	case XDR_FREE:
584 		trace1(TR_xdr_quadruple, 1);
585 		return (TRUE);
586 
587 	}
588 	trace1(TR_xdr_quadruple, 1);
589 	return (FALSE);
590 
591 }
592