ARM处理器NEON编程及优化技巧——处理剩余的元素

发布者:平和宁静最新更新时间:2016-07-13 来源: eefocus关键字:ARM处理器  NEON编程  优化技巧 手机看文章 扫描二维码
随时随地手机看文章
ARM的NEON协处理器技术是一个64/128-bit的混合SIMD架构,用于加速包括视频编码解码、音频解码编码、3D图像、语音和图像等多媒体和信号处理应用。本文主要介绍如何使用NEON的汇编程序来写SIMD的代码,包括如何开始NEON的开发,如何高效的利用NEON。首先会关注内存操作,即如何变更指令来灵活有效的加载和存储数据。接下来是由于SIMD指令的应用而导致剩下的若干个单元的处理,然后是用一个矩阵乘法的例子来说明用NEON来进行SIMD优化,最后关注如何用NEON来优化各种各样的移位操作,左移或者右移以及双向移位等。本节主要介绍当输入的数据大小不是一个向量大小的整数倍时,怎么处理剩余的几个元素,如把元素补齐到向量大小的整数倍的修复处理、重叠处理方式和单个元素处理方式。

关键字: ARM NEON Cortex-A8 cache 对齐

剩余的元素Leftovers

通常NEON会向量处理从4个到16个元素长度的数据,如果你发现你的数组不是这个这个长度的整数倍,你就需要单独处理那些剩下来的几个元素。如你每次可以使用NEON来加载处理并存储8个元素的数据,但是你的数组有21个元素,你就需要先迭代两次,然后第三次,你只剩下5个元素,此时应该如何处理呢?

Fixing Up修复处理方式

有三种处理方式来处理剩下来的元素,这些方法的需求、性能和代码大小不同,下面顺序介绍,从速度最快的方法开始。

Larger Arrays更大的数组

如果改变你要处理的数组大小,比如增加数组大小到向量大小的整数倍,这样就能在最后一次数据处理时也按照向量大小处理而不会把临近的数据损坏。如上面的例子里,把数组大小增加到24个元素,这样就能用NEON用3次迭代完成所有的数据处理而不会损坏周边数据。

图1. 填补数组到向量的整数个大小

注意事项Notes

  • 分配更大的数组需要更多的存储空间,这会增加相当大的空间如果包含非常多的短数组;
  • 在数组后面填补的数据元素需要初始化为一个不会影响到结果的值,例如你要做加法,那这个新元素需要初始化为0以影响计算结果。
  • 一些情况下,可能没法初始化填充的数据,无论填充什么都会影响计算的结果;

Code Fragment代码片段实例

@ r0 是输入的数组指针;

@ r1 是输出数组指针;

@ r2 是数组数据的长度;

假设数组长度大于0,是向量大小的整数倍,并且大于或者等于数组的长度;

add     r2, r2, #7 @ 数据长度加上向量长度-1

lsr     r2, r2, #3 @ 把数组长度变成向量个数,即除以向量大小8

loop:

subs r2, r2, #1 @ 减少循环计数器个数

vld1.8 {d0}, [r0]!     @ 从数组加载8个元素,从地址r0到寄存器d0,然后更新地址寄存器r0到下一个向量地址;

...

...     @ 处理在d0寄存器的数据

...

 

vst1.8 {d0}, [r1]!     @ 把8个结果元素保存到输出数组,更新地址r1到下一个向量

bne     loop @ 如果r2不等于0,继续循环

 

Overlapping重叠计算

如果进行数据处理的操作合适的话,可以考虑把剩余部分的元素通过重叠计算的方式处理,这就会把某些重叠部分的元素计算两次。如下面的例子里,第一次迭代计算元素0到7,第一次计算5到12,第三次计算13到20。从而第一次计算和第二次计算重叠的元素5到7就被计算了两次。

                            图2. 重叠向量,在橙色区域的数据计算两次

Notes需要事项

  • 重叠处理只适用于需要处理的数组长度不会随着每次迭代而改变的情况,但不适用于每次迭代结果改变的情况,如累加计算,这样重叠部分的数据会被计算两次;
  • 数组内元素的个数至少大于一次完整迭代的向量大小;

Code Fragment代码片段实例

@ r0 是输入的数组指针;

@ r1 是输出数组指针;

@ r2 是数组数据的长度;

假设数据操作幂等,并且数组长度大于等于一个向量大小长度。

ands r3, r2, #7 @ 计算每次处理完整个向量后剩余元素个数,使用与操作

beq     loopsetup     @ 如果剩余元素个数为0,则数组长度是整数个向量大小,不用重叠计算,单独处理第一个元素部分

vld1.8 {d0}, [r0], r3 @ 加载数组第一个向量,然后更新数组大小为剩余元素个数r3内保持

...

...     @ 处理d0寄存器内的输入数据

...

vst1.8 {d0}, [r1], r3 @ 保持8个元素到输出数组,更新指针,然后开始处理循环

loopsetup:

lsr     r2, r2, #3 @ 把数组长度除以8,计算循环迭代次数,若干元素跟第一次迭代的重叠

loop:

subs r2, r2, #1 @ 减少循环计数器个数

vld1.8 {d0}, [r0]!     @ 从数组加载8个元素,从地址r0到寄存器d0,然后更新地址寄存器r0到下一个向量地址;

...

...     @ 处理在d0寄存器的数据

...

 

vst1.8 {d0}, [r1]!     @ 把8个结果元素保存到输出数组,更新地址r1到下一个向量

bne     loop @ 如果r2不等于0,继续循环

单个元素的计算过程Single Elements

NEON提供了能处理向量里的单一元素的加载和存储指令,用这些指令,你能加载包含一个元素的部分向量,处理它然后把结果保存到内存。如下面的例子,前两次的迭代处理跟前面类似,处理元素0到7以及8到15,剩下的5个元素可以在第三次迭代处理,加载处理并存储单一的元素。

图3. 处理单一的元素实例

注意事项

  • 这种方法比前面的两种方法速度要慢,每个元素的处理都需要单独进行;
  • 这种的剩余元素处理方法需要两个迭代循环,第一个处理向量的循环,还有处理剩余元素的循环,这会增加代码大小;
  • NEON的单一元素加载只改变目标元素的值,而保留其他的元素不变,如果你向量计算的指令会在一个向量间反复计算,如VPADD,这些寄存器需要在第一个元素加载时初始化。

代码片段

@ r0 是输入的数组指针;

@ r1 是输出数组指针;

@ r2 是数组数据的长度;

lsrs r3, r2, #3 @ 计算向量循环迭代的次数

beq     singlesetup     @ 如果没有完整的一次迭代向量计算,则跳转到单一元素处理循环

@ 处理向量循环

vectors:

subs r3, r3, #1 @减少循环计数器个数

vld1.8 {d0}, [r0]!     @ 从数组加载8个元素,从地址r0到寄存器d0,然后更新地址寄存器r0到下一个向量地址;

...

...     @ 处理在d0寄存器的数据

...

 

vst1.8 {d0}, [r1]!     @ 把8个结果元素保存到输出数组,更新地址r1到下一个向量

bne     vectors     @如果r3不等于0,继续循环

 

singlesetup:

ands r3, r2, #7 @ 计算单一元素迭代的次数

beq     exit @ 如果单一元素计算次数为0,则跳转退出

@ 处理单一元素的循环

singles:

subs r3, r3, #1 @减少循环计数器个数

vld1.8 {d0[0]}, [r0]! @从数组加载单一元素,从地址r0到寄存器d0,然后更新地址寄存器r0到下一个地址

...

...     @ 处理在d0[0]内的输入数据

...

 

vst1.8 {d0[0]}, [r1]! @ 保存单一元素结果到输出数组,更新指针地址

bne     singles     @如果r3不等于0,继续循环

 

exit:

其他的考虑

在开始处还是结束处

用重叠计算的方式以及用单一元素处理都能在数组开始处或者结束处处理,因而代码就要考虑两种实现方式哪种效率高些,哪个更适合你的系统应用。

数据对齐

