On Fri, 2020-01-31 at 12:04 -0700, Martin Sebor wrote:
> Attached is a reworked patch since the first one didn't go far
> enough to solve the major problems.  The new solution relies on
> get_range_strlen_dynamic the same way as the sprintf optimization,
> and does away with the determine_min_objsize function and calling
> compute_builtin_object_size.
> 
> To minimize testsuite fallout I extended get_range_strlen to handle
> a couple more kinds expressions(*), but I still had to xfail and
> disable a few tests that were relying on being able to use the type
> of the destination object as the upper bound on the string length.
> 
> Tested on x86_64-linux.
> 
> Martin
> 
> [*] With all the issues around MEM_REFs and types this change needs
> extra scrutiny.  I'm still not sure I fully understand what can and
> what cannot be safely relied on at this level.
> 
> On 1/15/20 6:18 AM, Martin Sebor wrote:
> > The strcmp optimization newly introduced in GCC 10 relies on
> > the size of the smallest referenced array object to determine
> > whether the function can return zero.  When the size of
> > the object is smaller than the length of the other string
> > argument the optimization folds the equality to false.
> > 
> > The bug report has identified a couple of problems here:
> > 1) when the access to the array object is via a pointer to
> > a (possibly indirect) member of a union, in GIMPLE the pointer
> > may actually point to a different member than the one in
> > the original source code.  Thus the size of the array may
> > appear to be smaller than in the source code which can then
> > result in the optimization being invalid.
> > 2) when the pointer in the access may point to two or more
> > arrays of different size (i.e., it's the result of a PHI),
> > assuming it points to the smallest of them can also lead
> > to an incorrect result when the optimization is applied.
> > 
> > The attached patch adjusts the optimization to 1) avoid making
> > any assumptions about the sizes of objects accessed via union
> > types, and b) use the size of the largest object in PHI nodes.
> > 
> > Tested on x86_64-linux.
> > 
> > Martin
> 
> 
> PR tree-optimization/92765 - wrong code for strcmp of a union member
> 
> gcc/ChangeLog:
> 
>         PR tree-optimization/92765
>         * gimple-fold.c (get_range_strlen_tree): Handle MEM_REF and PARM_DECL.
>         * tree-ssa-strlen.c (compute_string_length): Remove.
>         (determine_min_objsize): Remove.
>         (get_len_or_size): Add an argument.  Call get_range_strlen_dynamic.
>         Avoid using type size as the upper bound on string length.
>         (handle_builtin_string_cmp): Add an argument.  Adjust.
>         (strlen_check_and_optimize_call): Pass additional argument to
>         handle_builtin_string_cmp.
> 
> gcc/testsuite/ChangeLog:
> 
>         PR tree-optimization/92765
>         * g++.dg/tree-ssa/strlenopt-1.C: New test.
>         * g++.dg/tree-ssa/strlenopt-2.C: New test.
>         * gcc.dg/Warray-bounds-58.c: New test.
>         * gcc.dg/Wrestrict-20.c: Avoid a valid -Wformat-overflow.
>         * gcc.dg/Wstring-compare.c: Xfail a test.
>         * gcc.dg/strcmpopt_2.c: Disable tests.
>         * gcc.dg/strcmpopt_4.c: Adjust tests.
>         * gcc.dg/strcmpopt_10.c: New test.
>         * gcc.dg/strlenopt-69.c: Disable tests.
>         * gcc.dg/strlenopt-92.c: New test.
>         * gcc.dg/strlenopt-93.c: New test.
>         * gcc.dg/strlenopt.h: Declare calloc.
>         * gcc.dg/tree-ssa/pr92056.c: Xfail tests until pr93518 is resolved.
>         * gcc.dg/tree-ssa/builtin-sprintf-warn-23.c: Correct test (pr93517).
> 
> diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
> index ed225922269..d70ac67e1ca 100644
> --- a/gcc/gimple-fold.c
> +++ b/gcc/gimple-fold.c
> @@ -1280,7 +1280,7 @@ get_range_strlen_tree (tree arg, bitmap *visited, 
> strlen_range_kind rkind,
>                        c_strlen_data *pdata, unsigned eltsize)
>  {
>    gcc_assert (TREE_CODE (arg) != SSA_NAME);
> - 
> +
>    /* The length computed by this invocation of the function.  */
>    tree val = NULL_TREE;
>  
> @@ -1422,7 +1422,42 @@ get_range_strlen_tree (tree arg, bitmap *visited, 
> strlen_range_kind rkind,
>              type about the length here.  */
>           tight_bound = true;
>         }
> -      else if (VAR_P (arg))
> +      else if (TREE_CODE (arg) == MEM_REF
> +              && TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE
> +              && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == INTEGER_TYPE
> +              && TREE_CODE (TREE_OPERAND (arg, 0)) == ADDR_EXPR)
> +       {
> +         /* Handle a MEM_REF into a DECL accessing an array of integers,
> +            being conservative about references to extern structures with
> +            flexible array members that can be initialized to arbitrary
> +            numbers of elements as an extension (static structs are okay).
> +            FIXME: Make this less conservative -- see
> +            component_ref_size in tree.c.  */
I think it's generally been agreed that we can look at sizes of _DECL
nodes and this code doesn't look like this walks backwards through
casts or anything like that.  So the worry would be if we forward
propagated through a cast into the MEM_REF node.

It looks like forwprop only propagates through "compatible" pointer
conversions.  It makes me a bit nervous.

Jakub/Richi, comments on this hunk?



> diff --git a/gcc/testsuite/gcc.dg/Wstring-compare.c 
> b/gcc/testsuite/gcc.dg/Wstring-compare.c
> index 0ca492db0ab..d1534bf7555 100644
> --- a/gcc/testsuite/gcc.dg/Wstring-compare.c
> +++ b/gcc/testsuite/gcc.dg/Wstring-compare.c
In general I have a slight preference for pulling these into new files
when we need to xfail them.  Why?  Because a test which previously
passed, but now fails (even an xfail) causes the tester to flag the
build as failing due to a testsuite regression.

But I don't think that preference is significant enough to ask you to
redo the work.  Just something to ponder in the future.

 
> diff --git a/gcc/testsuite/gcc.dg/strcmpopt_2.c 
> b/gcc/testsuite/gcc.dg/strcmpopt_2.c
> index 57d8f651c28..f31761be173 100644
> --- a/gcc/testsuite/gcc.dg/strcmpopt_2.c
> +++ b/gcc/testsuite/gcc.dg/strcmpopt_2.c
So I'd pulled f1, f3, f5, f7 into a new file.  But disabling them like
you've done is reasonable as well.


> diff --git a/gcc/testsuite/gcc.dg/strcmpopt_4.c 
> b/gcc/testsuite/gcc.dg/strcmpopt_4.c
> index 4e26522eed1..b07fbb6b7b0 100644
> --- a/gcc/testsuite/gcc.dg/strcmpopt_4.c
> +++ b/gcc/testsuite/gcc.dg/strcmpopt_4.c
THanks for creating the new test.  I'd done the exact same thing in my
local tree.  I'm a little surprised that f_param passes.  Can you
double check that?



diff --git a/gcc/testsuite/gcc.dg/strlenopt-69.c
b/gcc/testsuite/gcc.dg/strlenopt-69.c
> index 9ad8e2e8aac..9df6eeccb97 100644
> --- a/gcc/testsuite/gcc.dg/strlenopt-69.c
> +++ b/gcc/testsuite/gcc.dg/strlenopt-69.c
I'd pulled the offending tests into a new file, but your approach is
fine too.

> 
> diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
> index ad9e98973b1..b9972c16e18 100644
> --- a/gcc/tree-ssa-strlen.c
> +++ b/gcc/tree-ssa-strlen.c
> -
> -/* Given strinfo IDX for ARG, set LENRNG[] to the range of lengths
> -   of  the string(s) referenced by ARG if it can be determined.
> -   If the length cannot be determined, set *SIZE to the size of
> +/* Given strinfo IDX for ARG, sets LENRNG[] to the range of lengths
> +   of the string(s) referenced by ARG if it can be determined.
> +   If the length cannot be determined, sets *SIZE to the size of
>     the array the string is stored in, if any.  If no such array is
> -   known, set *SIZE to -1.  When the strings are nul-terminated set
> -   *NULTERM to true, otherwise to false.  Return true on success.  */
> +   known, sets *SIZE to -1.  When the strings are nul-terminated sets
> +   *NULTERM to true, otherwise to false.  When nonnull uses RVALS to
> +   determine range information. Returns true on success.  */
"When nonnull uses RVALS to detemrine range information."  That isn't a
sentence and just doesn't seem to make sense.  Please review for
comment clarity.

This looks OK to me with the comment fixed.  I like that we drop the
whole determine_min_objsize and replace it it the standard range bits
that we're using elsewhere.

Please give Richi and Jakub time to chime in on the gimple-fold.c
changes.


Jeff

Reply via email to