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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ARM和NEON指令 very nice

發(fā)布時(shí)間:2023/12/13 编程问答 69 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ARM和NEON指令 very nice 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在移動(dòng)平臺(tái)上進(jìn)行一些復(fù)雜算法的開發(fā),一般需要用到指令集來進(jìn)行加速。目前在移動(dòng)上使用最多的是ARM芯片。

ARM是微處理器行業(yè)的一家知名企業(yè),其芯片結(jié)構(gòu)有:armv5、armv6、armv7和armv8系列。芯片類型有:arm7、arm9、arm11、cortex系列。指令集有:armv5、armv6和neon指令。關(guān)于ARM到知識(shí)參考:http://baike.baidu.com/view/11200.htm

最初的ARM指令集為通用計(jì)算型指令集,指令集都是針對單個(gè)數(shù)據(jù)進(jìn)行計(jì)算,沒有并行計(jì)算到功能。隨著版本的更新,后面逐漸加入了一些復(fù)雜到指令以及并行計(jì)算到指令。而NEON指令是專門針對大規(guī)模到并行運(yùn)算而設(shè)計(jì)的。

NEON 技術(shù)可加速多媒體和信號(hào)處理算法(如視頻編碼/解碼、2D/3D 圖形、游戲、音頻和語音處理、圖像處理技術(shù)、電話和聲音合成),其性能至少為ARMv5 性能的3倍,為?ARMv6 SIMD性能的2倍。

關(guān)于SIMD和SISD:Single Instruction Multiple Data,單指令多數(shù)據(jù)流。反之SISD是單指令單數(shù)據(jù)。以加法指令為例,單指令單數(shù)據(jù)(SISD)的CPU對加法指令譯碼后,執(zhí)行部件先訪問內(nèi)存,取得第一個(gè)操作數(shù);之后再一次訪問內(nèi)存,取得第二個(gè)操作數(shù);隨后才能進(jìn)行求和運(yùn)算。而在SIMD型的CPU中,指令譯碼后幾個(gè)執(zhí)行部件同時(shí)訪問內(nèi)存,一次性獲得所有操作數(shù)進(jìn)行運(yùn)算。這個(gè)特點(diǎn)使SIMD特別適合于多媒體應(yīng)用等數(shù)據(jù)密集型運(yùn)算。如下圖所示:

???

如何才能快速到寫出高效的指令代碼?這就需要對各個(gè)指令比較熟悉,知道各個(gè)指令的使用規(guī)范和使用場合。

ARM指令有16個(gè)32位通用寄存器,為r0-r15,其中r13為堆棧指針寄存器,r15為指令計(jì)算寄存器。實(shí)際可以使用的寄存器只有14個(gè)。r0-r3一般作為函數(shù)參數(shù)使用,函數(shù)返回值放在r0中。若函數(shù)參數(shù)超過4個(gè),超過到參數(shù)壓入堆棧。

有效立即數(shù)的概念:每個(gè)立即數(shù)采用一個(gè)8位的常數(shù)(bit[7:0])循環(huán)右移偶數(shù)位而間接得到,其中循環(huán)右移的位數(shù)由一個(gè)4位二進(jìn)制(bit[11:8] )的兩倍表示。如果立即數(shù)記作<immediate> , 8位常數(shù)記作immed_8 , 4位的循環(huán)右移值記作rotate_imm ,有效的立即數(shù)是由一個(gè)8位的立即數(shù)循環(huán)右移偶數(shù)位得到,可以表示成:

<immediate>=immed_8循環(huán)右移( 2×rotate_imm)

如:mov r4 , #0x8000 000A??? #0x8000 000A 由0xA8循環(huán)右移0x2位得到。

下面介紹一些比較常用到一些指令。


內(nèi)存訪問指令:

LDR和STR,有三種方式,比較容易搞混

