162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Linux/PA-RISC Project (http://www.parisc-linux.org/)
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Floating-point emulation code
662306a36Sopenharmony_ci *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * BEGIN_DESC
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *  File:
1262306a36Sopenharmony_ci *	@(#)	pa/spmath/sfsqrt.c		$Revision: 1.1 $
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *  Purpose:
1562306a36Sopenharmony_ci *	Single Floating-point Square Root
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *  External Interfaces:
1862306a36Sopenharmony_ci *	sgl_fsqrt(srcptr,nullptr,dstptr,status)
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *  Internal Interfaces:
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci *  Theory:
2362306a36Sopenharmony_ci *	<<please update with a overview of the operation of this file>>
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * END_DESC
2662306a36Sopenharmony_ci*/
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "float.h"
3062306a36Sopenharmony_ci#include "sgl_float.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci *  Single Floating-point Square Root
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*ARGSUSED*/
3762306a36Sopenharmony_ciunsigned int
3862306a36Sopenharmony_cisgl_fsqrt(
3962306a36Sopenharmony_ci    sgl_floating_point *srcptr,
4062306a36Sopenharmony_ci    unsigned int *nullptr,
4162306a36Sopenharmony_ci    sgl_floating_point *dstptr,
4262306a36Sopenharmony_ci    unsigned int *status)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	register unsigned int src, result;
4562306a36Sopenharmony_ci	register int src_exponent;
4662306a36Sopenharmony_ci	register unsigned int newbit, sum;
4762306a36Sopenharmony_ci	register boolean guardbit = FALSE, even_exponent;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	src = *srcptr;
5062306a36Sopenharmony_ci        /*
5162306a36Sopenharmony_ci         * check source operand for NaN or infinity
5262306a36Sopenharmony_ci         */
5362306a36Sopenharmony_ci        if ((src_exponent = Sgl_exponent(src)) == SGL_INFINITY_EXPONENT) {
5462306a36Sopenharmony_ci                /*
5562306a36Sopenharmony_ci                 * is signaling NaN?
5662306a36Sopenharmony_ci                 */
5762306a36Sopenharmony_ci                if (Sgl_isone_signaling(src)) {
5862306a36Sopenharmony_ci                        /* trap if INVALIDTRAP enabled */
5962306a36Sopenharmony_ci                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
6062306a36Sopenharmony_ci                        /* make NaN quiet */
6162306a36Sopenharmony_ci                        Set_invalidflag();
6262306a36Sopenharmony_ci                        Sgl_set_quiet(src);
6362306a36Sopenharmony_ci                }
6462306a36Sopenharmony_ci                /*
6562306a36Sopenharmony_ci                 * Return quiet NaN or positive infinity.
6662306a36Sopenharmony_ci		 *  Fall through to negative test if negative infinity.
6762306a36Sopenharmony_ci                 */
6862306a36Sopenharmony_ci		if (Sgl_iszero_sign(src) || Sgl_isnotzero_mantissa(src)) {
6962306a36Sopenharmony_ci                	*dstptr = src;
7062306a36Sopenharmony_ci                	return(NOEXCEPTION);
7162306a36Sopenharmony_ci		}
7262306a36Sopenharmony_ci        }
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci        /*
7562306a36Sopenharmony_ci         * check for zero source operand
7662306a36Sopenharmony_ci         */
7762306a36Sopenharmony_ci	if (Sgl_iszero_exponentmantissa(src)) {
7862306a36Sopenharmony_ci		*dstptr = src;
7962306a36Sopenharmony_ci		return(NOEXCEPTION);
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci        /*
8362306a36Sopenharmony_ci         * check for negative source operand
8462306a36Sopenharmony_ci         */
8562306a36Sopenharmony_ci	if (Sgl_isone_sign(src)) {
8662306a36Sopenharmony_ci		/* trap if INVALIDTRAP enabled */
8762306a36Sopenharmony_ci		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
8862306a36Sopenharmony_ci		/* make NaN quiet */
8962306a36Sopenharmony_ci		Set_invalidflag();
9062306a36Sopenharmony_ci		Sgl_makequietnan(src);
9162306a36Sopenharmony_ci		*dstptr = src;
9262306a36Sopenharmony_ci		return(NOEXCEPTION);
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/*
9662306a36Sopenharmony_ci	 * Generate result
9762306a36Sopenharmony_ci	 */
9862306a36Sopenharmony_ci	if (src_exponent > 0) {
9962306a36Sopenharmony_ci		even_exponent = Sgl_hidden(src);
10062306a36Sopenharmony_ci		Sgl_clear_signexponent_set_hidden(src);
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci	else {
10362306a36Sopenharmony_ci		/* normalize operand */
10462306a36Sopenharmony_ci		Sgl_clear_signexponent(src);
10562306a36Sopenharmony_ci		src_exponent++;
10662306a36Sopenharmony_ci		Sgl_normalize(src,src_exponent);
10762306a36Sopenharmony_ci		even_exponent = src_exponent & 1;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci	if (even_exponent) {
11062306a36Sopenharmony_ci		/* exponent is even */
11162306a36Sopenharmony_ci		/* Add comment here.  Explain why odd exponent needs correction */
11262306a36Sopenharmony_ci		Sgl_leftshiftby1(src);
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci	/*
11562306a36Sopenharmony_ci	 * Add comment here.  Explain following algorithm.
11662306a36Sopenharmony_ci	 *
11762306a36Sopenharmony_ci	 * Trust me, it works.
11862306a36Sopenharmony_ci	 *
11962306a36Sopenharmony_ci	 */
12062306a36Sopenharmony_ci	Sgl_setzero(result);
12162306a36Sopenharmony_ci	newbit = 1 << SGL_P;
12262306a36Sopenharmony_ci	while (newbit && Sgl_isnotzero(src)) {
12362306a36Sopenharmony_ci		Sgl_addition(result,newbit,sum);
12462306a36Sopenharmony_ci		if(sum <= Sgl_all(src)) {
12562306a36Sopenharmony_ci			/* update result */
12662306a36Sopenharmony_ci			Sgl_addition(result,(newbit<<1),result);
12762306a36Sopenharmony_ci			Sgl_subtract(src,sum,src);
12862306a36Sopenharmony_ci		}
12962306a36Sopenharmony_ci		Sgl_rightshiftby1(newbit);
13062306a36Sopenharmony_ci		Sgl_leftshiftby1(src);
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci	/* correct exponent for pre-shift */
13362306a36Sopenharmony_ci	if (even_exponent) {
13462306a36Sopenharmony_ci		Sgl_rightshiftby1(result);
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	/* check for inexact */
13862306a36Sopenharmony_ci	if (Sgl_isnotzero(src)) {
13962306a36Sopenharmony_ci		if (!even_exponent && Sgl_islessthan(result,src))
14062306a36Sopenharmony_ci			Sgl_increment(result);
14162306a36Sopenharmony_ci		guardbit = Sgl_lowmantissa(result);
14262306a36Sopenharmony_ci		Sgl_rightshiftby1(result);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		/*  now round result  */
14562306a36Sopenharmony_ci		switch (Rounding_mode()) {
14662306a36Sopenharmony_ci		case ROUNDPLUS:
14762306a36Sopenharmony_ci		     Sgl_increment(result);
14862306a36Sopenharmony_ci		     break;
14962306a36Sopenharmony_ci		case ROUNDNEAREST:
15062306a36Sopenharmony_ci		     /* stickybit is always true, so guardbit
15162306a36Sopenharmony_ci		      * is enough to determine rounding */
15262306a36Sopenharmony_ci		     if (guardbit) {
15362306a36Sopenharmony_ci			Sgl_increment(result);
15462306a36Sopenharmony_ci		     }
15562306a36Sopenharmony_ci		     break;
15662306a36Sopenharmony_ci		}
15762306a36Sopenharmony_ci		/* increment result exponent by 1 if mantissa overflowed */
15862306a36Sopenharmony_ci		if (Sgl_isone_hiddenoverflow(result)) src_exponent+=2;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci		if (Is_inexacttrap_enabled()) {
16162306a36Sopenharmony_ci			Sgl_set_exponent(result,
16262306a36Sopenharmony_ci			 ((src_exponent-SGL_BIAS)>>1)+SGL_BIAS);
16362306a36Sopenharmony_ci			*dstptr = result;
16462306a36Sopenharmony_ci			return(INEXACTEXCEPTION);
16562306a36Sopenharmony_ci		}
16662306a36Sopenharmony_ci		else Set_inexactflag();
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci	else {
16962306a36Sopenharmony_ci		Sgl_rightshiftby1(result);
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci	Sgl_set_exponent(result,((src_exponent-SGL_BIAS)>>1)+SGL_BIAS);
17262306a36Sopenharmony_ci	*dstptr = result;
17362306a36Sopenharmony_ci	return(NOEXCEPTION);
17462306a36Sopenharmony_ci}
175