<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/87640>87640</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [clang] Poor performance because gather and scatter operations are emitted by the compiler targeting AVX512 or at level 3 of optimization 
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          wolfpld
      </td>
    </tr>
</table>

<pre>
    Using `-march=native` and/or `-O3` compilation flags can result in a significantly (more that x2) slower executable.

The code I am seeing problems with is https://github.com/wolfpld/etcpak, specifically https://github.com/wolfpld/etcpak/blob/master/bcdec.h.

Reproducing the results is a bit involved and requires a specific image file I cannot share, but any other image will suffice, provided it is large enough to produce long enough computation times. It may be necessary to use an image with an alpha channel, as different encoding modes (and code paths) are used when alpha is present.

To build the program and get the results, you need to do the following:

```sh
% meson setup build --buildtype=release
% cd build
% ninja
# any reasonably large image file will do instead of 16k.png, this only needs to be done once to get 16k.dds
% ./etcpak -c bc7 -h dds ~/16k.png 16k.dds
% ./etcpak -v -b 16k.dds 
Median decode time for 9 runs: 3483.195 ms (77.066 Mpx/s)
```

The 77 Mpx/s result is a measure of performance. The meson setup command configured the compiler to use `-O3` and `-march=native`. I am running on i7-1185G7, which supports AVX512.

Building the program with `meson setup build --buildtype=release --optimization=2`, which lowers the optimization level to `-O2` results in 2274.264 ms (118.032 Mpx/s), which is not what you would normally expect from lowering the optimization level.

Similarly, changing the `-march=native` parameter to `-march=skylake` (which requires modifying the `meson.build` file) results in 2776.365 ms (96.686 Mpx/s). The Skylake ISA doesn't support AVX512.

Interestingly, building with both `-march=skylake` and `-O2` results in 1693.646 ms (158.496 Mpx/s). This is twice the speed of `-march=native` + `-O3` build.

The behavior is also reproducible on Ryzen 7950X (Zen4, another AVX512-enabled uarch), where `-march=native` + `-O3` results in 170 Mpx/s and `-march=skylake` + `O3` results in 190 Mpx/s.

---

In the case of `-march=native` + `-O3`, the first problematic place in the code is lines 1171-1173. The compiler emits a lot of gather + scatter instructions that are microcoded and have big latency.

