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?
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..8b15e25e8b50dd671174b8c971589e904f95607f
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..64a773be34c0c28e18a1c2b3b0a84ce369633010
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..c7fa687514e48aad2897ddc85880a4685c3b7602
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..004676a8dbacf438beb5c5598a39f80988bb6a48
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..734089772517e69af448dd44acf5b20982b8cc3a
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..c257e8e7b72014d672c92d94f27aeaa8ededd6f8
--- /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));
+}
+