diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index 7867ac8424419bfeb1cdbd21f6b98f62979fbf8d..3f9f8c9bdf26f2bc30ac6400b058b2f98f7a6fd1 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -1442,6 +1442,10 @@ vector alignment.
 Target supports both signed and unsigned averaging operations on vectors
 of bytes.
 
+@item vect_condred_si
+Target supports both signed and unsigned averaging operations on vectors
+of integers.
+
 @item vect_condition
 Target supports vector conditional operations.
 
diff --git a/gcc/match.pd b/gcc/match.pd
index 1d13543a6159dc94ce1ff1112c0bfc6b0d588638..3643da4f1158181329987b48b008b0fc82baea32 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3206,7 +3206,41 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  /* !A ? B : C -> A ? C : B.  */
  (simplify
   (cnd (logical_inverted_value truth_valued_p@0) @1 @2)
-  (cnd @0 @2 @1)))
+  (cnd @0 @2 @1))
+
+ /* !A ? B : C -> A ? C : B.  */
+ (simplify
+  (cnd (logical_inverted_value truth_valued_p@0) @1 @2)
+  (cnd @0 @2 @1))
+
+ /* Hack: generic-match causes infinite recursion
+    by reverting this transformation when
+    i) -fno-trapping-math is enabled, and
+    ii) the common operand does not need to be wrapped in a SAVE_EXPR.  */
+#if GIMPLE
+ /* ???  Conditional reduction for supported binary operations of the
+    following form:
+      A ? (B op C) : (B op D) -> B op (A ? C : D)
+    and other operand permutations subject to commutativity of op.
+ */
+ (for op (plus minus mult
+	  min max
+	  bit_and bit_ior bit_xor)
+  (simplify
+   (cnd @0 (op @1 @2) (op @1 @3))
+   (op @1 (cnd @0 @2 @3)))
+  (simplify
+   (cnd @0 (op @1 @2) (op @3 @2))
+   (op (cnd @0 @1 @3) @2))
+  (if (op != MINUS_EXPR)
+   (simplify
+    (cnd @0 (op @1 @2) (op @3 @1))
+    (op @1 (cnd @0 @2 @3)))
+   (simplify
+    (cnd @0 (op @2 @1) (op @1 @3))
+    (op @1 (cnd @0 @2 @3)))))
+#endif
+)
 
 /* A + (B vcmp C ? 1 : 0) -> A - (B vcmp C ? -1 : 0), since vector comparisons
    return all -1 or all 0 results.  */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-condred-1.c b/gcc/testsuite/gcc.dg/vect/vect-condred-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..dd4a62aecb6ce268c191ac31e8bda6e48c2d0485
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-condred-1.c
@@ -0,0 +1,109 @@
+/* { dg-require-effective-target vect_int } */
+
+#include "tree-vect.h"
+
+#ifndef OPERATION
+#define OPERATION(X,Y) ((X) + (Y))
+#endif
+#ifndef COMMUTATIVE
+#define COMMUTATIVE 1
+#endif
+
+#ifndef VALUE_A
+#define VALUE_A 0
+#endif
+#ifndef VALUE_B
+#define VALUE_B 0x4231ed
+#endif
+#ifndef VALUE_C
+#define VALUE_C 0x38abf1
+#endif
+
+#ifndef N
+#define N 50
+#endif
+
+#ifndef PRED_LL
+#define PRED_LL
+static inline int
+predict_LL (int n, int c)
+{
+  return VALUE_A + VALUE_B * c + VALUE_C * (n - c);
+}
+#endif
+#ifndef PRED_RR
+#define PRED_RR
+#define predict_RR predict_LL
+#endif
+#if COMMUTATIVE
+#ifndef PRED_LR
+#define PRED_LR
+#define predict_LR predict_LL
+#endif
+#ifndef PRED_RL
+#define PRED_RL
+#define predict_RL predict_LL
+#endif
+#endif
+
+#define ORDER_L(OP,x,y)	(x) = OP (x,y)
+#define ORDER_R(OP,x,y) (x) = OP (y,x)
+
+#define TEMPLATE(OP,O1,O2)			\
+int __attribute__ ((noipa))			\
+f ## _ ## O1 ## _ ## O2				\
+  (int a, int b, int c, int *restrict m)	\
+{						\
+  for (__INTPTR_TYPE__ i = 0; i < N; i++)	\
+    {						\
+      if ( m[i] == 0 )				\
+	O1 (OP,a,b);				\
+      else					\
+	O2 (OP,a,c);				\
+    }						\
+  return a;					\
+}
+
+TEMPLATE (OPERATION, ORDER_L, ORDER_L);
+TEMPLATE (OPERATION, ORDER_R, ORDER_R);
+#if COMMUTATIVE
+TEMPLATE (OPERATION, ORDER_L, ORDER_R);
+TEMPLATE (OPERATION, ORDER_R, ORDER_L);
+#endif
+
+int
+main (void)
+{
+  check_vect ();
+
+  int m[N];
+  int c = 1;
+  for (int i = 0, k = 0; i < N; i++)
+    {
+      if (k >= c) { k = 0; c++; }
+      m[i] = k++;
+      asm volatile ("" ::: "memory");
+    }
+
+  int a_ll = f_ORDER_L_ORDER_L (VALUE_A, VALUE_B, VALUE_C, m);
+  if (a_ll != predict_LL (N, c))
+    __builtin_abort ();
+  int a_rr = f_ORDER_R_ORDER_R (VALUE_A, VALUE_B, VALUE_C, m);
+  if (a_rr != predict_RR (N, c))
+    __builtin_abort ();
+#if COMMUTATIVE
+  int a_lr = f_ORDER_L_ORDER_R (VALUE_A, VALUE_B, VALUE_C, m);
+  if (a_lr != predict_LR (N, c))
+    __builtin_abort ();
+  int a_rl = f_ORDER_R_ORDER_L (VALUE_A, VALUE_B, VALUE_C, m);
+  if (a_rl != predict_RL (N, c))
+    __builtin_abort ();
+#endif
+
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times {VEC_COND_EXPR} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times {\.COND_ADD} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 4 "vect" { target vect_condred_si } } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-condred-2.c b/gcc/testsuite/gcc.dg/vect/vect-condred-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..85f76fa91c8de618de607bdf361c01c393058259
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-condred-2.c
@@ -0,0 +1,40 @@
+/* { dg-require-effective-target vect_int } */
+
+#define OPERATION(X,Y) ((X) - (Y))
+#define COMMUTATIVE 0
+
+#define VALUE_A 0
+#define VALUE_B 1
+#define VALUE_C 2
+
+#define PRED_LL
+static inline int
+predict_LL (int n, int c)
+{
+  return VALUE_A - (VALUE_B * c + VALUE_C * (n - c));
+}
+#define PRED_RR
+static inline int
+predict_RR (int n, int c)
+{
+  int Nb, Nc;
+  int d = (n - (c * (c - 1) / 2)) % 2;
+  if (c % 2 == 0)
+    {
+      Nb = 0;
+      Nc = ((c / 2) + d) % 2;
+    }
+  else
+    {
+      Nb = 2 * d - 1;
+      Nc = ((c / 2) % 2 == 0) ? (1 - d) : (2 - 3 * d);
+    }
+  return VALUE_A * (2 * (n % 2) - 1) + VALUE_B * Nb + VALUE_C * Nc;
+}
+
+#include "vect-condred-1.c"
+
+/* { dg-final { scan-tree-dump-times {VEC_COND_EXPR} 1 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times {\.COND_SUB} 1 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 4 "vect" { target vect_condred_si } } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-condred-3.c b/gcc/testsuite/gcc.dg/vect/vect-condred-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..838138a51994e3b8255d9a61bc12532704c36dc9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-condred-3.c
@@ -0,0 +1,32 @@
+/* { dg-require-effective-target vect_int } */
+
+#define OPERATION(X,Y) ((X) * (Y))
+
+#define VALUE_A 1
+#define VALUE_B 3
+#define VALUE_C 2
+
+#define N 20
+
+static inline int
+ipow (int x, int n)
+{
+  int y = 1;
+  for (int i = 0; i < n; i++)
+    y *= x;
+  return y;
+}
+
+#define PRED_LL
+static inline int
+predict_LL (int n, int c)
+{
+  return VALUE_A * ipow (VALUE_B, c) * ipow (VALUE_C, n - c);
+}
+
+#include "vect-condred-1.c"
+
+/* { dg-final { scan-tree-dump-times {VEC_COND_EXPR} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times {\.COND_MUL} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 4 "vect" { target vect_condred_si } } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-condred-4.c b/gcc/testsuite/gcc.dg/vect/vect-condred-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..661e41e17ce7d06e33e1914d0f3e9217e2950d74
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-condred-4.c
@@ -0,0 +1,21 @@
+/* { dg-require-effective-target vect_int } */
+
+#define OPERATION(X,Y) ((X) < (Y) ? (X) : (Y))
+
+#define VALUE_A 0x434bed
+#define VALUE_B 0x13bc09
+#define VALUE_C 0xf13a54
+
+#define PRED_LL
+static inline int
+predict_LL (int n, int c)
+{
+  return OPERATION (VALUE_A, OPERATION (VALUE_B, VALUE_C));
+}
+
+#include "vect-condred-1.c"
+
+/* { dg-final { scan-tree-dump-times {VEC_COND_EXPR} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times {\.COND_MIN} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 4 "vect" { target vect_condred_si } } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-condred-5.c b/gcc/testsuite/gcc.dg/vect/vect-condred-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..e34063d75a1c7c2d8fb7ccfd8e693e604799b84c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-condred-5.c
@@ -0,0 +1,21 @@
+/* { dg-require-effective-target vect_int } */
+
+#define OPERATION(X,Y) ((X) > (Y) ? (X) : (Y))
+
+#define VALUE_A 0x342132
+#define VALUE_B 0x539134
+#define VALUE_C 0x767249
+
+#define PRED_LL
+static inline int
+predict_LL (int n, int c)
+{
+  return OPERATION (VALUE_A, OPERATION (VALUE_B, VALUE_C));
+}
+
+#include "vect-condred-1.c"
+
+/* { dg-final { scan-tree-dump-times {VEC_COND_EXPR} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times {\.COND_MAX} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 4 "vect" { target vect_condred_si } } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-condred-6.c b/gcc/testsuite/gcc.dg/vect/vect-condred-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..d95aca375de3626552f6e02a20d2ab655bfe314f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-condred-6.c
@@ -0,0 +1,21 @@
+/* { dg-require-effective-target vect_int } */
+
+#define OPERATION(X,Y) ((X) & (Y))
+
+#define VALUE_A 0x23451f
+#define VALUE_B 0x43509c
+#define VALUE_C 0x52fbea
+
+#define PRED_LL
+static inline int
+predict_LL (int n, int c)
+{
+  return VALUE_A & VALUE_B & VALUE_C;
+}
+
+#include "vect-condred-1.c"
+
+/* { dg-final { scan-tree-dump-times {VEC_COND_EXPR} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times {\.COND_AND} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 4 "vect" { target vect_condred_si } } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-condred-7.c b/gcc/testsuite/gcc.dg/vect/vect-condred-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..343a17743cf87ee77fa25943b05b7bbdfcf8820d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-condred-7.c
@@ -0,0 +1,21 @@
+/* { dg-require-effective-target vect_int } */
+
+#define OPERATION(X,Y) ((X) | (Y))
+
+#define VALUE_A 0x23451f
+#define VALUE_B 0x43509c
+#define VALUE_C 0x52fbea
+
+#define PRED_LL
+static inline int
+predict_LL (int n, int c)
+{
+  return VALUE_A | VALUE_B | VALUE_C;
+}
+
+#include "vect-condred-1.c"
+
+/* { dg-final { scan-tree-dump-times {VEC_COND_EXPR} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times {\.COND_IOR} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 4 "vect" { target vect_condred_si } } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-condred-8.c b/gcc/testsuite/gcc.dg/vect/vect-condred-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..b61cecf0fcd04febfd925efc4286cec096660946
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-condred-8.c
@@ -0,0 +1,21 @@
+/* { dg-require-effective-target vect_int } */
+
+#define OPERATION(X,Y) ((X) ^ (Y))
+
+#define VALUE_A 0x5415be
+#define VALUE_B 0x843fca
+#define VALUE_C 0x1142fc
+
+#define PRED_LL
+static inline int
+predict_LL (int n, int c)
+{
+  return VALUE_A ^ (VALUE_B & (-(c % 2))) ^ (VALUE_C & (-((n - c) % 2)));
+}
+
+#include "vect-condred-1.c"
+
+/* { dg-final { scan-tree-dump-times {VEC_COND_EXPR} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times {\.COND_EOR} 4 "vect" { target vect_condred_si } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 4 "vect" { target vect_condred_si } } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/condred_1.c b/gcc/testsuite/gcc.target/aarch64/sve2/condred_1.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d90548c0fa7cffb266b3c74f7c7c66a918b66dc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve2/condred_1.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-details --save-temps" } */
+
+#include <stdint.h>
+
+#define OP_ADD(X,Y) ((X) + (Y))
+#define OP_SUB(X,Y) ((X) - (Y))
+#define OP_MUL(X,Y) ((X) * (Y))
+#define OP_MIN(X,Y) ((X) < (Y) ? (X) : (Y))
+#define OP_MAX(X,Y) ((X) > (Y) ? (X) : (Y))
+#define OP_AND(X,Y) ((X) & (Y))
+#define OP_IOR(X,Y) ((X) | (Y))
+#define OP_EOR(X,Y) ((X) ^ (Y))
+
+#define CONDRED(OP)				\
+int __attribute__ ((noinline, noclone))		\
+condred_ ## OP					\
+  (int a, int b, int c, int *restrict m, int n)	\
+{						\
+  int i;					\
+  for (i = 0; i < n; i++)			\
+    {						\
+      if ( m[i] == 0 )				\
+	a = OP (a,b);				\
+      else					\
+	a = OP (a,c);				\
+    }						\
+  return a;					\
+}
+
+CONDRED (OP_ADD);
+CONDRED (OP_SUB);
+CONDRED (OP_MUL);
+CONDRED (OP_MIN);
+CONDRED (OP_MAX);
+CONDRED (OP_AND);
+CONDRED (OP_IOR);
+CONDRED (OP_EOR);
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 8 "vect" } } */
+
+/* { dg-final { scan-assembler-times {\tcmpeq\tp[0-9]+\.s, p[0-7]/z, z[0-9]+\.s, #0\n} 7 } } */
+/* { dg-final { scan-assembler-times {\tsel\tz[0-9]+\.s, p[0-7], z[0-9]+\.s, z[0-9]+\.s\n} 7 } } */
+
+/* { dg-final { scan-assembler-times {\tadd\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tsub\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tsmin\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tsmax\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tand\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\torr\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\teor\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+
+// mul falls back to NEON
+/* { dg-final { scan-assembler-times {\tcmeq\tv[0-9]+\.4s, v[0-9]+\.4s, #0\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tmul\tv[0-9]+\.4s, v[0-9]+\.4s, v[0-9]+\.4s\n} 3 } } */
+
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index e32d42491d96959ad04547263f2cc3631f4994d9..5091e9ee5dc84b5f84c0c5a7c9d897b480223731 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -6167,6 +6167,14 @@ proc check_effective_target_vect_avg_qi {} {
 		   && ![check_effective_target_aarch64_sve1_only] }]
 }
 
+# Return 1 if the target plus current options supports both signed
+# and unsigned condition reduction operations on vectors of ints.
+
+proc check_effective_target_vect_condred_si {} {
+    return [expr { [istarget aarch64*-*-*]
+		   && [check_effective_target_aarch64_sve] }]
+}
+
 # Return 1 if the target plus current options supports a vector
 # demotion (packing) of shorts (to chars) and ints (to shorts) 
 # using modulo arithmetic, 0 otherwise.
