0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Arm NEON編程技術(shù)上手指南

安芯教育科技 ? 來(lái)源:極術(shù)社區(qū) ? 作者:yang ? 2022-12-06 09:09 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

1 簡(jiǎn)介

本文旨在介紹Arm NEON技術(shù),希望NEON初學(xué)者在閱讀本文后能很快上手開(kāi)始NEON編程

2 NEON概覽

本節(jié)介紹NEON技術(shù)及一些背景知識(shí)。

2.1 什么是NEON?

NEON是指適用于Arm Cortex-A系列處理器的一種高級(jí)SIMD(單指令多數(shù)據(jù))擴(kuò)展指令集。NEON 技術(shù)可加速多媒體和信號(hào)處理算法(如視頻編碼/解碼、2D/3D 圖形、游戲、音頻和語(yǔ)音處理、圖像處理技術(shù)、電話和聲音合成)。

NEON 指令可執(zhí)行并行數(shù)據(jù)處理:

寄存器被視為同一數(shù)據(jù)類型的元素的矢量

數(shù)據(jù)類型可為:8 /16 /32/64 位整數(shù),單精度(Arm 32位平臺(tái)),單精度浮點(diǎn)/雙精度浮點(diǎn)(Arm 64位平臺(tái))

指令在所有通道中執(zhí)行同一操作

f70f27ee-7501-11ed-8abf-dac502259ad0.png ?
2.2 Arm 高級(jí)SIMD發(fā)展歷史

f721b2c4-7501-11ed-8abf-dac502259ad0.png ?

2.3 為什么要用NEON

NEON提供:

支持整數(shù)和浮點(diǎn)操作,以確保適合從編解碼器、高性能計(jì)算到 3D 圖形等廣泛應(yīng)用領(lǐng)域。

與 Arm處理器緊密結(jié)合,提供指令流和內(nèi)存的統(tǒng)一視圖,編程比外部硬件加速器更簡(jiǎn)單。

3 Arm v8架構(gòu)簡(jiǎn)介

Arm v8-A是一個(gè)非常重要的架構(gòu)變化,它支持64位執(zhí)行模式 “AArch64” ,并且?guī)?lái)了全新的64位指令集 “A64” 。同時(shí),為了兼容Arm v7-A (32位架構(gòu))指令集,也引入了 “AArch32” 的概念。大部分Arm v7-A代碼可以運(yùn)行在Arm v8-A AArch32執(zhí)行模式下。

本節(jié)會(huì)對(duì)Arm v8-A 架構(gòu)NEON相關(guān)的特點(diǎn)做出一些介紹。此外,本節(jié)也會(huì)略微介紹在NEON編程時(shí)經(jīng)常使用的CPU通用目的寄存器和CPU指令,但是重點(diǎn)依然是NEON技術(shù)。

3.1 寄存器

Arm v8-A AArch64有31個(gè)64位通用目的寄存器,每一個(gè)通用寄存器具有64位(X0-X30)或是32位模式(W0-W30)。其寄存器視圖如下:

f732e5bc-7501-11ed-8abf-dac502259ad0.png

Arm v8-A AArch64有32個(gè)128位寄存器,也能當(dāng)作32位Sn寄存器或是64位Dn寄存器使用。其寄存器視圖如下:

f75fbd76-7501-11ed-8abf-dac502259ad0.png ?

3.2 指令集

Arm v8-A AArch32指令集是由A32(Arm指令,32 位固定長(zhǎng)度指令集)和T32(Thumb指令集,16 位固定長(zhǎng)度指令集;Thumb2指令集, 16/32位長(zhǎng)度指令集)指令集組成。它是Arm v7 Cortex-A指令集的超集,因此Arm v8-A AArch32能后向兼容Arm v7-A以便運(yùn)行早期軟件。同時(shí),為了維持與A64指令集的一致性,AArch32指令集又新增了NEON除法,加密指令擴(kuò)展。

