Что произойдет, если начальный счетчик префикса x86 rep
будет равен нулю?
В руководстве Intel прямо говорится, что это while count != 0
цикл с тестом наверху, что является разумным ожидаемым поведением.
Но большинство расплывчатых отчетов, которые я видел в других местах, предполагают, что нет никакого начального теста на ноль, поэтому это будет похоже на обратный отсчет с тестом в конце, и поэтому катастрофа, если это repeat
{… count —=1; }
until count == 0;
или кто знает.
У z80 не было начального теста для своих строковых инструкций, может быть, вы слышали это в этом контексте?
Я старый профессиональный программист Z80 на ассемблере. Так что, возможно, страх остался в моем сердце.
При RCX=0 ничего не происходит; rep
префиксы сначала проверяют наличие нуля, как говорит псевдокод. (В отличие от инструкции loop
, которая точно такая же, как нижняя часть do{}while(--ecx)
или dec rcx
/jnz
, но не влияет на ФЛАГИ.)
Я думаю, что слышал, что это редко используется в качестве идиомы для условной загрузки или сохранения с rep lodsw
или rep stosw
со счетом 0 или 1, особенно в старые добрые времена до cmov. (cmov
— это безусловная загрузка, подающая операцию выбора ALU, поэтому ей нужен допустимый адрес, в отличие от rep lods
с нулевым счетчиком.) Это неэффективно, особенно для rep stos
на современном x86 с микрокодом Fast Strings (P6 и выше), особенно без что-нибудь вроде Fast Short Rep-Moves (Ice Lake IIRC.)
То же самое относится к инструкциям, которые обрабатывают префиксы как repz
/ repnz
(cmps/scas) вместо безусловного rep
(lods/stos/movs). Выполнение нулевых итераций означает, что они оставляют FLAGS немодифицированными.
Если вы хотите проверить FLAGS после repe/ne cmps/scas
, вам нужно убедиться, что счетчик не равен нулю, или что FLAGS уже установлен таким образом, что вы будете выполнять полезный переход для буферов нулевой длины. (Возможно, из-за xor-обнуления регистра, который вам понадобится позже.)
rep movs
и rep stos
имеют микрокод быстрых строк на ЦП, начиная с P6, но накладные расходы при запуске делают их редкостными, особенно когда размеры могут быть короткими и/или данные могут быть смещены. Они более полезны в коде ядра, где вы не можете свободно использовать регистры XMM. Некоторые последние процессоры, такие как Ice Lake, имеют микрокод fast-short-rep, который, я думаю, должен уменьшить накладные расходы при запуске для небольших количеств.
repe/ne scas/cmps
не имеют микрокода быстрых строк на большинстве процессоров, только на самых последних процессорах, таких как Sapphire Rapids и, возможно, на P-ядрах Alder Lake. Таким образом, они довольно медленные, например, одна загрузка за такт (то есть 2 цикла за счет для cmpsb/w/d/q
), согласно тестированию https://agner.org/optimize/ и https://uops.info/.
-O1
использовал repne scasb
для встраивания strlen
. Это катастрофа для длинных строк.rep movs
будет использовать хранилища без RFO для больших размеров, аналогично хранилищам NT, но без обхода кеша. Хорошие общие вопросы и ответы о соображениях пропускной способности памяти.repe
и repne
оба работают одинаково, если счетчик изначально равен нулю, то повторные инструкции пропускаются без какого-либо эффекта. Важно отметить, что флаги не изменяются инструкцией cmps
или scas
, пропущенной таким образом. Поэтому, если вы хотите перейти, например, к нулевому флагу, вы должны убедиться, что счетчик изначально никогда не равен нулю, или что нулевой флаг предварительно инициализирован так, как вы хотите, например, в hg.pushbx.org/ecm. /ldebug/file/eb3730a8118e/источник/…@ecm: Спасибо, я думаю, что возможная ошибка без изменений FLAGS была тем, что я пытался запомнить как «особое» в нулевом счете для rep[n]e cmps/scas. Обновлять.
Я добавил явную условную ветку вверху и хотел бы удалить ее, если смогу.