日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

neon 指令 c语言,NEON初步使用

發布時間:2023/12/8 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 neon 指令 c语言,NEON初步使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

指令集并行是CPU的優化加速的一個方向,在ARM芯片主要是利用NEON指令集實現指令集并行

NEON簡介

NEON就是高級SIMD,單指令多數據,適用于圖像、音頻等數據處理。ARMv6就叫SIMD,ARMv7開始叫NEON,aarch64又有點不一樣,下文只針對ARMv7或者ARMv8 aarch32的NEON進行

NEON有32個64位長的寄存器(D0-D31,每個D可以裝2個浮點數據),也可以看做為16個128位長的寄存器(Q0-Q15,每個Q可以裝4個浮點數據),所以一句指令最多可以同時實現4個乘法操作,理論速度可以提升4倍

如何使用NEON

三種使用NEON的方法

庫函數

官方給了2個庫可以使用,OpenMax DL和Ne10,后者在github上有,也是我用來參考學習的主要對象

匯編函數

用匯編語句編寫.s文件

在C/C++代碼中嵌入匯編語句(inline assembly)

內聯函數(intrinsics function)

在C代碼中直接嵌入內聯函數用以實現功能,但是性能會取決于編譯器和具體設備

匯編函數基礎

想要高效利用NEON的話,匯編是避不開的。下面是ARM匯編相關的準備知識

參考資料

匯編基礎原理

b、bx、bl指令

arm匯編指令

GNU ARM Assembler Quick Reference

特殊寄存器

TODO: sb、ip是干嘛的

匯編函數文件directive(指令、偽操作)

常見directive(指令、偽操作)

參數

說明

.text

后面那些指令都屬于.text段

.syntax

unified

說明下面的指令是ARM和THUMB通用格式

TODO:不太懂

.align

4

4字節對齊

.balign

4

TODO:不太懂

.global

xx_func

函數xx_func可以被外部文件調用訪問

.thumb_func

指明一個函數是thumb指令集的函數

TODO:不太懂

編譯調用匯編函數

編譯匯編文件neon.s的命令需要加選項-mfpu=neon: arm-linux-gnueabihf-gcc -mfpu=neon -c neon.s -o neon.o

主文件main.o鏈接neon.o的命令: arm-linux-gnueabihf-gcc neon.o main.o -o test

相關編譯參數

堆棧讀取參數

TODO:匯編讀取多參數

參考鏈接

ARM匯編基礎指令

ldr

ldr R0, [R1]! @將內存地址為R1的數據加載到R0,并將R1指向下一個位置

