Atualizado: 09/11/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

Comparação Vetorial de Inteiros com SSE e AVX em Assembly NASM

As instruções (v)pcmpeq*, (v)pcmpgt* comparam inteiros nas pistas correspondentes de dois operandos. O resultado da comparação, que é uma máscara de bits, é armazenado no primeiro operando.

Comparação de Igualdade

As instruções pcmpeq* testam a igualdade entre os elementos dos vetores.

pcmpeqb xmmdest, xmmsrc/mem128 ; Compara 16 pistas de bytes
pcmpeqw xmmdest, xmmsrc/mem128 ; Compara 8 pistas de words
pcmpeqd xmmdest, xmmsrc/mem128 ; Compara 4 pistas de dwords
pcmpeqq xmmdest, xmmsrc/mem128 ; Compara 2 pistas de qwords

Se os dois valores em uma pista são iguais, a instrução preenche todos os bits daquela pista no registrador de destino com 1. Caso contrário, preenche com 0. Um valor com todos os bits 1 é representado como -1 em notação de complemento de dois.

O programa a seguir para Linux demonstra essa operação.

global main

extern printf

section .data
    nums0 dd 1, 2, 4, 8
    nums1 dd 1, 2, 3, 8
    format_str db "%d, %d, %d, %d", 10, 0

section .text
main:
    sub rsp, 8

    movaps xmm0, [nums0]
    movaps xmm1, [nums1]
    pcmpeqd xmm0, xmm1       ; XMM0 = (XMM0 == XMM1)
    ; Resultado em XMM0: [-1, -1, 0, -1]

    ; Exibe os dados no console
    movd esi, xmm0
    psrldq xmm0, 4
    movd edx, xmm0
    psrldq xmm0, 4
    movd ecx, xmm0
    psrldq xmm0, 4
    movd r8d, xmm0

    mov rdi, format_str
    xor rax, rax
    call printf

    add rsp, 8
    ret

Como os elementos nas pistas 0, 1 e 3 são iguais, essas pistas em xmm0 são preenchidas com 0xFFFFFFFF (-1). A pista 2, onde os valores são diferentes, é preenchida com 0.

Resultado da execução:

$ nasm -f elf64 hello.asm -o hello.o
$ gcc -static hello.o -o hello
$ ./hello
-1, -1, 0, -1

A seguir, a versão análoga do programa para Windows.

global main

extern printf

section .data
    nums0 dd 1, 2, 4, 8
    nums1 dd 1, 2, 3, 8
    format_str db "%d, %d, %d, %d", 10, 0

section .text
main:
    sub rsp, 40
    movaps xmm0, [rel nums0]
    movaps xmm1, [rel nums1]
    pcmpeqd xmm0, xmm1       ; XMM0 = (XMM0 == XMM1)
    ; Resultado em XMM0: [-1, -1, 0, -1]

    movd edx, xmm0
    psrldq xmm0, 4
    movd r8d, xmm0
    psrldq xmm0, 4
    movd r9d, xmm0
    psrldq xmm0, 4
    movd eax, xmm0
    mov dword [rsp+32], eax

    mov rcx, format_str
    call printf

    add rsp, 40
    ret

Comparação "Maior Que"

As instruções pcmpgt* verificam se o valor no primeiro operando é maior que o valor no segundo.

pcmpgtb xmmdest, xmmsrc/mem128 ; Compara 16 pistas de bytes
pcmpgtw xmmdest, xmmsrc/mem128 ; Compara 8 pistas de words
pcmpgtd xmmdest, xmmsrc/mem128 ; Compara 4 pistas de dwords
pcmpgtq xmmdest, xmmsrc/mem128 ; Compara 2 pistas de qwords

A lógica é a mesma: a pista de destino é preenchida com 1s se a condição dest > src for verdadeira, e com 0s caso contrário.

global main

extern printf

section .data
    nums0 dd 0, 2, 4, 5
    nums1 dd 0, 1, 2, 7
    format_str db "%d, %d, %d, %d", 10, 0

section .text
main:
    sub rsp, 8

    movaps xmm0, [nums0]
    movaps xmm1, [nums1]
    pcmpgtd xmm0, xmm1       ; XMM0 = (XMM0 > XMM1)
    ; Resultado em XMM0: [0, -1, -1, 0]

    ; Exibe os dados no console
    movd esi, xmm0
    psrldq xmm0, 4
    movd edx, xmm0
    psrldq xmm0, 4
    movd ecx, xmm0
    psrldq xmm0, 4
    movd r8d, xmm0

    mov rdi, format_str
    xor rax, rax
    call printf

    add rsp, 8
    ret

As versões AVX (vpcmpeq* e vpcmpgt*) usam três operandos (dest = src1 op src2) e as variantes de 256 bits dobram o número de pistas processadas. É importante notar que essas instruções de comparação não afetam os flags de status do processador.

Verificação do Resultado com (v)pmovmskb

A instrução (v)pmovmskb é uma ferramenta para analisar o resultado de uma comparação vetorial. Ela extrai o bit mais significativo (MSB) de cada byte em um registrador XMM ou YMM e os compacta em um registrador de propósito geral.

pmovmskb reg, xmm
vpmovmskb reg, xmm
vpmovmskb reg, ymm

