2010-04-15 25 views
15

He intentado obtener un buen control del lenguaje de ensamblaje x86 y me preguntaba si había un equivalente rápido y corto de movl $1, %eax. Fue entonces cuando pensé que una lista de modismos utilizados con frecuencia en el idioma tal vez sería una buena idea.x86 modismos de ensamblaje

Esto podría incluir el uso preferido de xorl %eax, %eax en contraposición a movl $0, %eax, o testl %eax, %eax contra cmpl $0, %eax.

¡Oh, y amablemente publica un ejemplo por publicación!

+5

'movl $ 1,% eax' es bastante rápido y corto. En algunos procesadores, 'xorl% eax,% eax' es realmente más lento que' movl $ 0,% eax'. En otros, 'incl% eax' es más lento que' addl $ 1,% eax'. Si se toma la molestia de escribir una asamblea en 2010, debe saber para qué arquitectura está escribiendo y seleccionar su "dialecto" (para mantener la metáfora lingüística) en consecuencia. –

+0

@Pascal Cuoq, ¿podría explicar qué factores afectan este tipo de diferencia en el rendimiento? Estoy especialmente desconcertado por 'incl% eax' que es más lento que' addl $ 1,% eax'. Además, si pudiera indicarme algún enlace que detalle este tipo de comportamiento, ¡le estaré agradecido! – susmits

+0

Para todas las arquitecturas x86 en 2010 xor eax, eax es más rápido o equivalente, en cualquier caso es más corto. Eche un vistazo a http://stackoverflow.com/questions/1396527/any-reason-to-do-a-xor-eax-eax/1396552#1396552. Esto es más o menos desde los días de 486. – hirschhornsalz

Respuesta

5

en x64:

xor eax, eax 

para

xor rax, rax 

(el primero también borra implícitamente la mitad superior de rax, pero tiene un código de operación más pequeño)

7

Usando LEA para, por ejemplo, multiplicación, como:

lea eax, [ecx+ecx*4] 

para EAX = 5 * ECX

+5

BTW: este es un perro lento en NetBurst, porque Intel eliminó la palanca de cambios para poder obtener velocidades de reloj más altas. Irónicamente, en el momento en que salió el P4, esto aún estaba documentado en los manuales de optimización de Intel. –

+0

Gracias por el comentario re. velocidad. Me doy cuenta de que un modismo no es necesariamente lo mismo que una optimización. Sin embargo, como una expresión idiomática, creo que LEA ha sido ampliamente utilizada (ab). – PhiS

+5

Bueno, es * una * optimización. E incluso es oficialmente recomendado por Intel.Es solo que, después de recomendarlo oficialmente durante 15 años, lanzan repentinamente una nueva CPU en la que era lenta, por lo que esencialmente requería recompilar * cada programa que se haya escrito *. Afortunadamente, NetBurst murió de una muerte rápida y dolorosa y todas las microarquitecturas actuales son evoluciones del Pentium III, no del Pentium4, por lo que todas las CPU actuales tienen una palanca de cambios. Básicamente, * todas las * CPU de Intel desde 80385 y todas las Athlons lo tienen, solo el Pentium4 no. –

5

Es posible que así como la manera de optimizar el montaje. Entonces, tendrías que preguntar para qué estás optimizando: ¿tamaño o velocidad? De todos modos, aquí está mi "lenguaje", un reemplazo para xchg:

xor eax, ebx 
xor ebx, eax 
xor eax, ebx 
+0

** ADVERTENCIA: ** Si eax == ebx - ¡Ambos serán puestos a cero! – LiraNuna

+11

¿Estás seguro de eso? 42^42 = 0; 42^0 = 42; 0^42 = 42 – Sparafusile

2

Usando SHL y SHR para la multiplicación/división por una potencia de 2

+0

Se puede extender a otros números también. Por ejemplo, 'y * 320 = (y << 8) + (y << 6)'. Sin embargo, eso no siempre es más rápido que una simple multiplicación. Depende de tu procesador. – csl

2

otro (lado xor) para

mov eax, 0 ; B800000000h 

es

sub eax, eax ; 29C0h 

Justificación: código de operación más pequeña

2

No sé si esto cuenta como un idioma, pero en la mayoría de los procesadores i7 antes

movq xmm0, [eax] 
movhps xmm0, [eax+8] 

o, si está disponible SSE3,

lddqu xmm0, [eax] 

son más rápidos para leer desde una ubicación de memoria no alineada que

movdqu xmm0, [eax] 
4

Expandiendo en mi comentario:

Para un procesador poco claro como el Pentium Pro, xorl %eax, %eax parece tener una dependencia en %eax y, por lo tanto, debe esperar a que el valor de ese registro esté disponible. Los procesadores posteriores en realidad tienen una lógica adicional para reconocer que la instrucción no tiene ninguna dependencia.

Las instrucciones incl y decl establecen algunas de las marcas pero dejan otras sin modificar.Esa es la peor situación si las banderas se modelan como un registro único para reordenar las instrucciones: cualquier instrucción que lea una bandera después de incl o decl debe considerarse según el incl o decl (en caso de que esté leyendo uno de los indicadores que establece esta instrucción) y también en la instrucción previa que establece las banderas (en caso de que esté leyendo uno de los indicadores que esta instrucción no establece). Una solución sería dividir el registro de banderas en dos y considerar las dependencias con este grano más fino ... pero AMD tuvo una mejor idea y eliminó estas instrucciones completamente de la extensión de 64 bits que propusieron hace unos años.

En cuanto a los enlaces, he encontrado esta en los manuales de Intel para el que es inútil para proporcionar un enlace porque están en una página web corporativa que se reorganizó cada seis meses, o en el sitio de Agner Fog: http://www.agner.org/optimize/#manuals

4

En bucles ...

dec  ecx 
    cmp  ecx, -1  
    jnz  Loop    

es

dec  ecx 
    jns  Loop 

más rápido y más corto.

+0

¿No es más fácil el loop .Loop? –

+1

@Hasan Saad: Es pero ti es más lento, el uso de bucle en x86 está en desuso. –

+0

Muchas gracias :) No tenía ni idea, así que gracias por la información. Altamente apreciado :) –

10

Aquí hay otro "modismo" interesante. Afortunadamente, todos saben que la división es una gran pérdida de tiempo, incluso en comparación con una multiplicación. Usando un poco de matemática, es posible multiplicar por el inverso de la constante en lugar de dividir por ella. Esto va más allá de los trucos de shr. Por ejemplo, para dividir por 5:

mov eax, some_number 
mov ebx, 3435973837 // 32-bit inverse of 5 
mul ebx 

Ahora eax se ha dividido por 5 sin utilizar el código de operación div lento. Aquí está una lista de constantes útiles para la división desvergonzada robado de http://blogs.msdn.com/devdev/archive/2005/12/12/502980.aspx

3 2863311531 
5 3435973837 
7 3067833783 
9 954437177 
11 3123612579 
13 3303820997 
15 4008636143 
17 4042322161 

Para los números que no están en la lista, es posible que tenga que hacer un cambio de antemano (dividir por 6, SHR 1, luego se multiplica por el inverso de 3).

Cuestiones relacionadas