- Что
rep; nop
значит? - Это то же самое, что и
pause
инструкция? - Это то же самое, что
rep nop
(без точки с запятой)? - Чем отличается простая
nop
инструкция? - По-разному ли ведет себя на процессорах AMD и Intel?
- (бонус) Где официальная документация к этим инструкциям?
Мотивация на этот вопрос
После некоторого обсуждения в комментариях к другому вопросу я понял, что не знаю, что rep; nop;
означает сборка x86 (или x86-64). К тому же я не смог найти в сети хорошего объяснения.
Я знаю, что rep
это префикс, который означает «повторить следующую команду cx
раз» (или, по крайней мере, так было в старой 16-битной сборке x86). Согласно этой сводной таблице в Википедии , кажется , rep
могут быть использованы только с movs
, stos
, cmps
, lods
, scas
(но , возможно , это ограничение было снято на новых процессорах). Таким образом, я бы подумал rep nop
(без точки с запятой) повторил бы nop
операцию cx
раз.
Однако после дальнейших поисков я запутался еще больше. Кажется, что rep; nop
и pause
отображается на один и тот же код операции и pause
имеет немного другое поведение, чем просто nop
. В одной старой почте от 2005 года говорилось о другом:
- "постарайтесь не сжигать слишком много энергии"
- "это эквивалентно nop только с двухбайтовой кодировкой".
- "Это магия на разведке. Это как" нет, но пусть другой брат HT бежит ""
- "это пауза на Intel и быстрое дополнение на Athlon"
С этими разными мнениями я не мог понять правильного значения.
Он используется в ядре Linux (как на i386, так и на x86_64 ) вместе с этим комментарием: /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
Он также используется в BeRTOS с тем же комментарием.
Ответы:
rep; nop
действительно совпадает сpause
инструкцией (код операцииF390
). Его можно использовать для ассемблеров, которые еще не поддерживаютpause
инструкцию. На предыдущих процессорах это просто ничего не делало, как иnop
в двух байтах. На новых процессорах, поддерживающих гиперпоточность, он используется как подсказка процессору, что вы выполняете спин-петлю для повышения производительности. Из справочника инструкций Intel :источник
pause
ваш спин-цикл будет фактически на один конвейер медленнее, чтобы заметить изменение состояния области памяти, записанной другим ядром.rep nop
= F3 90 = кодировкаpause
, а также то, как она декодируется на старых процессорах, которые не поддерживаютpause
.Префиксы (кроме
lock
), которые не применяются к инструкции, на практике игнорируются существующими процессорами.В документации говорится, что использование
rep
с инструкциями, к которым оно не применяется, «зарезервировано и может вызвать непредсказуемое поведение», потому что будущие процессоры могут распознавать его как часть какой-то новой инструкции. Как только они устанавливают какую-либо конкретную новую кодировку инструкцийf3 xx
, они документируют, как она работает на старых процессорах. (Да, пространство кода операции x86 настолько ограничено, что они делают такие сумасшедшие вещи, и да, это усложняет декодеры.)В этом случае это означает, что вы можете использовать
pause
циклические циклы без нарушения обратной совместимости . Старые процессоры, которые не знают об этом,pause
будут декодировать его как NOP без какого-либо вреда, как гарантирует вводpause
вручную Intel ISA ref для . На новых процессорах вы получаете преимущество энергосбережения / HT-дружественности и избегаете неправильных предположений о порядке памяти, когда память, на которой вы вращаетесь, действительно изменяется, и вы выходите из цикла вращения.Ссылки на руководства Intel и множество других полезных материалов на информационной странице wiki-тега x86
Еще один случай, когда бессмысленный
rep
префикс становится новой инструкцией на новых процессорах:lzcnt
isF3 0F BD /r
. На процессорах, которые не поддерживают эту инструкцию (отсутствует флаг функции LZCNT в их CPUID), он декодируется какrep bsr
, который выполняется так же, какbsr
. Таким образом, на старых процессорах он производит32 - expected_result
и не определен, когда вход был нулевым.Но
tzcnt
иbsf
сделайте то же самое с ненулевыми входными данными, чтобы компиляторы могли использовать и используют,tzcnt
даже если не гарантируется, что целевой ЦП будет запускать его какtzcnt
. У процессоров AMD есть быстрыеtzcnt
и медленныеbsf
, а у Intel они оба быстрые. До тех пор, пока это не имеет значения для правильности (вы не полагаетесь на установку флага или не оставляете неизменное поведение пункта назначения в случае input = 0),tzcnt
полезно его декодирование, как на процессорах, которые его поддерживают.Один случай бессмысленного
rep
префикса, который, вероятно, никогда не будет декодироваться по-другому:rep ret
используется по умолчанию gcc при нацеливании на «общие» процессоры (т.е. не нацеленный на конкретный процессор с помощью-march
или-mtune
, и не нацеленный на AMD K8 или K10). мог бы сделать процессор, который декодируетrep ret
что угодно, кромеret
, потому что он присутствует в большинстве двоичных файлов в большинстве дистрибутивов Linux. См. Что означает `rep ret`?источник
rep
Префикс также используется Intel для добавления блокировки Пропуска.F2H
иF3H
) зарезервированы и могут привести к непредсказуемому поведению в таблице 11-3. Влияние префиксов на инструкции SSE, SSE2 и SSE3 . Таким образом, применение префикса игнорируется для некоторых инструкций, а не для всех. Так считается ли эта функция недокументированной?f3 xx
они документируют, как она работает на старых процессорах.rep movbe
причины#UD
, поэтомуrep
не всегда игнорируется. Даже если это не относится к инструкции в том смысле, как это указано вREP/REPE/REPZ/REPNE/REPNZ
ручном вводе.