(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)
--- /dev/null
+/* 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;
+}