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 для каждого цикла, даже если им нужен еще один счетчик внутри цикла. Но, по крайней мере, это было бы не так плохо.