Hi Artemiy,
> -----Original Message-----
> From: Artemiy Volkov <[email protected]>
> Sent: 21 May 2026 17:52
> To: [email protected]
> Cc: Tamar Christina <[email protected]>; Wilco Dijkstra
> <[email protected]>; [email protected]; Richard
> Earnshaw <[email protected]>; [email protected]; Alice
> Carlotti <[email protected]>; Alex Coplan <[email protected]>;
> Artemiy Volkov <[email protected]>
> Subject: [PATCH v2 1/4] aarch64: introduce partial AdvSIMD vector modes
>
> In addition to V2HF that already exists, this patch adds 4 more partial
> (16- and 32-bit) AdvSIMD vector modes: V4QI, V2QI, V2HI, and V2BF. For
> now, these are intended only for duplication into full-sized (32-, 64-,
> and 128-bit) registers. As a minimal closure required to bootstrap the
> compiler, this also implements the "mov" expand and the
> "aarch64_simd_mov"
> insn_and_split for the new modes (gathered under the VSUB64 iterator).
>
> This patch also adds the new aarch64_advsimd_sub_dword_mode_p () helper
> to
> facilitate detecting the new modes; that is then used (a) to disable
> vec_perm_const vectorization for those modes, (b) in the "mov" expander
> for those modes, and (c) to define the new "Da" constraint.
>
> Some existing testcases were adjusted where needed. (The _Float16
> testcase in sve/slp_1.c temporarily expects GPRs to be used for V2HF,
> which is corrected to FPRs by the succeeding patch; and the half-float
> complex tests now recognize some of the patterns, but check that V2BF
> still can't be used for vectorization.)
>
> gcc/ChangeLog:
>
> * config/aarch64/aarch64-modes.def (VECTOR_MODE): Remove
> V2HF.
> (VECTOR_MODES): Define V2QI, V4QI, V2HI, V2HF, V2BF.
> * config/aarch64/aarch64-simd.md (*aarch64_simd_mov<mode>):
> New
> define_insn_and_split pattern.
> (mov<mode>): Add sub-64-bit vector modes to the VALL_F16
> expander.
> Forego const vector expansion for those modes.
> (aarch64_classify_vector_mode): Handle 16- and 32-bit vector
> modes.
> (aarch64_advsimd_sub_dword_mode_p): New predicate.
> (aarch64_vectorize_vec_perm_const): Refuse for partial vector
> modes.
> * config/aarch64/constraints.md (Da): New constraint.
> * config/aarch64/iterators.md (VSUB64): New iterator.
> (VALL_F16_SUB64): Likewise.
> (size): Define attribute for sub-64-bit vector modes.
> (VSC): New mode attribute.
> (vstype): Likewise.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.dg/vect/complex/bb-slp-complex-add-half-float.c: Adjust
> testcase.
> * gcc.dg/vect/complex/bb-slp-complex-mla-half-float.c: Likewise.
> * gcc.dg/vect/complex/bb-slp-complex-mul-half-float.c: Likewise.
> * gcc.target/aarch64/sve/slp_1.c: Likewise.
> ---
> gcc/config/aarch64/aarch64-modes.def | 4 +-
> gcc/config/aarch64/aarch64-protos.h | 1 +
> gcc/config/aarch64/aarch64-simd.md | 64 ++++++++++++++++++-
> gcc/config/aarch64/aarch64.cc | 18 ++++++
> gcc/config/aarch64/constraints.md | 5 ++
> gcc/config/aarch64/iterators.md | 19 +++++-
> .../complex/bb-slp-complex-add-half-float.c | 2 +
> .../complex/bb-slp-complex-mla-half-float.c | 4 +-
> .../complex/bb-slp-complex-mul-half-float.c | 6 +-
> gcc/testsuite/gcc.target/aarch64/sve/slp_1.c | 11 ++--
> 10 files changed, 121 insertions(+), 13 deletions(-)
>
> diff --git a/gcc/config/aarch64/aarch64-modes.def
> b/gcc/config/aarch64/aarch64-modes.def
> index d9bff61adec..d5a54689f7a 100644
> --- a/gcc/config/aarch64/aarch64-modes.def
> +++ b/gcc/config/aarch64/aarch64-modes.def
> @@ -79,8 +79,10 @@ VECTOR_MODES (FLOAT, 8); /* V2SF. */
> VECTOR_MODES (FLOAT, 16); /* V4SF V2DF. */
> VECTOR_MODE (INT, DI, 1); /* V1DI. */
> VECTOR_MODE (FLOAT, DF, 1); /* V1DF. */
> -VECTOR_MODE (FLOAT, HF, 2); /* V2HF. */
>
> +VECTOR_MODES (INT, 2); /* V2QI. */
> +VECTOR_MODES (INT, 4); /* V4QI V2HI. */
> +VECTOR_MODES (FLOAT, 4); /* V2BF V2HF. */
>
> /* Integer vector modes used to represent intermediate widened values in
> some
> instructions. Not intended to be moved to and from registers or memory.
> */
> diff --git a/gcc/config/aarch64/aarch64-protos.h
> b/gcc/config/aarch64/aarch64-protos.h
> index 8d201821e93..769b628c946 100644
> --- a/gcc/config/aarch64/aarch64-protos.h
> +++ b/gcc/config/aarch64/aarch64-protos.h
> @@ -872,6 +872,7 @@ bool aarch64_and_bitmask_imm (unsigned
> HOST_WIDE_INT val_in, machine_mode mode);
> int aarch64_branch_cost (bool, bool);
> enum aarch64_symbol_type aarch64_classify_symbolic_expression (rtx);
> bool aarch64_advsimd_struct_mode_p (machine_mode mode);
> +bool aarch64_advsimd_sub_dword_mode_p (machine_mode mode);
> opt_machine_mode aarch64_v64_mode (scalar_mode);
> opt_machine_mode aarch64_v128_mode (scalar_mode);
> opt_machine_mode aarch64_full_sve_mode (scalar_mode);
> diff --git a/gcc/config/aarch64/aarch64-simd.md
> b/gcc/config/aarch64/aarch64-simd.md
> index 74a2a06c45b..c2fdc4d6adc 100644
> --- a/gcc/config/aarch64/aarch64-simd.md
> +++ b/gcc/config/aarch64/aarch64-simd.md
> @@ -49,8 +49,8 @@
> (define_subst_attr "vczbe" "add_vec_concat_subst_be" ""
> "_vec_concatz_be")
>
> (define_expand "mov<mode>"
> - [(set (match_operand:VALL_F16 0 "nonimmediate_operand")
> - (match_operand:VALL_F16 1 "general_operand"))]
> + [(set (match_operand:VALL_F16_SUB64 0 "nonimmediate_operand")
> + (match_operand:VALL_F16_SUB64 1 "general_operand"))]
> "TARGET_FLOAT"
> "
> /* Force the operand into a register if it is not an
> @@ -77,7 +77,8 @@
> aarch64_expand_vector_init (operands[0], operands[1]);
> DONE;
> }
> - else if (!aarch64_simd_imm_zero (operands[1], <MODE>mode)
> + else if (!aarch64_advsimd_sub_dword_mode_p (<MODE>mode)
> + && !aarch64_simd_imm_zero (operands[1], <MODE>mode)
> && !aarch64_simd_special_constant_p (operands[1],
> <MODE>mode)
> && !aarch64_simd_valid_mov_imm (operands[1])
> && !aarch64_const_vec_fmov_p (operands[1]))
> @@ -244,6 +245,63 @@
> }
> )
>
> +(define_insn_and_split "*aarch64_simd_mov<mode>"
> + [(set (match_operand:VSUB64 0 "nonimmediate_operand")
> + (match_operand:VSUB64 1 "general_operand"))]
> + "TARGET_FLOAT
> + && (register_operand (operands[0], <MODE>mode)
> + || aarch64_simd_reg_or_zero (operands[1], <MODE>mode)
> + || CONST_VECTOR_P (operands[1]))"
> + {@ [cons: =0, 1; attrs: type, arch]
> + [r , Dz ; mov_imm , * ] mov\t%w0, 0
> + [r , rZ ; mov_reg , * ] mov\t%w0, %w1
> + [r , Da ; mov_imm , * ] #
> + [r , w ; mov_reg , simd ] #
> + [r , m ; load_4 , * ] ldr<size>\t%w0, %1
> + [w , w ; neon_logic , simd ] mov\t%0.8b, %1.8b
> + [w , m ; neon_load1_1reg , simd ] ldr\t%<vstype>0, %1
> + [w , Dz ; f_mcr , * ] fmov\t%<vstype>0, xzr
Should use [w, Dz ; neon_move , simd ] movi\t%0.2d, #0
here to avoid an GRP -> FPR move.
OK with that change.
Thanks,
Tamar
> + [m , rZ ; store_4 , * ] str<size>\t%w1, %0
> + [m , w ; neon_store1_1reg , simd ] str\t%<vstype>1, %0
> + }
> + "&& reload_completed
> + && REG_P (operands[0])"
> + [(const_int 0)]
> + {
> + if (CONST_VECTOR_P (operands[1]))
> + {
> + int elt_bitsize
> + = GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE
> (operands[1])));
> + int n_elts = CONST_VECTOR_NUNITS (operands[1]).to_constant ();
> + int val = 0;
> + bool int_vector_p = CONST_INT_P (CONST_VECTOR_ELT (operands[1],
> 0));
> + unsigned HOST_WIDE_INT eltval;
> + rtx elt;
> + for (int i = 0; i < n_elts; i++)
> + {
> + elt = CONST_VECTOR_ELT (operands[1], BYTES_BIG_ENDIAN
> + ? i
> + : n_elts - 1 - i);
> + if (int_vector_p)
> + eltval = INTVAL (elt);
> + else
> + {
> + bool res = aarch64_reinterpret_float_as_int (elt, &eltval);
> + gcc_assert (res);
> + }
> +
> + val = (val << elt_bitsize) + (eltval & ((1 << elt_bitsize) - 1));
> + }
> + emit_move_insn (gen_rtx_REG (SImode, REGNO (operands[0])),
> + GEN_INT (val));
> + }
> + else if (REG_P (operands[1]))
> + aarch64_simd_emit_reg_reg_move (operands, <VSC>mode, 1);
> + DONE;
> + }
> + [(set_attr "type" "mov_reg")]
> +)
> +
> ;; When storing lane zero we can use the normal STR and its more permissive
> ;; addressing modes.
>
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 291e191f788..0f78f36cba3 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -1778,6 +1778,13 @@ aarch64_classify_vector_mode (machine_mode
> mode, bool any_target_p = false)
> case E_V4x2DFmode:
> return (TARGET_FLOAT || any_target_p) ? VEC_ADVSIMD | VEC_STRUCT :
> 0;
>
> + /* 16-bit Advanced SIMD vectors. */
> + case E_V2QImode:
> + /* 32-bit Advanced SIMD vectors. */
> + case E_V2HFmode:
> + case E_V2BFmode:
> + case E_V2HImode:
> + case E_V4QImode:
> /* 64-bit Advanced SIMD vectors. */
> case E_V8QImode:
> case E_V4HImode:
> @@ -1856,6 +1863,14 @@ aarch64_advsimd_full_struct_mode_p
> (machine_mode mode)
> return (aarch64_classify_vector_mode (mode) == (VEC_ADVSIMD |
> VEC_STRUCT));
> }
>
> +/* Return true if MODE is a partial (sub-64-bit) Advanced SIMD mode. */
> +bool
> +aarch64_advsimd_sub_dword_mode_p (machine_mode mode)
> +{
> + return (aarch64_classify_vector_mode (mode) == VEC_ADVSIMD)
> + && known_lt (GET_MODE_BITSIZE (mode), 64);
> +}
> +
> /* Return true if MODE is any of the data vector modes, including
> structure modes. */
> static bool
> @@ -28383,6 +28398,9 @@ aarch64_vectorize_vec_perm_const
> (machine_mode vmode, machine_mode op_mode,
> {
> struct expand_vec_perm_d d;
>
> + if (aarch64_advsimd_sub_dword_mode_p (op_mode))
> + return false;
> +
> /* Check whether the mask can be applied to a single vector. */
> if (sel.ninputs () == 1
> || (op0 && rtx_equal_p (op0, op1)))
> diff --git a/gcc/config/aarch64/constraints.md
> b/gcc/config/aarch64/constraints.md
> index 8760220835b..829b2c949d0 100644
> --- a/gcc/config/aarch64/constraints.md
> +++ b/gcc/config/aarch64/constraints.md
> @@ -531,6 +531,11 @@
> (and (match_code "const_int")
> (match_test "aarch64_simd_scalar_immediate_valid_for_move (op,
> QImode)")))
> +(define_constraint "Da"
> + "@internal
> + A constraint that matches all sub-64-bit AdvSIMD vectors."
> + (and (match_code "const_vector")
> + (match_test "aarch64_advsimd_sub_dword_mode_p (GET_MODE
> (op))")))
>
> (define_constraint "Dt"
> "@internal
> diff --git a/gcc/config/aarch64/iterators.md
> b/gcc/config/aarch64/iterators.md
> index 39b1e84edcc..dfca3327f1f 100644
> --- a/gcc/config/aarch64/iterators.md
> +++ b/gcc/config/aarch64/iterators.md
> @@ -227,10 +227,17 @@
> ;; All Advanced SIMD integer modes
> (define_mode_iterator VALLI [VDQ_BHSI V2DI])
>
> +;; All sub-64-bit vector modes.
> +(define_mode_iterator VSUB64 [V2QI V4QI V2HI V2HF V2BF])
> +
> ;; All Advanced SIMD modes suitable for moving, loading, and storing.
> (define_mode_iterator VALL_F16 [V8QI V16QI V4HI V8HI V2SI V4SI V2DI
> V4HF V8HF V4BF V8BF V2SF V4SF V2DF])
>
> +;; All Advanced SIMD modes suitable for moving, loading, and storing,
> +;; plus all sub-64-bit vector modes.
> +(define_mode_iterator VALL_F16_SUB64 [VALL_F16 VSUB64])
> +
> ;; The VALL_F16 modes except the 128-bit 2-element ones.
> (define_mode_iterator VALL_F16_NO_V2Q [V8QI V16QI V4HI V8HI V2SI
> V4SI
> V4HF V8HF V2SF V4SF])
> @@ -1466,7 +1473,9 @@
> (define_mode_attr s [(HF "h") (SF "s") (DF "d") (SI "s") (DI "d")])
>
> ;; Give the length suffix letter for a sign- or zero-extension.
> -(define_mode_attr size [(QI "b") (HI "h") (SI "w")])
> +(define_mode_attr size [(QI "b") (HI "h") (SI "w") (HF "") (BF "") (SF "")
> + (V2QI "h") (V4QI "") (V2HI "")
> + (V2HF "") (V2BF "")])
>
> ;; Give the number of bits in the mode
> (define_mode_attr sizen [(QI "8") (HI "16") (SI "32") (DI "64")])
> @@ -1883,6 +1892,10 @@
> (VNx4SI "v2si") (VNx4SF "v2sf")
> (VNx2DI "di") (VNx2DF "df")])
>
> +;; Sub-64-bit vector mode to equivalent scalar mode.
> +(define_mode_attr VSC [(V4QI "SI") (V2QI "HI")
> + (V2HI "SI") (V2HF "SF") (V2BF "SF")])
> +
> (define_mode_attr vnx [(V4SI "vnx4si") (V2DI "vnx2di")])
>
> ;; 64-bit container modes the inner or scalar source mode.
> @@ -2169,6 +2182,10 @@
> (V2SI "q") (V2SF "q")
> (DI "q") (DF "q")])
>
> +;; Scalar size of a sub-64-bit vector mode.
> +(define_mode_attr vstype [(V4QI "s") (V2QI "h")
> + (V2HI "s") (V2BF "s") (V2HF "s")])
> +
> ;; Define corresponding core/FP element mode for each vector mode.
> (define_mode_attr vw [(V8QI "w") (V16QI "w")
> (V4HI "w") (V8HI "w")
> diff --git a/gcc/testsuite/gcc.dg/vect/complex/bb-slp-complex-add-half-
> float.c b/gcc/testsuite/gcc.dg/vect/complex/bb-slp-complex-add-half-float.c
> index 3f1cce56955..6234f8646fe 100644
> --- a/gcc/testsuite/gcc.dg/vect/complex/bb-slp-complex-add-half-float.c
> +++ b/gcc/testsuite/gcc.dg/vect/complex/bb-slp-complex-add-half-float.c
> @@ -12,3 +12,5 @@
>
> /* { dg-final { scan-tree-dump "add new stmt:
> \[^\n\r]*COMPLEX_ADD_ROT270" "slp1" { xfail *-*-* } } } */
> /* { dg-final { scan-tree-dump "add new stmt:
> \[^\n\r]*COMPLEX_ADD_ROT90" "slp1" { xfail *-*-* } } } */
> +/* { dg-final { scan-tree-dump "Found COMPLEX_ADD_ROT90" "slp1" } } */
> +/* { dg-final { scan-tree-dump "Found COMPLEX_ADD_ROT270" "slp1" } } */
> diff --git a/gcc/testsuite/gcc.dg/vect/complex/bb-slp-complex-mla-half-float.c
> b/gcc/testsuite/gcc.dg/vect/complex/bb-slp-complex-mla-half-float.c
> index 33e500f3f4c..831f84bc1c8 100644
> --- a/gcc/testsuite/gcc.dg/vect/complex/bb-slp-complex-mla-half-float.c
> +++ b/gcc/testsuite/gcc.dg/vect/complex/bb-slp-complex-mla-half-float.c
> @@ -9,4 +9,6 @@
> #include "complex-mla-template.c"
>
> /* { dg-final { scan-tree-dump "Found COMPLEX_FMA_CONJ" "slp1" { xfail *-
> *-* } } } */
> -/* { dg-final { scan-tree-dump "Found COMPLEX_FMA" "slp1" { xfail *-*-* } }
> } */
> +
> +/* { dg-final { scan-tree-dump-times "add new
> stmt:\[^\n\r]*COMPLEX_FMA" 1 "slp1" { xfail *-*-* } } } */
> +/* { dg-final { scan-tree-dump "Found COMPLEX_FMA" "slp1" } } */
> diff --git a/gcc/testsuite/gcc.dg/vect/complex/bb-slp-complex-mul-half-
> float.c b/gcc/testsuite/gcc.dg/vect/complex/bb-slp-complex-mul-half-float.c
> index 259dd6b2e06..f74274ad034 100644
> --- a/gcc/testsuite/gcc.dg/vect/complex/bb-slp-complex-mul-half-float.c
> +++ b/gcc/testsuite/gcc.dg/vect/complex/bb-slp-complex-mul-half-float.c
> @@ -8,5 +8,7 @@
> #define N 16
> #include "complex-mul-template.c"
>
> -/* { dg-final { scan-tree-dump "Found COMPLEX_MUL_CONJ" "slp1" { xfail *-
> *-* } } } */
> -/* { dg-final { scan-tree-dump "Found COMPLEX_MUL" "slp1" { xfail *-*-* } }
> } */
> +/* { dg-final { scan-tree-dump-times "add new
> stmt:\[^\n\r]*COMPLEX_MUL_CONJ" 1 "slp1" { xfail *-*-* } } } */
> +/* { dg-final { scan-tree-dump "Found COMPLEX_MUL_CONJ" "slp1" } } */
> +/* { dg-final { scan-tree-dump-times "add new
> stmt:\[^\n\r]*COMPLEX_MUL" 1 "slp1" { xfail *-*-* } } } */
> +/* { dg-final { scan-tree-dump "Found COMPLEX_MUL" "slp1" } } */
> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/slp_1.c
> b/gcc/testsuite/gcc.target/aarch64/sve/slp_1.c
> index 07d71a63414..739e63a96a1 100644
> --- a/gcc/testsuite/gcc.target/aarch64/sve/slp_1.c
> +++ b/gcc/testsuite/gcc.target/aarch64/sve/slp_1.c
> @@ -30,12 +30,14 @@ vec_slp_##TYPE (TYPE *restrict a, TYPE b, TYPE c, int
> n) \
> TEST_ALL (VEC_PERM)
>
> /* We should use one DUP for each of the 8-, 16- and 32-bit types,
> - although we currently use LD1RW for _Float16. We should use two
> + (for now, insert both elements with umov + ins for _Float16). We should
> use two
> DUPs for each of the three 64-bit types. */
> /* { dg-final { scan-assembler-times {\tmov\tz[0-9]+\.h, [hw]} 2 } } */
> -/* { dg-final { scan-assembler-times {\tmov\tz[0-9]+\.s, [sw]} 2 } } */
> -/* { dg-final { scan-assembler-times {\tld1rw\tz[0-9]+\.s, } 1 } } */
> +/* { dg-final { scan-assembler-times {\tmov\tz[0-9]+\.s, [sw]} 3 } } */
> /* { dg-final { scan-assembler-times {\tmov\tz[0-9]+\.d, [dx]} 9 } } */
> +/* { dg-final { scan-assembler-times {\tumov\tw[0-9]+, v[0-9]+\.h} 2 } } */
> +/* { dg-final { scan-assembler-times {\tins\tv[0-9]+\.h\[0\], w[0-9]+} 3 } }
> */
> +/* { dg-final { scan-assembler-times {\tins\tv[0-9]+\.h\[1\], w[0-9]+} 3 } }
> */
> /* { dg-final { scan-assembler-times {\tzip1\tz[0-9]+\.d, z[0-9]+\.d, z[0-
> 9]+\.d\n} 3 } } */
> /* { dg-final { scan-assembler-not {\tzip2\t} } } */
>
> @@ -53,7 +55,6 @@ TEST_ALL (VEC_PERM)
> /* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.s} 6 } } */
> /* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.d} 6 } } */
> /* { dg-final { scan-assembler-not {\tldr} } } */
> -/* { dg-final { scan-assembler-times {\tstr} 2 } } */
> -/* { dg-final { scan-assembler-times {\tstr\th[0-9]+} 2 } } */
> +/* { dg-final { scan-assembler-not {\tstr} } } */
>
> /* { dg-final { scan-assembler-not {\tuqdec} } } */
> --
> 2.43.0