Битовые манипуляции с SSE на суббайтах? - PullRequest
1 голос
/ 13 июля 2011

Можно ли использовать SSE для битовых манипуляций с данными, которые не выровнены по байту? Например, я хотел бы реализовать это с помощью SSE:

const char buf[8];
assert(n <= 8);
long rv = 0;
for (int i = 0; i < n; i++)
    rv = (rv << 6) | (buf[i] & 0x3f);

Вместо этого я хотел бы загрузить buf в регистр xmm и использовать инструкции SSE, чтобы избежать зацикливания. К сожалению, операции сдвига (такие как PSLLW) сдвигают каждое упакованное целое число на такое же значение , поэтому я не могу использовать его здесь. Использование умножения (PMULLW) для эмуляции сдвигов также не представляется правильным ...

Глядя на документацию SSE, кажется, что битовые манипуляции не особенно хорошо поддерживаются в целом. Это правда? Или есть хорошие примеры битовых манипуляций с использованием SSE?

Ответы [ 2 ]

4 голосов
/ 13 июля 2011

Я не уверен, что инструкции SSE помогают сократить количество операций, необходимых для реализации того, что ваш код выполняет здесь; если кто-нибудь знает, мне тоже будет любопытно. Давайте немного разложим код.

Код представляет собой рекурсивный сдвиг / или последовательность, то есть вы берете младшие 6 бит, сдвигаете их влево на шесть или следующие 6 бит, снова сдвигаете и т. Д.

Таким образом, вы конвертируете массив из восьмибитных значений в упакованный массив из шести битов, и вы уменьшаете размер с 64 до 48 бит. Как:

|76543210|76543210|76543210|76543210|76543210|76543210|76543210|76543210|
|-----------------|54321054|32105432|10543210|54321054|32105432|10543210|

Поэтому вы можете размотать цикл и записать его следующим образом:

/*
 * (buf[x] << 58)
 *   moves lowest six bits of a 64bit long into the highest bits, clears others
 *
 * >> (6 * x + 16)
 *   shifts the bits into the expected final position
 */
#define L(x) (((long)buf[x] << 58) >> (6 * x + 16))

long rv = L(0) | L(1) | L(2) | L(3) | L(4) | L(5) | L(6) | L(7);

Как уже упоминалось, я не знаю инструкции SSE, которая бы помогла с такой упаковкой (пакеты SSE выполняют четырехзначное, слово-короткое, короткое-байтовое).

Вы можете выполнять операции внутри регистров SSE, но, насколько я вижу, не уменьшать количество инструкций, необходимых для получения конечного результата.

0 голосов
/ 13 июля 2011

В SSE вы можете выполнять несколько побитовых операций. Вы можете просто использовать _mm_and_si128, _mm_or_si128 и есть огромный набор операций shift. Google _mm_slli_si128, чтобы найти полный список. Эти инструкции были добавлены в SSE2, поэтому они широко доступны.

...