1*660662f8SThomas 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 * Purpose:
121da177e4SLinus Torvalds * Single Floating-point Round to Integer
131da177e4SLinus Torvalds * Double Floating-point Round to Integer
141da177e4SLinus Torvalds * Quad Floating-point Round to Integer (returns unimplemented)
151da177e4SLinus Torvalds *
161da177e4SLinus Torvalds * External Interfaces:
171da177e4SLinus Torvalds * dbl_frnd(srcptr,nullptr,dstptr,status)
181da177e4SLinus Torvalds * sgl_frnd(srcptr,nullptr,dstptr,status)
191da177e4SLinus Torvalds *
201da177e4SLinus Torvalds * END_DESC
211da177e4SLinus Torvalds */
221da177e4SLinus Torvalds
231da177e4SLinus Torvalds
241da177e4SLinus Torvalds #include "float.h"
251da177e4SLinus Torvalds #include "sgl_float.h"
261da177e4SLinus Torvalds #include "dbl_float.h"
271da177e4SLinus Torvalds #include "cnv_float.h"
281da177e4SLinus Torvalds
291da177e4SLinus Torvalds /*
301da177e4SLinus Torvalds * Single Floating-point Round to Integer
311da177e4SLinus Torvalds */
321da177e4SLinus Torvalds
331da177e4SLinus Torvalds /*ARGSUSED*/
341da177e4SLinus Torvalds int
sgl_frnd(sgl_floating_point * srcptr,unsigned int * nullptr,sgl_floating_point * dstptr,unsigned int * status)351da177e4SLinus Torvalds sgl_frnd(sgl_floating_point *srcptr,
361da177e4SLinus Torvalds unsigned int *nullptr,
371da177e4SLinus Torvalds sgl_floating_point *dstptr,
381da177e4SLinus Torvalds unsigned int *status)
391da177e4SLinus Torvalds {
401da177e4SLinus Torvalds register unsigned int src, result;
411da177e4SLinus Torvalds register int src_exponent;
421da177e4SLinus Torvalds register boolean inexact = FALSE;
431da177e4SLinus Torvalds
441da177e4SLinus Torvalds src = *srcptr;
451da177e4SLinus Torvalds /*
461da177e4SLinus Torvalds * check source operand for NaN or infinity
471da177e4SLinus Torvalds */
481da177e4SLinus Torvalds if ((src_exponent = Sgl_exponent(src)) == SGL_INFINITY_EXPONENT) {
491da177e4SLinus Torvalds /*
501da177e4SLinus Torvalds * is signaling NaN?
511da177e4SLinus Torvalds */
521da177e4SLinus Torvalds if (Sgl_isone_signaling(src)) {
531da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
541da177e4SLinus Torvalds if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
551da177e4SLinus Torvalds /* make NaN quiet */
561da177e4SLinus Torvalds Set_invalidflag();
571da177e4SLinus Torvalds Sgl_set_quiet(src);
581da177e4SLinus Torvalds }
591da177e4SLinus Torvalds /*
601da177e4SLinus Torvalds * return quiet NaN or infinity
611da177e4SLinus Torvalds */
621da177e4SLinus Torvalds *dstptr = src;
631da177e4SLinus Torvalds return(NOEXCEPTION);
641da177e4SLinus Torvalds }
651da177e4SLinus Torvalds /*
661da177e4SLinus Torvalds * Need to round?
671da177e4SLinus Torvalds */
681da177e4SLinus Torvalds if ((src_exponent -= SGL_BIAS) >= SGL_P - 1) {
691da177e4SLinus Torvalds *dstptr = src;
701da177e4SLinus Torvalds return(NOEXCEPTION);
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds /*
731da177e4SLinus Torvalds * Generate result
741da177e4SLinus Torvalds */
751da177e4SLinus Torvalds if (src_exponent >= 0) {
761da177e4SLinus Torvalds Sgl_clear_exponent_set_hidden(src);
771da177e4SLinus Torvalds result = src;
781da177e4SLinus Torvalds Sgl_rightshift(result,(SGL_P-1) - (src_exponent));
791da177e4SLinus Torvalds /* check for inexact */
801da177e4SLinus Torvalds if (Sgl_isinexact_to_fix(src,src_exponent)) {
811da177e4SLinus Torvalds inexact = TRUE;
821da177e4SLinus Torvalds /* round result */
831da177e4SLinus Torvalds switch (Rounding_mode()) {
841da177e4SLinus Torvalds case ROUNDPLUS:
851da177e4SLinus Torvalds if (Sgl_iszero_sign(src)) Sgl_increment(result);
861da177e4SLinus Torvalds break;
871da177e4SLinus Torvalds case ROUNDMINUS:
881da177e4SLinus Torvalds if (Sgl_isone_sign(src)) Sgl_increment(result);
891da177e4SLinus Torvalds break;
901da177e4SLinus Torvalds case ROUNDNEAREST:
911da177e4SLinus Torvalds if (Sgl_isone_roundbit(src,src_exponent))
921da177e4SLinus Torvalds if (Sgl_isone_stickybit(src,src_exponent)
931da177e4SLinus Torvalds || (Sgl_isone_lowmantissa(result)))
941da177e4SLinus Torvalds Sgl_increment(result);
951da177e4SLinus Torvalds }
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds Sgl_leftshift(result,(SGL_P-1) - (src_exponent));
981da177e4SLinus Torvalds if (Sgl_isone_hiddenoverflow(result))
991da177e4SLinus Torvalds Sgl_set_exponent(result,src_exponent + (SGL_BIAS+1));
1001da177e4SLinus Torvalds else Sgl_set_exponent(result,src_exponent + SGL_BIAS);
1011da177e4SLinus Torvalds }
1021da177e4SLinus Torvalds else {
1031da177e4SLinus Torvalds result = src; /* set sign */
1041da177e4SLinus Torvalds Sgl_setzero_exponentmantissa(result);
1051da177e4SLinus Torvalds /* check for inexact */
1061da177e4SLinus Torvalds if (Sgl_isnotzero_exponentmantissa(src)) {
1071da177e4SLinus Torvalds inexact = TRUE;
1081da177e4SLinus Torvalds /* round result */
1091da177e4SLinus Torvalds switch (Rounding_mode()) {
1101da177e4SLinus Torvalds case ROUNDPLUS:
1111da177e4SLinus Torvalds if (Sgl_iszero_sign(src))
1121da177e4SLinus Torvalds Sgl_set_exponent(result,SGL_BIAS);
1131da177e4SLinus Torvalds break;
1141da177e4SLinus Torvalds case ROUNDMINUS:
1151da177e4SLinus Torvalds if (Sgl_isone_sign(src))
1161da177e4SLinus Torvalds Sgl_set_exponent(result,SGL_BIAS);
1171da177e4SLinus Torvalds break;
1181da177e4SLinus Torvalds case ROUNDNEAREST:
1191da177e4SLinus Torvalds if (src_exponent == -1)
1201da177e4SLinus Torvalds if (Sgl_isnotzero_mantissa(src))
1211da177e4SLinus Torvalds Sgl_set_exponent(result,SGL_BIAS);
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds }
1241da177e4SLinus Torvalds }
1251da177e4SLinus Torvalds *dstptr = result;
1261da177e4SLinus Torvalds if (inexact) {
1271da177e4SLinus Torvalds if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
1281da177e4SLinus Torvalds else Set_inexactflag();
1291da177e4SLinus Torvalds }
1301da177e4SLinus Torvalds return(NOEXCEPTION);
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds
1331da177e4SLinus Torvalds /*
1341da177e4SLinus Torvalds * Double Floating-point Round to Integer
1351da177e4SLinus Torvalds */
1361da177e4SLinus Torvalds
1371da177e4SLinus Torvalds /*ARGSUSED*/
1381da177e4SLinus Torvalds int
dbl_frnd(dbl_floating_point * srcptr,unsigned int * nullptr,dbl_floating_point * dstptr,unsigned int * status)1391da177e4SLinus Torvalds dbl_frnd(
1401da177e4SLinus Torvalds dbl_floating_point *srcptr,
1411da177e4SLinus Torvalds unsigned int *nullptr,
1421da177e4SLinus Torvalds dbl_floating_point *dstptr,
1431da177e4SLinus Torvalds unsigned int *status)
1441da177e4SLinus Torvalds {
1451da177e4SLinus Torvalds register unsigned int srcp1, srcp2, resultp1, resultp2;
1461da177e4SLinus Torvalds register int src_exponent;
1471da177e4SLinus Torvalds register boolean inexact = FALSE;
1481da177e4SLinus Torvalds
1491da177e4SLinus Torvalds Dbl_copyfromptr(srcptr,srcp1,srcp2);
1501da177e4SLinus Torvalds /*
1511da177e4SLinus Torvalds * check source operand for NaN or infinity
1521da177e4SLinus Torvalds */
1531da177e4SLinus Torvalds if ((src_exponent = Dbl_exponent(srcp1)) == DBL_INFINITY_EXPONENT) {
1541da177e4SLinus Torvalds /*
1551da177e4SLinus Torvalds * is signaling NaN?
1561da177e4SLinus Torvalds */
1571da177e4SLinus Torvalds if (Dbl_isone_signaling(srcp1)) {
1581da177e4SLinus Torvalds /* trap if INVALIDTRAP enabled */
1591da177e4SLinus Torvalds if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
1601da177e4SLinus Torvalds /* make NaN quiet */
1611da177e4SLinus Torvalds Set_invalidflag();
1621da177e4SLinus Torvalds Dbl_set_quiet(srcp1);
1631da177e4SLinus Torvalds }
1641da177e4SLinus Torvalds /*
1651da177e4SLinus Torvalds * return quiet NaN or infinity
1661da177e4SLinus Torvalds */
1671da177e4SLinus Torvalds Dbl_copytoptr(srcp1,srcp2,dstptr);
1681da177e4SLinus Torvalds return(NOEXCEPTION);
1691da177e4SLinus Torvalds }
1701da177e4SLinus Torvalds /*
1711da177e4SLinus Torvalds * Need to round?
1721da177e4SLinus Torvalds */
1731da177e4SLinus Torvalds if ((src_exponent -= DBL_BIAS) >= DBL_P - 1) {
1741da177e4SLinus Torvalds Dbl_copytoptr(srcp1,srcp2,dstptr);
1751da177e4SLinus Torvalds return(NOEXCEPTION);
1761da177e4SLinus Torvalds }
1771da177e4SLinus Torvalds /*
1781da177e4SLinus Torvalds * Generate result
1791da177e4SLinus Torvalds */
1801da177e4SLinus Torvalds if (src_exponent >= 0) {
1811da177e4SLinus Torvalds Dbl_clear_exponent_set_hidden(srcp1);
1821da177e4SLinus Torvalds resultp1 = srcp1;
1831da177e4SLinus Torvalds resultp2 = srcp2;
1841da177e4SLinus Torvalds Dbl_rightshift(resultp1,resultp2,(DBL_P-1) - (src_exponent));
1851da177e4SLinus Torvalds /* check for inexact */
1861da177e4SLinus Torvalds if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
1871da177e4SLinus Torvalds inexact = TRUE;
1881da177e4SLinus Torvalds /* round result */
1891da177e4SLinus Torvalds switch (Rounding_mode()) {
1901da177e4SLinus Torvalds case ROUNDPLUS:
1911da177e4SLinus Torvalds if (Dbl_iszero_sign(srcp1))
1921da177e4SLinus Torvalds Dbl_increment(resultp1,resultp2);
1931da177e4SLinus Torvalds break;
1941da177e4SLinus Torvalds case ROUNDMINUS:
1951da177e4SLinus Torvalds if (Dbl_isone_sign(srcp1))
1961da177e4SLinus Torvalds Dbl_increment(resultp1,resultp2);
1971da177e4SLinus Torvalds break;
1981da177e4SLinus Torvalds case ROUNDNEAREST:
1991da177e4SLinus Torvalds if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
2001da177e4SLinus Torvalds if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent)
2011da177e4SLinus Torvalds || (Dbl_isone_lowmantissap2(resultp2)))
2021da177e4SLinus Torvalds Dbl_increment(resultp1,resultp2);
2031da177e4SLinus Torvalds }
2041da177e4SLinus Torvalds }
2051da177e4SLinus Torvalds Dbl_leftshift(resultp1,resultp2,(DBL_P-1) - (src_exponent));
2061da177e4SLinus Torvalds if (Dbl_isone_hiddenoverflow(resultp1))
2071da177e4SLinus Torvalds Dbl_set_exponent(resultp1,src_exponent + (DBL_BIAS+1));
2081da177e4SLinus Torvalds else Dbl_set_exponent(resultp1,src_exponent + DBL_BIAS);
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds else {
2111da177e4SLinus Torvalds resultp1 = srcp1; /* set sign */
2121da177e4SLinus Torvalds Dbl_setzero_exponentmantissa(resultp1,resultp2);
2131da177e4SLinus Torvalds /* check for inexact */
2141da177e4SLinus Torvalds if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
2151da177e4SLinus Torvalds inexact = TRUE;
2161da177e4SLinus Torvalds /* round result */
2171da177e4SLinus Torvalds switch (Rounding_mode()) {
2181da177e4SLinus Torvalds case ROUNDPLUS:
2191da177e4SLinus Torvalds if (Dbl_iszero_sign(srcp1))
2201da177e4SLinus Torvalds Dbl_set_exponent(resultp1,DBL_BIAS);
2211da177e4SLinus Torvalds break;
2221da177e4SLinus Torvalds case ROUNDMINUS:
2231da177e4SLinus Torvalds if (Dbl_isone_sign(srcp1))
2241da177e4SLinus Torvalds Dbl_set_exponent(resultp1,DBL_BIAS);
2251da177e4SLinus Torvalds break;
2261da177e4SLinus Torvalds case ROUNDNEAREST:
2271da177e4SLinus Torvalds if (src_exponent == -1)
2281da177e4SLinus Torvalds if (Dbl_isnotzero_mantissa(srcp1,srcp2))
2291da177e4SLinus Torvalds Dbl_set_exponent(resultp1,DBL_BIAS);
2301da177e4SLinus Torvalds }
2311da177e4SLinus Torvalds }
2321da177e4SLinus Torvalds }
2331da177e4SLinus Torvalds Dbl_copytoptr(resultp1,resultp2,dstptr);
2341da177e4SLinus Torvalds if (inexact) {
2351da177e4SLinus Torvalds if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
2361da177e4SLinus Torvalds else Set_inexactflag();
2371da177e4SLinus Torvalds }
2381da177e4SLinus Torvalds return(NOEXCEPTION);
2391da177e4SLinus Torvalds }
240