Optimize strchr (s, 0) to s + strlen (s).
authorWilco Dijkstra <wdijkstr@arm.com>
Wed, 28 Sep 2016 11:06:41 +0000 (11:06 +0000)
committerWilco Dijkstra <wilco@gcc.gnu.org>
Wed, 28 Sep 2016 11:06:41 +0000 (11:06 +0000)
Optimize strchr (s, 0) to s + strlen (s).  strchr (s, 0) appears a common
idiom for finding the end of a string, however it is not a very efficient
way of doing so.  Strlen is a much simpler operation which is significantly
faster (eg. on x86 strlen is 50% faster for strings of 8 bytes and about
twice as fast as strchr on strings of 1KB).

    gcc/
* gimple-fold.c (gimple_fold_builtin_strchr):
New function to optimize strchr (s, 0) to strlen.
(gimple_fold_builtin): Add BUILT_IN_STRCHR case.

    testsuite/
* gcc.dg/strlenopt-20.c: Update test.
* 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.dg/strlenopt-5.c: Likewise.
* gcc.dg/strlenopt-7.c: Likewise.
* gcc.dg/strlenopt-9.c: Likewise.

From-SVN: r240568

gcc/ChangeLog
gcc/gimple-fold.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/strlenopt-20.c
gcc/testsuite/gcc.dg/strlenopt-21.c
gcc/testsuite/gcc.dg/strlenopt-22.c
gcc/testsuite/gcc.dg/strlenopt-22g.c
gcc/testsuite/gcc.dg/strlenopt-26.c
gcc/testsuite/gcc.dg/strlenopt-5.c
gcc/testsuite/gcc.dg/strlenopt-7.c
gcc/testsuite/gcc.dg/strlenopt-9.c

index 479364658a6254b4d61c5b1c240111306e46922e..75eeb632adb124f6c6451b56aa70af6dd2784c18 100644 (file)
@@ -1,3 +1,10 @@
+2016-09-28  Wilco Dijkstra  <wdijkstr@arm.com>
+
+       PR tree-optimization/61056
+       * gimple-fold.c (gimple_fold_builtin_strchr):
+       New function to optimize strchr (s, 0) to strlen.
+       (gimple_fold_builtin): Add BUILT_IN_STRCHR case.
+
 2016-09-27  Robin Dapp  <rdapp@linux.vnet.ibm.com>
 
        PR tree-optimization/77724
index 23e4516e02039035c814334c1d8ef2f002bbe724..f5a5e5db2830d4f7ecc05084b488f16c3d67f3fb 100644 (file)
@@ -1457,6 +1457,55 @@ gimple_fold_builtin_strncpy (gimple_stmt_iterator *gsi,
   return true;
 }
 