LDR r0, [r1, #4] ??r0 := mem[r1+4]?? ,#4是直接偏移量,這時(shí)候只能在正負(fù)4Kb到范圍內(nèi)。也可以是寄存器偏移,用+/-表示。記住r1不進(jìn)行偏移。

LDR r0, [r1, #4]! ?r0 :=mem[r1+4],r1 := r1 + 4,取值是取偏移量到值,并且r1進(jìn)行偏移。

LDR r0, [r1], #4 ??r0 :=mem[r1] ,r1 := r1 +4,取值是取r1地方到值,取值后進(jìn)行偏移。運(yùn)算后自動(dòng)加4,后變址。

另外:LDRB是無符號(hào)字節(jié),SB是有符號(hào)字節(jié),H無符號(hào)半字,SH有符號(hào)半字。

?

存儲(chǔ)器和寄存器數(shù)據(jù)交換:SWP,SWPB

如SWP r0, r1, [r2]?? r0 := mem[r2],mem[r2] := r1

多寄存器數(shù)據(jù)傳輸:

LDMIA r1, {r0,r2,r5}? r0 = mem[r1], r2 = mem[r1+4], r5=mem[r1+8]

?

通用數(shù)據(jù)處理指令

第二操作數(shù),常用到有LSR,LSL等,如mov r1, r2, lsl #2 將r2左移2位然后賦值到r1中。

常用到操作有ADD、SUB、AND、ORR、EOR、BIC、ORN,如果加上了S則會(huì)更新條件標(biāo)記。

MOV移動(dòng),MVN取反移動(dòng)。MOV可以是R寄存器,立即數(shù)以及接第二操作數(shù)。

REV:在字或半字內(nèi)反轉(zhuǎn)字節(jié)或位到順序

MUL、MLA和MLS,乘法、乘加和乘減。MLA R1,R2,R3,R4表示R1=R2*R3+R4,還有有符號(hào)和無符號(hào)乘法等。

?

跳轉(zhuǎn)指令

B:無條件跳轉(zhuǎn),BL:帶鏈接到跳轉(zhuǎn),BX跳轉(zhuǎn)并交換指令集等。

?

重點(diǎn)介紹一下NEON指令,目前使用較多。而且使用難度也較大,很多文檔上都沒有比較詳細(xì)到介紹,也沒有給出相應(yīng)到例子或者圖示。

?

一、NEON基本知識(shí)

NEON的寄存器:

有16個(gè)128位四字到寄存器Q0-Q15,32個(gè)64位雙子寄存器D0-D31,兩個(gè)寄存器是重疊的,在使用到時(shí)候需要特別注意,不小心就會(huì)覆蓋掉。如下圖所示:

兩個(gè)寄存器的關(guān)系:Qn =D2n和D2n+1,如Q8是d16和d17的組合。

?

NEON的數(shù)據(jù)類型:

注意數(shù)據(jù)類型針對到時(shí)操作數(shù),而不是目標(biāo)數(shù),這點(diǎn)在寫的時(shí)候要特別注意,很容易搞錯(cuò),尤其是對那些長指令寬指令的時(shí)候,因?yàn)榻?jīng)常Q和D一起操作。

?

NEON中的正常指令、寬指令、窄指令、飽和指令、長指令

正常指令:生成大小相同且類型通常與操作數(shù)向量相同到結(jié)果向量

長指令:對雙字向量操作數(shù)執(zhí)行運(yùn)算,生產(chǎn)四字向量到結(jié)果。所生成的元素一般是操作數(shù)元素寬度到兩倍,并屬于同一類型。L標(biāo)記,如VMOVL。

寬指令:一個(gè)雙字向量操作數(shù)和一個(gè)四字向量操作數(shù)執(zhí)行運(yùn)算,生成四字向量結(jié)果。W標(biāo)記,如VADDW。

窄指令:四字向量操作數(shù)執(zhí)行運(yùn)算,并生成雙字向量結(jié)果,所生成的元素一般是操作數(shù)元素寬度的一半。N標(biāo)記,如VMOVN。

飽和指令:當(dāng)超過數(shù)據(jù)類型指定到范圍則自動(dòng)限制在該范圍內(nèi)。Q標(biāo)記,如VQSHRUN

?

二、NEON指令

NEON指令較多,下面主要介紹一些常見的指令用法。

?

復(fù)制指令:

VMOV:

兩個(gè)arm寄存器和d之間

vmov d0, r0, r1:將r1的內(nèi)容送到d0到低半部分,r0的內(nèi)容送到d0到高半部分

vmov r0, r1, d0:將d0的低半部分送到r0,d0的高半部分內(nèi)容送到r1

一個(gè)arm寄存器和d之間

vmov.U32 d0[0], r0:將r0的內(nèi)容送到d0[0]中,d0[0]指d0到低32位

vmov.U32 r0, d0[0]:將d0[0]的內(nèi)容送到r0中

立即數(shù):

vmov.U16 d0, #1:將立即數(shù)1賦值給d0的每個(gè)16位

vmov.U32 q0, #1:將立即數(shù)1賦值給q0的每個(gè)32位

長指令:VMOVL:d賦值給q

vmovl.U16 q0, d0:將d0的每個(gè)16位數(shù)據(jù)賦值到q0的每個(gè)32位數(shù)據(jù)中

窄指令:VMOVN:q賦值給d

vmovn.I32 d0, q0:將q0的每32位數(shù)據(jù)賦值到q0的每16位數(shù)據(jù)中

飽和指令:VQMOVN等,飽和到指定的數(shù)據(jù)類型

?vqmovun.S32 d0, q0:將q0到每個(gè)32位移動(dòng)到d0中到每個(gè)16位中,范圍是0-65535

????????

VDUP:

VDUP.8 d0, r0:將r0復(fù)制到d0中,8位

