From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 115332 invoked by alias); 29 Jul 2019 16:10:11 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 115324 invoked by uid 89); 29 Jul 2019 16:10:10 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.5 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS autolearn=ham version=3.3.1 spammy=nearest, lowest, packed, 005 X-HELO: mx1.suse.de Received: from mx2.suse.de (HELO mx1.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 29 Jul 2019 16:10:08 +0000 X-Amavis-Alert: BAD HEADER SECTION, Duplicate header field: "Cc" Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 8E63EAC91; Mon, 29 Jul 2019 16:10:05 +0000 (UTC) From: Martin Jambor To: Tejas Joshi , gcc-patches@gcc.gnu.org Cc: hubicka@ucw.cz, joseph@codesourcery.com Cc: Subject: Re: [PATCH] Builtin function roundeven folding implementation In-Reply-To: References: User-Agent: Notmuch/0.29.1 (https://notmuchmail.org) Emacs/26.2 (x86_64-suse-linux-gnu) Date: Mon, 29 Jul 2019 16:49:00 -0000 Message-ID: MIME-Version: 1.0 Content-Type: text/plain X-IsSubscribed: yes X-SW-Source: 2019-07/txt/msg01739.txt.bz2 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 > > * 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 > > * 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