xref: /openbsd-src/sys/arch/hppa/spmath/sfmpy.c (revision c2feb25228e11b3c285a2d9400475896f2dd1562)
1*c2feb252Smickey /*	$OpenBSD: sfmpy.c,v 1.5 2002/05/07 22:19:30 mickey Exp $	*/
2*c2feb252Smickey /*
3*c2feb252Smickey   (c) Copyright 1986 HEWLETT-PACKARD COMPANY
4*c2feb252Smickey   To anyone who acknowledges that this file is provided "AS IS"
5*c2feb252Smickey   without any express or implied warranty:
6*c2feb252Smickey       permission to use, copy, modify, and distribute this file
7*c2feb252Smickey   for any purpose is hereby granted without fee, provided that
8*c2feb252Smickey   the above copyright notice and this notice appears in all
9*c2feb252Smickey   copies, and that the name of Hewlett-Packard Company not be
10*c2feb252Smickey   used in advertising or publicity pertaining to distribution
11*c2feb252Smickey   of the software without specific, written prior permission.
12*c2feb252Smickey   Hewlett-Packard Company makes no representations about the
13*c2feb252Smickey   suitability of this software for any purpose.
14*c2feb252Smickey */
15*c2feb252Smickey /* @(#)sfmpy.c: Revision: 2.9.88.1 Date: 93/12/07 15:07:07 */
16b94afd46Smickey 
17*c2feb252Smickey #include "float.h"
18*c2feb252Smickey #include "sgl_float.h"
198a472b3eSmickey 
208a472b3eSmickey /*
218a472b3eSmickey  *  Single Precision Floating-point Multiply
228a472b3eSmickey  */
23b94afd46Smickey int
sgl_fmpy(srcptr1,srcptr2,dstptr,status)248a472b3eSmickey sgl_fmpy(srcptr1,srcptr2,dstptr,status)
258a472b3eSmickey 	sgl_floating_point *srcptr1, *srcptr2, *dstptr;
268a472b3eSmickey 	unsigned int *status;
278a472b3eSmickey {
288a472b3eSmickey 	register unsigned int opnd1, opnd2, opnd3, result;
298a472b3eSmickey 	register int dest_exponent, count;
30628bbdd4Smickey 	register int inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
31628bbdd4Smickey 	int is_tiny;
328a472b3eSmickey 
338a472b3eSmickey 	opnd1 = *srcptr1;
348a472b3eSmickey 	opnd2 = *srcptr2;
358a472b3eSmickey 	/*
368a472b3eSmickey 	 * set sign bit of result
378a472b3eSmickey 	 */
388a472b3eSmickey 	if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);
398a472b3eSmickey 	else Sgl_setzero(result);
408a472b3eSmickey 	/*
418a472b3eSmickey 	 * check first operand for NaN's or infinity
428a472b3eSmickey 	 */
438a472b3eSmickey 	if (Sgl_isinfinity_exponent(opnd1)) {
448a472b3eSmickey 		if (Sgl_iszero_mantissa(opnd1)) {
458a472b3eSmickey 			if (Sgl_isnotnan(opnd2)) {
468a472b3eSmickey 				if (Sgl_iszero_exponentmantissa(opnd2)) {
478a472b3eSmickey 					/*
488a472b3eSmickey 					 * invalid since operands are infinity
498a472b3eSmickey 					 * and zero
508a472b3eSmickey 					 */
518a472b3eSmickey 					if (Is_invalidtrap_enabled())
528a472b3eSmickey 						return(INVALIDEXCEPTION);
538a472b3eSmickey 					Set_invalidflag();
548a472b3eSmickey 					Sgl_makequietnan(result);
558a472b3eSmickey 					*dstptr = result;
568a472b3eSmickey 					return(NOEXCEPTION);
578a472b3eSmickey 				}
588a472b3eSmickey 				/*
598a472b3eSmickey 				 * return infinity
608a472b3eSmickey 				 */
618a472b3eSmickey 				Sgl_setinfinity_exponentmantissa(result);
628a472b3eSmickey 				*dstptr = result;
638a472b3eSmickey 				return(NOEXCEPTION);
648a472b3eSmickey 			}
658a472b3eSmickey 		}
668a472b3eSmickey 		else {
678a472b3eSmickey 			/*
688a472b3eSmickey 			 * is NaN; signaling or quiet?
698a472b3eSmickey 			 */
708a472b3eSmickey 			if (Sgl_isone_signaling(opnd1)) {
718a472b3eSmickey 				/* trap if INVALIDTRAP enabled */
728a472b3eSmickey 				if (Is_invalidtrap_enabled())
738a472b3eSmickey 					return(INVALIDEXCEPTION);
748a472b3eSmickey 				/* make NaN quiet */
758a472b3eSmickey 				Set_invalidflag();
768a472b3eSmickey 				Sgl_set_quiet(opnd1);
778a472b3eSmickey 			}
788a472b3eSmickey 			/*
798a472b3eSmickey 			 * is second operand a signaling NaN?
808a472b3eSmickey 			 */
818a472b3eSmickey 			else if (Sgl_is_signalingnan(opnd2)) {
828a472b3eSmickey 				/* trap if INVALIDTRAP enabled */
838a472b3eSmickey 				if (Is_invalidtrap_enabled())
848a472b3eSmickey 					return(INVALIDEXCEPTION);
858a472b3eSmickey 				/* make NaN quiet */
868a472b3eSmickey 				Set_invalidflag();
878a472b3eSmickey 				Sgl_set_quiet(opnd2);
888a472b3eSmickey 				*dstptr = opnd2;
898a472b3eSmickey 				return(NOEXCEPTION);
908a472b3eSmickey 			}
918a472b3eSmickey 			/*
928a472b3eSmickey 			 * return quiet NaN
938a472b3eSmickey 			 */
948a472b3eSmickey 			*dstptr = opnd1;
958a472b3eSmickey 			return(NOEXCEPTION);
968a472b3eSmickey 		}
978a472b3eSmickey 	}
988a472b3eSmickey 	/*
998a472b3eSmickey 	 * check second operand for NaN's or infinity
1008a472b3eSmickey 	 */
1018a472b3eSmickey 	if (Sgl_isinfinity_exponent(opnd2)) {
1028a472b3eSmickey 		if (Sgl_iszero_mantissa(opnd2)) {
1038a472b3eSmickey 			if (Sgl_iszero_exponentmantissa(opnd1)) {
1048a472b3eSmickey 				/* invalid since operands are zero & infinity */
1058a472b3eSmickey 				if (Is_invalidtrap_enabled())
1068a472b3eSmickey 					return(INVALIDEXCEPTION);
1078a472b3eSmickey 				Set_invalidflag();
1088a472b3eSmickey 				Sgl_makequietnan(opnd2);
1098a472b3eSmickey 				*dstptr = opnd2;
1108a472b3eSmickey 				return(NOEXCEPTION);
1118a472b3eSmickey 			}
1128a472b3eSmickey 			/*
1138a472b3eSmickey 			 * return infinity
1148a472b3eSmickey 			 */
1158a472b3eSmickey 			Sgl_setinfinity_exponentmantissa(result);
1168a472b3eSmickey 			*dstptr = result;
1178a472b3eSmickey 			return(NOEXCEPTION);
1188a472b3eSmickey 		}
1198a472b3eSmickey 		/*
1208a472b3eSmickey 		 * is NaN; signaling or quiet?
1218a472b3eSmickey 		 */
1228a472b3eSmickey 		if (Sgl_isone_signaling(opnd2)) {
1238a472b3eSmickey 			/* trap if INVALIDTRAP enabled */
1248a472b3eSmickey 			if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
1258a472b3eSmickey 
1268a472b3eSmickey 			/* make NaN quiet */
1278a472b3eSmickey 			Set_invalidflag();
1288a472b3eSmickey 			Sgl_set_quiet(opnd2);
1298a472b3eSmickey 		}
1308a472b3eSmickey 		/*
1318a472b3eSmickey 		 * return quiet NaN
1328a472b3eSmickey 		 */
1338a472b3eSmickey 		*dstptr = opnd2;
1348a472b3eSmickey 		return(NOEXCEPTION);
1358a472b3eSmickey 	}
1368a472b3eSmickey 	/*
1378a472b3eSmickey 	 * Generate exponent
1388a472b3eSmickey 	 */
1398a472b3eSmickey 	dest_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
1408a472b3eSmickey 
1418a472b3eSmickey 	/*
1428a472b3eSmickey 	 * Generate mantissa
1438a472b3eSmickey 	 */
1448a472b3eSmickey 	if (Sgl_isnotzero_exponent(opnd1)) {
1458a472b3eSmickey 		/* set hidden bit */
1468a472b3eSmickey 		Sgl_clear_signexponent_set_hidden(opnd1);
1478a472b3eSmickey 	}
1488a472b3eSmickey 	else {
1498a472b3eSmickey 		/* check for zero */
1508a472b3eSmickey 		if (Sgl_iszero_mantissa(opnd1)) {
1518a472b3eSmickey 			Sgl_setzero_exponentmantissa(result);
1528a472b3eSmickey 			*dstptr = result;
1538a472b3eSmickey 			return(NOEXCEPTION);
1548a472b3eSmickey 		}
1558a472b3eSmickey 		/* is denormalized, adjust exponent */
1568a472b3eSmickey 		Sgl_clear_signexponent(opnd1);
1578a472b3eSmickey 		Sgl_leftshiftby1(opnd1);
1588a472b3eSmickey 		Sgl_normalize(opnd1,dest_exponent);
1598a472b3eSmickey 	}
1608a472b3eSmickey 	/* opnd2 needs to have hidden bit set with msb in hidden bit */
1618a472b3eSmickey 	if (Sgl_isnotzero_exponent(opnd2)) {
1628a472b3eSmickey 		Sgl_clear_signexponent_set_hidden(opnd2);
1638a472b3eSmickey 	}
1648a472b3eSmickey 	else {
1658a472b3eSmickey 		/* check for zero */
1668a472b3eSmickey 		if (Sgl_iszero_mantissa(opnd2)) {
1678a472b3eSmickey 			Sgl_setzero_exponentmantissa(result);
1688a472b3eSmickey 			*dstptr = result;
1698a472b3eSmickey 			return(NOEXCEPTION);
1708a472b3eSmickey 		}
1718a472b3eSmickey 		/* is denormalized; want to normalize */
1728a472b3eSmickey 		Sgl_clear_signexponent(opnd2);
1738a472b3eSmickey 		Sgl_leftshiftby1(opnd2);
1748a472b3eSmickey 		Sgl_normalize(opnd2,dest_exponent);
1758a472b3eSmickey 	}
1768a472b3eSmickey 
1778a472b3eSmickey 	/* Multiply two source mantissas together */
1788a472b3eSmickey 
1798a472b3eSmickey 	Sgl_leftshiftby4(opnd2);     /* make room for guard bits */
1808a472b3eSmickey 	Sgl_setzero(opnd3);
1818a472b3eSmickey 	/*
1828a472b3eSmickey 	 * Four bits at a time are inspected in each loop, and a
1838a472b3eSmickey 	 * simple shift and add multiply algorithm is used.
1848a472b3eSmickey 	 */
1858a472b3eSmickey 	for (count=1;count<SGL_P;count+=4) {
1868a472b3eSmickey 		stickybit |= Slow4(opnd3);
1878a472b3eSmickey 		Sgl_rightshiftby4(opnd3);
1888a472b3eSmickey 		if (Sbit28(opnd1)) Sall(opnd3) += (Sall(opnd2) << 3);
1898a472b3eSmickey 		if (Sbit29(opnd1)) Sall(opnd3) += (Sall(opnd2) << 2);
1908a472b3eSmickey 		if (Sbit30(opnd1)) Sall(opnd3) += (Sall(opnd2) << 1);
1918a472b3eSmickey 		if (Sbit31(opnd1)) Sall(opnd3) += Sall(opnd2);
1928a472b3eSmickey 		Sgl_rightshiftby4(opnd1);
1938a472b3eSmickey 	}
1948a472b3eSmickey 	/* make sure result is left-justified */
1958a472b3eSmickey 	if (Sgl_iszero_sign(opnd3)) {
1968a472b3eSmickey 		Sgl_leftshiftby1(opnd3);
1978a472b3eSmickey 	}
1988a472b3eSmickey 	else {
1998a472b3eSmickey 		/* result mantissa >= 2. */
2008a472b3eSmickey 		dest_exponent++;
2018a472b3eSmickey 	}
2028a472b3eSmickey 	/* check for denormalized result */
2038a472b3eSmickey 	while (Sgl_iszero_sign(opnd3)) {
2048a472b3eSmickey 		Sgl_leftshiftby1(opnd3);
2058a472b3eSmickey 		dest_exponent--;
2068a472b3eSmickey 	}
2078a472b3eSmickey 	/*
2088a472b3eSmickey 	 * check for guard, sticky and inexact bits
2098a472b3eSmickey 	 */
2108a472b3eSmickey 	stickybit |= Sgl_all(opnd3) << (SGL_BITLENGTH - SGL_EXP_LENGTH + 1);
2118a472b3eSmickey 	guardbit = Sbit24(opnd3);
2128a472b3eSmickey 	inexact = guardbit | stickybit;
2138a472b3eSmickey 
2148a472b3eSmickey 	/* re-align mantissa */
2158a472b3eSmickey 	Sgl_rightshiftby8(opnd3);
2168a472b3eSmickey 
2178a472b3eSmickey 	/*
2188a472b3eSmickey 	 * round result
2198a472b3eSmickey 	 */
2208a472b3eSmickey 	if (inexact && (dest_exponent>0 || Is_underflowtrap_enabled())) {
2218a472b3eSmickey 		Sgl_clear_signexponent(opnd3);
2228a472b3eSmickey 		switch (Rounding_mode()) {
2238a472b3eSmickey 			case ROUNDPLUS:
2248a472b3eSmickey 				if (Sgl_iszero_sign(result))
2258a472b3eSmickey 					Sgl_increment(opnd3);
2268a472b3eSmickey 				break;
2278a472b3eSmickey 			case ROUNDMINUS:
2288a472b3eSmickey 				if (Sgl_isone_sign(result))
2298a472b3eSmickey 					Sgl_increment(opnd3);
2308a472b3eSmickey 				break;
2318a472b3eSmickey 			case ROUNDNEAREST:
232628bbdd4Smickey 				if (guardbit &&
233628bbdd4Smickey 				    (stickybit || Sgl_isone_lowmantissa(opnd3)))
2348a472b3eSmickey 					Sgl_increment(opnd3);
235628bbdd4Smickey 				break;
2368a472b3eSmickey 		}
2378a472b3eSmickey 		if (Sgl_isone_hidden(opnd3)) dest_exponent++;
2388a472b3eSmickey 	}
2398a472b3eSmickey 	Sgl_set_mantissa(result,opnd3);
2408a472b3eSmickey 
2418a472b3eSmickey 	/*
2428a472b3eSmickey 	 * Test for overflow
2438a472b3eSmickey 	 */
2448a472b3eSmickey 	if (dest_exponent >= SGL_INFINITY_EXPONENT) {
2458a472b3eSmickey 		/* trap if OVERFLOWTRAP enabled */
2468a472b3eSmickey 		if (Is_overflowtrap_enabled()) {
2478a472b3eSmickey 			/*
2488a472b3eSmickey 			 * Adjust bias of result
2498a472b3eSmickey 			 */
2508a472b3eSmickey 			Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
2518a472b3eSmickey 			*dstptr = result;
252b94afd46Smickey 			if (inexact) {
2538a472b3eSmickey 			    if (Is_inexacttrap_enabled())
2548a472b3eSmickey 				return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
2558a472b3eSmickey 			    else Set_inexactflag();
256b94afd46Smickey 			}
2578a472b3eSmickey 			return(OVERFLOWEXCEPTION);
2588a472b3eSmickey 		}
2598a472b3eSmickey 		inexact = TRUE;
2608a472b3eSmickey 		Set_overflowflag();
2618a472b3eSmickey 		/* set result to infinity or largest number */
2628a472b3eSmickey 		Sgl_setoverflow(result);
2638a472b3eSmickey 	}
2648a472b3eSmickey 	/*
2658a472b3eSmickey 	 * Test for underflow
2668a472b3eSmickey 	 */
2678a472b3eSmickey 	else if (dest_exponent <= 0) {
2688a472b3eSmickey 		/* trap if UNDERFLOWTRAP enabled */
2698a472b3eSmickey 		if (Is_underflowtrap_enabled()) {
2708a472b3eSmickey 			/*
2718a472b3eSmickey 			 * Adjust bias of result
2728a472b3eSmickey 			 */
2738a472b3eSmickey 			Sgl_setwrapped_exponent(result,dest_exponent,unfl);
2748a472b3eSmickey 			*dstptr = result;
275b94afd46Smickey 			if (inexact) {
2768a472b3eSmickey 			    if (Is_inexacttrap_enabled())
2778a472b3eSmickey 				return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
2788a472b3eSmickey 			    else Set_inexactflag();
279b94afd46Smickey 			}
2808a472b3eSmickey 			return(UNDERFLOWEXCEPTION);
2818a472b3eSmickey 		}
2828a472b3eSmickey 
2838a472b3eSmickey 		/* Determine if should set underflow flag */
2848a472b3eSmickey 		is_tiny = TRUE;
2858a472b3eSmickey 		if (dest_exponent == 0 && inexact) {
2868a472b3eSmickey 			switch (Rounding_mode()) {
2878a472b3eSmickey 			case ROUNDPLUS:
2888a472b3eSmickey 				if (Sgl_iszero_sign(result)) {
2898a472b3eSmickey 					Sgl_increment(opnd3);
2908a472b3eSmickey 					if (Sgl_isone_hiddenoverflow(opnd3))
2918a472b3eSmickey 						is_tiny = FALSE;
2928a472b3eSmickey 					Sgl_decrement(opnd3);
2938a472b3eSmickey 				}
2948a472b3eSmickey 				break;
2958a472b3eSmickey 			case ROUNDMINUS:
2968a472b3eSmickey 				if (Sgl_isone_sign(result)) {
2978a472b3eSmickey 					Sgl_increment(opnd3);
2988a472b3eSmickey 					if (Sgl_isone_hiddenoverflow(opnd3))
2998a472b3eSmickey 						is_tiny = FALSE;
3008a472b3eSmickey 					Sgl_decrement(opnd3);
3018a472b3eSmickey 				}
3028a472b3eSmickey 				break;
3038a472b3eSmickey 			case ROUNDNEAREST:
3048a472b3eSmickey 				if (guardbit && (stickybit ||
3058a472b3eSmickey 				    Sgl_isone_lowmantissa(opnd3))) {
3068a472b3eSmickey 					Sgl_increment(opnd3);
3078a472b3eSmickey 					if (Sgl_isone_hiddenoverflow(opnd3))
3088a472b3eSmickey 						is_tiny = FALSE;
3098a472b3eSmickey 					Sgl_decrement(opnd3);
3108a472b3eSmickey 				}
3118a472b3eSmickey 				break;
3128a472b3eSmickey 			}
3138a472b3eSmickey 		}
3148a472b3eSmickey 
3158a472b3eSmickey 		/*
3168a472b3eSmickey 		 * denormalize result or set to signed zero
3178a472b3eSmickey 		 */
3188a472b3eSmickey 		stickybit = inexact;
3198a472b3eSmickey 		Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
3208a472b3eSmickey 
3218a472b3eSmickey 		/* return zero or smallest number */
3228a472b3eSmickey 		if (inexact) {
3238a472b3eSmickey 			switch (Rounding_mode()) {
3248a472b3eSmickey 			case ROUNDPLUS:
325628bbdd4Smickey 				if (Sgl_iszero_sign(result))
3268a472b3eSmickey 					Sgl_increment(opnd3);
3278a472b3eSmickey 				break;
3288a472b3eSmickey 			case ROUNDMINUS:
329628bbdd4Smickey 				if (Sgl_isone_sign(result))
3308a472b3eSmickey 					Sgl_increment(opnd3);
3318a472b3eSmickey 				break;
3328a472b3eSmickey 			case ROUNDNEAREST:
3338a472b3eSmickey 				if (guardbit && (stickybit ||
334628bbdd4Smickey 				    Sgl_isone_lowmantissa(opnd3)))
3358a472b3eSmickey 					Sgl_increment(opnd3);
3368a472b3eSmickey 				break;
3378a472b3eSmickey 			}
3388a472b3eSmickey 		if (is_tiny) Set_underflowflag();
3398a472b3eSmickey 		}
3408a472b3eSmickey 		Sgl_set_exponentmantissa(result,opnd3);
3418a472b3eSmickey 	}
3428a472b3eSmickey 	else Sgl_set_exponent(result,dest_exponent);
3438a472b3eSmickey 	*dstptr = result;
3448a472b3eSmickey 
3458a472b3eSmickey 	/* check for inexact */
3468a472b3eSmickey 	if (inexact) {
3478a472b3eSmickey 		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
3488a472b3eSmickey 		else Set_inexactflag();
3498a472b3eSmickey 	}
3508a472b3eSmickey 	return(NOEXCEPTION);
3518a472b3eSmickey }
352