Отличный пост сегодня на hn, трюк знакомый, пугающий, и вроде даже в комментариях разобрались.

https://news.ycombinator.com/item?id=42579969

https://tavianator.com/2025/shlx.html



Автор поста обнаружил, что при таком патче в определённых условиях.



LOOP:

- MOV RCX, 1

+ MOV ECX, 1





Инструкция SHLX RAX, RAX, RCX (означающая RAX = RAX << RCX) ускоряется в три раза на Alder Lake.



Почему?



Решение этой загадки скорее всего заключается в том, что в Alder Lake увели много инструкций в стадию rename -- это когда процессор не ждёт регистра и его результата, а выдаёт новый готовый регистр (возможно с метаданными, например, что к нему надо что-то добавить). Например, лучше всего это видно в случаях циклов.



loop:

inc rax

cmp rax, rcx

jb .loop



Существуют две стратегии как переименовывать RAX, например



r1 = rax

r2 = r1 + 1

r3 = r2 + 1

...





Пока не закончатся физические регистры на самом процессоре. Можно слегка по-другому:



r1 = rax

r2 = r1 + 1

r3 = r1 + 2

r4 = r1 + 3

...





Тем самым вы делаете трейдофф между кодированием как выдать новый регистр и параллелизмом (r3 не надо ждать r2 и тд, но зато число 2 надо где-то закодировать). В реальности там скорее всего поддерживается до определённого лимита. Вы удивитесь, но вторую стратегию стали только применять с Alder Lake. Более удивительный вопрос, почему MOVE ECX работает, когда 64 битный RCX нет. Казалось бы :)



Там в целом можно упороться и в процессорах существуют регистры с константами, поэтому mov ecx, 1024будет быстрым, когда как mov ecx, 1023 медленным.



Почитать про этот трюк можно тут



https://www.computerenhance.com/p/the-case-of-the-missing-increment#footnote-anchor-6-149406677



Вот такие сюрпризы бывают.