加载或者存储指令的地址应该对齐到cache line,这样内存的访问效率更高。这样就需要在Cortex-A8的处理器上至少16字对齐,如果你不能把输入和输出数组的起始地址对齐到16字,你就必须处理开始和结束数据处理的那若干个元素以使得后续的数据访问是对齐到cache行的。为了使用内存对齐的方式访问内存以提高速度,你在使用NEON指令时需要使用诸如64或者128或者256等地址限定符来制定加载和存储指令。你可以比较发出一个对齐的访问和非对齐访问的性能, 以下是始终周期的页面Cortex-A8 TRM.

使用ARM来做修复

在使用单个元素处理的情况下,你可以使用ARM指令来进行单个元素的操作,但是同时使用ARM和NEON来访问同一块区域的内存会降低系统性能,因为从ARM的流水线发出的写操作会在NEON的流水线完成之后才能进行。因而你要尽量的避免在ARM和NEON的代码里同时访问同一块内存区域(当然,这同一块内存区域也对应于同一个cache line)

关键字:ARM处理器  NEON编程  优化技巧 引用地址:ARM处理器NEON编程及优化技巧——处理剩余的元素

上一篇:ARM高效C编程和优化--编译器,内存和Cache优化以及功耗管理
下一篇:ARM处理器NEON编程及优化技巧——矩阵乘法的实例

推荐阅读最新更新时间:2024-03-16 15:00

关于ARM处理器Remap的理解
什么是Remap ? 我的理解是:在ROM从0x0用几句指令引导系统之后,把RAM映射到0x0就是Remap。 1.Remap的作用 当ARM处理器上电或者Reset之后,处理器从0x0取指。因此,必须保证系统上电时,0x0 处有指令可以执行。所以,上电的时候,0x0地址处必定是ROM或者Flash(NOR)。 但是,为了加快启动的速度,也方便可以更改异常向量表,加快中断响应速度,往往把 异常向量表映射到更快、更宽(32bit/16bit)的RAM中。但是异常向量表的开始地址是 由ARM架构决定的,必须位于0x0处,因此,必须把RAM映射到0x0。 2.Remap的配置 Remap的实现和ARM处理器的实现相关。 1)如
[单片机]
基于ARM处理器的TSC2046触摸屏控制器的应用
0 引言 随着信息技术的不断发展,嵌入式系统正在越来越广泛地应用到消费类电子、通信设备等便携式电子类产品中。触摸屏由于其轻便、占用空间少、灵活等优点,已经逐渐取代键盘,成为嵌入式系统中最简单、方便、自然的一种人机交互方式。触摸屏分为电阻、电容、表面声波、红外线扫描等类型,其中使用最多的是四线或五线电阻触摸屏。四线电阻触摸屏是由两个透明电阻膜构成的,在它的水平和垂直电阻网上施加电压,就可通过转换面板在触摸点测量出电压而对应出坐标值。 TSC2046是典型的逐次逼近寄存器型A/D变换器,其结构以电容再分布为基础,包含了取样/保持功能,支持低电压的I/O接口。本文介绍了利用飞利浦公司的LPC2100系列ARM芯片LPC2132、T
[单片机]
基于<font color='red'>ARM处理器</font>的TSC2046触摸屏控制器的应用
ARM处理器的工作模式 (二)
接 ARM处理器的工作模式(一) 实验二 各工作模式下堆栈初始化实验(ARM9)(工程exp9,文件exp9_2_1.s) 本实验实现各工作模式下堆栈初始化,采用ARMmulator方式调试,选用ARM9作为目标处理器。 AREA INIT_STACK,CODE,READONLY ENTRY ;工作于管理模式 START MOV R1,#1 ;初始化R1 BL INITSTACK ;设置各模式下的堆栈指针
[单片机]
俄罗斯公布全新国产PC电脑:自研4核ARM处理器+魔改Linux系统加持
因为一些客观情况,俄罗斯加快了研制国产PC的步伐,以满足需求和替代进口。日前,名为MIG Akinak的新款PC产品问世,硬件和软件均由俄罗斯本土打造。 核心CPU名为Skif (Scythian),64bit ARM架构,采用4核Cortex-A53 CPU+PowerVR Series8XE GE8300 GPU+双核DSP设计,频率1.8GHz,功耗仅24W。 其他配置方面,8GB~64GB LPDDR4内存、32GB/64GB eMMC硬盘,可通过microSD卡或者SATA II扩展2TB。预留的M.2不能接SSD,只能接Wi-Fi/蓝牙无线模块、蜂窝数据模块等。 系统预装基于Linux的Alt发行版
[家用电子]
俄罗斯公布全新国产PC电脑:自研4核<font color='red'>ARM处理器</font>+魔改Linux系统加持
俄罗斯打算研发ARM处理器替代Intel和AMD处理器
    有时候,DIY比采购更好,甚至是在微处理器产品上。俄罗斯本周证实,政府将资助一个项目,即俄罗斯自行研发代号为贝加尔湖的处理器。这个项目最后交易价值数千万美元。俄罗斯超级计算机厂商T-Platforms将成为该项目的牵头厂商。 和地球上其他国家类似,俄罗斯希望对内部机密进行保密。因此,它认为它不能信任美国制造的处理器,例如那些由英特尔和AMD制造的处理器。鉴于外界传闻表示,美国国家安全局已经与这两个公司在过去进行合作,有可能在计算机硬件中内建几乎无法察觉后门程序,因此我们很容易理解为什么俄罗斯希望走自行研发的道路。 俄罗斯的贝加尔处理器将采用ARM Cortex A57处理器架构。之前,普京在2010年定下目标,将所有政府电
