arm - 为什么 Clang 不对 AArch32 上的 __builtin_popcountll 使用 vcnt?

标签 arm clang bit-manipulation micro-optimization neon

简单的测试,

unsigned f(unsigned long long x) {
    return __builtin_popcountll(x);
}

当使用 clang --target=arm-none-linux-eabi -mfpu=neon -mfloat-abi=softfp -mcpu=cortex-a15 -Os 编译时, 导致编译器发出实现经典 popcount 所需的大量指令对x中的低位和高位字进行并行处理,然后将结果相加。

在我看来,通过浏览架构手册,NEON 代码类似于生成的代码

#include <arm_neon.h>
unsigned f(unsigned long long x) {
    uint8x8_t v = vcnt_u8(vcreate_u8(x));
    return vget_lane_u64(vpaddl_u32(vpaddl_u16(vpaddl_u8(v))), 0);
}

至少在尺寸方面应该是有益的,即使不一定是性能改进。

为什么 Clang 不这样做?我只是给了它错误的选择吗? ARM 到 NEON 到 ARM 的转换是否非常缓慢,即使在 A15 上也是如此,以至于不值得吗? (这就是 a comment on a related question 似乎暗示的,但非常简短。)鉴于几乎所有现代移动设备都使用 AArch64,AArch32 的 Clang 代码生成是否缺乏关注和关注? (这似乎有些牵强,但众所周知,例如 GCC 偶尔会在 PowerPC 或 MIPS 等非主流架构上出现错误的代码生成。)

<支持> Clang 选项可能是错误的或多余的,请根据需要进行调整。
在我的实验中,GCC 似乎也没有这样做,只是发出对 __popcountdi2 的调用,但这表明我可能只是调用错误。

最佳答案

Are the ARM-to-NEON-to-ARM transitions so spectacularly slow, even on the A15, that it wouldn’t be worth it?

嗯,你问的很对。
很快,是的,是的。它很慢,在大多数情况下,在 NEON 和 ARM CPU 之间移动数据,反之亦然,这是一个很大的性能损失,超过了使用“快速”NEON 指令带来的性能提升。

详细来说,NEON 是基于 ARMv7 的芯片中的可选协处理器。 ARM CPU 和 NEON 并行工作,我可以说彼此“独立”。
CPU 和 NEON 协处理器之间的交互通过 FIFO 组织。 CPU 将 neon 指令放入 FIFO 中,NEON 协处理器获取并执行它。 当 CPU 和 NEON 需要彼此同步时,就会出现延迟。 Sync 正在访问相同的内存区域或在寄存器之间传输数据。

所以使用vcnt的整个过程是这样的:

  • ARM CPU 将 vcnt 放入 NEON FIFO
  • 将数据从 CPU 寄存器移动到 NEON 寄存器
  • NEON 从 FIFO 中获取 vcnt
  • NEON 执行 vcnt
  • 将数据从 NEON 寄存器移动到 CPU 寄存器

CPU 一直在等待,而 NEON 正在执行它的工作。
由于 NEON 流水线,延迟可能高达 20 个周期(如果我没记错的话)。

注意:“最多 20 个周期”是任意的,因为如果 ARM CPU 有其他不依赖于 NEON 计算结果的指令,CPU 可以执行它们。

结论:根据经验,这是不值得的,除非您手动优化代码以减少/消除同步延迟。

PS:ARMv7 也是如此。 ARMv8 将 NEON 扩展作为核心的一部分,因此它不相关。

关于arm - 为什么 Clang 不对 AArch32 上的 __builtin_popcountll 使用 vcnt?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70008561/

相关文章:

c# - 单元测试 c# Windows 10 IoT 核心应用程序(错误 : DEP0700)

xcode - 什么是 llvm/clang/xcode 的正确版本?

c - 在没有双重评估的情况下在 Clang 中实现 min() 和 max()

c# - 比较并识别特定位置的位置和值并打印

python - 对 0xfff 进行按位与运算 - 毫无意义?

php - ~ 位运算符(波浪号)的作用是什么

c - 如何调试无法使用gdb访问地址

ios - 使用 xamarin 为 sdk >= 11.14 的 iphone 5c 构建一个 ios 应用程序

iphone - 取消引用 NSCoder 的decodeBytesForKey 返回的指针时,iOS 设备崩溃

c++ - Clang 编译有效,而 gcc 不适用于菱形继承(钻石问题)