OSDN Git Service

Backported from mainline
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-strlen.c
index 71cefaa..3a3aeea 100644 (file)
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-propagate.h"
 #include "gimple-pretty-print.h"
 #include "params.h"
+#include "expr.h"
 
 /* A vector indexed by SSA_NAME_VERSION.  0 means unknown, positive value
    is an index into strinfo vector, negative value stands for
@@ -176,7 +177,7 @@ get_addr_stridx (tree exp)
 static int
 get_stridx (tree exp)
 {
-  tree l;
+  tree s, o;
 
   if (TREE_CODE (exp) == SSA_NAME)
     return VEC_index (int, ssa_ver_to_stridx, SSA_NAME_VERSION (exp));
@@ -188,14 +189,17 @@ get_stridx (tree exp)
        return idx;
     }
 
-  l = c_strlen (exp, 0);
-  if (l != NULL_TREE
-      && host_integerp (l, 1))
+  s = string_constant (exp, &o);
+  if (s != NULL_TREE
+      && (o == NULL_TREE || host_integerp (o, 0))
+      && TREE_STRING_LENGTH (s) > 0)
     {
-      unsigned HOST_WIDE_INT len = tree_low_cst (l, 1);
-      if (len == (unsigned int) len
-         && (int) len >= 0)
-       return ~(int) len;
+      HOST_WIDE_INT offset = o ? tree_low_cst (o, 0) : 0;
+      const char *p = TREE_STRING_POINTER (s);
+      int max = TREE_STRING_LENGTH (s) - 1;
+
+      if (p[max] == '\0' && offset >= 0 && offset <= max)
+       return ~(int) strlen (p + offset);
     }
   return 0;
 }
@@ -397,7 +401,7 @@ get_string_length (strinfo si)
       callee = gimple_call_fndecl (stmt);
       gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
       lhs = gimple_call_lhs (stmt);
-      gcc_assert (implicit_built_in_decls[BUILT_IN_STRCPY] != NULL_TREE);
+      gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
       /* unshare_strinfo is intentionally not called here.  The (delayed)
         transformation of strcpy or strcat into stpcpy is done at the place
         of the former strcpy/strcat call and so can affect all the strinfos
@@ -409,7 +413,7 @@ get_string_length (strinfo si)
        case BUILT_IN_STRCAT:
        case BUILT_IN_STRCAT_CHK:
          gsi = gsi_for_stmt (stmt);
-         fn = implicit_built_in_decls[BUILT_IN_STRLEN];
+         fn = builtin_decl_implicit (BUILT_IN_STRLEN);
          gcc_assert (lhs == NULL_TREE);
          lhs_var = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)), NULL);
          add_referenced_var (lhs_var);
@@ -434,9 +438,9 @@ get_string_length (strinfo si)
        case BUILT_IN_STRCPY:
        case BUILT_IN_STRCPY_CHK:
          if (gimple_call_num_args (stmt) == 2)
-           fn = implicit_built_in_decls[BUILT_IN_STPCPY];
+           fn = builtin_decl_implicit (BUILT_IN_STPCPY);
          else
-           fn = built_in_decls[BUILT_IN_STPCPY_CHK];
+           fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
          gcc_assert (lhs == NULL_TREE);
          if (dump_file && (dump_flags & TDF_DETAILS) != 0)
            {
@@ -588,13 +592,13 @@ zero_length_string (tree ptr, strinfo chainsi)
                  || si->prev != chainsi->idx)
                break;
            }
-         gcc_assert (chainsi->length);
+         gcc_assert (chainsi->length || chainsi->stmt);
          if (chainsi->endptr == NULL_TREE)
            {
              chainsi = unshare_strinfo (chainsi);
              chainsi->endptr = ptr;
            }
-         if (integer_zerop (chainsi->length))
+         if (chainsi->length && integer_zerop (chainsi->length))
            {
              if (chainsi->next)
                {
@@ -626,6 +630,8 @@ zero_length_string (tree ptr, strinfo chainsi)
       if (chainsi->first == 0)
        chainsi->first = chainsi->idx;
       chainsi->next = idx;
+      if (chainsi->endptr == NULL_TREE)
+       chainsi->endptr = ptr;
       si->prev = chainsi->idx;
       si->first = chainsi->first;
       si->writable = chainsi->writable;
@@ -654,11 +660,19 @@ adjust_related_strinfos (location_t loc, strinfo origsi, tree adj)
          tree tem;
 
          si = unshare_strinfo (si);
-         gcc_assert (si->length);
-         tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
-         si->length = fold_build2_loc (loc, PLUS_EXPR,
-                                       TREE_TYPE (si->length), si->length,
-                                       tem);
+         if (si->length)
+           {
+             tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
+             si->length = fold_build2_loc (loc, PLUS_EXPR,
+                                           TREE_TYPE (si->length), si->length,
+                                           tem);
+           }
+         else if (si->stmt != NULL)
+           /* Delayed length computation is unaffected.  */
+           ;
+         else
+           gcc_unreachable ();
+
          si->endptr = NULL_TREE;
          si->dont_invalidate = true;
        }
