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

Reply via email to