Hi!

This patch is a small step towards fixing that PR that I had sitting on my
disk for quite a while, but didn't get to further steps so far.
I'll try to at least get to the multibyte memcpy/memmove expanded as
load followed by store, if the '\0' is known not to appear at all, or
known to appear on the last byte, or on the first byte during stage4,
but this part is self-contained enough that it should go in independently.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2015-01-08  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/63989
        * params.def (PARAM_MAX_TRACKED_STRLENS): Increment default
        from 1000 to 10000.
        * tree-ssa-strlen.c (get_strinfo): Moved earlier.
        (get_stridx): If we don't have a record for certain SSA_NAME,
        but it is POINTER_PLUS_EXPR of some SSA_NAME we do with
        constant offset, call get_stridx_plus_constant.
        (get_stridx_plus_constant): New function.
        (zero_length_string): Don't use get_stridx here.

        * gcc.dg/strlenopt-27.c: New test.

--- gcc/params.def.jj   2015-01-06 16:14:11.439103073 +0100
+++ gcc/params.def      2015-01-08 18:23:36.305200712 +0100
@@ -1078,7 +1078,7 @@ DEFPARAM (PARAM_MAX_TRACKED_STRLENS,
          "max-tracked-strlens",
          "Maximum number of strings for which strlen optimization pass will "
          "track string lengths",
-         1000, 0, 0)
+         10000, 0, 0)
 
 /* Keep this in sync with the sched_pressure_algorithm enum.  */
 DEFPARAM (PARAM_SCHED_PRESSURE_ALGORITHM,
--- gcc/tree-ssa-strlen.c.jj    2015-01-06 16:14:11.379104086 +0100
+++ gcc/tree-ssa-strlen.c       2015-01-08 18:41:42.351763774 +0100
@@ -181,6 +181,18 @@ struct laststmt_struct
   int stridx;
 } laststmt;
 
+static int get_stridx_plus_constant (strinfo, HOST_WIDE_INT, tree);
+
+/* Return strinfo vector entry IDX.  */
+
+static inline strinfo
+get_strinfo (int idx)
+{
+  if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
+    return NULL;
+  return (*stridx_to_strinfo)[idx];
+}
+
 /* Helper function for get_stridx.  */
 
 static int
@@ -219,7 +231,43 @@ get_stridx (tree exp)
   tree s, o;
 
   if (TREE_CODE (exp) == SSA_NAME)
-    return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
+    {
+      if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
+       return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
+      int i;
+      tree e = exp;
+      HOST_WIDE_INT off = 0;
+      for (i = 0; i < 5; i++)
+       {
+         gimple def_stmt = SSA_NAME_DEF_STMT (e);
+         if (!is_gimple_assign (def_stmt)
+             || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
+           return 0;
+         tree rhs1 = gimple_assign_rhs1 (def_stmt);
+         tree rhs2 = gimple_assign_rhs2 (def_stmt);
+         if (TREE_CODE (rhs1) != SSA_NAME
+             || !tree_fits_shwi_p (rhs2))
+           return 0;
+         HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
+         if (this_off < 0)
+           return 0;
+         off = (unsigned HOST_WIDE_INT) off + this_off;
+         if (off < 0)
+           return 0;
+         if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
+           {
+             strinfo si
+               = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
+             if (si
+                 && si->length
+                 && TREE_CODE (si->length) == INTEGER_CST
+                 && compare_tree_int (si->length, off) != -1)
+               return get_stridx_plus_constant (si, off, exp);
+           }
+         e = rhs1;
+       }
+      return 0;
+    }
 
   if (TREE_CODE (exp) == ADDR_EXPR)
     {
@@ -388,16 +436,6 @@ free_strinfo (strinfo si)
     pool_free (strinfo_pool, si);
 }
 
-/* Return strinfo vector entry IDX.  */
-
-static inline strinfo
-get_strinfo (int idx)
-{
-  if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
-    return NULL;
-  return (*stridx_to_strinfo)[idx];
-}
-
 /* Set strinfo in the vector entry IDX to SI.  */
 
 static inline void
@@ -555,7 +593,7 @@ maybe_invalidate (gimple stmt)
   return nonempty;
 }
 
