From 543a9bcd216d9a9fb377b7f84766cdcc858c21c0 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 26 Oct 2015 09:29:26 +0000 Subject: [PATCH] Move int rounding folds to match.pd Tested on x86_64-linux-gnu, aarch64-linux-gnu and arm-linux-gnueabi. gcc/ * builtins.c (do_real_to_int_conversion): New function. (fold_fixed_mathfn, fold_builtin_int_roundingfn): Delete. (fold_builtin_1): Handle constant {i,l,ll}{ceil,floor,round}{f,,l} arguments here. * match.pd: Add rules previously handled by fold_fixed_mathfn and fold_builtin_int_roundingfn. gcc/testsuite/ * gcc.dg/torture/builtin-minmax-1.c: Don't run at -O0. From-SVN: r229311 --- gcc/ChangeLog | 9 + gcc/builtins.c | 213 +++--------------- gcc/match.pd | 92 +++++++- gcc/testsuite/ChangeLog | 4 + .../gcc.dg/torture/builtin-minmax-1.c | 1 + 5 files changed, 138 insertions(+), 181 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b8fd4630847..3285ca4ee41 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2015-10-26 Richard Sandiford + + * builtins.c (do_real_to_int_conversion): New function. + (fold_fixed_mathfn, fold_builtin_int_roundingfn): Delete. + (fold_builtin_1): Handle constant {i,l,ll}{ceil,floor,round}{f,,l} + arguments here. + * match.pd: Add rules previously handled by fold_fixed_mathfn + and fold_builtin_int_roundingfn. + 2015-10-26 Richard Sandiford * match.pd: Use macros to define built-in operator lists. diff --git a/gcc/builtins.c b/gcc/builtins.c index c70bbfd8bf4..f947f1e415b 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -158,7 +158,6 @@ static rtx expand_builtin_fabs (tree, rtx, rtx); static rtx expand_builtin_signbit (tree, rtx); static tree fold_builtin_pow (location_t, tree, tree, tree, tree); static tree fold_builtin_powi (location_t, tree, tree, tree, tree); -static tree fold_builtin_int_roundingfn (location_t, tree, tree); static tree fold_builtin_bitop (tree, tree); static tree fold_builtin_strchr (location_t, tree, tree, tree); static tree fold_builtin_memchr (location_t, tree, tree, tree, tree); @@ -7273,6 +7272,35 @@ fold_builtin_strlen (location_t loc, tree type, tree arg) } } +/* If ARG is a foldable constant real, use FN to round it to an integer + value and try to represent the result in integer type ITYPE. Return + the value on success, otherwise return null. */ + +static tree +do_real_to_int_conversion (tree itype, tree arg, + void (*fn) (REAL_VALUE_TYPE *, machine_mode, + const REAL_VALUE_TYPE *)) +{ + if (TREE_CODE (arg) != REAL_CST || TREE_OVERFLOW (arg)) + return NULL_TREE; + + const REAL_VALUE_TYPE *value = TREE_REAL_CST_PTR (arg); + if (!real_isfinite (value)) + return NULL_TREE; + + tree ftype = TREE_TYPE (arg); + REAL_VALUE_TYPE rounded; + fn (&rounded, TYPE_MODE (ftype), value); + + bool fail = false; + wide_int ival = real_to_integer (&rounded, &fail, TYPE_PRECISION (itype)); + if (fail) + return NULL_TREE; + + return wide_int_to_tree (itype, ival); +} + + /* Fold a call to __builtin_inf or __builtin_huge_val. */ static tree @@ -7314,112 +7342,6 @@ fold_builtin_nan (tree arg, tree type, int quiet) return build_real (type, real); } -/* FNDECL is assumed to be builtin which can narrow the FP type of - the argument, for instance lround((double)f) -> lroundf (f). - Do the transformation for a call with argument ARG. */ - -static tree -fold_fixed_mathfn (location_t loc, tree fndecl, tree arg) -{ - enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); - - if (!validate_arg (arg, REAL_TYPE)) - return NULL_TREE; - - /* If argument is already integer valued, and we don't need to worry - about setting errno, there's no need to perform rounding. */ - if (! flag_errno_math && integer_valued_real_p (arg)) - return fold_build1_loc (loc, FIX_TRUNC_EXPR, - TREE_TYPE (TREE_TYPE (fndecl)), arg); - - if (optimize) - { - tree ftype = TREE_TYPE (arg); - tree arg0 = strip_float_extensions (arg); - tree newtype = TREE_TYPE (arg0); - tree decl; - - if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype) - && (decl = mathfn_built_in (newtype, fcode))) - return build_call_expr_loc (loc, decl, 1, - fold_convert_loc (loc, newtype, arg0)); - } - - /* Canonicalize iround (x) to lround (x) on ILP32 targets where - sizeof (int) == sizeof (long). */ - if (TYPE_PRECISION (integer_type_node) - == TYPE_PRECISION (long_integer_type_node)) - { - tree newfn = NULL_TREE; - switch (fcode) - { - CASE_FLT_FN (BUILT_IN_ICEIL): - newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LCEIL); - break; - - CASE_FLT_FN (BUILT_IN_IFLOOR): - newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LFLOOR); - break; - - CASE_FLT_FN (BUILT_IN_IROUND): - newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LROUND); - break; - - CASE_FLT_FN (BUILT_IN_IRINT): - newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LRINT); - break; - - default: - break; - } - - if (newfn) - { - tree newcall = build_call_expr_loc (loc, newfn, 1, arg); - return fold_convert_loc (loc, - TREE_TYPE (TREE_TYPE (fndecl)), newcall); - } - } - - /* Canonicalize llround (x) to lround (x) on LP64 targets where - sizeof (long long) == sizeof (long). */ - if (TYPE_PRECISION (long_long_integer_type_node) - == TYPE_PRECISION (long_integer_type_node)) - { - tree newfn = NULL_TREE; - switch (fcode) - { - CASE_FLT_FN (BUILT_IN_LLCEIL): - newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LCEIL); - break; - - CASE_FLT_FN (BUILT_IN_LLFLOOR): - newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LFLOOR); - break; - - CASE_FLT_FN (BUILT_IN_LLROUND): - newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LROUND); - break; - - CASE_FLT_FN (BUILT_IN_LLRINT): - newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LRINT); - break; - - default: - break; - } - - if (newfn) - { - tree newcall = build_call_expr_loc (loc, newfn, 1, arg); - return fold_convert_loc (loc, - TREE_TYPE (TREE_TYPE (fndecl)), newcall); - } - } - - return NULL_TREE; -} - /* Fold function call to builtin sincos, sincosf, or sincosl. Return NULL_TREE if no simplification can be made. */ @@ -7460,74 +7382,6 @@ fold_builtin_sincos (location_t loc, build1 (REALPART_EXPR, type, call))); } -/* Fold function call to builtin lround, lroundf or lroundl (or the - corresponding long long versions) and other rounding functions. ARG - is the argument to the call. Return NULL_TREE if no simplification - can be made. */ - -static tree -fold_builtin_int_roundingfn (location_t loc, tree fndecl, tree arg) -{ - if (!validate_arg (arg, REAL_TYPE)) - return NULL_TREE; - - /* Optimize lround of constant value. */ - if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg)) - { - const REAL_VALUE_TYPE x = TREE_REAL_CST (arg); - - if (real_isfinite (&x)) - { - tree itype = TREE_TYPE (TREE_TYPE (fndecl)); - tree ftype = TREE_TYPE (arg); - REAL_VALUE_TYPE r; - bool fail = false; - - switch (DECL_FUNCTION_CODE (fndecl)) - { - CASE_FLT_FN (BUILT_IN_IFLOOR): - CASE_FLT_FN (BUILT_IN_LFLOOR): - CASE_FLT_FN (BUILT_IN_LLFLOOR): - real_floor (&r, TYPE_MODE (ftype), &x); - break; - - CASE_FLT_FN (BUILT_IN_ICEIL): - CASE_FLT_FN (BUILT_IN_LCEIL): - CASE_FLT_FN (BUILT_IN_LLCEIL): - real_ceil (&r, TYPE_MODE (ftype), &x); - break; - - CASE_FLT_FN (BUILT_IN_IROUND): - CASE_FLT_FN (BUILT_IN_LROUND): - CASE_FLT_FN (BUILT_IN_LLROUND): - real_round (&r, TYPE_MODE (ftype), &x); - break; - - default: - gcc_unreachable (); - } - - wide_int val = real_to_integer (&r, &fail, TYPE_PRECISION (itype)); - if (!fail) - return wide_int_to_tree (itype, val); - } - } - - switch (DECL_FUNCTION_CODE (fndecl)) - { - CASE_FLT_FN (BUILT_IN_LFLOOR): - CASE_FLT_FN (BUILT_IN_LLFLOOR): - /* Fold lfloor (x) where x is nonnegative to FIX_TRUNC (x). */ - if (tree_expr_nonnegative_p (arg)) - return fold_build1_loc (loc, FIX_TRUNC_EXPR, - TREE_TYPE (TREE_TYPE (fndecl)), arg); - break; - default:; - } - - return fold_fixed_mathfn (loc, fndecl, arg); -} - /* Fold function call to builtin ffs, clz, ctz, popcount and parity and their long and long long variants (i.e. ffsl and ffsll). ARG is the argument to the call. Return NULL_TREE if no simplification can @@ -9453,18 +9307,23 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0) CASE_FLT_FN (BUILT_IN_ICEIL): CASE_FLT_FN (BUILT_IN_LCEIL): CASE_FLT_FN (BUILT_IN_LLCEIL): + return do_real_to_int_conversion (type, arg0, real_ceil); + CASE_FLT_FN (BUILT_IN_LFLOOR): CASE_FLT_FN (BUILT_IN_IFLOOR): CASE_FLT_FN (BUILT_IN_LLFLOOR): + return do_real_to_int_conversion (type, arg0, real_floor); + CASE_FLT_FN (BUILT_IN_IROUND): CASE_FLT_FN (BUILT_IN_LROUND): CASE_FLT_FN (BUILT_IN_LLROUND): - return fold_builtin_int_roundingfn (loc, fndecl, arg0); + return do_real_to_int_conversion (type, arg0, real_round); CASE_FLT_FN (BUILT_IN_IRINT): CASE_FLT_FN (BUILT_IN_LRINT): CASE_FLT_FN (BUILT_IN_LLRINT): - return fold_fixed_mathfn (loc, fndecl, arg0); + /* Not yet folded to a constant. */ + return NULL_TREE; case BUILT_IN_BSWAP16: case BUILT_IN_BSWAP32: diff --git a/gcc/match.pd b/gcc/match.pd index e790d5b2f94..00c6e7c1abc 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -52,6 +52,30 @@ along with GCC; see the file COPYING3. If not see #define DEFINE_MATH_FN(FN) \ (define_operator_list FN BUILT_IN_##FN##F BUILT_IN_##FN BUILT_IN_##FN##L) +/* Define operand lists for math rounding functions {,i,l,ll}FN, + where the versions prefixed with "i" return an int, those prefixed with + "l" return a long and those prefixed with "ll" return a long long. + + Also define operand lists: + + XF for all float functions, in the order i, l, ll + X for all double functions, in the same order + XL for all long double functions, in the same order. */ +#define DEFINE_INT_AND_FLOAT_ROUND_FN(FN) \ + DEFINE_MATH_FN (FN) \ + DEFINE_MATH_FN (I##FN) \ + DEFINE_MATH_FN (L##FN) \ + DEFINE_MATH_FN (LL##FN) \ + (define_operator_list X##FN##F BUILT_IN_I##FN##F \ + BUILT_IN_L##FN##F \ + BUILT_IN_LL##FN##F) \ + (define_operator_list X##FN BUILT_IN_I##FN \ + BUILT_IN_L##FN \ + BUILT_IN_LL##FN) \ + (define_operator_list X##FN##L BUILT_IN_I##FN##L \ + BUILT_IN_L##FN##L \ + BUILT_IN_LL##FN##L) + DEFINE_MATH_FN (LOG) DEFINE_MATH_FN (EXP) DEFINE_MATH_FN (LOG2) @@ -76,11 +100,12 @@ DEFINE_MATH_FN (HYPOT) DEFINE_MATH_FN (COPYSIGN) DEFINE_MATH_FN (CABS) DEFINE_MATH_FN (TRUNC) -DEFINE_MATH_FN (FLOOR) -DEFINE_MATH_FN (CEIL) -DEFINE_MATH_FN (ROUND) DEFINE_MATH_FN (NEARBYINT) -DEFINE_MATH_FN (RINT) + +DEFINE_INT_AND_FLOAT_ROUND_FN (FLOOR) +DEFINE_INT_AND_FLOAT_ROUND_FN (CEIL) +DEFINE_INT_AND_FLOAT_ROUND_FN (ROUND) +DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* Simplifications of operations with one constant operand and simplifications to constants or single values. */ @@ -2655,6 +2680,65 @@ DEFINE_MATH_FN (RINT) (froms (convert float_value_p@0)) (convert (tos @0))))) +(for froms (XFLOORL XCEILL XROUNDL XRINTL) + tos (XFLOOR XCEIL XROUND XRINT) + /* llfloorl(extend(x)) -> llfloor(x), etc., if x is a double. */ + (if (optimize && canonicalize_math_p ()) + (simplify + (froms (convert double_value_p@0)) + (tos @0)))) + +(for froms (XFLOORL XCEILL XROUNDL XRINTL + XFLOOR XCEIL XROUND XRINT) + tos (XFLOORF XCEILF XROUNDF XRINTF) + /* llfloorl(extend(x)) and llfloor(extend(x)) -> llfloorf(x), etc., + if x is a float. */ + (if (optimize && canonicalize_math_p ()) + (simplify + (froms (convert float_value_p@0)) + (tos @0)))) + +(if (canonicalize_math_p ()) + /* xfloor(x) -> fix_trunc(x) if x is nonnegative. */ + (for floors (IFLOOR LFLOOR LLFLOOR) + (simplify + (floors tree_expr_nonnegative_p@0) + (fix_trunc @0)))) + +(if (canonicalize_math_p ()) + /* xfloor(x) -> fix_trunc(x), etc., if x is integer valued. */ + (for fns (IFLOOR LFLOOR LLFLOOR + ICEIL LCEIL LLCEIL + IROUND LROUND LLROUND) + (simplify + (fns integer_valued_real_p@0) + (fix_trunc @0))) + (if (!flag_errno_math) + /* xrint(x) -> fix_trunc(x), etc., if x is integer valued. */ + (for rints (IRINT LRINT LLRINT) + (simplify + (rints integer_valued_real_p@0) + (fix_trunc @0))))) + +(if (canonicalize_math_p ()) + (for ifn (IFLOOR ICEIL IROUND IRINT) + lfn (LFLOOR LCEIL LROUND LRINT) + llfn (LLFLOOR LLCEIL LLROUND LLRINT) + /* Canonicalize iround (x) to lround (x) on ILP32 targets where + sizeof (int) == sizeof (long). */ + (if (TYPE_PRECISION (integer_type_node) + == TYPE_PRECISION (long_integer_type_node)) + (simplify + (ifn @0) + (lfn:long_integer_type_node @0))) + /* Canonicalize llround (x) to lround (x) on LP64 targets where + sizeof (long long) == sizeof (long). */ + (if (TYPE_PRECISION (long_long_integer_type_node) + == TYPE_PRECISION (long_integer_type_node)) + (simplify + (llfn @0) + (lfn:long_integer_type_node @0))))) + /* cproj(x) -> x if we're ignoring infinities. */ (simplify (CPROJ @0) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8ecfd096781..45dc22ec255 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2015-10-26 Richard Sandiford + + * gcc.dg/torture/builtin-minmax-1.c: Don't run at -O0. + 2015-01-25 Paul Thomas PR fortran/67171 diff --git a/gcc/testsuite/gcc.dg/torture/builtin-minmax-1.c b/gcc/testsuite/gcc.dg/torture/builtin-minmax-1.c index 13831ad3a2e..a7c05b6dbbe 100644 --- a/gcc/testsuite/gcc.dg/torture/builtin-minmax-1.c +++ b/gcc/testsuite/gcc.dg/torture/builtin-minmax-1.c @@ -7,6 +7,7 @@ /* { dg-do link } */ /* { dg-options "-fno-math-errno" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */ /* All references to link_error should go away at compile-time. */ extern void link_error(int); -- 2.30.2