On Thu, Jul 11, 2019 at 1:54 AM Martin Sebor <mse...@gmail.com> wrote: > > On 7/2/19 4:38 PM, Jeff Law wrote: > > On 7/1/19 7:47 PM, Martin Sebor wrote: > >> Attached is a more complete solution that fully resolves the bug > >> report by avoiding a warning in cases like: > >> > >> char a[32], b[8]; > >> > >> void f (void) > >> { > >> if (strlen (a) < sizeof b - 2) > >> snprintf (b, sizeof b, "b=%s", a); // no -Wformat-truncation > >> } > >> > >> It does that by having get_range_strlen_dynamic use the EVRP > >> information for non-constant strlen calls: EVRP has recorded > >> that the result is less sizeof b - 2 and so the function > >> returns this limited range of lengths to snprintf which can > >> then avoid warning. It also improves the checking and can > >> find latent bugs it missed before (like the off-by-one in > >> print-rtl.c). > >> > >> Besides improving the accuracy of the -Wformat-overflow and > >> truncation warnings this can also result in better code. > >> So far this only benefits snprintf but there may be other > >> opportunities to string functions as well (e.g., strcmp or > >> memcmp). > >> > >> Jeff, I looked into your question/suggestion for me last week > >> when we spoke, to introduce some sort of a recursion limit for > >> get_range_strlen_dynamic. It's easily doable but before we go > >> down that path I did some testing to see how bad it can get and > >> to compare it with get_range_strlen. Here are the results for > >> a few packages. The dept is the maximum recursion depth, success > >> and fail are the numbers of successful and failed calls to > >> the function: > >> > >> binutils-gdb: > >> depth success fail > >> get_range_strlen: 319 8302 21621 > >> get_range_strlen_dynamic: 41 1503 161 > >> gcc: > >> get_range_strlen: 46 7211 11365 > >> get_range_strlen_dynamic: 23 10272 12 > >> glibc: > >> get_range_strlen: 76 2840 11422 > >> get_range_strlen_dynamic: 51 1186 46 > >> elfutils: > >> get_range_strlen: 33 1198 2516 > >> get_range_strlen_dynamic: 31 685 36 > >> kernel: > >> get_range_strlen: 25 5299 11698 > >> get_range_strlen_dynamic: 31 9911 122 > >> > >> Except the first case of get_range_strlen (I haven't looked into > >> it yet), it doesn't seem too bad, and with just one exception it's > >> better than get_range_strlen. Let me know if you think it's worth > >> adding a parameter (I assume we'd use it for both functions) and > >> what to set it to. > >> > >> On 6/11/19 5:26 PM, Martin Sebor wrote: > >>> The sprintf and strlen passes both work with strings but > >>> run independently of one another and don't share state. As > >>> a result, lengths of strings dynamically created by functions > >>> that are available to the strlen pass are not available to > >>> sprintf. Conversely, lengths of strings formatted by > >>> the sprintf functions are not made available to the strlen > >>> pass. The result is less efficient code, poor diagnostics, > >>> and ultimately less than optimal user experience. > >>> > >>> The attached patch is the first step toward rectifying this > >>> design problem. It integrates the two passes into one and > >>> exposes the string length data managed by the strlen pass to > >>> the sprintf "module." (It does not expose any sprintf data > >>> to the strlen pass yet.) > >>> > >>> The sprintf pass invocations in passes.def have been replaced > >>> with those of strlen. The first "early" invocation is only > >>> effective for the sprintf module to enable warnings without > >>> optimization. The second invocation is "late" and enables > >>> both warnings and the sprintf and strlen optimizations unless > >>> explicitly disabled via -fno-optimize-strlen. > >>> > >>> Since the strlen optimization is the second invocation of > >>> the pass tests that scan the strlen dump have been adjusted > >>> to look for the "strlen2" dump file. > >>> > >>> The changes in the patch are mostly mechanical. The one new > >>> "feature" worth calling out is the get_range_strlen_dynamic > >>> function. It's analogous to get_range_strlen in gimple-fold.c > >>> except that it makes use of the strlen "dynamically" obtained > >>> string length info. In cases when the info is not available > >>> the former calls the latter. > >>> > >>> The other new functions in tree-ssa-strlen.c are > >>> check_and_optimize_call and handle_integral_assign: I added > >>> them only to keep the check_and_optimize_stmt function from > >>> getting excessively long and hard to follow. Otherwise, > >>> the code in the functions is unchanged. > >>> > >>> There are a number of further enhancements to consider as > >>> the next steps: > >>> * enhance the strlen module to determine string length range > >>> information from integer variable to which it was previously > >>> assigned (necessary to fully resolve pr83431 and pr90625), > >>> * make the sprintf/snprintf string length results directly > >>> available to the strlen module, > >>> * enhance the sprintf module to optimize snprintf(0, 0, fmt) > >>> calls with fmt strings consisting solely of plain characters > >>> and %s directives to series of strlen calls on the arguments, > >>> * and more. > >>> > >>> Martin > >> > >> > >> gcc-83431.diff > >> > >> 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-ssa-strlen.c (strlen_optimize): New variable. > >> (get_string_length): Add comments. > >> (get_range_strlen_dynamic): New functions. > >> (check_and_optimize_call): New function. > >> (handle_integral_assign): New function. > >> (strlen_check_and_optimize_stmt): Rename... > >> (check_and_optimize_stmt): ...to this. Factor code out into > >> 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. > >> (pass_data_strlen): Remove property not satisfied during an early run. > >> (pass_strlen::do_optimize): New data member. > >> (pass_strlen::set_pass_param): New member function. > >> (pass_strlen::gate): Update to handle printf calls. > >> (pass_strlen::execute): Initialize loop and scev optimizers. > >> (dump_strlen_info): New function. > >> * tree-ssa-strlen.h (get_range_strlen_dynamic): Declare. > >> (handle_printf_call): Same. > >> > >> gcc/testsuite/ChangeLog: > >> > >> PR c++/83431 > >> * gcc.dg/strlenopt-63.c: New test. > >> * 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-sprintf-warn-21.c: New test. > >> * gcc.dg/tree-ssa/dump-4.c: New test. > >> * gcc.dg/tree-ssa/pr83501.c: Adjust pass name. > > So if I'm reading things correctly, it appears gimple-ssa-sprintf.c is > > no longer a distinct pass. Instead it co-exists with the strlen pass. > > Right? > > Yes. strlen just calls into sprintf to handle the calls. > > >> diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c > >> index a0934bcaf87..b05e4050f1d 100644 > >> --- a/gcc/gimple-ssa-sprintf.c > >> +++ b/gcc/gimple-ssa-sprintf.c > >> @@ -683,7 +618,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 class vr_values *vr_values); > > FWIW, I think this is something *I* could do a lot better at. > > Specifically I think we're not supposed to be writing the "class" here > > and I'm not as good as I should be with marking things const. Thanks > > for cleaning up my lack of consts. > > I think you did the best you could given the APIs you had to work > with There's still plenty of room to improve const-correctness but > it involves changing other APIs outsid strlen/sprintf. > > >> diff --git a/gcc/passes.def b/gcc/passes.def > >> index 9a5b0cd554a..637e228f988 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_strlen, false); > > So this is something we discussed a bit on the phone. This is very > > early in the pipeline -- before we've gone into SSA form. > > > > I'm a bit concerned that we're running strlen that early without some > > kind of auditing of whether or not the strlen pass can safely run that > > early. Similarly have we done any review for issues that might arise > > from running strlen more than once? I guess in some small way > > encapsulating the state into a class like my unsubmitted patch does > > would help there. > > The strlen optimization machinery only runs once. The code avoids > running it when the pass is invoked early and only calls into sprintf > to do format checking. > > > > > More generally I think we concluded that the placement of sprintf this > > early was driven by the early placement of walloca. I don't want to > > open a huge can of worms here, but do we really need to run this early > > in the pipeline? > > We decided to run it early when optimization is disabled because > there's a good amount of code that can be checked even without > ranges and string lengths (especially at the conservative level > 2 setting when we consider the largest integers and array sizes > instead of values or string lengths). > > For example, this is diagnosed for the potential buffer overflow > at -Wformat-overflow=2 even without optimization: > > char a[8], s[4]; > > void f (int i) > { > __builtin_sprintf (a, "%s = %i", s, i); > } > > warning: ā%iā directive writing between 1 and 11 bytes into a region > of size between 2 and 5 [-Wformat-overflow=] > > > >> diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c > >> index 74cd6c44874..89932713476 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" > > Nit: Drop the extra newline. > > > >> @@ -604,14 +614,19 @@ 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 constant string length, or NULL if it can't be computed. > >> */> > >> 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; > > IIUC get_string_length could return a non-constant expression that gives > > the runtime length of a string. So I think the comment change is a bit > > misleading. > > Yes, good catch, thanks! > > > Nit: Use NULL rather than null. I think this happens in more than one > > place in your patch. Similarly I think we generally use NUL rather than > > nul when referring to a single character. > The term is a "null pointer." NULL is a C macro that has in C++ 11 > been superseded by nullptr. I don't mind using NUL character but > I also don't think it matters. No one will be confused about what > either means. > > >> +/* 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. > >> */ > >> + > >> +static bool > >> +get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited, > >> + const vr_values *rvals) > > [ ... ] > > We've already touched on the need to limit the backwards walk out of > > this code. Limiting based on the product of # phi args * number of phis > > visited, recursion depth, or number of SSA_NAME_DEF_STMTs visited all > > seem reasonable to me. > > > > I do think Richi's suggestion for figuring out a suitable inflection > > point is reasonable. > > It's easy enough to add here. But I know I've introduced other > algorithms that recurse on SSA_NAME_DEF_STMT, and I'm quite sure > others predate those. To make a difference I think we need to > review at least the one most likely to be exposed to this problem > and introduce the same limit there. I could probably fix the ones > I wrote reasonably quickly, but making the change to the others > would be much more of a project. I looked to see how pervasive > this might be and here is just a small sampling of things that > jumped out at me in a quick grep search: > > * compute_builtin_object_size (for _FORTIFY_SOURCE) > * compute_objsize (for -Wstringop-overflow) > * get_range_strlen > * maybe_fold_{and,or}_comparisons in gimple-fold.c > * -Warray-bounds (computing an offset into an object) > * -Wrestrict (computing an offset into an object) > * -Wreturn-local-addr (is_addr_local) > * -Wuninitialized (collect_phi_def_edges)
I don't see the recursion in maybe_fold_{and,or}_comparisons. The others all smell like they might be yours ;) (besides object-size maybe but that one is limited by having a cache - hopefully also used when not used in the compute-everything mode). > Given how wide-spread this technique seems to be, if the recursion > is in fact a problem it's just as likely (if not more) to come up > in the folder or in BOS or some other place as it is here. So if > it needs fixing it seems it should be done as its own project and > everywhere (or as close as we can get), and not as part of this > integration. It's never an excuse to add new cases though and adding a limit is _really_ simple. Richard. > > + if (strinfo *si = get_strinfo (idx)) > >> + { > >> + pdata->minlen = get_string_length (si); > >> + if (!pdata->minlen > >> + && si->nonzero_chars) > > Nit: No need for a line break in that conditional. > > > > > > > >> + > >> +/* 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 ARG, or the size of the largest array ARG 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) > > I think you need to s/ARG/SRC/ in the function comment since SRC is the > > name of the parameter. > > Yes, thanks. > > > > >> @@ -3703,84 +4031,231 @@ fold_strstr_to_strncmp (tree rhs1, tree rhs2, > >> gimple *stmt) > >> } > >> } > >> > >> +/* 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 > >> +check_and_optimize_call (gimple_stmt_iterator *gsi, const vr_values > >> *rvals) > > It was suggested that perhaps we should prefix this call name, but I > > think the better solution might be to classify the pass and make this a > > member function. That would seem to naturally fall to me since I've got > > a classification patch for this code from last year that I could easily > > update after your patch. > > Well, sure. The whole pass can be a class (or a set of classes). > It began as C code and then C++ started to slowly and organically > creep in. There are many other nice improvements we could make > by putting C++ to better use. One very simple one I'd like is > moving local variable declarations to the point of their > initialization. Making the APIs const-correct would also improve > readability. But I've resisted making these changes because I > know people are sensitive to too much churn. If you think it's > a good idea for me to make these changes let me know. I'd be > happy to do it, just separately from this integration. > > >> +{ > >> + 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; > >> + } > > Shouldn't the guard here be similar, if not the same as the gate for the > > old sprintf pass? Which was: > > > >> 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); > >> -} > > This test is now integrated into pass_strlen::gate so the guard > above is only entered when the pass is running early (i.e., at > -O0) or when the strlen optimization is disabled. Otherwise > there's another call to handle_printf_call in the big switch > statement in check_and_optimize_call. > > >> @@ -4119,7 +4504,10 @@ const pass_data pass_data_strlen = > >> "strlen", /* name */ > >> OPTGROUP_NONE, /* optinfo_flags */ > >> TV_TREE_STRLEN, /* tv_id */ > >> - ( PROP_cfg | PROP_ssa ), /* properties_required */ > >> + /* Normally the pass would require PROP_ssa but because it also > >> + 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 */ > >> @@ -4128,20 +4516,50 @@ const pass_data pass_data_strlen = > > So the question I'd come back to is what are we capturing with the > > instance that runs before we're in SSA form and can we reasonably catch > > that stuff after going into SSA form? > > > > It may be that we went through this at the initial submission of the > > sprintf patches. I simply can't remember. > > Please see my answer + example above. > > >> /* opt_pass methods: */ > >> - virtual bool gate (function *) { return flag_optimize_strlen != 0; } > >> + > >> + opt_pass * clone () { > >> + return new pass_strlen (m_ctxt); > >> + } > > Nit. I think this is trivial enough to just have on a single line and > > is generally consistent with other passes. > > > > > >> + > >> + virtual bool gate (function *); > >> virtual unsigned int execute (function *); > >> > >> + void set_pass_param (unsigned int n, bool param) > >> + { > >> + gcc_assert (n == 0); > >> + do_optimize = param; > >> + } > >> }; // class pass_strlen > >> > >> + > >> +bool > >> +pass_strlen::gate (function *) > >> +{ > >> + /* Run the pass iff -Warn-format-overflow or -Warn-format-truncation > > Aren't these Wformat-overflow and Wformat-trunction? > > Yes, thanks. > > > > > > >> + 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_optimize_strlen > 0 > >> + || flag_printf_return_value) > >> + && (optimize > 0) == do_optimize); > >> +} > > Ah, this is where the sprintf gateing clause went. > > > > > > > >> + > >> unsigned int > >> pass_strlen::execute (function *fun) > >> { > >> + strlen_optimize = do_optimize; > >> + > >> gcc_assert (!strlen_to_stridx); > >> if (warn_stringop_overflow || warn_stringop_truncation) > >> strlen_to_stridx = new hash_map<tree, stridx_strlenloc> (); > >> @@ -4151,10 +4569,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 (); > >> @@ -4175,6 +4600,15 @@ 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; > >> } > > Is scev really that useful here? If it is, fine, if not I'd rather not > > pay the price to set it up. > > It was introduced by Aldy to fix PR 85598. > > > > > My brain is turning to mush, so I think I'm going to need to do another > > iteration over this patch. > > I want to respond because it's been a while but I'll post an updated > patch later this week. In the meantime, if you have more comments > on the rest of it please send them my way. > > Thanks > Martin