21

我正在尝试为 Cortex A9 ARM 处理器(更具体地说是 OMAP4)构建一个库,但对于在浮点运算和 SIMD 的上下文中何时使用 NEON 和 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(比如这个)、论坛和博客文章,并且每个人似乎都同意使用 NEON 比使用 VFP 或至少混合 NEON 更好(例如使用 instrinsics 来实现一些算法在 SIMD 中)和 VFP 不是一个好主意;我还不能 100% 确定这是否适用于整个应用程序\库的上下文或仅适用于代码中的特定位置(函数)。

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

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

"

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

对于softfp:

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

"

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

谁能阐明如何正确使用 Cortex A9/A8 的浮点和 NEON 以及我应该使用哪些编译标志?

4

3 回答 3

10

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

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

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

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

  • 十六个 128 位四字寄存器,Q0-Q15
  • 三十二个 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 黑色

$ 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

香蕉派专业版

$ 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 位 ARMAarch32。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 指令,但缺少可选的加密扩展(类似于 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 and Linux Stack Exchange上的这个答案,它解读了以下输出/proc/cpuinfo

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

所以我们也许可以从数据库中查找值。我不知道它是否存在或它的位置。

于 2016-08-04T19:28:15.227 回答
9

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

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

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

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

于 2011-09-13T11:49:45.450 回答
3

我会远离VFP。就像 Thmub 模式一样:它是为编译器准备的。为它们优化是没有意义的。

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

只需花两三天时间学习基本的 ARM 组装:您只需要学习很少的循环控制/终止指令。

然后,您可以开始编写原生 NEON 代码,而不必担心编译器会执行一些错误/警告。

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

完全优化的 NEON 本机代码的运行速度通常是编写良好的内在函数对应代码的两倍以上。

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

使用 NEON 优化 RGBA8888 到 RGB565 的转换

问候

于 2011-11-01T13:41:12.693 回答