Как "удалить" байты в конце регистра 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, просто замаскируйте биты в результирующей маске, которые соответствуют дополнительным байтам. Это очень стандартный подход в векторизации; вместо того, чтобы прыгать через обручи, чтобы получить только те данные, которые вы хотите, обработать все, а затем очистить биты, которые вы не хотели позже.

Другие вопросы по тегам