> On 14 Sep 2026, at 11:25, Tamar Christina <[email protected]> wrote:
> 
> This patch implements the control flow IFNs for Adv.SIMD.  It gives the
> AArch64 expansions for counting active lanes, finding the
> first active lane, creating inclusive and exclusive active-lane masks, and
> extracting the first active value from a vector.
> 
> The implementation uses ADDHN to compress byte, halfword and word predicates
> down to a scalar bitmap.  Plain vector branches use the cheaper zero/nonzero
> compressed predicate path.  When the vectorizer needs the active lane number,
> the exit block masks the compressed bitmap and uses scalar bit operations to
> find the lane.  For live register values the final extraction can use a vector
> table lookup instead of replaying scalar loads.
> 
> For example, consider:
> 
>  unsigned char a[1008], b[1008];
> 
>  unsigned char f1 (void)
>  {
>    unsigned char res = 0;
>    for (unsigned int i = 0; i < 1008; ++i)
>      {
> unsigned char x = a[i] & b[i];
> res = x;
> if (x > 5)
>  break;
>      }
>    return res;
>  }
> 
> Today we we generate at -O3 -march=armv8-a:
> 
>  cmhi    v30.16b, v31.16b, v29.16b
>  umaxp   v30.4s, v30.4s, v30.4s
>  fmov    x0, d30
>  cbz     x0, .L2
>  ldrb    w0, [x2, w1, uxtw]
>  cmp     w0, 5
>  bhi     .L3
>  ... repeated scalar lane checks ...
> 
> and with this branch:
> 
>  cmhi    v31.16b, v30.16b, v29.16b
>  addhn   v31.8b, v31.8h, v31.8h
>  umov    x0, v31.d[0]
>  cbz     x0, .L8
>  rbit    x0, x0
>  clz     x0, x0
>  ...
>  tbl     v30.16b, {v30.16b}, v31.16b
>  fmov    w0, s30
> 
> There is one complication in how we perform the Adv. SIMD optimization which
> replaces an Adv. SIMD compare with an SVE one.
> 
> This now has to be delayed until after expand when we can tell if the compare
> is single use.  Otherwise we'd end up with an Adv. SIMD and SVE compare for 
> the
> same as CSE can't remove the duplicate then.
> 
> 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?
> 
> Thanks,
> Tamar
> 
> gcc/ChangeLog:
> 
> * config/aarch64/aarch64-protos.h (aarch64_gen_shareable_ptrue):
> Declare.
> * config/aarch64/aarch64-simd.md (cbranch<mode>4): Use compressed
> predicate branches for Adv.SIMD masks.
> (@aarch64_addhn_scalar<mode>): New expander.
> (@aarch64_addhn_mask_scalar<mode>): Likewise.
> (count_active_<mode>): Likewise.
> (index_first_active_<mode>): Likewise.
> (extract_first_<mode>): Likewise.
> (take_<take_active>_active_<mode>): Likewise.
> * config/aarch64/aarch64.cc (aarch64_gen_shareable_ptrue): New
> function.
> * config/aarch64/aarch64.h (advsimd_ptrue_insn): New.
> * config/aarch64/iterators.md (VADDHN_MASK_WIDE, VADDHN_MASK_NARROW,
> vaddhn_mask_wide, vaddhn_lane_mask, TAKE_ACTIVE_CMP, take_active): New.
> 
> gcc/testsuite/ChangeLog:
> 
> * gcc.target/aarch64/noeffect11.c: Update expected code generation.
> * gcc.target/aarch64/noeffect2.c: Likewise.
> * gcc.target/aarch64/noeffect3.c: Likewise.
> * gcc.target/aarch64/noeffect4.c: Likewise.
> * gcc.target/aarch64/noeffect5.c: Likewise.
> * gcc.target/aarch64/noeffect6.c: Likewise.
> * gcc.target/aarch64/noeffect7.c: Likewise.
> * gcc.target/aarch64/noeffect8.c: Likewise.
> * gcc.target/aarch64/vect-early-break-cbranch.c: Likewise.
> * gcc.target/aarch64/vect-early-break-cbranch_2.c: Likewise.
> * gcc.target/aarch64/vect-early-break-cbranch_3.c: Likewise.
> * gcc.target/aarch64/vect-early-break-cbranch_4.c: Likewise.
> * gcc.target/aarch64/vect-early-break-cbranch_5.c: Likewise.
> * lib/target-supports.exp: Add Adv.SIMD LUT support checks.
> * gcc.target/aarch64/noeffect12.c: New test.
> * gcc.target/aarch64/noeffect13-run.c: New test.
> * gcc.target/aarch64/noeffect13.c: New test.
> * gcc.target/aarch64/vect-early-break-cbranch_7.c: New test.
> 
> ---
> diff --git a/gcc/config/aarch64/aarch64-protos.h 
> b/gcc/config/aarch64/aarch64-protos.h
> index 
> e8ae3d427949896f5a34d21bd55ce770cdcdcd76..4d882ce90ae2ea50b9b33a380af7a6f1d0bc27a5
>  100644
> --- a/gcc/config/aarch64/aarch64-protos.h
> +++ b/gcc/config/aarch64/aarch64-protos.h
> @@ -1015,6 +1015,7 @@ rtx aarch64_return_addr_rtx (void);
> rtx aarch64_return_addr (int, rtx);
> rtx aarch64_simd_gen_const_vector_dup (machine_mode, HOST_WIDE_INT);
> rtx aarch64_gen_shareable_zero (machine_mode);
> +rtx aarch64_gen_shareable_ptrue (machine_mode, unsigned int);
> bool aarch64_split_simd_shift_p (rtx_insn *);
> bool aarch64_simd_mem_operand_p (rtx);
> bool aarch64_sve_ld1r_operand_p (rtx);
> diff --git a/gcc/config/aarch64/aarch64-simd.md 
> b/gcc/config/aarch64/aarch64-simd.md
> index 
> f9b2fd6b2db1c88e50aac3b6f6f77ab9ba626654..5c45db988b3a83948a01ebf1071c88e9e8814cb7
>  100644
> --- a/gcc/config/aarch64/aarch64-simd.md
> +++ b/gcc/config/aarch64/aarch64-simd.md
> @@ -4475,8 +4475,8 @@ (define_expand "cbranch<mode>4"
>   [(set (pc)
>         (if_then_else
>           (match_operator 0 "aarch64_equality_operator"
> -            [(match_operand:VDQ_I 1 "register_operand")
> -             (match_operand:VDQ_I 2 "aarch64_simd_reg_or_zero")])
> +            [(match_operand:VD_BHSI 1 "register_operand")
> +             (match_operand:VD_BHSI 2 "aarch64_simd_reg_or_zero")])
>           (label_ref (match_operand 3 ""))
>           (pc)))]
>   "TARGET_SIMD"
> @@ -4492,16 +4492,46 @@ (define_expand "cbranch<mode>4"
>       emit_insn (gen_xor<mode>3 (tmp, operands[1], operands[2]));
>     }
> 
> -  /* For 64-bit vectors we need no reductions.  */
> -  if (known_eq (128, GET_MODE_BITSIZE (<MODE>mode)))
> +  rtx val = gen_reg_rtx (DImode);
> +  emit_move_insn (val, gen_lowpart (DImode, tmp));
> +
> +  rtx cc_reg = aarch64_gen_compare_reg (code, val, const0_rtx);
> +  rtx cmp_rtx = gen_rtx_fmt_ee (code, DImode, cc_reg, const0_rtx);
> +  emit_jump_insn (gen_aarch64_bcond (cmp_rtx, cc_reg, operands[3]));
> +  DONE;
> +})
> +
> +(define_expand "cbranch<mode>4"
> +  [(set (pc)
> +        (if_then_else
> +          (match_operator 0 "aarch64_equality_operator"
> +            [(match_operand:VQ_I 1 "register_operand")
> +             (match_operand:VQ_I 2 "aarch64_simd_reg_or_zero")])
> +          (label_ref (match_operand 3 ""))
> +          (pc)))]
> +  "TARGET_SIMD"
> +{
> +  auto code = GET_CODE (operands[0]);
> +  rtx tmp = operands[1];
> +
> +  /* If comparing against a non-zero vector we have to do a comparison first
> +     so we can have a != 0 comparison with the result.  */
> +  if (operands[2] != CONST0_RTX (<MODE>mode))
>     {
> -      /* Always reduce using a V4SI.  */
> -      rtx reduc = gen_lowpart (V4SImode, tmp);
> -      rtx res = gen_reg_rtx (V4SImode);
> -      emit_insn (gen_aarch64_umaxpv4si (res, reduc, reduc));
> -      emit_move_insn (tmp, gen_lowpart (<MODE>mode, res));
> +      tmp = gen_reg_rtx (<MODE>mode);
> +      emit_insn (gen_xor<mode>3 (tmp, operands[1], operands[2]));
>     }
> 
> +  /* This expander can be used for arbitrary vector zero tests, for example
> +     the XOR result produced by __builtin_memcmp_eq.  ADDHN is only valid for
> +     boolean masks whose true lanes are all ones.  Use UMAXP here; the
> +     vec_cbranch expanders below still use ADDHN after producing a compare
> +     mask.  */
> +  rtx reduc = gen_lowpart (V4SImode, tmp);
> +  rtx res = gen_reg_rtx (V4SImode);
> +  emit_insn (gen_aarch64_umaxpv4si (res, reduc, reduc));
> +  tmp = gen_lowpart (<MODE>mode, res);
> +
>   rtx val = gen_reg_rtx (DImode);
>   emit_move_insn (val, gen_lowpart (DImode, tmp));
> 
> @@ -4511,6 +4541,298 @@ (define_expand "cbranch<mode>4"
>   DONE;
> })
> 
> +;; Compress a 128-bit Adv.SIMD boolean vector into a 64-bit scalar value.
> +;; ADDHN folds each adjacent pair of lanes into one narrower lane.  This is
> +;; enough for zero/nonzero tests: a nonzero bit in any original lane produces
> +;; a nonzero bit in the scalar result.
> +;;
> +;; Keep this separate from aarch64_addhn_mask_scalar.  Vector branches such 
> as
> +;; those in gcc.dg/vect/vect-uncounted_1.c only need a cbz/cbnz-style test 
> and
> +;; should not pay for the lane mask that index/count operations need later.
> +(define_expand "@aarch64_addhn_scalar<mode>"
> +  [(match_operand:DI 0 "register_operand")
> +   (match_operand:VQ_I 1 "register_operand")]
> +  "TARGET_SIMD"
> +{
> +  rtx wide = gen_lowpart (<VADDHN_MASK_WIDE>mode, operands[1]);
> +  rtx narrow = gen_reg_rtx (<VADDHN_MASK_NARROW>mode);
> +  emit_insn (gen_aarch64_addhn<vaddhn_mask_wide> (narrow, wide, wide));
> +
> +  emit_move_insn (operands[0], gen_lowpart (DImode, narrow));
> +  DONE;
> +})
> +
> +;; Compress a 128-bit Adv.SIMD boolean vector into a 64-bit scalar bitmap.
> +;; The raw ADDHN result is sparse.  After masking with <vaddhn_lane_mask>,
> +;; each original lane has exactly one bit in the scalar result, so ctz and
> +;; popcount can recover a lane index or count.
> +;; This is the exit-block form used by INDEX_FIRST_ACTIVE and COUNT_ACTIVE.
> +(define_expand "@aarch64_addhn_mask_scalar<mode>"
> +  [(match_operand:DI 0 "register_operand")
> +   (match_operand:VQ_I 1 "register_operand")]
> +  "TARGET_SIMD"
> +{
> +  rtx val = gen_reg_rtx (DImode);
> +  emit_insn (gen_aarch64_addhn_scalar<mode> (val, operands[1]));
> +  emit_move_insn (operands[0],
> +  gen_rtx_AND (DImode, val,
> +       gen_int_mode (<vaddhn_lane_mask>, DImode)));
> +  DONE;
> +})
> +
> +(define_expand "count_active_<mode>"
> +  [(match_operand:DI 0 "register_operand")
> +   (match_operand:VQ_I 1 "register_operand")]
> +  "TARGET_SIMD"
> +{
> +  /* For example: addhn v0.2s, v1.2d, v1.2d; and; cnt.  */
> +  rtx mask = gen_reg_rtx (DImode);
> +  emit_insn (gen_aarch64_addhn_mask_scalar<mode> (mask, operands[1]));
> +  emit_insn (gen_popcountdi2 (operands[0], mask));
> +  DONE;
> +})
> +
> +(define_expand "index_first_active_<mode>"
> +  [(match_operand:DI 0 "register_operand")
> +   (match_operand:VQ_I 1 "register_operand")]
> +  "TARGET_SIMD"
> +{
> +  /* For example: addhn v0.2s, v1.2d, v1.2d; and; rbit; clz; lsr.  */
> +  rtx mask = gen_reg_rtx (DImode);
> +  rtx bitno = gen_reg_rtx (DImode);
> +  emit_insn (gen_aarch64_addhn_mask_scalar<mode> (mask, operands[1]));
> +  emit_insn (gen_ctzdi2 (bitno, mask));
> +  emit_move_insn (operands[0],
> +  gen_rtx_LSHIFTRT (DImode, bitno,
> +    GEN_INT (exact_log2
> +     (GET_MODE_UNIT_BITSIZE
> + (<MODE>mode) / 2))));
> +  DONE;
> +})
> +
> +(define_expand "extract_first_<mode>"
> +  [(match_operand:<VEL> 0 "register_operand")
> +   (match_operand:<V_INT_EQUIV> 1 "register_operand")
> +   (match_operand:VQ_NO2E 2 "register_operand")]
> +  "TARGET_SIMD"
> +{
> +  /* For example: addhn; ctz; dup; add; tbl.  */
> +  rtx index = gen_reg_rtx (DImode);
> +  emit_insn (gen_index_first_active_<v_int_equiv> (index, operands[1]));
> +
> +  if (TARGET_LUT && <MODE>mode == V16QImode)
> +    {
> +      rtx index_vec = gen_reg_rtx (V8QImode);
> +      emit_move_insn (gen_lowpart (DImode, index_vec), index);
> +
> +      rtx selected = gen_reg_rtx (V16QImode);
> +      emit_insn (gen_aarch64_lutv16qiv8qi
> + (selected, operands[2], index_vec, const0_rtx, GEN_INT (4)));
> +
> +      emit_move_insn (operands[0], gen_lowpart (<VEL>mode, selected));
> +      DONE;
> +    }
> +
> +  if (TARGET_LUT && <MODE>mode == V8HImode)
> +    {
> +      rtx index_vec = gen_reg_rtx (V8QImode);
> +      emit_move_insn (gen_lowpart (DImode, index_vec), index);
> +
> +      rtx table = gen_reg_rtx (V2x8HImode);
> +      rtx first = simplify_gen_subreg (V8HImode, table, V2x8HImode, 0);
> +      emit_move_insn (first, operands[2]);
> +
> +      rtx zero = force_reg (V8HImode, CONST0_RTX (V8HImode));
> +      rtx second = simplify_gen_subreg (V8HImode, table, V2x8HImode, 16);
> +      emit_move_insn (second, zero);
> +
> +      rtx selected = gen_reg_rtx (V8HImode);
> +      emit_insn (gen_aarch64_lutv2x8hiv8qi
> + (selected, table, index_vec, const0_rtx, GEN_INT (4)));
> +
> +      emit_move_insn (operands[0], gen_lowpart (<VEL>mode, selected));
> +      DONE;
> +    }
> +

Drive-by comment: 
Can you add somewhere in the commit message or in the comments how the LUT 
instructions are used here?

Thanks,
Kyrill

> +  /* The live-load fast path in tree-vect-loop.cc avoids this sequence for
> +     memory values by reloading the selected scalar element.  This expander 
> is
> +     for values that are already in vector registers, such as the register
> +     live-out cases in gcc.target/aarch64/noeffect11.c.
> +
> +     INDEX_FIRST_ACTIVE gives the active element number.  Turn it into a byte
> +     offset, duplicate the offset across a byte vector and add {0, 1, ... 
> 15}.
> +     TBL then moves the selected element's bytes down to lane 0.  This avoids
> +     transferring both 64-bit halves to general registers before choosing 
> which
> +     half contains the first active element.  */
> +  unsigned int elt_bytes = GET_MODE_UNIT_SIZE (<MODE>mode);
> +  if (elt_bytes > 1)
> +    {
> +      rtx byte_index = gen_reg_rtx (DImode);
> +      emit_move_insn (byte_index,
> +      gen_rtx_ASHIFT (DImode, index,
> +      GEN_INT (exact_log2 (elt_bytes))));
> +      index = byte_index;
> +    }
> +
> +  rtx byte_index_vec = gen_reg_rtx (V16QImode);
> +  emit_insn (gen_aarch64_simd_dupv16qi (byte_index_vec,
> + gen_lowpart (QImode, index)));
> +
> +  rtvec v = rtvec_alloc (16);
> +  for (unsigned int i = 0; i < 16; ++i)
> +    RTVEC_ELT (v, i) = GEN_INT (i);
> +  rtx byte_numbers = force_reg (V16QImode,
> + gen_rtx_CONST_VECTOR (V16QImode, v));
> +
> +  rtx selector = gen_reg_rtx (V16QImode);
> +  emit_insn (gen_addv16qi3 (selector, byte_index_vec, byte_numbers));
> +
> +  rtx selected = gen_reg_rtx (V16QImode);
> +  emit_insn (gen_aarch64_qtbl1v16qi (selected,
> +     gen_lowpart (V16QImode, operands[2]),
> +     selector));
> +
> +  emit_move_insn (operands[0], gen_lowpart (<VEL>mode, selected));
> +  DONE;
> +})
> +
> +(define_expand "extract_first_<mode>"
> +  [(match_operand:<VEL> 0 "register_operand")
> +   (match_operand:<V_INT_EQUIV> 1 "register_operand")
> +   (match_operand:VQ_2E 2 "register_operand")]
> +  "TARGET_SIMD"
> +{
> +  /* For example: addhn; ctz; umov xlo; umov xhi; csel.  */
> +  rtx index = gen_reg_rtx (DImode);
> +  emit_insn (gen_index_first_active_<v_int_equiv> (index, operands[1]));
> +
> +  /* V2DI/V2DF only need to choose between the two 64-bit halves.  This keeps
> +     the sequence in the scalar integer domain after INDEX_FIRST_ACTIVE and
> +     avoids building a vector table control.  */
> +  rtx lo = gen_reg_rtx (DImode);
> +  emit_insn (gen_aarch64_get_lanev2di (lo, gen_lowpart (V2DImode, 
> operands[2]),
> +       aarch64_endian_lane_rtx (V2DImode,
> + 0)));
> +
> +  rtx hi = gen_reg_rtx (DImode);
> +  emit_insn (gen_aarch64_get_lanev2di (hi, gen_lowpart (V2DImode, 
> operands[2]),
> +       aarch64_endian_lane_rtx (V2DImode,
> + 1)));
> +
> +  rtx cc_reg = aarch64_gen_compare_reg (NE, index, const0_rtx);
> +  rtx cmp = gen_rtx_NE (VOIDmode, cc_reg, const0_rtx);
> +  rtx data = gen_reg_rtx (DImode);
> +  emit_insn (gen_rtx_SET (data, gen_rtx_IF_THEN_ELSE (DImode, cmp, hi, lo)));
> +
> +  emit_move_insn (operands[0], gen_lowpart (<VEL>mode, data));
> +  DONE;
> +})
> +
> +(define_expand "take_<take_active>_active_<mode>"
> +  [(set (match_operand:VQ_I 0 "register_operand")
> + (neg:VQ_I
> +  (TAKE_ACTIVE_CMP:VQ_I
> +    (match_operand:VQ_I 1 "register_operand")
> +    (match_dup 1))))]
> +  "TARGET_SIMD"
> +{
> +  /* For example: addhn; ctz; dup; cmhs.  */
> +  rtx index = gen_reg_rtx (DImode);
> +  emit_insn (gen_index_first_active_<mode> (index, operands[1]));
> +
> +  rtx elt_index = gen_lowpart (<VEL>mode, index);
> +  rtx index_vec = gen_reg_rtx (<MODE>mode);
> +  emit_insn (gen_aarch64_simd_dup<mode> (index_vec, elt_index));
> +
> +  rtvec v = rtvec_alloc (<nunits>);
> +  for (unsigned int i = 0; i < <nunits>; ++i)
> +    RTVEC_ELT (v, i) = GEN_INT (i);
> +  rtx lane_numbers = force_reg (<MODE>mode,
> + gen_rtx_CONST_VECTOR (<MODE>mode, v));
> +
> +  emit_insn (gen_vec_cmp<mode><v_int_equiv> (operands[0],
> +     gen_rtx_<CMP> (VOIDmode,
> +    lane_numbers,
> +    index_vec),
> +     lane_numbers, index_vec));
> +  DONE;
> +})
> +
> +;; If a vector compare is used only to feed a vector branch, use an SVE
> +;; predicate compare and PTEST instead of materializing and reducing an
> +;; Adv.SIMD mask.  Keep this as a combine-time split rather than doing it in
> +;; the vec_cbranch expander, since the compare mask might also be needed 
> later
> +;; for live-value extraction.  In that case the ADDHN result remains live 
> after
> +;; the branch and combine cannot consume the reduction into this pattern.
> +;;
> +;; This must be a define_split rather than a define_insn_and_split.  The 
> split
> +;; needs the original compare producer to be the previous insn; if that stops
> +;; being true, FAILing is correct during combine, but would be an ICE if a
> +;; recognized "#" insn survived until final.
> +(define_split
> +  [(set (pc)
> + (if_then_else
> +  (match_operator 0 "aarch64_equality_operator"
> +    [(subreg:DI
> +       (truncate:<VADDHN_MASK_NARROW>
> + (ashiftrt:<VADDHN_MASK_WIDE>
> +   (plus:<VADDHN_MASK_WIDE>
> +     (subreg:<VADDHN_MASK_WIDE>
> +       (match_operand:VQ_I 1 "register_operand") 0)
> +     (subreg:<VADDHN_MASK_WIDE>
> +       (match_dup 1) 0))
> +   (match_operand:<VADDHN_MASK_WIDE> 3
> +     "aarch64_simd_shift_imm_vec_exact_top")))
> +       0)
> +     (const_int 0)])
> +  (label_ref (match_operand 2 ""))
> +  (pc)))]
> +  "TARGET_SIMD
> +   && TARGET_SVE
> +   && can_create_pseudo_p ()
> +   && known_eq (128, GET_MODE_BITSIZE (<MODE>mode))"
> +  [(const_int 0)]
> +{
> +  if (find_regno_note (curr_insn, REG_DEAD, REGNO (operands[1])) == NULL_RTX)
> +    FAIL;
> +
> +  rtx_insn *prev = prev_nonnote_nondebug_insn (curr_insn);
> +  rtx set = prev ? single_set (prev) : NULL_RTX;
> +  if (!set || !rtx_equal_p (SET_DEST (set), operands[1]))
> +    FAIL;
> +
> +  rtx src = SET_SRC (set);
> +  if (GET_CODE (src) != NEG || !COMPARISON_P (XEXP (src, 0)))
> +    FAIL;
> +
> +  rtx cmp = XEXP (src, 0);
> +  rtx_code cmp_code = GET_CODE (cmp);
> +  machine_mode full_mode = aarch64_full_sve_mode (<VEL>mode).require ();
> +
> +  rtx in1 = force_lowpart_subreg (full_mode, XEXP (cmp, 0), <MODE>mode);
> +  rtx in2;
> +  if (CONST0_RTX (<MODE>mode) == XEXP (cmp, 1))
> +    in2 = CONST0_RTX (full_mode);
> +  else
> +    in2 = force_lowpart_subreg (full_mode, XEXP (cmp, 1), <MODE>mode);
> +
> +  machine_mode pred_mode = aarch64_sve_pred_mode (full_mode);
> +  unsigned int vl = exact_div (GET_MODE_BITSIZE (<MODE>mode), 8).to_constant 
> ();
> +  rtx ptrue = aarch64_gen_shareable_ptrue (VNx16BImode, vl);
> +  rtx cast_ptrue = gen_lowpart (pred_mode, ptrue);
> +  rtx hint = gen_int_mode (SVE_MAYBE_NOT_PTRUE, SImode);
> +  rtx tmp = gen_reg_rtx (pred_mode);
> +  emit_insn (gen_aarch64_pred_cmp_ptest (cmp_code, full_mode, tmp, ptrue,
> + in1, in2, cast_ptrue, hint,
> + cast_ptrue, hint));
> +
> +  rtx cc_reg = gen_rtx_REG (CC_NZCmode, CC_REGNUM);
> +  rtx cmp_reg = gen_rtx_fmt_ee (GET_CODE (operands[0]), VOIDmode,
> + cc_reg, const0_rtx);
> +  emit_jump_insn (gen_aarch64_bcond (cmp_reg, cc_reg, operands[2]));
> +  DONE;
> +})
> +
> ;; Define vec_cbranch_any and vec_cbranch_all
> ;; Vector comparison and branch for Adv. SIMD Integer types using SVE
> ;; instructions.
> @@ -4526,62 +4848,29 @@ (define_expand "<optab><mode>"
> CBRANCH_CMP))]
>   "TARGET_SIMD"
> {
> -  auto code = GET_CODE (operands[0]);
> -  if (TARGET_SVE)
> -    {
> -      machine_mode full_mode = aarch64_full_sve_mode (<VEL>mode).require ();
> -
> -      rtx in1 = force_lowpart_subreg (full_mode, operands[1], <MODE>mode);
> -      rtx in2;
> -      if (CONST0_RTX (<MODE>mode) == operands[2])
> - in2 = CONST0_RTX (full_mode);
> -      else
> - in2 = force_lowpart_subreg (full_mode, operands[2], <MODE>mode);
> -
> -      unsigned lanes
> - = exact_div (GET_MODE_BITSIZE (<MODE>mode), 8).to_constant ();
> -      machine_mode pred_mode = aarch64_sve_pred_mode (full_mode);
> -      rtx ptrue = aarch64_ptrue_reg (VNx16BImode, lanes);
> -      rtx hint = gen_int_mode (SVE_MAYBE_NOT_PTRUE, SImode);
> -
> -      rtx tmp = gen_reg_rtx (pred_mode);
> -      rtx cast_ptrue = gen_lowpart (pred_mode, ptrue);
> -
> -      if (FLOAT_MODE_P (full_mode))
> - {
> -  aarch64_expand_sve_vec_cmp<sve_cmp_suff> (tmp, code, in1, in2);
> -  emit_insn (gen_and3 (pred_mode, tmp, tmp, cast_ptrue));
> -  emit_insn (gen_aarch64_ptest (pred_mode, ptrue, cast_ptrue, hint,
> - tmp));
> - }
> -      else
> - emit_insn (gen_aarch64_pred_cmp_ptest (code, full_mode, tmp, ptrue, in1,
> -       in2, cast_ptrue, hint,
> -       cast_ptrue, hint));
> -
> -      rtx cc_reg = gen_rtx_REG (CC_NZCmode, CC_REGNUM);
> -      rtx cmp_reg = gen_rtx_<cbranch_op> (VOIDmode, cc_reg, const0_rtx);
> -      emit_jump_insn (gen_aarch64_bcond (cmp_reg, cc_reg, operands[3]));
> -      DONE;
> -    }
> -
>   rtx tmp = gen_reg_rtx (<V_INT_EQUIV>mode);
>   emit_insn (gen_vec_cmp<mode><v_int_equiv> (tmp, operands[0], operands[1],
>     operands[2]));
> 
> -  /* For 128-bit vectors we need a reduction to 64-bit first.  */
> -  if (known_eq (128, GET_MODE_BITSIZE (<MODE>mode)))
> +  rtx val = gen_reg_rtx (DImode);
> +  rtx addhn_scalar
> +    = maybe_gen_aarch64_addhn_scalar (<V_INT_EQUIV>mode, val, tmp);
> +  if (known_eq (128, GET_MODE_BITSIZE (<MODE>mode)) && addhn_scalar)
> +    emit_insn (addhn_scalar);
> +  else
>     {
> -      /* Always reduce using a V4SI.  */
> -      rtx reduc = gen_lowpart (V4SImode, tmp);
> -      rtx res = gen_reg_rtx (V4SImode);
> -      emit_insn (gen_aarch64_umaxpv4si (res, reduc, reduc));
> -      emit_move_insn (tmp, gen_lowpart (<V_INT_EQUIV>mode, res));
> +      /* For 128-bit vectors we need a reduction to 64-bit first.  */
> +      if (known_eq (128, GET_MODE_BITSIZE (<MODE>mode)))
> + {
> +  /* Always reduce using a V4SI.  */
> +  rtx reduc = gen_lowpart (V4SImode, tmp);
> +  rtx res = gen_reg_rtx (V4SImode);
> +  emit_insn (gen_aarch64_umaxpv4si (res, reduc, reduc));
> +  emit_move_insn (tmp, gen_lowpart (<V_INT_EQUIV>mode, res));
> + }
> +      emit_move_insn (val, gen_lowpart (DImode, tmp));
>     }
> 
> -  rtx val = gen_reg_rtx (DImode);
> -  emit_move_insn (val, gen_lowpart (DImode, tmp));
> -
>   rtx cc_reg = aarch64_gen_compare_reg (<cbranch_op>, val, const0_rtx);
>   rtx cmp_rtx = gen_rtx_fmt_ee (<cbranch_op>, DImode, cc_reg, const0_rtx);
>   emit_jump_insn (gen_aarch64_bcond (cmp_rtx, cc_reg, operands[3]));
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 
> 8e62ab6a72e0043fffd16d3d187f18da7fd41d4e..77e29815f224a9e3bfc2ab3c5662c5d0aedf753e
>  100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -25316,6 +25316,28 @@ aarch64_gen_shareable_zero (machine_mode mode)
>   return lowpart_subreg (mode, reg, GET_MODE (reg));
> }
> 
> +/* Return a shareable predicate register whose first VL bytes are active,
> +   viewed in mode MODE.
> +   This is for fixed-width Adv.SIMD sequences that want to use SVE flags for
> +   a vector branch.  Hoisting the predicate constant avoids recreating it in
> +   every loop iteration.  */
> +
> +rtx
> +aarch64_gen_shareable_ptrue (machine_mode mode, unsigned int vl)
> +{
> +  gcc_assert (vl == 8 || vl == 16);
> +
> +  rtx_vector_builder builder (VNx16BImode, vl, 2);
> +  for (unsigned int i = 0; i < vl; ++i)
> +    builder.quick_push (CONST1_RTX (BImode));
> +  for (unsigned int i = 0; i < vl; ++i)
> +    builder.quick_push (CONST0_RTX (BImode));
> +
> +  rtx reg = aarch64_get_shareable_reg (&cfun->machine->advsimd_ptrue_insn,
> +       builder.build ());
> +  return lowpart_subreg (mode, reg, GET_MODE (reg));
> +}
> +
> /* INSN is some form of extension or shift that can be split into a
>    permutation involving a shared zero.  Return true if we should
>    perform such a split.
> @@ -28913,7 +28935,7 @@ aarch64_vectorize_vec_perm_const (machine_mode vmode, 
> machine_mode op_mode,
>     {
>       d.op1 = op1;
>       if (d.op1 && !register_operand (d.op1, op_mode))
> -       d.op1 = force_reg (op_mode, d.op1);
> + d.op1 = force_reg (op_mode, d.op1);
>     }
>   d.testing_p = !target;
> 
> @@ -28926,6 +28948,7 @@ aarch64_vectorize_vec_perm_const (machine_mode vmode, 
> machine_mode op_mode,
> 
>   return ret;
> }
> +
> /* Generate a byte permute mask for a register of mode MODE,
>    which has NUNITS units.  */
> 
> diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
> index 
> fdedb04391127c5a1b821ed5d4b399c1c28d9f31..0673c8a64f7097e2d2ec4a155edeb12dfe72e957
>  100644
> --- a/gcc/config/aarch64/aarch64.h
> +++ b/gcc/config/aarch64/aarch64.h
> @@ -1249,6 +1249,10 @@ typedef struct GTY (()) machine_function
>      can be reused by other code.  */
>   rtx_insn *advsimd_zero_insn;
> 
> +  /* Like advsimd_zero_insn, but for a predicate with a fixed number of
> +     leading true bytes.  */
> +  rtx_insn *advsimd_ptrue_insn;
> +
>   /* During SEH output, this is non-null.  */
>   struct seh_frame_state * GTY ((skip (""))) seh;
> 
> diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
> index 
> b0571460ec7ded9252bc2a216b6cd8867e6a595b..af417b51ccf31bf56d4e4f368979971c05e0b482
>  100644
> --- a/gcc/config/aarch64/iterators.md
> +++ b/gcc/config/aarch64/iterators.md
> @@ -2181,6 +2181,25 @@ (define_mode_attr Vdblw [(V8QI "v4hi") (V16QI "v8hi")
> (V4HI "v2si") (V8HI "v4si")
> (V2SI "di")   (V4SI "v2di")])
> 
> +;; Source mode for using ADDHN to compress a boolean mask to a scalar.
> +(define_mode_attr VADDHN_MASK_WIDE [(V16QI "V8HI") (V8HI "V4SI")
> +    (V4SI "V2DI") (V2DI "V2DI")])
> +
> +;; Result mode for using ADDHN to compress a boolean mask to a scalar.
> +(define_mode_attr VADDHN_MASK_NARROW [(V16QI "V8QI") (V8HI "V4HI")
> +      (V4SI "V2SI") (V2DI "V2SI")])
> +
> +;; Source mode suffix for using ADDHN to compress a boolean mask to a scalar.
> +(define_mode_attr vaddhn_mask_wide [(V16QI "v8hi") (V8HI "v4si")
> +    (V4SI "v2di") (V2DI "v2di")])
> +
> +;; Scalar mask for the useful bits produced by using ADDHN to compress a
> +;; boolean mask to a scalar.
> +(define_mode_attr vaddhn_lane_mask [(V16QI "0x1111111111111111")
> +    (V8HI "0x0101010101010101")
> +    (V4SI "0x0001000100010001")
> +    (V2DI "0x0000000100000001")])
> +
> (define_mode_attr VQUADW [(V8QI "V4SI") (V16QI "V8SI")
>                   (V4HI "V2DI") (V8HI "V4DI")])
> 
> @@ -3237,6 +3256,9 @@ (define_code_iterator SAT_MINUS [ss_minus us_minus])
> ;; Comparison operators for <F>CM.
> (define_code_iterator COMPARISONS [lt le eq ge gt])
> 
> +;; Comparison operators for TAKE_{EXCL,INCL}_ACTIVE.
> +(define_code_iterator TAKE_ACTIVE_CMP [lt le])
> +
> ;; Unsigned comparison operators.
> (define_code_iterator UCOMPARISONS [ltu leu geu gtu])
> 
> @@ -3374,6 +3396,9 @@ (define_code_attr cmp_op [(lt "lt")
>  (geu "hs")
>  (gtu "hi")])
> 
> +;; The TAKE_ACTIVE optab suffix associated with an rtl comparison code.
> +(define_code_attr take_active [(lt "excl") (le "incl")])
> +
> (define_code_attr inv_cmp_op [(lt "ge")
>  (le "gt")
>  (eq "ne")
> diff --git a/gcc/testsuite/gcc.target/aarch64/noeffect11.c 
> b/gcc/testsuite/gcc.target/aarch64/noeffect11.c
> index 
> 82c2f00c7cb16df22fa051b8d5d421863321e464..875e3ca184d925691eaf99d3d45b8cfab8b6f3e6
>  100644
> --- a/gcc/testsuite/gcc.target/aarch64/noeffect11.c
> +++ b/gcc/testsuite/gcc.target/aarch64/noeffect11.c
> @@ -8,7 +8,10 @@
> ** ...
> ** cmhi v[0-9]+\.2d, v[0-9]+\.2d, v[0-9]+\.2d
> ** ...
> -** umaxp v[0-9]+\.4s, v[0-9]+\.4s, v[0-9]+\.4s
> +** addhn v[0-9]+\.2s, v[0-9]+\.2d, v[0-9]+\.2d
> +** addhn v[0-9]+\.2s, v[0-9]+\.2d, v[0-9]+\.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> ** ldr x[0-9]+, \[x[0-9]+, x[0-9]+\]
> ** ldr x[0-9]+, \[x[0-9]+, x[0-9]+\]
> @@ -34,7 +37,10 @@ int f1 (const unsigned long *restrict a, const unsigned 
> long *b, int n)
> ** ...
> ** cmhi v[0-9]+\.2d, v[0-9]+\.2d, v[0-9]+\.2d
> ** ...
> -** umaxp v[0-9]+\.4s, v[0-9]+\.4s, v[0-9]+\.4s
> +** addhn v[0-9]+\.2s, v[0-9]+\.2d, v[0-9]+\.2d
> +** addhn v[0-9]+\.2s, v[0-9]+\.2d, v[0-9]+\.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> ** ldr x[0-9]+, \[x[0-9]+, x[0-9]+\]
> ** ldr x[0-9]+, \[x[0-9]+, x[0-9]+\]
> diff --git a/gcc/testsuite/gcc.target/aarch64/noeffect12.c 
> b/gcc/testsuite/gcc.target/aarch64/noeffect12.c
> new file mode 100644
> index 
> 0000000000000000000000000000000000000000..a42d67b56c47ed07497a40ea4758f07aea2bae4a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/noeffect12.c
> @@ -0,0 +1,64 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O3 -march=armv8-a" } */
> +/* { dg-final { check-function-bodies "**" "" "" } } */
> +
> +#define N 1008
> +
> +unsigned char a[N] = {0};
> +unsigned char b[N] = {0};
> +unsigned int c[N] = {0};
> +unsigned int d[N] = {0};
> +
> +/*
> +** f1:
> +** ...
> +** cmhi v[0-9]+\.16b, v[0-9]+\.16b, v[0-9]+\.16b
> +** addhn v[0-9]+\.8b, v[0-9]+\.8h, v[0-9]+\.8h
> +** umov x[0-9]+, v[0-9]+\.d\[0\]
> +** cbz x[0-9]+, \.L[0-9]+
> +** ...
> +** tbl v[0-9]+\.16b, \{v[0-9]+\.16b\}, v[0-9]+\.16b
> +** fmov w0, s[0-9]+
> +** ret
> +** ...
> +*/
> +__attribute__ ((noipa, noinline))
> +unsigned char f1 (void)
> +{
> +  unsigned char res = 0;
> +  for (unsigned int i = 0; i < N; ++i)
> +    {
> +      unsigned char x = a[i] & b[i];
> +      res = x;
> +      if (x > 5)
> + break;
> +    }
> +  return res;
> +}
> +
> +/*
> +** f2:
> +** ...
> +** cmhi v[0-9]+\.4s, v[0-9]+\.4s, v[0-9]+\.4s
> +** addhn v[0-9]+\.2s, v[0-9]+\.2d, v[0-9]+\.2d
> +** umov x[0-9]+, v[0-9]+\.d\[0\]
> +** cbz x[0-9]+, \.L[0-9]+
> +** ...
> +** tbl v[0-9]+\.16b, \{v[0-9]+\.16b\}, v[0-9]+\.16b
> +** fmov w0, s[0-9]+
> +** ret
> +** ...
> +*/
> +__attribute__ ((noipa, noinline))
> +unsigned int f2 (void)
> +{
> +  unsigned int res = 0;
> +  for (unsigned int i = 0; i < 1000; ++i)
> +    {
> +      unsigned int x = c[i] & d[i];
> +      res = x;
> +      if (x > 5)
> + break;
> +    }
> +  return res;
> +}
> diff --git a/gcc/testsuite/gcc.target/aarch64/noeffect13-run.c 
> b/gcc/testsuite/gcc.target/aarch64/noeffect13-run.c
> new file mode 100644
> index 
> 0000000000000000000000000000000000000000..9e9eb715c83f6bda7981f36d1682908a8380c114
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/noeffect13-run.c
> @@ -0,0 +1,62 @@
> +/* { dg-do run { target aarch64_lut_hw } } */
> +/* { dg-options "-O3 -march=armv9-a+lut -mautovec-preference=asimd-only" } */
> +
> +#define N 1008
> +
> +unsigned char a[N];
> +unsigned char b[N];
> +unsigned short c[N];
> +unsigned short d[N];
> +
> +__attribute__ ((noipa, noinline))
> +unsigned char f1 (void)
> +{
> +  unsigned char res = 0;
> +  for (unsigned int i = 0; i < N; ++i)
> +    {
> +      unsigned char x = a[i] & b[i];
> +      res = x;
> +      if (x > 5)
> + break;
> +    }
> +  return res;
> +}
> +
> +__attribute__ ((noipa, noinline))
> +unsigned short f2 (void)
> +{
> +  unsigned short res = 0;
> +  for (unsigned int i = 0; i < N; ++i)
> +    {
> +      unsigned short x = c[i] & d[i];
> +      res = x;
> +      if (x > 5)
> + break;
> +    }
> +  return res;
> +}
> +
> +int
> +main (void)
> +{
> +  for (unsigned int i = 0; i < N; ++i)
> +    {
> +      a[i] = 1;
> +      b[i] = 1;
> +      c[i] = 1;
> +      d[i] = 1;
> +    }
> +
> +  if (f1 () != 1 || f2 () != 1)
> +    __builtin_abort ();
> +
> +  a[13] = 7;
> +  b[13] = 7;
> +  c[11] = 9;
> +  d[11] = 9;
> +
> +  if (f1 () != 7 || f2 () != 9)
> +    __builtin_abort ();
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/aarch64/noeffect13.c 
> b/gcc/testsuite/gcc.target/aarch64/noeffect13.c
> new file mode 100644
> index 
> 0000000000000000000000000000000000000000..502126d6c005775b0f08c8807b3dda14c6372d34
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/noeffect13.c
> @@ -0,0 +1,66 @@
> +/* { dg-do compile { target aarch64_asm_lut_ok } } */
> +/* { dg-options "-O3 -march=armv9-a+lut -mautovec-preference=asimd-only" } */
> +/* { dg-final { check-function-bodies "**" "" "" } } */
> +
> +#define N 1008
> +
> +unsigned char a[N] = {0};
> +unsigned char b[N] = {0};
> +unsigned short c[N] = {0};
> +unsigned short d[N] = {0};
> +
> +/*
> +** f1:
> +** ...
> +** cmhi v[0-9]+\.16b, v[0-9]+\.16b, v[0-9]+\.16b
> +** ...
> +** addhn v[0-9]+\.8b, v[0-9]+\.8h, v[0-9]+\.8h
> +** fmov x[0-9]+, d[0-9]+
> +** ...
> +** luti4 v[0-9]+\.16b, \{v[0-9]+\.16b\}, v[0-9]+\[0\]
> +** fmov w0, s[0-9]+
> +** ret
> +** ...
> +*/
> +__attribute__ ((noipa, noinline))
> +unsigned char f1 (void)
> +{
> +  unsigned char res = 0;
> +  for (unsigned int i = 0; i < N; ++i)
> +    {
> +      unsigned char x = a[i] & b[i];
> +      res = x;
> +      if (x > 5)
> + break;
> +    }
> +  return res;
> +}
> +
> +/*
> +** f2:
> +** ...
> +** cmhi v[0-9]+\.8h, v[0-9]+\.8h, v[0-9]+\.8h
> +** ...
> +** addhn v[0-9]+\.4h, v[0-9]+\.4s, v[0-9]+\.4s
> +** fmov x[0-9]+, d[0-9]+
> +** ...
> +** movi v[0-9]+\.4s, 0
> +** ...
> +** luti4 v[0-9]+\.8h, \{v[0-9]+\.8h, v[0-9]+\.8h\}, v[0-9]+\[0\]
> +** fmov w0, s[0-9]+
> +** ret
> +** ...
> +*/
> +__attribute__ ((noipa, noinline))
> +unsigned short f2 (void)
> +{
> +  unsigned short res = 0;
> +  for (unsigned int i = 0; i < N; ++i)
> +    {
> +      unsigned short x = c[i] & d[i];
> +      res = x;
> +      if (x > 5)
> + break;
> +    }
> +  return res;
> +}
> diff --git a/gcc/testsuite/gcc.target/aarch64/noeffect2.c 
> b/gcc/testsuite/gcc.target/aarch64/noeffect2.c
> index 
> 08c531fb18c817b018776a88db4f62eb03b001cb..bcd8848038527d3af1a4966ef55580e262b5d871
>  100644
> --- a/gcc/testsuite/gcc.target/aarch64/noeffect2.c
> +++ b/gcc/testsuite/gcc.target/aarch64/noeffect2.c
> @@ -13,7 +13,7 @@ int b[N] = {0};
> ** ldr q[0-9]+, \[x[0-9]+, x[0-9]+\]
> ** add x[0-9]+, x[0-9]+, 16
> ** cmgt v[0-9]+\.4s, v[0-9]+\.4s, v[0-9]+\.4s
> -** umaxp v[0-9]+\.4s, v[0-9]+\.4s, v[0-9]+\.4s
> +** addhn v[0-9]+\.2s, v[0-9]+\.2d, v[0-9]+\.2d
> ** fmov x[0-9]+, d[0-9]+
> ** cbz x[0-9]+, \.L[0-9]+
> ** mov w0, 1
> diff --git a/gcc/testsuite/gcc.target/aarch64/noeffect3.c 
> b/gcc/testsuite/gcc.target/aarch64/noeffect3.c
> index 
> 886ad7bda2f3ebd5048cc618bcf4fe473cd2f820..f4ece387fc355b5a7d8c23b416400ec81da47051
>  100644
> --- a/gcc/testsuite/gcc.target/aarch64/noeffect3.c
> +++ b/gcc/testsuite/gcc.target/aarch64/noeffect3.c
> @@ -10,11 +10,14 @@ int b[N] = {0};
> ** foo:
> ** ...
> ** cmgt v[0-9]+\.4s, v[0-9]+\.4s, v[0-9]+\.4s
> -** umaxp v[0-9]+\.4s, v[0-9]+\.4s, v[0-9]+\.4s
> -** ...
> -** ldr w[0-9]+, \[x[0-9]+, w[0-9]+, sxtw 2\]
> -** ldr w[0-9]+, \[x[0-9]+, w[0-9]+, sxtw 2\]
> -** cmp w[0-9]+, w[0-9]+
> +** addhn v[0-9]+\.2s, v[0-9]+\.2d, v[0-9]+\.2d
> +** umov x[0-9]+, v[0-9]+\.d\[0\]
> +** cbz x[0-9]+, \.L[0-9]+
> +** and x[0-9]+, x[0-9]+, 281479271743489
> +** rbit x[0-9]+, x[0-9]+
> +** clz x[0-9]+, x[0-9]+
> +** lsr x[0-9]+, x[0-9]+, 4
> +** add w0, w0, w[0-9]+
> ** ...
> ** ret
> */
> diff --git a/gcc/testsuite/gcc.target/aarch64/noeffect4.c 
> b/gcc/testsuite/gcc.target/aarch64/noeffect4.c
> index 
> 276843c9bbd82d9fd409418734cc9a39cddf0aeb..6a477d165f7fa006ef6cf34ae3e84abba9a63fe0
>  100644
> --- a/gcc/testsuite/gcc.target/aarch64/noeffect4.c
> +++ b/gcc/testsuite/gcc.target/aarch64/noeffect4.c
> @@ -10,12 +10,18 @@ short b[N] = {0};
> ** foo:
> ** ...
> ** cmgt v[0-9]+\.8h, v[0-9]+\.8h, v[0-9]+\.8h
> -** umaxp v[0-9]+\.4s, v[0-9]+\.4s, v[0-9]+\.4s
> -** ...
> -** ldrsh w[0-9]+, \[[^\n]+\]
> -** ldrsh w[0-9]+, \[[^\n]+\]
> -** cmp w[0-9]+, w[0-9]+
> +** addhn v[0-9]+\.4h, v[0-9]+\.4s, v[0-9]+\.4s
> +** umov x[0-9]+, v[0-9]+\.d\[0\]
> +** cbz x[0-9]+, \.L[0-9]+
> +** and x[0-9]+, x[0-9]+, 72340172838076673
> +** rbit x[0-9]+, x[0-9]+
> +** clz x[0-9]+, x[0-9]+
> +** ubfx x[0-9]+, x[0-9]+, 3, 32
> +** add w[0-9]+, w[0-9]+, w[0-9]+
> +** and w[0-9]+, w[0-9]+, 65535
> +** ret
> ** ...
> +** mov w0, 0
> ** ret
> */
> __attribute__ ((noipa, noinline))
> @@ -28,3 +34,5 @@ int foo (void)
>     }
>   return 0;
> }
> +
> +/* { dg-final { scan-assembler-not {\tldrsh\t} } } */
> diff --git a/gcc/testsuite/gcc.target/aarch64/noeffect5.c 
> b/gcc/testsuite/gcc.target/aarch64/noeffect5.c
> index 
> c15e52ebdfc4d07b0e6caf12f1c8e0c6d41d377a..e463509a299eb84323397cae68aeda84fa4c543a
>  100644
> --- a/gcc/testsuite/gcc.target/aarch64/noeffect5.c
> +++ b/gcc/testsuite/gcc.target/aarch64/noeffect5.c
> @@ -10,11 +10,14 @@ short b[N] = {0};
> ** foo:
> ** ...
> ** cmgt v[0-9]+\.8h, v[0-9]+\.8h, v[0-9]+\.8h
> -** umaxp v[0-9]+\.4s, v[0-9]+\.4s, v[0-9]+\.4s
> -** ...
> -** ldrsh w[0-9]+, \[[^\n]+\]
> -** ldrsh w[0-9]+, \[[^\n]+\]
> -** cmp w[0-9]+, w[0-9]+
> +** addhn v[0-9]+\.4h, v[0-9]+\.4s, v[0-9]+\.4s
> +** umov x[0-9]+, v[0-9]+\.d\[0\]
> +** cbz x[0-9]+, \.L[0-9]+
> +** and x[0-9]+, x[0-9]+, 72340172838076673
> +** rbit x[0-9]+, x[0-9]+
> +** clz x[0-9]+, x[0-9]+
> +** ubfx x[0-9]+, x[0-9]+, 3, 32
> +** add w0, w0, w[0-9]+
> ** ...
> ** ret
> */
> diff --git a/gcc/testsuite/gcc.target/aarch64/noeffect6.c 
> b/gcc/testsuite/gcc.target/aarch64/noeffect6.c
> index 
> 9da4f496a02e96f053b9c001748a91df7b31d12d..7b4c742da5b8af2e111798a8187c34789aa05bdb
>  100644
> --- a/gcc/testsuite/gcc.target/aarch64/noeffect6.c
> +++ b/gcc/testsuite/gcc.target/aarch64/noeffect6.c
> @@ -10,11 +10,14 @@ short b[N] = {0};
> ** foo:
> ** ...
> ** cmgt v[0-9]+\.8h, v[0-9]+\.8h, v[0-9]+\.8h
> -** umaxp v[0-9]+\.4s, v[0-9]+\.4s, v[0-9]+\.4s
> -** ...
> -** ldrsh w[0-9]+, \[[^\n]+\]
> -** ldrsh w[0-9]+, \[[^\n]+\]
> -** cmp w[0-9]+, w[0-9]+
> +** addhn v[0-9]+\.4h, v[0-9]+\.4s, v[0-9]+\.4s
> +** umov x[0-9]+, v[0-9]+\.d\[0\]
> +** cbz x[0-9]+, \.L[0-9]+
> +** and x[0-9]+, x[0-9]+, 72340172838076673
> +** rbit x[0-9]+, x[0-9]+
> +** clz x[0-9]+, x[0-9]+
> +** lsr x[0-9]+, x[0-9]+, 3
> +** ldrh w0, \[x[0-9]+, x[0-9]+, lsl 1\]
> ** ...
> ** ret
> */
> diff --git a/gcc/testsuite/gcc.target/aarch64/noeffect7.c 
> b/gcc/testsuite/gcc.target/aarch64/noeffect7.c
> index 
> 16fc921117aa2a94ac7dd8fe795fe046f34cdb07..fb20481351495a63d94f7ffe8c06f0a886222f1b
>  100644
> --- a/gcc/testsuite/gcc.target/aarch64/noeffect7.c
> +++ b/gcc/testsuite/gcc.target/aarch64/noeffect7.c
> @@ -1,26 +1,13 @@
> /* { dg-do compile } */
> /* { dg-options "-O3 -march=armv8-a" } */
> -/* { dg-final { check-function-bodies "**" "" "" } } */
> +/* { dg-final { scan-assembler {\tcmp\tw[0-9]+, w[0-9]+} } } */
> +/* { dg-final { scan-assembler {\tmov\tw0, 1} } } */
> +/* { dg-final { scan-assembler {\tmov\tw0, 0} } } */
> 
> #define N 1000
> int a[N] = {0};
> int b[N] = {0};
> 
> -/*
> -** foo:
> -** ...
> -** add x[0-9]+, x[0-9]+, 4000
> -** add x[0-9]+, x[0-9]+, 2000
> -** b \.L[0-9]+
> -** ldr w[0-9]+, \[x[0-9]+[^\n]*\]
> -** ...
> -** cmp w[0-9]+, w[0-9]+
> -** ...
> -** mov w0, 1
> -** ret
> -** mov w0, 0
> -** ret
> -*/
> __attribute__ ((noipa, noinline))
> int foo (void)
> {
> diff --git a/gcc/testsuite/gcc.target/aarch64/noeffect8.c 
> b/gcc/testsuite/gcc.target/aarch64/noeffect8.c
> index 
> ada79391a8acab2073517b4172570947ec16a8a6..d3e03a618fa970b5480eed619e00c670ff3aaab4
>  100644
> --- a/gcc/testsuite/gcc.target/aarch64/noeffect8.c
> +++ b/gcc/testsuite/gcc.target/aarch64/noeffect8.c
> @@ -6,7 +6,9 @@
> ** add:
> ** ...
> ** cmeq v[0-9]+\.4s, v[0-9]+\.4s, #0
> -** umaxp v[0-9]+\.4s, v[0-9]+\.4s, v[0-9]+\.4s
> +** addhn v[0-9]+\.2s, v[0-9]+\.2d, v[0-9]+\.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbnz x[0-9]+, \.L[0-9]+
> ** ...
> ** ldr q[0-9]+, \[x[0-9]+[^\n]*\]
> ** ...
> diff --git a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch.c 
> b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch.c
> index 
> ca4ef498485f68dbb8a178750db3f552cf7a66d0..b29f02a4418cd3a6d87bd617d9d3fb06d5e3f0c8
>  100644
> --- a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch.c
> +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch.c
> @@ -13,7 +13,7 @@ int b[N] = {0};
> ** f1:
> ** ...
> ** cmgt v[0-9]+.4s, v[0-9]+.4s, #0
> -** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> ** fmov x[0-9]+, d[0-9]+
> ** cbn?z x[0-9]+, \.L[0-9]+
> ** ...
> @@ -32,7 +32,7 @@ void f1 ()
> ** f2:
> ** ...
> ** cmge v[0-9]+.4s, v[0-9]+.4s, #0
> -** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> ** fmov x[0-9]+, d[0-9]+
> ** cbn?z x[0-9]+, \.L[0-9]+
> ** ...
> @@ -50,7 +50,8 @@ void f2 ()
> /*
> ** f3:
> ** ...
> -** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** cmeq v[0-9]+.4s, v[0-9]+.4s, #0
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> ** fmov x[0-9]+, d[0-9]+
> ** cbn?z x[0-9]+, \.L[0-9]+
> ** ...
> @@ -68,7 +69,8 @@ void f3 ()
> /*
> ** f4:
> ** ...
> -** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** cmtst v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> ** fmov x[0-9]+, d[0-9]+
> ** cbn?z x[0-9]+, \.L[0-9]+
> ** ...
> @@ -87,7 +89,7 @@ void f4 ()
> ** f5:
> ** ...
> ** cmlt v[0-9]+.4s, v[0-9]+.4s, #0
> -** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> ** fmov x[0-9]+, d[0-9]+
> ** cbn?z x[0-9]+, \.L[0-9]+
> ** ...
> @@ -106,7 +108,7 @@ void f5 ()
> ** f6:
> ** ...
> ** cmle v[0-9]+.4s, v[0-9]+.4s, #0
> -** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> ** fmov x[0-9]+, d[0-9]+
> ** cbn?z x[0-9]+, \.L[0-9]+
> ** ...
> diff --git a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_2.c 
> b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_2.c
> index 
> d5cb1946873f5e720c6e12e0dd4991582764f18f..e40843f11b046dc8b8c99428a93da5ab6234d16e
>  100644
> --- a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_2.c
> +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_2.c
> @@ -10,8 +10,10 @@ int b[N] = {0};
> /*
> ** f1:
> ** ...
> -** cmpgt p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0
> -** b(\.?eq|\.none) \.L[0-9]+
> +** cmgt v[0-9]+.4s, v[0-9]+.4s, #0
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f1 ()
> @@ -26,8 +28,10 @@ void f1 ()
> /*
> ** f2:
> ** ...
> -** cmpge p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0
> -** b(\.?eq|\.none) \.L[0-9]+
> +** cmge v[0-9]+.4s, v[0-9]+.4s, #0
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f2 ()
> @@ -42,8 +46,10 @@ void f2 ()
> /*
> ** f3:
> ** ...
> -** cmpeq p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0
> -** b(\.?eq|\.none) \.L[0-9]+
> +** cmeq v[0-9]+.4s, v[0-9]+.4s, #0
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f3 ()
> @@ -58,8 +64,10 @@ void f3 ()
> /*
> ** f4:
> ** ...
> -** cmpne p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0
> -** b(\.?eq|\.none) \.L[0-9]+
> +** cmtst v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f4 ()
> @@ -74,8 +82,10 @@ void f4 ()
> /*
> ** f5:
> ** ...
> -** cmplt p[0-9]+.s, p7/z, z[0-9]+.s, #0
> -** b(\.?eq|\.none) .L[0-9]+
> +** cmlt v[0-9]+.4s, v[0-9]+.4s, #0
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f5 ()
> @@ -90,8 +100,10 @@ void f5 ()
> /*
> ** f6:
> ** ...
> -** cmple p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0
> -** b(\.?eq|\.none) \.L[0-9]+
> +** cmle v[0-9]+.4s, v[0-9]+.4s, #0
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f6 ()
> diff --git a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_3.c 
> b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_3.c
> index 
> b252b80ef291efd4f6fc98224a44ef7fadc68d6c..9e4d3f951ad111df0f76032445ccce8673bca74e
>  100644
> --- a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_3.c
> +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_3.c
> @@ -11,9 +11,10 @@ float b[N] = {0};
> /*
> ** f1:
> ** ...
> -** fcmgt p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0
> -** ptest p[0-9]+, p[0-9]+\.b
> -** b(\.?eq|\.none) \.L[0-9]+
> +** fcmgt v[0-9]+.4s, v[0-9]+.4s, 0
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f1 ()
> @@ -28,9 +29,10 @@ void f1 ()
> /*
> ** f2:
> ** ...
> -** fcmge p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0
> -** ptest p[0-9]+, p[0-9]+\.b
> -** b(\.?eq|\.none) \.L[0-9]+
> +** fcmge v[0-9]+.4s, v[0-9]+.4s, 0
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f2 ()
> @@ -45,9 +47,10 @@ void f2 ()
> /*
> ** f3:
> ** ...
> -** fcmeq p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0
> -** ptest p[0-9]+, p[0-9]+\.b
> -** b(\.?eq|\.none) \.L[0-9]+
> +** fcmeq v[0-9]+.4s, v[0-9]+.4s, 0
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f3 ()
> @@ -62,9 +65,11 @@ void f3 ()
> /*
> ** f4:
> ** ...
> -** fcmne p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0
> -** ptest p[0-9]+, p[0-9]+\.b
> -** b(\.?eq|\.none) \.L[0-9]+
> +** fcmeq v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** not v[0-9]+.16b, v[0-9]+.16b
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f4 ()
> @@ -79,9 +84,10 @@ void f4 ()
> /*
> ** f5:
> ** ...
> -** fcmlt p[0-9]+.s, p7/z, z[0-9]+.s, #0.0
> -** ptest p[0-9]+, p[0-9]+\.b
> -** b(\.?eq|\.none) .L[0-9]+
> +** fcmlt v[0-9]+.4s, v[0-9]+.4s, 0
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f5 ()
> @@ -96,9 +102,10 @@ void f5 ()
> /*
> ** f6:
> ** ...
> -** fcmle p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0
> -** ptest p[0-9]+, p[0-9]+\.b
> -** b(\.?eq|\.none) \.L[0-9]+
> +** fcmle v[0-9]+.4s, v[0-9]+.4s, 0
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f6 ()
> diff --git a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_4.c 
> b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_4.c
> index 
> a49e7963cfa1afdce4bb1bf33224a1d79eb7b874..026c774e4de7f6381728f164fbfd89f8643f7c3d
>  100644
> --- a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_4.c
> +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_4.c
> @@ -13,9 +13,9 @@ unsigned int b[N] = {0};
> ** f1:
> ** ...
> ** cmhi v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> -** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> ** fmov x[0-9]+, d[0-9]+
> -** cbn?z x[0-9]+, \.L[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f1 ()
> @@ -32,9 +32,9 @@ void f1 ()
> ** f2:
> ** ...
> ** cmtst v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> -** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> ** fmov x[0-9]+, d[0-9]+
> -** cbn?z x[0-9]+, \.L[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f2 ()
> @@ -50,9 +50,10 @@ void f2 ()
> /*
> ** f3:
> ** ...
> -** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** cmeq v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> ** fmov x[0-9]+, d[0-9]+
> -** cbn?z x[0-9]+, \.L[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f3 ()
> @@ -68,9 +69,11 @@ void f3 ()
> /*
> ** f4:
> ** ...
> -** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** cmeq v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** not v[0-9]+.16b, v[0-9]+.16b
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> ** fmov x[0-9]+, d[0-9]+
> -** cbn?z x[0-9]+, \.L[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f4 ()
> @@ -87,9 +90,9 @@ void f4 ()
> ** f5:
> ** ...
> ** cmhs v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> -** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> ** fmov x[0-9]+, d[0-9]+
> -** cbn?z x[0-9]+, \.L[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f5 ()
> @@ -106,9 +109,9 @@ void f5 ()
> ** f6:
> ** ...
> ** cmhs v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> -** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> ** fmov x[0-9]+, d[0-9]+
> -** cbn?z x[0-9]+, \.L[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f6 ()
> diff --git a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_5.c 
> b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_5.c
> index 
> c28969dde1ff24872a5c3d9c236808f215cfdaa2..9679a9342f9b74170e21ec41e1959525942c0f14
>  100644
> --- a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_5.c
> +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_5.c
> @@ -10,8 +10,12 @@ unsigned int b[N] = {0};
> /*
> ** f1:
> ** ...
> -** cmphi p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #2
> -** b(\.?eq|\.none) \.L[0-9]+
> +** movi v[0-9]+.4s, 0x2
> +** ...
> +** cmhi v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f1 ()
> @@ -26,8 +30,12 @@ void f1 ()
> /*
> ** f2:
> ** ...
> -** cmphi p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #1
> -** b(\.?eq|\.none) \.L[0-9]+
> +** movi v[0-9]+.4s, 0x1
> +** ...
> +** cmhi v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f2 ()
> @@ -42,8 +50,12 @@ void f2 ()
> /*
> ** f3:
> ** ...
> -** cmpeq p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #1
> -** b(\.?eq|\.none) \.L[0-9]+
> +** movi v[0-9]+.4s, 0x1
> +** ...
> +** cmeq v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f3 ()
> @@ -58,8 +70,13 @@ void f3 ()
> /*
> ** f4:
> ** ...
> -** cmpne p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #1
> -** b(\.?eq|\.none) \.L[0-9]+
> +** movi v[0-9]+.4s, 0x1
> +** ...
> +** cmeq v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** not v[0-9]+.16b, v[0-9]+.16b
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f4 ()
> @@ -74,8 +91,12 @@ void f4 ()
> /*
> ** f5:
> ** ...
> -** cmpls p[0-9]+.s, p7/z, z[0-9]+.s, #1
> -** b(\.?eq|\.none) .L[0-9]+
> +** movi v[0-9]+.4s, 0x1
> +** ...
> +** cmhs v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f5 ()
> @@ -90,8 +111,12 @@ void f5 ()
> /*
> ** f6:
> ** ...
> -** cmpls p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #1
> -** b(\.?eq|\.none) \.L[0-9]+
> +** movi v[0-9]+.4s, 0x1
> +** ...
> +** cmhs v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> ** ...
> */
> void f6 ()
> diff --git a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_7.c 
> b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_7.c
> new file mode 100644
> index 
> 0000000000000000000000000000000000000000..e698ee5aa537c35a1c80a0bb0fbdf53790aac220
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_7.c
> @@ -0,0 +1,34 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O3 -mcpu=neoverse-v2 -fno-schedule-insns 
> -fno-reorder-blocks -fno-schedule-insns2 --param 
> aarch64-autovec-preference=asimd-only -fdump-tree-vect-details" } */
> +/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */
> +
> +#pragma GCC target "+nosve"
> +
> +void *a[640] = { 0 };
> +
> +void sink (void **);
> +
> +/*
> +** f1:
> +** ...
> +** ldp q[0-9]+, q[0-9]+, \[[x0-9]+.*\]
> +** cmeq v[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d
> +** cmeq v[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d
> +** addhn v[0-9]+.2s, v[0-9]+.2d, v[0-9]+.2d
> +** fmov x[0-9]+, d[0-9]+
> +** cbz x[0-9]+, \.L[0-9]+
> +** ...
> +*/
> +void
> +f1 (void *x, unsigned long n)
> +{
> +  void **end = a + n;
> +  for (void **p = a; p != end; ++p)
> +    if (*p == x)
> +      {
> + sink (p);
> + return;
> +      }
> +}
> +
> +/* { dg-final { scan-tree-dump "loop vectorized using 16 byte vectors and 
> unroll factor 4" "vect" } } */
> diff --git a/gcc/testsuite/lib/target-supports.exp 
> b/gcc/testsuite/lib/target-supports.exp
> index 
> 94a3dba222fd3d257263a0c3bd0daf83b8fe7490..73bf24a1073090686476c3cdea1b8cbf061cd2a0
>  100644
> --- a/gcc/testsuite/lib/target-supports.exp
> +++ b/gcc/testsuite/lib/target-supports.exp
> @@ -6800,6 +6800,24 @@ proc check_effective_target_aarch64_sve_hw { } {
>     } [add_options_for_aarch64_sve ""]]
> }
> 
> +# Return true if this is an AArch64 target that can run Adv.SIMD LUT code.
> +
> +proc check_effective_target_aarch64_lut_hw { } {
> +    if { ![istarget aarch64*-*-*] } {
> + return 0
> +    }
> +    return [check_runtime aarch64_lut_hw_available {
> + #pragma GCC target "+lut"
> + int
> + main (void)
> + {
> +  asm volatile ("movi v0.16b, #0\n\t"
> + "luti4 v0.16b, {v0.16b}, v0[0]");
> +  return 0;
> + }
> +    }]
> +}
> +
> # Return true if this is an AArch64 target that can run SVE2 code.
> 
> proc check_effective_target_aarch64_sve2_hw { } {
> 
> 
> -- 
> <rb20863.patch>

Reply via email to