This patch folds strchr (e, 0) to e + strlen (e), if e has no side-effects.
Bootstrapped, regtested on x86_64-unknown-linux-gnu
Ok for trunk ?

[gcc]
* gcc/builtins.c (fold_builtin_strchr):  returns tree for s1 + strlen (s1)
if TREE_SIDE_EFFECTS (s1) is false and integer_zerop (s2) is true.

[gcc/testsuite]
* gcc.dg/strlenopt-5.c: modified dg-final
scan-tree-dump-times for strchr and strlen
* gcc.dg/strlenopt-7.c: Likewise
* gcc.dg/strlenopt-9.c: Likewise
* gcc.dg/strlenopt-20.c: Likewise
* gcc.dg/strlenopt-21.c: Likewise
* gcc.dg/strlenopt-22.c: Likewise
* gcc.dg/strlenopt-22g.c: Likewise
* gcc.dg/strlenopt-26.c: Likewise
* gcc.c-torture/execute/builtins/strchr.c: added test case

Thanks and Regards,
Prathamesh
Index: gcc/builtins.c
===================================================================
--- gcc/builtins.c	(revision 207700)
+++ gcc/builtins.c	(working copy)
@@ -11587,6 +11587,17 @@ fold_builtin_strchr (location_t loc, tre
 	  tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
 	  return fold_convert_loc (loc, type, tem);
 	}
+      else if (integer_zerop (s2) && !TREE_SIDE_EFFECTS (s1))  // simplify strchr (s1, '\0') to s1 + strlen (s1)
+  {
+    tree fn = builtin_decl_implicit (BUILT_IN_STRLEN);
+
+    if (!fn)
+      return NULL_TREE;
+
+    tree call_expr = build_call_expr_loc (loc, fn, 1, s1);
+    tree ptr_plus_expr = build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (s1), s1, call_expr);
+    return fold_convert_loc (loc, type, ptr_plus_expr);
+  }
       return NULL_TREE;
     }
 }
Index: gcc/testsuite/gcc.dg/strlenopt-20.c
===================================================================
--- gcc/testsuite/gcc.dg/strlenopt-20.c	(revision 207700)
+++ gcc/testsuite/gcc.dg/strlenopt-20.c	(working copy)
@@ -48,7 +48,7 @@ __attribute__((noinline, noclone)) char
 fn3 (char *p)
 {
   char *c;
-  /* The strcpy call can be optimized into memcpy, strchr needs to stay,
+  /* The strcpy call can be optimized into memcpy, strchr (p, '\0') is converted to p + strlen (p), 
      strcat is optimized into memcpy.  */
   strcpy (p, "abc");
   p[3] = 'd';
@@ -86,10 +86,10 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
 /* { dg-final { cleanup-tree-dump "strlen" } } */
Index: gcc/testsuite/gcc.dg/strlenopt-21.c
===================================================================
--- gcc/testsuite/gcc.dg/strlenopt-21.c	(revision 207700)
+++ gcc/testsuite/gcc.dg/strlenopt-21.c	(working copy)
@@ -10,6 +10,7 @@ foo (char *x, int n)
 {
   int i;
   char a[64];
+  /* strlen (x, '\0') is converted to x + strlen (x) */
   char *p = strchr (x, '\0');
   struct S s;
   /* strcpy here is optimized into memcpy, length computed as p - x + 1.  */
@@ -57,10 +58,10 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
 /* { dg-final { cleanup-tree-dump "strlen" } } */
Index: gcc/testsuite/gcc.dg/strlenopt-22.c
===================================================================
--- gcc/testsuite/gcc.dg/strlenopt-22.c	(revision 207700)
+++ gcc/testsuite/gcc.dg/strlenopt-22.c	(working copy)
@@ -9,7 +9,7 @@ bar (char *p, char *q)
   size_t l1, l2, l3;
   char *r = strchr (p, '\0');
   strcpy (r, "abcde");
-  char *s = strchr (r, '\0');
+  char *s = strchr (r, '\0');  /* strchr (r, '\0') is converted to r + strlen (r) */
   strcpy (s, q);
   l1 = strlen (p);
   l2 = strlen (r);
@@ -31,10 +31,10 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } *
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
 /* { dg-final { cleanup-tree-dump "strlen" } } */
Index: gcc/testsuite/gcc.dg/strlenopt-22g.c
===================================================================
--- gcc/testsuite/gcc.dg/strlenopt-22g.c	(revision 207700)
+++ gcc/testsuite/gcc.dg/strlenopt-22g.c	(working copy)
@@ -5,10 +5,10 @@
 #define USE_GNU
 #include "strlenopt-22.c"
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */
 /* { dg-final { cleanup-tree-dump "strlen" } } */
Index: gcc/testsuite/gcc.dg/strlenopt-26.c
===================================================================
--- gcc/testsuite/gcc.dg/strlenopt-26.c	(revision 207700)
+++ gcc/testsuite/gcc.dg/strlenopt-26.c	(working copy)
@@ -7,7 +7,7 @@ __attribute__((noinline, noclone)) size_
 fn1 (char *p, const char *r)
 {
   size_t len1 = strlen (r);
-  char *q = strchr (p, '\0');
+  char *q = strchr (p, '\0'); // strchr (p, '\0') is converted to p + strlen (p)
   *q = '\0';
   return len1 - strlen (r); // This strlen should be optimized into len1.
 }
@@ -21,5 +21,5 @@ main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
 /* { dg-final { cleanup-tree-dump "strlen" } } */
Index: gcc/testsuite/gcc.dg/strlenopt-5.c
===================================================================
--- gcc/testsuite/gcc.dg/strlenopt-5.c	(revision 207700)
+++ gcc/testsuite/gcc.dg/strlenopt-5.c	(working copy)
@@ -6,7 +6,7 @@
 __attribute__((noinline, noclone)) char *
 foo (char *p, const char *q)
 {
-  char *e = strchr (p, '\0');
+  char *e = strchr (p, '\0');   /* strchr (p, '\0') is converted to p + strlen (p) */
   strcat (p, q);
   return e;
 }
@@ -21,7 +21,7 @@ bar (char *p)
 __attribute__((noinline, noclone)) void
 baz (char *p)
 {
-  char *e = strchr (p, '\0');
+  char *e = strchr (p, '\0');   /* strchr (p, '\0') is converted to p + strlen (p) */
   strcat (e, "abcd");
 }
 
@@ -48,10 +48,10 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
 /* { dg-final { cleanup-tree-dump "strlen" } } */
Index: gcc/testsuite/gcc.dg/strlenopt-7.c
===================================================================
--- gcc/testsuite/gcc.dg/strlenopt-7.c	(revision 207700)
+++ gcc/testsuite/gcc.dg/strlenopt-7.c	(working copy)
@@ -21,7 +21,7 @@ foo (void)
 __attribute__((noinline, noclone)) size_t
 bar (char *p)
 {
-  char *r = strchr (p, '\0');
+  char *r = strchr (p, '\0');  /* strchr (p, '\0') is converted to p + strlen (p) */
   /* This store shouldn't be optimized away, because we
      want to crash if p is e.g. a string literal.  */
   *r = '\0';
@@ -40,11 +40,11 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "\\*r_\[0-9\]* = 0;" 1 "strlen" } } */
 /* { dg-final { cleanup-tree-dump "strlen" } } */
