这个问题在这里已经有了答案:
Why is the loop instruction slow? Couldn't Intel have implemented it efficiently?
(3 个回答)
3年前关闭。
这让我很惊讶,因为我一直认为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
更改标志同时 loop
没有。为了模仿这个标志,我做了实验五:
平台:Win32(以下我一直假设平台对结果没有影响)
模式:调试
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
必须玩内存。但是,假设,例如,寄存器 eax
不保留在循环的末尾(可以通过更好地安排寄存器来实现),并且标志 OF
循环中不需要(这简化了事情,因为 OF
不在 flag
的低 8 位中),那么我们可以使用 lahf
和 sahf
为了保持旗帜,所以我做了实验六:
平台:Win32
模式:调试
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
这仍然比使用
loop
好得多直接对吧?我做的最后一个实验是尝试同时保留
OF
旗帜。实验七:
平台:Win32
模式:调试
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
不是在每个循环中设置。和使用 loop
几乎一样直接地 ...所以我的问题是:
dec
对其中的 5 个有影响)? lahf
是否有更长的形式?和 sahf
这也移动 OF
,这样我们就可以彻底摆脱loop
? 最佳答案
从历史上看,在 8088 和 8086 处理器上,LOOP
是一种优化,因为它只比条件分支多花一个周期,而在分支之前放置 DEC CX 将花费三到四个周期(取决于预取队列的状态)。
然而,今天的处理器与 8086 的工作方式非常不同。 对于几代处理器,即使制造商制造的机器基本上可以正确处理 8088/8086 或其后代拥有的所有记录指令,但他们一直专注于他们的精力只用于提高最有用指令的性能。出于各种原因,英特尔或 AMD 必须为现代 CPU 添加大量电路才能制造 LOOP
指导工作与 DEC CX/JNZ
一样高效可能会超过整个 8086 的电路总量,可能是一个巨大的差距。制造商并没有增加高性能 CPU 的复杂性,而是提供了一个更简单但速度更慢的处理单元,可以处理“晦涩的”指令。虽然高性能 CPU 将需要大量电路来允许多条指令的执行重叠,除非后面的指令需要早期计算的结果(并且必须等到它们可用),但“模糊指令处理单元”可以避免只需一次执行一条指令即可实现这种电路。
关于assembly - 为什么 LOOP 这么慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21565046/