入门:如何用C语言编写用了ARM NEON指令集的程序
本篇随笔将简介如何使用C语言,去编写调用ARM NEON指令集的程序。负优化警告,快跑
零、Neon指令集简介
和AVX等指令集类似,但Neon只能一口气算128位!!
一、引入头文件
首先你得引个头文件,接下来才能愉快玩耍:
#include <arm_neon.h>
二、数据结构定义
以下内容纯纯的是个人理解,没有任何资料做参考,因而也纯供参考,理性看待!
大部分数据结构都长这样:int8x8_t
或者 int64x2x4_t
根据文档,里头存的好像是存放数字的寄存器的标号。!!未经考证
如果把它分成三个部分,那就是——
<int/uint/float...><x1/x2/...>[x2/x3/x4/...]
第一部分(<int/uint/float...>
):向量里头每一个数字是啥类型的
第二部分(<x1/x2/...>
):这个x?,问号里头的数字,就是这个类型的变量所对应的寄存器中,存着几个某类型的值。
比如我们声明一个int8x8_t
类型的变量vector_a
,那么vector_a
(对应的寄存器)里头,存着8个int类型的变量。 (注:vector_a
里头存的好像是存放数字的寄存器的标号。!!未经考证)
第三部分([x2/x3/x4/...]
):如果有第三部分,那么就意味着这是个“数组”,之所以加引号,是因为用的时候,是采取vec.val[0]
这种方式调用的,本质是个结构体。x?,就意味着vec.val里头有几个元素;每个元素的类型,就是前面两个部分所定义的类型。
比如我们声明一个int64x2x4_t
类型的变量vector_array
,那么vector_array.val
就是类型为int64x2_t
类型的数组(对应int64x2x4_t
中的int64x2
),数组中有4个元素(对应int64x2x4_t
中的x4
),每个元素的类型是int64x2_t
。具体要用哪个int64x2_t
去处理,需要你使用vector_array.val[0/1/2/3]
来指定
三、一些常用函数类
开始的开始,先给个官方查函数的网页,点这里进去,帮你勾选了只显示neon指令集的相关函数。
和avx类似,neon的指令,常用的不外乎:加载的、写回的、运算的。
所谓加载,是把你正常数组中的数字,给干到专门用于算向量的寄存器里去;
所谓写回,是把专门用于算向量的寄存器里头存的向量,给干到你的某个数组里头去;
所谓运算,就是加减乘除移位啥的。
加载类
一般情况下用的加载类的函数长这样:vld1_s8
,也可以拆成几个部分:
vld<1/2/3/4/..>[q]_[s/u/f/...][8/16/32/64]
一般只有一个参数,通常某个数组的地址就够用了。
根据具体函数,返回一个我们所提到的数据结构类型中的一种,比如int64x2x4_t
。
v
:应该是代表这是指令;ld
:应该是load
的缩写;<1/2/3/4/..>
:代表读几组。例如如果是vld【4】q_s64
,返回得到的是一个类型为int64x2【x4】_t
的东西。(不知我所云?看看上面数据结构定义那部分!)[q]
,可有可无。没有,则代表就从你给的地址开始,读64位就行;有,那就读128位。例子我们在说完下面的东西后给。_
,一条朴实无华的下划线;[s/u/f/...]
,代表每个元素的数据类型,s是有符号整数,u是无符号整数,f是浮点数等等;[8/16/32/64]
,你这个数据类型有多少位。例如如果是vld4q_【s64】
,那你每个元素就是一个64位的有符号整数。
所以,我们来举个具体例子——如果我们要从ptr
这个地址读8个64位的无符号整数,读到专门用于计算的寄存器里头,该用啥函数呢?
答案是int64x2x4_t vector = vld4q_s64(ptr);
,因为——
v ld 4 q _ s 64 ——4
,读4组数字;q
,一组读128位;s
,读的是无符号整数;64
,一个元素的大小是64位。
无符号整数,一个元素的大小是64位,将一组128位读入一个寄存器,那一组里头可以放2个64位的整数,而我们读4组,所以总共读8个64位的无符号整数。
那么返回啥类型的值呢?int64x2x4_t
,64位的,一个寄存器里放俩64位的(int64x2x4_t
中的x2
),总共用了4个寄存器(int64x2x4_t
中的x4
)。
(未完待续)
评论已关闭