嵌入式程序优化(2)——内嵌neon汇编

2019-11-10  本文已影响0人  wipping的技术小栈

1. neon介绍

neon指令集arm 平台的 SIMD 指令集,也即单指令多数据指令集,如名字所说,一条只能可以同时处理多个数据,这里常常也使用另外一个名词来说 向量化编程。向量化编程在音视频处理领域中极为常见,随着人工智能深度学习等技术在嵌入式平台上的应用,neon指令集也可以被使用来优化某些后处理函数。本文将通过说明加代码例子讲解的方式尽量来阐述笔者的理解

PS:本文默认读者们已经熟悉了arm内嵌汇编语法

2. neon指令基础

本节将着重讲解一下 neon指令集 的基础知识,从而让读者更好地理解如何使用 neon指令

2.1 指令寄存器组

neon指令集 有专用的寄存器组,第一种是Q0-Q15一共16个,每个寄存器长度为128bit,第二种是D0-D31,一共32个,每个寄存器为64bit

neon寄存器有对照关系,可以理解为他们共同使用一块存储数据的区域,但该区域被分别映射为D寄存器和Q寄存器,下面的图是寄存器之间的对应关系

寄存器对应关系.png

neon指令集将每个寄存器视为均包含一个向量, 而该向量又包含 1、2、 4、 8 或 16 个大小和类型均相同的元素,也可以将各元素当作标量 加以访问。比如D0中有8个元素,每个元素是8bit,那么D0寄存器看成是有8个元素的向量

2.2 指令分类

neon指令 的操作对象为向量,向量有长有短,neon指令常用的有 64bit 的双字向量和 128bit 的四字向量其中,根据操作数的长度,可以将 neon指令 分为以下几种类型

2.3 指令格式

V{<mod>}<op>{<shape>}{<cond>}{.<dt>}{<dest>}, src1, src2

PS:带花括号的字段为可选字段

2.4 指令编译

在编译含有neon指令集的代码时,是指定使用的fpu和cpu,通常情况下我们使用arm-gcc需要加-ftree-vectorize-mfpu=neon-mcpu=your_chip_arch 来使能编译器使用neon指令集

neon指令集常常是在C语言中使用,除了使用汇编代码来编写外,我们还可以使用neon的开源库如Ne10等,也可以使用官方提供的neon内建函数

同时,gcc编译器 支持对一般的代码进行 neon优化,但需要满足以下条件

• 短而简单的循环

• 不使用break跳出循环.

• 循环次数为2的幂次.

• 循环次数为编译器支持的范围.

• 循环内部调试函数时,该函数需要是内联属性

• 使用数组索引而不是指针.

• 间接寻址无法向量化.

• 使用strict关键字告诉编译器指针不引用内存的重叠区域。

3. 例子说明

下面通过一个简单的 neon指令 的语句来了解一下具体的语法

指令示意.png

上面的图例应该展现得足够清楚

qd 是mod字段,表明该指令支持饱和和对结果进行双倍放大操作

mla是neon指令集操作,标志相乘并累加结果

l 表示的是指令的操作类型为长整型操作

s16 表示的是向量中的元素长度

dest 表示的是目标寄存器

src 表示的是源寄存器

关于 neon 的具体例子请参加笔者的github,地址为https://github.com/wipping/neon

因为该代码例程中有上千行,不便在文章中呈现,请读者们下载阅读,代码中做了相应的注释,当然还是要搭配neon指导手册 进行阅读。因为代码是根据手册中的内容进行编写

4. 参考资料

NEON简介及基本架构:http://zyddora.github.io/2016/02/28/neon_1/
ARM平台NEON指令的编译和优化https://blog.csdn.net/heli200482128/article/details/79303286
neon函数速查地址: https://developer.arm.com/architectures/instruction-sets/simd-isas/neon/intrinsics

上一篇下一篇

猜你喜欢

热点阅读