assembly - 为什么 LOOP 这么慢?

标签 assembly

这个问题在这里已经有了答案:





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中文件。但最终结果是一样的。

从这点开始我开始动脑- loopdec 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
这是可以理解的,因为pushfpopf必须玩内存。但是,假设,例如,寄存器 eax不保留在循环的末尾(可以通过更好地安排寄存器来实现),并且标志 OF循环中不需要(这简化了事情,因为 OF 不在 flag 的低 8 位中),那么我们可以使用 lahfsahf为了保持旗帜,所以我做了

实验六:

平台: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/

    相关文章:

    assembly - 修改Makefile生成程序集

    assembly - 在 ARM 中设置一位寄存器的最有效方法是什么?

    c - 为什么动态二进制翻译比静态二进制翻译更实用?

    assembly - 在除以零的中断处理程序中该怎么做?

    assembly - 在程序集问题中将大写字母转换为小写字母

    c - 这两个函数序言指令序列有什么区别?

    assembly - 这些汇编语言语句的含义是什么?

    c++ - 如何在没有硬件抽象层的情况下直接访问x64硬件?

    assembly - AVX 支持是否意味着 BMI1 支持?

    c++ - 简单的 x86-64 C++ 内联汇编 "Hello World"示例