Pregunta

Estoy copiando elementos de una matriz a otra en C ++. Encontré el rep movs Instrucción en x86 que parece copiar una matriz en ESI a una matriz en EDI de Size ECX. Sin embargo, ni el for ni while bucles que intenté compilarse con un rep movs Instrucción en VS 2008 (en un procesador Intel Xeon X64). ¿Cómo puedo escribir un código que se compilará en esta instrucción?

¿Fue útil?

Solución

Si necesita exactamente esa instrucción, use el ensamblador incorporado y escriba esa instrucción manualmente. No puede confiar en el compilador para producir ningún código de máquina específico - Incluso si lo emite en una compilación, puede decidir emitir algún otro equivalente durante la próxima compilación.

Otros consejos

Honestamente, no deberías. REP es una especie de remanente obsoleto en el conjunto de instrucciones, y en realidad es bastante lento ya que tiene que llamar a una subrutina microcoded dentro de la CPU, que tiene una latencia de búsqueda ROM y también no espipelada.

En casi todas las implementaciones, encontrará que el memcpy() compilador intrínseco es más fácil de usar y funciona más rápido.

Bajo MSVC está el __movsxxx & __stosxxx intrínsecs que generará un REP instrucción prefijada.

También hay un 'hack' para forzar intrínseco memset aka REP STOS bajo VC9+, como la intrínseca ya no sale, debido a la ramificación de SSE2 en la CRT. Esto es mejor que __stosxxx Debido al hecho de 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 lo mejor para usar, en mi camino mejor usar memcpy, se ramificará a SSE2 o REPS MOV Basado en su sistema (bajo MSVC), a menos que tenga ganas de escribir un ensamblaje personalizado para áreas 'calientes' ...

Representante y amigos fue agradable una vez, cuando la CPU X86 era un procesador industrial de CISC de Pipeline.

Pero eso ha cambiado. Hoy en día cuando se encuentra el procesador ningún Instrucción, la primera que lo hace es traducirlo en un formato más fácil (micro-opciones tipo VLIW) y programarlo para una ejecución futura (esto es parte de la ejecución fuera de orden, parte de la programación entre diferentes núcleos de CPU lógicos, TI, TI, TI. Se puede usar para simplificar las secuencias de escritura-después de la escritura en escrituras individuales, et.C.). Esta maquinaria funciona bien para instrucciones que se traducen en algunos códigos de operación tipo VLIW, pero no en código de máquina que se traduce en bucles. El código de la máquina traducido en bucle probablemente hará que la tubería de ejecución se detenga.

En lugar de gastar cientos de miles de transistores en la construcción de la circuición de la CPU para manejar las porciones de bucle de las micro-opciones en la tubería de ejecución, simplemente lo manejan en algún tipo de modo heredado que tartamudean la tubería y piden a los programadores modernos ¡Escribe tus propios bucles!

Por lo tanto, rara vez se usa cuando las máquinas escriben código. Si se encuentra con el representante en un ejecutable binario, probablemente sea un muppet de asamblea humana que no sabía mejor, o una galleta 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 las partes internas de X86 CPU, me metí en otros pasatiempos ...)

Utilizo las variantes de prefijo Rep* con CMPS*, MOVS*, SCAS* y STOS* Variantes de instrucción para generar código en línea que minimiza el tamaño del código, evita llamadas/saltos innecesarios y, por lo tanto, mantiene abajo el trabajo realizado por los cachés. La alternativa es configurar los parámetros y llamar a un Memset o Memcpy a otro lugar que en general puede ser más rápido si quiero copiar cien bytes o más, pero si se trata solo de 10-20 bytes que usan REP es más rápido (o al menos fue la última vez que medí).

Dado que mi compilador permite la especificación y el uso de funciones de ensamblaje en línea e incluye su uso/modificación de registro en las actividades de optimización, es posible que las use cuando las circunstancias son correctas.

En una nota histórica, sin tener ninguna idea de las estrategias del fabricante, hubo un momento en que las instrucciones "RepOms*(etc) eran muy lentas. Creo que fue en la época del Pentium/Pentium MMX. Un colega mío (que tenía más información que yo) dijo que los fabricantes habían disminuido el área de chip (<=> menos transistores/más microcódigo) asignados al manejo de Rep y lo usaron para hacer otras instrucciones más utilizadas más rápido.

En los quince años más o menos, desde que REP se ha vuelto relativamente más rápido nuevamente, lo que sugeriría más transistores/menos microcódigo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top