Xi Ruoyao <[email protected]> writes:

Hi Ruoyao:

> A hot loop in SPEC 2026 stockfish_r calculates the dot product of a
> sign-extended vector and a zero-extended vector.  Add the corresponding
> usdot_prod pattern to use the instructions with such a semantic, for
> example xvmulwev.h.bu.b, to optimize the loop.
>
>       PR target/125474
>
> gcc/
>
>       * config/loongarch/simd.md (usdot_prod<wvec_half><mode>): New
>       define_expand.
>       (usdot_prod<wvec_quarter><mode>): New define_expand.

LGTM.

> gcc/testsuite/
>
>       * g++.target/loongarch/pr125474.C: New test.

Plase move this test case to gcc.target/loongarch/vector/lasx directory and 
rename it to lasx-dot-prod.C. You can put the PR number in the comments.

Thanks.


> ---
>
> Bootstrapped and regtested on loongarch64-linux-gnu.  Ok for trunk?
>
>  gcc/config/loongarch/simd.md                  | 54 +++++++++++++++
>  gcc/testsuite/g++.target/loongarch/pr125474.C | 68 +++++++++++++++++++
>  2 files changed, 122 insertions(+)
>  create mode 100644 gcc/testsuite/g++.target/loongarch/pr125474.C
>
> diff --git a/gcc/config/loongarch/simd.md b/gcc/config/loongarch/simd.md
> index 3d1e3e7a787..c4ca3cf2480 100644
> --- a/gcc/config/loongarch/simd.md
> +++ b/gcc/config/loongarch/simd.md
> @@ -934,6 +934,60 @@ (define_expand 
> "<simd_isa>_<x>vmaddw<ev_od>_<simdfmt_w>_<simdfmt>u_<simdfmt>"
>    DONE;
>  })
>  
> +(define_expand "usdot_prod<wvec_half><mode>"
> +  [(match_operand:<WVEC_HALF> 0 "register_operand")
> +   (match_operand:IVEC             1 "register_operand")
> +   (match_operand:IVEC             2 "register_operand")
> +   (match_operand:<WVEC_HALF> 3 "reg_or_0_operand")]
> +  ""
> +{
> +  rtx *op = operands;
> +
> +  if (op[3] == CONST0_RTX (<WVEC_HALF>mode))
> +    emit_insn (
> +      gen_<simd_isa>_<x>vmulwev_<simdfmt_w>_<simdfmt>u_<simdfmt> (
> +     op[0], op[1], op[2]));
> +  else
> +    emit_insn (
> +      gen_<simd_isa>_<x>vmaddwev_<simdfmt_w>_<simdfmt>u_<simdfmt> (
> +     op[0], op[3], op[1], op[2]));
> +
> +  emit_insn (
> +    gen_<simd_isa>_<x>vmaddwod_<simdfmt_w>_<simdfmt>u_<simdfmt> (
> +      op[0], op[0], op[1], op[2]));
> +  DONE;
> +})
> +
> +(define_expand "usdot_prod<wvec_quarter><mode>"
> +  [(match_operand:<WVEC_QUARTER> 0 "register_operand")
> +   (match_operand:IVEC_HB        1 "register_operand")
> +   (match_operand:IVEC_HB        2 "register_operand")
> +   (match_operand:<WVEC_QUARTER> 3 "reg_or_0_operand")]
> +  ""
> +{
> +  rtx *op = operands;
> +  rtx res_mulev = gen_reg_rtx (<WVEC_HALF>mode);
> +  rtx res_mulod = gen_reg_rtx (<WVEC_HALF>mode);
> +  rtx res_addev = gen_reg_rtx (<WVEC_QUARTER>mode);
> +  rtx res_addod = gen_reg_rtx (<WVEC_QUARTER>mode);
> +  emit_insn (gen_<simd_isa>_<x>vmulwev_<simdfmt_w>_<simdfmt>u_<simdfmt>
> +           (res_mulev, op[1], op[2]));
> +  emit_insn (gen_<simd_isa>_<x>vmulwod_<simdfmt_w>_<simdfmt>u_<simdfmt>
> +           (res_mulod, op[1], op[2]));
> +  emit_insn (gen_<simd_isa>_<x>vhaddw_<simdfmt_qw>_<simdfmt_w>
> +              (res_addev, res_mulev, res_mulev));
> +  emit_insn (gen_<simd_isa>_<x>vhaddw_<simdfmt_qw>_<simdfmt_w>
> +           (res_addod, res_mulod, res_mulod));
> +
> +  rtx sum = gen_rtx_PLUS (<WVEC_QUARTER>mode, res_addev, res_addod);
> +  if (op[3] == CONST0_RTX (<WVEC_QUARTER>mode))
> +    emit_move_insn (op[0], sum);
> +  else
> +    emit_insn (gen_add<wvec_quarter>3 (
> +              op[0], force_reg (<WVEC_QUARTER>mode, sum), op[3]));
> +  DONE;
> +})
> +
>  ; For "historical" reason we need a punned version of q_d variants.
>  (define_mode_iterator DIVEC [(V2DI "ISA_HAS_LSX") (V4DI "ISA_HAS_LASX")])
>  
> diff --git a/gcc/testsuite/g++.target/loongarch/pr125474.C 
> b/gcc/testsuite/g++.target/loongarch/pr125474.C
> new file mode 100644
> index 00000000000..ac14a72ff70
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/loongarch/pr125474.C
> @@ -0,0 +1,68 @@
> +/* { dg-do compile } */
> +/* { dg-do-if run { target { loongarch_asx_hw } } } */
> +/* { dg-options "-O3 -mlasx -fno-unroll-loops -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump-times "DOT_PROD_EXPR" 1 "optimized" } } */
> +
> +namespace std {
> +  using uint32_t = unsigned int;
> +  using int32_t = int;
> +  using uint8_t = unsigned char;
> +  using int8_t = char;
> +}
> +
> +using IndexType = std::uint32_t;
> +
> +[[gnu::noipa]]
> +void transform(std::int32_t *__restrict__ output, const std::int8_t *weights,
> +               const std::int32_t *biases, const std::uint8_t *input) {
> +  for (IndexType i = 0; i < 0x10; ++i) {
> +    const IndexType offset = i * 0x1000;
> +
> +    std::int32_t sum = biases[i];
> +    for (IndexType j = 0; j < 0x1000; ++j) {
> +      sum += weights[offset + j] * input[j];
> +    }
> +    output[i] = sum;
> +  }
> +}
> +
> +[[gnu::noipa]]
> +void transform_novec(std::int32_t *__restrict__ output,
> +                     const std::int8_t *weights,
> +                     const std::int32_t *biases,
> +                     const std::uint8_t *input) {
> +#pragma GCC novector
> +  for (IndexType i = 0; i < 0x10; ++i) {
> +    const IndexType offset = i * 0x1000;
> +
> +    std::int32_t sum = biases[i];
> +#pragma GCC novector
> +    for (IndexType j = 0; j < 0x1000; ++j) {
> +      sum += weights[offset + j] * input[j];
> +    }
> +    output[i] = sum;
> +  }
> +}
> +
> +std::int8_t w[0x11000];
> +std::uint8_t in[0x1000];
> +std::int32_t out[0x10];
> +std::int32_t out_novec[0x10];
> +std::int32_t b[0x10];
> +
> +int
> +main ()
> +{
> +  for (unsigned i = 0; i < 0x11000; i++)
> +    w[i] = (std::int8_t)(std::uint8_t)(i * i + 113 * i + 47);
> +  for (unsigned i = 0x11000; i < 0x12000; i++)
> +    in[i - 0x11000] = (std::uint8_t)(i * i + 113 * i + 47);
> +  for (int i = 0; i < 0x10; i++)
> +    b[i] = i;
> +
> +  transform (out, w, b, in);
> +  transform_novec (out_novec, w, b, in);
> +
> +  if (__builtin_memcmp (out, out_novec, sizeof (out)))
> +    __builtin_trap ();
> +}

Reply via email to