tree-ssa-strlen.c (fold_strstr_to_memcmp): New function.
2016-12-14 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org> Jakub Jelinek <jakub@redhat.com> * tree-ssa-strlen.c (fold_strstr_to_memcmp): New function. (strlen_optimize_stmt): Call fold_strstr_to_memcmp. testsuite/ * gcc.dg/strlenopt-30.c: New test-case. Co-Authored-By: Jakub Jelinek <jakub@redhat.com> From-SVN: r243633
This commit is contained in:
parent
164f063463
commit
3b1970cb3c
@ -1,3 +1,9 @@
|
||||
2016-12-14 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
|
||||
Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* tree-ssa-strlen.c (fold_strstr_to_memcmp): New function.
|
||||
(strlen_optimize_stmt): Call fold_strstr_to_memcmp.
|
||||
|
||||
2016-12-14 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* lra-constraints.c (process_address_1): Do not attempt to decompose
|
||||
|
@ -1,3 +1,8 @@
|
||||
2016-12-14 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
|
||||
Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* gcc.dg/strlenopt-30.c: New test-case.
|
||||
|
||||
2016-12-14 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/78788
|
||||
|
63
gcc/testsuite/gcc.dg/strlenopt-30.c
Normal file
63
gcc/testsuite/gcc.dg/strlenopt-30.c
Normal file
@ -0,0 +1,63 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
__attribute__((no_icf))
|
||||
_Bool f1(char *s)
|
||||
{
|
||||
return __builtin_strstr (s, "hello") == s;
|
||||
}
|
||||
|
||||
__attribute__((no_icf))
|
||||
_Bool f2(char *s)
|
||||
{
|
||||
return s == __builtin_strstr (s, "hello");
|
||||
}
|
||||
|
||||
__attribute__((no_icf))
|
||||
_Bool f3(char *s)
|
||||
{
|
||||
return s != __builtin_strstr (s, "hello");
|
||||
}
|
||||
|
||||
__attribute__((no_icf))
|
||||
_Bool f4()
|
||||
{
|
||||
char *foo_f4(void);
|
||||
char *t1 = foo_f4();
|
||||
char *t2 = __builtin_strstr (t1, "hello");
|
||||
_Bool t3 = t2 == t1;
|
||||
return t3;
|
||||
}
|
||||
|
||||
__attribute__((no_icf))
|
||||
void f5(char *s)
|
||||
{
|
||||
char *t1 = __builtin_strstr (s, "hello");
|
||||
void foo_f5(void);
|
||||
if (t1 != s)
|
||||
foo_f5();
|
||||
}
|
||||
|
||||
/* Do not perform transform, since strlen (t)
|
||||
is unknown. */
|
||||
|
||||
__attribute__((no_icf))
|
||||
_Bool f6(char *s, char *t)
|
||||
{
|
||||
return __builtin_strstr (s, t) == s;
|
||||
}
|
||||
|
||||
/* Do not perform transform in this case, since
|
||||
t1 doesn't have single use. */
|
||||
|
||||
__attribute__((no_icf))
|
||||
_Bool f7(char *s)
|
||||
{
|
||||
void foo_f7(char *);
|
||||
|
||||
char *t1 = __builtin_strstr (s, "hello");
|
||||
foo_f7 (t1);
|
||||
return (t1 == s);
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "__builtin_memcmp" 5 "strlen" } } */
|
@ -2222,6 +2222,90 @@ handle_char_store (gimple_stmt_iterator *gsi)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Try to fold strstr (s, t) eq/ne s to memcmp (s, t, strlen (t)) eq/ne 0. */
|
||||
|
||||
static void
|
||||
fold_strstr_to_memcmp (tree rhs1, tree rhs2, gimple *stmt)
|
||||
{
|
||||
if (TREE_CODE (rhs1) != SSA_NAME
|
||||
|| TREE_CODE (rhs2) != SSA_NAME)
|
||||
return;
|
||||
|
||||
gimple *call_stmt = NULL;
|
||||
for (int pass = 0; pass < 2; pass++)
|
||||
{
|
||||
gimple *g = SSA_NAME_DEF_STMT (rhs1);
|
||||
if (gimple_call_builtin_p (g, BUILT_IN_STRSTR)
|
||||
&& has_single_use (rhs1)
|
||||
&& gimple_call_arg (g, 0) == rhs2)
|
||||
{
|
||||
call_stmt = g;
|
||||
break;
|
||||
}
|
||||
std::swap (rhs1, rhs2);
|
||||
}
|
||||
|
||||
if (call_stmt)
|
||||
{
|
||||
tree arg0 = gimple_call_arg (call_stmt, 0);
|
||||
|
||||
if (arg0 == rhs2)
|
||||
{
|
||||
tree arg1 = gimple_call_arg (call_stmt, 1);
|
||||
tree arg1_len = NULL_TREE;
|
||||
int idx = get_stridx (arg1);
|
||||
|
||||
if (idx)
|
||||
{
|
||||
if (idx < 0)
|
||||
arg1_len = build_int_cst (size_type_node, ~idx);
|
||||
else
|
||||
{
|
||||
strinfo *si = get_strinfo (idx);
|
||||
if (si)
|
||||
arg1_len = get_string_length (si);
|
||||
}
|
||||
}
|
||||
|
||||
if (arg1_len != NULL_TREE)
|
||||
{
|
||||
gimple_stmt_iterator gsi = gsi_for_stmt (call_stmt);
|
||||
tree memcmp_decl = builtin_decl_explicit (BUILT_IN_MEMCMP);
|
||||
gcall *memcmp_call = gimple_build_call (memcmp_decl, 3,
|
||||
arg0, arg1, arg1_len);
|
||||
tree memcmp_lhs = make_ssa_name (integer_type_node);
|
||||
gimple_set_vuse (memcmp_call, gimple_vuse (call_stmt));
|
||||
gimple_call_set_lhs (memcmp_call, memcmp_lhs);
|
||||
gsi_remove (&gsi, true);
|
||||
gsi_insert_before (&gsi, memcmp_call, GSI_SAME_STMT);
|
||||
tree zero = build_zero_cst (TREE_TYPE (memcmp_lhs));
|
||||
|
||||
if (is_gimple_assign (stmt))
|
||||
{
|
||||
if (gimple_assign_rhs_code (stmt) == COND_EXPR)
|
||||
{
|
||||
tree cond = gimple_assign_rhs1 (stmt);
|
||||
TREE_OPERAND (cond, 0) = memcmp_lhs;
|
||||
TREE_OPERAND (cond, 1) = zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
gimple_assign_set_rhs1 (stmt, memcmp_lhs);
|
||||
gimple_assign_set_rhs2 (stmt, zero);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gcond *cond = as_a<gcond *> (stmt);
|
||||
gimple_cond_set_lhs (cond, memcmp_lhs);
|
||||
gimple_cond_set_rhs (cond, zero);
|
||||
}
|
||||
update_stmt (stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to optimize a single statement at *GSI using string length
|
||||
knowledge. */
|
||||
|
||||
@ -2302,7 +2386,23 @@ strlen_optimize_stmt (gimple_stmt_iterator *gsi)
|
||||
else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
|
||||
handle_pointer_plus (gsi);
|
||||
}
|
||||
else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
|
||||
else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
|
||||
{
|
||||
enum tree_code code = gimple_assign_rhs_code (stmt);
|
||||
if (code == COND_EXPR)
|
||||
{
|
||||
tree cond = gimple_assign_rhs1 (stmt);
|
||||
enum tree_code cond_code = TREE_CODE (cond);
|
||||
|
||||
if (cond_code == EQ_EXPR || cond_code == NE_EXPR)
|
||||
fold_strstr_to_memcmp (TREE_OPERAND (cond, 0),
|
||||
TREE_OPERAND (cond, 1), stmt);
|
||||
}
|
||||
else if (code == EQ_EXPR || code == NE_EXPR)
|
||||
fold_strstr_to_memcmp (gimple_assign_rhs1 (stmt),
|
||||
gimple_assign_rhs2 (stmt), stmt);
|
||||
}
|
||||
else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
|
||||
{
|
||||
tree type = TREE_TYPE (lhs);
|
||||
if (TREE_CODE (type) == ARRAY_TYPE)
|
||||
@ -2316,6 +2416,13 @@ strlen_optimize_stmt (gimple_stmt_iterator *gsi)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (gcond *cond = dyn_cast<gcond *> (stmt))
|
||||
{
|
||||
enum tree_code code = gimple_cond_code (cond);
|
||||
if (code == EQ_EXPR || code == NE_EXPR)
|
||||
fold_strstr_to_memcmp (gimple_cond_lhs (stmt),
|
||||
gimple_cond_rhs (stmt), stmt);
|
||||
}
|
||||
|
||||
if (gimple_vdef (stmt))
|
||||
maybe_invalidate (stmt);
|
||||
|
Loading…
x
Reference in New Issue
Block a user