VDUP.16 q0, r0:將r0復(fù)制到q0中,16位

VDUP.32 q0, d2[0]:將d2的一半復(fù)制到q0中

VDUP.32 d0, d2[1]:將d2的一半復(fù)制到d0中

注意是vdup可以將r寄存器中的內(nèi)容復(fù)制到整個(gè)neon寄存器中,不能將立即數(shù)進(jìn)行vdup,立即數(shù)只能用vmov

?

邏輯運(yùn)算

VADD:按位與;VBIC:位清除;VEOR:按位異或;VORN:按位或非;VORR:按位或

?

移位指令:

VSHL:左移、VSHLL:左移擴(kuò)展、VQSHL:左移飽和、VQSHLU:無符號(hào)左移飽和擴(kuò)展

VSHR:右移、VSHRN:右移窄、VRSHR:右移舍入、VQSHRUN:無符號(hào)右移飽和舍入

?

通用算術(shù)指令:

VABA:絕對值累加、VABD:絕對值相加、VABS:絕對值、VNEG:求反、VADD、VADDW、VADDL、VSUB、VSUBL、VSUBW:加減

VPADD:將兩個(gè)向量的相鄰元素相加

如VPADD.I16 {d2}, d0, d1


VPADDL:VPADDL.S16 d0, d1


VMAX:最大值,VMIN:最小值

VMUL、VMULL、VMLA(乘加)、VMLS(乘減)、

?

加載存儲(chǔ)指令:

VLD和VST



交叉存取的示意圖:

VREV反轉(zhuǎn)元素指令:

?

VEXT移位指令:

?

VTRN轉(zhuǎn)置指令:可以用于矩陣的轉(zhuǎn)置



VZIP指令:壓縮,類似交叉存取

VUZP指令:解壓操作,類似交叉存取


?

VTBL查表指令:從d0,d1中查找d3中的索引值,如果找到則取出,沒有找到則為0,存入d2中

?

三、需要注意的地方

??? load數(shù)據(jù)的時(shí)候,第一次load會(huì)把數(shù)據(jù)放在cache里面,只要不超過cache的大小,下一次load同樣數(shù)據(jù)的時(shí)候,則會(huì)比第一次load要快很多,會(huì)直接從cache中l(wèi)oad數(shù)據(jù),這樣在匯編程序設(shè)計(jì)的時(shí)候是非常需要考慮的問題。

???? 如:求取一個(gè)圖像的均值,8*8的窗口,先行求和,然后列求和出來均值,這時(shí)候會(huì)有兩個(gè)函數(shù),數(shù)據(jù)會(huì)加載兩遍,如果按照這樣去優(yōu)化的話則優(yōu)化不了多少。如果換成上面這種思路,先做行16行,然后再做列,這樣數(shù)據(jù)都在cache里面,做列的時(shí)候load數(shù)據(jù)會(huì)很快。

?? 在做neon乘法指令的時(shí)候會(huì)有大約2個(gè)clock的阻塞時(shí)間,如果你要立即使用乘法的結(jié)果,則就會(huì)阻塞在這里,在寫neon指令的時(shí)候需要特別注意。乘法的結(jié)果不能立即使用,可以將一些其他的操作插入到乘法后面而不會(huì)有時(shí)間的消耗。

如:vmul.u16 q1, d3, d4?

? ? ? ? ?vadd.u32 q1, q2, q3

此時(shí)直接使用乘法的結(jié)果q1則會(huì)阻塞,執(zhí)行vadd需要再等待2個(gè)clock的時(shí)間

使用飽和指令的時(shí)候,如乘法飽和的時(shí)候,在做乘法后會(huì)再去做一次飽和,所以時(shí)間要比直接做乘法要慢。

如:? vmul.u16 q1, d3, d4

? ? ? ? ? vqmul.u32 q1, q2, q3

后一個(gè)的時(shí)間要比第一個(gè)的時(shí)間要久。

在對16位數(shù)據(jù)進(jìn)行l(wèi)oad或者store操作的時(shí)候,需要注意的是字節(jié)移位。比如是16位數(shù)據(jù),則load 8個(gè)16位數(shù)據(jù),如果指定寄存器進(jìn)行偏移,此時(shí)需要特別注意。

例如:vld1.64 {d0}, [r0], r1

?

參考資料:

http://blogs.arm.com/software-enablement/277-coding-for-neon-part-4-shifting-left-and-right/

http://blogs.arm.com/software-enablement/161-coding-for-neon-part-1-load-and-stores/

http://blogs.arm.com/software-enablement/684-coding-for-neon-part-5-rearranging-vectors/


轉(zhuǎn)自:http://blog.csdn.net/chshplp_liaoping/article/details/12752749

總結(jié)

以上是生活随笔為你收集整理的ARM和NEON指令 very nice的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。