Cosa significa "rep; nop; " significa in x86 assembly? È la stessa dell'istruzione "pausa"?


86
  • Cosa rep; nopsignifica?
  • È lo stesso pausedell'istruzione?
  • È uguale a rep nop(senza il punto e virgola)?
  • Qual è la differenza rispetto alla semplice nopistruzione?
  • Si comporta in modo diverso sui processori AMD e Intel?
  • (bonus) Dov'è la documentazione ufficiale per queste istruzioni?

Motivazione per questa domanda

Dopo alcune discussioni nei commenti di un'altra domanda , mi sono reso conto che non so cosa rep; nop;significhi nell'assembly x86 (o x86-64). E inoltre non sono riuscito a trovare una buona spiegazione sul web.

So che repè un prefisso che significa "ripeti i cxtempi di istruzione successivi " (o almeno lo era, nel vecchio assembly x86 a 16 bit). In base a questa tabella riassuntiva a Wikipedia , a quanto pare reppuò essere utilizzato solo con movs, stos, cmps, lods, scas(ma forse questa limitazione è stata rimossa su processori più recenti). Quindi, penserei rep nop(senza punto e virgola) ripeterei nopun'operazione cxvolte.

Tuttavia, dopo ulteriori ricerche, sono diventato ancora più confuso. Sembra che rep; nopsia pause mappato esattamente allo stesso codice operativo e pauseha un comportamento leggermente diverso dal semplice nop. Alcuni vecchi messaggi del 2005 dicevano cose diverse:

  • "cerca di non bruciare troppa energia"
  • "è equivalente a 'nop' solo con la codifica a 2 byte."
  • "è magico su Intel. È come 'nop ma lascia correre l'altro fratello HT'"
  • "è pausa su Intel e imbottitura veloce su Athlon"

Con queste diverse opinioni, non riuscivo a capire il significato corretto.

Viene utilizzato nel kernel Linux (sia su i386 che x86_64 ), insieme a questo commento: /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */Viene utilizzato anche in BeRTOS , con lo stesso commento.


Risposte:


75

rep; nopè effettivamente la stessa pausedell'istruzione (opcode F390). Potrebbe essere utilizzato per gli assemblatori che non supportano pauseancora l' istruzione. Sui processori precedenti, questo semplicemente non faceva nulla, proprio come nopma in due byte. Sui nuovi processori che supportano l'hyperthreading, viene utilizzato per suggerire al processore che si sta eseguendo uno spinloop per aumentare le prestazioni. Dal riferimento alle istruzioni di Intel :

Migliora le prestazioni dei cicli di spin-wait. Quando si esegue un "ciclo di attesa e rotazione", un processore Pentium 4 o Intel Xeon subisce una grave riduzione delle prestazioni quando esce dal ciclo perché rileva una possibile violazione dell'ordine della memoria. L'istruzione PAUSE fornisce un suggerimento al processore che la sequenza di codice è un ciclo di spin-wait. Il processore utilizza questo suggerimento per evitare la violazione dell'ordine della memoria nella maggior parte delle situazioni, il che migliora notevolmente le prestazioni del processore. Per questo motivo, si consiglia di inserire un'istruzione PAUSE in tutti i cicli di spin-wait.


4
Il ciclo di rotazione e attesa è lo stesso del ciclo di attesa occupata ? Questo "miglioramento" si applica solo ai processori hyperthreading? (e perché?)
Denilson Sá Maia

11
Sì, il ciclo di attesa e rotazione è lo stesso del ciclo di attesa occupata. Il vantaggio si applica anche alle CPU che non supportano l'hyper-threading. Può essere pensato come una limitazione del numero di istruzioni (non necessarie) nella pipeline (piuttosto che tentare di eseguire molte iterazioni del ciclo in parallelo)
Brendan

1
@Brendan, grazie! Non ho capito affatto, finché non hai detto la cosa sulle iterazioni del ciclo in parallelo.
Prof.Falken

11
@Brendan, Oh, ora ho capito! Questi processori moderni sono superscalari e quindi tenteranno di eseguire più istruzioni contemporaneamente. Se questo è un ciclo di attesa occupata, eseguire più istruzioni non lo renderà più veloce, poiché è solo in attesa di un'altra condizione.
Denilson Sá Maia

1
@Denilson: Sì, l'hyperthreading-friendly (o semplicemente il risparmio di energia senza HT) è un grande vantaggio, ma l'altro è evitare una speculazione errata nell'ordinamento della memoria quando si lascia lo spin-loop. Senza pause, il tuo spin-loop è effettivamente una pipeline-clear più lento per notare il cambiamento di stato della posizione di memoria scritta da un altro core.
Peter Cordes

