¿Qué significa “rep; nop; " significa en ensamblaje x86? ¿Es lo mismo que la instrucción de "pausa"?

86
  • ¿Qué rep; nopsignifica?
  • ¿Es lo mismo que la pauseinstrucción?
  • ¿Es lo mismo que rep nop(sin el punto y coma)?
  • ¿Cuál es la diferencia con la nopinstrucción simple ?
  • ¿Se comporta de manera diferente en procesadores AMD e Intel?
  • (bonificación) ¿Dónde está la documentación oficial de estas instrucciones?

Motivación para esta pregunta

Después de una discusión en los comentarios de otra pregunta , me di cuenta de que no sé qué rep; nop;significa en el ensamblaje x86 (o x86-64). Y tampoco pude encontrar una buena explicación en la web.

Sé que repes un prefijo que significa "repetir los siguientes cxtiempos de instrucción " (o al menos lo era, en el antiguo ensamblaje x86 de 16 bits). De acuerdo con esta tabla resumen en la Wikipedia , parece que repsólo se puede utilizar con movs, stos, cmps, lods, scas(pero tal vez esta limitación se eliminó en los procesadores más recientes). Por lo tanto, pensaría rep nop(sin punto y coma) repetir una nopoperación cxveces.

Sin embargo, después de buscar más, me confundí aún más. Parece que rep; nopy se pause asignan exactamente al mismo código de operación , y pausetiene un comportamiento un poco diferente al de solo nop. Algún correo antiguo de 2005 decía cosas diferentes:

  • "intenta no quemar demasiada energía"
  • "es equivalente a 'nop' solo con codificación de 2 bytes".
  • "es mágico en Intel. Es como 'nop, pero deja que el otro hermano HT corra'"
  • "es una pausa en Intel y un relleno rápido en Athlon"

Con estas opiniones diferentes, no pude entender el significado correcto.

Se está utilizando en el kernel de Linux (tanto en i386 como en x86_64 ), junto con este comentario: /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */También se está utilizando en BeRTOS , con el mismo comentario.

Denilson Sá Maia
fuente

Respuestas:

75

rep; nopes de hecho lo mismo que la pauseinstrucción (código de operación F390). Podría usarse para ensambladores que aún no admiten la pauseinstrucción. En procesadores anteriores, esto simplemente no hizo nada, como noppero en dos bytes. En los nuevos procesadores que admiten hyperthreading, se utiliza como una pista para el procesador de que está ejecutando un spinloop para aumentar el rendimiento. De la referencia de instrucciones de Intel :

Mejora el rendimiento de los bucles de espera de giro. Al ejecutar un "bucle de espera de giro", un procesador Pentium 4 o Intel Xeon sufre una grave penalización de rendimiento al salir del bucle porque detecta una posible violación del orden de memoria. La instrucción PAUSE proporciona una pista al procesador de que la secuencia de código es un bucle de espera de giro. El procesador usa esta sugerencia para evitar la violación del orden de la memoria en la mayoría de las situaciones, lo que mejora enormemente el rendimiento del procesador. Por esta razón, se recomienda que se coloque una instrucción PAUSE en todos los bucles de espera de giro.

ughoavgfhw
fuente
4
¿Es el bucle de espera de giro lo mismo que el bucle de espera ocupado ? ¿Esta "mejora" solo se aplica a los procesadores de hyperthreading? (¿y por qué?)
Denilson Sá Maia
11
Sí, el ciclo de espera de giro es el mismo que el ciclo de espera ocupado. El beneficio también se aplica a las CPU que no admiten Hyper-Threading. Se puede pensar que limita la cantidad de instrucciones (innecesarias) en la tubería (en lugar de intentar hacer muchas iteraciones del ciclo en paralelo)
Brendan
1
@Brendan, ¡gracias! No entendí en absoluto, hasta que dijiste lo de las iteraciones del ciclo en paralelo.
Prof. Falken
11
@Brendan, ¡Oh, ahora lo entiendo! Estos procesadores modernos son superescalares y, por lo tanto, intentarán ejecutar varias instrucciones al mismo tiempo. Si este es un ciclo de espera ocupado, ejecutar más instrucciones no lo hará más rápido, ya que solo está esperando otra condición.
Denilson Sá Maia
1
@Denilson: Sí, la facilidad de uso de hyperthreading (o simplemente el ahorro de energía sin HT) es un gran beneficio, pero el otro es evitar una especulación errónea en el orden de la memoria al salir del bucle giratorio. Sin pause, su bucle giratorio es efectivamente un pipeline-clear más lento para notar el cambio de estado de la ubicación de la memoria escrita por otro núcleo.
Peter Cordes
14

