微信公眾號(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)盡可能地告知客戶們。
在 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)法正常跑。
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.
為了可以是之前的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.
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

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