ldr R0,[R1,#8] ;將存儲器地址為R1+8的字數據讀入寄存器R0。

str

str R0,[R1,#8] ;將R0中的字數據寫入以R1+8為地址的存儲器中。

b 無條件跳轉

b label_fun

bl 帶返回的跳轉,保存當前位置到lr,用于子函數調用

bl label_fun @bx lr或者mov pc, lr實現返回

bx 跳轉并切換狀態,一般用于子函數返回

bx lr

bgt 比較跳轉,如果經過之前某句操作后狀態寄存器是大于(great than)就跳轉

cmp r0, #5

bgt label_foo

and 按位與

and r3, r2, #3 @ r3 = r2 % 4

asr 右移

asr r2, r2, #2 @ r2 = r2 >> 2

cbz 比較跳轉,如果為零就跳到后面的指令

cbz r3, label_foo

sub 減命令

sub r0, r1, r2 @ r0 = r1 - r2

subs 減命令,并更新狀態寄存器

同sub一樣,多的更新狀態寄存器功能可以配合bgt

NEON矢量讀取命令vld1

vld1.32 {d0}, [r1]@從內存地址r1開始讀取2個32位數據到d0里,因為d能存2個32位浮點數

vld1.32 {q0}, [r1]@從內存地址r1開始讀取4個32位數據到q0里,因為q能存2個32位浮點數

NEON矢量存儲命令vst1

vst1.32 {d0}, [r1]@將d0里的2個32位浮點數寫到內存地址r1里

vst1.32 {q0}, [r1]@將q0里的4個32位浮點數寫到內存地址r1里

NEON矢量加命令vadd

圖文并茂,不用多說 vadd.i16 d3, d0, d1 @ d3 = d0 + d1

NEON簡單對比實驗

github鏈接記得點贊

C語言實現 void mul_float_c(float *dst, float *src1, float *src2, int count)

{

int i = 0, j = 0;

for (j = 0; j < count; j++)

for (i = 0; i < 4; i++)

*(dst++) = *(src1++) * *(src2++);

}

匯編實現assembly .text

.syntax unified

.align 4

.global mul_float_neon

.thumb

.thumb_func

mul_float_neon:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@ r0: *dst & current dst entry's address浮點型指針,存儲結果

@ r1: *src1 & current src1 entry's address浮點型指針,操作對象1

@ r2: *src2 & current src2 entry's address浮點型指針,操作對象2

@ r3: count,循環次數

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

.loop:

cbz r3, .return

subs r3, r3, #1

vld1.32 {q0}, [r1]!

vld1.32 {q1}, [r2]! @ for current set

@ calculate values for current set

vmul.f32 q3, q0, q1 @ q3 = q0 + q1

@ store the result for current set

vst1.32 {q3}, [r0]!

b .loop

.return:

mov r0, #0

bx lr

C語言內嵌匯編實現inline assembly void mul_float_neon_inline(float *dst, float *src1, float *src2, int count)

{

asm volatile(

".loop:\n"

"cbz %[count], .return\n"

"subs %[count], %[count], #1\n"

"vld1.32 {q0}, [%[src1]]!\n"

"vld1.32 {q1}, [%[src2]]! @ for current set\n"

"vmul.f32 q3, q0, q1 @ q3 = q0 + q1\n"

"vst1.32 {q3}, [%[dst]]!\n"

"b .loop\n"

".return:\n"

// "mov %[dst], #0\n"//不需要函數的返回跳轉

// "bx lr\n"

: // 解釋返回參數,如[ dst ] "+r"(dst),有個加號

: [ dst ] "r"(dst), [ src1 ] "r"(src1), [ src2 ] "r"(src2), [ count ] "r"(count)// 解釋輸入參數

: "memory", "q0", "q1", "q3");// 不太懂,但是要加

}

內聯函數實現

內聯函數官方在線文檔 #include//要用neon內聯函數必須要該頭文件

void add_float_neon(float* dst, float* src1, float* src2, int count)

{

int i;

for (i = 0; i < count; i += 4)

{

float32x4_t in1, in2, out;

in1 = vld1q_f32(src1);

src1 += 4;

in2 = vld1q_f32(src2);

src2 += 4;

out = vaddq_f32(in1, in2);

vst1q_f32(dst, out);

dst +=4;

}

}

結果對比和分析 pi@raspberrypi:~/mnt/neon_test $ ./neon_test

mul_float_c used: 0.000095 s

mul_float_neon used: 0.000012 s

mul_float_neon_inline used: 0.000011 s

mul_float_neon_intrinsics used: 0.000059 s

mul_float_c and mul_float_neon result same!!!

mul_float_c and mul_float_inline result same!!!

mul_float_c and mul_float_intrinsics result same!!!

分別用C語言的for循環、neon的匯編實現、neon的內聯匯編(inline assembly)、neon的內聯函數(intrinsics function)這4種方式在A53上實現4*100次浮點運算,可以看出,最快的還是neon匯編實現,約10倍的速度提升,同時兩種neon匯編的速度一樣沒啥區別,但是還是建議不用內聯匯編,因為gdb沒法debug,至于為什么會達到10倍的提升,一方面是neon的矢量乘法有4倍理論提升,還有就是讀數據和存數據都是4倍提速。而neon的內聯函數卻只有不到2倍的速度提升,真辣雞

TODO:上述實驗數據是在編譯優化參數為debug模式"-O0 -g"的情況下測出來的,但是release模式"-Ofast"會報錯

總結

來,弄優化,學匯編,用NEON!手動狗頭

總結

以上是生活随笔為你收集整理的neon 指令 c语言,NEON初步使用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。