Initialize __m256i from 64 high or low bits of four __m128i variables

avx, avx2, c++, simd, sse

Solution

If I understand you question correctly, this is a simple 4x2 transpose (or 2x4 tranpose?).

Here's a code that is working for me:

#include <iostream>
#include <immintrin.h>

using namespace std;
int main() {
    __m128i a = _mm_set_epi64x(1, 11);
    __m128i b = _mm_set_epi64x(2, 22);
    __m128i c = _mm_set_epi64x(3, 33);
    __m128i d = _mm_set_epi64x(4, 44);

    __m256i ac = _mm256_castsi128_si256(a);
    ac = _mm256_inserti128_si256(ac, c, 1); // {3, 33, 1, 11}

    __m256i bd = _mm256_castsi128_si256(b);
    bd = _mm256_inserti128_si256(bd, d, 1); // {4, 44, 2, 22}

    __m256i high = _mm256_unpackhi_epi64(ac, bd);
    __m256i low = _mm256_unpacklo_epi64(ac, bd);

    uint64_t t[4];

    _mm256_storeu_si256((__m256i*) t, high);

    for (int i = 0; i < 4; ++i) {
        cout << t[i] << endl;
    }

    _mm256_storeu_si256((__m256i*) t, low);

    for (int i = 0; i < 4; ++i) {
        cout << t[i] << endl;
    }

    return 0;
}

This should compile into 4 instructions.

Problem

Suppose I have four `__m128i` variables that contain data resulting from some computation. For example, let us say: ``` __m128i a = _mm_set_epi64x(1, 11); __m128i b = _mm_set_epi64x(2, 22); __m128i c = _mm_set_epi64x(3, 33); __m128i d = _mm_set_epi64x(4, 44); ``` I want to initialize two `__m256i` variables, where the first one contains all the high 64-bits of four variables, and the second one contains the low 64-bits of each. So I want to have: ``` __m256i x = ...; // x = { 4, 3, 2, 1 }; __m256i y = ...; // y = { 44, 33, 22, 11 }; ``` The obvious way of doing this is to use `_mm256_set_epi64x` and `_mm_extract_epi64`. However, it's probably not particularly fast. Is there a faster way of doing it? In particular, for accessing the 64 high bits, I see no suitable load (there is a load for the lower 64 bits in SSE2) or shuffle instruction (there seems to be no "64-bit shuffle").

Original source