On Tue, 11 Oct 2016, Marc Glisse wrote:

> On Tue, 11 Oct 2016, Richard Biener wrote:
> 
> > > An example that regressed at -O (looking at the .optimized dump)
> > > 
> > > int f(int a, unsigned b){
> > >   a &= 1;
> > >   b &= 1;
> > >   return a&b;
> > > }
> > 
> > Yeah, but it usually also shows a badly written pattern:
> > 
> > /* (X & Y) & (X & Z) -> (X & Y) & Z
> >   (X | Y) | (X | Z) -> (X | Y) | Z  */
> > (for op (bit_and bit_ior)
> > (simplify
> >  (op:c (convert1?@3 (op:c@4 @0 @1)) (convert2?@5 (op:c@6 @0 @2)))
> >  (if (tree_nop_conversion_p (type, TREE_TYPE (@1))
> >       && tree_nop_conversion_p (type, TREE_TYPE (@2)))
> > 
> > so how could we ever match the @0s when we have either of the two
> > conversions not present?  We could only do this then facing constants
> > (due to using operand_equal_p).  We for example fail to handle
> > 
> > (X & Y) & (unsigned) ((singed)X & Z)
> 
> Indeed... (oups, looks like I wrote that one)
> 
> Trying to find other examples
> 
> /* Fold A - (A & B) into ~B & A.  */
> (simplify
>  (minus (convert? @0) (convert?:s (bit_and:cs @0 @1)))
>  (if (tree_nop_conversion_p (type, TREE_TYPE (@0))
>       && tree_nop_conversion_p (type, TREE_TYPE (@1)))
>   (convert (bit_and (bit_not @1) @0))))
> 
> Hmm, should be convert1/convert2 to handle the case where @0 is a constant.
> 
> /* (X | Y) ^ X -> Y & ~ X*/
> (simplify
>  (bit_xor:c (convert? (bit_ior:c @0 @1)) (convert? @0))
>  (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
>   (convert (bit_and @1 (bit_not @0)))))
> 
> Again, will never match when there is a convert and @0 is a constant.
> 
> (for op (bit_and bit_ior bit_xor)
>      rop (bit_ior bit_and bit_and)
>  (simplify
>   (op (convert? (rop:c @0 @1)) (convert? (rop:c @0 @2)))
> ...
> 
> Again won't match for constant @0 that has a different type in both parts.
> 
> /* (X & Y) & Y -> X & Y
>    (X | Y) | Y -> X | Y  */
> (for op (bit_and bit_ior)
>  (simplify
>   (op:c (convert?@2 (op:c @0 @1)) (convert? @1))
>   @2))
> 
> Same issue.
> 
> Ok, not many transformations are concerned, and most need a rewrite anyway...
> 
> In the other direction, looking at the transformations for which we used
> explicitly operand_equal_p as a workaround for lax integer constant matches,
> it doesn't look like changing them back to use matching captures would help,
> it would require duplicating the pattern for constants.

So with doing the same on GENERIC I hit

FAIL: g++.dg/cpp1y/constexpr-array4.C  -std=c++14 (test for excess errors)

with the pattern

  /* (T)(P + A) - (T)P -> (T) A */
  (for add (plus pointer_plus)
   (simplify
    (minus (convert (add @0 @1))
     (convert @0))
    ...
     (convert @1))))


no longer applying to

(long int) ((int *) &ar + 12) - (long int) &ar

because while (int *) &ar is equal to (long int) &ar (operand_equal_p
does STRIP_NOPS) they obviously do not have the same type.  So on
GENERIC we have to consider that we feed operand_equal_p with
non-ATOMs (arbitrary expressions).  The pattern above is "safe" as
it doesn't reference @0 in the result (not sure if we should take
advantage of that in genmatch).

The other FAILs with doing the same on GENERIC are

FAIL: g++.dg/gomp/declare-simd-3.C  -std=gnu++11 (test for excess errors)
FAIL: g++.dg/torture/pr71448.C   -O0  (test for excess errors)
FAIL: g++.dg/vect/simd-clone-6.cc  -std=c++11 (test for excess errors)

the simd ones are 'warning: ignoring large linear step' and the pr71448.C
case is very similar to the above.

> > > If we stick to the old behavior, maybe we could have some genmatch magic
> > > to
> > > help with the constant capture weirdness. With matching captures, we could
> > > select which operand (among those supposed to be equivalent) is actually
> > > captured more cleverly, either with an explicit marker, or by giving
> > > priority
> > > to the one that is not immediatly below convert? in the pattern.
> > 
> > This route is a difficult one to take
> 
> The simplest version I was thinking about was @0 for a true capture, and @@0
> for something that just has to be checked for equality with @0.

Hmm, ok.  So you'd have @@0 having to match @0 and we'd get the @0 for
the result in a reliable way?  Sounds like a reasonable idea, I'll see
how that works out (we could auto-detect '@@' if the capture is not
used in the result, see above).

> > -- what would be possible is to
> > capture a specific operand.  Like allow one to write
> > 
> > (op (op @0@4 @1) (op @0@3 @2))
> > 
> > and thus actually have three "names" for @0.  We have this internally
> > already when you write
> > 
> > (convert?@0 @1)
> > 
> > for the case where there is no conversion.  @0 and @1 are the same
> > in this case.
> 
> Looks nice and convenient (assuming lax constant matching).

Yes, w/o lax matching it has of course little value.

> > Not sure if this helps enough cases.
> 
> IIRC, in all cases where we had trouble with operand_equal_p, chosing which
> operand to capture would have solved the issue.

Yes.  We'd still need to actually catch all those cases...

> > I still think that having two things matched that are not really
> > the same is werid (and a possible source of errors as in, ICEs,
> > rather than missed optimizations).
> 
> Ok. Let's go with the strict matching, it is indeed less confusing.

I'll hold off with the GENERIC strict matching and will investigate
the @@ idea (plus auto-detecting it).

> > > And if we move to stricter matching, maybe genmatch could be updated so
> > > convert could also match integer constants in some cases.
> > 
> > You mean when trying to match @0 ... (convert @0) and @0 is an INTEGER_CST
> > allow then (convert ...) case to match an INTEGER_CST of different type?
> > That's an interesting idea (not sure how to implement that though).
> 
> Yes, though I am not sure of the exact semantics that would work best.
> 
> On a related note, seeing duplicated patterns for constants, I tried several
> variants of
> 
> (match (mynot @0)
>  (bit_not @0))
> (match (mynot @0)
>  INTEGER_CST@0
>  (if (@0 = wide_int_to_tree (TREE_TYPE (@0), wi::bit_not (@0)))))
> 
> (simplify
>  (minus (bit_and:cs @0 (mynot @1)) (bit_and:cs @0 @1))
>   (minus (bit_xor @0 @1) @1))
> 
> This kind of hack feels wrong, but I don't see a proper way to write it.

Yes.  The above is very much a hack.  Must have been me inventing it
just to avoid duplicating the pattern.

Richard.

> 
> > > > I agree that some transforms would need updates - I've actually tried
> > > > to implement a warning for genmatch whenever seeing a match with
> > > > (T)@0 but there isn't any good existing place to sneak that in.
> > > 
> > > 
> > > > > >     * match.pd ((X /[ex] A) * A -> X): Properly handle converted
> > > > > >     and constant A.
> > > > > 
> > > > > This regressed
> > > > > int f(int*a,int*b){return 4*(int)(b-a);}
> > > > 
> > > > This is because (int)(b-a) could be a truncation in which case
> > > > multiplying with 4 might not result in the same value as
> > > > b-a truncated(?).  The comment before the unpatched patterns
> > > > said "sign-changing conversions" but nothign actually verified this.
> > > > Might be that truncations are indeed ok now that I think about it.
> > > 
> > > 2015-05-22  Marc Glisse  <marc.gli...@inria.fr>
> > > 
> > >         PR tree-optimization/63387
> > >         * match.pd ((X /[ex] A) * A -> X): Remove unnecessary condition.
> > > 
> > > Apparently I forgot to remove the comment at that time :-(
> > 
> > Ok.  I'm now testing a patch to remove the restriction again (and adjust
> > the comment).
> 
> Thanks. (since exact_div is used almost only with constant divisors, the old
> pattern was fine before strict matching, but indeed your more general pattern
> is better)

Reply via email to