【问题标题】:Is a shift instruction faster than an IMUL instruction?移位指令比 IMUL 指令快吗?
【发布时间】:2011-05-25 06:05:36
【问题描述】:

哪个更快 -

val = val*10;

val = (val<<3) + (val<<2);

与移位指令相比,imul 需要多少个时钟周期?

【问题讨论】:

  • 之前也有人问过类似的问题——最终结果是:“查看制造商提供的说明文档”(这会因型号而异)和“它很复杂”(现代超标量输出-有序流水线 CPU 不能像“传统”微处理器那样简单计算)。
  • 至少包括目标 CPU model。这可能实际上会导致一些有趣的事情。
  • 让编译器担心它的更多理由:以标准方式编写它更具可读性(对人类而言),并且编译器更有可能为手头的架构做正确的事情。
  • 这个我说的还不够:测量它!并查找您的 CPU 文档。
  • 您正在用 C 语言编写,但谈论的是 asm。在启用优化的情况下进行编译,您会看到编译器会为您执行此操作。

标签: assembly optimization x86


【解决方案1】:

这是 21 世纪。现代硬件和编译器知道如何生成高度优化的代码。使用移位编写乘法不会提高性能,但会帮助您生成有错误的代码。

您已经用乘以 12 而不是 10 的代码自己证明了这一点。

【讨论】:

  • +1 表示“您已经用乘以 12 而不是 10 的代码自己证明了这一点”。一个非常好的答案!
【解决方案2】:

我会说,写val = val * 10;val *= 10;,让编译器担心这些问题。

【讨论】:

  • +1 "我们应该忘记小的效率,比如说大约 97% 的时间:过早的优化是万恶之源"
  • 特别是考虑到如果需要,编译器可以轻松完成这种优化(Warren 有一整章介绍了这些内容,这让 Hacker 很高兴)。
【解决方案3】:

在这种情况下,它们可能需要相同数量的周期,尽管您的手动“优化”需要多一个寄存器(这会减慢周围的代码):

val = val * 10;
lea    (%eax,%eax,4),%eax
add    %eax,%eax

val = (val<<3) + (val<<1);
lea    (%eax,%eax,1),%edx
lea    (%edx,%eax,8),%eax

编译器知道怎么做strength reduction,而且可能比你好得多。此外,当您将代码移植到其他平台(例如 ARM)时,编译器也知道如何在该平台上进行强度降低(x86 的 LEA 提供了与 ARM 的 ADDRSB 不同的优化机会)。

【讨论】:

    【解决方案4】:

    用高级语言手动进行这种愚蠢的“优化”只会向人们展示您与现代技术和编程实践脱节。

    如果您直接在汇编中编写,那么担心这一点是有道理的,但您不是。

    话虽如此,在少数 种情况下编译器将无法优化这样的内容。考虑一个可能的乘法因子数组,每个因子正好由 2 个非零位组成,代码如下:

    x *= a[i];
    

    如果分析表明这是您程序中的主要瓶颈,您可以考虑将其替换为:

    x = (x<<s1[i]) + (x<<s2[i]);
    

    只要您计划衡量结果。但是,我怀疑很少有这种情况会有所帮助,或者甚至有可能。与移位和总指令吞吐量相比,只有在乘法单元较弱的 CPU 上才有可能。

    【讨论】:

    • 您的两班制想法可能有助于 CPU 具有非常慢的乘法但快速的可变计数班次,特别是如果 x__int128,甚至是 32 位 CPU 上的 int64_t . (虽然做两个扩展精度的移位也不是很好。)英特尔最初的奔腾(P5)有imul,需要9c。不幸的是shl r32, cl 需要 4c,所以这个想法在 P5 上是行不通的。有序 Atom(Silvermont 之前)对于 imul r64, r64 有 13c 延迟(而不是流水线),但对于 shl r64, cl 有 1c 延迟,所以这可能会在那里获胜。
    • 特别是如果你将两个移位计数打包到一个 16 位结构中,所以不是两个单独的加载,而是 movzx ecx, word s[i] / shl rax, cl / shr ecx, 8 / ... / shl rbx, cl /add rax, rbx。 (我认为您希望 + 而不是 | 将两个部分相乘结果结合起来)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多