public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Builtin function roundeven folding implementation
@ 2019-06-28  3:40 Tejas Joshi
  2019-07-29 16:49 ` Martin Jambor
  2019-08-09 21:26 ` Joseph Myers
  0 siblings, 2 replies; 16+ messages in thread
From: Tejas Joshi @ 2019-06-28  3:40 UTC (permalink / raw)
  To: gcc-patches; +Cc: Martin Jambor, hubicka, joseph

[-- Attachment #1: Type: text/plain, Size: 1408 bytes --]

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.

[-- Attachment #2: roundeven.diff --]
[-- Type: text/x-patch, Size: 9089 bytes --]

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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Builtin function roundeven folding implementation
  2019-06-28  3:40 [PATCH] Builtin function roundeven folding implementation Tejas Joshi
@ 2019-07-29 16:49 ` Martin Jambor
  2019-08-09 21:26 ` Joseph Myers
  1 sibling, 0 replies; 16+ messages in thread
From: Martin Jambor @ 2019-07-29 16:49 UTC (permalink / raw)
  To: Tejas Joshi, gcc-patches; +Cc: hubicka, joseph

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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Builtin function roundeven folding implementation
  2019-06-28  3:40 [PATCH] Builtin function roundeven folding implementation Tejas Joshi
  2019-07-29 16:49 ` Martin Jambor
@ 2019-08-09 21:26 ` Joseph Myers
  2019-08-14  7:24   ` Tejas Joshi
  1 sibling, 1 reply; 16+ messages in thread
From: Joseph Myers @ 2019-08-09 21:26 UTC (permalink / raw)
  To: Tejas Joshi; +Cc: gcc-patches, Martin Jambor, hubicka

On Fri, 28 Jun 2019, Tejas Joshi wrote:

> +    CASE_CFN_ROUNDEVEN:
> +    CASE_CFN_ROUNDEVEN_FN:
> +      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)

Checking flag_errno_math here does not make sense.  roundeven never sets 
errno (at least, TS 18661-1 makes it implementation-defined whether sNaN 
input counts as a domain error, but I'm not aware of implementations that 
make it a domain error and set errno, and typically GCC follows glibc in 
such cases in the absence of known implementations requiring a different 
approach).

The only case where you need to avoid folding is where the argument is a 
signaling NaN (it's fine to fold for quiet NaNs).  In that case, you need 
to avoid folding to avoid losing an exception (if the user cares about 
signaling NaNs, they probably care about exceptions) - so it still doesn't 
matter whether the library implementation also sets errno or not.

(Yes, this means the existing ceil / floor / round checks should be 
adjusted just to check for signaling NaN, though that's fairly cosmetic as 
calls to those functions with quiet NaN argument still get folded via 
match.pd.  trunc ought also check for signaling NaN rather than folding 
unconditionally, so all those functions should end up with the same 
conditions for folding.)

> @@ -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);
> +

This is the version of fold_const_call_ss for functions returning a result 
of integer type; roundeven returns an integer value in a floating-point 
type.  I don't think this code should be there, and I don't think this 
version of the function should be called at all for roundeven.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Builtin function roundeven folding implementation
  2019-08-09 21:26 ` Joseph Myers
@ 2019-08-14  7:24   ` Tejas Joshi
  2019-08-21 11:52     ` Martin Jambor
  0 siblings, 1 reply; 16+ messages in thread
From: Tejas Joshi @ 2019-08-14  7:24 UTC (permalink / raw)
  To: gcc-patches; +Cc: Martin Jambor, hubicka, joseph

[-- Attachment #1: Type: text/plain, Size: 3677 bytes --]

Hi.
Here is a clean patch that does not fold roundeven resulting for
integer type and the conditions for folding functions
round/ceil/floor/roundeven and trunc only checks for signaling NaN.
This patch also conforms to GNU's coding style and standards. The fact
that it should be CASE_MATHFN_FLOATN rather than CASE_MATHFN for
roundeven is corrected in i386 expansion patch.

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 roundeven
    function call.
    * 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.

On Sat, 10 Aug 2019 at 02:15, Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Fri, 28 Jun 2019, Tejas Joshi wrote:
>
> > +    CASE_CFN_ROUNDEVEN:
> > +    CASE_CFN_ROUNDEVEN_FN:
> > +      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
>
> Checking flag_errno_math here does not make sense.  roundeven never sets
> errno (at least, TS 18661-1 makes it implementation-defined whether sNaN
> input counts as a domain error, but I'm not aware of implementations that
> make it a domain error and set errno, and typically GCC follows glibc in
> such cases in the absence of known implementations requiring a different
> approach).
>
> The only case where you need to avoid folding is where the argument is a
> signaling NaN (it's fine to fold for quiet NaNs).  In that case, you need
> to avoid folding to avoid losing an exception (if the user cares about
> signaling NaNs, they probably care about exceptions) - so it still doesn't
> matter whether the library implementation also sets errno or not.
>
> (Yes, this means the existing ceil / floor / round checks should be
> adjusted just to check for signaling NaN, though that's fairly cosmetic as
> calls to those functions with quiet NaN argument still get folded via
> match.pd.  trunc ought also check for signaling NaN rather than folding
> unconditionally, so all those functions should end up with the same
> conditions for folding.)
>
> > @@ -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);
> > +
>
> This is the version of fold_const_call_ss for functions returning a result
> of integer type; roundeven returns an integer value in a floating-point
> type.  I don't think this code should be there, and I don't think this
> version of the function should be called at all for roundeven.
>
> --
> Joseph S. Myers
> joseph@codesourcery.com

[-- Attachment #2: roundeven.diff --]
[-- Type: text/x-patch, Size: 9685 bytes --]

diff --git a/gcc/builtins.c b/gcc/builtins.c
index e2ba356c0d3..8ceb077b0bf 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -2056,6 +2056,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..73dfb6980f1 100644
--- a/gcc/fold-const-call.c
+++ b/gcc/fold-const-call.c
@@ -806,7 +806,7 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_FLOOR:
     CASE_CFN_FLOOR_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISNAN (*arg))
 	{
 	  real_floor (result, format, arg);
 	  return true;
@@ -815,7 +815,7 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_CEIL:
     CASE_CFN_CEIL_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISNAN (*arg))
 	{
 	  real_ceil (result, format, arg);
 	  return true;
@@ -824,18 +824,31 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_TRUNC:
     CASE_CFN_TRUNC_FN:
-      real_trunc (result, format, arg);
-      return true;
+      if (!REAL_VALUE_ISNAN (*arg))
+	{
+	  real_trunc (result, format, arg);
+	  return true;
+	}
+      return false;
 
     CASE_CFN_ROUND:
     CASE_CFN_ROUND_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISNAN (*arg))
 	{
 	  real_round (result, format, arg);
 	  return true;
 	}
       return false;
 
+    CASE_CFN_ROUNDEVEN:
+    CASE_CFN_ROUNDEVEN_FN:
+      if (!REAL_VALUE_ISNAN (*arg))
+	{
+	  real_roundeven (result, format, arg);
+	  return true;
+	}
+      return false;
+
     CASE_CFN_LOGB:
       return fold_const_logb (result, arg, format);
 
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..0c0d8c51fe4 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..2f41834ecfd 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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Builtin function roundeven folding implementation
  2019-08-14  7:24   ` Tejas Joshi
@ 2019-08-21 11:52     ` Martin Jambor
  2019-08-21 12:48       ` Joseph Myers
  0 siblings, 1 reply; 16+ messages in thread
From: Martin Jambor @ 2019-08-21 11:52 UTC (permalink / raw)
  To: Tejas Joshi, gcc-patches; +Cc: hubicka, joseph

Hi Tejas,

On Wed, Aug 14 2019, Tejas Joshi wrote:
> Hi.
> Here is a clean patch that does not fold roundeven resulting for
> integer type and the conditions for folding functions
> round/ceil/floor/roundeven and trunc only checks for signaling NaN.

wouldn't checking for *signalling* NaNs mean using the macro
REAL_VALUE_ISSIGNALING_NAN rather than REAL_VALUE_ISNAN?

Joseph, would fixing this make the patch good to go?  Tejas's GSoC
project results would look much better if we could get this and the
(already approved) follow-up patch committed by the end of the week.

Thanks a lot,

Martin


> 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 roundeven
>     function call.
>     * 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.
>
> On Sat, 10 Aug 2019 at 02:15, Joseph Myers <joseph@codesourcery.com> wrote:
>>
>> On Fri, 28 Jun 2019, Tejas Joshi wrote:
>>
>> > +    CASE_CFN_ROUNDEVEN:
>> > +    CASE_CFN_ROUNDEVEN_FN:
>> > +      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
>>
>> Checking flag_errno_math here does not make sense.  roundeven never sets
>> errno (at least, TS 18661-1 makes it implementation-defined whether sNaN
>> input counts as a domain error, but I'm not aware of implementations that
>> make it a domain error and set errno, and typically GCC follows glibc in
>> such cases in the absence of known implementations requiring a different
>> approach).
>>
>> The only case where you need to avoid folding is where the argument is a
>> signaling NaN (it's fine to fold for quiet NaNs).  In that case, you need
>> to avoid folding to avoid losing an exception (if the user cares about
>> signaling NaNs, they probably care about exceptions) - so it still doesn't
>> matter whether the library implementation also sets errno or not.
>>
>> (Yes, this means the existing ceil / floor / round checks should be
>> adjusted just to check for signaling NaN, though that's fairly cosmetic as
>> calls to those functions with quiet NaN argument still get folded via
>> match.pd.  trunc ought also check for signaling NaN rather than folding
>> unconditionally, so all those functions should end up with the same
>> conditions for folding.)
>>
>> > @@ -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);
>> > +
>>
>> This is the version of fold_const_call_ss for functions returning a result
>> of integer type; roundeven returns an integer value in a floating-point
>> type.  I don't think this code should be there, and I don't think this
>> version of the function should be called at all for roundeven.
>>
>> --
>> Joseph S. Myers
>> joseph@codesourcery.com
> diff --git a/gcc/builtins.c b/gcc/builtins.c
> index e2ba356c0d3..8ceb077b0bf 100644
> --- a/gcc/builtins.c
> +++ b/gcc/builtins.c
> @@ -2056,6 +2056,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..73dfb6980f1 100644
> --- a/gcc/fold-const-call.c
> +++ b/gcc/fold-const-call.c
> @@ -806,7 +806,7 @@ fold_const_call_ss (real_value *result, combined_fn fn,
>  
>      CASE_CFN_FLOOR:
>      CASE_CFN_FLOOR_FN:
> -      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
> +      if (!REAL_VALUE_ISNAN (*arg))
>  	{
>  	  real_floor (result, format, arg);
>  	  return true;
> @@ -815,7 +815,7 @@ fold_const_call_ss (real_value *result, combined_fn fn,
>  
>      CASE_CFN_CEIL:
>      CASE_CFN_CEIL_FN:
> -      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
> +      if (!REAL_VALUE_ISNAN (*arg))
>  	{
>  	  real_ceil (result, format, arg);
>  	  return true;
> @@ -824,18 +824,31 @@ fold_const_call_ss (real_value *result, combined_fn fn,
>  
>      CASE_CFN_TRUNC:
>      CASE_CFN_TRUNC_FN:
> -      real_trunc (result, format, arg);
> -      return true;
> +      if (!REAL_VALUE_ISNAN (*arg))
> +	{
> +	  real_trunc (result, format, arg);
> +	  return true;
> +	}
> +      return false;
>  
>      CASE_CFN_ROUND:
>      CASE_CFN_ROUND_FN:
> -      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
> +      if (!REAL_VALUE_ISNAN (*arg))
>  	{
>  	  real_round (result, format, arg);
>  	  return true;
>  	}
>        return false;
>  
> +    CASE_CFN_ROUNDEVEN:
> +    CASE_CFN_ROUNDEVEN_FN:
> +      if (!REAL_VALUE_ISNAN (*arg))
> +	{
> +	  real_roundeven (result, format, arg);
> +	  return true;
> +	}
> +      return false;
> +
>      CASE_CFN_LOGB:
>        return fold_const_logb (result, arg, format);
>  
> 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..0c0d8c51fe4 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..2f41834ecfd 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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Builtin function roundeven folding implementation
  2019-08-21 11:52     ` Martin Jambor
@ 2019-08-21 12:48       ` Joseph Myers
  2019-08-21 19:10         ` Martin Jambor
  0 siblings, 1 reply; 16+ messages in thread
From: Joseph Myers @ 2019-08-21 12:48 UTC (permalink / raw)
  To: Martin Jambor; +Cc: Tejas Joshi, gcc-patches, hubicka

On Wed, 21 Aug 2019, Martin Jambor wrote:

> Hi Tejas,
> 
> On Wed, Aug 14 2019, Tejas Joshi wrote:
> > Hi.
> > Here is a clean patch that does not fold roundeven resulting for
> > integer type and the conditions for folding functions
> > round/ceil/floor/roundeven and trunc only checks for signaling NaN.
> 
> wouldn't checking for *signalling* NaNs mean using the macro
> REAL_VALUE_ISSIGNALING_NAN rather than REAL_VALUE_ISNAN?

Yes, it would.  So the patch should be retested / reposted with that 
change.

> > \ No newline at end of file

This should be fixed (in both places, the tests should each end with 
exactly one newline character).

The new built-in functions roundeven / roundevenf / roundevenl also need 
to be added to the lists in extend.texi (the list of GNU extension 
functions for now, though once we add DEF_C2X_BUILTIN they'd go in a list 
of C2X built-in functions instead).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Builtin function roundeven folding implementation
  2019-08-21 12:48       ` Joseph Myers
@ 2019-08-21 19:10         ` Martin Jambor
  2019-08-21 20:50           ` Joseph Myers
  0 siblings, 1 reply; 16+ messages in thread
From: Martin Jambor @ 2019-08-21 19:10 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Tejas Joshi, gcc-patches, hubicka

Hi,

On Wed, Aug 21 2019, Joseph Myers wrote:
> On Wed, 21 Aug 2019, Martin Jambor wrote:
>
>> Hi Tejas,
>> 
>> On Wed, Aug 14 2019, Tejas Joshi wrote:
>> > Hi.
>> > Here is a clean patch that does not fold roundeven resulting for
>> > integer type and the conditions for folding functions
>> > round/ceil/floor/roundeven and trunc only checks for signaling NaN.
>> 
>> wouldn't checking for *signalling* NaNs mean using the macro
>> REAL_VALUE_ISSIGNALING_NAN rather than REAL_VALUE_ISNAN?
>
> Yes, it would.  So the patch should be retested / reposted with that 
> change.
>
>> > \ No newline at end of file
>
> This should be fixed (in both places, the tests should each end with 
> exactly one newline character).
>
> The new built-in functions roundeven / roundevenf / roundevenl also need 
> to be added to the lists in extend.texi (the list of GNU extension 
> functions for now, though once we add DEF_C2X_BUILTIN they'd go in a list 
> of C2X built-in functions instead).

OK, because I will be committing the patch on Tejas's behalf anyway, I
took the liberty of doing these few last changes too:

  - I replaced all REAL_VALUE_ISNAN in Tejas's patch with
    REAL_VALUE_ISSIGNALING_NAN.

  - I have fixed the missing newlines in the testcases

  - I have listed roundeven variants in extend.texi.  If I did not find
    the right spot, I will gladly move to a more appropriate one.

Otherwise I have not changed the patch in any way.  It has passed
bootstrap and testing on x86_64-linux, I will test on at least aarch64
too together with the followup i386 expansion patch.

Tejas, please have a quick look whether it all looks OK.

Joseph, please let me know if I can commit this to trunk.

Thanks a lot,

Martin


gcc/ChangeLog:

2019-08-21  Tejas Joshi  <tejasjoshi9673@gmail.com>
            Martin Jambor  <mjambor@suse.cz>

    * 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 roundeven
    function call.
    * 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.
    * doc/extend.texi (Other Builtins): Document roundeven and its variants.

gcc/testsuite/ChangeLog:

2019-08-21  Tejas Joshi  <tejasjoshi9673@gmail.com>

    * gcc.dg/torture/builtin-round-roundeven.c: New test.
    * gcc.dg/torture/builtin-round-roundevenf128.c: New test.
---
 gcc/builtins.c                                |  1 +
 gcc/builtins.def                              |  6 ++
 gcc/doc/extend.texi                           | 16 ++++
 gcc/fold-const-call.c                         | 23 +++--
 gcc/fold-const.c                              |  6 ++
 gcc/real.c                                    | 83 +++++++++++++++++++
 gcc/real.h                                    |  9 ++
 .../gcc.dg/torture/builtin-round-roundeven.c  | 23 +++++
 .../torture/builtin-round-roundevenf128.c     | 20 +++++
 9 files changed, 182 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/builtin-round-roundeven.c
 create mode 100644 gcc/testsuite/gcc.dg/torture/builtin-round-roundevenf128.c

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 9a766e4ad63..5149d901a96 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -2056,6 +2056,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/doc/extend.texi b/gcc/doc/extend.texi
index 2ba9b74811a..4d11f522466 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -13584,6 +13584,22 @@ Returns the openacc gang, worker or vector size depending on whether @var{x} is
 0, 1 or 2.
 @end deftypefn
 
+@deftypefn {Built-in Function} double __builtin_roundeven (double x)
+Returns the argument @var{x} rounded to the nearest integer value in
+floating-point format, rounding halfway cases to the nearest even
+integer.
+@end deftypefn
+
+@deftypefn {Built-in Function} float __builtin_roundevenf (float x)
+Similar to @code{__builtin_roundeven}, except the argument and return
+types are @code{float}.
+@end deftypefn
+
+@deftypefn {Built-in Function} {long double} __builtin_roundevenl (long double x)
+Similar to @code{__builtin_roundeven}, except the argument and return types
+are @code{long double}.
+@end deftypefn
+
 @node Target Builtins
 @section Built-in Functions Specific to Particular Target Machines
 
diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c
index e21d8e11072..3a14d2a41c1 100644
--- a/gcc/fold-const-call.c
+++ b/gcc/fold-const-call.c
@@ -836,7 +836,7 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_FLOOR:
     CASE_CFN_FLOOR_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
 	{
 	  real_floor (result, format, arg);
 	  return true;
@@ -845,7 +845,7 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_CEIL:
     CASE_CFN_CEIL_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
 	{
 	  real_ceil (result, format, arg);
 	  return true;
@@ -854,18 +854,31 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_TRUNC:
     CASE_CFN_TRUNC_FN:
-      real_trunc (result, format, arg);
-      return true;
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
+	{
+	  real_trunc (result, format, arg);
+	  return true;
+	}
+      return false;
 
     CASE_CFN_ROUND:
     CASE_CFN_ROUND_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
 	{
 	  real_round (result, format, arg);
 	  return true;
 	}
       return false;
 
+    CASE_CFN_ROUNDEVEN:
+    CASE_CFN_ROUNDEVEN_FN:
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
+	{
+	  real_roundeven (result, format, arg);
+	  return true;
+	}
+      return false;
+
     CASE_CFN_LOGB:
       return fold_const_logb (result, arg, format);
 
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 8c711aba12a..0376cdb73a4 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:
@@ -13107,6 +13109,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:
@@ -13630,6 +13634,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..0c0d8c51fe4 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..2f41834ecfd 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..f3b7b40fc1f
--- /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;
+}
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..42c28ddb0cd
--- /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;
+}
-- 
2.22.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Builtin function roundeven folding implementation
  2019-08-21 19:10         ` Martin Jambor
@ 2019-08-21 20:50           ` Joseph Myers
  2019-08-22 14:40             ` Martin Jambor
  0 siblings, 1 reply; 16+ messages in thread
From: Joseph Myers @ 2019-08-21 20:50 UTC (permalink / raw)
  To: Martin Jambor; +Cc: Tejas Joshi, gcc-patches, hubicka

On Wed, 21 Aug 2019, Martin Jambor wrote:

>   - I have listed roundeven variants in extend.texi.  If I did not find
>     the right spot, I will gladly move to a more appropriate one.

I don't think they should be documented with the __builtin_* that are 
always expanded inline.  They should be documented in the list of 
functions that *might* be expanded inline.  That is, where extend.texi 
says:

  [...]  Many of these
  functions are only optimized in certain cases; if they are not optimized in
  a particular case, a call to the library function is emitted.

  @opindex ansi
  @opindex std
  Outside strict ISO C mode (@option{-ansi}, @option{-std=c90},
  @option{-std=c99} or @option{-std=c11}), the functions
  @code{_exit}, [...]
  may be handled as built-in functions.
  All these functions have corresponding versions
  prefixed with @code{__builtin_}, which may be used even in strict C90
  mode.

(Until we enable these by default for C2X, at which point they'd be listed 
as C2X functions after the C99 ones.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Builtin function roundeven folding implementation
  2019-08-21 20:50           ` Joseph Myers
@ 2019-08-22 14:40             ` Martin Jambor
  2019-08-22 15:52               ` Joseph Myers
  0 siblings, 1 reply; 16+ messages in thread
From: Martin Jambor @ 2019-08-22 14:40 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Tejas Joshi, gcc-patches, hubicka

Hi,

On Wed, Aug 21 2019, Joseph Myers wrote:
> On Wed, 21 Aug 2019, Martin Jambor wrote:
>
>>   - I have listed roundeven variants in extend.texi.  If I did not find
>>     the right spot, I will gladly move to a more appropriate one.
>
> I don't think they should be documented with the __builtin_* that are 
> always expanded inline.  They should be documented in the list of 
> functions that *might* be expanded inline.  That is, where extend.texi 
> says:
>
>   [...]  Many of these
>   functions are only optimized in certain cases; if they are not optimized in
>   a particular case, a call to the library function is emitted.
>
>   @opindex ansi
>   @opindex std
>   Outside strict ISO C mode (@option{-ansi}, @option{-std=c90},
>   @option{-std=c99} or @option{-std=c11}), the functions
>   @code{_exit}, [...]
>   may be handled as built-in functions.
>   All these functions have corresponding versions
>   prefixed with @code{__builtin_}, which may be used even in strict C90
>   mode.
>
> (Until we enable these by default for C2X, at which point they'd be listed 
> as C2X functions after the C99 ones.)
>

that indeed makes more sense.  I have changed that in the patch below.
I hope the patch is good to be committed now and would like to do that
tomorrow.

I have bootstrapped and tested it on x86_64-linux and aarch64-linux and
I also checked the documentation changes with make info and make pdf.

Thanks,

Martin



gcc/ChangeLog:

2019-08-22  Tejas Joshi  <tejasjoshi9673@gmail.com>
            Martin Jambor  <mjambor@suse.cz>

	* 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 roundeven
	function call.
	* 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.
	* doc/extend.texi (Other Builtins): List roundeven variants among
	functions which can be handled as builtins.

gcc/testsuite/ChangeLog:

2019-08-21  Tejas Joshi  <tejasjoshi9673@gmail.com>

	* gcc.dg/torture/builtin-round-roundeven.c: New test.
	* gcc.dg/torture/builtin-round-roundevenf128.c: New test.
---
 gcc/builtins.c                                |  1 +
 gcc/builtins.def                              |  6 ++
 gcc/doc/extend.texi                           |  3 +-
 gcc/fold-const-call.c                         | 23 +++--
 gcc/fold-const.c                              |  6 ++
 gcc/real.c                                    | 83 +++++++++++++++++++
 gcc/real.h                                    |  9 ++
 .../gcc.dg/torture/builtin-round-roundeven.c  | 23 +++++
 .../torture/builtin-round-roundevenf128.c     | 20 +++++
 9 files changed, 168 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/builtin-round-roundeven.c
 create mode 100644 gcc/testsuite/gcc.dg/torture/builtin-round-roundevenf128.c

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 9a766e4ad63..5149d901a96 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -2056,6 +2056,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/doc/extend.texi b/gcc/doc/extend.texi
index 2ba9b74811a..36341037087 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12448,7 +12448,8 @@ Outside strict ISO C mode (@option{-ansi}, @option{-std=c90},
 @code{j1f}, @code{j1l}, @code{j1}, @code{jnf}, @code{jnl}, @code{jn},
 @code{lgammaf_r}, @code{lgammal_r}, @code{lgamma_r}, @code{mempcpy},
 @code{pow10f}, @code{pow10l}, @code{pow10}, @code{printf_unlocked},
-@code{rindex}, @code{scalbf}, @code{scalbl}, @code{scalb},
+@code{rindex}, @code{roundeven}, @code{roundevenf}, @code{roundevenl},
+@code{scalbf}, @code{scalbl}, @code{scalb},
 @code{signbit}, @code{signbitf}, @code{signbitl}, @code{signbitd32},
 @code{signbitd64}, @code{signbitd128}, @code{significandf},
 @code{significandl}, @code{significand}, @code{sincosf},
diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c
index e21d8e11072..3a14d2a41c1 100644
--- a/gcc/fold-const-call.c
+++ b/gcc/fold-const-call.c
@@ -836,7 +836,7 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_FLOOR:
     CASE_CFN_FLOOR_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
 	{
 	  real_floor (result, format, arg);
 	  return true;
@@ -845,7 +845,7 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_CEIL:
     CASE_CFN_CEIL_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
 	{
 	  real_ceil (result, format, arg);
 	  return true;
@@ -854,18 +854,31 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_TRUNC:
     CASE_CFN_TRUNC_FN:
-      real_trunc (result, format, arg);
-      return true;
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
+	{
+	  real_trunc (result, format, arg);
+	  return true;
+	}
+      return false;
 
     CASE_CFN_ROUND:
     CASE_CFN_ROUND_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
 	{
 	  real_round (result, format, arg);
 	  return true;
 	}
       return false;
 
+    CASE_CFN_ROUNDEVEN:
+    CASE_CFN_ROUNDEVEN_FN:
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
+	{
+	  real_roundeven (result, format, arg);
+	  return true;
+	}
+      return false;
+
     CASE_CFN_LOGB:
       return fold_const_logb (result, arg, format);
 
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 8c711aba12a..0376cdb73a4 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:
@@ -13107,6 +13109,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:
@@ -13630,6 +13634,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..0c0d8c51fe4 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..2f41834ecfd 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..f3b7b40fc1f
--- /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;
+}
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..42c28ddb0cd
--- /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;
+}
-- 
2.22.0

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Builtin function roundeven folding implementation
  2019-08-22 14:40             ` Martin Jambor
@ 2019-08-22 15:52               ` Joseph Myers
  2019-08-22 21:39                 ` Tejas Joshi
  0 siblings, 1 reply; 16+ messages in thread
From: Joseph Myers @ 2019-08-22 15:52 UTC (permalink / raw)
  To: Martin Jambor; +Cc: Tejas Joshi, gcc-patches, hubicka

On Thu, 22 Aug 2019, Martin Jambor wrote:

> +/* 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);

I'm concerned that this would produce +0.0 for an argument of -0.5 (via 
-0.5 - 0.5 - -1.0 producing +0.0) when it needs to produce -0.0.

Note that testcases for the sign of zero results need to check e.g. 
!!__builtin_signbit on the result, or the result of calling 
__builtin_copysign* to extract the sign of the result, since 0.0 == -0.0 
so checking with ==, while necessary, is not sufficient in that case.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Builtin function roundeven folding implementation
  2019-08-22 15:52               ` Joseph Myers
@ 2019-08-22 21:39                 ` Tejas Joshi
  2019-08-23 12:21                   ` Martin Jambor
  2019-08-23 21:24                   ` Joseph Myers
  0 siblings, 2 replies; 16+ messages in thread
From: Tejas Joshi @ 2019-08-22 21:39 UTC (permalink / raw)
  To: gcc-patches; +Cc: Martin Jambor, hubicka, joseph

[-- Attachment #1: Type: text/plain, Size: 2551 bytes --]

Hi,
This is a full patch for the roundeven variants along with
documentation and additional testcases. The following code also
conforms to GNU's coding standards.

Thanks,
Tejas

2019-08-22  Tejas Joshi  <tejasjoshi9673@gmail.com>
            Martin Jambor  <mjambor@suse.cz>

        * 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 roundeven
        function call.
        * 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.
        * doc/extend.texi (Other Builtins): List roundeven variants among
        functions which can be handled as builtins.

gcc/testsuite/ChangeLog:

2019-08-21  Tejas Joshi  <tejasjoshi9673@gmail.com>

        * gcc.dg/torture/builtin-round-roundeven.c: New test.
        * gcc.dg/torture/builtin-round-roundevenf128.c: New test.

On Thu, 22 Aug 2019 at 20:03, Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Thu, 22 Aug 2019, Martin Jambor wrote:
>
> > +/* 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);
>
> I'm concerned that this would produce +0.0 for an argument of -0.5 (via
> -0.5 - 0.5 - -1.0 producing +0.0) when it needs to produce -0.0.
>
> Note that testcases for the sign of zero results need to check e.g.
> !!__builtin_signbit on the result, or the result of calling
> __builtin_copysign* to extract the sign of the result, since 0.0 == -0.0
> so checking with ==, while necessary, is not sufficient in that case.
>
> --
> Joseph S. Myers
> joseph@codesourcery.com

[-- Attachment #2: roundeven.diff --]
[-- Type: text/x-patch, Size: 11272 bytes --]

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 9a766e4ad63..5149d901a96 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -2056,6 +2056,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/doc/extend.texi b/gcc/doc/extend.texi
index 235be99abcb..4aea4d31761 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12448,7 +12448,8 @@ Outside strict ISO C mode (@option{-ansi}, @option{-std=c90},
 @code{j1f}, @code{j1l}, @code{j1}, @code{jnf}, @code{jnl}, @code{jn},
 @code{lgammaf_r}, @code{lgammal_r}, @code{lgamma_r}, @code{mempcpy},
 @code{pow10f}, @code{pow10l}, @code{pow10}, @code{printf_unlocked},
-@code{rindex}, @code{scalbf}, @code{scalbl}, @code{scalb},
+@code{rindex}, @code{roundeven}, @code{roundevenf}, @code{roudnevenl},
+@code{scalbf}, @code{scalbl}, @code{scalb},
 @code{signbit}, @code{signbitf}, @code{signbitl}, @code{signbitd32},
 @code{signbitd64}, @code{signbitd128}, @code{significandf},
 @code{significandl}, @code{significand}, @code{sincosf},
diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c
index e21d8e11072..3a14d2a41c1 100644
--- a/gcc/fold-const-call.c
+++ b/gcc/fold-const-call.c
@@ -836,7 +836,7 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_FLOOR:
     CASE_CFN_FLOOR_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
 	{
 	  real_floor (result, format, arg);
 	  return true;
@@ -845,7 +845,7 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_CEIL:
     CASE_CFN_CEIL_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
 	{
 	  real_ceil (result, format, arg);
 	  return true;
@@ -854,18 +854,31 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_TRUNC:
     CASE_CFN_TRUNC_FN:
-      real_trunc (result, format, arg);
-      return true;
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
+	{
+	  real_trunc (result, format, arg);
+	  return true;
+	}
+      return false;
 
     CASE_CFN_ROUND:
     CASE_CFN_ROUND_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
 	{
 	  real_round (result, format, arg);
 	  return true;
 	}
       return false;
 
+    CASE_CFN_ROUNDEVEN:
+    CASE_CFN_ROUNDEVEN_FN:
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
+	{
+	  real_roundeven (result, format, arg);
+	  return true;
+	}
+      return false;
+
     CASE_CFN_LOGB:
       return fold_const_logb (result, arg, format);
 
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 8c711aba12a..0376cdb73a4 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:
@@ -13107,6 +13109,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:
@@ -13630,6 +13634,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..b252609e197 100644
--- a/gcc/real.c
+++ b/gcc/real.c
@@ -5010,6 +5010,99 @@ 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))
+  {
+    /* Special case as -0.5 rounds to -0.0 and
+       similarly +0.5 rounds to +0.0.  */
+    if (REAL_EXP (x) == 0)
+    {
+      *r = *x;
+      clear_significand_below (r, SIGNIFICAND_BITS);
+    }
+    else
+    {
+      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..2f41834ecfd 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..a39ab0c8de2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/builtin-round-roundeven.c
@@ -0,0 +1,36 @@
+/* { 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);
+
+  if (__builtin_copysign (1, __builtin_roundeven (-0.5)) != -1)
+    link_error (__LINE__);
+  if (__builtin_copysign (1, __builtin_roundeven (-0.0)) != -1)
+    link_error (__LINE__);
+  if (__builtin_copysign (-1, __builtin_roundeven (0.5)) != 1)
+    link_error (__LINE__);
+  if (__builtin_copysign (-1, __builtin_roundeven (0.0)) != 1)
+    link_error (__LINE__);
+  if (__builtin_copysign (1, __builtin_roundeven (-0.25)) != -1)
+    link_error (__LINE__);
+  if (__builtin_copysign (-1, __builtin_roundeven (0.25)) != 1)
+    link_error (__LINE__);
+ return 0;
+}
+
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..85a8cbfd532
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/builtin-round-roundevenf128.c
@@ -0,0 +1,21 @@
+/* { 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;
+}
+

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Builtin function roundeven folding implementation
  2019-08-22 21:39                 ` Tejas Joshi
@ 2019-08-23 12:21                   ` Martin Jambor
  2019-08-23 21:24                   ` Joseph Myers
  1 sibling, 0 replies; 16+ messages in thread
From: Martin Jambor @ 2019-08-23 12:21 UTC (permalink / raw)
  To: Tejas Joshi, gcc-patches; +Cc: hubicka, joseph

Hi,

On Fri, Aug 23 2019, Tejas Joshi wrote:
> Hi,
> This is a full patch for the roundeven variants along with
> documentation and additional testcases. The following code also
> conforms to GNU's coding standards.
>
> Thanks,
> Tejas
>
> 2019-08-22  Tejas Joshi  <tejasjoshi9673@gmail.com>
>             Martin Jambor  <mjambor@suse.cz>
>
>         * 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 roundeven
>         function call.
>         * 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.
>         * doc/extend.texi (Other Builtins): List roundeven variants among
>         functions which can be handled as builtins.
>
> gcc/testsuite/ChangeLog:
>
> 2019-08-21  Tejas Joshi  <tejasjoshi9673@gmail.com>
>
>         * gcc.dg/torture/builtin-round-roundeven.c: New test.
>         * gcc.dg/torture/builtin-round-roundevenf128.c: New test.

For the record, I bootstrapped and tested the patch on an x86_64-linux
and it passes both fine.

Joseph, please have a look and hopefully this is the version that I can
commit?

Thanks,

Martin

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Builtin function roundeven folding implementation
  2019-08-22 21:39                 ` Tejas Joshi
  2019-08-23 12:21                   ` Martin Jambor
@ 2019-08-23 21:24                   ` Joseph Myers
  2019-08-25 20:28                     ` Tejas Joshi
  2020-02-12  6:20                     ` [PATCH] real: Fix roundeven on inf/nan [PR93663] Jakub Jelinek
  1 sibling, 2 replies; 16+ messages in thread
From: Joseph Myers @ 2019-08-23 21:24 UTC (permalink / raw)
  To: Tejas Joshi; +Cc: gcc-patches, Martin Jambor, hubicka

On Fri, 23 Aug 2019, Tejas Joshi wrote:

> diff --git a/gcc/builtins.c b/gcc/builtins.c
> index 9a766e4ad63..5149d901a96 100644
> --- a/gcc/builtins.c
> +++ b/gcc/builtins.c
> @@ -2056,6 +2056,7 @@ mathfn_built_in_2 (tree type, combined_fn fn)
>      CASE_MATHFN (REMQUO)
>      CASE_MATHFN_FLOATN (RINT)
>      CASE_MATHFN_FLOATN (ROUND)
> +    CASE_MATHFN (ROUNDEVEN)

This should use CASE_MATHFN_FLOATN, as for the other round-to-integer 
functions.

> +  /* 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;

Fix the indentation here (the braces should be indented two columns from 
the "else", the contents then two columns from the braces).

> +  }
> +
> +  else

And remove the stray blank line before "else".

> +/* 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;

Explicitly check for rvc_zero and return false in that case (that seems to 
be the convention in real.c, rather than relying on code using REAL_EXP to 
do something sensible for zero, which has REAL_EXP of 0).

> +  else if (REAL_EXP (r) < SIGNIFICAND_BITS)
> +  {

Another place to fix indentation.

> +void
> +real_roundeven (REAL_VALUE_TYPE *r, format_helper fmt,
> +		const REAL_VALUE_TYPE *x)
> +{
> +  if (is_halfway_below (x))
> +  {

Again, fix indentation throughout this function.

The patch is OK with those fixes, assuming the fixed patch passes testing.  
I encourage a followup looking for and fixing further places in the source 
tree that handle round-to-integer function families (ceil / floor / trunc 
/ round / rint / nearbyint) and should handle roundeven as well, as that 
would lead to more optimization of roundeven calls.  Such places aren't 
that easy to search for because most of those names are common words used 
in other contexts in the compiler.  But, for example, match.pd has 
patterns

/* trunc(trunc(x)) -> trunc(x), etc.  */

/* f(x) -> x if x is integer valued and f does nothing for such values.  */

 /* truncl(extend(x)) -> extend(trunc(x)), etc., if x is a double.  */

 /* truncl(extend(x)) and trunc(extend(x)) -> extend(truncf(x)), etc.,
    if x is a float.  */

which should apply to roundeven as well.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Builtin function roundeven folding implementation
  2019-08-23 21:24                   ` Joseph Myers
@ 2019-08-25 20:28                     ` Tejas Joshi
  2020-02-12  6:20                     ` [PATCH] real: Fix roundeven on inf/nan [PR93663] Jakub Jelinek
  1 sibling, 0 replies; 16+ messages in thread
From: Tejas Joshi @ 2019-08-25 20:28 UTC (permalink / raw)
  To: gcc-patches, Martin Jambor; +Cc: hubicka, joseph

[-- Attachment #1: Type: text/plain, Size: 4447 bytes --]

Hi.
This is the full patch for roundeven folding. The patch bootstraps and
passes regression tests.

2019-08-25  Tejas Joshi  <tejasjoshi9673@gmail.com>
            Martin Jambor  <mjambor@suse.cz>

        * builtins.c (mathfn_built_in_2): Added CASE_MATHFN_FLOATN
        for ROUNDEVEN.
        * builtins.def: Added function definitions for roundeven function
        variants.
        * fold-const-call.c (fold_const_call_ss): Added case for roundeven
        function call.
        * 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.
        * doc/extend.texi (Other Builtins): List roundeven variants among
        functions which can be handled as builtins.

gcc/testsuite/ChangeLog:

2019-08-25  Tejas Joshi  <tejasjoshi9673@gmail.com>

        * gcc.dg/torture/builtin-round-roundeven.c: New test.
        * gcc.dg/torture/builtin-round-roundevenf128.c: New test.

On Sat, 24 Aug 2019 at 02:08, Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Fri, 23 Aug 2019, Tejas Joshi wrote:
>
> > diff --git a/gcc/builtins.c b/gcc/builtins.c
> > index 9a766e4ad63..5149d901a96 100644
> > --- a/gcc/builtins.c
> > +++ b/gcc/builtins.c
> > @@ -2056,6 +2056,7 @@ mathfn_built_in_2 (tree type, combined_fn fn)
> >      CASE_MATHFN (REMQUO)
> >      CASE_MATHFN_FLOATN (RINT)
> >      CASE_MATHFN_FLOATN (ROUND)
> > +    CASE_MATHFN (ROUNDEVEN)
>
> This should use CASE_MATHFN_FLOATN, as for the other round-to-integer
> functions.
>
> > +  /* 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;
>
> Fix the indentation here (the braces should be indented two columns from
> the "else", the contents then two columns from the braces).
>
> > +  }
> > +
> > +  else
>
> And remove the stray blank line before "else".
>
> > +/* 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;
>
> Explicitly check for rvc_zero and return false in that case (that seems to
> be the convention in real.c, rather than relying on code using REAL_EXP to
> do something sensible for zero, which has REAL_EXP of 0).
>
> > +  else if (REAL_EXP (r) < SIGNIFICAND_BITS)
> > +  {
>
> Another place to fix indentation.
>
> > +void
> > +real_roundeven (REAL_VALUE_TYPE *r, format_helper fmt,
> > +             const REAL_VALUE_TYPE *x)
> > +{
> > +  if (is_halfway_below (x))
> > +  {
>
> Again, fix indentation throughout this function.
>
> The patch is OK with those fixes, assuming the fixed patch passes testing.
> I encourage a followup looking for and fixing further places in the source
> tree that handle round-to-integer function families (ceil / floor / trunc
> / round / rint / nearbyint) and should handle roundeven as well, as that
> would lead to more optimization of roundeven calls.  Such places aren't
> that easy to search for because most of those names are common words used
> in other contexts in the compiler.  But, for example, match.pd has
> patterns
>
> /* trunc(trunc(x)) -> trunc(x), etc.  */
>
> /* f(x) -> x if x is integer valued and f does nothing for such values.  */
>
>  /* truncl(extend(x)) -> extend(trunc(x)), etc., if x is a double.  */
>
>  /* truncl(extend(x)) and trunc(extend(x)) -> extend(truncf(x)), etc.,
>     if x is a float.  */
>
> which should apply to roundeven as well.
>
> --
> Joseph S. Myers
> joseph@codesourcery.com

[-- Attachment #2: roundeven.diff --]
[-- Type: text/x-patch, Size: 11320 bytes --]

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 9a766e4ad63..e44866e2a60 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -2056,6 +2056,7 @@ mathfn_built_in_2 (tree type, combined_fn fn)
     CASE_MATHFN (REMQUO)
     CASE_MATHFN_FLOATN (RINT)
     CASE_MATHFN_FLOATN (ROUND)
+    CASE_MATHFN_FLOATN (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/doc/extend.texi b/gcc/doc/extend.texi
index 235be99abcb..4aea4d31761 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12448,7 +12448,8 @@ Outside strict ISO C mode (@option{-ansi}, @option{-std=c90},
 @code{j1f}, @code{j1l}, @code{j1}, @code{jnf}, @code{jnl}, @code{jn},
 @code{lgammaf_r}, @code{lgammal_r}, @code{lgamma_r}, @code{mempcpy},
 @code{pow10f}, @code{pow10l}, @code{pow10}, @code{printf_unlocked},
-@code{rindex}, @code{scalbf}, @code{scalbl}, @code{scalb},
+@code{rindex}, @code{roundeven}, @code{roundevenf}, @code{roudnevenl},
+@code{scalbf}, @code{scalbl}, @code{scalb},
 @code{signbit}, @code{signbitf}, @code{signbitl}, @code{signbitd32},
 @code{signbitd64}, @code{signbitd128}, @code{significandf},
 @code{significandl}, @code{significand}, @code{sincosf},
diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c
index e21d8e11072..3a14d2a41c1 100644
--- a/gcc/fold-const-call.c
+++ b/gcc/fold-const-call.c
@@ -836,7 +836,7 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_FLOOR:
     CASE_CFN_FLOOR_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
 	{
 	  real_floor (result, format, arg);
 	  return true;
@@ -845,7 +845,7 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_CEIL:
     CASE_CFN_CEIL_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
 	{
 	  real_ceil (result, format, arg);
 	  return true;
@@ -854,18 +854,31 @@ fold_const_call_ss (real_value *result, combined_fn fn,
 
     CASE_CFN_TRUNC:
     CASE_CFN_TRUNC_FN:
-      real_trunc (result, format, arg);
-      return true;
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
+	{
+	  real_trunc (result, format, arg);
+	  return true;
+	}
+      return false;
 
     CASE_CFN_ROUND:
     CASE_CFN_ROUND_FN:
-      if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math)
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
 	{
 	  real_round (result, format, arg);
 	  return true;
 	}
       return false;
 
+    CASE_CFN_ROUNDEVEN:
+    CASE_CFN_ROUNDEVEN_FN:
+      if (!REAL_VALUE_ISSIGNALING_NAN (*arg))
+	{
+	  real_roundeven (result, format, arg);
+	  return true;
+	}
+      return false;
+
     CASE_CFN_LOGB:
       return fold_const_logb (result, arg, format);
 
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 8c711aba12a..0376cdb73a4 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:
@@ -13107,6 +13109,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:
@@ -13630,6 +13634,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..6e6a3949a45 100644
--- a/gcc/real.c
+++ b/gcc/real.c
@@ -5010,6 +5010,101 @@ 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;
+
+  if (r->cl == rvc_zero)
+    return false;
+
+  /* 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))
+    {
+      /* Special case as -0.5 rounds to -0.0 and
+	 similarly +0.5 rounds to +0.0.  */
+      if (REAL_EXP (x) == 0)
+	{
+	  *r = *x;
+	  clear_significand_below (r, SIGNIFICAND_BITS);
+	}
+      else
+	{
+	  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..2f41834ecfd 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..a39ab0c8de2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/builtin-round-roundeven.c
@@ -0,0 +1,36 @@
+/* { 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);
+
+  if (__builtin_copysign (1, __builtin_roundeven (-0.5)) != -1)
+    link_error (__LINE__);
+  if (__builtin_copysign (1, __builtin_roundeven (-0.0)) != -1)
+    link_error (__LINE__);
+  if (__builtin_copysign (-1, __builtin_roundeven (0.5)) != 1)
+    link_error (__LINE__);
+  if (__builtin_copysign (-1, __builtin_roundeven (0.0)) != 1)
+    link_error (__LINE__);
+  if (__builtin_copysign (1, __builtin_roundeven (-0.25)) != -1)
+    link_error (__LINE__);
+  if (__builtin_copysign (-1, __builtin_roundeven (0.25)) != 1)
+    link_error (__LINE__);
+ return 0;
+}
+
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..85a8cbfd532
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/builtin-round-roundevenf128.c
@@ -0,0 +1,21 @@
+/* { 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;
+}
+

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH] real: Fix roundeven on inf/nan [PR93663]
  2019-08-23 21:24                   ` Joseph Myers
  2019-08-25 20:28                     ` Tejas Joshi
@ 2020-02-12  6:20                     ` Jakub Jelinek
  2020-02-12 20:56                       ` Joseph Myers
  1 sibling, 1 reply; 16+ messages in thread
From: Jakub Jelinek @ 2020-02-12  6:20 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Tejas Joshi, gcc-patches

On Fri, Aug 23, 2019 at 08:38:43PM +0000, Joseph Myers wrote:
> > +/* 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;
> 
> Explicitly check for rvc_zero and return false in that case (that seems to 
> be the convention in real.c, rather than relying on code using REAL_EXP to 
> do something sensible for zero, which has REAL_EXP of 0).

As can be seen in the testcase, roundeven with inf or nan arguments
ICE because of those asserts where nothing prevents from is_halfway_below
being called with those arguments.

The following patch fixes that by just returning false for rvc_inf/rvc_nan
like it returns for rvc_zero, so that we handle roundeven with all those
values as round.  Inf/NaN are not halfway in between two integers...

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2020-02-12  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/93663
	* real.c (is_even): Make static.  Function comment fix.
	(is_halfway_below): Make static, don't assert R is not inf/nan,
	instead return false for those.  Small formatting fixes.

	* gcc.dg/torture/builtin-round-roundeven.c (main): Add tests
	for DBL_MAX, inf, their negations and nan.

--- gcc/real.c.jj	2020-01-23 16:16:16.456601333 +0100
+++ gcc/real.c	2020-02-11 12:40:06.571398420 +0100
@@ -5150,10 +5150,10 @@ real_round (REAL_VALUE_TYPE *r, format_h
     real_convert (r, fmt, r);
 }
 
-/* Return true including 0 if integer part of R is even, else return
+/* 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
+static bool
 is_even (REAL_VALUE_TYPE *r)
 {
   gcc_assert (r->cl != rvc_inf);
@@ -5184,16 +5184,12 @@ is_even (REAL_VALUE_TYPE *r)
 }
 
 /* Return true if R is halfway between two integers, else return
-   false.  The function is not valid for rvc_inf and rvc_nan classes.  */
+   false.  */
 
-bool
+static bool
 is_halfway_below (const REAL_VALUE_TYPE *r)
 {
-  gcc_assert (r->cl != rvc_inf);
-  gcc_assert (r->cl != rvc_nan);
-  int i;
-
-  if (r->cl == rvc_zero)
+  if (r->cl != rvc_normal)
     return false;
 
   /* For numbers (-0.5,0) and (0,0.5).  */
@@ -5205,13 +5201,13 @@ is_halfway_below (const REAL_VALUE_TYPE
       unsigned int n = SIGNIFICAND_BITS - REAL_EXP (r) - 1;
       int w = n / HOST_BITS_PER_LONG;
 
-      for (i = 0; i < w; ++i)
+      for (int i = 0; i < w; ++i)
 	if (r->sig[i] != 0)
 	  return false;
 
-      unsigned long num = ((unsigned long)1 << (n % HOST_BITS_PER_LONG));
+      unsigned long num = 1UL << (n % HOST_BITS_PER_LONG);
 
-      if (((r->sig[w] & num) != 0) && ((r->sig[w] & (num-1)) == 0))
+      if ((r->sig[w] & num) != 0 && (r->sig[w] & (num - 1)) == 0)
 	return true;
     }
   return false;
--- gcc/testsuite/gcc.dg/torture/builtin-round-roundeven.c.jj	2020-01-12 11:54:37.547396300 +0100
+++ gcc/testsuite/gcc.dg/torture/builtin-round-roundeven.c	2020-02-11 12:47:55.346354893 +0100
@@ -18,6 +18,13 @@ main (void)
   TEST(roundeven,  -1.5, -2);
   TEST(roundeven,  3.499, 3);
   TEST(roundeven,  3.501, 4);
+  TEST(roundeven,  __DBL_MAX__, __DBL_MAX__);
+  TEST(roundeven,  -__DBL_MAX__, -__DBL_MAX__);
+  TEST(roundeven,  __builtin_inf (), __builtin_inf ());
+  TEST(roundeven,  -__builtin_inf (), -__builtin_inf ());
+
+  if (!__builtin_isnan (__builtin_roundeven (__builtin_nan (""))))
+    link_error (__LINE__);
 
   if (__builtin_copysign (1, __builtin_roundeven (-0.5)) != -1)
     link_error (__LINE__);
@@ -31,6 +38,5 @@ main (void)
     link_error (__LINE__);
   if (__builtin_copysign (-1, __builtin_roundeven (0.25)) != 1)
     link_error (__LINE__);
- return 0;
+  return 0;
 }
-


	Jakub

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] real: Fix roundeven on inf/nan [PR93663]
  2020-02-12  6:20                     ` [PATCH] real: Fix roundeven on inf/nan [PR93663] Jakub Jelinek
@ 2020-02-12 20:56                       ` Joseph Myers
  0 siblings, 0 replies; 16+ messages in thread
From: Joseph Myers @ 2020-02-12 20:56 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Tejas Joshi, gcc-patches

On Wed, 12 Feb 2020, Jakub Jelinek wrote:

> As can be seen in the testcase, roundeven with inf or nan arguments
> ICE because of those asserts where nothing prevents from is_halfway_below
> being called with those arguments.
> 
> The following patch fixes that by just returning false for rvc_inf/rvc_nan
> like it returns for rvc_zero, so that we handle roundeven with all those
> values as round.  Inf/NaN are not halfway in between two integers...
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2020-02-12 20:56 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-28  3:40 [PATCH] Builtin function roundeven folding implementation Tejas Joshi
2019-07-29 16:49 ` Martin Jambor
2019-08-09 21:26 ` Joseph Myers
2019-08-14  7:24   ` Tejas Joshi
2019-08-21 11:52     ` Martin Jambor
2019-08-21 12:48       ` Joseph Myers
2019-08-21 19:10         ` Martin Jambor
2019-08-21 20:50           ` Joseph Myers
2019-08-22 14:40             ` Martin Jambor
2019-08-22 15:52               ` Joseph Myers
2019-08-22 21:39                 ` Tejas Joshi
2019-08-23 12:21                   ` Martin Jambor
2019-08-23 21:24                   ` Joseph Myers
2019-08-25 20:28                     ` Tejas Joshi
2020-02-12  6:20                     ` [PATCH] real: Fix roundeven on inf/nan [PR93663] Jakub Jelinek
2020-02-12 20:56                       ` Joseph Myers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).