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

            Bug ID: 127946
           Summary: Missing destination-dependency breaking for an
                    all-ones-masked AVX-512 gather in a loop
           Product: gcc
           Version: 16.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: z00823823 at outlook dot com
  Target Milestone: ---

```
#include <immintrin.h>
#include <cstddef>

extern "C" __attribute__((noinline))
void gather_polynomial(const double* __restrict table,
                       const long long* __restrict indices,
                       double* __restrict output, std::size_t count) {
    const __m512d a = _mm512_set1_pd(0.123);
    const __m512d b = _mm512_set1_pd(0.456);
    for (std::size_t i = 0; i < count; i += 8) {
        const __m512i index = _mm512_loadu_si512(indices + i);
        __m512d result = _mm512_i64gather_pd(index, table, 8);
        for (int j = 0; j < 8; ++j)
            result = _mm512_fmadd_pd(result, a, b);
        _mm512_storeu_pd(output + i, result);
    }
}
```

online version: https://godbolt.org/z/efE45aha1

compile with -O2 -march=tigerlake

```
.L4:
        vmovdqu64       zmm3, ZMMWORD PTR [rsi+rdx*8]
        kxnorb  k2, k2, k2
        mov     eax, 8
        vgatherqpd      zmm0{k2}, [rdi+zmm3*8]
.L3:
        vfmadd132pd     zmm0, zmm1, zmm2
        vfmadd132pd     zmm0, zmm1, zmm2
        sub     eax, 2
        jne     .L3
        vmovupd ZMMWORD PTR [r8+rdx*8], zmm0
        add     rdx, 8
        cmp     rdx, rcx
        jb      .L4
```

This example gather data then use result to do FMA, then write to result. GCC
reuse the gather destination register zmm0 between loops, but the 

`vgatherqpd      zmm0{k2}, [rdi+zmm3*8]`

actually cause a dependent on the zmm0 of previous iteraion: CPU do not take
advantage of the fact that k2 is all true, assume some lanes might use data
from previous iter's zmm0, and create an implicit dependent, prevents register
rename and ILP. there is a related discussion in llvm:
https://groups.google.com/g/llvm-dev/c/KiydZ5id0UI?pli=1

clang fixed this problem by zero out gather destination before gather:

```
        vxorpd  xmm3, xmm3, xmm3
        vgatherqpd      zmm3 {k1}, qword ptr [rdi + 8*zmm2]
```

Reply via email to