LOOP (запись в ручном режиме Intel ref) уменьшает ecx/rcx, а затем перескакивает, если отличная от нуля. Это медленное, но не могло ли Intel дешево сделать это быстро? dec/jnz
уже макро-предохранители в один uop на семье Sandybridge; с той лишь разницей, что это устанавливает флаги.
loop
на различных микроархитектурах, из таблиц инструкций Agner Fog:
- K8/K10: 7 m-ops
-
Bulldozer-family/Ryzen: 1 m-op (
jecxz
же стоимость, как и макро-сплавленная тестовая ветвь илиjecxz
) -
P4: 4 uops (то же, что и
jecxz
) - P6 (PII/PIII): 8 часов
- Pentium M, Core2: 11 uops
- Nehalem: 6 часов. (11 для
loope
/loopne
). Пропускная способность = 4c (loop
) или 7c (loope/ne
). - SnB-family: 7 uops. (11 для
loope
/loopne
). Пропускная способность = один на 5 циклов, как большая часть узкого места, так как ваш счетчик циклов в памяти!jecxz
- это всего 2 выхода с одинаковой пропускной способностью, как обычныйjcc
- Silvermont: 7 часов
- AMD Jaguar (маломощный): 8 часов, пропускная способность 5 с
- Через Nano3000: 2 uops
Не могли ли декодеры просто декодировать то же, что и lea rcx, [rcx-1]
/jrcxz
? Это будет 3 часа. По крайней мере, это будет иметь место без префикса размера адреса, в противном случае он должен использовать ecx
и обрезать RIP
для EIP
если EIP
переход; возможно, странный выбор размера адреса, управляющего шириной декремента, объясняет многие ошибки?
Или лучше, просто расшифруйте его как плавкую де-и-ветку, которая не устанавливает флаги? dec ecx
/jnz
на SnB декодирует до одного uop (который устанавливает флаги).
Я знаю, что настоящий код не использует его (потому что он был медленным, так как по крайней мере P5 или что-то еще), но AMD решила, что стоило бы быстро сделать это для Bulldozer. Наверное, потому что это было легко.
-
Было бы легко, чтобы уарм семейства SnB имел быструю
loop
? Если да, то почему? Если нет, то почему это сложно? Много транзисторов декодера? Или дополнительные биты в объединенном dec & branch uop для записи, что он не устанавливает флаги? Что могли бы сделать эти 7? Это действительно простая инструкция. -
Что особенного в Bulldozer, который сделал быстрый
loop
легким/стоит? Или AMD потратила кучу транзисторов на быстрыйloop
? Если это так, то, по-видимому, кто-то думал, что это хорошая идея.
Если бы loop
был быстрым, это было бы идеально для целых циклов adc с произвольной точностью BigInteger, чтобы избегать партитур /adc
с частичным флагом (см. Мои комментарии к моему ответу) или любого другого случая, когда вы хотите зацикливать, не касаясь флагов. Он также имеет незначительное преимущество по сравнению с dec/jnz
. (И dec/jnz
только макро-предохранители на семействе SnB).
На современных процессорах, где dec/jnz
в порядке в цикле ADC, loop
все равно будет приятным для циклов ADCX/ADOX (для сохранения OF).
Если бы loop
был быстрым, компиляторы уже использовали бы его как оптимизацию подкачки для скорости кода + скорость на процессорах без макро-слияния.
Это не помешало бы мне разозлиться на все вопросы с плохим 16-битным кодом, который использует loop
для каждого цикла, даже если им нужен еще один счетчик внутри цикла. Но, по крайней мере, это было бы не так плохо.