Эта перестановка является своего рода беспорядком, причем каждый соответствующий бит имеет определенное расстояние перемещения. Диаграмма перестановок выглядит следующим образом (выводится верхняя строка):
Это предполагает некоторые подходы, хотя. Если мы посмотрим ближе к вершине, каждая «группа» формируется путем сбора некоторых битов из ввода в порядке возрастания, так что это можно сделать с помощью 7 compress_right операций, также известных как PEXT
, которые эффективен на Intel (пока не так эффективен на AMD). На самом деле все сводится к выборке из вертикальных столбцов, поэтому выборка битов происходит с шагом 8.
Так что, если PEXT
приемлемо, это можно сделать следующим образом (не проверено):
uint64_t g0 = _pext_u64(in, 0x8080808);
uint64_t g1 = _pext_u64(in, 0x404040404);
uint64_t g2 = _pext_u64(in, 0x20202020202);
uint64_t g3 = _pext_u64(in, 0x1010101010101);
uint64_t g4 = _pext_u64(in, 0x808080808080);
uint64_t g5 = _pext_u64(in, 0x404040404000);
uint64_t g6 = _pext_u64(in, 0x202020200000);
uint64_t out = g0 | (g1 << 7) | (g2 << 14) | (g3 << 21) |
(g4 << 28) | (g5 << 35) | (g6 << 42);
Эта перестановка не маршрутизируется сетью бабочек, но сети Бенеша универсальны, так что они будут работать.
Таким образом, это можно сделать с помощью 11 из этих шагов перестановки, также известных как дельта-свопы:
word bit_permute_step(word source, word mask, int shift) {
word t;
t = ((source >> shift) ^ source) & mask;
return (source ^ t) ^ (t << shift);
}
Существует несколько вариантов создания точных масок, но это работает:
x = bit_permute_step(x, 0x1001400550054005, 1);
x = bit_permute_step(x, 0x2213223111023221, 2);
x = bit_permute_step(x, 0x01010B020104090E, 4);
x = bit_permute_step(x, 0x002900C400A7007B, 8);
x = bit_permute_step(x, 0x00000A0400002691, 16);
x = bit_permute_step(x, 0x0000000040203CAD, 32);
x = bit_permute_step(x, 0x0000530800001CE0, 16);
x = bit_permute_step(x, 0x000C001400250009, 8);
x = bit_permute_step(x, 0x0C00010403080104, 4);
x = bit_permute_step(x, 0x2012000011100100, 2);
x = bit_permute_step(x, 0x0141040000000010, 1);