@@ -692,6 +706,14 @@ find_equal_ptrs (tree ptr, int idx)
        {
        case SSA_NAME:
          break;
+       CASE_CONVERT:
+         if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
+           return;
+         if (TREE_CODE (ptr) == SSA_NAME)
+           break;
+         if (TREE_CODE (ptr) != ADDR_EXPR)
+           return;
+         /* FALLTHRU */
        case ADDR_EXPR:
          {
            int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
@@ -699,10 +721,6 @@ find_equal_ptrs (tree ptr, int idx)
              *pidx = idx;
            return;
          }
-       CASE_CONVERT:
-         if (POINTER_TYPE_P (TREE_TYPE (ptr)))
-           break;
-         return;
        default:
          return;
        }
@@ -794,10 +812,10 @@ adjust_last_stmt (strinfo si, gimple stmt, bool is_strcat)
 
   if (!is_gimple_call (last.stmt))
     return;
-  callee = gimple_call_fndecl (last.stmt);
-  if (callee == NULL_TREE || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL)
+  if (!gimple_call_builtin_class_p (last.stmt, BUILT_IN_NORMAL))
     return;
 
+  callee = gimple_call_fndecl (last.stmt);
   switch (DECL_FUNCTION_CODE (callee))
     {
     case BUILT_IN_MEMCPY:
@@ -1066,8 +1084,7 @@ handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
       {
       case BUILT_IN_STRCPY:
       case BUILT_IN_STRCPY_CHK:
-       if (implicit_built_in_decls[BUILT_IN_STPCPY] == NULL_TREE
-           || lhs != NULL_TREE)
+       if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
          return;
        break;
       case BUILT_IN_STPCPY:
@@ -1114,10 +1131,30 @@ handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
 
   if (dsi->length == NULL_TREE)
     {
+      strinfo chainsi;
+
       /* If string length of src is unknown, use delayed length
         computation.  If string lenth of dst will be needed, it
         can be computed by transforming this strcpy call into
         stpcpy and subtracting dst from the return value.  */
+
+      /* Look for earlier strings whose length could be determined if
+        this strcpy is turned into an stpcpy.  */
+
+      if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
+       {
+         for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
+           {
+             /* When setting a stmt for delayed length computation
+                prevent all strinfos through dsi from being
+                invalidated.  */
+             chainsi = unshare_strinfo (chainsi);
+             chainsi->stmt = stmt;
+             chainsi->length = NULL_TREE;
+             chainsi->endptr = NULL_TREE;
+             chainsi->dont_invalidate = true;
+           }
+       }
       dsi->stmt = stmt;
       return;
     }
@@ -1150,12 +1187,12 @@ handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
   switch (bcode)
     {
     case BUILT_IN_STRCPY:
-      fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+      fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
       if (lhs)
        VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs), didx);
       break;
     case BUILT_IN_STRCPY_CHK:
-      fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
+      fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
       if (lhs)
        VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs), didx);
       break;
