【问题标题】:Assembly generated from NEON intrinsics [LLVM - Xcode]从 NEON 内在函数生成的程序集 [LLVM - Xcode]
【发布时间】:2013-12-31 16:26:39
【问题描述】:

我正在尝试更多地了解 ARM 程序集,并了解 NEON 内在函数在幕后究竟发生了什么。我正在使用最新的 Xcode LLVM 编译器。我经常发现,从内部函数生成的程序集实际上甚至比简单的 C 代码还要慢。

例如这段代码:

void ArmTest::runTest()
{

    const float vector[4] = {1,2,3,4};
    float result[4];
    float32x4_t vA = vld1q_f32(vector);

    asm("#Begin Test");

    vA = vmulq_f32(vA, vA);

    asm("#End Test");

    vst1q_f32(result, vA);
}

产生这个输出:

#Begin Test

ldr q0, [sp, #16]
stp q0, q0, [fp, #-48]
ldur    q1, [fp, #-32]
fmul.4s v0, v1, v0
str q0, [sp, #16]

#End Test

我无法理解的是为什么所有的负载/存储都会在这里访问内存?我一定遗漏了一些明显的东西,对吧?另外,如何在内联汇编中编写它以使其达到最佳状态?我希望只有一条指令,但输出却大不相同。

请帮助我理解。

谢谢!

【问题讨论】:

  • 你永远不应该相信编译器。看看你的例子,特别是 64 位代码远非一半。停止在内部函数和检查生成的代码上浪费时间,而是学习汇编。无论如何,如果不知道实际指令,您就不会对内在函数走得太远。
  • 您还应该知道,使用 ARM 和 NEON 访问同一内存区域会在“切换”时浪费许多周期。因此,如果您编写测试函数,您应该让它们通过多次迭代来处理大量数据。在您的示例中,向量可能由 ARM 在堆栈上初始化,并由 NEON 读取和计算 - 确实非常慢。
  • void square(float * pDst, float * pSrc, unsigned int size);

标签: arm inline-assembly intrinsics


【解决方案1】:

您需要更好的测试。您的测试不会将您的计算结果用于任何事情,因此编译器只是通过动作让您开心。看起来您正在使用 -O0 进行编译,这将产生一堆不必要的加载和存储以用于调试目的。如果您使用 -O3 进行编译,您的所有代码都将被删除。我重写了您的测试以保留结果并使用 -O3 进行编译,结果如下:

$ cat neon.c 
#include <arm_neon.h>

void runTest(const float vector[], float result[])
{
    float32x4_t vA = vld1q_f32(vector);
     vA = vmulq_f32(vA, vA);
     vst1q_f32(result, vA);
}

$ xcrun -sdk iphoneos clang -arch arm64 -S neon.c -O3
$ cat neon.s 
    .section    __TEXT,__text,regular,pure_instructions
    .globl  _runTest
    .align  2
_runTest:                               ; @runTest
; BB#0:
    ldr q0, [x0]
    fmul.4s v0, v0, v0
    str q0, [x1]
    ret lr

此代码看起来最佳

【讨论】:

  • 谢谢!我知道我错过了一些简单的东西。你得到的结果正是我所期望的,你的猜测是正确的,我没有用 O3 标志编译
猜你喜欢
  • 2014-07-20
  • 1970-01-01
  • 2017-03-05
  • 1970-01-01
  • 2013-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多