* [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).