ARM 有一个桶形移位器,可用于移位指令的第二个操作数。可以这样写
add x0, x0, x1, lsl #2
而不是
lsl x1, x1, #2
add x0, x0, x1
我找到了一些旧 ARM CPU 的文档(例如 wikichip 上的 ARM2 页面),这似乎表明指令的第二个操作数在到达 ALU 之前要经过桶形移位器。
但是,我无法在更新的 CPU 上找到相同的信息。例如,Cortex-A76 的Wikichip 页面根本没有提到桶形移位器,并且核心图也没有显示专用的桶形移位器单元。
现代 ARM/ARM64 CPU 上是否仍然有专用的桶形移位器单元,或者它们是否使用常规 ALU 单元? (我对 ARM 和 ARM64 都感兴趣,但如果答案必须是特定于 CPU 的,那么就说 Cortex-A76)
我问这个问题是因为我想知道使用桶形移位器进行重复计算是否/何时有意义。例如,考虑这个函数:
int f(int* arr1, long int offset, int repl) {
int a = arr1[offset];
arr1[offset] = repl;
return a;
}
是否应该在汇编中实现
ldr w3, [x0, x1, lsl #2]
str w2, [x0, x1, lsl #2]
或与
lsl x1, x1, #2
ldr w3, [x0, x1]
str w2, [x0, x1]
GCC 13.2 似乎更喜欢前者,但 GCC 14.0 Trunk 更喜欢后者。 我猜测桶形移位器的具体实现会影响哪一个更快。 (对于这个问题,我们假设套准压力不是问题)
这里是一些关于桶式移位器的信息。请注意,ARMv2 是在 1980 年设计的,Verilog 和 VHDL 等技术刚刚被发明。这时设计师审视了每一个大门。 “桶形变速装置”是一种执行动态变速操作的技术。有多种方法可以实现这一点。硬件中的固定移位只是从源到目的地的线路,用于执行移位/旋转。
现代 ARM/ARM64 CPU 上是否仍然有专用的桶形移位器单元,或者它们是否使用常规 ALU 单元?
虽然我不知道,我无法想象“奉献的东西”?很可能有“shift.v”或类似的东西。完成初步设计后,您可以根据需要制作任意数量的“shift.v”饼干模具。工具现在将重新实现/连接“shift.v”模块所做的任何事情。因此,每个加载存储单元可以具有移位器和/或支持移位寄存器的所有操作数。在一个设计中,一个寄存器也可以有多个副本。在 20 世纪 80 年代,人们可能会为变速杆而出汗。 CPU 需要多个周期才能完成所有工作。 RAM从来都不是真正的问题(与速度有关)。今天,我认为 CPU 中可能有数千个移位器电路,并且 CPU 可以等待外部 RAM 的数千个周期。
是否应该在汇编中实现
对于,
第 2,3 项可能是并列的。除非 CPU 的文档说明这需要额外的周期(对于 Cortex-A 设计或更高版本不太可能),否则复制移位是最好的方法。
单次移位完全有可能节省电量,但不太可能,因为 CPU 内部的大量开销会被额外的指令读取耗尽。
比编译器级别的转换成本更大的是管理数据流。编译器会做不同的事情,具体取决于它判断事物的重要性。如果您没有在循环中使用此代码,那么不相关的代码部分可能会导致替代指令选择。我认为依赖编译器是错误的(对于这个问题主题)。您需要查阅感兴趣的CPU的技术参考手册。
一般最佳实践是,
第四项通常只有在您拥有完整的实施例时才能得到回答,因为许多系统设备(缓存、RAM、CPU)相互作用会影响性能。此外,当/如果代码移动到另一个平台时,过早的优化也会限制代码。最常见的是,现代 CPU 会等待 RAM,而像特定操作码类型这样的项目很少能获得性能提升;与使用 SIMD、定点/整数等技术转变相反。