This patch implements the AArch64 SVE optabs for early break/control flow
vectorization.  The Splice change is needed to avoid an early-ra weirdness
in that for some reason it really doesn't like using the same register for
all operands.

The SVE implementation maps the active-predicate operations onto BRK*, CNTP,
PFIRST and splice/extract-first sequences.  The count_active_ expander emits a
CNTP under ptrue.  The cond_count_active_ expander emits CNTP under the
caller-supplied governing predicate and now has only the two predicate inputs
that it actually consumes.

For example, a conditional count-active operation is represented as:

  cond_count_active (pg, pred)

and lowers directly to:

  cntp    x0, pg, pred.d

rather than carrying an unused third predicate operand in the expander
pattern.

The patch also generalizes the SVE splice/extract patterns to SVE_ALL so the
same machinery works for partial vectors, derives the 128-bit container mode
from the element mode, and updates the existing no-epilogue SVE codegen tests.

Bootstrapped Regtested on aarch64-none-linux-gnu,
arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
-m32, -m64 and no issues.

-O3, profiled, profiled -O3 and -O3 -LTO bootstrap tested and no issues.

 Also SPECCPU 2017 and SPECCPU 2026 tested.

OK for master?

gcc/ChangeLog:
        * config/aarch64/aarch64-sve.md
        (*vec_extract<mode><Vel>_0): Use SVE_ALL and derive the 128-bit
        container mode from the element mode.
        (@aarch64_sve_splice<mode>): Use SVE_ALL and Vctype.
        (extract_first_<mode>): New expander.
        (take_<brk_name>_active_<mode>): Likewise.
        (cond_take_<brk_name>_active_<mode>): Likewise.
        (count_active_<mode>): Likewise.
        (cond_count_active_<mode>): Likewise.
        * config/aarch64/aarch64-sve2.md
        (index_first_active_<mode>): New expander.
        (cond_index_first_active_<mode>): Likewise.
        * config/aarch64/iterators.md (brk_name): New int attribute.

gcc/testsuite/ChangeLog:
        * gcc.target/aarch64/sve/noeffect3.c: Update expected output.
        * gcc.target/aarch64/sve/noeffect4.c: Likewise.
        * gcc.target/aarch64/sve/noeffect5.c: Likewise.
        * gcc.target/aarch64/sve/noeffect6.c: Likewise.
        * gcc.target/aarch64/sve/noeffect7.c: Likewise.
        * gcc.target/aarch64/sve2/vect-early-break-firstp_1.c: New test.

---
diff --git a/gcc/config/aarch64/aarch64-sve.md 
b/gcc/config/aarch64/aarch64-sve.md
index 
7a5db18586f1bdf9df1626477d81d42368f9e0a4..f5c0066ad11126797176b2092635045442d77783
 100644
