re PR middle-end/62090 (ice in compute_may_aliases)
authorRichard Biener <rguenther@suse.de>
Mon, 18 Aug 2014 14:51:04 +0000 (14:51 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Mon, 18 Aug 2014 14:51:04 +0000 (14:51 +0000)
2014-08-18  Richard Biener  <rguenther@suse.de>

PR tree-optimization/62090
* builtins.c (fold_builtin_snprintf): Move to gimple-fold.c.
(fold_builtin_3): Do not fold snprintf.
(fold_builtin_4): Likewise.
* gimple-fold.c (gimple_fold_builtin_snprintf): New function
moved from builtins.c.
(gimple_fold_builtin_with_strlen): Fold snprintf and sprintf.
(gimple_fold_builtin): Do not fold sprintf here.

* gcc.dg/pr62090-2.c: New testcase.

From-SVN: r214105

gcc/ChangeLog
gcc/builtins.c
gcc/gimple-fold.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr62090-2.c [new file with mode: 0644]

index f471e2c..75591f4 100644 (file)
@@ -1,5 +1,16 @@
 2014-08-18  Richard Biener  <rguenther@suse.de>
 
+       PR tree-optimization/62090
+       * builtins.c (fold_builtin_snprintf): Move to gimple-fold.c.
+       (fold_builtin_3): Do not fold snprintf.
+       (fold_builtin_4): Likewise.
+       * gimple-fold.c (gimple_fold_builtin_snprintf): New function
+       moved from builtins.c.
+       (gimple_fold_builtin_with_strlen): Fold snprintf and sprintf.
+       (gimple_fold_builtin): Do not fold sprintf here.
+
+2014-08-18  Richard Biener  <rguenther@suse.de>
+
        * gimple-fold.c (maybe_fold_reference): Move re-gimplification
        code to ...
        (maybe_canonicalize_mem_ref_addr): ... this function.
index 8468568..29ddde8 100644 (file)
@@ -190,7 +190,6 @@ static tree fold_builtin_strrchr (location_t, tree, tree, tree);
 static tree fold_builtin_strncat (location_t, tree, tree, tree);
 static tree fold_builtin_strspn (location_t, tree, tree);
 static tree fold_builtin_strcspn (location_t, tree, tree);
-static tree fold_builtin_snprintf (location_t, tree, tree, tree, tree, int);
 
 static rtx expand_builtin_object_size (tree);
 static rtx expand_builtin_memory_chk (tree, rtx, enum machine_mode,
@@ -10309,9 +10308,6 @@ fold_builtin_3 (location_t loc, tree fndecl,
     case BUILT_IN_MEMCMP:
       return fold_builtin_memcmp (loc, arg0, arg1, arg2);;
 
-    case BUILT_IN_SNPRINTF:
-      return fold_builtin_snprintf (loc, arg0, arg1, arg2, NULL_TREE, ignore);
-
     case BUILT_IN_STRCAT_CHK:
       return fold_builtin_strcat_chk (loc, fndecl, arg0, arg1, arg2);
 
@@ -10364,9 +10360,6 @@ fold_builtin_4 (location_t loc, tree fndecl,
     case BUILT_IN_STRNCAT_CHK:
       return fold_builtin_strncat_chk (loc, fndecl, arg0, arg1, arg2, arg3);
 
-    case BUILT_IN_SNPRINTF:
-      return fold_builtin_snprintf (loc, arg0, arg1, arg2, arg3, ignore);
-
     case BUILT_IN_FPRINTF_CHK:
     case BUILT_IN_VFPRINTF_CHK:
       if (!validate_arg (arg1, INTEGER_TYPE)
@@ -11230,126 +11223,6 @@ fold_builtin_next_arg (tree exp, bool va_start_p)
 }
 
 
-/* Simplify a call to the snprintf builtin with arguments DEST, DESTSIZE,
-   FMT, and ORIG.  ORIG may be null if this is a 3-argument call.  We don't
-   attempt to simplify calls with more than 4 arguments.
-
-   Return NULL_TREE if no simplification was possible, otherwise return the
-   simplified form of the call as a tree.  If IGNORED is true, it means that
-   the caller does not use the returned value of the function.  */
-
-static tree
-fold_builtin_snprintf (location_t loc, tree dest, tree destsize, tree fmt,
-                      tree orig, int ignored)
-{
-  tree call, retval;
-  const char *fmt_str = NULL;
-  unsigned HOST_WIDE_INT destlen;
-
-  /* Verify the required arguments in the original call.  We deal with two
-     types of snprintf() calls: 'snprintf (str, cst, fmt)' and
-     'snprintf (dest, cst, "%s", orig)'.  */
-  if (!validate_arg (dest, POINTER_TYPE)
-      || !validate_arg (destsize, INTEGER_TYPE)
-      || !validate_arg (fmt, POINTER_TYPE))
-    return NULL_TREE;
-  if (orig && !validate_arg (orig, POINTER_TYPE))
-    return NULL_TREE;
-
-  if (!tree_fits_uhwi_p (destsize))
-    return NULL_TREE;
-
-  /* Check whether the format is a literal string constant.  */
-  fmt_str = c_getstr (fmt);
-  if (fmt_str == NULL)
-    return NULL_TREE;
-
-  call = NULL_TREE;
-  retval = NULL_TREE;
-
-  if (!init_target_chars ())
-    return NULL_TREE;
-
-  destlen = tree_to_uhwi (destsize);
-
-  /* If the format doesn't contain % args or %%, use strcpy.  */
-  if (strchr (fmt_str, target_percent) == NULL)
-    {
-      tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
-      size_t len = strlen (fmt_str);
-
-      /* Don't optimize snprintf (buf, 4, "abc", ptr++).  */
-      if (orig)
-       return NULL_TREE;
-
-      /* We could expand this as
-        memcpy (str, fmt, cst - 1); str[cst - 1] = '\0';
-        or to
-        memcpy (str, fmt_with_nul_at_cstm1, cst);
-        but in the former case that might increase code size
-        and in the latter case grow .rodata section too much.
-        So punt for now.  */
-      if (len >= destlen)
-       return NULL_TREE;
-
-      if (!fn)
-       return NULL_TREE;
-
-      /* Convert snprintf (str, cst, fmt) into strcpy (str, fmt) when
-        'format' is known to contain no % formats and
-        strlen (fmt) < cst.  */
-      call = build_call_expr_loc (loc, fn, 2, dest, fmt);
-
-      if (!ignored)
-       retval = build_int_cst (integer_type_node, strlen (fmt_str));
-    }
-
-  /* If the format is "%s", use strcpy if the result isn't used.  */
-  else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
-    {
-      tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
-      unsigned HOST_WIDE_INT origlen;
-
-      /* Don't crash on snprintf (str1, cst, "%s").  */
-      if (!orig)
-       return NULL_TREE;
-
-      retval = c_strlen (orig, 1);
-      if (!retval || !tree_fits_uhwi_p (retval))
-       return NULL_TREE;
-
-      origlen = tree_to_uhwi (retval);
-      /* We could expand this as
-        memcpy (str1, str2, cst - 1); str1[cst - 1] = '\0';
-        or to
-        memcpy (str1, str2_with_nul_at_cstm1, cst);
-        but in the former case that might increase code size
-        and in the latter case grow .rodata section too much.
-        So punt for now.  */
-      if (origlen >= destlen)
-       return NULL_TREE;
-
-      /* Convert snprintf (str1, cst, "%s", str2) into
-        strcpy (str1, str2) if strlen (str2) < cst.  */
-      if (!fn)
-       return NULL_TREE;
-
-      call = build_call_expr_loc (loc, fn, 2, dest, orig);
-
-      if (ignored)
-       retval = NULL_TREE;
-    }
-
-  if (call && retval)
-    {
-      tree fn = builtin_decl_explicit (BUILT_IN_SNPRINTF);
-      retval = fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fn)), retval);
-      return build2 (COMPOUND_EXPR, TREE_TYPE (retval), call, retval);
-    }
-  else
-    return call;
-}
-
 /* Expand a call EXP to __builtin_object_size.  */
 
 static rtx
index d34be0a..f432baf 100644 (file)
@@ -2091,7 +2091,7 @@ gimple_fold_builtin_sprintf_chk (gimple_stmt_iterator *gsi,
    the caller does not use the returned value of the function.  */
 
 static bool
-gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi)
+gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi, tree orig_len)
 {
   gimple stmt = gsi_stmt (*gsi);
   tree dest = gimple_call_arg (stmt, 0);
@@ -2169,11 +2169,11 @@ gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi)
       if (!orig)
        return false;
 
