[PATCH][Middle-end][version 2]2nd patch of PR78809 and PR83026

Richard Biener rguenther@suse.de
Mon Jan 15 08:56:00 GMT 2018


On Fri, 12 Jan 2018, Jeff Law wrote:

> On 12/21/2017 02:25 PM, Qing Zhao wrote:
> > Hi, 
> > 
> > I updated my patch based on all your comments. 
> > 
> > the major changes are the following:
> > 
> > 	1. replace the candidate calls with __builtin_str(n)cmp_eq instead of __builtin_memcmp_eq;
> >             in builtins.c,  when expanding the new __builtin_str(n)cmp_eq call, expand them first as
> >             __builtin_memcmp_eq, if Not succeed,  change the call back to __builtin_str(n)cmp.
> > 	2. change the call to “get_range_strlen” with “compute_objsize”.
> Please read the big comment before compute_objsize.  If you are going to
> use it to influence code generation or optimization, then you're most
> likely doing something wrong.
> 
> compute_objsize can return an estimate in some circumstances.
> 
> 
> > 	3. add the missing case for equality checking with zero;
> > 	4. adjust the new testing case for PR83026; add a new testing case for the missing case added in 3.
> > 	5. update “uhwi” to “shwi” for where it needs;
> > 	6. some other minor format changes.
> > 
> > the changes are retested on x86 and aarch64, bootstrapped and regression tested. no issue.
> > 
> > Okay for trunk?
> > 
> > thanks.
> > 
> > Qing
> > 
> > Please see the updated patch:
> > 
> > gcc/ChangeLog:
> > 
> > +2017-12-21  Qing Zhao  <qing.zhao@oracle.com>
> > +
> > +	PR middle-end/78809
> > +	PR middle-end/83026
> > +	* builtins.c (expand_builtin): Add the handling of BUILT_IN_STRCMP_EQ
> > +	and BUILT_IN_STRNCMP_EQ.
> > +	* builtins.def: Add new builtins BUILT_IN_STRCMP_EQ and
> > +	BUILT_IN_STRNCMP_EQ.
> > +	* tree-ssa-strlen.c (compute_string_length): New function.
> > +	(handle_builtin_string_cmp): New function to handle calls to
> > +	string compare functions.
> > +	(strlen_optimize_stmt): Add handling to builtin string compare
> > +	calls. 
> > +	* tree.c (build_common_builtin_nodes): Add new defines of
> > +	BUILT_IN_STRNCMP_EQ and BUILT_IN_STRCMP_EQ.
> > +
> > gcc/testsuite/ChangeLog
> > 
> > +2017-12-21  Qing Zhao  <qing.zhao@oracle.com> 
> > +
> > +	PR middle-end/78809
> > +	* gcc.dg/strcmpopt_2.c: New testcase.
> > +	* gcc.dg/strcmpopt_3.c: New testcase.
> > +
> > +	PR middle-end/83026
> > +	* gcc.dg/strcmpopt_3.c: New testcase.
> What I don't like here is the introduction of STRCMP_EQ and STRNCMP_EQ.
> ISTM that if you're going to introduce those new builtins, then you have
> to audit all the code that runs between their introduction into the IL
> and when you expand them to ensure they're handled properly.
> 
> All you're really doing is carrying along a status bit about what
> tree-ssa-strlen did.  So you could possibly store that status bit somewhere.
> 
> The concern with both is that something later invalidates the analysis
> you've done.  I'm having a hard time coming up with a case where this
> could happen, but I'm definitely concerned about this possibility.
> Though I feel it's more likely to happen if we store a status bit vs
> using STRCMP_EQ STRNCMP_EQ.
> 
> [ For example, we have two calls with the same arguments, but one feeds
> an equality test, the other does not.  If we store a status bit that one
> could be transformed, but then we end up CSE-ing the two calls, the
> status bit would be incorrect because one of the calls did not feed an
> equality test.  Hmmm. ]
> 
> 
> 
> 
> > diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
> > index 94f20ef..57563ef 100644
> > --- a/gcc/tree-ssa-strlen.c
> > +++ b/gcc/tree-ssa-strlen.c
> > @@ -2540,6 +2540,216 @@ handle_builtin_memcmp (gimple_stmt_iterator *gsi)
> >    return false;
> >  }
> >  
> > +/* Given an index to the strinfo vector, compute the string length for the
> > +   corresponding string. Return -1 when unknown.  */
> > + 
> > +static HOST_WIDE_INT 
> > +compute_string_length (int idx)
> > +{
> > +  HOST_WIDE_INT string_leni = -1; 
> > +  gcc_assert (idx != 0);
> > +
> > +  if (idx < 0)
> > +    string_leni = ~idx;
> So it seems to me you should just
>   return ~idx;
> 
> Then appropriately simplify the rest of the code.
> 
> > +
> > +/* Handle a call to strcmp or strncmp. When the result is ONLY used to do 
> > +   equality test against zero:
> > +
> > +   A. When both arguments are constant strings and it's a strcmp:
> > +      * if the length of the strings are NOT equal, we can safely fold the call
> > +        to a non-zero value.
> > +      * otherwise, do nothing now.
> I'm guessing your comment needs a bit of work.  If both arguments are
> constant strings, then we can just use the host str[n]cmp to fold the
> str[n]cmp to a constant.  Presumably this is handled earlier :-)
> 
> So what I'm guessing is you're really referring to the case where the
> lengths are known constants, even if the contents of the strings
> themselves are not.  In that case if its an equality comparison, then
> you can fold to a constant.  Otherwise we do nothing.  So I think the
> comment needs updating here.
> 
> 
> 
> 
> 
> 
> > +  
> > +   B. When one of the arguments is constant string, try to replace the call with
> > +   a __builtin_str(n)cmp_eq call where possible, i.e:
> > +
> > +   strncmp (s, STR, C) (!)= 0 in which, s is a pointer to a string, STR is a 
> > +   constant string, C is a constant.
> > +     if (C <= strlen(STR) && sizeof_array(s) > C)
> > +       {
> > +         replace this call with
> > +         strncmp_eq (s, STR, C) (!)= 0
> > +       }
> > +     if (C > strlen(STR)
> > +       {
> > +         it can be safely treated as a call to strcmp (s, STR) (!)= 0
> > +         can handled by the following strcmp.
> > +       }
> > +
> > +   strcmp (s, STR) (!)= 0 in which, s is a pointer to a string, STR is a 
> > +   constant string.
> > +     if  (sizeof_array(s) > strlen(STR))
> > +       {
> > +         replace this call with
> > +         strcmp_eq (s, STR, strlen(STR)+1) (!)= 0
> So I'd hazard a guess that this comment has the same problem.  It's
> mixing up the concept of a constant string and the concept of a
> nonconstant string, but which has a known constant length.
> 
> First, if one of the arguments is a string constant, then it should be
> easy to get the constant at expansion time with minimal effort.  It's
> also the case that knowing if we're comparing the result against zero is
> trivial to figure out at expansion time.  This would probably be a
> reasonble thing to add to the expanders.
> 
> 
> 
> Your function comment for handle_builtin_string_cmp does not indicate
> what the return value means.  From reading the code is appears to return
> TRUE when it does nothing and FALSE when it optimizes the call in some
> way.  Is that correct?  That seems inverted from the way we'd normally
> write this stuff.
> 
> 
> 
> > +
> > +  /* When one of args is constant string.  */
> > +  tree var_string = NULL_TREE;
> > +  HOST_WIDE_INT const_string_leni = -1;
> > +  
> > +  if (idx1)
> > +    {
> > +      const_string_leni = compute_string_length (idx1);
> > +      var_string = arg2;
> > +    } 
> > +  else 
> > +    {
> > +      gcc_checking_assert (idx2);
> > +      const_string_leni = compute_string_length (idx2);
> > +      var_string = arg1;
> > +    } 
> > +
> > +  if (const_string_leni < 0) 
> > +    return true;
> > + 
> > +  unsigned HOST_WIDE_INT var_sizei = 0;
> > +  /* try to determine the minimum size of the object pointed by var_string.  */
> > +  tree size = compute_objsize (var_string, 2);
> So this worries me as well.  compute_objsize is not supposed to be used
> to influence code generation or optimization.  It is not guaranteed to
> return an exact size, but instead may return an estimate!

Yes, compute_objsize cannot be used for optimizations.

> I'd really like to hear Jakub or Richi chime in with their thoughts on
> how this transforms one builtin into another and whether or not they
> think that is wise.

Given it follows how we handle memcmp () != 0 it's ok to trigger
inline expansion.  Didn't look into the patch whether it does this.
And yes, places that look at STR[N]CMP now also have to look at
STR[N]CMP_EQ.

We're now in stage4 so please queue this patch and ping it during
next stage1.

Thanks,
Richard.


More information about the Gcc-patches mailing list