Armv8上不棄不離的NEON/FPU

微信公眾號(hào)mindshare思享

此文來(lái)源于本人在arm開(kāi)發(fā)者網(wǎng)站發(fā)布的英文文章

Hints?for running software on V8-A processors without FPU

現(xiàn)用中文講一遍。

熟悉arm

processor的朋友應(yīng)該知道arm的Cortex-A是帶有FPU和NEON的,F(xiàn)PU用來(lái)做浮點(diǎn)數(shù)運(yùn)算的,而NEON是SIMD指令做并行運(yùn)算的。在現(xiàn)有Cortex-A的設(shè)計(jì)里,NEON和FPU是不可分的,也就是不能單獨(dú)只有NEON或是FPU。在比較高性能的Cortex-A

CPU(比如Cortex-A15/A57/A72/A73/A75)中,NEON和FPU是不能在RTL配置里去掉的,在高能效的Cortex-A的CPU(比如Cortex-A7/A53/A55)中NEON和FPU是可以在RTL配置里面配置有或是沒(méi)有。

NEON和FPU畢竟是占面積的,也許你會(huì)認(rèn)為你的應(yīng)用可能用不到NEON或是FPU,所以你可以配置RTL沒(méi)有NEON/FPU,以減少面積die size或功耗。

這在Armv7里可能不是問(wèn)題,但是在armv8 64位里需要非常小心,也許因?yàn)檫@個(gè)配置導(dǎo)致你的芯片稱為無(wú)用的廢片,有些客戶因此遭受損失,雖然我們已經(jīng)盡可能地告知客戶們。

問(wèn)題描述

在 armv8 aarch64中,arm規(guī)定了過(guò)程調(diào)用規(guī)范Procedure Call Standard for the ARM 64-bit Architecture’--AAPCS64,這個(gè)規(guī)范時(shí)規(guī)定在函數(shù)調(diào)用過(guò)程中怎么傳輸入和輸出參數(shù),哪些寄存器需要調(diào)用者保護(hù),哪些寄存器需要被調(diào)用者保護(hù)。之所以要定義這個(gè)規(guī)范就是要使不同的compiler (arm compiler, gcc, llvm)生成的庫(kù)能兼容地被使用,能被鏈接器鏈接起來(lái)生成一個(gè)可執(zhí)行文件或是庫(kù)。這保證了arm生態(tài)的軟件兼容,非常重要。

和我們這次要討論的話題相關(guān)的是怎么來(lái)傳浮點(diǎn)數(shù)的函數(shù)輸入輸出參數(shù)。

在Armv7的AAPCS32規(guī)范里,我們實(shí)際上定義了兩種傳浮點(diǎn)數(shù)的方式:

softfp

hardfp

這兩個(gè)的區(qū)別在于,softfp 是用整形的通用寄存器(r0-r3)來(lái)傳浮點(diǎn)數(shù)參數(shù)的,比如

float fadd(float a, float b)

a和b實(shí)際上是通過(guò)r0,r1傳入到被調(diào)函數(shù)的,結(jié)果也是通過(guò)r0傳出的。

但如果使用hardfp,那么用浮點(diǎn)數(shù)寄存器來(lái)傳參數(shù),以上同樣的例子,a和b是通過(guò)s0, s1寄存器來(lái)傳的,結(jié)果是通過(guò)s0傳出的。

在GCC compiler里提供了一下選項(xiàng)來(lái)選擇你編譯的代碼是使用哪個(gè)方式

-mfloat-abi=softfp/hard

因?yàn)槭褂貌煌膮?shù)傳遞方式,所以你不能將一個(gè)使用softfp另外一個(gè)使用hardfp的庫(kù)或目標(biāo)文件鏈接起來(lái)。

正式因?yàn)槿绱?,在armv7的時(shí)候有些編譯好的庫(kù)(比如glibc使用softfp)沒(méi)法在使用另一種(使用hardfp)的應(yīng)用編譯中。


