From 0425f4c1b63107bf3bc4778d1fe53c91ace7838d Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 15 Jan 2021 21:12:14 +0100 Subject: [PATCH] match.pd: Generalize the PR64309 simplifications [PR96669] 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). 2021-01-15 Jakub Jelinek 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 | 21 ++++++-- gcc/testsuite/gcc.dg/tree-ssa/pr96669-1.c | 59 +++++++++++++++++++++++ 2 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr96669-1.c 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; +} -- 2.30.2