ARM平台上NEON加速常用的函数
[TOC]
概述
文章参考:http://blog.csdn.net/may0324/article/details/72847800
文章参考:https://blog.csdn.net/fengbingchun/article/details/38085781
代码示例
NEON 技术是 ARM Cortex™-A 系列处理器的 128 位 SIMD(单指令,多数据)架构扩展,旨在为消费性多媒体应用程序提供灵活、强大的加速功能,从而显著改善用户体验。它具有 32 个寄存器,64 位宽(双倍视图为 16 个寄存器,128 位宽。)
目前主流的iPhone手机和大部分android手机都支持ARM NEON加速,因此在编写移动端算法时,可利用NEON技术进行算法加速,以长度为4的寄存器大小为例,相应的提速倍数约是原始的4倍。
NEON 指令可执行“打包的 SIMD”处理:
- 寄存器被视为同一数据类型的元素的矢量
- 数据类型可为:签名/未签名的 8 位、16 位、32 位、64 位单精度浮点
- 指令在所有通道中执行同一操作
float32x4_t
本文主要介绍float32x4_t相关的结构及函数
float32x4_t 可以理解为vector<float32
> (4), 同理typexN_t即为vector<type
>(N)。
在NEON编程中,对单个数据的操作可以扩展为对寄存器,也即同一类型元素矢量的操作,因此大大减少了操作次数。
这里以一个小例子来解释如何利用NEON内置函数来加速实现统计一个数组内的元素之和。
原始算法代码如下:
1 | float d0[4] = {0.f, 1.f, 2.f, 3.f}; |
1 | v<mod><opname><shape><flags>_<type> |
基本加载存储操作
vld1q_f32
从128位寄存器中 加载 d0 地址起始的 4 个 float 数据到 q0(128位寄存器中是q0-q15)
1 | float32x4_t q0 = vld1q_f32(d0); // 从128位寄存器中 加载 d0 地址起始的 4 个 float 数据到 q0(128位寄存器中是q0-q15) |
vst1q_f32
1 | vst1q_f32(d1, q0);// 将 q0 中 4 个 float32,赋值给以 d1 为起始地址的 4 个 float32 |
vld2q_f32
1 | float d4[8]= {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f}; |
vst2q_f32
1 | vst2q_f32 (d4, ret); |
注意,由于寄存器是交错存储的,所以内存保持不变!
vld3q_f32
1 | float d5[12] = {1.f, 2.f, 3.f, 4.f, |
vst3q_f32
1 | vst3q_f32 (d5, f); |
vld4q_f32, vst4q_f32
特殊操作
vadd_type常规加法
vaddl_type支撑长整型操作
vaddw_type支持宽整型操作
vhadd_type将结果减半
vrhadd_type将结果减半后舍入(因为减半后会带入小数)。
vaddq_type, 和vadd_type类似,只是使用的寄存器不同。 vaddq_type使用的是128位寄存器,vadd_type使用的是64位值寄存器。
vaddhn_type支持窄型计算,将四字节加法转换为双字节结果, 该计算会返回四字节的上半部分, vraddhn_type支持结果舍入
vdupq_n_f32
1 | float32x4_t res = vdupq_n_f32(0.f); // 存储的四个 float32 都初始化为 0 |
基本的算术运算
vadd_f32
1 | float32x2_t ss0 = vadd_f32(vget_low_f32(q2), vget_high_f32(q2)); //对应元素相加 |
vaddq_f32
1 | float32x4_t q4 = vaddq_f32 (q1, q2); |
函数汇总
文章参考:https://developer.arm.com/architectures/instruction-sets/intrinsics
文章参考:https://arm-software.github.io/acle/neon_intrinsics/advsimd.html