ARM平臺NEON指令的編譯和優化

2020-12-18 電子產品世界
本文介紹了ARM平臺基於ARM v7-A架構的ARM Cortex-A系列處理器(Cortex-A5, Cortex-A7, Cortex-A8, Cortex-A9, Cortex-A15)上的NEON多媒體處理硬體加速器針對C/C++語言、彙編語言和NEON intrinsics如何編譯和優化,包含如何向量化、向量化的ARMCC和GCC編譯器選項、NEON的彙編和EABI程序調用規範、如何在bare-metal和Linux作業系統上檢測NEON硬體、如何指導編譯器進行向量化NEON指令的優化等內容。

NEON向量化

基於ARM v7-A架構的ARM Cortex-A系列處理器(Cortex-A5, Cortex-A7, Cortex-A8, Cortex-A9, Cortex-A15)都可以選用NEON多媒體處理器加速程序運行,NEON是一種SIMD(Single Instruction Multiple Data)架構的協處理器,ARM的NEON處理器還可選配置成向量浮點VFPv3(Vector Floating-Point)指令集處理器。

本文引用地址:http://www.eepw.com.cn/article/201611/317417.htm

常用的編譯器選項配置

自動向量化選項

armcc編譯器使用--vectorize選項來使能向量化編譯,一般選擇更高的優化等級如-O2或者-O3就能使能--vectorize選項。

gcc編譯器的向量化選項-ftree-vectorize來使能向量化選項,使用-O3會自動使能-ftree-vectorize選項。

選擇處理器類型

armcc編譯器使--cpu 7-A或者--cpu Cortex-A8來指定指令集架構和CPU類型。

gcc編譯器的處理器選項-mfpu=neon和-mcpu來指定cpu類型。如-mcpu=cortex-a5

選擇NEON和VFP類型

gcc選擇用-mfpu=vfpv3-fp16來指定為vfp協處理,而-mfpu=neon-vfpv4等就能指定為NEON+VFP結構。

選擇浮點處理器和ABI接口類型

-mfloat-abi=soft使用軟體浮點庫,不是用VFP或者NEON指令;-mfloat-abi=softfp使用軟體浮點的調用規則,而可以使用VFP和NEON指令,編譯的目標代碼和軟體浮點庫連結使用;

-mfloat-abi=hard使用VFP和NEON指令,並且改變ABI調用規則來產生更有效率的代碼,如用vfp寄存器來進行浮點數據的參數傳遞,從而減少NEON寄存器和ARM寄存器的拷貝。

常用的CPU類型編譯器選項

CPU類型

CPU類型選項

FP選項

FP + SIMD選項

備註

Cortex-A5

-mcpu=cortex-a5

-mfpu=vfpv3-fp16

-mfpu=vfpv3-d16-fp16

-mfpu=neon-fp16

-d16表明只有前16個浮點寄存器可用

Cortex-A7

-mcpu=cortex-a7

-mfpu=vfpv4

-mfpu=vfpv4-d16

-mfpu=neon-vfpv4

-fp16表明支持16bit半精度浮點操作

Cortex-A8

-mcpu=cortex-a8

-mfpu=vfpv3

-mfpu=neon

Cortex-A9

-mcpu=cortex-a9

-mfpu=vfpv3-fp16

-mfpu=vfpv3-d16-fp16

-mfpu=neon-fp16

Cortex-A15

-mcpu=cortex-a15

-mfpu=vfpv4

-mfpu=neon-vfpv4

常用的gcc組合編譯器選項

Cortex-A15 with a NEON unit

arm-gcc -O3 -mcpu=cortex-a15 -mfpu=neon-vfpv4 -mfloat-abi=hard -ffast-math -omyprog.exe myprog.c

Cortex-A9 with a NEON unit

arm-gcc -O3 -mcpu=cortex-a9 -mfpu=neon-vfpv3-fp16 -mfloat-abi=hard -ffast-math -omyprog.exe myprog.c

Cortex-A7 without a NEON unit

arm-gcc -O3 -mcpu=cortex-a7 -mfpu=vfpv4-d16 -mfloat-abi=softfp -ffast-math -omyprog2.exe myprog2.c

Cortex-A8 without a NEON unit

arm-gcc -O3 -mcpu=cortex-a8 -mfloat-abi=soft -c -o myfile.o myfile.c

NEON彙編和EABI程序調用規範