@@ -1163,7 +1200,7 @@ handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
       /* This would need adjustment of the lhs (subtract one),
         or detection that the trailing '\0' doesn't need to be
         written, if it will be immediately overwritten.
-      fn = built_in_decls[BUILT_IN_MEMPCPY];  */
+      fn = builtin_decl_explicit (BUILT_IN_MEMPCPY);  */
       if (lhs)
        {
          dsi->endptr = lhs;
@@ -1174,7 +1211,7 @@ handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
       /* This would need adjustment of the lhs (subtract one),
         or detection that the trailing '\0' doesn't need to be
         written, if it will be immediately overwritten.
-      fn = built_in_decls[BUILT_IN_MEMPCPY_CHK];  */
+      fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK);  */
       if (lhs)
        {
          dsi->endptr = lhs;
@@ -1297,7 +1334,7 @@ handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
   if (si != NULL)
     newlen = si->length;
   else
-    newlen = build_int_cst (TREE_TYPE (len), ~idx);
+    newlen = build_int_cst (size_type_node, ~idx);
   oldlen = NULL_TREE;
   if (olddsi != NULL)
     {
@@ -1396,8 +1433,7 @@ handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
         with length endptr - p if we need to compute the length
         later on.  Don't do this transformation if we don't need
         it.  */
-      if (implicit_built_in_decls[BUILT_IN_STPCPY] != NULL_TREE
-         && lhs == NULL_TREE)
+      if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
        {
          if (didx == 0)
            {
@@ -1456,8 +1492,7 @@ handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
   else
     {
       dsi->length = NULL;
-      if (implicit_built_in_decls[BUILT_IN_STPCPY] != NULL_TREE
-         && lhs == NULL_TREE)
+      if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
        dsi->dont_invalidate = true;
     }
 
@@ -1477,15 +1512,15 @@ handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
     {
     case BUILT_IN_STRCAT:
       if (srclen != NULL_TREE)
-       fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+       fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
       else
-       fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+       fn = builtin_decl_implicit (BUILT_IN_STRCPY);
       break;
     case BUILT_IN_STRCAT_CHK:
       if (srclen != NULL_TREE)
-       fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
+       fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
       else
-       fn = built_in_decls[BUILT_IN_STRCPY_CHK];
+       fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
       objsz = gimple_call_arg (stmt, 2);
       break;
     default:
@@ -1718,7 +1753,7 @@ strlen_optimize_stmt (gimple_stmt_iterator *gsi)
   if (is_gimple_call (stmt))
     {
       tree callee = gimple_call_fndecl (stmt);
-      if (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
+      if (gimple_call_builtin_class_p (stmt, BUILT_IN_NORMAL))
        switch (DECL_FUNCTION_CODE (callee))
          {
          case BUILT_IN_STRLEN:
@@ -1861,6 +1896,29 @@ strlen_enter_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
                  int count_vdef = 100;
                  do_invalidate (dombb, phi, visited, &count_vdef);
                  BITMAP_FREE (visited);
+                 if (count_vdef == 0)
+                   {
+                     /* If there were too many vdefs in between immediate
+                        dominator and current bb, invalidate everything.
+                        If stridx_to_strinfo has been unshared, we need
+                        to free it, otherwise just set it to NULL.  */
+                     if (!strinfo_shared ())
+                       {
+                         unsigned int i;
+                         strinfo si;
+
+                         for (i = 1;
+                              VEC_iterate (strinfo, stridx_to_strinfo, i, si);
+                              ++i)
+                           {
+                             free_strinfo (si);
+                             VEC_replace (strinfo, stridx_to_strinfo,
+                                          i, NULL);
+                           }
+                       }
+                     else
+                       stridx_to_strinfo = NULL;
+                   }
                  break;
                }
            }