@@ -1694,7 +1694,8 @@ handle_char_store (gimple_stmt_iterator
else
{
si->writable = true;
- si->dont_invalidate = true;
+ gsi_next (gsi);
+ return false;
}
}
else
@@ -1717,6 +1718,33 @@ handle_char_store (gimple_stmt_iterator
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)))
{
@@ -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" } } */
@@ -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" } } */