这让我很吃惊,因为我一直认为loop
应该有一些内部优化。
以下是我今天做的实验。我使用的是Microsoft Visual Studio 2010.我的操作系统是64位Windows 8.我的问题就在最后。
第一个实验:
平台:Win32
模式:调试(禁用优化)
begin = clock();
_asm
{
mov ecx, 07fffffffh
start:
loop start
}
end = clock();
cout<<"passed time: "<<double(end - begin)/CLOCKS_PER_SEC<<endl;
输出:passed time: 3.583
(每次运行时,这个数字会有一点变化,但它在道德上的大小相同。)
第二次实验:
平台:Win32
模式:调试
begin = clock();
_asm
{
mov ecx, 07fffffffh
start:
dec ecx
jnz start
}
end = clock();
cout<<"passed time: "<<double(end - begin)/CLOCKS_PER_SEC<<endl;
输出:passed time: 0.903
第三和第四个实验:
只需将平台更改为x64即可。由于VC ++不支持64位内联汇编,我必须将循环放在另一个*.asm
文件中。但最后结果是一样的。
从这一点开始,我开始使用我的大脑 - loop
比dec ecx, jnz start
慢4倍,它们之间唯一的区别是AFAIK,dec ecx
改变了标志{ {1}}并非如此。为了模仿这种标志,我做了
第五个实验:
平台:Win32(以下我总是假设平台对结果没有影响)
模式:调试
loop
输出:begin = clock();
_asm
{
mov ecx, 07fffffffh
pushf
start:
popf
; do the loop here
pushf
dec ecx
jnz start
popf
}
end = clock();
cout<<"passed time: "<<double(end - begin)/CLOCKS_PER_SEC<<endl;
这是可以理解的,因为passed time: 22.134
和pushf
必须使用内存。但是,让我们说,例如,寄存器popf
不应保留在循环的末尾(这可以通过更好地安排寄存器来实现),并且标志{{1循环中不需要这个(这简化了事情,因为eax
不在OF
的低8位),那么我们可以使用OF
和flag
来保持标志,所以我做了
第六个实验:
平台:Win32
模式:调试
lahf
输出:sahf
这比直接使用begin = clock();
_asm
{
mov ecx, 07fffffffh
lahf
start:
sahf
; do the loop here
lahf
dec ecx
jnz start
sahf
}
end = clock();
cout<<"passed time: "<<double(end - begin)/CLOCKS_PER_SEC<<endl;
要好得多,对吗?
我做的最后一个实验是尝试保留passed time: 1.933
标志。
第七次实验:
平台:Win32
模式:调试
loop
输出:OF
这个结果是最坏的情况,即每个循环都没有设置begin = clock();
_asm
{
mov ecx, 07fffffffh
start:
inc al
sahf
; do the loop here
lahf
mov al, 0FFh
jo dec_ecx
mov al, 0
dec_ecx:
dec ecx
jnz start
}
end = clock();
cout<<"passed time: "<<double(end - begin)/CLOCKS_PER_SEC<<endl;
。它与直接使用passed time: 3.612
几乎相同......
所以我的问题是:
我是对的,使用循环的唯一好处是它会处理标志(实际上只有OF
对其中的5个有效)?
是否有loop
和dec
的更长形式也会移动lahf
,以便我们可以完全摆脱sahf
?
答案 0 :(得分:6)
从历史上看,在8088和8086处理器上,LOOP
是一个优化,因为它只比条件分支花了一个周期,而在分支之前放置一个DEC CX需要花费三到四个周期(取决于预取队列的状态。)
LOOP
指令与DEC CX/JNZ
一样有效工作的电路数量可能会超过整个 8086中的电路总量,可能是一个巨大的差距。制造商不是增加高性能CPU的复杂性,而是包括一个更简单但更慢的处理单元,它可以处理“模糊”的指令。虽然高性能CPU需要大量电路来允许执行多个指令重叠,除非后面的指令需要早期计算的结果(并且必须等到它们可用),“模糊指令处理单元”可以避免只需一次执行一条指令就需要这种电路。