https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115392
--- Comment #2 from Drea Pinski <pinskia at gcc dot gnu.org> ---
(a^b) <= 3
is the same as:
b ? (a^1 <= 3) : (a <= 3)
For the a^1 <= 3 side:
(a&1) ? (a&(~1) <= 3) : (a|1 <= 3)
`a&(~1) <= 3` is just `a <= 3` so is `a|1 <= 3`
Note we have a pattern for the &~1 case (added by r17-2951-g1c71996e6e067a):
```
/* Fold (X & HIGHMASK) >/<= C into X >/<= (C | ~HIGHMASK). Clearing the
low bits of X rounds it down, and a rounded value passes the comparison
exactly when X passes it against the constant with those bits set. */
(for cmp (gt le)
(simplify
(cmp (bit_and:s @0 INTEGER_CST@1) INTEGER_CST@2)
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
&& bitmask_inv_cst_vector_p (@1))
(with { wide_int c = wi::to_wide (@2) | wi::bit_not (wi::to_wide (@1)); }
(cmp @0 { wide_int_to_tree (TREE_TYPE (@0), c); })))))
```
We don't have one for the `a|LOWMASK` case or the `a^LOWMASK` case either.
That is:
unsigned f2(unsigned a)
{
a |= 0x2; // CST1
return a <= 0x13; // CST2
}
// CST2&CST1 == CST1 and CST1 has to be a shifted mask.