ARM NEON指令集优化理论与实践

一.简介

NEON就是一种基于SIMD思想的ARM技术,相比于ARMv6或之前的架构,NEON结合了64-bit和128-bit的SIMD指令集,提供128-bit宽的向量运算(vector operations)。NEON技术从ARMv7开始被采用,目前可以在ARM Cortex-A和Cortex-R系列处理器中采用。NEON在Cortex-A7、Cortex-A12、Cortex-A15处理器中被设置为默认选项,但是在其余的ARMv7 Cortex-A系列中是可选项。NEON与VFP共享了同样的寄存器,但它具有自己独立的执行流水线。

二. NEON寄存器

三. NEON指令集

所有的支持NEON指令都有一个助记符V,下面以32位指令为例,说明指令的一般格式:

V{}{}{}{.}{}, src1, src2Q: The instruction uses saturating arithmetic, so that the result is saturated within the range of the specified data type, such as VQABS, VQSHL etc.

H: The instruction will halve the result. It does this by shifting right by one place (effectively a divide by two with truncation), such as VHADD, VHSUB.

D: The instruction doubles the result, such as VQDMULL, VQDMLAL, VQDMLSL and VQ{R}DMULH.

R: The instruction will perform rounding on the result, equivalent to adding 0.5 to the result before truncating, such as VRHADD, VRSHR.

- the operation (for example, ADD, SUB, MUL).

- Shape,即前文中的Long (L), Wide (W), Narrow (N).

- Condition, used with IT instruction.

<.dt> - Data type, such as s8, u8, f32 etc.

- Destination.

- Source operand 1.

- Source operand 2.

注: {} 表示可选的参数。

比如:

VADD.I16 D0, D1, D2 @ 16位加法

VMLAL.S16 Q2, D8, D9 @ 有符号16位乘加

四.NEON支持的指令总结运算:和、差、积、商

共享的 NEON 和 VFP 指令:涉及加载、多寄存器间的传送、存储

五. NEON 优化技术

在利用NEON优化程序时,有下述几项比较通用的优化技巧。

1. 降低数据依赖性

在ARM v7-A NEON指令通常需要3~9个指令周期,NEON指令比ARM指令需要更多周期数。因此,为了减少指令延时,最好避免将当前指令的目的寄存器当作下条指令的源寄存器。如下例所示:

/***************************************************************/

// C代码

float SumSquareError_C(const float* src_a, const float* src_b, int count)

{

float sse = 0u;

int i;

for (i = 0; i < count; ++i) {

float diff = src_a[i] - src_b[i];

sse += (float)(diff * diff);

}

return sse;

}

// NEON实现一

float SumSquareError_NEON1(const float* src_a, const float* src_b, int count)

