Cortex A9 NEON与VFP使用混淆

我正在尝试为Cortex A9 ARM处理器(更具体的OMAP4)构建一个库,我对于哪些\何时在浮点运算和SIMD中使用NEON vs VFP有点困惑。 需要注意的是,我知道2个硬件协处理器单元之间的区别(这也在SO上有所描述),我对它们的正确使用有一些误解。

与此相关我使用以下编译标志:

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( 比如这个 ),论坛和博客post,每个人似乎都同意使用NEON比使用VFP或至少混合NEON更好(例如使用instrinsics来实现一些算法在SIMD)和VFP不是一个好主意; 如果这适用于整个应用程序\库的上下文或仅适用于代码中的特定位置(函数),我还不是100%确定。

所以我在我的应用程序中使用neon作为FPU,因为我也想使用内在函数。 结果我遇到了一些麻烦,我对如何在Cortex A9上最好地使用这些function(NEON vs VFP)的困惑只是进一步深化而不是清理。 我有一些代码为我的应用程序进行基准测试,并使用一些自定义的计时器类,其中计算基于双精度浮点。 使用NEON作为FPU会产生完全不合适的结果(尝试打印这些值会导致打印主要是inf和NaN;相同的代码在为x86构建时没有任何障碍)。 所以我改变了我的计算以使用单精度浮点, 据记载,NEON不处理双精度浮点 。 我的基准测试仍然没有给出正确的结果(最糟糕的是现在它在x86上不再起作用了;我认为这是因为精度损失但我不确定)。 所以我几乎完全迷失了:一方面我想使用NEON用于SIMDfunction并使用它,因为FPU没有提供正确的结果,另一方面将它与VFP混合似乎不是一个好主意。 在这方面的任何建议将不胜感激!!

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

  • 仅使用单精度浮点
  • 当您发现瓶颈FPfunction时,请使用NEON内在函数/ ASM。 你可以比编译器做得更好。
  • 最小化条件分支
  • 启用RunFast模式

对于softfp:

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

我不能用于浮动ABI,因为我无法链接到我可用的库。 大多数的推荐对我来说都是有意义的(除了“runfast模式”,我不明白应该做什么以及此时我能做得比编译器更好的事实)但是我一直得到不一致的结果和我现在不确定。

任何人都可以了解如何正确使用浮点和NEON用于Cortex A9 / A8以及我应该使用哪些编译标志?

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

但是要掩盖一部分困惑:“使用NEON作为FPU”的建议听起来像是一种误解。 NEON是SIMD引擎,VFP是FPU。 您可以在最多4个并行的单精度值上使用NEON进行单精度浮点运算,这样(如果可能)对性能有利。

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

有关更多信息,请参阅http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html 。

…论坛和博客文章,每个人似乎都同意使用NEON比使用VFP或至少混合NEON(例如使用instrinsics在SIMD中实现一些算法)和VFP不是一个好主意

我不确定这是否正确。 据ARM 介绍NEON开发文章| NEON注册 :

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

NEON单元可以查看相同的寄存器组:

  • 16个128位四字寄存器,Q0-Q15
  • 32个64位双字寄存器,D0-D31。

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

登记册不竞争; 相反,它们作为注册银行的观点共存。 没有办法去除NEON和FPU装备。


与此相关我使用以下编译标志:

 -O3 -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp -O3 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=softfp 

这就是我的所作所为; 你的旅费可能会改变。 它源于从平台和编译器收集的混合信息。

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

BeagleBone Black

 $ 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 

所以Banana Pi使用:

 -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指令,但缺少可选的加密扩展。

 $ 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 ... 

所以Raspberry Pi可以使用:

 -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指令,但缺少可选的加密扩展(类似于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部件:部件号。 0xd03表示Cortex-A53处理器。

所以我们可以从数据库中查找值。 我不知道它是否存在或它位于何处。

我会远离VFP。 它就像Thmub模式:它适用于编译器。 优化它们没有意义。

这可能听起来很粗鲁,但我真的没有看到NEON内在函数有任何意义。 这比帮助更麻烦 – 如果有的话。

只需在基本的ARM组装中投入两到三天:您只需要学习很少的循环控制/终止指令。

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

学习NEON指令的要求比所有内在宏都要低。 而在此之上,结果要好得多。

完全优化的NEON本机代码通常比编写良好的内在代码快两倍。

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

使用NEON优化RGBA8888到RGB565的转换

问候