(root)/
glibc-2.38/
math/
math-narrow.h
       1  /* Helper macros for functions returning a narrower type.
       2     Copyright (C) 2018-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #ifndef	_MATH_NARROW_H
      20  #define	_MATH_NARROW_H	1
      21  
      22  #include <bits/floatn.h>
      23  #include <bits/long-double.h>
      24  #include <errno.h>
      25  #include <fenv.h>
      26  #include <ieee754.h>
      27  #include <math-barriers.h>
      28  #include <math_private.h>
      29  #include <fenv_private.h>
      30  #include <math-narrow-alias.h>
      31  #include <stdbool.h>
      32  
      33  /* Carry out a computation using round-to-odd.  The computation is
      34     EXPR; the union type in which to store the result is UNION and the
      35     subfield of the "ieee" field of that union with the low part of the
      36     mantissa is MANTISSA; SUFFIX is the suffix for both underlying libm
      37     functions for the argument type (for computations where a libm
      38     function rather than a C operator is used when argument and result
      39     types are the same) and the libc_fe* macros to ensure that the
      40     correct rounding mode is used, for platforms with multiple rounding
      41     modes where those macros set only the relevant mode.
      42     CLEAR_UNDERFLOW indicates whether underflow exceptions must be
      43     cleared (in the case where a round-toward-zero underflow might not
      44     indicate an underflow after narrowing, when that narrowing only
      45     reduces precision not exponent range and the architecture uses
      46     before-rounding tininess detection).  This macro does not work
      47     correctly if the sign of an exact zero result depends on the
      48     rounding mode, so that case must be checked for separately.  */
      49  #define ROUND_TO_ODD(EXPR, UNION, SUFFIX, MANTISSA, CLEAR_UNDERFLOW)	\
      50    ({									\
      51      fenv_t env;								\
      52      UNION u;								\
      53  									\
      54      libc_feholdexcept_setround ## SUFFIX (&env, FE_TOWARDZERO);		\
      55      u.d = (EXPR);							\
      56      math_force_eval (u.d);						\
      57      if (CLEAR_UNDERFLOW)						\
      58        feclearexcept (FE_UNDERFLOW);					\
      59      u.ieee.MANTISSA							\
      60        |= libc_feupdateenv_test ## SUFFIX (&env, FE_INEXACT) != 0;	\
      61  									\
      62      u.d;								\
      63    })
      64  
      65  /* Check for error conditions from a narrowing add function returning
      66     RET with arguments X and Y and set errno as needed.  Overflow and
      67     underflow can occur for finite arguments and a domain error for
      68     infinite ones.  */
      69  #define CHECK_NARROW_ADD(RET, X, Y)			\
      70    do							\
      71      {							\
      72        if (!isfinite (RET))				\
      73  	{						\
      74  	  if (isnan (RET))				\
      75  	    {						\
      76  	      if (!isnan (X) && !isnan (Y))		\
      77  		__set_errno (EDOM);			\
      78  	    }						\
      79  	  else if (isfinite (X) && isfinite (Y))	\
      80  	    __set_errno (ERANGE);			\
      81  	}						\
      82        else if ((RET) == 0 && (X) != -(Y))		\
      83  	__set_errno (ERANGE);				\
      84      }							\
      85    while (0)
      86  
      87  /* Implement narrowing add using round-to-odd.  The arguments are X
      88     and Y, the return type is TYPE and UNION, MANTISSA and SUFFIX are
      89     as for ROUND_TO_ODD.  */
      90  #define NARROW_ADD_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA)	\
      91    do									\
      92      {									\
      93        TYPE ret;								\
      94  									\
      95        /* Ensure a zero result is computed in the original rounding	\
      96  	 mode.  */							\
      97        if ((X) == -(Y))							\
      98  	ret = (TYPE) ((X) + (Y));					\
      99        else								\
     100  	ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) + (Y),		\
     101  				   UNION, SUFFIX, MANTISSA, false);	\
     102  									\
     103        CHECK_NARROW_ADD (ret, (X), (Y));					\
     104        return ret;							\
     105      }									\
     106    while (0)
     107  
     108  /* Implement a narrowing add function that is not actually narrowing
     109     or where no attempt is made to be correctly rounding (the latter
     110     only applies to IBM long double).  The arguments are X and Y and
     111     the return type is TYPE.  */
     112  #define NARROW_ADD_TRIVIAL(X, Y, TYPE)		\
     113    do						\
     114      {						\
     115        TYPE ret;					\
     116  						\
     117        ret = (TYPE) ((X) + (Y));			\
     118        CHECK_NARROW_ADD (ret, (X), (Y));		\
     119        return ret;				\
     120      }						\
     121    while (0)
     122  
     123  /* Check for error conditions from a narrowing subtract function
     124     returning RET with arguments X and Y and set errno as needed.
     125     Overflow and underflow can occur for finite arguments and a domain
     126     error for infinite ones.  */
     127  #define CHECK_NARROW_SUB(RET, X, Y)			\
     128    do							\
     129      {							\
     130        if (!isfinite (RET))				\
     131  	{						\
     132  	  if (isnan (RET))				\
     133  	    {						\
     134  	      if (!isnan (X) && !isnan (Y))		\
     135  		__set_errno (EDOM);			\
     136  	    }						\
     137  	  else if (isfinite (X) && isfinite (Y))	\
     138  	    __set_errno (ERANGE);			\
     139  	}						\
     140        else if ((RET) == 0 && (X) != (Y))		\
     141  	__set_errno (ERANGE);				\
     142      }							\
     143    while (0)
     144  
     145  /* Implement narrowing subtract using round-to-odd.  The arguments are
     146     X and Y, the return type is TYPE and UNION, MANTISSA and SUFFIX are
     147     as for ROUND_TO_ODD.  */
     148  #define NARROW_SUB_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA)	\
     149    do									\
     150      {									\
     151        TYPE ret;								\
     152  									\
     153        /* Ensure a zero result is computed in the original rounding	\
     154  	 mode.  */							\
     155        if ((X) == (Y))							\
     156  	ret = (TYPE) ((X) - (Y));					\
     157        else								\
     158  	ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) - (Y),		\
     159  				   UNION, SUFFIX, MANTISSA, false);	\
     160  									\
     161        CHECK_NARROW_SUB (ret, (X), (Y));					\
     162        return ret;							\
     163      }									\
     164    while (0)
     165  
     166  /* Implement a narrowing subtract function that is not actually
     167     narrowing or where no attempt is made to be correctly rounding (the
     168     latter only applies to IBM long double).  The arguments are X and Y
     169     and the return type is TYPE.  */
     170  #define NARROW_SUB_TRIVIAL(X, Y, TYPE)		\
     171    do						\
     172      {						\
     173        TYPE ret;					\
     174  						\
     175        ret = (TYPE) ((X) - (Y));			\
     176        CHECK_NARROW_SUB (ret, (X), (Y));		\
     177        return ret;				\
     178      }						\
     179    while (0)
     180  
     181  /* Check for error conditions from a narrowing multiply function
     182     returning RET with arguments X and Y and set errno as needed.
     183     Overflow and underflow can occur for finite arguments and a domain
     184     error for Inf * 0.  */
     185  #define CHECK_NARROW_MUL(RET, X, Y)			\
     186    do							\
     187      {							\
     188        if (!isfinite (RET))				\
     189  	{						\
     190  	  if (isnan (RET))				\
     191  	    {						\
     192  	      if (!isnan (X) && !isnan (Y))		\
     193  		__set_errno (EDOM);			\
     194  	    }						\
     195  	  else if (isfinite (X) && isfinite (Y))	\
     196  	    __set_errno (ERANGE);			\
     197  	}						\
     198        else if ((RET) == 0 && (X) != 0 && (Y) != 0)	\
     199  	__set_errno (ERANGE);				\
     200      }							\
     201    while (0)
     202  
     203  /* Implement narrowing multiply using round-to-odd.  The arguments are
     204     X and Y, the return type is TYPE and UNION, MANTISSA, SUFFIX and
     205     CLEAR_UNDERFLOW are as for ROUND_TO_ODD.  */
     206  #define NARROW_MUL_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA,	\
     207  				CLEAR_UNDERFLOW)			\
     208    do									\
     209      {									\
     210        TYPE ret;								\
     211  									\
     212        ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) * (Y),		\
     213  				 UNION, SUFFIX, MANTISSA,		\
     214  				 CLEAR_UNDERFLOW);			\
     215  									\
     216        CHECK_NARROW_MUL (ret, (X), (Y));					\
     217        return ret;							\
     218      }									\
     219    while (0)
     220  
     221  /* Implement a narrowing multiply function that is not actually
     222     narrowing or where no attempt is made to be correctly rounding (the
     223     latter only applies to IBM long double).  The arguments are X and Y
     224     and the return type is TYPE.  */
     225  #define NARROW_MUL_TRIVIAL(X, Y, TYPE)		\
     226    do						\
     227      {						\
     228        TYPE ret;					\
     229  						\
     230        ret = (TYPE) ((X) * (Y));			\
     231        CHECK_NARROW_MUL (ret, (X), (Y));		\
     232        return ret;				\
     233      }						\
     234    while (0)
     235  
     236  /* Check for error conditions from a narrowing divide function
     237     returning RET with arguments X and Y and set errno as needed.
     238     Overflow, underflow and divide-by-zero can occur for finite
     239     arguments and a domain error for Inf / Inf and 0 / 0.  */
     240  #define CHECK_NARROW_DIV(RET, X, Y)			\
     241    do							\
     242      {							\
     243        if (!isfinite (RET))				\
     244  	{						\
     245  	  if (isnan (RET))				\
     246  	    {						\
     247  	      if (!isnan (X) && !isnan (Y))		\
     248  		__set_errno (EDOM);			\
     249  	    }						\
     250  	  else if (isfinite (X))			\
     251  	    __set_errno (ERANGE);			\
     252  	}						\
     253        else if ((RET) == 0 && (X) != 0 && !isinf (Y))	\
     254  	__set_errno (ERANGE);				\
     255      }							\
     256    while (0)
     257  
     258  /* Implement narrowing divide using round-to-odd.  The arguments are X
     259     and Y, the return type is TYPE and UNION, MANTISSA, SUFFIX and
     260     CLEAR_UNDERFLOW are as for ROUND_TO_ODD.  */
     261  #define NARROW_DIV_ROUND_TO_ODD(X, Y, TYPE, UNION, SUFFIX, MANTISSA,	\
     262  				CLEAR_UNDERFLOW)			\
     263    do									\
     264      {									\
     265        TYPE ret;								\
     266  									\
     267        ret = (TYPE) ROUND_TO_ODD (math_opt_barrier (X) / (Y),		\
     268  				 UNION, SUFFIX, MANTISSA,		\
     269  				 CLEAR_UNDERFLOW);			\
     270  									\
     271        CHECK_NARROW_DIV (ret, (X), (Y));					\
     272        return ret;							\
     273      }									\
     274    while (0)
     275  
     276  /* Implement a narrowing divide function that is not actually
     277     narrowing or where no attempt is made to be correctly rounding (the
     278     latter only applies to IBM long double).  The arguments are X and Y
     279     and the return type is TYPE.  */
     280  #define NARROW_DIV_TRIVIAL(X, Y, TYPE)		\
     281    do						\
     282      {						\
     283        TYPE ret;					\
     284  						\
     285        ret = (TYPE) ((X) / (Y));			\
     286        CHECK_NARROW_DIV (ret, (X), (Y));		\
     287        return ret;				\
     288      }						\
     289    while (0)
     290  
     291  /* Check for error conditions from a narrowing square root function
     292     returning RET with argument X and set errno as needed.  Overflow
     293     and underflow can occur for finite positive arguments and a domain
     294     error for negative arguments.  */
     295  #define CHECK_NARROW_SQRT(RET, X)		\
     296    do						\
     297      {						\
     298        if (!isfinite (RET))			\
     299  	{					\
     300  	  if (isnan (RET))			\
     301  	    {					\
     302  	      if (!isnan (X))			\
     303  		__set_errno (EDOM);		\
     304  	    }					\
     305  	  else if (isfinite (X))		\
     306  	    __set_errno (ERANGE);		\
     307  	}					\
     308        else if ((RET) == 0 && (X) != 0)		\
     309  	__set_errno (ERANGE);			\
     310      }						\
     311    while (0)
     312  
     313  /* Implement narrowing square root using round-to-odd.  The argument
     314     is X, the return type is TYPE and UNION, MANTISSA and SUFFIX are as
     315     for ROUND_TO_ODD.  */
     316  #define NARROW_SQRT_ROUND_TO_ODD(X, TYPE, UNION, SUFFIX, MANTISSA)	\
     317    do									\
     318      {									\
     319        TYPE ret;								\
     320  									\
     321        ret = (TYPE) ROUND_TO_ODD (sqrt ## SUFFIX (math_opt_barrier (X)),	\
     322  				 UNION, SUFFIX, MANTISSA, false);	\
     323  									\
     324        CHECK_NARROW_SQRT (ret, (X));					\
     325        return ret;							\
     326      }									\
     327    while (0)
     328  
     329  /* Implement a narrowing square root function where no attempt is made
     330     to be correctly rounding (this only applies to IBM long double; the
     331     case where the function is not actually narrowing is handled by
     332     aliasing other sqrt functions in libm, not using this macro).  The
     333     argument is X and the return type is TYPE.  */
     334  #define NARROW_SQRT_TRIVIAL(X, TYPE, SUFFIX)	\
     335    do						\
     336      {						\
     337        TYPE ret;					\
     338  						\
     339        ret = (TYPE) (sqrt ## SUFFIX (X));	\
     340        CHECK_NARROW_SQRT (ret, (X));		\
     341        return ret;				\
     342      }						\
     343    while (0)
     344  
     345  /* Check for error conditions from a narrowing fused multiply-add
     346     function returning RET with arguments X, Y and Z and set errno as
     347     needed.  Checking for error conditions for fma (either narrowing or
     348     not) and setting errno is not currently implemented.  See bug
     349     6801.  */
     350  #define CHECK_NARROW_FMA(RET, X, Y, Z)		\
     351    do						\
     352      {						\
     353      }						\
     354    while (0)
     355  
     356  /* Implement narrowing fused multiply-add using round-to-odd.  The
     357     arguments are X, Y and Z, the return type is TYPE and UNION,
     358     MANTISSA, SUFFIX and CLEAR_UNDERFLOW are as for ROUND_TO_ODD.  */
     359  #define NARROW_FMA_ROUND_TO_ODD(X, Y, Z, TYPE, UNION, SUFFIX, MANTISSA, \
     360  				CLEAR_UNDERFLOW)			\
     361    do									\
     362      {									\
     363        typeof (X) tmp;							\
     364        TYPE ret;								\
     365  									\
     366        tmp = ROUND_TO_ODD (fma ## SUFFIX (math_opt_barrier (X), (Y),	\
     367  					 (Z)),				\
     368  			  UNION, SUFFIX, MANTISSA, CLEAR_UNDERFLOW);	\
     369        /* If the round-to-odd result is zero, the result is an exact	\
     370  	 zero and must be recomputed in the original rounding mode.  */ \
     371        if (tmp == 0)							\
     372  	ret = (TYPE) (math_opt_barrier (X) * (Y) + (Z));		\
     373        else								\
     374  	ret = (TYPE) tmp;						\
     375  									\
     376        CHECK_NARROW_FMA (ret, (X), (Y), (Z));				\
     377        return ret;							\
     378      }									\
     379    while (0)
     380  
     381  /* Implement a narrowing fused multiply-add function where no attempt
     382     is made to be correctly rounding (this only applies to IBM long
     383     double; the case where the function is not actually narrowing is
     384     handled by aliasing other fma functions in libm, not using this
     385     macro).  The arguments are X, Y and Z and the return type is
     386     TYPE.  */
     387  #define NARROW_FMA_TRIVIAL(X, Y, Z, TYPE, SUFFIX)	\
     388    do							\
     389      {							\
     390        TYPE ret;						\
     391  							\
     392        ret = (TYPE) (fma ## SUFFIX ((X), (Y), (Z)));	\
     393        CHECK_NARROW_FMA (ret, (X), (Y), (Z));		\
     394        return ret;					\
     395      }							\
     396    while (0)
     397  
     398  #endif /* math-narrow.h.  */