diff mbox series

minor tweak to complete strlen fix for PR83501

Message ID 925be551-3dea-508b-5366-28237b3851cd@gmail.com
State New
Headers show
Series minor tweak to complete strlen fix for PR83501 | expand

Commit Message

Martin Sebor Jan. 3, 2018, 9:29 p.m. UTC
Prathamesh's fix restores the optimization for the test case
reported in the bug (thanks!) but it isn't sufficient to bring
GCC 8 completely up to par with 7.  Prior GCC versions are able
to compute the string length in the test case below but GCC 8
cannot.

   char d[8];
   const char s[] = "1234567";

   void f (void)
   {
     __builtin_strcpy (d, s);
     if (__builtin_strlen (d) != sizeof s - 1)
       __builtin_abort ();
   }

The attached patch slightly tweaks Prathamesh's patch to also
handle the case above.  There still are outstanding cases where
folding into MEM_REF defeats the strlen pass (I've raised
a couple of new bugs to track those I noticed today) but, AFAICT,
those aren't recent regressions so they can be dealt with later
and separately.

Martin

PS I've renamed the function because I had initially thought it
also needed to handle PHIs that refer to strings of the same
length (and there isn't necessarily one "right" string to return)
but then realized that the lack of that handling isn't part of
the regression so I didn't include it but kept the new return
type and name.  When the pass is enhanced to handle PHIs and
some of the other cases it doesn't handle the function won't
need to change.

Comments

Jeff Law Jan. 4, 2018, 6:20 p.m. UTC | #1
On 01/03/2018 02:29 PM, Martin Sebor wrote:
> Prathamesh's fix restores the optimization for the test case
> reported in the bug (thanks!) but it isn't sufficient to bring
> GCC 8 completely up to par with 7.  Prior GCC versions are able
> to compute the string length in the test case below but GCC 8
> cannot.
> 
>   char d[8];
>   const char s[] = "1234567";
> 
>   void f (void)
>   {
>     __builtin_strcpy (d, s);
>     if (__builtin_strlen (d) != sizeof s - 1)
>       __builtin_abort ();
>   }
> 
> The attached patch slightly tweaks Prathamesh's patch to also
> handle the case above.  There still are outstanding cases where
> folding into MEM_REF defeats the strlen pass (I've raised
> a couple of new bugs to track those I noticed today) but, AFAICT,
> those aren't recent regressions so they can be dealt with later
> and separately.
> 
> Martin
> 
> PS I've renamed the function because I had initially thought it
> also needed to handle PHIs that refer to strings of the same
> length (and there isn't necessarily one "right" string to return)
> but then realized that the lack of that handling isn't part of
> the regression so I didn't include it but kept the new return
> type and name.  When the pass is enhanced to handle PHIs and
> some of the other cases it doesn't handle the function won't
> need to change.
> 
> gcc-83501.diff
> 
> 
> PR tree-optimization/83501 - strlen(a) not folded after strcpy(a, ...)
> 
> gcc/ChangeLog:
> 
> 	PR tree-optimization/83501
> 	* tree-ssa-strlen.c (get_string_cst): Rename...
> 	(get_strlen): ...to this.  Handle global constants.
> 	(handle_char_store): Adjust.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR tree-optimization/83501
> 	* gcc.dg/strlenopt-39.c: New test.
OK.
jeff
diff mbox series

Patch

PR tree-optimization/83501 - strlen(a) not folded after strcpy(a, ...)

gcc/ChangeLog:

	PR tree-optimization/83501
	* tree-ssa-strlen.c (get_string_cst): Rename...
	(get_strlen): ...to this.  Handle global constants.
	(handle_char_store): Adjust.

gcc/testsuite/ChangeLog:

	PR tree-optimization/83501
	* gcc.dg/strlenopt-39.c: New test.

Index: gcc/testsuite/gcc.dg/strlenopt-39.c
===================================================================
--- gcc/testsuite/gcc.dg/strlenopt-39.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/strlenopt-39.c	(working copy)
@@ -0,0 +1,66 @@ 
+/* PR tree-optimization/83444
+   { dg-do compile }
+   { dg-options "-O2 -fdump-tree-optimized" } */
+
+#include "strlenopt.h"
+
+#define STR "1234567"
+
+const char str[] = STR;
+
+char dst[10];
+
+void copy_from_global_str (void)
+{
+  strcpy (dst, str);
+
+  if (strlen (dst) != sizeof str - 1)
+    abort ();
+}
+
+void copy_from_local_str (void)
+{
+  const char s[] = STR;
+
+  strcpy (dst, s);
+
+  if (strlen (dst) != sizeof s - 1)
+    abort ();
+}
+
+void copy_from_local_memstr (void)
+{
+  struct {
+    char s[sizeof STR];
+  } x = { STR };
+
+  strcpy (dst, x.s);
+
+  if (strlen (dst) != sizeof x.s - 1)
+    abort ();
+}
+
+void copy_to_local_str (void)
+{
+  char d[sizeof STR];
+
+  strcpy (d, str);
+
+  if (strlen (d) != sizeof str - 1)
+    abort ();
+}
+
+void copy_to_local_memstr (void)
+{
+  struct {
+    char d[sizeof STR];
+  } x;
+
+  strcpy (x.d, str);
+
+  if (strlen (x.d) != sizeof str- 1)
+    abort ();
+}
+
+/* Verify that all calls to strlen have been eliminated.
+  { dg-final { scan-tree-dump-not "(abort|strlen) \\(\\)" "optimized" } } */
Index: gcc/tree-ssa-strlen.c
===================================================================
--- gcc/tree-ssa-strlen.c	(revision 256180)
+++ gcc/tree-ssa-strlen.c	(working copy)
@@ -2772,9 +2772,11 @@  handle_pointer_plus (gimple_stmt_iterator *gsi)
     }
 }
 
