Ping. https://gcc.gnu.org/pipermail/gcc-patches/2026-October/733602.html Thanks, Kyrill
> On 6 Oct 2026, at 16:02, Kyrylo Tkachov <[email protected]> wrote: > > From: Kyrylo Tkachov <[email protected]> > > The FADDP patterns use UNSPEC_FADDV, so RTL optimizations cannot see that > FADDP adds pairs of elements. ADDP already uses standard RTL. Describe > FADDP in the same way and let it share the ADDP patterns, which get > parameterized names. > > For two-lane vectors, FADDP and the scalar FADDP reduction add the two > elements of each input. RTL simplification describes the low element of > a vector as a lowpart subreg, so use that form for these sums: > > (plus:SF (vec_select:SF (reg:V2SF x) (parallel [(const_int 1)])) > (subreg:SF (reg:V2SF x) 0)) > > The insn condition checks that the subreg is the lowpart of the vector > operand. The instruction only reads the vector operand. > > Combine can now use FADDP for the sum of the two elements of a vector, and > pack two such sums into one FADDP. For example, with -O2: > > float32x2_t > f (float32x2_t a, float32x2_t b) > { > return (float32x2_t) { vaddv_f32 (a), vaddv_f32 (b) }; > } > > Before: > faddp s1, v1.2s > faddp s0, v0.2s > zip1 v0.2s, v0.2s, v1.2s > > After: > faddp v0.2s, v0.2s, v1.2s > > For x[0] + x[1], where x is a float32x2_t: > > Before: > dup s31, v0.s[1] > fadd s0, s31, s0 > > After: > faddp s0, v0.2s > > Tests check lane extraction from FADDP results for both byte orders. The > runtime test also passes under big-endian QEMU. > > Bootstrapped and tested on aarch64-none-linux-gnu. > Ok for trunk? > Thanks, > Kyrill > > Cc: Tamar Christina <[email protected]> > Cc: Wilco Dijkstra <[email protected]> > > gcc/ChangeLog: > > * config/aarch64/aarch64-protos.h (aarch64_simd_lowpart_of_p): > Declare. > * config/aarch64/aarch64.cc (aarch64_simd_lowpart_of_p): New > function. > * config/aarch64/iterators.md (VD_ADDP, VQ_ADDP, VDQ_ADDP): New mode > iterators. > (addp_type): New mode attribute. > * config/aarch64/aarch64-simd.md (aarch64_faddp<mode><vczle><vczbe>): > Remove. > (reduc_plus_scal_<mode>): Use standard RTL for V2F. > (aarch64_faddp_scal<mode>): New pattern. > (aarch64_addp<mode>_insn): Rename to... > (@aarch64_addp<mode>_concat): ...this. Handle FADDP. > (aarch64_addp<mode><vczle><vczbe>_insn): Rename to... > (@aarch64_addp<mode>_select<vczle><vczbe>): ...this. Handle FADDP. > (@aarch64_faddp_scal_pair<mode><vczle><vczbe>): New pattern. > (*aarch64_addp_same_reg<mode>): Handle FADDP. > (aarch64_addp<mode>): Rename to... > (aarch64_<f>addp<mode>): ...this. Handle FADDP. > > gcc/testsuite/ChangeLog: > > * gcc.target/aarch64/faddp-concat-1.c: New test. > * gcc.target/aarch64/faddp-concat-3.c: Likewise. > * gcc.target/aarch64/faddp-concat-be.c: Likewise. > * gcc.target/aarch64/simd/faddp_lane_1.c: Likewise. > * gcc.target/aarch64/simd/faddp_lane_2.c: Likewise. > * gcc.target/aarch64/simd/faddp_reinterpret_1.c: Likewise. > > Signed-off-by: Kyrylo Tkachov <[email protected]> > --- > gcc/config/aarch64/aarch64-protos.h | 1 + > gcc/config/aarch64/aarch64-simd.md | 183 ++++++++++++------ > gcc/config/aarch64/aarch64.cc | 9 + > gcc/config/aarch64/iterators.md | 20 ++ > .../gcc.target/aarch64/faddp-concat-1.c | 64 ++++++ > .../gcc.target/aarch64/faddp-concat-3.c | 25 +++ > .../gcc.target/aarch64/faddp-concat-be.c | 51 +++++ > .../gcc.target/aarch64/simd/faddp_lane_1.c | 76 ++++++++ > .../gcc.target/aarch64/simd/faddp_lane_2.c | 53 +++++ > .../aarch64/simd/faddp_reinterpret_1.c | 51 +++++ > 10 files changed, 471 insertions(+), 62 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/aarch64/faddp-concat-1.c > create mode 100644 gcc/testsuite/gcc.target/aarch64/faddp-concat-3.c > create mode 100644 gcc/testsuite/gcc.target/aarch64/faddp-concat-be.c > create mode 100644 gcc/testsuite/gcc.target/aarch64/simd/faddp_lane_1.c > create mode 100644 gcc/testsuite/gcc.target/aarch64/simd/faddp_lane_2.c > create mode 100644 gcc/testsuite/gcc.target/aarch64/simd/faddp_reinterpret_1.c > > diff --git a/gcc/config/aarch64/aarch64-protos.h > b/gcc/config/aarch64/aarch64-protos.h > index e8ae3d42794..b825ff5b584 100644 > --- a/gcc/config/aarch64/aarch64-protos.h > +++ b/gcc/config/aarch64/aarch64-protos.h > @@ -963,6 +963,7 @@ bool aarch64_regno_ok_for_index_p (int, bool); > bool aarch64_reinterpret_float_as_int (rtx value, unsigned HOST_WIDE_INT > *fail); > bool aarch64_simd_check_vect_par_cnst_half (rtx op, machine_mode mode, > bool high); > +bool aarch64_simd_lowpart_of_p (rtx, rtx); > bool aarch64_parallel_select_half_p (machine_mode, rtx); > bool aarch64_pars_overlap_p (rtx, rtx); > bool aarch64_simd_scalar_immediate_valid_for_move (rtx, scalar_int_mode); > diff --git a/gcc/config/aarch64/aarch64-simd.md > b/gcc/config/aarch64/aarch64-simd.md > index f928c5958cd..e1ce90bfafb 100644 > --- a/gcc/config/aarch64/aarch64-simd.md > +++ b/gcc/config/aarch64/aarch64-simd.md > @@ -3760,16 +3760,6 @@ > > ;; 'across lanes' add. > > -(define_insn "aarch64_faddp<mode><vczle><vczbe>" > - [(set (match_operand:VHSDF 0 "register_operand" "=w") > - (unspec:VHSDF [(match_operand:VHSDF 1 "register_operand" "w") > - (match_operand:VHSDF 2 "register_operand" "w")] > - UNSPEC_FADDV))] > - "TARGET_SIMD" > - "faddp\t%0.<Vtype>, %1.<Vtype>, %2.<Vtype>" > - [(set_attr "type" "neon_fp_reduc_add_<stype><q>")] > -) > - > (define_insn "reduc_plus_scal_<mode>" > [(set (match_operand:<VEL> 0 "register_operand" "=w") > (unspec:<VEL> [(match_operand:VDQV 1 "register_operand" "w")] > @@ -3799,12 +3789,31 @@ > [(set_attr "type" "neon_reduc_add<VDQV_E:q>")] > ) > > -(define_insn "reduc_plus_scal_<mode>" > - [(set (match_operand:<VEL> 0 "register_operand" "=w") > - (unspec:<VEL> [(match_operand:V2F 1 "register_operand" "w")] > - UNSPEC_FADDV))] > - "TARGET_SIMD" > - "faddp\\t%<Vetype>0, %1.<Vtype>" > +(define_expand "reduc_plus_scal_<mode>" > + [(match_operand:<VEL> 0 "register_operand") > + (match_operand:V2F 1 "register_operand")] > + "TARGET_SIMD" > + { > + rtx hi = aarch64_gen_stepped_int_parallel (1, ENDIAN_LANE_N (2, 1), 1); > + rtx x = force_reg (<MODE>mode, operands[1]); > + emit_insn (gen_aarch64_faddp_scal<mode> (operands[0], x, hi, > + gen_lowpart (<VEL>mode, x))); > + DONE; > + } > +) > + > +;; The sum of the two elements of a vector. RTL simplification describes > +;; the low element as a lowpart of the vector, so operand 3 is that lowpart > +;; of operand 1. > +(define_insn "aarch64_faddp_scal<mode>" > + [(set (match_operand:<VEL> 0 "register_operand" "=w") > + (plus:<VEL> > + (vec_select:<VEL> > + (match_operand:V2F 1 "register_operand" "w") > + (match_operand:V2F 2 "vect_par_cnst_hi_half")) > + (match_operand:<VEL> 3 "register_operand" "w")))] > + "TARGET_SIMD && aarch64_simd_lowpart_of_p (operands[3], operands[1])" > + "faddp\t%<Vetype>0, %1.<Vtype>" > [(set_attr "type" "neon_fp_reduc_add_<Vetype><q>")] > ) > > @@ -8304,27 +8313,27 @@ > [(set_attr "type" "neon_fp_compare_<stype><q>")] > ) > > -;; addp > +;; addp and faddp > > -;; ADDP with two registers semantically concatenates them and performs > -;; a pairwise addition on the result. For 128-bit input modes represent this > -;; as a concatenation of the pairwise addition results of the two input > -;; registers. This allow us to avoid using intermediate 256-bit modes. > -;; The RTL uses GCC's lane numbering, so on big-endian targets operand 1 > -;; provides the architecturally high half of the result. > -(define_insn "aarch64_addp<mode>_insn" > - [(set (match_operand:VQ_I 0 "register_operand" "=w") > - (vec_concat:VQ_I > +;; ADDP and FADDP with two registers semantically concatenate them and > +;; perform a pairwise addition on the result. For 128-bit input modes > +;; represent this as a concatenation of the pairwise addition results of the > +;; two input registers. This allows us to avoid using intermediate 256-bit > +;; modes. The RTL uses GCC's lane numbering, so on big-endian targets > +;; operand 1 provides the architecturally high half of the result. > +(define_insn "@aarch64_addp<mode>_concat" > + [(set (match_operand:VQ_ADDP 0 "register_operand" "=w") > + (vec_concat:VQ_ADDP > (plus:<VHALF> > (vec_select:<VHALF> > - (match_operand:VQ_I 1 "register_operand" "w") > - (match_operand:VQ_I 3 "vect_par_cnst_even_or_odd_half")) > + (match_operand:VQ_ADDP 1 "register_operand" "w") > + (match_operand:VQ_ADDP 3 "vect_par_cnst_even_or_odd_half")) > (vec_select:<VHALF> > (match_dup 1) > - (match_operand:VQ_I 4 "vect_par_cnst_even_or_odd_half"))) > + (match_operand:VQ_ADDP 4 "vect_par_cnst_even_or_odd_half"))) > (plus:<VHALF> > (vec_select:<VHALF> > - (match_operand:VQ_I 2 "register_operand" "w") > + (match_operand:VQ_ADDP 2 "register_operand" "w") > (match_dup 3)) > (vec_select:<VHALF> > (match_dup 2) > @@ -8332,26 +8341,27 @@ > "TARGET_SIMD && !rtx_equal_p (operands[3], operands[4])" > { > if (BYTES_BIG_ENDIAN) > - return "addp\t%<v>0<Vmtype>, %<v>2<Vmtype>, %<v>1<Vmtype>"; > - return "addp\t%<v>0<Vmtype>, %<v>1<Vmtype>, %<v>2<Vmtype>"; > + return "<f>addp\t%<v>0<Vmtype>, %<v>2<Vmtype>, %<v>1<Vmtype>"; > + return "<f>addp\t%<v>0<Vmtype>, %<v>1<Vmtype>, %<v>2<Vmtype>"; > } > - [(set_attr "type" "neon_reduc_add<q>")] > + [(set_attr "type" "<addp_type>")] > ) > > -;; For 64-bit input modes an ADDP is represented as a concatenation > +;; For 64-bit input modes an ADDP or FADDP is represented as a concatenation > ;; of the input registers into an 128-bit register which is then fed > ;; into a pairwise add. That way we avoid having to create intermediate > -;; 32-bit vector modes. As above, operand 1 provides the architecturally > -;; high half of the result on big-endian targets. > -(define_insn "aarch64_addp<mode><vczle><vczbe>_insn" > - [(set (match_operand:VD_BHSI 0 "register_operand" "=w") > - (plus:VD_BHSI > - (vec_select:VD_BHSI > +;; 32-bit vector modes. vpadd_f32 uses @aarch64_faddp_scal_pair<mode> > +;; instead. As above, operand 1 provides the architecturally high half of > +;; the result on big-endian targets. > +(define_insn "@aarch64_addp<mode>_select<vczle><vczbe>" > + [(set (match_operand:VD_ADDP 0 "register_operand" "=w") > + (plus:VD_ADDP > + (vec_select:VD_ADDP > (vec_concat:<VDBL> > - (match_operand:VD_BHSI 1 "register_operand" "w") > - (match_operand:VD_BHSI 2 "register_operand" "w")) > + (match_operand:VD_ADDP 1 "register_operand" "w") > + (match_operand:VD_ADDP 2 "register_operand" "w")) > (match_operand:<VDBL> 3 "vect_par_cnst_even_or_odd_half")) > - (vec_select:VD_BHSI > + (vec_select:VD_ADDP > (vec_concat:<VDBL> > (match_dup 1) > (match_dup 2)) > @@ -8359,10 +8369,39 @@ > "TARGET_SIMD && !rtx_equal_p (operands[3], operands[4])" > { > if (BYTES_BIG_ENDIAN) > - return "addp\t%<v>0<Vmtype>, %<v>2<Vmtype>, %<v>1<Vmtype>"; > - return "addp\t%<v>0<Vmtype>, %<v>1<Vmtype>, %<v>2<Vmtype>"; > + return "<f>addp\t%<v>0<Vmtype>, %<v>2<Vmtype>, %<v>1<Vmtype>"; > + return "<f>addp\t%<v>0<Vmtype>, %<v>1<Vmtype>, %<v>2<Vmtype>"; > + } > + [(set_attr "type" "<addp_type>")] > +) > + > +;; FADDP of two-lane vectors, represented as the concatenation of the sums of > +;; the two elements of each input. RTL simplification describes the low > +;; element of a vector as a lowpart of the vector, so operands 4 and 5 are > +;; those lowparts of operands 1 and 2. As above, operand 1 provides the > +;; architecturally high half of the result on big-endian targets. > +(define_insn "@aarch64_faddp_scal_pair<mode><vczle><vczbe>" > + [(set (match_operand:V2F 0 "register_operand" "=w") > + (vec_concat:V2F > + (plus:<VEL> > + (vec_select:<VEL> > + (match_operand:V2F 1 "register_operand" "w") > + (match_operand:V2F 3 "vect_par_cnst_hi_half")) > + (match_operand:<VEL> 4 "register_operand" "w")) > + (plus:<VEL> > + (vec_select:<VEL> > + (match_operand:V2F 2 "register_operand" "w") > + (match_dup 3)) > + (match_operand:<VEL> 5 "register_operand" "w"))))] > + "TARGET_SIMD > + && aarch64_simd_lowpart_of_p (operands[4], operands[1]) > + && aarch64_simd_lowpart_of_p (operands[5], operands[2])" > + { > + if (BYTES_BIG_ENDIAN) > + return "faddp\t%0.<Vtype>, %2.<Vtype>, %1.<Vtype>"; > + return "faddp\t%0.<Vtype>, %1.<Vtype>, %2.<Vtype>"; > } > - [(set_attr "type" "neon_reduc_add<q>")] > + [(set_attr "type" "<addp_type>")] > ) > > ;; A common usecase of 64-bit ADDP is to have both operands come from the same > @@ -8372,11 +8411,11 @@ > [(set (match_operand:<VHALF> 0 "register_operand" "=w") > (plus:<VHALF> > (vec_select:<VHALF> > - (match_operand:VQ_I 1 "register_operand" "w") > - (match_operand:VQ_I 2 "vect_par_cnst_even_or_odd_half")) > + (match_operand:VQ_ADDP 1 "register_operand" "w") > + (match_operand:VQ_ADDP 2 "vect_par_cnst_even_or_odd_half")) > (vec_select:<VHALF> > (match_dup 1) > - (match_operand:VQ_I 3 "vect_par_cnst_even_or_odd_half"))))] > + (match_operand:VQ_ADDP 3 "vect_par_cnst_even_or_odd_half"))))] > "TARGET_SIMD && !rtx_equal_p (operands[2], operands[3])" > "#" > "&& 1" > @@ -8388,29 +8427,49 @@ > else > scratch = lowpart_subreg (<MODE>mode, operands[0], <VHALF>mode); > > - emit_insn (gen_aarch64_addp<mode>_insn (scratch, operands[1], > operands[1], > - operands[2], operands[3])); > + emit_insn (gen_aarch64_addp_concat (<MODE>mode, scratch, operands[1], > + operands[1], operands[2], > + operands[3])); > emit_move_insn (operands[0], gen_lowpart (<VHALF>mode, scratch)); > DONE; > } > ) > > -(define_expand "aarch64_addp<mode>" > - [(match_operand:VDQ_I 0 "register_operand") > - (match_operand:VDQ_I 1 "register_operand") > - (match_operand:VDQ_I 2 "register_operand")] > +(define_expand "aarch64_<f>addp<mode>" > + [(match_operand:VDQ_ADDP 0 "register_operand") > + (match_operand:VDQ_ADDP 1 "register_operand") > + (match_operand:VDQ_ADDP 2 "register_operand")] > "TARGET_SIMD" > { > - int nunits = GET_MODE_NUNITS (<MODE>mode).to_constant (); > - if (known_eq (GET_MODE_BITSIZE (<MODE>mode), 128)) > - nunits /= 2; > - rtx par_even = aarch64_gen_stepped_int_parallel (nunits, 0, 2); > - rtx par_odd = aarch64_gen_stepped_int_parallel (nunits, 1, 2); > /* The intrinsic uses architectural lane numbering. */ > if (BYTES_BIG_ENDIAN) > std::swap (operands[1], operands[2]); > - emit_insn (gen_aarch64_addp<mode>_insn (operands[0], operands[1], > - operands[2], par_even, par_odd)); > + int nunits = GET_MODE_NUNITS (<MODE>mode).to_constant (); > + if (nunits == 2 && FLOAT_MODE_P (<MODE>mode)) > + { > + rtx hi = aarch64_gen_stepped_int_parallel (1, ENDIAN_LANE_N (2, 1), 1); > + rtx x = force_reg (<MODE>mode, operands[1]); > + rtx y = force_reg (<MODE>mode, operands[2]); > + emit_insn (gen_aarch64_faddp_scal_pair (<MODE>mode, operands[0], x, y, > + hi, gen_lowpart (<VEL>mode, x), > + gen_lowpart (<VEL>mode, y))); > + } > + else if (known_eq (GET_MODE_BITSIZE (<MODE>mode), 128)) > + { > + rtx even = aarch64_gen_stepped_int_parallel (nunits / 2, 0, 2); > + rtx odd = aarch64_gen_stepped_int_parallel (nunits / 2, 1, 2); > + emit_insn (gen_aarch64_addp_concat (<MODE>mode, operands[0], > + operands[1], operands[2], even, > + odd)); > + } > + else > + { > + rtx even = aarch64_gen_stepped_int_parallel (nunits, 0, 2); > + rtx odd = aarch64_gen_stepped_int_parallel (nunits, 1, 2); > + emit_insn (gen_aarch64_addp_select (<MODE>mode, operands[0], > + operands[1], operands[2], even, > + odd)); > + } > DONE; > } > ) > diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc > index 6693cec98bd..d7b5775a66d 100644 > --- a/gcc/config/aarch64/aarch64.cc > +++ b/gcc/config/aarch64/aarch64.cc > @@ -25552,6 +25552,15 @@ aarch64_simd_check_vect_par_cnst_half (rtx op, > machine_mode mode, > return true; > } > > +/* Return true if X is the low element of vector V, in the lowpart form > + that RTL simplification uses for it. */ > + > +bool > +aarch64_simd_lowpart_of_p (rtx x, rtx v) > +{ > + return rtx_equal_p (x, lowpart_subreg (GET_MODE (x), v, GET_MODE (v))); > +} > + > /* Return a PARALLEL containing NELTS elements, with element I equal > to BASE + I * STEP. */ > > diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md > index 568786e3714..66db3f4a5fd 100644 > --- a/gcc/config/aarch64/iterators.md > +++ b/gcc/config/aarch64/iterators.md > @@ -238,6 +238,15 @@ > ;; Advanced SIMD Float modes with 2 elements. > (define_mode_iterator V2F [V2SF V2DF]) > > +;; 64-bit modes of ADDP and FADDP. > +(define_mode_iterator VD_ADDP [VD_BHSI (V4HF "TARGET_SIMD_F16INST") V2SF]) > + > +;; 128-bit modes of ADDP and FADDP. > +(define_mode_iterator VQ_ADDP [VQ_I (V8HF "TARGET_SIMD_F16INST") V4SF V2DF]) > + > +;; Modes of ADDP and FADDP. > +(define_mode_iterator VDQ_ADDP [VDQ_I VHSDF]) > + > ;; All Advanced SIMD modes on which we support any arithmetic operations. > (define_mode_iterator VALL [V8QI V16QI V4HI V8HI V2SI V4SI V2DI V2SF V4SF > V2DF]) > > @@ -2715,6 +2724,17 @@ > (V2SF "f") (V4SF "f") > (V2DF "f") (DF "f")]) > > +;; The type of ADDP and FADDP. > +(define_mode_attr addp_type [(V8QI "neon_reduc_add") (V16QI > "neon_reduc_add_q") > + (V4HI "neon_reduc_add") (V8HI "neon_reduc_add_q") > + (V2SI "neon_reduc_add") (V4SI "neon_reduc_add_q") > + (V2DI "neon_reduc_add_q") > + (V4HF "neon_fp_reduc_add_s") > + (V8HF "neon_fp_reduc_add_s_q") > + (V2SF "neon_fp_reduc_add_s") > + (V4SF "neon_fp_reduc_add_s_q") > + (V2DF "neon_fp_reduc_add_d_q")]) > + > ;; Defined to '_fp' for types whose element type is a float type. > (define_mode_attr fp [(V8QI "") (V16QI "") > (V4HI "") (V8HI "") > diff --git a/gcc/testsuite/gcc.target/aarch64/faddp-concat-1.c > b/gcc/testsuite/gcc.target/aarch64/faddp-concat-1.c > new file mode 100644 > index 00000000000..8b5f69cd6e2 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/faddp-concat-1.c > @@ -0,0 +1,64 @@ > +/* { dg-do compile } */ > +/* { dg-final { check-function-bodies "**" "" } } */ > +/* { dg-options "-O2" } */ > + > +#include <arm_neon.h> > + > +/* > +** pair_f32: { target aarch64_little_endian } > +** faddp\tv0\.2s, v0\.2s, v1\.2s > +** ret > +*/ > +/* > +** pair_f32: { target aarch64_big_endian } > +** faddp\tv0\.2s, v1\.2s, v0\.2s > +** ret > +*/ > +__attribute__ ((noipa)) float32x2_t > +pair_f32 (float32x2_t a, float32x2_t b) > +{ > + return (float32x2_t) { vaddv_f32 (a), vaddv_f32 (b) }; > +} > + > +/* > +** pair_f64: { target aarch64_little_endian } > +** faddp\tv0\.2d, v0\.2d, v1\.2d > +** ret > +*/ > +/* > +** pair_f64: { target aarch64_big_endian } > +** faddp\tv0\.2d, v1\.2d, v0\.2d > +** ret > +*/ > +__attribute__ ((noipa)) float64x2_t > +pair_f64 (float64x2_t a, float64x2_t b) > +{ > + return (float64x2_t) { vaddvq_f64 (a), vaddvq_f64 (b) }; > +} > + > +/* > +** pair_mixed: { target aarch64_little_endian } > +** faddp\tv0\.2s, v0\.2s, v1\.2s > +** ret > +*/ > +/* > +** pair_mixed: { target aarch64_big_endian } > +** faddp\tv0\.2s, v1\.2s, v0\.2s > +** ret > +*/ > +__attribute__ ((noipa)) float32x2_t > +pair_mixed (float32x2_t a, float32x2_t b) > +{ > + return (float32x2_t) { vaddv_f32 (a), b[0] + b[1] }; > +} > + > +/* > +** sum_lanes: > +** faddp\ts0, v0\.2s > +** ret > +*/ > +__attribute__ ((noipa)) float32_t > +sum_lanes (float32x2_t a) > +{ > + return a[0] + a[1]; > +} > diff --git a/gcc/testsuite/gcc.target/aarch64/faddp-concat-3.c > b/gcc/testsuite/gcc.target/aarch64/faddp-concat-3.c > new file mode 100644 > index 00000000000..3fcaa9f0935 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/faddp-concat-3.c > @@ -0,0 +1,25 @@ > +/* { dg-do compile } */ > +/* { dg-final { check-function-bodies "**" "" } } */ > +/* { dg-options "-O2" } */ > + > +#include <arm_neon.h> > + > +/* > +** shared_reductions: > +** faddp\ts[0-9]+, v[0-9]+\.2s > +** faddp\ts[0-9]+, v[0-9]+\.2s > +** (?:str|zip1|ins)\t[^\n]+ > +** (?:str|zip1|ins)\t[^\n]+ > +** (?:str|zip1|ins)\t[^\n]+ > +** ret > +*/ > +float32x2_t > +shared_reductions (float32x2_t a, float32x2_t b, > + volatile float *p, volatile float *q) > +{ > + float x = vaddv_f32 (a); > + float y = vaddv_f32 (b); > + *p = x; > + *q = y; > + return (float32x2_t) { x, y }; > +} > diff --git a/gcc/testsuite/gcc.target/aarch64/faddp-concat-be.c > b/gcc/testsuite/gcc.target/aarch64/faddp-concat-be.c > new file mode 100644 > index 00000000000..84b7a08fbd1 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/faddp-concat-be.c > @@ -0,0 +1,51 @@ > +/* { dg-do compile } */ > +/* { dg-require-effective-target aarch64_mbig_endian } */ > +/* Avoid a dependence on big-endian C library headers. */ > +/* { dg-options "-O2 -mbig-endian -ffreestanding" } */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > +#include <arm_neon.h> > + > +/* > +** pair_f32: > +** faddp\tv0\.2s, v1\.2s, v0\.2s > +** ret > +*/ > +float32x2_t > +pair_f32 (float32x2_t a, float32x2_t b) > +{ > + return (float32x2_t) { vaddv_f32 (a), vaddv_f32 (b) }; > +} > + > +/* > +** pair_f64: > +** faddp\tv0\.2d, v1\.2d, v0\.2d > +** ret > +*/ > +float64x2_t > +pair_f64 (float64x2_t a, float64x2_t b) > +{ > + return (float64x2_t) { vaddvq_f64 (a), vaddvq_f64 (b) }; > +} > + > +/* > +** pair_mixed: > +** faddp\tv0\.2s, v1\.2s, v0\.2s > +** ret > +*/ > +float32x2_t > +pair_mixed (float32x2_t a, float32x2_t b) > +{ > + return (float32x2_t) { vaddv_f32 (a), b[0] + b[1] }; > +} > + > +/* > +** sum_lanes: > +** faddp\ts0, v0\.2s > +** ret > +*/ > +float32_t > +sum_lanes (float32x2_t a) > +{ > + return a[0] + a[1]; > +} > diff --git a/gcc/testsuite/gcc.target/aarch64/simd/faddp_lane_1.c > b/gcc/testsuite/gcc.target/aarch64/simd/faddp_lane_1.c > new file mode 100644 > index 00000000000..5ae2231697f > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/simd/faddp_lane_1.c > @@ -0,0 +1,76 @@ > +/* { dg-do run } */ > +/* { dg-options "-O2" } */ > + > +#include <arm_neon.h> > + > +__attribute__ ((noipa)) float32_t > +lane0_q (float32x4_t a, float32x4_t b) > +{ > + return vgetq_lane_f32 (vpaddq_f32 (a, b), 0); > +} > + > +__attribute__ ((noipa)) float32_t > +lane3_q (float32x4_t a, float32x4_t b) > +{ > + return vgetq_lane_f32 (vpaddq_f32 (a, b), 3); > +} > + > +__attribute__ ((noipa)) float32x2_t > +low_q (float32x4_t a, float32x4_t b) > +{ > + return vget_low_f32 (vpaddq_f32 (a, b)); > +} > + > +__attribute__ ((noipa)) float32_t > +lane1_d (float32x2_t a, float32x2_t b) > +{ > + return vget_lane_f32 (vpadd_f32 (a, b), 1); > +} > + > +__attribute__ ((noipa)) float64_t > +lane0_q64 (float64x2_t a, float64x2_t b) > +{ > + return vgetq_lane_f64 (vpaddq_f64 (a, b), 0); > +} > + > +__attribute__ ((noipa)) float32x4_t > +const_q (void) > +{ > + float32_t a[] = { 1, 2, 4, 8 }; > + float32_t b[] = { 16, 32, 64, 128 }; > + return vpaddq_f32 (vld1q_f32 (a), vld1q_f32 (b)); > +} > + > +__attribute__ ((noipa)) float32_t > +sum_d (float32x2_t a) > +{ > + return vaddv_f32 (a); > +} > + > +int > +main (void) > +{ > + float32_t a32[] = { 1, 2, 4, 8 }; > + float32_t b32[] = { 16, 32, 64, 128 }; > + float64_t a64[] = { 1, 2 }; > + float64_t b64[] = { 4, 8 }; > + float32x4_t a = vld1q_f32 (a32); > + float32x4_t b = vld1q_f32 (b32); > + float32_t res[4]; > + > + if (lane0_q (a, b) != 3 || lane3_q (a, b) != 192) > + __builtin_abort (); > + vst1_f32 (res, low_q (a, b)); > + if (res[0] != 3 || res[1] != 12) > + __builtin_abort (); > + if (lane1_d (vld1_f32 (a32), vld1_f32 (b32)) != 48) > + __builtin_abort (); > + if (lane0_q64 (vld1q_f64 (a64), vld1q_f64 (b64)) != 3) > + __builtin_abort (); > + vst1q_f32 (res, const_q ()); > + if (res[0] != 3 || res[1] != 12 || res[2] != 48 || res[3] != 192) > + __builtin_abort (); > + if (sum_d (vld1_f32 (b32)) != 48) > + __builtin_abort (); > + return 0; > +} > diff --git a/gcc/testsuite/gcc.target/aarch64/simd/faddp_lane_2.c > b/gcc/testsuite/gcc.target/aarch64/simd/faddp_lane_2.c > new file mode 100644 > index 00000000000..1c29c94c2d0 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/simd/faddp_lane_2.c > @@ -0,0 +1,53 @@ > +/* { dg-do compile } */ > +/* { dg-require-effective-target aarch64_mbig_endian } */ > +/* Avoid a dependence on big-endian C library headers. */ > +/* { dg-options "-O2 -mbig-endian -ffreestanding" } */ > +/* { dg-final { check-function-bodies "**" "" "" } } */ > + > +#include <arm_neon.h> > + > +/* The architectural lanes of the low half depend only on A. */ > + > +/* > +** lane0_q: > +** faddp v0\.4s, v0\.4s, v0\.4s > +** ret > +*/ > +float32_t > +lane0_q (float32x4_t a, float32x4_t b) > +{ > + return vgetq_lane_f32 (vpaddq_f32 (a, b), 0); > +} > + > +/* > +** low_q: > +** faddp v0\.4s, v0\.4s, v0\.4s > +** ret > +*/ > +float32x2_t > +low_q (float32x4_t a, float32x4_t b) > +{ > + return vget_low_f32 (vpaddq_f32 (a, b)); > +} > + > +/* > +** full_d: > +** faddp v0\.2s, v0\.2s, v1\.2s > +** ret > +*/ > +float32x2_t > +full_d (float32x2_t a, float32x2_t b) > +{ > + return vpadd_f32 (a, b); > +} > + > +/* > +** full_q64: > +** faddp v0\.2d, v0\.2d, v1\.2d > +** ret > +*/ > +float64x2_t > +full_q64 (float64x2_t a, float64x2_t b) > +{ > + return vpaddq_f64 (a, b); > +} > diff --git a/gcc/testsuite/gcc.target/aarch64/simd/faddp_reinterpret_1.c > b/gcc/testsuite/gcc.target/aarch64/simd/faddp_reinterpret_1.c > new file mode 100644 > index 00000000000..1422706591d > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/simd/faddp_reinterpret_1.c > @@ -0,0 +1,51 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2" } */ > +/* { dg-final { check-function-bodies "**" "" "" } } */ > + > +#include <arm_neon.h> > + > +/* The FADDP inputs are subregs of vectors with a different element mode. */ > + > +/* > +** sum_f32: > +** faddp s0, v0\.2s > +** ret > +*/ > +float32_t > +sum_f32 (int32x2_t x) > +{ > + return vaddv_f32 (vreinterpret_f32_s32 (x)); > +} > + > +/* > +** sum_f64: > +** faddp d0, v0\.2d > +** ret > +*/ > +float64_t > +sum_f64 (int64x2_t x) > +{ > + return vaddvq_f64 (vreinterpretq_f64_s64 (x)); > +} > + > +/* > +** pair_f32: > +** faddp v0\.2s, v0\.2s, v1\.2s > +** ret > +*/ > +float32x2_t > +pair_f32 (int32x2_t x, int32x2_t y) > +{ > + return vpadd_f32 (vreinterpret_f32_s32 (x), vreinterpret_f32_s32 (y)); > +} > + > +/* > +** pair_f64: > +** faddp v0\.2d, v0\.2d, v1\.2d > +** ret > +*/ > +float64x2_t > +pair_f64 (int64x2_t x, int64x2_t y) > +{ > + return vpaddq_f64 (vreinterpretq_f64_s64 (x), vreinterpretq_f64_s64 (y)); > +} > -- > 2.50.1 (Apple Git-155) >
