The strlen enhancement committed in r263018 to handle multi-character
assignments extended the handle_char_store() function to handle such
stores via MEM_REFs.  Prior to that the function only dealt with
single-char stores.  The enhancement neglected to constrain a case
in the function that assumed the function's previous constraint.
As a result, when the original optimization takes place with
a multi-character store, the function computes the wrong string
length.

The attached patch adds the missing constraint.

Martin
PR tree-optimization - incorrrect strlen result after second strcpy into
the same destination

gcc/ChangeLog:

	* tree-ssa-strlen.c (handle_char_store): Constrain a single character
	optimization to just single character stores.

gcc/testsuite/ChangeLog:

	* gcc.dg/strlenopt-26.c: Exit with test result status.
	* gcc.dg/strlenopt-67.c: New test.

Index: gcc/testsuite/gcc.dg/strlenopt-26.c
===================================================================
--- gcc/testsuite/gcc.dg/strlenopt-26.c	(revision 272618)
+++ gcc/testsuite/gcc.dg/strlenopt-26.c	(working copy)
@@ -17,8 +17,7 @@ main (void)
 {
   char p[] = "foobar";
   const char *volatile q = "xyzzy";
-  fn1 (p, q);
-  return 0;
+  return fn1 (p, q);
 }
 
 /* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
Index: gcc/testsuite/gcc.dg/strlenopt-67.c
===================================================================
--- gcc/testsuite/gcc.dg/strlenopt-67.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/strlenopt-67.c	(working copy)
@@ -0,0 +1,52 @@
+/* PR tree-optimization/90989 - incorrrect strlen result after second strcpy
+   into the same destination.
+   { dg-do compile }
+   { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+
+// #include "strlenopt.h"
+
+char a[4];
+
+int f4 (void)
+{
+  char b[4];
+  __builtin_strcpy (b, "12");
+
+  int i = __builtin_strcmp (a, b);
+
+  __builtin_strcpy (b, "123");
+  if (__builtin_strlen (b) != 3)
+    __builtin_abort ();
+
+  return i;
+}
+
+int f6 (void)
+{
+  char b[6];
+  __builtin_strcpy (b, "1234");
+
+  int i = __builtin_strcmp (a, b);
+
+  __builtin_strcpy (b, "12345");
+  if (__builtin_strlen (b) != 5)
+    __builtin_abort ();
+
+  return i;
+}
+
+int f8 (void)
+{
+  char b[8];
+  __builtin_strcpy (b, "1234");
+
+  int i = __builtin_strcmp (a, b);
+
+  __builtin_strcpy (b, "1234567");
+  if (__builtin_strlen (b) != 7)
+    __builtin_abort ();
+
+  return i;
+}
+
+/* { dg-final { scan-tree-dump-times "abort|strlen" 0 "optimized" } } */
Index: gcc/tree-ssa-strlen.c
===================================================================
--- gcc/tree-ssa-strlen.c	(revision 272618)
+++ gcc/tree-ssa-strlen.c	(working copy)
@@ -3462,34 +3462,38 @@ handle_char_store (gimple_stmt_iterator *gsi)
 	      return false;
 	    }
 	}
-      /* If si->nonzero_chars > OFFSET, 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:
+      if (cmp > 0
+	  && storing_nonzero_p
+	  && TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE)
+	{
+	  /* Handle a single non-nul character store.
+	     If si->nonzero_chars > OFFSET, 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.
 
-	 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 (storing_nonzero_p && cmp > 0)
-	{
+	     This is benefical for cases like:
+
+	     char p[20];
+	     void foo (char *q)
+	     {
+	       strcpy (p, "foobar");
+	       size_t len = strlen (p);     // can be folded to 6
+	       size_t len2 = strlen (q);    // has to be computed
+	       p[0] = 'X';
+	       size_t len3 = strlen (p);    // can be folded to 6
+	       size_t len4 = strlen (q);    // can be folded to len2
+	       bar (len, len2, len3, len4);
+	       } */
 	  gsi_next (gsi);
 	  return false;
 	}
-      else if (storing_all_zeros_p
-	       || storing_nonzero_p
-	       || (offset != 0 && cmp > 0))
+
+      if (storing_all_zeros_p
+	  || storing_nonzero_p
+	  || (offset != 0 && cmp > 0))
 	{
 	  /* When STORING_NONZERO_P, we know that the string will start
 	     with at least OFFSET + 1 nonzero characters.  If storing

Reply via email to