How to perform uint32/float conversion with SSE?
c, simd, sse, x86
Solution
This functionality exists in AVX-512, but if you can't wait until then the only thing I can suggest is to convert the `unsigned int` input values into pairs of smaller values, convert these, and then add them together again, e.g.
inline __m128 _mm_cvtepu32_ps(const __m128i v)
{
__m128i v2 = _mm_srli_epi32(v, 1); // v2 = v / 2
__m128i v1 = _mm_sub_epi32(v, v2); // v1 = v - (v / 2)
__m128 v2f = _mm_cvtepi32_ps(v2);
__m128 v1f = _mm_cvtepi32_ps(v1);
return _mm_add_ps(v2f, v1f);
}
UPDATE
As noted by @wim in his answer, the above solution fails for an input value of `UINT_MAX`. Here is a more robust, but slightly less efficient solution, which should work for the full `uint32_t` input range:
inline __m128 _mm_cvtepu32_ps(const __m128i v)
{
__m128i v2 = _mm_srli_epi32(v, 1); // v2 = v / 2
__m128i v1 = _mm_and_si128(v, _mm_set1_epi32(1)); // v1 = v & 1
__m128 v2f = _mm_cvtepi32_ps(v2);
__m128 v1f = _mm_cvtepi32_ps(v1);
return _mm_add_ps(_mm_add_ps(v2f, v2f), v1f); // return 2 * v2 + v1
}
Problem
In SSE there is a function `_mm_cvtepi32_ps(__m128i input)` which takes input vector of 32 bits wide signed integers (`int32_t`) and converts them into `float`s. Now, I want to interpret input integers as not signed. But there is no function `_mm_cvtepu32_ps` and I could not find an implementation of one. Do you know where I can find such a function or at least give a hint on the implementation? To illustrate the the difference in results: ``` unsigned int a = 2480160505; // 10010011 11010100 00111110 11111001 float a1 = a; // 01001111 00010011 11010100 00111111; float a2 = (signed int)a; // 11001110 11011000 01010111 10000010 ```