diff options
Diffstat (limited to 'gcc/gimple-ssa-sprintf.c')
-rw-r--r-- | gcc/gimple-ssa-sprintf.c | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c index ead8b0e..dc2b66d 100644 --- a/gcc/gimple-ssa-sprintf.c +++ b/gcc/gimple-ssa-sprintf.c @@ -62,6 +62,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-object-size.h" #include "params.h" #include "tree-cfg.h" +#include "tree-ssa-propagate.h" #include "calls.h" #include "cfgloop.h" #include "intl.h" @@ -122,7 +123,7 @@ public: fold_return_value = param; } - void handle_gimple_call (gimple_stmt_iterator); + void handle_gimple_call (gimple_stmt_iterator*); struct call_info; void compute_format_length (const call_info &, format_result *); @@ -712,6 +713,11 @@ struct pass_sprintf_length::call_info /* True for functions like snprintf that specify the size of the destination, false for others like sprintf that don't. */ bool bounded; + + /* True for bounded functions like snprintf that specify a zero-size + buffer as a request to compute the size of output without actually + writing any. */ + bool nowrite; }; /* Return the result of formatting the '%%' directive. */ @@ -2481,7 +2487,7 @@ get_destination_size (tree dest) have its range set to the range of return values, if that is known. */ static void -try_substitute_return_value (gimple_stmt_iterator gsi, +try_substitute_return_value (gimple_stmt_iterator *gsi, const pass_sprintf_length::call_info &info, const format_result &res) { @@ -2497,14 +2503,29 @@ try_substitute_return_value (gimple_stmt_iterator gsi, && (info.bounded || res.number_chars <= info.objsize) && res.number_chars - 1 <= target_int_max ()) { - /* Replace the left-hand side of the call with the constant - result of the formatted function minus 1 for the terminating - NUL which the functions' return value does not include. */ - gimple_call_set_lhs (info.callstmt, NULL_TREE); tree cst = build_int_cst (integer_type_node, res.number_chars - 1); - gimple *g = gimple_build_assign (lhs, cst); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - update_stmt (info.callstmt); + + if (info.nowrite) + { + /* Replace the call to the bounded function with a zero size + (e.g., snprintf(0, 0, "%i", 123) with the constant result + of the function minus 1 for the terminating NUL which + the function's return value does not include. */ + if (!update_call_from_tree (gsi, cst)) + gimplify_and_update_call_from_tree (gsi, cst); + gimple *callstmt = gsi_stmt (*gsi); + update_stmt (callstmt); + } + else + { + /* Replace the left-hand side of the call with the constant + result of the formatted function minus 1 for the terminating + NUL which the function's return value does not include. */ + gimple_call_set_lhs (info.callstmt, NULL_TREE); + gimple *g = gimple_build_assign (lhs, cst); + gsi_insert_after (gsi, g, GSI_NEW_STMT); + update_stmt (info.callstmt); + } if (dump_file) { @@ -2514,7 +2535,8 @@ try_substitute_return_value (gimple_stmt_iterator gsi, print_generic_expr (dump_file, cst, dump_flags); fprintf (dump_file, " for "); print_generic_expr (dump_file, info.func, dump_flags); - fprintf (dump_file, " return value (output %s).\n", + fprintf (dump_file, " %s (output %s).\n", + info.nowrite ? "call" : "return value", res.constant ? "constant" : "variable"); } } @@ -2579,11 +2601,11 @@ try_substitute_return_value (gimple_stmt_iterator gsi, functions and if so, handle it. */ void -pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator gsi) +pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi) { call_info info = call_info (); - info.callstmt = gsi_stmt (gsi); + info.callstmt = gsi_stmt (*gsi); if (!gimple_call_builtin_p (info.callstmt, BUILT_IN_NORMAL)) return; @@ -2736,6 +2758,7 @@ pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator gsi) without actually producing any. Pretend the size is unlimited in this case. */ info.objsize = HOST_WIDE_INT_MAX; + info.nowrite = true; } else { @@ -2796,7 +2819,7 @@ pass_sprintf_length::execute (function *fun) gimple *stmt = gsi_stmt (si); if (is_gimple_call (stmt)) - handle_gimple_call (si); + handle_gimple_call (&si); } } |