rep nop= F3 90 = la codificación pausey la forma en que decodifica en CPU más antiguas que no admiten pause.


Los prefijos (distintos de lock) que no se aplican a una instrucción son ignorados en la práctica por las CPU existentes.

La documentación dice que el uso repcon instrucciones a las que no se aplica está "reservado y puede causar un comportamiento impredecible" porque las CPU futuras podrían reconocerlo como parte de alguna instrucción nueva. Una vez que establecen el uso de codificación de instrucciones nuevas específicas f3 xx, documentan cómo se ejecuta en CPU más antiguas. (Sí, el espacio de código de operación x86 es tan limitado que hacen cosas locas como esta, y sí, complica los decodificadores).

En este caso, significa que puede usarlo pauseen spinloops sin romper la compatibilidad con versiones anteriores . Las CPU antiguas que no conocen pauselo decodificarán como un NOP sin ningún daño, como lo garantiza la entradapause manual de referencia ISA de Intel para . En las nuevas CPU, obtiene el beneficio del ahorro de energía / compatibilidad con HT y evita la especulación errónea en el orden de la memoria cuando la memoria en la que está girando cambia y abandona el ciclo de giro.


Vínculos a los manuales de Intel y toneladas de otras cosas buenas en la página de información wiki de etiquetas x86

Otro caso de un repprefijo sin sentido que se convierte en una nueva instrucción en nuevas CPU: lzcntes F3 0F BD /r. En las CPU que no admiten esa instrucción (falta el indicador de función LZCNT en su CPUID), se decodifica como rep bsr, que se ejecuta igual que bsr. Entonces, en las CPU antiguas, produce 32 - expected_resulty no está definido cuando la entrada era cero.

Pero tzcnty bsfhacer lo mismo con entradas distintas de cero, por lo que los compiladores pueden usar y lo hacen tzcntincluso cuando no se garantiza que la CPU de destino lo ejecute como tzcnt. Las CPU de AMD son rápidas tzcnt, lentas bsfy en Intel ambas son rápidas. Siempre que no importe la corrección (no confía en la configuración de la bandera o en dejar el comportamiento de destino sin modificar en el caso input = 0), tzcntes útil tenerlo decodificado como en las CPU que lo admiten.


Un caso de un repprefijo sin sentido que probablemente nunca se decodificará de manera diferente: rep retes usado por defecto por gcc cuando apunta a CPU "genéricas" (es decir, no apunta a una CPU específica con -marcho -mtune, y no apunta a AMD K8 o K10). Pasarán décadas antes de que alguien podría hacer una CPU que decodifica rep retcomo cualquier otra cosa ret, porque está presente en la mayoría de los binarios en la mayoría de las distribuciones de Linux. Consulte ¿Qué significa "rep ret"?

Peter Cordes
fuente
3
El repprefijo también fue utilizado por Intel para agregar la elisión de bloqueo.
Paul A. Clayton
Los prefijos que no se aplican a una instrucción se ignoran. Pero se menciona que los prefijos repetidos ( F2Hy F3H) reservados y pueden resultar en un comportamiento impredecible en la Tabla 11-3. Efecto de los prefijos en las instrucciones SSE, SSE2 y SSE3 . Por lo tanto, la aplicación de prefijo se ignora para algunas de las instrucciones, no para todas. Entonces, ¿esta característica se considera indocumentada?
St.Antario
2
@ St.Antario: Lo expresan de esa manera porque las CPU futuras podrían reconocerlo como parte de alguna instrucción nueva. En todas las CPU reales ese ha sido el caso, y una vez que establecen una codificación f3 xx, documentan cómo se ejecuta en las CPU más antiguas.
Peter Cordes
1
En la práctica, las CPU existentes ignoran los prefijos (distintos del bloqueo) que no se aplican a una instrucción. Está documentado que las rep movbecausas #UD, por replo que no siempre se ignora. Incluso si no se aplica a una instrucción en el sentido especificado en la REP/REPE/REPZ/REPNE/REPNZentrada manual.
St.Antario
2
@ St.Antario: ¡Interesante! Sin embargo, en general, para las instrucciones más antiguas, se ignoran los prefijos no aplicables. Al introducir una nueva instrucción, es posible agregar reglas más estrictas si así lo desean. IDK por qué elegirían eso para este caso específico.
Peter Cordes