- ¿Qué
rep; nop
significa? - ¿Es lo mismo que la
pause
instrucción? - ¿Es lo mismo que
rep nop
(sin el punto y coma)? - ¿Cuál es la diferencia con la
nop
instrucció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 rep
es un prefijo que significa "repetir los siguientes cx
tiempos 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 rep
só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 nop
operación cx
veces.
Sin embargo, después de buscar más, me confundí aún más. Parece que rep; nop
y se pause
asignan exactamente al mismo código de operación , y pause
tiene 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.
Respuestas:
rep; nop
es de hecho lo mismo que lapause
instrucción (código de operaciónF390
). Podría usarse para ensambladores que aún no admiten lapause
instrucción. En procesadores anteriores, esto simplemente no hizo nada, comonop
pero 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 :fuente
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.rep nop
= F3 90 = la codificaciónpause
y la forma en que decodifica en CPU más antiguas que no admitenpause
.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
rep
con 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íficasf3 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
pause
en spinloops sin romper la compatibilidad con versiones anteriores . Las CPU antiguas que no conocenpause
lo 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
rep
prefijo sin sentido que se convierte en una nueva instrucción en nuevas CPU:lzcnt
esF3 0F BD /r
. En las CPU que no admiten esa instrucción (falta el indicador de función LZCNT en su CPUID), se decodifica comorep bsr
, que se ejecuta igual quebsr
. Entonces, en las CPU antiguas, produce32 - expected_result
y no está definido cuando la entrada era cero.Pero
tzcnt
ybsf
hacer lo mismo con entradas distintas de cero, por lo que los compiladores pueden usar y lo hacentzcnt
incluso cuando no se garantiza que la CPU de destino lo ejecute comotzcnt
. Las CPU de AMD son rápidastzcnt
, lentasbsf
y 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),tzcnt
es útil tenerlo decodificado como en las CPU que lo admiten.Un caso de un
rep
prefijo sin sentido que probablemente nunca se decodificará de manera diferente:rep ret
es usado por defecto por gcc cuando apunta a CPU "genéricas" (es decir, no apunta a una CPU específica con-march
o-mtune
, y no apunta a AMD K8 o K10). Pasarán décadas antes de que alguien podría hacer una CPU que decodificarep ret
como cualquier otra cosaret
, porque está presente en la mayoría de los binarios en la mayoría de las distribuciones de Linux. Consulte ¿Qué significa "rep ret"?fuente
rep
prefijo también fue utilizado por Intel para agregar la elisión de bloqueo.F2H
yF3H
) 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?f3 xx
, documentan cómo se ejecuta en las CPU más antiguas.rep movbe
causas#UD
, porrep
lo que no siempre se ignora. Incluso si no se aplica a una instrucción en el sentido especificado en laREP/REPE/REPZ/REPNE/REPNZ
entrada manual.