re PR tree-optimization/63989 (tree-ssa-strlen.c doesn't handle constant pointer...
authorJakub Jelinek <jakub@redhat.com>
Thu, 8 Jan 2015 21:30:56 +0000 (22:30 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 8 Jan 2015 21:30:56 +0000 (22:30 +0100)
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.

From-SVN: r219362

gcc/ChangeLog
gcc/params.def
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/strlenopt-27.c [new file with mode: 0644]
gcc/tree-ssa-strlen.c

index 53eb2f29a19fb2dbc8cee1f29c826cf2da2d0410..33ba9dae10a771a70ece9856b786a4a35955fb03 100644 (file)
@@ -1,5 +1,15 @@
 2015-01-08  Jakub Jelinek  <jakub@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.
+
        PR target/55023
        PR middle-end/64388
        * dse.c (struct insn_info): Mention frame_read set also
index 4e68273d0749764861d6bdd326285666d36ecd43..cbdc4774047cda482d447a0a9e58af5e010cfbf7 100644 (file)
@@ -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,
index 6ec4ba2ba32a05f9264c3df66acdce384370f5c8..c3ab41832ad3a8fbbf7b70c6cfec3fa63df659b7 100644 (file)
@@ -1,3 +1,8 @@
+2015-01-08  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/63989
+       * gcc.dg/strlenopt-27.c: New test.
+
 2015-01-08  David Malcolm  <dmalcolm@redhat.com>
 
        * jit.dg/harness.h (set_up_logging): New function.
diff --git a/gcc/testsuite/gcc.dg/strlenopt-27.c b/gcc/testsuite/gcc.dg/strlenopt-27.c
new file mode 100644 (file)
index 0000000..8d06aac
--- /dev/null
@@ -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" } } */
index acf4f5886904034aef50f3aae4ae52e47f88dbcb..c9e8f1e5292aab0436b1d4d501dec00a7bdca81a 100644 (file)
@@ -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 chainsi)
 {
   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;