<saurabh....@arm.com> writes: > The AArch64 FEAT_FAMINMAX extension is optional from Armv9.2-a and > mandatory from Armv9.5-a. It introduces instructions for computing the > floating point absolute maximum and minimum of the two vectors element-wise. > > This patch introduces AdvSIMD faminmax intrinsics. The intrinsics of > this extension are implemented as the following builtin functions: > * vamax_f16 > * vamaxq_f16 > * vamax_f32 > * vamaxq_f32 > * vamaxq_f64 > * vamin_f16 > * vaminq_f16 > * vamin_f32 > * vaminq_f32 > * vaminq_f64 > > We are defining a new way to add AArch64 AdvSIMD intrinsics by listing > all the intrinsics in a .def file and then using that .def file to > initialise various data structures. This would lead to more concise code > and easier addition of the new AdvSIMD intrinsics in future. > > The faminmax intrinsics are defined using the new approach. > > gcc/ChangeLog: > > * config/aarch64/aarch64-builtins.cc > (ENTRY): Macro to parse the contents of > aarch64-simd-pragma-builtins.def. > (ENTRY_VHSDF): Macro to parse the contents of > aarch64-simd-pragma-builtins.def. > (enum aarch64_builtins): New enum values for faminmax builtins > via aarch64-simd-pragma-builtins.def. > (enum class aarch64_builtin_signatures): Enum class to specify > the number of operands a builtin will take. > (struct aarch64_pragma_builtins_data): Struct to hold data from > aarch64-simd-pragma-builtins.def. > (aarch64_fntype): New function to define function types of > intrinsics given an object of type aarch64_pragma_builtins_data. > (aarch64_init_pragma_builtins): New function to define pragma > builtins. > (aarch64_get_pragma_builtin): New function to get a row of > aarch64_pragma_builtins, given code. > (handle_arm_neon_h): Modify to call > aarch64_init_pragma_builtins. > (aarch64_general_check_builtin_call): Modify to check whether > required flag is being used for pragma builtins. > (aarch64_expand_pragma_builtin): New function to emit > instructions of pragma_builtin. > (aarch64_general_expand_builtin): Modify to call > aarch64_expand_pragma_builtin. > * config/aarch64/aarch64-option-extensions.def > (AARCH64_OPT_EXTENSION): Introduce new flag for this extension. > * config/aarch64/aarch64-simd.md > (@aarch64_<faminmax_uns_op><mode>): Instruction pattern for > faminmax intrinsics. > * config/aarch64/aarch64.h > (TARGET_FAMINMAX): Introduce new flag for this extension. > * config/aarch64/iterators.md: New iterators and unspecs. > * doc/invoke.texi: Document extension in AArch64 Options. > * config/aarch64/aarch64-simd-pragma-builtins.def: New file to > list pragma builtins. > > gcc/testsuite/ChangeLog: > > * gcc.target/aarch64/simd/faminmax-builtins-no-flag.c: New test. > * gcc.target/aarch64/simd/faminmax-builtins.c: New test.
LGTM. OK, thanks. It looks from MAINTAINERS that you don't currently have commit access. Could you follow the procedure on https://gcc.gnu.org/gitwrite.html , listing me as sponsor? Or if you already have an account for binutils, I think the process is to email overseers directly. Thanks for adding the new builtins infrastructure. Richard > --- > gcc/config/aarch64/aarch64-builtins.cc | 119 ++++++++++++++++++ > .../aarch64/aarch64-option-extensions.def | 2 + > .../aarch64/aarch64-simd-pragma-builtins.def | 23 ++++ > gcc/config/aarch64/aarch64-simd.md | 10 ++ > gcc/config/aarch64/aarch64.h | 4 + > gcc/config/aarch64/iterators.md | 9 ++ > gcc/doc/invoke.texi | 2 + > .../aarch64/simd/faminmax-builtins-no-flag.c | 10 ++ > .../aarch64/simd/faminmax-builtins.c | 115 +++++++++++++++++ > 9 files changed, 294 insertions(+) > create mode 100644 gcc/config/aarch64/aarch64-simd-pragma-builtins.def > create mode 100644 > gcc/testsuite/gcc.target/aarch64/simd/faminmax-builtins-no-flag.c > create mode 100644 gcc/testsuite/gcc.target/aarch64/simd/faminmax-builtins.c > > diff --git a/gcc/config/aarch64/aarch64-builtins.cc > b/gcc/config/aarch64/aarch64-builtins.cc > index eb878b933fe..6266bea3b39 100644 > --- a/gcc/config/aarch64/aarch64-builtins.cc > +++ b/gcc/config/aarch64/aarch64-builtins.cc > @@ -757,6 +757,18 @@ typedef struct > #define VAR1(T, N, MAP, FLAG, A) \ > AARCH64_SIMD_BUILTIN_##T##_##N##A, > > +#undef ENTRY > +#define ENTRY(N, S, M, U, F) \ > + AARCH64_##N, > + > +#undef ENTRY_VHSDF > +#define ENTRY_VHSDF(NAME, SIGNATURE, UNSPEC, EXTENSIONS) \ > + AARCH64_##NAME##_f16, \ > + AARCH64_##NAME##q_f16, \ > + AARCH64_##NAME##_f32, \ > + AARCH64_##NAME##q_f32, \ > + AARCH64_##NAME##q_f64, > + > enum aarch64_builtins > { > AARCH64_BUILTIN_MIN, > @@ -829,6 +841,10 @@ enum aarch64_builtins > AARCH64_RBIT, > AARCH64_RBITL, > AARCH64_RBITLL, > + /* Pragma builtins. */ > + AARCH64_PRAGMA_BUILTIN_START, > +#include "aarch64-simd-pragma-builtins.def" > + AARCH64_PRAGMA_BUILTIN_END, > /* System register builtins. */ > AARCH64_RSR, > AARCH64_RSRP, > @@ -947,6 +963,7 @@ const char *aarch64_scalar_builtin_types[] = { > > extern GTY(()) aarch64_simd_type_info aarch64_simd_types[]; > > +#undef ENTRY > #define ENTRY(E, M, Q, G) \ > {E, "__" #E, #G "__" #E, NULL_TREE, NULL_TREE, E_##M##mode, qualifier_##Q}, > struct aarch64_simd_type_info aarch64_simd_types [] = { > @@ -1547,6 +1564,78 @@ aarch64_init_simd_builtin_functions (bool > called_from_pragma) > } > } > > +enum class aarch64_builtin_signatures > +{ > + binary, > +}; > + > +#undef ENTRY > +#define ENTRY(N, S, M, U, F) \ > + {#N, aarch64_builtin_signatures::S, E_##M##mode, U, F}, > + > +#undef ENTRY_VHSDF > +#define ENTRY_VHSDF(NAME, SIGNATURE, UNSPEC, EXTENSIONS) \ > + ENTRY (NAME##_f16, SIGNATURE, V4HF, UNSPEC, EXTENSIONS) \ > + ENTRY (NAME##q_f16, SIGNATURE, V8HF, UNSPEC, EXTENSIONS) \ > + ENTRY (NAME##_f32, SIGNATURE, V2SF, UNSPEC, EXTENSIONS) \ > + ENTRY (NAME##q_f32, SIGNATURE, V4SF, UNSPEC, EXTENSIONS) \ > + ENTRY (NAME##q_f64, SIGNATURE, V2DF, UNSPEC, EXTENSIONS) > + > +/* Initialize pragma builtins. */ > + > +struct aarch64_pragma_builtins_data > +{ > + const char *name; > + aarch64_builtin_signatures signature; > + machine_mode mode; > + int unspec; > + aarch64_feature_flags required_extensions; > +}; > + > +static aarch64_pragma_builtins_data aarch64_pragma_builtins[] = { > +#include "aarch64-simd-pragma-builtins.def" > +}; > + > +static tree > +aarch64_fntype (const aarch64_pragma_builtins_data &builtin_data) > +{ > + auto type = aarch64_simd_builtin_type (builtin_data.mode, qualifier_none); > + switch (builtin_data.signature) > + { > + case aarch64_builtin_signatures::binary: > + return build_function_type_list (type, type, type, NULL_TREE); > + default: > + gcc_unreachable (); > + } > +} > + > +static void > +aarch64_init_pragma_builtins () > +{ > + for (size_t i = 0; i < ARRAY_SIZE (aarch64_pragma_builtins); ++i) > + { > + auto data = aarch64_pragma_builtins[i]; > + auto fntype = aarch64_fntype (data); > + auto code = AARCH64_PRAGMA_BUILTIN_START + i + 1; > + aarch64_builtin_decls[code] > + = aarch64_general_simulate_builtin (data.name, fntype, code); > + } > +} > + > +/* If the builtin function with code CODE has an entry in > + aarch64_pragma_builtins, return its entry, otherwise return null. */ > + > +static const aarch64_pragma_builtins_data* > +aarch64_get_pragma_builtin (int code) > +{ > + if (!(code > AARCH64_PRAGMA_BUILTIN_START > + && code < AARCH64_PRAGMA_BUILTIN_END)) > + return NULL; > + > + auto idx = code - (AARCH64_PRAGMA_BUILTIN_START + 1); > + return &aarch64_pragma_builtins[idx]; > +} > + > /* Register the tuple type that contains NUM_VECTORS of the AdvSIMD type > indexed by TYPE_INDEX. */ > static void > @@ -1640,6 +1729,7 @@ handle_arm_neon_h (void) > > aarch64_init_simd_builtin_functions (true); > aarch64_init_simd_intrinsics (); > + aarch64_init_pragma_builtins (); > } > > static void > @@ -2326,6 +2416,12 @@ aarch64_general_check_builtin_call (location_t > location, vec<location_t>, > return aarch64_check_required_extensions (location, decl, > AARCH64_FL_MEMTAG); > > + if (auto builtin_data = aarch64_get_pragma_builtin (code)) > + { > + auto flags = builtin_data->required_extensions; > + return aarch64_check_required_extensions (location, decl, flags); > + } > + > return true; > } > > @@ -3189,6 +3285,25 @@ aarch64_expand_builtin_data_intrinsic (unsigned int > fcode, tree exp, rtx target) > return ops[0].value; > } > > +static rtx > +aarch64_expand_pragma_builtin (tree exp, rtx target, > + const aarch64_pragma_builtins_data *builtin_data) > +{ > + expand_operand ops[3]; > + auto mode = builtin_data->mode; > + auto op1 = expand_normal (CALL_EXPR_ARG (exp, 0)); > + auto op2 = expand_normal (CALL_EXPR_ARG (exp, 1)); > + create_output_operand (&ops[0], target, mode); > + create_input_operand (&ops[1], op1, mode); > + create_input_operand (&ops[2], op2, mode); > + > + auto unspec = builtin_data->unspec; > + auto icode = code_for_aarch64 (unspec, mode); > + expand_insn (icode, 3, ops); > + > + return target; > +} > + > /* Expand an expression EXP as fpsr or fpcr setter (depending on > UNSPEC) using MODE. */ > static void > @@ -3369,6 +3484,9 @@ aarch64_general_expand_builtin (unsigned int fcode, > tree exp, rtx target, > && fcode <= AARCH64_RBITLL) > return aarch64_expand_builtin_data_intrinsic (fcode, exp, target); > > + if (auto builtin_data = aarch64_get_pragma_builtin (fcode)) > + return aarch64_expand_pragma_builtin (exp, target, builtin_data); > + > gcc_unreachable (); > } > > @@ -4021,6 +4139,7 @@ aarch64_resolve_overloaded_builtin_general (location_t > loc, tree function, > #undef CF3 > #undef CF4 > #undef CF10 > +#undef ENTRY_VHSDF > #undef VAR1 > #undef VAR2 > #undef VAR3 > diff --git a/gcc/config/aarch64/aarch64-option-extensions.def > b/gcc/config/aarch64/aarch64-option-extensions.def > index 6998627f377..8279f5a76ea 100644 > --- a/gcc/config/aarch64/aarch64-option-extensions.def > +++ b/gcc/config/aarch64/aarch64-option-extensions.def > @@ -234,6 +234,8 @@ AARCH64_OPT_EXTENSION("gcs", GCS, (), (), (), "gcs") > > AARCH64_OPT_EXTENSION("fp8", FP8, (SIMD), (), (), "fp8") > > +AARCH64_OPT_EXTENSION("faminmax", FAMINMAX, (SIMD), (), (), "faminmax") > + > #undef AARCH64_OPT_FMV_EXTENSION > #undef AARCH64_OPT_EXTENSION > #undef AARCH64_FMV_FEATURE > diff --git a/gcc/config/aarch64/aarch64-simd-pragma-builtins.def > b/gcc/config/aarch64/aarch64-simd-pragma-builtins.def > new file mode 100644 > index 00000000000..f432185be46 > --- /dev/null > +++ b/gcc/config/aarch64/aarch64-simd-pragma-builtins.def > @@ -0,0 +1,23 @@ > +/* AArch64 SIMD pragma builtins > + Copyright (C) 2024 Free Software Foundation, Inc. > + Contributed by ARM Ltd. > + > + This file is part of GCC. > + > + GCC is free software; you can redistribute it and/or modify it > + under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3, or (at your option) > + any later version. > + > + GCC is distributed in the hope that it will be useful, but > + WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with GCC; see the file COPYING3. If not see > + <http://www.gnu.org/licenses/>. */ > + > +// faminmax > +ENTRY_VHSDF (vamax, binary, UNSPEC_FAMAX, AARCH64_FL_FAMINMAX) > +ENTRY_VHSDF (vamin, binary, UNSPEC_FAMIN, AARCH64_FL_FAMINMAX) > diff --git a/gcc/config/aarch64/aarch64-simd.md > b/gcc/config/aarch64/aarch64-simd.md > index 23c03a96371..67f0fe26f93 100644 > --- a/gcc/config/aarch64/aarch64-simd.md > +++ b/gcc/config/aarch64/aarch64-simd.md > @@ -9910,3 +9910,13 @@ > "shl\\t%d0, %d1, #16" > [(set_attr "type" "neon_shift_imm")] > ) > + > +;; faminmax > +(define_insn "@aarch64_<faminmax_uns_op><mode>" > + [(set (match_operand:VHSDF 0 "register_operand" "=w") > + (unspec:VHSDF [(match_operand:VHSDF 1 "register_operand" "w") > + (match_operand:VHSDF 2 "register_operand" "w")] > + FAMINMAX_UNS))] > + "TARGET_FAMINMAX" > + "<faminmax_uns_op>\t%0.<Vtype>, %1.<Vtype>, %2.<Vtype>" > +) > diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h > index 2dfb999bea5..e754c4ea748 100644 > --- a/gcc/config/aarch64/aarch64.h > +++ b/gcc/config/aarch64/aarch64.h > @@ -457,6 +457,10 @@ constexpr auto AARCH64_FL_DEFAULT_ISA_MODE > ATTRIBUTE_UNUSED > enabled through +gcs. */ > #define TARGET_GCS AARCH64_HAVE_ISA (GCS) > > +/* Floating Point Absolute Maximum/Minimum extension instructions are > + enabled through +faminmax. */ > +#define TARGET_FAMINMAX AARCH64_HAVE_ISA (FAMINMAX) > + > /* Prefer different predicate registers for the output of a predicated > operation over re-using an existing input predicate. */ > #define TARGET_SVE_PRED_CLOBBER (TARGET_SVE \ > diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md > index 20a318e023b..17ac5e073aa 100644 > --- a/gcc/config/aarch64/iterators.md > +++ b/gcc/config/aarch64/iterators.md > @@ -1057,6 +1057,8 @@ > UNSPEC_BFCVTN2 ; Used in aarch64-simd.md. > UNSPEC_BFCVT ; Used in aarch64-simd.md. > UNSPEC_FCVTXN ; Used in aarch64-simd.md. > + UNSPEC_FAMAX ; Used in aarch64-simd.md. > + UNSPEC_FAMIN ; Used in aarch64-simd.md. > > ;; All used in aarch64-sve2.md > UNSPEC_FCVTN > @@ -4463,3 +4465,10 @@ > (UNSPECV_SET_FPCR "fpcr")]) > > (define_int_attr bits_etype [(8 "b") (16 "h") (32 "s") (64 "d")]) > + > +;; Iterators and attributes for faminmax > + > +(define_int_iterator FAMINMAX_UNS [UNSPEC_FAMAX UNSPEC_FAMIN]) > + > +(define_int_attr faminmax_uns_op > + [(UNSPEC_FAMAX "famax") (UNSPEC_FAMIN "famin")]) > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index 511b8c8d311..e005d9bbfb0 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -21865,6 +21865,8 @@ Enable support for Armv8.9-a/9.4-a translation > hardening extension. > Enable the RCpc3 (Release Consistency) extension. > @item fp8 > Enable the fp8 (8-bit floating point) extension. > +@item faminmax > +Enable the Floating Point Absolute Maximum/Minimum extension. > > @end table > > diff --git > a/gcc/testsuite/gcc.target/aarch64/simd/faminmax-builtins-no-flag.c > b/gcc/testsuite/gcc.target/aarch64/simd/faminmax-builtins-no-flag.c > new file mode 100644 > index 00000000000..63ed1508c23 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/simd/faminmax-builtins-no-flag.c > @@ -0,0 +1,10 @@ > +/* { dg-do assemble} */ > +/* { dg-additional-options "-march=armv9-a" } */ > + > +#include "arm_neon.h" > + > +void > +test (float32x4_t a, float32x4_t b) > +{ > + vamaxq_f32 (a, b); /* { dg-error {ACLE function 'vamaxq_f32' requires ISA > extension 'faminmax'} } */ > +} > diff --git a/gcc/testsuite/gcc.target/aarch64/simd/faminmax-builtins.c > b/gcc/testsuite/gcc.target/aarch64/simd/faminmax-builtins.c > new file mode 100644 > index 00000000000..7e4f3eba81a > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/simd/faminmax-builtins.c > @@ -0,0 +1,115 @@ > +/* { dg-do assemble} */ > +/* { dg-additional-options "-O3 -march=armv9-a+faminmax" } */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > +#include "arm_neon.h" > + > +/* > +** test_vamax_f16: > +** famax v0.4h, v0.4h, v1.4h > +** ret > +*/ > +float16x4_t > +test_vamax_f16 (float16x4_t a, float16x4_t b) > +{ > + return vamax_f16 (a, b); > +} > + > +/* > +** test_vamaxq_f16: > +** famax v0.8h, v0.8h, v1.8h > +** ret > +*/ > +float16x8_t > +test_vamaxq_f16 (float16x8_t a, float16x8_t b) > +{ > + return vamaxq_f16 (a, b); > +} > + > +/* > +** test_vamax_f32: > +** famax v0.2s, v0.2s, v1.2s > +** ret > +*/ > +float32x2_t > +test_vamax_f32 (float32x2_t a, float32x2_t b) > +{ > + return vamax_f32 (a, b); > +} > + > +/* > +** test_vamaxq_f32: > +** famax v0.4s, v0.4s, v1.4s > +** ret > +*/ > +float32x4_t > +test_vamaxq_f32 (float32x4_t a, float32x4_t b) > +{ > + return vamaxq_f32 (a, b); > +} > + > +/* > +** test_vamaxq_f64: > +** famax v0.2d, v0.2d, v1.2d > +** ret > +*/ > +float64x2_t > +test_vamaxq_f64 (float64x2_t a, float64x2_t b) > +{ > + return vamaxq_f64 (a, b); > +} > + > +/* > +** test_vamin_f16: > +** famin v0.4h, v0.4h, v1.4h > +** ret > +*/ > +float16x4_t > +test_vamin_f16 (float16x4_t a, float16x4_t b) > +{ > + return vamin_f16 (a, b); > +} > + > +/* > +** test_vaminq_f16: > +** famin v0.8h, v0.8h, v1.8h > +** ret > +*/ > +float16x8_t > +test_vaminq_f16 (float16x8_t a, float16x8_t b) > +{ > + return vaminq_f16 (a, b); > +} > + > +/* > +** test_vamin_f32: > +** famin v0.2s, v0.2s, v1.2s > +** ret > +*/ > +float32x2_t > +test_vamin_f32 (float32x2_t a, float32x2_t b) > +{ > + return vamin_f32 (a, b); > +} > + > +/* > +** test_vaminq_f32: > +** famin v0.4s, v0.4s, v1.4s > +** ret > +*/ > +float32x4_t > +test_vaminq_f32 (float32x4_t a, float32x4_t b) > +{ > + return vaminq_f32 (a, b); > +} > + > +/* > +** test_vaminq_f64: > +** famin v0.2d, v0.2d, v1.2d > +** ret > +*/ > +float64x2_t > +test_vaminq_f64 (float64x2_t a, float64x2_t b) > +{ > + return vaminq_f64 (a, b); > +}