跳到主要内容

NEON(ARM架构)与RISCV的Vector拓展(RISC-V架构)是两种针对SIMD(单指令多数据)并行计算的指令集扩展,其设计目标和应用场景有相似之处,但在实现方式、灵活性及生态支持等方面存在显著差异。以下从多个维度对比两者的异同:

1 相同点

1.1 SIMD加速目标

两者均旨在通过单指令操作多个数据,提升多媒体处理、科学计算、AI/机器学习等数据密集型任务的性能。

  • NEON应用场景
    • 在视频编解码、图像处理中广泛应用
    • 能够同时处理多个像素或数据元素
    • 加速视频压缩和解压缩过程
    • 快速进行图像滤波、边缘检测、色彩空间转换等操作
  • RVV应用场景
    • 优化OpenCV、TensorFlow等框架的执行效率
    • 提供更高效的向量指令集
    • 加速图像识别、目标检测等任务
    • 提升模型训练和推理速度

1.2 支持数据类型

  • 均支持整数(8/16/32/64位)和浮点数(单精度/双精度)操作
  • 可通过向量寄存器并行处理多个元素:
    • NEON:128位寄存器可同时操作16个8位整数
    • RVV:向量寄存器宽度可动态配置,如128,256,512,1024

1.3 应用场景重叠

两者均适用于需要高吞吐量的场景,如:

  • 矩阵运算
  • 信号处理
  • 加密计算

2 不同点

2.1 应用领域扩展性

指令集应用领域作用
NEON传统的嵌入式及移动终端提升多媒体处理效率,优化用户体验
RVV人工智能和高性能计算领域支持机器学习和深度学习,高效处理大数据

2.2 寄存器设计与灵活性

指令集寄存器长度特点
NEON固定长度包括 16 个 128 位的 Q 寄存器或者 32 个 64 位的 D 寄存器,
数据类型和并行度由指令明确指定,指令阅读门槛较低
RVV可变长度支持可变长度向量寄存器(VLEN),
元素宽度(SEW)和向量长度(LMUL)能通过vsetvli指令动态配置,
能适配不同硬件环境,为开发者提供更大灵活性和可扩展性

2.3 指令集设计哲学

指令集设计思想
NEON提供了丰富全面的指令集,
支持加法、乘法、比较、移位、绝对值、极值运算等多种操作。
通过扩展功能(如饱和操作、数据类型转换等)增强了指令的灵活性。
RVVRISC 架构的核心思想是使用较少且简单的指令集。
每条指令通常只完成一个基本操作,从而实现高效的指令执行和更高的处理速度。
与复杂指令集(CISC)相比,RISC 的指令集更精简,硬件实现更简单,
强调通过优化的流水线设计和高效的指令调度来提高性能。

2.4 生态与兼容性

指令集描述
NEON在 ARM 生态中是强制性扩展,所有 Cortex-A 系列处理器均支持。
旨在为多媒体和信号处理等应用提供高效的向量处理能力,可并行处理多个数据元素提高处理速度,
但不同版本工具链支持的 NEON 版本不同,可能带来兼容性问题。
RVV进迭时空在开源与生态建设方面正在大步前行,积极参与各类开源项目,与众多开发者共享技术成果,
不断推动技术的创新与发展。
同时,进迭时空还致力于构建一个活跃且包容的开源社区,为开发者们提供交流与合作的平台,
促进社区成员之间的知识共享和经验交流。

2.5 开发门槛

指令集描述
NEON依赖静态数据对齐和特定内存操作指令(如vld1/vst1)提升访存效率,需手动优化数据结构。
在实际应用中,开发人员需要仔细分析数据的存储方式和访问模式。
这一过程不仅需要对硬件架构有深入的理解,还需要具备丰富的编程经验和优化技巧。开发门槛较高。
RVV通过内存连续访问自动向量化,支持非对齐访问,对普通数组即可启用 SIMD 加速,降低开发门槛。
RVV 技术的出现极大地简化了 SIMD 编程的复杂性,它能够自动识别连续的内存访问模式,并将其向量化,
从而在无需手动调整数据结构的情况下,实现高效的并行计算。
这一特性不仅提高了开发效率,还减少了因手动优化不当而可能引入的错误。降低了开发门槛。

