Но программа выглядит некрасиво
Поздравляю с замечанием: P
Я ищу способ сделать это как можно быстрее
SSE2 является базовой для x86-64, поэтому вы должны его использовать.Вы можете сделать это в паре инструкций, используя pcmpeqb / pmovmskb для получения растрового изображения результатов сравнения байтов, затем используйте команду битового сканирования, такую как bsr
(обратное сканирование дает индекс наибольшегоустановите бит).
default rel ; don't forget this: RIP-relative addressing is best for loading/storing global data
_start:
movq xmm0, [dt] ; movq xmm0, rdx or whatever works too.
pcmpeqb xmm0, [newline_mask] ; -1 for match, 0 for no-match
pmovmskb edi, xmm0
bsr edi, edi ; index of highest set bit
mov eax, SYS_exit
jz .not_found ; BSR sets ZF if the *input* was zero
; [dt+rdi] == 0xA
syscall ; exit(0..7)
.not_found:
mov edi, -1 ; exit only cares about the low byte of its arg; a 64-bit -1 is pointless.
syscall
section .rodata
align 16
newline_mask: times 16 db 0x0a
section .data
dt: dq 0xAB97450A8733AA1F
Очевидно, что в цикле вы будете хранить newline_mask
в регистре (а затем вы можете транслировать его с помощью AVX vbroadcastss
или SSE3 movddup
вместотребуется целая 16-байтовая константа в памяти).
И, конечно, вы можете сделать это для 16 байт за раз с нагрузкой movdqu
или 32 байт за раз с AVX2. Если у вас большой буфер, вы в основном реализуете memcmp
в обратном направлении и должны смотреть на оптимизированные реализации библиотек. Они могут объединять pcmpeqb
результаты для всей строки кэша с por
, поэтому онисохраните 3/4 из pmovmskb
работы до конца, когда они выяснят, какая часть строки кэша имела удар.
Если вы заботитесь о процессорах AMD (где bsr
медленно), возможно, отдельнопроверить на вход = 0 с помощью test edi,edi
/ jz
перед использованием tzcnt
.(tzcnt(x)
дает вам 31-bsr(x)
или 32, если вход был полностью нулевым.) Если вы можете зависеть от доступности BMI2 ...
Если вы хотите сделать это со скаляромВ цикле вы можете использовать сравнение байтов младшего байта регистра вместо копирования и маскирования значения.
; we test byte 7 first, so start the counter there.
mov edi, 7 ; no idea why you were using a 64-bit counter register
; loop body runs with edi=7..0
.loop: ; do{
rol rbx, 8 ; high byte becomes low
cmp bl, 0xa ; check the low byte
je .found
dec edi
jge .loop ; } while(--edi>=0) signed compare
; not found falls through with edi=-1
.found:
mov eax, SYS_exit
syscall ; exit(7..0) for found, or exit(-1) for not-found
В зависимости от того, что вы делаете с результатом, вы можете расположить счетчик цикла по-разному.