> -----Original Message-----
> From: Wilco Dijkstra <[email protected]>
> Sent: 11 September 2026 17:53
> To: Tamar Christina <[email protected]>; Kyrylo Tkachov
> <[email protected]>; Alice Carlotti <[email protected]>; Alex Coplan
> <[email protected]>; Andrew Pinski
> <[email protected]>
> Cc: GCC Patches <[email protected]>
> Subject: Re: [PATCH v2] AArch64: Add tune for zeroing SVE move
>
> Hi Tamar,
>
> > So instead of
> >
> > mov z0.s, p0/z, #5
> >
> > we generate with the flag
> >
> > movi d0, #0
> > fmov z0.s, p0/m, #1.0
>
> Correct - and that is exactly what we already do for FP immediates since there
> is
> no zeroing variant.
>
> > ? Weird but sure I believe you. But should aarch64_sel_dup<mode> also get
> the
> > same treatment then? You previously changed this to drop the movprfx
> version
> > so I'd expect the same behaviour?
>
> It already does, I removed all the zeroing movprfx variants, so they already
> use
> movi.
> This case is the last zeroing variant.
>
> > Could you also please add a testcase for the tune.
>
> Done.
>
> Cheers,
> Wilco
>
>
> v2: Add testcase, improve description
>
> Add a new tune to select whether to prefer zeroing SVE move immediate or
> use the merging variant after zeroing the destination. Since the expander
> is bypassed in multiple places, split after reload to zero the destination.
> Enable it on cores where the latter was measured to be slightly faster.
>
> With -mcpu=neoverse-v2 we now emit this for the testcase:
>
> movi d0, #0
> mov z0.s, p0/m, #1
>
> instead of:
>
> mov z0.s, p0/z, #1
>
> This matches the floating point case (where there is no zeroing variant):
>
> movi d0, #0
> fmov z0.s, p0/m, #1.0
>
> Passes regress, OK for commit?
OK.
Thanks,
Tamar
>
> gcc:
> * config/aarch64/aarch64.h
> (TARGET_SVE_PREFER_ZEROING_MOVIMM): New
> define.
> * config/aarch64/aarch64-sve.md
> (*vcond_mask_<mode><vpred>): Add a
> split condition for zero predicate.
> * config/aarch64/aarch64-tuning-flags.def: Add AVOID_MOVIMM_Z
> tune.
> * config/aarch64/tuning_models/neoversev1.h (tune_flags): Update.
> * config/aarch64/tuning_models/neoversev2.h (tune_flags): Update.
>
> gcc/testsuite:
> * gcc.target/aarch64/sve/zeroing_mov_z.c: New test.
>
> ---
>
> diff --git a/gcc/config/aarch64/aarch64-sve.md
> b/gcc/config/aarch64/aarch64-sve.md
> index
> 1667145d3c71c14b7d19e32d14f521c8f3c91ad7..8b15e25e8b50dd671174
> b8c971589e904f95607f 100644
> --- a/gcc/config/aarch64/aarch64-sve.md
> +++ b/gcc/config/aarch64/aarch64-sve.md
> @@ -8622,7 +8622,7 @@ (define_expand "@vcond_mask_<mode><vpred>"
> ;; This creates a false dependency on z0 which can result in stalls.
> ;; The zeroing will be done via a movi d0, 0 which is cheaper.
> ;;
> -(define_insn "*vcond_mask_<mode><vpred>"
> +(define_insn_and_rewrite "*vcond_mask_<mode><vpred>"
> [(set (match_operand:SVE_ALL 0 "register_operand")
> (unspec:SVE_ALL
> [(match_operand:<VPRED> 3 "aarch64_predicate_operand")
> @@ -8640,6 +8640,13 @@ (define_insn "*vcond_mask_<mode><vpred>"
> [ ?&w , vss , w , Upa ; yes ] movprfx\t%0,
> %2\;mov\t%0.<Vetype>,
> %3/m, #%I1
> [ ?&w , Ufc , w , Upa ; yes ] movprfx\t%0,
> %2\;fmov\t%0.<Vetype>, %3/m, #%1
> }
> + "&& reload_completed
> + && aarch64_simd_or_scalar_imm_zero (operands[2], <MODE>mode)
> + && !TARGET_SVE_PREFER_ZEROING_MOVIMM"
> + {
> + emit_move_insn (operands[0], operands[2]);
> + operands[2] = copy_rtx (operands[0]);
> + }
> )
>
> ;; Optimize selects between a duplicated scalar variable and another vector.
> diff --git a/gcc/config/aarch64/aarch64-tuning-flags.def
> b/gcc/config/aarch64/aarch64-tuning-flags.def
> index
> 32bc1c4f3eecf04f35740bb573ea39c8449cf901..64a773be34c0c28e18a1c2
> b3b0a84ce369633010 100644
> --- a/gcc/config/aarch64/aarch64-tuning-flags.def
> +++ b/gcc/config/aarch64/aarch64-tuning-flags.def
> @@ -81,4 +81,7 @@ AARCH64_EXTRA_TUNING_OPTION ("dispatch_sched",
> DISPATCH_SCHED)
> 32 bits are unused. */
> AARCH64_EXTRA_TUNING_OPTION ("narrow_gp_writes",
> NARROW_GP_WRITES)
>
> +/* Enable when the target prefers SVE merging movimm over zeroing. */
> +AARCH64_EXTRA_TUNING_OPTION ("avoid_zeroing_movimm",
> AVOID_MOVIMM_Z)
> +
> #undef AARCH64_EXTRA_TUNING_OPTION
> diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
> index
> fdedb04391127c5a1b821ed5d4b399c1c28d9f31..c7fa687514e48aad2897d
> dc85880a4685c3b7602 100644
> --- a/gcc/config/aarch64/aarch64.h
> +++ b/gcc/config/aarch64/aarch64.h
> @@ -519,6 +519,10 @@ constexpr auto AARCH64_FL_DEFAULT_ISA_MODE
> ATTRIBUTE_UNUSED
> &&
> (aarch64_tune_params.extra_tuning_flags \
> &
> AARCH64_EXTRA_TUNE_AVOID_PRED_RMW))
>
> +/* Set if we prefer SVE merging predicated mov immediate over zeroing. */
> +#define TARGET_SVE_PREFER_ZEROING_MOVIMM \
> + !(aarch64_tune_params.extra_tuning_flags &
> AARCH64_EXTRA_TUNE_AVOID_MOVIMM_Z)
> +
> /* fp8 instructions are enabled through +fp8. */
> #define TARGET_FP8 AARCH64_HAVE_ISA (FP8)
>
> diff --git a/gcc/config/aarch64/tuning_models/neoversev1.h
> b/gcc/config/aarch64/tuning_models/neoversev1.h
> index
> 253f11e87a68548a51201ee8e1318aaae606cab2..004676a8dbacf438beb5c
> 5598a39f80988bb6a48 100644
> --- a/gcc/config/aarch64/tuning_models/neoversev1.h
> +++ b/gcc/config/aarch64/tuning_models/neoversev1.h
> @@ -229,7 +229,8 @@ static const struct tune_params neoversev1_tunings
> =
> (AARCH64_EXTRA_TUNE_BASE
> | AARCH64_EXTRA_TUNE_CSE_SVE_VL_CONSTANTS
> | AARCH64_EXTRA_TUNE_MATCHED_VECTOR_THROUGHPUT
> - | AARCH64_EXTRA_TUNE_AVOID_PRED_RMW), /* tune_flags. */
> + | AARCH64_EXTRA_TUNE_AVOID_PRED_RMW
> + | AARCH64_EXTRA_TUNE_AVOID_MOVIMM_Z), /* tune_flags. */
> &generic_armv9a_prefetch_tune,
> AARCH64_LDP_STP_POLICY_ALWAYS, /* ldp_policy_model. */
> AARCH64_LDP_STP_POLICY_ALWAYS, /* stp_policy_model. */
> diff --git a/gcc/config/aarch64/tuning_models/neoversev2.h
> b/gcc/config/aarch64/tuning_models/neoversev2.h
> index
> 6df0cc444b804cf098e8f16d10d7afff6340dd9e..734089772517e69af448d
> d44acf5b20982b8cc3a 100644
> --- a/gcc/config/aarch64/tuning_models/neoversev2.h
> +++ b/gcc/config/aarch64/tuning_models/neoversev2.h
> @@ -359,6 +359,7 @@ static const struct tune_params neoversev2_tunings
> =
> | AARCH64_EXTRA_TUNE_CSE_SVE_VL_CONSTANTS
> | AARCH64_EXTRA_TUNE_MATCHED_VECTOR_THROUGHPUT
> | AARCH64_EXTRA_TUNE_AVOID_PRED_RMW
> + | AARCH64_EXTRA_TUNE_AVOID_MOVIMM_Z
> | AARCH64_EXTRA_TUNE_AVOID_LDAPUR
> | AARCH64_EXTRA_TUNE_DISPATCH_SCHED), /* tune_flags. */
> &generic_armv9a_prefetch_tune,
> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/zeroing_mov_z.c
> b/gcc/testsuite/gcc.target/aarch64/sve/zeroing_mov_z.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..c257e8e7b72014d672
> c92d94f27aeaa8ededd6f8
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/sve/zeroing_mov_z.c
> @@ -0,0 +1,27 @@
> +/* { dg-options "-O2 -mcpu=neoverse-v2" } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +#include <arm_sve.h>
> +
> +/*
> +** foo:
> +** movi d0, #0
> +** mov z0.s, p0/m, #1
> +** ret
> +*/
> +svint32_t foo (svbool_t pg)
> +{
> + return svsel (pg, svdup_s32 (1), svdup_s32 (0));
> +}
> +
> +/*
> +** foo2:
> +** movi d0, #0
> +** fmov z0.s, p0/m, #1.0
> +** ret
> +*/
> +svfloat32_t foo2 (svbool_t pg)
> +{
> + return svsel (pg, svdup_f32 (1.0f), svdup_f32 (0.0f));
> +}
> +