GNU assembler (gas) and ARM Compiler toolchain assembler (armasm)都支持NEON指令的彙編。但必須遵循ARM Embedded Application Binary Interface (EABI)EABI的規範,即NEON寄存器的S0-S15 (D0-D7, Q0-Q3)用於傳遞參數和返回值,被調用函數內可以直接使用,不用保存;D16-D31 (Q8-Q15)則有調用函數來保存,被調用函數內可以不保存的隨意使用;而S16-S31 (D8-D15, Q4-Q7)則必須由被調用函數內部保存。對於調用傳參規範則有,對於軟體浮點,參數有R0~R3和堆棧stack傳遞,而硬體浮點,可以通過NEON寄存器來傳遞參數。

NEON硬體檢測和使能

編譯時指定NEON單元是否存在

ARM編譯器(armcc)從4.0之後就支持在某些處理器和FPU的選項中預定義宏__ARM_NEON__, armasm的宏TARGET_FEATURE_NEON.

運行時指定檢測NEON單元

OS內可以檢測NEON單元是否存在,如Linux下cat /proc/cpuinfo看是否包含NEON或者VFP,如Tegra2 (雙核 Cortex-A9 帶 FPU), cat /proc/cpuinfo:

Features : swp half thumb fastmult vfp edsp thumbee vfpv3 vfpv3d16

四核 Cortex-A9 帶NEON單元

Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3

另外可以查看/proc/self/auxv,這裡會包含二進位格式的hwcap,可以通過AT_HWCAP來搜索到。HWCAP_NEON bit (4096).另外如Ubuntu的發布在路徑/lib/neon/vfp下包含lib的NEON優化版本。

Bare-metal模式下使能NEON

#include

// Bare-minimum start-up code to run NEON code

__asm void EnableNEON(void)

{

MRC p15,0,r0,c1,c0,2 // Read CP Access register

ORR r0,r0,#0x00f00000 // Enable full access to NEON/VFP by enabling access to

// Coprocessors 10 and 11

MCR p15,0,r0,c1,c0,2 // Write CP Access register

ISB

MOV r0,#0x40000000 // Switch on the VFP and NEON hardware

MSR FPEXC,r0 // Set EN bit in FPEXC

}

下面的EnableNEON函數使能NEON協處理器;使用下面的編譯選擇就能在bare-metal下使能NEON

armcc -c --cpu=Cortex-A8 --debug hello.c -o hello.o

armlink --entry=EnableNEON hello.o -o hello.axf

系統運行時使能NEON

內核在遇到第一個NEON指令時會產生一個Undefined Instruction的異常,這會讓內核自動重啟NEON協處理器,內核還可以在上下文切換時關閉NEON來省電。

Linux內核的NEON配置

圖1. NEON的Linux內核配置

使能NEON,需要選擇

Floating point emulation→VFP-format floating point maths

和Floating point emulation→Advanced SIMD (NEON) Extension

檢查Linux的配置文件來確認內核是否使能NEON

zcat /proc/config.gz | grep NEON

看是否存在

CONFIG_NEON=y

確認處理器是否支持NEON

cat /proc/cpuinfo | grep neon

看是否有如下內容

Features : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt

向量化NEON優化指南

避免指針混疊alias

C90不要求指針位置,不同指針可以指向相同的內存區域,C99中引入了__restrict關鍵字來表明只有這個指針能指向它工作的區域。

告訴編譯器循環信息

如循環是否某個整數的整數倍,以方便向量化;如下表明循環次數是4的整數倍:

for(i=0 ; i < (len & ~3) ; i++)

{

。。。

}

