Move all existing strchr and strrchr folding from builtins.c to gimple-fold.c.
authorWilco Dijkstra <wdijkstr@arm.com>
Wed, 5 Oct 2016 12:31:05 +0000 (12:31 +0000)
committerWilco Dijkstra <wilco@gcc.gnu.org>
Wed, 5 Oct 2016 12:31:05 +0000 (12:31 +0000)
    gcc/
        * builtins.c (fold_builtin_strchr): Remove function.
        (fold_builtin_strrchr): Likewise.
        (fold_builtin2): Remove strchr, index, strrchr, rindex cases.
        * gimple-fold.c (target_char_cst_p): New function.
        (gimple_fold_builtin_strchr) Add more foldings.
        (gimple_fold_builtin): Add index, strrchr, rindex cases.

From-SVN: r240782

gcc/ChangeLog
gcc/builtins.c
gcc/gimple-fold.c

index 4fcd8f5b69ec96acfa225cc0096b4ccb6ba92c14..81e4235d2e45bdd2080edcca899ab54e46f0ade8 100644 (file)
@@ -1,3 +1,12 @@
+2016-10-05  Wilco Dijkstra  <wdijkstr@arm.com>
+
+       * builtins.c (fold_builtin_strchr): Remove function.
+       (fold_builtin_strrchr): Likewise.
+       (fold_builtin2): Remove strchr, index, strrchr, rindex cases.
+       * gimple-fold.c (target_char_cst_p): New function.
+       (gimple_fold_builtin_strchr) Add more foldings.
+       (gimple_fold_builtin): Add index, strrchr, rindex cases.
+
 2016-10-05  Richard Biener  <rguenther@suse.de>
 
        PR middle-end/77863
index 35cb109bc4bfbf384c662a3d1ab567b724dda4c3..facecd3cfef711fdb9190ab2e80c07778be3fffe 100644 (file)
@@ -148,7 +148,6 @@ static tree rewrite_call_expr (location_t, tree, int, tree, int, ...);
 static bool validate_arg (const_tree, enum tree_code code);
 static rtx expand_builtin_fabs (tree, rtx, rtx);
 static rtx expand_builtin_signbit (tree, rtx);
-static tree fold_builtin_strchr (location_t, tree, tree, tree);
 static tree fold_builtin_memchr (location_t, tree, tree, tree, tree);
 static tree fold_builtin_memcmp (location_t, tree, tree, tree);
 static tree fold_builtin_strcmp (location_t, tree, tree);
@@ -168,7 +167,6 @@ static tree fold_builtin_varargs (location_t, tree, tree*, int);
 
 static tree fold_builtin_strpbrk (location_t, tree, tree, tree);
 static tree fold_builtin_strstr (location_t, tree, tree, tree);
-static tree fold_builtin_strrchr (location_t, tree, tree, tree);
 static tree fold_builtin_strspn (location_t, tree, tree);
 static tree fold_builtin_strcspn (location_t, tree, tree);
 
@@ -8395,14 +8393,6 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1)
     case BUILT_IN_STRCSPN:
       return fold_builtin_strcspn (loc, arg0, arg1);
 
-    case BUILT_IN_STRCHR:
-    case BUILT_IN_INDEX:
-      return fold_builtin_strchr (loc, arg0, arg1, type);
-
-    case BUILT_IN_STRRCHR:
-    case BUILT_IN_RINDEX:
-      return fold_builtin_strrchr (loc, arg0, arg1, type);
-
     case BUILT_IN_STRCMP:
       return fold_builtin_strcmp (loc, arg0, arg1);
 
@@ -8895,124 +8885,6 @@ fold_builtin_strstr (location_t loc, tree s1, tree s2, tree type)
     }
 }
 