3 总结

RISC-V的主要优势

  • 应用领域优势

    • 在人工智能和高性能计算领域表现出色
    • 为机器学习和深度学习提供有力支持
    • 高效处理大量数据,加速模型训练和推理
    • 为科学研究和工程应用提供强大计算能力
  • 寄存器设计灵活

    • 支持可变长度向量寄存器(VLEN)
    • 元素宽度(SEW)和向量长度(LMUL)可通过vsetvli指令动态配置
    • 适配不同硬件环境
    • 为开发者提供更大灵活性和可扩展性
  • 设计哲学先进

    • 遵循RISC架构核心思想
    • 使用精简指令集,每条指令完成一个基本操作
    • 硬件实现简单
    • 通过优化流水线设计和高效指令调度提高性能
  • 开发门槛较低

    • 支持内存连续访问自动向量化
    • 支持非对齐访问
    • 对普通数组即可启用SIMD加速
    • 开发人员可专注于算法实现和业务逻辑
  • 生态建设积极

    • 开源社区建设持续推进
    • 积极参与各类开源项目
    • 共享技术成果
    • 构建活跃包容的开源社区

4 参考代码

代码下载:add-examples

以下以向量加法为例,介绍NEON和RVV代码的异同:

4.1 NEON实现

详细代码可参考:

void vector_add_neon(int32_t *vec1, int32_t *vec2, int32_t *result, int size)
{
// 按照 4 个整数一组进行处理
for (int i = 0; i < size / 4; ++i)
{
// 加载向量数据到 NEON 寄存器
int32x4_t v1 = vld1q_s32(&vec1[i * 4]);
int32x4_t v2 = vld1q_s32(&vec2[i * 4]);

// 执行向量加法
int32x4_t vresult = vaddq_s32(v1, v2);

// 将结果存储回内存
vst1q_s32(&result[i * 4], vresult);
}
}

此代码仅供参考,旨在展示两种指令集在实际使用时的不同

使用NEON指令集实现向量加法的关键特点:

  • 使用固定长度的向量寄存器
  • 需要手动对齐数据
  • 使用特定的向量加载/存储指令

4.2 RVV实现

代码可参考:

void vector_add_rvv(int32_t* vec1, int32_t* vec2, int32_t* result, size_t size) {
// 设置向量长度
size_t vl;

for (size_t i = 0; i < size; i += vl) {
// 动态设置向量长度,如果__riscv_vsetvlmax_e32m4()>size-i,长度会被设置为size-i,否则会被设置为__riscv_vsetvlmax_e32m4()
vl = __riscv_vsetvl_e32m4(size - i);
vint32m4_t v1 = __riscv_vle32_v_i32m4(&vec1[i], vl); // 加载 vec1
vint32m4_t v2 = __riscv_vle32_v_i32m4(&vec2[i], vl); // 加载 vec2
vint32m4_t vresult = __riscv_vadd_vv_i32m4(v1, v2, vl); // 向量加法
__riscv_vse32_v_i32m4(&result[i], vresult, vl); // 存储结果
}
}

使用RVV指令集实现向量加法的关键特点:

  • 支持动态向量长度
  • 自动处理数据对齐
  • 简化的内存访问操作

编译运行:

# 交叉编译
riscv64-unknown-linux-gnu-gcc riscv_vector_add.c -march=rv64gcv -o ins.out -static
#本地编译
gcc riscv_vector_add.c -march=rv64gcv -o ins.out -static
#运行
./ins.out

运行结果:

9 9 9 9 9 9 9 9