Index: gcc/testsuite/gcc.dg/strlenopt-9.c
===================================================================
--- gcc/testsuite/gcc.dg/strlenopt-9.c	(revision 207700)
+++ gcc/testsuite/gcc.dg/strlenopt-9.c	(working copy)
@@ -7,8 +7,7 @@ __attribute__((noinline, noclone)) char
 fn1 (int r)
 {
   char *p = r ? "a" : "bc";
-  /* String length for p varies, therefore strchr below isn't
-     optimized away.  */
+  /* strchr (p, '\0') is converted to p + strlen (p) */ 
   return strchr (p, '\0');
 }
 
@@ -27,7 +26,7 @@ __attribute__((noinline, noclone)) size_
 fn3 (char *p, int n)
 {
   int i;
-  p = strchr (p, '\0');
+  p = strchr (p, '\0');   /* strchr (p, '\0') is converted to p + strlen (p) */
   /* strcat here can be optimized into memcpy.  */
   strcat (p, "abcd");
   for (i = 0; i < n; i++)
@@ -47,7 +46,7 @@ fn4 (char *x, int n)
   int i;
   size_t l;
   char a[64];
-  char *p = strchr (x, '\0');
+  char *p = strchr (x, '\0'); /* strchr (x, '\0') is converted to x + strlen (x) */
   /* strcpy here is optimized into memcpy, length computed as p - x + 1.  */
   strcpy (a, x);
   /* strcat here is optimized into memcpy.  */
@@ -98,11 +97,11 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 7 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
 /* { dg-final { cleanup-tree-dump "strlen" } } */
 /* { dg-final { scan-tree-dump-times "return 4;" 1 "optimized" } } */
Index: gcc/testsuite/gcc.c-torture/execute/builtins/strchr.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/builtins/strchr.c	(revision 207700)
+++ gcc/testsuite/gcc.c-torture/execute/builtins/strchr.c	(working copy)
@@ -9,6 +9,8 @@ extern void abort (void);
 extern char *strchr (const char *, int);
 extern char *index (const char *, int);
 
+int x = 7;
+
 void
 main_test (void)
 {
@@ -22,6 +24,8 @@ main_test (void)
     abort ();
   if (strchr (foo, '\0')  != foo + 11)
     abort ();
+  if (strchr (foo + (x++ & 3), '\0') != foo + 11)
+    abort ();
   /* Test only one instance of index since the code path is the same
      as that of strchr. */
   if (index ("hello", 'z')  != 0)

Reply via email to