Assembly 比整数模运算更快?

Assembly 比整数模运算更快?,assembly,arm,cpu-architecture,micro-optimization,Assembly,Arm,Cpu Architecture,Micro Optimization,可以重新表达: 我是%m 作为: i和(m-1) 在哪里, i是一个无符号整数 m是2的幂 我的问题是:手术和手术是否更快?难道现代CPU不支持单指令中硬件的整数模运算吗?我对ARM很感兴趣,但在它的指令集中看不到模运算。如果您使用的是启用了优化功能的体面的C编译器,它会将其优化到更快的速度,这是一种称为“强度降低”的技术。若你们在做手写汇编,唯一可靠的测试方法就是对它进行基准测试。但是要注意,即使是同一处理器的不同型号也可能给出不同的结果。根据,ARM没有除法指令。如果这是真的,那

可以重新表达:

  • 我是%m
作为:

  • i和(m-1)
在哪里,

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

我的问题是:手术和手术是否更快?难道现代CPU不支持单指令中硬件的整数模运算吗?我对ARM很感兴趣,但在它的指令集中看不到模运算。

如果您使用的是启用了优化功能的体面的C编译器,它会将其优化到更快的速度,这是一种称为“强度降低”的技术。若你们在做手写汇编,唯一可靠的测试方法就是对它进行基准测试。但是要注意,即使是同一处理器的不同型号也可能给出不同的结果。

根据,ARM没有除法指令。如果这是真的,那么我也不希望它有一个
MOD
指令。

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

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

在任何情况下,我都不知道32位除法在任何内核上都是单周期延迟,ARM与否。在“现代”ARM上有整数除法指令,但仅在一些实现上,最明显的是在最常见的实现上——Cortex A8和A9上没有

在某些情况下,编译器可以为您省去将除法/模转换为位移位/掩码操作的麻烦。但是,只有在编译时知道该值时,这才有可能。在您的情况下,如果编译器可以确定“m”始终是a 2的幂,那么它会将其优化为位运算,但如果它是传递到函数中的变量,则(或以其他方式计算),则它不能,并将采用全除法/模。这种代码构造通常有效(但并不总是有效-取决于优化器的智能程度):

unsigned page\u size\u bits=12;//即使这里没有常量,优化也可以工作
无符号foo(无符号地址){
您可能感兴趣的未签名页面大小=1U

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


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

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

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


我不认为这通常是正确的。如果我想让编译器进行这种优化,我必须通过确保这个除数是一个文本值来编程。如果这个除数是一个变量,那么只有完全的模运算才能发生。你是对的,我似乎跳过了“m是2的幂”部分。定义“现代CPU”.ARM7TDMI(ARMv4体系结构)和ARM9(26EJ-S)(ARMv5体系结构)没有硬件划分。Cortex-M(ARMv7M体系结构)和Cortex-R(不太常见,ARMv7R)有硬件划分,Cortex-A(ARMv7体系结构,而不是7R或7M)没有硬件划分。应用于“ARM”时,请参阅和如果没有限定条件,此声明是错误的。某些ARM体系结构/处理器确实有整数除法指令。这仅适用于非2次幂除法。现代编译器为您这样做:。它们还优化2次幂余数或简单的
lsr
(移位),除非它是有符号的,在这种情况下,
x%4
为负x,这需要额外的工作。
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;
}