[手机便携]
基于ARM处理器的非特定人语音识别系统设计
  随着高新技术在军事领域的广泛运用,武器装备逐步向高、精、尖方向发展。传统的军事训练由于训练时间长、训练费用高、训练空间窄,常常不能达到预期的训练效果,已不能满足现代军事训练的需要。为解决上述问题,模拟训练应运而生。   为进一步提高训练效果,本文利用智能语音交互芯片设计了某模拟训练器的示教与回放系统。示教系统为操作人员生动的演示标准操作流程及相应的操作现象,极大地缩短了对操作人员的培训时间,提高了培训效果。回放系统通过记录操作训练过程中各操作人员的口令、声音强度、动作、时间、操作现象等,待操作训练结束后通过重演训练过程,以便操作者及时纠正自己的问题。示教系统也可理解为对标准操作训练过程的回放。该系统不需要虚拟现实技术的支持,在小
[单片机]
基于<font color='red'>ARM处理器</font>的非特定人语音识别系统设计
用FIFO实现A/D与ARM处理器的接口
  在高速数据采集系统中,若A/D转换器直接与微处理器MCU相接,则因高速A/D的转换速率较高,迫使MCU不断地读取转换结果,因而就占用了MCU大部分的I/O带宽,降低了MCU的工作效率。在此情况下通常都会加缓存器,这样“模/数转换器缓存器一处理器”就成为一种通用模式。下面就介绍如何利用FIFO芯片CY7C4255V实现高速高精度模/数转换器AD767l与LPC2200系列ARM处理器的接口。   1 器件简介   1.1 模/数转换器AD7671   AD767l是采样速率达1Msps的16位逐次逼近型高速高精度模/数转换器,采用5V单电源供电,并能提供单极性和双极性两种输入方式,可适用不同的输入范围;它还提供校准与误
[单片机]
用FIFO实现A/D与<font color='red'>ARM处理器</font>的接口
基于ARM处理器的LCD编程设计
随着单片机技术的飞速发展,新型的仪器仪表呈现出操作简单、便携化的趋势。LCD模块能够满足嵌入式系统日益增长的要求,它可以显示汉字、字符和图形,同时还具有低压、低功耗、体积小、重量轻等诸多优点,因而应用十分广泛。 液晶显示模块(LCM)是由控制器、行驱动器、列驱动器、显示存储器和液晶显示屏等器件通过PCB组装成一体的低成本输出设备,被广泛用于各种仪器仪表等设备中。其核心部件LCD控制器是可编程接口芯片,它一方面提供与微控制器(MCU)的接口,一方面连接行/列驱动器。用户对LCD控制器编程就是实现对LCM的操作控制。LCD控制器的功能是接收计算机发来的指令和数据,并向计算机反馈所需的数据信息。 T6963控制模块
[单片机]
基于<font color='red'>ARM处理器</font>的LCD<font color='red'>编程</font>设计
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved