Xi Ruoyao <[email protected]> writes:

LGTM, please apply.

> On Thu, 2026-06-18 at 06:33 +0800, Xi Ruoyao wrote:
>> 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.
>> 
>> gcc/testsuite/
>> 
>>      * gcc.target/loongarch/vector/lasx/dot-prod-mixed-signedness.c:
>>      New test.
>> ---
>> 
>> Change from v1: rewrite the test in C and put it into
>> gcc.target/loongarch/vector/lasx.
>> 
>> Bootstrapped and regtested on loongarch64-linux-gnu.  Ok for trunk?
>
> Ping.
>
>> 
>>  gcc/config/loongarch/simd.md                  | 54 ++++++++++++++++
>>  .../vector/lasx/dot-prod-mixed-signedness.c   | 63 +++++++++++++++++++
>>  2 files changed, 117 insertions(+)
>>  create mode 100644 
>> gcc/testsuite/gcc.target/loongarch/vector/lasx/dot-prod-mixed-signedness.c
>> 
>> diff --git a/gcc/config/loongarch/simd.md b/gcc/config/loongarch/simd.md
>> index 377e94fb356..09e746c56e7 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/gcc.target/loongarch/vector/lasx/dot-prod-mixed-signedness.c 
>> b/gcc/testsuite/gcc.target/loongarch/vector/lasx/dot-prod-mixed-signedness.c
>> new file mode 100644
>> index 00000000000..d5f42ebdc96
>> --- /dev/null
>> +++ 
>> b/gcc/testsuite/gcc.target/loongarch/vector/lasx/dot-prod-mixed-signedness.c
>> @@ -0,0 +1,63 @@
>> +/* { dg-options "-O3 -mlasx -fno-unroll-loops -fdump-tree-optimized" } */
>> +/* { dg-final { scan-tree-dump-times "DOT_PROD_EXPR" 1 "optimized" } } */
>> +
>> +typedef unsigned int uint32_t;
>> +typedef int int32_t;
>> +typedef unsigned char uint8_t;
>> +typedef char int8_t;
>> +typedef uint32_t IndexType;
>> +
>> +[[gnu::noipa]]
>> +void transform(int32_t *__restrict__ output, const int8_t *weights,
>> +               const int32_t *biases, const uint8_t *input) {
>> +  for (IndexType i = 0; i < 0x10; ++i) {
>> +    const IndexType offset = i * 0x1000;
>> +
>> +    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(int32_t *__restrict__ output,
>> +                     const int8_t *weights,
>> +                     const int32_t *biases,
>> +                     const uint8_t *input) {
>> +#pragma GCC novector
>> +  for (IndexType i = 0; i < 0x10; ++i) {
>> +    const IndexType offset = i * 0x1000;
>> +
>> +    int32_t sum = biases[i];
>> +#pragma GCC novector
>> +    for (IndexType j = 0; j < 0x1000; ++j) {
>> +      sum += weights[offset + j] * input[j];
>> +    }
>> +    output[i] = sum;
>> +  }
>> +}
>> +
>> +int8_t w[0x11000];
>> +uint8_t in[0x1000];
>> +int32_t out[0x10];
>> +int32_t out_novec[0x10];
>> +int32_t b[0x10];
>> +
>> +int
>> +main ()
>> +{
>> +  for (unsigned i = 0; i < 0x11000; i++)
>> +    w[i] = (int8_t)(uint8_t)(i * i + 113 * i + 47);
>> +  for (unsigned i = 0x11000; i < 0x12000; i++)
>> +    in[i - 0x11000] = (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