-      tree len = NULL_TREE;
-      if (gimple_call_lhs (stmt))
+      if (gimple_call_lhs (stmt)
+         && !orig_len)
        {
-         len = c_strlen (orig, 1);
-         if (!len)
+         orig_len = c_strlen (orig, 1);
+         if (!orig_len)
            return false;
        }
 
@@ -2183,9 +2183,10 @@ gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi)
       gimple_seq_add_stmt_without_update (&stmts, repl);
       if (gimple_call_lhs (stmt))
        {
-         if (!useless_type_conversion_p (integer_type_node, TREE_TYPE (len)))
-           len = fold_convert (integer_type_node, len);
-         repl = gimple_build_assign (gimple_call_lhs (stmt), len);
+         if (!useless_type_conversion_p (integer_type_node,
+                                         TREE_TYPE (orig_len)))
+           orig_len = fold_convert (integer_type_node, orig_len);
+         repl = gimple_build_assign (gimple_call_lhs (stmt), orig_len);
          gimple_seq_add_stmt_without_update (&stmts, repl);
          gsi_replace_with_seq_vops (gsi, stmts);
          /* gsi now points at the assignment to the lhs, get a
@@ -2206,7 +2207,147 @@ gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi)
   return false;
 }
 
+/* Simplify a call to the snprintf builtin with arguments DEST, DESTSIZE,
+   FMT, and ORIG.  ORIG may be null if this is a 3-argument call.  We don't
+   attempt to simplify calls with more than 4 arguments.
 
+   Return NULL_TREE if no simplification was possible, otherwise return the
+   simplified form of the call as a tree.  If IGNORED is true, it means that
+   the caller does not use the returned value of the function.  */
+
+static bool
+gimple_fold_builtin_snprintf (gimple_stmt_iterator *gsi, tree orig_len)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  tree dest = gimple_call_arg (stmt, 0);
+  tree destsize = gimple_call_arg (stmt, 1);
+  tree fmt = gimple_call_arg (stmt, 2);
+  tree orig = NULL_TREE;
+  const char *fmt_str = NULL;
+
+  if (gimple_call_num_args (stmt) > 4)
+    return false;
+
+  if (gimple_call_num_args (stmt) == 4)
+    orig = gimple_call_arg (stmt, 3);
+
+  if (!tree_fits_uhwi_p (destsize))
+    return false;
+  unsigned HOST_WIDE_INT destlen = tree_to_uhwi (destsize);
+
+  /* Check whether the format is a literal string constant.  */
+  fmt_str = c_getstr (fmt);
+  if (fmt_str == NULL)
+    return false;
+
+  if (!init_target_chars ())
+    return false;
+
+  /* If the format doesn't contain % args or %%, use strcpy.  */
+  if (strchr (fmt_str, target_percent) == NULL)
+    {
+      tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+      if (!fn)
+       return false;
+
+      /* Don't optimize snprintf (buf, 4, "abc", ptr++).  */
+      if (orig)
+       return false;
+
+      /* We could expand this as
+        memcpy (str, fmt, cst - 1); str[cst - 1] = '\0';
+        or to
+        memcpy (str, fmt_with_nul_at_cstm1, cst);
+        but in the former case that might increase code size
+        and in the latter case grow .rodata section too much.
+        So punt for now.  */
+      size_t len = strlen (fmt_str);
+      if (len >= destlen)
+       return false;
+
+      gimple_seq stmts = NULL;
+      gimple repl = gimple_build_call (fn, 2, dest, fmt);
+      gimple_seq_add_stmt_without_update (&stmts, repl);
+      if (gimple_call_lhs (stmt))
+       {
+         repl = gimple_build_assign (gimple_call_lhs (stmt),
+                                     build_int_cst (integer_type_node, len));
+         gimple_seq_add_stmt_without_update (&stmts, repl);
+         gsi_replace_with_seq_vops (gsi, stmts);
+         /* gsi now points at the assignment to the lhs, get a
+            stmt iterator to the memcpy call.
+            ???  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);
+       }
+      else
+       {
+         gsi_replace_with_seq_vops (gsi, stmts);
+         fold_stmt (gsi);
+       }
+      return true;
+    }
+
+  /* If the format is "%s", use strcpy if the result isn't used.  */
+  else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
+    {
+      tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+      if (!fn)
+       return false;
+
+      /* Don't crash on snprintf (str1, cst, "%s").  */
+      if (!orig)
+       return false;
+
+      if (!orig_len)
+       {
+         orig_len = c_strlen (orig, 1);
+         if (!orig_len)
+           return false;
+       }
+
+      /* We could expand this as
+        memcpy (str1, str2, cst - 1); str1[cst - 1] = '\0';
+        or to
+        memcpy (str1, str2_with_nul_at_cstm1, cst);
+        but in the former case that might increase code size
+        and in the latter case grow .rodata section too much.
+        So punt for now.  */
+      if (compare_tree_int (orig_len, destlen) >= 0)
+       return false;
+
+      /* Convert snprintf (str1, cst, "%s", str2) into
+        strcpy (str1, str2) if strlen (str2) < cst.  */
+      gimple_seq stmts = NULL;
+      gimple repl = gimple_build_call (fn, 2, dest, orig);
+      gimple_seq_add_stmt_without_update (&stmts, repl);
+      if (gimple_call_lhs (stmt))
+       {
+         if (!useless_type_conversion_p (integer_type_node,
+                                         TREE_TYPE (orig_len)))
+           orig_len = fold_convert (integer_type_node, orig_len);
+         repl = gimple_build_assign (gimple_call_lhs (stmt), orig_len);
+         gimple_seq_add_stmt_without_update (&stmts, repl);
+         gsi_replace_with_seq_vops (gsi, stmts);
+         /* gsi now points at the assignment to the lhs, get a
+            stmt iterator to the memcpy call.
+            ???  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);
+       }
+      else
+       {
+         gsi_replace_with_seq_vops (gsi, stmts);
+         fold_stmt (gsi);
+       }
+      return true;
+    }
+  return false;
+}
 
 
 /* Fold a call to __builtin_strlen with known length LEN.  */
@@ -2232,7 +2373,7 @@ static bool
 gimple_fold_builtin_with_strlen (gimple_stmt_iterator *gsi)
 {
   gimple stmt = gsi_stmt (*gsi);
-  tree val[3];
+  tree val[4];
   tree a;
   int arg_idx, type;
   bitmap visited;
@@ -2276,23 +2417,32 @@ gimple_fold_builtin_with_strlen (gimple_stmt_iterator *gsi)
       arg_idx = 1;
       type = 2;
       break;
+    case BUILT_IN_SPRINTF:
+      arg_idx = 2;
+      type = 0;
+      break;
+    case BUILT_IN_SNPRINTF:
+      arg_idx = 3;
+      type = 0;
+      break;
     default:
       return false;
     }
 
   int nargs = gimple_call_num_args (stmt);
-  if (arg_idx >= nargs)
-    return false;
 
   /* Try to use the dataflow information gathered by the CCP process.  */
   visited = BITMAP_ALLOC (NULL);
   bitmap_clear (visited);
 
   memset (val, 0, sizeof (val));
-  a = gimple_call_arg (stmt, arg_idx);
-  if (!get_maxval_strlen (a, &val[arg_idx], visited, type)
-      || !is_gimple_val (val[arg_idx]))
-    val[arg_idx] = NULL_TREE;
+  if (arg_idx < nargs)
+    {
+      a = gimple_call_arg (stmt, arg_idx);
+      if (!get_maxval_strlen (a, &val[arg_idx], visited, type)
+         || !is_gimple_val (val[arg_idx]))
+       val[arg_idx] = NULL_TREE;
+    }
 
   BITMAP_FREE (visited);
 
@@ -2364,7 +2514,10 @@ gimple_fold_builtin_with_strlen (gimple_stmt_iterator *gsi)
     case BUILT_IN_VSNPRINTF_CHK:
       return gimple_fold_builtin_snprintf_chk (gsi, val[1],
                                               DECL_FUNCTION_CODE (callee));
-
+    case BUILT_IN_SNPRINTF:
+      return gimple_fold_builtin_snprintf (gsi, val[3]);
+    case BUILT_IN_SPRINTF:
+      return gimple_fold_builtin_sprintf (gsi, val[2]);
     default:
       gcc_unreachable ();
     }
@@ -2414,8 +2567,6 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
     case BUILT_IN_SPRINTF_CHK:
     case BUILT_IN_VSPRINTF_CHK:
       return gimple_fold_builtin_sprintf_chk (gsi, DECL_FUNCTION_CODE (callee));
-    case BUILT_IN_SPRINTF:
-      return gimple_fold_builtin_sprintf (gsi);
     default:;
     }
 
index e43e295..89d164c 100644 (file)
@@ -1,3 +1,8 @@
+2014-08-18  Richard Biener  <rguenther@suse.de>
+
+       PR tree-optimization/62090
+       * gcc.dg/pr62090-2.c: New testcase.
+
 2014-08-18  Ilya Enkovich  <ilya.enkovich@intel.com>
 
        * g++.dg/ipa/pr61800.C: New.
diff --git a/gcc/testsuite/gcc.dg/pr62090-2.c b/gcc/testsuite/gcc.dg/pr62090-2.c
new file mode 100644 (file)
index 0000000..5bddc53
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef long unsigned int size_t;
+extern __inline __attribute__ ((__always_inline__))
+__attribute__ ((__gnu_inline__)) int
+snprintf (char *__restrict __s, size_t __n, const char *__restrict __fmt, ...)
+{
+  return __builtin___snprintf_chk (__s, __n, 2 - 1,
+                                  __builtin_object_size (__s, 2 > 1),
+                                  __fmt, __builtin_va_arg_pack ());
+}
+typedef struct apacket apacket;
+struct apacket {
+    unsigned char data[4096];
+};
+static size_t fill_connect_data(char *buf, size_t bufsize)
+{
+  return snprintf(buf, bufsize, "host::") + 1;
+}
+unsigned send_connect(apacket *cp)
+{
+  return fill_connect_data((char *)cp->data, sizeof(cp->data));
+}