“如果为零跳”(jz)更快吗?

时间:2014-09-05 04:39:18

标签: performance optimization assembly cpu-registers cpu-architecture

我正在阅读this article,我注意到了jz指令。这让我想到了:

这段代码的汇编

for (int i=max;i!=0;--i){
    //Some operation
}

优于此代码的程序集?

for (int i=0;i<max;++i){
    //Some operation
}

只要您不关心数据是否随着i的增加而处理,就没有语义差异。高速缓存未命中也不应该受到影响,因为它们可以按任意方式顺序工作。

我在汇编时写的不够好,但我认为第一个例子只使用jz。第二个使用cmp,然后是jg,还需要另一个变量max。第一个例子只需要循环计数器,因为0是隐式的。

这也可能是编译器用来优化的东西,但我可以想象它无法进行优化的情况。

3 个答案:

答案 0 :(得分:2)

假设我们有cmp a,b

处理器将临时减去操作数(不影响其值),正确设置标志,然后评估jmp跳转操作。

因此,在您的示例中,制作jz,而不是cmpjmp的速度更快。

答案 1 :(得分:0)

我认为这主要是solved problem与现代编译器。或者,如果没有解决,那么至少通常正确,应用启发式方法来产生更好的循环变换。对于x86 [-64],有更重要的考虑因素,例如,循环&#39; body&#39;适合指令缓存?跳跃目的地是否适当对齐?分支预测是否有效?

使用x86实现循环有多种方法。例如,

  • 使用j[e|r]cxz指令,避免标记寄存器 - 虽然解码速度较慢。

  • sub之前使用addj<cond>而不是decinc,以避免部分标记寄存器停止。

    < / LI>

operation也很重要。编译时是否知道max

for (int i = 0; i < max / 4; i++)
{
    operation;
    operation;
    operation;
    operation;
}

如果operation足够简单(例如,浮点运算),它可能会从这种n路调度中受益。如果每个操作都取决于之前的操作,则不会。

查看GMP之类的内容。 mpn/x86[-64]目录为不同的微架构优化循环。 Agner Fog's optimization manuals是一个很好的资源。

答案 2 :(得分:0)

有时循环倒计时可以释放一个寄存器,这可能会比跳转条件的任何差异更有用(特别是在x86-32,寄存器很少)。

然而,在循环中倒计时可以防止自动矢量化。如果你的计算可以使用SSE / AVX /无论如何,你可能需要编写像

这样的代码
for (i=end; i;){
    i-=4;
    val[i+0] = foo(i);
    val[i+1] = foo(i);
    val[i+2] = foo(i);
    val[i+3] = foo(i);
    }

然后你必须确保end%4 == 0,以保存一个寄存器。