2014-08-14 Richard Biener <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 14 Aug 2014 09:02:18 +0000 (09:02 +0000)
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 14 Aug 2014 09:02:18 +0000 (09:02 +0000)
PR tree-optimization/62090
* builtins.c (fold_builtin_sprintf): Move to gimple-fold.c.
(fold_builtin_2): Do not fold sprintf.
(fold_builtin_3): Likewise.
* gimple-fold.c (gimple_fold_builtin_sprintf): New function
moved from builtins.c.
(gimple_fold_builtin): Fold sprintf.

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

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@213951 138bc75d-0d04-0410-961f-82ee72b054a4

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

index 7ec321c..00f5867 100644 (file)
@@ -1,5 +1,15 @@
 2014-08-14  Richard Biener  <rguenther@suse.de>
 
+       PR tree-optimization/62090
+       * builtins.c (fold_builtin_sprintf): Move to gimple-fold.c.
+       (fold_builtin_2): Do not fold sprintf.
+       (fold_builtin_3): Likewise.
+       * gimple-fold.c (gimple_fold_builtin_sprintf): New function
+       moved from builtins.c.
+       (gimple_fold_builtin): Fold sprintf.
+
+2014-08-14  Richard Biener  <rguenther@suse.de>
+
        PR rtl-optimization/62079
        * recog.c (peephole2_optimize): If peep2_do_cleanup_cfg
        run cleanup_cfg.
index c1bd263..8468568 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_sprintf (location_t, tree, tree, tree, int);
 static tree fold_builtin_snprintf (location_t, tree, tree, tree, tree, int);
 
 static rtx expand_builtin_object_size (tree);
@@ -10234,9 +10233,6 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1, bool ignore)
     case BUILT_IN_VA_START:
       break;
 
-    case BUILT_IN_SPRINTF:
-      return fold_builtin_sprintf (loc, arg0, arg1, NULL_TREE, ignore);
-
     case BUILT_IN_OBJECT_SIZE:
       return fold_builtin_object_size (arg0, arg1);
 
@@ -10313,9 +10309,6 @@ fold_builtin_3 (location_t loc, tree fndecl,
     case BUILT_IN_MEMCMP:
       return fold_builtin_memcmp (loc, arg0, arg1, arg2);;
 
-    case BUILT_IN_SPRINTF:
-      return fold_builtin_sprintf (loc, arg0, arg1, arg2, ignore);
-
     case BUILT_IN_SNPRINTF:
       return fold_builtin_snprintf (loc, arg0, arg1, arg2, NULL_TREE, ignore);
 
@@ -11237,94 +11230,6 @@ fold_builtin_next_arg (tree exp, bool va_start_p)
 }
 
 
-/* Simplify a call to the sprintf builtin with arguments DEST, FMT, and ORIG.
-   ORIG may be null if this is a 2-argument call.  We don't attempt to
-   simplify calls with more than 3 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_sprintf (location_t loc, tree dest, tree fmt,
-                     tree orig, int ignored)
-{
-  tree call, retval;
-  const char *fmt_str = NULL;
-
-  /* Verify the required arguments in the original call.  We deal with two
-     types of sprintf() calls: 'sprintf (str, fmt)' and
-     'sprintf (dest, "%s", orig)'.  */
-  if (!validate_arg (dest, POINTER_TYPE)
-      || !validate_arg (fmt, POINTER_TYPE))
-    return NULL_TREE;
-  if (orig && !validate_arg (orig, POINTER_TYPE))
-    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;
-
-  /* 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 NULL_TREE;
-
-      /* Don't optimize sprintf (buf, "abc", ptr++).  */
-      if (orig)
-       return NULL_TREE;
-
-      /* Convert sprintf (str, fmt) into strcpy (str, fmt) when
-        'format' is known to contain no % formats.  */
-      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;
-      fn = builtin_decl_implicit (BUILT_IN_STRCPY);
-
-      if (!fn)
-       return NULL_TREE;
-
-      /* Don't crash on sprintf (str1, "%s").  */
-      if (!orig)
-       return NULL_TREE;
-
-      /* Convert sprintf (str1, "%s", str2) into strcpy (str1, str2).  */
-      if (!ignored)
-       {
-         retval = c_strlen (orig, 1);
-         if (!retval || TREE_CODE (retval) != INTEGER_CST)
-           return NULL_TREE;
-       }
-      call = build_call_expr_loc (loc, fn, 2, dest, orig);
-    }
-
-  if (call && retval)
-    {
-      retval = fold_convert_loc
-       (loc, TREE_TYPE (TREE_TYPE (builtin_decl_implicit (BUILT_IN_SPRINTF))),
-        retval);
-      return build2 (COMPOUND_EXPR, TREE_TYPE (retval), call, retval);
-    }
-  else
-    return call;
-}
-
 /* 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.
index 20c7cb0..4fa1a35 100644 (file)
@@ -2143,6 +2143,132 @@ gimple_fold_builtin_sprintf_chk (gimple_stmt_iterator *gsi,
   return true;
 }
 
+/* Simplify a call to the sprintf builtin with arguments DEST, FMT, and ORIG.
+   ORIG may be null if this is a 2-argument call.  We don't attempt to
+   simplify calls with more than 3 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_sprintf (gimple_stmt_iterator *gsi)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  tree dest = gimple_call_arg (stmt, 0);
+  tree fmt = gimple_call_arg (stmt, 1);
+  tree orig = NULL_TREE;
+  const char *fmt_str = NULL;
+
+  /* Verify the required arguments in the original call.  We deal with two
+     types of sprintf() calls: 'sprintf (str, fmt)' and
+     'sprintf (dest, "%s", orig)'.  */
+  if (gimple_call_num_args (stmt) > 3)
+    return false;
+
+  if (gimple_call_num_args (stmt) == 3)
+    orig = gimple_call_arg (stmt, 2);
+
+  /* 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 sprintf (buf, "abc", ptr++).  */
+      if (orig)
+       return false;
+
+      /* Convert sprintf (str, fmt) into strcpy (str, fmt) when
+        'format' is known to contain no % formats.  */
+      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,
+                                                    strlen (fmt_str)));
+         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;
+      fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+
+      if (!fn)
+       return false;
+
+      /* Don't crash on sprintf (str1, "%s").  */
+      if (!orig)
+       return false;
+
+      tree len = NULL_TREE;
+      if (gimple_call_lhs (stmt))
+       {
+         len = c_strlen (orig, 1);
+         if (!len)
+           return false;
+       }
+
+      /* Convert sprintf (str1, "%s", str2) into strcpy (str1, str2).  */
+      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 (len)))
+           len = fold_convert (integer_type_node, len);
+         repl = gimple_build_assign (gimple_call_lhs (stmt), 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.  */
 
@@ -2349,6 +2475,8 @@ 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 0dd986b..17e75e1 100644 (file)
@@ -1,5 +1,10 @@
 2014-08-14  Richard Biener  <rguenther@suse.de>
 
+       PR tree-optimization/62090
+       * gcc.dg/pr62090.c: New testcase.
+
+2014-08-14  Richard Biener  <rguenther@suse.de>
+
        PR rtl-optimization/62079
        * g++.dg/pr62079.C: New testcase.
 
diff --git a/gcc/testsuite/gcc.dg/pr62090.c b/gcc/testsuite/gcc.dg/pr62090.c
new file mode 100644 (file)
index 0000000..53089cf
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+long a;
+int *b;
+extern __inline __attribute__ ((__always_inline__))
+__attribute__ ((__gnu_inline__)) int sprintf (int *p1, char *p2, ...)
+{
+  a = __builtin_object_size (0, 0);
+  return __builtin___sprintf_chk (0, 0, a, p2, __builtin_va_arg_pack ());
+}
+
+void
+log_bad_request ()
+{
+  b += sprintf (0, "foo");
+}