NEON 指令集【基礎備忘】
轉自?http://blog.sina.com.cn/s/blog_602f87700102wj5w.html
其他優(yōu)秀鏈接:https://blog.csdn.net/hemmingway/article/details/44832013
之前在一些ARM CPU下,曾在編譯時指定過Neon。
0. Neon簡介:
0.1: 簡介:
ARM Advanced SIMD延伸集,(ARM Cortex-A系列處理器的128位SIMD架構擴展)稱為NEON技術,它是一個結合64bit和128bit的SIMD(Single Instruction Multiple Data單指令多數(shù)據(jù))指令集。其針對多媒體和訊號處理程式具備標準化加速的能力,NEON具有一組廣泛的指令集、各自的寄存器陣列,以及獨立執(zhí)行的硬件。ARM NEON技術可加速多媒體和信號處理算法(如視頻編碼/解碼、2D/3D圖形、游戲、音頻和語音處理、圖像處理技術、電話和聲音合成)。
NEON的寄存器:有16個128位四字寄存器Q0-Q15,32個64位雙字寄存器D0-D31,兩個寄存器是重疊的,在使用的時候需要特別注意,不小心就會被覆蓋掉。
0.2: SIMD:
通常我們進行多媒體處理的時候,很多的數(shù)據(jù)都是16位或者8位的,如果這些程序運行在32位的機器上,那么計算機有一部分的計算單元是沒有工作的.所以這是一種浪費.為了更好的使用那些被浪費的資源.SIMD就應運而生了.SIMD這種技術就是使用一條指令,但對多個相同類型和尺寸的數(shù)據(jù)進行并行處理.就像我們現(xiàn)實生活中的好幾個人都在做同一件事情那樣,這樣就可以將速度提升很多倍
0.3:使用Neon的方式:
按Sam的理解,使用Neon的方式有以下幾種:
A:使用C的neon內聯(lián)函數(shù)。
B:直接使用Neon匯編指令。
C:使用某些第三方庫如OpenMAX.
各自的優(yōu)缺點:
A:使用Neon?intrinsics函數(shù),可以在直接接觸ASM的情況下,使用Neon。這些函數(shù)被定義在:
arm_neon.h 中。
類似于:
vadd_s8 (int8x8_t __a, int8x8_t __b)
此方法需要注意2點:
1.必須: #include
2.編譯時必須加入; -mfloat-abi=softfp -mfpu=neon
B:使用匯編指令:
效率最高.?使用intrinsics沒法控制寄存器分配和內存對齊等。
1.SIMD寄存器基本知識:
SIMD寄存器共有16個128位的向量寄存器構成。而32個雙精度浮點寄存器共享了這16個寄存器;32個單精度浮點寄存器共享了前8個寄存器。因此,這寄存器組是與浮點寄存器共享的.
單精度寄存器用s0~s31表示;(32bit)
雙精度寄存器用d0~d31來表示;(64bit)
而128位的SIMD寄存器則用q0~q15來表示.(128bit)
2. Neon的數(shù)據(jù)從內存向寄存器加載(vld)和從寄存器向內存存儲(vst):
如何靈活有效的加載和存儲數(shù)據(jù),對SIMD來說非常重要。先舉一下例子:
24-bit的RGB圖像,像素在內存里的組織方式是R, G, B, R, G, B...,如果你想做一個簡單的圖像處理,比如把R和B通道互換,你該如何高效的使用NEON協(xié)處理器呢?
首先想到的辦法是:從存儲空間線性加載RGB數(shù)據(jù)到D寄存器(64位雙精度寄存器),然后交換R和B數(shù)據(jù)。 但是這種線性加載的數(shù)據(jù)進行R和B通道的數(shù)據(jù)交換非常麻煩,需要首先掩碼mask,然后移位并合并掩碼數(shù)據(jù)。這種復雜的運算顯然并不高效。如圖所示:
從r0內存處,開始讀取數(shù)據(jù)到寄存器。
D0,D1,D2這三個64bit寄存器中各放置了雜亂的8個色數(shù)據(jù)。這樣非常不利于快速計算。
NEON提供了各種結構的加載和存儲指令來處理這種情況,這些指令能把數(shù)據(jù)從存儲區(qū)加載的同時還能把這些值分開存儲到不同的寄存器中。
從r0內存處開始讀取數(shù)據(jù)。
然后使用VLD3分開加載的數(shù)據(jù)就能方便的使用指令(VSWP d0, d2)來進行R和B通道的交換了。
然后把結果再寫入內存,當然也要使用interleave交織模式的存儲,即VST3存儲指令。
3.?結構化加載和存儲語法和具體指令:
NEON結構化加載會讀取內存內容到64-bit的NEON寄存器,使用可選的deinterleave選項,同樣加載指令也可以采用這種reinterleave的方式把寄存器的內容寫到內存空間。
NEON存儲和加載的結構化方式,語法包括如下5個部分:
加載VLD或者存儲VST指令助記符:instruction mnemonic
一個表示interleave模式的數(shù)字,表示每個結構體元素間的間隔:interleave pattern
表示每次訪問單元的位寬比特數(shù),即結構體內元素類型:element type
讀寫的64-bit的NEON寄存器集合,最多可以列出4個寄存器,取決于interleave模式:NEON registers
表示內存訪問地址的ARM寄存器,該地址可以在每次訪問時更新: ARM?address register
交織模式:Interleave Pattern:
加載和存儲指令可以用從1到4個相同大小的元素的交織結構體,這些元素可以是NEON指令通常支持的8,16或者32比特。
VLD1是最簡單的形式,從內存加載1~4個寄存器的數(shù)據(jù),沒有deinterleave,即線性加載;
VLD2加載2或者4個寄存器的數(shù)據(jù),解交織奇偶元素到各自的寄存器,這樣很容易的把交織的立體聲音頻數(shù)據(jù)分解為左右聲道的數(shù)據(jù);
VLD3加載3個寄存器的數(shù)據(jù),很方便的把RGB的數(shù)據(jù)分為R、G、B通道;
VLD4加載4個寄存器的數(shù)據(jù),解交織,用于分解ARGB圖像數(shù)據(jù);
存儲和加載類似,只是把寄存器的數(shù)據(jù)interleave然后寫到內存。
元素類型?Element Types
加載和存儲interleave的數(shù)據(jù)的基本元素可以為8,16或者32比特的數(shù)據(jù)。比如NEON指令VLD2.16 {d0, d1}將加載4個16-bit元素到第一個寄存器,然后4個16-bit元素到第二個寄存器,把臨近的奇偶對分開保存到每個寄存器。
把元素大小變成32-bits還是加載相同大小的數(shù)據(jù),但是只有2個元素來構成一個向量,同樣分成奇偶元素部分。
4. 關于優(yōu)化的幾個例子:
// C version
void add_int_c(int* dst, int* src1, int* src2, int count)
{
int i;
for (i = 0; i < count; i++)
{
dst[i] = src1[i] + src2[i];
}
}
// NEON version
void add_float_neon1(int* dst, int* src1, int* src2, int count)
{
int i;
for (i = 0; i < count; i += 4)
{
int32x4_t in1, in2, out;
in1 = vld1q_s32(src1);
src1 += 4;
in2 = vld1q_s32(src2);
src2 += 4;
out = vaddq_s32(in1, in2);
vst1q_s32(dst, out);
dst += 4;
}
}
其中 vld1q_s32(src1):
被解析為:?vld1.32 {d0, d1}, [r0]
vld: load數(shù)據(jù)到寄存器。 1:表示依次讀取。32:每份數(shù)據(jù)32bit. ?d0, d1,兩個64bit寄存器。所以,表示要讀4份數(shù)據(jù)。 ?r0:從r0內存處開始讀。
單片機 匯編語言
版權聲明:本文內容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內刪除侵權內容。