-/* Unshare strinfo record SI, if it has recount > 1 or
+/* Unshare strinfo record SI, if it has refcount > 1 or
    if stridx_to_strinfo vector is shared with some other
    bbs.  */
 
@@ -605,6 +643,82 @@ verify_related_strinfos (strinfo origsi)
   return si;
 }
 
+/* Attempt to create a new strinfo for BASESI + OFF, or find existing
+   strinfo if there is any.  Return it's idx, or 0 if no strinfo has
+   been created.  */
+
+static int
+get_stridx_plus_constant (strinfo basesi, HOST_WIDE_INT off, tree ptr)
+{
+  gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME);
+
+  if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
+    return 0;
+
+  if (basesi->length == NULL_TREE
+      || TREE_CODE (basesi->length) != INTEGER_CST
+      || compare_tree_int (basesi->length, off) == -1
+      || !tree_fits_shwi_p (basesi->length))
+    return 0;
+
+  HOST_WIDE_INT len = tree_to_shwi (basesi->length) - off;
+  strinfo si = basesi, chainsi;
+  if (si->first || si->prev || si->next)
+    si = verify_related_strinfos (basesi);
+  if (si == NULL
+      || si->length == NULL_TREE
+      || TREE_CODE (si->length) != INTEGER_CST)
+    return 0;
+
+  if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
+    ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
+
+  gcc_checking_assert (compare_tree_int (si->length, off) != -1);
+  for (chainsi = si; chainsi->next; chainsi = si)
+    {
+      si = get_strinfo (chainsi->next);
+      if (si == NULL
+         || si->first != chainsi->first
+         || si->prev != chainsi->idx
+         || si->length == NULL_TREE
+         || TREE_CODE (si->length) != INTEGER_CST)
+       break;
+      int r = compare_tree_int (si->length, len);
+      if (r != 1)
+       {
+         if (r == 0)
+           {
+             ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
+             return si->idx;
+           }
+         break;
+       }
+    }
+
+  int idx = new_stridx (ptr);
+  if (idx == 0)
+    return 0;
+  si = new_strinfo (ptr, idx, build_int_cst (size_type_node, len));
+  set_strinfo (idx, si);
+  if (chainsi->next)
+    {
+      strinfo nextsi = unshare_strinfo (get_strinfo (chainsi->next));
+      si->next = nextsi->idx;
+      nextsi->prev = idx;
+    }
+  chainsi = unshare_strinfo (chainsi);
+  if (chainsi->first == 0)
+    chainsi->first = chainsi->idx;
+  chainsi->next = idx;
+  if (chainsi->endptr == NULL_TREE && len == 0)
+    chainsi->endptr = ptr;
+  si->endptr = chainsi->endptr;
+  si->prev = chainsi->idx;
+  si->first = chainsi->first;
+  si->writable = chainsi->writable;
+  return si->idx;
+}
+
 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
    to a zero-length string and if possible chain it to a related strinfo
    chain whose part is or might be CHAINSI.  */
@@ -614,8 +728,10 @@ zero_length_string (tree ptr, strinfo ch
 {
   strinfo si;
   int idx;
+  if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
+    ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
   gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
-                      && get_stridx (ptr) == 0);
+                      && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
 
   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
     return NULL;
--- gcc/testsuite/gcc.dg/strlenopt-27.c.jj      2015-01-08 18:23:59.790803547 
+0100
+++ gcc/testsuite/gcc.dg/strlenopt-27.c 2015-01-08 18:27:57.690780425 +0100
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+#include "strlenopt.h"
+
+__attribute__((noinline, noclone)) size_t
+fn1 (char *p)
+{
+  strcpy (p, "foobar");
+  return strlen (p + 2); // This strlen should be optimized into 4.
+}
+
+int
+main (void)
+{
+  char p[] = "barfoo";
+  if (fn1 (p) != 4)
+    abort ();
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */

        Jakub

Reply via email to