C++转换为汇编语言

C++ convert to assembly language

本文关键字:汇编语言 转换 C++      更新时间:2023-10-16

这是我的任务。我已经为这个程序集完成了我的代码,但是有没有办法使转换速度更快?提前感谢任何帮助;D

//Convert this nested for loop to assembly instructions
    for (a = 0; a < y; a++)
        for (b = 0; b < y; b++)
            for (c = 0; c < y; c++)
                if ((a + 2 * b - 8 * c) == y)
                    count++;
convert
    _asm {
                mov ecx,0
                mov ax, 0
                mov bx, 0
                mov cx, 0
                Back:
                push cx
                push bx
                push ax
                add bx, bx
                mov dx, 8
                mul dx
                add cx, bx
                sub cx, ax
                pop ax
                pop bx
                cmp cx, y
                jne increase
                inc count
                increase : pop cx
                          inc ax
                           cmp ax, y
                           jl Back
                           inc bx
                           mov ax, 0
                           cmp bx, y
                           jl Back
                           inc cx
                           mov ax, 0
                           mov bx, 0
                           cmp cx, y
                           jl Back
        }

一些通用技巧:

  1. 使您的循环计数器倒计时而不是向上倒计时。你以这种方式消除比较。
  2. 了解LEA的魔力,以计算包含加法和按 2 的某些幂缩放的表达式。你不需要在任何地方MUL
  3. 提升机回路不变工作在内回路外。 对于 c 循环的每次迭代,a + 2*b都是常数。
  4. 使用 SIDI 来保存值。 这应该可以帮助您避免所有这些pushpop说明。
  5. 如果您的值适合 8 位,请使用 AHAL 等来更有效地使用寄存器。

哦,inc cx之后你不需要那个mov ax, 0,因为那里AX已经是 0。

特定于此算法:如果y奇数,则跳过a偶数的迭代,反之亦然。 近 2 倍的加速等待着您... (如果你想知道为什么,可以用铅笔和纸锻炼。 提示:您也不需要测试每次迭代。 如果你足够聪明,你可以简单地一步2秒。

或者更好的是,制定一个封闭的形式,让你直接计算答案。

优化时,始终从高处开始,然后从低处开始,即从算法级别开始,当一切都用尽时,转到程序集转换。

首先,观察:

8 * c = (a + 2 * b - y)

每个三元组(a,b,y(都有一个唯一的c解。

这是什么意思? 您的 3 个循环可以折叠为 2 个。 这是从θ y^3到θ y^2 的运行时的巨大减少。

重写代码:

for (a = 0; a < y; a++)
    for (b = 0; b < y; b++) {
        c = (a+2*b-y);
        if (((c%8)==0) && (c >= 0)) count++;
    }

接下来观察 c>=0 表示:

      a+2*b-y >= 0 
      a+2*b >= y
      a >= y-2b

请注意,这两个循环可以互换,这给出了:

for (b = 0; b < y; b++) {
for (a = max(y-2*b,0); a < y; a++) {
        if (((a+2*b-y)%8)==0) count++;
} }

我们可以分为两部分:

for (b = 0; b < y/2; b++) {
for (a = y-2*b; a < y; a++) {
        if (((a+2*b-y)%8)==0) count++;
} }
for (b = y/2; b < y; b++) {
for (a = 0; a < y; a++) {
        if (((a+2*b-y)%8)==0) count++;
} }

现在我们已经完全消除了c。 如果不提出封闭形式公式(或至少部分封闭形式公式(,我们就无法完全消除 a 或 b,为什么?

因此,这里有几个练习可以让您"到达那里"。

  1. 我们如何摆脱%8? 我们现在可以消除A或B吗?
  2. 观察到对于每个 y,大约有 theta y^2 计数。 为什么没有单一的闭合形式二次(即 a*y^2+b*y+c(给我们正确的计数?
  3. 给定 2,如何提出一个封闭式公式?

现在,转换为汇编语言将使您对事物的宏伟计划略有改进:p

(我希望所有细节都是正确的。 如果您看到错误,请更正(

在汇编语言中,Jeff在第230页写道,

现在,速度优化在 x86 世界中是一项非常滑溜的业务,在 CPU 缓存中拥有指令与必须从内存中提取指令是一种速度差异,它淹没了指令本身之间的大多数速度差异。其他因素在最新的奔腾级CPU中发挥作用,这使得关于指令速度的概括几乎是不可能的,当然也不可能以任何精度陈述。

假设你在一台 x86 机器上,我的建议是尽可能好地吸收其他答案中的所有数学,以进行优化。