NEON指令
按照操作数类型可以分为正常指令、宽指令、窄指令、饱和指令、长指令。
- 正常指令:生成大小相同且类型通常与操作数向量相同到结果向量。
- 长指令:对双字向量操作数执行运算,生产四字向量到结果。所生成的元素一般是操作数元素宽度到两倍,并属于同一类型。L标记,如VMOVL。
- 宽指令:一个双字向量操作数和一个四字向量操作数执行运算,生成四字向量结果。W标记,如VADDW。
- 窄指令:四字向量操作数执行运算,并生成双字向量结果,所生成的元素一般是操作数元素宽度的一半。N标记,如VMOVN。
- 饱和指令:当超过数据类型指定到范围则自动限制在该范围内。Q标记,如VQSHRUN
指令的格式理解
NEON指令中有的加q,有的不加q,有何区别?
操作符后的q,如vmulq, 表示128位满位宽寄存器运算
v后的q,如vqrdmulh,q表示饱和运算,溢位后,为自动限制在数据类型的最大范围内。
rdmul表示向量与标量进行加倍乘运算的具体操作意义。
hq表示高位饱和,lq表示低位饱和。
int16x8_t vqaddq_s16 (int16x8_t, int16x8_t)
和int16x4_t vqadd_s16 (int16x4_t, int16x4_t)
中vqaddq_s16和vqadd_s16各个字段的解释如下:
第一个字母’v’指明是vector向量指令,也就是NEON指令;
第二个字母’q’指明是饱和指令,即后续的加法结果会自动饱和;
第三个字段’add’指明是加法指令;
第四个字段’q’指明操作寄存器宽度,为’q’时操作QWORD, 为128位;未指明时操作寄存器为DWORD,为64位;
第五个字段’s16’指明操作的基本单元为有符号16位整数,其最大表示范围为-32768 ~ 32767;
形参和返回值类型约定与C语言一致。
其它助记符包括:
l 长指令,数据扩展
w 宽指令,数据对齐
n 窄指令, 数据压缩
NEON变量的命名规则
没有统一的规则,如果想要规范些,可采用以下命名方式。变量类型 变量名:vTNnVar
解释
v,表示向量运算
T,表示变量的类型,分别用s表示有符号整型,u表示无符号整型,f表示浮点
N,表示变量元素所占位宽,如s32,u16,f32中的数字即N,表示元素占位
n,表示向量线元素结构,如x4,x4x2
Var,表示变量自定义的名字
vld1 格式
Result_t vld1_type(Scalar_t* N);
Result_t vld1q_type(Scalar_t* N);
这个指令的作用是从内存加载到向量中
例子:
vld1q_u16
是一个 ARM NEON 指令,用于加载一组连续的 16 位无符号整数(uint16_t)值到一个 128 位的 NEON 寄存器。从内存中读取连续的 8 个 16 位无符号整数值,并将它们存储到一个 NEON 寄存器中。ptr
是一个指向这些值的内存地址的指针
uint16_t *src = image_src;
uint16x8_t vsrc;
vsrc = vld1q_u16(src);
vdup_n 格式
vdup_n_type(Scalar_t N)
:将标量值N
复制到一个 64 位的 NEON 向量寄存器中,并将其扩展为给定类型的元素。vdupq_n_type(Scalar_t N)
:将标量值N
复制到一个 128 位的 NEON 向量寄存器中,并将其扩展为给定类型的元素
这个指令的作用是创建一个具有相同值的向量,其中每个元素都等于给定的标量值。例如,如果使用 VDUPQ_N
指令将标量值 5
复制到一个 128 位的 NEON 向量寄存器中,那么该向量的每个元素都将被设置为 5
。使用 VDUPQ_N
指令可以方便地初始化向量寄存器,生成常量向量或将标量值扩展为向量形式。这对于需要对向量中的每个元素执行相同操作的情况非常有用,并且可以提高数据处理的效率
例如:
uint16x8_t q0 = vdupq_n_u16(UINT16_MAX);//初始化创建
vst1格式
void vst1_type(Scalar_t* N, Vector_t M);
void vst1q_type(Scalar_t* N, Vector_t M);
存储向量到内存
例子
uint8x8_t v; // define v as a vector with 8 lanes of 8-bit data
unsigned char A[8]; // allocate memory for eight 8-bit data
v = vcreate_u8(0x0102030405060708); // create a vector that contains the values
// 1,2,3,4,5,6,7,8
vst1_u8(A, v); // store the vector to memory, in this case, to array A
arm_neon.h 支持的操作
add 加法
mul 乘法
sub 减法
mla 乘加
mls 乘减
ceq 比较,类似与 ==
cge 比较,类似与 >=
cle 比较,类似与 <=
cgt 比较,类似与 >
clt 比较,类似与 <
tst 做与运算后,判断是否等于0 ,ri = (ai & bi != 0) ? 1…1:0…0;
abd 两个向量相减后的绝对值,vabd -> ri = |ai - bi|;
max 求最大值,ri = ai >= bi ? ai : bi;
min 求最小值,ri = ai >= bi ? bi : ai;
shl 左移位, ri = ai << b;
shr 右移位, ri = ai >> b;
abs 求绝对值,ri = |ai|;
neg 取反,ri = -ai;
mvn 按位取反,ri = ~ai;
and 与运算,ri = ai & bi;
orr 或运算,ri = ai | bi;
eor 异或运算,ri = ai ^ bi;
cls 计算连续相同的位数
get 取值,从向量中取出一个值,所谓的向量可以认为是一个数组,给数组中的某个元素赋值
set 赋值,给向量中赋值
dup 构造一个向量,并赋上初始值,ri = a;
combine 合并操作,把两个向量合并
mov 改变数据类型,数据范围,比如把u8 变成u16,或者u16变成u8
zip 压缩操作
uzp 解压操作
ld1 加载数据,给定的buffer 指针中拷贝数据,注意是ld后面的是数字1,而不是字母l
st1 拷贝数据,将neon数据类型拷贝到指定buffer中
指令查询表