]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: Implement mask reduction.
authorRobin Dapp <rdapp@ventanamicro.com>
Mon, 20 Oct 2025 08:47:45 +0000 (10:47 +0200)
committerRobin Dapp <rdapp@ventanamicro.com>
Tue, 9 Dec 2025 08:36:03 +0000 (09:36 +0100)
This implements mask reductions by first counting the bits in the mask
(vcpop.m) and then comparing the resulting scalar against 0 or len.

gcc/ChangeLog:

* config/riscv/autovec.md (reduc_sbool_and_scal_<mode>): New
expander.
(reduc_sbool_ior_scal_<mode>): Ditto.
(reduc_sbool_xor_scal_<mode>): Ditto.
* config/riscv/riscv-protos.h (expand_mask_reduction): Declare.
* config/riscv/riscv-v.cc (expand_mask_reduction): New function.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1-run.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2-run.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3-run.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4-run.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5-run.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6-run.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7-run.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8-run.c: New test.
* gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8.c: New test.

19 files changed:
gcc/config/riscv/autovec.md
gcc/config/riscv/riscv-protos.h
gcc/config/riscv/riscv-v.cc
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1-run.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2-run.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3-run.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4-run.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5-run.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6-run.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7-run.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8-run.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8.c [new file with mode: 0644]

index cec0113fca32d80af028e4b8463470398a1b9e49..c694684328f4598cb7a4e4cbae4c13db59279870 100644 (file)
   DONE;
 })
 
+;; -------------------------------------------------------------------------
+;; ---- [INT] Mask reductions
+;; -------------------------------------------------------------------------
+
+(define_expand "reduc_sbool_and_scal_<mode>"
+  [(match_operand:QI 0 "register_operand")
+   (match_operand:VB_VLS 1 "register_operand")]
+  "TARGET_VECTOR"
+{
+  riscv_vector::expand_mask_reduction (operands, AND);
+  DONE;
+})
+
+(define_expand "reduc_sbool_ior_scal_<mode>"
+  [(match_operand:QI 0 "register_operand")
+   (match_operand:VB_VLS 1 "register_operand")]
+  "TARGET_VECTOR"
+{
+  riscv_vector::expand_mask_reduction (operands, IOR);
+  DONE;
+})
+
+(define_expand "reduc_sbool_xor_scal_<mode>"
+  [(match_operand:QI 0 "register_operand")
+   (match_operand:VB_VLS 1 "register_operand")]
+  "TARGET_VECTOR"
+{
+  riscv_vector::expand_mask_reduction (operands, XOR);
+  DONE;
+})
+
 ;; -------------------------------------------------------------------------
 ;; ---- [FP] Tree reductions
 ;; -------------------------------------------------------------------------
index 261c25c4c6b87f72472846bcc6966c42a5695728..817f2d7be4ab6e20870aa365681803c6078511f1 100644 (file)
@@ -664,6 +664,7 @@ bool expand_vec_cmp_float (rtx, rtx_code, rtx, rtx, bool);
 void expand_cond_len_unop (unsigned, rtx *);
 void expand_cond_len_binop (unsigned, rtx *);
 void expand_reduction (unsigned, unsigned, unsigned, rtx *, rtx);
+void expand_mask_reduction (rtx *, rtx_code);
 void expand_vec_ceil (rtx, rtx, machine_mode, machine_mode);
 void expand_vec_floor (rtx, rtx, machine_mode, machine_mode);
 void expand_vec_nearbyint (rtx, rtx, machine_mode, machine_mode);
index c0f0b99fe2484a4d74de6298c0f97002952bf631..fbf2e7a5c4648c4bc57f7007cec731026c2f354d 100644 (file)
@@ -4885,6 +4885,54 @@ expand_reduction (unsigned unspec, unsigned unspec_for_vl0_safe,
   emit_insn (gen_pred_extract_first (m1_mode, scalar_dest, m1_tmp2));
 }
 
