我不是想要一个基准。
(如果是这样的话,我会亲自动手的。)
我的问题是:
为了方便起见,我倾向于避免间接/索引寻址模式。
作为替代,我经常使用即时、绝对或注册地址。
守则:
; %esi has the array address. Say we iterate a doubleword (4bytes) array.
; %ecx is the array elements count
(0x98767) myloop:
... ;do whatever with %esi
add $4, %esi
dec %ecx
jnz 0x98767;这里,我们有一个序列化的组合体(dec和jnz),它阻止了正常的无序执行(依赖关系)。
有什么办法可以避免那个/打破这个错误吗?(我不是装配专家)。
发布于 2015-08-03 01:53:59
当对Intel CPU进行优化时,总是将设置标志的指令放在条件跳转指令之前(如果它是下表中列出的简单指令之一),这样它们就可以在解码器中融合到一个uop中。
对于不进行宏融合的旧CPU来说,这样做并不会显着地更糟。提前设置标志可能会将分支错误地预测对此类CPU的惩罚,但无序执行意味着将dec提前一对指令移动将不会产生真正的影响。另见通过提前计算条件来避免管道停滞。要真正发挥作用,您可以在一些可以更简单地计算的东西上展开循环和/或分支,理想情况下不依赖于缓慢的输入,因此OoO exec可以在处理循环体的旧迭代时已经解析分支。也就是说,环路计数器dep链可以在主要工作之前运行。
我没有基准,但我不认为越来越少的CPU的小缺点是有理由忽略前端吞吐量好处(解码和发行)的CPU进行融合。总uop吞吐量通常是一个瓶颈。
AMD /Piledriver/Steamroller可以将test/cmp与任何jcc融合,但只有test/cmp,而不是任何其他ALU指令。所以肯定要和树枝做比较。对于英特尔的CPU来说,如果它们可以在沙桥家族上进行宏融合,那么把其他的东西放在分支上仍然是很有价值的。
来自阿格纳雾微弓指南,表9.2 (用于沙桥/象牙桥):
First | can pair with these | cannot pair with
instruction | (and the inverse) |
---------------------------------------------
cmp |jz, jc, jb, ja, jl, jg| js, jp, jo
add, sub |jz, jc, jb, ja, jl, jg| js, jp, jo
adc, sbb |none |
inc, dec |jz, jl, jg | jc, jb, ja, js, jp, jo
test | all |
and | all |
or, xor, not, neg | none |
shift, rotate | none |
Table 9.2. Instruction fusion因此,基本上,只要条件只依赖于由inc/dec修改的位,jcc就可以与inc/dec进行宏融合。
(否则,它们没有宏保险丝,就会插入一个额外的uop来合并标志(就像在编写eax之后读取al时一样)。或者在早期的CPU上,一个部分标志停止。)
Core2 / Nehalem在宏融合能力上比较有限(仅用于CMP/测试,且有更多的JCC组合),而Core2在64位模式下根本不能进行宏融合。
如果您还没有阅读Agner的优化asm和C指南。他们充满了基本的知识。
https://stackoverflow.com/questions/31771526
复制相似问题