【问题标题】:How to write intinsic code for this inline assembly code?如何为此内联汇编代码编写内部代码?
【发布时间】:2019-11-30 04:00:20
【问题描述】:

我不擅长 SIMD,所以,我需要帮助来将此代码转换为内部代码。 在我看来,这似乎是 C = A * B,但我不确定。 有谁能够帮我? 另外我想问一下内在函数是否可用于移动处理器。 事实上,下面的代码是针对英特尔 CPU 的,但我的工作最终是针对移动设备的。提前致谢。

for (int i = 0; i < M; i++, C += N) {
    float x = A[i];
    _asm {
        mov             esi, N8;
        sub             esi, 8;
        shl             esi, 2;
        xor             edi, edi;
        mov             ebx, B;
        mov             edx, C;
        vbroadcastss    ymm7, x;
    Lrep1:
        cmp             edi, esi;
        jg              Lexit1;
        vmovups         ymm0, ymmword ptr[ebx + edi];
        vmulps          ymm0, ymm0, ymm7;
        vmovups         ymmword ptr[edx + edi], ymm0;
        add             edi, 32;
        jmp             Lrep1;

    Lexit1:
    }
    for (int j = N8; j < N; j++) C[j] = x * B[j];
}

【问题讨论】:

  • 这个循环优化不好;它可能只有 4 或 5 个微指令,但它是 6 个微指令。另外,您是指像笔记本电脑中那样的移动 x86 CPU 吗?还是你的意思是ARM?是的,ARM NEON 有内在函数。但是编译器通常在 NEON 内在函数方面做得不好,这与 x86 的内在函数得到很好的优化不同。

标签: c simd inline-assembly intrinsics


【解决方案1】:

您最好用以下代码替换整个代码:

float x = A[i];
for (int j = 0; j < N; j++) C[j] = x * B[j];

编译器在优化它方面会做得比上面介绍的有点幼稚的 asm 优化尝试要好得多。解雇你的同事:)

至于它在做什么,不是很多。它只是以 8 个批次循环遍历浮点数。不过,正如我所说,它非常愚蠢,而且您最好从使用上面的标准 C 代码的性能 POV 中获得更好的结果。

float x = A[i];
__m256 _x = _mm256_set1_ps(x);
for (int j = 0; j < N8; j += 8) 
{
  _mm256_storeu_ps(C + j, _mm256_mul_ps(_x, _mm256_loadu_ps(B + j)));
}
for (int j = N8; j < N; j++) C[j] = x * B[j];

【讨论】:

  • 感谢您的回答。实际上,我尝试将原始代码作为您的建议。但它变慢了。有没有编译器优化开关?
  • -mavx2 -mfma -O2 -ffast-math (虽然要小心最后一个 - 它可能会改变精度)
  • 确实不应该慢。请参阅此处:godbolt.org/z/agyTp0 查找使用 vmulps 指令的内部循环。实际上,由于此处完成的实际 CPU 工作量很少,因此代码将受到内存带宽的限制。
  • 精彩的答案。还有一个问题。它们在 Visual Studio 项目属性页中是什么?
  • 如果编译器在优化方面做得比在 asm 优化方面有点天真的尝试要好得多,我什么时候应该使用 SIMD?
猜你喜欢
  • 2019-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-12
  • 2021-08-16
  • 2021-01-19
相关资源
最近更新 更多