[PATCH] match.pd: combine a pair of vector comparisons against zero

<[email protected]> Tue, 4 Aug 2026 11:51:59 +0200
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
From: Kyrylo Tkachov <[email protected]>

A lane of A | B is zero exactly when the corresponding lanes of A and of B
are both zero, so

  (A == 0) & (B == 0)  ->  (A | B) == 0

and the De Morgan dual for the inequality.  One vector comparison goes
away.  Reassociation performs this for scalars, but it never runs on
vector masks, so the vector form is left alone today.

  typedef int v4si __attribute__((vector_size (16)));
  v4si f (v4si a, v4si b) { v4si z = {0,0,0,0}; return (a == z) & (b == z); }

aarch64 -O3 before:

	cmeq	v0.4s, v0.4s, #0
	cmeq	v1.4s, v1.4s, #0
	and	v0.16b, v0.16b, v1.16b

after:

	orr	v0.16b, v0.16b, v1.16b
	cmeq	v0.4s, v0.4s, #0

Bootstrapped and tested on aarch64-none-linux-gnu.
Ok for trunk?
Thanks,
Kyrill

gcc/ChangeLog:

	* match.pd ((A == 0) & (B == 0), (A != 0) | (B != 0)): New
	simplifications for vector operands.

gcc/testsuite/ChangeLog:

	* gcc.dg/tree-ssa/vec-mask-zero-1.c: New test.

Signed-off-by: Kyrylo Tkachov <[email protected]>
---
 gcc/match.pd                                    | 14 ++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/vec-mask-zero-1.c | 12 ++++++++++++
 2 files changed, 26 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vec-mask-zero-1.c

diff --git a/gcc/match.pd b/gcc/match.pd
index 22202af2cc1..fc81dfc5e66 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3823,6 +3823,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       { constant_boolean_node (true, type); })
      ))))))
 
+/* Combine two vector comparisons against zero into one:
+     (A == 0) & (B == 0)  -->  (A | B) == 0
+     (A != 0) | (B != 0)  -->  (A | B) != 0
+   Reassociation does this for scalars only, it never runs on vector
+   masks.  */
+(for eqne (eq ne)
+     bitop (bit_and bit_ior)
+ (simplify
+  (bitop (eqne:s @0 integer_zerop) (eqne:s @1 integer_zerop))
+  (if (VECTOR_INTEGER_TYPE_P (TREE_TYPE (@0))
+       && types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
+   (eqne (bit_ior @0 @1)
+	  { build_zero_cst (TREE_TYPE (@0)); }))))
+
 /* Optimize (a CMP b) ^ (a CMP b)  */
 /* Optimize (a CMP b) != (a CMP b)  */
 (for op (bit_xor ne)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vec-mask-zero-1.c b/gcc/testsuite/gcc.dg/tree-ssa/vec-mask-zero-1.c
new file mode 100644
index 00000000000..f8c669636fd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vec-mask-zero-1.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* A lane of A | B is zero exactly when both lanes are, so a pair of vector
+   comparisons against zero becomes one.  Reassociation does this for
+   scalars but never runs on vector masks.  */
+typedef int v4si __attribute__((vector_size (16)));
+v4si f (v4si a, v4si b) { v4si z = {0,0,0,0}; return (a == z) & (b == z); }
+v4si g (v4si a, v4si b) { v4si z = {0,0,0,0}; return (a != z) | (b != z); }
+/* { dg-final { scan-tree-dump-times " == " 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " != " 1 "optimized" } } */
+/* Each function keeps one OR and one comparison.  */
+/* { dg-final { scan-tree-dump-times " \\| " 2 "optimized" } } */
-- 
2.50.1 (Apple Git-155)