[gcc(refs/vendors/vrull/heads/slp-improvements)] aarch64: expand VEC_PERM into ins + uzp[12]

Andrew Pinski pinskia@gmail.com
Tue Jan 23 23:50:44 GMT 2024


On Tue, Jan 23, 2024 at 12:57 PM Philipp Tomsich via Gcc-cvs
<gcc-cvs@gcc.gnu.org> wrote:
>
> https://gcc.gnu.org/g:d61be742513b5b8529ab9ef4022011c471925622
>
> commit d61be742513b5b8529ab9ef4022011c471925622
> Author: Manolis Tsamis <manolis.tsamis@vrull.eu>
> Date:   Fri Nov 3 14:36:34 2023 +0100
>
>     aarch64: expand VEC_PERM into ins + uzp[12]
>
>     The AArch64 backend has specific strategies that can be used to expand
>     VEC_PERM expression (see aarch64_expand_vec_perm_const_1).
>
>     The last strategy applied if everything else fails is to use a tbl
>     instruction, which is known to have very bad latency and performance
>     (see aarch64_evpc_tbl). There are various improvements and additions
>     that can be done to the reduce the harmful tbl instructions.

Actually NOT all cores a very bad performance with TBL. This
definitely needs to be tunable.

Thanks,
Andrew

>
>     The existing mechanisms work for cases that the permute can be done
>     with a single existing AArch64 vector instruction, but for x264's
>     first loop we need some patterns that may need two vector
>     instructions.
>
>     On x264, this change results in the following change in instruction
>     distribution:
>             tbl: 8 -> 0
>             ldr: 10 -> 8 (due to the eliminated tbls)
>             ins: 8 -> 16
>             uzp: 8 -> 16
>     A reduction of the newly introduced ins/uzp[12] sequences will be
>     addressed in a follow-on change.
>
>     Ref #344
>
> Diff:
> ---
>  gcc/config/aarch64/aarch64.cc | 76 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 76 insertions(+)
>
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index e6bd3fd0bb4..0f2423ef7de 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -25890,6 +25890,80 @@ aarch64_evpc_ins (struct expand_vec_perm_d *d)
>    return true;
>  }
>
> +/* Recognize patterns suitable for the an INS + UZP.
> +   This addresses limited permute optimizations before a more generic search
> +   algorithm for two operator sequences is implemented.  */
> +static bool
> +aarch64_evpc_ins_uzp (struct expand_vec_perm_d *d)
> +{
> +  machine_mode mode = d->vmode;
> +
> +  if (d->vec_flags != VEC_ADVSIMD || BYTES_BIG_ENDIAN)
> +    return false;
> +
> +  unsigned HOST_WIDE_INT nelt = d->perm.length ().to_constant ();
> +
> +  if (nelt != 4
> +      || !d->perm[0].is_constant()
> +      || !d->perm[1].is_constant()
> +      || !d->perm.series_p (0, 2, d->perm[0], 0)
> +      || !d->perm.series_p (1, 2, d->perm[1], 0))
> +    return false;
> +
> +  /* We have a {A, B, A, B} permutation.  */
> +  HOST_WIDE_INT A = d->perm[0].to_constant ();
> +  HOST_WIDE_INT B = d->perm[1].to_constant ();
> +
> +  if (A >= nelt || B < nelt || d->op0 == d->op1)
> +    return false;
> +
> +  rtx insv;
> +  rtx extractv;
> +  HOST_WIDE_INT idx, extractindex;
> +
> +  /* If A is the first element or B is the second element of a UZP1/2 then we
> +     can emit this permute as INS + UZP .  */
> +  if (A == 0 || A == 1)
> +    {
> +      insv = d->op0;
> +      extractv = d->op1;
> +      idx = A == 0 ? 2 : 3;
> +      extractindex = B;
> +    }
> +  else if (B == nelt + 2 || B == nelt + 3)
> +    {
> +      insv = d->op1;
> +      extractv = d->op0;
> +      idx = B == nelt + 2 ? 0 : 1;
> +      extractindex = A;
> +    }
> +  else
> +    return false;
> +
> +  if (d->testing_p)
> +    return true;
> +
> +  if (extractindex >= nelt)
> +    extractindex -= nelt;
> +  gcc_assert (extractindex < nelt);
> +
> +  /* Emit INS.  */
> +  insn_code icode = code_for_aarch64_simd_vec_copy_lane (mode);
> +  expand_operand ops[5];
> +  create_output_operand (&ops[0], d->target, mode);
> +  create_input_operand (&ops[1], insv, mode);
> +  create_integer_operand (&ops[2], 1 << idx);
> +  create_input_operand (&ops[3], extractv, mode);
> +  create_integer_operand (&ops[4], extractindex);
> +  expand_insn (icode, 5, ops);
> +
> +  /* Emit UZP.  */
> +  emit_set_insn (d->target, gen_rtx_UNSPEC (mode, gen_rtvec (2, d->target, d->target),
> +                                     idx & 1 ? UNSPEC_UZP2 : UNSPEC_UZP1));
> +
> +  return true;
> +}
> +
>  static bool
>  aarch64_expand_vec_perm_const_1 (struct expand_vec_perm_d *d)
>  {
> @@ -25931,6 +26005,8 @@ aarch64_expand_vec_perm_const_1 (struct expand_vec_perm_d *d)
>             return true;
>           else if (aarch64_evpc_ins (d))
>             return true;
> +         else if (aarch64_evpc_ins_uzp (d))
> +           return true;
>           else if (aarch64_evpc_reencode (d))
>             return true;


More information about the Gcc-cvs mailing list