+/* Simplify strchr (str, 0) into str + strlen (str).
+   In general strlen is significantly faster than strchr
+   due to being a simpler operation.  */
+static bool
+gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi)
+{
+  gimple *stmt = gsi_stmt (*gsi);
+  tree str = gimple_call_arg (stmt, 0);
+  tree c = gimple_call_arg (stmt, 1);
+  location_t loc = gimple_location (stmt);
+
+  if (optimize_function_for_size_p (cfun))
+    return false;
+
+  if (!integer_zerop (c) || !gimple_call_lhs (stmt))
+    return false;
+
+  tree len;
+  tree strlen_fn = builtin_decl_implicit (BUILT_IN_STRLEN);
+
+  if (!strlen_fn)
+    return false;
+
+  /* Create newstr = strlen (str).  */
+  gimple_seq stmts = NULL;
+  gimple *new_stmt = gimple_build_call (strlen_fn, 1, str);
+  gimple_set_location (new_stmt, loc);
+  if (gimple_in_ssa_p (cfun))
+    len = make_ssa_name (size_type_node);
+  else
+    len = create_tmp_reg (size_type_node);
+  gimple_call_set_lhs (new_stmt, len);
+  gimple_seq_add_stmt_without_update (&stmts, new_stmt);
+
+  /* Create (str p+ strlen (str)).  */
+  new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
+                                 POINTER_PLUS_EXPR, str, len);
+  gimple_seq_add_stmt_without_update (&stmts, new_stmt);
+  gsi_replace_with_seq_vops (gsi, stmts);
+  /* gsi now points at the assignment to the lhs, get a
+     stmt iterator to the strlen.
+     ???  We can't use gsi_for_stmt as that doesn't work when the
+     CFG isn't built yet.  */
+  gimple_stmt_iterator gsi2 = *gsi;
+  gsi_prev (&gsi2);
+  fold_stmt (&gsi2);
+  return true;
+}
+
 /* Simplify a call to the strcat builtin.  DST and SRC are the arguments
    to the call.
 
@@ -2898,6 +2947,8 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
                                         gimple_call_arg (stmt, 1));
     case BUILT_IN_STRNCAT:
       return gimple_fold_builtin_strncat (gsi);
+    case BUILT_IN_STRCHR:
+      return gimple_fold_builtin_strchr (gsi);
     case BUILT_IN_FPUTS:
       return gimple_fold_builtin_fputs (gsi, gimple_call_arg (stmt, 0),
                                        gimple_call_arg (stmt, 1), false);
index 3de855ffde0d96f78836975a2d929d468ad77a04..0642e23aec79f7a9722505dfc76279b1cef322cd 100644 (file)
@@ -1,3 +1,14 @@
+2016-09-28  Wilco Dijkstra  <wdijkstr@arm.com>
+
+       * gcc.dg/strlenopt-20.c: Update test.
+       * 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.dg/strlenopt-5.c: Likewise.
+       * gcc.dg/strlenopt-7.c: Likewise.
+       * gcc.dg/strlenopt-9.c: Likewise.
+
 2016-09-27  Jakub Jelinek  <jakub@redhat.com>
 
        * g++.dg/cpp1z/feat-cxx1z.C: Add __cpp_capture_star_this test.
index a83e845c26d88e5acdcabf142f7b319136663488..7b483eaeac1aa47278111a92148a16f00b2aaa2d 100644 (file)
@@ -86,9 +86,9 @@ 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" } } */
index e22fa9fca9ba14354db2cd5f602283b64bd8dcac..05b85a49dde0a7f5d269174fd4269e40be910dbd 100644 (file)
@@ -57,9 +57,9 @@ 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" } } */
index aa55f5ebd6a2d4803ee9a7fd60fc538d86f47124..b4ef772f0e59252f10a5419ede6837b3c8ca8265 100644 (file)
@@ -31,9 +31,9 @@ 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 "strchr \\(" 0 "strlen" } } */
 /* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
index 3e2f8c4633939a0b5ff667fb3671e11cde8fe6ed..9c5d020588f3f338a9acf51d36facfea55810760 100644 (file)
@@ -5,9 +5,9 @@
 #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" } } */
index 4bd54bef540806ca90d2b9bcfc33eb531991c967..da2f465a5b5003fa5dca05f3a6ee00e97b98b5dd 100644 (file)
@@ -21,4 +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 { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
index 1b006a93045599a75bdb10a39e86ffa59b475c83..a24aea44e8b00ff7b35a907aaa941b4c509642c4 100644 (file)
@@ -48,9 +48,9 @@ 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" } } */
index 3ae1e2cb3f0d08c8b05107c4e65b67bdb39cf7ab..aa53d7e75254dfe56c93172afc49f95e5b7901e6 100644 (file)
@@ -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 { scan-tree-dump-times "return 3;" 1 "optimized" } } */
index f78defe6287cee9e9ed4779c70675e91c6541d40..e8ff1023d71268e2067993189d5f62eab37a16e5 100644 (file)
@@ -98,10 +98,10 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 5 "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 { scan-tree-dump-times "return 4;" 1 "optimized" } } */