diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index fec2cc91d24..cc9372b178c 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -2588,6 +2588,18 @@
   [(set_attr "type" "neon_tst<q>")]
 )
 
+(define_insn "neon_vtst_combine<mode>"
+  [(set (match_operand:VDQIW 0 "s_register_operand" "=w")
+        (plus:VDQIW
+	  (eq:VDQIW
+	    (and:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w")
+		       (match_operand:VDQIW 2 "s_register_operand" "w"))
+	    (match_operand:VDQIW 3 "zero_operand" "i"))
+	  (match_operand:VDQIW 4 "minus_one_operand" "i")))]
+  "TARGET_NEON"
+  "vtst.<V_sz_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2"
+)
+
 (define_insn "neon_vabd<sup><mode>"
   [(set (match_operand:VDQIW 0 "s_register_operand" "=w")
         (unspec:VDQIW [(match_operand:VDQIW 1 "s_register_operand" "w")
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index c661f015fc5..9db061dc88c 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -200,6 +200,10 @@
   (and (match_code "const_int,const_double,const_vector")
        (match_test "op == CONST0_RTX (mode)")))
 
+(define_predicate "minus_one_operand"
+  (and (match_code "const_int,const_double,const_vector")
+       (match_test "op == CONSTM1_RTX (mode)")))
+
 ;; Match a register, or zero in the appropriate mode.
 (define_predicate "reg_or_zero_operand"
   (ior (match_operand 0 "s_register_operand")
diff --git a/gcc/testsuite/gcc.target/arm/pr97903.c b/gcc/testsuite/gcc.target/arm/pr97903.c
new file mode 100644
index 00000000000..f4058bb1588
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr97903.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-O3" }  */
+/* { dg-add-options arm_neon } */
+
+#include <arm_neon.h>
+
+uint8x8_t f1(int8x8_t a, int8x8_t b) {
+  return (uint8x8_t) ((a & b) != 0);
+}
+
+/* { dg-final { scan-assembler "vtst" } } */
