diff --git a/gcc/match.pd b/gcc/match.pd index e731bdba171..84c4ee66a79 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -3117,13 +3117,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (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) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96669-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr96669-1.c new file mode 100644 index 00000000000..a1efba76770 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr96669-1.c @@ -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; +}