[PATCH] Add (1 << A) & 1) folding (PR middle-end/64309)

Marek Polacek polacek@redhat.com
Tue Dec 16 13:28:00 GMT 2014


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  <polacek@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



More information about the Gcc-patches mailing list