xref: /openbmc/linux/arch/parisc/math-emu/dfsqrt.c (revision 660662f8)
1660662f8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Linux/PA-RISC Project (http://www.parisc-linux.org/)
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Floating-point emulation code
61da177e4SLinus Torvalds  *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds /*
91da177e4SLinus Torvalds  * BEGIN_DESC
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  *  File:
121da177e4SLinus Torvalds  *	@(#)	pa/spmath/dfsqrt.c		$Revision: 1.1 $
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *  Purpose:
151da177e4SLinus Torvalds  *	Double Floating-point Square Root
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *  External Interfaces:
181da177e4SLinus Torvalds  *	dbl_fsqrt(srcptr,nullptr,dstptr,status)
191da177e4SLinus Torvalds  *
201da177e4SLinus Torvalds  *  Internal Interfaces:
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  *  Theory:
231da177e4SLinus Torvalds  *	<<please update with a overview of the operation of this file>>
241da177e4SLinus Torvalds  *
251da177e4SLinus Torvalds  * END_DESC
261da177e4SLinus Torvalds */
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #include "float.h"
301da177e4SLinus Torvalds #include "dbl_float.h"
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds /*
331da177e4SLinus Torvalds  *  Double Floating-point Square Root
341da177e4SLinus Torvalds  */
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds /*ARGSUSED*/
371da177e4SLinus Torvalds unsigned int
dbl_fsqrt(dbl_floating_point * srcptr,unsigned int * nullptr,dbl_floating_point * dstptr,unsigned int * status)381da177e4SLinus Torvalds dbl_fsqrt(
391da177e4SLinus Torvalds 	    dbl_floating_point *srcptr,
401da177e4SLinus Torvalds 	    unsigned int *nullptr,
411da177e4SLinus Torvalds 	    dbl_floating_point *dstptr,
421da177e4SLinus Torvalds 	    unsigned int *status)
431da177e4SLinus Torvalds {
441da177e4SLinus Torvalds 	register unsigned int srcp1, srcp2, resultp1, resultp2;
451da177e4SLinus Torvalds 	register unsigned int newbitp1, newbitp2, sump1, sump2;
461da177e4SLinus Torvalds 	register int src_exponent;
471da177e4SLinus Torvalds 	register boolean guardbit = FALSE, even_exponent;
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds 	Dbl_copyfromptr(srcptr,srcp1,srcp2);
501da177e4SLinus Torvalds         /*
511da177e4SLinus Torvalds          * check source operand for NaN or infinity
521da177e4SLinus Torvalds          */
531da177e4SLinus Torvalds         if ((src_exponent = Dbl_exponent(srcp1)) == DBL_INFINITY_EXPONENT) {
541da177e4SLinus Torvalds                 /*
551da177e4SLinus Torvalds                  * is signaling NaN?
561da177e4SLinus Torvalds                  */
571da177e4SLinus Torvalds                 if (Dbl_isone_signaling(srcp1)) {
581da177e4SLinus Torvalds                         /* trap if INVALIDTRAP enabled */
591da177e4SLinus Torvalds                         if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
601da177e4SLinus Torvalds                         /* make NaN quiet */
611da177e4SLinus Torvalds                         Set_invalidflag();
621da177e4SLinus Torvalds                         Dbl_set_quiet(srcp1);
631da177e4SLinus Torvalds                 }
641da177e4SLinus Torvalds                 /*
651da177e4SLinus Torvalds                  * Return quiet NaN or positive infinity.
667022672eSSimon Arlott 		 *  Fall through to negative test if negative infinity.
671da177e4SLinus Torvalds                  */
681da177e4SLinus Torvalds 		if (Dbl_iszero_sign(srcp1) ||
691da177e4SLinus Torvalds 		    Dbl_isnotzero_mantissa(srcp1,srcp2)) {
701da177e4SLinus Torvalds                 	Dbl_copytoptr(srcp1,srcp2,dstptr);
711da177e4SLinus Torvalds                 	return(NOEXCEPTION);
721da177e4SLinus Torvalds 		}
731da177e4SLinus Torvalds         }
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds         /*
761da177e4SLinus Torvalds          * check for zero source operand
771da177e4SLinus Torvalds          */
781da177e4SLinus Torvalds 	if (Dbl_iszero_exponentmantissa(srcp1,srcp2)) {
791da177e4SLinus Torvalds 		Dbl_copytoptr(srcp1,srcp2,dstptr);
801da177e4SLinus Torvalds 		return(NOEXCEPTION);
811da177e4SLinus Torvalds 	}
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds         /*
841da177e4SLinus Torvalds          * check for negative source operand
851da177e4SLinus Torvalds          */
861da177e4SLinus Torvalds 	if (Dbl_isone_sign(srcp1)) {
871da177e4SLinus Torvalds 		/* trap if INVALIDTRAP enabled */
881da177e4SLinus Torvalds 		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
891da177e4SLinus Torvalds 		/* make NaN quiet */
901da177e4SLinus Torvalds 		Set_invalidflag();
911da177e4SLinus Torvalds 		Dbl_makequietnan(srcp1,srcp2);
921da177e4SLinus Torvalds 		Dbl_copytoptr(srcp1,srcp2,dstptr);
931da177e4SLinus Torvalds 		return(NOEXCEPTION);
941da177e4SLinus Torvalds 	}
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	/*
971da177e4SLinus Torvalds 	 * Generate result
981da177e4SLinus Torvalds 	 */
991da177e4SLinus Torvalds 	if (src_exponent > 0) {
1001da177e4SLinus Torvalds 		even_exponent = Dbl_hidden(srcp1);
1011da177e4SLinus Torvalds 		Dbl_clear_signexponent_set_hidden(srcp1);
1021da177e4SLinus Torvalds 	}
1031da177e4SLinus Torvalds 	else {
1041da177e4SLinus Torvalds 		/* normalize operand */
1051da177e4SLinus Torvalds 		Dbl_clear_signexponent(srcp1);
1061da177e4SLinus Torvalds 		src_exponent++;
1071da177e4SLinus Torvalds 		Dbl_normalize(srcp1,srcp2,src_exponent);
1081da177e4SLinus Torvalds 		even_exponent = src_exponent & 1;
1091da177e4SLinus Torvalds 	}
1101da177e4SLinus Torvalds 	if (even_exponent) {
1111da177e4SLinus Torvalds 		/* exponent is even */
1121da177e4SLinus Torvalds 		/* Add comment here.  Explain why odd exponent needs correction */
1131da177e4SLinus Torvalds 		Dbl_leftshiftby1(srcp1,srcp2);
1141da177e4SLinus Torvalds 	}
1151da177e4SLinus Torvalds 	/*
1161da177e4SLinus Torvalds 	 * Add comment here.  Explain following algorithm.
1171da177e4SLinus Torvalds 	 *
1181da177e4SLinus Torvalds 	 * Trust me, it works.
1191da177e4SLinus Torvalds 	 *
1201da177e4SLinus Torvalds 	 */
1211da177e4SLinus Torvalds 	Dbl_setzero(resultp1,resultp2);
1221da177e4SLinus Torvalds 	Dbl_allp1(newbitp1) = 1 << (DBL_P - 32);
1231da177e4SLinus Torvalds 	Dbl_setzero_mantissap2(newbitp2);
1241da177e4SLinus Torvalds 	while (Dbl_isnotzero(newbitp1,newbitp2) && Dbl_isnotzero(srcp1,srcp2)) {
1251da177e4SLinus Torvalds 		Dbl_addition(resultp1,resultp2,newbitp1,newbitp2,sump1,sump2);
1261da177e4SLinus Torvalds 		if(Dbl_isnotgreaterthan(sump1,sump2,srcp1,srcp2)) {
1271da177e4SLinus Torvalds 			Dbl_leftshiftby1(newbitp1,newbitp2);
1281da177e4SLinus Torvalds 			/* update result */
1291da177e4SLinus Torvalds 			Dbl_addition(resultp1,resultp2,newbitp1,newbitp2,
1301da177e4SLinus Torvalds 			 resultp1,resultp2);
1311da177e4SLinus Torvalds 			Dbl_subtract(srcp1,srcp2,sump1,sump2,srcp1,srcp2);
1321da177e4SLinus Torvalds 			Dbl_rightshiftby2(newbitp1,newbitp2);
1331da177e4SLinus Torvalds 		}
1341da177e4SLinus Torvalds 		else {
1351da177e4SLinus Torvalds 			Dbl_rightshiftby1(newbitp1,newbitp2);
1361da177e4SLinus Torvalds 		}
1371da177e4SLinus Torvalds 		Dbl_leftshiftby1(srcp1,srcp2);
1381da177e4SLinus Torvalds 	}
1391da177e4SLinus Torvalds 	/* correct exponent for pre-shift */
1401da177e4SLinus Torvalds 	if (even_exponent) {
1411da177e4SLinus Torvalds 		Dbl_rightshiftby1(resultp1,resultp2);
1421da177e4SLinus Torvalds 	}
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	/* check for inexact */
1451da177e4SLinus Torvalds 	if (Dbl_isnotzero(srcp1,srcp2)) {
1461da177e4SLinus Torvalds 		if (!even_exponent && Dbl_islessthan(resultp1,resultp2,srcp1,srcp2)) {
1471da177e4SLinus Torvalds 			Dbl_increment(resultp1,resultp2);
1481da177e4SLinus Torvalds 		}
1491da177e4SLinus Torvalds 		guardbit = Dbl_lowmantissap2(resultp2);
1501da177e4SLinus Torvalds 		Dbl_rightshiftby1(resultp1,resultp2);
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 		/*  now round result  */
1531da177e4SLinus Torvalds 		switch (Rounding_mode()) {
1541da177e4SLinus Torvalds 		case ROUNDPLUS:
1551da177e4SLinus Torvalds 		     Dbl_increment(resultp1,resultp2);
1561da177e4SLinus Torvalds 		     break;
1571da177e4SLinus Torvalds 		case ROUNDNEAREST:
1581da177e4SLinus Torvalds 		     /* stickybit is always true, so guardbit
1591da177e4SLinus Torvalds 		      * is enough to determine rounding */
1601da177e4SLinus Torvalds 		     if (guardbit) {
1611da177e4SLinus Torvalds 			    Dbl_increment(resultp1,resultp2);
1621da177e4SLinus Torvalds 		     }
1631da177e4SLinus Torvalds 		     break;
1641da177e4SLinus Torvalds 		}
1651da177e4SLinus Torvalds 		/* increment result exponent by 1 if mantissa overflowed */
1661da177e4SLinus Torvalds 		if (Dbl_isone_hiddenoverflow(resultp1)) src_exponent+=2;
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 		if (Is_inexacttrap_enabled()) {
1691da177e4SLinus Torvalds 			Dbl_set_exponent(resultp1,
1701da177e4SLinus Torvalds 			 ((src_exponent-DBL_BIAS)>>1)+DBL_BIAS);
1711da177e4SLinus Torvalds 			Dbl_copytoptr(resultp1,resultp2,dstptr);
1721da177e4SLinus Torvalds 			return(INEXACTEXCEPTION);
1731da177e4SLinus Torvalds 		}
1741da177e4SLinus Torvalds 		else Set_inexactflag();
1751da177e4SLinus Torvalds 	}
1761da177e4SLinus Torvalds 	else {
1771da177e4SLinus Torvalds 		Dbl_rightshiftby1(resultp1,resultp2);
1781da177e4SLinus Torvalds 	}
1791da177e4SLinus Torvalds 	Dbl_set_exponent(resultp1,((src_exponent-DBL_BIAS)>>1)+DBL_BIAS);
1801da177e4SLinus Torvalds 	Dbl_copytoptr(resultp1,resultp2,dstptr);
1811da177e4SLinus Torvalds 	return(NOEXCEPTION);
1821da177e4SLinus Torvalds }
183