有的工具鏈直接只支持一種方式比如arm-linux-gnueabi,和arm-linux-gnueabihf。

但是維護(hù)這種不同的ABI帶來(lái)了兼容性維護(hù)的問(wèn)題,比如同樣一套庫(kù)可能要提供兩個(gè)版本。因此很多OS廠商開(kāi)始只支持一種方式,比如ubuntu從12.04開(kāi)始只支持hardfp.

正是因?yàn)橐陨显?,armv8 aarch64的AAPCS只支持hardfp,這就需要用到NEON/FPU寄存器。如果你的CPU配置了沒(méi)有NEON/FPU,可能軟件上會(huì)帶來(lái)比較大的問(wèn)題,導(dǎo)致一些通用的OS分發(fā)版本(ubuntu,Redhat)沒(méi)法正常跑。

對(duì)軟件和compiler的影響

Compiler和一般的OS分發(fā)版本都會(huì)假設(shè)armv8

aarch64的CPU是帶NEON/FPU的,除非你能非常肯定地知道你的軟件和庫(kù)不會(huì)使用任何的浮點(diǎn)數(shù)運(yùn)算,這樣的話我們之后會(huì)提供一些編譯選項(xiàng),以便compiler不生成使用浮點(diǎn)數(shù)的指令。這樣的話你或許可以在RTL里去掉NEON/FPU.

對(duì)Linux kernel的影響

為了可以是之前的32位且使用softfp應(yīng)用可以跑在arm64kernel上,Linux kernel提供下面的patch,

https://patchwork.kernel.org/patch/9405787/

這個(gè)patch允許arm64 Linux kernel本身可以在沒(méi)有NEON/FPU的CPU上跑。

但是我們不建議去除NEON/FPU,因?yàn)槟憧赡苄枰芡ㄓ玫腖inux kernel.即使Linux kernel本身可以在沒(méi)有NEON/FPU的CPU上運(yùn)行,但是還需要考慮user space的應(yīng)用和庫(kù)是使用AAPCS64ABI編譯的,他們還是需要NEON/FPU.

Compiler的支持

GCC提供了-mgeneral-regs-onlyoption選項(xiàng),這個(gè)選項(xiàng)禁止生成的代碼使用浮點(diǎn)數(shù)寄存器,但他不限制匯編使用浮點(diǎn)數(shù)寄存器。

Arm compiler 6也提供了-mcpu=name+nofp+nosimd這個(gè)選項(xiàng)達(dá)到以上目標(biāo),但是一旦使用這個(gè)選項(xiàng),你的代碼就不能有浮點(diǎn)數(shù)的類(lèi)型和運(yùn)算。

如果你肯定你的程序和庫(kù)都只需要整形運(yùn)算,你可以試以上選項(xiàng),這樣的話就不需要NEON/FPU的硬件支持。

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0773g/chr1383143713787.html

Linux分發(fā)版本情況



附錄

AAPCS32 allows both soft and hard float ABI by defining ‘The base standard’ and ‘The standard variants’.



5 THE BASE PROCEDURE CALL STANDARD?

The

base standard defines a machine-level, core-registers-only calling

standard common to the ARM and Thumb instruction sets. It should be used

for systems where there is no floating-point hardware, or where a high

degree of inter-working with Thumb code is required.

6.1 VFP and Advanced SIMD Register Arguments?

This

variant alters the manner in which floating-point values are passed

between a subroutine and its caller and allows significantly better

performance when a VFP co-processor or the Advanced SIMD Extension is

present.


6.1.1 Mapping between registers and memory format?

Values passed across a procedure call interface in VFP registers are laid out as follows:?

??A

half precision floating point type is passed as if it were loaded from

its memory format into the least significant 16 bits of a single

precision register.?

??A

single precision floating point type is passed as if it were loaded

from its memory format into a single precision register with VLDR.?

??A

double precision floating point type is passed as if it were loaded

from its memory format into a double precision register with VLDR.

See more information in AAPCS32 spec,

http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容