Após uma comparação, cada pista do registrador de resultado contém 0x00 (falso) ou 0xFF (verdadeiro). A instrução pmovmskb cria uma máscara de bits onde cada bit corresponde ao resultado da comparação de um byte.

O exemplo a seguir para Linux demonstra seu uso.

global main

extern printf

section .data
    nums0 dd 0, 2, 4, 5
    nums1 dd 0, 1, 2, 7
    format_str db "%#x", 10, 0

section .text
main:
    sub rsp, 8

    movaps xmm0, [nums0]
    movaps xmm1, [nums1]
    pcmpgtd xmm0, xmm1       ; Resultado em XMM0: [0, -1, -1, 0]

    pmovmskb esi, xmm0

    ; Exibe os dados no console
    mov rdi, format_str
    xor rax, rax
    call printf

    add rsp, 8
    ret

Resultado da execução:

$ nasm -f elf64 hello.asm -o hello.o
$ gcc -static hello.o -o hello
$ ./hello
0xff0

O registrador xmm0 contém o vetor [0, -1, -1, 0], que em bytes é [00 00 00 00] [FF FF FF FF] [FF FF FF FF] [00 00 00 00]. A instrução pmovmskb extrai o bit de sinal de cada um desses 16 bytes. Os 4 primeiros bytes têm MSB 0, os 8 seguintes têm MSB 1, e os 4 últimos têm MSB 0. Isso forma a máscara binária 0000111111110000, que em hexadecimal é 0x0FF0.

Aplicação Prática: Comparação de Strings

Essas instruções são muito eficientes para comparar strings de até 16 bytes de uma só vez.

global main

extern printf

section .data
    str0 db "Hello World",0
align 16
    str1 db "Hello World", 0
align 16
    mask dw 0xffff
    equal_str db "String are equal", 10, 0
    notequal_str db "String are not equal", 10, 0

section .text
main:
    sub rsp, 8

    movdqa xmm0, [str0]
    movdqa xmm1, [str1]
    pcmpeqb xmm0, xmm1      ; Compara os bytes (caracteres) das strings
    vpmovmskb edi, xmm0     ; Copia o resultado para edi
    cmp di, [mask]          ; Compara a máscara de resultado com 0xffff
    jz equal                ; Se forem iguais, as strings são idênticas

    mov rdi, notequal_str   ; Se as strings não são iguais
    jmp exit

equal:
    mov rdi, equal_str      ; Se as strings são iguais

exit:
    xor rax, rax
    call printf
    add rsp, 8
    ret

O código compara 16 bytes das strings com pcmpeqb. Se todos os bytes forem iguais, vpmovmskb produzirá o valor 0xFFFF. Esse valor é então comparado com uma máscara para determinar se as strings são idênticas.

Aplicação Avançada: Conversão Condicional de Caracteres

As operações de comparação permitem manipulações condicionais, como converter apenas as letras minúsculas de uma string para maiúsculas, sem afetar outros caracteres.

O código a seguir implementa essa lógica:

  1. Encontra todos os caracteres no intervalo de 'a' a 'z' usando duas comparações (>='a' e <='z').
  2. Combina os resultados com AND para criar uma máscara que identifica apenas as letras minúsculas.
  3. Usa essa máscara para zerar o 5º bit (o bit que diferencia maiúsculas de minúsculas no ASCII) apenas nos caracteres selecionados.
global _start

section .data
    msg db "Hello World", 10, 0
    msglen equ $-msg
align 16
    mask_ge_a times 16 db 'a' - 1   ; Caracteres >= 'a'
    mask_le_z times 16 db 'z' + 1   ; Caracteres <= 'z'
    mask_case times 16 db 0b00100000 ; Máscara do 5º bit

section .text
_start:
    movdqa xmm0, [msg]               ; Carrega a string em xmm0

    ; Cria máscara para letras minúsculas (>= 'a' E < 'z')
    vpcmpgtb xmm1, xmm0, [mask_ge_a] ; Máscara 1: Caracteres > ('a'-1)
    movdqa xmm2, [mask_le_z]
    vpcmpgtb xmm2, xmm2, xmm0        ; Máscara 2: Caracteres < ('z'+1)
    pand xmm1, xmm2                  ; Interseção das máscaras

    ; Isola o 5º bit apenas para as letras minúsculas
    pand xmm1, [mask_case]

    ; Zera o 5º bit nos caracteres da string original
    pxor xmm0, xmm1

    movdqa [msg], xmm0               ; Salva a string convertida

    ; Imprime a string com a chamada de sistema write
    mov rax, 1
    mov rdi, 1
    mov rsi, msg
    mov rdx, msglen
    syscall

    mov rax, 60
    xor rdi, rdi
    syscall

Resultado da execução:

$ nasm -f elf64 hello.asm -o hello.o
$ ld hello.o -o hello
$ ./hello
HELLO WORLD

Resumo

  • As instruções pcmpeq e pcmpgt realizam comparações paralelas, gerando uma máscara de 1s (verdadeiro) ou 0s (falso) para cada pista.
  • A instrução pmovmskb é usada para converter a máscara vetorial resultante em um único registrador inteiro, facilitando a verificação do resultado com instruções tradicionais.
  • Essas ferramentas são eficientes para operações como comparação de strings e manipulação condicional de dados em larga escala.
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com