文章目录
- SVE Load 和 Store 指令使用介绍
- LD1 加载指令
- ST1 存储指令
- PFR 预取指令
- 参考示例
- LD1 加载示例
- ST1 存储示例
- 代码实例
SVE Load 和 Store 指令使用介绍
ARMv9架构中的SVE(Scalable Vector Extension)指令集为向量计算提供了强大支持,特别是针对不同数据类型和访问模式的加载(Load)和存储(Store)操作。下面是对您提到的一些SVE指令的简要介绍和使用示例。
LD1 加载指令
LD1{B|D|H|W} {Zt.<T>}, Pg/Zn, [Xn, Xm{, LSL #imm}]
:- 加载一个或多个元素到向量寄存器
Zt
中。 {B|D|H|W}
指定加载的元素大小(字节、双字、半字、字)。Pg/Zn
为谓词寄存器,控制加载操作。[Xn, Xm{, LSL #imm}]
指定内存地址。
- 加载一个或多个元素到向量寄存器
LD1R{B|D|H|W} {Zt.<T>}, Pg/Zn, [Xn]
:- 从内存加载一个元素并重复到向量
Zt
的所有元素中。 R
代表重复(Repeat)。
- 从内存加载一个元素并重复到向量
LD1RO{B|D|H|W} {Zt.<T>}, Pg/Zn, [Xn, Xm]
:- 从内存加载一个旋转(Rotate)元素到向量
Zt
中。 RO
代表旋转(Rotate)。
- 从内存加载一个旋转(Rotate)元素到向量
LDFF1{B|H|W|D} {Zt.<T>}, Pg/Zn, [Xn, Xm]
:- 第一次找到的(First-Fault)加载。如果遇到不能访问的内存,则停止加载剩余元素。
FF
代表第一次遇到故障就停止。
ST1 存储指令
ST1{B|D|H|W} {Zt.<T>}, Pg, [Xn, Xm{, LSL #imm}]
:- 将向量寄存器
Zt
中的一个或多个元素存储到内存。 - 用法类似于加载指令,但用于存储。
- 将向量寄存器
PFR 预取指令
PRF{B|D|H|W}
:- 预取指令用于将内存数据预取到高速缓存,以提高访问速度。
- 指定预取的数据大小和类型。
参考示例
假设我们需要将一个双字(64位)的数据加载到向量寄存器Z0
中,然后将这个向量的数据存储回内存。
LD1 加载示例
// 假设X0包含了数据的内存地址
// 使用Pg作为谓词寄存器,控制加载过程
ptrue p0.d
// 从[X0]地址加载一个双字数据到Z0的所有元素中
ld1rd {z0.d}, p0, [x0]
这里,ld1rd
指令从X0
指向的内存地址加载一个双字数据,并将其重复填充到向量寄存器Z0
的所有元素中,受谓词寄存器P0
的控制。
ST1 存储示例
// 假设X1包含了要存储数据的目标内存地址
// 将Z0寄存器中的数据存储到[X1]地址
st1d {z0.d}, p0, [x1]
这里,st1d
指令将向量寄存器Z0
中的数据存储到X1
指向的内存地址中,操作受谓词寄存器P0
的控制。
代码实例
测试代码如下:
- 首先将谓词寄存器
p0
中所有字节元素的控制位都设为1,意味着所有后续操作都会影响到z0
的所有字节元素; - 执行
ST1B {z0.d}, p0, [x1]
按8位(即1字节)的单元将z0
寄存器中的数据(根据谓词寄存器p0
的掩码)存储到x1
指向的开始地址0xb0000000
处; - 最后将地址
0xb0000000
地址处的值返回。
func sve_add_test
stp x29, x30, [sp, #-0x10]!
ptrue p0.b
ldr w0, =0x11111111
dup z0.b, w0
cpy z0.b, p0/z, #0x55
ldr x1, =0xb0000000
st1b {z0.d}, p0, [x1]
mov x0, xzr
ldr x0, [x1]
ldp x29,x30, [sp], #0x10
ret
endfunc sve_add_byte_test
需要注意的是 指令 ST1{B|D|H|W}
写的次数是和 {z0.n}
的配置有关,比如当测试代码修改为 st1w {z0.d}, p0, [x1]
之后,表示每次写一个word,一共写2次,因为z0 向量寄存器的大小为128bits,在写入操作时每个元素的大小是按照64bits计算的。
msh >dump 0xb0000000 4
0xb0000000: 0x55555555 0x55555555 0x00000000 0x00000000
修改为 st1b {z0.d}, p0, [x1]
之后,在写入操作时每个元素的大小是按照64bits计算的,每次写1入byte:
msh >dump 0xb0000000 4
0xb0000000: 0x00005555 0x00000000 0x00000000 0x00000000
修改为 st1b {z0.b}, p0, [x1]
之后,在写入操作时每个元素的大小是按照8bits计算的,每次写1入byte:
msh >dump 0xb0000000 4
0xb0000000: 0x55555555 0x55555555 0x55555555 0x55555555
修改为 st1b {z0.h}, p0, [x1]
之后,在写入操作时每个元素的大小是按照16bits(half-word)计算的,每次写1入byte, 一共写入8次:
msh >dump 0xb0000000 4
0xb0000000: 0x55555555 0x55555555 0x00000000 0x00000000