- Co to
rep; nop
znaczy? - Czy to to samo, co
pause
instrukcja? - Czy to to samo co
rep nop
(bez średnika)? - Jaka jest różnica w stosunku do prostej
nop
instrukcji? - Czy zachowuje się inaczej na procesorach AMD i Intel?
- (bonus) Gdzie jest oficjalna dokumentacja tych instrukcji?
Motywacja do tego pytania
Po krótkiej dyskusji w komentarzach do innego pytania zdałem sobie sprawę, że nie wiem, co to rep; nop;
znaczy w asemblerze x86 (lub x86-64). Nie mogłem też znaleźć dobrego wyjaśnienia w internecie.
Wiem, że rep
jest to przedrostek, który oznacza „powtórz czas następnej instrukcji cx
” (a przynajmniej tak było w starym 16-bitowym zestawie x86). Według tej tabeli podsumowującej w Wikipedii , wydaje się rep
może być używany tylko z movs
, stos
, cmps
, lods
, scas
(ale może to ograniczenie zostało usunięte w nowszych procesorów). Dlatego myślę, że rep nop
(bez średnika) powtórzyłbym nop
operację cx
razy.
Jednak po dalszych poszukiwaniach jeszcze bardziej się zdezorientowałem. Wydaje się, że rep; nop
i pause
map do dokładnie tego samego kodu operacji i pause
ma nieco inne zachowanie niż tylko nop
. Niektóre stare listy z 2005 roku mówiły różne rzeczy:
- „staraj się nie spalać zbyt dużo energii”
- „jest to odpowiednik 'nop' tylko z kodowaniem 2-bajtowym”.
- „To jest magia na temat danych wywiadowczych. To jak 'nie, ale niech ucieknie inne rodzeństwo HT'”
- „jest przerwa w informacjach i szybkie uzupełnianie informacji na temat Athlona”
Przy tych różnych opiniach nie mogłem zrozumieć właściwego znaczenia.
Jest używany w jądrze Linuksa (zarówno na i386, jak i x86_64 ), wraz z następującym komentarzem: /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
Jest również używany w BeRTOS , z tym samym komentarzem.
Odpowiedzi:
rep; nop
jest rzeczywiście taka sama jakpause
instrukcja (kod operacjiF390
). Może być używany dla asemblerów, którzy jeszcze nie obsługują tejpause
instrukcji. Na poprzednich procesorach to po prostu nic nie dało, tak jaknop
tylko w dwóch bajtach. W przypadku nowych procesorów obsługujących wielowątkowość jest używany jako wskazówka dla procesora, że wykonujesz pętlę spinloop w celu zwiększenia wydajności. Z instrukcji firmy Intel :źródło
pause
tego pętla spinowa jest efektywnie usuwana o jeden potok wolniej, aby zauważyć zmianę stanu lokalizacji pamięci zapisanej przez inny rdzeń.rep nop
= F3 90 = kodowaniepause
, a także sposób dekodowania na starszych procesorach, które nie obsługująpause
.Prefiksy (inne niż
lock
), które nie dotyczą instrukcji, są w praktyce ignorowane przez istniejące procesory.Dokumentacja mówi, że używanie
rep
z instrukcjami, których nie dotyczy, jest „zastrzeżone i może powodować nieprzewidywalne zachowanie”, ponieważ przyszłe procesory mogą je rozpoznać jako część nowej instrukcji. Kiedy już ustalą nowe kodowanie instrukcjif3 xx
, dokumentują, jak działa na starszych procesorach. (Tak, przestrzeń kodu operacji x86 jest tak ograniczona, że robią takie szalone rzeczy i tak, to komplikuje dekodery).W tym przypadku oznacza to
pause
, że możesz używać w spinloopach bez przerywania wstecznej kompatybilności . Stare procesory, które nie wiedzą opause
tym, dekodują go jako NOP bez szkody, co jest gwarantowane przez ręczny wpis dotyczącypause
ISA firmy Intel dla . W przypadku nowych procesorów zyskujesz oszczędność energii / przyjazność dla HT i unikasz błędnych spekulacji związanych z kolejnością pamięci, gdy pamięć, na której się obracasz, zmienia się i opuszczasz pętlę spinową.Linki do podręczników Intela i mnóstwa innych dobrych rzeczy na stronie informacyjnej wiki tagów x86
Innym przypadkiem bezsensownego
rep
prefiksu, który staje się nową instrukcją dla nowych procesorów:lzcnt
jestF3 0F BD /r
. Na procesorach, które nie obsługują tej instrukcji (brakuje flagi funkcji LZCNT w ich CPUID), dekoduje jakorep bsr
, który działa tak samo jakbsr
. Więc na starych procesorach generuje32 - expected_result
i jest niezdefiniowany, gdy wartość wejściowa wynosiła zero.Ale
tzcnt
ibsf
robią to samo z niezerowymi wejściami, więc kompilatory mogą i używajątzcnt
nawet wtedy, gdy nie ma gwarancji, że docelowy procesor będzie go uruchamiał jakotzcnt
. Procesory AMD są szybkietzcnt
i wolnebsf
, a na Intelu oba są szybkie. O ile nie ma to znaczenia dla poprawności (nie polegasz na ustawianiu flag ani na pozostawianiu niezmodyfikowanego zachowania celu w przypadku input = 0),tzcnt
pomocne jest dekodowanie go tak, jak na procesorach, które go obsługują.Jeden przypadek bezsensownego
rep
prefiksu, który prawdopodobnie nigdy nie będzie dekodował inaczej:rep ret
jest używany domyślnie przez gcc, gdy celujemy w "ogólne" procesory (tj. Nie jest celowany w konkretny procesor z-march
lub-mtune
i nie jest przeznaczony dla AMD K8 lub K10). Miną dekady, zanim ktokolwiek może stworzyć procesor, który dekodujerep ret
jak cokolwiek innego niżret
, ponieważ jest obecny w większości plików binarnych w większości dystrybucji Linuksa. Zobacz Co oznacza „rep ret”?źródło
rep
Prefiks został również wykorzystywane przez firmy Intel, aby dodać blokady elizja.F2H
iF3H
) zastrzeżone i może spowodować nieprzewidywalne zachowanie w tabeli 11-3. Wpływ prefiksów na instrukcje SSE, SSE2 i SSE3 . Tak więc aplikacja prefiksu jest ignorowana dla niektórych instrukcji, a nie dla wszystkich. Czy więc ta funkcja jest uważana za nieudokumentowaną?f3 xx
, dokumentują, jak działa na starszych procesorach.rep movbe
powoduje#UD
, więcrep
nie zawsze jest ignorowane. Nawet jeśli nie dotyczy instrukcji w sensie określonym weREP/REPE/REPZ/REPNE/REPNZ
wpisie ręcznym.