Estoy copiando elementos de una matriz a otra en C++. Encontré la instrucción rep movs
en x86 que parece copiar una matriz en ESI a una matriz en EDI de tamaño ECX. Sin embargo, ni los for
ni los while
loops intenté compilar a una instrucción rep movs
en VS 2008 (en un procesador Intel Xeon x64). ¿Cómo puedo escribir el código que se compilará en esta instrucción?¿Qué código de C++ se compila en la instrucción x86 REP?
Respuesta
Si necesita exactamente esa instrucción, use el ensamblador incorporado y escriba esa instrucción manualmente. You can't rely on the compiler to produce any specific machine code - incluso si lo emite en una compilación, puede decidir emitir algún otro equivalente durante la siguiente compilación.
Escribir las instrucciones manualmente a menudo alterará la optimización del compilador y, en tales casos, si la velocidad es importante, es mejor llamar a las rutinas de la biblioteca. –
@Olof Forshell: Bueno, sí. Pero ¿por qué alguien necesitaría específicamente esta instrucción de todos modos? – sharptooth
Como he escrito aquí en una respuesta, hay situaciones específicas en las que una representación en línea movsb/movsw/movsd y otros será más rápida y más compacta, lo que dará como resultado menos trabajo de caché en el lado de la instrucción. Si quiero copiar menos de 32 bytes, ¿por qué llamar a una rutina en otro lugar que está optimizado para fragmentos de 32 bytes cuando puedo hacerlo más rápido y menos perturbador en línea? –
Honestamente, no deberías. REP es una especie de holdover obsoleto en el conjunto de instrucciones, y en realidad es bastante lento, ya que tiene que llamar a una subrutina microcodificada dentro de la CPU, que tiene una latencia de búsqueda ROM y no tiene derivación también.
En casi todas las implementaciones, encontrará que el compilador memcpy()
intrínseco es más fácil de usar y más rápido.
REP no es una instrucción, es un prefijo de instrucción. También está lejos de ser obsoleto (ver conjunto de instrucciones amd64). –
@Michael Foukarakis Consulte la "Guía de optimización de software AMD para procesadores AMD64", sección 8.3. "Evite usar el prefijo REP al realizar operaciones de cadena, especialmente al copiar bloques de la memoria .En general, usar el prefijo REP para realizar repetidamente las instrucciones de cadena es menos óptimo que otros métodos, especialmente cuando se copian bloques de memoria. " – Crashworks
Interesante. Sé que esto no está relacionado con el tema, pero lo que sería - en términos de ensamblador x86 o amd64 - una forma óptima de copiar un bloque de memoria? – avakar
Debajo de MSVC hay __movsxxx
__stosxxx
intrínsecos que generarán una instrucción prefijada REP
.
También hay un 'truco' para forzar intrínseca memset
aka REP STOS
en vc9 +, ya que el intrínseco ya no sale, debido a la ramificación sse2 en el crt. esto es mejor que __stosxxx
debido a que el compilador puede optimizarlo para constantes y ordenarlo correctamente.
#define memset(mem,fill,size) memset((DWORD*)mem,((fill) << 24|(fill) << 16|(fill) << 8|(fill)),size)
__forceinline void memset(DWORD* pStart, unsigned long dwFill, size_t nSize)
{
//credits to Nepharius for finding this
DWORD* pLast = pStart + (nSize >> 2);
while(pStart < pLast)
*pStart++ = dwFill;
if((nSize &= 3) == 0)
return;
if(nSize == 3)
{
(((WORD*)pStart))[0] = WORD(dwFill);
(((BYTE*)pStart))[2] = BYTE(dwFill);
}
else if(nSize == 2)
(((WORD*)pStart))[0] = WORD(dwFill);
else
(((BYTE*)pStart))[0] = BYTE(dwFill);
}
por supuesto REP
no siempre es el mejor que se puede utilizar, imo su camino mejor usar memcpy
, que va rama en cualquiera SSE2 o REPS MOV
basado en su sistema (bajo msvc), a menos que sentirse como escritura de ensamblaje personalizado para áreas 'calientes' ...
Utilizo las variantes de prefijo rep * con las variantes de instrucción cmps *, movs *, scas * y stos * para generar código en línea que minimiza el tamaño del código, evita llamadas innecesarias/salta y por lo tanto mantiene el trabajo realizado por los cachés. La alternativa es configurar parámetros y llamar a un memset o memcpy en otro lugar que, en general, puede ser más rápido si quiero copiar cien bytes o más, pero si solo es una cuestión de 10-20 bytes, usar rep es más rápido (o al menos era la última vez que medí).
Como mi compilador permite la especificación y el uso de las funciones de ensamblaje en línea e incluye su uso/modificación de registros en las actividades de optimización, es posible que los use cuando las circunstancias sean las correctas.
En una nota histórica, sin tener ninguna idea de las estrategias del fabricante, hubo un momento en que las instrucciones "rep movs *" (etc.) fueron muy lentas. Creo que fue alrededor de la época del Pentium/Pentium MMX. Un colega mío (que tenía más conocimiento que yo) dijo que los fabricantes habían reducido el área de los chips (< => menos transistores/más microcódigo) asignados al manejo de rep y lo usaron para hacer más rápidas otras instrucciones más utilizadas.
En los quince años más o menos desde que el representante se ha vuelto relativamente más rápido hablando nuevamente, lo que sugeriría más transistores/menos microcódigo.
REP y amigos eran agradables érase una vez, cuando la CPU x86 era un procesador industrial CISC de una sola tubería.
Pero eso ha cambiado.Hoy en día, cuando el procesador encuentra cualquier instrucción, lo primero que hace es traducirla a un formato más fácil (microoperaciones tipo VLIW) y programarla para su futura ejecución (esto es parte de la ejecución fuera de orden, parte de programación entre diferentes núcleos de CPU lógicos, se puede usar para simplificar las secuencias de escritura después de escritura en escrituras únicas, et.c.). Esta maquinaria funciona bien para obtener instrucciones que se traducen en algunos códigos de operación similares a VLIW, pero no en códigos de máquina que se traducen en bucles. El código de máquina traducido en bucle probablemente hará que la tubería de ejecución se bloquee.
En lugar de gastar cientos de miles de transistores en construir circuitos de CPU para manejar porciones de bucle de las microoperaciones en la tubería de ejecución, simplemente lo manejan en algún tipo de modo heredado que bloquea la tubería, y ¡pida a los programadores modernos que escriban sus propios malditos bucles!
Por lo tanto, rara vez se utiliza cuando las máquinas escriben código. Si encuentra REP en un ejecutable binario, es probable que sea un humano-ensamblador-muppet que no lo conocía mejor, o un cracker que realmente necesitaba los pocos bytes que guardó para usarlo en lugar de un bucle real, que lo escribió.
(Sin embargo, tome todo lo que acabo de escribir con un grano de sal. Tal vez esto ya no sea cierto. Ya no estoy 100% actualizado con los componentes de las CPU x86, me metí en otros pasatiempos ...)
- 1. ¿Por qué compila este código C?
- 2. ¿Por qué no se compila este código de plantilla C++?
- 3. x86 Instrucción MUL de VS 2008/2010
- 4. Rendimiento de las instrucciones x86 rep en procesadores modernos (pipeline/superscalar)
- 5. ¿Por qué este código C# no se compila?
- 6. Conjunto X86 - Manejo de la instrucción IDIV
- 7. x86 instrucción CMP Diferencia
- 8. mov instrucción en ensamblado x86
- 9. ¿Por qué este código no se compila en g ++
- 10. ¿Qué hace la secuencia de instrucciones de ensamblaje "rep stos" x86?
- 11. ¿Qué sucede cuando una instrucción mov causa un error de página con interrupciones deshabilitadas en x86?
- 12. ¿Por qué el código .NET se compila en MSIL?
- 13. ¿Por qué compila este código Haskell?
- 14. ¿Por qué/cómo se compila?
- 15. ¿Información confiable sobre el rendimiento de la instrucción de cadena x86?
- 16. ¿Por qué no se compila este código C# cuando se usan parámetros con nombre?
- 17. ¿Por qué compila este fragmento de código?
- 18. ¿Por qué este código C++ se compila cuando se usa clang -std = gnu ++ 11?
- 19. ¿Compila ambos x86 y x64 en una configuración?
- 20. ¿Qué registro x86 denota la ubicación de la fuente en la instrucción movsb?
- 21. Obtener la dirección de la instrucción actual para x86
- 22. código se compila con OpenCV Bibliotecas
- 23. ¿Por qué este programa C se compila sin un error?
- 24. "loop:" en código Java. ¿Qué es esto? ¿Por qué compila?
- 25. Ayuda instrucción comprensión DIV en x86 ensamblador en línea
- 26. C++ deducción plantilla-puntero a método no compila cuando la orientación x86, x64, pero trabaja con
- 27. ¿Compila el código de C++ para AIX en Ubuntu?
- 28. ¿Cómo puedo determinar para qué plataforma se compila un ejecutable?
- 29. generación operando de instrucción CALL en x86-64 de AMD
- 30. ¿En qué se diferencia la arquitectura x64 de x86
Déjeme aclarar esto. ¿Desea usar C++ (un lenguaje de nivel medio a alto) para escribir instrucciones de ensamblador? ¿Que sigue? ¿Desea usar C++ para conectar un diodo a su placa base? –
@JUST ¿Se da cuenta de que C++ tiene bloques de ensamblaje? –
@Michael: no portátil. Por ejemplo, para MSVC ni siquiera es compatible con x64, y está en desuso (a favor de intrínsecos) en x86. –