As discussed in the PR, this adds folding of (1 << A) & 1) if in a eq/ne comparison. The assembly diff on my x86_64 box is
movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, -4(%rbp) - movl -4(%rbp), %eax - movl $1, %edx - movl %eax, %ecx - sarl %cl, %edx - movl %edx, %eax - andl $1, %eax - testl %eax, %eax - setne %al + cmpl $0, -4(%rbp) + sete %al movzbl %al, %eax popq %rbp .cfi_def_cfa 7, 8 Since this removes a shift, I was afraid that it could regress ubsan sanitization, but luckily that is not the case and the shift diagnostics seems to be intact. It triggers several times during the bootstrap. Bootstrapped/regtested on x86_64-linux + ppc64-linux, ok for trunk? 2014-12-16 Marek Polacek <pola...@redhat.com> PR middle-end/64309 * match.pd: Add ((1 << A) & 1) != 0 -> A == 0 and ((1 << A) & 1) == 0 -> A != 0. * gcc.dg/pr64309.c: New test. diff --git gcc/match.pd gcc/match.pd index 083d65f..47b01eb 100644 --- gcc/match.pd +++ gcc/match.pd @@ -599,6 +599,15 @@ along with GCC; see the file COPYING3. If not see build_int_cst (TREE_TYPE (@1), element_precision (type)), @1); })) +/* ((1 << A) & 1) != 0 -> A == 0 */ +(simplify + (ne (bit_and (lshift integer_onep @0) integer_onep) integer_zerop) + (eq @0 { build_zero_cst (TREE_TYPE (@0)); })) + +/* ((1 << A) & 1) == 0 -> A != 0 */ +(simplify + (eq (bit_and (lshift integer_onep @0) integer_onep) integer_zerop) + (ne @0 { build_zero_cst (TREE_TYPE (@0)); })) /* Simplifications of conversions. */ diff --git gcc/testsuite/gcc.dg/pr64309.c gcc/testsuite/gcc.dg/pr64309.c index e69de29..710a762 100644 --- gcc/testsuite/gcc.dg/pr64309.c +++ gcc/testsuite/gcc.dg/pr64309.c @@ -0,0 +1,66 @@ +/* PR middle-end/64309 */ +/* { dg-do run } */ +/* { dg-options "-fdump-tree-original" } */ + +int +fn1 (int n) +{ + return ((1 << n) & 1) != 0; +} + +int +fn2 (int n) +{ + return (1 & (1 << n)) != 0; +} + +int +fn3 (int n) +{ + return ((1 << n) & 1) == 0; +} + +int +fn4 (int n) +{ + return (1 & (1 << n)) == 0; +} + +int +main (void) +{ + if (fn1 (0) != 1 + || fn1 (1) != 0 + || fn1 (2) != 0 + || fn1 (3) != 0 + || fn1 (4) != 0 + || fn1 (5) != 0) + __builtin_abort (); + + if (fn2 (0) != 1 + || fn2 (1) != 0 + || fn2 (2) != 0 + || fn2 (3) != 0 + || fn2 (4) != 0 + || fn2 (5) != 0) + __builtin_abort (); + + if (fn3 (0) != 0 + || fn3 (1) != 1 + || fn3 (2) != 1 + || fn3 (3) != 1 + || fn3 (4) != 1 + || fn3 (5) != 1) + __builtin_abort (); + + if (fn4 (0) != 0 + || fn4 (1) != 1 + || fn4 (2) != 1 + || fn4 (3) != 1 + || fn4 (4) != 1 + || fn4 (5) != 1) + __builtin_abort (); +} + +/* { dg-final { scan-tree-dump-not "(<<|>>)" "original" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */ Marek