re PR tree-optimization/71625 (missing strlen optimization on different array initial...
authorJakub Jelinek <jakub@redhat.com>
Wed, 29 Jun 2016 08:47:46 +0000 (10:47 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 29 Jun 2016 08:47:46 +0000 (10:47 +0200)
PR tree-optimization/71625
* tree-ssa-strlen.c (get_addr_stridx): Add PTR argument.  Assume list
is sorted by ascending list->offset.  If PTR is non-NULL and there is
previous strinfo, call get_stridx_plus_constant.
(get_stridx): Pass exp as second argument to get_addr_stridx.
(addr_stridxptr): Add missing list = list->next, so that there can be
more than one entries in the list.  Bump limit from 16 to 32.  Ensure
the list is sorted by ascending list->offset.
(get_stridx_plus_constant): Adjust so that it can be also called with
ADDR_EXPR instead of SSA_NAME as PTR.
(handle_char_store): Pass NULL_TREE as second argument to
get_addr_stridx.

* gcc.dg/strlenopt-28.c: New test.

From-SVN: r237841

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/strlenopt-28.c [new file with mode: 0644]
gcc/tree-ssa-strlen.c

index 7f6dcb3866bc8c04d1e4e935a85168448fc104f7..2d4f9b3f6e3a82ad16682e25553793f969fdae5e 100644 (file)
@@ -1,3 +1,18 @@
+2016-06-29  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/71625
+       * tree-ssa-strlen.c (get_addr_stridx): Add PTR argument.  Assume list
+       is sorted by ascending list->offset.  If PTR is non-NULL and there is
+       previous strinfo, call get_stridx_plus_constant.
+       (get_stridx): Pass exp as second argument to get_addr_stridx.
+       (addr_stridxptr): Add missing list = list->next, so that there can be
+       more than one entries in the list.  Bump limit from 16 to 32.  Ensure
+       the list is sorted by ascending list->offset.
+       (get_stridx_plus_constant): Adjust so that it can be also called with
+       ADDR_EXPR instead of SSA_NAME as PTR.
+       (handle_char_store): Pass NULL_TREE as second argument to
+       get_addr_stridx.
+
 2016-06-29  Richard Biener  <rguenther@suse.de>
 
        PR rtl-optimization/68961
index 70e90482ba09a4d56fcca742546008fb286ae033..c1c9a31a8e47b92fa4bee7932e35151f47db71db 100644 (file)
@@ -1,3 +1,8 @@
+2016-06-29  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/71625
+       * gcc.dg/strlenopt-28.c: New test.
+
 2016-06-29  Richard Biener  <rguenther@suse.de>
 
        PR middle-end/71002
diff --git a/gcc/testsuite/gcc.dg/strlenopt-28.c b/gcc/testsuite/gcc.dg/strlenopt-28.c
new file mode 100644 (file)
index 0000000..03fb017
--- /dev/null
@@ -0,0 +1,59 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+volatile int v;
+
+size_t
+f1 (void)
+{
+  char a[30];
+  v += 1;
+  memcpy (a, "1234567", 8);
+  memcpy (a + 7, "89abcdefg", 10);
+  memcpy (a + 16, "h", 2);
+  return strlen (a);   // This strlen should be optimized into 17.
+}
+
+size_t
+f2 (void)
+{
+  char a[30];
+  v += 2;
+  strcpy (a, "1234567");
+  strcpy (a + 7, "89abcdefg");
+  strcpy (a + 16, "h");
+  return strlen (a);   // This strlen should be optimized into 17.
+}
+
+size_t
+f3 (char *a)
+{
+  v += 3;
+  memcpy (a, "1234567", 8);
+  memcpy (a + 7, "89abcdefg", 10);
+  memcpy (a + 16, "h", 2);
+  return strlen (a);   // This strlen should be optimized into 17.
+}
+
+size_t
+f4 (char *a)
+{
+  v += 4;
+  strcpy (a, "1234567");
+  strcpy (a + 7, "89abcdefg");
+  strcpy (a + 16, "h");
+  return strlen (a);   // This strlen should be optimized into 17.
+}
+
+int
+main ()
+{
+  char a[30];
+  if (f1 () != 17 || f2 () != 17 || f3 (a) != 17 || f4 (a) != 17)
+    abort ();
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
index f306a9c9f3dd707556337ccf3bd2509ddc8cd7f4..232594b92ab0e4d47e97f78a26a2f39e1745ee08 100644 (file)
@@ -159,10 +159,10 @@ get_strinfo (int idx)
 /* Helper function for get_stridx.  */
 
 static int
-get_addr_stridx (tree exp)
+get_addr_stridx (tree exp, tree ptr)
 {
   HOST_WIDE_INT off;
-  struct stridxlist *list;
+  struct stridxlist *list, *last = NULL;
   tree base;
 
   if (!decl_to_stridxlist_htab)
@@ -180,9 +180,22 @@ get_addr_stridx (tree exp)
     {
       if (list->offset == off)
        return list->idx;
+      if (list->offset > off)
+       return 0;
+      last = list;
       list = list->next;
     }
   while (list);
+
+  if (ptr && last && last->idx > 0)
+    {
+      strinfo *si = get_strinfo (last->idx);
+      if (si
+         && si->length
+         && TREE_CODE (si->length) == INTEGER_CST
+         && compare_tree_int (si->length, off - last->offset) != -1)
+       return get_stridx_plus_constant (si, off - last->offset, ptr);
+    }
   return 0;
 }
 
@@ -234,7 +247,7 @@ get_stridx (tree exp)
 
   if (TREE_CODE (exp) == ADDR_EXPR)
     {
-      int idx = get_addr_stridx (TREE_OPERAND (exp, 0));
+      int idx = get_addr_stridx (TREE_OPERAND (exp, 0), exp);
       if (idx != 0)
        return idx;
     }
@@ -304,15 +317,29 @@ addr_stridxptr (tree exp)
   if (existed)
     {
       int i;
-      for (i = 0; i < 16; i++)
+      stridxlist *before = NULL;
+      for (i = 0; i < 32; i++)
        {
          if (list->offset == off)
            return &list->idx;
+         if (list->offset > off && before == NULL)
+           before = list;
          if (list->next == NULL)
            break;
+         list = list->next;
        }
-      if (i == 16)
+      if (i == 32)
        return NULL;
+      if (before)
+       {
+         list = before;
+         before = XOBNEW (&stridx_obstack, struct stridxlist);
+         *before = *list;
+         list->next = before;
+         list->offset = off;
+         list->idx = 0;
+         return &list->idx;
+       }
       list->next = XOBNEW (&stridx_obstack, struct stridxlist);
       list = list->next;
     }
@@ -613,9 +640,7 @@ verify_related_strinfos (strinfo *origsi)
 static int
 get_stridx_plus_constant (strinfo *basesi, HOST_WIDE_INT off, tree ptr)
 {
-  gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME);
-
-  if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
+  if (TREE_CODE (ptr) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
     return 0;
 
   if (basesi->length == NULL_TREE
@@ -633,7 +658,8 @@ get_stridx_plus_constant (strinfo *basesi, HOST_WIDE_INT off, tree ptr)
       || TREE_CODE (si->length) != INTEGER_CST)
     return 0;
 
-  if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
+  if (TREE_CODE (ptr) == SSA_NAME
+      && ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
     ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
 
   gcc_checking_assert (compare_tree_int (si->length, off) != -1);
@@ -651,6 +677,7 @@ get_stridx_plus_constant (strinfo *basesi, HOST_WIDE_INT off, tree ptr)
        {
          if (r == 0)
            {
+             gcc_assert (TREE_CODE (ptr) == SSA_NAME);
              ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
              return si->idx;
            }
@@ -2063,7 +2090,7 @@ handle_char_store (gimple_stmt_iterator *gsi)
        }
     }
   else
-    idx = get_addr_stridx (lhs);
+    idx = get_addr_stridx (lhs, NULL_TREE);
 
   if (idx > 0)
     {