On Sun, Apr 24, 2016 at 7:24 PM, Marc Glisse <marc.gli...@inria.fr> wrote:
> On Fri, 22 Apr 2016, Marc Glisse wrote:
>
>> On Fri, 22 Apr 2016, Richard Biener wrote:
>>
>>> On Fri, Apr 22, 2016 at 5:29 AM, Marc Glisse <marc.gli...@inria.fr>
>>> wrote:
>>>>
>>>> Hello,
>>>>
>>>> this optimizes a common pattern for unsigned overflow detection, when
>>>> one of
>>>> the arguments turns out to be a constant. There are more ways this could
>>>> look like, (a + 42 <= 41) in particular, but that'll be for another
>>>> patch.
>>>
>>>
>>> This case is also covered by fold_comparison which should be re-written
>>> to match.pd patterns (and removed from fold-const.c).
>>>
>>> fold_binary also as a few interesting/similar equality compare cases
>>> like X +- Y CMP X to Y CMP 0 which look related.
>>>
>>> Also your case is in fold_binary for the case of undefined overflow:
>>
>>
>> As far as I can tell, fold-const.c handles this kind of transformation
>> strictly in the case of undefined overflow (or floats), while this is
>> strictly in the case of unsigned with wrapping overflow. I thought it would
>> be more readable to take advantage of the genmatch machinery and group the
>> wrapping transforms in one place, and the undefined overflow ones in another
>> place (they don't group the same way by operator, etc).
>>
>> If you prefer to group by pattern shape and port the related fold-const.c
>> bit at the same time, I could try that...
>>
>>> +/* When one argument is a constant, overflow detection can be
>>> simplified.
>>> +   Currently restricted to single use so as not to interfere too much
>>> with
>>> +   ADD_OVERFLOW detection in tree-ssa-math-opts.c.  */
>>> +(for cmp (lt le ge gt)
>>> +     out (gt gt le le)
>>> + (simplify
>>> +  (cmp (plus@2 @0 integer_nonzerop@1) @0)
>>> +  (if (TYPE_UNSIGNED (TREE_TYPE (@0))
>>> +       && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))
>>> +       && TYPE_MAX_VALUE (TREE_TYPE (@0))
>>> +       && single_use (@2))
>>> +   (out @0 (minus { TYPE_MAX_VALUE (TREE_TYPE (@0)); } @1)))))
>>> +(for cmp (gt ge le lt)
>>> +     out (gt gt le le)
>>> + (simplify
>>> +  (cmp @0 (plus@2 @0 integer_nonzerop@1))
>>> +  (if (TYPE_UNSIGNED (TREE_TYPE (@0))
>>> +       && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))
>>> +       && TYPE_MAX_VALUE (TREE_TYPE (@0))
>>> +       && single_use (@2))
>>> +   (out @0 (minus { TYPE_MAX_VALUE (TREE_TYPE (@0)); } @1)))))
>>>
>>> please add a comment with the actual transform - A + CST CMP A -> A CMP'
>>> CST'
>>>
>>> As we are relying on twos-complement wrapping you shouldn't need
>>> TYPE_MAX_VALUE
>>> here but you can use wi::max_value (precision, sign).  I'm not sure we
>>> have sensible
>>> TYPE_MAX_VALUE for vector or complex types - the accessor uses
>>> NUMERICAL_TYPE_CKECK
>>> and TYPE_OVERFLOW_WRAPS checks for ANY_INTEGRAL_TYPE.  Thus I wonder
>>> if we should restrict this to INTEGRAL_TYPE_P (making the
>>> wi::max_value route valid).
>>
>>
>> integer_nonzerop currently already restricts to INTEGER_CST or
>> COMPLEX_CST, and I don't think complex can appear in a comparison. I'll go
>> back to writing the more explicit INTEGER_CST in the pattern and I'll use
>> wide_int.
>
>
> Better this way?
>
> By the way, it would be cool to be able to write:
> (lt:c @0 @1)
>
> which would expand to both
> (lt @0 @1)
> (gt @1 @0)
>
> (as per swap_tree_comparison or swapped_tcc_comparison)

Yeah, I know...  I was hesitant to overload :c with "slightly" different
semantics though.

I can give it a shot though - it would avoid quite some repetition I guess.

Ok.

Thanks,
Richard.

> --
> Marc Glisse
> Index: trunk-ovf/gcc/match.pd
> ===================================================================
> --- trunk-ovf/gcc/match.pd      (revision 235371)
> +++ trunk-ovf/gcc/match.pd      (working copy)
> @@ -3071,10 +3071,36 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>  (simplify
>   /* signbit(x) -> 0 if x is nonnegative.  */
>   (SIGNBIT tree_expr_nonnegative_p@0)
>   { integer_zero_node; })
>
>  (simplify
>   /* signbit(x) -> x<0 if x doesn't have signed zeros.  */
>   (SIGNBIT @0)
>   (if (!HONOR_SIGNED_ZEROS (@0))
>    (convert (lt @0 { build_real (TREE_TYPE (@0), dconst0); }))))
> +
> +/* When one argument is a constant, overflow detection can be simplified.
> +   Currently restricted to single use so as not to interfere too much with
> +   ADD_OVERFLOW detection in tree-ssa-math-opts.c.
> +   A + CST CMP A  ->  A CMP' CST' */
> +(for cmp (lt le ge gt)
> +     out (gt gt le le)
> + (simplify
> +  (cmp (plus@2 @0 INTEGER_CST@1) @0)
> +  (if (TYPE_UNSIGNED (TREE_TYPE (@0))
> +       && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))
> +       && wi::ne_p (@1, 0)
> +       && single_use (@2))
> +   (out @0 { wide_int_to_tree (TREE_TYPE (@0), wi::max_value
> +              (TYPE_PRECISION (TREE_TYPE (@0)), UNSIGNED) - @1); }))))
> +/* A CMP A + CST  ->  A CMP' CST' */
> +(for cmp (gt ge le lt)
> +     out (gt gt le le)
> + (simplify
> +  (cmp @0 (plus@2 @0 INTEGER_CST@1))
> +  (if (TYPE_UNSIGNED (TREE_TYPE (@0))
> +       && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))
> +       && wi::ne_p (@1, 0)
> +       && single_use (@2))
> +   (out @0 { wide_int_to_tree (TREE_TYPE (@0), wi::max_value
> +              (TYPE_PRECISION (TREE_TYPE (@0)), UNSIGNED) - @1); }))))
> Index: trunk-ovf/gcc/testsuite/gcc.dg/tree-ssa/overflow-1.c
> ===================================================================
> --- trunk-ovf/gcc/testsuite/gcc.dg/tree-ssa/overflow-1.c        (revision 0)
> +++ trunk-ovf/gcc/testsuite/gcc.dg/tree-ssa/overflow-1.c        (working
> copy)
> @@ -0,0 +1,16 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O -fdump-tree-optimized" } */
> +
> +int f(unsigned a){
> +    unsigned b=5;
> +    unsigned c=a-b;
> +    return c>a;
> +}
> +int g(unsigned a){
> +    unsigned b=32;
> +    unsigned c=a+b;
> +    return c<a;
> +}
> +
> +/* { dg-final { scan-tree-dump "a_\[0-9\]+.D. <= 4;" "optimized" } } */
> +/* { dg-final { scan-tree-dump "a_\[0-9\]+.D. > 4294967263;" "optimized" }
> } */
>

Reply via email to