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 *  Purpose:
1262306a36Sopenharmony_ci *	Single Floating-point Round to Integer
1362306a36Sopenharmony_ci *	Double Floating-point Round to Integer
1462306a36Sopenharmony_ci *	Quad Floating-point Round to Integer (returns unimplemented)
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *  External Interfaces:
1762306a36Sopenharmony_ci *	dbl_frnd(srcptr,nullptr,dstptr,status)
1862306a36Sopenharmony_ci *	sgl_frnd(srcptr,nullptr,dstptr,status)
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * END_DESC
2162306a36Sopenharmony_ci*/
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "float.h"
2562306a36Sopenharmony_ci#include "sgl_float.h"
2662306a36Sopenharmony_ci#include "dbl_float.h"
2762306a36Sopenharmony_ci#include "cnv_float.h"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/*
3062306a36Sopenharmony_ci *  Single Floating-point Round to Integer
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/*ARGSUSED*/
3462306a36Sopenharmony_ciint
3562306a36Sopenharmony_cisgl_frnd(sgl_floating_point *srcptr,
3662306a36Sopenharmony_ci	unsigned int *nullptr,
3762306a36Sopenharmony_ci	sgl_floating_point *dstptr,
3862306a36Sopenharmony_ci	unsigned int *status)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	register unsigned int src, result;
4162306a36Sopenharmony_ci	register int src_exponent;
4262306a36Sopenharmony_ci	register boolean inexact = FALSE;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	src = *srcptr;
4562306a36Sopenharmony_ci        /*
4662306a36Sopenharmony_ci         * check source operand for NaN or infinity
4762306a36Sopenharmony_ci         */
4862306a36Sopenharmony_ci        if ((src_exponent = Sgl_exponent(src)) == SGL_INFINITY_EXPONENT) {
4962306a36Sopenharmony_ci                /*
5062306a36Sopenharmony_ci                 * is signaling NaN?
5162306a36Sopenharmony_ci                 */
5262306a36Sopenharmony_ci                if (Sgl_isone_signaling(src)) {
5362306a36Sopenharmony_ci                        /* trap if INVALIDTRAP enabled */
5462306a36Sopenharmony_ci                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
5562306a36Sopenharmony_ci                        /* make NaN quiet */
5662306a36Sopenharmony_ci                        Set_invalidflag();
5762306a36Sopenharmony_ci                        Sgl_set_quiet(src);
5862306a36Sopenharmony_ci                }
5962306a36Sopenharmony_ci                /*
6062306a36Sopenharmony_ci                 * return quiet NaN or infinity
6162306a36Sopenharmony_ci                 */
6262306a36Sopenharmony_ci                *dstptr = src;
6362306a36Sopenharmony_ci                return(NOEXCEPTION);
6462306a36Sopenharmony_ci        }
6562306a36Sopenharmony_ci	/*
6662306a36Sopenharmony_ci	 * Need to round?
6762306a36Sopenharmony_ci	 */
6862306a36Sopenharmony_ci	if ((src_exponent -= SGL_BIAS) >= SGL_P - 1) {
6962306a36Sopenharmony_ci		*dstptr = src;
7062306a36Sopenharmony_ci		return(NOEXCEPTION);
7162306a36Sopenharmony_ci	}
7262306a36Sopenharmony_ci	/*
7362306a36Sopenharmony_ci	 * Generate result
7462306a36Sopenharmony_ci	 */
7562306a36Sopenharmony_ci	if (src_exponent >= 0) {
7662306a36Sopenharmony_ci		Sgl_clear_exponent_set_hidden(src);
7762306a36Sopenharmony_ci		result = src;
7862306a36Sopenharmony_ci		Sgl_rightshift(result,(SGL_P-1) - (src_exponent));
7962306a36Sopenharmony_ci		/* check for inexact */
8062306a36Sopenharmony_ci		if (Sgl_isinexact_to_fix(src,src_exponent)) {
8162306a36Sopenharmony_ci			inexact = TRUE;
8262306a36Sopenharmony_ci			/*  round result  */
8362306a36Sopenharmony_ci			switch (Rounding_mode()) {
8462306a36Sopenharmony_ci			case ROUNDPLUS:
8562306a36Sopenharmony_ci			     if (Sgl_iszero_sign(src)) Sgl_increment(result);
8662306a36Sopenharmony_ci			     break;
8762306a36Sopenharmony_ci			case ROUNDMINUS:
8862306a36Sopenharmony_ci			     if (Sgl_isone_sign(src)) Sgl_increment(result);
8962306a36Sopenharmony_ci			     break;
9062306a36Sopenharmony_ci			case ROUNDNEAREST:
9162306a36Sopenharmony_ci			     if (Sgl_isone_roundbit(src,src_exponent))
9262306a36Sopenharmony_ci			        if (Sgl_isone_stickybit(src,src_exponent)
9362306a36Sopenharmony_ci				|| (Sgl_isone_lowmantissa(result)))
9462306a36Sopenharmony_ci					Sgl_increment(result);
9562306a36Sopenharmony_ci			}
9662306a36Sopenharmony_ci		}
9762306a36Sopenharmony_ci		Sgl_leftshift(result,(SGL_P-1) - (src_exponent));
9862306a36Sopenharmony_ci		if (Sgl_isone_hiddenoverflow(result))
9962306a36Sopenharmony_ci			Sgl_set_exponent(result,src_exponent + (SGL_BIAS+1));
10062306a36Sopenharmony_ci		else Sgl_set_exponent(result,src_exponent + SGL_BIAS);
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci	else {
10362306a36Sopenharmony_ci		result = src;  		/* set sign */
10462306a36Sopenharmony_ci		Sgl_setzero_exponentmantissa(result);
10562306a36Sopenharmony_ci		/* check for inexact */
10662306a36Sopenharmony_ci		if (Sgl_isnotzero_exponentmantissa(src)) {
10762306a36Sopenharmony_ci			inexact = TRUE;
10862306a36Sopenharmony_ci			/*  round result  */
10962306a36Sopenharmony_ci			switch (Rounding_mode()) {
11062306a36Sopenharmony_ci			case ROUNDPLUS:
11162306a36Sopenharmony_ci			     if (Sgl_iszero_sign(src))
11262306a36Sopenharmony_ci				Sgl_set_exponent(result,SGL_BIAS);
11362306a36Sopenharmony_ci			     break;
11462306a36Sopenharmony_ci			case ROUNDMINUS:
11562306a36Sopenharmony_ci			     if (Sgl_isone_sign(src))
11662306a36Sopenharmony_ci				Sgl_set_exponent(result,SGL_BIAS);
11762306a36Sopenharmony_ci			     break;
11862306a36Sopenharmony_ci			case ROUNDNEAREST:
11962306a36Sopenharmony_ci			     if (src_exponent == -1)
12062306a36Sopenharmony_ci			        if (Sgl_isnotzero_mantissa(src))
12162306a36Sopenharmony_ci				   Sgl_set_exponent(result,SGL_BIAS);
12262306a36Sopenharmony_ci			}
12362306a36Sopenharmony_ci		}
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci	*dstptr = result;
12662306a36Sopenharmony_ci	if (inexact) {
12762306a36Sopenharmony_ci		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
12862306a36Sopenharmony_ci		else Set_inexactflag();
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci	return(NOEXCEPTION);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/*
13462306a36Sopenharmony_ci *  Double Floating-point Round to Integer
13562306a36Sopenharmony_ci */
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/*ARGSUSED*/
13862306a36Sopenharmony_ciint
13962306a36Sopenharmony_cidbl_frnd(
14062306a36Sopenharmony_ci	dbl_floating_point *srcptr,
14162306a36Sopenharmony_ci	unsigned int *nullptr,
14262306a36Sopenharmony_ci	dbl_floating_point *dstptr,
14362306a36Sopenharmony_ci	unsigned int *status)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	register unsigned int srcp1, srcp2, resultp1, resultp2;
14662306a36Sopenharmony_ci	register int src_exponent;
14762306a36Sopenharmony_ci	register boolean inexact = FALSE;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	Dbl_copyfromptr(srcptr,srcp1,srcp2);
15062306a36Sopenharmony_ci        /*
15162306a36Sopenharmony_ci         * check source operand for NaN or infinity
15262306a36Sopenharmony_ci         */
15362306a36Sopenharmony_ci        if ((src_exponent = Dbl_exponent(srcp1)) == DBL_INFINITY_EXPONENT) {
15462306a36Sopenharmony_ci                /*
15562306a36Sopenharmony_ci                 * is signaling NaN?
15662306a36Sopenharmony_ci                 */
15762306a36Sopenharmony_ci                if (Dbl_isone_signaling(srcp1)) {
15862306a36Sopenharmony_ci                        /* trap if INVALIDTRAP enabled */
15962306a36Sopenharmony_ci                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
16062306a36Sopenharmony_ci                        /* make NaN quiet */
16162306a36Sopenharmony_ci                        Set_invalidflag();
16262306a36Sopenharmony_ci                        Dbl_set_quiet(srcp1);
16362306a36Sopenharmony_ci                }
16462306a36Sopenharmony_ci                /*
16562306a36Sopenharmony_ci                 * return quiet NaN or infinity
16662306a36Sopenharmony_ci                 */
16762306a36Sopenharmony_ci                Dbl_copytoptr(srcp1,srcp2,dstptr);
16862306a36Sopenharmony_ci                return(NOEXCEPTION);
16962306a36Sopenharmony_ci        }
17062306a36Sopenharmony_ci	/*
17162306a36Sopenharmony_ci	 * Need to round?
17262306a36Sopenharmony_ci	 */
17362306a36Sopenharmony_ci	if ((src_exponent -= DBL_BIAS) >= DBL_P - 1) {
17462306a36Sopenharmony_ci		Dbl_copytoptr(srcp1,srcp2,dstptr);
17562306a36Sopenharmony_ci		return(NOEXCEPTION);
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci	/*
17862306a36Sopenharmony_ci	 * Generate result
17962306a36Sopenharmony_ci	 */
18062306a36Sopenharmony_ci	if (src_exponent >= 0) {
18162306a36Sopenharmony_ci		Dbl_clear_exponent_set_hidden(srcp1);
18262306a36Sopenharmony_ci		resultp1 = srcp1;
18362306a36Sopenharmony_ci		resultp2 = srcp2;
18462306a36Sopenharmony_ci		Dbl_rightshift(resultp1,resultp2,(DBL_P-1) - (src_exponent));
18562306a36Sopenharmony_ci		/* check for inexact */
18662306a36Sopenharmony_ci		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
18762306a36Sopenharmony_ci			inexact = TRUE;
18862306a36Sopenharmony_ci			/*  round result  */
18962306a36Sopenharmony_ci			switch (Rounding_mode()) {
19062306a36Sopenharmony_ci			case ROUNDPLUS:
19162306a36Sopenharmony_ci			     if (Dbl_iszero_sign(srcp1))
19262306a36Sopenharmony_ci				Dbl_increment(resultp1,resultp2);
19362306a36Sopenharmony_ci			     break;
19462306a36Sopenharmony_ci			case ROUNDMINUS:
19562306a36Sopenharmony_ci			     if (Dbl_isone_sign(srcp1))
19662306a36Sopenharmony_ci				Dbl_increment(resultp1,resultp2);
19762306a36Sopenharmony_ci			     break;
19862306a36Sopenharmony_ci			case ROUNDNEAREST:
19962306a36Sopenharmony_ci			     if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
20062306a36Sopenharmony_ci			      if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent)
20162306a36Sopenharmony_ci				  || (Dbl_isone_lowmantissap2(resultp2)))
20262306a36Sopenharmony_ci					Dbl_increment(resultp1,resultp2);
20362306a36Sopenharmony_ci			}
20462306a36Sopenharmony_ci		}
20562306a36Sopenharmony_ci		Dbl_leftshift(resultp1,resultp2,(DBL_P-1) - (src_exponent));
20662306a36Sopenharmony_ci		if (Dbl_isone_hiddenoverflow(resultp1))
20762306a36Sopenharmony_ci			Dbl_set_exponent(resultp1,src_exponent + (DBL_BIAS+1));
20862306a36Sopenharmony_ci		else Dbl_set_exponent(resultp1,src_exponent + DBL_BIAS);
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci	else {
21162306a36Sopenharmony_ci		resultp1 = srcp1;  /* set sign */
21262306a36Sopenharmony_ci		Dbl_setzero_exponentmantissa(resultp1,resultp2);
21362306a36Sopenharmony_ci		/* check for inexact */
21462306a36Sopenharmony_ci		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
21562306a36Sopenharmony_ci			inexact = TRUE;
21662306a36Sopenharmony_ci			/*  round result  */
21762306a36Sopenharmony_ci			switch (Rounding_mode()) {
21862306a36Sopenharmony_ci			case ROUNDPLUS:
21962306a36Sopenharmony_ci			     if (Dbl_iszero_sign(srcp1))
22062306a36Sopenharmony_ci				Dbl_set_exponent(resultp1,DBL_BIAS);
22162306a36Sopenharmony_ci			     break;
22262306a36Sopenharmony_ci			case ROUNDMINUS:
22362306a36Sopenharmony_ci			     if (Dbl_isone_sign(srcp1))
22462306a36Sopenharmony_ci				Dbl_set_exponent(resultp1,DBL_BIAS);
22562306a36Sopenharmony_ci			     break;
22662306a36Sopenharmony_ci			case ROUNDNEAREST:
22762306a36Sopenharmony_ci			     if (src_exponent == -1)
22862306a36Sopenharmony_ci			        if (Dbl_isnotzero_mantissa(srcp1,srcp2))
22962306a36Sopenharmony_ci				   Dbl_set_exponent(resultp1,DBL_BIAS);
23062306a36Sopenharmony_ci			}
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci	Dbl_copytoptr(resultp1,resultp2,dstptr);
23462306a36Sopenharmony_ci	if (inexact) {
23562306a36Sopenharmony_ci		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
23662306a36Sopenharmony_ci		else Set_inexactflag();
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci	return(NOEXCEPTION);
23962306a36Sopenharmony_ci}
240