From 22fca489eaf98f2691772b51773a1e4eb7bb4ef2 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Mon, 26 Aug 2019 18:29:45 +0000 Subject: [PATCH] PR tree-optimization/83431 - -Wformat-truncation may incorrectly report truncation gcc/ChangeLog: PR c++/83431 * gimple-ssa-sprintf.c (pass_data_sprintf_length): Remove object. (sprintf_dom_walker): Remove class. (get_int_range): Make argument const. (directive::fmtfunc, directive::set_precision): Same. (format_none): Same. (build_intmax_type_nodes): Same. (adjust_range_for_overflow): Same. (format_floating): Same. (format_character): Same. (format_string): Same. (format_plain): Same. (get_int_range): Cast away constness. (format_integer): Same. (get_string_length): Call get_range_strlen_dynamic. Handle null lendata.maxbound. (should_warn_p): Adjust argument scope qualifier. (maybe_warn): Same. (format_directive): Same. (parse_directive): Same. (is_call_safe): Same. (try_substitute_return_value): Same. (sprintf_dom_walker::handle_printf_call): Rename... (handle_printf_call): ...to this. Initialize target to host charmap here instead of in pass_sprintf_length::execute. (struct call_info): Make global. (sprintf_dom_walker::compute_format_length): Make global. (sprintf_dom_walker::handle_gimple_call): Same. * passes.def (pass_sprintf_length): Replace with pass_strlen. * print-rtl.c (print_pattern): Reduce the number of spaces to avoid -Wformat-truncation. * tree-pass.h (make_pass_warn_printf): New function. * tree-ssa-strlen.c (strlen_optimize): New variable. (get_string_length): Add comments. (get_range_strlen_dynamic): New function. (check_and_optimize_call): New function. (handle_integral_assign): New function. (strlen_check_and_optimize_stmt): Factor code out into strlen_check_and_optimize_call and handle_integral_assign. (strlen_dom_walker::evrp): New member. (strlen_dom_walker::before_dom_children): Use evrp member. (strlen_dom_walker::after_dom_children): Use evrp member. (printf_strlen_execute): New function. (pass_strlen::gate): Update to handle printf calls. (dump_strlen_info): New function. (pass_data_warn_printf): New variable. (pass_warn_printf): New class. * tree-ssa-strlen.h (get_range_strlen_dynamic): Declare. (handle_printf_call): Same. * tree-vrp.c (value_range_base::type): Adjust assertion. * vr-values.c (vr_values::update_value_range): Use type of the first argument rather than the second. gcc/testsuite/ChangeLog: PR c++/83431 * gcc.dg/strlenopt-63.c: New test. * gcc.dg/pr79538.c: Adjust text of expected warning. * gcc.dg/pr81292-1.c: Adjust pass name. * gcc.dg/pr81292-2.c: Same. * gcc.dg/pr81703.c: Same. * gcc.dg/strcmpopt_2.c: Same. * gcc.dg/strcmpopt_3.c: Same. * gcc.dg/strcmpopt_4.c: Same. * gcc.dg/strlenopt-1.c: Same. * gcc.dg/strlenopt-10.c: Same. * gcc.dg/strlenopt-11.c: Same. * gcc.dg/strlenopt-13.c: Same. * gcc.dg/strlenopt-14g.c: Same. * gcc.dg/strlenopt-14gf.c: Same. * gcc.dg/strlenopt-15.c: Same. * gcc.dg/strlenopt-16g.c: Same. * gcc.dg/strlenopt-17g.c: Same. * gcc.dg/strlenopt-18g.c: Same. * gcc.dg/strlenopt-19.c: Same. * gcc.dg/strlenopt-1f.c: Same. * gcc.dg/strlenopt-2.c: Same. * gcc.dg/strlenopt-20.c: Same. * gcc.dg/strlenopt-21.c: Same. * gcc.dg/strlenopt-22.c: Same. * gcc.dg/strlenopt-22g.c: Same. * gcc.dg/strlenopt-24.c: Same. * gcc.dg/strlenopt-25.c: Same. * gcc.dg/strlenopt-26.c: Same. * gcc.dg/strlenopt-27.c: Same. * gcc.dg/strlenopt-28.c: Same. * gcc.dg/strlenopt-29.c: Same. * gcc.dg/strlenopt-2f.c: Same. * gcc.dg/strlenopt-3.c: Same. * gcc.dg/strlenopt-30.c: Same. * gcc.dg/strlenopt-31g.c: Same. * gcc.dg/strlenopt-32.c: Same. * gcc.dg/strlenopt-33.c: Same. * gcc.dg/strlenopt-33g.c: Same. * gcc.dg/strlenopt-34.c: Same. * gcc.dg/strlenopt-35.c: Same. * gcc.dg/strlenopt-4.c: Same. * gcc.dg/strlenopt-48.c: Same. * gcc.dg/strlenopt-49.c: Same. * gcc.dg/strlenopt-4g.c: Same. * gcc.dg/strlenopt-4gf.c: Same. * gcc.dg/strlenopt-5.c: Same. * gcc.dg/strlenopt-50.c: Same. * gcc.dg/strlenopt-51.c: Same. * gcc.dg/strlenopt-52.c: Same. * gcc.dg/strlenopt-53.c: Same. * gcc.dg/strlenopt-54.c: Same. * gcc.dg/strlenopt-55.c: Same. * gcc.dg/strlenopt-56.c: Same. * gcc.dg/strlenopt-6.c: Same. * gcc.dg/strlenopt-61.c: Same. * gcc.dg/strlenopt-7.c: Same. * gcc.dg/strlenopt-8.c: Same. * gcc.dg/strlenopt-9.c: Same. * gcc.dg/strlenopt.h (snprintf, snprintf): Declare. * gcc.dg/tree-ssa/builtin-snprintf-6.c: New test. * gcc.dg/tree-ssa/builtin-snprintf-7.c: New test. * gcc.dg/tree-ssa/builtin-snprintf-8.c: New test. * gcc.dg/tree-ssa/builtin-snprintf-9.c: New test. * gcc.dg/tree-ssa/builtin-sprintf-warn-21.c: New test. * gcc.dg/tree-ssa/dump-4.c: New test. * gcc.dg/tree-ssa/pr83501.c: Adjust pass name. From-SVN: r274933 --- gcc/ChangeLog | 55 ++ gcc/gimple-ssa-sprintf.c | 263 ++--- gcc/passes.def | 5 +- gcc/print-rtl.c | 2 +- gcc/testsuite/ChangeLog | 70 ++ gcc/testsuite/gcc.dg/pr79538.c | 2 +- gcc/testsuite/gcc.dg/pr81292-1.c | 2 +- gcc/testsuite/gcc.dg/pr81292-2.c | 2 +- gcc/testsuite/gcc.dg/pr81703.c | 2 +- gcc/testsuite/gcc.dg/strcmpopt_2.c | 2 +- gcc/testsuite/gcc.dg/strcmpopt_3.c | 2 +- gcc/testsuite/gcc.dg/strcmpopt_4.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-1.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-10.c | 18 +- gcc/testsuite/gcc.dg/strlenopt-11.c | 22 +- gcc/testsuite/gcc.dg/strlenopt-13.c | 24 +- gcc/testsuite/gcc.dg/strlenopt-14g.c | 14 +- gcc/testsuite/gcc.dg/strlenopt-14gf.c | 24 +- gcc/testsuite/gcc.dg/strlenopt-15.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-16g.c | 14 +- gcc/testsuite/gcc.dg/strlenopt-17g.c | 14 +- gcc/testsuite/gcc.dg/strlenopt-18g.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-19.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-1f.c | 20 +- gcc/testsuite/gcc.dg/strlenopt-2.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-20.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-21.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-22.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-22g.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-24.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-25.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-26.c | 4 +- gcc/testsuite/gcc.dg/strlenopt-27.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-28.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-29.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-2f.c | 20 +- gcc/testsuite/gcc.dg/strlenopt-3.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-30.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-31g.c | 6 +- gcc/testsuite/gcc.dg/strlenopt-32.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-33.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-33g.c | 4 +- gcc/testsuite/gcc.dg/strlenopt-34.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-35.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-4.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-48.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-49.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-4g.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-4gf.c | 20 +- gcc/testsuite/gcc.dg/strlenopt-5.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-50.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-51.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-52.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-53.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-54.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-55.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-56.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-6.c | 12 +- gcc/testsuite/gcc.dg/strlenopt-61.c | 2 +- gcc/testsuite/gcc.dg/strlenopt-68.c | 382 ++++++++ gcc/testsuite/gcc.dg/strlenopt-7.c | 14 +- gcc/testsuite/gcc.dg/strlenopt-9.c | 12 +- gcc/testsuite/gcc.dg/strlenopt.h | 5 +- .../gcc.dg/tree-ssa/builtin-snprintf-6.c | 139 +++ .../gcc.dg/tree-ssa/builtin-snprintf-7.c | 152 +++ .../gcc.dg/tree-ssa/builtin-snprintf-8.c | 41 + .../gcc.dg/tree-ssa/builtin-snprintf-9.c | 163 ++++ .../gcc.dg/tree-ssa/builtin-snprintf-warn-5.c | 140 +++ .../gcc.dg/tree-ssa/builtin-sprintf-warn-21.c | 94 ++ gcc/testsuite/gcc.dg/tree-ssa/dump-4.c | 11 + gcc/testsuite/gcc.dg/tree-ssa/pr83501.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/strlen-2.c | 2 +- gcc/tree-pass.h | 1 + gcc/tree-ssa-strlen.c | 905 ++++++++++++++---- gcc/tree-ssa-strlen.h | 7 + gcc/tree-vrp.c | 2 +- gcc/vr-values.c | 2 +- 77 files changed, 2264 insertions(+), 631 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/strlenopt-68.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-6.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-7.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-8.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-9.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-5.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-21.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/dump-4.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b2c97674904..852382efcb5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,58 @@ +2019-08-23 Martin Sebor + + PR c++/83431 + * gimple-ssa-sprintf.c (pass_data_sprintf_length): Remove object. + (sprintf_dom_walker): Remove class. + (get_int_range): Make argument const. + (directive::fmtfunc, directive::set_precision): Same. + (format_none): Same. + (build_intmax_type_nodes): Same. + (adjust_range_for_overflow): Same. + (format_floating): Same. + (format_character): Same. + (format_string): Same. + (format_plain): Same. + (get_int_range): Cast away constness. + (format_integer): Same. + (get_string_length): Call get_range_strlen_dynamic. Handle + null lendata.maxbound. + (should_warn_p): Adjust argument scope qualifier. + (maybe_warn): Same. + (format_directive): Same. + (parse_directive): Same. + (is_call_safe): Same. + (try_substitute_return_value): Same. + (sprintf_dom_walker::handle_printf_call): Rename... + (handle_printf_call): ...to this. Initialize target to host charmap + here instead of in pass_sprintf_length::execute. + (struct call_info): Make global. + (sprintf_dom_walker::compute_format_length): Make global. + (sprintf_dom_walker::handle_gimple_call): Same. + * passes.def (pass_sprintf_length): Replace with pass_strlen. + * print-rtl.c (print_pattern): Reduce the number of spaces to + avoid -Wformat-truncation. + * tree-pass.h (make_pass_warn_printf): New function. + * tree-ssa-strlen.c (strlen_optimize): New variable. + (get_string_length): Add comments. + (get_range_strlen_dynamic): New function. + (check_and_optimize_call): New function. + (handle_integral_assign): New function. + (strlen_check_and_optimize_stmt): Factor code out into + strlen_check_and_optimize_call and handle_integral_assign. + (strlen_dom_walker::evrp): New member. + (strlen_dom_walker::before_dom_children): Use evrp member. + (strlen_dom_walker::after_dom_children): Use evrp member. + (printf_strlen_execute): New function. + (pass_strlen::gate): Update to handle printf calls. + (dump_strlen_info): New function. + (pass_data_warn_printf): New variable. + (pass_warn_printf): New class. + * tree-ssa-strlen.h (get_range_strlen_dynamic): Declare. + (handle_printf_call): Same. + * tree-vrp.c (value_range_base::type): Adjust assertion. + * vr-values.c (vr_values::update_value_range): Use type of the first + argument rather than the second. + 2019-08-26 Richard Biener * config/i386/i386-features.c (general_remove_non_convertible_regs): diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c index 88ba1f2cac1..6a39a71900a 100644 --- a/gcc/gimple-ssa-sprintf.c +++ b/gcc/gimple-ssa-sprintf.c @@ -85,7 +85,7 @@ along with GCC; see the file COPYING3. If not see #include "domwalk.h" #include "alloc-pool.h" #include "vr-values.h" -#include "gimple-ssa-evrp-analyze.h" +#include "tree-ssa-strlen.h" /* The likely worst case value of MB_LEN_MAX for the target, large enough for UTF-8. Ideally, this would be obtained by a target hook if it were @@ -100,80 +100,15 @@ along with GCC; see the file COPYING3. If not see namespace { -const pass_data pass_data_sprintf_length = { - GIMPLE_PASS, // pass type - "printf-return-value", // pass name - OPTGROUP_NONE, // optinfo_flags - TV_NONE, // tv_id - PROP_cfg, // properties_required - 0, // properties_provided - 0, // properties_destroyed - 0, // properties_start - 0, // properties_finish -}; - /* Set to the warning level for the current function which is equal either to warn_format_trunc for bounded functions or to warn_format_overflow otherwise. */ static int warn_level; +struct call_info; struct format_result; -class sprintf_dom_walker : public dom_walker -{ - public: - sprintf_dom_walker () - : dom_walker (CDI_DOMINATORS), - evrp_range_analyzer (false) {} - ~sprintf_dom_walker () {} - - edge before_dom_children (basic_block) FINAL OVERRIDE; - void after_dom_children (basic_block) FINAL OVERRIDE; - bool handle_gimple_call (gimple_stmt_iterator *); - - struct call_info; - bool compute_format_length (call_info &, format_result *); - class evrp_range_analyzer evrp_range_analyzer; -}; - -class pass_sprintf_length : public gimple_opt_pass -{ - bool fold_return_value; - -public: - pass_sprintf_length (gcc::context *ctxt) - : gimple_opt_pass (pass_data_sprintf_length, ctxt), - fold_return_value (false) - { } - - opt_pass * clone () { return new pass_sprintf_length (m_ctxt); } - - virtual bool gate (function *); - - virtual unsigned int execute (function *); - - void set_pass_param (unsigned int n, bool param) - { - gcc_assert (n == 0); - fold_return_value = param; - } - -}; - -bool -pass_sprintf_length::gate (function *) -{ - /* Run the pass iff -Warn-format-overflow or -Warn-format-truncation - is specified and either not optimizing and the pass is being invoked - early, or when optimizing and the pass is being invoked during - optimization (i.e., "late"). */ - return ((warn_format_overflow > 0 - || warn_format_trunc > 0 - || flag_printf_return_value) - && (optimize > 0) == fold_return_value); -} - /* The minimum, maximum, likely, and unlikely maximum number of bytes of output either a formatting function or an individual directive can result in. */ @@ -684,7 +619,7 @@ fmtresult::type_max_digits (tree type, int base) static bool get_int_range (tree, HOST_WIDE_INT *, HOST_WIDE_INT *, bool, HOST_WIDE_INT, - class vr_values *vr_values); + const vr_values *); /* Description of a format directive. A directive is either a plain string or a conversion specification that starts with '%'. */ @@ -719,7 +654,7 @@ struct directive /* Format conversion function that given a directive and an argument returns the formatting result. */ - fmtresult (*fmtfunc) (const directive &, tree, vr_values *); + fmtresult (*fmtfunc) (const directive &, tree, const vr_values *); /* Return True when a the format flag CHR has been used. */ bool get_flag (char chr) const @@ -756,9 +691,9 @@ struct directive or 0, whichever is greater. For a non-constant ARG in some range set width to its range adjusting each bound to -1 if it's less. For an indeterminate ARG set width to [0, INT_MAX]. */ - void set_width (tree arg, vr_values *vr_values) + void set_width (tree arg, const vr_values *vr) { - get_int_range (arg, width, width + 1, true, 0, vr_values); + get_int_range (arg, width, width + 1, true, 0, vr); } /* Set both bounds of the precision range to VAL. */ @@ -772,9 +707,9 @@ struct directive or -1 whichever is greater. For a non-constant ARG in some range set precision to its range adjusting each bound to -1 if it's less. For an indeterminate ARG set precision to [-1, INT_MAX]. */ - void set_precision (tree arg, vr_values *vr_values) + void set_precision (tree arg, const vr_values *vr) { - get_int_range (arg, prec, prec + 1, false, -1, vr_values); + get_int_range (arg, prec, prec + 1, false, -1, vr); } /* Return true if both width and precision are known to be @@ -904,7 +839,7 @@ bytes_remaining (unsigned HOST_WIDE_INT navail, const format_result &res) /* Description of a call to a formatted function. */ -struct sprintf_dom_walker::call_info +struct call_info { /* Function call statement. */ gimple *callstmt; @@ -978,7 +913,7 @@ struct sprintf_dom_walker::call_info /* Return the result of formatting a no-op directive (such as '%n'). */ static fmtresult -format_none (const directive &, tree, vr_values *) +format_none (const directive &, tree, const vr_values *) { fmtresult res (0); return res; @@ -987,7 +922,7 @@ format_none (const directive &, tree, vr_values *) /* Return the result of formatting the '%%' directive. */ static fmtresult -format_percent (const directive &, tree, vr_values *) +format_percent (const directive &, tree, const vr_values *) { fmtresult res (1); return res; @@ -1047,7 +982,7 @@ build_intmax_type_nodes (tree *pintmax, tree *puintmax) static bool get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax, bool absolute, HOST_WIDE_INT negbound, - class vr_values *vr_values) + const class vr_values *vr_values) { /* The type of the result. */ const_tree type = integer_type_node; @@ -1086,7 +1021,9 @@ get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax, && TYPE_PRECISION (argtype) <= TYPE_PRECISION (type)) { /* Try to determine the range of values of the integer argument. */ - const value_range *vr = vr_values->get_value_range (arg); + const value_range *vr + = CONST_CAST (class vr_values *, vr_values)->get_value_range (arg); + if (range_int_cst_p (vr)) { HOST_WIDE_INT type_min @@ -1203,7 +1140,7 @@ adjust_range_for_overflow (tree dirtype, tree *argmin, tree *argmax) used when the directive argument or its value isn't known. */ static fmtresult -format_integer (const directive &dir, tree arg, vr_values *vr_values) +format_integer (const directive &dir, tree arg, const vr_values *vr_values) { tree intmax_type_node; tree uintmax_type_node; @@ -1386,7 +1323,9 @@ format_integer (const directive &dir, tree arg, vr_values *vr_values) { /* Try to determine the range of values of the integer argument (range information is not available for pointers). */ - const value_range *vr = vr_values->get_value_range (arg); + const value_range *vr + = CONST_CAST (class vr_values *, vr_values)->get_value_range (arg); + if (range_int_cst_p (vr)) { argmin = vr->min (); @@ -1836,7 +1775,7 @@ format_floating (const directive &dir, const HOST_WIDE_INT prec[2]) ARG. */ static fmtresult -format_floating (const directive &dir, tree arg, vr_values *) +format_floating (const directive &dir, tree arg, const vr_values *) { HOST_WIDE_INT prec[] = { dir.prec[0], dir.prec[1] }; tree type = (dir.modifier == FMT_LEN_L || dir.modifier == FMT_LEN_ll @@ -2030,21 +1969,33 @@ format_floating (const directive &dir, tree arg, vr_values *) Used by the format_string function below. */ static fmtresult -get_string_length (tree str, unsigned eltsize) +get_string_length (tree str, unsigned eltsize, const vr_values *vr) { if (!str) return fmtresult (); - /* Determine the length of the shortest and longest string referenced - by STR. Strings of unknown lengths are bounded by the sizes of - arrays that subexpressions of STR may refer to. Pointers that - aren't known to point any such arrays result in LENDATA.MAXLEN - set to SIZE_MAX. */ + /* Try to determine the dynamic string length first. */ c_strlen_data lendata = { }; - get_range_strlen (str, &lendata, eltsize); + if (eltsize == 1) + get_range_strlen_dynamic (str, &lendata, vr); + else + { + /* Determine the length of the shortest and longest string referenced + by STR. Strings of unknown lengths are bounded by the sizes of + arrays that subexpressions of STR may refer to. Pointers that + aren't known to point any such arrays result in LENDATA.MAXLEN + set to SIZE_MAX. */ + get_range_strlen (str, &lendata, eltsize); + } + + /* LENDATA.MAXBOUND is null when LENDATA.MIN corresponds to the shortest + string referenced by STR. Otherwise, if it's not equal to .MINLEN it + corresponds to the bound of the largest array STR refers to, if known, + or it's SIZE_MAX otherwise. */ - /* Return the default result when nothing is known about the string. */ - if (integer_all_onesp (lendata.maxbound) + /* Return the default result when nothing is known about the string. */ + if (lendata.maxbound + && integer_all_onesp (lendata.maxbound) && integer_all_onesp (lendata.maxlen)) return fmtresult (); @@ -2054,7 +2005,7 @@ get_string_length (tree str, unsigned eltsize) : 0); HOST_WIDE_INT max - = (tree_fits_uhwi_p (lendata.maxbound) + = (lendata.maxbound && tree_fits_uhwi_p (lendata.maxbound) ? tree_to_uhwi (lendata.maxbound) : HOST_WIDE_INT_M1U); @@ -2093,10 +2044,11 @@ get_string_length (tree str, unsigned eltsize) else { /* When the upper bound is unknown (it can be zero or excessive) - set the likely length to the greater of 1 and the length of - the shortest string and reset the lower bound to zero. */ + set the likely length to the greater of 1. If MAXBOUND is + set, also reset the length of the lower bound to zero. */ res.range.likely = res.range.min ? res.range.min : warn_level > 1; - res.range.min = 0; + if (lendata.maxbound) + res.range.min = 0; } res.range.unlikely = unbounded ? HOST_WIDE_INT_MAX : res.range.max; @@ -2110,7 +2062,7 @@ get_string_length (tree str, unsigned eltsize) vsprinf). */ static fmtresult -format_character (const directive &dir, tree arg, vr_values *vr_values) +format_character (const directive &dir, tree arg, const vr_values *vr_values) { fmtresult res; @@ -2186,7 +2138,7 @@ format_character (const directive &dir, tree arg, vr_values *vr_values) vsprinf). */ static fmtresult -format_string (const directive &dir, tree arg, vr_values *) +format_string (const directive &dir, tree arg, const vr_values *vr_values) { fmtresult res; @@ -2204,7 +2156,7 @@ format_string (const directive &dir, tree arg, vr_values *) gcc_checking_assert (count_by == 2 || count_by == 4); } - fmtresult slen = get_string_length (arg, count_by); + fmtresult slen = get_string_length (arg, count_by, vr_values); if (slen.range.min == slen.range.max && slen.range.min < HOST_WIDE_INT_MAX) { @@ -2376,7 +2328,7 @@ format_string (const directive &dir, tree arg, vr_values *) /* Format plain string (part of the format string itself). */ static fmtresult -format_plain (const directive &dir, tree, vr_values *) +format_plain (const directive &dir, tree, const vr_values *) { fmtresult res (dir.len); return res; @@ -2386,7 +2338,7 @@ format_plain (const directive &dir, tree, vr_values *) should be diagnosed given the AVAILable space in the destination. */ static bool -should_warn_p (const sprintf_dom_walker::call_info &info, +should_warn_p (const call_info &info, const result_range &avail, const result_range &result) { if (result.max <= avail.min) @@ -2457,7 +2409,7 @@ should_warn_p (const sprintf_dom_walker::call_info &info, static bool maybe_warn (substring_loc &dirloc, location_t argloc, - const sprintf_dom_walker::call_info &info, + const call_info &info, const result_range &avail_range, const result_range &res, const directive &dir) { @@ -2737,9 +2689,9 @@ maybe_warn (substring_loc &dirloc, location_t argloc, in *RES. Return true if the directive has been handled. */ static bool -format_directive (const sprintf_dom_walker::call_info &info, +format_directive (const call_info &info, format_result *res, const directive &dir, - class vr_values *vr_values) + const class vr_values *vr_values) { /* Offset of the beginning of the directive from the beginning of the format string. */ @@ -3086,10 +3038,10 @@ format_directive (const sprintf_dom_walker::call_info &info, the directive. */ static size_t -parse_directive (sprintf_dom_walker::call_info &info, +parse_directive (call_info &info, directive &dir, format_result *res, const char *str, unsigned *argno, - vr_values *vr_values) + const vr_values *vr_values) { const char *pcnt = strchr (str, target_percent); dir.beg = str; @@ -3526,9 +3478,8 @@ parse_directive (sprintf_dom_walker::call_info &info, on, false otherwise (e.g., when a unknown or unhandled directive was seen that caused the processing to be terminated early). */ -bool -sprintf_dom_walker::compute_format_length (call_info &info, - format_result *res) +static bool +compute_format_length (call_info &info, format_result *res, const vr_values *vr) { if (dump_file) { @@ -3564,12 +3515,10 @@ sprintf_dom_walker::compute_format_length (call_info &info, directive dir = directive (); dir.dirno = dirno; - size_t n = parse_directive (info, dir, res, pf, &argno, - evrp_range_analyzer.get_vr_values ()); + size_t n = parse_directive (info, dir, res, pf, &argno, vr); /* Return failure if the format function fails. */ - if (!format_directive (info, res, dir, - evrp_range_analyzer.get_vr_values ())) + if (!format_directive (info, res, dir, vr)) return false; /* Return success the directive is zero bytes long and it's @@ -3617,7 +3566,7 @@ get_destination_size (tree dest) of its return values. */ static bool -is_call_safe (const sprintf_dom_walker::call_info &info, +is_call_safe (const call_info &info, const format_result &res, bool under4k, unsigned HOST_WIDE_INT retval[2]) { @@ -3676,7 +3625,7 @@ is_call_safe (const sprintf_dom_walker::call_info &info, static bool try_substitute_return_value (gimple_stmt_iterator *gsi, - const sprintf_dom_walker::call_info &info, + const call_info &info, const format_result &res) { tree lhs = gimple_get_lhs (info.callstmt); @@ -3794,7 +3743,7 @@ try_substitute_return_value (gimple_stmt_iterator *gsi, static bool try_simplify_call (gimple_stmt_iterator *gsi, - const sprintf_dom_walker::call_info &info, + const call_info &info, const format_result &res) { unsigned HOST_WIDE_INT dummy[2]; @@ -3847,13 +3796,17 @@ get_user_idx_format (tree fndecl, unsigned *idx_args) return tree_to_uhwi (fmtarg) - 1; } -/* Determine if a GIMPLE CALL is to one of the sprintf-like built-in - functions and if so, handle it. Return true if the call is removed - and gsi_next should not be performed in the caller. */ +} /* Unnamed namespace. */ + +/* Determine if a GIMPLE call at *GSI is to one of the sprintf-like built-in + functions and if so, handle it. Return true if the call is removed and + gsi_next should not be performed in the caller. */ bool -sprintf_dom_walker::handle_gimple_call (gimple_stmt_iterator *gsi) +handle_printf_call (gimple_stmt_iterator *gsi, const vr_values *vr_values) { + init_target_to_host_charmap (); + call_info info = call_info (); info.callstmt = gsi_stmt (*gsi); @@ -4119,7 +4072,9 @@ sprintf_dom_walker::handle_gimple_call (gimple_stmt_iterator *gsi) /* Try to determine the range of values of the argument and use the greater of the two at level 1 and the smaller of them at level 2. */ - const value_range *vr = evrp_range_analyzer.get_value_range (size); + const value_range *vr + = CONST_CAST (class vr_values *, vr_values)->get_value_range (size); + if (range_int_cst_p (vr)) { unsigned HOST_WIDE_INT minsize = TREE_INT_CST_LOW (vr->min ()); @@ -4230,7 +4185,7 @@ sprintf_dom_walker::handle_gimple_call (gimple_stmt_iterator *gsi) never set to true again). */ res.posunder4k = posunder4k && dstptr; - bool success = compute_format_length (info, &res); + bool success = compute_format_length (info, &res, vr_values); if (res.warned) gimple_set_no_warning (info.callstmt, true); @@ -4256,71 +4211,3 @@ sprintf_dom_walker::handle_gimple_call (gimple_stmt_iterator *gsi) return call_removed; } - -edge -sprintf_dom_walker::before_dom_children (basic_block bb) -{ - evrp_range_analyzer.enter (bb); - 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); - - /* First record ranges generated by this statement. */ - evrp_range_analyzer.record_ranges_from_stmt (stmt, false); - - if (is_gimple_call (stmt) && handle_gimple_call (&si)) - /* If handle_gimple_call returns true, the iterator is - already pointing to the next statement. */ - continue; - - gsi_next (&si); - } - return NULL; -} - -void -sprintf_dom_walker::after_dom_children (basic_block bb) -{ - evrp_range_analyzer.leave (bb); -} - -/* Execute the pass for function FUN. */ - -unsigned int -pass_sprintf_length::execute (function *fun) -{ - init_target_to_host_charmap (); - - calculate_dominance_info (CDI_DOMINATORS); - bool use_scev = optimize > 0 && flag_printf_return_value; - if (use_scev) - { - loop_optimizer_init (LOOPS_NORMAL); - scev_initialize (); - } - - sprintf_dom_walker sprintf_dom_walker; - sprintf_dom_walker.walk (ENTRY_BLOCK_PTR_FOR_FN (fun)); - - if (use_scev) - { - scev_finalize (); - loop_optimizer_finalize (); - } - - /* Clean up object size info. */ - fini_object_sizes (); - return 0; -} - -} /* Unnamed namespace. */ - -/* Return a pointer to a pass object newly constructed from the context - CTXT. */ - -gimple_opt_pass * -make_pass_sprintf_length (gcc::context *ctxt) -{ - return new pass_sprintf_length (ctxt); -} diff --git a/gcc/passes.def b/gcc/passes.def index fe5a411504d..e50cf62657c 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -42,7 +42,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_build_cfg); NEXT_PASS (pass_warn_function_return); NEXT_PASS (pass_expand_omp); - NEXT_PASS (pass_sprintf_length, false); + NEXT_PASS (pass_warn_printf); NEXT_PASS (pass_walloca, /*strict_mode_p=*/true); NEXT_PASS (pass_build_cgraph_edges); TERMINATE_PASS_LIST (all_lowering_passes) @@ -307,7 +307,6 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_lower_vector_ssa); NEXT_PASS (pass_lower_switch); NEXT_PASS (pass_cse_reciprocals); - NEXT_PASS (pass_sprintf_length, true); NEXT_PASS (pass_reassoc, false /* insert_powi_p */); NEXT_PASS (pass_strength_reduction); NEXT_PASS (pass_split_paths); @@ -358,7 +357,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_object_sizes); /* Fold remaining builtins. */ NEXT_PASS (pass_fold_builtins); - NEXT_PASS (pass_sprintf_length, true); + NEXT_PASS (pass_strlen); /* Copy propagation also copy-propagates constants, this is necessary to forward object-size and builtin folding results properly. */ NEXT_PASS (pass_copy_prop); diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c index 10948efddd9..b96ab5e0544 100644 --- a/gcc/print-rtl.c +++ b/gcc/print-rtl.c @@ -1815,7 +1815,7 @@ print_pattern (pretty_printer *pp, const_rtx x, int verbose) gcc_assert (strlen (print_rtx_head) < sizeof (indented_print_rtx_head) - 4); snprintf (indented_print_rtx_head, sizeof (indented_print_rtx_head), - "%s ", print_rtx_head); + "%s ", print_rtx_head); print_rtx_head = indented_print_rtx_head; for (int i = 0; i < seq->len (); i++) print_insn_with_notes (pp, seq->insn (i)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fab9d338e30..9bdc2f9b0fb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -77,6 +77,76 @@ * gcc.target/mips/get-fcsr-3.c: New test. +2019-08-23 Martin Sebor + + PR c++/83431 + * gcc.dg/strlenopt-63.c: New test. + * gcc.dg/pr79538.c: Adjust text of expected warning. + * gcc.dg/pr81292-1.c: Adjust pass name. + * gcc.dg/pr81292-2.c: Same. + * gcc.dg/pr81703.c: Same. + * gcc.dg/strcmpopt_2.c: Same. + * gcc.dg/strcmpopt_3.c: Same. + * gcc.dg/strcmpopt_4.c: Same. + * gcc.dg/strlenopt-1.c: Same. + * gcc.dg/strlenopt-10.c: Same. + * gcc.dg/strlenopt-11.c: Same. + * gcc.dg/strlenopt-13.c: Same. + * gcc.dg/strlenopt-14g.c: Same. + * gcc.dg/strlenopt-14gf.c: Same. + * gcc.dg/strlenopt-15.c: Same. + * gcc.dg/strlenopt-16g.c: Same. + * gcc.dg/strlenopt-17g.c: Same. + * gcc.dg/strlenopt-18g.c: Same. + * gcc.dg/strlenopt-19.c: Same. + * gcc.dg/strlenopt-1f.c: Same. + * gcc.dg/strlenopt-2.c: Same. + * gcc.dg/strlenopt-20.c: Same. + * gcc.dg/strlenopt-21.c: Same. + * gcc.dg/strlenopt-22.c: Same. + * gcc.dg/strlenopt-22g.c: Same. + * gcc.dg/strlenopt-24.c: Same. + * gcc.dg/strlenopt-25.c: Same. + * gcc.dg/strlenopt-26.c: Same. + * gcc.dg/strlenopt-27.c: Same. + * gcc.dg/strlenopt-28.c: Same. + * gcc.dg/strlenopt-29.c: Same. + * gcc.dg/strlenopt-2f.c: Same. + * gcc.dg/strlenopt-3.c: Same. + * gcc.dg/strlenopt-30.c: Same. + * gcc.dg/strlenopt-31g.c: Same. + * gcc.dg/strlenopt-32.c: Same. + * gcc.dg/strlenopt-33.c: Same. + * gcc.dg/strlenopt-33g.c: Same. + * gcc.dg/strlenopt-34.c: Same. + * gcc.dg/strlenopt-35.c: Same. + * gcc.dg/strlenopt-4.c: Same. + * gcc.dg/strlenopt-48.c: Same. + * gcc.dg/strlenopt-49.c: Same. + * gcc.dg/strlenopt-4g.c: Same. + * gcc.dg/strlenopt-4gf.c: Same. + * gcc.dg/strlenopt-5.c: Same. + * gcc.dg/strlenopt-50.c: Same. + * gcc.dg/strlenopt-51.c: Same. + * gcc.dg/strlenopt-52.c: Same. + * gcc.dg/strlenopt-53.c: Same. + * gcc.dg/strlenopt-54.c: Same. + * gcc.dg/strlenopt-55.c: Same. + * gcc.dg/strlenopt-56.c: Same. + * gcc.dg/strlenopt-6.c: Same. + * gcc.dg/strlenopt-61.c: Same. + * gcc.dg/strlenopt-7.c: Same. + * gcc.dg/strlenopt-8.c: Same. + * gcc.dg/strlenopt-9.c: Same. + * gcc.dg/strlenopt.h (snprintf, snprintf): Declare. + * gcc.dg/tree-ssa/builtin-snprintf-6.c: New test. + * gcc.dg/tree-ssa/builtin-snprintf-7.c: New test. + * gcc.dg/tree-ssa/builtin-snprintf-8.c: New test. + * gcc.dg/tree-ssa/builtin-snprintf-9.c: New test. + * gcc.dg/tree-ssa/builtin-sprintf-warn-21.c: New test. + * gcc.dg/tree-ssa/dump-4.c: New test. + * gcc.dg/tree-ssa/pr83501.c: Adjust pass name. + 2019-08-23 Martin Sebor * gcc.dg/Warray-bounds-36.c: Make functions static to avoid failures diff --git a/gcc/testsuite/gcc.dg/pr79538.c b/gcc/testsuite/gcc.dg/pr79538.c index 6cdab45128a..4f10d97395e 100644 --- a/gcc/testsuite/gcc.dg/pr79538.c +++ b/gcc/testsuite/gcc.dg/pr79538.c @@ -17,6 +17,6 @@ void f () { char des[3]; char src[] = "abcd"; - __builtin_sprintf (des, "%s", src); /* { dg-warning "directive writing up to 4 bytes into a region of size 3" } */ + __builtin_sprintf (des, "%s", src); /* { dg-warning "directive writing 4 bytes into a region of size 3" } */ return; } diff --git a/gcc/testsuite/gcc.dg/pr81292-1.c b/gcc/testsuite/gcc.dg/pr81292-1.c index 931e4c37c17..2a454df88a1 100644 --- a/gcc/testsuite/gcc.dg/pr81292-1.c +++ b/gcc/testsuite/gcc.dg/pr81292-1.c @@ -32,4 +32,4 @@ main (void) return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/pr81292-2.c b/gcc/testsuite/gcc.dg/pr81292-2.c index c1c507f982e..252884abca7 100644 --- a/gcc/testsuite/gcc.dg/pr81292-2.c +++ b/gcc/testsuite/gcc.dg/pr81292-2.c @@ -32,4 +32,4 @@ main (void) return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 6 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 6 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/pr81703.c b/gcc/testsuite/gcc.dg/pr81703.c index 190f4a833dd..02edf267437 100644 --- a/gcc/testsuite/gcc.dg/pr81703.c +++ b/gcc/testsuite/gcc.dg/pr81703.c @@ -9,4 +9,4 @@ unsigned g (void) return __builtin_strlen (d); } -/* { dg-final { scan-tree-dump-not "__builtin_strlen" "strlen" } } */ +/* { dg-final { scan-tree-dump-not "__builtin_strlen" "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strcmpopt_2.c b/gcc/testsuite/gcc.dg/strcmpopt_2.c index 0131b8f7d69..57d8f651c28 100644 --- a/gcc/testsuite/gcc.dg/strcmpopt_2.c +++ b/gcc/testsuite/gcc.dg/strcmpopt_2.c @@ -64,4 +64,4 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 8 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 8 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strcmpopt_3.c b/gcc/testsuite/gcc.dg/strcmpopt_3.c index 86a0d7a08b3..571646ce001 100644 --- a/gcc/testsuite/gcc.dg/strcmpopt_3.c +++ b/gcc/testsuite/gcc.dg/strcmpopt_3.c @@ -28,4 +28,4 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump-times "strcmp" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strcmp" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strcmpopt_4.c b/gcc/testsuite/gcc.dg/strcmpopt_4.c index d727bc363e5..4e26522eed1 100644 --- a/gcc/testsuite/gcc.dg/strcmpopt_4.c +++ b/gcc/testsuite/gcc.dg/strcmpopt_4.c @@ -13,4 +13,4 @@ f1 (S * s) return result; } -/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 1 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 1 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-1.c b/gcc/testsuite/gcc.dg/strlenopt-1.c index 910ec672e96..24772c14499 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-1.c +++ b/gcc/testsuite/gcc.dg/strlenopt-1.c @@ -36,9 +36,9 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-10.c b/gcc/testsuite/gcc.dg/strlenopt-10.c index 97167df959f..ce959c34a80 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-10.c +++ b/gcc/testsuite/gcc.dg/strlenopt-10.c @@ -69,14 +69,14 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ /* avr has BIGGEST_ALIGNMENT 8, allowing fold_builtin_memory_op to expand the memcpy call at the end of fn2. */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 8 "strlen" { target { ! avr-*-* } } } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" { target { avr-*-* } } } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "\\*q_\[0-9\]* = 32;" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(\[^\n\r\]*, 1\\)" 1 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 8 "strlen1" { target { ! avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen1" { target { avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "\\*q_\[0-9\]* = 32;" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(\[^\n\r\]*, 1\\)" 1 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-11.c b/gcc/testsuite/gcc.dg/strlenopt-11.c index f7fa44bde35..abd9faebed6 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-11.c +++ b/gcc/testsuite/gcc.dg/strlenopt-11.c @@ -58,18 +58,18 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen1" } } */ /* avr has BIGGEST_ALIGNMENT 8, allowing fold_builtin_memory_op to expand the memcpy call at the end of fn1. */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" { target { ! avr-*-* } } } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" { target { avr-*-* } } } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen1" { target { ! avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen1" { target { avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ /* Where the memcpy is expanded, the assignemts to elements of l are propagated. */ -/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.0. = " 1 "strlen" { target { ! avr-*-* } } } } */ -/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.6. = " 1 "strlen" { target { ! avr-*-* } } } } */ -/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.9. = " 1 "strlen" { target { ! avr-*-* } } } } */ -/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;" 3 "strlen" { target { avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.0. = " 1 "strlen1" { target { ! avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.6. = " 1 "strlen1" { target { ! avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.9. = " 1 "strlen1" { target { ! avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;" 3 "strlen1" { target { avr-*-* } } } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-13.c b/gcc/testsuite/gcc.dg/strlenopt-13.c index 3502599b28c..27ecc79c2d9 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-13.c +++ b/gcc/testsuite/gcc.dg/strlenopt-13.c @@ -55,19 +55,19 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen1" } } */ /* avr has BIGGEST_ALIGNMENT 8, allowing fold_builtin_memory_op to expand the memcpy call at the end of fn1. */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" { target { ! avr-*-* } } } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" { target { avr-*-* } } } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen1" { target { ! avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen1" { target { avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ /* Where the memcpy is expanded, the assignemts to elements of l are propagated. */ -/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.0. = " 1 "strlen" { target { ! avr-*-* } } } } */ -/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.1. = " 1 "strlen" { target { ! avr-*-* } } } } */ -/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.5. = " 1 "strlen" { target { ! avr-*-* } } } } */ -/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.6. = " 1 "strlen" { target { ! avr-*-* } } } } */ -/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;" 4 "strlen" { target { avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.0. = " 1 "strlen1" { target { ! avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.1. = " 1 "strlen1" { target { ! avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.5. = " 1 "strlen1" { target { ! avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]* l.6. = " 1 "strlen1" { target { ! avr-*-* } } } } */ +/* { dg-final { scan-tree-dump-times " _\[0-9\]* = strlen \\(\[^\n\r\]*;" 4 "strlen1" { target { avr-*-* } } } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-14g.c b/gcc/testsuite/gcc.dg/strlenopt-14g.c index 62a83bf8fd7..1368ed3f68e 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-14g.c +++ b/gcc/testsuite/gcc.dg/strlenopt-14g.c @@ -107,10 +107,10 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "mempcpy \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "mempcpy \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-14gf.c b/gcc/testsuite/gcc.dg/strlenopt-14gf.c index 8b126fcb7ea..f7db2a8a53e 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-14gf.c +++ b/gcc/testsuite/gcc.dg/strlenopt-14gf.c @@ -11,15 +11,15 @@ /* Compared to strlenopt-14gf.c, strcpy_chk with string literal as second argument isn't being optimized by builtins.c into memcpy. */ -/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__mempcpy_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "mempcpy \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__mempcpy_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "mempcpy \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-15.c b/gcc/testsuite/gcc.dg/strlenopt-15.c index 827ea07b6ea..b72c096ffa9 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-15.c +++ b/gcc/testsuite/gcc.dg/strlenopt-15.c @@ -51,9 +51,9 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-16g.c b/gcc/testsuite/gcc.dg/strlenopt-16g.c index 0cf8410735a..816cbbce801 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-16g.c +++ b/gcc/testsuite/gcc.dg/strlenopt-16g.c @@ -24,10 +24,10 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-17g.c b/gcc/testsuite/gcc.dg/strlenopt-17g.c index 184e530788e..aa86f78ec7f 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-17g.c +++ b/gcc/testsuite/gcc.dg/strlenopt-17g.c @@ -47,10 +47,10 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-18g.c b/gcc/testsuite/gcc.dg/strlenopt-18g.c index f734675ec40..de692e0767a 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-18g.c +++ b/gcc/testsuite/gcc.dg/strlenopt-18g.c @@ -73,9 +73,9 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-19.c b/gcc/testsuite/gcc.dg/strlenopt-19.c index 022ba8b4787..814f51b27f6 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-19.c +++ b/gcc/testsuite/gcc.dg/strlenopt-19.c @@ -72,9 +72,9 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-1f.c b/gcc/testsuite/gcc.dg/strlenopt-1f.c index 856774de7ad..4e3abd9472d 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-1f.c +++ b/gcc/testsuite/gcc.dg/strlenopt-1f.c @@ -5,13 +5,13 @@ #define FORTIFY_SOURCE 2 #include "strlenopt-1.c" -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-2.c b/gcc/testsuite/gcc.dg/strlenopt-2.c index fd59a3cd513..b09f7c17e39 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-2.c +++ b/gcc/testsuite/gcc.dg/strlenopt-2.c @@ -40,9 +40,9 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 5 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 5 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-20.c b/gcc/testsuite/gcc.dg/strlenopt-20.c index 7b483eaeac1..79db12bc102 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-20.c +++ b/gcc/testsuite/gcc.dg/strlenopt-20.c @@ -86,9 +86,9 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-21.c b/gcc/testsuite/gcc.dg/strlenopt-21.c index 05b85a49dde..7924ff30b51 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-21.c +++ b/gcc/testsuite/gcc.dg/strlenopt-21.c @@ -57,9 +57,9 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-22.c b/gcc/testsuite/gcc.dg/strlenopt-22.c index b4ef772f0e5..2d127b11832 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-22.c +++ b/gcc/testsuite/gcc.dg/strlenopt-22.c @@ -31,9 +31,9 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-22g.c b/gcc/testsuite/gcc.dg/strlenopt-22g.c index 9c5d020588f..1ecb85eae0c 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-22g.c +++ b/gcc/testsuite/gcc.dg/strlenopt-22g.c @@ -5,9 +5,9 @@ #define USE_GNU #include "strlenopt-22.c" -/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-24.c b/gcc/testsuite/gcc.dg/strlenopt-24.c index 639501a53e0..275b5602b70 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-24.c +++ b/gcc/testsuite/gcc.dg/strlenopt-24.c @@ -13,4 +13,4 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-25.c b/gcc/testsuite/gcc.dg/strlenopt-25.c index 89b60e3ebed..faed5bec889 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-25.c +++ b/gcc/testsuite/gcc.dg/strlenopt-25.c @@ -14,4 +14,4 @@ main () return len - len2; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-26.c b/gcc/testsuite/gcc.dg/strlenopt-26.c index 6bb0263d315..0385aceaad3 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-26.c +++ b/gcc/testsuite/gcc.dg/strlenopt-26.c @@ -20,5 +20,5 @@ main (void) return fn1 (p, q); } -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-27.c b/gcc/testsuite/gcc.dg/strlenopt-27.c index c539edb821c..e3655930b3e 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-27.c +++ b/gcc/testsuite/gcc.dg/strlenopt-27.c @@ -19,4 +19,4 @@ main (void) return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-28.c b/gcc/testsuite/gcc.dg/strlenopt-28.c index 03fb01781bd..6bdbed7e9d0 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-28.c +++ b/gcc/testsuite/gcc.dg/strlenopt-28.c @@ -56,4 +56,4 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-29.c b/gcc/testsuite/gcc.dg/strlenopt-29.c index fb4b4c9cc71..8922101f549 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-29.c +++ b/gcc/testsuite/gcc.dg/strlenopt-29.c @@ -24,4 +24,4 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-2f.c b/gcc/testsuite/gcc.dg/strlenopt-2f.c index 1e915dac928..5786f8a1904 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-2f.c +++ b/gcc/testsuite/gcc.dg/strlenopt-2f.c @@ -5,13 +5,13 @@ #define FORTIFY_SOURCE 2 #include "strlenopt-2.c" -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 5 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 5 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-3.c b/gcc/testsuite/gcc.dg/strlenopt-3.c index f17779c0a66..a748f011c80 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-3.c +++ b/gcc/testsuite/gcc.dg/strlenopt-3.c @@ -53,12 +53,12 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ /* { dg-final { scan-tree-dump-times "return 0" 3 "optimized" } } */ /* { dg-final { scan-tree-dump-times "return 4" 1 "optimized" } } */ /* { dg-final { scan-tree-dump-times "return 3" 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-30.c b/gcc/testsuite/gcc.dg/strlenopt-30.c index a85df686ce2..2a3098ba96f 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-30.c +++ b/gcc/testsuite/gcc.dg/strlenopt-30.c @@ -60,4 +60,4 @@ _Bool f7(char *s) return (t1 == s); } -/* { dg-final { scan-tree-dump-times "__builtin_strncmp" 5 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_strncmp" 5 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-31g.c b/gcc/testsuite/gcc.dg/strlenopt-31g.c index 45cc29c1024..4eff86448f1 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-31g.c +++ b/gcc/testsuite/gcc.dg/strlenopt-31g.c @@ -4,6 +4,6 @@ #define USE_GNU #include "strlenopt-31.c" -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-not "strlen \\(" "strlen" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-not "strlen \\(" "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-32.c b/gcc/testsuite/gcc.dg/strlenopt-32.c index 08eb6bc2b08..4220314fb3f 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-32.c +++ b/gcc/testsuite/gcc.dg/strlenopt-32.c @@ -190,4 +190,4 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-33.c b/gcc/testsuite/gcc.dg/strlenopt-33.c index 1e1c4dee1f8..4903a91a0a4 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-33.c +++ b/gcc/testsuite/gcc.dg/strlenopt-33.c @@ -39,4 +39,4 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-33g.c b/gcc/testsuite/gcc.dg/strlenopt-33g.c index 7d24d2bfc32..a814160e234 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-33g.c +++ b/gcc/testsuite/gcc.dg/strlenopt-33g.c @@ -40,5 +40,5 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-34.c b/gcc/testsuite/gcc.dg/strlenopt-34.c index c9433c0399e..1979370cb5e 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-34.c +++ b/gcc/testsuite/gcc.dg/strlenopt-34.c @@ -35,4 +35,4 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-35.c b/gcc/testsuite/gcc.dg/strlenopt-35.c index 03b3e13a8e2..d175fd7ff50 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-35.c +++ b/gcc/testsuite/gcc.dg/strlenopt-35.c @@ -28,4 +28,4 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-4.c b/gcc/testsuite/gcc.dg/strlenopt-4.c index 802e4ca7ce4..1d0a6e615bc 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-4.c +++ b/gcc/testsuite/gcc.dg/strlenopt-4.c @@ -66,9 +66,9 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 3 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 3 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 3 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 3 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-48.c b/gcc/testsuite/gcc.dg/strlenopt-48.c index 179edd82a43..c2d0ac66521 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-48.c +++ b/gcc/testsuite/gcc.dg/strlenopt-48.c @@ -31,5 +31,5 @@ void h (void) abort(); } -/* { dg-final { scan-tree-dump-times "strlen" 0 "optimized" } } +/* { dg-final { scan-tree-dump-times "strlen1" 0 "optimized" } } { dg-final { scan-tree-dump-times "abort" 0 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-49.c b/gcc/testsuite/gcc.dg/strlenopt-49.c index f901fd14b54..bbea0e2db72 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-49.c +++ b/gcc/testsuite/gcc.dg/strlenopt-49.c @@ -45,7 +45,7 @@ int cmp88 (void) return cmp88; } -/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } } +/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } } { dg-final { scan-tree-dump-times "len0 = 0;" 1 "gimple" } } { dg-final { scan-tree-dump-times "len = 18;" 1 "gimple" } } { dg-final { scan-tree-dump-times "lenx = 8;" 1 "gimple" } } diff --git a/gcc/testsuite/gcc.dg/strlenopt-4g.c b/gcc/testsuite/gcc.dg/strlenopt-4g.c index 879d5666c90..88dcec647e7 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-4g.c +++ b/gcc/testsuite/gcc.dg/strlenopt-4g.c @@ -5,9 +5,9 @@ #define USE_GNU #include "strlenopt-4.c" -/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 5 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 5 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-4gf.c b/gcc/testsuite/gcc.dg/strlenopt-4gf.c index 7f261b7d34d..033661ad4a9 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-4gf.c +++ b/gcc/testsuite/gcc.dg/strlenopt-4gf.c @@ -6,13 +6,13 @@ #define FORTIFY_SOURCE 2 #include "strlenopt-4.c" -/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 5 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 5 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-5.c b/gcc/testsuite/gcc.dg/strlenopt-5.c index a24aea44e8b..5a31322bfa1 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-5.c +++ b/gcc/testsuite/gcc.dg/strlenopt-5.c @@ -48,9 +48,9 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-50.c b/gcc/testsuite/gcc.dg/strlenopt-50.c index 1d1d36808a9..8e7c9dbd93d 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-50.c +++ b/gcc/testsuite/gcc.dg/strlenopt-50.c @@ -112,5 +112,5 @@ void test_array_ref (void) T (&b[16], 0); T (&b[17], 0); T (&b[18], 0); T (&b[19], 0); } -/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } } +/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } } { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated" 0 "ccp1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-51.c b/gcc/testsuite/gcc.dg/strlenopt-51.c index 3d879f1329a..22a89385f5e 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-51.c +++ b/gcc/testsuite/gcc.dg/strlenopt-51.c @@ -84,4 +84,4 @@ void test_elim_a9_9 (unsigned i) T (0); T (1); T (2); T (3); T (4); T (5); T (6); T (7); T (8); } -/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-52.c b/gcc/testsuite/gcc.dg/strlenopt-52.c index 03e063b435e..97b3da7cd0e 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-52.c +++ b/gcc/testsuite/gcc.dg/strlenopt-52.c @@ -284,5 +284,5 @@ void test_global_struct_struct_array (void) T (ssa[5].sa9[3].a6, 3); } -/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } } +/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } } { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated" 0 "ccp1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-53.c b/gcc/testsuite/gcc.dg/strlenopt-53.c index baa680d125b..489c22b6937 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-53.c +++ b/gcc/testsuite/gcc.dg/strlenopt-53.c @@ -112,5 +112,5 @@ void test_array_ref (void) T (&b[16], 0); T (&b[17], 0); T (&b[18], 0); T (&b[19], 0); } -/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } } +/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } } { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated" 0 "ccp1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-54.c b/gcc/testsuite/gcc.dg/strlenopt-54.c index c38e7918f8b..d4e57ff6255 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-54.c +++ b/gcc/testsuite/gcc.dg/strlenopt-54.c @@ -105,5 +105,5 @@ void elim_after_init_memcpy (void) T ("AB\000CD", 0, "ab\000c", 4, 2); } -/* { dg-final { scan-tree-dump-times "strlen" 0 "optimized" } } +/* { dg-final { scan-tree-dump-times "strlen1" 0 "optimized" } } { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated" 0 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-55.c b/gcc/testsuite/gcc.dg/strlenopt-55.c index d5a02953d36..ea6fb22a2ed 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-55.c +++ b/gcc/testsuite/gcc.dg/strlenopt-55.c @@ -224,7 +224,7 @@ const void test_large_string_size (void) } -/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } } +/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } } { dg-final { scan-tree-dump-times "memcmp" 0 "gimple" } } { dg-final { scan-tree-dump-times "strcmp" 0 "gimple" } } { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated" 0 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-56.c b/gcc/testsuite/gcc.dg/strlenopt-56.c index 39a532bf8d4..ffd02f1b6cf 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-56.c +++ b/gcc/testsuite/gcc.dg/strlenopt-56.c @@ -45,6 +45,6 @@ void test_contents (void) } -/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } } +/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } } { dg-final { scan-tree-dump-times "strcmp" 0 "gimple" } } { dg-final { scan-tree-dump-times "abort" 0 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-6.c b/gcc/testsuite/gcc.dg/strlenopt-6.c index fbff14c4fdb..dcbe778a27a 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-6.c +++ b/gcc/testsuite/gcc.dg/strlenopt-6.c @@ -77,9 +77,9 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-61.c b/gcc/testsuite/gcc.dg/strlenopt-61.c index 4f8e9c053e4..3ddfa2ebc9f 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-61.c +++ b/gcc/testsuite/gcc.dg/strlenopt-61.c @@ -215,4 +215,4 @@ void test_ta2 (void) } /* { dg-final { scan-tree-dump-not "failure" "optimized" } } - { dg-final { scan-tree-dump-not "strlen" "gimple" } } */ + { dg-final { scan-tree-dump-not "strlen1" "gimple" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-68.c b/gcc/testsuite/gcc.dg/strlenopt-68.c new file mode 100644 index 00000000000..56d314e5d45 --- /dev/null +++ b/gcc/testsuite/gcc.dg/strlenopt-68.c @@ -0,0 +1,382 @@ +/* PR tree-optimization/83431 - Verify that snprintf (0, 0, "%s", + with an argument that's a conditional expression evaluates to + the expected result regardless of the order of the expression + operands. + { dg-do run } + { dg-options "-O2 -Wall" } */ + +#include "strlenopt.h" + +#define A(expr) \ + ((expr) \ + ? (void)0 \ + : (__builtin_printf ("assertion failed on line %i: %s\n", \ + __LINE__, #expr), \ + __builtin_abort ())) + +const char gs0[] = ""; +const char gs3[] = "123"; + +char gc; +char ga5[7]; + +struct S { char n, ma7[7], max[]; }; + + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_gs0_gs3_ga5_m1 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? gs0 : 0 < i ? gs3 : ga5; + + A (snprintf (0, 0, "%s", p) == 0); +} + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_gs0_gs3_ga5_0 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? gs0 : 0 < i ? gs3 : ga5; + + A (snprintf (0, 0, "%s", p) == 4); +} + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_gs0_gs3_ga5_p1 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? gs0 : 0 < i ? gs3 : ga5; + + A (snprintf (0, 0, "%s", p) == 3); +} + + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_gs0_ga5_gs3_m1 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? gs0 : 0 < i ? ga5 : gs3; + + A (snprintf (0, 0, "%s", p) == 0); +} + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_gs0_ga5_gs3_0 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? gs0 : 0 < i ? ga5 : gs3; + + A (snprintf (0, 0, "%s", p) == 3); +} + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_gs0_ga5_gs3_p1 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? gs0 : 0 < i ? ga5 : gs3; + + A (snprintf (0, 0, "%s", p) == 4); +} + + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_ga5_gs0_gs3_m1 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? ga5 : 0 < i ? gs0 : gs3; + + A (snprintf (0, 0, "%s", p) == 4); +} + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_ga5_gs0_gs3_0 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? ga5 : 0 < i ? gs0 : gs3; + + A (snprintf (0, 0, "%s", p) == 3); +} + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_ga5_gs0_gs3_p1 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? ga5 : 0 < i ? gs0 : gs3; + + A (snprintf (0, 0, "%s", p) == 0); +} + + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_ga5_gs3_gs0_m1 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? ga5 : 0 < i ? gs3 : gs0; + + A (snprintf (0, 0, "%s", p) == 4); +} + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_ga5_gs3_gs0_0 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? ga5 : 0 < i ? gs3 : gs0; + + A (snprintf (0, 0, "%s", p) == 0); +} + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_ga5_gs3_gs0_p1 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? ga5 : 0 < i ? gs3 : gs0; + + A (snprintf (0, 0, "%s", p) == 3); +} + + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_gs3_gs0_ga5_m1 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? gs3 : 0 < i ? gs0 : ga5; + + A (snprintf (0, 0, "%s", p) == 3); +} + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_gs3_gs0_ga5_0 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? gs3 : 0 < i ? gs0 : ga5; + + A (snprintf (0, 0, "%s", p) == 4); +} + +__attribute__ ((noclone, noinline, noipa)) void +equal_4_gs3_gs0_ga5_p1 (int i) +{ + strcpy (ga5, "1234"); + const char *p = i < 0 ? gs3 : 0 < i ? gs0 : ga5; + + A (snprintf (0, 0, "%s", p) == 0); +} + + +/* Similar to the above but with memcpy creating a string at least + four characters long, and the address of the NUL character. */ + +__attribute__ ((noclone, noinline, noipa)) void +min_4_gc_gs3_ga5_m1 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? &gc : 0 < i ? gs3 : ga5; + + A (snprintf (0, 0, "%s", p) == 0); +} + +__attribute__ ((noclone, noinline, noipa)) void +min_4_gc_gs3_ga5_0 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? &gc : 0 < i ? gs3 : ga5; + + A (snprintf (0, 0, "%s", p) == 4); +} + +__attribute__ ((noclone, noinline, noipa)) void +min_4_gc_gs3_ga5_p1 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? &gc : 0 < i ? gs3 : ga5; + + A (snprintf (0, 0, "%s", p) == 3); +} + + +__attribute__ ((noclone, noinline, noipa)) void +min_4_gc_ga5_gs3_m1 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? &gc : 0 < i ? ga5 : gs3; + + A (snprintf (0, 0, "%s", p) == 0); +} + +__attribute__ ((noclone, noinline, noipa)) void +min_4_gc_ga5_gs3_0 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? &gc : 0 < i ? ga5 : gs3; + + A (snprintf (0, 0, "%s", p) == 3); +} + +__attribute__ ((noclone, noinline, noipa)) void +min_4_gc_ga5_gs3_p1 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? &gc : 0 < i ? ga5 : gs3; + + A (snprintf (0, 0, "%s", p) == 4); +} + + +__attribute__ ((noclone, noinline, noipa)) void +min_4_ga5_gc_gs3_m1 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? ga5 : 0 < i ? &gc : gs3; + + A (snprintf (0, 0, "%s", p) == 4); +} + +__attribute__ ((noclone, noinline, noipa)) void +min_4_ga5_gc_gs3_0 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? ga5 : 0 < i ? &gc : gs3; + + A (snprintf (0, 0, "%s", p) == 3); +} + +__attribute__ ((noclone, noinline, noipa)) void +min_4_ga5_gc_gs3_p1 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? ga5 : 0 < i ? &gc : gs3; + + A (snprintf (0, 0, "%s", p) == 0); +} + + +__attribute__ ((noclone, noinline, noipa)) void +min_4_ga5_gs3_gc_m1 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? ga5 : 0 < i ? gs3 : &gc; + + A (snprintf (0, 0, "%s", p) == 4); +} + +__attribute__ ((noclone, noinline, noipa)) void +min_4_ga5_gs3_gc_0 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? ga5 : 0 < i ? gs3 : &gc; + + A (snprintf (0, 0, "%s", p) == 0); +} + +__attribute__ ((noclone, noinline, noipa)) void +min_4_ga5_gs3_gc_p1 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? ga5 : 0 < i ? gs3 : &gc; + + A (snprintf (0, 0, "%s", p) == 3); +} + + +__attribute__ ((noclone, noinline, noipa)) void +min_4_gs3_gc_ga5_m1 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? gs3 : 0 < i ? &gc : ga5; + + A (snprintf (0, 0, "%s", p) == 3); +} + +__attribute__ ((noclone, noinline, noipa)) void +min_4_gs3_gc_ga5_0 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? gs3 : 0 < i ? &gc : ga5; + + A (snprintf (0, 0, "%s", p) == 4); +} + +__attribute__ ((noclone, noinline, noipa)) void +min_4_gs3_gc_ga5_p1 (int i) +{ + gc = 0; + memcpy (ga5, "1234", 4); + const char *p = i < 0 ? gs3 : 0 < i ? &gc : ga5; + + A (snprintf (0, 0, "%s", p) == 0); +} + + +int main (void) +{ + equal_4_gs0_gs3_ga5_m1 (-1); + equal_4_gs0_gs3_ga5_0 ( 0); + equal_4_gs0_gs3_ga5_p1 (+1); + + equal_4_gs0_ga5_gs3_m1 (-1); + equal_4_gs0_ga5_gs3_0 ( 0); + equal_4_gs0_ga5_gs3_p1 (+1); + + equal_4_ga5_gs0_gs3_m1 (-1); + equal_4_ga5_gs0_gs3_0 ( 0); + equal_4_ga5_gs0_gs3_p1 (+1); + + equal_4_ga5_gs3_gs0_m1 (-1); + equal_4_ga5_gs3_gs0_0 ( 0); + equal_4_ga5_gs3_gs0_p1 (+1); + + equal_4_gs3_gs0_ga5_m1 (-1); + equal_4_gs3_gs0_ga5_0 ( 0); + equal_4_gs3_gs0_ga5_p1 (+1); + + /* Same as aabove but with memcpy creating a string at least four + characters long. */ + memset (ga5, 0, sizeof ga5); + min_4_gc_gs3_ga5_m1 (-1); + memset (ga5, 0, sizeof ga5); + min_4_gc_gs3_ga5_0 ( 0); + memset (ga5, 0, sizeof ga5); + min_4_gc_gs3_ga5_p1 (+1); + + memset (ga5, 0, sizeof ga5); + min_4_gc_ga5_gs3_m1 (-1); + memset (ga5, 0, sizeof ga5); + min_4_gc_ga5_gs3_0 ( 0); + memset (ga5, 0, sizeof ga5); + min_4_gc_ga5_gs3_p1 (+1); + + memset (ga5, 0, sizeof ga5); + min_4_ga5_gc_gs3_m1 (-1); + memset (ga5, 0, sizeof ga5); + min_4_ga5_gc_gs3_0 ( 0); + memset (ga5, 0, sizeof ga5); + min_4_ga5_gc_gs3_p1 (+1); + + memset (ga5, 0, sizeof ga5); + min_4_ga5_gs3_gc_m1 (-1); + memset (ga5, 0, sizeof ga5); + min_4_ga5_gs3_gc_0 ( 0); + memset (ga5, 0, sizeof ga5); + min_4_ga5_gs3_gc_p1 (+1); + + memset (ga5, 0, sizeof ga5); + min_4_gs3_gc_ga5_m1 (-1); + memset (ga5, 0, sizeof ga5); + min_4_gs3_gc_ga5_0 ( 0); + memset (ga5, 0, sizeof ga5); + min_4_gs3_gc_ga5_p1 (+1); +} diff --git a/gcc/testsuite/gcc.dg/strlenopt-7.c b/gcc/testsuite/gcc.dg/strlenopt-7.c index aa53d7e7525..ba62c039622 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-7.c +++ b/gcc/testsuite/gcc.dg/strlenopt-7.c @@ -40,12 +40,12 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "\\*r_\[0-9\]* = 0;" 1 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "\\*r_\[0-9\]* = 0;" 1 "strlen1" } } */ /* { dg-final { scan-tree-dump-times "return 3;" 1 "optimized" } } */ /* { dg-final { scan-tree-dump-times "return 0;" 2 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-9.c b/gcc/testsuite/gcc.dg/strlenopt-9.c index e8ff1023d71..df6b594946a 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-9.c +++ b/gcc/testsuite/gcc.dg/strlenopt-9.c @@ -98,10 +98,10 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 5 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */ -/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 5 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */ +/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */ /* { dg-final { scan-tree-dump-times "return 4;" 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt.h b/gcc/testsuite/gcc.dg/strlenopt.h index d25e08a8a42..518d0cf08b2 100644 --- a/gcc/testsuite/gcc.dg/strlenopt.h +++ b/gcc/testsuite/gcc.dg/strlenopt.h @@ -1,4 +1,4 @@ -/* This is a replacement of needed parts from stdlib.h and string.h +/* This is a replacement of needed parts from and for -foptimize-strlen testing, to ensure we are testing the builtins rather than whatever the OS has in its headers. */ @@ -25,6 +25,9 @@ void *mempcpy (void *__restrict, const void *__restrict, size_t); char *stpcpy (char *__restrict, const char *__restrict); #endif +int sprintf (char * __restrict, const char *__restrict, ...); +int snprintf (char * __restrict, size_t, const char *__restrict, ...); + #if defined(FORTIFY_SOURCE) && FORTIFY_SOURCE > 0 && __OPTIMIZE__ # define bos(ptr) __builtin_object_size (ptr, FORTIFY_SOURCE > 0) # define bos0(ptr) __builtin_object_size (ptr, 0) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-6.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-6.c new file mode 100644 index 00000000000..0d9b27505ec --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-6.c @@ -0,0 +1,139 @@ +/* Test to verify that snprintf can determine the length of a dynamically + constructed string argument and fold the result into a constant. + { dg-do compile } + { dg-options "-O2 -Wall -fdump-tree-optimized" } */ + +typedef __SIZE_TYPE__ size_t; + +char* strcpy (char * restrict, const char * restrict); +int sprintf (char * restrict, const char *restrict, ...); +int snprintf (char * restrict, size_t, const char *restrict, ...); + + +#define CONCAT(x, y) x ## y +#define CAT(x, y) CONCAT (x, y) +#define FAILNAME(name, counter) \ + CAT (CAT (CAT (call_ ## name ##_on_line_, __LINE__), _), counter) + +#define FAIL(name, counter) do { \ + extern void FAILNAME (name, counter) (void); \ + FAILNAME (name, counter)(); \ + } while (0) + +/* Macro to emit a call to funcation named + call_in_true_branch_not_eliminated_on_line_NNN() + for each call that's expected to be eliminated. The dg-final + scan-tree-dump-time directive at the bottom of the test verifies + that no such call appears in output. */ +#define ELIM(expr) \ + if (!(expr)) FAIL (in_true_branch_not_eliminated, __COUNTER__); else (void)0 + +#define ARGS(...) __VA_ARGS__ + +#define T(expect, init, fmt, ...) \ + do { \ + char a[] = init; \ + ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__)); \ + } while (0) + +/* Exercise a non-const local char array initialized by a string literal. */ +void test_assign_string (void) +{ + T (0, "", "%s", a); + T (1, "1", "%s", a); + T (4, "1234", "%s", a); + T (5, "123", "s=%s", a); + T (5, "1234", "s=%s", a + 1); + T (2, "1234", "s=%s", a + 4); + T (5, "12345", "s=%s", &a[2]); + T (5, "123456", "s=%.*s", 3, &a[2]); +} + +/* Exercise a non-const local char array initialized by an initializer + list. */ +void test_assign_init_list (void) +{ + T (0, ARGS ({ 0 }), "%s", a); + T (1, ARGS ({ 1, 0 }), "%s", a); + T (3, ARGS ({ [3] = 0, [1] = 2, [0] = 1, [2] = 3 }), "%s", a); + T (3, ARGS ({ [3] = 0, [1] = 2, [0] = 1, [2] = 3, [4] = 0 }), "%s", a); + T (4, ARGS ({ 1, 2, 3, 4, 0 }), "%s", a); + T (5, ARGS ({ 1, 2, 3, 0 }), "s=%s", a); + T (5, ARGS ({ 1, 2, 3, 4, 0 }), "s=%s", a + 1); + T (2, ARGS ({ 1, 2, 3, 4, 0 }), "s=%s", a + 4); + T (5, ARGS ({ 1, 2, 3, 4, 5, 0 }), "s=%s", &a[2]); + T (5, ARGS ({ 1, 2, 3, 4, 5, 6, 0 }), "s=%.*s", 3, &a[2]); +} + +#undef T +#define T(expect, init, fmt, ...) \ + do { \ + struct { int n; char a[sizeof init]; } \ + s = { sizeof init, init }; \ + ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__)); \ + } while (0) + +/* Exercise a non-const local struct initialized by an initializer + list. */ +void test_assign_aggregate (void) +{ + T (0, "", "%s", s.a); + T (1, "1", "%s", s.a); + T (4, "1234", "%s", s.a); + T (5, "123", "s=%s", s.a); + T (5, "1234", "s=%s", s.a + 1); + T (2, "1234", "s=%s", s.a + 4); + T (5, "12345", "s=%s", &s.a[2]); + T (5, "123456", "s=%.*s", 3, &s.a[2]); +} + + +#undef T +#define T(expect, init, fmt, ...) \ + do { \ + char a[sizeof init]; \ + strcpy (a, init); \ + ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__)); \ + } while (0) + +/* Exercise a local char array initialized by a call to strcpy. */ +void test_local_strcpy (void) +{ + T (0, "", "%s", a); + T (1, "1", "%s", a); + T (2, "12", "%s", a); + T (3, "123", "%s", a); + T (4, "1234", "%s", a); + T (5, "123", "s=%s", a); + T (5, "1234", "s=%s", a + 1); + T (2, "1234", "s=%s", a + 4); + T (5, "12345", "s=%s", &a[2]); + T (5, "123456", "s=%.*s", 3, &a[2]); +} + +#undef T +#define T(expect, init, fmt, ...) \ + do { \ + char a[n]; \ + strcpy (a, init); \ + ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__)); \ + } while (0) + +/* Exercise a VLA initialized by a call to strcpy. */ +void test_vla_strcpy (unsigned n) +{ + T (0, "", "%s", a); + T (1, "1", "%s", a); + T (2, "12", "%s", a); + T (3, "123", "%s", a); + T (4, "1234", "%s", a); + T (5, "123", "s=%s", a); + T (5, "1234", "s=%s", a + 1); + T (2, "1234", "s=%s", a + 4); + T (5, "12345", "s=%s", &a[2]); + T (5, "123456", "s=%.*s", 3, &a[2]); +} + +/* { dg-final { scan-tree-dump-times "printf" 0 "optimized" } } + { dg-final { scan-tree-dump-times "strlen" 0 "optimized" } } + { dg-final { scan-tree-dump-times "not_eliminated" 0 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-7.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-7.c new file mode 100644 index 00000000000..bf5072e955c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-7.c @@ -0,0 +1,152 @@ +/* Test to verify that snprintf can determine the correct range + of lengths of dynamically constructed string arguments. + { dg-do compile } + { dg-options "-O2 -Wall -fdump-tree-optimized" } */ + +typedef __SIZE_TYPE__ size_t; + +void* memcpy (void*, const void*, size_t); + +char* strcpy (char * restrict, const char * restrict); +int snprintf (char * restrict, size_t, const char *restrict, ...); + +void sink (void*, ...); + +#define CONCAT(x, y) x ## y +#define CAT(x, y) CONCAT (x, y) +#define FAILNAME(name, counter) \ + CAT (CAT (CAT (call_ ## name ##_on_line_, __LINE__), _), counter) + +#define FAIL(name, counter) do { \ + extern void FAILNAME (name, counter) (void); \ + FAILNAME (name, counter)(); \ + } while (0) + +/* Macro to emit a call to funcation named + call_in_true_branch_not_eliminated_on_line_NNN() + for each call that's expected to be eliminated. The dg-final + scan-tree-dump-time directive at the bottom of the test verifies + that no such call appears in output. */ +#define VERIFY_ELIM(expr) \ + if (!(expr)) FAIL (in_true_branch_not_eliminated, __COUNTER__); else (void)0 + +/* Macro to emit a call to a function named + call_made_in_{true,false}_branch_on_line_NNN() + for each call that's expected to be retained. The dg-final + scan-tree-dump-time directive at the bottom of the test verifies + that the expected number of both kinds of calls appears in output + (a pair for each line with the invocation of the KEEP() macro. */ +#define VERIFY_KEEP(expr) \ + if (expr) \ + FAIL (made_in_true_branch, __COUNTER__); \ + else \ + FAIL (made_in_false_branch, __COUNTER__) + +#define ARGS(...) __VA_ARGS__ + +/* Each test macro expands to a new function to get around bug 81776 + - missing sprintf optimization due to pointer escape analysis. */ +#define ELIM(expect, dst, init, fmt, ...) \ + void CAT (test_func_on_line_, __LINE__)(void) \ + { \ + memcpy (dst, init, sizeof (init) - 1); \ + const int res = snprintf (0, 0, fmt, __VA_ARGS__); \ + VERIFY_ELIM (expect res); \ + } typedef void dummy_typedef + +#define KEEP(expect, dst, init, fmt, ...) \ + void CAT (test_func_on_line_, __LINE__)(void) \ + { \ + memcpy (dst, init, sizeof (init) - 1); \ + const int ret = snprintf (0, 0, fmt, __VA_ARGS__); \ + VERIFY_KEEP (expect ret); \ + } typedef void dummy_typedef + + +/* Verify that conditions involving snprintf calls with a string + of some minimum but otherwise unbounded length stored in an array + of unknown bound are not folded unless the format string itself + restricts the maximum. The string could be longer than INT_MAX + making the snprintf call fail and return a negative value. */ + +extern char gax[]; + +KEEP (1 <=, gax, "1", "%s", gax); +KEEP (2 <=, gax, "12", "%s", gax); +KEEP (3 <=, gax, "123", "%s", gax); + +ELIM (3 ==, gax, "123", "%.3s", gax); +ELIM (5 ==, gax, "123", "%.3s%.2s", gax, gax); + + +/* Disabled. The global pointer passed to memcpy as the destination + might point at itself, i.e., gptr == &gptr is a valid argument to + memcpy. + +extern char *gptr; + +KEEP (1 <=, gptr, "1", "%s", gptr); +KEEP (2 <=, gptr, "12", "%s", gptr); +KEEP (3 <=, gptr, "123", "%s", gptr); + +ELIM (3 ==, gptr, "123", "%.3s", gptr); +ELIM (5 ==, gptr, "123", "%.3s%.2s", gptr, gptr); + +*/ + +/* Verify that conditions involving snprintf calls with a string + of some minimum but otherwise unbounded length stored in an array + of a known bound are folded. The longest string that can be + stored in such arrays is bounded by the size of the array. */ + +extern char ga4[4]; + +ELIM (0 <=, ga4, "\0", "%s", ga4); +ELIM (3 >=, ga4, "\0", "%s", ga4); + +ELIM (1 <=, ga4, "1", "%s", ga4); +ELIM (0 <=, ga4, "1", "%s", ga4 + 1); +ELIM (0 <=, ga4, "1", "%s", &ga4[1]); + +ELIM (3 >=, ga4, "1", "%s", ga4); +ELIM (2 >=, ga4, "1", "%s", ga4 + 1); +ELIM (2 >=, ga4, "1", "%s", &ga4[1]); + +ELIM (2 <=, ga4, "12", "%s", ga4); +ELIM (3 >=, ga4, "12", "%s", ga4); + +ELIM (3 <=, ga4, "123", "%s", ga4); +ELIM (3 ==, ga4, "123", "%.3s", ga4); +ELIM (5 ==, ga4, "123", "%.3s%.2s", ga4, ga4); + +/* Verify conditionals involving dynamically created strings of known + length stored in local arrays. */ + +#undef ELIM +#define ELIM(expect, N1, N2, init1, init2, fmt, ...) \ + void CAT (test_func_on_line_, __LINE__)(int i) \ + { \ + char a1[N1], a2[N2]; \ + memcpy (a1, init1, sizeof (init1) - 1); \ + memcpy (a2, init2, sizeof (init2) - 1); \ + const int res = snprintf (0, 0, fmt, __VA_ARGS__); \ + VERIFY_ELIM (expect res); \ + } typedef void dummy_typedef + +ELIM (0 ==, 2, 2, "\0", "\0", "%s", i ? a1 : a2); +ELIM (2 ==, 2, 2, "\0", "\0", "s=%s", i ? a1 : a2); + +ELIM (1 ==, 2, 2, "a\0", "b\0", "%s", i ? a1 : a2); +ELIM (3 ==, 2, 2, "a\0", "b\0", "s=%s", i ? a1 : a2); + +ELIM (2 ==, 3, 5, "ab\0", "cd\0", "%s", i ? a1 : a2); +ELIM (3 ==, 3, 5, "ab\0", "cd\0", "%3s", i ? a1 : a2); +ELIM (3 ==, 5, 5, "abcd\0", "efgh\0", "%.3s", i ? a1 : a2); + +ELIM (3 ==, 4, 1, "abc\0", "", "%s", i ? a1 : "def"); +ELIM (4 ==, 1, 5, "", "efgh\0", "%s", i ? "abcd" : a2); + +ELIM (4 ==, 5, 5, "abcd\0", "efgh\0", "%s", i < 0 ? a1 : 0 < i ? a2 : "ijkl"); + +/* { dg-final { scan-tree-dump-times "_not_eliminated" 0 "optimized" } } + { dg-final { scan-tree-dump-times "call_made_" 6 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-8.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-8.c new file mode 100644 index 00000000000..95b0b44bcf0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-8.c @@ -0,0 +1,41 @@ +/* Test to verify that snprintf can determine the correct range + of lengths of string arguments based on the results of prior + calls to strlen. + { dg-do compile } + { dg-options "-O2 -Wall -fdump-tree-optimized" } */ + +typedef __SIZE_TYPE__ size_t; + +void abort (void); +size_t strlen (const char *); +int snprintf (char * restrict, size_t, const char *restrict, ...); + +void one_str_exact (const char *str) +{ + if (1 == strlen (str)) + if (1 != snprintf (0, 0, "%s", str)) + abort (); +} + +void two_str_exact (const char *s1, const char *s2) +{ + if (1 == strlen (s1) && 2 == strlen (s2)) + if (3 != snprintf (0, 0, "%s%s", s1, s2)) + abort (); +} + +void one_str_maxlen (const char *str) +{ + if (2 >= strlen (str)) + if (2 < snprintf (0, 0, "%s", str)) + abort (); +} + +void two_str_maxlen (const char *s1, const char *s2) +{ + if (2 >= strlen (s1) && 3 >= strlen (s2)) + if (5 < snprintf (0, 0, "%s%s", s1, s2)) + abort (); +} + +/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-9.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-9.c new file mode 100644 index 00000000000..9c238ce8bcc --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-9.c @@ -0,0 +1,163 @@ +/* Test to verify that --param ssa_name_def_chain_limit can be used to + limit the maximum number of SSA_NAME assignments the built-in code + follows to determine the variable value/string length. + { dg-do compile } + { dg-options "-O2 -Wall --param ssa-name-def-chain-limit=4 -fdump-tree-optimized" } */ + +void abort (void); +int sprintf (char * restrict, const char *restrict, ...); + +void sink (const char*, ...); + +const char a0[] = ""; +const char a1[] = "1"; +const char a2[] = "12"; +const char a3[] = "123"; +const char a4[] = "1234"; +const char a5[] = "12345"; +const char a6[] = "123456"; +const char a7[] = "1234567"; +const char a8[] = "12345678"; +const char a9[] = "123456789"; + +int i0, i1, i2, i3, i4, i5, i6, i7, i8; + +void g1 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + + sink (p0, p1); + + if (sprintf (d, "%s", p1) > 2) + abort (); +} + +void g2 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + + sink (p0, p1, p2); + + if (sprintf (d, "%s", p2) > 3) + abort (); +} + +void g3 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + const char *p3 = i3 ? p2 : a4; + + sink (p0, p1, p2, p3); + + if (sprintf (d, "%s", p3) > 4) + abort (); +} + +void g4 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + const char *p3 = i3 ? p2 : a4; + const char *p4 = i4 ? p3 : a5; + + sink (p0, p1, p2, p3, p4); + + // p4 below is the result of the following five PHI assignments + // and with the limit set to 4 the sprintf call result is not + // determined: + // iftmp.0_7 = PHI <&a0(2), &a1(3)> + // iftmp.2_8 = PHI + // iftmp.4_9 = PHI + // iftmp.6_10 = PHI + // iftmp.8_17 = PHI + // p4 = iftmp.8_17 + extern void keep_g4 (void); + if (sprintf (d, "%s", p4) > 5) + keep_g4 (); +} + +void g5 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + const char *p3 = i3 ? p2 : a4; + const char *p4 = i4 ? p3 : a5; + const char *p5 = i5 ? p4 : a6; + + sink (p0, p1, p2, p3, p4, p5); + + extern void keep_g5 (void); + if (sprintf (d, "%s", p5) > 6) + keep_g5 (); + + /* { dg-final { scan-tree-dump-times "keep_g5" 1 "optimized" } } */ +} + +void g6 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + const char *p3 = i3 ? p2 : a4; + const char *p4 = i4 ? p3 : a5; + const char *p5 = i5 ? p4 : a6; + const char *p6 = i6 ? p5 : a7; + + sink (p0, p1, p2, p3, p4, p5, p6); + + extern void keep_g6 (void); + if (sprintf (d, "%s", p6) > 7) + keep_g6 (); + + /* { dg-final { scan-tree-dump-times "keep_g6" 1 "optimized" } } */ +} + +void g7 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + const char *p3 = i3 ? p2 : a4; + const char *p4 = i4 ? p3 : a5; + const char *p5 = i5 ? p4 : a6; + const char *p6 = i6 ? p5 : a7; + const char *p7 = i7 ? p6 : a8; + + sink (p0, p1, p2, p3, p4, p5, p6, p7); + + extern void keep_g7 (void); + if (sprintf (d, "%s", p7) > 8) + keep_g7 (); + + /* { dg-final { scan-tree-dump-times "keep_g7" 1 "optimized" } } */ +} + +void g8 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + const char *p3 = i3 ? p2 : a4; + const char *p4 = i4 ? p3 : a5; + const char *p5 = i5 ? p4 : a6; + const char *p6 = i6 ? p5 : a7; + const char *p7 = i7 ? p6 : a8; + const char *p8 = i8 ? p7 : a9; + + sink (p0, p1, p2, p3, p4, p5, p6, p7, p8); + + extern void keep_g8 (void); + if (sprintf (d, "%s", p8) > 9) + keep_g8 (); + + /* { dg-final { scan-tree-dump-times "keep_g8" 1 "optimized" } } */ +} + +/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-5.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-5.c new file mode 100644 index 00000000000..becba05277b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-5.c @@ -0,0 +1,140 @@ +/* Test to verify that --param ssa_name_def_chain_limit can be used to + limit the maximum number of SSA_NAME assignments the built-in code + follows. + { dg-do compile } + { dg-options "-O2 -Wall -Wformat-truncation=2 --param ssa-name-def-chain-limit=4 -fdump-tree-optimized" } */ + +typedef __SIZE_TYPE__ size_t; + +int snprintf (char * restrict, size_t, const char *restrict, ...); + +void sink (const char*, ...); + +const char a0[] = ""; +const char a1[] = "1"; +const char a2[] = "12"; +const char a3[] = "123"; +const char a4[] = "1234"; +const char a5[] = "12345"; +const char a6[] = "123456"; +const char a7[] = "1234567"; +const char a8[] = "12345678"; +const char a9[] = "123456789"; + +int i0, i1, i2, i3, i4, i5, i6, i7, i8; + +void g1 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + + sink (p0, p1); + + snprintf (d, 1, "%s", p1); // { dg-warning "\\\[-Wformat-truncation" } +} + +void g2 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + + sink (p0, p1, p2); + + snprintf (d, 2, "%s", p2); // { dg-warning "\\\[-Wformat-truncation" } +} + +void g3 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + const char *p3 = i3 ? p2 : a4; + + sink (p0, p1, p2, p3); + + snprintf (d, 3, "%s", p3); // { dg-warning "\\\[-Wformat-truncation" } +} + +void g4 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + const char *p3 = i3 ? p2 : a4; + const char *p4 = i4 ? p3 : a5; + + sink (p0, p1, p2, p3, p4); + + // p4 below is the result of the following five PHI assignments + // and with the limit set to 4 the snprintf call is not diagnosed + // iftmp.0_7 = PHI <&a0(2), &a1(3)> + // iftmp.2_8 = PHI + // iftmp.4_9 = PHI + // iftmp.6_10 = PHI + // iftmp.8_17 = PHI + // p4 = iftmp.8_17 + snprintf (d, 4, "%s", p4); +} + +void g5 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + const char *p3 = i3 ? p2 : a4; + const char *p4 = i4 ? p3 : a5; + const char *p5 = i5 ? p4 : a6; + + sink (p0, p1, p2, p3, p4, p5); + + snprintf (d, 5, "%s", p5); +} + +void g6 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + const char *p3 = i3 ? p2 : a4; + const char *p4 = i4 ? p3 : a5; + const char *p5 = i5 ? p4 : a6; + const char *p6 = i6 ? p5 : a7; + + sink (p0, p1, p2, p3, p4, p5, p6); + + snprintf (d, 6, "%s", p6); +} + +void g7 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + const char *p3 = i3 ? p2 : a4; + const char *p4 = i4 ? p3 : a5; + const char *p5 = i5 ? p4 : a6; + const char *p6 = i6 ? p5 : a7; + const char *p7 = i7 ? p6 : a8; + + sink (p0, p1, p2, p3, p4, p5, p6, p7); + + snprintf (d, 7, "%s", p7); +} + +void g8 (char *d) +{ + const char *p0 = i0 ? a0 : a1; + const char *p1 = i1 ? p0 : a2; + const char *p2 = i2 ? p1 : a3; + const char *p3 = i3 ? p2 : a4; + const char *p4 = i4 ? p3 : a5; + const char *p5 = i5 ? p4 : a6; + const char *p6 = i6 ? p5 : a7; + const char *p7 = i7 ? p6 : a8; + const char *p8 = i8 ? p7 : a9; + + sink (p0, p1, p2, p3, p4, p5, p6, p7, p8); + + snprintf (d, 8, "%s", p8); +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-21.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-21.c new file mode 100644 index 00000000000..41f932a41a8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-21.c @@ -0,0 +1,94 @@ +/* PR tree-optimization/83431 -Wformat-truncation may incorrectly report + truncation + { dg-do compile } + { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */ + +typedef __SIZE_TYPE__ size_t; + +extern int snprintf (char*, size_t, const char*, ...); +extern char* strcpy (char*, const char*); + +struct S +{ + char a9[9]; + char a5[5]; + int x; +}; + + +void test_assign_nowarn (struct S* s) +{ + int i = 0; + + { + char a9[9] = "1234"; + snprintf (s[i].a5, sizeof (s[i].a5), "%s", a9); /* { dg-bogus "\\\[-Wformat-truncation]" } */ + } + + { + ++i; + char a8[8] = "123"; + snprintf (s[i].a5, sizeof (s[i].a5), "%s\n", a8); /* { dg-bogus "\\\[-Wformat-truncation]" } */ + } + + { + ++i; + char a7[7] = "12"; + snprintf (s[i].a5, sizeof (s[i].a5), "[%s]", a7); /* { dg-bogus "\\\[-Wformat-truncation]" } */ + } + + { + ++i; + char a6[6] = "1"; + snprintf (s[i].a5, sizeof (s[i].a5), "[%s]\n", a6); /* { dg-bogus "\\\[-Wformat-truncation]" } */ + } +} + + +void test_strcpy_nowarn (struct S* s) +{ + int i = 0; + + strcpy (s[i].a9, "1234"); + snprintf (s[i].a5, sizeof (s[i].a5), "%s", s[i].a9); + + ++i; + strcpy (s[i].a9, "123"); + snprintf (s[i].a5, sizeof (s[i].a5), "%s\n", s[i].a9); /* { dg-bogus "\\\[-Wformat-truncation]" } */ + + ++i; + strcpy (s[i].a9, "12"); + snprintf (s[i].a5, sizeof (s[i].a5), "[%s]", s[i].a9); /* { dg-bogus "\\\[-Wformat-truncation]" } */ + + ++i; + strcpy (s[i].a9, "1"); + snprintf (s[i].a5, sizeof (s[i].a5), "[%s]\n", s[i].a9); /* { dg-bogus "\\\[-Wformat-truncation]" } */ +} + + +void test_warn (struct S* s) +{ + int i = 0; + strcpy (s[i].a9, "12345678"); + snprintf (s[i].a5, sizeof (s[i].a5), "%s", s[i].a9); /* { dg-warning "'%s' directive output truncated writing 8 bytes into a region of size 5" } */ + + ++i; + strcpy (s[i].a9, "1234567"); + snprintf (s[i].a5, sizeof (s[i].a5), "%s", s[i].a9); /* { dg-warning "'%s' directive output truncated writing 7 bytes into a region of size 5" } */ + + ++i; + strcpy (s[i].a9, "123456"); + snprintf (s[i].a5, sizeof (s[i].a5), "%s", s[i].a9); /* { dg-warning "'%s' directive output truncated writing 6 bytes into a region of size 5" } */ + + ++i; + strcpy (s[i].a9, "12345"); + snprintf (s[i].a5, sizeof (s[i].a5), "%s", s[i].a9); /* { dg-warning "'snprintf' output truncated before the last format character" } */ + + ++i; + strcpy (s[i].a9, "1234"); + snprintf (s[i].a5, sizeof (s[i].a5), "%s\n", s[i].a9); /* { dg-warning "output truncated before the last format character" } */ + + ++i; + strcpy (s[i].a9, "123"); + snprintf (s[i].a5, sizeof (s[i].a5), ">%s<", s[i].a9); /* { dg-warning "output truncated before the last format character" } */ +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/dump-4.c b/gcc/testsuite/gcc.dg/tree-ssa/dump-4.c new file mode 100644 index 00000000000..9377ed4f420 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/dump-4.c @@ -0,0 +1,11 @@ +/* PR middle-end/87052 - STRING_CST printing incomplete in Gimple dumps + { dg-do compile } + { dg-options "-fdump-tree-original" } */ + +void* f (char *d, int c) +{ + return __builtin_memchr ("1\0\0", c, 4); +} + +/* Veriy the full string appears in the dump: + { dg-final { scan-tree-dump "\"1\\\\x00\\\\x00\"" "original" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr83501.c b/gcc/testsuite/gcc.dg/tree-ssa/pr83501.c index d8d3bf6039a..a301d0d2e2b 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr83501.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr83501.c @@ -11,4 +11,4 @@ void f (void) __builtin_abort (); } -/* { dg-final { scan-tree-dump-not "__builtin_strlen" "strlen" } } */ +/* { dg-final { scan-tree-dump-not "__builtin_strlen" "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/strlen-2.c b/gcc/testsuite/gcc.dg/tree-ssa/strlen-2.c index 1bca06fb1a4..079ee745a2c 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/strlen-2.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/strlen-2.c @@ -12,4 +12,4 @@ void f3 (void) f (__builtin_strlen (s)); } -/* { dg-final { scan-tree-dump-times "strlen" 0 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen" 0 "strlen1" } } */ diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 1c8df3d0a71..be7603a4c72 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -419,6 +419,7 @@ extern gimple_opt_pass *make_pass_omp_target_link (gcc::context *ctxt); extern gimple_opt_pass *make_pass_oacc_device_lower (gcc::context *ctxt); extern gimple_opt_pass *make_pass_omp_device_lower (gcc::context *ctxt); extern gimple_opt_pass *make_pass_object_sizes (gcc::context *ctxt); +extern gimple_opt_pass *make_pass_warn_printf (gcc::context *ctxt); extern gimple_opt_pass *make_pass_strlen (gcc::context *ctxt); extern gimple_opt_pass *make_pass_fold_builtins (gcc::context *ctxt); extern gimple_opt_pass *make_pass_post_ipa_warn (gcc::context *ctxt); diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index ef2b6ae65f2..5c5b83833c8 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -55,6 +55,12 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "attribs.h" #include "calls.h" +#include "cfgloop.h" +#include "tree-ssa-loop.h" +#include "tree-scalar-evolution.h" + +#include "vr-values.h" +#include "gimple-ssa-evrp-analyze.h" /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value is an index into strinfo vector, negative value stands for @@ -64,6 +70,9 @@ static vec ssa_ver_to_stridx; /* Number of currently active string indexes plus one. */ static int max_stridx; +/* Set to true to optimize, false when just checking. */ +static bool strlen_optimize; + /* String information record. */ struct strinfo { @@ -154,7 +163,8 @@ struct decl_stridxlist_map /* Hash table for mapping decls to a chained list of offset -> idx mappings. */ -static hash_map *decl_to_stridxlist_htab; +typedef hash_map decl_to_stridxlist_htab_t; +static decl_to_stridxlist_htab_t *decl_to_stridxlist_htab; /* Hash table mapping strlen (or strnlen with constant bound and return smaller than bound) calls to stridx instances describing @@ -604,14 +614,21 @@ set_endptr_and_length (location_t loc, strinfo *si, tree endptr) si->full_string_p = true; } -/* Return string length, or NULL if it can't be computed. */ +/* Return the string length, or NULL if it can't be computed. + The length may but need not be constant. Instead, it might be + the result of a strlen() call. */ static tree get_string_length (strinfo *si) { + /* If the length has already been computed return it if it's exact + (i.e., the string is nul-terminated at NONZERO_CHARS), or return + null if it isn't. */ if (si->nonzero_chars) return si->full_string_p ? si->nonzero_chars : NULL; + /* If the string is the result of one of the built-in calls below + attempt to compute the length from the call statement. */ if (si->stmt) { gimple *stmt = si->stmt, *lenstmt; @@ -702,6 +719,336 @@ get_string_length (strinfo *si) return si->nonzero_chars; } +/* Dump strlen data to FP for statement STMT. When non-null, RVALS + points to EVRP info and is used to dump strlen range for non-constant + results. */ + +DEBUG_FUNCTION void +dump_strlen_info (FILE *fp, gimple *stmt, const vr_values *rvals) +{ + if (stmt) + { + fprintf (fp, "\nDumping strlen pass data after "); + print_gimple_expr (fp, stmt, TDF_LINENO); + fputc ('\n', fp); + } + else + fprintf (fp, "\nDumping strlen pass data\n"); + + fprintf (fp, "max_stridx = %i\n", max_stridx); + fprintf (fp, "ssa_ver_to_stridx has %u elements\n", + ssa_ver_to_stridx.length ()); + fprintf (fp, "stridx_to_strinfo"); + if (stridx_to_strinfo) + { + fprintf (fp, " has %u elements\n", stridx_to_strinfo->length ()); + for (unsigned i = 0; i != stridx_to_strinfo->length (); ++i) + { + if (strinfo *si = (*stridx_to_strinfo)[i]) + { + if (!si->idx) + continue; + fprintf (fp, " idx = %i", si->idx); + if (si->ptr) + { + fprintf (fp, ", ptr = "); + print_generic_expr (fp, si->ptr); + } + fprintf (fp, ", nonzero_chars = "); + print_generic_expr (fp, si->nonzero_chars); + if (TREE_CODE (si->nonzero_chars) == SSA_NAME) + { + value_range_kind rng = VR_UNDEFINED; + wide_int min, max; + if (rvals) + { + const value_range *vr + = CONST_CAST (class vr_values *, rvals) + ->get_value_range (si->nonzero_chars); + rng = vr->kind (); + if (range_int_cst_p (vr)) + { + min = wi::to_wide (vr->min ()); + max = wi::to_wide (vr->max ()); + } + else + rng = VR_UNDEFINED; + } + else + rng = get_range_info (si->nonzero_chars, &min, &max); + + if (rng == VR_RANGE || rng == VR_ANTI_RANGE) + { + fprintf (fp, " %s[%llu, %llu]", + rng == VR_RANGE ? "" : "~", + (long long) min.to_uhwi (), + (long long) max.to_uhwi ()); + } + } + fprintf (fp, " , refcount = %i", si->refcount); + if (si->stmt) + { + fprintf (fp, ", stmt = "); + print_gimple_expr (fp, si->stmt, 0); + } + if (si->writable) + fprintf (fp, ", writable"); + if (si->full_string_p) + fprintf (fp, ", full_string_p"); + if (strinfo *next = get_next_strinfo (si)) + { + fprintf (fp, ", {"); + do + fprintf (fp, "%i%s", next->idx, next->first ? ", " : ""); + while ((next = get_next_strinfo (next))); + fprintf (fp, "}"); + } + fputs ("\n", fp); + } + } + } + else + fprintf (fp, " = null\n"); + + fprintf (fp, "decl_to_stridxlist_htab"); + if (decl_to_stridxlist_htab) + { + fputs ("\n", fp); + typedef decl_to_stridxlist_htab_t::iterator iter_t; + for (iter_t it = decl_to_stridxlist_htab->begin (); + it != decl_to_stridxlist_htab->end (); ++it) + { + tree decl = (*it).first; + stridxlist *list = &(*it).second; + fprintf (fp, " decl = "); + print_generic_expr (fp, decl); + if (list) + { + fprintf (fp, ", offsets = {"); + for (; list; list = list->next) + fprintf (fp, "%lli%s", (long long) list->offset, + list->next ? ", " : ""); + fputs ("}", fp); + } + fputs ("\n", fp); + } + } + else + fprintf (fp, " = null\n"); + + if (laststmt.stmt) + { + fprintf (fp, "laststmt = "); + print_gimple_expr (fp, laststmt.stmt, 0); + fprintf (fp, ", len = "); + print_generic_expr (fp, laststmt.len); + fprintf (fp, ", stridx = %i\n", laststmt.stridx); + } +} + +/* Attempt to determine the length of the string SRC. On success, store + the length in *PDATA and return true. Otherwise, return false. + VISITED is a bitmap of visited PHI nodes. RVALS points to EVRP info + and PSSA_DEF_MAX to an SSA_NAME assignment limit used to prevent runaway + recursion. */ + +static bool +get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited, + const vr_values *rvals, unsigned *pssa_def_max) +{ + int idx = get_stridx (src); + if (!idx) + { + if (TREE_CODE (src) == SSA_NAME) + { + gimple *def_stmt = SSA_NAME_DEF_STMT (src); + if (gimple_code (def_stmt) == GIMPLE_PHI) + { + if (!*visited) + *visited = BITMAP_ALLOC (NULL); + + if (!bitmap_set_bit (*visited, SSA_NAME_VERSION (src))) + return true; + + if (*pssa_def_max == 0) + return false; + + --*pssa_def_max; + + /* Iterate over the PHI arguments and determine the minimum + and maximum length/size of each and incorporate them into + the overall result. */ + gphi *phi = as_a (def_stmt); + for (unsigned i = 0; i != gimple_phi_num_args (phi); ++i) + { + tree arg = gimple_phi_arg_def (phi, i); + if (arg == gimple_phi_result (def_stmt)) + continue; + + c_strlen_data argdata = { }; + if (get_range_strlen_dynamic (arg, &argdata, visited, rvals, + pssa_def_max)) + { + /* Set the DECL of an unterminated array this argument + refers to if one hasn't been found yet. */ + if (!pdata->decl && argdata.decl) + pdata->decl = argdata.decl; + + if (!argdata.minlen + || (integer_zerop (argdata.minlen) + && integer_all_onesp (argdata.maxbound) + && integer_all_onesp (argdata.maxlen))) + { + /* Set the upper bound of the length to unbounded. */ + pdata->maxlen = build_all_ones_cst (size_type_node); + continue; + } + + /* Adjust the minimum and maximum length determined + so far and the upper bound on the array size. */ + if (!pdata->minlen + || tree_int_cst_lt (argdata.minlen, pdata->minlen)) + pdata->minlen = argdata.minlen; + if (!pdata->maxlen + || tree_int_cst_lt (pdata->maxlen, argdata.maxlen)) + pdata->maxlen = argdata.maxlen; + if (!pdata->maxbound + || (tree_int_cst_lt (pdata->maxbound, + argdata.maxbound) + && !integer_all_onesp (argdata.maxbound))) + pdata->maxbound = argdata.maxbound; + } + else + pdata->maxlen = build_all_ones_cst (size_type_node); + } + + return true; + } + } + + /* Return success regardless of the result and handle *PDATA + in the caller. */ + get_range_strlen (src, pdata, 1); + return true; + } + + if (idx < 0) + { + /* SRC is a string of constant length. */ + pdata->minlen = build_int_cst (size_type_node, ~idx); + pdata->maxlen = pdata->minlen; + pdata->maxbound = pdata->maxlen; + return true; + } + + if (strinfo *si = get_strinfo (idx)) + { + pdata->minlen = get_string_length (si); + if (!pdata->minlen + && si->nonzero_chars) + { + if (TREE_CODE (si->nonzero_chars) == INTEGER_CST) + pdata->minlen = si->nonzero_chars; + else if (TREE_CODE (si->nonzero_chars) == SSA_NAME) + { + const value_range *vr + = CONST_CAST (class vr_values *, rvals) + ->get_value_range (si->nonzero_chars); + if (vr->kind () == VR_RANGE + && range_int_cst_p (vr)) + { + pdata->minlen = vr->min (); + pdata->maxlen = vr->max (); + } + else + pdata->minlen = build_zero_cst (size_type_node); + } + else + pdata->minlen = build_zero_cst (size_type_node); + + tree base = si->ptr; + if (TREE_CODE (base) == ADDR_EXPR) + base = TREE_OPERAND (base, 0); + + HOST_WIDE_INT off; + poly_int64 poff; + base = get_addr_base_and_unit_offset (base, &poff); + if (base + && DECL_P (base) + && TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE + && TYPE_SIZE_UNIT (TREE_TYPE (base)) + && poff.is_constant (&off)) + { + tree basetype = TREE_TYPE (base); + tree size = TYPE_SIZE_UNIT (basetype); + ++off; /* Increment for the terminating nul. */ + pdata->maxlen = fold_build2 (MINUS_EXPR, size_type_node, size, + build_int_cst (size_type_node, off)); + pdata->maxbound = pdata->maxlen; + } + else + pdata->maxlen = build_all_ones_cst (size_type_node); + } + else if (TREE_CODE (pdata->minlen) == SSA_NAME) + { + const value_range *vr + = CONST_CAST (class vr_values *, rvals) + ->get_value_range (si->nonzero_chars); + if (vr->kind () == VR_RANGE + && range_int_cst_p (vr)) + { + pdata->minlen = vr->min (); + pdata->maxlen = vr->max (); + pdata->maxbound = pdata->maxlen; + } + else + { + pdata->minlen = build_zero_cst (size_type_node); + pdata->maxlen = build_all_ones_cst (size_type_node); + } + } + else + { + pdata->maxlen = pdata->minlen; + pdata->maxbound = pdata->minlen; + } + + return true; + } + + return false; +} + +/* Analogous to get_range_strlen but for dynamically created strings, + i.e., those created by calls to strcpy as opposed to just string + constants. + Try to obtain the range of the lengths of the string(s) referenced + by SRC, or the size of the largest array SRC refers to if the range + of lengths cannot be determined, and store all in *PDATA. RVALS + points to EVRP info. */ + +void +get_range_strlen_dynamic (tree src, c_strlen_data *pdata, + const vr_values *rvals) +{ + bitmap visited = NULL; + + unsigned limit = PARAM_VALUE (PARAM_SSA_NAME_DEF_CHAIN_LIMIT); + if (!get_range_strlen_dynamic (src, pdata, &visited, rvals, &limit)) + { + /* On failure extend the length range to an impossible maximum + (a valid MAXLEN must be less than PTRDIFF_MAX - 1). Other + members can stay unchanged regardless. */ + pdata->minlen = ssize_int (0); + pdata->maxlen = build_all_ones_cst (size_type_node); + } + else if (!pdata->minlen) + pdata->minlen = ssize_int (0); + + if (visited) + BITMAP_FREE (visited); +} + /* Invalidate string length information for strings whose length might change due to stores in stmt. */ @@ -4017,84 +4364,232 @@ is_char_type (tree type) && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node)); } +/* Check the built-in call at GSI for validity and optimize it. + Return true to let the caller advance *GSI to the statement + in the CFG and false otherwise. */ + +static bool +strlen_check_and_optimize_call (gimple_stmt_iterator *gsi, + const vr_values *rvals) +{ + gimple *stmt = gsi_stmt (*gsi); + + if (!flag_optimize_strlen + || !strlen_optimize + || !valid_builtin_call (stmt)) + { + /* When not optimizing we must be checking printf calls which + we do even for user-defined functions when they are declared + with attribute format. */ + handle_printf_call (gsi, rvals); + return true; + } + + tree callee = gimple_call_fndecl (stmt); + switch (DECL_FUNCTION_CODE (callee)) + { + case BUILT_IN_STRLEN: + case BUILT_IN_STRNLEN: + handle_builtin_strlen (gsi); + break; + case BUILT_IN_STRCHR: + handle_builtin_strchr (gsi); + break; + case BUILT_IN_STRCPY: + case BUILT_IN_STRCPY_CHK: + case BUILT_IN_STPCPY: + case BUILT_IN_STPCPY_CHK: + handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi); + break; + + case BUILT_IN_STRNCAT: + case BUILT_IN_STRNCAT_CHK: + handle_builtin_strncat (DECL_FUNCTION_CODE (callee), gsi); + break; + + case BUILT_IN_STPNCPY: + case BUILT_IN_STPNCPY_CHK: + case BUILT_IN_STRNCPY: + case BUILT_IN_STRNCPY_CHK: + handle_builtin_stxncpy (DECL_FUNCTION_CODE (callee), gsi); + break; + + case BUILT_IN_MEMCPY: + case BUILT_IN_MEMCPY_CHK: + case BUILT_IN_MEMPCPY: + case BUILT_IN_MEMPCPY_CHK: + handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi); + break; + case BUILT_IN_STRCAT: + case BUILT_IN_STRCAT_CHK: + handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi); + break; + case BUILT_IN_MALLOC: + case BUILT_IN_CALLOC: + handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi); + break; + case BUILT_IN_MEMSET: + if (handle_builtin_memset (gsi)) + return false; + break; + case BUILT_IN_MEMCMP: + if (handle_builtin_memcmp (gsi)) + return false; + break; + case BUILT_IN_STRCMP: + case BUILT_IN_STRNCMP: + if (handle_builtin_string_cmp (gsi)) + return false; + break; + default: + handle_printf_call (gsi, rvals); + break; + } + + return true; +} + +/* Handle an assignment statement at *GSI to a LHS of integral type. + If GSI's basic block needs clean-up of EH, set *CLEANUP_EH to true. */ + +static void +handle_integral_assign (gimple_stmt_iterator *gsi, bool *cleanup_eh) +{ + gimple *stmt = gsi_stmt (*gsi); + tree lhs = gimple_assign_lhs (stmt); + tree lhs_type = TREE_TYPE (lhs); + + enum tree_code code = gimple_assign_rhs_code (stmt); + if (code == COND_EXPR) + { + tree cond = gimple_assign_rhs1 (stmt); + enum tree_code cond_code = TREE_CODE (cond); + + if (cond_code == EQ_EXPR || cond_code == NE_EXPR) + fold_strstr_to_strncmp (TREE_OPERAND (cond, 0), + TREE_OPERAND (cond, 1), stmt); + } + else if (code == EQ_EXPR || code == NE_EXPR) + fold_strstr_to_strncmp (gimple_assign_rhs1 (stmt), + gimple_assign_rhs2 (stmt), stmt); + else if (gimple_assign_load_p (stmt) + && TREE_CODE (lhs_type) == INTEGER_TYPE + && TYPE_MODE (lhs_type) == TYPE_MODE (char_type_node) + && (TYPE_PRECISION (lhs_type) + == TYPE_PRECISION (char_type_node)) + && !gimple_has_volatile_ops (stmt)) + { + tree off = integer_zero_node; + unsigned HOST_WIDE_INT coff = 0; + int idx = 0; + tree rhs1 = gimple_assign_rhs1 (stmt); + if (code == MEM_REF) + { + idx = get_stridx (TREE_OPERAND (rhs1, 0)); + if (idx > 0) + { + strinfo *si = get_strinfo (idx); + if (si + && si->nonzero_chars + && TREE_CODE (si->nonzero_chars) == INTEGER_CST + && (wi::to_widest (si->nonzero_chars) + >= wi::to_widest (off))) + off = TREE_OPERAND (rhs1, 1); + else + /* This case is not useful. See if get_addr_stridx + returns something usable. */ + idx = 0; + } + } + if (idx <= 0) + idx = get_addr_stridx (rhs1, NULL_TREE, &coff); + if (idx > 0) + { + strinfo *si = get_strinfo (idx); + if (si + && si->nonzero_chars + && TREE_CODE (si->nonzero_chars) == INTEGER_CST) + { + widest_int w1 = wi::to_widest (si->nonzero_chars); + widest_int w2 = wi::to_widest (off) + coff; + if (w1 == w2 + && si->full_string_p) + { + if (dump_file && (dump_flags & TDF_DETAILS) != 0) + { + fprintf (dump_file, "Optimizing: "); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + } + + /* Reading the final '\0' character. */ + tree zero = build_int_cst (lhs_type, 0); + gimple_set_vuse (stmt, NULL_TREE); + gimple_assign_set_rhs_from_tree (gsi, zero); + *cleanup_eh + |= maybe_clean_or_replace_eh_stmt (stmt, + gsi_stmt (*gsi)); + stmt = gsi_stmt (*gsi); + update_stmt (stmt); + + if (dump_file && (dump_flags & TDF_DETAILS) != 0) + { + fprintf (dump_file, "into: "); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + } + } + else if (w1 > w2) + { + /* Reading a character before the final '\0' + character. Just set the value range to ~[0, 0] + if we don't have anything better. */ + wide_int min, max; + signop sign = TYPE_SIGN (lhs_type); + int prec = TYPE_PRECISION (lhs_type); + value_range_kind vr = get_range_info (lhs, &min, &max); + if (vr == VR_VARYING + || (vr == VR_RANGE + && min == wi::min_value (prec, sign) + && max == wi::max_value (prec, sign))) + set_range_info (lhs, VR_ANTI_RANGE, + wi::zero (prec), wi::zero (prec)); + } + } + } + } + + if (strlen_to_stridx) + { + tree rhs1 = gimple_assign_rhs1 (stmt); + if (stridx_strlenloc *ps = strlen_to_stridx->get (rhs1)) + strlen_to_stridx->put (lhs, stridx_strlenloc (*ps)); + } +} + /* Attempt to check for validity of the performed access a single statement at *GSI using string length knowledge, and to optimize it. If the given basic block needs clean-up of EH, CLEANUP_EH is set to true. */ static bool -strlen_check_and_optimize_stmt (gimple_stmt_iterator *gsi, bool *cleanup_eh) +check_and_optimize_stmt (gimple_stmt_iterator *gsi, bool *cleanup_eh, + const vr_values *rvals) { gimple *stmt = gsi_stmt (*gsi); if (is_gimple_call (stmt)) { - tree callee = gimple_call_fndecl (stmt); - if (valid_builtin_call (stmt)) - switch (DECL_FUNCTION_CODE (callee)) - { - case BUILT_IN_STRLEN: - case BUILT_IN_STRNLEN: - handle_builtin_strlen (gsi); - break; - case BUILT_IN_STRCHR: - handle_builtin_strchr (gsi); - break; - case BUILT_IN_STRCPY: - case BUILT_IN_STRCPY_CHK: - case BUILT_IN_STPCPY: - case BUILT_IN_STPCPY_CHK: - handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi); - break; - - case BUILT_IN_STRNCAT: - case BUILT_IN_STRNCAT_CHK: - handle_builtin_strncat (DECL_FUNCTION_CODE (callee), gsi); - break; - - case BUILT_IN_STPNCPY: - case BUILT_IN_STPNCPY_CHK: - case BUILT_IN_STRNCPY: - case BUILT_IN_STRNCPY_CHK: - handle_builtin_stxncpy (DECL_FUNCTION_CODE (callee), gsi); - break; - - case BUILT_IN_MEMCPY: - case BUILT_IN_MEMCPY_CHK: - case BUILT_IN_MEMPCPY: - case BUILT_IN_MEMPCPY_CHK: - handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi); - break; - case BUILT_IN_STRCAT: - case BUILT_IN_STRCAT_CHK: - handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi); - break; - case BUILT_IN_MALLOC: - case BUILT_IN_CALLOC: - handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi); - break; - case BUILT_IN_MEMSET: - if (handle_builtin_memset (gsi)) - return false; - break; - case BUILT_IN_MEMCMP: - if (handle_builtin_memcmp (gsi)) - return false; - break; - case BUILT_IN_STRCMP: - case BUILT_IN_STRNCMP: - if (handle_builtin_string_cmp (gsi)) - return false; - break; - default: - break; - } + if (!strlen_check_and_optimize_call (gsi, rvals)) + return false; } + else if (!flag_optimize_strlen || !strlen_optimize) + return true; else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt)) { + /* Handle non-clobbering assignment. */ tree lhs = gimple_assign_lhs (stmt); + tree lhs_type = TREE_TYPE (lhs); - if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs))) + if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (lhs_type)) { if (gimple_assign_single_p (stmt) || (gimple_assign_cast_p (stmt) @@ -4106,117 +4601,10 @@ strlen_check_and_optimize_stmt (gimple_stmt_iterator *gsi, bool *cleanup_eh) else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) handle_pointer_plus (gsi); } - else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (lhs))) - { - enum tree_code code = gimple_assign_rhs_code (stmt); - if (code == COND_EXPR) - { - tree cond = gimple_assign_rhs1 (stmt); - enum tree_code cond_code = TREE_CODE (cond); - - if (cond_code == EQ_EXPR || cond_code == NE_EXPR) - fold_strstr_to_strncmp (TREE_OPERAND (cond, 0), - TREE_OPERAND (cond, 1), stmt); - } - else if (code == EQ_EXPR || code == NE_EXPR) - fold_strstr_to_strncmp (gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt), stmt); - else if (gimple_assign_load_p (stmt) - && TREE_CODE (TREE_TYPE (lhs)) == INTEGER_TYPE - && TYPE_MODE (TREE_TYPE (lhs)) == TYPE_MODE (char_type_node) - && (TYPE_PRECISION (TREE_TYPE (lhs)) - == TYPE_PRECISION (char_type_node)) - && !gimple_has_volatile_ops (stmt)) - { - tree off = integer_zero_node; - unsigned HOST_WIDE_INT coff = 0; - int idx = 0; - tree rhs1 = gimple_assign_rhs1 (stmt); - if (code == MEM_REF) - { - idx = get_stridx (TREE_OPERAND (rhs1, 0)); - if (idx > 0) - { - strinfo *si = get_strinfo (idx); - if (si - && si->nonzero_chars - && TREE_CODE (si->nonzero_chars) == INTEGER_CST - && (wi::to_widest (si->nonzero_chars) - >= wi::to_widest (off))) - off = TREE_OPERAND (rhs1, 1); - else - /* This case is not useful. See if get_addr_stridx - returns something usable. */ - idx = 0; - } - } - if (idx <= 0) - idx = get_addr_stridx (rhs1, NULL_TREE, &coff); - if (idx > 0) - { - strinfo *si = get_strinfo (idx); - if (si - && si->nonzero_chars - && TREE_CODE (si->nonzero_chars) == INTEGER_CST) - { - widest_int w1 = wi::to_widest (si->nonzero_chars); - widest_int w2 = wi::to_widest (off) + coff; - if (w1 == w2 - && si->full_string_p) - { - if (dump_file && (dump_flags & TDF_DETAILS) != 0) - { - fprintf (dump_file, "Optimizing: "); - print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); - } - - /* Reading the final '\0' character. */ - tree zero = build_int_cst (TREE_TYPE (lhs), 0); - gimple_set_vuse (stmt, NULL_TREE); - gimple_assign_set_rhs_from_tree (gsi, zero); - *cleanup_eh - |= maybe_clean_or_replace_eh_stmt (stmt, - gsi_stmt (*gsi)); - stmt = gsi_stmt (*gsi); - update_stmt (stmt); - - if (dump_file && (dump_flags & TDF_DETAILS) != 0) - { - fprintf (dump_file, "into: "); - print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); - } - } - else if (w1 > w2) - { - /* Reading a character before the final '\0' - character. Just set the value range to ~[0, 0] - if we don't have anything better. */ - wide_int min, max; - tree type = TREE_TYPE (lhs); - enum value_range_kind vr - = get_range_info (lhs, &min, &max); - if (vr == VR_VARYING - || (vr == VR_RANGE - && min == wi::min_value (TYPE_PRECISION (type), - TYPE_SIGN (type)) - && max == wi::max_value (TYPE_PRECISION (type), - TYPE_SIGN (type)))) - set_range_info (lhs, VR_ANTI_RANGE, - wi::zero (TYPE_PRECISION (type)), - wi::zero (TYPE_PRECISION (type))); - } - } - } - } - - if (strlen_to_stridx) - { - tree rhs1 = gimple_assign_rhs1 (stmt); - if (stridx_strlenloc *ps = strlen_to_stridx->get (rhs1)) - strlen_to_stridx->put (lhs, stridx_strlenloc (*ps)); - } - } - else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs)) + else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (lhs_type)) + /* Handle assignment to a character. */ + handle_integral_assign (gsi, cleanup_eh); + else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs)) { tree type = TREE_TYPE (lhs); if (TREE_CODE (type) == ARRAY_TYPE) @@ -4312,12 +4700,18 @@ class strlen_dom_walker : public dom_walker { public: strlen_dom_walker (cdi_direction direction) - : dom_walker (direction), m_cleanup_cfg (false) + : dom_walker (direction), + evrp (false), + m_cleanup_cfg (false) {} virtual edge before_dom_children (basic_block); virtual void after_dom_children (basic_block); + /* EVRP analyzer used for printf argument range processing, and + to track strlen results across integer variable assignments. */ + evrp_range_analyzer evrp; + /* Flag that will trigger TODO_cleanup_cfg to be returned in strlen execute function. */ bool m_cleanup_cfg; @@ -4329,6 +4723,8 @@ public: edge strlen_dom_walker::before_dom_children (basic_block bb) { + evrp.enter (bb); + basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb); if (dombb == NULL) @@ -4402,8 +4798,16 @@ strlen_dom_walker::before_dom_children (basic_block bb) /* Attempt to optimize individual statements. */ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); ) - if (strlen_check_and_optimize_stmt (&gsi, &cleanup_eh)) - gsi_next (&gsi); + { + gimple *stmt = gsi_stmt (gsi); + + /* First record ranges generated by this statement so they + can be used by printf argument processing. */ + evrp.record_ranges_from_stmt (stmt, false); + + if (check_and_optimize_stmt (&gsi, &cleanup_eh, evrp.get_vr_values ())) + gsi_next (&gsi); + } if (cleanup_eh && gimple_purge_dead_eh_edges (bb)) m_cleanup_cfg = true; @@ -4420,6 +4824,8 @@ strlen_dom_walker::before_dom_children (basic_block bb) void strlen_dom_walker::after_dom_children (basic_block bb) { + evrp.leave (bb); + if (bb->aux) { stridx_to_strinfo = ((vec *) bb->aux); @@ -4437,39 +4843,13 @@ strlen_dom_walker::after_dom_children (basic_block bb) } } -/* Main entry point. */ - namespace { -const pass_data pass_data_strlen = -{ - GIMPLE_PASS, /* type */ - "strlen", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - TV_TREE_STRLEN, /* tv_id */ - ( PROP_cfg | PROP_ssa ), /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_strlen : public gimple_opt_pass +static unsigned int +printf_strlen_execute (function *fun, bool warn_only) { -public: - pass_strlen (gcc::context *ctxt) - : gimple_opt_pass (pass_data_strlen, ctxt) - {} + strlen_optimize = !warn_only; - /* opt_pass methods: */ - virtual bool gate (function *) { return flag_optimize_strlen != 0; } - virtual unsigned int execute (function *); - -}; // class pass_strlen - -unsigned int -pass_strlen::execute (function *fun) -{ gcc_assert (!strlen_to_stridx); if (warn_stringop_overflow || warn_stringop_truncation) strlen_to_stridx = new hash_map (); @@ -4479,10 +4859,17 @@ pass_strlen::execute (function *fun) calculate_dominance_info (CDI_DOMINATORS); + bool use_scev = optimize > 0 && flag_printf_return_value; + if (use_scev) + { + loop_optimizer_init (LOOPS_NORMAL); + scev_initialize (); + } + /* String length optimization is implemented as a walk of the dominator tree and a forward walk of statements within each block. */ strlen_dom_walker walker (CDI_DOMINATORS); - walker.walk (fun->cfg->x_entry_block_ptr); + walker.walk (ENTRY_BLOCK_PTR_FOR_FN (fun)); ssa_ver_to_stridx.release (); strinfo_pool.release (); @@ -4503,11 +4890,113 @@ pass_strlen::execute (function *fun) strlen_to_stridx = NULL; } + if (use_scev) + { + scev_finalize (); + loop_optimizer_finalize (); + } + + /* Clean up object size info. */ + fini_object_sizes (); + return walker.m_cleanup_cfg ? TODO_cleanup_cfg : 0; } +/* This file defines two passes: one for warnings that runs only when + optimization is disabled, and another that implements optimizations + and also issues warnings. */ + +const pass_data pass_data_warn_printf = +{ + GIMPLE_PASS, /* type */ + "warn-printf", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + /* Normally an optimization pass would require PROP_ssa but because + this pass runs early, with no optimization, to do sprintf format + checking, it only requires PROP_cfg. */ + PROP_cfg, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_warn_printf : public gimple_opt_pass +{ +public: + pass_warn_printf (gcc::context *ctxt) + : gimple_opt_pass (pass_data_warn_printf, ctxt) + {} + + virtual bool gate (function *); + virtual unsigned int execute (function *fun) + { + return printf_strlen_execute (fun, true); + } +}; + + +/* Return true to run the warning pass only when not optimizing and + iff either -Wformat-overflow or -Wformat-truncation is specified. */ + +bool +pass_warn_printf::gate (function *) +{ + return !optimize && (warn_format_overflow > 0 || warn_format_trunc > 0); +} + +const pass_data pass_data_strlen = +{ + GIMPLE_PASS, /* type */ + "strlen", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_TREE_STRLEN, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_strlen : public gimple_opt_pass +{ +public: + pass_strlen (gcc::context *ctxt) + : gimple_opt_pass (pass_data_strlen, ctxt) + {} + + opt_pass * clone () { return new pass_strlen (m_ctxt); } + + virtual bool gate (function *); + virtual unsigned int execute (function *fun) + { + return printf_strlen_execute (fun, false); + } +}; + +/* Return true to run the pass only when the sprintf and/or strlen + optimizations are enabled and -Wformat-overflow or -Wformat-truncation + are specified. */ + +bool +pass_strlen::gate (function *) +{ + return ((warn_format_overflow > 0 + || warn_format_trunc > 0 + || flag_optimize_strlen > 0 + || flag_printf_return_value) + && optimize > 0); +} + } // anon namespace +gimple_opt_pass * +make_pass_warn_printf (gcc::context *ctxt) +{ + return new pass_warn_printf (ctxt); +} + gimple_opt_pass * make_pass_strlen (gcc::context *ctxt) { diff --git a/gcc/tree-ssa-strlen.h b/gcc/tree-ssa-strlen.h index 395c74e88e1..4d43fc65e9e 100644 --- a/gcc/tree-ssa-strlen.h +++ b/gcc/tree-ssa-strlen.h @@ -25,4 +25,11 @@ extern bool is_strlen_related_p (tree, tree); extern bool maybe_diag_stxncpy_trunc (gimple_stmt_iterator, tree, tree); extern tree set_strlen_range (tree, wide_int, wide_int, tree = NULL_TREE); +struct c_strlen_data; +class vr_values; +extern void get_range_strlen_dynamic (tree , c_strlen_data *, const vr_values *); + +/* APIs internal to strlen pass. Defined in in gimple-ssa-sprintf.c. */ +extern bool handle_printf_call (gimple_stmt_iterator *, const vr_values *); + #endif // GCC_TREE_SSA_STRLEN_H diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 4145bcc83a9..5ec4d17f23b 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -369,7 +369,7 @@ value_range_base::singleton_p (tree *result) const tree value_range_base::type () const { - gcc_assert (m_min || undefined_p ()); + gcc_assert (m_min); return TREE_TYPE (min ()); } diff --git a/gcc/vr-values.c b/gcc/vr-values.c index 6f9a3612931..96c764c987b 100644 --- a/gcc/vr-values.c +++ b/gcc/vr-values.c @@ -234,7 +234,7 @@ vr_values::update_value_range (const_tree var, value_range *new_vr) called, if we are anyway, keep it VARYING. */ if (old_vr->varying_p ()) { - new_vr->set_varying (new_vr->type ()); + new_vr->set_varying (TREE_TYPE (var)); is_new = false; } else if (new_vr->undefined_p ()) -- 2.30.2