Add tree-ssa-strlen optimization.
authormpolacek <mpolacek@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 17 May 2013 09:32:01 +0000 (09:32 +0000)
committermpolacek <mpolacek@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 17 May 2013 09:32:01 +0000 (09:32 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@199006 138bc75d-0d04-0410-961f-82ee72b054a4

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

index 0394c0e..7bb4e28 100644 (file)
@@ -1,3 +1,12 @@
+2013-05-17  Marek Polacek  <polacek@redhat.com>
+
+       * tree-ssa-strlen.c (handle_char_store): Don't invalidate
+       cached length when doing non-zero store of storing '\0' to
+       '\0'.
+
+       * gcc.dg/strlenopt-25.c: New test.
+       * gcc.dg/strlenopt-26.c: Likewise.
+
 2013-05-17  Jakub Jelinek  <jakub@redhat.com>
 
        * tree-vect-patterns.c (vect_recog_rotate_pattern): For
diff --git a/gcc/testsuite/gcc.dg/strlenopt-25.c b/gcc/testsuite/gcc.dg/strlenopt-25.c
new file mode 100644 (file)
index 0000000..4862156
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+int
+main ()
+{
+  char p[] = "foobar";
+  int len, len2;
+  len = strlen (p);
+  p[0] = 'O';
+  len2 = strlen (p);
+  return len - len2;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-26.c b/gcc/testsuite/gcc.dg/strlenopt-26.c
new file mode 100644 (file)
index 0000000..089355e
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) size_t
+fn1 (char *p, const char *r)
+{
+  size_t len1 = strlen (r);
+  char *q = strchr (p, '\0');
+  *q = '\0';
+  return len1 - strlen (r); // This strlen should be optimized into len1.
+}
+
+int
+main (void)
+{
+  char p[] = "foobar";
+  const char *volatile q = "xyzzy";
+  fn1 (p, q);
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
index 5ab3764..c0f9ccd 100644 (file)
@@ -1694,7 +1694,8 @@ handle_char_store (gimple_stmt_iterator *gsi)
              else
                {
                  si->writable = true;
-                 si->dont_invalidate = true;
+                 gsi_next (gsi);
+                 return false;
                }
            }
          else
@@ -1717,6 +1718,33 @@ handle_char_store (gimple_stmt_iterator *gsi)
            si->endptr = ssaname;
          si->dont_invalidate = true;
        }
+      /* If si->length is non-zero constant, we aren't overwriting '\0',
+        and if we aren't storing '\0', we know that the length of the
+        string and any other zero terminated string in memory remains
+        the same.  In that case we move to the next gimple statement and
+        return to signal the caller that it shouldn't invalidate anything.  
+
+        This is benefical for cases like:
+
+        char p[20];
+        void foo (char *q)
+        {
+          strcpy (p, "foobar");
+          size_t len = strlen (p);        // This can be optimized into 6
+          size_t len2 = strlen (q);        // This has to be computed
+          p[0] = 'X';
+          size_t len3 = strlen (p);        // This can be optimized into 6
+          size_t len4 = strlen (q);        // This can be optimized into len2
+          bar (len, len2, len3, len4);
+        }
+       */ 
+      else if (si != NULL && si->length != NULL_TREE
+              && TREE_CODE (si->length) == INTEGER_CST
+              && integer_nonzerop (gimple_assign_rhs1 (stmt)))
+       {
+         gsi_next (gsi);
+         return false;
+       }
     }
   else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
     {