Re: [PATCH v2 1/1] aarch64: Add SVE AES2 ACLE builtins
Alice Carlotti <[email protected]> Tue, 4 Aug 2026 20:06:37 +0100
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
On Fri, Jul 10, 2026 at 10:37:10AM +0000, Sivan Shani wrote:
> Add ACLE support for the SVE AES2 multi-vector AES indexed
> instructions and the 128-bit PMULL/PMLAL pair forms.
>
> This adds builtin shapes and expanders for svaese_lane, svaesd_lane,
> svaesemc_lane, svaesdimc_lane, svpmull_pair and svpmlal_pair, together
> with the corresponding RTL patterns and tests. Also add preprocessor
> feature macros for SVE AES2 and SSVE AES.
>
> gcc/
> * config/aarch64/aarch64-c.cc (aarch64_update_cpp_builtins): Define
> __ARM_FEATURE_SVE_AES2 and __ARM_FEATURE_SSVE_AES.
> * config/aarch64/aarch64.h (TARGET_SVE_AES2): Define.
> * config/aarch64/aarch64.md (UNSPEC_SSVE_LANE_SELECT): New unspec.
> * config/aarch64/aarch64-sve-builtins-functions.h
> (unspec_based_aes_lane_function): New typedef.
> (unspec_based_aes_lane_mc_function): Likewise.
> * config/aarch64/aarch64-sve-builtins-shapes.cc
> (binary_to_pair_opt_n_def): New shape.
> (ternary_to_pair_opt_n_def): Likewise.
> (binary_aes_lane_def): Likewise.
> * config/aarch64/aarch64-sve-builtins-shapes.h: Declare new shapes.
> * config/aarch64/aarch64-sve-builtins-sve2.cc: Add new function
> entries.
> * config/aarch64/aarch64-sve-builtins-sve2.def: Add new ACLE
> builtin definitions.
> * config/aarch64/aarch64-sve-builtins-sve2.h: Declare new functions.
> * config/aarch64/aarch64-sve2.md: Add PMULL/PMLAL pair and AES
> indexed multi-vector patterns.
> * config/aarch64/iterators.md: Add iterators and attrs for new
> patterns.
> * config/aarch64/predicates.md (const_0_to_3_operand): New predicate.
>
> gcc/testsuite/
> * gcc.target/aarch64/pragma_cpp_predefs_5.c: Test new feature macros.
> * gcc.target/aarch64/sve/acle/asm/test_sve_acle.h
> (TEST_XN_INDEXED): New macro.
You also changed TEST_XN_SINGLE without using it. If you remove that hunk,
then I think this patch is ok for master.
I have a few more comments below, but I'm happy for those to be left unchanged.
> * gcc.target/aarch64/sve2/acle/asm/aesd_lane_u8.c: New test.
> * gcc.target/aarch64/sve2/acle/asm/aesdimc_lane_u8.c: New test.
> * gcc.target/aarch64/sve2/acle/asm/aese_lane_u8.c: New test.
> * gcc.target/aarch64/sve2/acle/asm/aesemc_lane_u8.c: New test.
> * gcc.target/aarch64/sve2/acle/asm/pmlal_pair_u64.c: New test.
> * gcc.target/aarch64/sve2/acle/asm/pmull_pair_u64.c: New test.
> * lib/target-supports.exp: Add sve-aes2 assembler probe.
...
> +/* svuint8x2_t svaes<...>_lane[_u8_x2] (svuint8x2_t zdn, svuint8_t zm, uint64_t
> + index);
> + and
> + svuint8x4_t svaes<...>_lane[_u8_x4] (svuint8x4_t zdn, svuint8_t zm, uint64_t
> + index);
> + When index is in range[0-3]
> +*/
> +struct binary_aes_lane_def : public overloaded_base<0>
> +{
> + bool explicit_group_suffix_p () const override { return false; }
> +
> + void
> + build (function_builder &b, const function_group_info &group) const override
> + {
> + b.add_overloaded_functions (group, MODE_none);
> + build_all (b, "t0,t0,v0,su64", group, MODE_none);
> + }
> +
> + tree
> + resolve (function_resolver &r) const override
> + {
> + if (!r.check_num_arguments (3))
> + return error_mark_node;
> +
> + sve_type type = r.infer_sve_type (0);
> + if (!type)
> + return error_mark_node;
> +
> + if (type.num_vectors != 2 && type.num_vectors != 4)
> + return error_mark_node;
I think this check is unnecessary, and I think the function would be slightly
more readable written as a single if(... && ... && ... && ...). However, it's
still fine as is.
> +
> + if (!r.require_vector_type (1, VECTOR_TYPE_svuint8_t))
> + return error_mark_node;
> +
> + if (!r.require_integer_immediate (2))
> + return error_mark_node;
> +
> + return r.resolve_to (MODE_none, type);
> + }
...
> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/asm/test_sve_acle.h b/gcc/testsuite/gcc.target/aarch64/sve/acle/asm/test_sve_acle.h
> index aeb58ead0dd..586ddb45ae0 100644
> --- a/gcc/testsuite/gcc.target/aarch64/sve/acle/asm/test_sve_acle.h
> +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/asm/test_sve_acle.h
> @@ -687,6 +687,24 @@
> __asm volatile ("" :: "w" (RES)); \
> }
>
> +#define TEST_XN_INDEXED(NAME, TTYPE, VTYPE, CODE1, CODE2) \
> + PROTO (NAME, TTYPE, (TTYPE t, VTYPE v)) \
> + { \
> + register TTYPE z0 __asm ("z0"); \
> + register TTYPE z1 __asm ("z1"); \
> + register TTYPE z2 __asm ("z2"); \
> + register TTYPE z3 __asm ("z3"); \
I'm a little wary of using overlapping register asms (since the tuples cover
multiple registers), and this was another reason why I suggested using
TEST_XN_SINGLE instead (which uses tuple register asms that are not
overlapping). However, if the tests are passing then probably this is ok.
Incidentally, I don't really understand this rationale in your cover letter:
> I kept `TEST_XN_INDEXED` because it matches the intrinsic signature and the ABI
> register allocation, making it easier to write tests with the expected assembly
> for this class of instructions. It should also be useful for similar cases in
> the future.
but I'm ok with keeping the new macro.
> + register VTYPE z4 __asm ("z4"); \
> + register VTYPE z5 __asm ("z5"); \
> + register VTYPE z6 __asm ("z6"); \
> + register VTYPE z7 __asm ("z7"); \
> + register uint64_t x0 __asm ("x0"); \
> + __asm volatile ("" : "=r" (x0)); \
Why is this volatile asm needed? I don't understand why it might be necessary,
but it should at least be harmless.
> + INVOKE (CODE1, CODE2); \
> + __asm volatile ("" :: "w" (t)); \
> + return t; \
> + }
> +
> #define TEST_DUAL_XN(NAME, TTYPE1, TTYPE2, RES, CODE1, CODE2) \
> PROTO (NAME, void, ()) \
> { \
> @@ -716,6 +734,8 @@
> __asm volatile ("" : "=w" (z0), "=w" (z1), "=w" (z5), \
> "=w" (z7), "=w" (z16), "=w" (z18), \
> "=w" (z23), "=w" (z24), "=w" (z28)); \
> + register uint64_t x0 __asm ("x0"); \
> + __asm volatile ("" : "=r" (x0)); \
This hunk should be dropped if you're not using TEST_XN_SINGLE in your patch.
> INVOKE (RES = CODE1, RES = CODE2); \
> __asm volatile ("" :: "w" (RES)); \
> }
>