與AArch32指令集相比,AArch64指令集A64(32位固定長(zhǎng)度)發(fā)生了很大變化,比如,它們具有完全不同的指令格式。但是在功能上來(lái)說(shuō),AArch64指令集基本上實(shí)現(xiàn)了AArch32指令集的全部功能,另外添加了NEON雙精度浮點(diǎn)的支持。

3.3 NEON指令格式

現(xiàn)在大部分已經(jīng)是Arm v8平臺(tái),因此本節(jié)只介紹AArch64 NEON指令格式。通用描述如下:

{}{} Vd., Vn., Vm.

這里:

——前綴,如S/U/F/P 分別表示 有符號(hào)整數(shù)/無(wú)符號(hào)整數(shù)/浮點(diǎn)數(shù)/布爾數(shù)據(jù)類型
——操作符。例如ADD,AND等。
——后綴,通常是有以下幾種

P:將向量按對(duì)操作,例如ADDP

V:跨所有的數(shù)據(jù)通道操作,例如FMAXV

2:在寬指令/窄指令中操作數(shù)據(jù)的高位部分。例如ADDHN2,SADDL2。

ADDHN2:兩個(gè)128位矢量相加,得到64位矢量結(jié)果,并將結(jié)果存到NEON寄存器的高64位部分。

SADDL2:兩個(gè)NEON寄存器的高64位部分相加,得到128-位結(jié)果。

——數(shù)據(jù)類型,通常是8B/16B/4H/8H/2S/4S/2D等。B代表8位數(shù)據(jù)類型;H代表16位數(shù)據(jù)寬度;S代表32位數(shù)據(jù)寬度,可以是32位整數(shù)或單精度浮點(diǎn);D代表64位數(shù)據(jù)寬度,可以是64位整數(shù)或雙精度浮點(diǎn)。

下面列出具體的NEON指令例子:

UADDLP V0.8H, V0.16B

FADD V0.4S, V0.4S, V0.4S

