c - 在 VS 2017 中编写管道优化的 C AVX 代码

标签 c visual-studio compiler-optimization pipeline avx

我正在尝试编写 C 代码,通过使用管道来掩盖 CPU 操作延迟。以下是摘录:

__m256  v256f_rslt_0 = _mm256_loadu_ps(&ch_results_8[pos + (0 * FLOATS_IN_M256)]);
__m256  v256f_rslt_1 = _mm256_loadu_ps(&ch_results_8[pos + (1 * FLOATS_IN_M256)]);
__m256  v256f_rslt_2 = _mm256_loadu_ps(&ch_results_8[pos + (2 * FLOATS_IN_M256)]);
__m256  v256f_rslt_3 = _mm256_loadu_ps(&ch_results_8[pos + (3 * FLOATS_IN_M256)]);

__m256  v256f_scale_0 = _mm256_loadu_ps(&cl_8[pos + (0 * FLOATS_IN_M256)]);
__m256  v256f_scale_1 = _mm256_loadu_ps(&cl_8[pos + (1 * FLOATS_IN_M256)]);
__m256  v256f_scale_2 = _mm256_loadu_ps(&cl_8[pos + (2 * FLOATS_IN_M256)]);
__m256  v256f_scale_3 = _mm256_loadu_ps(&cl_8[pos + (3 * FLOATS_IN_M256)]);

v256f_rslt_0 = _mm256_max_ps(v256f_rslt_0, v256f_c_zero);
v256f_rslt_1 = _mm256_max_ps(v256f_rslt_1, v256f_c_zero);
v256f_rslt_2 = _mm256_max_ps(v256f_rslt_2, v256f_c_zero);
v256f_rslt_3 = _mm256_max_ps(v256f_rslt_3, v256f_c_zero);

v256f_rslt_0 = _mm256_mul_ps(v256f_rslt_0, v256f_scale_0);
v256f_rslt_1 = _mm256_mul_ps(v256f_rslt_1, v256f_scale_1);
v256f_rslt_2 = _mm256_mul_ps(v256f_rslt_2, v256f_scale_2);
v256f_rslt_3 = _mm256_mul_ps(v256f_rslt_3, v256f_scale_3);

有 5 个数学运算 * 4;显示 2 个。

但是,编译器破坏了流水线。这是 ASM 的一部分:

vmaxps  ymm2, ymm0, ymm10
vmulps  ymm0, ymm2, YMMWORD PTR [r9+rax-96]
vminps  ymm2, ymm0, ymm7
vmovups ymm0, YMMWORD PTR [rax-64]
vmulps  ymm6, ymm3, ymm8
vsubps  ymm3, ymm7, ymm2

vmaxps  ymm2, ymm0, ymm10
vmulps  ymm0, ymm2, YMMWORD PTR [r9+rax-64]
vminps  ymm2, ymm0, ymm7
vmovups ymm0, YMMWORD PTR [rax-160]
vmulps  ymm5, ymm3, ymm8
vsubps  ymm3, ymm7, ymm2

编译器已明确将代码分为 4 个 block ,这意味着将出现最大延迟。

编译器优化:/O2/Oi/Ot/GL 链接器优化:/OPT:REF/OPT:ICF/LTCG:incremental

有没有办法阻止编译器对指令重新排序,从而保留流水线源代码?

最佳答案

在乱序执行的 CPU 上,通常不需要如此小规模的软件流水线,只要您使用多个累加器,这样 CPU 就可以找到一些 ILP。

现代 x86 CPU 在小规模指令调度方面出人意料地强大,现在 uop 缓存基本上消除了前端解码/对齐问题。 (但是,32 字节边界的指令位置仍然会对 uop 缓存产生影响,如果您遇到前端瓶颈,这可能会很重要。)

由于指令调度而导致的后端瓶颈很少见,直到您获得更长的 dep 链(大于 RS 大小):请参阅 Understanding the impact of lfence on a loop with two long dependency chains, for increasing lengths了解有关现代 CPU 如何处理多个长 dep 链以及查找 ILP 的限制的大量详细信息。

唯一可以运行此 AVX 代码的有序 CPU 是第一代 Xeon Phi (Knight's Corner),您通常希望使用它的 AVX512 变体而不是 AVX2。


同意此指令调度可能比您在源代码中使用的顺序更糟糕。

在较大规模下,或者如果您发现即使在这种规模下,手动调度指令(例如通过编辑编译器生成的 asm)也有助于提高性能,那么请尝试使用更好的编译器。

gcc、clang 和 ICC 都可以编译内部函数,因此您不会受制于 MSVC。

关于c - 在 VS 2017 中编写管道优化的 C AVX 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52041552/

相关文章:

c - 可以在c函数中传递的指针所指向的变量的最大大小是多少?

c# - 如何将动态变化的字符串传递给脚本任务?

visual-studio - VS2012 签名程序集错误 - "Cannot find the certificate..."

c - 哪个免费的 C 编译器提供了更好的优化选项?

c++ - 是否有一种巧妙的方法可以避免在 C++ 中使用嵌套类进行额外填充?

c - if语句整数

c - ANSI C 的可移植类型定义

c - 如何轻松地将一个字节的最后 x 位替换为另一个字节的 x 位?

C++ (Visual Studio) : Recieving nothing when trying to read input from a . txt 文件

java - 编译器优化: will double checking a case cause removal?