aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-strlen.c
diff options
context:
space:
mode:
authorPrathamesh Kulkarni <prathamesh.kulkarni@linaro.org>2016-12-14 09:10:31 +0000
committerPrathamesh Kulkarni <prathamesh3492@gcc.gnu.org>2016-12-14 09:10:31 +0000
commit3b1970cb3c603c900a175d9c7c36428cc031920f (patch)
tree87482185bbedc0d7800e5662413a0b59a40d0755 /gcc/tree-ssa-strlen.c
parent164f063463d64a1575841d6735ba0298605c4626 (diff)
downloadgcc-3b1970cb3c603c900a175d9c7c36428cc031920f.zip
gcc-3b1970cb3c603c900a175d9c7c36428cc031920f.tar.gz
gcc-3b1970cb3c603c900a175d9c7c36428cc031920f.tar.bz2
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
Diffstat (limited to 'gcc/tree-ssa-strlen.c')
-rw-r--r--gcc/tree-ssa-strlen.c109
1 files changed, 108 insertions, 1 deletions
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 339812e..67075f0 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -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);