Move int rounding folds to match.pd
authorRichard Sandiford <richard.sandiford@arm.com>
Mon, 26 Oct 2015 09:29:26 +0000 (09:29 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Mon, 26 Oct 2015 09:29:26 +0000 (09:29 +0000)
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
gcc/builtins.c
gcc/match.pd
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/builtin-minmax-1.c

index b8fd463..3285ca4 100644 (file)
@@ -1,5 +1,14 @@
 2015-10-26  Richard Sandiford  <richard.sandiford@arm.com>
 
+       * 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  <richard.sandiford@arm.com>
+
        * match.pd: Use macros to define built-in operator lists.
 
 2015-10-20  Richard Sandiford  <richard.sandiford@arm.com>
index c70bbfd..f947f1e 100644 (file)
@@ -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:
index e790d5b..00c6e7c 100644 (file)
@@ -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:
+
+     X<FN>F for all float functions, in the order i, l, ll
+     X<FN> for all double functions, in the same order
+     X<FN>L 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)
index 8ecfd09..45dc22e 100644 (file)
@@ -1,3 +1,7 @@
+2015-10-26  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * gcc.dg/torture/builtin-minmax-1.c: Don't run at -O0.
+
 2015-01-25  Paul Thomas  <pault@gcc.gnu.org>
 
        PR fortran/67171
index 13831ad..a7c05b6 100644 (file)
@@ -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);