simd-neno加速
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加速相关推荐
- 【27】SIMD:如何加速矩阵乘法?
[计算机组成原理]学习笔记--总目录 [27]SIMD:如何加速矩阵乘法? 引言 一.超线程:Intel 多卖给你的那一倍 CPU 1.背景 2.超线程(Hyper-Threading)技术 二.SI ...
- 使用SIMD指令加速计算
SIMD即单指令多数据流(Single Instruction Multiple Data)指令集,是通过一条指令同时对多个数据进行运算的硬件加速技术,在传统计算,中使用标量运算一次只能对一对数据执行 ...
- SIMD via C#
简介 TL;DR 我们为C#(准确地说是.NET Core)引入了一套全新的机制,使得C# 以后可以像C/C++ 一样直接使用intrinsic functions 来直接操作Intel CPU 的大 ...
- Cortex-M4和Cortex-M7中的SIMD指令
SIMD指令简介 单指令多数据流,即SIMD(Single Instruction, Multiple Data)指一类能够在单个指令周期内同时处理多个数据元素的指令集,利用的是数据级并行来提高运行效 ...
- 使用SIMD指令实现数据库运算(论文阅读笔记)
摘要 现代cpu的指令允许在多个数据元素上并行执行基本操作.这些指令称为SIMD指令,因为它们将一条指令应用于多个数据元素.SIMD技术最初被内置到商业处理器中,以加速多媒体应用程序的性能.SIMD指 ...
- 深度学习实战——模型推理优化(模型压缩与加速)
忆如完整项目/代码详见github:https://github.com/yiru1225(转载标明出处 勿白嫖 star for projects thanks) 目录 系列文章目录 一.实验思路综 ...
- Rust 1.0发布一周年,发展回顾与总结
本文为InfoQ中文站特供稿件,首发地址为: http://www.infoq.com/cn/articles/anniversary-of-the-release-of-rust-1 .如需转载,请 ...
- libyuv库的使用
libyuv是Google开源的实现各种YUV与RGB之间相互转换.旋转.缩放的库.它是跨平台的,可在Windows.Linux.Mac.Android等操作系统,x86.x64.arm架构上进行编译 ...
- C# vs C++ 全局照明渲染性能比试
512x512像素,每像素1000采样,C#版本渲染时间为40分47秒 最近有多篇讨论程序语言趋势的博文,其中谈及到C#的性能问题.本人之前未做过相关测试,自己的回覆流于理论猜测,所以花了点时间做个简 ...
最新文章
- PHP 中提示undefined index如何解决(多种方法)
- linux shell crond crontab 定时器 计划任务 定时任务
- luogu1514 [NOIp2010]引水入城 (bfs+记忆化搜索)
- 前端学习(1939)vue之电商管理系统电商系统之完成全部功能
- 【java小知识】FileReader读取文件出现乱码的解决办法
- 【JAVA基础篇】多线程
- 腾讯开源视频动作检测算法DBG,打破两项世界纪录!
- 【CodeVS2226】飞行棋
- arm中的.a文件如何产生的_如何在IPFS中Pin一个文件?
- 全球开发者大调查:编程始于少年,Python 成最爱
- java this() super(),Java super()和this()的区别用法及代码示例
- 2D空间中求线段与圆的交点
- 黑客帝国装逼的代码雨
- 今日头条的排名算法_今日头条的推荐算法原理分析
- 1分钟教你破解风行电视禁止安装应用!
- 无线电波是怎么产生的
- 数组名 和数组名的理解
- python推箱子代码详细讲解_Python使用tkinter模块实现推箱子游戏
- react native Android 键盘将底部导航栏/按钮顶起
- 《操作系统》--RR、进程同步、银行家算法及Clock算法复习题
热门文章
- CSCD刊源(2007年-2008年)
- RMAN备份归档日志时的not backed up与catalog数据库结合时的问题
- 无法向虚拟机中拷贝文件解决办法
- android版本连击,死神vs火影无限能量连招版本-死神vs火影无限连招版v3.2 安卓版-腾牛安卓网...
- 程序员必备神器机械键盘,真香!
- html借助JS简单实现图片闪烁功能
- 管理经济学 知识点总结(一)
- 用Interl 5100AGN 无线网卡破解无线网络WEP密码
- 基于卷积神经网络 CNN 的猫狗识别详细过程
- Could not find artifact org.eclipse.m2e:lifecycle-mapping:pom:1.0.0