for (i=0; i

{

。。。

}

循環展開

#pragma unroll (n)

採用NEON Intrinsics

armcc, GCC/g++和llvm等編譯器都支持 NEON C/C++ intrinsics,並且採用相同的語法規範。因而代碼可以在各個編譯器間共享。NEON Intrinsics的代碼容易維護而且效率高。NEON Intrinsics採用新的數據類型,這些類型對應於D和Q寄存器。NEON Intrinsics寫起來像是函數調用但對應於每一條NEON指令。編程NEON Intrinsics時不用考慮具體的寄存器分配和代碼的schedule,pipeline流水安排等。但NEON Intrinsics往往不能產生想像的代碼,性能上相比純彙編要稍差一些。

減少循環內的相關性

如果當前迭代時使用的數據是上次迭代計算的結果,就產生了迭代間的相關性,可以拆分循環來減少相關。

向量化其他準則

  • 短小的循環更容易讓編譯器實現自動向量化;
  • 避免在循環內使用break退出循環
  • 避免在循環內使用過多的條件語句,減少可能產生的條件跳轉;
  • 讓循環次數儘可能是2的冪次
  • 讓編譯器知曉循環次數,減少對循環次數為0等的判斷;
  • 循環內調用的函數儘量inline內聯
  • 使用數組+索引的方式訪問比指針形式更容易向量化;
  • 間接尋址(多重索引)不會向量化;
  • 使用restrict關鍵字來告訴編譯器沒有重疊的內存區域;

總結

本文介紹了ARM平臺基於ARM v7-A架構的ARM Cortex-A系列處理器(Cortex-A5, Cortex-A7, Cortex-A8, Cortex-A9, Cortex-A15)上的NEON多媒體處理硬體加速器針對C/C++語言、彙編語言和NEON intrinsics如何編譯和優化,包含如何向量化、向量化的ARMCC和GCC編譯器選項、NEON的彙編和EABI程序調用規範、如何在bare-metal和Linux作業系統上檢測NEON硬體、如何指導編譯器進行向量化NEON指令的優化等內容。

參考

http://houh-1984.blog.163.com/

本文介紹了ARM平臺基於ARM v7-A架構的ARM Cortex-A系列處理器(Cortex-A5, Cortex-A7, Cortex-A8, Cortex-A9, Cortex-A15)上的NEON多媒體處理硬體加速器針對C/C++語言、彙編語言和NEON intrinsics如何編譯和優化,包含如何向量化、向量化的ARMCC和GCC編譯器選項、NEON的彙編和EABI程序調用規範、如何在bare-metal和Linux作業系統上檢測NEON硬體、如何指導編譯器進行向量化NEON指令的優化等內容。

相關焦點

  • ARM Cortex系列(A8/A9/A15/A7) NEON多媒體處理SIMD引擎優化
    · 系統設計:ARM RealView® SoC Designer工具提供快速的架構優化和性能分析,並允許在硬體完成以前很長時間即可進行軟體驅動程序和對時間要求很嚴格的代碼的早期開發。RealView系統發生器(RealView System Generator)工具為基於Cortex-A9處理器的虛擬平臺的採用提供超快建模能力。
  • android平臺arm指令學習和調試
    :123456)Ni是單步,setdisassemble-nexton下一句指令顯示反彙編,使用setarmforce-modearm或者setarmforce-modethumb讓gdb切換thumb和arm代碼顯示。
  • ARM處理器NEON編程及優化技巧——數據加載和存儲
    首先會關注內存操作,即如何變更指令來靈活有效的加載和存儲數據。接下來是由於SIMD指令的應用而導致剩下的若干個單元的處理,最後是一個例子來說明用NEON來進行SIMD優化。使用結構化的加載指令加載RGB數據然後使用VLD3分開加載的數據就能方便的使用指令(VSWP d0, d2)來進行R和B通道的交換了,然後把結果再寫入內存,當然也要使用interleave交織模式的存儲,即VST3存儲指令。
  • ARM處理器NEON編程及優化技巧——矩陣乘法的實例
    ARM的NEON協處理器技術是一個64/128-bit的混合SIMD架構,用於加速包括視頻編碼解碼、音頻解碼編碼、3D圖像、語音和圖像等多媒體和信號處理應用。本文主要介紹如何使用NEON的彙編程序來寫SIMD的代碼,包括如何開始NEON的開發,如何高效的利用NEON。首先會關注內存操作,即如何變更指令來靈活有效的加載和存儲數據。
  • 常用ARM彙編指令
    本文引用地址:http://www.eepw.com.cn/article/201611/322957.htmARM指令集可以分為六大類,分別為數據處理指令、Load/Store指令、跳轉指令、程序狀態寄存器處理指令、協處理器指令和異常產生指令。
  • ARM處理器NEON編程及優化技巧——處理剩餘的元素
    ARM的NEON協處理器技術是一個64/128-bit的混合SIMD架構,用於加速包括視頻編碼解碼、音頻解碼編碼、3D圖像、語音和圖像等多媒體和信號處理應用。本文主要介紹如何使用NEON的彙編程序來寫SIMD的代碼,包括如何開始NEON的開發,如何高效的利用NEON。首先會關注內存操作,即如何變更指令來靈活有效的加載和存儲數據。
  • ARM高效C編程和優化--編譯器,內存和Cache優化以及功耗管理
    C編譯器不能產生很多指令,尤其是最近ARM架構中引入的指令,這主要因為這些指令的語義跟C語言並不完全一致。熟練的程式設計師可以手工鞋彙編代碼來使用這些新指令,但是使用ARM C編譯器提供的豐富的intrinsic函數將更為簡單些。下面的例子是使用ARMv6以後引入的SMUSD和SMUADX指令實現的複數乘法,
  • Arm Linux+Arduino板=現代版遊戲機
    從理論上講,它也應該是一個很好的教育平臺,孩子們可以創建自己的遊戲,還能了解Linux和Arduino。趁熱,盤它!按下電源啟動後,幾秒鐘後我們進入主菜單,其中包含幾個圖標,具體是設置、MAME、MGBA、NES和PCxs遊戲模擬器,運行模擬器裝在相應ROM/BIOS就可以運行遊戲了。
  • 超另類:在vscode下實現編譯仿真下載,你絕對想不到
    這個教程將介紹下如何在vscode下實現這些操作,真正實現一個vscode可以吃天、實現編譯仿真下載一條龍服務,而你只需要在vscode下的終端敲幾個命令而已。。。本教程以阿波羅開發板stm32f429igt6為例,先瞅瞅最終界面最終可以用的功能如下:1,vscode終端下執行make指令,即可在build文件下編譯出.hex .bin .elf文件,中間文件放在build/Obj/文件夾下2,執行make clean,可清除build文件夾3,執行make download,可一鍵下載hex
  • 有關arm彙編中的align
    經常會看到arm-linux彙編中有如下的指令:.align n它的含義就是使得下面的代碼按一定規則對齊,.align n 指令的對齊值有兩種方案,n 或 2^n ,各種平臺最初的彙編器一般都不是gas,採取方案1或2的都很多,gas的目標是取代原來的彙編器,必然要保持和原來彙編器的兼容,因此在gas中如何解釋 .align指令會顯得有些混亂,原因在於保持兼容。
  • ARM-Linux開發與MCU開發的差別是什麼
    (5)啟動方式不同 單片機: 其結構簡單,內部集成flash, 通常是晶片廠商在程序上電時加入固定的跳轉指令,直接跳轉到程序入口(通常在flash上);開發的應用程式通過編譯器編譯,採用專用下載工具直接下載到相應的地址空間;所以系統上電後直接運行到相應的程序入口,實現系統的啟動。
  • 一文看懂arm架構和x86架構有什麼區別
    本文主要介紹的是arm架構和x86架構的區別,首先介紹了ARM架構圖,其次介紹了x86架構圖,最後從性能、擴展能力、作業系統的兼容性、軟體開發的方便性及可使用工具的多樣性及功耗這五個方面詳細的對比了arm架構和x86架構的區別,具體的跟隨小編一起來了解一下。
  • ARM架構是什麼?為什麼連高通都離不開?
    所有的iPhone和iPad都使用ARM晶片,多數Kindle閱讀器和Android設備也都採用這一架構。這點蘋果三星能比華為好到哪裡去呢?而現在其實可以說ARM是全球唯一認可的手機晶片架構標準制定商。
  • 在Eclipse下編譯Keil MDK工程
    基中xxx為工程根目錄路徑, "-d"表示設置KeilBuilder的工程路徑, "-e"表示在編譯時自動對Eclipse工程進行設置, 目前僅設置"C/C++ Build" -> "Settings" -> "Cross GCC Compiler" -> 「Symbols」和」Includes」以及」Cross GCC Assmebler」 -> 「General」項.
  • ARM彙編指令集之三——跳轉指令
    ARM指令集中的跳轉指令可以完成從當前指令向前或向後的32MB的地址空間的跳轉,包括以下4條指令:1、 B指令B指令的格式為:B{條件}目標地址B指令是最簡單的跳轉指令。一旦遇到一個B指令,ARM處理器將立即跳轉到給定的目標地址,從那裡繼續執行。
  • 常用ARM指令集及彙編
    318760.htm(一)ARM指令集1.指令格式2.條件碼3.ARM存儲器訪問指令1)LDR/ STR-加載/ 存儲指令2)LDM/ STM-多寄存器加載/ 存儲指令3)SWP-寄存器和存儲器交換指令4.ARM數據處理指令1)數據傳送指令a)MOV-數據傳送指令
  • 基於Android的ARM彙編語言系列之五:ARM指令集與Thumb指令集
    與Thumb指令集之六:NEON指令集與VFP指令集本文引用地址:http://www.eepw.com.cn/article/201611/317690.htm寫在前面:本篇文章旨在大致介紹下ARM指令集的相關內容,這裡也同時提供一個有詳細解釋和用例的待書籤的PDF版本,方便大家查閱。
  • ARM彙編指令集之五——乘法指令與乘加指令
    ,指令中的所有操作數、目的寄存器必須為通用寄存器,不能對操作數使用立即數或被移位的寄存器,同時,目的寄存器和操作數1必須是不同的寄存器。其中,操作數1和操作數2均為32位的有符號數。其中,操作數1和操作數2均為32位的有符號數。對於目的寄存器Low,在指令執行前存放64位加數的低32位,指令執行後存放結果的低32位。對於目的寄存器High,在指令執行前存放64位加數的高32位,指令執行後存放結果的高32位。
  • ARM指令中特殊符號意義
    特殊符號 對應指令 含義= DCB 分配一片連續的字節存儲單元並用指定的數據初始化& DCD 分配一片連續的字存儲單元並用指定的數據初始化% SPACE