[PATCH] Move fold_div_compare optimization to match.pd (PR tree-optimization/81346)
Jakub Jelinek
jakub@redhat.com
Tue Jul 18 15:34:00 GMT 2017
On Tue, Jul 18, 2017 at 05:21:42PM +0200, Marc Glisse wrote:
> On Tue, 18 Jul 2017, Jakub Jelinek wrote:
>
> > +/* X / C1 op C2 into a simple range test. */
> > +(for cmp (simple_comparison)
> > + (simplify
> > + (cmp (trunc_div:s @0 INTEGER_CST@1) INTEGER_CST@2)
> > + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
> > + && integer_nonzerop (@1)
> > + && !TREE_OVERFLOW (@1)
> > + && !TREE_OVERFLOW (@2))
>
> (not specific to this patch)
> I wonder if we should check TREE_OVERFLOW for the input that way in many
> more transformations in match.pd, or never, or how to decide in which
> cases to do it...
The reason for putting it here was that: 1) fold_div_compare did that
2) it relies on TREE_OVERFLOW to detect if the optimization is ok or not,
if there are some TREE_OVERFLOW on the inputs, then it might misbehave.
> > + (with
> > + {
> > + tree etype = range_check_type (TREE_TYPE (@0));
> > + if (etype)
> > + {
> > + if (! TYPE_UNSIGNED (etype))
> > + etype = unsigned_type_for (etype);
>
> Now that you enforce unsignedness, can you think of cases where going
> through range_check_type is useful compared to
> tree etype = unsigned_type_for (TREE_TYPE (@0));
> ? I can propose that trivial patch as a follow-up if you like.
I couldn't convince myself it is safe. While enums and bool are handled
early, aren't there e.g. Ada integral types with weirdo min/max values and
similar stuff where the range_check_type test would fail? If it never
fails, why we do it there? The reason I've added unsigned_type_for
afterwards is that that build_range_check actually does something like
that too.
With -fwrapv it will perform the subtraction of lo in whatever type
range_check_type returns (could be e.g. int for -fwrapv) but then
recurses and runs into:
if (integer_zerop (low))
{
if (! TYPE_UNSIGNED (etype))
{
etype = unsigned_type_for (etype);
high = fold_convert_loc (loc, etype, high);
exp = fold_convert_loc (loc, etype, exp);
}
return build_range_check (loc, type, exp, 1, 0, high);
}
I was thinking whether e.g. range_check_type shouldn't have an extra
argument which would be false for build_range_check and true for
the use in match.pd, and if that arg is false, it would use
!TYPE_OVERFLOW_WRAPS (etype) and if that arg is true, it would
use !TYPE_UNSIGNED (etype) instead.
> > + hi = fold_convert (etype, hi);
> > + lo = fold_convert (etype, lo);
> > + hi = const_binop (MINUS_EXPR, etype, hi, lo);
> > + }
> > + }
> > + (if (etype && hi && !TREE_OVERFLOW (hi))
>
> I don't think you can have an overflow here anymore, now that etype is
> always unsigned and since you check the input (doesn't hurt though).
If const_binop for unsigned etype will never return NULL nor TREE_OVERFLOW
on the result, then that can surely go. But again, I'm not 100% sure.
>
> > + (if (code == EQ_EXPR)
> > + (le (minus (convert:etype @0) { lo; }) { hi; })
> > + (gt (minus (convert:etype @0) { lo; }) { hi; })))))))))
Jakub
More information about the Gcc-patches
mailing list