On 5 December 2016 at 23:47, Jakub Jelinek <ja...@redhat.com> wrote:
> On Mon, Dec 05, 2016 at 11:32:15PM +0530, Prathamesh Kulkarni wrote:
>> So I had to check if SSA_NAME_DEF_STMT (rhs2) was call to strstr
>> rather than rhs1.
>
> Then you need to test both whether it is strstr (s, t) == s or
> s == strstr (s, t).
>
>> +                           gassign *ga = gimple_build_assign (lhs, code,
>> +                                                     strcmp_lhs, zero);
>
> The formatting is wrong here.
>
>> +                           gsi_replace (&gsi, ga, false);
>> +                         }
>> +                     }
>> +                 }
>> +             }
>> +         }
>> +     }
>>        else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
>>       {
>>         tree type = TREE_TYPE (lhs);
>> @@ -2505,7 +2554,7 @@ const pass_data pass_data_strlen =
>>    0, /* properties_provided */
>>    0, /* properties_destroyed */
>>    0, /* todo_flags_start */
>> -  0, /* todo_flags_finish */
>> +  TODO_update_ssa, /* todo_flags_finish */
>
> No, please don't.  Just make sure to build proper SSA right away.
Hi,
Thanks for the suggestions, I have tried to modify the patch accordingly.
Does this version look OK ?
Bootstrap+tested on x86_64-unknown-linux-gnu with --enable-languages=all,ada
Cross tested on arm*-*-*, aarch64*-*-*.

Thanks,
Prathamesh
>
>         Jakub
2016-12-07  Prathamesh Kulkarni  <prathamesh.kulka...@linaro.org>

        * tree-ssa-strlen.c (strlen_optimize_stmt): Fold strstr(s, t) == s to
        memcmp (s, t, strlen (t)) == 0.
        Include tree-into-ssa.h.

testsuite/
        * gcc.dg/strlenopt-30.c: New test-case.

diff --git a/gcc/testsuite/gcc.dg/strlenopt-30.c 
b/gcc/testsuite/gcc.dg/strlenopt-30.c
new file mode 100644
index 0000000..603e23c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-30.c
@@ -0,0 +1,42 @@
+/* { 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 *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 f5(char *s, char *t)
+{
+  void foo(char *);
+
+  char *t1 = __builtin_strstr (s, t);
+  foo (t1);
+  return (t1 == s);
+}
+
+/* { dg-final { scan-tree-dump-times "__builtin_memcmp" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__builtin_strlen" 1 "strlen" } } */
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 339812e..b7f4cee 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -45,6 +45,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-chkp.h"
 #include "tree-hash-traits.h"
 #include "builtins.h"
+#include "tree-into-ssa.h"
 
 /* A vector indexed by SSA_NAME_VERSION.  0 means unknown, positive value
    is an index into strinfo vector, negative value stands for
@@ -2302,7 +2303,94 @@ 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))
+
+      /* Fold strstr (s, t) == s to memcmp (s, t, strlen (t)) == 0.
+        if var holding return value of strstr has single use.  */
+
+      else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE 
(lhs)))
+       {
+         enum tree_code code = gimple_assign_rhs_code (stmt);
+         if (code == EQ_EXPR || code == NE_EXPR)
+           {
+             tree rhs1 = gimple_assign_rhs1 (stmt);
+             tree rhs2 = gimple_assign_rhs2 (stmt);
+             if (TREE_CODE (rhs1) == SSA_NAME
+                 && TREE_CODE (rhs2) == SSA_NAME)
+               {
+                 gcall *call_stmt = dyn_cast<gcall *> (SSA_NAME_DEF_STMT 
(rhs1));
+                 if (!call_stmt)
+                   {
+                     call_stmt = dyn_cast<gcall *> (SSA_NAME_DEF_STMT (rhs2));
+                     tree tmp = rhs1;
+                     rhs1 = rhs2;
+                     rhs2 = tmp;
+                   }
+
+                 tree call_lhs;
+                 if (call_stmt
+                     && gimple_call_builtin_p (call_stmt, BUILT_IN_STRSTR)
+                     && (call_lhs = gimple_call_lhs (call_stmt))
+                     && has_single_use (call_lhs))
+                   {
+                     tree arg0 = gimple_call_arg (call_stmt, 0);
+                     if (operand_equal_p (arg0, rhs2, 0))
+                       {
+                         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;
+                             tree strlen_decl;
+                             gimple *strlen_call;
+
+                             strlen_decl = builtin_decl_explicit 
(BUILT_IN_STRLEN);
+                             strlen_call = gimple_build_call (strlen_decl, 1,
+                                                              arg1);
+                             arg1_len = make_ssa_name (size_type_node);
+                             gimple_call_set_lhs (strlen_call, arg1_len);
+                             update_stmt (strlen_call);
+                             gsi = gsi_for_stmt (call_stmt);
+                             gsi_insert_before (&gsi, strlen_call, 
GSI_SAME_STMT);
+                           }
+
+                         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_call_set_lhs (memcmp_call, memcmp_lhs);
+                         update_stmt (memcmp_call);
+                         gsi_remove (&gsi, true);
+                         gsi_insert_before (&gsi, memcmp_call, GSI_SAME_STMT);
+
+                         gsi = gsi_for_stmt (stmt);
+                         tree zero = build_zero_cst (TREE_TYPE (memcmp_lhs));
+                         gassign *ga = gimple_build_assign (lhs, code,
+                                                            memcmp_lhs, zero);
+                         gsi_replace (&gsi, ga, false);
+                         update_ssa (TODO_update_ssa);
+                       }
+                   }
+               }
+           }
+       }
+    else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
        {
          tree type = TREE_TYPE (lhs);
          if (TREE_CODE (type) == ARRAY_TYPE)

Reply via email to