IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> NEON优化:ARM优化高频指令总结 -> 正文阅读

[嵌入式]NEON优化:ARM优化高频指令总结

NEON优化:ARM优化高频指令总结

本篇博客主要分享根据优化经验总结的高频NEON指令。

总体划分:

  • 读写:数据存取及寄存器读写
  • 计算:加减乘和乘加
  • 转换:位宽、类型、重解释
  • 操作:移位、比较、绝对值、最大值

前言


了解指令前,你需要知道什么是向量?什么是向量线?

  • 向量,就是指一个寄存器中同时存的不同值,比如float32x4_t类型,就是个4元素的向量。
  • 向量线,就是向量里的具体元素值。

随后,为便于理解指令意义,你需要知道指令格式规范是什么?

  • 指令样式:int16x4_t vqmovn_s32(int32x4_t a);

    • int16x4,表示返回的类型,int16表示16位整型,x4表示为4个元素的向量
    • vq中的v表示vector向量运算,q表示饱和运算,比如溢出就截断为最值
      • 而如vmulq_n_f32中,_前面的q是指满位宽128位运算
    • movn表示运算类型,是做位宽变换操作
    • s32表示操作对象为int32
  • 饱和运算:

    • 涉及字符位由宽变窄时,超过当前类型最大值时自动截断成该类型最值
  • 并行位数:

    • arm平台的NEON并行计算:最大支持128位
    • 指令中,类型符下划线前,加q为128位运算,不加为64位运算;
      • vld1q_f32,对应f32x4的类型,满128位
      • vld1_f32,对应f32x2的类型,仅64位
  • 涉及到有标量的运算,函数会有_n_作为标识

    • 涉及标量:float32x4_t vmulq_n_f32(float32x4_t a, float32_t b);
    • 不涉及标量:float32x4_t vmulq_f32(float32x4_t a, float32x4_t b);

读写


数据存取

  • 读数据指令:
    • 指令1:vld1q_f32(float p), 读满维128位数据,324,4个32位float数据
    • 指令2:vld2q_f32(float p), 读2个满维128位数据,324*2
    • 指令3:vld4q_f32(float p), 读4个满维128位数据,324*4
    • 效果:从内存读取数据到NEON寄存器中
  • 写数据指令:
    • 指令1:void vst1q_f32(__transfersize(4) float32_t * ptr, float32x4_t val); // 拷贝4个32位的浮点,共128位
    • 指令2:void vst1q_s16(__transfersize(8) int16_t * ptr, int16x8_t val); // 拷贝8个16位的整型,共128位
    • 指令3:void vst1_s16(__transfersize(4) int16_t * ptr, int16x4_t val); // 拷贝4个16位的整型,共 64
    • 效果:将NEON寄存器的值存入到内存(正常浮点变量),存储NEON向量到内存 store

在向量内设置向量线

  • 指令:float32x4_t vdupq_n_f32(float32_t value);
  • 效果:将所有向量线设置为相同的值,将向量初始为特定相同值
  • 注意:进阶指令可调具体位置去设定相应值

取向量中的向量线

  • 取前两个向量线指令:float32x2_t vget_low_f32(float32x4_t a); // a1, a2, a3, a4 => a1, a2
  • 取后两个向量线指令:float32x2_t vget_high_f32(float32x4_t a); // a1, a2, a3, a4 => a3, a4
  • 效果:取向量中的部分对,从4个值中取前两个与后两个

计算


加法

  • 指令:int32x4_t vaddq_s32(int32x4_t a, int32x4_t b);
  • 效果:vr = a + b

减法

  • 指令:int32x4_t vsubq_s32(int32x4_t a, int32x4_t b);
  • 效果:vr = a - b

向量乘标量

  • 指令:float32x4_t vmulq_n_f32(float32x4_t a, float32_t b); // a1, a2, a3, a4;
  • 效果:输出为vr = (a1, a2, a3, a4) * b

