diff options
author | Jakub Jelinek <jakub@redhat.com> | 2016-12-07 20:45:45 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2016-12-07 20:45:45 +0100 |
commit | c89529306c91eafa81c762e9050d51c747c14af0 (patch) | |
tree | bd3017b456fa1faec07937e6000fdcee0fa4895e /gcc/gimple-fold.c | |
parent | 77f1efdbe8fe401040adb9b2b43aac85916682ac (diff) | |
download | gcc-c89529306c91eafa81c762e9050d51c747c14af0.zip gcc-c89529306c91eafa81c762e9050d51c747c14af0.tar.gz gcc-c89529306c91eafa81c762e9050d51c747c14af0.tar.bz2 |
builtins.c (fold_builtin_strstr): Removed.
* builtins.c (fold_builtin_strstr): Removed.
(fold_builtin_2): Don't call fold_builtin_strstr.
* gimple-fold.c (gimple_fold_builtin_strchr): Check is_strrchr
earlier in the strrchr (x, 0) -> strchr (x, 0) optimization.
(gimple_fold_builtin_strstr): New function.
(gimple_fold_builtin): Call it.
* fold-const-call.c (fold_const_call): Handle CFN_BUILT_IN_STRSTR.
* gcc.dg/builtin-strstr-1.c: New test.
* g++.dg/cpp0x/constexpr-strstr.C: New test.
From-SVN: r243378
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r-- | gcc/gimple-fold.c | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index f586c09..d00625b 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -1506,11 +1506,11 @@ gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi, bool is_strrchr) return false; /* Transform strrchr (s, 0) to strchr (s, 0) when optimizing for size. */ - if (optimize_function_for_size_p (cfun)) + if (is_strrchr && optimize_function_for_size_p (cfun)) { tree strchr_fn = builtin_decl_implicit (BUILT_IN_STRCHR); - if (is_strrchr && strchr_fn) + if (strchr_fn) { gimple *repl = gimple_build_call (strchr_fn, 2, str, c); replace_call_with_call_and_fold (gsi, repl); @@ -1549,6 +1549,68 @@ gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi, bool is_strrchr) return true; } +/* Fold function call to builtin strstr. + If both arguments are constant, evaluate and fold the result, + additionally fold strstr (x, "") into x and strstr (x, "c") + into strchr (x, 'c'). */ +static bool +gimple_fold_builtin_strstr (gimple_stmt_iterator *gsi) +{ + gimple *stmt = gsi_stmt (*gsi); + tree haystack = gimple_call_arg (stmt, 0); + tree needle = gimple_call_arg (stmt, 1); + const char *p, *q; + + if (!gimple_call_lhs (stmt)) + return false; + + q = c_getstr (needle); + if (q == NULL) + return false; + + if ((p = c_getstr (haystack))) + { + const char *r = strstr (p, q); + + if (r == NULL) + { + replace_call_with_value (gsi, integer_zero_node); + return true; + } + + tree len = build_int_cst (size_type_node, r - p); + gimple_seq stmts = NULL; + gimple *new_stmt + = gimple_build_assign (gimple_call_lhs (stmt), POINTER_PLUS_EXPR, + haystack, len); + gimple_seq_add_stmt_without_update (&stmts, new_stmt); + gsi_replace_with_seq_vops (gsi, stmts); + return true; + } + + /* For strstr (x, "") return x. */ + if (q[0] == '\0') + { + replace_call_with_value (gsi, haystack); + return true; + } + + /* Transform strstr (x, "c") into strchr (x, 'c'). */ + if (q[1] == '\0') + { + tree strchr_fn = builtin_decl_implicit (BUILT_IN_STRCHR); + if (strchr_fn) + { + tree c = build_int_cst (integer_type_node, q[0]); + gimple *repl = gimple_build_call (strchr_fn, 2, haystack, c); + replace_call_with_call_and_fold (gsi, repl); + return true; + } + } + + return false; +} + /* Simplify a call to the strcat builtin. DST and SRC are the arguments to the call. @@ -3236,6 +3298,8 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi) case BUILT_IN_RINDEX: case BUILT_IN_STRRCHR: return gimple_fold_builtin_strchr (gsi, true); + case BUILT_IN_STRSTR: + return gimple_fold_builtin_strstr (gsi); case BUILT_IN_STRCMP: case BUILT_IN_STRCASECMP: case BUILT_IN_STRNCMP: |