Cortex A9 NEON与VFP使用混淆

Cortex A9 NEON vs VFP usage confusion

本文关键字:VFP A9 NEON Cortex      更新时间:2023-10-16

我正试图为Cortex A9 ARM处理器(更具体地说,是OMAP4)构建一个库,我对在浮点操作和SIMD的上下文中使用NEON与VFP有一点困惑。需要注意的是,我知道两个硬件协处理器单元之间的区别(也在这里概述),我只是对它们的正确使用有一些误解。

与此相关,我使用以下编译标志:
GCC
-O3 -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
-O3 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=softfp
ARMCC
--cpu=Cortex-A9 --apcs=/softfp
--cpu=Cortex-A9 --fpu=VFPv3 --apcs=/softfp

我已经通读了ARM文档,很多wiki(像这个),论坛和博客帖子,每个人似乎都同意使用NEON比使用VFP更好或者至少混合氖(例如:在SIMD和VFP中使用内部实现一些算法并不是一个好主意;我还不能100%确定这是否适用于整个应用程序库或仅适用于代码中的特定位置(函数)。

所以我使用霓虹灯作为我的应用程序的FPU,因为我也想使用内在的。因此,我遇到了一点麻烦,我对如何在Cortex A9上最好地使用这些功能(NEON vs VFP)的困惑进一步加深,而不是澄清。我有一些代码,为我的应用程序做基准测试,并使用一些自定义定时器类其中计算是基于双精度浮点数。使用NEON作为FPU给出了完全不合适的结果(试图打印这些值导致主要打印inf和NaN;当为x86构建时,相同的代码可以正常工作)。所以我改变了我的计算使用单精度浮点,因为被记录为NEON不处理双精度浮点。我的基准测试仍然没有给出正确的结果(最糟糕的是,现在它在x86上不再工作了;我认为这是因为失去了精确度,但我不确定)。所以我几乎完全迷路了:一方面,我想使用NEON作为SIMD功能,使用它作为FPU不能提供适当的结果,另一方面,将它与VFP混合似乎不是一个很好的主意。在这方面的任何建议将非常感激!!

我在上面提到的wiki上找到了一篇文章,总结了在NEON环境下浮点优化应该做些什么:

"

  • 只使用单精度浮点数
  • 当你发现一个瓶颈FP函数时,使用NEON intrinsic/ASM。你可以做得比编译器更好。
  • 最小化条件分支
  • 启用RunFast模式
softfp

:

  • 内联浮点代码(除非它非常大)
  • 通过指针而不是值传递FP参数,并在函数调用之间做整数工作。

"

我不能为浮点ABI使用hard,因为我不能链接到我可用的库。大多数的建议对我来说是有意义的(除了"快跑模式",我不明白到底应该做什么,事实上,在这个时刻,我可以做得比编译器更好),但我一直得到不一致的结果,我不确定任何事情现在。

有没有人能告诉我如何正确使用Cortex A9/A8的浮点数和NEON,以及我应该使用哪些编译标志?

…论坛和博客帖子中,每个人似乎都同意使用NEON比使用VFP更好,或者至少混合使用NEON(例如。在SIMD)和VFP中使用内部实现一些算法并不是一个好主意

我不确定这是正确的。根据ARM在介绍NEON开发文章| NEON寄存器:

NEON寄存器库由32个64位寄存器组成。如果两个高级SIMD和VFPv3被实现,它们共享这个寄存器银行。在这种情况下,VFPv3以VFPv3- d32的形式实现支持32个双精度浮点寄存器。这集成简化了实现上下文切换支持,因为保存和恢复VFP上下文的相同例程也保存和

NEON单元可以查看与

相同的寄存器库:
  • 16个128位四字寄存器,Q0-Q15
  • 32位双字寄存器,D0-D31.

NEON D0-D31寄存器与VFPv3 D0-D31寄存器相同每个Q0-Q15寄存器映射到一对D寄存器。图1.3显示了共享的NEON和VFP的不同视图登记银行。所有这些视图都可以在任何时候访问。软件不需要显式地在它们之间切换,因为使用的指令确定适当的视图。

寄存器不竞争;相反,它们作为注册库的视图共存。霓虹灯和FPU齿轮是无法排出的。


与此相关,我使用以下编译标志:
-O3 -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
-O3 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=softfp

我是这样做的;你的里程可能会有所不同。它来源于从平台和编译器收集的信息的混搭。

gnueabihf告诉我平台使用硬浮动,这可以加快过程调用。如果有疑问,请使用softfp,因为它与硬浮点数兼容。

BeagleBone黑色 :

$ gcc -v 2>&1 | grep Target          
Target: arm-linux-gnueabihf
$ cat /proc/cpuinfo
model name  : ARMv7 Processor rev 2 (v7l)
Features    : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32 
...

所以BeagleBone使用:

-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard

CubieTruck v5 :

$ gcc -v 2>&1 | grep Target 
Target: arm-linux-gnueabihf
$ cat /proc/cpuinfo
Processor   : ARMv7 Processor rev 5 (v7l)
Features    : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4 
所以CubieTruck使用:
-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard

Banana Pi Pro:

$ gcc -v 2>&1 | grep Target 
Target: arm-linux-gnueabihf
$ cat /proc/cpuinfo
Processor   : ARMv7 Processor rev 4 (v7l)
Features    : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt

所以香蕉派使用:

-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard

树莓派3:

RPI3的独特之处在于它的ARMv8,但它运行的是32位操作系统。这意味着它是有效的32位ARM Aarch32。32位ARM和Aarch32之间有更多的区别,但这将向您展示Aarch32标志

此外,RPI3使用Broadcom A53 SoC,它具有NEON和可选的CRC32指令,但缺乏可选的Crypto扩展。

$ gcc -v 2>&1 | grep Target 
Target: arm-linux-gnueabihf
$ cat /proc/cpuinfo 
model name  : ARMv7 Processor rev 4 (v7l)
Features    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
...

所以树莓派可以使用:

-march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard

或者它可以使用(我不知道该用什么-mtune):

-march=armv7-a -mfpu=neon-vfpv4 -mfloat-abi=hard 

ODROID C2 :

ODROID C2使用Amlogic A53 SoC,但使用64位操作系统。ODROID C2,它有NEON和可选的CRC32指令,但缺乏可选的Crypto扩展(类似于RPI3的配置)。

$ gcc -v 2>&1 | grep Target 
Target: aarch64-linux-gnu
$ cat /proc/cpuinfo 
Features    : fp asimd evtstrm crc32

所以ODROID使用:

-march=armv8-a+crc -mtune=cortex-a53

在上面的配方中,我通过查看数据表来了解ARM处理器(如Cortex A9或A53)。根据Unix和Linux Stack Exchange上的这个答案,它破译了/proc/cpuinfo的输出:

CPU part:部件号。0xd03表示Cortex-A53处理器。

因此,我们可以从数据库中查找该值。我不知道它是否存在,也不知道它在哪里。

我认为这个问题应该分成几个,添加一些代码示例并详细说明所使用的目标平台和工具链的版本。

但是为了掩盖一部分困惑:"使用NEON作为FPU"的建议听起来像是一个误解。NEON是SIMD引擎,VFP是FPU。您可以使用NEON对多达4个单精度值并行进行单精度浮点操作,这(在可能的情况下)有利于性能。

-mfpu=neon可以看作是-mfpu=neon-vfpv3的简写。

我会远离VFP。它就像thumb模式:它是为编译器设计的。对它们进行优化是没有意义的。

这可能听起来很粗鲁,但我真的不认为NEON intrinsic有任何意义。如果有的话,麻烦多于帮助。

只需花两到三天的时间在基本的ARM组装上:你只需要学习一些循环控制/终止的指令。

然后你就可以开始编写本地NEON代码,而不用担心编译器会做一些奇怪的事情,吐出大量的错误/警告。

学习NEON指令比所有这些内在宏要求更低。除此之外,结果要好得多。

完全优化的NEON本机代码通常比编写良好的内部代码运行速度快两倍以上。

只要将OP的版本与下面链接中的我的版本进行比较,你就会明白我的意思了。

利用NEON优化rgb8888到RGB565的转换