aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-fold.c
diff options
context:
space:
mode:
authorWilco Dijkstra <wdijkstr@arm.com>2016-10-05 12:31:05 +0000
committerWilco Dijkstra <wilco@gcc.gnu.org>2016-10-05 12:31:05 +0000
commit71dea1dd60888030f3130f16933becdf597538ab (patch)
tree2e5b327406e5695e411f9f03cf0000a0eb1aafa8 /gcc/gimple-fold.c
parent92805612f4e0cdd33e10282eaf2cc0369bca3293 (diff)
downloadgcc-71dea1dd60888030f3130f16933becdf597538ab.zip
gcc-71dea1dd60888030f3130f16933becdf597538ab.tar.gz
gcc-71dea1dd60888030f3130f16933becdf597538ab.tar.bz2
Move all existing strchr and strrchr folding from builtins.c to gimple-fold.c.
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
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r--gcc/gimple-fold.c69
1 files changed, 61 insertions, 8 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 1aae845..59c4cb8 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -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);