【问题标题】:GCC to emit ARM idiv instructions (continued)GCC 发出 ARM idiv 指令(续)
【发布时间】:2014-02-25 11:32:41
【问题描述】:

我想知道这对于 Krait 400 CPU 是否可行。我遵循了一些建议 here

当我使用 mcpu=cortexa15 进行编译时,代码会编译并有效地在程序集转储中看到 udiv 指令。

不过,我想知道:

  1. 是否可以让它与march=armv7-a 一起工作? (不指定 cpu;这就是我最初的方式)
  2. 我尝试使用 mcpu=krait2,但由于我没有使用 snapdragon llvm(我还不知道要付出多少努力),它无法识别它。是否可以从 llvm 获取 cpu 定义并以某种方式使其可用于我的编译器?
  3. 还有其他方法/补丁/技巧吗?

我的编译器选项如下:

 /development/android-ndk-r8e/toolchains/arm-linux-androideabi-4.7/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc  -DANDROID -DNEON -fexceptions -Wno-psabi --sysroot=/development/android-ndk-r8e/platforms/android-14/arch-arm -fpic -funwind-tables -funswitch-loops -finline-limit=300 -fsigned-char -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=neon -fdata-sections -ffunction-sections -Wa,--noexecstack  -marm -fomit-frame-pointer -fstrict-aliasing -O3 -DNDEBUG

我得到的错误是:

Error: selected processor does not support ARM mode `udiv r1,r1,r3'

作为旁注,我不得不说我才刚刚开始了解整个方案,因此我想保持小步骤以了解我在做什么。

提前致谢。

编辑 1

我尝试编译一个单独的模块,只包含 udiv 指令。该模块使用 -mcpu=cortex-a15 参数编译,而应用程序的其余部分使用 -march=armv7-a 参数编译。结果是(以某种方式预期)函数调用开销影响了应用程序的时间性能。我无法获得内联代码,因为进入内联的字符串导致了与我最初遇到的相同的错误。在尝试重新发明轮子之前,我将切换到 Snapdragon 看看是否有更好的性能。感谢大家的回答和提示。

【问题讨论】:

  • 如果您使用的是 ndk,您就无法进行此类黑客攻击,并期望它可以与许多目标一起使用。如果你想和 krait 一起玩,那么只需使用 a15。这将是最简单的。
  • @auselen 感谢您注意到它是 Android。对于查询idiv 支持,我给出了bare metal 答案;如果你有 Linux,/proc/cpuinfo 是最好的信息来源。我将尝试删除 ISAR0 并将所有 cmets 合并到我的答案中...
  • 感谢@auselen 和无艺术的噪音。我知道如果实现了这一点,那么代码将(可能)仅适用于 Armv7-a CPU支持 idiv。当你说:“如果你想玩 krait,那就用 a15。”你的意思是让它最容易编译? (即切换 gcc 的标志)。尽管生成的代码是为我实际上没有的 CPU 量身定制的,但我有点担心。目前我无法评估这种变化的影响。我想我也会寻找有关这方面的文献。

标签: android gcc arm


【解决方案1】:

idiv - 表示sdivudiv 的混合物是可选的Cortex-A 指令。 Cortex-A 的支持可以通过ID_ISAR0 cp15 寄存器查询,位[27:24]。

  /* Get idiv support. */
  unsigned int ISAR0;
  int idiv;
  __asm ("mrc 15, 0, %0, c0, c2, 0" :"=r" (ISAR0));
#ifdef __thumb2__
  idiv = (ISAR0 & 0xf000000UL) ? 1 : 0;
#else
  idiv = (ISAR0 & 0xf000000UL) == 0x2000000UL ? 1 : 0;
#endif

如果只有 thumb2 支持 udivsdiv 指令,位 [27:24] 是 0001。如果位 [27:24] 为 0010,则两种模式都支持指令。

由于 gcc 标志 -march=armv7-a 等意味着代码应该在 ALL 这种类型的 CPU 上运行,并且该指令是可选的,因此 gcc 发出该指令将是错误的。

您可以使用不同的标志编译不同的模块,例如,

gcc -march=armv7-a -o general.o -c general.c 
gcc -mcpu=cortex-a15 -D_USE_IDIV_=1 -o fast_idiv.o -c fast_div.c 

这些模块可以链接在一起,上面的代码可以用来在运行时选择一个合适的例程。例如,两个文件可能都有,

  #include "fir_template.def"

这个文件可能有,

#ifdef _USE_IDIV_
  #define _FUNC(x) idiv_ ## x
#else
  #define _FUNC(x) x
#endif

int _FUNC(fir8)(FILTER8 *filter, SAMPLE *data,)
{
   ....
}

如果您知道您的代码只能在 Cortex-a15 上运行,请使用 -mcpu 选项。如果您希望它运行得更快 IF 它可以是通用的(支持所有 armv7-a CPU),那么您必须按照上面的说明标识 CPU 并动态选择代码。

附录:上述文件(general.cfast_idiv.c)可以放在具有相同 API 的单独共享库中。然后询问/proc/cpuinfo,看看是否支持idiv。将LD_LIBRARY_PATH(或dlopen())设置为适当的版本。选择取决于涉及多少代码。

【讨论】:

  • 还有很多其他方法可以做到这一点。将来gcc 可能会在 ARM 上支持 tune 函数别名;但我认为这目前仅在 x86 上可用。但是,这个想法总是有效的。在运行时使用两组函数和 ID。 cortex-a5 可能是最好的,因为它支持idiv 并且是最低公分母。还有其他可选指令需要注意 fast_idiv.c 不会发出。有关可能的 CPU,请参阅另一个问题。
  • 错误。你有一个FUBAR CPU;您将不得不根据链接以另一种方式识别它。
  • 我想知道你是否可以用自己的 '__aeabi_idiv' 实现来欺骗 gcc,并期望链接时间优化能够完美地修复它。
  • 所以我要说的是使用 armv7a 开关并提供您自己的包含硬件除法的 idiv,您能否获得最终的二进制文件,因为它是在支持硬件 div 的情况下编译的。
  • @auselen 使用 multi-lib,您也许可以将 __aeabi_idiv 链接到像 udiv r0, r1, r2\n bx lr\n 这样的例程,但是直接使用 idiv 的优势是没有函数调用或寄存器杂耍来调用一个函数。我想可能会更好;但我认为我上面提出的将是目前工具状态下最快的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-12
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多