Как "удалить" байты в конце регистра SSE?
Для универсального присваивания мне нужно написать функцию, которая подсчитывает количество пробелов в строке (определяемых указателем и индексом) в сборке. Там есть требование использовать pcmpeqb
для этого (то есть работа с регистрами SSE) и подсказка для использования popcnt
а также pmovmskb
, Мой основной подход заключается в обработке строки в 16-байтовых чанках с загрузкой каждого чанка в %xmm8
и сравнивая это с %xmm9
который инициализирован, чтобы содержать 16 пробелов. Однако мне нужно как-то обработать последний кусок.
Моей первой мыслью было использовать инструкцию поворота, чтобы удалить мусор за концом строки. (Строка гарантированно будет иметь некоторое дополнительное пространство после конца, чтобы предотвратить segfaults, но данные там, вероятно, не должны использоваться для сравнения.) Я наткнулся на PSRLDQ
но это, кажется, не принимает не немедленный аргумент. (Или, по крайней мере, отказался от того, что я бросил в него.) Итак, мой вопрос: как я могу удалить последние X байтов регистра SSE, не обнуляя половину этого, или делая это дословно? (Как я понимаю, большинство доступных операций над ними делают.)
Мой код (шаблон по модулю) в настоящее время выглядит следующим образом - проблемный бит ближе к концу, после метки _last:
:
# === Arguments ===
# %rdi - char *input
# %rsi - size_t count
# === Temporaries ===
# %rdx - how many chars to process in final run
# %rcx - how many characters were "read" already
# %r8 - pop count of last iteration
# %r9
# %r11
# === SSE Temporaries ===
# %xmm8 - the chunk of the string being processed
# %xmm9 - 16 spaces
xor %rcx, %rcx
xor %rax, %rax
movdqu _spaces(%rip), %xmm9
_loop:
# set %rdx to number of characters left to process
mov %rsi, %rdx
sub %rcx, %rdx
# we've reached the end of the string
cmp %rdx, %rsi
jge _end
movdqu (%rdi, %rcx), %xmm8 # load chunk of string to process
add $16, %rcx
# less than 16 characters to process
cmp $16, %rdx
jg _last
_compare: #compare %xmm8 with spaces and add count of spaces to %eax
pcmpeqb %xmm9, %xmm8
pmovmskb %xmm8, %r8d
popcntl %r8d, %r8d
add %r8d, %eax
jmp _loop
_last: # last part of string, less than 16 chars
sub $16, %rdx
neg %rdx
# I need to delete possible garbage after the last chars
psrldq %edx, %xmm8
jmp _compare
_end:
ret
(Поток управления там может все еще быть ошибочным, но я рассмотрю это позже.)
2 ответа
Я думаю, что самым простым решением было бы использовать все 16 символов в регистре SSE, но замаскировать биты после pmovmskb
, Обратите внимание, что использование 16-байтовых загрузок, как вы делаете, небезопасно, поскольку вы можете перейти на недоступную страницу.
Не пытайтесь "удалить" лишние байты в регистре SSE. Вместо этого, после сравнения и выполнения PMOVMSKB, просто замаскируйте биты в результирующей маске, которые соответствуют дополнительным байтам. Это очень стандартный подход в векторизации; вместо того, чтобы прыгать через обручи, чтобы получить только те данные, которые вы хотите, обработать все, а затем очистить биты, которые вы не хотели позже.