性能優化篇(3):NEON快速入門指南
Author:stormQ
Sunday, 24. November 2019 10:28PM
向量數據類型
- 語法格式
向量類型:
<type><size><number_of_lanes>_t
向量數組:
<type><size><number_of_lanes><length_of_array>_t
注:type
,表示數據類型,可選項:int(帶符號整型)、uint(無符號整型)、float(浮點型)和 poly(多項式)。size
,表示一個元素佔用多少 bit。number_of_lanes
,表示一個向量中包含的元素數量,第一個元素位於 lane[0] 的位置,第 n 個元素位於 lane[n-1] 的位置,lane[0] 對應向量寄存器最低位的size
個 bit。length_of_array
,向量數組的大小。
- 示例
向量類型 | 含義 |
---|---|
uint8x8_t | 一個包含八個元素,元素類型爲 8-bit 無符號整型的向量 |
uint8x8x2_t | 一個包含兩個向量的向量數組,每個向量包含八個元素,元素類型爲 8-bit 無符號整型 |
向量賦值
向量常數賦值
uint8x8_t 向量常數賦值(每個元素的值都相同)
- 函數原型
uint8x8_t vdup_n_u8(uint32_t a);
-
作用
- 將類型爲
uint8x8_t
的向量中每個元素的值設置爲參數a
的值。
- 將類型爲
-
注意事項
- 參數
a
的值大於 255 時會發生”整型截斷“;每個元素的賦值互不影響。
- 參數
-
代碼示例
#include "arm_neon.h"
int main()
{
// 聲明一個包含八個元素的向量,每個元素的數據類型爲 uint8_t
uint8x8_t a_uint8x8;
// 將向量的每個元素賦值爲 255
a_uint8x8 = vdup_n_u8(255);
return 0;
}
注:使用NEON Intrinsics
需要包含頭文件arm_neon.h
。
- 代碼調試
; 語句 a_uint8x8 = vdup_n_u8(255); 對應的彙編指令:dup v0.8b, w0
(gdb) disas
...
0x0000000000400a18 <+40>: dup v0.8b, w0
...
; 執行 dup v0.8b, w0 前,打印 w0 寄存器的值
(gdb) p $w0
$2 = 255
...
; 執行 dup v0.8b, w0 後,打印 v0 寄存器的值
(gdb) p $v0.b.u
$3 = {255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}
(gdb) p $v0.b.u[0]
$4 = 255
(gdb) p $v0.b.u[7]
$5 = 255
(gdb) p $v0.b.u[8]
$6 = 0
可以看出 v0 寄存器的低位 8 字節分別被賦值爲 255。
uint8x8_t 向量常數賦值(每個元素的值可以不同)
- 函數原型
uint8x8_t vcreate_u8 (uint64_t __a);
-
作用
- 將參數
a
賦值給類型爲uint8x8_t
的向量。
- 將參數
-
注意事項
- 賦值順序:參數
__a
的值從右到左每字節的內容依次賦值給向量的第一個元素到第八個元素(即lane[0]
到lane[7]
)。
- 賦值順序:參數
-
代碼示例
void print_uint8x8_t(uint8x8_t val)
{
std::printf("lane0=0x%x\n", vget_lane_u8(val, 0));
std::printf("lane1=0x%x\n", vget_lane_u8(val, 1));
std::printf("lane2=0x%x\n", vget_lane_u8(val, 2));
std::printf("lane3=0x%x\n", vget_lane_u8(val, 3));
std::printf("lane4=0x%x\n", vget_lane_u8(val, 4));
std::printf("lane5=0x%x\n", vget_lane_u8(val, 5));
std::printf("lane6=0x%x\n", vget_lane_u8(val, 6));
std::printf("lane7=0x%x\n", vget_lane_u8(val, 7));
std::printf("\n");
}
void assign_different_constant()
{
std::printf("assign_different_constant function..............\n");
uint8x8_t a_uint8x8 = vcreate_u8(0x12345678abcdef01);
print_uint8x8_t(a_uint8x8);
}
輸出結果爲:
assign_different_constant function..............
lane0=0x1
lane1=0xef
lane2=0xcd
lane3=0xab
lane4=0x78
lane5=0x56
lane6=0x34
lane7=0x12
可以看出,參數__a
的值從右到左每字節的內容依次賦值給向量的第一個元素到第八個元素。
向量內存賦值
uint8x8_t 向量內存賦值
- 函數原型
uint8x8_t vld1_u8 (const uint8_t *a);
-
作用
- 將內存起始地址爲
a
的後面八字節的內容賦值給類型爲uint8x8_t
的向量。
- 將內存起始地址爲
-
注意事項
- 如果參數
a
的有效元素數量小於8,那麼會發生非法讀。
- 如果參數
-
代碼示例
{
// 源數據的有效元素數量等於8,合法
uint8_t f_arr_uint8[] = {0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8};
uint8x8_t f_uint8x8 = vld1_u8(f_arr_uint8);
print_uint8x8_t(f_uint8x8);
}
{
// 源數據的有效元素數量小於8,最後一個元素爲非法讀
uint8_t a_arr_uint8[] = {0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8};
uint8x8_t a_uint8x8 = vld1_u8(&a_arr_uint8[1]);
print_uint8x8_t(a_uint8x8);
}
{
// 源數據的有效元素數量大於8,合法
uint8_t b_arr_uint8[] = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf};
uint8x8_t b_uint8x8 = vld1_u8(b_arr_uint8);
print_uint8x8_t(b_uint8x8);
}
{
// 源數據的有效元素數量小於8,第五個元素到第八個元素爲非法讀
uint8_t c_arr_uint8[] = {0xc1, 0xc2, 0xc3, 0xc4};
uint8x8_t c_uint8x8 = vld1_u8(c_arr_uint8);
print_uint8x8_t(c_uint8x8);
}
{
// 源數據的有效元素數量小於8,除第一個元素外其他元素爲非法讀
uint8_t d_arr_uint8 = 0xd1;
uint8x8_t d_uint8x8 = vld1_u8(&d_arr_uint8);
print_uint8x8_t(d_uint8x8);
}
注:關於print_uint8x8_t
函數的實現可以在其他示例中找到,此處省略。
- 代碼調試
(gdb) x/b &a_arr_uint8[0]+8
0x7ffffff320: 0xff
; 打印 uint8x8_t a_uint8x8 = vld1_u8(&a_arr_uint8[1]); 執行的結果
(gdb) p/x $v0.b.u
$4 = {0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
; 可以看出v0.b.u[7]的值爲0xff,即內存地址爲&a_arr_uint8[0]+8的值。驗證了最後一個元素爲非法讀。
(gdb) x/4b c_arr_uint8+4
0x7ffffff31c: 0xb4 0xb5 0xb6 0xb7
; 打印 uint8x8_t c_uint8x8 = vld1_u8(c_arr_uint8); 執行的結果
(gdb) display/x $v0.b.u
1: /x $v0.b.u = {0xc1, 0xc2, 0xc3, 0xc4, 0xb4, 0xb5, 0xb6, 0xb7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
; 可以看出v0.b.u[4]、v0.b.u[5]、v0.b.u[6]、v0.b.u[7]的值分別爲0xb4、 0xb5、 0xb6、 0xb7,
; 即內存起始地址爲c_arr_uint8+4後面4字節的值。驗證了第五個元素到第八個元素爲非法讀。
(gdb) x/7b &d_arr_uint8+1
0x7ffffff2c8: 0x19 0xf3 0xff 0xff 0x7f 0x00 0x00
; 打印 uint8x8_t d_uint8x8 = vld1_u8(&d_arr_uint8); 執行的結果
(gdb) display/x $v0.b.u
1: /x $v0.b.u = {0xd1, 0x19, 0xf3, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
2: /x $v0.b.u = {0xd1, 0x19, 0xf3, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
; 可以看出v0.b.u[1]、v0.b.u[2]、v0.b.u[3]、v0.b.u[4]、v0.b.u[5]、v0.b.u[6]、v0.b.u[7]的值
; 分別爲0x19、 0xf3、 0xff、 0xff、 0x7f、 0x0、 0x0,即內存起始地址爲&d_arr_uint8+1後面7字節的值。
; 驗證了除第一個元素外其他元素爲非法讀。
上述示例驗證了:vld1_u8()函數作用是將參數的值作爲內存起始地址,無條件地將其後面的八字節的值賦值給向量。但如果源數據的有效元素數量小於8,會發生非法讀
。
uint8x8x2_t 向量內存賦值
- 函數原型
uint8x8x2_t vld2_u8 (const uint8_t * __a);
-
作用
- 內存地址爲
__a、__a+2、__a+4、... __a+14
的內容分別賦值給第一個向量的lane[0]、lane[1]、...、lane[7]
,內存地址爲__a+1、__a+3、__a+5、... __a+15
的內容分別賦值給第二個向量的lane[0]、lane[1]、...、lane[7]
。
- 內存地址爲
-
代碼示例
void print_uint8x8_t(uint8x8_t val)
{
std::printf("lane0=0x%x\n", vget_lane_u8(val, 0));
std::printf("lane1=0x%x\n", vget_lane_u8(val, 1));
std::printf("lane2=0x%x\n", vget_lane_u8(val, 2));
std::printf("lane3=0x%x\n", vget_lane_u8(val, 3));
std::printf("lane4=0x%x\n", vget_lane_u8(val, 4));
std::printf("lane5=0x%x\n", vget_lane_u8(val, 5));
std::printf("lane6=0x%x\n", vget_lane_u8(val, 6));
std::printf("lane7=0x%x\n", vget_lane_u8(val, 7));
std::printf("\n");
}
void print_uint8x8x2_t(uint8x8x2_t data)
{
std::printf("print val[0] ...\n");
print_uint8x8_t(data.val[0]);
std::printf("print val[1] ...\n");
print_uint8x8_t(data.val[1]);
}
void assign_from_mem()
{
std::printf("assign_from_mem function..............\n");
uint8_t arr_uint8[] = {0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8};
uint8x8x2_t a_uint8x8x2 = vld2_u8(arr_uint8);
print_uint8x8x2_t(a_uint8x8x2);
}
輸出結果爲:
assign_from_mem function..............
print val[0] ...
lane0=0xe1
lane1=0xe3
lane2=0xe5
lane3=0xe7
lane4=0xf1
lane5=0xf3
lane6=0xf5
lane7=0xf7
print val[1] ...
lane0=0xe2
lane1=0xe4
lane2=0xe6
lane3=0xe8
lane4=0xf2
lane5=0xf4
lane6=0xf6
lane7=0xf8
向量單個元素內存賦值
uint8x8_t 向量單個元素內存賦值
- 宏定義
#define vld1_lane_u8(a, b, c)
-
作用
- 設置向量中指定元素的值,而不改變其他元素的值。參數
a
爲指向數據類型爲uint8_t
的指針;參數b
爲指向數據類型爲uint8x8_t
的向量;參數c
爲向量中元素的索引,合法範圍爲0 <= c <=7
。
- 設置向量中指定元素的值,而不改變其他元素的值。參數
-
代碼示例
void print_uint8x8_t(uint8x8_t val)
{
std::printf("lane0=0x%x\n", vget_lane_u8(val, 0));
std::printf("lane1=0x%x\n", vget_lane_u8(val, 1));
std::printf("lane2=0x%x\n", vget_lane_u8(val, 2));
std::printf("lane3=0x%x\n", vget_lane_u8(val, 3));
std::printf("lane4=0x%x\n", vget_lane_u8(val, 4));
std::printf("lane5=0x%x\n", vget_lane_u8(val, 5));
std::printf("lane6=0x%x\n", vget_lane_u8(val, 6));
std::printf("lane7=0x%x\n", vget_lane_u8(val, 7));
std::printf("\n");
}
void assign_lane()
{
std::printf("assign_lane function..............\n");
uint8_t a_arr_uint8[] = {0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8};
uint8x8_t a_uint8x8;
std::printf("set lane[0] ...\n");
a_uint8x8 = vld1_lane_u8(a_arr_uint8, a_uint8x8, 0);
print_uint8x8_t(a_uint8x8);
std::printf("set lane[1] ...\n");
a_uint8x8 = vld1_lane_u8(a_arr_uint8 + 1, a_uint8x8, 1);
print_uint8x8_t(a_uint8x8);
std::printf("set lane[2] ...\n");
a_uint8x8 = vld1_lane_u8(a_arr_uint8 + 2, a_uint8x8, 2);
print_uint8x8_t(a_uint8x8);
std::printf("set lane[3] ...\n");
a_uint8x8 = vld1_lane_u8(a_arr_uint8 + 3, a_uint8x8, 3);
print_uint8x8_t(a_uint8x8);
std::printf("set lane[4] ...\n");
a_uint8x8 = vld1_lane_u8(a_arr_uint8 + 4, a_uint8x8, 4);
print_uint8x8_t(a_uint8x8);
std::printf("set lane[5] ...\n");
a_uint8x8 = vld1_lane_u8(a_arr_uint8 + 5, a_uint8x8, 5);
print_uint8x8_t(a_uint8x8);
std::printf("set lane[6] ...\n");
a_uint8x8 = vld1_lane_u8(a_arr_uint8 + 6, a_uint8x8, 6);
print_uint8x8_t(a_uint8x8);
std::printf("set lane[7] ...\n");
a_uint8x8 = vld1_lane_u8(a_arr_uint8 + 7, a_uint8x8, 7);
print_uint8x8_t(a_uint8x8);
}
輸出結果爲:
assign_lane function..............
set lane[0] ...
lane0=0xa1
lane1=0xed
lane2=0x21
lane3=0xe3
lane4=0x7f
lane5=0x0
lane6=0x0
lane7=0x0
set lane[1] ...
lane0=0xa1
lane1=0xa2
lane2=0x21
lane3=0xe3
lane4=0x7f
lane5=0x0
lane6=0x0
lane7=0x0
set lane[2] ...
lane0=0xa1
lane1=0xa2
lane2=0xa3
lane3=0xe3
lane4=0x7f
lane5=0x0
lane6=0x0
lane7=0x0
set lane[3] ...
lane0=0xa1
lane1=0xa2
lane2=0xa3
lane3=0xa4
lane4=0x7f
lane5=0x0
lane6=0x0
lane7=0x0
set lane[4] ...
lane0=0xa1
lane1=0xa2
lane2=0xa3
lane3=0xa4
lane4=0xa5
lane5=0x0
lane6=0x0
lane7=0x0
set lane[5] ...
lane0=0xa1
lane1=0xa2
lane2=0xa3
lane3=0xa4
lane4=0xa5
lane5=0xa6
lane6=0x0
lane7=0x0
set lane[6] ...
lane0=0xa1
lane1=0xa2
lane2=0xa3
lane3=0xa4
lane4=0xa5
lane5=0xa6
lane6=0xa7
lane7=0x0
set lane[7] ...
lane0=0xa1
lane1=0xa2
lane2=0xa3
lane3=0xa4
lane4=0xa5
lane5=0xa6
lane6=0xa7
lane7=0xa8
訪問/存儲向量的值
訪問 uint8x8_t 的值
- 函數原型
uint8_t vget_lane_u8(uint8x8_t __a, const int __b);
-
作用
- 返回類型爲
uint8x8_t
向量(由參數__a
確定)的第n
個元素(由參數__b
確定)的值。
- 返回類型爲
-
注意事項
-
參數
__b
指明訪問向量中第幾個元素的值,有效範圍爲0 <= b <= 7
。 -
如果參數
__b
的值不在有效範圍,在編譯時會報如下錯誤——error: lane 8 out of range 0 - 7
。 -
參數
__b
的值必須在編譯期確定。也就是說,參數__b
只能是常數。如果不是,編譯時會報如下錯誤——error: lane index must be a constant immediate
。
-
-
代碼示例
// 聲明一個包含八個元素的向量,每個元素的數據類型爲 uint8_t
uint8x8_t a_uint8x8;
// 將向量的每個元素賦值爲 255
a_uint8x8 = vdup_n_u8(255);
// 分別打印變量 a_uint8x8 的八個元素的值(十六進制)
std::printf("a_uint8x8: lane0=0x%x\n", vget_lane_u8(a_uint8x8, 0));
std::printf("a_uint8x8: lane1=0x%x\n", vget_lane_u8(a_uint8x8, 1));
std::printf("a_uint8x8: lane2=0x%x\n", vget_lane_u8(a_uint8x8, 2));
std::printf("a_uint8x8: lane3=0x%x\n", vget_lane_u8(a_uint8x8, 3));
std::printf("a_uint8x8: lane4=0x%x\n", vget_lane_u8(a_uint8x8, 4));
std::printf("a_uint8x8: lane5=0x%x\n", vget_lane_u8(a_uint8x8, 5));
std::printf("a_uint8x8: lane6=0x%x\n", vget_lane_u8(a_uint8x8, 6));
std::printf("a_uint8x8: lane7=0x%x\n", vget_lane_u8(a_uint8x8, 7));
輸出結果爲:
a_uint8x8: lane0=0xff
a_uint8x8: lane1=0xff
a_uint8x8: lane2=0xff
a_uint8x8: lane3=0xff
a_uint8x8: lane4=0xff
a_uint8x8: lane5=0xff
a_uint8x8: lane6=0xff
a_uint8x8: lane7=0xff
存儲 uint8x8_t 的值
- 函數原型
void vst1_u8 (uint8_t *a, uint8x8_t b);
-
作用
- 將類型爲
uint8x8_t
向量(由參數b
確定)的值存儲到內存起始地址爲a
後面八字節的內存中。
- 將類型爲
-
注意事項
- 參數
a
所指向的合法內存必須不小於八字節,否則會產生非法寫。
- 參數
-
代碼示例
void store_uint8x8_t(uint8x8_t val_uint8x8)
{
{
// 目的數據的元素數量等於8,合法
uint8_t f_arr_uint8[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8};
std::printf("f_arr_uint8 ...\n");
vst1_u8(f_arr_uint8, val_uint8x8);
}
{
// 目的數據的元素數量等於8,但參數不是首元素的地址,最後一個元素爲非法寫
uint8_t a_arr_uint8[] = {0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8};
std::printf("a_arr_uint8 ...\n");
vst1_u8(&a_arr_uint8[1], val_uint8x8);
}
{
// 目的數據的元素數量大於8,只寫數組b_arr_uint8的前八個元素,合法
uint8_t b_arr_uint8[] = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf};
std::printf("b_arr_uint8 ...\n");
vst1_u8(b_arr_uint8, val_uint8x8);
}
{
// 目的數據的元素數量小於8,最後四個元素爲非法寫
uint8_t c_arr_uint8[] = {0xc1, 0xc2, 0xc3, 0xc4};
std::printf("c_arr_uint8 ...\n");
vst1_u8(c_arr_uint8, val_uint8x8);
}
{
// 目的數據是標量,最後七個元素爲非法寫
uint8_t d_arr_uint8 = 0xd1;
std::printf("d_arr_uint8 ...\n");
vst1_u8(&d_arr_uint8, val_uint8x8);
}
}
注:參數val_uint8x8
的值爲:{0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8},參數val_uint8x8
的值爲:{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}。
- 代碼調試
(gdb) p/x &f_arr_uint8[0]
$1 = 0x7ffffff2c8
(gdb) display/9ubx 0x7ffffff2c8
1: x/9xb 0x7ffffff2c8
0x7ffffff2c8: 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08
0x7ffffff2d0: 0xf1
(gdb) n
f_arr_uint8 ...
34 vst1_u8(f_arr_uint8, val_uint8x8);
1: x/9xb 0x7ffffff2c8
0x7ffffff2c8: 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08
0x7ffffff2d0: 0xf1
(gdb) n
39 uint8_t a_arr_uint8[] = {0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8};
1: x/9xb 0x7ffffff2c8
0x7ffffff2c8: 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 0xf8
0x7ffffff2d0: 0xf1
; 可以看出,“第九個元素”(0x7ffffff2d0處的內容)沒有被修改,驗證了目的數據的元素數量等於8,合法。
(gdb) n
40 std::printf("a_arr_uint8 ...\n");
1: x/9xb 0x7ffffff2c8
0x7ffffff2c8: 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa8
0x7ffffff2d0: 0xf1
(gdb)
a_arr_uint8 ...
41 vst1_u8(&a_arr_uint8[1], val_uint8x8);
1: x/9xb 0x7ffffff2c8
0x7ffffff2c8: 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa8
0x7ffffff2d0: 0xf1
(gdb)
47 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf};
1: x/9xb 0x7ffffff2c8
0x7ffffff2c8: 0xa1 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7
0x7ffffff2d0: 0xf8
; 可以看出,“第八個元素”(0x7ffffff2d0處的內容)的值由0xf1變成了0xf8,但這個元素不是有效的,發生了非法寫。
(gdb) n
48 std::printf("b_arr_uint8 ...\n");
1: x/9xb 0x7ffffff2c8
0x7ffffff2c8: 0xb0 0xb1 0xb2 0xb3 0xb4 0xb5 0xb6 0xb7
0x7ffffff2d0: 0xb8
(gdb)
b_arr_uint8 ...
49 vst1_u8(b_arr_uint8, val_uint8x8);
1: x/9xb 0x7ffffff2c8
0x7ffffff2c8: 0xb0 0xb1 0xb2 0xb3 0xb4 0xb5 0xb6 0xb7
0x7ffffff2d0: 0xb8
(gdb)
54 uint8_t c_arr_uint8[] = {0xc1, 0xc2, 0xc3, 0xc4};
1: x/9xb 0x7ffffff2c8
0x7ffffff2c8: 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 0xf8
0x7ffffff2d0: 0xb8
(gdb) x/16ubx 0x7ffffff2c8
0x7ffffff2c8: 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 0xf8
0x7ffffff2d0: 0xb8 0xb9 0xba 0xbb 0xbc 0xbd 0xbe 0xbf
; 可以看出,只有b_arr_uint8的前八個元素被修改了,合法
(gdb) n
55 std::printf("c_arr_uint8 ...\n");
1: x/9xb 0x7ffffff2c8
0x7ffffff2c8: 0xc1 0xc2 0xc3 0xc4 0xf5 0xf6 0xf7 0xf8
0x7ffffff2d0: 0xb8
(gdb)
c_arr_uint8 ...
56 vst1_u8(c_arr_uint8, val2_uint8x8);
1: x/9xb 0x7ffffff2c8
0x7ffffff2c8: 0xc1 0xc2 0xc3 0xc4 0xf5 0xf6 0xf7 0xf8
0x7ffffff2d0: 0xb8
(gdb)
61 uint8_t d_arr_uint8 = 0xd1;
1: x/9xb 0x7ffffff2c8
0x7ffffff2c8: 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08
0x7ffffff2d0: 0xb8
; 可以看出,c_arr_uint8[3]後面的四個元素被修改了,但這幾個元素不是有效的,發生了非法寫。
(gdb) undisplay
Delete all auto-display expressions? (y or n) y
(gdb) n
61 uint8_t d_arr_uint8 = 0xd1;
(gdb)
62 std::printf("d_arr_uint8 ...\n");
(gdb) p/x &d_arr_uint8
$1 = 0x7ffffff277
(gdb) display/8ubx 0x7ffffff277
1: x/8xb 0x7ffffff277
0x7ffffff277: 0xd1 0xc9 0xf2 0xff 0xff 0x7f 0x00 0x00
(gdb) n
d_arr_uint8 ...
63 vst1_u8(&d_arr_uint8, val_uint8x8);
1: x/8xb 0x7ffffff277
0x7ffffff277: 0xd1 0xc9 0xf2 0xff 0xff 0x7f 0x00 0x00
(gdb)
65 }
1: x/8xb 0x7ffffff277
0x7ffffff277: 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 0xf8
; 可以看出,&d_arr_uint8後面的七個元素被修改了,但這幾個元素不是有效的,發生了非法寫。
向量算術邏輯運算
向量加法運算
兩個 uint8x8_t 相加
- 函數原型
uint8x8_t vadd_u8(uint8x8_t a, uint8x8_t b);
-
作用
- 將兩個類型爲
uint8x8_t
向量的對應位置元素相加,任意對應位置元素相加的結果(可能會進位或溢出)不會影響其他位置相加的結果。
- 將兩個類型爲
-
代碼示例
uint8x8_t a_uint8x8, b_uint8x8;
a_uint8x8 = vdup_n_u8(0x12);
b_uint8x8 = vdup_n_u8(0x34);
uint8x8_t sum_uint8x8;
sum_uint8x8 = vadd_u8(a_uint8x8, b_uint8x8);
// 分別打印變量 sum_uint8x8 的八個元素的值(十六進制)
std::printf("sum_uint8x8: lane0=0x%x\n", vget_lane_u8(sum_uint8x8, 0));
std::printf("sum_uint8x8: lane1=0x%x\n", vget_lane_u8(sum_uint8x8, 1));
std::printf("sum_uint8x8: lane2=0x%x\n", vget_lane_u8(sum_uint8x8, 2));
std::printf("sum_uint8x8: lane3=0x%x\n", vget_lane_u8(sum_uint8x8, 3));
std::printf("sum_uint8x8: lane4=0x%x\n", vget_lane_u8(sum_uint8x8, 4));
std::printf("sum_uint8x8: lane5=0x%x\n", vget_lane_u8(sum_uint8x8, 5));
std::printf("sum_uint8x8: lane6=0x%x\n", vget_lane_u8(sum_uint8x8, 6));
std::printf("sum_uint8x8: lane7=0x%x\n", vget_lane_u8(sum_uint8x8, 7));
輸出結果爲:
sum_uint8x8: lane0=0x46
sum_uint8x8: lane1=0x46
sum_uint8x8: lane2=0x46
sum_uint8x8: lane3=0x46
sum_uint8x8: lane4=0x46
sum_uint8x8: lane5=0x46
sum_uint8x8: lane6=0x46
sum_uint8x8: lane7=0x46
如果你覺得本文對你有所幫助,歡迎關注公衆號,支持一下!