基於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.htmarmcc編譯器使用--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
gcc選擇用-mfpu=vfpv3-fp16來指定為vfp協處理,而-mfpu=neon-vfpv4等就能指定為NEON+VFP結構。
-mfloat-abi=soft使用軟體浮點庫,不是用VFP或者NEON指令;-mfloat-abi=softfp使用軟體浮點的調用規則,而可以使用VFP和NEON指令,編譯的目標代碼和軟體浮點庫連結使用;
-mfloat-abi=hard使用VFP和NEON指令,並且改變ABI調用規則來產生更有效率的代碼,如用vfp寄存器來進行浮點數據的參數傳遞,從而減少NEON寄存器和ARM寄存器的拷貝。
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 |
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
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寄存器來傳遞參數。
ARM編譯器(armcc)從4.0之後就支持在某些處理器和FPU的選項中預定義宏__ARM_NEON__, armasm的宏TARGET_FEATURE_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優化版本。
#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指令時會產生一個Undefined Instruction的異常,這會讓內核自動重啟NEON協處理器,內核還可以在上下文切換時關閉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
C90不要求指針位置,不同指針可以指向相同的內存區域,C99中引入了__restrict關鍵字來表明只有這個指針能指向它工作的區域。
如循環是否某個整數的整數倍,以方便向量化;如下表明循環次數是4的整數倍:
for(i=0 ; i < (len & ~3) ; i++)
{
。。。
}
for (i=0; i
{
。。。
}
#pragma unroll (n)
armcc, GCC/g++和llvm等編譯器都支持 NEON C/C++ intrinsics,並且採用相同的語法規範。因而代碼可以在各個編譯器間共享。NEON Intrinsics的代碼容易維護而且效率高。NEON Intrinsics採用新的數據類型,這些類型對應於D和Q寄存器。NEON Intrinsics寫起來像是函數調用但對應於每一條NEON指令。編程NEON Intrinsics時不用考慮具體的寄存器分配和代碼的schedule,pipeline流水安排等。但NEON Intrinsics往往不能產生想像的代碼,性能上相比純彙編要稍差一些。
如果當前迭代時使用的數據是上次迭代計算的結果,就產生了迭代間的相關性,可以拆分循環來減少相關。
本文介紹了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指令的優化等內容。