ARM的NEON协处理器技术是一个64/128-bit的混合SIMD,用于加速包括视频编码解码、音频解码编码、3D图像、语音和图像等多媒体和信号处理应用。本文主要介绍如何使用NEON的汇编程序来写SIMD的代码,包括如何开始NEON的开发,如何高效的利用NEON。首先会关注内存操作,即如何变更指令来灵活有效的加载和存储数据。接下来是由于SIMD指令的应用而导致剩下的若干个单元的处理,最后是一个例子来说明用NEON来进行SIMD优化。
SIMD的例子
首先看一个实例,24-bit的RGB图像,像素在内存里的组织方式是R, G, B, R, G, B...,如果你想做一个简单的图像处理,比如把R和B通道互换,你该如何高效的使用NEON协处理器呢?首先从存储空间线性加载RGB数据到D寄存器,然后交换R和B数据。 但是这种线性加载的数据进行R和B通道的数据交换非常麻烦,需要首先掩码mask,然后移位并合并掩码数据。这种复杂的运算显然并不高效。
图1. 线性加载RGB数据
NEON提供了各种结构的加载和存储指令来处理这种情况,这些指令能把数据从存储区加载的同时还能把这些值分开存储到不同的寄存器中,如下图2所示,你可以使用VLD3加载来把RGB数据分开存储。
图2. 使用结构化的加载指令加载RGB数据
然后使用VLD3分开加载的数据就能方便的使用指令(VSWP d0, d2)来进行R和B通道的交换了,然后把结果再写入内存,当然也要使用interleave交织模式的存储,即VST3存储指令。
图3. 交换寄存器d0和d2然后存储
结构化加载和存储语法和具体指令
NEON结构化加载会读取内存内容到64-bit的NEON寄存器,使用可选的de-interleave选项,同样加载指令也可以采用这种reinterleave的方式把寄存器的内容写到内存空间。
图4. NEON的结构化加载和存储
下面介绍NEON存储和加载的结构化方式,语法包括如下5个部分:
图5. NEON的结构化加载和存储语法
交织模式:Interleave Pattern
加载和存储指令可以用从1到4个相同大小的元素的交织结构体,这些元素可以是NEON指令通常支持的8,16或者32比特。
存储和加载类似,只是把寄存器的数据interleave然后写到内存。
元素类型 Element Types
加载和存储interleave的数据的基本元素可以为8,16或者32比特的数据。比如NEON指令VLD2.16将加载4个16-bit元素到第一个寄存器,然后4个16-bit元素到第二个寄存器,把临近的奇偶对分开保存到每个寄存器。
图6. 加载并解交织16-bit的数据
把元素大小变成32-bits还是加载相同大小的数据,但是只有2个元素来构成一个向量,同样分成奇偶元素部分。
图6. 加载并解交织32-bit的数据
单个或者多个元素 Single or Multiple Elements
除了加载多个元素,结构读取还能从内存用deinterleave的模式读取一个元素到NEON寄存器的多个通道或者一个通道而保存其他通道不变。
图7. 加载并解交织到所有的通道
加载到单一通道对于从分散的内存空间的数据读取来构建一个向量非常有用。存储数据到内存也是一样,也可以采用通道的模式进行存储。
图8. 加载并解交织到单一的通道
寻址模式Addressing
NEON的加载和存储指令支持3种格式的寻址模式:
其他的加载和存储
NEON还支持以下的数据加载和存储:
更多的关于支持的加载和存储运算可以参考ARM的参考手册ARM 《Architecture Reference Manual》. 详细的指令周期信息可以参考每个单独的指令《Technical Reference Manual for each core》.