https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128303

            Bug ID: 128303
           Summary: [MVE] 16 -> 32-bit widening reductions (dot product,
                    widening sum) not vectorized for Cortex-M55
           Product: gcc
           Version: 16.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: aleksandr.o.makarov at gmail dot com
  Target Milestone: ---

Version: GCC 16.1.0, arm-none-eabi (Compiler Explorer)
Flags: -O3 -mcpu=cortex-m55 -mthumb -mfloat-abi=hard -mfpu=auto
-fopt-info-vec-all

Source code:
```
#include <stdint.h>

int32_t dot16(const int16_t *restrict x, const int16_t *restrict y, int n)
{
    int32_t acc = 0;
    for (int i = 0; i < n; i++)
        acc += (int32_t)x[i] * y[i];
    return acc;
}

int32_t sum16(const int16_t *restrict x, int n)
{
    int32_t acc = 0;
    for (int i = 0; i < n; i++)
        acc += x[i];
    return acc;
}

/* Control: same-width reduction, which is vectorized. */
int32_t dot32(const int32_t *restrict x, const int32_t *restrict y, int n)
{
    int32_t acc = 0;
    for (int i = 0; i < n; i++)
        acc += x[i] * y[i];
    return acc;
}
```

Observed: dot32 is vectorized (vldrw.32, vmul.i32, vadd.i32, vaddv.s32). dot16
and sum16 stay scalar:


dot16:  ldrh / ldrh / smlabb / le        (one element per iteration)
sum16:  ldrsh / add / le


The vectorizer tries V8HI and V8QI and gives up:

missed: couldn't vectorize loop
missed: unsupported SLP instances
note: ***** Analysis failed with vector mode V8HI
note: ***** Analysis failed with vector mode V8QI

Making the trip count a constant (64) doesn't change the result.

Expected: MVE has single-instruction widening reductions: VMLADAVA.S16
(multiply-accumulate across vector into a 32-bit scalar) and VADDVA.S16. Clang
(trunk, --target=thumbv8.1m.main-none-eabi -mcpu=cortex-m55 -O3) compiles dot16
to:

dlstp.16  lr, r2
vldrh.u16 q0, [r0], #16
vldrh.u16 q1, [r1], #16
vmlava.s16 r12, q0, q1
letp      lr, ...

This looks like the MVE backend is missing the sdot_prod / widen_ssum (or
equivalent reduction) patterns for V8HI→SI, possibly V16QI too. LLVM needed the
equivalent i8/i16 VMLAV patterns.

Impact: 16-bit fixed-point DSP code (audio codecs such as libopus: pitch
correlation, inner products, LPC filters) gets no MVE benefit from GCC on
Cortex-M55/M85.

Minor, related: even for dot32, GCC emits dls/le plus a scalar epilogue instead
of a tail-predicated dlstp/letp loop.
  • [Bug c/128303] New: [MVE... aleksandr.o.makarov at gmail dot com via Gcc-bugs

Reply via email to