Hello. I can't figure out from the documentation how to add test cases in the testsuite and inspect the results. How can I do that? Although, Taking the mentioned conditions under consideration, I have made another patch, attached.
Thanks, -Tejas On Wed, 8 May 2019 at 09:01, Tejas Joshi <tejasjoshi9...@gmail.com> wrote: > > I should have taken all the test cases into consideration. Fool of me. I will > try to make changes taking all the test cases into consideration along with > the testsuite. > Thanks. > > On Wed, 8 May 2019 at 02:31, Joseph Myers <jos...@codesourcery.com> wrote: >> >> On Wed, 8 May 2019, Tejas Joshi wrote: >> >> > Hello. >> > As per my understanding, 3.5 would be represented in GCC as follows : >> > r->uexp = 2 >> > and >> > r->sig[2] = 1110000....00 in binary 64 bit. (first 2 bits being 3 and >> > following 1000....0 being 0.5, which later only happens for halfway cases) >> > So, if we clear out the significand part and the immediate bit to the right >> > which represent 0.5, the entire significand would become 0 due to bit-wise >> > ANDing. >> > >> > > + tempsig[w] &= (((unsigned long)1 << ((n % HOST_BITS_PER_LONG) - 1)) - >> > > 1); >> > > >> > >> > That is what the following line intend to do. The clearing part would >> > change the significand, that's why significand was copied to a temporary >> >> That much is fine. My issues are two other things: >> >> * The function would wrongly return true for 3, not just for 3.5, because >> it never checks the bit representing 0.5. (If you don't care what it >> returns for 3, see my previous point about every function needing a >> comment defining its semantics. Without such a comment, I have to guess, >> and my guess here is that the function should return true for 3.5 but >> false for 3 and for 3.5000...0001.) >> >> * The function would wrongly return true for 3.5000...0001, if there are >> enough 0s that all those low bits in sig[2] are 0, but some low bits in >> sig[1] or sig[0] are not 0. >> >> And also: >> >> * You should never need to modify parts of (a copy of) the significand in >> place. Compare low parts of the significand (masked as needed) with 0. >> If not 0, just return false. Likewise for comparing the 0.5 bit with 1. >> It's not that copying and modifying in place results in incorrect logic, >> it's simply excessively convoluted compared to things like: >> >> if ((something & mask) != 0) >> return false >> >> (the function is probably twice as long as necessary because of that >> copying). >> >> > array for checking. This logic is inspired by the clear_significand_below >> > function. Or isn't this the way it was meant to be implemented? Also, why >> > unsigned long sig[SIGSZ] has to be an array? >> >> What would it be other than an array? It can't be a single scalar because >> floating-point significands may be longer than any supported integer type >> on the host (remember the IEEE binary128 case). And if you made it a >> sequence of individually named fields, a load of loops would need to be >> manually unrolled, which would be much more error prone and hard to read. >> >> -- >> Joseph S. Myers >> jos...@codesourcery.com
diff --git a/gcc/builtins.c b/gcc/builtins.c index 25e01e4092b..0b2d6bf82f9 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -2067,6 +2067,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 ef89729fd0c..e1d593a8765 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -542,6 +542,9 @@ 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) diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c index 06a420601c0..7eafd91e9a2 100644 --- a/gcc/fold-const-call.c +++ b/gcc/fold-const-call.c @@ -792,6 +792,14 @@ fold_const_call_ss (real_value *result, combined_fn fn, } return false; + case CFN_BUILT_IN_ROUNDEVEN: + 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); @@ -854,6 +862,9 @@ fold_const_call_ss (wide_int *result, combined_fn fn, return fold_const_conversion (result, real_round, arg, precision, format); + case CFN_BUILT_IN_ROUNDEVEN: + 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 59cedeafd71..30c409e95bf 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -329,6 +329,7 @@ negate_mathfn_p (combined_fn fn) CASE_CFN_LLROUND: CASE_CFN_LROUND: CASE_CFN_ROUND: + CASE_CFN_ROUNDEVEN: CASE_CFN_SIN: CASE_CFN_SINH: CASE_CFN_TAN: @@ -13060,6 +13061,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: @@ -13583,6 +13586,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 f822ae82d61..045dc758048 100644 --- a/gcc/real.c +++ b/gcc/real.c @@ -5010,6 +5010,53 @@ real_round (REAL_VALUE_TYPE *r, format_helper fmt, real_convert (r, fmt, r); } +/* Return true if integer part of R is even, else return false. */ + +bool +is_even (REAL_VALUE_TYPE *r) +{ + unsigned int n = SIGNIFICAND_BITS - REAL_EXP (r); + + unsigned long num = ((unsigned long)1 << (n % HOST_BITS_PER_LONG)); + + if ((r->sig[SIGSZ-1] & num) == 0) + return true; + return false; +} + +/* Return true if R is halfway between two integers, else return false. */ + +bool +is_halfway_below (const REAL_VALUE_TYPE *r) +{ + if (r->sig[0] != 0 && r->sig[1] != 0) + return false; + + unsigned int n = SIGNIFICAND_BITS - REAL_EXP (r); + + unsigned long num = ((unsigned long)1 << ((n - 1) % HOST_BITS_PER_LONG)); + + if (((r->sig[SIGSZ-1] & num) != 0) && ((r->sig[SIGSZ-1] & (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); + } + 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 0ce42565708..10898eae79e 100644 --- a/gcc/real.h +++ b/gcc/real.h @@ -499,6 +499,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 *);