NEON介绍
轉自:ARM NEON技術之NEON基礎介紹 - 知乎
一、背景簡介
ARM CPU 最初只有普通的寄存器,可以進行基本數據類型的基礎運算。從 ARMv5 架構開始引入 VFP(vector-floating-point) 指令擴展,可以通過使用短向量指令來加速浮點計算。從 ARMv7 架構開始引入 NEON 技術,NEON 技術同樣是依靠向量指令來加速計算。鑒于 NEON 技術提供的向量技術加速效果體驗更優秀,從 ARMv7 架構開始使用 VFP 向量指令加速的模式被棄用,因此 VFP 單元有時也稱之為 FPU(Floating Point Unit)單元。
NEON 技術意在通過加速音頻和視頻編解碼、用戶界面、2D/3D圖形和游戲來改善多媒體用戶體驗。NEON 還可以加速信號處理算法,以加快音頻和視頻處理、聲音和面部識別、計算機視覺和深度學習等應用。
二、基本架構
ARM NEON 技術本質上是一種高級的單指令多數據(SIMD)架構擴展,這種擴展僅在一些 ARMv7-A 和 ARMv7-R 架構以及 ARMv8 架構上支持。
熟悉 ARMv7-A 架構的應該知道 ARMv7 架構的內核是一個32位的系統,使用32位的寄存器。但是 NEON 單元使用的是64位或者128位的寄存器。這里的原因就是 NEON 單元使用獨立的寄存器文件。不過,NEON 單元還是完全集成到處理器中的,可以和處理器共享整型操作單元、循環控制和緩存資源,相比于使用硬件加速器,大大降低了面積和功耗成本。而且由于 NEON 單元和應用程序使用相同的地址空間,可以使用更簡單的編程模型。
ARM NEON 技術的核心是 NEON 單元,主要由四個模塊組成,分別是 NEON 寄存器文件、整型執行流水線、單精度浮點執行流水線和數據加載和重排流水線。
NEON 單元
三、NEON 寄存器
NEON 寄存器主要是用來存放包含相同數據類型元素的向量。在 ARMv7 架構中, 一共有16個128位寄存器,這個128位寄存器也稱之為 Q 寄存器,一個128位寄存器又可以分為兩個64位寄存器,即一共有32個64位寄存器,64位寄存器又稱之為 D 寄存器。在ARMv8 架構中寄存器的數量相比 ARMv7 架構數量翻倍。Q 寄存器和 D 寄存器對應表如下所示:
關系對應表
NEON 向量的元素數量取決于寄存器的類型和元素的數據類型。NEON 寄存器支持常見的數據類,包括整型和浮點類型等,具體如下所示:
NEON 寄存器元素類型
根據向量元素的數據類型以及寄存器的類型,向量的類型如下所示:
NEON 寄存器向量類型
從上表中可以看出,對于32位數據,比如 int 和 float 類型數據,一個 Q 寄存器包含四個元素,D 寄存器則包含兩個元素。對于16位數據,比如 float16 和 short 類型,一個 Q 寄存器則包含八個元素, D 寄存器則包含四個元素。對于8位數據, 比如 char 和 poly 類型數據,一個 Q 寄存器包含十六個元素,D 寄存器則包含八個元素。
四、NEON 調用
ARM 平臺提供了四種使用 NEON 技術的方式,分別為 NEON 內嵌函數、NEON 開源庫、編譯器自動向量化和 NEON 匯編。
調用方式
NEON 內嵌函數調用類似于普通函數調用,通過調用函數接口告知編譯器需要優化的代碼,編譯器在編譯階段直接使用 NEON指令替換這些內嵌函數而不是執行類似子函數調用的操作。NEON 內嵌函數提供了一種低級的 NEON 指令訪問方式,而編譯器負責將 NEON 指令替換成匯編語言的復雜任務,主要包括寄存器分配和代碼調度以及指令集重排,來達到獲取最高性能的目標。NEON 內嵌函數的缺點在于匯編語言和開發代碼不一致。
鑒于 NEON 指令的強大優化效果,市場上出現了很多支持 NEON 優化的開源庫,比如 Ne10、OpenMAX、ffmpeg、Eigen3和Math-neon等。
矢量化編譯器可以將 C 或 C++ 源代碼進行矢量化,以實現對 NEON 硬件的有效使用。這意味著可以編寫可移植的 C 代碼,同時還可以獲得 NEON 指令帶來的性能水平。
當使用的是 ARM 編譯器工具鏈的時候,可通過下圖幾種方式實現自動向量化:
自動向量化方式
當使用的是 GCC 編譯器工具鏈的時候,可通過下圖幾種方式實現自動向量化:
使用 GCC 時需要指定 CPU,否則會使用編譯環境默認的內核,導致代碼無優化或者異常。如果開啟 -O3 優化選項,則默認開啟 -ftree-vectorize 選項。
如果想獲取非常高的性能提升,手寫 NEON 匯編優化代碼是最有效的方法,GNU 匯編器 (gas) 和 ARM 編譯器工具鏈匯編器 (armasm) 都支持 NEON 指令的匯編。ARM 嵌入式應用程序二進制接口 (EABI) 規定了哪些寄存器用于傳遞參數、返回結果或必須保留。
五、NEON 指令集
鑒于 NEON 指令集是處理向量類型的數據,所以這里先給出 NEON 指令集支持的向量類型,具體如下表所示:
NEON 向量類型
從上表可以看成,NEON 指令集的向量是由基本上就是常見的數據類型組成,根據 D 寄存器和 Q 寄存器以及數據類型形成多種向量類型。這些向量類型將作為 NEON 指令集的輸入輸出參數參與計算。
NEON 指令集提供了多種多樣的功能,基本上可以滿足絕大部分代碼的使用需求,具體支持的功能如下圖所示:
NEON 指令表
從上表中可以看出來 NEON 指令集支持的功能有加減乘法、特殊相鄰元素加法、飽和乘法、乘累加、移位、邏輯運算、極值獲取、BIT統計等。除此之外,還支持比較大小、取倒數、向量分割拼接重排、查表等功能。
此外,按照 NEON 指令的輸出輸入向量類型,還可以將 NEON 指令分為以下幾種:
NEON 指令類型
常指令,結果向量和操作數向量的長度、元素類型一致。下圖展示了以下指令的過程:
VADD.I16 Q0, Q1, Q2長指令通常對雙字向量進行操作,并產生一個四字向量。結果元素的寬度是操作元素的兩倍。長指令是用指令后面的 L 來指定的。下圖顯示了一個長指令的例子,輸入操作數在操作前被提升為四字。
窄指令對四字向量操作數進行操作,并產生一個雙字向量。結果元素是操作數元素寬度的一半。窄指令是用指令后面的 N 來指定的。如下圖所示。
寬指令對一個雙字向量操作數和一個四字向量操作數進行操作,產生一個四字向量結果。結果元素和第一操作數的寬度是第二操作數元素的兩倍。寬指令有一個 W 附加在指令上。下圖顯示了這一點,輸入的雙字操作數在操作前被提升為四字。
六、優化示例
在圖像處理時,彩色圖轉灰度圖是很常見的一種圖像格式轉換。彩色圖轉灰度圖的公式如下所示:
根據上述公式,實現彩色圖轉灰度圖的 C 語言代碼和 NEON 優化代碼。代碼如下所示:
static void BGR2GRAY(const unsigned char *bgr, int width, int height, unsigned char *gray) {int coef_q8[3] = { 29, 150, 77 };unsigned char *temp_s = (unsigned char*)bgr;unsigned char *temp_d = gray; #ifdef USE_NEONuint8x8_t vwr = vdup_n_u8(coef_q8[0]);uint8x8_t vwg = vdup_n_u8(coef_q8[1]);uint8x8_t vwb = vdup_n_u8(coef_q8[2]); #endiffor (int row = 0; row < height; row++) {int col = 0; #ifdef USE_NEONfor ( ; col < width - 8; col += 8) {uint8x8x3_t vsrc = vld3_u8(temp_s);uint16x8_t vsum = vmull_u8(vsrc.val[0], vwr);vsum = vmlal_u8(vsum, vsrc.val[1], vwg);vsum = vmlal_u8(vsum, vsrc.val[2], vwb);vst1_u8(temp_d, vshrn_n_u16(vsum, 8));temp_d += 8;temp_s += 24;} #endiffor ( ; col < width; col++) {temp_d[0] = (temp_s[0] * coef_q8[0] + temp_s[1] * coef_q8[1] + temp_s[2] * coef_q8[2]) >> 8;temp_d += 1;temp_s += 3;}}return; }七、結語
NEON 技術所能探討的內容遠不止于此,這里僅僅介紹了 NEON 技術最基礎的知識,更多是概括性介紹,后續將對每個點進行深度分析探討。
八、附錄
以下是部分官方文檔地址鏈接
- NEON 簡介:https://www.arm.com/why-arm/technologies/neon
- NEON 指令:https://developer.arm.com/architectures/instruction-sets/intrinsics
- NEON 入門文檔:https://developer.arm.com/documentation/102159/latest
- NEON 開發文檔:https://developer.arm.com/documentation/den0018/latest
總結
- 上一篇: 使用AutoFac组织多项目应用程序
- 下一篇: 卷积神经网络发展(网络骨架:Backbo