aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2013-05-17 09:32:01 +0000
committerMarek Polacek <mpolacek@gcc.gnu.org>2013-05-17 09:32:01 +0000
commit5b115c1f2bb402931e06e2979df006e607d5c6f4 (patch)
tree37045e2b3b3747a97aa02b2f03011ed1fee86477
parent68119618f7a027c1c0205319fc9d315169e6d60f (diff)
downloadgcc-5b115c1f2bb402931e06e2979df006e607d5c6f4.zip
gcc-5b115c1f2bb402931e06e2979df006e607d5c6f4.tar.gz
gcc-5b115c1f2bb402931e06e2979df006e607d5c6f4.tar.bz2
Add tree-ssa-strlen optimization.
From-SVN: r199006
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-25.c18
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-26.c25
-rw-r--r--gcc/tree-ssa-strlen.c30
4 files changed, 81 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0394c0e..7bb4e28 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
index 0000000..4862156
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-25.c
@@ -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
index 0000000..089355e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-26.c
@@ -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" } } */
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 5ab3764..c0f9ccd 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -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)))
{