性能優化篇(3):NEON快速入門指南

​性能優化篇(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

返回上一級

如果你覺得本文對你有所幫助,歡迎關注公衆號,支持一下!

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章