Hi! The following patch generalizes the PR64309 simplifications, so that instead of working only with constants 1 and 1 it works with any two power of two constants, and works also for right shift (in that case it rules out the first one being negative, as it is arithmetic shift then).
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2021-01-15 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/96669 * match.pd (((1 << A) & 1) != 0 -> A == 0, ((1 << A) & 1) == 0 -> A != 0): Generalize for 1s replaced by possibly different power of two constants and to right shift too. * gcc.dg/tree-ssa/pr96669-1.c: New test. --- gcc/match.pd.jj 2021-01-15 14:00:21.567135280 +0100 +++ gcc/match.pd 2021-01-15 17:03:49.207071209 +0100 @@ -3117,13 +3117,26 @@ (define_operator_list COND_TERNARY (op @0 { build_int_cst (TREE_TYPE (@1), low); }))))))) -/* ((1 << A) & 1) != 0 -> A == 0 - ((1 << A) & 1) == 0 -> A != 0 */ +/* Simplify ((C << x) & D) != 0 where C and D are power of two constants, + either to false if D is smaller (unsigned comparison) than C, or to + x == log2 (D) - log2 (C). Similarly for right shifts. */ (for cmp (ne eq) icmp (eq ne) (simplify - (cmp (bit_and (lshift integer_onep @0) integer_onep) integer_zerop) - (icmp @0 { build_zero_cst (TREE_TYPE (@0)); }))) + (cmp (bit_and (lshift integer_pow2p@1 @0) integer_pow2p@2) integer_zerop) + (with { int c1 = wi::clz (wi::to_wide (@1)); + int c2 = wi::clz (wi::to_wide (@2)); } + (if (c1 < c2) + { constant_boolean_node (cmp == NE_EXPR ? false : true, type); } + (icmp @0 { build_int_cst (TREE_TYPE (@0), c1 - c2); })))) + (simplify + (cmp (bit_and (rshift integer_pow2p@1 @0) integer_pow2p@2) integer_zerop) + (if (tree_int_cst_sgn (@1) > 0) + (with { int c1 = wi::clz (wi::to_wide (@1)); + int c2 = wi::clz (wi::to_wide (@2)); } + (if (c1 > c2) + { constant_boolean_node (cmp == NE_EXPR ? false : true, type); } + (icmp @0 { build_int_cst (TREE_TYPE (@0), c2 - c1); })))))) /* (CST1 << A) == CST2 -> A == ctz (CST2) - ctz (CST1) (CST1 << A) != CST2 -> A != ctz (CST2) - ctz (CST1) --- gcc/testsuite/gcc.dg/tree-ssa/pr96669-1.c.jj 2021-01-15 17:12:11.067414204 +0100 +++ gcc/testsuite/gcc.dg/tree-ssa/pr96669-1.c 2021-01-15 17:11:55.486589792 +0100 @@ -0,0 +1,59 @@ +/* PR tree-optimization/96669 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-original" } */ +/* { dg-final { scan-tree-dump "return a == 0;" "original" } } */ +/* { dg-final { scan-tree-dump "return 1;" "original" } } */ +/* { dg-final { scan-tree-dump "return c == 3;" "original" } } */ +/* { dg-final { scan-tree-dump "return d != 1;" "original" } } */ +/* { dg-final { scan-tree-dump "return e != 0;" "original" } } */ +/* { dg-final { scan-tree-dump "return f == 1;" "original" } } */ +/* { dg-final { scan-tree-dump "return 0;" "original" } } */ +/* { dg-final { scan-tree-dump "return h != 1;" "original" } } */ + +int +f1 (int a) +{ + return ((1 << a) & 1) != 0; +} + +int +f2 (int b) +{ + return ((2 << b) & 1) == 0; +} + +int +f3 (int c) +{ + return ((2 << c) & 16) != 0; +} + +int +f4 (int d) +{ + return ((16 << d) & 32) == 0; +} + +int +f5 (int e) +{ + return ((1 >> e) & 1) == 0; +} + +int +f6 (int f) +{ + return ((2 >> f) & 1) != 0; +} + +int +f7 (int g) +{ + return ((1 >> g) & 2) != 0; +} + +int +f8 (int h) +{ + return ((32 >> h) & 16) == 0; +} Jakub