![obraz](https://github.com/llvm/llvm-project/assets/600573/854923d9-3dd0-4b7c-b98e-6dc2dc928989)

Here are example measurements for one of the gather instructions:

![obraz](https://github.com/llvm/llvm-project/assets/600573/ee82f8ed-3759-4cb4-912d-476aff9bf58b)

Another problematic place is at line 1225, where a series of gather operations is emitted (four gathers are emitted, but I only show one here).

![obraz](https://github.com/llvm/llvm-project/assets/600573/ee8ff4c5-f6ea-4cd1-8214-1b7c0dd2c799)

---

With `-march=native` and `-O2`, the first place mentioned above still emits gathers and scatters, and takes a larger percentage of the runtime.

![obraz](https://github.com/llvm/llvm-project/assets/600573/47a54eee-dd54-4f6f-b730-e46451933981)

The second code fragment is now emitted as a series of scalar operations, which causes it to practically disappear from the list of hot spots.

![obraz](https://github.com/llvm/llvm-project/assets/600573/43311f16-b8fb-4c46-96bd-d07b519ce6de)

---

The `-march=skylake` + `-O3` configuration produces a number of AVX2 operations (since AVX512 is not supported by Skylake) that have virtually no impact on execution speed.

![obraz](https://github.com/llvm/llvm-project/assets/600573/fbe79deb-1036-46b0-8675-8d7e2d03e9b6)

The second location dominates again due to a series of gather operations (oops, AVX2 has gathers and scatters too!).

![obraz](https://github.com/llvm/llvm-project/assets/600573/4af5a056-953a-4be8-9855-dbecd0667018)

This gather instruction is again heavily microcoded and has high latency.

![obraz](https://github.com/llvm/llvm-project/assets/600573/a3196ca5-948e-4c4d-98af-d66709cee2db)

---

With `-march=skylake` and `-O2`, gather operations are no longer emitted, moving hotspots in the code to scalar computation elsewhere in the code as expected.

---

Checked with clang version 17.0.6. I have also observed similar behavior with clang version 19.0.0git (https://github.com/llvm/llvm-project.git 35886dc63a2d024e20c10d2e1cb3f5fa5d9f72cc).
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy8WE2T47YR_TWcSxdZJPh9mMOupybZgysp20lcuYFAU4QXBBgA1Kx8yG9PNShqJM14Yx_WVVOjkoiP7tevX3eTe68OBvExqT8m9dMDX8Nk3eOL1eOi5cNg5enxH16ZAyRNns7ciSkpnwwP6ohJkwM3MmHP1sXHfyvpJ2HnRWkelDUwan7wILgBh37VAZQBDnSlGpXgJugTJKybrUMIEw_whSWsB6_tCzrALyjWwAeNWZI_JfmH7f9PE4KwEuET8Bk8Ipm3ODtonD28qDCB8jCFsPik_JCw54Q9H1SY1iETdk7Y89m7hD1jEAv_nLDvwC8ook1an_7Y3udB2yFhzzP3AR19FxJFNt3Y_AMuzspVkKlhwjMcngzlMCgC5mj1ESUhCg7_syqH9Gy3C9TMDwij0uS34MbYAH7iDsn6YQ3AzQlsmNCdl74orcGv46hEXLM4e1QSJdBtHjR3BwQ0dj1MECxs9iFoaw77zxTKNWyhDGpGn8GnADM_wYBgUKD33J1o9-oRuLncHCb6xvUycRATNwY1mcA9SDWO6NAEQCOsJDxmK9ETDcj1GNiFh8kTEbhDOlrCy4T7ecrD4tCjCbessDCsSssI7-LswfE5gnnAcA052XGyKxhESZZLG5-OVmv7osyBwn51bNLk25-fzj-wGmb01oDHsC7nS9M0fobTgkn55FAj9_i6Qcht3esvRplf-P61jMFzyL01fNCnc3CuQh6DKS0o4wNyCXaEovmcLeZA_oRJebBGn6JXntwaEKQ1CNYIpO-EAu2Q0r8akV1oDKmAQbSQTiClh_8m7Pl8_td3HSEd9hWwLfkepeIGJMZQEm1gtA56cKuhpIKy6sqs6GuYY9TbNsubBr5fviTsmaJ-B_x96rftvvYiKpQoM3K_OiRkFnSjdTM3AjOgLdfxEnaeN6KZUR1WhxtjNtVCt5P5Vc9o8bvil20C5FZjiMbWgGrToujqv7QUlJdJiQn8uizWBQ8f_vlzXbAbyn4kSuyKsFM2Jk_S5L-TY5CmdglqVr_GNE3KJ0aYXe6PSurjDdfrQOMRNTkbHaU9r5pkgLG2ylhTnUNUFF2Wl-w6RpcLlAeSohdSb8qrF7tqCYbwJynFLwuKAKOz82bL7u9ba26w-VHNSnOnT3QTSchh3_h-IVq44zOGLYDXS_znk-af45qEdZvNF32drVTj6erkiHq25WqTx9wjHbqGpm2brGx29vZN1nTX7N0Y9-N2K3z68QNIi94krA07Gd7jwicT0KEPyhw2n4edHJEQg91Y8Z5bO0HfRLFo-jJrqmaPYt1lVX9vq4pFKLwo0okJqeBg1Jf3cU7Yx6vciEa-Kc4DTvyorIuJqb0Ft1e_QZMiwQ-nX9FA29f5z2TYv9FUsTyYrX5t8KRIWogS1mjEzjl0v0WBW9OucWjzi2TcZ_MNPeL-t9v7y_YbV9M0vY3gJiSUlL8Pvk26SeGdD3sHw4MSsGgukO4Oe69DFVsZ9FAUbZEWRVtuRLvoFs4qkA5qG-j6A49Q0n1e8ECJQbXDrYISzm_dFpXXWQln6Yqt9Zj4EWFQB9A8oBGnG48TViT1Rzs4_mtSPyWs-0qjpPVx_0gXZ39BERL2zL1HqsHPTZ7XbZmw566uelbKPi2lzNNqaEU69B2mjRRMip51fde_FoX4_6_EAbIdv_B50bhr_4wm-FhsYuUbI3pnIK6dvy_x38ArxI6NHcq0bOs-rcRQpX3BZFq1DR_Hfhjrbrjz6sOZ_e_wwAMPMfxQMFa_5gEHj06hvwq4XdDxLcTKR1IElJRko13deZHfwNue7e3jp62B8JN9ifDRBSQRfwJS41iJOh0b5GklZJF2rKjSYmhFLiUTbX8f_7vE-5e608ab8eRVGu_SLUJLlFHWEPkHe0TwgRqtLZcuYBm555DfZEpC4J9jex4bNUcdh0ATqF07086thlqfbw5f1fK6QsRUyrpKq7EZ06Et8xSrpqqLviz7rriDj2TDo7B7tz06fiActlL-ciEN9zcE84Jrfk2w1x5A8NWjp8EiDhJchPMgJZXny4LcbQ0AAaOVjwI10fyy2OC_PURlWRRj0aRDNw5pJaom7ZtBpjJvh7roBTYSv86wn-7ajrdF4zL7bk3l1tWcRyqC0azzQNk5UnFj11masM4ratK3qrf3U-dWASUMp72boE4k6nYU6aNyYY0oGwtqXrgIVFu3oZmuj5X8m6M7Dtj2Eoe0yMsmrZohT7umrdNOtshkXmI_NL9NQG3FhpW0szI8EFgHrgzINY4tX1e4hHXWLpGIEdaJv5-1EKwl3_8EOav4WPO8btK-LnlaDdilfVfXqRxQyLxp2rzo3sCh_DtlKsp-xGJCflT69LZUe5jUYfrTSjUvi74RvE77qkNKJJn2HR9TSW71ApHJ-6L2_6T6t9pYCunbeFPZMja-ojh3POcCNtsjtcqTDVFSbjqnYHfpun6dgdrjVkSv13J_HljuEufOje8mFJ9Rbq250Nwc4IjO07lFm-VZQ6NhTNLY_trBozuiBL8NNa8N8nsH9Fme5QcV4A8HLaNdZd11jRRNyZnMWYUsF0UuGRZiKMd65LXsx5YJQcnwIB9L2Zc9f8DHoi0Yq_K-7x6mR1nKToysHRqJTY29wJaXfSvavmnYgN2DemQ5q_Iqr4qK9XWX5axlfZuPrMG8q9smqXKcudIZGZhZd3hQ3q_42LVNlT9oPqD28aUjY9H_hLGkfnpwj9GhYT34pMqpVvjXE4IKOr6p3HbUT_B3a931uA8Dxlq0c-dKBO55tFe54XQ3_1NFpzFsF2TrYvcV5-WSdOhmcn1YnX78w7kVsaDcinD8LwAA___Mwdoz">