Store lower 16 bits of each AVX 32-bit element to memory

Viewed 338

I have 8 integer values in an AVX value __m256i which are all capped at 0xffff, so the upper 16 bits are all zero.

Now I want to store these 8 values as 8 consecutive uint16_t values.

How can I write them to memory in this way? Can I somehow convert an __m256i value of 8 packed integers into a __m128i value that holds 8 packed shorts?

I am targeting AVX2 intrinsics, but if it can be done in AVX intrinsics, even better.

1 Answers

With AVX2, use _mm256_packus_epi32 + _mm256_permutex_epi64 to fix up the in-lane behaviour of packing two __m256i inputs, like @chtz said. Then you can store all 32 bytes of output from 64 bytes of input.

With AVX1, extract the high half of one vector and _mm_packus_epi32 pack into a __m128i. That would still cost 2 shuffle instructions but produce half the width of data output from them. (Although it's good on Zen1 where YMM registers get treated as 2x 128-bit halves anyway, and vextractf128 is cheaper on Zen1 than on CPUs where it's an actual shuffle.)

Of course, with only AVX1 you're unlikely to have integer data in a __m256i unless it was loaded from memory, in which case you should just do _mm_loadu_si128 in the first place. But with AVX2 it is probably worth doing 32 byte loads even though that means you need 2 shuffles per store instead of 1. Especially if any of your inputs aren't aligned by 16.

Related