18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Linux/PA-RISC Project (http://www.parisc-linux.org/)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Floating-point emulation code
68c2ecf20Sopenharmony_ci *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci/*
98c2ecf20Sopenharmony_ci * BEGIN_DESC
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *  File:
128c2ecf20Sopenharmony_ci *	@(#)	pa/spmath/sfsqrt.c		$Revision: 1.1 $
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *  Purpose:
158c2ecf20Sopenharmony_ci *	Single Floating-point Square Root
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci *  External Interfaces:
188c2ecf20Sopenharmony_ci *	sgl_fsqrt(srcptr,nullptr,dstptr,status)
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci *  Internal Interfaces:
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci *  Theory:
238c2ecf20Sopenharmony_ci *	<<please update with a overview of the operation of this file>>
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * END_DESC
268c2ecf20Sopenharmony_ci*/
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include "float.h"
308c2ecf20Sopenharmony_ci#include "sgl_float.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/*
338c2ecf20Sopenharmony_ci *  Single Floating-point Square Root
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/*ARGSUSED*/
378c2ecf20Sopenharmony_ciunsigned int
388c2ecf20Sopenharmony_cisgl_fsqrt(
398c2ecf20Sopenharmony_ci    sgl_floating_point *srcptr,
408c2ecf20Sopenharmony_ci    unsigned int *nullptr,
418c2ecf20Sopenharmony_ci    sgl_floating_point *dstptr,
428c2ecf20Sopenharmony_ci    unsigned int *status)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	register unsigned int src, result;
458c2ecf20Sopenharmony_ci	register int src_exponent;
468c2ecf20Sopenharmony_ci	register unsigned int newbit, sum;
478c2ecf20Sopenharmony_ci	register boolean guardbit = FALSE, even_exponent;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	src = *srcptr;
508c2ecf20Sopenharmony_ci        /*
518c2ecf20Sopenharmony_ci         * check source operand for NaN or infinity
528c2ecf20Sopenharmony_ci         */
538c2ecf20Sopenharmony_ci        if ((src_exponent = Sgl_exponent(src)) == SGL_INFINITY_EXPONENT) {
548c2ecf20Sopenharmony_ci                /*
558c2ecf20Sopenharmony_ci                 * is signaling NaN?
568c2ecf20Sopenharmony_ci                 */
578c2ecf20Sopenharmony_ci                if (Sgl_isone_signaling(src)) {
588c2ecf20Sopenharmony_ci                        /* trap if INVALIDTRAP enabled */
598c2ecf20Sopenharmony_ci                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
608c2ecf20Sopenharmony_ci                        /* make NaN quiet */
618c2ecf20Sopenharmony_ci                        Set_invalidflag();
628c2ecf20Sopenharmony_ci                        Sgl_set_quiet(src);
638c2ecf20Sopenharmony_ci                }
648c2ecf20Sopenharmony_ci                /*
658c2ecf20Sopenharmony_ci                 * Return quiet NaN or positive infinity.
668c2ecf20Sopenharmony_ci		 *  Fall through to negative test if negative infinity.
678c2ecf20Sopenharmony_ci                 */
688c2ecf20Sopenharmony_ci		if (Sgl_iszero_sign(src) || Sgl_isnotzero_mantissa(src)) {
698c2ecf20Sopenharmony_ci                	*dstptr = src;
708c2ecf20Sopenharmony_ci                	return(NOEXCEPTION);
718c2ecf20Sopenharmony_ci		}
728c2ecf20Sopenharmony_ci        }
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci        /*
758c2ecf20Sopenharmony_ci         * check for zero source operand
768c2ecf20Sopenharmony_ci         */
778c2ecf20Sopenharmony_ci	if (Sgl_iszero_exponentmantissa(src)) {
788c2ecf20Sopenharmony_ci		*dstptr = src;
798c2ecf20Sopenharmony_ci		return(NOEXCEPTION);
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci        /*
838c2ecf20Sopenharmony_ci         * check for negative source operand
848c2ecf20Sopenharmony_ci         */
858c2ecf20Sopenharmony_ci	if (Sgl_isone_sign(src)) {
868c2ecf20Sopenharmony_ci		/* trap if INVALIDTRAP enabled */
878c2ecf20Sopenharmony_ci		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
888c2ecf20Sopenharmony_ci		/* make NaN quiet */
898c2ecf20Sopenharmony_ci		Set_invalidflag();
908c2ecf20Sopenharmony_ci		Sgl_makequietnan(src);
918c2ecf20Sopenharmony_ci		*dstptr = src;
928c2ecf20Sopenharmony_ci		return(NOEXCEPTION);
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/*
968c2ecf20Sopenharmony_ci	 * Generate result
978c2ecf20Sopenharmony_ci	 */
988c2ecf20Sopenharmony_ci	if (src_exponent > 0) {
998c2ecf20Sopenharmony_ci		even_exponent = Sgl_hidden(src);
1008c2ecf20Sopenharmony_ci		Sgl_clear_signexponent_set_hidden(src);
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci	else {
1038c2ecf20Sopenharmony_ci		/* normalize operand */
1048c2ecf20Sopenharmony_ci		Sgl_clear_signexponent(src);
1058c2ecf20Sopenharmony_ci		src_exponent++;
1068c2ecf20Sopenharmony_ci		Sgl_normalize(src,src_exponent);
1078c2ecf20Sopenharmony_ci		even_exponent = src_exponent & 1;
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci	if (even_exponent) {
1108c2ecf20Sopenharmony_ci		/* exponent is even */
1118c2ecf20Sopenharmony_ci		/* Add comment here.  Explain why odd exponent needs correction */
1128c2ecf20Sopenharmony_ci		Sgl_leftshiftby1(src);
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci	/*
1158c2ecf20Sopenharmony_ci	 * Add comment here.  Explain following algorithm.
1168c2ecf20Sopenharmony_ci	 *
1178c2ecf20Sopenharmony_ci	 * Trust me, it works.
1188c2ecf20Sopenharmony_ci	 *
1198c2ecf20Sopenharmony_ci	 */
1208c2ecf20Sopenharmony_ci	Sgl_setzero(result);
1218c2ecf20Sopenharmony_ci	newbit = 1 << SGL_P;
1228c2ecf20Sopenharmony_ci	while (newbit && Sgl_isnotzero(src)) {
1238c2ecf20Sopenharmony_ci		Sgl_addition(result,newbit,sum);
1248c2ecf20Sopenharmony_ci		if(sum <= Sgl_all(src)) {
1258c2ecf20Sopenharmony_ci			/* update result */
1268c2ecf20Sopenharmony_ci			Sgl_addition(result,(newbit<<1),result);
1278c2ecf20Sopenharmony_ci			Sgl_subtract(src,sum,src);
1288c2ecf20Sopenharmony_ci		}
1298c2ecf20Sopenharmony_ci		Sgl_rightshiftby1(newbit);
1308c2ecf20Sopenharmony_ci		Sgl_leftshiftby1(src);
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci	/* correct exponent for pre-shift */
1338c2ecf20Sopenharmony_ci	if (even_exponent) {
1348c2ecf20Sopenharmony_ci		Sgl_rightshiftby1(result);
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	/* check for inexact */
1388c2ecf20Sopenharmony_ci	if (Sgl_isnotzero(src)) {
1398c2ecf20Sopenharmony_ci		if (!even_exponent && Sgl_islessthan(result,src))
1408c2ecf20Sopenharmony_ci			Sgl_increment(result);
1418c2ecf20Sopenharmony_ci		guardbit = Sgl_lowmantissa(result);
1428c2ecf20Sopenharmony_ci		Sgl_rightshiftby1(result);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		/*  now round result  */
1458c2ecf20Sopenharmony_ci		switch (Rounding_mode()) {
1468c2ecf20Sopenharmony_ci		case ROUNDPLUS:
1478c2ecf20Sopenharmony_ci		     Sgl_increment(result);
1488c2ecf20Sopenharmony_ci		     break;
1498c2ecf20Sopenharmony_ci		case ROUNDNEAREST:
1508c2ecf20Sopenharmony_ci		     /* stickybit is always true, so guardbit
1518c2ecf20Sopenharmony_ci		      * is enough to determine rounding */
1528c2ecf20Sopenharmony_ci		     if (guardbit) {
1538c2ecf20Sopenharmony_ci			Sgl_increment(result);
1548c2ecf20Sopenharmony_ci		     }
1558c2ecf20Sopenharmony_ci		     break;
1568c2ecf20Sopenharmony_ci		}
1578c2ecf20Sopenharmony_ci		/* increment result exponent by 1 if mantissa overflowed */
1588c2ecf20Sopenharmony_ci		if (Sgl_isone_hiddenoverflow(result)) src_exponent+=2;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci		if (Is_inexacttrap_enabled()) {
1618c2ecf20Sopenharmony_ci			Sgl_set_exponent(result,
1628c2ecf20Sopenharmony_ci			 ((src_exponent-SGL_BIAS)>>1)+SGL_BIAS);
1638c2ecf20Sopenharmony_ci			*dstptr = result;
1648c2ecf20Sopenharmony_ci			return(INEXACTEXCEPTION);
1658c2ecf20Sopenharmony_ci		}
1668c2ecf20Sopenharmony_ci		else Set_inexactflag();
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci	else {
1698c2ecf20Sopenharmony_ci		Sgl_rightshiftby1(result);
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci	Sgl_set_exponent(result,((src_exponent-SGL_BIAS)>>1)+SGL_BIAS);
1728c2ecf20Sopenharmony_ci	*dstptr = result;
1738c2ecf20Sopenharmony_ci	return(NOEXCEPTION);
1748c2ecf20Sopenharmony_ci}
175