2011-10-24 23 views
6

¿Cuál es la forma más eficiente de hacer un cambio de 128 bits en una CPU Intel moderna (Core i7, puente de arena).¿Cambios de 128 bits utilizando el lenguaje ensamblador?

Un código similar está en mi bucle más interno:

u128 a[N]; 
void xor() { 
    for (int i = 0; i < N; ++i) { 
    a[i] = a[i]^(a[i] >> 1)^(a[i] >> 2); 
    } 
} 

Los datos en a[N] es casi al azar.

+0

64 bits o 32 bits? –

+1

Puede comenzar activando la optimización máxima y viendo lo que genera el compilador. –

+0

¿Puede mostrarnos la definición de 'u128'? Probablemente pueda proporcionar una solución eficiente usando SSE. – Mysticial

Respuesta

9

Usando la instrucción Shift Double.

SHLD o SHRD instrucciones, porque SSE no está diseñado para este propósito. Hay un método clásico, aquí tiene casos de prueba para el desplazamiento a la izquierda de 128 bits en 16 bits en el modo de CPU de 32 y 64 bits.

De esta forma puede realizar cambios de tamaño ilimitados para hasta 32/64 bits. Yoo puede cambiar por un número inmediato de bits o por un número en el registro cl. La primera instrucción operante también puede abordar variables en la memoria.

128 bit desplazamiento a la izquierda por 16 bits en el modo x86 CPU 32 bits:

mov  eax, $04030201; 
    mov  ebx, $08070605; 
    mov  ecx, $0C0B0A09; 
    mov  edx, $100F0E0D; 

    shld edx, ecx, 16 
    shld ecx, ebx, 16 
    shld ebx, eax, 16 
    shl  eax, 16 

Y 128 bit desplazamiento a la izquierda por 16 bits en el modo x86 CPU 64 bits:

mov rax, $0807060504030201; 
    mov rdx, $100F0D0E0B0C0A09; 

    shld rdx, rax, 16 
    shl rax, 16 
+1

Lo he usado. Funciona y es razonablemente rápido, pero debe mencionar que el código de 32 bits permite cambiar hasta 31 y el código de 64 bits hasta 63. Si desea cambiar por una cantidad variable, que no se puede garantizar que sea menor que 64, esto no puede ser usado. – hirschhornsalz

+0

@drhirsch: He mencionado hasta 32/64 bits y, por supuesto, debería ser de hasta 31/63bits si desea algo más que mover palabras de 32/64 bits. –

3

En este caso particular, podría usar una combinación de x86 instrucciones SHR y RCR:

; a0 - bits 0-31 of a[i] 
; a1 - bits 32-63 of a[i] 
; a2 - bits 64-95 of a[i] 
; a3 - bits 96-127 of a[i] 
mov eax, a0 
mov ebx, a1 
mov ecx, a2 
mov ecx, a3 

shr eax, 1 
rcr ebx, 1 
rcr ecx, 1 
rcr edx, 1 

; b0 - bits 0-31 of b[i] := a[i] >> 1 
; b1 - bits 32-63 of b[i] := a[i] >> 1 
; b2 - bits 64-95 of b[i] := a[i] >> 1 
; b3 - bits 96-127 of b[i] := a[i] >> 1 
mov b0, eax 
mov b1, ebx 
mov b2, ecx 
mov b3, edx 

shr eax, 1 
rcr ebx, 1 
rcr ecx, 1 
rcr edx, 1 

; c0 - bits 0-31 of c[i] := a[i] >> 2 = b[i] >> 1 
; c1 - bits 32-63 of c[i] := a[i] >> 2 = b[i] >> 1 
; c2 - bits 64-95 of c[i] := a[i] >> 2 = b[i] >> 1 
; c3 - bits 96-127 of c[i] := a[i] >> 2 = b[i] >> 1 
mov c0, eax 
mov c1, ebx 
mov c2, ecx 
mov c3, edx 

Si su objetivo es x86-64 esto simplifica a:

; a0 - bits 0-63 of a[i] 
; a1 - bits 64-127 of a[i] 
mov rax, a0 
mov rbx, a1 

shr rax, 1 
rcr rbx, 1 

; b0 - bits 0-63 of b[i] := a[i] >> 1 
; b1 - bits 64-127 of b[i] := a[i] >> 1 
mov b0, rax 
mov b1, rbx 

shr rax, 1 
rcr rbx, 1 

; c0 - bits 0-63 of c[i] := a[i] >> 2 = b[i] >> 1 
; c1 - bits 64-127 of c[i] := a[i] >> 2 = b[i] >> 1 
mov c0, rax 
mov c1, rbx 

Actualizar: corregido los errores tipográficos en la versión de 64 bits

+0

Desafortunadamente, las instrucciones RCR/RCL son excepcionalmente lentas en casi todos los procesadores modernos.SHLD/SHRD es una mejor alternativa – hirschhornsalz

+0

Y en el segundo caso en su lugar ** shr eax, 1; rcr ebx, 1 ** debe ser ** shr rax, 1; rcr rbx, 1 ** –

+0

RCR/RCL es rápido cuando el segundo argumento es 1. Este es exactamente el caso para este problema. Cuando el segundo argumento es 1, RCR/RCL es más rápido que SHLD/SHRD en todas las CPU modernas: –

Cuestiones relacionadas