【NEON 和 VFP 编程】NEON加载、存储元素和结构指令
本节包括以下小节:
• 交叉存取。
• 加载/存储元素和结构指令中的对齐限制。
• VLDn 和 VSTn(单个 n 元素结构到一条向量线)。
此类指令几乎可用于所有数据访问。可加载标准向量 (n = 1)。
• VLDn(单个 n 元素结构到所有向量线)。
• VLDn 和 VSTn(多个 n 元素结构)。
一、交叉存取
此组中的许多指令在将结构存储到内存时提供交叉存取功能,并在从内存加载结构时提供反向交叉存取功能。下图显示了一个反向交叉存取示例。 交叉存取就是反向的过程。
二、加载/存储元素和结构指令中的对齐限制
其中许多指令允许指定内存对齐限制。 如果指令中未指定对齐,则由 A 位(CP15 寄存器 1 位 [1])控制对齐限制。
• 如果 A 位为 0,则没有对齐限制(但强序或设备内存除外,其访问必须对齐元素,否则会出现意外结果)。
• 如果 A 位为 1,则访问必须对齐元素。
如果地址未正确对齐,则会发生对齐故障。
三、VLDn 和 VSTn(单个 n 元素结构到一条向量线)
向量加载(单个 n 元素结构到一个向量线)将一个 n 元素结构从内存加载到一个或多个 NEON 寄存器。未加载的寄存器元素将保持不变。
语法
Vopn{cond}.datatype list, [Rn{@align}]{!}
Vopn{cond}.datatype list, [Rn{@align}], Rm
其中:
op 必须为 LD 或 ST。
n 必须为 1、2、3 或 4 之一。
cond 是一个可选的条件代码。
datatype 见下表。
list 指定 NEON 寄存器列表。 有关选项,见下表。
Rn 是包含基址的 ARM 寄存器。Rn 不得为 R15。
align 指定可选对齐。 有关选项,见下表。
! 如果 ! 存在,则将 Rn 更新为(Rn + 指令传送的字节数)。 在完成所有加载/存储后,执行该更新。
Rm 是一个包含基址偏移量的 ARM 寄存器。 如果 Rm 存在,则在使用该地址访问内存之后,将 Rn 更新为 (Rn + Rm)。Rm 不得为 R13 或 R15。
下面是单个 2 元素结构到一条向量线的示例。
unsigned int *data = new unsigned int[4];
unsigned int *data1 = new unsigned int[4];
for (int i = 0; i < 4; i++) {
data[i] = 0x0;
data1[i] = (unsigned int) (i + 1);
LOGI("1 data[%d]=%#0X data1[%d]=%#0X", i, data[i], i, data1[i]);
}
asm volatile(
"VBIC q0,q0\t\n"
"VLD2.32 {d0[0],d2[0]},[%1]\t\n"
"VST2.32 {d0[0],d2[0]},[%0]\t\n"
:"+r"(data),//%0
"+r"(data1) //%1
:
: "memory", "q0", "q1"
);
for (int i = 0; i < 4; i++) {
LOGI("2 data[%d]=%#0X data1[%d]=%#0X", i, data[i], i, data1[i]);
}
运行结果:
11-11 08:38:28.860 3290-3290/ndk.example.com.ndkexample I/Native: 1 data[0]=0 data1[0]=0X1
1 data[1]=0 data1[1]=0X2
1 data[2]=0 data1[2]=0X3
1 data[3]=0 data1[3]=0X4
2 data[0]=0X1 data1[0]=0X1
2 data[1]=0X2 data1[1]=0X2
2 data[2]=0 data1[2]=0X3
2 data[3]=0 data1[3]=0X4
先将data1中的前两个元素分别加载到D0[0]和D2[0]中,然后将他们存储到数组data中。
四、VLDn(单个 n 元素结构到所有向量线)
向量加载(单个 n 元素结构到所有向量线)将一个 n 元素结构的多个副本从内存加载到一个或多个 NEON 寄存器中。
语法
VLDn{cond}.datatype list, [Rn{@align}]{!}
VLDn{cond}.datatype list, [Rn{@align}], Rm
其中:
n 必须为 1、2、3 或 4 之一。
cond 是一个可选的条件代码。
datatype 见下表。
list 指定 NEON 寄存器列表。 有关选项,见下表。
Rn 是包含基址的 ARM 寄存器。Rn 不得为 R15。
align 指定可选对齐。 有关选项,见下表。
! 如果 ! 存在,则将 Rn 更新为(Rn + 指令传送的字节数)。 在完成所有加载/存储后,执行该更新。
Rm 是一个包含基址偏移量的 ARM 寄存器。 如果 Rm 存在,则在使用该地址访问内存之后,将 Rn 更新为 (Rn + Rm)。Rm 不得为 R13 或 R15。
将代码稍作修改即可。
unsigned int *data = new unsigned int[4];
unsigned int *data1 = new unsigned int[4];
for (int i = 0; i < 4; i++) {
data[i] = 0x0;
data1[i] = (unsigned int) (i + 1);
LOGI("1 data[%d]=%#0X data1[%d]=%#0X", i, data[i], i, data1[i]);
}
asm volatile(
"VBIC q0,q0\t\n"
"VBIC q1,q1\t\n"
"VLD2.32 {d0[],d2[]},[%1]\t\n"
"VSTM %0,{q0}\t\n"
"VSTM %1,{q1}\t\n"
:"+r"(data),//%0
"+r"(data1) //%1
:
: "memory", "q0", "q1"
);
for (int i = 0; i < 4; i++) {
LOGI("2 data[%d]=%#0X data1[%d]=%#0X", i, data[i], i, data1[i]);
}
运行结果
11-11 09:08:06.200 3530-3530/ndk.example.com.ndkexample I/Native: 1 data[0]=0 data1[0]=0X1
1 data[1]=0 data1[1]=0X2
1 data[2]=0 data1[2]=0X3
1 data[3]=0 data1[3]=0X4
2 data[0]=0X1 data1[0]=0X2
2 data[1]=0X1 data1[1]=0X2
2 data[2]=0 data1[2]=0
2 data[3]=0 data1[3]=0
说明d0寄存器中都是0x1,d2寄存器中都是0x2。
五、VLDn 和 VSTn(多个 n 元素结构)
向量加载(多个 n 元素结构)使用反向交叉存取功能,将多个 n 元素结构从内存加载到一个或多个 NEON 寄存器中(除非 n == 1)。 会加载每个寄存器的每个元素。
向量存储(多个 n 元素结构)使用交叉存取功能将多个 n 元素结构从一个或多个 NEON 寄存器存储到内存中(除非 n == 1)。 会存储每个寄存器的每个元素。
语法
Vopn{cond}.datatype list, [Rn{@align}]{!}
Vopn{cond}.datatype list, [Rn{@align}], Rm
其中:
op 必须为 LD 或 ST。
n 必须为 1、2、3 或 4 之一。
cond 是一个可选的条件代码。
datatype 有关选项,见下表。
list 指定 NEON 寄存器列表。 有关选项,见下表。
Rn 是包含基址的 ARM 寄存器。Rn 不得为 R15。
align 指定可选对齐。 有关选项,见下表。
! 如果 ! 存在,则将 Rn 更新为(Rn + 指令传送的字节数)。 在完成所有加载/存储后,执行该更新。
Rm 是一个包含基址偏移量的 ARM 寄存器。 如果 Rm 存在,则在使用该地址访问内存之后,将 Rn 更新为 (Rn + Rm)。Rm 不得为 R13 或 R15。
下面是代码示例片段,将上面的例子稍作修改。
unsigned int *data = new unsigned int[4];
unsigned int *data1 = new unsigned int[4];
for (int i = 0; i < 4; i++) {
data[i] = 0x0;
data1[i] = (unsigned int) (i + 1);
LOGI("1 data[%d]=%#0X data1[%d]=%#0X", i, data[i], i, data1[i]);
}
asm volatile(
"VBIC q0,q0\t\n"
"VBIC q1,q1\t\n"
"VLD2.32 {d0,d2},[%1]\t\n"
"VST2.32 {d0,d2},[%0]\t\n"
:"+r"(data),//%0
"+r"(data1) //%1
:
: "memory", "q0", "q1"
);
for (int i = 0; i < 4; i++) {
LOGI("2 data[%d]=%#0X data1[%d]=%#0X", i, data[i], i, data1[i]);
}
运行结果:
11-12 07:59:34.720 3084-3084/ndk.example.com.ndkexample I/Native: 1 data[0]=0 data1[0]=0X1
1 data[1]=0 data1[1]=0X2
1 data[2]=0 data1[2]=0X3
1 data[3]=0 data1[3]=0X4
2 data[0]=0X1 data1[0]=0X1
2 data[1]=0X2 data1[1]=0X2
2 data[2]=0X3 data1[2]=0X3
2 data[3]=0X4 data1[3]=0X4
上一篇: 传统车厂转型 吉利推"iNTEC"品牌专注人性化智驾
下一篇: 放气,折好,锁抽屉