-/* Check if RHS is string_cst possibly wrapped by mem_ref.  */
-static tree
-get_string_cst (tree rhs)
+/* If RHS, either directly or indirectly, refers to a string of constant
+   length, return it.  Otherwise return a negative value.  */
+
+static int
+get_strlen (tree rhs)
 {
   if (TREE_CODE (rhs) == MEM_REF
       && integer_zerop (TREE_OPERAND (rhs, 1)))
@@ -2784,7 +2786,17 @@  handle_pointer_plus (gimple_stmt_iterator *gsi)
 	rhs = TREE_OPERAND (rhs, 0);
     }
 
-  return (TREE_CODE (rhs) == STRING_CST) ? rhs : NULL_TREE;
+  if (TREE_CODE (rhs) == VAR_DECL
+      && TREE_READONLY (rhs))
+    rhs = DECL_INITIAL (rhs);
+
+  if (rhs && TREE_CODE (rhs) == STRING_CST)
+    {
+      unsigned HOST_WIDE_INT ilen = strlen (TREE_STRING_POINTER (rhs));
+      return ilen <= INT_MAX ? ilen : -1;
+    }
+
+  return -1;
 }
 
 /* Handle a single character store.  */
@@ -2799,6 +2811,9 @@  handle_char_store (gimple_stmt_iterator *gsi)
   tree rhs = gimple_assign_rhs1 (stmt);
   unsigned HOST_WIDE_INT offset = 0;
 
+  /* Set to the length of the string being assigned if known.  */
+  int rhslen;
+
   if (TREE_CODE (lhs) == MEM_REF
       && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
     {
@@ -2942,19 +2957,18 @@  handle_char_store (gimple_stmt_iterator *gsi)
 	}
     }
   else if (idx == 0
-	   && (rhs = get_string_cst (gimple_assign_rhs1 (stmt)))
+	   && (rhslen = get_strlen (gimple_assign_rhs1 (stmt))) >= 0
 	   && ssaname == NULL_TREE
 	   && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
     {
-      size_t l = strlen (TREE_STRING_POINTER (rhs));
       HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
-      if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
+      if (a > 0 && (unsigned HOST_WIDE_INT) a > (unsigned HOST_WIDE_INT) rhslen)
 	{
 	  int idx = new_addr_stridx (lhs);
 	  if (idx != 0)
 	    {
 	      si = new_strinfo (build_fold_addr_expr (lhs), idx,
-				build_int_cst (size_type_node, l), true);
+				build_int_cst (size_type_node, rhslen), true);
 	      set_strinfo (idx, si);
 	      si->dont_invalidate = true;
 	    }