更多內(nèi)容請(qǐng)參考 Armasm_user_guide.pdf(http://infocenter.arm.com/help/topic/com.Arm.doc.dui0801g/DUI0801G_Armasm_user_guide.pdf)

13~15章介紹A32和T32指令。

16~20章介紹A64指令,其中第20章專門介紹NEON指令。

4 NEON編程基礎(chǔ)

上面幾章已經(jīng)介紹了NEON的概念,硬件資源和指令集?,F(xiàn)在我們可以開(kāi)始使用NEON開(kāi)始加速我們的應(yīng)用了。使用NEON 技術(shù)通常有下列四種方式:

調(diào)用NEON優(yōu)化過(guò)的庫(kù)函數(shù)

使用編譯器自動(dòng)矢量化選項(xiàng)

使用NEON intrinsics指令

手寫(xiě)NEON匯編

4.1 調(diào)用庫(kù)函數(shù)

用戶只需要在程序中直接調(diào)用NEON優(yōu)化過(guò)的庫(kù)函數(shù)就可以了,簡(jiǎn)單易用。目前你有下列庫(kù)可以選擇:

Arm Compute library

一系列經(jīng)過(guò)Arm CPU和GPU優(yōu)化過(guò)的底層函數(shù)庫(kù)。用于圖像處理、機(jī)器學(xué)習(xí)計(jì)算機(jī)視覺(jué)。更多信息: https://developer.Arm.com/technologies/compute-library

Ne10開(kāi)源庫(kù)

由Arm主導(dǎo)開(kāi)發(fā)的,目前提供了比較通用的數(shù)學(xué)函數(shù),部分圖像處理函數(shù),以及FFT函數(shù)。http://projectne10.github.io/Ne10/

4.2 自動(dòng)矢量化

在GCC編譯器選項(xiàng)中有自動(dòng)矢量化編譯選項(xiàng)可以幫助現(xiàn)有的代碼編譯生成NEON代碼。GNU GCC提供一系列的選項(xiàng),有的能提升性能,有的能降低生成可執(zhí)行文件的代碼大小。

對(duì)于每一行代碼,有很多種匯編指令可以選擇。編譯器在寄存器、堆??臻g、代碼大小、編譯時(shí)間、便于調(diào)試、指令執(zhí)行時(shí)間等許多選項(xiàng)中必須有所取舍,這樣才能生成最優(yōu)的映像文件。

4.3 NEON intrinsics

NEON intrinsics可以視作在NEON指令上面封裝了一層接口。當(dāng)用戶在C程序中調(diào)用NEON intrinsics接口時(shí),編譯器會(huì)自動(dòng)生成相關(guān)的NEON指令。

NEON intrinsics可以跨Arm v7-A/v8-A運(yùn)行。只要編程一次,就可以借助編譯器生成相應(yīng)的NEON代碼。

如果用戶在代碼中使用了Arm v8-A AArch64特有的NEON指令,只要如下例所示,用宏定義(__aarch64__)將這部分代碼分隔即可。

下面是NEON intrinsics的一個(gè)例程。


//下面是浮點(diǎn)數(shù)組的加法,假設(shè)count為4的整數(shù)倍

#include

voidadd_float_c(float*dst,float*src1,float*src2,intcount)
{
inti;
for(i=0;i
通過(guò)查看反匯編,在Arm v7-A下,可以看到vld1/vadd/vst1 NEON指令。在Arm v8-A下可以看到ldr/fadd/str NEON指令。 

4.4 NEON匯編

NEON手寫(xiě)匯編主要有兩種方式:

獨(dú)立匯編文件

內(nèi)嵌匯編

4.4.1 獨(dú)立匯編文件

獨(dú)立匯編文件可以用“.S”作為文件后綴,也可以用“.s”作為文件后綴。區(qū)別在于.S文件會(huì)經(jīng)過(guò)C/C++預(yù)處理器處理,這樣我們可以利用宏定義等C語(yǔ)言特性。

手寫(xiě)NEON匯編文件時(shí),我們需要注意寄存器的保存。對(duì)于Arm v7/v8我們需要保存下列寄存器:

f76d6d36-7501-11ed-8abf-dac502259ad0.png ?

下面是Arm v7-A/v8-A NEON 匯編的一個(gè)例程。


//在頭文件中定義
voidadd_float_neon2(float*dst,float*src1,float*src2,intcount);

下面是手寫(xiě)匯編代碼,保存到.S文件中

//Armv7-A/Armv8-AAArch32版本
.text
.syntaxunified

.align4
.globaladd_float_neon2
.typeadd_float_neon2,%function
.thumb
.thumb_func

add_float_neon2:
.L_loop:
vld1.32{q0},[r1]!
vld1.32{q1},[r2]!
vadd.f32q0,q0,q1
subsr3,r3,#4
vst1.32{q0},[r0]!
bgt.L_loop

bxlr

//Armv8-AAArch64版本
.text

.align4
.globaladd_float_neon2
.typeadd_float_neon2,%function

add_float_neon2:

.L_loop:
ld1{v0.4s},[x1],#16
ld1{v1.4s},[x2],#16
faddv0.4s,v0.4s,v1.4s
subsx3,x3,#4
st1{v0.4s},[x0],#16
bgt.L_loop

ret
更多代碼請(qǐng)參考: https://github.com/projectNe10/Ne10/tree/master/modules/dsp

4.4.2 內(nèi)嵌匯編

顧名思義,內(nèi)嵌匯編是和C代碼緊密結(jié)合在一起的一種方式。我們可以直接把匯編代碼內(nèi)嵌在C/C++代碼中,我們可以在需要NEON的地方即時(shí)添加。
優(yōu)點(diǎn):

過(guò)程調(diào)用規(guī)則簡(jiǎn)單,不需要自己手動(dòng)保存寄存器。

可以使用 C/C++ 變量和函數(shù),因此它能非常容易地整合到 C/C++ 代碼

缺點(diǎn):

內(nèi)嵌匯編有一套復(fù)雜的語(yǔ)法規(guī)則

NEON代碼內(nèi)嵌在C/C++代碼中,不易于移植到其他平臺(tái)

例程:


//Armv7-A/Armv8-AAArch32
voidadd_float_neon3(float*dst,float*src1,float*src2,intcount)
{
asmvolatile(
"1:
"
"vld1.32{q0},[%[src1]]!
"
"vld1.32{q1},[%[src2]]!
"
"vadd.f32q0,q0,q1
"
"subs%[count],%[count],#4
"
"vst1.32{q0},[%[dst]]!
"
"bgt1b
"
:[dst]"+r"(dst)
:[src1]"r"(src1),[src2]"r"(src2),[count]"r"(count)
:"memory","q0","q1"
);
}

//Armv8-AAArch64
voidadd_float_neon3(float*dst,float*src1,float*src2,intcount)
{
asmvolatile(
"1:
"
"ld1{v0.4s},[%[src1]],#16
"
"ld1{v1.4s},[%[src2]],#16
"
"faddv0.4s,v0.4s,v1.4s
"
"subs%[count],%[count],#4
"
"st1{v0.4s},[%[dst]],#16
"
"bgt1b
"
:[dst]"+r"(dst)
:[src1]"r"(src1),[src2]"r"(src2),[count]"r"(count)
:"memory","v0","v1"
);

}
更多例程請(qǐng)參考libyuv

4.5 NEON intrinsics和NEON匯編

NEON intrinsics和NEON手寫(xiě)匯編是最常使用的NEON優(yōu)化方式。

下面就這兩種方式的優(yōu)缺點(diǎn)做一些簡(jiǎn)單對(duì)比。

NEON 匯編 NEON intrinsic
性能 對(duì)于指定平臺(tái),匯編總是呈現(xiàn)最好性能。 現(xiàn)在的編譯器已經(jīng)能得到媲美手工匯編的性能。
可移植性 Arm v7-A/v8-A平臺(tái) 具有不同的匯編格式。即使在Arm v8-A平臺(tái),匯編程序可能也需要針對(duì)Cortex A53/A57微架構(gòu)做出不同調(diào)整,才能呈現(xiàn)最好性能。 選擇合適的編譯器選項(xiàng),一次編程即可以很容易實(shí)現(xiàn)跨平臺(tái)并針對(duì)該平臺(tái)微架構(gòu)調(diào)整性能,例如Arm v7-A Cortex A9/A7/A15和Arm v8-A Cortex A53/A57。
可維護(hù)性 相比C語(yǔ)言,較難編程,可讀性較差 跟C語(yǔ)言類似,比較容易編程與維護(hù)

這只是簡(jiǎn)單的優(yōu)缺點(diǎn)對(duì)比,當(dāng)應(yīng)用NEON的情景比較復(fù)雜時(shí),會(huì)有更多的特殊情況出現(xiàn),在另一篇文章“Arm NEON 優(yōu)化”中,我會(huì)對(duì)這個(gè)問(wèn)題進(jìn)行進(jìn)一步分析。

有了以上基礎(chǔ),選擇一種NEON實(shí)現(xiàn)方式,現(xiàn)在可以開(kāi)始NEON編程之旅了!





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • ARM
    ARM
    +關(guān)注

    關(guān)注

    134

    文章

    9349

    瀏覽量

    377357
  • SIMD
    +關(guān)注

    關(guān)注

    0

    文章

    36

    瀏覽量

    10540
  • NEON技術(shù)
    +關(guān)注

    關(guān)注

    1

    文章

    9

    瀏覽量

    6212

原文標(biāo)題:技術(shù)分享|Arm NEON編程快速上手指南

文章出處:【微信號(hào):Ithingedu,微信公眾號(hào):安芯教育科技】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 0人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    ModelSim快速上手指南

    ModelSim快速上手指南
    發(fā)表于 08-16 17:14

    vga使用編程技術(shù)

    vga使用編程技術(shù)
    發(fā)表于 03-21 19:04

    資料推薦:nRF51822上手指南

    nRF51822上手指南
    發(fā)表于 06-12 13:48

    小白快速上手Arm NEON編程手冊(cè)指南

    1 簡(jiǎn)介本文旨在介紹Arm NEON技術(shù),希望NEON初學(xué)者在閱讀本文后能很快上手開(kāi)始NEON
    發(fā)表于 07-15 15:38

    如何使用Arm Compiler 6自動(dòng)矢量化功能為Neon編譯

    ,并重點(diǎn)介紹有助于編譯器的編碼最佳實(shí)踐產(chǎn)生最好的結(jié)果。 本指南對(duì)每個(gè)為Arm開(kāi)發(fā)的人都很有用,對(duì)那些人尤其有用他們想要使用Neon技術(shù),而不必在匯編中
    發(fā)表于 08-02 19:31

    Arm Neon技術(shù)指南

    指南介紹了Arm Neon技術(shù),即用于執(zhí)行Armv8-A或Armv8-R結(jié)構(gòu)剖面的高級(jí) SIMD(單一指示多數(shù)據(jù))架構(gòu)擴(kuò)展,Neon
    發(fā)表于 08-08 06:13

    ModelSim快速上手指南

    ModelSim快速上手指南 快速上手四部曲:建立Project、引進(jìn)HDL Files、Compile、模擬(Simulate/Loading and Run)
    發(fā)表于 05-08 17:29 ?0次下載

    Halcon9.0編程技術(shù)詳解

    Halcon9.0編程技術(shù)詳解Halcon9.0編程技術(shù)詳解
    發(fā)表于 12-22 15:20 ?0次下載

    適用于TI mmWave sensor的CCS在線調(diào)試腳本上手指南

    適用于TI mmWave sensor的CCS在線調(diào)試腳本上手指南
    發(fā)表于 10-28 11:59 ?0次下載
    適用于TI mmWave sensor的CCS在線調(diào)試腳本<b class='flag-5'>上手指南</b>

    NEON編程中的一些常見(jiàn)優(yōu)化技巧

      讀過(guò)上一篇文章“ARM NEON快速上手指南”之后,相信你已經(jīng)對(duì)ARM NEON編程有了基本
    的頭像 發(fā)表于 12-12 09:11 ?2412次閱讀

    RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南

    RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南
    發(fā)表于 02-22 18:23 ?10次下載
    RT-Thread文檔_RT-Thread 潘多拉 STM32L475 <b class='flag-5'>上手指南</b>

    RT-Thread文檔_正點(diǎn)原子 nano STM32F103 上手指南

    RT-Thread文檔_正點(diǎn)原子 nano STM32F103 上手指南
    發(fā)表于 02-22 18:24 ?5次下載
    RT-Thread文檔_正點(diǎn)原子 nano STM32F103 <b class='flag-5'>上手指南</b>

    RT-Thread文檔_正點(diǎn)原子阿波羅 STM32F429 上手指南

    RT-Thread文檔_正點(diǎn)原子阿波羅 STM32F429 上手指南
    發(fā)表于 02-22 18:25 ?5次下載
    RT-Thread文檔_正點(diǎn)原子阿波羅 STM32F429 <b class='flag-5'>上手指南</b>

    RT-Thread文檔_Nordic BSP 上手指南

    RT-Thread文檔_Nordic BSP 上手指南
    發(fā)表于 02-22 18:26 ?7次下載
    RT-Thread文檔_Nordic BSP <b class='flag-5'>上手指南</b>

    Venue快速上手指南

    電子發(fā)燒友網(wǎng)站提供《Venue快速上手指南.pdf》資料免費(fèi)下載
    發(fā)表于 03-26 14:34 ?0次下載