向量与标量乘后加

  • 指令:float32x4_t vmlaq_n_f32(float32x4_t a, float32x4_t b, float32_t c);
  • 效果:向量与标量进行的乘加,结果为 vr = a + b * c
  • 特别注意:不是 a * b + c

转换


位宽转换

  • 窄到宽指令:int32x4_t vmovl_s16(int16x4_t a);
  • 效果:把4个16位数值扩展为4个32位的数值,相当于:int16_t a = 3; int32_t b = (int32_t)a;
  • 宽到窄指令:int16x4_t vqmovn_s32(int32x4_t a);
  • 效果:由宽字符到窄字符,由于可能溢位,故要做饱和运算

类型转换

  • 指令:float32x4_t vcvtq_f32_s32(int32x4_t a);
  • 效果:将32位整型转换为32位浮点,cvt是convert的缩写

类型重解释

  • 指令:int8x16_t vreinterpretq_s8_f32(float32x4_t a); // 将float32x4的a解释成int8x16_t类型
  • 效果:向量重新解释类型转换运算
  • 说明:不更改值本身,将原始二进制值按不同类型进行解码

操作


左右移位

  • 左移指令:uint32x4_t vshlq_n_u32(uint32x4_t a, __constrange(0,31) int b); // 左移,b范围:[0, 31]
  • 右移指令:uint32x4_t vshrq_n_u32(uint32x4_t a, __constrange(1,32) int b); // 右移,b范围:[1, 32]
  • 效果:向量按常数标量左右移位

差值绝对值

  • 指令:float32x4_t vabdq_f32(float32x4_t a, float32x4_t b);
  • 效果:vr = |a - b|
  • 说明:能直接和标量进行运算的,只有乘法;其他如最大值,加减都不行

最大值

  • 指令:float32x4_t vmaxq_f32(float32x4_t a, float32x4_t b); // a1, a2, a3, a4; b1, b2, b3, b4;
  • 效果:成对取最大值,输出值为:[max(a1, b1), max(a2, b2), ..., max(a4, b4)]

折叠最大值

  • 指令:float32x2_t vpmax_f32(float32x2_t a, float32x2_t b); // a1, a2; b1, b2;
  • 效果:取相零对的最大值,输出值为:[max(a1, a2), max(b1, b2)]

比较大小

  • 小于比较:uint32x4_t vcltq_f32(float32x4_t a, float32x4_t b); // 判断a<b

  • <=比较:uint32x4_t vcleq_s32(int32x4_t a, int32x4_t b); // 判断a<=b

  • >=比较:uint32x4_t vcgeq_s32(int32x4_t a, int32x4_t b); // 判断a>=b

  • 缩略助记:clt(compare less than),cgt(compare grete than),ceq(comprae equal), ge(>=), le(<=)

  • 返回类型:无符号数,位宽与入参相同

按位选择

  • 指令:int32x4_t vbslq_s32(uint32x4_t a, int32x4_t b, int32x4_t c);
  • 函数用法:将a的每一位进行判断,若是1,则输出b中对应位;否则输出c中对应位
  • 注意事项:通常和比较函数的输出a结合使用,a为无符号比较结果,返回值类型与输入值b/c类型相同

向量内元素反转

  • 指令:uint8x8_t vrev16_u8(uint8x8_t vec);

  • 助记符:vrev(bit)_(type)

  • 效果:向量内按指定的位数bit,成对相互交换

  • 举例:

    uint8x8_t src = {1,2,3,4,5,6,7,8};
    dst = vrev16_u8(src) --> dst = {2,1,4,3,6,5,8,7} // 按16位为1小组,内部以8位为元素逆序
    dst = vrev64_u8(src) --> dst = {8,7,6,5,4,3,2,1} // 按64位为1小组,内部以8位为元素逆序  
    

参考资料


  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-07-04 23:07:47  更:2022-07-04 23:08:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:36:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码