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

    <tr>
        <th>Summary</th>
        <td>
            Missed optimization and unexpected compilation difference when using inlined function to cast int32_t to uint8_t
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

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

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

<pre>
    Hi,

I didn't know what would be good title for this issue. Basically what happens is that `uint8_t min = mpeg_min;` where `mpeg_min` is `int32_t` is ignored for vectorization unless it is done via `static inline` function call... which is fully inlined.

The issue is that version vectorized using `uint8_t` is significantly faster than the one using `int32_t` and I had to add dummy static inline function to make llvm produce better code. Which is unexpected, because for what it's worth, both version should compile to the same code. I tried `__builtin_assume` doesn't change anything, except initial cast. I assume that LLVM decided to ignore the variable range, even if explicitly narrowed and use `int32_t` version directly, which hinders performance.

If you look at IR, we can see:

That fast version is doing vectorization on i8
```
 %broadcast.splatinsert = insertelement <16 x i8> poison, i8 %conv, i64 0
```

While slow version is doing things on i32
``` LLVM
 %broadcast.splatinsert = insertelement <16 x i32> poison, i32 %mpeg_min, i64 0
```

This is just one line, take a look at full output.

Code here https://godbolt.org/z/aeG8zbE9x with diff and attached below.

Compiled with `clang -O3`. 

## Fast version
``` c
#include <stddef.h>
#include <stdint.h>

static inline int fast_impl(const uint8_t *data, ptrdiff_t stride,
                           ptrdiff_t width, ptrdiff_t height,
 uint8_t mpeg_min, uint8_t mpeg_max)
{
    while (height--) {
        uint8_t cond = 0;
        for (int x = 0; x < width; x++) {
            const uint8_t val = data[x];
            cond |= val < mpeg_min || val > mpeg_max;
        }
        if (cond)
            return 1;
        data += stride;
    }
    return 0;
}

int fast(const uint8_t *data, ptrdiff_t stride,
         ptrdiff_t width, ptrdiff_t height,
         int mpeg_min, int mpeg_max)
{
 __builtin_assume(mpeg_min >= 0 && mpeg_min <= UINT8_MAX);
 __builtin_assume(mpeg_max >= 0 && mpeg_max <= UINT8_MAX);
    return foo_impl(data, stride, width, height, mpeg_min, mpeg_max);
}
```

## Slow version
``` c
#include <stddef.h>
#include <stdint.h>

int slow(const uint8_t *data, ptrdiff_t stride, 
         ptrdiff_t width, ptrdiff_t height,
         int32_t mpeg_min, int32_t mpeg_max)
{
 __builtin_assume(mpeg_min >= 0 && mpeg_min <= UINT8_MAX);
 __builtin_assume(mpeg_max >= 0 && mpeg_max <= UINT8_MAX);
    uint8_t min = mpeg_min;
    uint8_t max = mpeg_max;
    while (height--) {
 uint8_t cond = 0;
        for (int x = 0; x < width; x++) {
 const uint8_t val = data[x];
            cond |= val < min || val > max;
 }
        if (cond)
            return 1;
        data += stride;
 }
    return 0;
}
```

Thanks,
Kacper
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzUV01z27AR_TXQZccaGjQp6aCDLFutp0k706ZNbxoIWImISYBDLCU5v76zIEV9JE4_khzK8YxFALvY9_ZhuVAh2J1DnIvsUWRPI9VS4Zv5qwo1NrN0tPHmbf5HK-RSJAuRLF7AWOOEnBC8On-AQ6EIDr4tDWwQdt4bIEslwtY3QIUNYENocQyPKlityvKtMylUXaPjWSB-F3nSWkfTNUFlHYj0Caoad-vKOpE-ijyBQ4EN8rphPE_YXOSJdZTKNfUDdud8gyZGsEdNvrFfFVnvoHUlhgCWeJnxDmFvFTsIpMhqsK60DtnNtnU6mnDI4_EYDoXVBZttW8bQrTTjjpRPBXYwBzh7bAKbn_ZHA22wbneBs4-W6bdbq5Wj8g22KhAyccoBFQgc42B4AVM5Ay9QKAPkQRkDpq2qN7jCcQZBHir1ilCW-wrqxptWI2yQeCvtDY7h8wle6_BYoyY0Qi5hg1q1oUtmTJslIScBDr6hIi7wVAxgQxF1oH1V2xJ5V4YQVIX9Li9AjUXDWNbrTWtLsm6tQmirSLrxGDpp6UK5HYJyb1RYt-Od8KixJrDOklUlaBWIHXbWHekfPvzjIxjU1mDkpRNCDGKvGqs2JULDjqO_PTqwW8BjXVptmXynmsYf0ER2GfY15yeYxjaoqXxjL50sCusMNgFqbLa-qZTT2CvjZQtvvoXS-1dQBC9_jUYIWjkIiCJdnBSkKCZ_2CUqlBN_LWGembJNnvR_yQKEzDaNVyaSEupSkXUBG4rHqPuJJVboeGR5n8ORnaTPUHsbvOOY7JS9aO_28S1_gORmF5EsPhec11D6w7dhxkSFGF8qL01jWv7XKFN5E2Yq2c9QAt6P9VNXe-BLGygeo3i05RKIT4IaUsLnGXxLdUt9zpbeIMRiUxDVgXMkV0Kudt5sfElj3-yEXH0VcqXwD9Ovm-fZEQ6WCjB2u43aUURKF8glsfSHwW08FqZbK_JEl8rt4O4vqciTMXSLhEyFTGF1oYQrLnW3xjpdtgaZp0DG4HZciPT5e3PW0TCXLK7rg3Wd5ta2qkshp9q7QHAqw0IujCLFlNXUMLY1QaDGGuy-BvD-czY4WNNVivNQgXZXUO9jKPoXGb0eU0chZxz-5LHf9BBlKOS083R3J-QMztP8nFxo70zUV8JfkfM8FzQhp8zAcZiPP5d9yPwq5GP8u_XOzzVZe1VGN5Gx7PEosqfrDXsTA2Ky5IWdwXLAHccny378-Yz9youYPF282S10WTMdQ5d7NUht4-D-2p7DA4aUPp1SOcyfffe2PWXduEgWJ7n8hFL-c10MGN21Ns7vN7r45oMip2du0-eYYxAyFzK_ID2Nyfj7y58_TdcfF_9kj-mP3anjO-7ixHvuzqxuvT-dtxNpA1VnVgYursBfAr_MzXXl62vI3y7K9K-sIZwB_gT8lzKAn9YBf4dvtXAx9v-mhx-1uzcr1PFixWVN-FEl_E0l8FfVve-UvAHZbytz_6bG3XYQyr2GTod_UrrGZmTmqZmlMzXC-f0ke8jSLM0mo2K-yVJlkgwneabv1WSWJNJgPstmUk_zaTId2blMZJZMk0kisyybjPMkzzZbneYP6eRhcn8vHhKslC3H3KNzizGKF4r5fSYf0mRUqg2WIV7SpHR46K4bQkq-szVzNrrbtLsgHpLSBgpnN_E2Nv9oQ0ADviZbnVrJ2OUO7X7ftndTfBKxQaeRr12uv4L0l56rewU3c8NBJH8SxqhtyvlN-2SpaDdj7SshVxxe_--ubvwX1CTkKoIKQq561Pu5_FcAAAD___I1fww">