This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Builtin function roundeven folding implementation


Hi Joseph,

can you please have look at this patch from Tejas, whether it is perhaps
ready to be committed to trunk or what things still need to be
addressed?

Thanks a lot,

Martin



On Fri, Jun 28 2019, Tejas Joshi wrote:
> Hi.
> This patch includes implementation of new function roundeven along
> with two utility functions. The patch bootstraps on x86_64-linux-gnu
> and passes regression tests.
>
> Thanks,
> Tejas
>
> gcc/ChangeLog:
>
> 2019-06-12  Tejas Joshi  <tejasjoshi9673@gmail.com>
>
>     * builtins.c (mathfn_built_in_2): Added CASE_MATHFN for ROUNDEVEN.
>     * builtins.def: Added function definitions for roundeven function
>     variants.
>     * fold-const-call.c (fold_const_call_ss): Added case for function
>     call and fold_const_conversion call for roundeven function.
>     * fold-const.c (negate_mathfn_p): Added case for roundeven function.
>     (tree_call_nonnegative_warnv_p): Added case for roundeven function.
>     (integer_valued_real_call_p): Added case for roundeven function.
>     * real.c (is_even): New function. Returns true if real number is
>     even, otherwise returns false.
>     (is_halfway_below): New function. Returns true if real number is
>     halfway between two integers, else return false.
>     (real_roundeven): New function. Round real number to nearest
>     integer, rounding halfway cases towards even.
>     * real.h (real_value): Added descriptive comments.
>     Added function declaration for roundeven function.
>
> gcc/testsuite/ChangeLog:
>
> 2019-06-12  Tejas Joshi  <tejasjoshi9673@gmail.com>
>
>     * gcc.dg/torture/builtin-round-roundeven.c: New test.
>     * gcc.dg/torture/builtin-round-roundevenf128.c: New test.
> diff --git a/gcc/builtins.c b/gcc/builtins.c
> index 3463ffb1539..85a945877a4 100644
> --- a/gcc/builtins.c
> +++ b/gcc/builtins.c
> @@ -2085,6 +2085,7 @@ mathfn_built_in_2 (tree type, combined_fn fn)
>      CASE_MATHFN (REMQUO)
>      CASE_MATHFN_FLOATN (RINT)
>      CASE_MATHFN_FLOATN (ROUND)
> +    CASE_MATHFN (ROUNDEVEN)
>      CASE_MATHFN (SCALB)
>      CASE_MATHFN (SCALBLN)
>      CASE_MATHFN (SCALBN)
> diff --git a/gcc/builtins.def b/gcc/builtins.def
> index 6d41bdb4f44..8bb7027aac7 100644
> --- a/gcc/builtins.def
> +++ b/gcc/builtins.def
> @@ -542,12 +542,18 @@ DEF_C99_BUILTIN        (BUILT_IN_RINTL, "rintl", BT_FN_LONGDOUBLE_LONGDOUBLE, AT
>  #define RINT_TYPE(F) BT_FN_##F##_##F
>  DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_RINT, "rint", RINT_TYPE, ATTR_CONST_NOTHROW_LEAF_LIST)
>  #undef RINT_TYPE
> +DEF_EXT_LIB_BUILTIN    (BUILT_IN_ROUNDEVEN, "roundeven", BT_FN_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
> +DEF_EXT_LIB_BUILTIN    (BUILT_IN_ROUNDEVENF, "roundevenf", BT_FN_FLOAT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
> +DEF_EXT_LIB_BUILTIN    (BUILT_IN_ROUNDEVENL, "roundevenl", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_C99_BUILTIN        (BUILT_IN_ROUND, "round", BT_FN_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_C99_BUILTIN        (BUILT_IN_ROUNDF, "roundf", BT_FN_FLOAT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_C99_BUILTIN        (BUILT_IN_ROUNDL, "roundl", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
>  #define ROUND_TYPE(F) BT_FN_##F##_##F
>  DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_ROUND, "round", ROUND_TYPE, ATTR_CONST_NOTHROW_LEAF_LIST)
>  #undef ROUND_TYPE
> +#define ROUNDEVEN_TYPE(F) BT_FN_##F##_##F
> +DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_ROUNDEVEN, "roundeven", ROUNDEVEN_TYPE, ATTR_CONST_NOTHROW_LEAF_LIST)
> +#undef ROUNDEVEN_TYPE
>  DEF_EXT_LIB_BUILTIN    (BUILT_IN_SCALB, "scalb", BT_FN_DOUBLE_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
>  DEF_EXT_LIB_BUILTIN    (BUILT_IN_SCALBF, "scalbf", BT_FN_FLOAT_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
>  DEF_EXT_LIB_BUILTIN    (BUILT_IN_SCALBL, "scalbl", BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
> diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c
> index 702c8b4057a..d9b546e6803 100644
> --- a/gcc/fold-const-call.c
> +++ b/gcc/fold-const-call.c
> @@ -836,6 +836,15 @@ fold_const_call_ss (real_value *result, combined_fn fn,
>  	}
>        return false;
>  
> +    CASE_CFN_ROUNDEVEN:
> +    CASE_CFN_ROUNDEVEN_FN:
> +      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
> +  {
> +    real_roundeven (result, format, arg);
> +    return true;
> +  }
> +      return false;
> +
>      CASE_CFN_LOGB:
>        return fold_const_logb (result, arg, format);
>  
> @@ -898,6 +907,10 @@ fold_const_call_ss (wide_int *result, combined_fn fn,
>        return fold_const_conversion (result, real_round, arg,
>  				    precision, format);
>  
> +    CASE_CFN_ROUNDEVEN:
> +    CASE_CFN_ROUNDEVEN_FN:
> +      return fold_const_conversion (result, real_roundeven, arg, precision, format);
> +
>      CASE_CFN_IRINT:
>      CASE_CFN_LRINT:
>      CASE_CFN_LLRINT:
> diff --git a/gcc/fold-const.c b/gcc/fold-const.c
> index 0ca472d422f..07d82a17e25 100644
> --- a/gcc/fold-const.c
> +++ b/gcc/fold-const.c
> @@ -329,6 +329,8 @@ negate_mathfn_p (combined_fn fn)
>      CASE_CFN_LLROUND:
>      CASE_CFN_LROUND:
>      CASE_CFN_ROUND:
> +    CASE_CFN_ROUNDEVEN:
> +    CASE_CFN_ROUNDEVEN_FN:
>      CASE_CFN_SIN:
>      CASE_CFN_SINH:
>      CASE_CFN_TAN:
> @@ -13063,6 +13065,8 @@ tree_call_nonnegative_warnv_p (tree type, combined_fn fn, tree arg0, tree arg1,
>      CASE_CFN_RINT_FN:
>      CASE_CFN_ROUND:
>      CASE_CFN_ROUND_FN:
> +    CASE_CFN_ROUNDEVEN:
> +    CASE_CFN_ROUNDEVEN_FN:
>      CASE_CFN_SCALB:
>      CASE_CFN_SCALBLN:
>      CASE_CFN_SCALBN:
> @@ -13586,6 +13590,8 @@ integer_valued_real_call_p (combined_fn fn, tree arg0, tree arg1, int depth)
>      CASE_CFN_RINT_FN:
>      CASE_CFN_ROUND:
>      CASE_CFN_ROUND_FN:
> +    CASE_CFN_ROUNDEVEN:
> +    CASE_CFN_ROUNDEVEN_FN:
>      CASE_CFN_TRUNC:
>      CASE_CFN_TRUNC_FN:
>        return true;
> diff --git a/gcc/real.c b/gcc/real.c
> index 0164f097a53..ab71430709f 100644
> --- a/gcc/real.c
> +++ b/gcc/real.c
> @@ -5010,6 +5010,89 @@ real_round (REAL_VALUE_TYPE *r, format_helper fmt,
>      real_convert (r, fmt, r);
>  }
>  
> +/* Return true including 0 if integer part of R is even, else return
> +   false. The function is not valid for rvc_inf and rvc_nan classes. */
> +
> +bool
> +is_even (REAL_VALUE_TYPE *r)
> +{
> +  gcc_assert (r->cl != rvc_inf);
> +  gcc_assert (r->cl != rvc_nan);
> +
> +  if (r->cl == rvc_zero)
> +    return true;
> +
> +  /* For (-1,1), number is even. */
> +  if (REAL_EXP (r) <= 0)
> +    return true;
> +
> +  /* Check lowest bit, if not set, return true. */
> +  else if (REAL_EXP (r) <= SIGNIFICAND_BITS)
> +  {
> +    unsigned int n = SIGNIFICAND_BITS - REAL_EXP (r);
> +    int w = n / HOST_BITS_PER_LONG;
> +
> +    unsigned long num = ((unsigned long)1 << (n % HOST_BITS_PER_LONG));
> +
> +    if ((r->sig[w] & num) == 0)
> +      return true;
> +  }
> +
> +  else
> +    return true;
> +
> +  return false;
> +}
> +
> +/* Return true if R is halfway between two integers, else return
> +   false. The function is not valid for rvc_inf and rvc_nan classes. */
> +
> +bool
> +is_halfway_below (const REAL_VALUE_TYPE *r)
> +{
> +  gcc_assert (r->cl != rvc_inf);
> +  gcc_assert (r->cl != rvc_nan);
> +  int i;
> +
> +  /* For numbers (-0.5,0) and (0,0.5). */
> +  if (REAL_EXP (r) < 0)
> +    return false;
> +
> +  else if (REAL_EXP (r) < SIGNIFICAND_BITS)
> +  {
> +    unsigned int n = SIGNIFICAND_BITS - REAL_EXP (r) - 1;
> +    int w = n / HOST_BITS_PER_LONG;
> +
> +    for (i = 0; i < w; ++i)
> +      if (r->sig[i] != 0)
> +        return false;
> +
> +    unsigned long num = ((unsigned long)1 << (n % HOST_BITS_PER_LONG));
> +
> +    if (((r->sig[w] & num) != 0) && ((r->sig[w] & (num-1)) == 0))
> +      return true;
> +  }
> +  return false;
> +}
> +
> +/* Round X to nearest integer, rounding halfway cases towards even. */
> +
> +void
> +real_roundeven (REAL_VALUE_TYPE *r, format_helper fmt,
> +		const REAL_VALUE_TYPE *x)
> +{
> +  if (is_halfway_below (x))
> +  {
> +    do_add (r, x, &dconsthalf, x->sign);
> +    if (!is_even (r))
> +      do_add (r, r, &dconstm1, x->sign);
> +    if (fmt)
> +      real_convert (r, fmt, r);
> +  }
> +  else
> +    real_round (r, fmt, x);
> +}
> +
>  /* Set the sign of R to the sign of X.  */
>  
>  void
> diff --git a/gcc/real.h b/gcc/real.h
> index 95b9db83d24..76889bff0ea 100644
> --- a/gcc/real.h
> +++ b/gcc/real.h
> @@ -41,11 +41,18 @@ struct GTY(()) real_value {
>       sure they're packed together, otherwise REAL_VALUE_TYPE_SIZE will
>       be miscomputed.  */
>    unsigned int /* ENUM_BITFIELD (real_value_class) */ cl : 2;
> +  /* 1 if number is decimal floating point */
>    unsigned int decimal : 1;
> +  /* 1 if number is negative */
>    unsigned int sign : 1;
> +  /* 1 if number is signalling */
>    unsigned int signalling : 1;
> +  /* 1 if number is canonical
> +  All are generally used for handling cases in real.c */
>    unsigned int canonical : 1;
> +  /* unbiased exponent of the number */
>    unsigned int uexp : EXP_BITS;
> +  /* significand of the number */
>    unsigned long sig[SIGSZ];
>  };
>  
> @@ -500,6 +507,8 @@ extern void real_ceil (REAL_VALUE_TYPE *, format_helper,
>  		       const REAL_VALUE_TYPE *);
>  extern void real_round (REAL_VALUE_TYPE *, format_helper,
>  			const REAL_VALUE_TYPE *);
> +extern void real_roundeven (REAL_VALUE_TYPE *, format_helper,
> +      const REAL_VALUE_TYPE *);
>  
>  /* Set the sign of R to the sign of X.  */
>  extern void real_copysign (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
> diff --git a/gcc/testsuite/gcc.dg/torture/builtin-round-roundeven.c b/gcc/testsuite/gcc.dg/torture/builtin-round-roundeven.c
> new file mode 100644
> index 00000000000..f75adf6ec8a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/builtin-round-roundeven.c
> @@ -0,0 +1,23 @@
> +/* { dg-do link } */
> +
> +extern int link_error (int);
> +
> +#define TEST(FN, VALUE, RESULT) \
> +  if (__builtin_##FN (VALUE) != RESULT) link_error (__LINE__);
> +
> +int
> +main (void)
> +{
> +  TEST(roundeven,  0, 0);
> +  TEST(roundeven,  0.5, 0);
> +  TEST(roundeven,  -0.5, 0);
> +  TEST(roundeven,  6, 6);
> +  TEST(roundeven,  -8, -8);
> +  TEST(roundeven,  2.5, 2);
> +  TEST(roundeven,  3.5, 4);
> +  TEST(roundeven,  -1.5, -2);
> +  TEST(roundeven,  3.499, 3);
> +  TEST(roundeven,  3.501, 4);
> +
> +  return 0;
> +}
> \ No newline at end of file
> diff --git a/gcc/testsuite/gcc.dg/torture/builtin-round-roundevenf128.c b/gcc/testsuite/gcc.dg/torture/builtin-round-roundevenf128.c
> new file mode 100644
> index 00000000000..592bad49623
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/builtin-round-roundevenf128.c
> @@ -0,0 +1,20 @@
> +/* { dg-do link } */
> +/* { dg-add-options float128 } */
> +/* { dg-require-effective-target float128 } */
> +
> +extern int link_error (int);
> +
> +#define TEST(FN, VALUE, RESULT) \
> +  if (__builtin_##FN##f128 (VALUE) != RESULT) link_error (__LINE__);
> +
> +int
> +main (void)
> +{
> +  TEST(roundeven,  (0x1p64+0.5f128), (0x1p64f128));
> +  TEST(roundeven,  (0x1p63+0.5f128), (0x1p63f128));
> +  TEST(roundeven,  (0x1p63-0.5f128), (0x1p63f128));
> +  TEST(roundeven,  (0x1p64-0.5f128), (0x1p64f128));
> +  TEST(roundeven,  (0x1p64+0.501f128), (0x1p64+1.0f128));
> +  TEST(roundeven,  (0x1.C00000000000039A5653p1f128), (0x1p2f128))
> +  return 0;
> +}
> \ No newline at end of file


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]