> Am 15.05.2026 um 19:54 schrieb Andrew Pinski <[email protected]>:
>
> On Fri, May 15, 2026 at 6:21 AM Richard Biener
> <[email protected]> wrote:
>>
>>> On Thu, May 14, 2026 at 4:11 AM Pengxuan Zheng
>>> <[email protected]> wrote:
>>>
>>> The patch adds the following simplification pattern.
>>>
>>> (a == b) & (a == c) & (b != c) -> false
>>>
>>> Bootstrapped and tested on x86_64-linux-gnu and aarch64-linux-gnu.
>>
>> This feels like sth for reassoc instead (my hunch as soon as when
>> I see two or more &|^)?
>
> So this is the transitive property being used here. So reassociation
> is not the right place.
But it becomes relevant if there’s another & associated inbetween. It’s a
simplification of a kind that reassoc does IMO
> VRP is the place which should handle this but currently the transitive
> property usage is only across blocks and not associated with ssa
> names.
> I wonder if it is important to enhance VRP to handle this.
>
> so we have:
> _1 = a == b
> _2 = a == c
> _3 = _1 & _2 ;; // when true Implies a == b, a == c and b == c
> _4 = _b != c
> _r = _4 & _3 ;; _3 and _4 are opposites so they can never be true at
> the same time so false
>
> (note this I think is only true for integers or maybe !HONOR_NANS)
>
> This is definitely VRPish but I have not looked to see if there are
> any papers written on doing this in a reasonable way. I tried looking
> for one but I didn't see one.
I guess VRP would have similar ordering issues like VN does in some cases.
> I am also not a fan of adding these transitive property/VRP match
> patterns either because where do we stop.
> We already have some patterns which are VRP-like already (though not
> using the transitive property):
> (a != b) & ((a|b) != 0)
> ((a ^ b) & c) cmp d || a != b
> a * ((a || b) != 0)
> x > y && x != XXX_MIN
> (X == CST1) && ((other)X OP2 CST2)
> (X == Y) && (X OP2 Y)
> etc.
>
> Adding these patterns definitely have been easier than enhancing VRP.
> But the question becomes maybe we should improve VRP in the end.
Or other passes. Yes.
Richard
>
> Thanks,
> Andrea
>
>
>
>
>
>>
>>> PR tree-optimization/110922
>>>
>>> gcc/ChangeLog:
>>>
>>> * match.pd ((a==b)&(a==c)&(b!=c)): New Pattern.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> * gcc.dg/tree-ssa/pr110922.c: New test.
>>>
>>> Signed-off-by: Pengxuan Zheng <[email protected]>
>>> ---
>>> gcc/match.pd | 12 +++
>>> gcc/testsuite/gcc.dg/tree-ssa/pr110922.c | 100 +++++++++++++++++++++++
>>> 2 files changed, 112 insertions(+)
>>> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr110922.c
>>>
>>> diff --git a/gcc/match.pd b/gcc/match.pd
>>> index b037b1a2876..e6552c4e868 100644
>>> --- a/gcc/match.pd
>>> +++ b/gcc/match.pd
>>> @@ -6643,6 +6643,18 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>>> (simplify
>>> (bitop (neeql @0 @1) (neeqr (bit_ior @0 @1) integer_zerop))
>>> { constant_boolean_node (bitop == BIT_IOR_EXPR, type); }))
>>> +
>>> +/* (a == b) & (a == c) & (b != c) -> false */
>>> +(simplify
>>> + (bit_and:c
>>> + (bit_and:c (eq:c @0 @1) (eq:c @0 @2))
>>> + (ne:c @1 @2))
>>> + { constant_boolean_node (false, type); })
>>> +(simplify
>>> + (bit_and:c
>>> + (bit_and:c (eq:c @0 @1) (ne:c @1 @2))
>>> + (eq:c @0 @2))
>>> + { constant_boolean_node (false, type); })
>>> #endif
>>>
>>> /* These was part of minmax phiopt. */
>>> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr110922.c
>>> b/gcc/testsuite/gcc.dg/tree-ssa/pr110922.c
>>> new file mode 100644
>>> index 00000000000..353c99bbc2d
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr110922.c
>>> @@ -0,0 +1,100 @@
>>> +/* { dg-do compile } */
>>> +/* { dg-options "-O2 -fdump-tree-optimized" } */
>>> +
>>> +int f1(int a, int b, int c)
>>> +{
>>> + _Bool t = a == b;
>>> + _Bool t1 = a == c;
>>> + _Bool t2 = b != c;
>>> + return t&t1&t2;
>>> +}
>>> +
>>> +int f2(int a, int b, int c)
>>> +{
>>> + _Bool t = a == b;
>>> + _Bool t1 = a == c;
>>> + _Bool t2 = b != c;
>>> + return t1&t&t2;
>>> +}
>>> +
>>> +int f3(int a, int b, int c)
>>> +{
>>> + _Bool t = a == b;
>>> + _Bool t1 = a == c;
>>> + _Bool t2 = b != c;
>>> + return t2&(t&t1);
>>> +}
>>> +
>>> +int f4(int a, int b, int c)
>>> +{
>>> + _Bool t = a == b;
>>> + _Bool t1 = a == c;
>>> + _Bool t2 = b != c;
>>> + return t2&(t1&t);
>>> +}
>>> +
>>> +int f5(int a, int b, int c)
>>> +{
>>> + _Bool t = a == b;
>>> + _Bool t1 = a == c;
>>> + _Bool t2 = b != c;
>>> + return t&t2&t1;
>>> +}
>>> +
>>> +int f6(int a, int b, int c)
>>> +{
>>> + _Bool t = a == b;
>>> + _Bool t1 = a == c;
>>> + _Bool t2 = b != c;
>>> + return t2&t&t1;
>>> +}
>>> +
>>> +int f7(int a, int b, int c)
>>> +{
>>> + _Bool t = a == b;
>>> + _Bool t1 = a == c;
>>> + _Bool t2 = b != c;
>>> + return t2&(t&t1);
>>> +}
>>> +
>>> +int f8(int a, int b, int c)
>>> +{
>>> + _Bool t = a == b;
>>> + _Bool t1 = a == c;
>>> + _Bool t2 = b != c;
>>> + return t2&(t1&t);
>>> +}
>>> +
>>> +int f9(int a, int b)
>>> +{
>>> + _Bool t = a == b;
>>> + _Bool t1 = a == 0;
>>> + _Bool t2 = b != 0;
>>> + return t&(t1&t2);
>>> +}
>>> +
>>> +int f10(int a, int b)
>>> +{
>>> + _Bool t = a == b;
>>> + _Bool t1 = a == 0;
>>> + _Bool t2 = b != 0;
>>> + return t&(t2&t1);
>>> +}
>>> +
>>> +int f11(int a, int b)
>>> +{
>>> + _Bool t = a == b;
>>> + _Bool t1 = a == 0;
>>> + _Bool t2 = b != 0;
>>> + return (t1&t2)&t;
>>> +}
>>> +
>>> +int f12(int a, int b)
>>> +{
>>> + _Bool t = a == b;
>>> + _Bool t1 = a == 0;
>>> + _Bool t2 = b != 0;
>>> + return (t2&t1)&t;
>>> +}
>>> +
>>> +/* { dg-final { scan-tree-dump-times "return 0;" 12 "optimized" } } */
>>> --
>>> 2.34.1
>>>