Commit c8952930 by Jakub Jelinek Committed by Jakub Jelinek

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
parent 77f1efdb
2016-12-07 Jakub Jelinek <jakub@redhat.com> 2016-12-07 Jakub Jelinek <jakub@redhat.com>
* 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.
PR c++/78692 PR c++/78692
* cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Set lhs * cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Set lhs
var to lhs of new_stmt right before noreturn handling rather than to var to lhs of new_stmt right before noreturn handling rather than to
...@@ -163,7 +163,6 @@ static tree fold_builtin_3 (location_t, tree, tree, tree, tree); ...@@ -163,7 +163,6 @@ static tree fold_builtin_3 (location_t, tree, tree, tree, tree);
static tree fold_builtin_varargs (location_t, tree, tree*, int); static tree fold_builtin_varargs (location_t, tree, tree*, int);
static tree fold_builtin_strpbrk (location_t, tree, tree, tree); static tree fold_builtin_strpbrk (location_t, tree, tree, tree);
static tree fold_builtin_strstr (location_t, tree, tree, tree);
static tree fold_builtin_strspn (location_t, tree, tree); static tree fold_builtin_strspn (location_t, tree, tree);
static tree fold_builtin_strcspn (location_t, tree, tree); static tree fold_builtin_strcspn (location_t, tree, tree);
...@@ -8303,9 +8302,6 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1) ...@@ -8303,9 +8302,6 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1)
CASE_FLT_FN (BUILT_IN_MODF): CASE_FLT_FN (BUILT_IN_MODF):
return fold_builtin_modf (loc, arg0, arg1, type); return fold_builtin_modf (loc, arg0, arg1, type);
case BUILT_IN_STRSTR:
return fold_builtin_strstr (loc, arg0, arg1, type);
case BUILT_IN_STRSPN: case BUILT_IN_STRSPN:
return fold_builtin_strspn (loc, arg0, arg1); return fold_builtin_strspn (loc, arg0, arg1);
...@@ -8729,72 +8725,6 @@ readonly_data_expr (tree exp) ...@@ -8729,72 +8725,6 @@ readonly_data_expr (tree exp)
return false; return false;
} }
/* Simplify a call to the strstr 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_strstr (location_t loc, tree s1, tree s2, tree type)
{
if (!validate_arg (s1, POINTER_TYPE)
|| !validate_arg (s2, POINTER_TYPE))
return NULL_TREE;
else
{
tree fn;
const char *p1, *p2;
p2 = c_getstr (s2);
if (p2 == NULL)
return NULL_TREE;
p1 = c_getstr (s1);
if (p1 != NULL)
{
const char *r = strstr (p1, p2);
tree tem;
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);
}
/* The argument is const char *, and the result is char *, so we need
a type conversion here to avoid a warning. */
if (p2[0] == '\0')
return fold_convert_loc (loc, type, s1);
if (p2[1] != '\0')
return NULL_TREE;
fn = builtin_decl_implicit (BUILT_IN_STRCHR);
if (!fn)
return NULL_TREE;
/* New argument list transforming strstr(s1, s2) to
strchr(s1, s2[0]). */
return build_call_expr_loc (loc, fn, 2, s1,
build_int_cst (integer_type_node, p2[0]));
}
}
/* Simplify a call to the strpbrk builtin. S1 and S2 are the arguments /* Simplify a call to the strpbrk builtin. S1 and S2 are the arguments
to the call, and TYPE is its return type. to the call, and TYPE is its return type.
......
...@@ -1434,6 +1434,22 @@ fold_const_call (combined_fn fn, tree type, tree arg0, tree arg1) ...@@ -1434,6 +1434,22 @@ fold_const_call (combined_fn fn, tree type, tree arg0, tree arg1)
} }
return NULL_TREE; return NULL_TREE;
case CFN_BUILT_IN_STRSTR:
if ((p1 = c_getstr (arg1)))
{
if ((p0 = c_getstr (arg0)))
{
const char *r = strstr (p0, p1);
if (r == NULL)
return build_int_cst (type, 0);
return fold_convert (type,
fold_build_pointer_plus_hwi (arg0, r - p0));
}
if (*p1 == '\0')
return fold_convert (type, arg0);
}
return NULL_TREE;
default: default:
return fold_const_call_1 (fn, type, arg0, arg1); return fold_const_call_1 (fn, type, arg0, arg1);
} }
......
...@@ -1506,11 +1506,11 @@ gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi, bool is_strrchr) ...@@ -1506,11 +1506,11 @@ gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi, bool is_strrchr)
return false; return false;
/* Transform strrchr (s, 0) to strchr (s, 0) when optimizing for size. */ /* 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); 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); gimple *repl = gimple_build_call (strchr_fn, 2, str, c);
replace_call_with_call_and_fold (gsi, repl); replace_call_with_call_and_fold (gsi, repl);
...@@ -1549,6 +1549,68 @@ gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi, bool is_strrchr) ...@@ -1549,6 +1549,68 @@ gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi, bool is_strrchr)
return true; 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 /* Simplify a call to the strcat builtin. DST and SRC are the arguments
to the call. to the call.
...@@ -3236,6 +3298,8 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi) ...@@ -3236,6 +3298,8 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
case BUILT_IN_RINDEX: case BUILT_IN_RINDEX:
case BUILT_IN_STRRCHR: case BUILT_IN_STRRCHR:
return gimple_fold_builtin_strchr (gsi, true); return gimple_fold_builtin_strchr (gsi, true);
case BUILT_IN_STRSTR:
return gimple_fold_builtin_strstr (gsi);
case BUILT_IN_STRCMP: case BUILT_IN_STRCMP:
case BUILT_IN_STRCASECMP: case BUILT_IN_STRCASECMP:
case BUILT_IN_STRNCMP: case BUILT_IN_STRNCMP:
......
2016-12-07 Jakub Jelinek <jakub@redhat.com> 2016-12-07 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/builtin-strstr-1.c: New test.
* g++.dg/cpp0x/constexpr-strstr.C: New test.
PR c++/78692 PR c++/78692
* g++.dg/torture/pr78692.C: New test. * g++.dg/torture/pr78692.C: New test.
......
// { dg-do compile { target c++11 } }
constexpr const char *f1 (const char *p, const char *q) { return __builtin_strstr (p, q); }
constexpr const char a[] = "abcdefedcbaaaaab";
constexpr const char b[] = "fed";
constexpr const char c[] = "aaab";
static_assert (f1 ("abcde", "ee") == nullptr, "");
static_assert (f1 (a, b) == a + 5, "");
static_assert (f1 (a, c) == a + 12, "");
static_assert (f1 (a, "") == a, "");
static_assert (f1 (a, "aaaaaab") == nullptr, "");
static_assert (f1 (a, "aaa") == a + 10, "");
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
/* { dg-final { scan-tree-dump-not "link_error" "optimized" } } */
/* { dg-final { scan-tree-dump-not "__builtin_strstr" "optimized" } } */
/* { dg-final { scan-tree-dump-times "return p_\[0-9]*.D.;" 1 "optimized" } } */
/* { dg-final { scan-tree-dump-times "__builtin_strchr" 1 "optimized" } } */
extern void link_error (void);
void
foo (void)
{
const char *p = "abcdef";
const char *q = "def";
p++;
q++;
if (__builtin_strstr (p, q) != p + 3)
link_error ();
}
char *
bar (const char *p)
{
return __builtin_strstr (p, "");
}
char *
baz (const char *p)
{
return __builtin_strstr (p, "d");
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment