本文继续分析NEON指令,上篇文章中我们浅析了arm指令集,指令格式相关的基础知识,本文会继续深入NEON intrinsics指令的相关内容和作用浅析,内容可能会有点多,为保证大家的学习效果和良好的阅读体验,准备分上下两篇文章讲解,请各位读者耐心阅读。
Load/Store
以解交织的方式加载数据,将内存加载数据进neon寄存器
- // 以解交织方式加载数据到n个向量寄存器, n为1~4
- Result_t vld[n]
_type(Scalar_t *p_addr);
-
- //用type类型的内存中第一个值,初始化第一个新vector的所有元素,用内存中第二个值,初始化第二个新vector的所有元素。
- vld2_dup_type
以交织的方式存储数据,从neon寄存器加载数据进内存
- // 将n个寄存器的N通道数据以交织方式存储到内存中, n为1~4
- void vst[n]
_lane_type(Scalar_t *p_addr, Vector_t M, int N);
- // 将元素类型为type格式的vector中指定的某个元素装入内存
- vst1_lane_type
整数和浮点数的加减运算
- // 基本的加减操作
- Result_t vadd
_type(Vector1_t N, Vector2_t M);
- Result_t vsub
_type(Vector1_t N, Vector2_t M);
-
- // L(Long)类型的指令加减运算,输出向量长度是输入的两倍。
- Result_t vaddl_type(Vector1_t N, Vector2_t M);
- Result_t vsubl_type(Vector1_t N, Vector2_t M);
-
- // W(Wide)类型的指令加减运算,第一个输入向量的长度是第二个输入向量长度的两倍。
- Result_t vaddw_type(Vector1_t N, Vector2_t M);
- Result_t vsubw_type(Vector1_t N, Vector2_t M);
-
- // H(half)类型的加减运算;将计算结果除以2。
- Result_t vhadd
_type(Vector1_t N, Vector2_t M);
- Result_t vhsub
_type(Vector1_t N, Vector2_t M);
-
- // Q(Saturated)饱和类型的加减操作,结果超出元素的最大值时,元素就取最大值。
- Result_t vqadd
_type(Vector1_t N, Vector2_t M);
- Result_t vqsub
_type(Vector1_t N, Vector2_t M);
-
- // RH(Rounding Half)类型的加减运算
- Result_t vrhadd
_type(Vector1_t N, Vector2_t M);
- Result_t vrhsub
_type(Vector1_t N, Vector2_t M);
-
- // HN(half Narrow)类型的加减操作
- Result_t vaddhn_type(Vector1_t N, Vector2_t M);
- Result_t vsubhn_type(Vector1_t N, Vector2_t M);
-
- // RHN(rounding half Narrow)类型的加减操作
- Result_t vraddhn_type(Vector1_t N, Vector2_t M);
- Result_t vrsubhn_type(Vector1_t N, Vector2_t M);
整型和浮点型的乘法运算, 参与计算的都是向量
- // 基本乘法操作
- Result_t vmul
_type(Vector1_t N, Vector2_t M);
-
- // l(Long)类型的乘法操作,防止溢出
- Result_t vmull_type(Vector1_t N, Vector2_t M);
-
- // QDL(Saturated, Double, Long)类型的乘法操作,当结果溢出时,取饱和值
- Result_t vqdmull_type(Vector1_t N, Vector2_t M);
-
- // 基本的乘加和乘减操作
- Result_t vmla
_type(Vector1_t N, Vector2_t M, Vector3_t P);
- Result_t vmls
_type(Vector1_t N, Vector2_t M, Vector3_t P);
-
- // L(Long)类型的乘加和乘减操作
- Result_t vmlal_type(Vector1_t N, Vector2_t M, Vector3_t P);
- Result_t vmlsl_type(Vector1_t N, Vector2_t M, Vector3_t P);
-
- // QDL(Saturated, Double, Long)类型的乘加和乘减操作
- Result_t vqdmlal_type(Vector1_t N, Vector2_t M, Vector3_t P);
- Result_t vqdmlsl_type(Vector1_t N, Vector2_t M, Vector3_t P);
-
- // QDLH(Saturated, Double, Long, Half)类型的乘法操作
- Result_t vqdmulh
_type(Vector1_t N, Vector2_t M);
-
- // QRDLH(Saturated, Rounding Double, Long, Half)类型的乘法操作
- Result_t vqrdmulh
_type(Vector1_t N, Vector2_t M);
带通道类型的乘法操作
- // 基本的乘法操作
- Result_t vmull_lane_type(Vector1_t N, Vector2_t M, int n);
-
- // 基本的乘加和乘减操作
- Result_t vmla
_lane_type(Vector1_t N, Vector2_t M, Vector3_t P, int n);
- Result_t vmls
_lane_type(Vector1_t N, Vector2_t M, Vector3_t P, int n);
-
- // L(long) 类型的乘加和乘减操作
- Result_t vmlal_lane_type(Vector1_t N, Vector2_t M, Vector3_t P, int n);
- Result_t vmlsl_lane_type(Vector1_t N, Vector2_t M, Vector3_t P, int n);
-
- // QDL(Saturated, Double, long) 类型的乘加和乘减操作
- Result_t vqdmlal_lane_type(Vector1_t N, Vector2_t M, Vector3_t P, int n);
- Result_t vqdmlsl_lane_type(Vector1_t N, Vector2_t M, Vector3_t P, int n);
-
- // QDH(Saturated, Double, Half) 类型的操作
- Result_t vqdmulh
_lane_type(Vector1_t N, Vector2_t M, int n);
-
- vqdmull_lane_type
-
- vqdmulh_lane_type
-
- // QRDLH(Saturated, Rounding Double, Long, Half)类型的乘法操作
- vqrdmulhq_lane_type
向量和标量的乘法
- // 基本的向量和标量的乘法
- Result_t vmul
_n_type(Vector_t N, Scalar_t M);
-
- // L(Long) 类型的向量和标量的乘法
- Result_t vmull_n_type(Vector_t N, Scalar_t M);
-
- // QDL(Saturated, Double, long) 类型的向量和标量的乘法
- Result_t vqdmull_n_type(Vector_t N, Scalar_t M);
-
- // QDH(Saturated, Double, Half) 类型的向量和标量的乘法
- Result_t vqdmulh
_n_type(Vector_t N, Scalar_t M);
-
- // QRDH(Saturated, Double, Half) 类型的向量和标量的乘法
- Result_t vqrdmulh
_n_type(Vector_t N, Scalar_t M);
-
- // L(Long) 类型的乘加和乘减操作
- Result_t vmlal_n_type(Vector1_t N, Vector2_t M, Scalar_t P);
- Result_t vmlsl_n_type(Vector1_t N, Vector2_t M, Scalar_t P);
-
- // QDL(Saturated, Double, long) 类型的乘加和乘减
- Result_t vqdmlal_n_type(Vector1_t N, Vector2_t M, Scalar_t P);
- Result_t vqdmlsl_n_type(Vector1_t N, Vector2_t M, Scalar_t P);
-
- // QRDLH(Saturated, Rounding Double, Long, Half)类型的乘法操作
- Result_t vqrdmulhq_n_type(Vector1_t N, Vector2_t M, Scalar_t P);
比较类型
注: eq 表示相等, ge 表示大于或等于, gt 表示大于, le 表示小于或等于, lt 表示小于
逻辑比较操作,比较结果为true,输出向量的对应通道将被设置为全 1,否则设置为全0 。
- Result_t vceq
_type(Vector1_t N, Vector2_t M);
- vceqq_type
- Result_t vcge
_type(Vector1_t N, Vector2_t M);
- vcgeq_type
- Result_t vcle
_type(Vector1_t N, Vector2_t M);
- vcleq_type
- Result_t vcgt
_type(Vector1_t N, Vector2_t M);
- vcgtq_type
- Result_t vclt
_type(Vector1_t N, Vector2_t M);
- vcltq_type
向量的绝对值比较,比较结果为true时,输出向量对应通道将被设置为全1,否则设置为全0。
- Result_t vcage
_type(Vector1_t N, Vector2_t M);
- vcageq_f32
- Result_t vcale
_type(Vector1_t N, Vector2_t M);
- vcaleq_f32
- Result_t vcalt
_type(Vector1_t N, Vector2_t M);
- vcaltq_f32
- Result_t vcagt
_type(Vector1_t N, Vector2_t M);
- vcagtq_f32
逻辑类
按位与\或\非\异或操作
- Result_t vand
_type(Vector1_t N, Vector2_t M);
- Result_t vorr
_type(Vector1_t N, Vector2_t M);
- Result_t vmvn
_type(Vector_t N);
- Result_t veor
_type(Vector1_t N, Vector2_t M);
其他
- // 按通道做与操作,为 true 时,将输出向量对应通道设置为全 1,否则设置为全 0
- Result_t vtst
_type(Vector1_t N, Vector2_t M);
-
- // M 作为 mask,标识是否对 N 做清零操作。当 M 中某位为 1, 则将 N 中对应位清零,ri = ~M & N
- Result_t vbic
_type(Vector1_t N, Vector2_t M);
-
- // ri = ai | (~bi)
- Result_t vorn
_type(Vector1_t N, Vector2_t M);
-
- // 按位选择,参数为(N, M, P)。P 作为 mask,按位 select。当 P 中某位是 1 时,将选择 N 中对应位作为输出,否则选择 M
- Result_t vbsl
_type(Vector1_t N, Vector2_t M, Vector3_t P);
浮点数之间的转化, 以及浮点类型与整数类型之间的转化
- // f32、u32、s32之间的转换。在f32转到u32时,是向下取整,且如果是负数,则转换后为0
- Result_t vcvt_type1_type2
- // 单精度浮点转化为整数类型
- Result_t vcvt
_type_f32(Vector_t N);
-
- // 整数类型转化为单精度浮点
- Result_t vcvt
_f32_type(Vector_t N);
-
- // f16转化为f32
- Result_t vcvt_f16_f32(Vector_t N);
-
- // f32转化为f16
- Result_t vcvt_f32_f16(Vector_t N);
向量提取
- //取第2个输入vector的低n个元素放入新vector的高位,新vector剩下的元素取自第1个输入vector最高的几个元素(可实现vector内元素位置的移动)
- Result_t vext
_type(Vector1_t N, Vector2_t M, int n);
- vextq_type
查找操作
- //第二个vector是索引,根据索引去第一个vector(相当于数组)中搜索相应的元素,并输出新的vector,超过范围的索引返回的是0.
- Result_t vtbl[n]_type(Vector1_t N, Vector2_t M);
- // 根vtbl1_type功能一样,不过搜索到的元素是用来替换第一个vector中的元素,并输出替换后的新vector,当索引超出范围时,则不替换第一个vector中相应的元素。
- Result_t vtbx[n]_type(Vector1_t N, Vector2_t M, Vector3_t P);
向量翻转
- Result_t vrev64
_type(Vector_t N);
- Result_t vrev32
_type(Vector_t N);
- Result_t vrev16
_type(Vector_t N);
-
- vrev16
_type 按照 16bit 为块,块内数据按照 8bit 为单位进行翻转。
- vrev32
_type 按照 32bit 为块,块内数据按照 8bit,16bit 为单位进行翻转。
- vrev64
_type 按照 64bit 为块,块内数据按照8bit, 16bit, 32bit为单位进行翻转。
交叉和解交叉操作
- // 交织操作,将两个输入vector的元素通过交叉生成一个有两个vector的矩阵
- Result_t vzip
_type(Vector1_t N, Vector2_t M);
-
- // 解交织操作,将两个输入vector的元素通过反交叉生成一个有两个vector的矩阵(通过这个可实现n-way 交织)
- Result_t vuzp
_type(Vector1_t N, Vector2_t M);
立即数类型的位移
- // 基本的立即数左移和右移
- Result_t vshr
_n_type(Vector_t N, int n);
- Result_t vshl
_n_type(Vector_t N, int n);
-
- // R(rounding) 类型的右移操作
- Result_t vrshr
_n_type(Vector_t N, int n);
-
- // QL(Saturated, long) 类型的右移操作
- Result_t vqshl
_n_type(Vector_t N, int n);
-
- // 右移累加操作
- Result_t vsra
_n_type(Vector1_t N, Vector2_t M, int n);
-
- // R(rounding) 类型的右移累加操作
- Result_t vrsraq_n_type(Vector1_t N, Vector2_t M, int n);
-
- // ri = N << n 输入vector是有符号,输出vector是无符号
- Result_t vqshlu_n_type(Vector_t N, int n);
- // Q(Saturated) 类型的左移操作,而且输入是有符号,输出是无符号的
- Result_t vqshluq_n_type(Vector_t N, int n);
-
-
- // N(Narrow) 类型的右移操作
- Result_t vshrn_n_type(Vector_t N, int n);
-
- // QN(Saturated, Narrow) 类型的右移操作, 而且输入是有符号,输出是无符号的
- Result_t vqshrun_n_type(Vector_t N, int n);
-
- // QRN(Saturated, Rounding, Narrow) 类型的右移操作, 而且输入是有符号,输出是无符号的
- Result_t vqrshrun_n_type(Vector_t N, int n);
-
- // QN(Saturated, Narrow) 类型的右移操作
- Result_t vqshrn_n_type(Vector_t N, int n);
-
- // RN(Rounding, Narrow) 类型的右移操作
- Result_t vrshrn_n_type(Vector_t N, int n);
-
- // QRN(Rounding, Rounding, Narrow) 类型的右移操作
- Result_t vqrshrn_n_type(Vector_t N, int n);
-
- // N(Narrow) 类型的左移操作
- Result_t vshll_n_type(Vector_t N, int n);
非立即数类型的位移
- // 左移
- Result_t vshlq_type(Vector1_t N, Vector2_t M);
-
- // Q(Saturated) 类型的左移操作
- Result_t vqshl
_type(Vector1_t N, Vector2_t M);
-
- // QR(Saturated, rounding) 类型的左移操作
- Result_t vrshl
_type(Vector1_t N, Vector2_t M);
移位并插入
- // 将向量 M 中各个通道先右移动 n 位, 然后将移动后元素插入到 N 对应的元素中,
- // 并保持 N 中每个元素的高 n 位保持不变
- Result_t vsri
_n_type(Vector1_t N, Vector2_t M, int n);
- vsri_n_type:
- vsriq_n_type:
-
- // 将向量 M 中各个通道先左移动 n 位, 然后将移动后元素插入到 N 对应的元素中,
- // 并保持 N 中第每个元素的低 n 位保持不变
- Result_t vsli
_n_type(Vector1_t N, Vector2_t M, int n);
- vsli_n_type:
- vsliq_n_type:
本文主要归纳总结了 NEON intrinsics常用指令相关的知识,附有对应的解释,希望耐心读文章的你能有所收获,敬请期待下篇文章。