{

float sse;

asm volatile (

"veor q8, q8, q8 \n"

"veor q9, q9, q9 \n"

"veor q10, q10, q10 \n"

"veor q11, q11, q11 \n"

"1: \n"

"vld1.32 {q0, q1}, [%0]! \n"

"vld1.32 {q2, q3}, [%0]! \n"

"vld1.32 {q12, q13}, [%1]! \n"

"vld1.32 {q14, q15}, [%1]! \n"

"subs %2, %2, #16 \n"

// q0, q1, q2, q3 是vsub的目的地寄存器.

// 也是vmla的源寄存器。

"vsub.f32 q0, q0, q12 \n"

"vmla.f32 q8, q0, q0 \n"

"vsub.f32 q1, q1, q13 \n"

"vmla.f32 q9, q1, q1 \n"

"vsub.f32 q2, q2, q14 \n"

"vmla.f32 q10, q2, q2 \n"

"vsub.f32 q3, q3, q15 \n"

"vmla.f32 q11, q3, q3 \n"

"bgt 1b \n"

"vadd.f32 q8, q8, q9 \n"

"vadd.f32 q10, q10, q11 \n"

"vadd.f32 q11, q8, q10 \n"

"vpadd.f32 d2, d22, d23 \n"

"vpadd.f32 d0, d2, d2 \n"

"vmov.32 %3, d0[0] \n"

: "+r"(src_a),

"+r"(src_b),

"+r"(count),

"=r"(sse)

:

: "memory", "cc", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11","q12", "q13","q14", "q15");

return sse;

}

// NEON实现二

float SumSquareError_NEON2(const float* src_a, const float* src_b, int count)

{

float sse;

asm volatile (

"veor q8, q8, q8 \n"

"veor q9, q9, q9 \n"

"veor q10, q10, q10 \n"

"veor q11, q11, q11 \n"

"1: \n"

"vld1.32 {q0, q1}, [%0]! \n"

"vld1.32 {q2, q3}, [%0]! \n"

"vld1.32 {q12, q13}, [%1]! \n"

"vld1.32 {q14, q15}, [%1]! \n"

"subs %2, %2, #16 \n"

"vsub.f32 q0, q0, q12 \n"

"vsub.f32 q1, q1, q13 \n"

"vsub.f32 q2, q2, q14 \n"

"vsub.f32 q3, q3, q15 \n"

"vmla.f32 q8, q0, q0 \n"

"vmla.f32 q9, q1, q1 \n"

"vmla.f32 q10, q2, q2 \n"

"vmla.f32 q11, q3, q3 \n"

"bgt 1b \n"

"vadd.f32 q8, q8, q9 \n"

"vadd.f32 q10, q10, q11 \n"

"vadd.f32 q11, q8, q10 \n"

"vpadd.f32 d2, d22, d23 \n"

"vpadd.f32 d0, d2, d2 \n"

"vmov.32 %3, d0[0] \n"

: "+r"(src_a),

"+r"(src_b),

"+r"(count),

"=r"(sse)

:

: "memory", "cc", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12", "q13","q14", "q15");

return sse;

}

/***************************************************************/

在NEON实现一中,我们把目的寄存器立刻当作源寄存器;在NEON实现二中,我们重新排布了指令,并给予目的寄存器尽量多的延时。经过测试实现二比实现一快30%。由此可见,降低数据依赖性对于提高程序性能有重要意义。一个好消息是编译器能自动调整NEON intrinsics以降低数据依赖性。这个利用NEON intrinsics的一个很大优势。

2. 减少跳转

NEON指令集没有跳转指令,当需要跳转时,我们需要借助ARM指令。在ARM处理器中,分支预测技术被广泛使用。但是一旦分支预测失败,惩罚还是比较高的。因此我们最好尽量减少跳转指令的使用。其实,在有些情况下,我们可以用逻辑运算来代替跳转,如下例所示:

ARM NEON指令集提供了下列指令来帮助用户实现上述逻辑实现:

/***************************************************************/

// C实现

if( flag )

{

dst[x * 4] = a;

dst[x * 4 + 1] = a;

dst[x * 4 + 2] = a;

dst[x * 4 + 3] = a;

}

else

{

dst[x * 4] = b;

dst[x * 4 + 1] = b;

dst[x * 4 + 2] = b;

dst[x * 4 + 3] = b;

}

// NEON实现

//dst[x * 4] = (a&Eflag) | (b&~Eflag);

//dst[x * 4 + 1] = (a&Eflag) | (b&~Eflag);

//dst[x * 4 + 2] = (a&Eflag) | (b&~Eflag);

//dst[x * 4 + 3] = (a&Eflag) | (b&~Eflag);

VBSL qFlag, qA, qB

/***************************************************************/

• VCEQ, VCGE, VCGT, VCLE, VCLT……

• VBIT, VBIF, VBSL……

减少跳转,不仅仅是在NEON中使用的技巧,是一个比较通用的问题。即使在C程序中,这个问题也是值得注意的。

3. 其它技巧

在ARM NEON编程时,一种功能有时有多种实现方式,但是更少的指令不总是意味着更好的性能,要依据测试结果和profiling数据,具体问题具体分析。下面列出来我遇到的一些特殊情况。

4. 浮点累加指令

通常情况下,我们会用VMLA/VMLS来代替VMUL + VADD/ VMUL + VSUB,这样使用较少的指令,完成更多的功能。但是与浮点VMUL相比,浮点VMLA/VMLS具有更长的指令延时,如果在指令延时中间不能插入其它计算的情况下,使用浮点VMUL + VADD/ VMUL + VSUB反而具有更好的性能。

一个真实例子就是Ne10库函数的浮点FIR函数。代码片段如下所示:

实现1:在两条VMLA指令之间,仅有VEXT指令。而根据指令延时表,VMLA需要9个周期。

实现2:对于qAcc0,依然存在指令延时。但是VADD/VMUL只需要5个周期。

neon浮点运算_ARM NEON指令集优化理论与实践相关推荐

  1. ARM NEON指令集优化理论与实践

    ARM NEON指令集优化理论与实践 一.简介 NEON就是一种基于SIMD思想的ARM技术,相比于ARMv6或之前的架构,NEON结合了64-bit和128-bit的SIMD指令集,提供128-bi ...

  2. neon浮点运算_ARM 浮点运算详解

    原标题:ARM 浮点运算详解 一:早期 上的浮点模拟器: 早期的ARM没有协处理器,所以是由CPU来模拟的,即所需浮点运算均在浮点运算模拟器(float math emulation)上进行,需要的浮 ...

  3. 「性能优化系列」APP内存优化理论与实践

    当一个应用同时运行越来越多的任务以及复杂的业务,Android系统的内存管理机制已经无法满足内存的释放与回收,为了应用的稳定性与性能,去控制内存的创建和回收就成为了一个重要的命题. 本篇文章主要涉及内 ...

  4. 【genius_platform软件平台开发】第二十八讲:NEON指令集优化(附实例)

    当在ARM芯片上进行一些例如图像处理等计算的时候,常常会因为计算量太大造成计算帧率较低的情况.因而,需要选择一种更加简单快捷的计算方式以获得处理速度上的提升.ARM NEON就是一个不错的选择. ※ ...

  5. neon 指令 c语言,Neon指令集优化快速入门教程

    Neon指令集优化快速入门教程 Neon指令集优化快速入门教程 文章目录 1. Neon是什么? 2.Neon为什么速度快 3. Neon基础概念 4. Neon的C语言接口 C语言程序中集成Neon ...

  6. neon浮点运算_NEON简单介绍

    "ARM Advanced SIMD",nick-named "NEON", it provides:(1).A set of interesting scal ...

  7. ARM Cortex系列(A8/A9/A15/A7) NEON多媒体处理SIMD引擎优化

    出处: http://houh-1984.blog.163.com/blog/static/31127834201211275111378/ Cortex-A9的NEON多媒体处理器是基于ARMv7的 ...

  8. 综述 | 深度学习中的优化理论

    来源:运筹OR帷幄 本文约5200字,建议阅读10+分钟. 展望未来研究趋势,拒绝做调参侠从我开始. 标签:人工智能 神经网络的训练主要通过求解一个优化问题来完成,但这是一个困难的非线性优化问题,传统 ...

  9. 【视频课】模型优化拆分!分别学习模型剪枝与模型量化理论与实践

    前言 好的模型结构是深度学习成功的关键因素之一,不仅是非常重要的学术研究方向,在工业界实践中也是模型是否能上线的关键.对各类底层深度学习模型设计和优化技术理解的深度是决定我们能否在深度学习项目中游刃有 ...

最新文章

  1. js双等号探索(一): [] == ![]为Ture ?
  2. python 格式化时间
  3. MySQL 中主键的几种表设计组合的实际应用效果
  4. IOS开发之──传感器使用
  5. 继承extends、super、this、方法重写overiding、final、代码块_DAY08
  6. c语言分配内存空间方法,C语言之动态分配内存空间
  7. [Deep Learning]任意层cnn的matlab版本实现
  8. 平滑滤波器模板尺寸与平滑效果的关系_用PPT基础功能,教你打造发布会效果,这骚操作谁顶得住啊?...
  9. 计算机c语言模拟考试,国家计算机二级c语言考试模拟题
  10. Java 并发编程 --- ThreadPoolExecutor(五)
  11. 如何在 iPhone、iPad 和 Mac 上通过 iMessage 共享照片和视频?
  12. npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! taoism@1.0.0 dev: `webpack-dev-server --inline --
  13. 怎么管理员工混工时的现象?
  14. Git的下载安装 (图文教程)
  15. Git初学(5)--关联远程库
  16. Python模拟QQ群发邮件
  17. Java制作JDK8文档搜索引擎项目并部署到阿里云服务器
  18. JDB调试代码 20165324 何春江
  19. 几种常用网页文本编辑器总结
  20. 闲置电脑搭建一台linux服务器,在局域网内访问

热门文章

  1. 数字化转型,要把功夫炼到任督二脉
  2. Lattice SII9293CNUC 接收器 集成电路IC
  3. C语言编程练手必备,C 语言快速实现五子棋!
  4. matlab 对圆三角剖分,Delaunay三角剖分及MATLAB实例
  5. 常见职位的英文简称_常见职位英文缩写()
  6. 2188 完成比赛的最少时间(递推)
  7. String.format()的详细用法
  8. maya2018的uv导入和导出
  9. spring cloud 之 Ribbon
  10. QQ技术全攻略(原来简单的QQ,还隐藏着这么多秘密!)