simd-neno加速

  • 前言
  • 一、基本概念
  • 二、NEON
    • 1.基本类型
    • 2.结构体类型(组合多个向量类型)
    • 3.NEON intrinsics指令命名
    • 4.NEON intrinsics指令使用流程
    • 5.NEON intrinsics指令分类
  • 其他

前言

最近需要使用neon指令集对使用C语言编写的算子进行加速,这里简单记录一下neno加速的基础知识。

一、基本概念

  • simd
    simd是Single instruction, multiple data的缩写,指的是单指令多数据并行,即可以用一条指令处理多条数据。这种SIMD指令功能,主流的体系结构一般都用一组特殊的指令子集给予支持,比如x86的SSE,还比如本文讲的ARM的NEON。

  • ARM
    ARM架构,过去称作进阶精简指令集机器(Advanced RISC Machine,更早称作:Acorn RISC Machine),是一个32位精简指令集(RISC)处理器架构,其广泛地使用在许多嵌入式系统设计。ARM的NEON是类似于X86的SSE2的一种优化的指令集,主要就是为了实现SIMD全称Single Instruction Multiple Data,单指令多数据流,能够复制多个操作数,并把它们打包在大型寄存器的一组指令集。

  • NENO
    NEON是ARM下的一个SIMD指令集合。可实现64位/128位的并行计算。NENO包含两种寄存器

    • 32 个 64-bit 的 D-Register
    • 可组成 16个 128-bit 的 Q-Register

    寄存器可拆分如下:

寄存器 可拆分
D寄存器(64bit) int8x8_t 、 int16x4_t 、int32x2_t 、int64x1_t 、uint8x8_t 、 uint16x4_t 、uint32x2_t 、uint64x1_t 、float32x2_t 、float64x1_t、poly8x8_t 、 poly16x4_t 、
R寄存器(128bit) int8x16_t 、 int16x8_t 、int32x4_t 、int64x2_t 、uint8x16_t 、 uint16x8_t 、uint32x4_t 、uint64x2_t 、float32x4_t 、float64x2_t、poly8x16_t 、 poly16x8_t 、
  • NEON intrinsics
    Neon 内在函数是一组在 arm_neon.h 中定义的 C 和 C++ 函数。直接使用汇编写neno会导致效率不高且编码困难,C编译器支持将NEON指令封装成内置函数供程序员直接使用,就相当于函数调用,但事实上,但将生成的代码反汇编后可以发现,其实没有调用函数,只是在使用NEON寄存器和指令罢了。详情可见Neon Intrinsics官方文档

二、NEON

1.基本类型

<基本类型>x<向量个数>_t
基本类型包括:int8,int16,int32,int64,uint8,uint16,uint32,uint64,float16,float32
如:int16x4_t 表示 一个向量,包含了4个16位整型并行的向量(4个lane,每个lane存16位的数)

2.结构体类型(组合多个向量类型)

type size x <number_of_lanes>x<length_of_array>_t
例:包含两个寄存器的结构体,访问单个元素<var_name>.val[0]。

struct int16x4x2_t
{
int16x4_t val[2];
} <var_name>

3.NEON intrinsics指令命名

<指令名>[后缀]_<数据基本类型简写>
后缀类型:如果没有后缀,表示是D寄存器,64位并行;如果后缀是q,表示128位并行;如果后缀是l,表示长指令,输出数据的基本类型位数是输入的2倍;如果后缀是n,表示窄指令,输出数据的基本类型位数是输入的一半。
数据基本类型简写:s8,s16,s32,s64,u8,u16,u32,u64,f16,f32
例如:vadd_u16:两个uint16x4相加为一个uint16x4
vaddq_u16:两个uint16x8相加为一个uint16x8
vaddl_u16:两个uint8x8相加为一个uint16x8

完整定义:v<noen函数前缀>q<饱和操作>ops<具体操作>type<指令类型 q,l,w,n>_flag<标识 n,lane,high or low>_dtype<返回值类型或参数类型>
例如:int8x8_t vadd_s8 (int8x8_t __a, int8x8_t __b); v是向量操作,add 是相加,s8表示结果是s8类型
int8x8_t vshr_n_s8 (int8x8_t __a, const int __b);v是向量操作,shr是右移位,n表示参数中有个基本数据类型

4.NEON intrinsics指令使用流程

  • 定义Neon向量
  • 读取数据(vld1)
  • 处理数据
  • 回写数据(vst1)
int main(void){uint8x8x3_t v;  // 定义neno向量unsigned char A[24] = {1};    v = vld3_u8(A); // 读取数据v.val[0] = vadd_u8(v.val[0], v.val[0]); //处理数据vst3_u8(A, v);  // 回写数据}

5.NEON intrinsics指令分类

  • 算术和位运算指令

    add 加法 、sub 减法、mul 乘法、mla 乘加、mls 乘减、max 最大值、min 最小值、shl 左移位、shr 右移位、abs 求绝对值、neg 取反、mvn 按位取反、and 与运算、orr 或运算、eor 异或运算、tst 进行与运算之后,判断是否等于0、abd 两个向量相减之后的绝对值

  • 数据移动指令
    get 取值、set 赋值、dup 构造一个向量,并进行初始化
    combine 合并操作,将两个向量进行合并
    mov 改变数据类型和数据范围

    uint32_t vector_add_of_n(uint32_t* ptr, uint32_t items)
    {uint32_t result, *i;uint32x2_t vec64a, vec64b;uint32x4_t vec128 = vdupq_n_u32(0);     // clear acccumulatorsfor(i = ptr, i < (ptr + (items/4)); i += 4){uint32x4_t temp128 = vld1q_u32(i);  // load four 32-bit valuesvec128 = vaddq_u32(vec128, temp128);// add 128-bit vectors}vec64a = vget_low_u32(vec128);      // split 128-bit vectorvec64b = vget_high_u32(vec128);     // into two 64-bit vectorsvec64a = vadd_u32(vec64a, vec64b);  // add 64-bit vectors togetherresult = vget_lane_u32(vec64a, 0);  // extract lanes andresult += vget_lane_u32(vec64a, 1); // add together scalarsreturn result;
    }
    
  • 访存指令
    vld<向量数>[后缀]<数据基本类型简写>:读内存
    vst<向量数>[后缀]
    <数据基本类型简写>:写内存
    例如,vld1_u8从内存读取一个uint8x8_t数据,vst3q_u8写入一个u8x16x3_t数据。

    void split(uint8_t *rgb, uint8_t *r, uint8_t *g, uint8_t *b) {uint8x16x3_t v = vld3q_u8(rgb);vst1q_u8(r, v.val[0]);vst1q_u8(g, v.val[1]);vst1q_u8(b, v.val[2]);
    }
    
  • 条件指令
    ceq 比较 ==
    cge 比较 >=
    cle 比较 <=
    cgt 比较 >
    clt 比较 <

    其他

    查询更多函数可参考ARM Neon Intrinsics各函数

simd-neno加速相关推荐

  1. 【27】SIMD:如何加速矩阵乘法?

    [计算机组成原理]学习笔记--总目录 [27]SIMD:如何加速矩阵乘法? 引言 一.超线程:Intel 多卖给你的那一倍 CPU 1.背景 2.超线程(Hyper-Threading)技术 二.SI ...

  2. 使用SIMD指令加速计算

    SIMD即单指令多数据流(Single Instruction Multiple Data)指令集,是通过一条指令同时对多个数据进行运算的硬件加速技术,在传统计算,中使用标量运算一次只能对一对数据执行 ...

  3. SIMD via C#

    简介 TL;DR 我们为C#(准确地说是.NET Core)引入了一套全新的机制,使得C# 以后可以像C/C++ 一样直接使用intrinsic functions 来直接操作Intel CPU 的大 ...

  4. Cortex-M4和Cortex-M7中的SIMD指令

    SIMD指令简介 单指令多数据流,即SIMD(Single Instruction, Multiple Data)指一类能够在单个指令周期内同时处理多个数据元素的指令集,利用的是数据级并行来提高运行效 ...

  5. 使用SIMD指令实现数据库运算(论文阅读笔记)

    摘要 现代cpu的指令允许在多个数据元素上并行执行基本操作.这些指令称为SIMD指令,因为它们将一条指令应用于多个数据元素.SIMD技术最初被内置到商业处理器中,以加速多媒体应用程序的性能.SIMD指 ...

  6. 深度学习实战——模型推理优化(模型压缩与加速)

    忆如完整项目/代码详见github:https://github.com/yiru1225(转载标明出处 勿白嫖 star for projects thanks) 目录 系列文章目录 一.实验思路综 ...

  7. Rust 1.0发布一周年,发展回顾与总结

    本文为InfoQ中文站特供稿件,首发地址为: http://www.infoq.com/cn/articles/anniversary-of-the-release-of-rust-1 .如需转载,请 ...

  8. libyuv库的使用

    libyuv是Google开源的实现各种YUV与RGB之间相互转换.旋转.缩放的库.它是跨平台的,可在Windows.Linux.Mac.Android等操作系统,x86.x64.arm架构上进行编译 ...

  9. C# vs C++ 全局照明渲染性能比试

    512x512像素,每像素1000采样,C#版本渲染时间为40分47秒 最近有多篇讨论程序语言趋势的博文,其中谈及到C#的性能问题.本人之前未做过相关测试,自己的回覆流于理论猜测,所以花了点时间做个简 ...

最新文章

  1. PHP 中提示undefined index如何解决(多种方法)
  2. linux shell crond crontab 定时器 计划任务 定时任务
  3. luogu1514 [NOIp2010]引水入城 (bfs+记忆化搜索)
  4. 前端学习(1939)vue之电商管理系统电商系统之完成全部功能
  5. 【java小知识】FileReader读取文件出现乱码的解决办法
  6. 【JAVA基础篇】多线程
  7. 腾讯开源视频动作检测算法DBG,打破两项世界纪录!
  8. 【CodeVS2226】飞行棋
  9. arm中的.a文件如何产生的_如何在IPFS中Pin一个文件?
  10. 全球开发者大调查:编程始于少年,Python 成最爱
  11. java this() super(),Java super()和this()的区别用法及代码示例
  12. 2D空间中求线段与圆的交点
  13. 黑客帝国装逼的代码雨
  14. 今日头条的排名算法_今日头条的推荐算法原理分析
  15. 1分钟教你破解风行电视禁止安装应用!
  16. 无线电波是怎么产生的
  17. 数组名 和数组名的理解
  18. python推箱子代码详细讲解_Python使用tkinter模块实现推箱子游戏
  19. react native Android 键盘将底部导航栏/按钮顶起
  20. 《操作系统》--RR、进程同步、银行家算法及Clock算法复习题

热门文章

  1. CSCD刊源(2007年-2008年)
  2. RMAN备份归档日志时的not backed up与catalog数据库结合时的问题
  3. 无法向虚拟机中拷贝文件解决办法
  4. android版本连击,死神vs火影无限能量连招版本-死神vs火影无限连招版v3.2 安卓版-腾牛安卓网...
  5. 程序员必备神器机械键盘,真香!
  6. html借助JS简单实现图片闪烁功能
  7. 管理经济学 知识点总结(一)
  8. 用Interl 5100AGN 无线网卡破解无线网络WEP密码
  9. 基于卷积神经网络 CNN 的猫狗识别详细过程
  10. Could not find artifact org.eclipse.m2e:lifecycle-mapping:pom:1.0.0