Ответ 1
Я не могу гарантировать быстрый, но это подход, который использует SSE. Для каждой итерации выполняется восемь преобразований на 12-16 бит, а для каждого шага выполняется два преобразования (приблизительное) (т.е. каждая итерация занимает несколько шагов).
Этот подход охватывает 12-битные целые числа вокруг 16-битных границ в регистре xmm. Ниже показано, как это делается.
- Используется один регистр xmm (предположим xmm0). Состояние регистра представлено одной строкой букв.
- Каждая буква представляет собой 4 бита целочисленного 12-битного числа (т.е. AAA - это все первое 12-битное слово в массиве).
- Каждый зазор представляет собой 16-разрядную границу.
- → 2 указывает логический сдвиг вправо одного байта.
- Символ моркови (^) используется, чтобы выделить, какие соответствующие 12-битные целые числа разделяют 16-битную границу на каждом шаге.
:
load
AAAB BBCC CDDD EEEF FFGG GHHH JJJK KKLL
^^^
>>2
00AA ABBB CCCD DDEE EFFF GGGH HHJJ JKKK
^^^ ^^^
>>2
0000 AAAB BBCC CDDD EEEF FFGG GHHH JJJK
^^^ ^^^
>>2
0000 00AA ABBB CCCD DDEE EFFF GGGH HHJJ
^^^ ^^^
>>2
0000 0000 AAAB BBCC CDDD EEEF FFGG GHHH
^^^
На каждом шаге мы можем извлечь выровненные 12-битные целые числа и сохранить их в регистре xmm1. В конце, наш xmm1 будет выглядеть следующим образом. Вопросительные знаки обозначают значения, которые нам не нужны.
AAA? ?BBB CCC? ?DDD EEE? ?FFF GGG? ?HHH
Извлеките высокоограниченные целые числа (A, C, E, G) в xmm2, а затем на xmm2 выполните правильный сдвиг логического слова в 4 бита. Это преобразует выровненные целые числа с низким выровненным. Смешайте эти скорректированные целые числа обратно в xmm1. Теперь состояние xmm1:
?AAA ?BBB ?CCC ?DDD ?EEE ?FFF ?GGG ?HHH
Наконец, мы можем замаскировать целые числа (т.е. преобразовать "0" ) с 0FFFh для каждого слова.
0AAA 0BBB 0CCC 0DDD 0EEE 0FFF 0GGG 0HHH
Теперь xmm1 содержит восемь последовательных преобразованных целых чисел.
Следующая программа NASM демонстрирует этот алгоритм.
global main
segment .data
sample dw 1234, 5678, 9ABCh, 1234, 5678, 9ABCh, 1234, 5678
low12 times 8 dw 0FFFh
segment .text
main:
movdqa xmm0, [sample]
pblendw xmm1, xmm0, 10000000b
psrldq xmm0, 1
pblendw xmm1, xmm0, 01100000b
psrldq xmm0, 1
pblendw xmm1, xmm0, 00011000b
psrldq xmm0, 1
pblendw xmm1, xmm0, 00000110b
psrldq xmm0, 1
pblendw xmm1, xmm0, 00000001b
pblendw xmm2, xmm1, 10101010b
psrlw xmm2, 4
pblendw xmm1, xmm2, 10101010b
pand xmm1, [low12] ; low12 could be stored in another xmm register