aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-fold.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2016-12-07 20:45:45 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2016-12-07 20:45:45 +0100
commitc89529306c91eafa81c762e9050d51c747c14af0 (patch)
treebd3017b456fa1faec07937e6000fdcee0fa4895e /gcc/gimple-fold.c
parent77f1efdbe8fe401040adb9b2b43aac85916682ac (diff)
downloadgcc-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.c68
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: