Gentle Ping ________________________________ From: Richard Ball via Sourceware Forge <[email protected]> Sent: 15 July 2026 13:36 To: gcc-patches mailing list <[email protected]> Cc: Tamar Christina <[email protected]>; Richard Earnshaw <[email protected]>; [email protected] <[email protected]>; Wilco Dijkstra <[email protected]>; Alex Coplan <[email protected]>; Alice Carlotti <[email protected]> Subject: [PATCH v2 1/1] aarch64: Add Support for F16F32DOT
From: Richard Ball <[email protected]> This patch adds the following advsimd intrinsics: *vdot_f32_f16 *vdotq_f32_f16 *vdot_lane_f32_f16 *vdot_laneq_f32_f16 *vdotq_lane_f32_f16 *vdotq_laneq_f32_f16 gcc/ChangeLog: * config/aarch64/aarch64-c.cc (aarch64_update_cpp_builtins): New target flag. * config/aarch64/aarch64-simd-builtins.def: New functions. * config/aarch64/aarch64-simd.md (aarch64_simdfdot<mode>): New pattern. (aarch64_simdfdot_lane<VF:isquadop><VDQSF:mode>): Likewise. * config/aarch64/aarch64.h (TARGET_F16F32DOT): New target flag. * config/aarch64/arm_neon.h (target): Add f16f32dot section (__attribute__): New builtin function calls. (vdot_f32_f16): Likewise. (vdotq_f32_f16): Likewise. (vdot_lane_f32_f16): Likewise. (vdot_laneq_f32_f16): Likewise. (vdotq_lane_f32_f16): Likewise. (vdotq_laneq_f32_f16): Likewise. * config/aarch64/iterators.md (q): New options for isquadop. * doc/invoke.texi: Add f16f32dot. gcc/testsuite/ChangeLog: * lib/target-supports.exp: New check_effective_target. * gcc.target/aarch64/advsimd-intrinsics/fdot-1.c: New test. * gcc.target/aarch64/advsimd-intrinsics/fdot-2.c: New test. * gcc.target/aarch64/advsimd-intrinsics/fdot-3.c: New test. --- gcc/config/aarch64/aarch64-c.cc | 1 + gcc/config/aarch64/aarch64-simd-builtins.def | 6 ++ gcc/config/aarch64/aarch64-simd.md | 30 ++++++++ gcc/config/aarch64/aarch64.h | 2 + gcc/config/aarch64/arm_neon.h | 50 +++++++++++++ gcc/config/aarch64/iterators.md | 12 +++- gcc/doc/invoke.texi | 2 + .../aarch64/advsimd-intrinsics/fdot-1.c | 68 ++++++++++++++++++ .../aarch64/advsimd-intrinsics/fdot-2.c | 70 +++++++++++++++++++ .../aarch64/advsimd-intrinsics/fdot-3.c | 32 +++++++++ gcc/testsuite/lib/target-supports.exp | 41 +++++++++++ 11 files changed, 311 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/fdot-1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/fdot-2.c create mode 100644 gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/fdot-3.c diff --git a/gcc/config/aarch64/aarch64-c.cc b/gcc/config/aarch64/aarch64-c.cc index c4ddcc6d717d..eb47a57ede44 100644 --- a/gcc/config/aarch64/aarch64-c.cc +++ b/gcc/config/aarch64/aarch64-c.cc @@ -320,6 +320,7 @@ aarch64_update_cpp_builtins (cpp_reader *pfile) aarch64_def_or_undef (AARCH64_HAVE_ISA (SSVE_FEXPA), "__ARM_FEATURE_SSVE_FEXPA", pfile); builtin_define ("__ARM_PREFETCH_RANGE"); + aarch64_def_or_undef (TARGET_F16F32DOT, "__ARM_FEATURE_F16F32DOT", pfile); // Function multi-versioning defines aarch64_def_or_undef (targetm.has_ifunc_p (), diff --git a/gcc/config/aarch64/aarch64-simd-builtins.def b/gcc/config/aarch64/aarch64-simd-builtins.def index 02938d48b4eb..9c61cc05a050 100644 --- a/gcc/config/aarch64/aarch64-simd-builtins.def +++ b/gcc/config/aarch64/aarch64-simd-builtins.def @@ -921,6 +921,12 @@ VAR2 (QUADOP_LANE_PAIR, bfdot_lane, 0, QUIET, v2sf, v4sf) VAR2 (QUADOP_LANE_PAIR, bfdot_laneq, 0, QUIET, v2sf, v4sf) + /* Implemented by sdot_prod<mode>. */ + BUILTIN_VF (TERNOP, sdot_prod, 10, DEFAULT) + /* Implemented by sdot_lane{q}<dot_mode>. */ + BUILTIN_VF (QUADOP_LANE_PAIR, sdot_lane, 10, DEFAULT) + BUILTIN_VF (QUADOP_LANE_PAIR, sdot_laneq, 10, DEFAULT) + /* Implemented by aarch64_bfmmlaqv4sf */ VAR1 (TERNOP, bfmmlaq, 0, QUIET, v4sf) diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md index ce51e24da36a..433f16052bf2 100644 --- a/gcc/config/aarch64/aarch64-simd.md +++ b/gcc/config/aarch64/aarch64-simd.md @@ -782,6 +782,36 @@ [(set_attr "type" "neon_dot<VS:q>")] ) +(define_insn "sdot_prod<VDQSF:vsi2qi><vczle><vczbe>" + [(set (match_operand:VDQSF 0 "register_operand" "=w") + (plus:VDQSF + (unspec:VDQSF + [(match_operand:<VSI2QI> 2 "register_operand" "w") + (match_operand:<VSI2QI> 3 "register_operand" "w")] + UNSPEC_FDOT) + (match_operand:VDQSF 1 "register_operand" "0")))] + "TARGET_F16F32DOT" + "fdot\t%0.<Vtype>, %2.<Vbfdottype>, %3.<Vbfdottype>" + [(set_attr "type" "neon_dot<q>")] +) + +(define_insn "sdot_lane<VF:isquadop><VDQSF:vsi2qi><vczle><vczbe>" + [(set (match_operand:VDQSF 0 "register_operand" "=w") + (plus:VDQSF + (unspec:VDQSF + [(match_operand:<VDQSF:VSI2QI> 2 "register_operand" "w") + (match_operand:VF 3 "register_operand" "w") + (match_operand:SI 4 "immediate_operand" "i")] + UNSPEC_FDOT) + (match_operand:VDQSF 1 "register_operand" "0")))] + "TARGET_F16F32DOT" +{ + operands[4] = aarch64_endian_lane_rtx (<VF:MODE>mode, INTVAL (operands[4])); + return "fdot\t%0.<VDQSF:Vtype>, %2.<VDQSF:Vbfdottype>, %3.2h[%4]"; +} + [(set_attr "type" "neon_dot<VDQSF:q>")] +) + (define_expand "copysign<mode>3" [(match_operand:VHSDF 0 "register_operand") (match_operand:VHSDF 1 "register_operand") diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 26db4958a80f..a544a1877ef3 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -427,6 +427,8 @@ constexpr auto AARCH64_FL_DEFAULT_ISA_MODE ATTRIBUTE_UNUSED #define TARGET_F8F16MM (AARCH64_HAVE_ISA (F8F16MM)) /* SVE_F16F32MM instructions, enabled through +sve-f16f32mm. */ #define TARGET_SVE_F16F32MM (AARCH64_HAVE_ISA (SVE_F16F32MM)) +/* F16F32DOT instructions enabled through +f16f32dot. */ +#define TARGET_F16F32DOT (AARCH64_HAVE_ISA (F16F32DOT)) /* Make sure this is always defined so we don't have to check for ifdefs but rather use normal ifs. */ diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h index 3e401dbe6a0f..101a6e521068 100644 --- a/gcc/config/aarch64/arm_neon.h +++ b/gcc/config/aarch64/arm_neon.h @@ -22404,6 +22404,56 @@ vst4q_lane_bf16 (bfloat16_t *__ptr, bfloat16x8x4_t __val, const int __lane) #pragma GCC pop_options +#pragma GCC push_options +#pragma GCC target ("+nothing+f16f32dot") + +__extension__ extern __inline float32x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +vdot_f32_f16 (float32x2_t __r, float16x4_t __a, float16x4_t __b) +{ + return __builtin_aarch64_sdot_prodv4hf (__r, __a, __b); +} + +__extension__ extern __inline float32x4_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +vdotq_f32_f16 (float32x4_t __r, float16x8_t __a, float16x8_t __b) +{ + return __builtin_aarch64_sdot_prodv8hf (__r, __a, __b); +} + +__extension__ extern __inline float32x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +vdot_lane_f32_f16 (float32x2_t __r, float16x4_t __a, float16x4_t __b, + const int __index) +{ + return __builtin_aarch64_sdot_lanev4hf (__r, __a, __b, __index); +} + +__extension__ extern __inline float32x2_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +vdot_laneq_f32_f16 (float32x2_t __r, float16x4_t __a, float16x8_t __b, + const int __index) +{ + return __builtin_aarch64_sdot_laneqv4hf (__r, __a, __b, __index); +} + +__extension__ extern __inline float32x4_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +vdotq_lane_f32_f16 (float32x4_t __r, float16x8_t __a, float16x4_t __b, + const int __index) +{ + return __builtin_aarch64_sdot_lanev8hf (__r, __a, __b, __index); +} + +__extension__ extern __inline float32x4_t +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +vdotq_laneq_f32_f16 (float32x4_t __r, float16x8_t __a, float16x8_t __b, + const int __index) +{ + return __builtin_aarch64_sdot_laneqv8hf (__r, __a, __b, __index); +} + +#pragma GCC pop_options /* AdvSIMD 8-bit Integer Matrix Multiply (I8MM) intrinsics. */ #pragma GCC push_options diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index a8b976e4b71e..5dfb27449703 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -172,6 +172,9 @@ ;; BFmode vector modes. (define_mode_iterator VBF [V4BF V8BF]) +;; Fmode vector modes. +(define_mode_iterator VF [V4HF V8HF]) + ;; This mode iterator allows :P to be used for patterns that operate on ;; addresses in different modes. In LP64, only DI will match, while in ;; ILP32, either can match. @@ -2668,9 +2671,11 @@ (V4HF "v") (V8HF "v")]) (define_mode_attr vsi2qi [(V2SI "v8qi") (V4SI "v16qi") - (VNx4SI "vnx16qi") (VNx2DI "vnx8hi")]) + (VNx4SI "vnx16qi") (VNx2DI "vnx8hi") + (V2SF "v4hf") (V4SF "v8hf")]) (define_mode_attr VSI2QI [(V2SI "V8QI") (V4SI "V16QI") - (VNx4SI "VNx16QI") (VNx2DI "VNx8HI")]) + (VNx4SI "VNx16QI") (VNx2DI "VNx8HI") + (V2SF "V4HF") (V4SF "V8HF")]) ;; Register suffix for DOTPROD input types from the return type. @@ -2720,7 +2725,8 @@ (define_mode_attr f16quad [(V2SF "") (V4SF "q")]) -(define_mode_attr isquadop [(V8QI "") (V16QI "q") (V4BF "") (V8BF "q")]) +(define_mode_attr isquadop [(V8QI "") (V16QI "q") (V4BF "") (V8BF "q") + (V4HF "") (V8HF "q")]) (define_code_attr f16mac [(plus "a") (minus "s")]) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 78052b229a58..498cd795c5c0 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -22099,6 +22099,8 @@ extension. @item ssve-fp8dot2 Enable the fp8 (8-bit floating point) to half-precision 2-way dot product extension in streaming mode. +@item f16f32dot +Enable the Half-precision to single-precision dot product extension. @item faminmax Enable the Floating Point Absolute Maximum/Minimum extension. @item lut diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/fdot-1.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/fdot-1.c new file mode 100644 index 000000000000..4abbdf57ef69 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/fdot-1.c @@ -0,0 +1,68 @@ +/* { dg-do assemble { target { aarch64*-*-* } } } */ +/* { dg-require-effective-target aarch64_f16f32dot_neon_ok } */ +/* { dg-add-options aarch64_f16f32dot_neon } */ +/* { dg-additional-options "-save-temps" } */ +/* { dg-final { check-function-bodies "**" "" {-O[^0]} } } */ +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ + +#include <arm_neon.h> + +/* +**ufoo: +** fdot v0.2s, (v1.4h, v2.4h|v2.4h, v1.4h) +** ret +*/ +float32x2_t ufoo(float32x2_t r, float16x4_t x, float16x4_t y) +{ + return vdot_f32_f16 (r, x, y); +} + +/* +**ufooq: +** fdot v0.4s, (v1.8h, v2.8h|v2.8h, v1.8h) +** ret +*/ +float32x4_t ufooq(float32x4_t r, float16x8_t x, float16x8_t y) +{ + return vdotq_f32_f16 (r, x, y); +} + +/* +**ufoo_lane: +** fdot v0.2s, v1.4h, v2.2h\[0\] +** ret +*/ +float32x2_t ufoo_lane(float32x2_t r, float16x4_t x, float16x4_t y) +{ + return vdot_lane_f32_f16 (r, x, y, 0); +} + +/* +**ufoo_laneq: +** fdot v0.2s, v1.4h, v2.2h\[2\] +** ret +*/ +float32x2_t ufoo_laneq(float32x2_t r, float16x4_t x, float16x8_t y) +{ + return vdot_laneq_f32_f16 (r, x, y, 2); +} + +/* +**ufooq_lane: +** fdot v0.4s, v1.8h, v2.2h\[1\] +** ret +*/ +float32x4_t ufooq_lane(float32x4_t r, float16x8_t x, float16x4_t y) +{ + return vdotq_lane_f32_f16 (r, x, y, 1); +} + +/* +**ufooq_laneq: +** fdot v0.4s, v1.8h, v2.2h\[2\] +** ret +*/ +float32x4_t ufooq_laneq(float32x4_t r, float16x8_t x, float16x8_t y) +{ + return vdotq_laneq_f32_f16 (r, x, y, 2); +} \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/fdot-2.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/fdot-2.c new file mode 100644 index 000000000000..b42bfa09c77c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/fdot-2.c @@ -0,0 +1,70 @@ +/* { dg-do assemble { target { aarch64*-*-* } } } */ +/* { dg-require-effective-target stdint_types_mbig_endian } */ +/* { dg-require-effective-target aarch64_f16f32dot_neon_ok } */ +/* { dg-add-options aarch64_f16f32dot_neon } */ +/* { dg-additional-options "-mbig-endian --save-temps" } */ +/* { dg-final { check-function-bodies "**" "" {-O[^0]} } } */ +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ + + +#include <arm_neon.h> + +/* +**ufoo: +** fdot v0.2s, (v1.4h, v2.4h|v2.4h, v1.4h) +** ret +*/ +float32x2_t ufoo(float32x2_t r, float16x4_t x, float16x4_t y) +{ + return vdot_f32_f16 (r, x, y); +} + +/* +**ufooq: +** fdot v0.4s, (v1.8h, v2.8h|v2.8h, v1.8h) +** ret +*/ +float32x4_t ufooq(float32x4_t r, float16x8_t x, float16x8_t y) +{ + return vdotq_f32_f16 (r, x, y); +} + +/* +**ufoo_lane: +** fdot v0.2s, v1.4h, v2.2h\[0\] +** ret +*/ +float32x2_t ufoo_lane(float32x2_t r, float16x4_t x, float16x4_t y) +{ + return vdot_lane_f32_f16 (r, x, y, 0); +} + +/* +**ufoo_laneq: +** fdot v0.2s, v1.4h, v2.2h\[2\] +** ret +*/ +float32x2_t ufoo_laneq(float32x2_t r, float16x4_t x, float16x8_t y) +{ + return vdot_laneq_f32_f16 (r, x, y, 2); +} + +/* +**ufooq_lane: +** fdot v0.4s, v1.8h, v2.2h\[1\] +** ret +*/ +float32x4_t ufooq_lane(float32x4_t r, float16x8_t x, float16x4_t y) +{ + return vdotq_lane_f32_f16 (r, x, y, 1); +} + +/* +**ufooq_laneq: +** fdot v0.4s, v1.8h, v2.2h\[2\] +** ret +*/ +float32x4_t ufooq_laneq(float32x4_t r, float16x8_t x, float16x8_t y) +{ + return vdotq_laneq_f32_f16 (r, x, y, 2); +} \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/fdot-3.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/fdot-3.c new file mode 100644 index 000000000000..314322a08345 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/fdot-3.c @@ -0,0 +1,32 @@ +/* { dg-do assemble { target { aarch64*-*-* } } } */ +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ +/* { dg-require-effective-target aarch64_f16f32dot_neon_ok } */ +/* { dg-add-options aarch64_f16f32dot_neon } */ +/* { dg-additional-options "--save-temps" } */ + +#include <arm_neon.h> + +float32x2_t ufoo_lane(float32x2_t r, float16x4_t x, float16x4_t y) +{ + return vdot_lane_f32_f16 (r, x, y, 2); +} + +float32x2_t ufoo_laneq(float32x2_t r, float16x4_t x, float16x8_t y) +{ + return vdot_laneq_f32_f16 (r, x, y, 4); +} + +float32x4_t ufooq_lane(float32x4_t r, float16x8_t x, float16x4_t y) +{ + return vdotq_lane_f32_f16 (r, x, y, 3); +} + +float32x4_t ufooq_laneq(float32x4_t r, float16x8_t x, float16x8_t y) +{ + return vdotq_laneq_f32_f16 (r, x, y, 5); +} + +/* { dg-error {lane 2 out of range 0 - 1} "" { target *-*-* } 0 } */ +/* { dg-error {lane 4 out of range 0 - 3} "" { target *-*-* } 0 } */ +/* { dg-error {lane 3 out of range 0 - 1} "" { target *-*-* } 0 } */ +/* { dg-error {lane 5 out of range 0 - 3} "" { target *-*-* } 0 } */ \ No newline at end of file diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index edd1290bd9e3..b494e0157136 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -7335,6 +7335,47 @@ proc add_options_for_arm_fp16fml_neon { flags } { return "$flags $et_arm_fp16fml_neon_flags" } +# Return 1 if the target supports F16F32DOT +# instructions, 0 otherwise. This test is valid +# for AARCH64. +# Record the command line options needed. + +proc check_effective_target_aarch64_f16f32dot_neon_ok_nocache { } { + global et_aarch64_f16f32dot_neon_flags + set et_aarch64_f16f32dot_neon_flags "" + + if { ![istarget aarch64*-*-*] } { + return 0; + } + + foreach flags {"" "" } { + if { [check_no_compiler_messages_nocache aarch64_f16f32dot_neon_ok object { + #include <arm_neon.h> + #if !defined (__ARM_FEATURE_F16F32DOT) + #error "__ARM_FEATURE_F16F32DOT not defined" + #endif + } "$flags -march=armv8.2-a+fp16+f16f32dot"] } { + set et_aarch64_f16f32dot_neon_flags "$flags -march=armv8.2-a+fp16+f16f32dot" + return 1 + } + } + + return 0; +} + +proc check_effective_target_aarch64_f16f32dot_neon_ok { } { + return [check_cached_effective_target aarch64_f16f32dot_neon_ok \ + check_effective_target_aarch64_f16f32dot_neon_ok_nocache] +} + +proc add_options_for_aarch64_f16f32dot_neon { flags } { + if { ! [check_effective_target_aarch64_f16f32dot_neon_ok] } { + return "$flags" + } + global et_aarch64_f16f32dot_neon_flags + return "$flags $et_aarch64_f16f32dot_neon_flags" +} + # Return 1 if the target supports BFloat16 SIMD instructions, 0 otherwise. # The test is valid for ARM and for AArch64. -- 2.54.0