-/* Simplify a call to the strchr builtin.  S1 and S2 are the arguments to
-   the call, and TYPE is its return type.
-
-   Return NULL_TREE if no simplification was possible, otherwise return the
-   simplified form of the call as a tree.
-
-   The simplified form may be a constant or other expression which
-   computes the same value, but in a more efficient manner (including
-   calls to other builtin functions).
-
-   The call may contain arguments which need to be evaluated, but
-   which are not useful to determine the result of the call.  In
-   this case we return a chain of COMPOUND_EXPRs.  The LHS of each
-   COMPOUND_EXPR will be an argument which must be evaluated.
-   COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
-   COMPOUND_EXPR in the chain will contain the tree for the simplified
-   form of the builtin function call.  */
-
-static tree
-fold_builtin_strchr (location_t loc, tree s1, tree s2, tree type)
-{
-  if (!validate_arg (s1, POINTER_TYPE)
-      || !validate_arg (s2, INTEGER_TYPE))
-    return NULL_TREE;
-  else
-    {
-      const char *p1;
-
-      if (TREE_CODE (s2) != INTEGER_CST)
-       return NULL_TREE;
-
-      p1 = c_getstr (s1);
-      if (p1 != NULL)
-       {
-         char c;
-         const char *r;
-         tree tem;
-
-         if (target_char_cast (s2, &c))
-           return NULL_TREE;
-
-         r = strchr (p1, c);
-
-         if (r == NULL)
-           return build_int_cst (TREE_TYPE (s1), 0);
-
-         /* Return an offset into the constant string argument.  */
-         tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
-         return fold_convert_loc (loc, type, tem);
-       }
-      return NULL_TREE;
-    }
-}
-
-/* Simplify a call to the strrchr builtin.  S1 and S2 are the arguments to
-   the call, and TYPE is its return type.
-
-   Return NULL_TREE if no simplification was possible, otherwise return the
-   simplified form of the call as a tree.
-
-   The simplified form may be a constant or other expression which
-   computes the same value, but in a more efficient manner (including
-   calls to other builtin functions).
-
-   The call may contain arguments which need to be evaluated, but
-   which are not useful to determine the result of the call.  In
-   this case we return a chain of COMPOUND_EXPRs.  The LHS of each
-   COMPOUND_EXPR will be an argument which must be evaluated.
-   COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
-   COMPOUND_EXPR in the chain will contain the tree for the simplified
-   form of the builtin function call.  */
-
-static tree
-fold_builtin_strrchr (location_t loc, tree s1, tree s2, tree type)
-{
-  if (!validate_arg (s1, POINTER_TYPE)
-      || !validate_arg (s2, INTEGER_TYPE))
-    return NULL_TREE;
-  else
-    {
-      tree fn;
-      const char *p1;
-
-      if (TREE_CODE (s2) != INTEGER_CST)
-       return NULL_TREE;
-
-      p1 = c_getstr (s1);
-      if (p1 != NULL)
-       {
-         char c;
-         const char *r;
-         tree tem;
-
-         if (target_char_cast (s2, &c))
-           return NULL_TREE;
-
-         r = strrchr (p1, c);
-
-         if (r == NULL)
-           return build_int_cst (TREE_TYPE (s1), 0);
-
-         /* Return an offset into the constant string argument.  */
-         tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
-         return fold_convert_loc (loc, type, tem);
-       }
-
-      if (! integer_zerop (s2))
-       return NULL_TREE;
-
-      fn = builtin_decl_implicit (BUILT_IN_STRCHR);
-      if (!fn)
-       return NULL_TREE;
-
-      /* Transform strrchr(s1, '\0') to strchr(s1, '\0').  */
-      return build_call_expr_loc (loc, fn, 2, s1, s2);
-    }
-}
-
 /* Simplify a call to the strpbrk builtin.  S1 and S2 are the arguments
    to the call, and TYPE is its return type.
 
index 1aae8456bc81c0291ebcf136ad5c70fde2e711a5..59c4cb80a362063c52e99eaf5775cb9bee197ab7 100644 (file)
@@ -57,6 +57,20 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfg.h"
 
 
+/* Return true if T is a constant and the value cast to a target char
+   can be represented by a host char.
+   Store the casted char constant in *P if so.  */
+
+static bool
+target_char_cst_p (tree t, char *p)
+{
+  if (!tree_fits_uhwi_p (t) || CHAR_TYPE_SIZE != HOST_BITS_PER_CHAR)
+    return false;
+
+  *p = (char)tree_to_uhwi (t);
+  return true;
+}
+
 /* Return true when DECL can be referenced from current unit.
    FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
    We can get declarations that are not possible to reference for various
@@ -1457,23 +1471,61 @@ gimple_fold_builtin_strncpy (gimple_stmt_iterator *gsi,
   return true;
 }
 
-/* Simplify strchr (str, 0) into str + strlen (str).
+/* Fold function call to builtin strchr or strrchr.
+   If both arguments are constant, evaluate and fold the result,
+   otherwise simplify str(r)chr (str, 0) into str + strlen (str).
    In general strlen is significantly faster than strchr
    due to being a simpler operation.  */
 static bool
-gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi)
+gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi, bool is_strrchr)
 {
   gimple *stmt = gsi_stmt (*gsi);
   tree str = gimple_call_arg (stmt, 0);
   tree c = gimple_call_arg (stmt, 1);
   location_t loc = gimple_location (stmt);
+  const char *p;
+  char ch;
 
-  if (optimize_function_for_size_p (cfun))
+  if (!gimple_call_lhs (stmt))
     return false;
 
-  if (!integer_zerop (c) || !gimple_call_lhs (stmt))
+  if ((p = c_getstr (str)) && target_char_cst_p (c, &ch))
+    {
+      const char *p1 = is_strrchr ? strrchr (p, ch) : strchr (p, ch);
+
+      if (p1 == NULL)
+       {
+         replace_call_with_value (gsi, integer_zero_node);
+         return true;
+       }
+
+      tree len = build_int_cst (size_type_node, p1 - p);
+      gimple_seq stmts = NULL;
+      gimple *new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
+                                             POINTER_PLUS_EXPR, str, len);
+      gimple_seq_add_stmt_without_update (&stmts, new_stmt);
+      gsi_replace_with_seq_vops (gsi, stmts);
+      return true;
+    }
+
+  if (!integer_zerop (c))
     return false;
 
+  /* Transform strrchr (s, 0) to strchr (s, 0) when optimizing for size.  */
+  if (optimize_function_for_size_p (cfun))
+    {
+      tree strchr_fn = builtin_decl_implicit (BUILT_IN_STRCHR);
+
+      if (is_strrchr && strchr_fn)
+       {
+         gimple *repl = gimple_build_call (strchr_fn, 2, str, c);
+         replace_call_with_call_and_fold (gsi, repl);
+         return true;
+       }
+
+      return false;
+    }
+
   tree len;
   tree strlen_fn = builtin_decl_implicit (BUILT_IN_STRLEN);
 
@@ -2947,11 +2999,12 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
                                         gimple_call_arg (stmt, 1));
     case BUILT_IN_STRNCAT:
       return gimple_fold_builtin_strncat (gsi);
+    case BUILT_IN_INDEX:
     case BUILT_IN_STRCHR:
-      if (gimple_fold_builtin_strchr (gsi))
-       return true;
-      /* Perform additional folding in builtin.c.  */
-      break;
+      return gimple_fold_builtin_strchr (gsi, false);
+    case BUILT_IN_RINDEX:
+    case BUILT_IN_STRRCHR:
+      return gimple_fold_builtin_strchr (gsi, true);
     case BUILT_IN_FPUTS:
       return gimple_fold_builtin_fputs (gsi, gimple_call_arg (stmt, 0),
                                        gimple_call_arg (stmt, 1), false);