循环(英特尔参考手册)
减量 ecx/rcx,如果非零则跳跃。它的速度很慢,但是英特尔不能廉价地让它变得更快吗?在 Sandybridge-family 上,dec/jnz
已经是 宏融合成一个单独的 uop了; 唯一的区别在于它设置了标志。
loop
on various microarchitectures, from Agner Fog 的指令表:
K8/K10:7m-ops
Bulldozer-family/Ryzen : 1 m-op (与宏融合测试和分支(或 jecxz
)相同的成本)
P4:4 Uops (与 jecxz
相同)
P6(PII/PIII) : 8 UOP
奔腾 M,核心2:11
Nehalem: 6分钟(loope
/loopne
为11分钟)。吞吐量 = 4c (loop
)或7c (loope/ne
)。
SnB-family : 7 uops.(loope
/loopne
为11)。吞吐量 = 每5个周期一个,作为一个瓶颈,因为保持您的循环计数器在内存中!jecxz
只有2个 uops,其吞吐量与常规 jcc
相同
西尔弗蒙特,七个人
AMD Jaguar (低功耗) : 8 uops,5c 吞吐量
通过 Nano3000:2 uops
难道解码器不能像 lea rcx, [rcx-1]
/jrcxz
一样解码吗?一共是三个人。至少在没有地址大小前缀的情况下是这样的,否则它必须使用 ecx
,并在跳转时将 RIP
截断为 EIP
; 也许地址大小的奇怪选择控制了减价的宽度,解释了为什么会有这么多支票?(有趣的事实: rep
-string 指令与使用32位地址大小的 ecx
具有相同的行为)
或者更好的方法是,把它解码为一个融合的不会设置标志的 dec-and-Branch?SnB 上的 dec ecx
/jnz
解码为一个 uop (它设置标志)。
我知道真正的代码不会使用它(因为它至少从 P5或者其他什么时候开始就一直很慢) ,但是 AMD 认为这是值得的,因为它可以让推土机变得更快。可能是因为太容易了。
对于 SnB 家族来说,拥有快速的 loop
是否容易?如果是这样,他们为什么不呢?如果不是,为什么这么难?很多解码器晶体管?或者在一个融合的十二月和分支上的额外位来记录它不设置标志?那7个人在干什么?这是个很简单的指令。
推土机有什么特别之处使得快速 loop
变得容易/值得?还是 AMD 浪费了一堆晶体管来让 loop
变得更快?如果是这样,想必有人认为这是个好主意。
如果 loop
是 fast ,那么对于 BigInteger 任意精度的 adc
循环,以避免部分标志停滞/减速(请参阅我在答案中的评论)或者任何其他不需要触摸标志的循环来说都是完美的。与 dec/jnz
相比,它还有一个小的代码大小优势。(dec/jnz
只在 SnB- 家族上使用大熔丝)。
在 ADC 循环中 dec/jnz
没问题的现代 CPU 上,loop
仍然适合 ADCX/ADOX 循环(保留 OF)。
如果 loop
很快的话,编译器早就把它当作一个窥视孔来优化 CPU 的代码大小 + 速度,而不需要进行宏融合了。
这并不能阻止我对每个循环都使用 loop
的糟糕的16位代码的所有问题感到恼火,即使他们在循环中还需要另一个计数器。但至少不会是坏的 作为。