- O que isso
rep; nop
significa? - É o mesmo que
pause
instrução? - É o mesmo que
rep nop
(sem o ponto e vírgula)? - Qual é a diferença para a
nop
instrução simples ? - Ele se comporta de maneira diferente nos processadores AMD e Intel?
- (bônus) Onde está a documentação oficial para essas instruções?
Motivação para esta questão
Depois de alguma discussão nos comentários de outra pergunta , percebi que não sei o que rep; nop;
significa em x86 (ou x86-64) assembly. E também não consegui encontrar uma boa explicação na web.
Eu sei que rep
é um prefixo que significa "repetir as próximas instruções cx
vezes" (ou pelo menos era, no antigo conjunto x86 de 16 bits). De acordo com esta tabela de resumo na Wikipedia , parece rep
só pode ser usado com movs
, stos
, cmps
, lods
, scas
(mas talvez essa limitação foi removida em processadores mais recentes). Assim, eu acho rep nop
(sem ponto-e-vírgula) repetiria nop
os cx
tempos de uma operação .
No entanto, depois de mais pesquisas, fiquei ainda mais confuso. Parece que rep; nop
e pause
mapeia exatamente para o mesmo opcode e pause
tem um comportamento um pouco diferente do que apenas nop
. Alguns e-mails antigos de 2005 diziam coisas diferentes:
- "tente não queimar muita energia"
- "é equivalente a 'nop' apenas com codificação de 2 bytes."
- "é mágico na inteligência. É como 'não, mas deixe o outro irmão HT correr'"
- "é uma pausa na inteligência e preenchimento rápido no Athlon"
Com essas opiniões diferentes, eu não conseguia entender o significado correto.
Ele está sendo usado no kernel Linux (em ambos i386 e x86_64 ), junto com este comentário: /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
Ele também está sendo usado no BeRTOS , com o mesmo comentário.
Respostas:
rep; nop
é de fato o mesmo que apause
instrução (opcodeF390
). Pode ser usado para montadores que ainda não suportam apause
instrução. Em processadores anteriores, isso simplesmente não fazia nada, apenas comonop
em dois bytes. Em novos processadores que suportam hyperthreading, ele é usado como uma dica para o processador de que você está executando um spinloop para aumentar o desempenho. Da referência de instrução da Intel :fonte
pause
, seu spin-loop é efetivamente um pipeline-clear mais lento para perceber a mudança de estado da localização da memória escrita por outro núcleo.rep nop
= F3 90 = a codificação parapause
, bem como como ele decodifica em CPUs mais antigas que não suportampause
.Prefixos (exceto
lock
) que não se aplicam a uma instrução são ignorados na prática pelas CPUs existentes.A documentação diz que o uso
rep
com instruções às quais não se aplica é "reservado e pode causar um comportamento imprevisível" porque futuras CPUs podem reconhecê-lo como parte de alguma nova instrução. Depois de estabelecer qualquer nova codificação de instrução específica usandof3 xx
, eles documentam como ela é executada em CPUs mais antigas. (Sim, o espaço do opcode x86 é tão limitado que eles fazem coisas malucas como esta e, sim, torna os decodificadores complicados.)Nesse caso, isso significa que você pode usar
pause
em spinloops sem quebrar a compatibilidade com versões anteriores . CPUs antigas que não conhecempause
irão decodificá-lo como um NOP sem causar danos, como garantido pela entrada dopause
manual ISA da Intel para . Em novas CPUs, você obtém o benefício de economia de energia / facilidade de HT e evita especulação incorreta de ordenação de memória quando a memória que você está girando muda e você sai do ciclo de rotação.Links para manuais da Intel e toneladas de outras coisas boas na página de informações wiki de tag x86
Outro caso de um
rep
prefixo sem sentido se tornando uma nova instrução em novas CPUs:lzcnt
éF3 0F BD /r
. Em CPUs que não suportam essa instrução (sem o sinalizador de recurso LZCNT em sua CPUID), ele decodifica comorep bsr
, que é executado da mesma forma quebsr
. Portanto, em CPUs antigas, ele produz32 - expected_result
e é indefinido quando a entrada era zero.Mas
tzcnt
ebsf
fazem a mesma coisa com entradas diferentes de zero, de modo que os compiladores podem usar e usamtzcnt
mesmo quando não há garantia de que a CPU de destino irá executá-lo comotzcnt
. As CPUs AMD têm velocidadetzcnt
, lentidãobsf
e na Intel são ambas rápidas. Contanto que não importe para a correção (você não está contando com a configuração de sinalizadores ou em deixar o comportamento de destino inalterado no caso de entrada = 0), fazer com que ele seja decodificado comotzcnt
em CPUs que o suportam é útil.Um caso de um
rep
prefixo sem sentido que provavelmente nunca decodificará de forma diferente:rep ret
é usado por padrão pelo gcc ao direcionar CPUs "genéricas" (ou seja, não direcionar uma CPU específica com-march
ou-mtune
, e não direcionar AMD K8 ou K10). Haverá décadas antes que alguém poderia fazer uma CPU que decodificarep ret
como algo diferente deret
, porque está presente na maioria dos binários na maioria das distros Linux. Veja o que significa `rep ret`?fonte
rep
prefixo também foi usado pela Intel para adicionar elisão de bloqueio.F2H
eF3H
) Reservados e pode resultar em um comportamento imprevisível na Tabela 11-3. Efeito dos prefixos nas instruções SSE, SSE2 e SSE3 . Portanto, a aplicação do prefixo é ignorada para algumas das instruções, não para todas. Então, esse recurso é considerado não documentado?f3 xx
, documentam como ela funciona em CPUs mais antigas.rep movbe
causa#UD
, por issorep
nem sempre é ignorado. Mesmo que não se aplique a uma instrução no sentido em que está especificada naREP/REPE/REPZ/REPNE/REPNZ
entrada manual.