NEON

ARM NEON (Advanced SIMD, Single Instruction, Multiple Data) 是 ARM 处理器架构中的一个扩展,用于加速多媒体和信号处理应用。NEON 支持一组向量操作指令,通常通过内建函数(intrinsics)来实现,可以同时处理多个数据元素,提高数据并行处理能力,可以直接在 C/C++ 代码中使用这些指令 参考资料:1

__ARM_NEON 是一个预处理宏,表示 ARM 的 NEON SIMD(Single Instruction, Multiple Data)扩展是否可用。NEON 是 ARM 架构的一部分,提供了高级 SIMD 加速功能,适用于多媒体处理、信号处理、图像处理等领域。

当编写需要利用 ARM NEON 指令集的代码时,可以使用 __ARM_NEON 来检查编译器是否支持 NEON,并根据这个条件编译相应的代码。

使用 __ARM_NEON 的示例

以下是如何使用 __ARM_NEON 宏来检查 NEON 支持并编写不同代码的示例:

#include <iostream>

#ifdef __ARM_NEON
#include <arm_neon.h>
#endif

void process_with_neon() {
#ifdef __ARM_NEON
    std::cout << "NEON is supported. Running NEON optimized code." << std::endl;
    // 使用 NEON 进行加速的代码
    float32x4_t a = vdupq_n_f32(1.0f);
    float32x4_t b = vdupq_n_f32(2.0f);
    float32x4_t c = vaddq_f32(a, b);
    float result[4];
    vst1q_f32(result, c);
    std::cout << "Result: " << result[0] << ", " << result[1] << ", " << result[2] << ", " << result[3] << std::endl;
#else
    std::cout << "NEON is not supported. Running fallback code." << std::endl;
    // 使用非 NEON 代码
    float a = 1.0f;
    float b = 2.0f;
    float c = a + b;
    std::cout << "Result: " << c << std::endl;
#endif
}

int main() {
    process_with_neon();
    return 0;
}

加载和存储指令

  • vld1q_f32(ptr): 加载128位浮点矢量(4个32位浮点数)。
  • vst1q_f32(ptr, val): 存储128位浮点矢量(4个32位浮点数)。
  • vdupq_n_s32:创建包含 4 个相同 32 位整数的向量
float32x4_t vec = vld1q_f32(data); // 从data指针加载128位浮点矢量 vst1q_f32(output, vec); // 将128位浮点矢量存储到output指针

算术指令

  • vaddq_f32(a, b): 4x32位浮点矢量加法。
  • vsubq_f32(a, b): 4x32位浮点矢量减法。
  • vmulq_f32(a, b): 4x32位浮点矢量乘法。
  • vmlaq_f32(a, b, c): 4x32位浮点矢量乘加。
  • vaddq_s32(a, b):4x32位有符号整数矢量加法
float32x4_t result = vaddq_f32(a, b);  // 矢量加法 
result = vsubq_f32(a, b);              // 矢量减法 
result = vmulq_f32(a, b);              // 矢量乘法 
result = vmlaq_f32(a, b, c);           // 矢量乘加

逻辑指令

  • vandq_u32(a, b): 128位无符号整型矢量按位与。
  • vorrq_u32(a, b): 128位无符号整型矢量按位或。
  • veorq_u32(a, b): 128位无符号整型矢量按位异或。
uint32x4_t result = vandq_u32(a, b);  // 按位与 
result = vorrq_u32(a, b);             // 按位或 
result = veorq_u32(a, b);             // 按位异或

比较指令

  • vcgtq_f32(a, b): 比较128位浮点矢量大于。
  • vcgeq_f32(a, b): 比较128位浮点矢量大于等于。
  • vcltq_f32(a, b): 比较128位浮点矢量小于。
  • vcleq_f32(a, b): 比较128位浮点矢量小于等于。
uint32x4_t result = vcgtq_f32(a, b);  // 比较大于 
result = vcgeq_f32(a, b);             // 比较大于等于 
result = vcltq_f32(a, b);             // 比较小于 
result = vcleq_f32(a, b);             // 比较小于等于

移位指令

  • vshlq_n_u32(a, n): 左移128位无符号整型矢量中的每个元素。
  • vqshrn_n_s32(a, n): 对 32 位有符号整数向量进行右移位缩窄操作,并进行饱和处理
uint32x4_t result = vshlq_n_u32(a, 1);  // 左移1位 
result = vshrq_n_u32(a, 1);             // 右移1位

数据类型

NEON 支持多种数据类型,常见的数据类型有:

  • int8x8_t, int8x16_t, uint8x8_t, uint8x16_t:8位整型。
  • int16x4_t, int16x8_t, uint16x4_t, uint16x8_t:16位整型。
  • int32x2_t, int32x4_t, uint32x2_t, uint32x4_t:32位整型。
  • int64x1_t, int64x2_t, uint64x1_t, uint64x2_t:64位整型。
  • float32x2_t, float32x4_t:32位浮点数。
  • float64x1_t, float64x2_t:64位浮点数。