clang 如何选择针对我的 ARM 目标上的浮点协处理器优化的 memcpy?

问题描述 投票:0回答:1

我正在开发当前使用 gcc 和基于 newlib 4.3.0 的运行时构建的项目。

作为一个实验,看看我们是否可以减少链接时间,我正在尝试与 lld Thin lto 链接的 clang 编译。到目前为止,良好的链接时间减少了,但我的目标的运行时性能随着 clang 变得更差。 Clang 运行时与 gcc 相同,也基于 newlib 4.3.0。

通过调试和比较我的 gcc 构建和 clang 构建,我观察到我的 clang 构建选择了“错误的”memcpy,即 clang 选择了名为 libc_a-aeabi_memcpy-armv7a.o 的函数,而 gcc 选择了名为 libc_a-memcpy-armv7a 的函数.o.通过 llvm-objdump 我可以看到 libc.a 包含这两种实现。

aeabi_memcpy-armv7a,似乎是针对arm优化的memcpy版本,具有硬浮点支持。因此,人们应该认为这是正确的选择,但它实际上比 gcc 选择的慢,因为它不使用 ARM 硬浮点单元/协处理器允许的矢量化指令?

当我为 gcc 和 clang 进行编译时,我使用选项 -mthumb -mfloat-abi=hard -mcpu=cortex-a9 -mfpu=neon -munaligned-access。 IE。基本上,我告诉我的 cpu 和 fpu,然后让 clang 在 newlib 中选择正确的 memcpy 优化版本。除非它选错了?

设置 cpu 和 fpu 不应该足以告诉 clang 可以选择“正确的”memcpy 吗? 其中“正确的”memcpy 是实际使用我的 cortex-a9 实际拥有的硬浮点单元的 memcpy,与 gcc 相同。

无论如何,clang 没有选择“正确的”memcpy,因此我的问题是我在做什么让 clang 选择“错误的”aeabi_memcpy? clang 如何选择它,我一直无法弄清楚,因为 libc.a 包含两个实现,它必须以某种方式选择它并将其映射到用户,但如何让我困惑。

以下是上面提到的 memcpy 函数放置的一些详细信息: libc(newlib 4.3.0)

newlib-cygwin ewlib\libc\machine rm\memcpy-armv7a.S 使用矢量化,即硬浮点协处理器。 这是 gcc 在我的 gcc 构建中选择的“正确”更快的选项。 newlib-cygwin ewlib\libc\machine rm eabi_memcpy-armv7a.S 不使用矢量化 这是我的 clang 构建中 clang 选择的“错误”较慢的一个。 希望有人可以帮助我找出我做错了什么,或者让 clang 为有问题的处理器设置选择正确版本的 memcpy

newlib-cygwin ewlib\libc\machine rm\memcpy-armv7a.S 是包含“正确”memcpy-armv7a.S 的那个。下面我包含了 memcpy-armv7a.S。 调试宏是否

__ARM_ARCH >= 7 && __ARM_ARCH_PROFILE == 'A' && defined(__ARM_FEATURE_UNALIGNED)

是真的,我试图引入编译错误。这会检查它是否与包含这两种实现的 libc.a 的 llvm-objdump 一致。

#include "arm-acle-compat.h"

#if defined (__OPTIMIZE_SIZE__) || defined (PREFER_SIZE_OVER_SPEED)
  /* Defined in memcpy-stub.c.  */

#elif (__ARM_ARCH >= 7 && __ARM_ARCH_PROFILE == 'A' \
       && defined (__ARM_FEATURE_UNALIGNED))
todo_memcpy_armv7a_was_included //temp compile error to determine if above are defined
**#include "memcpy-armv7a.S"**

#elif __ARM_ARCH_ISA_THUMB == 2 && !__ARM_ARCH_ISA_ARM
#include "memcpy-armv7m.S"

#else
  /* Defined in memcpy-stub.c.  */

#endif

由于 libc.a 的 llvm-objdump 包含这两种实现,所以一定是 clang 以某种方式为 mempcy 创建了正确的别名,我只是无法弄清楚这是否正确或它具体在哪里执行。

我还为我正在编译的项目生成了一个映射文件,映射文件显示使用了aeabi_memcpy-armv7a.S,我预计它是memcpy-armv7a.S。

memcpy-armv7m.S:
  1156bc   1156bc      208     4         C:\tools\llvm-project\18.1.3.B1.03062024\bin\..\lib\clang-runtimes/arm-none-eabi/armv7a_thumb_hard_neon_exn_rtti\lib\libc.a(libc_a-aeabi_memcpy-armv7a.o):(.text)
  1156bc   1156bc        0     1                 $a.0
  1156bc   1156bc        0     1                 __aeabi_memcpy
  1156dc   1156dc        0     1                 word_aligned
  1156fc   1156fc        0     1                 two_word_aligned
  11574c   11574c        0     1                 copy_less_than_64
  115764   115764        0     1                 copy_less_than_8
  11577c   11577c        0     1                 copy_less_than_4
  1157a0   1157a0        0     1                 return
  1157a8   1157a8        0     1                 dst_not_word_aligned
  1157d8   1157d8        0     1                 src_not_word_aligned
  11588c   11588c        0     1                 __aeabi_memcpy4
  1158a0   1158a0        0     1                 __aeabi_memcpy8
arm clang neon fpu newlib
1个回答
0
投票

当构建 newlib 时,编译器会通过称为 multilibs 的东西构建编译器支持的所有风格的 newlib。

您的问题是 clang 选择了 softfloat ABI multilib 而不是 Hardfloat,并且通常更改 -mcpu 应该更改所使用的函数。

但是 LLVM 中的 multilib 是相当新的(https://clang.llvm.org/docs/Multilib.html),因此您需要检查您的编译器是否支持此 multilib。你可以调用 -print-multi-lib 来查看编译器支持什么。

© www.soinside.com 2019 - 2024. All rights reserved.