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" } } */
