【问题标题】:AND faster than integer modulo operation?并且比整数模运算更快?
【发布时间】:2011-12-02 09:33:33
【问题描述】:

可以重新表达:

  • i % m

作为:

  • i & (m-1)

在哪里,

  • i 是一个无符号整数
  • m 是 2 的幂

我的问题是:AND 操作是否更快?现代 CPU 不支持在单条指令中对硬件进行整数模运算吗?我对 ARM 很感兴趣,但是在它的指令集中看不到模运算。

【问题讨论】:

  • 定义“现代 CPU”。 ARM7TDMI(ARMv4 架构)和 ARM9(26EJ-S)(ARMv5 架构)没有硬件划分。 Cortex-M(ARMv7M 架构)和 Cortex-R(不太常见,ARMv7R)确实有硬件划分,Cortex-A(ARMv7 架构,不是 7R 或 7M)没有硬件划分。请参阅the docs for sdiv and udivquick reference card

标签: assembly arm cpu-architecture micro-optimization


【解决方案1】:

现在它比“单一指令”更复杂。现代 CPU 是复杂的野兽,需要将它们的指令分解为问题/执行/延迟。它通常还取决于除法/模数的宽度 - 涉及多少位。

在任何情况下,我都不知道 32 位除法在任何内核上是单周期延迟,不管是不是 ARM。在“现代”ARM 上有整数除法指令,但仅限于某些实现,最值得注意的是最常见的 Cortex A8 和 A9 没有。

在某些情况下,编译器可以省去将除法/模数转换为位移/掩码操作的麻烦。然而,这只有在值在编译时已知时才有可能。在您的情况下,如果编译器可以肯定看到“m”始终是 2 的幂,那么它会将其优化为位操作,但如果它是传递给函数的变量(或否则计算),那么它不能,并且将诉诸完整的除法/模数。这种代码构造通常有效(但并非总是有效 - 取决于您的优化器有多聪明):

unsigned page_size_bits = 12;     // optimization works even without const here

unsigned foo(unsigned address) {
  unsigned page_size = 1U << page_size_bits;
  return address / page_size;
}

诀窍是让编译器知道“page_size”是 2 的幂。我知道 gcc 和变体会对此进行特殊处理,但我不确定其他编译器。

根据经验,无论是否为 ARM(甚至 x86),对于任何内核(甚至 x86),都更喜欢位移/掩码而不是除法/取模,尤其是对于任何不是编译时间常数的内核。即使你的核心有硬件划分,手动完成也会更快。

(另外,有符号的除法必须向 0 截断,并且 div / 余数能够产生负数,所以即使是 x % 4 也比 x &amp; 3 更昂贵的有符号 int x。)

【讨论】:

    【解决方案2】:

    你可能对Embedded Live: Embedded Programmers' Guide to ARM’s Cortex-M Architecture感兴趣。

    ARM Cortex-M 系列具有无符号和单点除法指令 UDIV 和 SDIV,它们需要 2 到 12 个周期。没有MOD指令,但是通过{S,U}DIV后跟乘减指令MLS得到等价的结果,需要2个周期,总共4-14个周期。

    AND 指令是单周期的,因此速度快 4-14 倍。

    【讨论】:

      【解决方案3】:

      ARM 非常通用。有很多不同的 ARM,并且有些 ARM 没有除法指令(正如 Ray Toal 已经提到的,模数通常作为除法实现的附加结果来实现)。因此,如果您不想调用非常慢的除法子程序,则逻辑运算要快得多(并且正如 cyco130 所提到的,任何好的编译器都会自行识别它并自行生成逻辑运算 - 所以为了程序代码的清晰我会留在除法(除非你编写汇编程序,那你当然要自己编写,然后你应该进行逻辑运算)。

      【讨论】:

        【解决方案4】:

        如果 m 在编译时已知(甚至它不是)整数除法和模数可以使用乘法乘以一个神奇的“乘法逆”来重新表示。除法的结果在高 32 位中结束,余数(模数)在低 32 位中:

        http://www.hackersdelight.org/magic.htm

        以下链接声称这是标准的编译器强度降低:

        http://www.flounder.com/multiplicative_inverse.htm

        【讨论】:

        【解决方案5】:

        如果您使用的是启用了优化的体面的 C 编译器,它已经将其优化为更快的,一种称为“强度降低”的技术。如果你正在做手写汇编,唯一确定的测试方法就是对其进行基准测试。但请注意,即使是同一处理器的不同型号也可能产生不同的结果。

        【讨论】:

        • 我不认为这是真的。如果我想让编译器进行这种优化,我必须通过确保这个除数是一个文字值来为它编程。如果这个除数是一个变量,那么只能进行全模运算。
        • 你说得对,我似乎跳过了“m 是 2 的幂”部分。
        【解决方案6】:

        根据http://www.coranac.com/tonc/text/asm.htm,ARM 没有除法指令。如果这是真的,那么我也不希望它有 MOD 指令。

        【讨论】:

        • 当无条件地应用于“ARM”时,此陈述是错误的。一些 ARM 架构/处理器确实有整数除法指令。
        猜你喜欢
        • 2016-02-20
        • 2017-05-31
        • 1970-01-01
        • 2019-01-25
        • 2023-03-14
        • 2019-02-14
        • 2015-02-24
        • 1970-01-01
        相关资源
        最近更新 更多