Это может быть сделано на основе чередования битов , но пропуская некоторые шаги, чтобы он чередовал только байты. Идея та же: сначала разбейте байты за пару шагов, затем объедините их.
Вот план, проиллюстрированный моими удивительными навыками рисования от руки:
В С (не проверено):
// step 1, moving the top two bytes
uint64_t a = (((uint64_t)x & 0xFFFF0000) << 16) | (x & 0xFFFF);
// step 2, moving bytes 2 and 6
a = ((a & 0x00FF000000FF0000) << 8) | (a & 0x000000FF000000FF);
// same thing with y
uint64_t b = (((uint64_t)y & 0xFFFF0000) << 16) | (y & 0xFFFF);
b = ((b & 0x00FF000000FF0000) << 8) | (b & 0x000000FF000000FF);
// merge them
uint64_t result = (a << 8) | b;
Было предложено использовать SSSE3 PSHUFB, оно будет работать, но есть инструкция, которая может выполнять побитовое чередование за один раз, punpcklbw . Таким образом, все, что нам действительно нужно сделать, это получить значения в векторных регистрах и из них, и эта единственная инструкция просто позаботится об этом.
Не тестировалось:
uint64_t interleave(uint32_t x, uint32_t y) {
__m128i xvec = _mm_cvtsi32_si128(x);
__m128i yvec = _mm_cvtsi32_si128(y);
__m128i interleaved = _mm_unpacklo_epi8(yvec, xvec);
return _mm_cvtsi128_si64(interleaved);
}