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 does three things: 1. Introduces AdvSIMD faminmax intrinsics. 2. Adds code generation support for famax and famin in terms of the existing operators. 3. Move report_missing_extension and reported_missing_extension_p to make it more usable. 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 For code generation, famax/famin is equivalent to first taking fabs of the operands and then taking fmax/fmin of the results of fabs. famax/famin (a, b) = fmax/fmin (fabs (a), fabs (b)) This is correct because NaN/Inf handling of famax/famin and fmax/fmin are same. We cannot use fmaxnm/fminnm here as Nan/Inf are handled differently in them. We moved the definition of `report_missing_extension` from gcc/config/aarch64/aarch64-sve-builtins.cc to gcc/config/aarch64/aarch64-builtins.cc and its declaration to gcc/config/aarch64/aarch64-builtins.h. We also moved the declaration of `reported_missing_extension_p` from gcc/config/aarch64/aarch64-sve-builtins.cc to gcc/config/aarch64/aarch64-builtins.cc, closer to the definition of `report_missing_extension`. In the exsiting code structure, this leads to `report_missing_extension` being usable from both normal builtins and sve builtins. gcc/ChangeLog: * config/aarch64/aarch64-builtins.cc (enum aarch64_builtins): New enum values for faminmax builtins. (aarch64_init_faminmax_builtins): New function to declare new builtins. (handle_arm_neon_h): Modify to call aarch64_init_faminmax_builtins. (aarch64_general_check_builtin_call): Modify to check whether +faminmax flag is being used and printing error message if not being used. (aarch64_expand_builtin_faminmax): New function to emit instructions of this extension. (aarch64_general_expand_builtin): Modify to call aarch64_expand_builtin_faminmax. (report_missing_extension): Move from config/aarch64/aarch64-sve-builtins.cc. * config/aarch64/aarch64-builtins.h (report_missing_extension): Declaration for this function so that it can be used wherever this header is included. (reported_missing_extension_p): Move from config/aarch64/aarch64-sve-builtins.cc * config/aarch64/aarch64-option-extensions.def (AARCH64_OPT_EXTENSION): Introduce new flag for this extension. * config/aarch64/aarch64-simd.md (aarch64_<faminmax><mode>): Introduce instruction pattern for this extension. * config/aarch64/aarch64-sve-builtins.cc (reported_missing_extension_p): Move to config/aarch64/aarch64-builtins.cc (report_missing_extension): Move to config/aarch64/aarch64-builtins.cc. * config/aarch64/aarch64.h (TARGET_FAMINMAX): Introduce new flag for this extension. * config/aarch64/iterators.md: Introduce new iterators for this extension. * config/arm/types.md: Introduce neon_fp_aminmax<q> attributes. * doc/invoke.texi: Document extension in AArch64 Options. gcc/testsuite/ChangeLog: * gcc.target/aarch64/simd/faminmax-builtins-no-flag.c: New test. * gcc.target/aarch64/simd/faminmax-builtins.c: New test. * gcc.target/aarch64/simd/faminmax-codegen-no-flag.c: New test. * gcc.target/aarch64/simd/faminmax-codegen.c: New test. --- Hi, Regression tested for aarch64-none-linux-gnu and found no regressions. This is a respin of https://gcc.gnu.org/pipermail/gcc-patches/2024-August/658968.html as the previous version failed patchwork CI due to not being able to apply. Ok for master? I don't have commit access so can someone please commit on my behalf? Regards, Saurabh --- gcc/config/aarch64/aarch64-builtins.cc | 173 +++++++++++++++++- gcc/config/aarch64/aarch64-builtins.h | 5 +- .../aarch64/aarch64-option-extensions.def | 2 + gcc/config/aarch64/aarch64-simd.md | 12 ++ gcc/config/aarch64/aarch64-sve-builtins.cc | 22 --- gcc/config/aarch64/aarch64.h | 4 + gcc/config/aarch64/iterators.md | 8 + gcc/config/arm/types.md | 6 + gcc/doc/invoke.texi | 2 + .../aarch64/simd/faminmax-builtins-no-flag.c | 10 + .../aarch64/simd/faminmax-builtins.c | 75 ++++++++ .../aarch64/simd/faminmax-codegen-no-flag.c | 54 ++++++ .../aarch64/simd/faminmax-codegen.c | 104 +++++++++++ 13 files changed, 445 insertions(+), 32 deletions(-) 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 create mode 100644 gcc/testsuite/gcc.target/aarch64/simd/faminmax-codegen-no-flag.c create mode 100644 gcc/testsuite/gcc.target/aarch64/simd/faminmax-codegen.c
diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc index 30669f8aa18..cd590186f22 100644 --- a/gcc/config/aarch64/aarch64-builtins.cc +++ b/gcc/config/aarch64/aarch64-builtins.cc @@ -829,6 +829,17 @@ enum aarch64_builtins AARCH64_RBIT, AARCH64_RBITL, AARCH64_RBITLL, + /* FAMINMAX builtins. */ + AARCH64_FAMINMAX_BUILTIN_FAMAX4H, + AARCH64_FAMINMAX_BUILTIN_FAMAX8H, + AARCH64_FAMINMAX_BUILTIN_FAMAX2S, + AARCH64_FAMINMAX_BUILTIN_FAMAX4S, + AARCH64_FAMINMAX_BUILTIN_FAMAX2D, + AARCH64_FAMINMAX_BUILTIN_FAMIN4H, + AARCH64_FAMINMAX_BUILTIN_FAMIN8H, + AARCH64_FAMINMAX_BUILTIN_FAMIN2S, + AARCH64_FAMINMAX_BUILTIN_FAMIN4S, + AARCH64_FAMINMAX_BUILTIN_FAMIN2D, /* System register builtins. */ AARCH64_RSR, AARCH64_RSRP, @@ -1547,6 +1558,66 @@ aarch64_init_simd_builtin_functions (bool called_from_pragma) } } +/* Initialize the absolute maximum/minimum (FAMINMAX) builtins. */ + +typedef struct +{ + const char *name; + unsigned int code; + tree eltype; + machine_mode mode; +} faminmax_builtins_data; + +static void +aarch64_init_faminmax_builtins () +{ + faminmax_builtins_data data[] = { + /* Absolute maximum. */ + {"vamax_f16", AARCH64_FAMINMAX_BUILTIN_FAMAX4H, + aarch64_simd_types[Float16x4_t].eltype, + aarch64_simd_types[Float16x4_t].mode}, + {"vamaxq_f16", AARCH64_FAMINMAX_BUILTIN_FAMAX8H, + aarch64_simd_types[Float16x8_t].eltype, + aarch64_simd_types[Float16x8_t].mode}, + {"vamax_f32", AARCH64_FAMINMAX_BUILTIN_FAMAX2S, + aarch64_simd_types[Float32x2_t].eltype, + aarch64_simd_types[Float32x2_t].mode}, + {"vamaxq_f32", AARCH64_FAMINMAX_BUILTIN_FAMAX4S, + aarch64_simd_types[Float32x4_t].eltype, + aarch64_simd_types[Float32x4_t].mode}, + {"vamaxq_f64", AARCH64_FAMINMAX_BUILTIN_FAMAX2D, + aarch64_simd_types[Float64x2_t].eltype, + aarch64_simd_types[Float64x2_t].mode}, + /* Absolute minimum. */ + {"vamin_f16", AARCH64_FAMINMAX_BUILTIN_FAMIN4H, + aarch64_simd_types[Float16x4_t].eltype, + aarch64_simd_types[Float16x4_t].mode}, + {"vaminq_f16", AARCH64_FAMINMAX_BUILTIN_FAMIN8H, + aarch64_simd_types[Float16x8_t].eltype, + aarch64_simd_types[Float16x8_t].mode}, + {"vamin_f32", AARCH64_FAMINMAX_BUILTIN_FAMIN2S, + aarch64_simd_types[Float32x2_t].eltype, + aarch64_simd_types[Float32x2_t].mode}, + {"vaminq_f32", AARCH64_FAMINMAX_BUILTIN_FAMIN4S, + aarch64_simd_types[Float32x4_t].eltype, + aarch64_simd_types[Float32x4_t].mode}, + {"vaminq_f64", AARCH64_FAMINMAX_BUILTIN_FAMIN2D, + aarch64_simd_types[Float64x2_t].eltype, + aarch64_simd_types[Float64x2_t].mode}, + }; + + for (size_t i = 0; i < ARRAY_SIZE (data); ++i) + { + tree type + = build_vector_type (data[i].eltype, GET_MODE_NUNITS (data[i].mode)); + tree fntype = build_function_type_list (type, type, type, NULL_TREE); + unsigned int code = data[i].code; + const char *name = data[i].name; + aarch64_builtin_decls[code] + = aarch64_general_simulate_builtin (name, fntype, code); + } +} + /* Register the tuple type that contains NUM_VECTORS of the AdvSIMD type indexed by TYPE_INDEX. */ static void @@ -1640,6 +1711,7 @@ handle_arm_neon_h (void) aarch64_init_simd_builtin_functions (true); aarch64_init_simd_intrinsics (); + aarch64_init_faminmax_builtins (); } static void @@ -2197,15 +2269,35 @@ aarch64_general_check_builtin_call (location_t location, vec<location_t>, case AARCH64_WSR64: case AARCH64_WSRF: case AARCH64_WSRF64: - tree addr = STRIP_NOPS (args[0]); - if (TREE_CODE (TREE_TYPE (addr)) != POINTER_TYPE - || TREE_CODE (addr) != ADDR_EXPR - || TREE_CODE (TREE_OPERAND (addr, 0)) != STRING_CST) - { - error_at (location, "first argument to %qD must be a string literal", - fndecl); - return false; - } + { + tree addr = STRIP_NOPS (args[0]); + if (TREE_CODE (TREE_TYPE (addr)) != POINTER_TYPE + || TREE_CODE (addr) != ADDR_EXPR + || TREE_CODE (TREE_OPERAND (addr, 0)) != STRING_CST) + { + error_at (location, + "first argument to %qD must be a string literal", + fndecl); + return false; + } + } + case AARCH64_FAMINMAX_BUILTIN_FAMAX4H: + case AARCH64_FAMINMAX_BUILTIN_FAMAX8H: + case AARCH64_FAMINMAX_BUILTIN_FAMAX2S: + case AARCH64_FAMINMAX_BUILTIN_FAMAX4S: + case AARCH64_FAMINMAX_BUILTIN_FAMAX2D: + case AARCH64_FAMINMAX_BUILTIN_FAMIN4H: + case AARCH64_FAMINMAX_BUILTIN_FAMIN8H: + case AARCH64_FAMINMAX_BUILTIN_FAMIN2S: + case AARCH64_FAMINMAX_BUILTIN_FAMIN4S: + case AARCH64_FAMINMAX_BUILTIN_FAMIN2D: + { + if (!TARGET_FAMINMAX) + { + report_missing_extension (location, fndecl, "faminmax"); + return false; + } + } } /* Default behavior. */ return true; @@ -3071,6 +3163,44 @@ aarch64_expand_builtin_data_intrinsic (unsigned int fcode, tree exp, rtx target) return ops[0].value; } +static rtx +aarch64_expand_builtin_faminmax (unsigned int fcode, tree exp, rtx target) +{ + machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); + rtx op0 = force_reg (mode, expand_normal (CALL_EXPR_ARG (exp, 0))); + rtx op1 = force_reg (mode, expand_normal (CALL_EXPR_ARG (exp, 1))); + + enum insn_code icode; + if (fcode == AARCH64_FAMINMAX_BUILTIN_FAMAX4H) + icode = CODE_FOR_aarch64_famaxv4hf; + else if (fcode == AARCH64_FAMINMAX_BUILTIN_FAMAX8H) + icode = CODE_FOR_aarch64_famaxv8hf; + else if (fcode == AARCH64_FAMINMAX_BUILTIN_FAMAX2S) + icode = CODE_FOR_aarch64_famaxv2sf; + else if (fcode == AARCH64_FAMINMAX_BUILTIN_FAMAX4S) + icode = CODE_FOR_aarch64_famaxv4sf; + else if (fcode == AARCH64_FAMINMAX_BUILTIN_FAMAX2D) + icode = CODE_FOR_aarch64_famaxv2df; + else if (fcode == AARCH64_FAMINMAX_BUILTIN_FAMIN4H) + icode = CODE_FOR_aarch64_faminv4hf; + else if (fcode == AARCH64_FAMINMAX_BUILTIN_FAMIN8H) + icode = CODE_FOR_aarch64_faminv8hf; + else if (fcode == AARCH64_FAMINMAX_BUILTIN_FAMIN2S) + icode = CODE_FOR_aarch64_faminv2sf; + else if (fcode == AARCH64_FAMINMAX_BUILTIN_FAMIN4S) + icode = CODE_FOR_aarch64_faminv4sf; + else if (fcode == AARCH64_FAMINMAX_BUILTIN_FAMIN2D) + icode = CODE_FOR_aarch64_faminv2df; + else + gcc_unreachable (); + + rtx pat = GEN_FCN (icode) (target, op0, op1); + + emit_insn (pat); + + return target; +} + /* Expand an expression EXP as fpsr or fpcr setter (depending on UNSPEC) using MODE. */ static void @@ -3250,6 +3380,9 @@ aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target, if (fcode >= AARCH64_REV16 && fcode <= AARCH64_RBITLL) return aarch64_expand_builtin_data_intrinsic (fcode, exp, target); + if (fcode >= AARCH64_FAMINMAX_BUILTIN_FAMAX4H + && fcode <= AARCH64_FAMINMAX_BUILTIN_FAMIN2D) + return aarch64_expand_builtin_faminmax (fcode, exp, target); gcc_unreachable (); } @@ -3794,6 +3927,28 @@ aarch64_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) reload_fenv, restore_fnenv), update_call); } +/* True if we've already complained about attempts to use functions + when the required extension is disabled. */ +static bool reported_missing_extension_p; + +/* Report an error against LOCATION that the user has tried to use + function FNDECL when extension EXTENSION is disabled. */ +void +report_missing_extension (location_t location, tree fndecl, + const char *extension) +{ + /* Avoid reporting a slew of messages for a single oversight. */ + if (reported_missing_extension_p) + return; + + error_at (location, "ACLE function %qD requires ISA extension %qs", + fndecl, extension); + inform (location, "you can enable %qs using the command-line" + " option %<-march%>, or by using the %<target%>" + " attribute or pragma", extension); + reported_missing_extension_p = true; +} + /* Resolve overloaded MEMTAG build-in functions. */ #define AARCH64_BUILTIN_SUBCODE(F) \ (DECL_MD_FUNCTION_CODE (F) >> AARCH64_BUILTIN_SHIFT) diff --git a/gcc/config/aarch64/aarch64-builtins.h b/gcc/config/aarch64/aarch64-builtins.h index e326fe66676..93e31a30ec6 100644 --- a/gcc/config/aarch64/aarch64-builtins.h +++ b/gcc/config/aarch64/aarch64-builtins.h @@ -96,4 +96,7 @@ struct GTY(()) aarch64_simd_type_info extern aarch64_simd_type_info aarch64_simd_types[]; -#endif \ No newline at end of file +void report_missing_extension (location_t location, tree fndecl, + const char *extension); + +#endif 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.md b/gcc/config/aarch64/aarch64-simd.md index 459e11b09a1..b87bac2e7ed 100644 --- a/gcc/config/aarch64/aarch64-simd.md +++ b/gcc/config/aarch64/aarch64-simd.md @@ -9881,3 +9881,15 @@ "shl\\t%d0, %d1, #16" [(set_attr "type" "neon_shift_imm")] ) + +;; faminmax +(define_insn "aarch64_<faminmax><mode>" + [(set (match_operand:VHSDF 0 "register_operand" "=w") + (unspec:VHSDF + [(abs:VHSDF (match_operand:VHSDF 1 "register_operand" "w")) + (abs:VHSDF (match_operand:VHSDF 2 "register_operand" "w"))] + FMAXMIN_ONLY_UNS))] + "TARGET_FAMINMAX" + "<faminmax>\t%0.<Vtype>, %1.<Vtype>, %2.<Vtype>" + [(set_attr "type" "neon_fp_aminmax<q>")] +) diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc b/gcc/config/aarch64/aarch64-sve-builtins.cc index 0a560eaedca..f9120575671 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins.cc @@ -947,10 +947,6 @@ static hash_table<registered_function_hasher> *function_table; are IDENTIFIER_NODEs. */ static GTY(()) hash_map<tree, registered_function *> *overload_names[2]; -/* True if we've already complained about attempts to use functions - when the required extension is disabled. */ -static bool reported_missing_extension_p; - /* True if we've already complained about attempts to use functions which require registers that are missing. */ static bool reported_missing_registers_p; @@ -1076,24 +1072,6 @@ lookup_fndecl (tree fndecl) return &(*registered_functions)[subcode]->instance; } -/* Report an error against LOCATION that the user has tried to use - function FNDECL when extension EXTENSION is disabled. */ -static void -report_missing_extension (location_t location, tree fndecl, - const char *extension) -{ - /* Avoid reporting a slew of messages for a single oversight. */ - if (reported_missing_extension_p) - return; - - error_at (location, "ACLE function %qD requires ISA extension %qs", - fndecl, extension); - inform (location, "you can enable %qs using the command-line" - " option %<-march%>, or by using the %<target%>" - " attribute or pragma", extension); - reported_missing_extension_p = true; -} - /* Check whether the registers required by SVE function fndecl are available. Report an error against LOCATION and return false if not. */ static bool diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 2dfb999bea5..de14f57071a 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 95fe8f070f4..8e144c8ee4e 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -4457,3 +4457,11 @@ (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 FMAXMIN_ONLY_UNS [UNSPEC_FMAX UNSPEC_FMIN]) +(define_int_attr faminmax + [(UNSPEC_FMAX "famax") (UNSPEC_FMIN "famin")]) + + diff --git a/gcc/config/arm/types.md b/gcc/config/arm/types.md index 9527bdb9e87..d8de9dbc9d1 100644 --- a/gcc/config/arm/types.md +++ b/gcc/config/arm/types.md @@ -492,6 +492,8 @@ ; neon_fp_reduc_minmax_s_q ; neon_fp_reduc_minmax_d ; neon_fp_reduc_minmax_d_q +; neon_fp_aminmax +; neon_fp_aminmax_q ; neon_fp_cvt_narrow_s_q ; neon_fp_cvt_narrow_d_q ; neon_fp_cvt_widen_h @@ -1044,6 +1046,8 @@ neon_fp_reduc_minmax_d,\ neon_fp_reduc_minmax_d_q,\ \ + neon_fp_aminmax,\ + neon_fp_aminmax_q,\ neon_fp_cvt_narrow_s_q,\ neon_fp_cvt_narrow_d_q,\ neon_fp_cvt_widen_h,\ @@ -1264,6 +1268,8 @@ neon_fp_reduc_add_d_q, neon_fp_reduc_minmax_s, neon_fp_reduc_minmax_s_q, neon_fp_reduc_minmax_d,\ neon_fp_reduc_minmax_d_q,\ + neon_fp_aminmax, neon_fp_aminmax_q,\ + neon_fp_aminmax, neon_fp_aminmax_q,\ neon_fp_cvt_narrow_s_q, neon_fp_cvt_narrow_d_q,\ neon_fp_cvt_widen_h, neon_fp_cvt_widen_s, neon_fp_to_int_s,\ neon_fp_to_int_s_q, neon_int_to_fp_s, neon_int_to_fp_s_q,\ diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index ef2213b4e84..7b800b0bd79 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -21851,6 +21851,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..f2b5bafb81c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/simd/faminmax-builtins.c @@ -0,0 +1,75 @@ +/* { dg-do assemble} */ +/* { dg-additional-options "-march=armv9-a+faminmax" } */ + +#include "arm_neon.h" + +float16x4_t +test_vamax_f16 (float16x4_t a, float16x4_t b) +{ + return vamax_f16 (a, b); +} + +float16x8_t +test_vamaxq_f16 (float16x8_t a, float16x8_t b) +{ + return vamaxq_f16 (a, b); +} + +float32x2_t +test_vamax_f32 (float32x2_t a, float32x2_t b) +{ + return vamax_f32 (a, b); +} + +float32x4_t +test_vamaxq_f32 (float32x4_t a, float32x4_t b) +{ + return vamaxq_f32 (a, b); +} + +float64x2_t +test_vamaxq_f64 (float64x2_t a, float64x2_t b) +{ + return vamaxq_f64 (a, b); +} + +float16x4_t +test_vamin_f16 (float16x4_t a, float16x4_t b) +{ + return vamin_f16 (a, b); +} + +float16x8_t +test_vaminq_f16 (float16x8_t a, float16x8_t b) +{ + return vaminq_f16 (a, b); +} + +float32x2_t +test_vamin_f32 (float32x2_t a, float32x2_t b) +{ + return vamin_f32 (a, b); +} + +float32x4_t +test_vaminq_f32 (float32x4_t a, float32x4_t b) +{ + return vaminq_f32 (a, b); +} + +float64x2_t +test_vaminq_f64 (float64x2_t a, float64x2_t b) +{ + return vaminq_f64 (a, b); +} + +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.4h, v[0-9]+.4h, v[0-9]+.4h} 1 } } */ +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.8h, v[0-9]+.8h, v[0-9]+.8h} 1 } } */ +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.2s, v[0-9]+.2s, v[0-9]+.2s} 1 } } */ +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s} 1 } } */ +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d} 1 } } */ +/* { dg-final { scan-assembler-times {\tfamin\tv[0-9]+.4h, v[0-9]+.4h, v[0-9]+.4h} 1 } } */ +/* { dg-final { scan-assembler-times {\tfamin\tv[0-9]+.8h, v[0-9]+.8h, v[0-9]+.8h} 1 } } */ +/* { dg-final { scan-assembler-times {\tfamin\tv[0-9]+.2s, v[0-9]+.2s, v[0-9]+.2s} 1 } } */ +/* { dg-final { scan-assembler-times {\tfamin\tv[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s} 1 } } */ +/* { dg-final { scan-assembler-times {\tfamin\tv[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d} 1 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/simd/faminmax-codegen-no-flag.c b/gcc/testsuite/gcc.target/aarch64/simd/faminmax-codegen-no-flag.c new file mode 100644 index 00000000000..545a9468fdc --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/simd/faminmax-codegen-no-flag.c @@ -0,0 +1,54 @@ +/* { dg-do assemble} */ +/* { dg-additional-options "-O -march=armv9-a" } */ + +#include "arm_neon.h" + +float16x4_t +test_vamax_f16 (float16x4_t a, float16x4_t b) +{ + return vmax_f16 (vabs_f16 (a), vabs_f16 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.4h, v[0-9]+.4h, v[0-9]+.4h} 0 } } */ +/* { dg-final { scan-assembler-times {\tfmax\tv[0-9]+.4h, v[0-9]+.4h, v[0-9]+.4h} 1 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.4h, v[0-9]+.4h} 2 } } */ + +float16x8_t +test_vamaxq_f16 (float16x8_t a, float16x8_t b) +{ + return vmaxq_f16 (vabsq_f16 (a), vabsq_f16 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.8h, v[0-9]+.8h, v[0-9]+.8h} 0 } } */ +/* { dg-final { scan-assembler-times {\tfmax\tv[0-9]+.8h, v[0-9]+.8h, v[0-9]+.8h} 1 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.8h, v[0-9]+.8h} 2 } } */ + +float32x2_t +test_vamax_f32 (float32x2_t a, float32x2_t b) +{ + return vmax_f32 (vabs_f32 (a), vabs_f32 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.2s, v[0-9]+.2s, v[0-9]+.2s} 0 } } */ +/* { dg-final { scan-assembler-times {\tfmax\tv[0-9]+.2s, v[0-9]+.2s, v[0-9]+.2s} 1 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.2s, v[0-9]+.2s} 2 } } */ + +float32x4_t +test_vamaxq_f32 (float32x4_t a, float32x4_t b) +{ + return vmaxq_f32 (vabsq_f32 (a), vabsq_f32 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s} 0 } } */ +/* { dg-final { scan-assembler-times {\tfmax\tv[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s} 1 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.4s, v[0-9]+.4s} 2 } } */ + +float64x2_t +test_vamaxq_f64 (float64x2_t a, float64x2_t b) +{ + return vmaxq_f64 (vabsq_f64 (a), vabsq_f64 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d} 0 } } */ +/* { dg-final { scan-assembler-times {\tfmax\tv[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d} 1 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.2d, v[0-9]+.2d} 2 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/simd/faminmax-codegen.c b/gcc/testsuite/gcc.target/aarch64/simd/faminmax-codegen.c new file mode 100644 index 00000000000..e4e079a6f9e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/simd/faminmax-codegen.c @@ -0,0 +1,104 @@ +/* { dg-do assemble} */ +/* { dg-additional-options "-O -march=armv9-a+faminmax" } */ + +#include "arm_neon.h" + +float16x4_t +test_vamax_f16 (float16x4_t a, float16x4_t b) +{ + return vmax_f16 (vabs_f16 (a), vabs_f16 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.4h, v[0-9]+.4h, v[0-9]+.4h} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmax\tv[0-9]+.4h, v[0-9]+.4h, v[0-9]+.4h} 0 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.4h, v[0-9]+.4h} 0 } } */ + +float16x8_t +test_vamaxq_f16 (float16x8_t a, float16x8_t b) +{ + return vmaxq_f16 (vabsq_f16 (a), vabsq_f16 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.8h, v[0-9]+.8h, v[0-9]+.8h} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmax\tv[0-9]+.8h, v[0-9]+.8h, v[0-9]+.8h} 0 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.8h, v[0-9]+.8h} 0 } } */ + +float32x2_t +test_vamax_f32 (float32x2_t a, float32x2_t b) +{ + return vmax_f32 (vabs_f32 (a), vabs_f32 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.2s, v[0-9]+.2s, v[0-9]+.2s} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmax\tv[0-9]+.2s, v[0-9]+.2s, v[0-9]+.2s} 0 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.2s, v[0-9]+.2s} 0 } } */ + +float32x4_t +test_vamaxq_f32 (float32x4_t a, float32x4_t b) +{ + return vmaxq_f32 (vabsq_f32 (a), vabsq_f32 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmax\tv[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s} 0 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.4s, v[0-9]+.4s} 0 } } */ + +float64x2_t +test_vamaxq_f64 (float64x2_t a, float64x2_t b) +{ + return vmaxq_f64 (vabsq_f64 (a), vabsq_f64 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamax\tv[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmax\tv[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d} 0 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.2d, v[0-9]+.2d} 0 } } */ + +float16x4_t +test_vamin_f16 (float16x4_t a, float16x4_t b) +{ + return vmin_f16 (vabs_f16 (a), vabs_f16 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamin\tv[0-9]+.4h, v[0-9]+.4h, v[0-9]+.4h} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmin\tv[0-9]+.4h, v[0-9]+.4h, v[0-9]+.4h} 0 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.4h, v[0-9]+.4h} 0 } } */ + +float16x8_t +test_vaminq_f16 (float16x8_t a, float16x8_t b) +{ + return vminq_f16 (vabsq_f16 (a), vabsq_f16 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamin\tv[0-9]+.8h, v[0-9]+.8h, v[0-9]+.8h} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmin\tv[0-9]+.8h, v[0-9]+.8h, v[0-9]+.8h} 0 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.8h, v[0-9]+.8h} 0 } } */ + +float32x2_t +test_vamin_f32 (float32x2_t a, float32x2_t b) +{ + return vmin_f32 (vabs_f32 (a), vabs_f32 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamin\tv[0-9]+.2s, v[0-9]+.2s, v[0-9]+.2s} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmin\tv[0-9]+.2s, v[0-9]+.2s, v[0-9]+.2s} 0 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.2s, v[0-9]+.2s} 0 } } */ + +float32x4_t +test_vaminq_f32 (float32x4_t a, float32x4_t b) +{ + return vminq_f32 (vabsq_f32 (a), vabsq_f32 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamin\tv[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmin\tv[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s} 0 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.4s, v[0-9]+.4s} 0 } } */ + +float64x2_t +test_vaminq_f64 (float64x2_t a, float64x2_t b) +{ + return vminq_f64 (vabsq_f64 (a), vabsq_f64 (b)); +} + +/* { dg-final { scan-assembler-times {\tfamin\tv[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmin\tv[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d} 0 } } */ +/* { dg-final { scan-assembler-times {\tfabs\tv[0-9]+.2d, v[0-9]+.2d} 0 } } */