+/* Expand mask reductions.  OPS are {dest, src} where DEST's mode
+   is QImode and SRC's mode is a mask mode.
+   CODE is one of AND, IOR, XOR.  */
+
+void
+expand_mask_reduction (rtx *ops, rtx_code code)
+{
+  machine_mode mode = GET_MODE (ops[1]);
+  rtx dest = ops[0];
+  gcc_assert (GET_MODE (dest) == QImode);
+
+  rtx tmp = gen_reg_rtx (Xmode);
+  rtx cpop_ops[] = {tmp, ops[1]};
+  emit_vlmax_insn (code_for_pred_popcount (mode, Xmode), CPOP_OP, cpop_ops);
+
+  bool eq_zero = false;
+
+  /* AND reduction is popcount (mask) == len,
+     IOR reduction is popcount (mask) != 0,
+     XOR reduction is popcount (mask) & 1 != 0.  */
+  if (code == AND)
+    {
+      rtx len = gen_int_mode (GET_MODE_NUNITS (mode), HImode);
+      tmp = expand_binop (Xmode, sub_optab, tmp, len, NULL, true,
+                         OPTAB_DIRECT);
+      eq_zero = true;
+    }
+  else if (code == IOR)
+    ;
+  else if (code == XOR)
+    tmp = expand_binop (Xmode, and_optab, tmp, GEN_INT (1), NULL, true,
+                       OPTAB_DIRECT);
+  else
+    gcc_unreachable ();
+
+  rtx els = gen_label_rtx ();
+  rtx end = gen_label_rtx ();
+
+  riscv_expand_conditional_branch (els, eq_zero ? EQ : NE, tmp, const0_rtx);
+  emit_move_insn (dest, const0_rtx);
+  emit_jump_insn (gen_jump (end));
+  emit_barrier ();
+
+  emit_label (els);
+  emit_move_insn (dest, const1_rtx);
+  emit_label (end);
+}
+
 /* Prepare ops for ternary operations.
    It can be called before or after RA.  */
 void
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1-run.c
new file mode 100644 (file)
index 0000000..b3bf8da
--- /dev/null
@@ -0,0 +1,49 @@
+/* { dg-do run } */
+/* { dg-require-effective-target riscv_v_ok } */
+
+char p[128];
+
+bool __attribute__((noipa))
+fand (int n)
+{
+  bool r = true;
+  for (int i = 0; i < n; ++i)
+    r &= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fior (int n)
+{
+  bool r = false;
+  for (int i = 0; i < n; ++i)
+    r |= (p[i] != 0);
+  return r;
+}
+
+int main()
+{
+  __builtin_memset (p, 1, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (!fand (n))
+      __builtin_abort ();
+
+  p[0] = 0;
+  for (int n = 1; n < 77; ++n)
+    if (fand (n))
+      __builtin_abort ();
+
+  __builtin_memset (p, 0, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (fior (n))
+      __builtin_abort ();
+
+  p[0] = 1;
+  for (int n = 1; n < 77; ++n)
+    if (!fior (n))
+      __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1.c
new file mode 100644 (file)
index 0000000..b8c4f22
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */
+
+char p[128];
+
+bool __attribute__((noipa))
+fand (int n)
+{
+  bool r = true;
+  for (int i = 0; i < 16; ++i)
+    r &= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fior (int n)
+{
+  bool r = false;
+  for (int i = 0; i < 16; ++i)
+    r |= (p[i] != 0);
+  return r;
+}
+
+/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */
+/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2-run.c
new file mode 100644 (file)
index 0000000..1a64b2b
--- /dev/null
@@ -0,0 +1,49 @@
+/* { dg-do run } */
+/* { dg-require-effective-target riscv_v_ok } */
+
+short p[128];
+
+bool __attribute__((noipa))
+fand (int n)
+{
+  bool r = true;
+  for (int i = 0; i < n; ++i)
+    r &= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fior (int n)
+{
+  bool r = false;
+  for (int i = 0; i < n; ++i)
+    r |= (p[i] != 0);
+  return r;
+}
+
+int main()
+{
+  __builtin_memset (p, 1, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (!fand (n))
+      __builtin_abort ();
+
+  p[0] = 0;
+  for (int n = 1; n < 77; ++n)
+    if (fand (n))
+      __builtin_abort ();
+
+  __builtin_memset (p, 0, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (fior (n))
+      __builtin_abort ();
+
+  p[0] = 1;
+  for (int n = 1; n < 77; ++n)
+    if (!fior (n))
+      __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2.c
new file mode 100644 (file)
index 0000000..868f91b
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */
+
+short p[128];
+
+bool __attribute__((noipa))
+fand ()
+{
+  bool r = true;
+  for (int i = 0; i < 16; ++i)
+    r &= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fior ()
+{
+  bool r = false;
+  for (int i = 0; i < 16; ++i)
+    r |= (p[i] != 0);
+  return r;
+}
+
+/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */
+/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3-run.c
new file mode 100644 (file)
index 0000000..693a911
--- /dev/null
@@ -0,0 +1,49 @@
+/* { dg-do run } */
+/* { dg-require-effective-target riscv_v_ok } */
+
+int p[128];
+
+bool __attribute__((noipa))
+fand (int n)
+{
+  bool r = true;
+  for (int i = 0; i < n; ++i)
+    r &= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fior (int n)
+{
+  bool r = false;
+  for (int i = 0; i < n; ++i)
+    r |= (p[i] != 0);
+  return r;
+}
+
+int main()
+{
+  __builtin_memset (p, 1, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (!fand (n))
+      __builtin_abort ();
+
+  p[0] = 0;
+  for (int n = 1; n < 77; ++n)
+    if (fand (n))
+      __builtin_abort ();
+
+  __builtin_memset (p, 0, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (fior (n))
+      __builtin_abort ();
+
+  p[0] = 1;
+  for (int n = 1; n < 77; ++n)
+    if (!fior (n))
+      __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3.c
new file mode 100644 (file)
index 0000000..d1a286b
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */
+
+int p[128];
+
+bool __attribute__((noipa))
+fand ()
+{
+  bool r = true;
+  for (int i = 0; i < 16; ++i)
+    r &= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fior ()
+{
+  bool r = false;
+  for (int i = 0; i < 16; ++i)
+    r |= (p[i] != 0);
+  return r;
+}
+
+/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */
+/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4-run.c
new file mode 100644 (file)
index 0000000..b55925e
--- /dev/null
@@ -0,0 +1,49 @@
+/* { dg-do run } */
+/* { dg-require-effective-target riscv_v_ok } */
+
+long long p[128];
+
+bool __attribute__((noipa))
+fand (int n)
+{
+  bool r = true;
+  for (int i = 0; i < n; ++i)
+    r &= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fior (int n)
+{
+  bool r = false;
+  for (int i = 0; i < n; ++i)
+    r |= (p[i] != 0);
+  return r;
+}
+
+int main()
+{
+  __builtin_memset (p, 1, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (!fand (n))
+      __builtin_abort ();
+
+  p[0] = 0;
+  for (int n = 1; n < 77; ++n)
+    if (fand (n))
+      __builtin_abort ();
+
+  __builtin_memset (p, 0, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (fior (n))
+      __builtin_abort ();
+
+  p[0] = 1;
+  for (int n = 1; n < 77; ++n)
+    if (!fior (n))
+      __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4.c
new file mode 100644 (file)
index 0000000..34a44b1
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */
+
+long long p[128];
+
+bool __attribute__((noipa))
+fand ()
+{
+  bool r = true;
+  for (int i = 0; i < 16; ++i)
+    r &= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fior ()
+{
+  bool r = false;
+  for (int i = 0; i < 16; ++i)
+    r |= (p[i] != 0);
+  return r;
+}
+
+/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */
+/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5-run.c
new file mode 100644 (file)
index 0000000..95570ac
--- /dev/null
@@ -0,0 +1,47 @@
+/* { dg-do run } */
+/* { dg-require-effective-target riscv_v_ok } */
+
+char p[128];
+
+bool __attribute__((noipa))
+fxort (int n)
+{
+  bool r = true;
+  for (int i = 0; i < n; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fxorf (int n)
+{
+  bool r = false;
+  for (int i = 0; i < n; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+int main()
+{
+  __builtin_memset (p, 1, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (fxort (n) != !(n & 1))
+      __builtin_abort ();
+
+  for (int n = 0; n < 77; ++n)
+    if (fxorf (n) != (n & 1))
+      __builtin_abort ();
+
+  __builtin_memset (p, 0, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (!fxort (n))
+      __builtin_abort ();
+
+  for (int n = 0; n < 77; ++n)
+    if (fxorf (n))
+      __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5.c
new file mode 100644 (file)
index 0000000..f179970
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */
+
+char p[128];
+
+bool __attribute__((noipa))
+fxort ()
+{
+  bool r = true;
+  for (int i = 0; i < 16; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fxorf ()
+{
+  bool r = false;
+  for (int i = 0; i < 16; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */
+/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6-run.c
new file mode 100644 (file)
index 0000000..267485b
--- /dev/null
@@ -0,0 +1,47 @@
+/* { dg-do run } */
+/* { dg-require-effective-target riscv_v_ok } */
+
+short p[128];
+
+bool __attribute__((noipa))
+fxort (int n)
+{
+  bool r = true;
+  for (int i = 0; i < n; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fxorf (int n)
+{
+  bool r = false;
+  for (int i = 0; i < n; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+int main()
+{
+  __builtin_memset (p, 1, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (fxort (n) != !(n & 1))
+      __builtin_abort ();
+
+  for (int n = 0; n < 77; ++n)
+    if (fxorf (n) != (n & 1))
+      __builtin_abort ();
+
+  __builtin_memset (p, 0, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (!fxort (n))
+      __builtin_abort ();
+
+  for (int n = 0; n < 77; ++n)
+    if (fxorf (n))
+      __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6.c
new file mode 100644 (file)
index 0000000..8486c6b
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */
+
+short p[128];
+
+bool __attribute__((noipa))
+fxort ()
+{
+  bool r = true;
+  for (int i = 0; i < 16; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fxorf ()
+{
+  bool r = false;
+  for (int i = 0; i < 16; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */
+/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7-run.c
new file mode 100644 (file)
index 0000000..242147b
--- /dev/null
@@ -0,0 +1,47 @@
+/* { dg-do run } */
+/* { dg-require-effective-target riscv_v_ok } */
+
+int p[128];
+
+bool __attribute__((noipa))
+fxort (int n)
+{
+  bool r = true;
+  for (int i = 0; i < n; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fxorf (int n)
+{
+  bool r = false;
+  for (int i = 0; i < n; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+int main()
+{
+  __builtin_memset (p, 1, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (fxort (n) != !(n & 1))
+      __builtin_abort ();
+
+  for (int n = 0; n < 77; ++n)
+    if (fxorf (n) != (n & 1))
+      __builtin_abort ();
+
+  __builtin_memset (p, 0, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (!fxort (n))
+      __builtin_abort ();
+
+  for (int n = 0; n < 77; ++n)
+    if (fxorf (n))
+      __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7.c
new file mode 100644 (file)
index 0000000..cc14996
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */
+
+int p[128];
+
+bool __attribute__((noipa))
+fxort ()
+{
+  bool r = true;
+  for (int i = 0; i < 16; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fxorf ()
+{
+  bool r = false;
+  for (int i = 0; i < 16; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */
+/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8-run.c
new file mode 100644 (file)
index 0000000..bf73da5
--- /dev/null
@@ -0,0 +1,47 @@
+/* { dg-do run } */
+/* { dg-require-effective-target riscv_v_ok } */
+
+long long p[128];
+
+bool __attribute__((noipa))
+fxort (int n)
+{
+  bool r = true;
+  for (int i = 0; i < n; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fxorf (int n)
+{
+  bool r = false;
+  for (int i = 0; i < n; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+int main()
+{
+  __builtin_memset (p, 1, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (fxort (n) != !(n & 1))
+      __builtin_abort ();
+
+  for (int n = 0; n < 77; ++n)
+    if (fxorf (n) != (n & 1))
+      __builtin_abort ();
+
+  __builtin_memset (p, 0, sizeof(p));
+
+  for (int n = 0; n < 77; ++n)
+    if (!fxort (n))
+      __builtin_abort ();
+
+  for (int n = 0; n < 77; ++n)
+    if (fxorf (n))
+      __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8.c
new file mode 100644 (file)
index 0000000..6842f39
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */
+
+long long p[128];
+
+bool __attribute__((noipa))
+fxort ()
+{
+  bool r = true;
+  for (int i = 0; i < 16; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+bool __attribute__((noipa))
+fxorf ()
+{
+  bool r = false;
+  for (int i = 0; i < 16; ++i)
+    r ^= (p[i] != 0);
+  return r;
+}
+
+/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */
+/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */