太常用就不列出了。
读写指令
读向量/浮点数
ld1
ld1 {v0.S}[0], [x0], #4
从x0出读一个float数,存到v0寄存器的第一个通道,并将x0加4
ld1 {v0.4S, v1.4S...}, [x0]
从x0处连续读入float,依次存到各个寄存器中
ld1 {v0.8B, v1.8B}, [x0]
ld1不仅可以读128位向量寄存器,也可以读64位向量寄存器,此时每个寄存器的高64位都是0,这样就可以处理8位向量
需要注意的是,ld1 是可以连续读浮点数到同一个vector中的,即:
ld1 {v0.S}[0], [x0], #4
ld1 {v0.S}[1], [x0], #4
ldr ldrb ldrh 区别
可以参考此文
ldrb R0, R1
从R1地址读一个字节存到R0,且将R0高位置为0。
ldrb w5, [x0], #1 //读一个字节
ldrb w6, [x1], #1 //读一个字节
add w7, w5, w6 //加
strb w7, [x2], #1 //存一个字节
相应地,ldrh和strh就是处理16位整数
ld1r
一个很好用的指令,从[x1]读一个元素,并赋值到向量所有通道
ld1r {v4.4S}, [x1], #4
偏移和元素有关的,具体如下:
Type | imm |
---|---|
8B/16B | 1 |
4H/8H | 2 |
2S/4S | 4 |
D/2D | 8 |
加法指令
UADDL, UADDL2 为了解决溢出问题,可以用长指令
UADDL{2} <Vd>.<Ta>, <Vn>.<Tb>, <Vm>.<Tb>
这两个长指令都是为了完成无符号整数的加法,不同的是,UADDL,是对两个源向量的低64位中的元素进行相加,并将长度增加2倍,写到目标寄存器中;UADDL2,是对高64位进行elemnetwise相加,并将结果写会目标寄存器。
ld1 {v0.16B}, [x0], #16
ld1 {v1.16B}, [x1], #16
uaddl v6.8H, v0.16B, v1.16B // 低64位,低位的8个数相加
uaddl2 v7.8H, v0.18B, v1.16B // 高64位
uqadd 饱和加
ld1 {v0.16B}, [x0], #16
ld1 {v1.16B}, [x1], #16
uqadd v2.16B, v0.16B, v1.16B
乘法
fmla 浮点乘加指令
在计算过程中是最强大最实用的指令了,有三大类场景
- 两个浮点数相乘,并与目标浮点寄存器相加
FMLA <Hd>, <Hn>, <Vm>.H[<index>]
- 向量与单个元素相乘,并与目标向量相加
FMLA <Vd>.<T>, <Vn>.<T>, <Vm>.<Ts>[<index>]
- 向量与向量逐个元素相乘,并与目标向量相加
FMLA <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
乘法支持16bit、32bit以及64bit,举例:
fmla H1, H0, {v3.H}[0]
fmla v2.4S, v1.4S, {v0.S}[0]
fmla v2.4S, v1.4S, v0.4S
mla 无符号整数乘加指令
所以不支持64位!
其他用法与fmla类似。