diff options
author | Wilco Dijkstra <wdijkstr@arm.com> | 2016-10-05 12:31:05 +0000 |
---|---|---|
committer | Wilco Dijkstra <wilco@gcc.gnu.org> | 2016-10-05 12:31:05 +0000 |
commit | 71dea1dd60888030f3130f16933becdf597538ab (patch) | |
tree | 2e5b327406e5695e411f9f03cf0000a0eb1aafa8 /gcc/gimple-fold.c | |
parent | 92805612f4e0cdd33e10282eaf2cc0369bca3293 (diff) | |
download | gcc-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.c | 69 |
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); |