--- a/gcc/config/aarch64/aarch64-sve.md
+++ b/gcc/config/aarch64/aarch64-sve.md
@@ -3220,11 +3220,12 @@ (define_expand "vec_extract<mode><v64>"
 (define_insn_and_split "*vec_extract<mode><Vel>_0"
   [(set (match_operand:<VEL> 0 "aarch64_simd_nonimmediate_operand" "=r, w, 
Utv")
        (vec_select:<VEL>
-         (match_operand:SVE_FULL 1 "register_operand" "w, 0, w")
+         (match_operand:SVE_ALL 1 "register_operand" "w, 0, w")
          (parallel [(const_int 0)])))]
   "TARGET_SVE"
   {
-    operands[1] = gen_rtx_REG (<V128>mode, REGNO (operands[1]));
+    machine_mode vq_mode = aarch64_v128_mode (<VEL>mode).require ();
+    operands[1] = gen_rtx_REG (vq_mode, REGNO (operands[1]));
     switch (which_alternative)
       {
        case 0:
@@ -10449,20 +10450,40 @@ (define_insn "@aarch64_sve_rev<mode>"
 
 ;; Like EXT, but start at the first active element.
 (define_insn "@aarch64_sve_splice<mode>"
-  [(set (match_operand:SVE_FULL 0 "register_operand")
-       (unspec:SVE_FULL
+  [(set (match_operand:SVE_ALL 0 "register_operand")
+       (unspec:SVE_ALL
          [(match_operand:<VPRED> 1 "register_operand")
-          (match_operand:SVE_FULL 2 "register_operand")
-          (match_operand:SVE_FULL 3 "register_operand")]
+          (match_operand:SVE_ALL 2 "register_operand")
+          (match_operand:SVE_ALL 3 "register_operand")]
          UNSPEC_SVE_SPLICE))]
   "TARGET_SVE"
   {@ [ cons: =0 , 1   , 2 , 3 ; attrs: movprfx ]
-     [ w        , Upl , 0 , w ; *              ] splice\t%0.<Vetype>, %1, 
%0.<Vetype>, %3.<Vetype>
-     [ ?&w      , Upl , w , w ; yes            ] movprfx\t%0, 
%2\;splice\t%0.<Vetype>, %1, %0.<Vetype>, %3.<Vetype>
+     [ w        , Upl , 0 , w ; *              ] splice\t%0.<Vctype>, %1, 
%0.<Vctype>, %3.<Vctype>
+     [ w        , Upl , 0 , 0 ; *              ] splice\t%0.<Vctype>, %1, 
%0.<Vctype>, %0.<Vctype>
+     [ ?&w      , Upl , w , w ; yes            ] movprfx\t%0, 
%2\;splice\t%0.<Vctype>, %1, %0.<Vctype>, %3.<Vctype>
   }
   [(set_attr "sve_type" "sve_int_extract")]
 )
 
+;; Vectorizer EXTRACT_FIRST implementation.
+;; For example: splice z0.d, p1, z0.d, z2.d; mov x0, z0.d[0].
+(define_expand "extract_first_<mode>"
+  [(set (match_operand:<VEL> 0 "register_operand")
+       (unspec:<VEL>
+         [(match_operand:<VPRED> 1 "register_operand")
+          (match_operand:SVE_ALL 2 "register_operand")]
+         UNSPEC_SVE_SPLICE))]
+  "TARGET_SVE"
+{
+  rtx dest = gen_reg_rtx (<MODE>mode);
+  emit_insn (gen_aarch64_sve_splice (<MODE>mode, dest, operands[1],
+                                    operands[2], operands[2]));
+  rtx sel = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, const0_rtx));
+  emit_insn (gen_rtx_SET (operands[0],
+                         gen_rtx_VEC_SELECT (<VEL>mode, dest, sel)));
+  DONE;
+})
+
 ;; Permutes that take half the elements from one vector and half the
 ;; elements from the other.
 (define_insn "@aarch64_sve_<perm_insn><mode>"
@@ -11703,6 +11724,45 @@ (define_insn "@aarch64_brk<brk_op>"
   [(set_attr "sve_type" "sve_pred_cnt_ctrl")]
 )
 
+;; Vectorizer implementations for take_*_active and cond_take_*_active.
+;; For example: brka p0.b, ptrue/z, p1.b.
+(define_expand "take_<brk_name>_active_<mode>"
+  [(set (match_operand:PRED_ALL 0 "register_operand")
+       (unspec:PRED_ALL
+         [(match_operand:PRED_ALL 1 "register_operand")]
+         SVE_BRK_UNARY))]
+  "TARGET_SVE"
+{
+  rtx dest = gen_reg_rtx (VNx16BImode);
+  rtx mask = aarch64_ptrue_reg (VNx16BImode);
+  rtx pred = force_lowpart_subreg (VNx16BImode, operands[1], <MODE>mode);
+  emit_insn (gen_aarch64_brk<brk_op> (dest, mask, pred,
+                                     CONST0_RTX (VNx16BImode)));
+  emit_move_insn (operands[0],
+                 force_lowpart_subreg (<MODE>mode, dest, VNx16BImode));
+  DONE;
+})
+
+;; For example: brkb p0.b, p1/m, p2.b.
+(define_expand "cond_take_<brk_name>_active_<mode>"
+  [(set (match_operand:PRED_ALL 0 "register_operand")
+       (unspec:PRED_ALL
+         [(match_operand:PRED_ALL 1 "register_operand")
+          (match_operand:PRED_ALL 2 "register_operand")
+          (match_operand:PRED_ALL 3 "aarch64_simd_reg_or_zero")]
+         SVE_BRK_UNARY))]
+  "TARGET_SVE"
+{
+  rtx dest = gen_reg_rtx (VNx16BImode);
+  rtx tmp1 = force_lowpart_subreg (VNx16BImode, operands[1], <MODE>mode);
+  rtx tmp2 = force_lowpart_subreg (VNx16BImode, operands[2], <MODE>mode);
+  rtx tmp3 = force_lowpart_subreg (VNx16BImode, operands[3], <MODE>mode);
+  emit_insn (gen_aarch64_brk<brk_op> (dest, tmp1, tmp2, tmp3));
+  emit_move_insn (operands[0],
+                 force_lowpart_subreg (<MODE>mode, dest, VNx16BImode));
+  DONE;
+})
+
 ;; Same, but also producing a flags result.
 (define_insn "*aarch64_brk<brk_op>_cc"
   [(set (reg:CC_NZC CC_REGNUM)
@@ -12401,6 +12461,39 @@ (define_insn "@aarch64_pred_cntp<mode>"
   [(set_attr "sve_type" "sve_pred_cnt_scalar")]
 )
 
+
+;; Vectorizer implementation of CNTP including special support for partial
+;; vectors which need to not double count.
+;; For example: cntp x0, ptrue, p1.d.
+(define_expand "count_active_<mode>"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (zero_extend:DI
+         (unspec:SI [(match_operand:PRED_ALL 1 "register_operand")]
+                    UNSPEC_CNTP)))]
+  "TARGET_SVE"
+{
+  rtx ptrue = aarch64_ptrue_reg (<MODE>mode);
+  rtx gp_flag = gen_int_mode (SVE_KNOWN_PTRUE, SImode);
+  emit_insn (gen_aarch64_pred_cntp (<MODE>mode, operands[0], ptrue,
+                                   gp_flag, operands[1]));
+  DONE;
+})
+
+;; For example: cntp x0, p1, p2.d.
+(define_expand "cond_count_active_<mode>"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (zero_extend:DI
+         (unspec:SI [(match_operand:PRED_ALL 1 "register_operand" "Upl")
+                     (match_operand:PRED_ALL 2 "register_operand" "Upa")]
+                    UNSPEC_CNTP)))]
+  "TARGET_SVE"
+{
+  rtx gp_flag = gen_int_mode (SVE_MAYBE_NOT_PTRUE, SImode);
+  emit_insn (gen_aarch64_pred_cntp (<MODE>mode, operands[0], operands[1],
+                                   gp_flag, operands[2]));
+  DONE;
+})
+
 ;; -------------------------------------------------------------------------
 ;; ---- [INT] Increment by the number of elements in a predicate (scalar)
 ;; -------------------------------------------------------------------------
diff --git a/gcc/config/aarch64/aarch64-sve2.md 
b/gcc/config/aarch64/aarch64-sve2.md
index 
3a1285a6a008d934a79eb91ac31c5598e4604898..4c1ded3ce6c93cf94093bfcb815c038458d4d4d0
 100644
--- a/gcc/config/aarch64/aarch64-sve2.md
+++ b/gcc/config/aarch64/aarch64-sve2.md
@@ -744,6 +744,32 @@ (define_insn "@aarch64_pred_firstp<mode>"
   [(set_attr "sve_type" "sve_pred_cnt_scalar")]
 )
 
+;; For example: firstp x0, ptrue, p1.d.
+(define_expand "index_first_active_<mode>"
+  [(set (match_operand:DI 0 "register_operand")
+       (unspec:DI [(match_operand:PRED_ALL 1 "register_operand")]
+                  UNSPEC_FIRSTP))]
+  "TARGET_SVE2p2_OR_SME2p2"
+{
+  rtx ptrue = aarch64_ptrue_reg (<MODE>mode);
+  emit_insn (gen_aarch64_pred_firstp (<MODE>mode, operands[0], ptrue,
+                                     operands[1]));
+  DONE;
+})
+
+;; For example: firstp x0, p1, p2.d.
+(define_expand "cond_index_first_active_<mode>"
+  [(set (match_operand:DI 0 "register_operand")
+       (unspec:DI [(match_operand:PRED_ALL 1 "register_operand")
+                   (match_operand:PRED_ALL 2 "register_operand")]
+                  UNSPEC_FIRSTP))]
+  "TARGET_SVE2p2_OR_SME2p2"
+{
+  emit_insn (gen_aarch64_pred_firstp (<MODE>mode, operands[0], operands[1],
+                                     operands[2]));
+  DONE;
+})
+
 ;; Count the number of set bits in a predicate.  Operand 3 is true if
 ;; operand 1 is known to be all-true.
 (define_insn "@aarch64_pred_lastp<mode>"
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 
af417b51ccf31bf56d4e4f368979971c05e0b482..7ed204a0b3669a887b453ac2dff36550986c53ef
 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -4997,6 +4997,8 @@ (define_int_attr brk_op [(UNSPEC_BRKA "a") (UNSPEC_BRKB 
"b")
                         (UNSPEC_BRKN "n")
                         (UNSPEC_BRKPA "pa") (UNSPEC_BRKPB "pb")])
 
+(define_int_attr brk_name [(UNSPEC_BRKA "incl") (UNSPEC_BRKB "excl")])
+
 (define_int_attr sve_pred_op [(UNSPEC_PFIRST "pfirst") (UNSPEC_PNEXT "pnext")])
 
 (define_int_attr sve_int_op [(UNSPEC_ADCLB "adclb")
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/noeffect3.c 
b/gcc/testsuite/gcc.target/aarch64/sve/noeffect3.c
index 
c5f81bb0d303a070b482ec40d2921f6e6236ce67..031af2f4887d3602d384e74754778d032c8ccba5
 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/noeffect3.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/noeffect3.c
@@ -14,10 +14,10 @@ int b[N] = {0};
 **     ld1w    z[0-9]+\.s, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 2\]
 **     ld1w    z[0-9]+\.s, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 2\]
 **     cmpgt   p[0-9]+\.s, p[0-9]+/z, z[0-9]+\.s, z[0-9]+\.s
+**     b\.none \.L[0-9]+
 **     ...
-**     ldr     w[0-9]+, \[x[0-9]+, x[0-9]+, lsl 2\]
-**     ldr     w[0-9]+, \[x[0-9]+, x[0-9]+, lsl 2\]
-**     cmp     w[0-9]+, w[0-9]+
+**     brkb    p[0-9]+\.b, p[0-9]+/z, p[0-9]+\.b
+**     incp    x[0-9]+, p[0-9]+\.s
 **     ...
 **     ret
 **     ...
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/noeffect4.c 
b/gcc/testsuite/gcc.target/aarch64/sve/noeffect4.c
index 
735b54523b4d29de56cc2d894c3a69d57173e4ca..230d9d7761baef1bb91be7b92086bb0475921dac
 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/noeffect4.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/noeffect4.c
@@ -12,11 +12,10 @@ short b[N] = {0};
 **     ld1h    z[0-9]+\.s, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 1\]
 **     ld1h    z[0-9]+\.s, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 1\]
 **     cmpgt   p[0-9]+\.h, p[0-9]+/z, z[0-9]+\.h, z[0-9]+\.h
-**     ...
-**     ldrsh   w[0-9]+, \[x[0-9]+, x[0-9]+\]
-**     ldrsh   w[0-9]+, \[x[0-9]+, x[0-9]+\]
-**     ...
-**     cmp     w[0-9]+, w[0-9]+
+**     ptest   p[0-9]+, p[0-9]+\.b
+**     b\.none \.L[0-9]+
+**     splice  z[0-9]+\.s, p[0-9]+, z[0-9]+\.s, z[0-9]+\.s
+**     umov    w0, v[0-9]+\.h\[0\]
 **     ...
 **     ret
 **     ...
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/noeffect5.c 
b/gcc/testsuite/gcc.target/aarch64/sve/noeffect5.c
index 
bfaec5805785217ae3d2672c3c6669e59d8a5c1a..8397c92760d64a43a930d3d258602f36b91b128b
 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/noeffect5.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/noeffect5.c
@@ -12,11 +12,10 @@ short b[N] = {0};
 **     ld1h    z[0-9]+\.h, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 1\]
 **     ld1h    z[0-9]+\.h, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 1\]
 **     cmpgt   p[0-9]+\.h, p[0-9]+/z, z[0-9]+\.h, z[0-9]+\.h
+**     b\.none \.L[0-9]+
 **     ...
-**     ldrsh   w[0-9]+, \[x[0-9]+, x[0-9]+\]
-**     ldrsh   w[0-9]+, \[x[0-9]+, x[0-9]+\]
-**     ...
-**     cmp     w[0-9]+, w[0-9]+
+**     brkb    p[0-9]+\.b, p[0-9]+/z, p[0-9]+\.b
+**     incp    x[0-9]+, p[0-9]+\.h
 **     ...
 **     ret
 **     ...
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/noeffect6.c 
b/gcc/testsuite/gcc.target/aarch64/sve/noeffect6.c
index 
14438830453aad97b325ac1e5aad849a095343d9..6675f97c41986659a8b03a6c3015b3c31a2046a9
 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/noeffect6.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/noeffect6.c
@@ -1,26 +1,14 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -march=armv8-a+sve 
--param=aarch64-autovec-preference=sve-only -msve-vector-bits=scalable" } */
-/* { dg-final { check-function-bodies "**" "" "" } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.h, p[0-9]+/z, 
\[x[0-9]+, x[0-9]+(, lsl 1)?\]} 2 } } */
+/* { dg-final { scan-assembler {\tcmpgt\tp[0-9]+\.h, p[0-9]+/z, z[0-9]+\.h, 
z[0-9]+\.h} } } */
+/* { dg-final { scan-assembler {\tb\.none\t\.L[0-9]+} } } */
+/* { dg-final { scan-assembler {\tsplice\tz[0-9]+\.h, p[0-9]+, z[0-9]+\.h, 
z[0-9]+\.h} } } */
 
 #define N 1000
 short a[N] = {0};
 short b[N] = {0};
 
-/*
-** foo:
-**     ...
-**     ld1h    z[0-9]+\.h, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 1\]
-**     ld1h    z[0-9]+\.h, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 1\]
-**     cmpgt   p[0-9]+\.h, p[0-9]+/z, z[0-9]+\.h, z[0-9]+\.h
-**     ...
-**     ldrsh   w[0-9]+, \[x[0-9]+, x[0-9]+\]
-**     ldrsh   w[0-9]+, \[x[0-9]+, x[0-9]+\]
-**     ...
-**     cmp     w[0-9]+, w[0-9]+
-**     ...
-**     ret
-**     ...
-*/
 __attribute__ ((noipa, noinline))
 short foo (void)
 {
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/noeffect7.c 
b/gcc/testsuite/gcc.target/aarch64/sve/noeffect7.c
index 
9dab90e72b25b552daad81fdc27dc69dc329cbb0..22f686f70faf418230b0671634770ab8c0356d43
 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/noeffect7.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/noeffect7.c
@@ -12,7 +12,7 @@ int b[N] = {0};
 **     ld2w    \{z[0-9]+\.s - z[0-9]+\.s\}, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 
2\]
 **     ...
 **     cmpgt   p[0-9]+\.s, p[0-9]+/z, z[0-9]+\.s, z[0-9]+\.s
-**     ptest   p[0-9]+, p[0-9]+\.b
+**     b\.any  \.L[0-9]+
 **     ...
 **     ldr     w[0-9]+, \[x[0-9]+, x[0-9]+, lsl 2\]
 **     ldr     w[0-9]+, \[x[0-9]+, x[0-9]+, lsl 2\]
diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/vect-early-break-firstp_1.c 
b/gcc/testsuite/gcc.target/aarch64/sve2/vect-early-break-firstp_1.c
new file mode 100644
index 
0000000000000000000000000000000000000000..a67352ff1a94b7c3ac40cb53bdd9f34b2805c086
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve2/vect-early-break-firstp_1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-Ofast -march=armv8.3-a+sve2p2 -mautovec-preference=sve-only" 
} */
+
+enum codetype { DISTS };
+
+int max_count;
+short count[5];
+
+int __attribute__ ((noipa))
+f (enum codetype type, short lens, unsigned codes, int table, unsigned *bits,
+   short work)
+{
+  unsigned int min;
+
+  if (max_count == 0)
+    {
+      *bits = 1;
+      return 0;
+    }
+
+  min = 1;
+  for (; min < max_count; min++)
+    if (count[min])
+      break;
+
+  *bits = min;
+  return 0;
+}
+
+/* { dg-final { scan-assembler {\tfirstp\tx[0-9]+, p[0-9]+, p[0-9]+\.s} } } */


-- 
diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md
index 7a5db18586f1bdf9df1626477d81d42368f9e0a4..f5c0066ad11126797176b2092635045442d77783 100644
--- a/gcc/config/aarch64/aarch64-sve.md
+++ b/gcc/config/aarch64/aarch64-sve.md
@@ -3220,11 +3220,12 @@ (define_expand "vec_extract<mode><v64>"
 (define_insn_and_split "*vec_extract<mode><Vel>_0"
   [(set (match_operand:<VEL> 0 "aarch64_simd_nonimmediate_operand" "=r, w, Utv")
 	(vec_select:<VEL>
-	  (match_operand:SVE_FULL 1 "register_operand" "w, 0, w")
+	  (match_operand:SVE_ALL 1 "register_operand" "w, 0, w")
 	  (parallel [(const_int 0)])))]
   "TARGET_SVE"
   {
-    operands[1] = gen_rtx_REG (<V128>mode, REGNO (operands[1]));
+    machine_mode vq_mode = aarch64_v128_mode (<VEL>mode).require ();
+    operands[1] = gen_rtx_REG (vq_mode, REGNO (operands[1]));
     switch (which_alternative)
       {
 	case 0:
@@ -10449,20 +10450,40 @@ (define_insn "@aarch64_sve_rev<mode>"
 
 ;; Like EXT, but start at the first active element.
 (define_insn "@aarch64_sve_splice<mode>"
-  [(set (match_operand:SVE_FULL 0 "register_operand")
-	(unspec:SVE_FULL
+  [(set (match_operand:SVE_ALL 0 "register_operand")
+	(unspec:SVE_ALL
 	  [(match_operand:<VPRED> 1 "register_operand")
-	   (match_operand:SVE_FULL 2 "register_operand")
-	   (match_operand:SVE_FULL 3 "register_operand")]
+	   (match_operand:SVE_ALL 2 "register_operand")
+	   (match_operand:SVE_ALL 3 "register_operand")]
 	  UNSPEC_SVE_SPLICE))]
   "TARGET_SVE"
   {@ [ cons: =0 , 1   , 2 , 3 ; attrs: movprfx ]
-     [ w        , Upl , 0 , w ; *              ] splice\t%0.<Vetype>, %1, %0.<Vetype>, %3.<Vetype>
-     [ ?&w      , Upl , w , w ; yes            ] movprfx\t%0, %2\;splice\t%0.<Vetype>, %1, %0.<Vetype>, %3.<Vetype>
+     [ w        , Upl , 0 , w ; *              ] splice\t%0.<Vctype>, %1, %0.<Vctype>, %3.<Vctype>
+     [ w        , Upl , 0 , 0 ; *              ] splice\t%0.<Vctype>, %1, %0.<Vctype>, %0.<Vctype>
+     [ ?&w      , Upl , w , w ; yes            ] movprfx\t%0, %2\;splice\t%0.<Vctype>, %1, %0.<Vctype>, %3.<Vctype>
   }
   [(set_attr "sve_type" "sve_int_extract")]
 )
 
+;; Vectorizer EXTRACT_FIRST implementation.
+;; For example: splice z0.d, p1, z0.d, z2.d; mov x0, z0.d[0].
+(define_expand "extract_first_<mode>"
+  [(set (match_operand:<VEL> 0 "register_operand")
+	(unspec:<VEL>
+	  [(match_operand:<VPRED> 1 "register_operand")
+	   (match_operand:SVE_ALL 2 "register_operand")]
+	  UNSPEC_SVE_SPLICE))]
+  "TARGET_SVE"
+{
+  rtx dest = gen_reg_rtx (<MODE>mode);
+  emit_insn (gen_aarch64_sve_splice (<MODE>mode, dest, operands[1],
+				     operands[2], operands[2]));
+  rtx sel = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, const0_rtx));
+  emit_insn (gen_rtx_SET (operands[0],
+			  gen_rtx_VEC_SELECT (<VEL>mode, dest, sel)));
+  DONE;
+})
+
 ;; Permutes that take half the elements from one vector and half the
 ;; elements from the other.
 (define_insn "@aarch64_sve_<perm_insn><mode>"
@@ -11703,6 +11724,45 @@ (define_insn "@aarch64_brk<brk_op>"
   [(set_attr "sve_type" "sve_pred_cnt_ctrl")]
 )
 
+;; Vectorizer implementations for take_*_active and cond_take_*_active.
+;; For example: brka p0.b, ptrue/z, p1.b.
+(define_expand "take_<brk_name>_active_<mode>"
+  [(set (match_operand:PRED_ALL 0 "register_operand")
+	(unspec:PRED_ALL
+	  [(match_operand:PRED_ALL 1 "register_operand")]
+	  SVE_BRK_UNARY))]
+  "TARGET_SVE"
+{
+  rtx dest = gen_reg_rtx (VNx16BImode);
+  rtx mask = aarch64_ptrue_reg (VNx16BImode);
+  rtx pred = force_lowpart_subreg (VNx16BImode, operands[1], <MODE>mode);
+  emit_insn (gen_aarch64_brk<brk_op> (dest, mask, pred,
+				      CONST0_RTX (VNx16BImode)));
+  emit_move_insn (operands[0],
+		  force_lowpart_subreg (<MODE>mode, dest, VNx16BImode));
+  DONE;
+})
+
+;; For example: brkb p0.b, p1/m, p2.b.
+(define_expand "cond_take_<brk_name>_active_<mode>"
+  [(set (match_operand:PRED_ALL 0 "register_operand")
+	(unspec:PRED_ALL
+	  [(match_operand:PRED_ALL 1 "register_operand")
+	   (match_operand:PRED_ALL 2 "register_operand")
+	   (match_operand:PRED_ALL 3 "aarch64_simd_reg_or_zero")]
+	  SVE_BRK_UNARY))]
+  "TARGET_SVE"
+{
+  rtx dest = gen_reg_rtx (VNx16BImode);
+  rtx tmp1 = force_lowpart_subreg (VNx16BImode, operands[1], <MODE>mode);
+  rtx tmp2 = force_lowpart_subreg (VNx16BImode, operands[2], <MODE>mode);
+  rtx tmp3 = force_lowpart_subreg (VNx16BImode, operands[3], <MODE>mode);
+  emit_insn (gen_aarch64_brk<brk_op> (dest, tmp1, tmp2, tmp3));
+  emit_move_insn (operands[0],
+		  force_lowpart_subreg (<MODE>mode, dest, VNx16BImode));
+  DONE;
+})
+
 ;; Same, but also producing a flags result.
 (define_insn "*aarch64_brk<brk_op>_cc"
   [(set (reg:CC_NZC CC_REGNUM)
@@ -12401,6 +12461,39 @@ (define_insn "@aarch64_pred_cntp<mode>"
   [(set_attr "sve_type" "sve_pred_cnt_scalar")]
 )
 
+
+;; Vectorizer implementation of CNTP including special support for partial
+;; vectors which need to not double count.
+;; For example: cntp x0, ptrue, p1.d.
+(define_expand "count_active_<mode>"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(zero_extend:DI
+	  (unspec:SI [(match_operand:PRED_ALL 1 "register_operand")]
+		     UNSPEC_CNTP)))]
+  "TARGET_SVE"
+{
+  rtx ptrue = aarch64_ptrue_reg (<MODE>mode);
+  rtx gp_flag = gen_int_mode (SVE_KNOWN_PTRUE, SImode);
+  emit_insn (gen_aarch64_pred_cntp (<MODE>mode, operands[0], ptrue,
+				    gp_flag, operands[1]));
+  DONE;
+})
+
+;; For example: cntp x0, p1, p2.d.
+(define_expand "cond_count_active_<mode>"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(zero_extend:DI
+	  (unspec:SI [(match_operand:PRED_ALL 1 "register_operand" "Upl")
+		      (match_operand:PRED_ALL 2 "register_operand" "Upa")]
+		     UNSPEC_CNTP)))]
+  "TARGET_SVE"
+{
+  rtx gp_flag = gen_int_mode (SVE_MAYBE_NOT_PTRUE, SImode);
+  emit_insn (gen_aarch64_pred_cntp (<MODE>mode, operands[0], operands[1],
+				    gp_flag, operands[2]));
+  DONE;
+})
+
 ;; -------------------------------------------------------------------------
 ;; ---- [INT] Increment by the number of elements in a predicate (scalar)
 ;; -------------------------------------------------------------------------
diff --git a/gcc/config/aarch64/aarch64-sve2.md b/gcc/config/aarch64/aarch64-sve2.md
index 3a1285a6a008d934a79eb91ac31c5598e4604898..4c1ded3ce6c93cf94093bfcb815c038458d4d4d0 100644
--- a/gcc/config/aarch64/aarch64-sve2.md
+++ b/gcc/config/aarch64/aarch64-sve2.md
@@ -744,6 +744,32 @@ (define_insn "@aarch64_pred_firstp<mode>"
   [(set_attr "sve_type" "sve_pred_cnt_scalar")]
 )
 
+;; For example: firstp x0, ptrue, p1.d.
+(define_expand "index_first_active_<mode>"
+  [(set (match_operand:DI 0 "register_operand")
+	(unspec:DI [(match_operand:PRED_ALL 1 "register_operand")]
+		   UNSPEC_FIRSTP))]
+  "TARGET_SVE2p2_OR_SME2p2"
+{
+  rtx ptrue = aarch64_ptrue_reg (<MODE>mode);
+  emit_insn (gen_aarch64_pred_firstp (<MODE>mode, operands[0], ptrue,
+				      operands[1]));
+  DONE;
+})
+
+;; For example: firstp x0, p1, p2.d.
+(define_expand "cond_index_first_active_<mode>"
+  [(set (match_operand:DI 0 "register_operand")
+	(unspec:DI [(match_operand:PRED_ALL 1 "register_operand")
+		    (match_operand:PRED_ALL 2 "register_operand")]
+		   UNSPEC_FIRSTP))]
+  "TARGET_SVE2p2_OR_SME2p2"
+{
+  emit_insn (gen_aarch64_pred_firstp (<MODE>mode, operands[0], operands[1],
+				      operands[2]));
+  DONE;
+})
+
 ;; Count the number of set bits in a predicate.  Operand 3 is true if
 ;; operand 1 is known to be all-true.
 (define_insn "@aarch64_pred_lastp<mode>"
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index af417b51ccf31bf56d4e4f368979971c05e0b482..7ed204a0b3669a887b453ac2dff36550986c53ef 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -4997,6 +4997,8 @@ (define_int_attr brk_op [(UNSPEC_BRKA "a") (UNSPEC_BRKB "b")
 			 (UNSPEC_BRKN "n")
 			 (UNSPEC_BRKPA "pa") (UNSPEC_BRKPB "pb")])
 
+(define_int_attr brk_name [(UNSPEC_BRKA "incl") (UNSPEC_BRKB "excl")])
+
 (define_int_attr sve_pred_op [(UNSPEC_PFIRST "pfirst") (UNSPEC_PNEXT "pnext")])
 
 (define_int_attr sve_int_op [(UNSPEC_ADCLB "adclb")
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/noeffect3.c b/gcc/testsuite/gcc.target/aarch64/sve/noeffect3.c
index c5f81bb0d303a070b482ec40d2921f6e6236ce67..031af2f4887d3602d384e74754778d032c8ccba5 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/noeffect3.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/noeffect3.c
@@ -14,10 +14,10 @@ int b[N] = {0};
 **	ld1w	z[0-9]+\.s, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 2\]
 **	ld1w	z[0-9]+\.s, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 2\]
 **	cmpgt	p[0-9]+\.s, p[0-9]+/z, z[0-9]+\.s, z[0-9]+\.s
+**	b\.none	\.L[0-9]+
 **	...
-**	ldr	w[0-9]+, \[x[0-9]+, x[0-9]+, lsl 2\]
-**	ldr	w[0-9]+, \[x[0-9]+, x[0-9]+, lsl 2\]
-**	cmp	w[0-9]+, w[0-9]+
+**	brkb	p[0-9]+\.b, p[0-9]+/z, p[0-9]+\.b
+**	incp	x[0-9]+, p[0-9]+\.s
 **	...
 **	ret
 **	...
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/noeffect4.c b/gcc/testsuite/gcc.target/aarch64/sve/noeffect4.c
index 735b54523b4d29de56cc2d894c3a69d57173e4ca..230d9d7761baef1bb91be7b92086bb0475921dac 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/noeffect4.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/noeffect4.c
@@ -12,11 +12,10 @@ short b[N] = {0};
 **	ld1h	z[0-9]+\.s, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 1\]
 **	ld1h	z[0-9]+\.s, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 1\]
 **	cmpgt	p[0-9]+\.h, p[0-9]+/z, z[0-9]+\.h, z[0-9]+\.h
-**	...
-**	ldrsh	w[0-9]+, \[x[0-9]+, x[0-9]+\]
-**	ldrsh	w[0-9]+, \[x[0-9]+, x[0-9]+\]
-**	...
-**	cmp	w[0-9]+, w[0-9]+
+**	ptest	p[0-9]+, p[0-9]+\.b
+**	b\.none	\.L[0-9]+
+**	splice	z[0-9]+\.s, p[0-9]+, z[0-9]+\.s, z[0-9]+\.s
+**	umov	w0, v[0-9]+\.h\[0\]
 **	...
 **	ret
 **	...
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/noeffect5.c b/gcc/testsuite/gcc.target/aarch64/sve/noeffect5.c
index bfaec5805785217ae3d2672c3c6669e59d8a5c1a..8397c92760d64a43a930d3d258602f36b91b128b 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/noeffect5.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/noeffect5.c
@@ -12,11 +12,10 @@ short b[N] = {0};
 **	ld1h	z[0-9]+\.h, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 1\]
 **	ld1h	z[0-9]+\.h, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 1\]
 **	cmpgt	p[0-9]+\.h, p[0-9]+/z, z[0-9]+\.h, z[0-9]+\.h
+**	b\.none	\.L[0-9]+
 **	...
-**	ldrsh	w[0-9]+, \[x[0-9]+, x[0-9]+\]
-**	ldrsh	w[0-9]+, \[x[0-9]+, x[0-9]+\]
-**	...
-**	cmp	w[0-9]+, w[0-9]+
+**	brkb	p[0-9]+\.b, p[0-9]+/z, p[0-9]+\.b
+**	incp	x[0-9]+, p[0-9]+\.h
 **	...
 **	ret
 **	...
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/noeffect6.c b/gcc/testsuite/gcc.target/aarch64/sve/noeffect6.c
index 14438830453aad97b325ac1e5aad849a095343d9..6675f97c41986659a8b03a6c3015b3c31a2046a9 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/noeffect6.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/noeffect6.c
@@ -1,26 +1,14 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -march=armv8-a+sve --param=aarch64-autovec-preference=sve-only -msve-vector-bits=scalable" } */
-/* { dg-final { check-function-bodies "**" "" "" } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.h, p[0-9]+/z, \[x[0-9]+, x[0-9]+(, lsl 1)?\]} 2 } } */
+/* { dg-final { scan-assembler {\tcmpgt\tp[0-9]+\.h, p[0-9]+/z, z[0-9]+\.h, z[0-9]+\.h} } } */
+/* { dg-final { scan-assembler {\tb\.none\t\.L[0-9]+} } } */
+/* { dg-final { scan-assembler {\tsplice\tz[0-9]+\.h, p[0-9]+, z[0-9]+\.h, z[0-9]+\.h} } } */
 
 #define N 1000
 short a[N] = {0};
 short b[N] = {0};
 
-/*
-** foo:
-**	...
-**	ld1h	z[0-9]+\.h, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 1\]
-**	ld1h	z[0-9]+\.h, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 1\]
-**	cmpgt	p[0-9]+\.h, p[0-9]+/z, z[0-9]+\.h, z[0-9]+\.h
-**	...
-**	ldrsh	w[0-9]+, \[x[0-9]+, x[0-9]+\]
-**	ldrsh	w[0-9]+, \[x[0-9]+, x[0-9]+\]
-**	...
-**	cmp	w[0-9]+, w[0-9]+
-**	...
-**	ret
-**	...
-*/
 __attribute__ ((noipa, noinline))
 short foo (void)
 {
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/noeffect7.c b/gcc/testsuite/gcc.target/aarch64/sve/noeffect7.c
index 9dab90e72b25b552daad81fdc27dc69dc329cbb0..22f686f70faf418230b0671634770ab8c0356d43 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/noeffect7.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/noeffect7.c
@@ -12,7 +12,7 @@ int b[N] = {0};
 **	ld2w	\{z[0-9]+\.s - z[0-9]+\.s\}, p[0-9]+/z, \[x[0-9]+, x[0-9]+, lsl 2\]
 **	...
 **	cmpgt	p[0-9]+\.s, p[0-9]+/z, z[0-9]+\.s, z[0-9]+\.s
-**	ptest	p[0-9]+, p[0-9]+\.b
+**	b\.any	\.L[0-9]+
 **	...
 **	ldr	w[0-9]+, \[x[0-9]+, x[0-9]+, lsl 2\]
 **	ldr	w[0-9]+, \[x[0-9]+, x[0-9]+, lsl 2\]
diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/vect-early-break-firstp_1.c b/gcc/testsuite/gcc.target/aarch64/sve2/vect-early-break-firstp_1.c
new file mode 100644
index 0000000000000000000000000000000000000000..a67352ff1a94b7c3ac40cb53bdd9f34b2805c086
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve2/vect-early-break-firstp_1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-Ofast -march=armv8.3-a+sve2p2 -mautovec-preference=sve-only" } */
+
+enum codetype { DISTS };
+
+int max_count;
+short count[5];
+
+int __attribute__ ((noipa))
+f (enum codetype type, short lens, unsigned codes, int table, unsigned *bits,
+   short work)
+{
+  unsigned int min;
+
+  if (max_count == 0)
+    {
+      *bits = 1;
+      return 0;
+    }
+
+  min = 1;
+  for (; min < max_count; min++)
+    if (count[min])
+      break;
+
+  *bits = min;
+  return 0;
+}
+
+/* { dg-final { scan-assembler {\tfirstp\tx[0-9]+, p[0-9]+, p[0-9]+\.s} } } */

Reply via email to