Hi!

As mentioned in PR78901, the current -fprintf-return-value optimization
will remove (replace with constant) calls like:
int
foo (void)
{
  return snprintf (0, 0, "%s%d", "abcde", 5);
}
but not
void
bar (void)
{
  snprintf (0, 0, "%s%d", "abcde", 5);
}
which doesn't have any side-effect either (and there we even don't care that
much about whether the return value is constant or not, just that there
are no other side-effects like %n directive).

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

2017-01-02  Jakub Jelinek  <ja...@redhat.com>

        * gimple-ssa-sprintf.c (try_substitute_return_value): Remove
        info.nowrite calls with no lhs that can't throw.  Return bool
        whether gsi_remove has been called or not.
        (pass_sprintf_length::handle_gimple_call): Return bool whether
        try_substitute_return_value called gsi_remove.  Formatting fix.
        (pass_sprintf_length::execute): Don't use gsi_remove if
        handle_gimple_call returned true.

        * gcc.dg/tree-ssa/builtin-snprintf-1.c: New test.

--- gcc/gimple-ssa-sprintf.c.jj 2017-01-02 13:05:08.400755201 +0100
+++ gcc/gimple-ssa-sprintf.c    2017-01-02 13:20:20.684895563 +0100
@@ -128,7 +128,7 @@ public:
       fold_return_value = param;
     }
 
-  void handle_gimple_call (gimple_stmt_iterator*);
+  bool handle_gimple_call (gimple_stmt_iterator *);
 
   struct call_info;
   bool compute_format_length (call_info &, format_result *);
@@ -2686,7 +2686,7 @@ get_destination_size (tree dest)
    is known and exact.  A result that isn't suitable for substitution may
    have its range set to the range of return values, if that is known.  */
 
-static void
+static bool
 try_substitute_return_value (gimple_stmt_iterator *gsi,
                             const pass_sprintf_length::call_info &info,
                             const format_result &res)
@@ -2746,6 +2746,23 @@ try_substitute_return_value (gimple_stmt
                   res.constant ? "constant" : "variable");
        }
     }
+  else if (lhs == NULL_TREE
+          && info.nowrite
+          && !stmt_ends_bb_p (info.callstmt))
+    {
+      /* Remove the call to the bounded function with a zero size
+        (e.g., snprintf(0, 0, "%i", 123)) if there is no lhs.  */
+      unlink_stmt_vdef (info.callstmt);
+      gsi_remove (gsi, true);
+      if (dump_file)
+       {
+         location_t callloc = gimple_location (info.callstmt);
+         fprintf (dump_file, "On line %i removing ",
+                  LOCATION_LINE (callloc));
+         print_generic_expr (dump_file, info.func, dump_flags);
+         fprintf (dump_file, " call.\n");
+       }
+    }
   else
     {
       unsigned HOST_WIDE_INT maxbytes;
@@ -2801,19 +2818,22 @@ try_substitute_return_value (gimple_stmt
                     inbounds, (unsigned long)res.number_chars, ign);
        }
     }
+
+  return false;
 }
 
 /* Determine if a GIMPLE CALL is to one of the sprintf-like built-in
-   functions and if so, handle it.  */
+   functions and if so, handle it.  Return true if the call is removed
+   and gsi_next should not be performed in the caller.  */
 
-void
+bool
 pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi)
 {
   call_info info = call_info ();
 
   info.callstmt = gsi_stmt (*gsi);
   if (!gimple_call_builtin_p (info.callstmt, BUILT_IN_NORMAL))
-    return;
+    return false;
 
   info.func = gimple_call_fndecl (info.callstmt);
   info.fncode = DECL_FUNCTION_CODE (info.func);
@@ -2904,7 +2924,7 @@ pass_sprintf_length::handle_gimple_call
       break;
 
     default:
-      return;
+      return false;
     }
 
   /* The first argument is a pointer to the destination.  */
@@ -2969,11 +2989,9 @@ pass_sprintf_length::handle_gimple_call
     }
 
   if (idx_objsize != HOST_WIDE_INT_M1U)
-    {
-      if (tree size = gimple_call_arg (info.callstmt, idx_objsize))
-         if (tree_fits_uhwi_p (size))
-           objsize = tree_to_uhwi (size);
-    }
+    if (tree size = gimple_call_arg (info.callstmt, idx_objsize))
+      if (tree_fits_uhwi_p (size))
+       objsize = tree_to_uhwi (size);
 
   if (info.bounded && !dstsize)
     {
@@ -2998,7 +3016,7 @@ pass_sprintf_length::handle_gimple_call
          location_t loc = gimple_location (info.callstmt);
          warning_at (EXPR_LOC_OR_LOC (dstptr, loc),
                      OPT_Wformat_length_, "null destination pointer");
-         return;
+         return false;
        }
 
       /* Set the object size to the smaller of the two arguments
@@ -3027,12 +3045,12 @@ pass_sprintf_length::handle_gimple_call
       location_t loc = gimple_location (info.callstmt);
       warning_at (EXPR_LOC_OR_LOC (info.format, loc),
                  OPT_Wformat_length_, "null format string");
-      return;
+      return false;
     }
 
   info.fmtstr = get_format_string (info.format, &info.fmtloc);
   if (!info.fmtstr)
-    return;
+    return false;
 
   /* The result is the number of bytes output by the formatted function,
      including the terminating NUL.  */
@@ -3048,7 +3066,8 @@ pass_sprintf_length::handle_gimple_call
       && optimize > 0
       && flag_printf_return_value
       && (!flag_rounding_math || !res.floating))
-    try_substitute_return_value (gsi, info, res);
+    return try_substitute_return_value (gsi, info, res);
+  return false;
 }
 
 /* Execute the pass for function FUN.  */
@@ -3059,14 +3078,14 @@ pass_sprintf_length::execute (function *
   basic_block bb;
   FOR_EACH_BB_FN (bb, fun)
     {
-      for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
-          gsi_next (&si))
+      for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si); )
        {
          /* Iterate over statements, looking for function calls.  */
          gimple *stmt = gsi_stmt (si);
 
-         if (is_gimple_call (stmt))
-           handle_gimple_call (&si);
+         if (is_gimple_call (stmt) && handle_gimple_call (&si))
+           continue;
+         gsi_next (&si);
        }
     }
 
--- gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-1.c.jj       2017-01-02 
13:13:09.401499255 +0100
+++ gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-1.c  2017-01-02 
13:14:33.000000000 +0100
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fprintf-return-value -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-not "__builtin_snprintf" "optimized"} } */
+
+int
+foo (void)
+{
+  int a = __builtin_snprintf (0, 0, "%s", "abcdefgh");
+  return a;
+}
+
+void
+bar (void)
+{
+  __builtin_snprintf (0, 0, "%s", "abcdefgh");
+}

        Jakub

Reply via email to