15

rep nop= F3 90 = la codifica per pause, nonché il modo in cui decodifica su CPU meno recenti che non supportano pause.


I prefissi (diversi da lock) che non si applicano a un'istruzione vengono in pratica ignorati dalle CPU esistenti.

La documentazione dice che l'uso repcon istruzioni a cui non si applica è "riservato e può causare comportamenti imprevedibili" perché le future CPU potrebbero riconoscerlo come parte di qualche nuova istruzione. Una volta stabilita una nuova codifica specifica dell'istruzione utilizzando f3 xx, documentano come viene eseguita su CPU meno recenti. (Sì, lo spazio del codice operativo x86 è così limitato che fanno cose folli come questa, e sì, rende complicati i decoder.)

In questo caso, significa che puoi usare pausein spinloops senza rompere la compatibilità all'indietro . Le vecchie CPU che non conoscono pauselo decodificheranno come un NOP senza alcun danno, come garantito dall'immissione manuale di riferimento ISA di Intel perpause . Sulle nuove CPU, ottieni il vantaggio del risparmio energetico / compatibilità HT, ed eviti speculazioni errate sull'ordinamento della memoria quando la memoria su cui stai girando cambia e lasci il ciclo di rotazione.


Collegamenti ai manuali di Intel e tonnellate di altre cose interessanti nella pagina delle informazioni del wiki sui tag x86

Un altro caso in cui un repprefisso privo di significato diventa una nuova istruzione su nuove CPU: lzcntè F3 0F BD /r. Sulle CPU che non supportano tale istruzione (manca il flag della funzione LZCNT nel loro CPUID), si decodifica come rep bsr, che viene eseguito allo stesso modo di bsr. Quindi sulle vecchie CPU, produce 32 - expected_resulte non è definito quando l'input era zero.

Ma tzcnte bsffare la stessa cosa con input diversi da zero, quindi i compilatori possono e fanno uso tzcntanche quando non è garantito che la CPU di destinazione lo eseguirà come tzcnt. Le CPU AMD sono veloci tzcnt, lente bsfe su Intel sono entrambe veloci. Fintanto che non ha importanza per la correttezza (non ti affidi all'impostazione dei flag, o lasciando il comportamento non modificato della destinazione nel caso input = 0), è utile averlo decodificato come tzcntsulle CPU che lo supportano.


Un caso di un repprefisso privo di significato che probabilmente non decodificherà mai in modo diverso: rep retè usato di default da gcc quando prende di mira CPU "generiche" (cioè non si rivolge a una CPU specifica con -marcho -mtune, e non si rivolge a AMD K8 o K10). Passeranno decenni prima che chiunque potrebbe creare una CPU che decodifica rep retcome qualcosa di diverso da ret, perché è presente nella maggior parte dei binari nella maggior parte delle distribuzioni Linux. Vedi cosa significa "rep ret"?


3
Il repprefisso è stato utilizzato anche da Intel per aggiungere l'elisione del blocco.
Paul A. Clayton

I prefissi che non si applicano a un'istruzione vengono ignorati. Ma è menzionato che i prefissi di ripetizione ( F2He F3H) riservati e possono provocare un comportamento imprevedibile nella Tabella 11-3. Effetto dei prefissi sulle istruzioni SSE, SSE2 e SSE3 . Quindi l'applicazione del prefisso viene ignorata per alcune istruzioni, non per tutte. Quindi questa caratteristica è considerata non documentata?
Sant'Antario

2
@ Sant'Antario: Lo formulano in questo modo perché le future CPU potrebbero riconoscerlo come parte di qualche nuova istruzione. Su tutte le CPU reali è stato così e, una volta stabilita una codifica utilizzando f3 xx, documentano come funziona su CPU meno recenti.
Peter Cordes,

1
I prefissi (diversi da lock) che non si applicano a un'istruzione vengono in pratica ignorati dalle CPU esistenti. È documentato che rep movbecausa #UD, quindi repnon viene sempre ignorato. Anche se non si applica a un'istruzione nel senso specificato nell'inserimento REP/REPE/REPZ/REPNE/REPNZmanuale.
Sant'Antario

2
@ Sant'Antario: Interessante! In generale, però, per le istruzioni meno recenti i prefissi non applicabili vengono ignorati. Quando si introduce una nuova istruzione è possibile aggiungere regole più rigide se lo desiderano. IDK perché lo sceglierebbero per questo caso specifico.
Peter Cordes,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.